Add support for syncing read status

// FREEBIE
This commit is contained in:
Moxie Marlinspike 2016-02-19 16:33:45 -08:00
parent 4aefe9576c
commit 515001741b
6 changed files with 1053 additions and 34 deletions

View File

@ -32,6 +32,7 @@ import org.whispersystems.textsecure.api.messages.TextSecureAttachment;
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream;
import org.whispersystems.textsecure.api.messages.TextSecureDataMessage;
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
import org.whispersystems.textsecure.api.messages.multidevice.ReadMessage;
import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage;
import org.whispersystems.textsecure.api.push.TextSecureAddress;
import org.whispersystems.textsecure.api.push.TrustStore;
@ -171,6 +172,8 @@ public class TextSecureMessageSender {
content = createMultiDeviceContactsContent(message.getContacts().get().asStream());
} else if (message.getGroups().isPresent()) {
content = createMultiDeviceGroupsContent(message.getGroups().get().asStream());
} else if (message.getRead().isPresent()) {
content = createMultiDeviceReadContent(message.getRead().get());
} else {
throw new IOException("Unsupported sync message!");
}
@ -238,6 +241,19 @@ public class TextSecureMessageSender {
}
}
private byte[] createMultiDeviceReadContent(List<ReadMessage> readMessages) {
Content.Builder container = Content.newBuilder();
SyncMessage.Builder builder = SyncMessage.newBuilder();
for (ReadMessage readMessage : readMessages) {
builder.addRead(SyncMessage.Read.newBuilder()
.setTimestamp(readMessage.getTimestamp())
.setSender(readMessage.getSender()));
}
return container.setSyncMessage(builder).build().toByteArray();
}
private GroupContext createGroupContent(TextSecureGroup group) throws IOException {
GroupContext.Builder builder = GroupContext.newBuilder();
builder.setId(ByteString.copyFrom(group.getGroupId()));

View File

@ -39,6 +39,7 @@ import org.whispersystems.textsecure.api.messages.TextSecureContent;
import org.whispersystems.textsecure.api.messages.TextSecureDataMessage;
import org.whispersystems.textsecure.api.messages.TextSecureEnvelope;
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
import org.whispersystems.textsecure.api.messages.multidevice.ReadMessage;
import org.whispersystems.textsecure.api.messages.multidevice.RequestMessage;
import org.whispersystems.textsecure.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage;
@ -186,6 +187,16 @@ public class TextSecureCipher {
return TextSecureSyncMessage.forRequest(new RequestMessage(content.getRequest()));
}
if (content.getReadList().size() > 0) {
List<ReadMessage> readMessages = new LinkedList<>();
for (SyncMessage.Read read : content.getReadList()) {
readMessages.add(new ReadMessage(read.getSender(), read.getTimestamp()));
}
return TextSecureSyncMessage.forRead(readMessages);
}
return TextSecureSyncMessage.empty();
}

View File

@ -0,0 +1,24 @@
package org.whispersystems.textsecure.api.messages.multidevice;
import java.util.LinkedList;
import java.util.List;
public class ReadMessage {
private final String sender;
private final long timestamp;
public ReadMessage(String sender, long timestamp) {
this.sender = sender;
this.timestamp = timestamp;
}
public long getTimestamp() {
return timestamp;
}
public String getSender() {
return sender;
}
}

View File

@ -4,57 +4,88 @@ import org.whispersystems.libaxolotl.util.guava.Optional;
import org.whispersystems.textsecure.api.messages.TextSecureAttachment;
import org.whispersystems.textsecure.api.messages.TextSecureGroup;
import java.util.LinkedList;
import java.util.List;
public class TextSecureSyncMessage {
private final Optional<SentTranscriptMessage> sent;
private final Optional<TextSecureAttachment> contacts;
private final Optional<TextSecureAttachment> groups;
private final Optional<RequestMessage> request;
private final Optional<List<ReadMessage>> reads;
private TextSecureSyncMessage(Optional<SentTranscriptMessage> sent,
Optional<TextSecureAttachment> contacts,
Optional<TextSecureAttachment> groups,
Optional<RequestMessage> request)
Optional<RequestMessage> request,
Optional<List<ReadMessage>> reads)
{
this.sent = sent;
this.contacts = contacts;
this.groups = groups;
this.request = request;
this.reads = reads;
}
public static TextSecureSyncMessage forSentTranscript(SentTranscriptMessage sent) {
return new TextSecureSyncMessage(Optional.of(sent),
Optional.<TextSecureAttachment>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<RequestMessage>absent());
Optional.<RequestMessage>absent(),
Optional.<List<ReadMessage>>absent());
}
public static TextSecureSyncMessage forContacts(TextSecureAttachment contacts) {
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
Optional.of(contacts),
Optional.<TextSecureAttachment>absent(),
Optional.<RequestMessage>absent());
Optional.<RequestMessage>absent(),
Optional.<List<ReadMessage>>absent());
}
public static TextSecureSyncMessage forGroups(TextSecureAttachment groups) {
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.of(groups),
Optional.<RequestMessage>absent());
Optional.<RequestMessage>absent(),
Optional.<List<ReadMessage>>absent());
}
public static TextSecureSyncMessage forRequest(RequestMessage request) {
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.of(request));
Optional.of(request),
Optional.<List<ReadMessage>>absent());
}
public static TextSecureSyncMessage forRead(List<ReadMessage> reads) {
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<RequestMessage>absent(),
Optional.of(reads));
}
public static TextSecureSyncMessage forRead(ReadMessage read) {
List<ReadMessage> reads = new LinkedList<>();
reads.add(read);
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<RequestMessage>absent(),
Optional.of(reads));
}
public static TextSecureSyncMessage empty() {
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<TextSecureAttachment>absent(),
Optional.<RequestMessage>absent());
Optional.<RequestMessage>absent(),
Optional.<List<ReadMessage>>absent());
}
public Optional<SentTranscriptMessage> getSent() {
@ -73,4 +104,8 @@ public class TextSecureSyncMessage {
return request;
}
public Optional<List<ReadMessage>> getRead() {
return reads;
}
}

View File

@ -62,10 +62,16 @@ message SyncMessage {
optional Type type = 1;
}
message Read {
optional string sender = 1;
optional uint64 timestamp = 2;
}
optional Sent sent = 1;
optional Contacts contacts = 2;
optional Groups groups = 3;
optional Request request = 4;
repeated Read read = 5;
}
message AttachmentPointer {