X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/2c6796e3ce830b0285223baa11ec5e8553b4d52f..9a1b348ed2d31ac63bf0ef6f64ad92a2f16d173c:/src/main/java/cli/Main.java diff --git a/src/main/java/cli/Main.java b/src/main/java/cli/Main.java index 199ea1eb..64bdfae3 100644 --- a/src/main/java/cli/Main.java +++ b/src/main/java/cli/Main.java @@ -20,25 +20,19 @@ import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.inf.*; import org.apache.commons.io.IOUtils; -import org.whispersystems.libaxolotl.InvalidMessageException; +import org.freedesktop.dbus.DBusConnection; +import org.freedesktop.dbus.exceptions.DBusException; import org.whispersystems.textsecure.api.crypto.UntrustedIdentityException; import org.whispersystems.textsecure.api.messages.*; import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage; -import org.whispersystems.textsecure.api.push.TextSecureAddress; import org.whispersystems.textsecure.api.push.exceptions.EncapsulatedExceptions; import org.whispersystems.textsecure.api.push.exceptions.NetworkFailureException; import org.whispersystems.textsecure.api.push.exceptions.UnregisteredUserException; -import org.whispersystems.textsecure.api.util.InvalidNumberException; +import org.whispersystems.textsecure.api.util.PhoneNumberFormatter; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; import java.security.Security; -import java.util.ArrayList; -import java.util.List; public class Main { @@ -95,57 +89,56 @@ public class Main { System.err.println("User is not registered."); System.exit(1); } - String messageText = ns.getString("message"); - if (messageText == null) { - try { - messageText = IOUtils.toString(System.in); - } catch (IOException e) { - System.err.println("Failed to read message from stdin: " + e.getMessage()); + + if (ns.getBoolean("endsession")) { + if (ns.getList("recipient") == null) { + System.err.println("No recipients given"); System.err.println("Aborting sending."); System.exit(1); } - } - - final List attachments = ns.getList("attachment"); - List textSecureAttachments = null; - if (attachments != null) { - textSecureAttachments = new ArrayList<>(attachments.size()); - for (String attachment : attachments) { + try { + m.sendEndSessionMessage(ns.getList("recipient")); + } catch (IOException e) { + handleIOException(e); + } catch (EncapsulatedExceptions e) { + handleEncapsulatedExceptions(e); + } catch (AssertionError e) { + handleAssertionError(e); + } + } else { + String messageText = ns.getString("message"); + if (messageText == null) { try { - File attachmentFile = new File(attachment); - InputStream attachmentStream = new FileInputStream(attachmentFile); - final long attachmentSize = attachmentFile.length(); - String mime = Files.probeContentType(Paths.get(attachment)); - textSecureAttachments.add(new TextSecureAttachmentStream(attachmentStream, mime, attachmentSize, null)); + messageText = IOUtils.toString(System.in); } catch (IOException e) { - System.err.println("Failed to add attachment \"" + attachment + "\": " + e.getMessage()); + System.err.println("Failed to read message from stdin: " + e.getMessage()); System.err.println("Aborting sending."); System.exit(1); } } - } - TextSecureGroup group = null; - List recipients = null; - if (ns.getString("group") != null) { + try { - GroupInfo g = m.getGroupInfo(Base64.decode(ns.getString("group"))); - if (g == null) { - System.err.println("Failed to send to grup \"" + ns.getString("group") + "\": Unknown group"); - System.err.println("Aborting sending."); - System.exit(1); + if (ns.getString("group") != null) { + byte[] groupId = decodeGroupId(ns.getString("group")); + m.sendGroupMessage(messageText, ns.getList("attachment"), groupId); + } else { + m.sendMessage(messageText, ns.getList("attachment"), ns.getList("recipient")); } - group = new TextSecureGroup(g.groupId); - recipients = g.members; } catch (IOException e) { - System.err.println("Failed to send to grup \"" + ns.getString("group") + "\": " + e.getMessage()); + handleIOException(e); + } catch (EncapsulatedExceptions e) { + handleEncapsulatedExceptions(e); + } catch (AssertionError e) { + handleAssertionError(e); + } catch (GroupNotFoundException e) { + handleGroupNotFoundException(e); + } catch (AttachmentInvalidException e) { + System.err.println("Failed to add attachment (\"" + e.getAttachment() + "\"): " + e.getMessage()); System.err.println("Aborting sending."); System.exit(1); } - } else { - recipients = ns.getList("recipient"); } - sendMessage(m, messageText, textSecureAttachments, recipients, group); break; case "receive": if (!m.isRegistered()) { @@ -164,20 +157,110 @@ public class Main { try { m.receiveMessages(timeout, returnOnTimeout, new ReceiveMessageHandler(m)); } catch (IOException e) { - System.err.println("Error while receiving message: " + e.getMessage()); + System.err.println("Error while receiving messages: " + e.getMessage()); System.exit(3); } catch (AssertionError e) { - System.err.println("Failed to receive message (Assertion): " + e.getMessage()); - System.err.println(e.getStackTrace()); - System.err.println("If you use an Oracle JRE please check if you have unlimited strength crypto enabled, see README"); + handleAssertionError(e); + } + break; + case "quitGroup": + if (!m.isRegistered()) { + System.err.println("User is not registered."); System.exit(1); } + + try { + m.sendQuitGroupMessage(decodeGroupId(ns.getString("group"))); + } catch (IOException e) { + handleIOException(e); + } catch (EncapsulatedExceptions e) { + handleEncapsulatedExceptions(e); + } catch (AssertionError e) { + handleAssertionError(e); + } catch (GroupNotFoundException e) { + handleGroupNotFoundException(e); + } + + break; + case "updateGroup": + if (!m.isRegistered()) { + System.err.println("User is not registered."); + System.exit(1); + } + + try { + byte[] groupId = null; + if (ns.getString("group") != null) { + groupId = decodeGroupId(ns.getString("group")); + } + byte[] newGroupId = m.sendUpdateGroupMessage(groupId, ns.getString("name"), ns.getList("member"), ns.getString("avatar")); + if (groupId == null) { + System.out.println("Creating new group \"" + Base64.encodeBytes(newGroupId) + "\" …"); + } + } catch (IOException e) { + handleIOException(e); + } catch (AttachmentInvalidException e) { + System.err.println("Failed to add avatar attachment (\"" + e.getAttachment() + ") for group\": " + e.getMessage()); + System.err.println("Aborting sending."); + System.exit(1); + } catch (GroupNotFoundException e) { + handleGroupNotFoundException(e); + } catch (EncapsulatedExceptions e) { + handleEncapsulatedExceptions(e); + } + + break; + case "daemon": + if (!m.isRegistered()) { + System.err.println("User is not registered."); + System.exit(1); + } + try { + int busType; + if (ns.getBoolean("system")) { + busType = DBusConnection.SYSTEM; + } else { + busType = DBusConnection.SESSION; + } + DBusConnection conn = DBusConnection.getConnection(busType); + conn.requestBusName("org.asamk.TextSecure"); + conn.exportObject("/org/asamk/TextSecure", m); + } catch (DBusException e) { + e.printStackTrace(); + System.exit(3); + } + try { + m.receiveMessages(3600, false, new ReceiveMessageHandler(m)); + } catch (IOException e) { + System.err.println("Error while receiving messages: " + e.getMessage()); + System.exit(3); + } catch (AssertionError e) { + handleAssertionError(e); + } + break; } m.save(); System.exit(0); } + private static void handleGroupNotFoundException(GroupNotFoundException e) { + System.err.println("Failed to send to group \"" + Base64.encodeBytes(e.getGroupId()) + "\": Unknown group"); + System.err.println("Aborting sending."); + System.exit(1); + } + + private static byte[] decodeGroupId(String groupId) { + try { + return Base64.decode(groupId); + } catch (IOException e) { + System.err.println("Failed to decode groupId (must be base64) \"" + groupId + "\": " + e.getMessage()); + System.err.println("Aborting sending."); + System.exit(1); + return null; + } + } + private static Namespace parseArgs(String[] args) { ArgumentParser parser = ArgumentParsers.newArgumentParser("textsecure-cli") .defaultHelp(true) @@ -216,12 +299,36 @@ public class Main { parserSend.addArgument("-a", "--attachment") .nargs("*") .help("Add file as attachment"); + parserSend.addArgument("-e", "--endsession") + .help("Clear session state and send end session message.") + .action(Arguments.storeTrue()); + + Subparser parserLeaveGroup = subparsers.addParser("quitGroup"); + parserLeaveGroup.addArgument("-g", "--group") + .required(true) + .help("Specify the recipient group ID."); + + Subparser parserUpdateGroup = subparsers.addParser("updateGroup"); + parserUpdateGroup.addArgument("-g", "--group") + .help("Specify the recipient group ID."); + parserUpdateGroup.addArgument("-n", "--name") + .help("Specify the new group name."); + parserUpdateGroup.addArgument("-a", "--avatar") + .help("Specify a new group avatar image file"); + parserUpdateGroup.addArgument("-m", "--member") + .nargs("*") + .help("Specify one or more members to add to the group"); Subparser parserReceive = subparsers.addParser("receive"); parserReceive.addArgument("-t", "--timeout") .type(int.class) .help("Number of seconds to wait for new messages (negative values disable timeout)"); + Subparser parserDaemon = subparsers.addParser("daemon"); + parserDaemon.addArgument("--system") + .action(Arguments.storeTrue()) + .help("Use DBus system bus instead of user bus."); + try { Namespace ns = parser.parseArgs(args); if (ns.getString("username") == null) { @@ -229,6 +336,10 @@ public class Main { System.err.println("You need to specify a username (phone number)"); System.exit(2); } + if (!PhoneNumberFormatter.isValidNumber(ns.getString("username"))) { + System.err.println("Invalid username (phone number), make sure you include the country code."); + System.exit(2); + } if (ns.getList("recipient") != null && !ns.getList("recipient").isEmpty() && ns.getString("group") != null) { System.err.println("You cannot specify recipients by phone number and groups a the same time"); System.exit(2); @@ -240,40 +351,30 @@ public class Main { } } - private static void sendMessage(Manager m, String messageText, List textSecureAttachments, - List recipients, TextSecureGroup group) { - final TextSecureDataMessage.Builder messageBuilder = TextSecureDataMessage.newBuilder().withBody(messageText); - if (textSecureAttachments != null) { - messageBuilder.withAttachments(textSecureAttachments); + private static void handleAssertionError(AssertionError e) { + System.err.println("Failed to send/receive message (Assertion): " + e.getMessage()); + System.err.println(e.getStackTrace()); + System.err.println("If you use an Oracle JRE please check if you have unlimited strength crypto enabled, see README"); + System.exit(1); + } + + private static void handleEncapsulatedExceptions(EncapsulatedExceptions e) { + System.err.println("Failed to send (some) messages:"); + for (NetworkFailureException n : e.getNetworkExceptions()) { + System.err.println("Network failure for \"" + n.getE164number() + "\": " + n.getMessage()); } - if (group != null) { - messageBuilder.asGroupMessage(group); + for (UnregisteredUserException n : e.getUnregisteredUserExceptions()) { + System.err.println("Unregistered user \"" + n.getE164Number() + "\": " + n.getMessage()); } - TextSecureDataMessage message = messageBuilder.build(); - - try { - m.sendMessage(recipients, message); - } catch (IOException e) { - System.err.println("Failed to send message: " + e.getMessage()); - } catch (EncapsulatedExceptions e) { - System.err.println("Failed to send (some) messages:"); - for (NetworkFailureException n : e.getNetworkExceptions()) { - System.err.println("Network failure for \"" + n.getE164number() + "\": " + n.getMessage()); - } - for (UnregisteredUserException n : e.getUnregisteredUserExceptions()) { - System.err.println("Unregistered user \"" + n.getE164Number() + "\": " + n.getMessage()); - } - for (UntrustedIdentityException n : e.getUntrustedIdentityExceptions()) { - System.err.println("Untrusted Identity for \"" + n.getE164Number() + "\": " + n.getMessage()); - } - } catch (AssertionError e) { - System.err.println("Failed to send message (Assertion): " + e.getMessage()); - System.err.println(e.getStackTrace()); - System.err.println("If you use an Oracle JRE please check if you have unlimited strength crypto enabled, see README"); - System.exit(1); + for (UntrustedIdentityException n : e.getUntrustedIdentityExceptions()) { + System.err.println("Untrusted Identity for \"" + n.getE164Number() + "\": " + n.getMessage()); } } + private static void handleIOException(IOException e) { + System.err.println("Failed to send message: " + e.getMessage()); + } + private static class ReceiveMessageHandler implements Manager.ReceiveMessageHandler { final Manager m;