X-Git-Url: https://git.nmode.ca/signal-cli/blobdiff_plain/09decf7916245fe1e031c8925b9f2128a449b150..4b5bfcba8001d23768ad1131b76eaf6325d260d4:/src/main/java/cli/Main.java?ds=sidebyside diff --git a/src/main/java/cli/Main.java b/src/main/java/cli/Main.java index c4a6a4c0..08c7b935 100644 --- a/src/main/java/cli/Main.java +++ b/src/main/java/cli/Main.java @@ -20,15 +20,14 @@ 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.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; @@ -96,20 +95,20 @@ public class Main { System.exit(1); } - TextSecureGroup group = null; + byte[] groupId = 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("Failed to send to group \"" + ns.getString("group") + "\": Unknown group"); System.err.println("Aborting sending."); System.exit(1); } - group = new TextSecureGroup(g.groupId); - recipients = g.members; + groupId = g.groupId; + recipients = new ArrayList<>(g.members); } catch (IOException e) { - System.err.println("Failed to send to grup \"" + ns.getString("group") + "\": " + e.getMessage()); + System.err.println("Failed to send to group \"" + ns.getString("group") + "\": " + e.getMessage()); System.err.println("Aborting sending."); System.exit(1); } @@ -120,23 +119,13 @@ public class Main { if (ns.getBoolean("endsession")) { sendEndSessionMessage(m, recipients); } else { - final List attachments = ns.getList("attachment"); List textSecureAttachments = null; - if (attachments != null) { - textSecureAttachments = new ArrayList<>(attachments.size()); - for (String attachment : attachments) { - 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)); - } catch (IOException e) { - System.err.println("Failed to add attachment \"" + attachment + "\": " + e.getMessage()); - System.err.println("Aborting sending."); - System.exit(1); - } - } + try { + textSecureAttachments = getTextSecureAttachments(ns.getList("attachment")); + } catch (IOException e) { + System.err.println("Failed to add attachment: " + e.getMessage()); + System.err.println("Aborting sending."); + System.exit(1); } String messageText = ns.getString("message"); @@ -150,7 +139,7 @@ public class Main { } } - sendMessage(m, messageText, textSecureAttachments, recipients, group); + sendMessage(m, messageText, textSecureAttachments, recipients, groupId); } break; @@ -179,12 +168,122 @@ public class Main { System.err.println("If you use an Oracle JRE please check if you have unlimited strength crypto enabled, see README"); System.exit(1); } + break; + case "quitGroup": + if (!m.isRegistered()) { + System.err.println("User is not registered."); + System.exit(1); + } + + try { + GroupInfo g = m.getGroupInfo(Base64.decode(ns.getString("group"))); + if (g == null) { + System.err.println("Failed to send to group \"" + ns.getString("group") + "\": Unknown group"); + System.err.println("Aborting sending."); + System.exit(1); + } + + sendQuitGroupMessage(m, new ArrayList<>(g.members), g.groupId); + } catch (IOException e) { + System.err.println("Failed to send to group \"" + ns.getString("group") + "\": " + e.getMessage()); + System.err.println("Aborting sending."); + System.exit(1); + } + break; + case "updateGroup": + if (!m.isRegistered()) { + System.err.println("User is not registered."); + System.exit(1); + } + + try { + GroupInfo g; + if (ns.getString("group") != null) { + g = m.getGroupInfo(Base64.decode(ns.getString("group"))); + if (g == null) { + System.err.println("Failed to send to group \"" + ns.getString("group") + "\": Unknown group"); + System.err.println("Aborting sending."); + System.exit(1); + } + } else { + // Create new group + g = new GroupInfo(Util.getSecretBytes(16)); + g.members.add(m.getUsername()); + System.out.println("Creating new group \"" + Base64.encodeBytes(g.groupId) + "\" …"); + } + + String name = ns.getString("name"); + if (name != null) { + g.name = name; + } + + final List members = ns.getList("member"); + + if (members != null) { + for (String member : members) { + try { + g.members.add(m.canonicalizeNumber(member)); + } catch (InvalidNumberException e) { + System.err.println("Failed to add member \"" + member + "\" to group: " + e.getMessage()); + System.err.println("Aborting…"); + System.exit(1); + } + } + } + + TextSecureGroup.Builder group = TextSecureGroup.newBuilder(TextSecureGroup.Type.UPDATE) + .withId(g.groupId) + .withName(g.name) + .withMembers(new ArrayList<>(g.members)); + + String avatar = ns.getString("avatar"); + if (avatar != null) { + try { + group.withAvatar(createAttachment(avatar)); + // TODO + g.avatarId = 0; + } catch (IOException e) { + System.err.println("Failed to add attachment \"" + avatar + "\": " + e.getMessage()); + System.err.println("Aborting sending."); + System.exit(1); + } + } + + m.setGroupInfo(g); + + sendUpdateGroupMessage(m, group.build()); + } catch (IOException e) { + System.err.println("Failed to send to group \"" + ns.getString("group") + "\": " + e.getMessage()); + System.err.println("Aborting sending."); + System.exit(1); + } + break; } m.save(); System.exit(0); } + private static List getTextSecureAttachments(List attachments) { + private static List getTextSecureAttachments(List attachments) throws IOException { + List textSecureAttachments = null; + if (attachments != null) { + textSecureAttachments = new ArrayList<>(attachments.size()); + for (String attachment : attachments) { + textSecureAttachments.add(createAttachment(attachment)); + } + } + return textSecureAttachments; + } + + private static TextSecureAttachmentStream createAttachment(String attachment) throws IOException { + File attachmentFile = new File(attachment); + InputStream attachmentStream = new FileInputStream(attachmentFile); + final long attachmentSize = attachmentFile.length(); + String mime = Files.probeContentType(Paths.get(attachment)); + return new TextSecureAttachmentStream(attachmentStream, mime, attachmentSize, null); + } + private static Namespace parseArgs(String[] args) { ArgumentParser parser = ArgumentParsers.newArgumentParser("textsecure-cli") .defaultHelp(true) @@ -227,6 +326,22 @@ public class Main { .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) @@ -239,6 +354,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); @@ -251,13 +370,13 @@ public class Main { } private static void sendMessage(Manager m, String messageText, List textSecureAttachments, - List recipients, TextSecureGroup group) { + List recipients, byte[] groupId) { final TextSecureDataMessage.Builder messageBuilder = TextSecureDataMessage.newBuilder().withBody(messageText); if (textSecureAttachments != null) { messageBuilder.withAttachments(textSecureAttachments); } - if (group != null) { - messageBuilder.asGroupMessage(group); + if (groupId != null) { + messageBuilder.asGroupMessage(new TextSecureGroup(groupId)); } TextSecureDataMessage message = messageBuilder.build(); @@ -272,6 +391,29 @@ public class Main { sendMessage(m, message, recipients); } + private static void sendQuitGroupMessage(Manager m, List recipients, byte[] groupId) { + final TextSecureDataMessage.Builder messageBuilder = TextSecureDataMessage.newBuilder(); + TextSecureGroup group = TextSecureGroup.newBuilder(TextSecureGroup.Type.QUIT) + .withId(groupId) + .build(); + + messageBuilder.asGroupMessage(group); + + TextSecureDataMessage message = messageBuilder.build(); + + sendMessage(m, message, recipients); + } + + private static void sendUpdateGroupMessage(Manager m, TextSecureGroup g) { + final TextSecureDataMessage.Builder messageBuilder = TextSecureDataMessage.newBuilder(); + + messageBuilder.asGroupMessage(g); + + TextSecureDataMessage message = messageBuilder.build(); + + sendMessage(m, message, g.getMembers().get()); + } + private static void sendMessage(Manager m, TextSecureDataMessage message, List recipients) { try { m.sendMessage(recipients, message);