mirror of
https://github.com/AsamK/signal-cli
synced 2025-09-02 20:40:38 +00:00
modify DBus unlisten and unregister
add unlisten() and unregister() to this branch move unlisten() and unregister() methods from Signal.java to SignalControl.java for consistency update documentation
This commit is contained in:
parent
690636b83d
commit
3e67d61681
9 changed files with 196 additions and 14 deletions
|
@ -922,8 +922,12 @@ public class ManagerImpl implements Manager {
|
|||
while (!Thread.interrupted()) {
|
||||
SignalServiceEnvelope envelope;
|
||||
final CachedMessage[] cachedMessage = {null};
|
||||
account.setLastReceiveTimestamp(System.currentTimeMillis());
|
||||
if (account == null) {
|
||||
logger.debug("Account closed.");
|
||||
break;
|
||||
}
|
||||
logger.debug("Checking for new message from server");
|
||||
account.setLastReceiveTimestamp(System.currentTimeMillis());
|
||||
try {
|
||||
var result = signalWebSocket.readOrEmpty(unit.toMillis(timeout), envelope1 -> {
|
||||
final var recipientId = envelope1.hasSourceUuid()
|
||||
|
@ -955,7 +959,7 @@ public class ManagerImpl implements Manager {
|
|||
} else {
|
||||
throw e;
|
||||
}
|
||||
} catch (WebSocketUnavailableException e) {
|
||||
} catch (IOException e) {
|
||||
logger.debug("Pipe unexpectedly unavailable, connecting");
|
||||
signalWebSocket.connect();
|
||||
continue;
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.util.KeyHelper;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager.NewDeviceRegistrationReturn;
|
||||
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
|
||||
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
@ -90,7 +91,13 @@ public class ProvisioningManager {
|
|||
}
|
||||
|
||||
public Manager finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExists {
|
||||
var ret = accountManager.getNewDeviceRegistration(tempIdentityKey);
|
||||
NewDeviceRegistrationReturn ret;
|
||||
logger.info("Waiting for addDevice request...");
|
||||
try {
|
||||
ret = accountManager.getNewDeviceRegistration(tempIdentityKey);
|
||||
} catch (IOException | TimeoutException e) {
|
||||
throw new TimeoutException(e.getMessage());
|
||||
}
|
||||
var number = ret.getNumber();
|
||||
|
||||
logger.info("Received link information from {}, linking in progress ...", number);
|
||||
|
|
|
@ -70,7 +70,7 @@ Exceptions: None
|
|||
listen(number<s>) -> <>::
|
||||
* number : Phone number
|
||||
|
||||
Starting checking the Signal servers on behalf of this number, and export a DBus object path for it.
|
||||
Start checking the Signal servers on behalf of this number, and export a DBus object path for it.
|
||||
Fails if user is not already registered.
|
||||
|
||||
Exceptions: Failure
|
||||
|
@ -90,6 +90,23 @@ Captcha strings may be obtained from `https://signalcaptchas.org/registration/ge
|
|||
|
||||
Exceptions: Failure, InvalidNumber, RequiresCaptcha
|
||||
|
||||
unlisten(number<s>) -> <>::
|
||||
* number : Phone number
|
||||
* keepData : true or omitted = keep files in data directory; false = delete files
|
||||
|
||||
Stops the current device from listening to DBus. In single-user mode, kills the daemon.
|
||||
|
||||
Exception: Failure
|
||||
|
||||
unregister(number<s>) -> <>::
|
||||
unregister(number<s>, keepData<b>) -> <>::
|
||||
* number : Phone number
|
||||
* keepData : true or omitted = keep files in data directory; false = delete files
|
||||
|
||||
Unregisters the current device. In single-user mode, kills the daemon.
|
||||
|
||||
Exception: Failure
|
||||
|
||||
verify(number<s>, verificationCode<s>) -> <>::
|
||||
* number : Phone number
|
||||
* verificationCode : Code received from Signal after successful registration request
|
||||
|
@ -173,7 +190,7 @@ isMember(groupId<ay>) -> active<b>::
|
|||
Note that this method does not raise an Exception for a non-existing/unknown group but will simply return 0 (false)
|
||||
|
||||
sendEndSessionMessage(recipients<as>) -> <>::
|
||||
* recipients : Array of phone numbers
|
||||
* recipients : Array of phone numbers
|
||||
|
||||
Exceptions: Failure, InvalidNumber, UntrustedIdentity
|
||||
|
||||
|
@ -209,7 +226,7 @@ sendMessage(message<s>, attachments<as>, recipients<as>) -> timestamp<x>::
|
|||
* message : Text to send (can be UTF8)
|
||||
* attachments : String array of filenames to send as attachments (passed as filename, so need to be readable by the user signal-cli is running under)
|
||||
* recipient : Phone number of a single recipient
|
||||
* recipients : Array of phone numbers
|
||||
* recipients : Array of phone numbers
|
||||
* timestamp : Can be used to identify the corresponding signal reply
|
||||
|
||||
Depending on the type of the recipient field this sends a message to one or multiple recipients.
|
||||
|
@ -285,7 +302,7 @@ groupList : Array of Byte arrays representing the internal group identifiers
|
|||
All groups known are returned, regardless of their active or blocked status. To query that use isMember() and isGroupBlocked()
|
||||
|
||||
getGroupName(groupId<ay>) -> groupName<s>::
|
||||
groupName : The display name of the group
|
||||
groupName : The display name of the group
|
||||
groupId : Byte array representing the internal group identifier
|
||||
|
||||
Exceptions: None, if the group name is not found an empty string is returned
|
||||
|
@ -361,7 +378,7 @@ removeDevice(deviceId<i>) -> <>::
|
|||
Exception: Failure
|
||||
|
||||
updateDeviceName(deviceName<s>) -> <>::
|
||||
* deviceName : New name
|
||||
* deviceName : New name
|
||||
|
||||
Set a new name for this device (main or linked).
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.freedesktop.dbus.interfaces.DBusInterface;
|
|||
import org.freedesktop.dbus.interfaces.Properties;
|
||||
import org.freedesktop.dbus.messages.DBusSignal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -16,7 +17,7 @@ import java.util.List;
|
|||
*/
|
||||
public interface Signal extends DBusInterface {
|
||||
|
||||
String getSelfNumber();
|
||||
String getSelfNumber();
|
||||
|
||||
long sendMessage(
|
||||
String message, List<String> attachments, String recipient
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.asamk;
|
||||
|
||||
import org.asamk.Signal.Error;
|
||||
import org.freedesktop.dbus.DBusPath;
|
||||
import org.freedesktop.dbus.exceptions.DBusExecutionException;
|
||||
import org.freedesktop.dbus.interfaces.DBusInterface;
|
||||
|
@ -24,12 +25,18 @@ public interface SignalControl extends DBusInterface {
|
|||
|
||||
void verifyWithPin(String number, String verificationCode, String pin) throws Error.Failure, Error.InvalidNumber;
|
||||
|
||||
void listen(String number) throws Error.Failure;
|
||||
|
||||
void unlisten(String number) throws Error.Failure;
|
||||
|
||||
void unregister(String number) throws Error.Failure;
|
||||
void unregister(String number, boolean keepData) throws Error.Failure;
|
||||
|
||||
|
||||
String link(String newDeviceName) throws Error.Failure;
|
||||
|
||||
public String version();
|
||||
|
||||
void listen(String number) throws Error.Failure;
|
||||
|
||||
List<DBusPath> listAccounts();
|
||||
|
||||
interface Error {
|
||||
|
|
|
@ -216,7 +216,10 @@ public class DaemonCommand implements MultiLocalCommand {
|
|||
initThread.join();
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
signal.close();
|
||||
try {
|
||||
signal.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
});
|
||||
|
||||
thread.start();
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
|
|||
import java.util.List;
|
||||
|
||||
public interface MultiLocalCommand extends LocalCommand {
|
||||
void handleCommand(Namespace ns, List<Manager> m, SignalCreator c, OutputWriter outputWriter, TrustNewIdentity trustNewIdentity) throws CommandException;
|
||||
void handleCommand(Namespace ns, List<Manager> managers, SignalCreator c, OutputWriter outputWriter, TrustNewIdentity trustNewIdentity) throws CommandException;
|
||||
void handleCommand(Namespace ns, Manager m, SignalCreator c, OutputWriter outputWriter, TrustNewIdentity trustNewIdentity) throws CommandException;
|
||||
|
||||
}
|
||||
|
|
|
@ -13,11 +13,15 @@ import org.asamk.signal.PlainTextWriter;
|
|||
import org.asamk.signal.commands.DaemonCommand;
|
||||
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.UserErrorException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.PathConfig;
|
||||
import org.asamk.signal.manager.ProvisioningManager;
|
||||
import org.asamk.signal.manager.RegistrationManager;
|
||||
import org.asamk.signal.manager.UserAlreadyExists;
|
||||
import org.asamk.signal.manager.config.ServiceEnvironment;
|
||||
import org.asamk.signal.manager.storage.SignalAccount;
|
||||
import org.asamk.signal.manager.storage.identities.TrustNewIdentity;
|
||||
|
||||
import org.freedesktop.dbus.DBusPath;
|
||||
|
@ -38,7 +42,11 @@ import java.io.InputStream;
|
|||
import java.io.InputStreamReader;
|
||||
import java.net.URI;
|
||||
import java.nio.channels.OverlappingFileLockException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -46,6 +54,7 @@ import java.util.concurrent.TimeoutException;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
||||
|
||||
|
@ -163,6 +172,53 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(String number) {
|
||||
unregister(number, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(String number, boolean keepData) {
|
||||
try {
|
||||
List<Manager> managers = new ArrayList<>();
|
||||
Manager manager = null;
|
||||
|
||||
synchronized (receiveThreads) {
|
||||
managers = receiveThreads.stream()
|
||||
.map(Pair::first)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (managers.size() == 0) {
|
||||
throw new Error.Failure("Unregister error: no manager found.");
|
||||
}
|
||||
|
||||
for (Manager m : managers) {
|
||||
try {
|
||||
m.getSelfNumber();
|
||||
} catch (NullPointerException ignore) {
|
||||
continue;
|
||||
}
|
||||
if (m.getSelfNumber().equals(number)) {
|
||||
manager = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (manager == null) {
|
||||
throw new Error.Failure("Unregister error, " + number + " is not listening.");
|
||||
}
|
||||
|
||||
manager.unregister();
|
||||
DBusConnection.DBusBusType busType = DaemonCommand.dBusType;
|
||||
if (!keepData) {
|
||||
removeUserData(number);
|
||||
}
|
||||
unlisten(number);
|
||||
} catch (Exception e) {
|
||||
throw new Error.Failure(e.getClass().getSimpleName() + " Unregister error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String link(final String newDeviceName) throws Error.Failure {
|
||||
try {
|
||||
|
@ -242,6 +298,59 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlisten(String number) {
|
||||
try {
|
||||
List<Manager> managers = new ArrayList<>();
|
||||
Manager manager = null;
|
||||
|
||||
synchronized (receiveThreads) {
|
||||
managers = receiveThreads.stream()
|
||||
.map(Pair::first)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (managers.size() == 0) {
|
||||
throw new Error.Failure("Unlisten error: no manager found.");
|
||||
}
|
||||
|
||||
for (Manager m : managers) {
|
||||
try {
|
||||
m.getSelfNumber();
|
||||
} catch (NullPointerException ignore) {
|
||||
continue;
|
||||
}
|
||||
if (m.getSelfNumber().equals(number)) {
|
||||
manager = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (manager == null) {
|
||||
throw new Error.Failure("Unlisten error, " + number + " is already not listening.");
|
||||
}
|
||||
|
||||
String objectPath = DbusConfig.getObjectPath(number);
|
||||
DBusConnection.DBusBusType busType = DaemonCommand.dBusType;
|
||||
var conn = DBusConnection.getConnection(busType);
|
||||
//if single-user mode, just close the manager because we're exiting anyway
|
||||
//else unexport the object
|
||||
try {
|
||||
//this will generate an error if we are in anonymous mode
|
||||
conn.exportObject(new DbusSignalImpl(manager, conn, objectPath));
|
||||
//no error, hence single-user mode
|
||||
manager.close();
|
||||
logger.info("unExported dbus object: " + DbusConfig.getObjectPath());
|
||||
} catch (DBusException ignore) {
|
||||
//anonymous mode
|
||||
conn.unExportObject(objectPath);
|
||||
manager.close();
|
||||
logger.info("unExported dbus object: " + objectPath);
|
||||
}
|
||||
} catch (IOException | DBusException e) {
|
||||
throw new Error.Failure(e.getClass().getSimpleName() + " Unlisten error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DBusPath> listAccounts() {
|
||||
synchronized (receiveThreads) {
|
||||
|
@ -252,4 +361,25 @@ public class DbusSignalControlImpl implements org.asamk.SignalControl {
|
|||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private void removeUserData(String number) {
|
||||
File dataPath = PathConfig.createDefault(c.getSettingsPath()).getDataPath();
|
||||
number.replaceFirst("_", "+");
|
||||
String eraseFileName = dataPath.getAbsolutePath() + File.separator + number;
|
||||
File eraseFile = new File(eraseFileName);
|
||||
if (eraseFile.delete()) {
|
||||
logger.info("erased " + eraseFileName);
|
||||
} else {
|
||||
logger.error("erase failed for " + eraseFileName);
|
||||
}
|
||||
String erasePath = dataPath.getAbsolutePath() + File.separator + number + ".d/";
|
||||
Path rootPath = Paths.get(erasePath);
|
||||
try (Stream<Path> walk = Files.walk(rootPath)) {
|
||||
walk.sorted(Comparator.reverseOrder())
|
||||
.map(Path::toFile)
|
||||
.forEach(File::delete);
|
||||
} catch (IOException e) {
|
||||
throw new Error.Failure(e.getClass().getSimpleName() + " RemoveUserData failed. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package org.asamk.signal.dbus;
|
||||
|
||||
import org.asamk.Signal;
|
||||
import org.asamk.Signal.Error;
|
||||
import org.asamk.signal.BaseConfig;
|
||||
import org.asamk.signal.DbusConfig;
|
||||
import org.asamk.signal.commands.DaemonCommand;
|
||||
import org.asamk.signal.manager.AttachmentInvalidException;
|
||||
import org.asamk.signal.manager.Manager;
|
||||
import org.asamk.signal.manager.NotMasterDeviceException;
|
||||
|
@ -20,10 +23,13 @@ import org.asamk.signal.manager.groups.NotAGroupMemberException;
|
|||
import org.asamk.signal.manager.storage.recipients.Profile;
|
||||
import org.asamk.signal.manager.storage.recipients.RecipientAddress;
|
||||
import org.asamk.signal.util.ErrorUtils;
|
||||
|
||||
import org.freedesktop.dbus.DBusPath;
|
||||
import org.freedesktop.dbus.connections.impl.DBusConnection;
|
||||
import org.freedesktop.dbus.exceptions.DBusException;
|
||||
import org.freedesktop.dbus.exceptions.DBusExecutionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
@ -35,16 +41,21 @@ import org.whispersystems.signalservice.internal.contacts.crypto.Unauthenticated
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
@ -53,6 +64,7 @@ public class DbusSignalImpl implements Signal {
|
|||
private final Manager m;
|
||||
private final DBusConnection connection;
|
||||
private final String objectPath;
|
||||
private final static Logger logger = LoggerFactory.getLogger(DbusSignalImpl.class);
|
||||
|
||||
private DBusPath thisDevice;
|
||||
private final List<DBusPath> devices = new ArrayList<>();
|
||||
|
@ -67,8 +79,9 @@ public class DbusSignalImpl implements Signal {
|
|||
updateDevices();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
public void close() throws IOException {
|
||||
unExportDevices();
|
||||
m.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue