Specify your phone number, that will be your identifier.
The phone number must include the country calling code, i.e. the number must start with a "+" sign.
+This flag must not be given for the `link` command.
+It is optional for the `daemon` command.
+For all other commands it is only optional if there is exactly one local user in the
+config directory.
+
*--dbus*::
Make request via user dbus.
=== daemon
signal-cli can run in daemon mode and provides an experimental dbus interface.
+If no `-u` username is given, all local users will be exported as separate dbus
+objects under the same bus name.
*--system*::
Use DBus system bus instead of user bus.
Trust new key, without having verified it. Only use this if you don't care about security::
signal-cli -u USERNAME trust -a NUMBER
+== Exit codes
+* *1*: Error is probably caused and fixable by the user
+* *2*: Some unexpected error
+* *3*: Server or IO error
+
== Files
The password and cryptographic keys are created when registering and stored in the current users home directory, the directory can be changed with *--config*:
import org.asamk.signal.commands.DbusCommand;
import org.asamk.signal.commands.ExtendedDbusCommand;
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.dbus.DbusSignalImpl;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.NotRegisteredException;
import org.asamk.signal.manager.ProvisioningManager;
import org.freedesktop.dbus.exceptions.DBusException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
import java.io.File;
import java.io.IOException;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
public class Cli {
Command command = getCommand();
if (command == null) {
logger.error("Command not implemented!");
- return 2;
+ return 1;
}
+ String username = ns.getString("username");
+
if (ns.getBoolean("dbus") || ns.getBoolean("dbus_system")) {
- return initDbusClient(command, ns.getBoolean("dbus_system"));
+ // If username is null, it will connect to the default object path
+ return initDbusClient(command, username, ns.getBoolean("dbus_system"));
}
- final String username = ns.getString("username");
-
final File dataPath;
String config = ns.getString("config");
if (config != null) {
+ " because the required native library dependency is missing: libzkgroup");
}
- if (username == null) {
- ProvisioningManager pm = new ProvisioningManager(dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
- return handleCommand(command, pm);
+ if (command instanceof ProvisioningCommand) {
+ if (username != null) {
+ System.err.println("You cannot specify a username (phone number) when linking");
+ return 1;
+ }
+
+ return handleProvisioningCommand((ProvisioningCommand) command, dataPath, serviceConfiguration);
}
- if (command instanceof RegistrationCommand) {
- final RegistrationManager manager;
- try {
- manager = RegistrationManager.init(username, dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
- } catch (Throwable e) {
- logger.error("Error loading or creating state file: {}", e.getMessage());
+ if (username == null) {
+ List<String> usernames = Manager.getAllLocalUsernames(dataPath);
+ if (usernames.size() == 0) {
+ System.err.println("No local users found, you first need to register or link an account");
return 1;
}
- try (RegistrationManager m = manager) {
- return handleCommand(command, m);
- } catch (Exception e) {
- logger.error("Cleanup failed", e);
- return 2;
+
+ if (command instanceof MultiLocalCommand) {
+ return handleMultiLocalCommand((MultiLocalCommand) command, dataPath, serviceConfiguration, usernames);
+ }
+
+ if (usernames.size() > 1) {
+ System.err.println("Multiple users found, you need to specify a username (phone number) with -u");
+ return 1;
}
+
+ username = usernames.get(0);
+ } else if (!PhoneNumberFormatter.isValidNumber(username, null)) {
+ System.err.println("Invalid username (phone number), make sure you include the country code.");
+ return 1;
}
- Manager manager;
+ if (command instanceof RegistrationCommand) {
+ return handleRegistrationCommand((RegistrationCommand) command, username, dataPath, serviceConfiguration);
+ }
+
+ if (!(command instanceof LocalCommand)) {
+ System.err.println("Command only works via dbus");
+ return 1;
+ }
+
+ return handleLocalCommand((LocalCommand) command, username, dataPath, serviceConfiguration);
+ }
+
+ private int handleProvisioningCommand(
+ final ProvisioningCommand command,
+ final File dataPath,
+ final SignalServiceConfiguration serviceConfiguration
+ ) {
+ ProvisioningManager pm = new ProvisioningManager(dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
+ return command.handleCommand(ns, pm);
+ }
+
+ private int handleRegistrationCommand(
+ final RegistrationCommand command,
+ final String username,
+ final File dataPath,
+ final SignalServiceConfiguration serviceConfiguration
+ ) {
+ final RegistrationManager manager;
try {
- manager = Manager.init(username, dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
- } catch (NotRegisteredException e) {
- System.err.println("User is not registered.");
- return 0;
+ manager = RegistrationManager.init(username, dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
} catch (Throwable e) {
- logger.error("Error loading state file: {}", e.getMessage());
- return 1;
+ logger.error("Error loading or creating state file: {}", e.getMessage());
+ return 2;
+ }
+ try (RegistrationManager m = manager) {
+ return command.handleCommand(ns, m);
+ } catch (IOException e) {
+ logger.error("Cleanup failed", e);
+ return 2;
}
+ }
- try (Manager m = manager) {
- try {
- m.checkAccountState();
- } catch (IOException e) {
- logger.error("Error while checking account: {}", e.getMessage());
- return 1;
+ private int handleLocalCommand(
+ final LocalCommand command,
+ final String username,
+ final File dataPath,
+ final SignalServiceConfiguration serviceConfiguration
+ ) {
+ try (Manager m = loadManager(username, dataPath, serviceConfiguration)) {
+ if (m == null) {
+ return 2;
}
- return handleCommand(command, m);
+ return command.handleCommand(ns, m);
} catch (IOException e) {
logger.error("Cleanup failed", e);
return 2;
}
}
+ private int handleMultiLocalCommand(
+ final MultiLocalCommand command,
+ final File dataPath,
+ final SignalServiceConfiguration serviceConfiguration,
+ final List<String> usernames
+ ) {
+ final List<Manager> managers = usernames.stream()
+ .map(u -> loadManager(u, dataPath, serviceConfiguration))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ int result = command.handleCommand(ns, managers);
+
+ for (Manager m : managers) {
+ try {
+ m.close();
+ } catch (IOException e) {
+ logger.warn("Cleanup failed", e);
+ }
+ }
+ return result;
+ }
+
+ private Manager loadManager(
+ final String username, final File dataPath, final SignalServiceConfiguration serviceConfiguration
+ ) {
+ Manager manager;
+ try {
+ manager = Manager.init(username, dataPath, serviceConfiguration, BaseConfig.USER_AGENT);
+ } catch (NotRegisteredException e) {
+ logger.error("User " + username + " is not registered.");
+ return null;
+ } catch (Throwable e) {
+ logger.error("Error loading state file for user " + username + ": {}", e.getMessage());
+ return null;
+ }
+
+ try {
+ manager.checkAccountState();
+ } catch (IOException e) {
+ logger.error("Error while checking account " + username + ": {}", e.getMessage());
+ return null;
+ }
+
+ return manager;
+ }
+
private Command getCommand() {
String commandKey = ns.getString("command");
return Commands.getCommand(commandKey);
}
- private int initDbusClient(final Command command, final boolean systemBus) {
+ private int initDbusClient(final Command command, final String username, final boolean systemBus) {
try {
DBusConnection.DBusBusType busType;
if (systemBus) {
busType = DBusConnection.DBusBusType.SESSION;
}
try (DBusConnection dBusConn = DBusConnection.getConnection(busType)) {
- Signal ts = dBusConn.getRemoteObject(DbusConfig.SIGNAL_BUSNAME,
- DbusConfig.SIGNAL_OBJECTPATH,
+ Signal ts = dBusConn.getRemoteObject(DbusConfig.getBusname(),
+ DbusConfig.getObjectPath(username),
Signal.class);
return handleCommand(command, ts, dBusConn);
}
}
- private int handleCommand(Command command, ProvisioningManager pm) {
- if (command instanceof ProvisioningCommand) {
- return ((ProvisioningCommand) command).handleCommand(ns, pm);
- } else {
- System.err.println("Command only works with a username");
- return 1;
- }
- }
-
- private int handleCommand(Command command, RegistrationManager m) {
- if (command instanceof RegistrationCommand) {
- return ((RegistrationCommand) command).handleCommand(ns, m);
- }
- return 1;
- }
-
- private int handleCommand(Command command, Manager m) {
- if (command instanceof LocalCommand) {
- return ((LocalCommand) command).handleCommand(ns, m);
- } else if (command instanceof DbusCommand) {
- return ((DbusCommand) command).handleCommand(ns, new DbusSignalImpl(m));
- } else {
- System.err.println("Command only works via dbus");
- return 1;
- }
- }
-
/**
* Uses $XDG_DATA_HOME/signal-cli if it exists, or if none of the legacy directories exist:
* - $HOME/.config/signal
public class DbusConfig {
- public static final String SIGNAL_BUSNAME = "org.asamk.Signal";
- public static final String SIGNAL_OBJECTPATH = "/org/asamk/Signal";
+ private static final String SIGNAL_BUSNAME = "org.asamk.Signal";
+ private static final String SIGNAL_OBJECT_BASE_PATH = "/org/asamk/Signal";
+
+ public static String getBusname() {
+ return SIGNAL_BUSNAME;
+ }
+
+ public static String getObjectPath() {
+ return getObjectPath(null);
+ }
+
+ public static String getObjectPath(String username) {
+ if (username == null) {
+ return SIGNAL_OBJECT_BASE_PATH;
+ }
+
+ return SIGNAL_OBJECT_BASE_PATH + "/" + username.replace('+', '_');
+ }
}
import org.asamk.signal.manager.LibSignalLogger;
import org.asamk.signal.util.SecurityProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import java.security.Security;
import java.util.Map;
Namespace ns = parseArgs(args);
if (ns == null) {
- System.exit(1);
+ System.exit(2);
}
int res = new Cli(ns).init();
return null;
}
- if ("link".equals(ns.getString("command"))) {
- if (ns.getString("username") != null) {
- parser.printUsage();
- System.err.println("You cannot specify a username (phone number) when linking");
- System.exit(2);
- }
- } else if (!ns.getBoolean("dbus") && !ns.getBoolean("dbus_system")) {
- if (ns.getString("username") == null) {
- parser.printUsage();
- System.err.println("You need to specify a username (phone number)");
- System.exit(2);
- }
- if (!PhoneNumberFormatter.isValidNumber(ns.getString("username"), null)) {
- System.err.println("Invalid username (phone number), make sure you include the country code.");
- System.exit(2);
- }
- }
-
if (ns.getList("recipient") != null && !ns.getList("recipient").isEmpty() && ns.getString("group") != null) {
System.err.println("You cannot specify recipients by phone number and groups at the same time");
System.exit(2);
parser.addArgument("--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 used for verification.");
+
MutuallyExclusiveGroup mut = parser.addMutuallyExclusiveGroup();
- mut.addArgument("-u", "--username").help("Specify your phone number, that will be used for verification.");
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());
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.DbusConfig;
import org.asamk.signal.DbusReceiveMessageHandler;
import org.asamk.signal.JsonDbusReceiveMessageHandler;
import org.asamk.signal.dbus.DbusSignalImpl;
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.TimeUnit;
-import static org.asamk.signal.DbusConfig.SIGNAL_BUSNAME;
-import static org.asamk.signal.DbusConfig.SIGNAL_OBJECTPATH;
-import static org.asamk.signal.util.ErrorUtils.handleAssertionError;
-
-public class DaemonCommand implements LocalCommand {
+public class DaemonCommand implements MultiLocalCommand {
private final static Logger logger = LoggerFactory.getLogger(ReceiveCommand.class);
logger.warn("\"--json\" option has been deprecated, please use the global \"--output=json\" instead.");
}
- DBusConnection conn = null;
- try {
+ boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
+
+ DBusConnection.DBusBusType busType;
+ if (ns.getBoolean("system")) {
+ busType = DBusConnection.DBusBusType.SYSTEM;
+ } else {
+ busType = DBusConnection.DBusBusType.SESSION;
+ }
+
+ try (DBusConnection conn = DBusConnection.getConnection(busType)) {
+ String objectPath = DbusConfig.getObjectPath();
+ Thread t = run(conn, objectPath, m, ignoreAttachments, inJson);
+
+ conn.requestBusName(DbusConfig.getBusname());
+
try {
- DBusConnection.DBusBusType busType;
- if (ns.getBoolean("system")) {
- busType = DBusConnection.DBusBusType.SYSTEM;
- } else {
- busType = DBusConnection.DBusBusType.SESSION;
- }
- conn = DBusConnection.getConnection(busType);
- conn.exportObject(SIGNAL_OBJECTPATH, new DbusSignalImpl(m));
- conn.requestBusName(SIGNAL_BUSNAME);
- } catch (UnsatisfiedLinkError e) {
- System.err.println("Missing native library dependency for dbus service: " + e.getMessage());
- return 1;
- } catch (DBusException e) {
- e.printStackTrace();
- return 2;
+ t.join();
+ } catch (InterruptedException ignored) {
}
- boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
- try {
- m.receiveMessages(1,
- TimeUnit.HOURS,
- false,
- ignoreAttachments,
- inJson
- ? new JsonDbusReceiveMessageHandler(m, conn, SIGNAL_OBJECTPATH)
- : new DbusReceiveMessageHandler(m, conn, SIGNAL_OBJECTPATH));
- return 0;
- } catch (IOException e) {
- System.err.println("Error while receiving messages: " + e.getMessage());
- return 3;
- } catch (AssertionError e) {
- handleAssertionError(e);
- return 1;
+ return 0;
+ } catch (DBusException | IOException e) {
+ logger.error("Dbus command failed", e);
+ return 2;
+ }
+ }
+
+ @Override
+ public int handleCommand(final Namespace ns, final List<Manager> managers) {
+ boolean inJson = ns.getString("output").equals("json") || ns.getBoolean("json");
+
+ // TODO delete later when "json" variable is removed
+ if (ns.getBoolean("json")) {
+ logger.warn("\"--json\" option has been deprecated, please use the global \"--output=json\" instead.");
+ }
+
+ boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
+
+ DBusConnection.DBusBusType busType;
+ if (ns.getBoolean("system")) {
+ busType = DBusConnection.DBusBusType.SYSTEM;
+ } else {
+ busType = DBusConnection.DBusBusType.SESSION;
+ }
+
+ try (DBusConnection conn = DBusConnection.getConnection(busType)) {
+ List<Thread> receiveThreads = new ArrayList<>();
+ for (Manager m : managers) {
+ String objectPath = DbusConfig.getObjectPath(m.getUsername());
+ Thread thread = run(conn, objectPath, m, ignoreAttachments, inJson);
+ receiveThreads.add(thread);
}
- } finally {
- if (conn != null) {
- conn.disconnect();
+
+ conn.requestBusName(DbusConfig.getBusname());
+
+ for (Thread t : receiveThreads) {
+ try {
+ t.join();
+ } catch (InterruptedException ignored) {
+ }
}
+ return 0;
+ } catch (DBusException | IOException e) {
+ logger.error("Dbus command failed", e);
+ return 2;
}
}
+
+ private Thread run(
+ DBusConnection conn, String objectPath, Manager m, boolean ignoreAttachments, boolean inJson
+ ) throws DBusException {
+ conn.exportObject(objectPath, new DbusSignalImpl(m));
+
+ final Thread thread = new Thread(() -> {
+ while (true) {
+ try {
+ m.receiveMessages(1,
+ TimeUnit.HOURS,
+ false,
+ ignoreAttachments,
+ inJson
+ ? new JsonDbusReceiveMessageHandler(m, conn, objectPath)
+ : new DbusReceiveMessageHandler(m, conn, objectPath));
+ } catch (IOException e) {
+ logger.warn("Receiving messages failed, retrying", e);
+ }
+ }
+ });
+
+ logger.info("Exported dbus object: " + objectPath);
+
+ thread.start();
+
+ return thread;
+ }
}
import net.sourceforge.argparse4j.inf.Namespace;
import org.asamk.Signal;
+import org.asamk.signal.dbus.DbusSignalImpl;
+import org.asamk.signal.manager.Manager;
-public interface DbusCommand extends Command {
+public interface DbusCommand extends LocalCommand {
int handleCommand(Namespace ns, Signal signal);
+
+ default int handleCommand(final Namespace ns, final Manager m) {
+ return handleCommand(ns, new DbusSignalImpl(m));
+ }
}
registered = m.areUsersRegistered(new HashSet<>(ns.getList("number")));
} catch (IOException e) {
System.err.println("Unable to check if users are registered");
- return 1;
+ return 3;
}
// Output
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
-import org.asamk.Signal;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.groups.GroupId;
import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
linkUrl = GroupInviteLinkUrl.fromUri(uri);
} catch (GroupInviteLinkUrl.InvalidGroupLinkException e) {
System.err.println("Group link is invalid: " + e.getMessage());
- return 2;
+ return 1;
} catch (GroupInviteLinkUrl.UnknownGroupLinkVersionException e) {
System.err.println("Group link was created with an incompatible version: " + e.getMessage());
- return 2;
+ return 1;
}
if (linkUrl == null) {
System.err.println("Link is not a signal group invitation link");
- return 2;
+ return 1;
}
try {
} catch (IOException e) {
e.printStackTrace();
handleIOException(e);
- return 1;
- } catch (Signal.Error.AttachmentInvalid e) {
- System.err.println("Failed to add avatar attachment for group\": " + e.getMessage());
- return 1;
+ return 3;
} catch (DBusExecutionException e) {
System.err.println("Failed to send message: " + e.getMessage());
- return 1;
+ return 2;
} catch (GroupLinkNotActiveException e) {
System.err.println("Group link is not valid: " + e.getMessage());
- return 2;
+ return 1;
}
}
}
package org.asamk.signal.commands;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.PropertyAccessor;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ListGroupsCommand implements LocalCommand {
private static Set<String> resolveMembers(Manager m, Set<SignalServiceAddress> addresses) {
- return addresses.stream().map(m::resolveSignalServiceAddress)
+ return addresses.stream()
+ .map(m::resolveSignalServiceAddress)
.map(SignalServiceAddress::getLegacyIdentifier)
.collect(Collectors.toSet());
}
System.out.println();
} catch (IOException e) {
System.err.println(e.getMessage());
- return 1;
+ return 3;
}
return 0;
@Override
public void attachToSubparser(final Subparser subparser) {
- subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue())
+ subparser.addArgument("-d", "--detailed")
+ .action(Arguments.storeTrue())
.help("List the members and group invite links of each group. If output=json, then this is always set");
subparser.help("List group information including names, ids, active status, blocked status and members");
public Set<String> requestingMembers;
public String groupInviteLink;
- public JsonGroup(String id, String name, boolean isMember, boolean isBlocked,
- Set<String> members, Set<String> pendingMembers,
- Set<String> requestingMembers, String groupInviteLink)
- {
+ public JsonGroup(
+ String id,
+ String name,
+ boolean isMember,
+ boolean isBlocked,
+ Set<String> members,
+ Set<String> pendingMembers,
+ Set<String> requestingMembers,
+ String groupInviteLink
+ ) {
this.id = id;
this.name = name;
this.isMember = isMember;
--- /dev/null
+package org.asamk.signal.commands;
+
+import net.sourceforge.argparse4j.inf.Namespace;
+
+import org.asamk.signal.manager.Manager;
+
+import java.util.List;
+
+public interface MultiLocalCommand extends LocalCommand {
+
+ int handleCommand(Namespace ns, List<Manager> m);
+
+ @Override
+ default int handleCommand(final Namespace ns, final Manager m) {
+ return handleCommand(ns, List.of(m));
+ }
+}
System.out.println();
}
});
- } catch (UnsatisfiedLinkError e) {
- System.err.println("Missing native library dependency for dbus service: " + e.getMessage());
- return 1;
} catch (DBusException e) {
e.printStackTrace();
- return 1;
+ return 2;
}
while (true) {
try {
try {
m.setRegistrationLockPin(Optional.absent());
return 0;
- } catch (IOException | UnauthenticatedResponseException e) {
+ } catch (UnauthenticatedResponseException e) {
+ System.err.println("Remove pin error: " + e.getMessage());
+ return 2;
+ } catch (IOException e) {
System.err.println("Remove pin error: " + e.getMessage());
return 3;
}
import org.asamk.signal.manager.groups.GroupIdFormatException;
import org.asamk.signal.util.IOUtils;
import org.asamk.signal.util.Util;
+import org.freedesktop.dbus.errors.UnknownObject;
import org.freedesktop.dbus.exceptions.DBusExecutionException;
import java.io.IOException;
return 1;
} catch (DBusExecutionException e) {
System.err.println("Failed to send message: " + e.getMessage());
- return 1;
+ return 2;
}
}
return 1;
} catch (DBusExecutionException e) {
System.err.println("Failed to send message: " + e.getMessage());
- return 1;
+ return 2;
}
try {
} catch (AssertionError e) {
handleAssertionError(e);
return 1;
+ } catch (UnknownObject e) {
+ System.err.println("Failed to find dbus object, maybe missing the -u flag: " + e.getMessage());
+ return 1;
} catch (DBusExecutionException e) {
System.err.println("Failed to send message: " + e.getMessage());
- return 1;
+ return 2;
}
}
}
try {
m.sendContacts();
return 0;
- } catch (IOException | UntrustedIdentityException e) {
+ } catch (UntrustedIdentityException e) {
+ System.err.println("SendContacts error: " + e.getMessage());
+ return 2;
+ } catch (IOException e) {
System.err.println("SendContacts error: " + e.getMessage());
return 3;
}
String registrationLockPin = ns.getString("registrationLockPin");
m.setRegistrationLockPin(Optional.of(registrationLockPin));
return 0;
- } catch (IOException | UnauthenticatedResponseException e) {
+ } catch (UnauthenticatedResponseException e) {
+ System.err.println("Set pin error: " + e.getMessage());
+ return 2;
+ } catch (IOException e) {
System.err.println("Set pin error: " + e.getMessage());
return 3;
}
return 1;
} catch (DBusExecutionException e) {
System.err.println("Failed to send message: " + e.getMessage());
- return 1;
+ return 2;
}
}
}
return 3;
} catch (StickerPackInvalidException e) {
System.err.println("Invalid sticker pack: " + e.getMessage());
- return 3;
+ return 1;
}
}
}
return new Manager(account, pathConfig, serviceConfiguration, userAgent);
}
+ public static List<String> getAllLocalUsernames(File settingsPath) {
+ PathConfig pathConfig = PathConfig.createDefault(settingsPath);
+ final File dataPath = pathConfig.getDataPath();
+ final File[] files = dataPath.listFiles();
+
+ if (files == null) {
+ return List.of();
+ }
+
+ return Arrays.stream(files)
+ .filter(File::isFile)
+ .map(File::getName)
+ .filter(file -> PhoneNumberFormatter.isValidNumber(file, null))
+ .collect(Collectors.toList());
+ }
+
public void checkAccountState() throws IOException {
if (accountManager.getPreKeysCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) {
refreshPreKeys();
import org.whispersystems.signalservice.internal.push.VerifyAccountResponse;
import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
+import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
-public class RegistrationManager implements AutoCloseable {
+public class RegistrationManager implements Closeable {
private SignalAccount account;
private final PathConfig pathConfig;
}
@Override
- public void close() throws Exception {
+ public void close() throws IOException {
if (account != null) {
account.close();
account = null;