diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 2bf5e0cf..f26eeb33 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -15,5 +15,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 56d67bfd..c40b30b2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,8 +20,8 @@ repositories {
}
dependencies {
- compile 'com.github.turasa:signal-service-java:2.13.8_unofficial_1'
- compile 'org.bouncycastle:bcprov-jdk15on:1.62'
+ compile 'com.github.turasa:signal-service-java:2.13.9_unofficial_1'
+ compile 'org.bouncycastle:bcprov-jdk15on:1.64'
compile 'net.sourceforge.argparse4j:argparse4j:0.8.1'
compile 'org.freedesktop.dbus:dbus-java:2.7.0'
}
diff --git a/man/signal-cli.1.adoc b/man/signal-cli.1.adoc
index d8e0cb90..2f1b2ac2 100644
--- a/man/signal-cli.1.adoc
+++ b/man/signal-cli.1.adoc
@@ -208,6 +208,38 @@ number::
Specify the safety number or fingerprint of the key, only use this option if you have verified
the fingerprint.
+updateProfile
+--------------
+Update the name and/or avatar image visible by message recipients for the current users.
+The profile is stored encrypted on the Signal servers. The decryption key is sent
+with every outgoing messages (excluding group messages).
+
+*--name*::
+ New name visible by message recipients.
+
+*--avatar*::
+ Path to the new avatar visible by message recipients.
+
+*--remove-avatar*::
+ Remove the avatar visible by message recipients.
+
+updateContact
+--------------
+Update the info associated to a number on our contact list. This change is only
+local but can be synchronized to other devices by using `sendContacts` (see
+below).
+If the contact doesn't exist yet, it will be added.
+
+NUMBER::
+ Specify the contact phone number.
+
+*-n*, *--name*::
+ Specify the new name for this contact.
+
+sendContacts
+------------
+Send a synchronization message with the local contacts list to all linked devices.
+This command should only be used if this is the master device.
daemon
~~~~~~
diff --git a/src/main/java/org/asamk/signal/JsonCallMessage.java b/src/main/java/org/asamk/signal/JsonCallMessage.java
index b10e6f7b..2c8518f9 100644
--- a/src/main/java/org/asamk/signal/JsonCallMessage.java
+++ b/src/main/java/org/asamk/signal/JsonCallMessage.java
@@ -1,6 +1,11 @@
package org.asamk.signal;
-import org.whispersystems.signalservice.api.messages.calls.*;
+import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
+import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
+import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
+import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage;
+import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
+import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import java.util.List;
diff --git a/src/main/java/org/asamk/signal/JsonDbusReceiveMessageHandler.java b/src/main/java/org/asamk/signal/JsonDbusReceiveMessageHandler.java
index c0977c0f..6a57e50b 100644
--- a/src/main/java/org/asamk/signal/JsonDbusReceiveMessageHandler.java
+++ b/src/main/java/org/asamk/signal/JsonDbusReceiveMessageHandler.java
@@ -4,7 +4,11 @@ import org.asamk.Signal;
import org.asamk.signal.manager.Manager;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusException;
-import org.whispersystems.signalservice.api.messages.*;
+import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
+import org.whispersystems.signalservice.api.messages.SignalServiceContent;
+import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
+import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
+import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/main/java/org/asamk/signal/JsonReceiveMessageHandler.java b/src/main/java/org/asamk/signal/JsonReceiveMessageHandler.java
index cbfe72bd..1aea2327 100644
--- a/src/main/java/org/asamk/signal/JsonReceiveMessageHandler.java
+++ b/src/main/java/org/asamk/signal/JsonReceiveMessageHandler.java
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
+
import org.asamk.signal.manager.Manager;
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
diff --git a/src/main/java/org/asamk/signal/JsonSyncDataMessage.java b/src/main/java/org/asamk/signal/JsonSyncDataMessage.java
index 06c9b32f..aaf04348 100644
--- a/src/main/java/org/asamk/signal/JsonSyncDataMessage.java
+++ b/src/main/java/org/asamk/signal/JsonSyncDataMessage.java
@@ -2,9 +2,6 @@ package org.asamk.signal;
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
-import java.util.ArrayList;
-import java.util.List;
-
class JsonSyncDataMessage extends JsonDataMessage {
String destination;
diff --git a/src/main/java/org/asamk/signal/Main.java b/src/main/java/org/asamk/signal/Main.java
index e1343fbf..f0010a44 100644
--- a/src/main/java/org/asamk/signal/Main.java
+++ b/src/main/java/org/asamk/signal/Main.java
@@ -18,9 +18,19 @@ package org.asamk.signal;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.impl.Arguments;
-import net.sourceforge.argparse4j.inf.*;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+import net.sourceforge.argparse4j.inf.MutuallyExclusiveGroup;
+import net.sourceforge.argparse4j.inf.Namespace;
+import net.sourceforge.argparse4j.inf.Subparser;
+import net.sourceforge.argparse4j.inf.Subparsers;
+
import org.asamk.Signal;
-import org.asamk.signal.commands.*;
+import org.asamk.signal.commands.Command;
+import org.asamk.signal.commands.Commands;
+import org.asamk.signal.commands.DbusCommand;
+import org.asamk.signal.commands.ExtendedDbusCommand;
+import org.asamk.signal.commands.LocalCommand;
import org.asamk.signal.manager.BaseConfig;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.util.IOUtils;
diff --git a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java
index f8c93f52..eeac7cb5 100644
--- a/src/main/java/org/asamk/signal/ReceiveMessageHandler.java
+++ b/src/main/java/org/asamk/signal/ReceiveMessageHandler.java
@@ -5,9 +5,27 @@ import org.asamk.signal.storage.contacts.ContactInfo;
import org.asamk.signal.storage.groups.GroupInfo;
import org.asamk.signal.util.DateUtils;
import org.asamk.signal.util.Util;
-import org.whispersystems.signalservice.api.messages.*;
-import org.whispersystems.signalservice.api.messages.calls.*;
-import org.whispersystems.signalservice.api.messages.multidevice.*;
+import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
+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;
+import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
+import org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage;
+import org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage;
+import org.whispersystems.signalservice.api.messages.calls.AnswerMessage;
+import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
+import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
+import org.whispersystems.signalservice.api.messages.calls.IceUpdateMessage;
+import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
+import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.ConfigurationMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.ContactsMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.internal.util.Base64;
diff --git a/src/main/java/org/asamk/signal/commands/AddDeviceCommand.java b/src/main/java/org/asamk/signal/commands/AddDeviceCommand.java
index c4402696..dab886d7 100644
--- a/src/main/java/org/asamk/signal/commands/AddDeviceCommand.java
+++ b/src/main/java/org/asamk/signal/commands/AddDeviceCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.whispersystems.libsignal.InvalidKeyException;
diff --git a/src/main/java/org/asamk/signal/commands/Commands.java b/src/main/java/org/asamk/signal/commands/Commands.java
index 6f262fdf..afd93e32 100644
--- a/src/main/java/org/asamk/signal/commands/Commands.java
+++ b/src/main/java/org/asamk/signal/commands/Commands.java
@@ -20,11 +20,14 @@ public class Commands {
addCommand("removeDevice", new RemoveDeviceCommand());
addCommand("removePin", new RemovePinCommand());
addCommand("send", new SendCommand());
+ addCommand("sendContacts", new SendContactsCommand());
+ addCommand("updateContact", new UpdateContactCommand());
addCommand("setPin", new SetPinCommand());
addCommand("trust", new TrustCommand());
addCommand("unregister", new UnregisterCommand());
addCommand("updateAccount", new UpdateAccountCommand());
addCommand("updateGroup", new UpdateGroupCommand());
+ addCommand("updateProfile", new UpdateProfileCommand());
addCommand("verify", new VerifyCommand());
}
diff --git a/src/main/java/org/asamk/signal/commands/DaemonCommand.java b/src/main/java/org/asamk/signal/commands/DaemonCommand.java
index 9b6c0d63..85fee723 100644
--- a/src/main/java/org/asamk/signal/commands/DaemonCommand.java
+++ b/src/main/java/org/asamk/signal/commands/DaemonCommand.java
@@ -3,6 +3,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.DbusReceiveMessageHandler;
import org.asamk.signal.JsonDbusReceiveMessageHandler;
import org.asamk.signal.manager.Manager;
diff --git a/src/main/java/org/asamk/signal/commands/DbusCommand.java b/src/main/java/org/asamk/signal/commands/DbusCommand.java
index 077600e4..4dee75b2 100644
--- a/src/main/java/org/asamk/signal/commands/DbusCommand.java
+++ b/src/main/java/org/asamk/signal/commands/DbusCommand.java
@@ -1,6 +1,7 @@
package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
+
import org.asamk.Signal;
public interface DbusCommand extends Command {
diff --git a/src/main/java/org/asamk/signal/commands/ExtendedDbusCommand.java b/src/main/java/org/asamk/signal/commands/ExtendedDbusCommand.java
index df47994f..b7f70dee 100644
--- a/src/main/java/org/asamk/signal/commands/ExtendedDbusCommand.java
+++ b/src/main/java/org/asamk/signal/commands/ExtendedDbusCommand.java
@@ -1,6 +1,7 @@
package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
+
import org.asamk.Signal;
import org.freedesktop.dbus.DBusConnection;
diff --git a/src/main/java/org/asamk/signal/commands/LinkCommand.java b/src/main/java/org/asamk/signal/commands/LinkCommand.java
index 5c7ce403..2a2d4c4b 100644
--- a/src/main/java/org/asamk/signal/commands/LinkCommand.java
+++ b/src/main/java/org/asamk/signal/commands/LinkCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.UserAlreadyExists;
import org.asamk.signal.manager.Manager;
import org.whispersystems.libsignal.InvalidKeyException;
diff --git a/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java b/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java
index e30acd78..d1590d7c 100644
--- a/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java
+++ b/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.asamk.signal.util.DateUtils;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
diff --git a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java
index 29d136f5..2f8bf411 100644
--- a/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java
+++ b/src/main/java/org/asamk/signal/commands/ListGroupsCommand.java
@@ -3,6 +3,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.asamk.signal.storage.groups.GroupInfo;
import org.whispersystems.signalservice.internal.util.Base64;
diff --git a/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java b/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java
index b2f6f31c..14250eea 100644
--- a/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java
+++ b/src/main/java/org/asamk/signal/commands/ListIdentitiesCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.asamk.signal.storage.protocol.JsonIdentityKeyStore;
import org.asamk.signal.util.Hex;
diff --git a/src/main/java/org/asamk/signal/commands/LocalCommand.java b/src/main/java/org/asamk/signal/commands/LocalCommand.java
index 9f785802..7bcb1a4b 100644
--- a/src/main/java/org/asamk/signal/commands/LocalCommand.java
+++ b/src/main/java/org/asamk/signal/commands/LocalCommand.java
@@ -1,6 +1,7 @@
package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
+
import org.asamk.signal.manager.Manager;
public interface LocalCommand extends Command {
diff --git a/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java b/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java
index 1bde1120..6e53cb2a 100644
--- a/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java
+++ b/src/main/java/org/asamk/signal/commands/QuitGroupCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.GroupIdFormatException;
import org.asamk.signal.GroupNotFoundException;
import org.asamk.signal.NotAGroupMemberException;
@@ -11,7 +12,12 @@ import org.whispersystems.signalservice.api.push.exceptions.EncapsulatedExceptio
import java.io.IOException;
-import static org.asamk.signal.util.ErrorUtils.*;
+import static org.asamk.signal.util.ErrorUtils.handleAssertionError;
+import static org.asamk.signal.util.ErrorUtils.handleEncapsulatedExceptions;
+import static org.asamk.signal.util.ErrorUtils.handleGroupIdFormatException;
+import static org.asamk.signal.util.ErrorUtils.handleGroupNotFoundException;
+import static org.asamk.signal.util.ErrorUtils.handleIOException;
+import static org.asamk.signal.util.ErrorUtils.handleNotAGroupMemberException;
public class QuitGroupCommand implements LocalCommand {
diff --git a/src/main/java/org/asamk/signal/commands/ReceiveCommand.java b/src/main/java/org/asamk/signal/commands/ReceiveCommand.java
index 03f3d1b2..9025aa55 100644
--- a/src/main/java/org/asamk/signal/commands/ReceiveCommand.java
+++ b/src/main/java/org/asamk/signal/commands/ReceiveCommand.java
@@ -3,6 +3,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.Signal;
import org.asamk.signal.JsonReceiveMessageHandler;
import org.asamk.signal.ReceiveMessageHandler;
diff --git a/src/main/java/org/asamk/signal/commands/RegisterCommand.java b/src/main/java/org/asamk/signal/commands/RegisterCommand.java
index 546578b6..2e2b7c4f 100644
--- a/src/main/java/org/asamk/signal/commands/RegisterCommand.java
+++ b/src/main/java/org/asamk/signal/commands/RegisterCommand.java
@@ -3,6 +3,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import java.io.IOException;
diff --git a/src/main/java/org/asamk/signal/commands/RemoveDeviceCommand.java b/src/main/java/org/asamk/signal/commands/RemoveDeviceCommand.java
index 9f5787ae..1e2343e7 100644
--- a/src/main/java/org/asamk/signal/commands/RemoveDeviceCommand.java
+++ b/src/main/java/org/asamk/signal/commands/RemoveDeviceCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import java.io.IOException;
diff --git a/src/main/java/org/asamk/signal/commands/RemovePinCommand.java b/src/main/java/org/asamk/signal/commands/RemovePinCommand.java
index 491c26bd..39eb1f1b 100644
--- a/src/main/java/org/asamk/signal/commands/RemovePinCommand.java
+++ b/src/main/java/org/asamk/signal/commands/RemovePinCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.whispersystems.libsignal.util.guava.Optional;
diff --git a/src/main/java/org/asamk/signal/commands/SendCommand.java b/src/main/java/org/asamk/signal/commands/SendCommand.java
index 176c2d92..7320d76d 100644
--- a/src/main/java/org/asamk/signal/commands/SendCommand.java
+++ b/src/main/java/org/asamk/signal/commands/SendCommand.java
@@ -3,6 +3,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.Signal;
import org.asamk.signal.AttachmentInvalidException;
import org.asamk.signal.GroupIdFormatException;
@@ -18,7 +19,13 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
-import static org.asamk.signal.util.ErrorUtils.*;
+import static org.asamk.signal.util.ErrorUtils.handleAssertionError;
+import static org.asamk.signal.util.ErrorUtils.handleDBusExecutionException;
+import static org.asamk.signal.util.ErrorUtils.handleEncapsulatedExceptions;
+import static org.asamk.signal.util.ErrorUtils.handleGroupIdFormatException;
+import static org.asamk.signal.util.ErrorUtils.handleGroupNotFoundException;
+import static org.asamk.signal.util.ErrorUtils.handleIOException;
+import static org.asamk.signal.util.ErrorUtils.handleNotAGroupMemberException;
public class SendCommand implements DbusCommand {
diff --git a/src/main/java/org/asamk/signal/commands/SendContactsCommand.java b/src/main/java/org/asamk/signal/commands/SendContactsCommand.java
new file mode 100644
index 00000000..523292ab
--- /dev/null
+++ b/src/main/java/org/asamk/signal/commands/SendContactsCommand.java
@@ -0,0 +1,31 @@
+package org.asamk.signal.commands;
+
+import net.sourceforge.argparse4j.inf.Namespace;
+import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.manager.Manager;
+import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
+
+import java.io.IOException;
+
+public class SendContactsCommand implements LocalCommand {
+
+ @Override
+ public void attachToSubparser(final Subparser subparser) {
+ subparser.help("Send a synchronization message with the local contacts list to all linked devices.");
+ }
+
+ @Override
+ public int handleCommand(final Namespace ns, final Manager m) {
+ if (!m.isRegistered()) {
+ System.err.println("User is not registered.");
+ return 1;
+ }
+ try {
+ m.sendContacts();
+ return 0;
+ } catch (IOException | UntrustedIdentityException e) {
+ System.err.println("SendContacts error: " + e.getMessage());
+ return 3;
+ }
+ }
+}
diff --git a/src/main/java/org/asamk/signal/commands/SetPinCommand.java b/src/main/java/org/asamk/signal/commands/SetPinCommand.java
index de4e28ec..9351dad0 100644
--- a/src/main/java/org/asamk/signal/commands/SetPinCommand.java
+++ b/src/main/java/org/asamk/signal/commands/SetPinCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.whispersystems.libsignal.util.guava.Optional;
diff --git a/src/main/java/org/asamk/signal/commands/TrustCommand.java b/src/main/java/org/asamk/signal/commands/TrustCommand.java
index 13fb63d4..f2744545 100644
--- a/src/main/java/org/asamk/signal/commands/TrustCommand.java
+++ b/src/main/java/org/asamk/signal/commands/TrustCommand.java
@@ -4,6 +4,7 @@ import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.MutuallyExclusiveGroup;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.asamk.signal.util.Hex;
diff --git a/src/main/java/org/asamk/signal/commands/UnregisterCommand.java b/src/main/java/org/asamk/signal/commands/UnregisterCommand.java
index 3830abe6..7a7616bd 100644
--- a/src/main/java/org/asamk/signal/commands/UnregisterCommand.java
+++ b/src/main/java/org/asamk/signal/commands/UnregisterCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import java.io.IOException;
diff --git a/src/main/java/org/asamk/signal/commands/UpdateAccountCommand.java b/src/main/java/org/asamk/signal/commands/UpdateAccountCommand.java
index 31964721..79459fe6 100644
--- a/src/main/java/org/asamk/signal/commands/UpdateAccountCommand.java
+++ b/src/main/java/org/asamk/signal/commands/UpdateAccountCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import java.io.IOException;
diff --git a/src/main/java/org/asamk/signal/commands/UpdateContactCommand.java b/src/main/java/org/asamk/signal/commands/UpdateContactCommand.java
new file mode 100644
index 00000000..e1afca69
--- /dev/null
+++ b/src/main/java/org/asamk/signal/commands/UpdateContactCommand.java
@@ -0,0 +1,34 @@
+package org.asamk.signal.commands;
+
+import net.sourceforge.argparse4j.inf.Namespace;
+import net.sourceforge.argparse4j.inf.Subparser;
+
+import org.asamk.signal.manager.Manager;
+
+public class UpdateContactCommand implements LocalCommand {
+
+ @Override
+ public void attachToSubparser(final Subparser subparser) {
+ subparser.addArgument("number")
+ .help("Contact number");
+ subparser.addArgument("-n", "--name")
+ .required(true)
+ .help("New contact name");
+ subparser.help("Update the details of a given contact");
+ }
+
+ @Override
+ public int handleCommand(final Namespace ns, final Manager m) {
+ if (!m.isRegistered()) {
+ System.err.println("User is not registered.");
+ return 1;
+ }
+
+ String number = ns.getString("number");
+ String name = ns.getString("name");
+
+ m.setContactName(number, name);
+
+ return 0;
+ }
+}
diff --git a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java
index 8f601a68..5778b333 100644
--- a/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java
+++ b/src/main/java/org/asamk/signal/commands/UpdateGroupCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.Signal;
import org.asamk.signal.AttachmentInvalidException;
import org.asamk.signal.GroupIdFormatException;
@@ -15,7 +16,11 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import static org.asamk.signal.util.ErrorUtils.*;
+import static org.asamk.signal.util.ErrorUtils.handleEncapsulatedExceptions;
+import static org.asamk.signal.util.ErrorUtils.handleGroupIdFormatException;
+import static org.asamk.signal.util.ErrorUtils.handleGroupNotFoundException;
+import static org.asamk.signal.util.ErrorUtils.handleIOException;
+import static org.asamk.signal.util.ErrorUtils.handleNotAGroupMemberException;
public class UpdateGroupCommand implements DbusCommand {
diff --git a/src/main/java/org/asamk/signal/commands/UpdateProfileCommand.java b/src/main/java/org/asamk/signal/commands/UpdateProfileCommand.java
new file mode 100644
index 00000000..a7b02937
--- /dev/null
+++ b/src/main/java/org/asamk/signal/commands/UpdateProfileCommand.java
@@ -0,0 +1,73 @@
+package org.asamk.signal.commands;
+
+import net.sourceforge.argparse4j.impl.Arguments;
+import net.sourceforge.argparse4j.inf.MutuallyExclusiveGroup;
+import net.sourceforge.argparse4j.inf.Namespace;
+import net.sourceforge.argparse4j.inf.Subparser;
+
+import org.asamk.signal.manager.Manager;
+
+import java.io.File;
+import java.io.IOException;
+
+public class UpdateProfileCommand implements LocalCommand {
+
+ @Override
+ public void attachToSubparser(final Subparser subparser) {
+ final MutuallyExclusiveGroup avatarOptions = subparser.addMutuallyExclusiveGroup();
+ avatarOptions.addArgument("--avatar")
+ .help("Path to new profile avatar");
+ avatarOptions.addArgument("--remove-avatar")
+ .action(Arguments.storeTrue());
+
+ subparser.addArgument("--name")
+ .help("New profile name");
+
+ subparser.help("Set a name and/or avatar image for the user profile");
+ }
+
+ @Override
+ public int handleCommand(final Namespace ns, final Manager m) {
+ if (!m.isRegistered()) {
+ System.err.println("User is not registered.");
+ return 1;
+ }
+
+ String name = ns.getString("name");
+
+ if (name != null) {
+ try {
+ m.setProfileName(name);
+ } catch (IOException e) {
+ System.err.println("UpdateAccount error: " + e.getMessage());
+ return 3;
+ }
+ }
+
+ String avatarPath = ns.getString("avatar");
+
+ if (avatarPath != null) {
+ File avatarFile = new File(avatarPath);
+
+ try {
+ m.setProfileAvatar(avatarFile);
+ } catch (IOException e) {
+ System.err.println("UpdateAccount error: " + e.getMessage());
+ return 3;
+ }
+ }
+
+ boolean removeAvatar = ns.getBoolean("remove_avatar");
+
+ if (removeAvatar) {
+ try {
+ m.removeProfileAvatar();
+ } catch (IOException e) {
+ System.err.println("UpdateAccount error: " + e.getMessage());
+ return 3;
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/src/main/java/org/asamk/signal/commands/VerifyCommand.java b/src/main/java/org/asamk/signal/commands/VerifyCommand.java
index aca0d700..9d99c0d2 100644
--- a/src/main/java/org/asamk/signal/commands/VerifyCommand.java
+++ b/src/main/java/org/asamk/signal/commands/VerifyCommand.java
@@ -2,6 +2,7 @@ package org.asamk.signal.commands;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+
import org.asamk.signal.manager.Manager;
import org.whispersystems.signalservice.internal.push.LockedException;
diff --git a/src/main/java/org/asamk/signal/manager/Manager.java b/src/main/java/org/asamk/signal/manager/Manager.java
index ee999194..a1458019 100644
--- a/src/main/java/org/asamk/signal/manager/Manager.java
+++ b/src/main/java/org/asamk/signal/manager/Manager.java
@@ -17,7 +17,11 @@
package org.asamk.signal.manager;
import org.asamk.Signal;
-import org.asamk.signal.*;
+import org.asamk.signal.AttachmentInvalidException;
+import org.asamk.signal.GroupNotFoundException;
+import org.asamk.signal.NotAGroupMemberException;
+import org.asamk.signal.TrustLevel;
+import org.asamk.signal.UserAlreadyExists;
import org.asamk.signal.storage.SignalAccount;
import org.asamk.signal.storage.contacts.ContactInfo;
import org.asamk.signal.storage.groups.GroupInfo;
@@ -26,8 +30,22 @@ import org.asamk.signal.storage.protocol.JsonIdentityKeyStore;
import org.asamk.signal.storage.threads.ThreadInfo;
import org.asamk.signal.util.IOUtils;
import org.asamk.signal.util.Util;
-import org.signal.libsignal.metadata.*;
-import org.whispersystems.libsignal.*;
+import org.signal.libsignal.metadata.InvalidMetadataMessageException;
+import org.signal.libsignal.metadata.InvalidMetadataVersionException;
+import org.signal.libsignal.metadata.ProtocolDuplicateMessageException;
+import org.signal.libsignal.metadata.ProtocolInvalidKeyException;
+import org.signal.libsignal.metadata.ProtocolInvalidKeyIdException;
+import org.signal.libsignal.metadata.ProtocolInvalidMessageException;
+import org.signal.libsignal.metadata.ProtocolInvalidVersionException;
+import org.signal.libsignal.metadata.ProtocolLegacyMessageException;
+import org.signal.libsignal.metadata.ProtocolNoSessionException;
+import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
+import org.signal.libsignal.metadata.SelfSendException;
+import org.whispersystems.libsignal.IdentityKey;
+import org.whispersystems.libsignal.IdentityKeyPair;
+import org.whispersystems.libsignal.InvalidKeyException;
+import org.whispersystems.libsignal.InvalidMessageException;
+import org.whispersystems.libsignal.InvalidVersionException;
import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.ecc.ECKeyPair;
import org.whispersystems.libsignal.ecc.ECPublicKey;
@@ -44,8 +62,26 @@ import org.whispersystems.signalservice.api.crypto.SignalServiceCipher;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
-import org.whispersystems.signalservice.api.messages.*;
-import org.whispersystems.signalservice.api.messages.multidevice.*;
+import org.whispersystems.signalservice.api.messages.SendMessageResult;
+import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
+import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer;
+import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream;
+import org.whispersystems.signalservice.api.messages.SignalServiceContent;
+import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
+import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
+import org.whispersystems.signalservice.api.messages.SignalServiceGroup;
+import org.whispersystems.signalservice.api.messages.multidevice.ContactsMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.DeviceContact;
+import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsInputStream;
+import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsOutputStream;
+import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
+import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream;
+import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
+import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
+import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
+import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage;
import org.whispersystems.signalservice.api.push.ContactTokenDetails;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
@@ -54,17 +90,35 @@ import org.whispersystems.signalservice.api.push.exceptions.NetworkFailureExcept
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.SleepTimer;
+import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
import org.whispersystems.signalservice.internal.push.UnsupportedDataMessageException;
import org.whispersystems.signalservice.internal.util.Base64;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -204,6 +258,20 @@ public class Manager implements Signal {
accountManager.setAccountAttributes(account.getSignalingKey(), account.getSignalProtocolStore().getLocalRegistrationId(), true, account.getRegistrationLockPin(), getSelfUnidentifiedAccessKey(), false);
}
+ public void setProfileName(String name) throws IOException {
+ accountManager.setProfileName(account.getProfileKey(), name);
+ }
+
+ public void setProfileAvatar(File avatar) throws IOException {
+ final StreamDetails streamDetails = Utils.createStreamDetailsFromFile(avatar);
+ accountManager.setProfileAvatar(account.getProfileKey(), streamDetails);
+ streamDetails.getStream().close();
+ }
+
+ public void removeProfileAvatar() throws IOException {
+ accountManager.setProfileAvatar(account.getProfileKey(), null);
+ }
+
public void unregister() throws IOException {
// When setting an empty GCM id, the Signal-Server also sets the fetchesMessages property to false.
// If this is the master device, other users can't send messages to this number anymore.
@@ -564,6 +632,7 @@ public class Manager implements Signal {
if (attachments != null) {
messageBuilder.withAttachments(Utils.getSignalServiceAttachments(attachments));
}
+ messageBuilder.withProfileKey(account.getProfileKey());
sendMessageLegacy(messageBuilder, recipients);
}
@@ -1347,7 +1416,7 @@ public class Manager implements Signal {
}
}
- private void sendContacts() throws IOException, UntrustedIdentityException {
+ public void sendContacts() throws IOException, UntrustedIdentityException {
File contactsFile = IOUtils.createTempFile();
try {
diff --git a/src/main/java/org/asamk/signal/manager/Utils.java b/src/main/java/org/asamk/signal/manager/Utils.java
index 4012674f..38dd65b8 100644
--- a/src/main/java/org/asamk/signal/manager/Utils.java
+++ b/src/main/java/org/asamk/signal/manager/Utils.java
@@ -15,14 +15,30 @@ import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
+import org.whispersystems.signalservice.api.util.StreamDetails;
import org.whispersystems.signalservice.internal.util.Base64;
-import java.io.*;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.file.Files;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import static org.whispersystems.signalservice.internal.util.Util.isEmpty;
@@ -53,7 +69,18 @@ class Utils {
// TODO mabybe add a parameter to set the voiceNote, preview, width, height and caption option
Optional preview = Optional.absent();
Optional caption = Optional.absent();
- return new SignalServiceAttachmentStream(attachmentStream, mime, attachmentSize, Optional.of(attachmentFile.getName()), false, preview, 0, 0, caption, null);
+ Optional blurHash = Optional.absent();
+ return new SignalServiceAttachmentStream(attachmentStream, mime, attachmentSize, Optional.of(attachmentFile.getName()), false, preview, 0, 0, caption, blurHash, null);
+ }
+
+ static StreamDetails createStreamDetailsFromFile(File file) throws IOException {
+ InputStream stream = new FileInputStream(file);
+ final long size = file.length();
+ String mime = Files.probeContentType(file.toPath());
+ if (mime == null) {
+ mime = "application/octet-stream";
+ }
+ return new StreamDetails(stream, mime, size);
}
static CertificateValidator getCertificateValidator() {
diff --git a/src/main/java/org/asamk/signal/storage/SignalAccount.java b/src/main/java/org/asamk/signal/storage/SignalAccount.java
index 6af9d460..1c6f320e 100644
--- a/src/main/java/org/asamk/signal/storage/SignalAccount.java
+++ b/src/main/java/org/asamk/signal/storage/SignalAccount.java
@@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode;
+
import org.asamk.signal.storage.contacts.JsonContactsStore;
import org.asamk.signal.storage.groups.JsonGroupStore;
import org.asamk.signal.storage.protocol.JsonSignalProtocolStore;
@@ -139,7 +140,9 @@ public class SignalAccount {
if (node != null) {
deviceId = node.asInt();
}
- if (rootNode.has("isMultiDevice")) isMultiDevice = Util.getNotNullNode(rootNode, "isMultiDevice").asBoolean();
+ if (rootNode.has("isMultiDevice")) {
+ isMultiDevice = Util.getNotNullNode(rootNode, "isMultiDevice").asBoolean();
+ }
username = Util.getNotNullNode(rootNode, "username").asText();
password = Util.getNotNullNode(rootNode, "password").asText();
JsonNode pinNode = rootNode.get("registrationLockPin");
diff --git a/src/main/java/org/asamk/signal/storage/contacts/JsonContactsStore.java b/src/main/java/org/asamk/signal/storage/contacts/JsonContactsStore.java
index 8d22550b..c10dfbb7 100644
--- a/src/main/java/org/asamk/signal/storage/contacts/JsonContactsStore.java
+++ b/src/main/java/org/asamk/signal/storage/contacts/JsonContactsStore.java
@@ -3,7 +3,12 @@ package org.asamk.signal.storage.contacts;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
diff --git a/src/main/java/org/asamk/signal/storage/groups/JsonGroupStore.java b/src/main/java/org/asamk/signal/storage/groups/JsonGroupStore.java
index 4c5677a6..2eee4eda 100644
--- a/src/main/java/org/asamk/signal/storage/groups/JsonGroupStore.java
+++ b/src/main/java/org/asamk/signal/storage/groups/JsonGroupStore.java
@@ -3,9 +3,15 @@ package org.asamk.signal.storage.groups;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
import org.whispersystems.signalservice.internal.util.Base64;
import java.io.IOException;
diff --git a/src/main/java/org/asamk/signal/storage/protocol/JsonIdentityKeyStore.java b/src/main/java/org/asamk/signal/storage/protocol/JsonIdentityKeyStore.java
index d7049e4a..ce9da228 100644
--- a/src/main/java/org/asamk/signal/storage/protocol/JsonIdentityKeyStore.java
+++ b/src/main/java/org/asamk/signal/storage/protocol/JsonIdentityKeyStore.java
@@ -2,7 +2,12 @@ package org.asamk.signal.storage.protocol;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
import org.asamk.signal.TrustLevel;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
@@ -12,7 +17,11 @@ import org.whispersystems.libsignal.state.IdentityKeyStore;
import org.whispersystems.signalservice.internal.util.Base64;
import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
public class JsonIdentityKeyStore implements IdentityKeyStore {
diff --git a/src/main/java/org/asamk/signal/storage/protocol/JsonPreKeyStore.java b/src/main/java/org/asamk/signal/storage/protocol/JsonPreKeyStore.java
index 3065bfde..e1ad4ddf 100644
--- a/src/main/java/org/asamk/signal/storage/protocol/JsonPreKeyStore.java
+++ b/src/main/java/org/asamk/signal/storage/protocol/JsonPreKeyStore.java
@@ -2,7 +2,12 @@ package org.asamk.signal.storage.protocol;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
import org.whispersystems.libsignal.InvalidKeyIdException;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.PreKeyStore;
diff --git a/src/main/java/org/asamk/signal/storage/protocol/JsonSessionStore.java b/src/main/java/org/asamk/signal/storage/protocol/JsonSessionStore.java
index 7f5c6b06..910fe44a 100644
--- a/src/main/java/org/asamk/signal/storage/protocol/JsonSessionStore.java
+++ b/src/main/java/org/asamk/signal/storage/protocol/JsonSessionStore.java
@@ -2,14 +2,23 @@ package org.asamk.signal.storage.protocol;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
import org.whispersystems.libsignal.SignalProtocolAddress;
import org.whispersystems.libsignal.state.SessionRecord;
import org.whispersystems.libsignal.state.SessionStore;
import org.whispersystems.signalservice.internal.util.Base64;
import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
class JsonSessionStore implements SessionStore {
diff --git a/src/main/java/org/asamk/signal/storage/protocol/JsonSignalProtocolStore.java b/src/main/java/org/asamk/signal/storage/protocol/JsonSignalProtocolStore.java
index 6fcb052b..65ee4a6e 100644
--- a/src/main/java/org/asamk/signal/storage/protocol/JsonSignalProtocolStore.java
+++ b/src/main/java/org/asamk/signal/storage/protocol/JsonSignalProtocolStore.java
@@ -3,6 +3,7 @@ package org.asamk.signal.storage.protocol;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+
import org.asamk.signal.TrustLevel;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.IdentityKeyPair;
diff --git a/src/main/java/org/asamk/signal/storage/protocol/JsonSignedPreKeyStore.java b/src/main/java/org/asamk/signal/storage/protocol/JsonSignedPreKeyStore.java
index c8f4c3cc..eb191eb8 100644
--- a/src/main/java/org/asamk/signal/storage/protocol/JsonSignedPreKeyStore.java
+++ b/src/main/java/org/asamk/signal/storage/protocol/JsonSignedPreKeyStore.java
@@ -2,7 +2,12 @@ package org.asamk.signal.storage.protocol;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
import org.whispersystems.libsignal.InvalidKeyIdException;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyStore;
diff --git a/src/main/java/org/asamk/signal/storage/threads/JsonThreadStore.java b/src/main/java/org/asamk/signal/storage/threads/JsonThreadStore.java
index 9ee613b8..a4a89ccd 100644
--- a/src/main/java/org/asamk/signal/storage/threads/JsonThreadStore.java
+++ b/src/main/java/org/asamk/signal/storage/threads/JsonThreadStore.java
@@ -3,7 +3,12 @@ package org.asamk.signal.storage.threads;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.*;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
diff --git a/src/main/java/org/asamk/signal/util/IOUtils.java b/src/main/java/org/asamk/signal/util/IOUtils.java
index e1464b1c..434669de 100644
--- a/src/main/java/org/asamk/signal/util/IOUtils.java
+++ b/src/main/java/org/asamk/signal/util/IOUtils.java
@@ -12,7 +12,9 @@ import java.nio.file.attribute.PosixFilePermissions;
import java.util.EnumSet;
import java.util.Set;
-import static java.nio.file.attribute.PosixFilePermission.*;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_EXECUTE;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_READ;
+import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
public class IOUtils {
diff --git a/src/main/java/org/asamk/signal/util/Util.java b/src/main/java/org/asamk/signal/util/Util.java
index e7a68668..f0d39601 100644
--- a/src/main/java/org/asamk/signal/util/Util.java
+++ b/src/main/java/org/asamk/signal/util/Util.java
@@ -1,6 +1,7 @@
package org.asamk.signal.util;
import com.fasterxml.jackson.databind.JsonNode;
+
import org.asamk.signal.GroupIdFormatException;
import org.whispersystems.signalservice.internal.util.Base64;