diff --git a/pom.xml b/pom.xml
index baf81f3f1..8669217a5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
org.whispersystems.textsecure
TextSecureServer
- 0.71
+ 0.75
0.9.0-rc3
diff --git a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
index ea1980034..74ce4e0a2 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java
@@ -18,6 +18,8 @@ package org.whispersystems.textsecuregcm;
import com.codahale.metrics.SharedMetricRegistries;
import com.codahale.metrics.graphite.GraphiteReporter;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.google.common.base.Optional;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -148,6 +150,8 @@ public class WhisperServerService extends Application getAuthenticatedDevice() {
- return Optional.of(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, System.currentTimeMillis(), System.currentTimeMillis()));
+ return Optional.of(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
}
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java b/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java
index 219eb86b6..5340ecf24 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/providers/RedisHealthCheck.java
@@ -31,9 +31,7 @@ public class RedisHealthCheck extends HealthCheck {
@Override
protected Result check() throws Exception {
- Jedis client = clientPool.getResource();
-
- try {
+ try (Jedis client = clientPool.getResource()) {
client.set("HEALTH", "test");
if (!"test".equals(client.get("HEALTH"))) {
@@ -41,8 +39,6 @@ public class RedisHealthCheck extends HealthCheck {
}
return Result.healthy();
- } finally {
- clientPool.returnResource(client);
}
}
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/push/FeedbackHandler.java b/src/main/java/org/whispersystems/textsecuregcm/push/FeedbackHandler.java
index 52ac44051..e76c7bbcb 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/push/FeedbackHandler.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/push/FeedbackHandler.java
@@ -82,6 +82,7 @@ public class FeedbackHandler implements Managed, Runnable {
device.get().setGcmId(event.getCanonicalId());
} else {
device.get().setGcmId(null);
+ device.get().setFetchesMessages(false);
}
accountsManager.update(account.get());
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java b/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java
index 15fa31716..c9cee94ee 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/storage/Account.java
@@ -71,7 +71,7 @@ public class Account {
}
public void removeDevice(long deviceId) {
- this.devices.remove(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, 0, 0));
+ this.devices.remove(new Device(deviceId, null, null, null, null, null, null, null, false, 0, null, 0, 0, false));
}
public Set getDevices() {
@@ -92,6 +92,16 @@ public class Account {
return Optional.absent();
}
+ public boolean isVoiceSupported() {
+ for (Device device : devices) {
+ if (device.isActive() && device.isVoiceSupported()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public boolean isActive() {
return
getMasterDevice().isPresent() &&
diff --git a/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java b/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java
index 085502419..13f260c47 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/storage/Accounts.java
@@ -16,8 +16,6 @@
*/
package org.whispersystems.textsecuregcm.storage;
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.skife.jdbi.v2.SQLStatement;
diff --git a/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java b/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java
index 04a22f52f..7a552eb10 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/storage/AccountsManager.java
@@ -100,7 +100,7 @@ public class AccountsManager {
private void updateDirectory(Account account) {
if (account.isActive()) {
byte[] token = Util.getContactToken(account.getNumber());
- ClientContact clientContact = new ClientContact(token, null);
+ ClientContact clientContact = new ClientContact(token, null, account.isVoiceSupported());
directory.add(clientContact);
} else {
directory.remove(account.getNumber());
diff --git a/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java b/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java
index 97f524978..65e4a0ff6 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/storage/Device.java
@@ -70,13 +70,16 @@ public class Device {
@JsonProperty
private long created;
+ @JsonProperty
+ private boolean voice;
+
public Device() {}
public Device(long id, String name, String authToken, String salt,
String signalingKey, String gcmId, String apnId,
String voipApnId, boolean fetchesMessages,
int registrationId, SignedPreKey signedPreKey,
- long lastSeen, long created)
+ long lastSeen, long created, boolean voice)
{
this.id = id;
this.name = name;
@@ -91,6 +94,7 @@ public class Device {
this.signedPreKey = signedPreKey;
this.lastSeen = lastSeen;
this.created = created;
+ this.voice = voice;
}
public String getApnId() {
@@ -157,6 +161,14 @@ public class Device {
this.name = name;
}
+ public boolean isVoiceSupported() {
+ return voice;
+ }
+
+ public void setVoiceSupported(boolean voice) {
+ this.voice = voice;
+ }
+
public void setAuthenticationCredentials(AuthenticationCredentials credentials) {
this.authToken = credentials.getHashedAuthenticationToken();
this.salt = credentials.getSalt();
diff --git a/src/main/java/org/whispersystems/textsecuregcm/storage/DirectoryManager.java b/src/main/java/org/whispersystems/textsecuregcm/storage/DirectoryManager.java
index bf40ed068..97e46ea0a 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/storage/DirectoryManager.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/storage/DirectoryManager.java
@@ -61,9 +61,9 @@ public class DirectoryManager {
}
public void remove(byte[] token) {
- Jedis jedis = redisPool.getResource();
- jedis.hdel(DIRECTORY_KEY, token);
- redisPool.returnResource(jedis);
+ try (Jedis jedis = redisPool.getResource()) {
+ jedis.hdel(DIRECTORY_KEY, token);
+ }
}
public void remove(BatchOperationHandle handle, byte[] token) {
@@ -72,7 +72,7 @@ public class DirectoryManager {
}
public void add(ClientContact contact) {
- TokenValue tokenValue = new TokenValue(contact.getRelay());
+ TokenValue tokenValue = new TokenValue(contact.getRelay(), contact.isVoice());
try (Jedis jedis = redisPool.getResource()) {
jedis.hset(DIRECTORY_KEY, contact.getToken(), objectMapper.writeValueAsBytes(tokenValue));
@@ -84,7 +84,7 @@ public class DirectoryManager {
public void add(BatchOperationHandle handle, ClientContact contact) {
try {
Pipeline pipeline = handle.pipeline;
- TokenValue tokenValue = new TokenValue(contact.getRelay());
+ TokenValue tokenValue = new TokenValue(contact.getRelay(), contact.isVoice());
pipeline.hset(DIRECTORY_KEY, contact.getToken(), objectMapper.writeValueAsBytes(tokenValue));
} catch (JsonProcessingException e) {
@@ -106,7 +106,7 @@ public class DirectoryManager {
}
TokenValue tokenValue = objectMapper.readValue(result, TokenValue.class);
- return Optional.of(new ClientContact(token, tokenValue.relay));
+ return Optional.of(new ClientContact(token, tokenValue.relay, tokenValue.voice));
} catch (IOException e) {
logger.warn("JSON Error", e);
return Optional.absent();
@@ -133,7 +133,7 @@ public class DirectoryManager {
try {
if (pair.second().get() != null) {
TokenValue tokenValue = objectMapper.readValue(pair.second().get(), TokenValue.class);
- ClientContact clientContact = new ClientContact(pair.first(), tokenValue.relay);
+ ClientContact clientContact = new ClientContact(pair.first(), tokenValue.relay, tokenValue.voice);
results.add(clientContact);
}
@@ -175,10 +175,14 @@ public class DirectoryManager {
@JsonProperty(value = "r")
private String relay;
+ @JsonProperty(value = "v")
+ private boolean voice;
+
public TokenValue() {}
- public TokenValue(String relay) {
+ public TokenValue(String relay, boolean voice) {
this.relay = relay;
+ this.voice = voice;
}
}
@@ -201,7 +205,7 @@ public class DirectoryManager {
}
TokenValue tokenValue = objectMapper.readValue(result, TokenValue.class);
- return Optional.of(new ClientContact(token, tokenValue.relay));
+ return Optional.of(new ClientContact(token, tokenValue.relay, tokenValue.voice));
}
}
diff --git a/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryUpdater.java b/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryUpdater.java
index 7b5d3cf96..d674cb469 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryUpdater.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/workers/DirectoryUpdater.java
@@ -26,7 +26,6 @@ import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.DirectoryManager;
import org.whispersystems.textsecuregcm.storage.DirectoryManager.BatchOperationHandle;
-import org.whispersystems.textsecuregcm.util.Base64;
import org.whispersystems.textsecuregcm.util.Util;
import java.io.IOException;
@@ -73,7 +72,7 @@ public class DirectoryUpdater {
for (Account account : accounts) {
if (account.isActive()) {
byte[] token = Util.getContactToken(account.getNumber());
- ClientContact clientContact = new ClientContact(token, null);
+ ClientContact clientContact = new ClientContact(token, null, account.isVoiceSupported());
directory.add(batchOperation, clientContact);
contactsAdded++;
diff --git a/src/main/java/org/whispersystems/textsecuregcm/workers/TrimMessagesCommand.java b/src/main/java/org/whispersystems/textsecuregcm/workers/TrimMessagesCommand.java
index 727fa7ff2..979c794e4 100644
--- a/src/main/java/org/whispersystems/textsecuregcm/workers/TrimMessagesCommand.java
+++ b/src/main/java/org/whispersystems/textsecuregcm/workers/TrimMessagesCommand.java
@@ -5,10 +5,7 @@ import org.skife.jdbi.v2.DBI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.WhisperServerConfiguration;
-import org.whispersystems.textsecuregcm.storage.Accounts;
-import org.whispersystems.textsecuregcm.storage.Keys;
import org.whispersystems.textsecuregcm.storage.Messages;
-import org.whispersystems.textsecuregcm.storage.PendingAccounts;
import java.util.concurrent.TimeUnit;
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java
index dae140b50..7c563bdd2 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/AccountControllerTest.java
@@ -19,6 +19,7 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.MessagesManager;
import org.whispersystems.textsecuregcm.storage.PendingAccountsManager;
import org.whispersystems.textsecuregcm.tests.util.AuthHelper;
+import org.whispersystems.textsecuregcm.util.SystemMapper;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
@@ -47,6 +48,7 @@ public class AccountControllerTest {
public final ResourceTestRule resources = ResourceTestRule.builder()
.addProvider(AuthHelper.getAuthFilter())
.addProvider(new AuthValueFactoryProvider.Binder())
+ .setMapper(SystemMapper.getMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new AccountController(pendingAccountsManager,
accountsManager,
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java
index 9f33cda73..9aa0752e2 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/DeviceControllerTest.java
@@ -135,7 +135,7 @@ public class DeviceControllerTest {
.target("/v1/devices/5678901")
.request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_NUMBER, "password1"))
- .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 1234, "this is a really long name that is longer than 80 characters"),
+ .put(Entity.entity(new AccountAttributes("keykeykeykey", false, 1234, "this is a really long name that is longer than 80 characters", true),
MediaType.APPLICATION_JSON_TYPE));
assertEquals(response.getStatus(), 422);
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java
index 834141c72..9c1616bbe 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/FederatedControllerTest.java
@@ -79,12 +79,12 @@ public class FederatedControllerTest {
@Before
public void setup() throws Exception {
Set singleDeviceList = new HashSet() {{
- add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, null, System.currentTimeMillis(), System.currentTimeMillis()));
+ add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
}};
Set multiDeviceList = new HashSet() {{
- add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, null, System.currentTimeMillis(), System.currentTimeMillis()));
- add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, null, System.currentTimeMillis(), System.currentTimeMillis()));
+ add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
+ add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
}};
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, singleDeviceList);
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java
index a8ae7823c..916c98d72 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/MessageControllerTest.java
@@ -74,13 +74,13 @@ public class MessageControllerTest {
@Before
public void setup() throws Exception {
Set singleDeviceList = new HashSet() {{
- add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, null, System.currentTimeMillis(), System.currentTimeMillis()));
+ add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
}};
Set multiDeviceList = new HashSet() {{
- add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis()));
- add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis()));
- add(new Device(3, null, "foo", "bar", "baz", "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis()));
+ add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, new SignedPreKey(111, "foo", "bar"), System.currentTimeMillis(), System.currentTimeMillis(), false));
+ add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, new SignedPreKey(222, "oof", "rab"), System.currentTimeMillis(), System.currentTimeMillis(), false));
+ add(new Device(3, null, "foo", "bar", "baz", "isgcm", null, null, false, 444, null, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31), System.currentTimeMillis(), false));
}};
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, singleDeviceList);
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ReceiptControllerTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ReceiptControllerTest.java
index 693812f48..bcc57690f 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ReceiptControllerTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/ReceiptControllerTest.java
@@ -53,12 +53,12 @@ public class ReceiptControllerTest {
@Before
public void setup() throws Exception {
Set singleDeviceList = new HashSet() {{
- add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, null, System.currentTimeMillis(), System.currentTimeMillis()));
+ add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 111, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
}};
Set multiDeviceList = new HashSet() {{
- add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, null, System.currentTimeMillis(), System.currentTimeMillis()));
- add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, null, System.currentTimeMillis(), System.currentTimeMillis()));
+ add(new Device(1, null, "foo", "bar", "baz", "isgcm", null, null, false, 222, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
+ add(new Device(2, null, "foo", "bar", "baz", "isgcm", null, null, false, 333, null, System.currentTimeMillis(), System.currentTimeMillis(), false));
}};
Account singleDeviceAccount = new Account(SINGLE_DEVICE_RECIPIENT, singleDeviceList);
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java
index 4d4d4450c..c23f459f9 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/ClientContactTest.java
@@ -14,9 +14,9 @@ public class ClientContactTest {
@Test
public void serializeToJSON() throws Exception {
byte[] token = Util.getContactToken("+14152222222");
- ClientContact contact = new ClientContact(token, null);
- ClientContact contactWithRelay = new ClientContact(token, "whisper");
- ClientContact contactWithRelaySms = new ClientContact(token, "whisper");
+ ClientContact contact = new ClientContact(token, null, false);
+ ClientContact contactWithRelay = new ClientContact(token, "whisper", false);
+ ClientContact contactWithRelayVox = new ClientContact(token, "whisper", true);
assertThat("Basic Contact Serialization works",
asJson(contact),
@@ -25,12 +25,16 @@ public class ClientContactTest {
assertThat("Contact Relay Serialization works",
asJson(contactWithRelay),
is(equalTo(jsonFixture("fixtures/contact.relay.json"))));
+
+ assertThat("Contact Relay Vox Serializaton works",
+ asJson(contactWithRelayVox),
+ is(equalTo(jsonFixture("fixtures/contact.relay.voice.json"))));
}
@Test
public void deserializeFromJSON() throws Exception {
ClientContact contact = new ClientContact(Util.getContactToken("+14152222222"),
- "whisper");
+ "whisper", false);
assertThat("a ClientContact can be deserialized from JSON",
fromJson(jsonFixture("fixtures/contact.relay.json"), ClientContact.class),
diff --git a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java
index a77ef3ffb..fee62ab83 100644
--- a/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java
+++ b/src/test/java/org/whispersystems/textsecuregcm/tests/entities/PreKeyTest.java
@@ -26,7 +26,7 @@ public class PreKeyTest {
@Test
public void deserializeFromJSONV() throws Exception {
ClientContact contact = new ClientContact(Util.getContactToken("+14152222222"),
- "whisper");
+ "whisper", false);
assertThat("a ClientContact can be deserialized from JSON",
fromJson(jsonFixture("fixtures/contact.relay.json"), ClientContact.class),
diff --git a/src/test/resources/fixtures/contact.relay.voice.json b/src/test/resources/fixtures/contact.relay.voice.json
new file mode 100644
index 000000000..6368ffb89
--- /dev/null
+++ b/src/test/resources/fixtures/contact.relay.voice.json
@@ -0,0 +1,5 @@
+{
+ "token" : "BQVVHxMt5zAFXA",
+ "voice" : true,
+ "relay" : "whisper"
+}
\ No newline at end of file