mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-29 18:30:51 +00:00
Support for group sync messages and requests.
// FREEBIE
This commit is contained in:
parent
d044a11bc0
commit
a20818f018
@ -1,5 +1,5 @@
|
||||
subprojects {
|
||||
ext.version_number = "1.6.0-RC19"
|
||||
ext.version_number = "1.6.0-RC21"
|
||||
ext.group_info = "org.whispersystems"
|
||||
ext.axolotl_version = "1.3.1"
|
||||
|
||||
|
@ -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.TextSecureSyncMessage;
|
||||
import org.whispersystems.textsecure.api.push.TextSecureAddress;
|
||||
import org.whispersystems.textsecure.api.push.TrustStore;
|
||||
import org.whispersystems.textsecure.api.push.exceptions.EncapsulatedExceptions;
|
||||
@ -122,7 +123,7 @@ public class TextSecureMessageSender {
|
||||
SendMessageResponse response = sendMessage(recipient, timestamp, content, true);
|
||||
|
||||
if (response != null && response.getNeedsSync()) {
|
||||
byte[] syncMessage = createSentTranscriptMessage(content, Optional.of(recipient), timestamp);
|
||||
byte[] syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.of(recipient), timestamp);
|
||||
sendMessage(localAddress, timestamp, syncMessage, false);
|
||||
}
|
||||
|
||||
@ -152,7 +153,7 @@ public class TextSecureMessageSender {
|
||||
|
||||
try {
|
||||
if (response != null && response.getNeedsSync()) {
|
||||
byte[] syncMessage = createSentTranscriptMessage(content, Optional.<TextSecureAddress>absent(), timestamp);
|
||||
byte[] syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.<TextSecureAddress>absent(), timestamp);
|
||||
sendMessage(localAddress, timestamp, syncMessage, false);
|
||||
}
|
||||
} catch (UntrustedIdentityException e) {
|
||||
@ -160,10 +161,19 @@ public class TextSecureMessageSender {
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMultiDeviceContactsUpdate(TextSecureAttachmentStream contacts)
|
||||
public void sendMessage(TextSecureSyncMessage message)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
byte[] content = createMultiDeviceContactsContent(contacts);
|
||||
byte[] content;
|
||||
|
||||
if (message.getContacts().isPresent()) {
|
||||
content = createMultiDeviceContactsContent(message.getContacts().get().asStream());
|
||||
} else if (message.getGroups().isPresent()) {
|
||||
content = createMultiDeviceGroupsContent(message.getGroups().get().asStream());
|
||||
} else {
|
||||
throw new IOException("Unsupported sync message!");
|
||||
}
|
||||
|
||||
sendMessage(localAddress, System.currentTimeMillis(), content, false);
|
||||
}
|
||||
|
||||
@ -199,7 +209,16 @@ public class TextSecureMessageSender {
|
||||
return container.setSyncMessage(builder).build().toByteArray();
|
||||
}
|
||||
|
||||
private byte[] createSentTranscriptMessage(byte[] content, Optional<TextSecureAddress> recipient, long timestamp) {
|
||||
private byte[] createMultiDeviceGroupsContent(TextSecureAttachmentStream groups) throws IOException {
|
||||
Content.Builder container = Content.newBuilder();
|
||||
SyncMessage.Builder builder = SyncMessage.newBuilder();
|
||||
builder.setGroups(SyncMessage.Groups.newBuilder()
|
||||
.setBlob(createAttachmentPointer(groups)));
|
||||
|
||||
return container.setSyncMessage(builder).build().toByteArray();
|
||||
}
|
||||
|
||||
private byte[] createMultiDeviceSentTranscriptContent(byte[] content, Optional<TextSecureAddress> recipient, long timestamp) {
|
||||
try {
|
||||
Content.Builder container = Content.newBuilder();
|
||||
SyncMessage.Builder syncMessage = SyncMessage.newBuilder();
|
||||
|
@ -28,7 +28,6 @@ import org.whispersystems.libaxolotl.LegacyMessageException;
|
||||
import org.whispersystems.libaxolotl.NoSessionException;
|
||||
import org.whispersystems.libaxolotl.SessionCipher;
|
||||
import org.whispersystems.libaxolotl.UntrustedIdentityException;
|
||||
import org.whispersystems.libaxolotl.logging.Log;
|
||||
import org.whispersystems.libaxolotl.protocol.CiphertextMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage;
|
||||
import org.whispersystems.libaxolotl.protocol.WhisperMessage;
|
||||
@ -36,9 +35,9 @@ import org.whispersystems.libaxolotl.state.AxolotlStore;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachment;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer;
|
||||
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.TextSecureDataMessage;
|
||||
import org.whispersystems.textsecure.api.messages.multidevice.RequestMessage;
|
||||
import org.whispersystems.textsecure.api.messages.multidevice.SentTranscriptMessage;
|
||||
import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage;
|
||||
@ -175,16 +174,16 @@ public class TextSecureCipher {
|
||||
private TextSecureSyncMessage createSynchronizeMessage(TextSecureEnvelope envelope, SyncMessage content) {
|
||||
if (content.hasSent()) {
|
||||
SyncMessage.Sent sentContent = content.getSent();
|
||||
return new TextSecureSyncMessage(new SentTranscriptMessage(sentContent.getDestination(),
|
||||
sentContent.getTimestamp(),
|
||||
createTextSecureMessage(envelope, sentContent.getMessage())));
|
||||
return TextSecureSyncMessage.forSentTranscript(new SentTranscriptMessage(sentContent.getDestination(),
|
||||
sentContent.getTimestamp(),
|
||||
createTextSecureMessage(envelope, sentContent.getMessage())));
|
||||
}
|
||||
|
||||
if (content.hasRequest()) {
|
||||
return new TextSecureSyncMessage(new RequestMessage(content.getRequest()));
|
||||
return TextSecureSyncMessage.forRequest(new RequestMessage(content.getRequest()));
|
||||
}
|
||||
|
||||
return new TextSecureSyncMessage();
|
||||
return TextSecureSyncMessage.empty();
|
||||
}
|
||||
|
||||
private TextSecureGroup createGroupInfo(TextSecureEnvelope envelope, DataMessage content) {
|
||||
|
@ -0,0 +1,116 @@
|
||||
package org.whispersystems.textsecure.api.messages.multidevice;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ChunkedInputStream {
|
||||
|
||||
protected final InputStream in;
|
||||
|
||||
public ChunkedInputStream(InputStream in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
protected int readRawVarint32() throws IOException {
|
||||
byte tmp = (byte)in.read();
|
||||
if (tmp >= 0) {
|
||||
return tmp;
|
||||
}
|
||||
int result = tmp & 0x7f;
|
||||
if ((tmp = (byte)in.read()) >= 0) {
|
||||
result |= tmp << 7;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 7;
|
||||
if ((tmp = (byte)in.read()) >= 0) {
|
||||
result |= tmp << 14;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 14;
|
||||
if ((tmp = (byte)in.read()) >= 0) {
|
||||
result |= tmp << 21;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 21;
|
||||
result |= (tmp = (byte)in.read()) << 28;
|
||||
if (tmp < 0) {
|
||||
// Discard upper 32 bits.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if ((byte)in.read() >= 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IOException("Malformed varint!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static final class LimitedInputStream extends FilterInputStream {
|
||||
|
||||
private long left;
|
||||
private long mark = -1;
|
||||
|
||||
LimitedInputStream(InputStream in, long limit) {
|
||||
super(in);
|
||||
left = limit;
|
||||
}
|
||||
|
||||
@Override public int available() throws IOException {
|
||||
return (int) Math.min(in.available(), left);
|
||||
}
|
||||
|
||||
// it's okay to mark even if mark isn't supported, as reset won't work
|
||||
@Override public synchronized void mark(int readLimit) {
|
||||
in.mark(readLimit);
|
||||
mark = left;
|
||||
}
|
||||
|
||||
@Override public int read() throws IOException {
|
||||
if (left == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result = in.read();
|
||||
if (result != -1) {
|
||||
--left;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (left == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = (int) Math.min(len, left);
|
||||
int result = in.read(b, off, len);
|
||||
if (result != -1) {
|
||||
left -= result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public synchronized void reset() throws IOException {
|
||||
if (!in.markSupported()) {
|
||||
throw new IOException("Mark not supported");
|
||||
}
|
||||
if (mark == -1) {
|
||||
throw new IOException("Mark not set");
|
||||
}
|
||||
|
||||
in.reset();
|
||||
left = mark;
|
||||
}
|
||||
|
||||
@Override public long skip(long n) throws IOException {
|
||||
n = Math.min(n, left);
|
||||
long skipped = in.skip(n);
|
||||
left -= skipped;
|
||||
return skipped;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.whispersystems.textsecure.api.messages.multidevice;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class ChunkedOutputStream {
|
||||
|
||||
protected final OutputStream out;
|
||||
|
||||
public ChunkedOutputStream(OutputStream out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
protected void writeVarint32(int value) throws IOException {
|
||||
while (true) {
|
||||
if ((value & ~0x7F) == 0) {
|
||||
out.write(value);
|
||||
return;
|
||||
} else {
|
||||
out.write((value & 0x7F) | 0x80);
|
||||
value >>>= 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeStream(InputStream in) throws IOException {
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
in.close();
|
||||
}
|
||||
|
||||
}
|
@ -5,16 +5,13 @@ import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream;
|
||||
import org.whispersystems.textsecure.internal.push.TextSecureProtos;
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class DeviceContactsInputStream {
|
||||
|
||||
private final InputStream in;
|
||||
public class DeviceContactsInputStream extends ChunkedInputStream {
|
||||
|
||||
public DeviceContactsInputStream(InputStream in) {
|
||||
this.in = in;
|
||||
super(in);
|
||||
}
|
||||
|
||||
public DeviceContact read() throws IOException {
|
||||
@ -38,105 +35,4 @@ public class DeviceContactsInputStream {
|
||||
return new DeviceContact(number, name, avatar);
|
||||
}
|
||||
|
||||
public int readRawVarint32() throws IOException {
|
||||
byte tmp = (byte)in.read();
|
||||
if (tmp >= 0) {
|
||||
return tmp;
|
||||
}
|
||||
int result = tmp & 0x7f;
|
||||
if ((tmp = (byte)in.read()) >= 0) {
|
||||
result |= tmp << 7;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 7;
|
||||
if ((tmp = (byte)in.read()) >= 0) {
|
||||
result |= tmp << 14;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 14;
|
||||
if ((tmp = (byte)in.read()) >= 0) {
|
||||
result |= tmp << 21;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 21;
|
||||
result |= (tmp = (byte)in.read()) << 28;
|
||||
if (tmp < 0) {
|
||||
// Discard upper 32 bits.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if ((byte)in.read() >= 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IOException("Malformed varint!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final class LimitedInputStream extends FilterInputStream {
|
||||
|
||||
private long left;
|
||||
private long mark = -1;
|
||||
|
||||
LimitedInputStream(InputStream in, long limit) {
|
||||
super(in);
|
||||
left = limit;
|
||||
}
|
||||
|
||||
@Override public int available() throws IOException {
|
||||
return (int) Math.min(in.available(), left);
|
||||
}
|
||||
|
||||
// it's okay to mark even if mark isn't supported, as reset won't work
|
||||
@Override public synchronized void mark(int readLimit) {
|
||||
in.mark(readLimit);
|
||||
mark = left;
|
||||
}
|
||||
|
||||
@Override public int read() throws IOException {
|
||||
if (left == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int result = in.read();
|
||||
if (result != -1) {
|
||||
--left;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (left == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = (int) Math.min(len, left);
|
||||
int result = in.read(b, off, len);
|
||||
if (result != -1) {
|
||||
left -= result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override public synchronized void reset() throws IOException {
|
||||
if (!in.markSupported()) {
|
||||
throw new IOException("Mark not supported");
|
||||
}
|
||||
if (mark == -1) {
|
||||
throw new IOException("Mark not set");
|
||||
}
|
||||
|
||||
in.reset();
|
||||
left = mark;
|
||||
}
|
||||
|
||||
@Override public long skip(long n) throws IOException {
|
||||
n = Math.min(n, left);
|
||||
long skipped = in.skip(n);
|
||||
left -= skipped;
|
||||
return skipped;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,18 +1,14 @@
|
||||
package org.whispersystems.textsecure.api.messages.multidevice;
|
||||
|
||||
import org.whispersystems.textsecure.internal.push.TextSecureProtos;
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class DeviceContactsOutputStream {
|
||||
|
||||
private final OutputStream out;
|
||||
public class DeviceContactsOutputStream extends ChunkedOutputStream {
|
||||
|
||||
public DeviceContactsOutputStream(OutputStream out) {
|
||||
this.out = out;
|
||||
super(out);
|
||||
}
|
||||
|
||||
public void write(DeviceContact contact) throws IOException {
|
||||
@ -26,16 +22,7 @@ public class DeviceContactsOutputStream {
|
||||
|
||||
private void writeAvatarImage(DeviceContact contact) throws IOException {
|
||||
if (contact.getAvatar().isPresent()) {
|
||||
InputStream in = contact.getAvatar().get().getInputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
in.close();
|
||||
writeStream(contact.getAvatar().get().getInputStream());
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +37,7 @@ public class DeviceContactsOutputStream {
|
||||
if (contact.getAvatar().isPresent()) {
|
||||
TextSecureProtos.ContactDetails.Avatar.Builder avatarBuilder = TextSecureProtos.ContactDetails.Avatar.newBuilder();
|
||||
avatarBuilder.setContentType(contact.getAvatar().get().getContentType());
|
||||
avatarBuilder.setLength(contact.getAvatar().get().getLength());
|
||||
avatarBuilder.setLength((int)contact.getAvatar().get().getLength());
|
||||
contactDetails.setAvatar(avatarBuilder);
|
||||
}
|
||||
|
||||
@ -60,16 +47,4 @@ public class DeviceContactsOutputStream {
|
||||
out.write(serializedContactDetails);
|
||||
}
|
||||
|
||||
private void writeVarint32(int value) throws IOException {
|
||||
while (true) {
|
||||
if ((value & ~0x7F) == 0) {
|
||||
out.write(value);
|
||||
return;
|
||||
} else {
|
||||
out.write((value & 0x7F) | 0x80);
|
||||
value >>>= 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package org.whispersystems.textsecure.api.messages.multidevice;
|
||||
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DeviceGroup {
|
||||
|
||||
private final byte[] id;
|
||||
private final Optional<String> name;
|
||||
private final List<String> members;
|
||||
private final Optional<TextSecureAttachmentStream> avatar;
|
||||
|
||||
public DeviceGroup(byte[] id, Optional<String> name, List<String> members, Optional<TextSecureAttachmentStream> avatar) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.members = members;
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public Optional<TextSecureAttachmentStream> getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public Optional<String> getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public byte[] getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package org.whispersystems.textsecure.api.messages.multidevice;
|
||||
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream;
|
||||
import org.whispersystems.textsecure.internal.push.TextSecureProtos;
|
||||
import org.whispersystems.textsecure.internal.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class DeviceGroupsInputStream extends ChunkedInputStream{
|
||||
|
||||
public DeviceGroupsInputStream(InputStream in) {
|
||||
super(in);
|
||||
}
|
||||
|
||||
public DeviceGroup read() throws IOException {
|
||||
long detailsLength = readRawVarint32();
|
||||
byte[] detailsSerialized = new byte[(int)detailsLength];
|
||||
Util.readFully(in, detailsSerialized);
|
||||
|
||||
TextSecureProtos.GroupDetails details = TextSecureProtos.GroupDetails.parseFrom(detailsSerialized);
|
||||
|
||||
if (!details.hasId()) {
|
||||
throw new IOException("ID missing on group record!");
|
||||
}
|
||||
|
||||
byte[] id = details.getId().toByteArray();
|
||||
Optional<String> name = Optional.fromNullable(details.getName());
|
||||
List<String> members = details.getMembersList();
|
||||
Optional<TextSecureAttachmentStream> avatar = Optional.absent();
|
||||
|
||||
if (details.hasAvatar()) {
|
||||
long avatarLength = details.getAvatar().getLength();
|
||||
InputStream avatarStream = new ChunkedInputStream.LimitedInputStream(in, avatarLength);
|
||||
String avatarContentType = details.getAvatar().getContentType();
|
||||
|
||||
avatar = Optional.of(new TextSecureAttachmentStream(avatarStream, avatarContentType, avatarLength));
|
||||
}
|
||||
|
||||
return new DeviceGroup(id, name, members, avatar);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package org.whispersystems.textsecure.api.messages.multidevice;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.whispersystems.textsecure.internal.push.TextSecureProtos;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class DeviceGroupsOutputStream extends ChunkedOutputStream {
|
||||
|
||||
public DeviceGroupsOutputStream(OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
public void write(DeviceGroup group) throws IOException {
|
||||
writeGroupDetails(group);
|
||||
writeAvatarImage(group);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
out.close();
|
||||
}
|
||||
|
||||
private void writeAvatarImage(DeviceGroup contact) throws IOException {
|
||||
if (contact.getAvatar().isPresent()) {
|
||||
writeStream(contact.getAvatar().get().getInputStream());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeGroupDetails(DeviceGroup group) throws IOException {
|
||||
TextSecureProtos.GroupDetails.Builder groupDetails = TextSecureProtos.GroupDetails.newBuilder();
|
||||
groupDetails.setId(ByteString.copyFrom(group.getId()));
|
||||
|
||||
if (group.getName().isPresent()) {
|
||||
groupDetails.setName(group.getName().get());
|
||||
}
|
||||
|
||||
if (group.getAvatar().isPresent()) {
|
||||
TextSecureProtos.GroupDetails.Avatar.Builder avatarBuilder = TextSecureProtos.GroupDetails.Avatar.newBuilder();
|
||||
avatarBuilder.setContentType(group.getAvatar().get().getContentType());
|
||||
avatarBuilder.setLength((int)group.getAvatar().get().getLength());
|
||||
groupDetails.setAvatar(avatarBuilder);
|
||||
}
|
||||
|
||||
groupDetails.addAllMembers(group.getMembers());
|
||||
|
||||
byte[] serializedContactDetails = groupDetails.build().toByteArray();
|
||||
|
||||
writeVarint32(serializedContactDetails.length);
|
||||
out.write(serializedContactDetails);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -13,4 +13,8 @@ public class RequestMessage {
|
||||
public boolean isContactsRequest() {
|
||||
return request.getType() == Request.Type.CONTACTS;
|
||||
}
|
||||
|
||||
public boolean isGroupsRequest() {
|
||||
return request.getType() == Request.Type.GROUPS;
|
||||
}
|
||||
}
|
||||
|
@ -8,50 +8,61 @@ public class TextSecureSyncMessage {
|
||||
|
||||
private final Optional<SentTranscriptMessage> sent;
|
||||
private final Optional<TextSecureAttachment> contacts;
|
||||
private final Optional<TextSecureGroup> group;
|
||||
private final Optional<TextSecureAttachment> groups;
|
||||
private final Optional<RequestMessage> request;
|
||||
|
||||
public TextSecureSyncMessage() {
|
||||
this.sent = Optional.absent();
|
||||
this.contacts = Optional.absent();
|
||||
this.group = Optional.absent();
|
||||
this.request = Optional.absent();
|
||||
private TextSecureSyncMessage(Optional<SentTranscriptMessage> sent,
|
||||
Optional<TextSecureAttachment> contacts,
|
||||
Optional<TextSecureAttachment> groups,
|
||||
Optional<RequestMessage> request)
|
||||
{
|
||||
this.sent = sent;
|
||||
this.contacts = contacts;
|
||||
this.groups = groups;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public TextSecureSyncMessage(SentTranscriptMessage sent) {
|
||||
this.sent = Optional.of(sent);
|
||||
this.contacts = Optional.absent();
|
||||
this.group = Optional.absent();
|
||||
this.request = Optional.absent();
|
||||
public static TextSecureSyncMessage forSentTranscript(SentTranscriptMessage sent) {
|
||||
return new TextSecureSyncMessage(Optional.of(sent),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.<RequestMessage>absent());
|
||||
}
|
||||
|
||||
public TextSecureSyncMessage(TextSecureAttachment contacts) {
|
||||
this.contacts = Optional.of(contacts);
|
||||
this.sent = Optional.absent();
|
||||
this.group = Optional.absent();
|
||||
this.request = Optional.absent();
|
||||
public static TextSecureSyncMessage forContacts(TextSecureAttachment contacts) {
|
||||
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
|
||||
Optional.of(contacts),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.<RequestMessage>absent());
|
||||
}
|
||||
|
||||
public TextSecureSyncMessage(TextSecureGroup group) {
|
||||
this.group = Optional.of(group);
|
||||
this.sent = Optional.absent();
|
||||
this.contacts = Optional.absent();
|
||||
this.request = Optional.absent();
|
||||
public static TextSecureSyncMessage forGroups(TextSecureAttachment groups) {
|
||||
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.of(groups),
|
||||
Optional.<RequestMessage>absent());
|
||||
}
|
||||
|
||||
public TextSecureSyncMessage(RequestMessage contactsRequest) {
|
||||
this.request = Optional.of(contactsRequest);
|
||||
this.sent = Optional.absent();
|
||||
this.contacts = Optional.absent();
|
||||
this.group = Optional.absent();
|
||||
public static TextSecureSyncMessage forRequest(RequestMessage request) {
|
||||
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.of(request));
|
||||
}
|
||||
|
||||
public static TextSecureSyncMessage empty() {
|
||||
return new TextSecureSyncMessage(Optional.<SentTranscriptMessage>absent(),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.<TextSecureAttachment>absent(),
|
||||
Optional.<RequestMessage>absent());
|
||||
}
|
||||
|
||||
public Optional<SentTranscriptMessage> getSent() {
|
||||
return sent;
|
||||
}
|
||||
|
||||
public Optional<TextSecureGroup> getGroup() {
|
||||
return group;
|
||||
public Optional<TextSecureAttachment> getGroups() {
|
||||
return groups;
|
||||
}
|
||||
|
||||
public Optional<TextSecureAttachment> getContacts() {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,14 +48,15 @@ message SyncMessage {
|
||||
optional AttachmentPointer blob = 1;
|
||||
}
|
||||
|
||||
message Group {
|
||||
optional GroupContext group = 1;
|
||||
message Groups {
|
||||
optional AttachmentPointer blob = 1;
|
||||
}
|
||||
|
||||
message Request {
|
||||
enum Type {
|
||||
UNKNOWN = 0;
|
||||
CONTACTS = 1;
|
||||
GROUPS = 2;
|
||||
}
|
||||
|
||||
optional Type type = 1;
|
||||
@ -63,7 +64,7 @@ message SyncMessage {
|
||||
|
||||
optional Sent sent = 1;
|
||||
optional Contacts contacts = 2;
|
||||
optional Group group = 3;
|
||||
optional Groups groups = 3;
|
||||
optional Request request = 4;
|
||||
}
|
||||
|
||||
@ -90,10 +91,22 @@ message GroupContext {
|
||||
message ContactDetails {
|
||||
message Avatar {
|
||||
optional string contentType = 1;
|
||||
optional uint64 length = 2;
|
||||
optional uint32 length = 2;
|
||||
}
|
||||
|
||||
optional string number = 1;
|
||||
optional string name = 2;
|
||||
optional Avatar avatar = 3;
|
||||
}
|
||||
|
||||
message GroupDetails {
|
||||
message Avatar {
|
||||
optional string contentType = 1;
|
||||
optional uint32 length = 2;
|
||||
}
|
||||
|
||||
optional bytes id = 1;
|
||||
optional string name = 2;
|
||||
repeated string members = 3;
|
||||
optional Avatar avatar = 4;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user