diff --git a/java/src/main/java/org/whispersystems/textsecure/api/TextSecureMessageSender.java b/java/src/main/java/org/whispersystems/textsecure/api/TextSecureMessageSender.java index 7a789ea7b4..eaee62e68f 100644 --- a/java/src/main/java/org/whispersystems/textsecure/api/TextSecureMessageSender.java +++ b/java/src/main/java/org/whispersystems/textsecure/api/TextSecureMessageSender.java @@ -341,11 +341,17 @@ public class TextSecureMessageSender { long attachmentId = socket.sendAttachment(attachmentData); - return AttachmentPointer.newBuilder() - .setContentType(attachment.getContentType()) - .setId(attachmentId) - .setKey(ByteString.copyFrom(attachmentKey)) - .build(); + AttachmentPointer.Builder builder = AttachmentPointer.newBuilder() + .setContentType(attachment.getContentType()) + .setId(attachmentId) + .setKey(ByteString.copyFrom(attachmentKey)) + .setSize((int)attachment.getLength()); + + if (attachment.getPreview().isPresent()) { + builder.setThumbnail(ByteString.copyFrom(attachment.getPreview().get())); + } + + return builder.build(); } diff --git a/java/src/main/java/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java b/java/src/main/java/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java index 5d54059885..8fafb0a604 100644 --- a/java/src/main/java/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java +++ b/java/src/main/java/org/whispersystems/textsecure/api/crypto/TextSecureCipher.java @@ -32,6 +32,7 @@ import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; import org.whispersystems.libaxolotl.protocol.WhisperMessage; import org.whispersystems.libaxolotl.state.AxolotlStore; +import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer; import org.whispersystems.textsecure.api.messages.TextSecureContent; @@ -164,7 +165,9 @@ public class TextSecureCipher { attachments.add(new TextSecureAttachmentPointer(pointer.getId(), pointer.getContentType(), pointer.getKey().toByteArray(), - envelope.getRelay())); + envelope.getRelay(), + pointer.hasSize() ? Optional.of(pointer.getSize()) : Optional.absent(), + pointer.hasThumbnail() ? Optional.of(pointer.getThumbnail().toByteArray()): Optional.absent())); } return new TextSecureDataMessage(envelope.getTimestamp(), groupInfo, attachments, diff --git a/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentPointer.java b/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentPointer.java index a86e6199d2..aad4805197 100644 --- a/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentPointer.java +++ b/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentPointer.java @@ -27,15 +27,25 @@ import org.whispersystems.libaxolotl.util.guava.Optional; */ public class TextSecureAttachmentPointer extends TextSecureAttachment { - private final long id; - private final byte[] key; - private final Optional relay; + private final long id; + private final byte[] key; + private final Optional relay; + private final Optional size; + private final Optional preview; public TextSecureAttachmentPointer(long id, String contentType, byte[] key, String relay) { + this(id, contentType, key, relay, Optional.absent(), Optional.absent()); + } + + public TextSecureAttachmentPointer(long id, String contentType, byte[] key, String relay, + Optional size, Optional preview) + { super(contentType); - this.id = id; - this.key = key; - this.relay = Optional.fromNullable(relay); + this.id = id; + this.key = key; + this.relay = Optional.fromNullable(relay); + this.size = size; + this.preview = preview; } public long getId() { @@ -59,4 +69,12 @@ public class TextSecureAttachmentPointer extends TextSecureAttachment { public Optional getRelay() { return relay; } + + public Optional getSize() { + return size; + } + + public Optional getPreview() { + return preview; + } } diff --git a/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java b/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java index 81fae9ed54..a3955cfba6 100644 --- a/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java +++ b/java/src/main/java/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java @@ -16,6 +16,8 @@ */ package org.whispersystems.textsecure.api.messages; +import org.whispersystems.libaxolotl.util.guava.Optional; + import java.io.InputStream; /** @@ -26,12 +28,18 @@ public class TextSecureAttachmentStream extends TextSecureAttachment { private final InputStream inputStream; private final long length; private final ProgressListener listener; + private final Optional preview; public TextSecureAttachmentStream(InputStream inputStream, String contentType, long length, ProgressListener listener) { + this(inputStream, contentType, length, Optional.absent(), listener); + } + + public TextSecureAttachmentStream(InputStream inputStream, String contentType, long length, Optional preview, ProgressListener listener) { super(contentType); this.inputStream = inputStream; this.length = length; this.listener = listener; + this.preview = preview; } @Override @@ -55,4 +63,8 @@ public class TextSecureAttachmentStream extends TextSecureAttachment { public ProgressListener getListener() { return listener; } + + public Optional getPreview() { + return preview; + } } diff --git a/java/src/main/java/org/whispersystems/textsecure/internal/push/TextSecureProtos.java b/java/src/main/java/org/whispersystems/textsecure/internal/push/TextSecureProtos.java index 652baefabb..ee3d6b2861 100644 --- a/java/src/main/java/org/whispersystems/textsecure/internal/push/TextSecureProtos.java +++ b/java/src/main/java/org/whispersystems/textsecure/internal/push/TextSecureProtos.java @@ -6480,6 +6480,26 @@ public final class TextSecureProtos { * optional bytes key = 3; */ com.google.protobuf.ByteString getKey(); + + // optional uint32 size = 4; + /** + * optional uint32 size = 4; + */ + boolean hasSize(); + /** + * optional uint32 size = 4; + */ + int getSize(); + + // optional bytes thumbnail = 5; + /** + * optional bytes thumbnail = 5; + */ + boolean hasThumbnail(); + /** + * optional bytes thumbnail = 5; + */ + com.google.protobuf.ByteString getThumbnail(); } /** * Protobuf type {@code textsecure.AttachmentPointer} @@ -6547,6 +6567,16 @@ public final class TextSecureProtos { key_ = input.readBytes(); break; } + case 32: { + bitField0_ |= 0x00000008; + size_ = input.readUInt32(); + break; + } + case 42: { + bitField0_ |= 0x00000010; + thumbnail_ = input.readBytes(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -6662,10 +6692,44 @@ public final class TextSecureProtos { return key_; } + // optional uint32 size = 4; + public static final int SIZE_FIELD_NUMBER = 4; + private int size_; + /** + * optional uint32 size = 4; + */ + public boolean hasSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional uint32 size = 4; + */ + public int getSize() { + return size_; + } + + // optional bytes thumbnail = 5; + public static final int THUMBNAIL_FIELD_NUMBER = 5; + private com.google.protobuf.ByteString thumbnail_; + /** + * optional bytes thumbnail = 5; + */ + public boolean hasThumbnail() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes thumbnail = 5; + */ + public com.google.protobuf.ByteString getThumbnail() { + return thumbnail_; + } + private void initFields() { id_ = 0L; contentType_ = ""; key_ = com.google.protobuf.ByteString.EMPTY; + size_ = 0; + thumbnail_ = com.google.protobuf.ByteString.EMPTY; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -6688,6 +6752,12 @@ public final class TextSecureProtos { if (((bitField0_ & 0x00000004) == 0x00000004)) { output.writeBytes(3, key_); } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeUInt32(4, size_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeBytes(5, thumbnail_); + } getUnknownFields().writeTo(output); } @@ -6709,6 +6779,14 @@ public final class TextSecureProtos { size += com.google.protobuf.CodedOutputStream .computeBytesSize(3, key_); } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(4, size_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(5, thumbnail_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -6831,6 +6909,10 @@ public final class TextSecureProtos { bitField0_ = (bitField0_ & ~0x00000002); key_ = com.google.protobuf.ByteString.EMPTY; bitField0_ = (bitField0_ & ~0x00000004); + size_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + thumbnail_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000010); return this; } @@ -6871,6 +6953,14 @@ public final class TextSecureProtos { to_bitField0_ |= 0x00000004; } result.key_ = key_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.size_ = size_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.thumbnail_ = thumbnail_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -6898,6 +6988,12 @@ public final class TextSecureProtos { if (other.hasKey()) { setKey(other.getKey()); } + if (other.hasSize()) { + setSize(other.getSize()); + } + if (other.hasThumbnail()) { + setThumbnail(other.getThumbnail()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -7068,6 +7164,75 @@ public final class TextSecureProtos { return this; } + // optional uint32 size = 4; + private int size_ ; + /** + * optional uint32 size = 4; + */ + public boolean hasSize() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional uint32 size = 4; + */ + public int getSize() { + return size_; + } + /** + * optional uint32 size = 4; + */ + public Builder setSize(int value) { + bitField0_ |= 0x00000008; + size_ = value; + onChanged(); + return this; + } + /** + * optional uint32 size = 4; + */ + public Builder clearSize() { + bitField0_ = (bitField0_ & ~0x00000008); + size_ = 0; + onChanged(); + return this; + } + + // optional bytes thumbnail = 5; + private com.google.protobuf.ByteString thumbnail_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes thumbnail = 5; + */ + public boolean hasThumbnail() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional bytes thumbnail = 5; + */ + public com.google.protobuf.ByteString getThumbnail() { + return thumbnail_; + } + /** + * optional bytes thumbnail = 5; + */ + public Builder setThumbnail(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000010; + thumbnail_ = value; + onChanged(); + return this; + } + /** + * optional bytes thumbnail = 5; + */ + public Builder clearThumbnail() { + bitField0_ = (bitField0_ & ~0x00000010); + thumbnail_ = getDefaultInstance().getThumbnail(); + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:textsecure.AttachmentPointer) } @@ -11161,23 +11326,24 @@ public final class TextSecureProtos { "\004blob\030\001 \001(\0132\035.textsecure.AttachmentPoint" + "er\032l\n\007Request\0222\n\004type\030\001 \001(\0162$.textsecure" + ".SyncMessage.Request.Type\"-\n\004Type\022\013\n\007UNK" + - "NOWN\020\000\022\014\n\010CONTACTS\020\001\022\n\n\006GROUPS\020\002\"A\n\021Atta" + + "NOWN\020\000\022\014\n\010CONTACTS\020\001\022\n\n\006GROUPS\020\002\"b\n\021Atta" + "chmentPointer\022\n\n\002id\030\001 \001(\006\022\023\n\013contentType" + - "\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\"\315\001\n\014GroupContext\022\n\n\002" + - "id\030\001 \001(\014\022+\n\004type\030\002 \001(\0162\035.textsecure.Grou", - "pContext.Type\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030\004" + - " \003(\t\022-\n\006avatar\030\005 \001(\0132\035.textsecure.Attach" + - "mentPointer\"6\n\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UPDA" + - "TE\020\001\022\013\n\007DELIVER\020\002\022\010\n\004QUIT\020\003\"\220\001\n\016ContactD" + - "etails\022\016\n\006number\030\001 \001(\t\022\014\n\004name\030\002 \001(\t\0221\n\006" + - "avatar\030\003 \001(\0132!.textsecure.ContactDetails" + - ".Avatar\032-\n\006Avatar\022\023\n\013contentType\030\001 \001(\t\022\016" + - "\n\006length\030\002 \001(\r\"\231\001\n\014GroupDetails\022\n\n\002id\030\001 " + - "\001(\014\022\014\n\004name\030\002 \001(\t\022\017\n\007members\030\003 \003(\t\022/\n\006av" + - "atar\030\004 \001(\0132\037.textsecure.GroupDetails.Ava", - "tar\032-\n\006Avatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006le" + - "ngth\030\002 \001(\rB?\n+org.whispersystems.textsec" + - "ure.internal.pushB\020TextSecureProtos" + "\030\002 \001(\t\022\013\n\003key\030\003 \001(\014\022\014\n\004size\030\004 \001(\r\022\021\n\tthu" + + "mbnail\030\005 \001(\014\"\315\001\n\014GroupContext\022\n\n\002id\030\001 \001(", + "\014\022+\n\004type\030\002 \001(\0162\035.textsecure.GroupContex" + + "t.Type\022\014\n\004name\030\003 \001(\t\022\017\n\007members\030\004 \003(\t\022-\n" + + "\006avatar\030\005 \001(\0132\035.textsecure.AttachmentPoi" + + "nter\"6\n\004Type\022\013\n\007UNKNOWN\020\000\022\n\n\006UPDATE\020\001\022\013\n" + + "\007DELIVER\020\002\022\010\n\004QUIT\020\003\"\220\001\n\016ContactDetails\022" + + "\016\n\006number\030\001 \001(\t\022\014\n\004name\030\002 \001(\t\0221\n\006avatar\030" + + "\003 \001(\0132!.textsecure.ContactDetails.Avatar" + + "\032-\n\006Avatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006lengt" + + "h\030\002 \001(\r\"\231\001\n\014GroupDetails\022\n\n\002id\030\001 \001(\014\022\014\n\004" + + "name\030\002 \001(\t\022\017\n\007members\030\003 \003(\t\022/\n\006avatar\030\004 ", + "\001(\0132\037.textsecure.GroupDetails.Avatar\032-\n\006" + + "Avatar\022\023\n\013contentType\030\001 \001(\t\022\016\n\006length\030\002 " + + "\001(\rB?\n+org.whispersystems.textsecure.int" + + "ernal.pushB\020TextSecureProtos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -11237,7 +11403,7 @@ public final class TextSecureProtos { internal_static_textsecure_AttachmentPointer_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_textsecure_AttachmentPointer_descriptor, - new java.lang.String[] { "Id", "ContentType", "Key", }); + new java.lang.String[] { "Id", "ContentType", "Key", "Size", "Thumbnail", }); internal_static_textsecure_GroupContext_descriptor = getDescriptor().getMessageTypes().get(5); internal_static_textsecure_GroupContext_fieldAccessorTable = new diff --git a/protobuf/TextSecure.proto b/protobuf/TextSecure.proto index d561175280..91514c4bc9 100644 --- a/protobuf/TextSecure.proto +++ b/protobuf/TextSecure.proto @@ -72,6 +72,8 @@ message AttachmentPointer { optional fixed64 id = 1; optional string contentType = 2; optional bytes key = 3; + optional uint32 size = 4; + optional bytes thumbnail = 5; } message GroupContext {