]> nmode's Git Repositories - signal-cli/blob - src/main/java/org/asamk/signal/commands/DaemonCommand.java
ee9368f87fb521096ed0004c2bc8aaa0b83b9f8d
[signal-cli] / src / main / java / org / asamk / signal / commands / DaemonCommand.java
1 package org.asamk.signal.commands;
2
3 import net.sourceforge.argparse4j.impl.Arguments;
4 import net.sourceforge.argparse4j.inf.Namespace;
5 import net.sourceforge.argparse4j.inf.Subparser;
6
7 import org.asamk.signal.DbusConfig;
8 import org.asamk.signal.DbusReceiveMessageHandler;
9 import org.asamk.signal.JsonReceiveMessageHandler;
10 import org.asamk.signal.JsonWriter;
11 import org.asamk.signal.OutputType;
12 import org.asamk.signal.OutputWriter;
13 import org.asamk.signal.PlainTextWriter;
14 import org.asamk.signal.ReceiveMessageHandler;
15 import org.asamk.signal.commands.exceptions.CommandException;
16 import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
17 import org.asamk.signal.dbus.DbusSignalControlImpl;
18 import org.asamk.signal.dbus.DbusSignalImpl;
19 import org.asamk.signal.manager.Manager;
20 import org.freedesktop.dbus.connections.impl.DBusConnection;
21 import org.freedesktop.dbus.exceptions.DBusException;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import java.io.IOException;
26 import java.util.List;
27
28 public class DaemonCommand implements MultiLocalCommand {
29
30 private final static Logger logger = LoggerFactory.getLogger(DaemonCommand.class);
31
32 @Override
33 public String getName() {
34 return "daemon";
35 }
36
37 @Override
38 public void attachToSubparser(final Subparser subparser) {
39 subparser.help("Run in daemon mode and provide an experimental dbus interface.");
40 subparser.addArgument("--system")
41 .action(Arguments.storeTrue())
42 .help("Use DBus system bus instead of user bus.");
43 subparser.addArgument("--ignore-attachments")
44 .help("Don’t download attachments of received messages.")
45 .action(Arguments.storeTrue());
46 }
47
48 @Override
49 public List<OutputType> getSupportedOutputTypes() {
50 return List.of(OutputType.PLAIN_TEXT, OutputType.JSON);
51 }
52
53 @Override
54 public void handleCommand(
55 final Namespace ns, final Manager m, final OutputWriter outputWriter
56 ) throws CommandException {
57 boolean ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments"));
58 m.setIgnoreAttachments(ignoreAttachments);
59
60 DBusConnection.DBusBusType busType;
61 if (Boolean.TRUE.equals(ns.getBoolean("system"))) {
62 busType = DBusConnection.DBusBusType.SYSTEM;
63 } else {
64 busType = DBusConnection.DBusBusType.SESSION;
65 }
66
67 try (var conn = DBusConnection.getConnection(busType)) {
68 var objectPath = DbusConfig.getObjectPath();
69 var t = run(conn, objectPath, m, outputWriter);
70
71 conn.requestBusName(DbusConfig.getBusname());
72 logger.info("DBus daemon running in single-user mode for " + m.getSelfNumber());
73
74 try {
75 t.join();
76 synchronized (this) {
77 wait();
78 }
79 } catch (InterruptedException ignored) {
80 }
81 } catch (DBusException | IOException e) {
82 logger.error("Dbus command failed", e);
83 throw new UnexpectedErrorException("Dbus command failed", e);
84 }
85 }
86
87 @Override
88 public void handleCommand(
89 final Namespace ns, final List<Manager> managers, final SignalCreator c, final OutputWriter outputWriter
90 ) throws CommandException {
91 boolean ignoreAttachments = Boolean.TRUE.equals(ns.getBoolean("ignore-attachments"));
92
93 DBusConnection.DBusBusType busType;
94 if (Boolean.TRUE.equals(ns.getBoolean("system"))) {
95 busType = DBusConnection.DBusBusType.SYSTEM;
96 } else {
97 busType = DBusConnection.DBusBusType.SESSION;
98 }
99
100 try (var conn = DBusConnection.getConnection(busType)) {
101 final var signalControl = new DbusSignalControlImpl(c, m -> {
102 m.setIgnoreAttachments(ignoreAttachments);
103 try {
104 final var objectPath = DbusConfig.getObjectPath(m.getSelfNumber());
105 return run(conn, objectPath, m, outputWriter);
106 } catch (DBusException e) {
107 logger.error("Failed to export object", e);
108 return null;
109 }
110 }, DbusConfig.getObjectPath());
111 conn.exportObject(signalControl);
112
113 for (var m : managers) {
114 signalControl.addManager(m);
115 }
116
117 conn.requestBusName(DbusConfig.getBusname());
118 logger.info("DBus daemon running in mulit-account mode");
119
120 signalControl.run();
121 } catch (DBusException | IOException e) {
122 logger.error("Dbus command failed", e);
123 throw new UnexpectedErrorException("Dbus command failed", e);
124 }
125 }
126
127 private Thread run(
128 DBusConnection conn, String objectPath, Manager m, OutputWriter outputWriter
129 ) throws DBusException {
130 final var signal = new DbusSignalImpl(m, conn, objectPath);
131 conn.exportObject(signal);
132 final var initThread = new Thread(signal::initObjects);
133 initThread.start();
134
135 logger.debug("Exported dbus object: " + objectPath);
136
137 final var handler = outputWriter instanceof JsonWriter ? new JsonReceiveMessageHandler(m,
138 (JsonWriter) outputWriter) : new ReceiveMessageHandler(m, (PlainTextWriter) outputWriter);
139 m.addReceiveHandler(handler);
140
141 final var dbusMessageHandler = new DbusReceiveMessageHandler(m, conn, objectPath);
142 m.addReceiveHandler(dbusMessageHandler);
143
144 return initThread;
145 }
146 }