X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/32818a8608f5bddc46ad5c7dc442f509c939791c..861f47d734a2c416ca3231ad72f9f129da5a706f:/src/main/java/org/asamk/signal/App.java diff --git a/src/main/java/org/asamk/signal/App.java b/src/main/java/org/asamk/signal/App.java index 720a5849..f42fef1e 100644 --- a/src/main/java/org/asamk/signal/App.java +++ b/src/main/java/org/asamk/signal/App.java @@ -12,19 +12,22 @@ import org.asamk.signal.commands.LocalCommand; import org.asamk.signal.commands.MultiLocalCommand; import org.asamk.signal.commands.ProvisioningCommand; import org.asamk.signal.commands.RegistrationCommand; -import org.asamk.signal.commands.SignalCreator; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.IOErrorException; import org.asamk.signal.commands.exceptions.UnexpectedErrorException; import org.asamk.signal.commands.exceptions.UserErrorException; import org.asamk.signal.dbus.DbusManagerImpl; import org.asamk.signal.manager.Manager; +import org.asamk.signal.manager.MultiAccountManagerImpl; import org.asamk.signal.manager.NotRegisteredException; import org.asamk.signal.manager.ProvisioningManager; import org.asamk.signal.manager.RegistrationManager; import org.asamk.signal.manager.config.ServiceConfig; import org.asamk.signal.manager.config.ServiceEnvironment; import org.asamk.signal.manager.storage.identities.TrustNewIdentity; +import org.asamk.signal.output.JsonWriterImpl; +import org.asamk.signal.output.OutputWriter; +import org.asamk.signal.output.PlainTextWriterImpl; import org.asamk.signal.util.IOUtils; import org.freedesktop.dbus.connections.impl.DBusConnection; import org.freedesktop.dbus.exceptions.DBusException; @@ -32,8 +35,11 @@ import org.freedesktop.dbus.exceptions.DBusExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.BufferedWriter; import java.io.File; import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -57,14 +63,18 @@ public class App { parser.addArgument("--verbose") .help("Raise log level and include lib signal logs.") .action(Arguments.storeTrue()); - parser.addArgument("--config") + parser.addArgument("-c", "--config") .help("Set the path, where to store the config (Default: $XDG_DATA_HOME/signal-cli , $HOME/.local/share/signal-cli)."); - parser.addArgument("-u", "--username").help("Specify your phone number, that will be your identifier."); + parser.addArgument("-a", "--account", "-u", "--username") + .help("Specify your phone number, that will be your identifier."); var mut = parser.addMutuallyExclusiveGroup(); - mut.addArgument("--dbus").help("Make request via user dbus.").action(Arguments.storeTrue()); - mut.addArgument("--dbus-system").help("Make request via system dbus.").action(Arguments.storeTrue()); + mut.addArgument("--dbus").dest("global-dbus").help("Make request via user dbus.").action(Arguments.storeTrue()); + mut.addArgument("--dbus-system") + .dest("global-dbus-system") + .help("Make request via system dbus.") + .action(Arguments.storeTrue()); parser.addArgument("-o", "--output") .help("Choose to output in plain text or JSON") @@ -105,21 +115,22 @@ public class App { var outputType = outputTypeInput == null ? command.getSupportedOutputTypes().stream().findFirst().orElse(null) : outputTypeInput; + var writer = new BufferedWriter(new OutputStreamWriter(System.out, Charset.defaultCharset())); var outputWriter = outputType == null ? null - : outputType == OutputType.JSON ? new JsonWriterImpl(System.out) : new PlainTextWriterImpl(System.out); + : outputType == OutputType.JSON ? new JsonWriterImpl(writer) : new PlainTextWriterImpl(writer); if (outputWriter != null && !command.getSupportedOutputTypes().contains(outputType)) { throw new UserErrorException("Command doesn't support output type " + outputType); } - var username = ns.getString("username"); + var account = ns.getString("account"); - final var useDbus = Boolean.TRUE.equals(ns.getBoolean("dbus")); - final var useDbusSystem = Boolean.TRUE.equals(ns.getBoolean("dbus-system")); + final var useDbus = Boolean.TRUE.equals(ns.getBoolean("global-dbus")); + final var useDbusSystem = Boolean.TRUE.equals(ns.getBoolean("global-dbus-system")); if (useDbus || useDbusSystem) { - // If username is null, it will connect to the default object path - initDbusClient(command, username, useDbusSystem, outputWriter); + // If account is null, it will connect to the default object path + initDbusClient(command, account, useDbusSystem, outputWriter); return; } @@ -131,11 +142,6 @@ public class App { dataPath = getDefaultDataPath(); } - if (!ServiceConfig.isZkgroupAvailable()) { - logger.warn("WARNING: Support for new group V2 is disabled," - + " because the required native library dependency is missing: libzkgroup"); - } - if (!ServiceConfig.isSignalClientAvailable()) { throw new UserErrorException("Missing required native library dependency: libsignal-client"); } @@ -151,41 +157,41 @@ public class App { : trustNewIdentityCli == TrustNewIdentityCli.ALWAYS ? TrustNewIdentity.ALWAYS : TrustNewIdentity.NEVER; if (command instanceof ProvisioningCommand provisioningCommand) { - if (username != null) { - throw new UserErrorException("You cannot specify a username (phone number) when linking"); + if (account != null) { + throw new UserErrorException("You cannot specify a account (phone number) when linking"); } handleProvisioningCommand(provisioningCommand, dataPath, serviceEnvironment, outputWriter); return; } - if (username == null) { - var usernames = Manager.getAllLocalNumbers(dataPath); + if (account == null) { + var accounts = Manager.getAllLocalAccountNumbers(dataPath); if (command instanceof MultiLocalCommand multiLocalCommand) { handleMultiLocalCommand(multiLocalCommand, dataPath, serviceEnvironment, - usernames, + accounts, outputWriter, trustNewIdentity); return; } - if (usernames.size() == 0) { + if (accounts.size() == 0) { throw new UserErrorException("No local users found, you first need to register or link an account"); - } else if (usernames.size() > 1) { + } else if (accounts.size() > 1) { throw new UserErrorException( - "Multiple users found, you need to specify a username (phone number) with -u"); + "Multiple users found, you need to specify an account (phone number) with -a"); } - username = usernames.get(0); - } else if (!Manager.isValidNumber(username, null)) { - throw new UserErrorException("Invalid username (phone number), make sure you include the country code."); + account = accounts.get(0); + } else if (!Manager.isValidNumber(account, null)) { + throw new UserErrorException("Invalid account (phone number), make sure you include the country code."); } if (command instanceof RegistrationCommand registrationCommand) { - handleRegistrationCommand(registrationCommand, username, dataPath, serviceEnvironment); + handleRegistrationCommand(registrationCommand, account, dataPath, serviceEnvironment); return; } @@ -194,7 +200,7 @@ public class App { } handleLocalCommand((LocalCommand) command, - username, + account, dataPath, serviceEnvironment, outputWriter, @@ -213,13 +219,13 @@ public class App { private void handleRegistrationCommand( final RegistrationCommand command, - final String username, + final String account, final File dataPath, final ServiceEnvironment serviceEnvironment ) throws CommandException { final RegistrationManager manager; try { - manager = RegistrationManager.init(username, dataPath, serviceEnvironment, BaseConfig.USER_AGENT); + manager = RegistrationManager.init(account, dataPath, serviceEnvironment, BaseConfig.USER_AGENT); } catch (Throwable e) { throw new UnexpectedErrorException("Error loading or creating state file: " + e.getMessage() @@ -227,8 +233,8 @@ public class App { + e.getClass().getSimpleName() + ")", e); } - try (var m = manager) { - command.handleCommand(ns, m); + try (manager) { + command.handleCommand(ns, manager); } catch (IOException e) { logger.warn("Cleanup failed", e); } @@ -236,13 +242,13 @@ public class App { private void handleLocalCommand( final LocalCommand command, - final String username, + final String account, final File dataPath, final ServiceEnvironment serviceEnvironment, final OutputWriter outputWriter, final TrustNewIdentity trustNewIdentity ) throws CommandException { - try (var m = loadManager(username, dataPath, serviceEnvironment, trustNewIdentity)) { + try (var m = loadManager(account, dataPath, serviceEnvironment, trustNewIdentity)) { command.handleCommand(ns, m, outputWriter); } catch (IOException e) { logger.warn("Cleanup failed", e); @@ -253,54 +259,41 @@ public class App { final MultiLocalCommand command, final File dataPath, final ServiceEnvironment serviceEnvironment, - final List usernames, + final List accounts, final OutputWriter outputWriter, final TrustNewIdentity trustNewIdentity ) throws CommandException { final var managers = new ArrayList(); - for (String u : usernames) { + for (String a : accounts) { try { - managers.add(loadManager(u, dataPath, serviceEnvironment, trustNewIdentity)); + managers.add(loadManager(a, dataPath, serviceEnvironment, trustNewIdentity)); } catch (CommandException e) { - logger.warn("Ignoring {}: {}", u, e.getMessage()); + logger.warn("Ignoring {}: {}", a, e.getMessage()); } } - command.handleCommand(ns, managers, new SignalCreator() { - @Override - public ProvisioningManager getNewProvisioningManager() { - return ProvisioningManager.init(dataPath, serviceEnvironment, BaseConfig.USER_AGENT); - } - - @Override - public RegistrationManager getNewRegistrationManager(String username) throws IOException { - return RegistrationManager.init(username, dataPath, serviceEnvironment, BaseConfig.USER_AGENT); - } - }, outputWriter); - - for (var m : managers) { - try { - m.close(); - } catch (IOException e) { - logger.warn("Cleanup failed", e); - } + try (var multiAccountManager = new MultiAccountManagerImpl(managers, + dataPath, + serviceEnvironment, + BaseConfig.USER_AGENT)) { + command.handleCommand(ns, multiAccountManager, outputWriter); } } private Manager loadManager( - final String username, + final String account, final File dataPath, final ServiceEnvironment serviceEnvironment, final TrustNewIdentity trustNewIdentity ) throws CommandException { Manager manager; try { - manager = Manager.init(username, dataPath, serviceEnvironment, BaseConfig.USER_AGENT, trustNewIdentity); + manager = Manager.init(account, dataPath, serviceEnvironment, BaseConfig.USER_AGENT, trustNewIdentity); } catch (NotRegisteredException e) { - throw new UserErrorException("User " + username + " is not registered."); + throw new UserErrorException("User " + account + " is not registered."); } catch (Throwable e) { throw new UnexpectedErrorException("Error loading state file for user " - + username + + account + ": " + e.getMessage() + " (" @@ -311,14 +304,19 @@ public class App { try { manager.checkAccountState(); } catch (IOException e) { - throw new IOErrorException("Error while checking account " + username + ": " + e.getMessage(), e); + try { + manager.close(); + } catch (IOException ie) { + logger.warn("Failed to close broken account", ie); + } + throw new IOErrorException("Error while checking account " + account + ": " + e.getMessage(), e); } return manager; } private void initDbusClient( - final Command command, final String username, final boolean systemBus, final OutputWriter outputWriter + final Command command, final String account, final boolean systemBus, final OutputWriter outputWriter ) throws CommandException { try { DBusConnection.DBusBusType busType; @@ -329,7 +327,7 @@ public class App { } try (var dBusConn = DBusConnection.getConnection(busType)) { var ts = dBusConn.getRemoteObject(DbusConfig.getBusname(), - DbusConfig.getObjectPath(username), + DbusConfig.getObjectPath(account), Signal.class); handleCommand(command, ts, dBusConn, outputWriter); @@ -344,11 +342,11 @@ public class App { Command command, Signal ts, DBusConnection dBusConn, OutputWriter outputWriter ) throws CommandException { if (command instanceof LocalCommand localCommand) { - try { - localCommand.handleCommand(ns, new DbusManagerImpl(ts, dBusConn), outputWriter); + try (final var m = new DbusManagerImpl(ts, dBusConn)) { + localCommand.handleCommand(ns, m, outputWriter); } catch (UnsupportedOperationException e) { throw new UserErrorException("Command is not yet implemented via dbus", e); - } catch (DBusExecutionException e) { + } catch (IOException | DBusExecutionException e) { throw new UnexpectedErrorException(e.getMessage(), e); } } else {