1 package org
.asamk
.signal
.dbus
;
3 import org
.asamk
.SignalControl
;
4 import org
.asamk
.signal
.BaseConfig
;
5 import org
.asamk
.signal
.DbusConfig
;
6 import org
.asamk
.signal
.commands
.SignalCreator
;
7 import org
.asamk
.signal
.manager
.Manager
;
8 import org
.asamk
.signal
.manager
.ProvisioningManager
;
9 import org
.asamk
.signal
.manager
.RegistrationManager
;
10 import org
.asamk
.signal
.manager
.UserAlreadyExists
;
11 import org
.asamk
.signal
.manager
.api
.Pair
;
12 import org
.freedesktop
.dbus
.DBusPath
;
13 import org
.whispersystems
.signalservice
.api
.KeyBackupServicePinException
;
14 import org
.whispersystems
.signalservice
.api
.KeyBackupSystemNoDataException
;
15 import org
.whispersystems
.signalservice
.api
.push
.exceptions
.CaptchaRequiredException
;
16 import org
.whispersystems
.signalservice
.api
.util
.PhoneNumberFormatter
;
18 import java
.io
.IOException
;
20 import java
.util
.ArrayList
;
21 import java
.util
.List
;
22 import java
.util
.concurrent
.TimeoutException
;
23 import java
.util
.function
.Function
;
24 import java
.util
.stream
.Collectors
;
26 public class DbusSignalControlImpl
implements org
.asamk
.SignalControl
{
28 private final SignalCreator c
;
29 private final Function
<Manager
, Thread
> newManagerRunner
;
31 private final List
<Pair
<Manager
, Thread
>> receiveThreads
= new ArrayList
<>();
32 private final Object stopTrigger
= new Object();
33 private final String objectPath
;
35 public DbusSignalControlImpl(
36 final SignalCreator c
, final Function
<Manager
, Thread
> newManagerRunner
, final String objectPath
39 this.newManagerRunner
= newManagerRunner
;
40 this.objectPath
= objectPath
;
43 public void addManager(Manager m
) {
44 var thread
= newManagerRunner
.apply(m
);
48 synchronized (receiveThreads
) {
49 receiveThreads
.add(new Pair
<>(m
, thread
));
54 synchronized (stopTrigger
) {
57 } catch (InterruptedException ignored
) {
61 synchronized (receiveThreads
) {
62 for (var t
: receiveThreads
) {
63 t
.second().interrupt();
68 synchronized (receiveThreads
) {
69 if (receiveThreads
.size() == 0) {
72 var pair
= receiveThreads
.remove(0);
73 thread
= pair
.second();
77 } catch (InterruptedException ignored
) {
83 public boolean isRemote() {
88 public String
getObjectPath() {
94 final String number
, final boolean voiceVerification
95 ) throws Error
.Failure
, Error
.InvalidNumber
{
96 registerWithCaptcha(number
, voiceVerification
, null);
100 public void registerWithCaptcha(
101 final String number
, final boolean voiceVerification
, final String captcha
102 ) throws Error
.Failure
, Error
.InvalidNumber
{
103 if (!PhoneNumberFormatter
.isValidNumber(number
, null)) {
104 throw new SignalControl
.Error
.InvalidNumber(
105 "Invalid username (phone number), make sure you include the country code.");
107 try (final RegistrationManager registrationManager
= c
.getNewRegistrationManager(number
)) {
108 registrationManager
.register(voiceVerification
, captcha
);
109 } catch (CaptchaRequiredException e
) {
110 String message
= captcha
== null ?
"Captcha required for verification." : "Invalid captcha given.";
111 throw new SignalControl
.Error
.RequiresCaptcha(message
);
112 } catch (IOException e
) {
113 throw new SignalControl
.Error
.Failure(e
.getClass().getSimpleName() + " " + e
.getMessage());
118 public void verify(final String number
, final String verificationCode
) throws Error
.Failure
, Error
.InvalidNumber
{
119 verifyWithPin(number
, verificationCode
, null);
123 public void verifyWithPin(
124 final String number
, final String verificationCode
, final String pin
125 ) throws Error
.Failure
, Error
.InvalidNumber
{
126 try (final RegistrationManager registrationManager
= c
.getNewRegistrationManager(number
)) {
127 final Manager manager
= registrationManager
.verifyAccount(verificationCode
, pin
);
129 } catch (IOException
| KeyBackupSystemNoDataException
| KeyBackupServicePinException e
) {
130 throw new SignalControl
.Error
.Failure(e
.getClass().getSimpleName() + " " + e
.getMessage());
135 public String
link(final String newDeviceName
) throws Error
.Failure
{
137 final ProvisioningManager provisioningManager
= c
.getNewProvisioningManager();
138 final URI deviceLinkUri
= provisioningManager
.getDeviceLinkUri();
141 final Manager manager
= provisioningManager
.finishDeviceLink(newDeviceName
);
143 } catch (IOException
| TimeoutException
| UserAlreadyExists e
) {
147 return deviceLinkUri
.toString();
148 } catch (TimeoutException
| IOException e
) {
149 throw new SignalControl
.Error
.Failure(e
.getClass().getSimpleName() + " " + e
.getMessage());
154 public String
version() {
155 return BaseConfig
.PROJECT_VERSION
;
159 public List
<DBusPath
> listAccounts() {
160 synchronized (receiveThreads
) {
161 return receiveThreads
.stream()
163 .map(Manager
::getSelfNumber
)
164 .map(u
-> new DBusPath(DbusConfig
.getObjectPath(u
)))
165 .collect(Collectors
.toList());