]> nmode's Git Repositories - signal-cli/commitdiff
Add option to disable adding message to send log
authorAsamK <asamk@gmx.de>
Sun, 30 Oct 2022 10:00:25 +0000 (11:00 +0100)
committerAsamK <asamk@gmx.de>
Sun, 30 Oct 2022 10:00:25 +0000 (11:00 +0100)
lib/src/main/java/org/asamk/signal/manager/ProvisioningManagerImpl.java
lib/src/main/java/org/asamk/signal/manager/Settings.java [new file with mode: 0644]
lib/src/main/java/org/asamk/signal/manager/SignalAccountFiles.java
lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java
lib/src/main/java/org/asamk/signal/manager/storage/sendLog/MessageSendLogStore.java
man/signal-cli.1.adoc
src/main/java/org/asamk/signal/App.java

index 17569401ba1c0933bf42b9e3fcf31bf96f8ad52e..c8df97740498ea9438a101a874bdc1d67dbe46ce 100644 (file)
@@ -21,7 +21,6 @@ import org.asamk.signal.manager.config.ServiceConfig;
 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.storage.accounts.AccountsStore;
 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.storage.accounts.AccountsStore;
-import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
 import org.asamk.signal.manager.util.KeyUtils;
 import org.signal.libsignal.protocol.IdentityKeyPair;
 import org.signal.libsignal.protocol.util.KeyHelper;
 import org.asamk.signal.manager.util.KeyUtils;
 import org.signal.libsignal.protocol.IdentityKeyPair;
 import org.signal.libsignal.protocol.util.KeyHelper;
