var subparsers = parser.addSubparsers().title("subcommands").dest("command");
- final var commands = Commands.getCommands();
- for (var entry : commands.entrySet()) {
- var subparser = subparsers.addParser(entry.getKey());
- entry.getValue().attachToSubparser(subparser);
- }
+ Commands.getCommandSubparserAttachers().forEach((key, value) -> {
+ var subparser = subparsers.addParser(key);
+ value.attachToSubparser(subparser);
+ });
return parser;
}
}
public void init() throws CommandException {
+ var outputType = ns.<OutputType>get("output");
+ var outputWriter = outputType == OutputType.JSON
+ ? new JsonWriter(System.out)
+ : new PlainTextWriterImpl(System.out);
+
var commandKey = ns.getString("command");
- var command = Commands.getCommand(commandKey);
+ var command = Commands.getCommand(commandKey, outputWriter);
if (command == null) {
throw new UserErrorException("Command not implemented!");
}
- var outputType = ns.<OutputType>get("output");
if (!command.getSupportedOutputTypes().contains(outputType)) {
throw new UserErrorException("Command doesn't support output type " + outputType.toString());
}
private final DBusConnection conn;
private final String objectPath;
- public DbusReceiveMessageHandler(Manager m, DBusConnection conn, final String objectPath) {
- super(m);
+ public DbusReceiveMessageHandler(Manager m, PlainTextWriter writer, DBusConnection conn, final String objectPath) {
+ super(m, writer);
this.conn = conn;
this.objectPath = objectPath;
}
private final String objectPath;
- public JsonDbusReceiveMessageHandler(Manager m, DBusConnection conn, final String objectPath) {
- super(m);
+ public JsonDbusReceiveMessageHandler(
+ Manager m, JsonWriter jsonWriter, DBusConnection conn, final String objectPath
+ ) {
+ super(m, jsonWriter);
this.conn = conn;
this.objectPath = objectPath;
}
protected final Manager m;
private final JsonWriter jsonWriter;
- public JsonReceiveMessageHandler(Manager m) {
+ public JsonReceiveMessageHandler(Manager m, JsonWriter jsonWriter) {
this.m = m;
- jsonWriter = new JsonWriter(System.out);
+ this.jsonWriter = jsonWriter;
}
@Override
import java.io.Writer;
import java.nio.charset.StandardCharsets;
-public class JsonWriter {
+public class JsonWriter implements OutputWriter {
private final Writer writer;
private final ObjectMapper objectMapper;
--- /dev/null
+package org.asamk.signal;
+
+public interface OutputWriter {
+
+}
package org.asamk.signal;
-public interface PlainTextWriter {
+import java.util.function.Consumer;
+
+public interface PlainTextWriter extends OutputWriter {
void println(String format, Object... args);
println("");
}
- default void indent(final WriterConsumer subWriter) {
- subWriter.consume(indentedWriter());
- }
-
- interface WriterConsumer {
-
- void consume(PlainTextWriter writer);
+ default void indent(final Consumer<PlainTextWriter> subWriter) {
+ subWriter.accept(indentedWriter());
}
}
public class ReceiveMessageHandler implements Manager.ReceiveMessageHandler {
final Manager m;
+ final PlainTextWriter writer;
- public ReceiveMessageHandler(Manager m) {
+ public ReceiveMessageHandler(Manager m, final PlainTextWriter writer) {
this.m = m;
+ this.writer = writer;
}
@Override
public void handleMessage(SignalServiceEnvelope envelope, SignalServiceContent content, Throwable exception) {
- PlainTextWriter writer = new PlainTextWriterImpl(System.out);
-
if (envelope.hasSource()) {
var source = envelope.getSourceAddress();
writer.println("Envelope from: {} (device: {})", formatContact(source), envelope.getSourceDevice());
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
private final static Logger logger = LoggerFactory.getLogger(AddDeviceCommand.class);
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Link another device to this device. Only works, if this is the master device.");
subparser.addArgument("--uri")
.required(true)
.help("Specify the uri contained in the QR code shown by the new device.");
}
+ public AddDeviceCommand(final OutputWriter outputWriter) {
+ }
+
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
try {
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.manager.Manager;
private final static Logger logger = LoggerFactory.getLogger(BlockCommand.class);
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Block the given contacts or groups (no messages will be received)");
subparser.addArgument("contact").help("Contact number").nargs("*");
subparser.addArgument("-g", "--group").help("Group ID").nargs("*");
}
+ public BlockCommand(final OutputWriter outputWriter) {
+ }
+
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- for (var contact_number : ns.<String>getList("contact")) {
+ for (var contactNumber : ns.<String>getList("contact")) {
try {
- m.setContactBlocked(contact_number, true);
+ m.setContactBlocked(contactNumber, true);
} catch (InvalidNumberException e) {
- logger.warn("Invalid number {}: {}", contact_number, e.getMessage());
+ logger.warn("Invalid number {}: {}", contactNumber, e.getMessage());
} catch (NotMasterDeviceException e) {
throw new UserErrorException("This command doesn't work on linked devices.");
}
package org.asamk.signal.commands;
-import net.sourceforge.argparse4j.inf.Subparser;
-
import org.asamk.signal.OutputType;
import java.util.Set;
public interface Command {
- void attachToSubparser(Subparser subparser);
-
default Set<OutputType> getSupportedOutputTypes() {
return Set.of(OutputType.PLAIN_TEXT);
}
package org.asamk.signal.commands;
+import org.asamk.signal.OutputWriter;
+
+import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class Commands {
- private static final Map<String, Command> commands = new TreeMap<>();
+ private static final Map<String, CommandConstructor> commands = new HashMap<>();
+ private static final Map<String, SubparserAttacher> commandSubparserAttacher = new TreeMap<>();
static {
- addCommand("addDevice", new AddDeviceCommand());
- addCommand("block", new BlockCommand());
- addCommand("daemon", new DaemonCommand());
- addCommand("getUserStatus", new GetUserStatusCommand());
- addCommand("link", new LinkCommand());
- addCommand("listContacts", new ListContactsCommand());
- addCommand("listDevices", new ListDevicesCommand());
- addCommand("listGroups", new ListGroupsCommand());
- addCommand("listIdentities", new ListIdentitiesCommand());
- addCommand("joinGroup", new JoinGroupCommand());
- addCommand("quitGroup", new QuitGroupCommand());
- addCommand("receive", new ReceiveCommand());
- addCommand("register", new RegisterCommand());
- addCommand("removeDevice", new RemoveDeviceCommand());
- addCommand("remoteDelete", new RemoteDeleteCommand());
- addCommand("removePin", new RemovePinCommand());
- addCommand("send", new SendCommand());
- addCommand("sendContacts", new SendContactsCommand());
- addCommand("sendReaction", new SendReactionCommand());
- addCommand("sendSyncRequest", new SendSyncRequestCommand());
- addCommand("sendTyping", new SendTypingCommand());
- addCommand("setPin", new SetPinCommand());
- addCommand("trust", new TrustCommand());
- addCommand("unblock", new UnblockCommand());
- addCommand("unregister", new UnregisterCommand());
- addCommand("updateAccount", new UpdateAccountCommand());
- addCommand("updateContact", new UpdateContactCommand());
- addCommand("updateGroup", new UpdateGroupCommand());
- addCommand("updateProfile", new UpdateProfileCommand());
- addCommand("uploadStickerPack", new UploadStickerPackCommand());
- addCommand("verify", new VerifyCommand());
+ addCommand("addDevice", AddDeviceCommand::new, AddDeviceCommand::attachToSubparser);
+ addCommand("block", BlockCommand::new, BlockCommand::attachToSubparser);
+ addCommand("daemon", DaemonCommand::new, DaemonCommand::attachToSubparser);
+ addCommand("getUserStatus", GetUserStatusCommand::new, GetUserStatusCommand::attachToSubparser);
+ addCommand("link", LinkCommand::new, LinkCommand::attachToSubparser);
+ addCommand("listContacts", ListContactsCommand::new, ListContactsCommand::attachToSubparser);
+ addCommand("listDevices", ListDevicesCommand::new, ListDevicesCommand::attachToSubparser);
+ addCommand("listGroups", ListGroupsCommand::new, ListGroupsCommand::attachToSubparser);
+ addCommand("listIdentities", ListIdentitiesCommand::new, ListIdentitiesCommand::attachToSubparser);
+ addCommand("joinGroup", JoinGroupCommand::new, JoinGroupCommand::attachToSubparser);
+ addCommand("quitGroup", QuitGroupCommand::new, QuitGroupCommand::attachToSubparser);
+ addCommand("receive", ReceiveCommand::new, ReceiveCommand::attachToSubparser);
+ addCommand("register", RegisterCommand::new, RegisterCommand::attachToSubparser);
+ addCommand("removeDevice", RemoveDeviceCommand::new, RemoveDeviceCommand::attachToSubparser);
+ addCommand("remoteDelete", RemoteDeleteCommand::new, RemoteDeleteCommand::attachToSubparser);
+ addCommand("removePin", RemovePinCommand::new, RemovePinCommand::attachToSubparser);
+ addCommand("send", SendCommand::new, SendCommand::attachToSubparser);
+ addCommand("sendContacts", SendContactsCommand::new, SendContactsCommand::attachToSubparser);
+ addCommand("sendReaction", SendReactionCommand::new, SendReactionCommand::attachToSubparser);
+ addCommand("sendSyncRequest", SendSyncRequestCommand::new, SendSyncRequestCommand::attachToSubparser);
+ addCommand("sendTyping", SendTypingCommand::new, SendTypingCommand::attachToSubparser);
+ addCommand("setPin", SetPinCommand::new, SetPinCommand::attachToSubparser);
+ addCommand("trust", TrustCommand::new, TrustCommand::attachToSubparser);
+ addCommand("unblock", UnblockCommand::new, UnblockCommand::attachToSubparser);
+ addCommand("unregister", UnregisterCommand::new, UnregisterCommand::attachToSubparser);
+ addCommand("updateAccount", UpdateAccountCommand::new, UpdateAccountCommand::attachToSubparser);
+ addCommand("updateContact", UpdateContactCommand::new, UpdateContactCommand::attachToSubparser);
+ addCommand("updateGroup", UpdateGroupCommand::new, UpdateGroupCommand::attachToSubparser);
+ addCommand("updateProfile", UpdateProfileCommand::new, UpdateProfileCommand::attachToSubparser);
+ addCommand("uploadStickerPack", UploadStickerPackCommand::new, UploadStickerPackCommand::attachToSubparser);
+ addCommand("verify", VerifyCommand::new, VerifyCommand::attachToSubparser);
}
- public static Map<String, Command> getCommands() {
- return commands;
+ public static Map<String, SubparserAttacher> getCommandSubparserAttachers() {
+ return commandSubparserAttacher;
}
- public static Command getCommand(String commandKey) {
+ public static Command getCommand(String commandKey, OutputWriter outputWriter) {
if (!commands.containsKey(commandKey)) {
return null;
}
- return commands.get(commandKey);
+ return commands.get(commandKey).constructCommand(outputWriter);
+ }
+
+ private static void addCommand(
+ String name, CommandConstructor commandConstructor, SubparserAttacher subparserAttacher
+ ) {
+ commands.put(name, commandConstructor);
+ commandSubparserAttacher.put(name, subparserAttacher);
}
- private static void addCommand(String name, Command command) {
- commands.put(name, command);
+ private interface CommandConstructor {
+
+ Command constructCommand(OutputWriter outputWriter);
}
}
import org.asamk.signal.DbusConfig;
import org.asamk.signal.DbusReceiveMessageHandler;
import org.asamk.signal.JsonDbusReceiveMessageHandler;
+import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputType;
+import org.asamk.signal.OutputWriter;
+import org.asamk.signal.PlainTextWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
import org.asamk.signal.dbus.DbusSignalImpl;
public class DaemonCommand implements MultiLocalCommand {
private final static Logger logger = LoggerFactory.getLogger(DaemonCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Run in daemon mode and provide an experimental dbus interface.");
subparser.addArgument("--system")
.action(Arguments.storeTrue())
.action(Arguments.storeTrue());
}
+ public DaemonCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
@Override
public Set<OutputType> getSupportedOutputTypes() {
return Set.of(OutputType.PLAIN_TEXT, OutputType.JSON);
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- var inJson = ns.get("output") == OutputType.JSON;
-
boolean ignoreAttachments = ns.getBoolean("ignore-attachments");
DBusConnection.DBusBusType busType;
try (var conn = DBusConnection.getConnection(busType)) {
var objectPath = DbusConfig.getObjectPath();
- var t = run(conn, objectPath, m, ignoreAttachments, inJson);
+ var t = run(conn, objectPath, m, ignoreAttachments);
conn.requestBusName(DbusConfig.getBusname());
@Override
public void handleCommand(final Namespace ns, final List<Manager> managers) throws CommandException {
- var inJson = ns.get("output") == OutputType.JSON;
-
boolean ignoreAttachments = ns.getBoolean("ignore-attachments");
DBusConnection.DBusBusType busType;
var receiveThreads = new ArrayList<Thread>();
for (var m : managers) {
var objectPath = DbusConfig.getObjectPath(m.getUsername());
- var thread = run(conn, objectPath, m, ignoreAttachments, inJson);
+ var thread = run(conn, objectPath, m, ignoreAttachments);
receiveThreads.add(thread);
}
}
private Thread run(
- DBusConnection conn, String objectPath, Manager m, boolean ignoreAttachments, boolean inJson
+ DBusConnection conn, String objectPath, Manager m, boolean ignoreAttachments
) throws DBusException {
conn.exportObject(objectPath, new DbusSignalImpl(m));
final var thread = new Thread(() -> {
while (true) {
try {
- m.receiveMessages(1,
- TimeUnit.HOURS,
- false,
- ignoreAttachments,
- inJson
- ? new JsonDbusReceiveMessageHandler(m, conn, objectPath)
- : new DbusReceiveMessageHandler(m, conn, objectPath));
+ final var receiveMessageHandler = outputWriter instanceof JsonWriter
+ ? new JsonDbusReceiveMessageHandler(m, (JsonWriter) outputWriter, conn, objectPath)
+ : new DbusReceiveMessageHandler(m, (PlainTextWriter) outputWriter, conn, objectPath);
+ m.receiveMessages(1, TimeUnit.HOURS, false, ignoreAttachments, receiveMessageHandler);
} catch (IOException e) {
logger.warn("Receiving messages failed, retrying", e);
}
import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputType;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
public class GetUserStatusCommand implements LocalCommand {
private final static Logger logger = LoggerFactory.getLogger(GetUserStatusCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Check if the specified phone number/s have been registered");
subparser.addArgument("number").help("Phone number").nargs("+");
}
+ public GetUserStatusCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
@Override
public Set<OutputType> getSupportedOutputTypes() {
return Set.of(OutputType.PLAIN_TEXT, OutputType.JSON);
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- // Setup the json object mapper
- var inJson = ns.get("output") == OutputType.JSON;
-
// Get a map of registration statuses
Map<String, Boolean> registered;
try {
}
// Output
- if (inJson) {
- final var jsonWriter = new JsonWriter(System.out);
+ if (outputWriter instanceof JsonWriter) {
+ final var jsonWriter = (JsonWriter) outputWriter;
var jsonUserStatuses = registered.entrySet()
.stream()
jsonWriter.write(jsonUserStatuses);
} else {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
for (var entry : registered.entrySet()) {
writer.println("{}: {}", entry.getKey(), entry.getValue());
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
public class JoinGroupCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ private final OutputWriter outputWriter;
+
+ public JoinGroupCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Join a group via an invitation link.");
subparser.addArgument("--uri").required(true).help("Specify the uri with the group invitation link.");
}
}
try {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
final var results = m.joinGroup(linkUrl);
var newGroupId = results.first();
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
public class LinkCommand implements ProvisioningCommand {
private final static Logger logger = LoggerFactory.getLogger(LinkCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public LinkCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Link to an existing device, instead of registering a new number.");
subparser.addArgument("-n", "--name").help("Specify a name to describe this new device.");
}
@Override
public void handleCommand(final Namespace ns, final ProvisioningManager m) throws CommandException {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
var deviceName = ns.getString("name");
if (deviceName == null) {
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.manager.Manager;
public class ListContactsCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ private final OutputWriter outputWriter;
+
+ public ListContactsCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Show a list of known contacts with names.");
}
@Override
public void handleCommand(final Namespace ns, final Manager m) {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
var contacts = m.getContacts();
for (var c : contacts) {
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
public class ListDevicesCommand implements LocalCommand {
private final static Logger logger = LoggerFactory.getLogger(ListDevicesCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public ListDevicesCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Show a list of linked devices.");
}
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
List<Device> devices;
try {
import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputType;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriter;
-import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.manager.Manager;
import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
import java.util.Set;
import java.util.stream.Collectors;
private final static Logger logger = LoggerFactory.getLogger(ListGroupsCommand.class);
+ public static void attachToSubparser(final Subparser subparser) {
+ subparser.help("List group information including names, ids, active status, blocked status and members");
+ 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");
+ }
+
private static Set<String> resolveMembers(Manager m, Set<RecipientId> addresses) {
return addresses.stream()
.map(m::resolveSignalServiceAddress)
}
}
- @Override
- public void attachToSubparser(final Subparser subparser) {
- subparser.help("List group information including names, ids, active status, blocked status and members");
- 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");
+ private final OutputWriter outputWriter;
+
+ public ListGroupsCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
}
@Override
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- if (ns.get("output") == OutputType.JSON) {
- final var jsonWriter = new JsonWriter(System.out);
+ final var groups = m.getGroups();
+
+ if (outputWriter instanceof JsonWriter) {
+ final var jsonWriter = (JsonWriter) outputWriter;
- var jsonGroups = new ArrayList<JsonGroup>();
- for (var group : m.getGroups()) {
+ var jsonGroups = groups.stream().map(group -> {
final var groupInviteLink = group.getGroupInviteLink();
- jsonGroups.add(new JsonGroup(group.getGroupId().toBase64(),
+ return new JsonGroup(group.getGroupId().toBase64(),
group.getTitle(),
group.getDescription(),
group.isMember(m.getSelfRecipientId()),
resolveMembers(m, group.getPendingMembers()),
resolveMembers(m, group.getRequestingMembers()),
resolveMembers(m, group.getAdminMembers()),
- groupInviteLink == null ? null : groupInviteLink.getUrl()));
- }
+ groupInviteLink == null ? null : groupInviteLink.getUrl());
+ }).collect(Collectors.toList());
jsonWriter.write(jsonGroups);
} else {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriter) outputWriter;
boolean detailed = ns.getBoolean("detailed");
- for (var group : m.getGroups()) {
+ for (var group : groups) {
printGroupPlainText(writer, m, group, detailed);
}
}
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
public class ListIdentitiesCommand implements LocalCommand {
private final static Logger logger = LoggerFactory.getLogger(ListIdentitiesCommand.class);
+ private final OutputWriter outputWriter;
+
+ public ListIdentitiesCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
private static void printIdentityFingerprint(PlainTextWriter writer, Manager m, IdentityInfo theirId) {
final SignalServiceAddress address = m.resolveSignalServiceAddress(theirId.getRecipientId());
digits);
}
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("List all known identity keys and their trust status, fingerprint and safety number.");
subparser.addArgument("-n", "--number").help("Only show identity keys for the given phone number.");
}
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
var number = ns.getString("number");
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
public class QuitGroupCommand implements LocalCommand {
private final static Logger logger = LoggerFactory.getLogger(QuitGroupCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public QuitGroupCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Send a quit group message to all group members and remove self from member list.");
subparser.addArgument("-g", "--group").required(true).help("Specify the recipient group ID.");
subparser.addArgument("--delete")
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
final GroupId groupId;
try {
import org.asamk.signal.JsonReceiveMessageHandler;
import org.asamk.signal.JsonWriter;
import org.asamk.signal.OutputType;
+import org.asamk.signal.OutputWriter;
+import org.asamk.signal.PlainTextWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.ReceiveMessageHandler;
import org.asamk.signal.commands.exceptions.CommandException;
public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
private final static Logger logger = LoggerFactory.getLogger(ReceiveCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Query the server for new messages.");
subparser.addArgument("-t", "--timeout")
.type(double.class)
.action(Arguments.storeTrue());
}
+ public ReceiveCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
@Override
public Set<OutputType> getSupportedOutputTypes() {
return Set.of(OutputType.PLAIN_TEXT, OutputType.JSON);
public void handleCommand(
final Namespace ns, final Signal signal, DBusConnection dbusconnection
) throws CommandException {
- var inJson = ns.get("output") == OutputType.JSON;
-
try {
- if (inJson) {
- final var jsonWriter = new JsonWriter(System.out);
+ if (outputWriter instanceof JsonWriter) {
+ final var jsonWriter = (JsonWriter) outputWriter;
dbusconnection.addSigHandler(Signal.MessageReceived.class, signal, messageReceived -> {
var envelope = new JsonMessageEnvelope(messageReceived);
jsonWriter.write(object);
});
} else {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
dbusconnection.addSigHandler(Signal.MessageReceived.class, signal, messageReceived -> {
writer.println("Envelope from: {}", messageReceived.getSender());
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- var inJson = ns.get("output") == OutputType.JSON;
-
double timeout = ns.getDouble("timeout");
var returnOnTimeout = true;
if (timeout < 0) {
}
boolean ignoreAttachments = ns.getBoolean("ignore-attachments");
try {
- final var handler = inJson ? new JsonReceiveMessageHandler(m) : new ReceiveMessageHandler(m);
+ final var handler = outputWriter instanceof JsonWriter ? new JsonReceiveMessageHandler(m,
+ (JsonWriter) outputWriter) : new ReceiveMessageHandler(m, (PlainTextWriter) outputWriter);
m.receiveMessages((long) (timeout * 1000),
TimeUnit.MILLISECONDS,
returnOnTimeout,
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UserErrorException;
public class RegisterCommand implements RegistrationCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public RegisterCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Register a phone number with SMS or voice verification.");
subparser.addArgument("-v", "--voice")
.help("The verification should be done over voice, not SMS.")
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.Signal;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
public class RemoteDeleteCommand implements DbusCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ private final OutputWriter outputWriter;
+
+ public RemoteDeleteCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Remotely delete a previously sent message.");
subparser.addArgument("-t", "--target-timestamp")
.required(true)
final long targetTimestamp = ns.getLong("target-timestamp");
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
byte[] groupId = null;
if (groupIdString != null) {
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.manager.Manager;
public class RemoveDeviceCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public RemoveDeviceCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Remove a linked device.");
subparser.addArgument("-d", "--device-id", "--deviceId")
.type(int.class)
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
public class RemovePinCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public RemovePinCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Remove the registration lock pin.");
}
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.Signal;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
public class SendCommand implements DbusCommand {
private final static Logger logger = LoggerFactory.getLogger(SendCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public SendCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Send a message to another user or group.");
subparser.addArgument("recipient").help("Specify the recipients' phone number.").nargs("*");
final var mutuallyExclusiveGroup = subparser.addMutuallyExclusiveGroup();
attachments = List.of();
}
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
if (groupIdString != null) {
byte[] groupId;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UntrustedKeyErrorException;
public class SendContactsCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public SendContactsCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Send a synchronization message with the local contacts list to all linked devices.");
}
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.Signal;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
public class SendReactionCommand implements DbusCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ private final OutputWriter outputWriter;
+
+ public SendReactionCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Send reaction to a previously received or sent message.");
subparser.addArgument("-g", "--group").help("Specify the recipient group ID.");
subparser.addArgument("recipient").help("Specify the recipients' phone number.").nargs("*");
final var targetAuthor = ns.getString("target-author");
final long targetTimestamp = ns.getLong("target-timestamp");
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
byte[] groupId = null;
if (groupIdString != null) {
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.manager.Manager;
public class SendSyncRequestCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public SendSyncRequestCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Send a synchronization request message to master device (for group, contacts, ...).");
}
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.manager.Manager;
public class SendTypingCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public SendTypingCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help(
"Send typing message to trigger a typing indicator for the recipient. Indicator will be shown for 15seconds unless a typing STOP message is sent first.");
subparser.addArgument("-g", "--group").help("Specify the recipient group ID.");
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
public class SetPinCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public SetPinCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Set a registration lock pin, to prevent others from registering this number.");
subparser.addArgument("registrationLockPin")
.help("The registration lock PIN, that will be required for new registrations (resets after 7 days of inactivity)");
--- /dev/null
+package org.asamk.signal.commands;
+
+import net.sourceforge.argparse4j.inf.Subparser;
+
+public interface SubparserAttacher {
+
+ void attachToSubparser(final Subparser subparser);
+}
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.manager.Manager;
public class TrustCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public TrustCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Set the trust level of a given number.");
subparser.addArgument("number").help("Specify the phone number, for which to set the trust.").required(true);
var mutTrust = subparser.addMutuallyExclusiveGroup();
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UserErrorException;
import org.asamk.signal.manager.Manager;
private final static Logger logger = LoggerFactory.getLogger(UnblockCommand.class);
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public UnblockCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Unblock the given contacts or groups (messages will be received again)");
subparser.addArgument("contact").help("Contact number").nargs("*");
subparser.addArgument("-g", "--group").help("Group ID").nargs("*");
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.manager.Manager;
public class UnregisterCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public UnregisterCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Unregister the current device from the signal server.");
subparser.addArgument("--delete-account")
.help("Delete account completely from server. CAUTION: Only do this if you won't use this number again!")
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.manager.Manager;
public class UpdateAccountCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public UpdateAccountCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Update the account attributes on the signal server.");
}
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UserErrorException;
public class UpdateContactCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public UpdateContactCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Update the details of a given contact");
subparser.addArgument("number").help("Contact number");
subparser.addArgument("-n", "--name").help("New contact name");
import org.asamk.Signal;
import org.asamk.signal.GroupLinkState;
import org.asamk.signal.GroupPermission;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
public class UpdateGroupCommand implements DbusCommand, LocalCommand {
private final static Logger logger = LoggerFactory.getLogger(UpdateGroupCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public UpdateGroupCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Create or update a group.");
subparser.addArgument("-g", "--group").help("Specify the recipient group ID.");
subparser.addArgument("-n", "--name").help("Specify the new group name.");
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
GroupId groupId = null;
final var groupIdString = ns.getString("group");
if (groupIdString != null) {
@Override
public void handleCommand(final Namespace ns, final Signal signal) throws CommandException {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
byte[] groupId = null;
if (ns.getString("group") != null) {
try {
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.manager.Manager;
public class UpdateProfileCommand implements LocalCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public UpdateProfileCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Set a name, about and avatar image for the user profile");
subparser.addArgument("--given-name", "--name").help("New profile (given) name");
subparser.addArgument("--family-name").help("New profile family name (optional)");
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.PlainTextWriterImpl;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
public class UploadStickerPackCommand implements LocalCommand {
private final static Logger logger = LoggerFactory.getLogger(UploadStickerPackCommand.class);
+ private final OutputWriter outputWriter;
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public UploadStickerPackCommand(final OutputWriter outputWriter) {
+ this.outputWriter = outputWriter;
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Upload a new sticker pack, consisting of a manifest file and the stickers images.");
subparser.addArgument("path")
.help("The path of the manifest.json or a zip file containing the sticker pack you wish to upload.");
@Override
public void handleCommand(final Namespace ns, final Manager m) throws CommandException {
- final var writer = new PlainTextWriterImpl(System.out);
+ final var writer = (PlainTextWriterImpl) outputWriter;
var path = new File(ns.getString("path"));
try {
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
+import org.asamk.signal.OutputWriter;
import org.asamk.signal.commands.exceptions.CommandException;
import org.asamk.signal.commands.exceptions.IOErrorException;
import org.asamk.signal.commands.exceptions.UnexpectedErrorException;
public class VerifyCommand implements RegistrationCommand {
- @Override
- public void attachToSubparser(final Subparser subparser) {
+ public VerifyCommand(final OutputWriter outputWriter) {
+ }
+
+ public static void attachToSubparser(final Subparser subparser) {
subparser.help("Verify the number using the code received via SMS or voice.");
subparser.addArgument("verificationCode").help("The verification code you received via sms or voice call.");
subparser.addArgument("-p", "--pin").help("The registration lock PIN, that was set by the user (Optional)");