1 package org
.asamk
.signal
.dbus
;
3 import org
.asamk
.Signal
;
4 import org
.asamk
.SignalControl
;
5 import org
.asamk
.signal
.DbusConfig
;
6 import org
.asamk
.signal
.commands
.Command
;
7 import org
.asamk
.signal
.commands
.CommandHandler
;
8 import org
.asamk
.signal
.commands
.LocalCommand
;
9 import org
.asamk
.signal
.commands
.MultiLocalCommand
;
10 import org
.asamk
.signal
.commands
.ProvisioningCommand
;
11 import org
.asamk
.signal
.commands
.RegistrationCommand
;
12 import org
.asamk
.signal
.commands
.exceptions
.CommandException
;
13 import org
.asamk
.signal
.commands
.exceptions
.UnexpectedErrorException
;
14 import org
.asamk
.signal
.commands
.exceptions
.UserErrorException
;
15 import org
.freedesktop
.dbus
.connections
.impl
.DBusConnection
;
16 import org
.freedesktop
.dbus
.connections
.impl
.DBusConnectionBuilder
;
17 import org
.freedesktop
.dbus
.errors
.ServiceUnknown
;
18 import org
.freedesktop
.dbus
.errors
.UnknownMethod
;
19 import org
.freedesktop
.dbus
.exceptions
.DBusException
;
20 import org
.freedesktop
.dbus
.exceptions
.DBusExecutionException
;
22 import java
.io
.IOException
;
24 public class DbusCommandHandler
{
26 public static void initDbusClient(
27 final Command command
,
29 final boolean systemBus
,
31 final CommandHandler commandHandler
32 ) throws CommandException
{
34 final var busType
= systemBus ? DBusConnection
.DBusBusType
.SYSTEM
: DBusConnection
.DBusBusType
.SESSION
;
35 try (var dBusConn
= DBusConnectionBuilder
.forType(busType
).build()) {
36 handleCommand(command
, account
, dBusConn
, busname
, commandHandler
);
38 } catch (ServiceUnknown e
) {
39 throw new UserErrorException("signal-cli DBus daemon not running on "
40 + (systemBus ?
"system" : "session")
43 } catch (DBusExecutionException
| DBusException
| IOException e
) {
44 throw new UnexpectedErrorException("Dbus client failed: " + e
.getMessage(), e
);
48 public static void handleCommand(
49 final Command command
,
51 final DBusConnection dBusConn
,
53 final CommandHandler commandHandler
54 ) throws CommandException
, DBusException
{
56 if (command
instanceof ProvisioningCommand c
) {
57 if (account
!= null) {
58 throw new UserErrorException("You cannot specify a account (phone number) when linking");
61 handleProvisioningCommand(c
, dBusConn
, busname
, commandHandler
);
65 if (account
== null && command
instanceof MultiLocalCommand c
) {
66 handleMultiLocalCommand(c
, dBusConn
, busname
, commandHandler
);
69 if (account
!= null && command
instanceof RegistrationCommand c
) {
70 handleRegistrationCommand(c
, account
, dBusConn
, busname
, commandHandler
);
73 if (!(command
instanceof LocalCommand localCommand
)) {
74 throw new UserErrorException("Command only works in multi-account mode");
77 var accountObjectPath
= account
== null ?
tryGetSingleAccountObjectPath(dBusConn
, busname
) : null;
78 if (accountObjectPath
== null) {
79 accountObjectPath
= DbusConfig
.getObjectPath(account
);
81 handleLocalCommand(localCommand
, accountObjectPath
, dBusConn
, busname
, commandHandler
);
82 } catch (UnsupportedOperationException e
) {
83 throw new UserErrorException("Command is not yet implemented via dbus", e
);
84 } catch (DBusExecutionException e
) {
85 throw new UnexpectedErrorException(e
.getMessage(), e
);
89 private static String
tryGetSingleAccountObjectPath(
90 final DBusConnection dBusConn
,
92 ) throws DBusException
, CommandException
{
93 var control
= dBusConn
.getRemoteObject(busname
, DbusConfig
.getObjectPath(), SignalControl
.class);
95 final var accounts
= control
.listAccounts();
96 if (accounts
.isEmpty()) {
97 throw new UserErrorException("No local users found, you first need to register or link an account");
98 } else if (accounts
.size() > 1) {
99 throw new UserErrorException(
100 "Multiple users found, you need to specify an account (phone number) with -a");
103 return accounts
.getFirst().getPath();
104 } catch (UnknownMethod e
) {
105 // dbus daemon not running in multi-account mode
110 private static void handleMultiLocalCommand(
111 final MultiLocalCommand c
,
112 final DBusConnection dBusConn
,
113 final String busname
,
114 final CommandHandler commandHandler
115 ) throws CommandException
, DBusException
{
116 final var signalControl
= dBusConn
.getRemoteObject(busname
, DbusConfig
.getObjectPath(), SignalControl
.class);
117 try (final var multiAccountManager
= new DbusMultiAccountManagerImpl(signalControl
, dBusConn
, busname
)) {
118 commandHandler
.handleMultiLocalCommand(c
, multiAccountManager
);
122 private static void handleLocalCommand(
123 final LocalCommand c
,
124 String accountObjectPath
,
125 final DBusConnection dBusConn
,
126 final String busname
,
127 final CommandHandler commandHandler
128 ) throws CommandException
, DBusException
{
129 var signal
= dBusConn
.getRemoteObject(busname
, accountObjectPath
, Signal
.class);
130 try (final var manager
= new DbusManagerImpl(signal
, dBusConn
, busname
)) {
131 commandHandler
.handleLocalCommand(c
, manager
);
135 private static void handleRegistrationCommand(
136 final RegistrationCommand c
,
138 final DBusConnection dBusConn
,
139 final String busname
,
140 final CommandHandler commandHandler
142 ) throws CommandException
, DBusException
{
143 final var signalControl
= dBusConn
.getRemoteObject(busname
, DbusConfig
.getObjectPath(), SignalControl
.class);
144 try (final var registrationManager
= new DbusRegistrationManagerImpl(account
, signalControl
, dBusConn
)) {
145 commandHandler
.handleRegistrationCommand(c
, registrationManager
);
149 private static void handleProvisioningCommand(
150 final ProvisioningCommand c
,
151 final DBusConnection dBusConn
,
152 final String busname
,
153 final CommandHandler commandHandler
155 ) throws CommandException
, DBusException
{
156 final var signalControl
= dBusConn
.getRemoteObject(busname
, DbusConfig
.getObjectPath(), SignalControl
.class);
157 final var provisioningManager
= new DbusProvisioningManagerImpl(signalControl
, dBusConn
);
158 commandHandler
.handleProvisioningCommand(c
, provisioningManager
);