@@ -147,7 +146,7 @@ class ProvisioningManagerImpl implements ProvisioningManager {
                     registrationId,
                     pniRegistrationId,
                     profileKey,
                     registrationId,
                     pniRegistrationId,
                     profileKey,
-                    TrustNewIdentity.ON_FIRST_USE);
+                    Settings.DEFAULT);
 
             ManagerImpl m = null;
             try {
 
             ManagerImpl m = null;
             try {
@@ -194,10 +193,7 @@ class ProvisioningManagerImpl implements ProvisioningManager {
     private boolean canRelinkExistingAccount(final String accountPath) throws IOException {
         final SignalAccount signalAccount;
         try {
     private boolean canRelinkExistingAccount(final String accountPath) throws IOException {
         final SignalAccount signalAccount;
         try {
-            signalAccount = SignalAccount.load(pathConfig.dataPath(),
-                    accountPath,
-                    false,
-                    TrustNewIdentity.ON_FIRST_USE);
+            signalAccount = SignalAccount.load(pathConfig.dataPath(), accountPath, false, Settings.DEFAULT);
         } catch (IOException e) {
             logger.debug("Account in use or failed to load.", e);
             return false;
         } catch (IOException e) {
             logger.debug("Account in use or failed to load.", e);
             return false;
diff --git a/lib/src/main/java/org/asamk/signal/manager/Settings.java b/lib/src/main/java/org/asamk/signal/manager/Settings.java
new file mode 100644 (file)
index 0000000..e4f4554
--- /dev/null
@@ -0,0 +1,8 @@
+package org.asamk.signal.manager;
+
+import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
+
+public record Settings(TrustNewIdentity trustNewIdentity, boolean disableMessageSendLog) {
+
+    public static Settings DEFAULT = new Settings(TrustNewIdentity.ON_FIRST_USE, false);
+}
index 9d0b344a97c3c8be4fbf2c8494e2098fbd945834..12eb3d999defad585aebf5ebb70f7931c8b52673 100644 (file)
@@ -7,7 +7,6 @@ import org.asamk.signal.manager.config.ServiceEnvironment;
 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.storage.accounts.AccountsStore;
 import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
 import org.asamk.signal.manager.storage.SignalAccount;
 import org.asamk.signal.manager.storage.accounts.AccountsStore;
-import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
 import org.asamk.signal.manager.util.KeyUtils;
 import org.signal.libsignal.protocol.util.KeyHelper;
 import org.slf4j.Logger;
 import org.asamk.signal.manager.util.KeyUtils;
 import org.signal.libsignal.protocol.util.KeyHelper;
 import org.slf4j.Logger;
@@ -28,27 +27,27 @@ public class SignalAccountFiles {
     private final ServiceEnvironment serviceEnvironment;
     private final ServiceEnvironmentConfig serviceEnvironmentConfig;
     private final String userAgent;
     private final ServiceEnvironment serviceEnvironment;
     private final ServiceEnvironmentConfig serviceEnvironmentConfig;
     private final String userAgent;
-    private final TrustNewIdentity trustNewIdentity;
+    private final Settings settings;
     private final AccountsStore accountsStore;
 
     public SignalAccountFiles(
             final File settingsPath,
             final ServiceEnvironment serviceEnvironment,
             final String userAgent,
     private final AccountsStore accountsStore;
 
     public SignalAccountFiles(
             final File settingsPath,
             final ServiceEnvironment serviceEnvironment,
             final String userAgent,
-            final TrustNewIdentity trustNewIdentity
+            final Settings settings
     ) throws IOException {
         this.pathConfig = PathConfig.createDefault(settingsPath);
         this.serviceEnvironment = serviceEnvironment;
         this.serviceEnvironmentConfig = ServiceConfig.getServiceEnvironmentConfig(this.serviceEnvironment, userAgent);
         this.userAgent = userAgent;
     ) throws IOException {
         this.pathConfig = PathConfig.createDefault(settingsPath);
         this.serviceEnvironment = serviceEnvironment;
         this.serviceEnvironmentConfig = ServiceConfig.getServiceEnvironmentConfig(this.serviceEnvironment, userAgent);
         this.userAgent = userAgent;
-        this.trustNewIdentity = trustNewIdentity;
+        this.settings = settings;
         this.accountsStore = new AccountsStore(pathConfig.dataPath(), serviceEnvironment, accountPath -> {
             if (accountPath == null || !SignalAccount.accountFileExists(pathConfig.dataPath(), accountPath)) {
                 return null;
             }
 
             try {
         this.accountsStore = new AccountsStore(pathConfig.dataPath(), serviceEnvironment, accountPath -> {
             if (accountPath == null || !SignalAccount.accountFileExists(pathConfig.dataPath(), accountPath)) {
                 return null;
             }
 
             try {
-                return SignalAccount.load(pathConfig.dataPath(), accountPath, false, trustNewIdentity);
+                return SignalAccount.load(pathConfig.dataPath(), accountPath, false, settings);
             } catch (Exception e) {
                 return null;
             }
             } catch (Exception e) {
                 return null;
             }
@@ -90,7 +89,7 @@ public class SignalAccountFiles {
             throw new NotRegisteredException();
         }
 
             throw new NotRegisteredException();
         }
 
-        var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, trustNewIdentity);
+        var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, settings);
         if (!number.equals(account.getNumber())) {
             account.close();
             throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());
         if (!number.equals(account.getNumber())) {
             account.close();
             throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());
@@ -168,7 +167,7 @@ public class SignalAccountFiles {
                     registrationId,
                     pniRegistrationId,
                     profileKey,
                     registrationId,
                     pniRegistrationId,
                     profileKey,
-                    trustNewIdentity);
+                    settings);
 
             return new RegistrationManagerImpl(account,
                     pathConfig,
 
             return new RegistrationManagerImpl(account,
                     pathConfig,
@@ -178,7 +177,7 @@ public class SignalAccountFiles {
                     new AccountFileUpdaterImpl(accountsStore, newAccountPath));
         }
 
                     new AccountFileUpdaterImpl(accountsStore, newAccountPath));
         }
 
-        var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, trustNewIdentity);
+        var account = SignalAccount.load(pathConfig.dataPath(), accountPath, true, settings);
         if (!number.equals(account.getNumber())) {
             account.close();
             throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());
         if (!number.equals(account.getNumber())) {
             account.close();
             throw new IOException("Number in account file doesn't match expected number: " + account.getNumber());
index 1759649e6a4c3d5c9795b13e166fb08da6afe415..dac8de94254f5cafb69012771ec5b6e7a5b6a870 100644 (file)
@@ -3,6 +3,7 @@ package org.asamk.signal.manager.storage;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import org.asamk.signal.manager.Settings;
 import org.asamk.signal.manager.api.Pair;
 import org.asamk.signal.manager.api.TrustLevel;
 import org.asamk.signal.manager.config.ServiceEnvironment;
 import org.asamk.signal.manager.api.Pair;
 import org.asamk.signal.manager.api.TrustLevel;
 import org.asamk.signal.manager.config.ServiceEnvironment;
@@ -17,7 +18,6 @@ import org.asamk.signal.manager.storage.groups.LegacyGroupStore;
 import org.asamk.signal.manager.storage.identities.IdentityKeyStore;
 import org.asamk.signal.manager.storage.identities.LegacyIdentityKeyStore;
 import org.asamk.signal.manager.storage.identities.SignalIdentityKeyStore;
 import org.asamk.signal.manager.storage.identities.IdentityKeyStore;
 import org.asamk.signal.manager.storage.identities.LegacyIdentityKeyStore;
 import org.asamk.signal.manager.storage.identities.SignalIdentityKeyStore;
-import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
 import org.asamk.signal.manager.storage.messageCache.MessageCache;
 import org.asamk.signal.manager.storage.prekeys.LegacyPreKeyStore;
 import org.asamk.signal.manager.storage.prekeys.LegacySignedPreKeyStore;
 import org.asamk.signal.manager.storage.messageCache.MessageCache;
 import org.asamk.signal.manager.storage.prekeys.LegacyPreKeyStore;
 import org.asamk.signal.manager.storage.prekeys.LegacySignedPreKeyStore;
@@ -136,7 +136,7 @@ public class SignalAccount implements Closeable {
     private IdentityKeyPair pniIdentityKeyPair;
     private int localRegistrationId;
     private int localPniRegistrationId;
     private IdentityKeyPair pniIdentityKeyPair;
     private int localRegistrationId;
     private int localPniRegistrationId;
-    private TrustNewIdentity trustNewIdentity;
+    private Settings settings;
     private long lastReceiveTimestamp = 0;
 
     private boolean registered = false;
     private long lastReceiveTimestamp = 0;
 
     private boolean registered = false;
@@ -170,7 +170,7 @@ public class SignalAccount implements Closeable {
     }
 
     public static SignalAccount load(
     }
 
     public static SignalAccount load(
-            File dataPath, String accountPath, boolean waitForLock, final TrustNewIdentity trustNewIdentity
+            File dataPath, String accountPath, boolean waitForLock, final Settings settings
     ) throws IOException {
         logger.trace("Opening account file");
         final var fileName = getFileName(dataPath, accountPath);
     ) throws IOException {
         logger.trace("Opening account file");
         final var fileName = getFileName(dataPath, accountPath);
@@ -178,7 +178,7 @@ public class SignalAccount implements Closeable {
         try {
             var signalAccount = new SignalAccount(pair.first(), pair.second());
             logger.trace("Loading account file");
         try {
             var signalAccount = new SignalAccount(pair.first(), pair.second());
             logger.trace("Loading account file");
-            signalAccount.load(dataPath, accountPath, trustNewIdentity);
+            signalAccount.load(dataPath, accountPath, settings);
             logger.trace("Migrating legacy parts of account file");
             signalAccount.migrateLegacyConfigs();
 
             logger.trace("Migrating legacy parts of account file");
             signalAccount.migrateLegacyConfigs();
 
@@ -200,7 +200,7 @@ public class SignalAccount implements Closeable {
             int registrationId,
             int pniRegistrationId,
             ProfileKey profileKey,
             int registrationId,
             int pniRegistrationId,
             ProfileKey profileKey,
-            final TrustNewIdentity trustNewIdentity
+            final Settings settings
     ) throws IOException {
         IOUtils.createPrivateDirectories(dataPath);
         var fileName = getFileName(dataPath, accountPath);
     ) throws IOException {
         IOUtils.createPrivateDirectories(dataPath);
         var fileName = getFileName(dataPath, accountPath);
@@ -221,7 +221,7 @@ public class SignalAccount implements Closeable {
         signalAccount.pniIdentityKeyPair = pniIdentityKey;
         signalAccount.localRegistrationId = registrationId;
         signalAccount.localPniRegistrationId = pniRegistrationId;
         signalAccount.pniIdentityKeyPair = pniIdentityKey;
         signalAccount.localRegistrationId = registrationId;
         signalAccount.localPniRegistrationId = pniRegistrationId;
-        signalAccount.trustNewIdentity = trustNewIdentity;
+        signalAccount.settings = settings;
         signalAccount.configurationStore = new ConfigurationStore(signalAccount::saveConfigurationStore);
 
         signalAccount.registered = false;
         signalAccount.configurationStore = new ConfigurationStore(signalAccount::saveConfigurationStore);
 
         signalAccount.registered = false;
@@ -248,7 +248,7 @@ public class SignalAccount implements Closeable {
             int registrationId,
             int pniRegistrationId,
             ProfileKey profileKey,
             int registrationId,
             int pniRegistrationId,
             ProfileKey profileKey,
-            final TrustNewIdentity trustNewIdentity
+            final Settings settings
     ) throws IOException {
         IOUtils.createPrivateDirectories(dataPath);
         var fileName = getFileName(dataPath, accountPath);
     ) throws IOException {
         IOUtils.createPrivateDirectories(dataPath);
         var fileName = getFileName(dataPath, accountPath);
@@ -267,10 +267,10 @@ public class SignalAccount implements Closeable {
                     registrationId,
                     pniRegistrationId,
                     profileKey,
                     registrationId,
                     pniRegistrationId,
                     profileKey,
-                    trustNewIdentity);
+                    settings);
         }
 
         }
 
-        final var signalAccount = load(dataPath, accountPath, true, trustNewIdentity);
+        final var signalAccount = load(dataPath, accountPath, true, settings);
         signalAccount.setProvisioningData(number,
                 aci,
                 pni,
         signalAccount.setProvisioningData(number,
                 aci,
                 pni,
@@ -318,7 +318,7 @@ public class SignalAccount implements Closeable {
             int registrationId,
             int pniRegistrationId,
             ProfileKey profileKey,
             int registrationId,
             int pniRegistrationId,
             ProfileKey profileKey,
-            final TrustNewIdentity trustNewIdentity
+            final Settings settings
     ) throws IOException {
         var fileName = getFileName(dataPath, accountPath);
         IOUtils.createPrivateFile(fileName);
     ) throws IOException {
         var fileName = getFileName(dataPath, accountPath);
         IOUtils.createPrivateFile(fileName);
@@ -331,7 +331,7 @@ public class SignalAccount implements Closeable {
         signalAccount.serviceEnvironment = serviceEnvironment;
         signalAccount.localRegistrationId = registrationId;
         signalAccount.localPniRegistrationId = pniRegistrationId;
         signalAccount.serviceEnvironment = serviceEnvironment;
         signalAccount.localRegistrationId = registrationId;
         signalAccount.localPniRegistrationId = pniRegistrationId;
-        signalAccount.trustNewIdentity = trustNewIdentity;
+        signalAccount.settings = settings;
         signalAccount.setProvisioningData(number,
                 aci,
                 pni,
         signalAccount.setProvisioningData(number,
                 aci,
                 pni,
@@ -502,7 +502,7 @@ public class SignalAccount implements Closeable {
     }
 
     private void load(
     }
 
     private void load(
-            File dataPath, String accountPath, final TrustNewIdentity trustNewIdentity
+            File dataPath, String accountPath, final Settings settings
     ) throws IOException {
         this.dataPath = dataPath;
         this.accountPath = accountPath;
     ) throws IOException {
         this.dataPath = dataPath;
         this.accountPath = accountPath;
@@ -685,7 +685,7 @@ public class SignalAccount implements Closeable {
 
         this.aciIdentityKeyPair = aciIdentityKeyPair;
         this.localRegistrationId = registrationId;
 
         this.aciIdentityKeyPair = aciIdentityKeyPair;
         this.localRegistrationId = registrationId;
-        this.trustNewIdentity = trustNewIdentity;
+        this.settings = settings;
 
         migratedLegacyConfig = loadLegacyStores(rootNode, legacySignalProtocolStore) || migratedLegacyConfig;
 
 
         migratedLegacyConfig = loadLegacyStores(rootNode, legacySignalProtocolStore) || migratedLegacyConfig;
 
@@ -1156,7 +1156,7 @@ public class SignalAccount implements Closeable {
 
     public IdentityKeyStore getIdentityKeyStore() {
         return getOrCreate(() -> identityKeyStore,
 
     public IdentityKeyStore getIdentityKeyStore() {
         return getOrCreate(() -> identityKeyStore,
-                () -> identityKeyStore = new IdentityKeyStore(getAccountDatabase(), trustNewIdentity));
+                () -> identityKeyStore = new IdentityKeyStore(getAccountDatabase(), settings.trustNewIdentity()));
     }
 
     public SignalIdentityKeyStore getAciIdentityKeyStore() {
     }
 
     public SignalIdentityKeyStore getAciIdentityKeyStore() {
@@ -1242,7 +1242,8 @@ public class SignalAccount implements Closeable {
 
     public MessageSendLogStore getMessageSendLogStore() {
         return getOrCreate(() -> messageSendLogStore,
 
     public MessageSendLogStore getMessageSendLogStore() {
         return getOrCreate(() -> messageSendLogStore,
-                () -> messageSendLogStore = new MessageSendLogStore(getAccountDatabase()));
+                () -> messageSendLogStore = new MessageSendLogStore(getAccountDatabase(),
+                        settings.disableMessageSendLog()));
     }
 
     public CredentialsProvider getCredentialsProvider() {
     }
 
     public CredentialsProvider getCredentialsProvider() {
index f672667d1ab534946ab35fc9aad5028e5563b506..bab0aa4fae7cc395f84008a2513642d48c30085d 100644 (file)
@@ -33,9 +33,11 @@ public class MessageSendLogStore implements AutoCloseable {
 
     private final Database database;
     private final Thread cleanupThread;
 
     private final Database database;
     private final Thread cleanupThread;
+    private final boolean sendLogDisabled;
 
 
-    public MessageSendLogStore(final Database database) {
+    public MessageSendLogStore(final Database database, final boolean disableMessageSendLog) {
         this.database = database;
         this.database = database;
+        this.sendLogDisabled = disableMessageSendLog;
         this.cleanupThread = new Thread(() -> {
             try {
                 final var interval = Duration.ofHours(1).toMillis();
         this.cleanupThread = new Thread(() -> {
             try {
                 final var interval = Duration.ofHours(1).toMillis();
@@ -43,6 +45,7 @@ public class MessageSendLogStore implements AutoCloseable {
                     try (final var connection = database.getConnection()) {
                         deleteOutdatedEntries(connection);
                     } catch (SQLException e) {
                     try (final var connection = database.getConnection()) {
                         deleteOutdatedEntries(connection);
                     } catch (SQLException e) {
+                        logger.debug("MSL", e);
                         logger.warn("Deleting outdated entries failed");
                         break;
                     }
                         logger.warn("Deleting outdated entries failed");
                         break;
                     }
@@ -113,6 +116,9 @@ public class MessageSendLogStore implements AutoCloseable {
     public long insertIfPossible(
             long sentTimestamp, SendMessageResult sendMessageResult, ContentHint contentHint, boolean urgent
     ) {
     public long insertIfPossible(
             long sentTimestamp, SendMessageResult sendMessageResult, ContentHint contentHint, boolean urgent
     ) {
+        if (sendLogDisabled) {
+            return -1;
+        }
         final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult);
         if (recipientDevice == null) {
             return -1;
         final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult);
         if (recipientDevice == null) {
             return -1;
@@ -128,6 +134,9 @@ public class MessageSendLogStore implements AutoCloseable {
     public long insertIfPossible(
             long sentTimestamp, List<SendMessageResult> sendMessageResults, ContentHint contentHint, boolean urgent
     ) {
     public long insertIfPossible(
             long sentTimestamp, List<SendMessageResult> sendMessageResults, ContentHint contentHint, boolean urgent
     ) {
+        if (sendLogDisabled) {
+            return -1;
+        }
         final var recipientDevices = sendMessageResults.stream()
                 .map(this::getRecipientDevices)
                 .filter(Objects::nonNull)
         final var recipientDevices = sendMessageResults.stream()
                 .map(this::getRecipientDevices)
                 .filter(Objects::nonNull)
@@ -146,6 +155,9 @@ public class MessageSendLogStore implements AutoCloseable {
     }
 
     public void addRecipientToExistingEntryIfPossible(final long contentId, final SendMessageResult sendMessageResult) {
     }
 
     public void addRecipientToExistingEntryIfPossible(final long contentId, final SendMessageResult sendMessageResult) {
+        if (sendLogDisabled) {
+            return;
+        }
         final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult);
         if (recipientDevice == null) {
             return;
         final RecipientDevices recipientDevice = getRecipientDevices(sendMessageResult);
         if (recipientDevice == null) {
             return;
@@ -157,6 +169,9 @@ public class MessageSendLogStore implements AutoCloseable {
     public void addRecipientToExistingEntryIfPossible(
             final long contentId, final List<SendMessageResult> sendMessageResults
     ) {
     public void addRecipientToExistingEntryIfPossible(
             final long contentId, final List<SendMessageResult> sendMessageResults
     ) {
+        if (sendLogDisabled) {
+            return;
+        }
         final var recipientDevices = sendMessageResults.stream()
                 .map(this::getRecipientDevices)
                 .filter(Objects::nonNull)
         final var recipientDevices = sendMessageResults.stream()
                 .map(this::getRecipientDevices)
                 .filter(Objects::nonNull)
index 9b6ec2dba89a1d7b777f57c7e403bab632dfac44..90b2c97d99cf3fa882ff7ea800f01f81cefd4d6a 100644 (file)
@@ -79,6 +79,9 @@ Choose when to trust new identities:
 - `always`: Trust any new identity key without verification
 - `never`: Don't trust any unknown identity key, every key must be verified manually
 
 - `always`: Trust any new identity key without verification
 - `never`: Don't trust any unknown identity key, every key must be verified manually
 
+*--disable-send-log*::
+Disable message send log (for resending messages that recipient couldn't decrypt).
+
 == Commands
 
 === register
 == Commands
 
 === register
index 4f045345b62e0d22294aad19e573b749641cd273..058ae6bb6936484ae588c8084e2a3a737c5de23a 100644 (file)
@@ -23,6 +23,7 @@ import org.asamk.signal.dbus.DbusProvisioningManagerImpl;
 import org.asamk.signal.dbus.DbusRegistrationManagerImpl;
 import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.RegistrationManager;
 import org.asamk.signal.dbus.DbusRegistrationManagerImpl;
 import org.asamk.signal.manager.Manager;
 import org.asamk.signal.manager.RegistrationManager;
+import org.asamk.signal.manager.Settings;
 import org.asamk.signal.manager.SignalAccountFiles;
 import org.asamk.signal.manager.api.AccountCheckException;
 import org.asamk.signal.manager.api.NotRegisteredException;
 import org.asamk.signal.manager.SignalAccountFiles;
 import org.asamk.signal.manager.api.AccountCheckException;
 import org.asamk.signal.manager.api.NotRegisteredException;
@@ -101,6 +102,10 @@ public class App {
                 .type(Arguments.enumStringType(TrustNewIdentityCli.class))
                 .setDefault(TrustNewIdentityCli.ON_FIRST_USE);
 
                 .type(Arguments.enumStringType(TrustNewIdentityCli.class))
                 .setDefault(TrustNewIdentityCli.ON_FIRST_USE);
 
+        parser.addArgument("--disable-send-log")
+                .help("Disable message send log (for resending messages that recipient couldn't decrypt)")
+                .action(Arguments.storeTrue());
+
         var subparsers = parser.addSubparsers().title("subcommands").dest("command");
 
         Commands.getCommandSubparserAttachers().forEach((key, value) -> {
         var subparsers = parser.addSubparsers().title("subcommands").dest("command");
 
         Commands.getCommandSubparserAttachers().forEach((key, value) -> {
@@ -167,12 +172,14 @@ public class App {
                 ? TrustNewIdentity.ON_FIRST_USE
                 : trustNewIdentityCli == TrustNewIdentityCli.ALWAYS ? TrustNewIdentity.ALWAYS : TrustNewIdentity.NEVER;
 
                 ? TrustNewIdentity.ON_FIRST_USE
                 : trustNewIdentityCli == TrustNewIdentityCli.ALWAYS ? TrustNewIdentity.ALWAYS : TrustNewIdentity.NEVER;
 
+        final var disableSendLog = Boolean.TRUE.equals(ns.getBoolean("disable-send-log"));
+
         final SignalAccountFiles signalAccountFiles;
         try {
             signalAccountFiles = new SignalAccountFiles(configPath,
                     serviceEnvironment,
                     BaseConfig.USER_AGENT,
         final SignalAccountFiles signalAccountFiles;
         try {
             signalAccountFiles = new SignalAccountFiles(configPath,
                     serviceEnvironment,
                     BaseConfig.USER_AGENT,
-                    trustNewIdentity);
+                    new Settings(trustNewIdentity, disableSendLog));
         } catch (IOException e) {
             throw new IOErrorException("Failed to read local accounts list", e);
         }
         } catch (IOException e) {
             throw new IOErrorException("Failed to read local accounts list", e);
         }