import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class Main {
ts = (Signal) dBusConn.getRemoteObject(
SIGNAL_BUSNAME, SIGNAL_OBJECTPATH,
Signal.class);
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Missing native library dependency for dbus service: " + e.getMessage());
+ return 1;
} catch (DBusException e) {
e.printStackTrace();
if (dBusConn != null) {
ts = m;
if (m.userExists()) {
try {
- m.load();
+ m.init();
} catch (Exception e) {
System.err.println("Error loading state file \"" + m.getFileName() + "\": " + e.getMessage());
return 2;
return 3;
}
break;
+ case "unregister":
+ if (dBusConn != null) {
+ System.err.println("unregister is not yet implemented via dbus");
+ return 1;
+ }
+ if (!m.isRegistered()) {
+ System.err.println("User is not registered.");
+ return 1;
+ }
+ try {
+ m.unregister();
+ } catch (IOException e) {
+ System.err.println("Unregister error: " + e.getMessage());
+ return 3;
+ }
+ break;
+ case "updateAccount":
+ if (dBusConn != null) {
+ System.err.println("updateAccount is not yet implemented via dbus");
+ return 1;
+ }
+ if (!m.isRegistered()) {
+ System.err.println("User is not registered.");
+ return 1;
+ }
+ try {
+ m.updateAccountAttributes();
+ } catch (IOException e) {
+ System.err.println("UpdateAccount error: " + e.getMessage());
+ return 3;
+ }
+ break;
case "verify":
if (dBusConn != null) {
System.err.println("verify is not yet implemented via dbus");
} catch (IOException e) {
System.err.println("Link request error: " + e.getMessage());
return 3;
+ } catch (AssertionError e) {
+ handleAssertionError(e);
+ return 1;
} catch (InvalidKeyException e) {
e.printStackTrace();
return 2;
} catch (InvalidKeyException e) {
e.printStackTrace();
return 2;
+ } catch (AssertionError e) {
+ handleAssertionError(e);
+ return 1;
} catch (URISyntaxException e) {
e.printStackTrace();
return 2;
for (DeviceInfo d : devices) {
System.out.println("Device " + d.getId() + (d.getId() == m.getDeviceId() ? " (this device)" : "") + ":");
System.out.println(" Name: " + d.getName());
- System.out.println(" Created: " + d.getCreated());
- System.out.println(" Last seen: " + d.getLastSeen());
+ System.out.println(" Created: " + formatTimestamp(d.getCreated()));
+ System.out.println(" Last seen: " + formatTimestamp(d.getLastSeen()));
}
} catch (IOException e) {
e.printStackTrace();
System.out.println();
}
});
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Missing native library dependency for dbus service: " + e.getMessage());
+ return 1;
} catch (DBusException e) {
e.printStackTrace();
return 1;
System.err.println("User is not registered.");
return 1;
}
- int timeout = 5;
- if (ns.getInt("timeout") != null) {
- timeout = ns.getInt("timeout");
+ double timeout = 5;
+ if (ns.getDouble("timeout") != null) {
+ timeout = ns.getDouble("timeout");
}
boolean returnOnTimeout = true;
if (timeout < 0) {
returnOnTimeout = false;
timeout = 3600;
}
+ boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
try {
- m.receiveMessages(timeout, returnOnTimeout, new ReceiveMessageHandler(m));
+ m.receiveMessages((long) (timeout * 1000), TimeUnit.MILLISECONDS, returnOnTimeout, ignoreAttachments, new ReceiveMessageHandler(m));
} catch (IOException e) {
System.err.println("Error while receiving messages: " + e.getMessage());
return 3;
if (ns.get("number") == null) {
for (Map.Entry<String, List<JsonIdentityKeyStore.Identity>> keys : m.getIdentities().entrySet()) {
for (JsonIdentityKeyStore.Identity id : keys.getValue()) {
- System.out.println(String.format("%s: %s Added: %s Fingerprint: %s", keys.getKey(), id.trustLevel, id.added, Hex.toStringCondensed(id.getFingerprint())));
+ printIdentityFingerprint(m, keys.getKey(), id);
}
}
} else {
String number = ns.getString("number");
for (JsonIdentityKeyStore.Identity id : m.getIdentities(number)) {
- System.out.println(String.format("%s: %s Added: %s Fingerprint: %s", number, id.trustLevel, id.added, Hex.toStringCondensed(id.getFingerprint())));
+ printIdentityFingerprint(m, number, id);
}
}
break;
} else {
String fingerprint = ns.getString("verified_fingerprint");
if (fingerprint != null) {
- byte[] fingerprintBytes;
- try {
- fingerprintBytes = Hex.toByteArray(fingerprint.replaceAll(" ", "").toLowerCase(Locale.ROOT));
- } catch (Exception e) {
- System.err.println("Failed to parse the fingerprint, make sure the fingerprint is a correctly encoded hex string without additional characters.");
- return 1;
- }
- boolean res = m.trustIdentityVerified(number, fingerprintBytes);
- if (!res) {
- System.err.println("Failed to set the trust for the fingerprint of this number, make sure the number and the fingerprint are correct.");
+ fingerprint = fingerprint.replaceAll(" ", "");
+ if (fingerprint.length() == 66) {
+ byte[] fingerprintBytes;
+ try {
+ fingerprintBytes = Hex.toByteArray(fingerprint.toLowerCase(Locale.ROOT));
+ } catch (Exception e) {
+ System.err.println("Failed to parse the fingerprint, make sure the fingerprint is a correctly encoded hex string without additional characters.");
+ return 1;
+ }
+ boolean res = m.trustIdentityVerified(number, fingerprintBytes);
+ if (!res) {
+ System.err.println("Failed to set the trust for the fingerprint of this number, make sure the number and the fingerprint are correct.");
+ return 1;
+ }
+ } else if (fingerprint.length() == 60) {
+ boolean res = m.trustIdentityVerifiedSafetyNumber(number, fingerprint);
+ if (!res) {
+ System.err.println("Failed to set the trust for the safety number of this phone number, make sure the phone number and the safety number are correct.");
+ return 1;
+ }
+ } else {
+ System.err.println("Fingerprint has invalid format, either specify the old hex fingerprint or the new safety number");
return 1;
}
} else {
conn = DBusConnection.getConnection(busType);
conn.exportObject(SIGNAL_OBJECTPATH, m);
conn.requestBusName(SIGNAL_BUSNAME);
+ } catch (UnsatisfiedLinkError e) {
+ System.err.println("Missing native library dependency for dbus service: " + e.getMessage());
+ return 1;
} catch (DBusException e) {
e.printStackTrace();
return 2;
}
+ ignoreAttachments = ns.getBoolean("ignore_attachments");
try {
- m.receiveMessages(3600, false, new DbusReceiveMessageHandler(m, conn));
+ m.receiveMessages(1, TimeUnit.HOURS, false, ignoreAttachments, new DbusReceiveMessageHandler(m, conn));
} catch (IOException e) {
System.err.println("Error while receiving messages: " + e.getMessage());
return 3;
}
}
+ private static void printIdentityFingerprint(Manager m, String theirUsername, JsonIdentityKeyStore.Identity theirId) {
+ String digits = formatSafetyNumber(m.computeSafetyNumber(theirUsername, theirId.identityKey));
+ System.out.println(String.format("%s: %s Added: %s Fingerprint: %s Safety Number: %s", theirUsername,
+ theirId.trustLevel, theirId.added, Hex.toStringCondensed(theirId.getFingerprint()), digits));
+ }
+
+ private static String formatSafetyNumber(String digits) {
+ final int partCount = 12;
+ int partSize = digits.length() / partCount;
+ StringBuilder f = new StringBuilder(digits.length() + partCount);
+ for (int i = 0; i < partCount; i++) {
+ f.append(digits.substring(i * partSize, (i * partSize) + partSize)).append(" ");
+ }
+ return f.toString();
+ }
+
private static void handleGroupNotFoundException(GroupNotFoundException e) {
System.err.println("Failed to send to group: " + e.getMessage());
System.err.println("Aborting sending.");
.help("The verification should be done over voice, not sms.")
.action(Arguments.storeTrue());
+ Subparser parserUnregister = subparsers.addParser("unregister");
+ parserUnregister.help("Unregister the current device from the signal server.");
+
+ Subparser parserUpdateAccount = subparsers.addParser("updateAccount");
+ parserUpdateAccount.help("Update the account attributes on the signal server.");
+
Subparser parserVerify = subparsers.addParser("verify");
parserVerify.addArgument("verificationCode")
.help("The verification code you received via sms or voice call.");
Subparser parserReceive = subparsers.addParser("receive");
parserReceive.addArgument("-t", "--timeout")
- .type(int.class)
+ .type(double.class)
.help("Number of seconds to wait for new messages (negative values disable timeout)");
+ parserReceive.addArgument("--ignore-attachments")
+ .help("Don’t download attachments of received messages.")
+ .action(Arguments.storeTrue());
Subparser parserDaemon = subparsers.addParser("daemon");
parserDaemon.addArgument("--system")
.action(Arguments.storeTrue())
.help("Use DBus system bus instead of user bus.");
+ parserDaemon.addArgument("--ignore-attachments")
+ .help("Don’t download attachments of received messages.")
+ .action(Arguments.storeTrue());
try {
Namespace ns = parser.parseArgs(args);