From 69da0b3c2594927ff6dce256188edf9e83c1afaf Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Sun, 28 Aug 2016 18:31:27 -0400 Subject: [PATCH] Sync Groups with Desktop // FREEBIE --- .../OWSOutgoingSentMessageTranscript.m | 2 +- .../DeviceSyncing/OWSOutgoingSyncMessage.m | 3 +- .../DeviceSyncing/OWSSyncContactsMessage.m | 29 ++------ .../DeviceSyncing/OWSSyncGroupsMessage.h | 2 + .../DeviceSyncing/OWSSyncGroupsMessage.m | 71 ++++++++++--------- src/Messages/Interactions/TSOutgoingMessage.h | 11 ++- src/Messages/Interactions/TSOutgoingMessage.m | 53 +++++++------- 7 files changed, 82 insertions(+), 89 deletions(-) diff --git a/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m b/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m index d98a8f6b6..329fe64b0 100644 --- a/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m +++ b/src/Messages/DeviceSyncing/OWSOutgoingSentMessageTranscript.m @@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN [sentBuilder setDestination:self.message.recipientIdentifier]; [sentBuilder setMessage:[self.message buildDataMessage]]; - [syncMessageBuilder setSent:[sentBuilder build]]; + [syncMessageBuilder setSentBuilder:sentBuilder]; return [syncMessageBuilder build]; } diff --git a/src/Messages/DeviceSyncing/OWSOutgoingSyncMessage.m b/src/Messages/DeviceSyncing/OWSOutgoingSyncMessage.m index 4c2af2cb3..f5cc5b9e0 100644 --- a/src/Messages/DeviceSyncing/OWSOutgoingSyncMessage.m +++ b/src/Messages/DeviceSyncing/OWSOutgoingSyncMessage.m @@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN - (OWSSignalServiceProtosSyncMessage *)buildSyncMessage { - NSAssert(NO, @"buildSyncMessage must be overridden in suclass"); + NSAssert(NO, @"buildSyncMessage must be overridden in subclass"); OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new]; return [syncMessageBuilder build]; @@ -28,7 +28,6 @@ NS_ASSUME_NONNULL_BEGIN return [[contentBuilder build] data]; } - @end NS_ASSUME_NONNULL_END diff --git a/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m b/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m index afc85628b..052e00525 100644 --- a/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m +++ b/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m @@ -31,36 +31,18 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - // no-op - - // There's no need to save this message, since it's not displayed to the user. - // Furthermore if we did save it, we probably don't want to save the conctactsManager property. -} - - (OWSSignalServiceProtosSyncMessage *)buildSyncMessage { OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new]; + OWSSignalServiceProtosSyncMessageContactsBuilder *contactsBuilder = + [OWSSignalServiceProtosSyncMessageContactsBuilder new]; + [syncMessageBuilder setContactsBuilder:contactsBuilder]; if (self.attachmentIds.count != 1) { DDLogError(@"expected sync contact message to have exactly one attachment, but found %lu", (unsigned long)self.attachmentIds.count); } - TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:self.attachmentIds[0]]; - - OWSSignalServiceProtosAttachmentPointerBuilder *attachmentBuilder = - [OWSSignalServiceProtosAttachmentPointerBuilder new]; - - [attachmentBuilder setId:[attachment.identifier unsignedLongLongValue]]; - [attachmentBuilder setContentType:attachment.contentType]; - [attachmentBuilder setKey:attachment.encryptionKey]; - - OWSSignalServiceProtosSyncMessageContactsBuilder *contactsBuilder = - [OWSSignalServiceProtosSyncMessageContactsBuilder new]; - [contactsBuilder setBlobBuilder:attachmentBuilder]; - - [syncMessageBuilder setContacts:[contactsBuilder build]]; + [contactsBuilder setBlobBuilder:[self attachmentBuilderForAttachmentId:self.attachmentIds[0]]]; return [syncMessageBuilder build]; } @@ -88,9 +70,8 @@ NS_ASSUME_NONNULL_BEGIN [avatarBuilder setContentType:@"image/png"]; avatarPng = UIImagePNGRepresentation(contact.image); - // TODO check datasize and safely cast to int [avatarBuilder setLength:(uint32_t)avatarPng.length]; - [contactBuilder setAvatar:[avatarBuilder build]]; + [contactBuilder setAvatarBuilder:avatarBuilder]; } NSData *contactData = [[contactBuilder build] data]; diff --git a/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h b/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h index 5d6ada7b4..f86a2ada8 100644 --- a/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h +++ b/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.h @@ -1,5 +1,7 @@ // Copyright © 2016 Open Whisper Systems. All rights reserved. +#import "OWSOutgoingSyncMessage.h" + NS_ASSUME_NONNULL_BEGIN @interface OWSSyncGroupsMessage : OWSOutgoingSyncMessage diff --git a/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m b/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m index 47221c422..0dd821bf5 100644 --- a/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m +++ b/src/Messages/DeviceSyncing/OWSSyncGroupsMessage.m @@ -1,12 +1,21 @@ // Copyright © 2016 Open Whisper Systems. All rights reserved. #import "OWSSyncGroupsMessage.h" +#import "NSDate+millisecondTimeStamp.h" #import "OWSSignalServiceProtos.pb.h" +#import "TSAttachment.h" +#import "TSGroupModel.h" +#import "TSGroupThread.h" NS_ASSUME_NONNULL_BEGIN @implementation OWSSyncGroupsMessage +- (instancetype)init +{ + return [super initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:nil messageBody:nil attachmentIds:@[]]; +} + - (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { // no-op @@ -18,25 +27,15 @@ NS_ASSUME_NONNULL_BEGIN - (OWSSignalServiceProtosSyncMessage *)buildSyncMessage { OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new]; + OWSSignalServiceProtosSyncMessageGroupsBuilder *groupsBuilder = + [OWSSignalServiceProtosSyncMessageGroupsBuilder new]; + [syncMessageBuilder setGroupsBuilder:groupsBuilder]; if (self.attachmentIds.count != 1) { - DDLogError(@"expected sync contact message to have exactly one attachment, but found %lu", + DDLogError(@"expected sync groups message to have exactly one attachment, but found %lu", (unsigned long)self.attachmentIds.count); } - TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:self.attachmentIds[0]]; - - OWSSignalServiceProtosAttachmentPointerBuilder *attachmentBuilder = - [OWSSignalServiceProtosAttachmentPointerBuilder new]; - - [attachmentBuilder setId:[attachment.identifier unsignedLongLongValue]]; - [attachmentBuilder setContentType:attachment.contentType]; - [attachmentBuilder setKey:attachment.encryptionKey]; - - OWSSignalServiceProtosSyncMessageContactsBuilder *contactsBuilder = - [OWSSignalServiceProtosSyncMessageContactsBuilder new]; - [contactsBuilder setBlobBuilder:attachmentBuilder]; - - [syncMessageBuilder setContacts:[contactsBuilder build]]; + [groupsBuilder setBlobBuilder:[self attachmentBuilderForAttachmentId:self.attachmentIds[0]]]; return [syncMessageBuilder build]; } @@ -50,35 +49,39 @@ NS_ASSUME_NONNULL_BEGIN [fileOutputStream open]; PBCodedOutputStream *outputStream = [PBCodedOutputStream streamWithOutputStream:fileOutputStream]; - DDLogInfo(@"Writing contacts data to %@", fileURL); - for (Contact *contact in self.contactsManager.signalContacts) { - OWSSignalServiceProtosContactDetailsBuilder *contactBuilder = [OWSSignalServiceProtosContactDetailsBuilder new]; - - [contactBuilder setName:contact.fullName]; - [contactBuilder setNumber:contact.textSecureIdentifiers.firstObject]; + DDLogInfo(@"Writing groups data to %@", fileURL); + [TSGroupThread enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) { + if (![obj isKindOfClass:[TSGroupThread class]]) { + DDLogError(@"Unexpected class in group collection: %@", obj); + return; + } + TSGroupModel *group = ((TSGroupThread *)obj).groupModel; + OWSSignalServiceProtosGroupDetailsBuilder *groupBuilder = [OWSSignalServiceProtosGroupDetailsBuilder new]; + [groupBuilder setId:group.groupId]; + [groupBuilder setName:group.groupName]; + [groupBuilder setMembersArray:group.groupMemberIds]; NSData *avatarPng; - if (contact.image) { - OWSSignalServiceProtosContactDetailsAvatarBuilder *avatarBuilder = - [OWSSignalServiceProtosContactDetailsAvatarBuilder new]; + if (group.groupImage) { + OWSSignalServiceProtosGroupDetailsAvatarBuilder *avatarBuilder = + [OWSSignalServiceProtosGroupDetailsAvatarBuilder new]; [avatarBuilder setContentType:@"image/png"]; - avatarPng = UIImagePNGRepresentation(contact.image); - // TODO check datasize and safely cast to int + avatarPng = UIImagePNGRepresentation(group.groupImage); [avatarBuilder setLength:(uint32_t)avatarPng.length]; - [contactBuilder setAvatar:[avatarBuilder build]]; + [groupBuilder setAvatarBuilder:avatarBuilder]; } - NSData *contactData = [[contactBuilder build] data]; + NSData *groupData = [[groupBuilder build] data]; + uint32_t groupDataLength = (uint32_t)groupData.length; + [outputStream writeRawVarint32:groupDataLength]; + [outputStream writeRawData:groupData]; - uint32_t contactDataLength = (uint32_t)contactData.length; - [outputStream writeRawVarint32:contactDataLength]; - [outputStream writeRawData:contactData]; - - if (contact.image) { + if (avatarPng) { [outputStream writeRawData:avatarPng]; } - } + }]; + [outputStream flush]; [fileOutputStream close]; diff --git a/src/Messages/Interactions/TSOutgoingMessage.h b/src/Messages/Interactions/TSOutgoingMessage.h index 23045cac3..121bb6147 100644 --- a/src/Messages/Interactions/TSOutgoingMessage.h +++ b/src/Messages/Interactions/TSOutgoingMessage.h @@ -5,7 +5,7 @@ NS_ASSUME_NONNULL_BEGIN -@class OWSSignalServiceProtosDataMessage; +@class OWSSignalServiceProtosAttachmentPointerBuilder; @interface TSOutgoingMessage : TSMessage @@ -36,6 +36,15 @@ typedef NS_ENUM(NSInteger, TSOutgoingMessageState) { */ - (BOOL)shouldSyncTranscript; +/** + * @param attachmentStream + * Containing the meta data used when populating the attachment proto + * + * @return + * An attachment builder suitable for including in various container protobuf builders + */ +- (OWSSignalServiceProtosAttachmentPointerBuilder *)attachmentBuilderForAttachmentId:(NSString *)attachmentId; + @end NS_ASSUME_NONNULL_END diff --git a/src/Messages/Interactions/TSOutgoingMessage.m b/src/Messages/Interactions/TSOutgoingMessage.m index 1bc96d384..8313e6014 100644 --- a/src/Messages/Interactions/TSOutgoingMessage.m +++ b/src/Messages/Interactions/TSOutgoingMessage.m @@ -45,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN OWSSignalServiceProtosDataMessageBuilder *builder = [OWSSignalServiceProtosDataMessageBuilder new]; [builder setBody:self.body]; - BOOL processAttachments = YES; + BOOL attachmentWasGroupAvatar = NO; if ([thread isKindOfClass:[TSGroupThread class]]) { TSGroupThread *gThread = (TSGroupThread *)thread; OWSSignalServiceProtosGroupContextBuilder *groupBuilder = [OWSSignalServiceProtosGroupContextBuilder new]; @@ -56,19 +56,11 @@ NS_ASSUME_NONNULL_BEGIN break; case TSGroupMessageUpdate: case TSGroupMessageNew: { - if (gThread.groupModel.groupImage != nil && [self.attachmentIds count] == 1) { - id dbObject = [TSAttachmentStream fetchObjectWithUniqueID:self.attachmentIds[0]]; - if ([dbObject isKindOfClass:[TSAttachmentStream class]]) { - TSAttachmentStream *attachment = (TSAttachmentStream *)dbObject; - OWSSignalServiceProtosAttachmentPointerBuilder *attachmentbuilder = - [OWSSignalServiceProtosAttachmentPointerBuilder new]; - [attachmentbuilder setId:[attachment.identifier unsignedLongLongValue]]; - [attachmentbuilder setContentType:attachment.contentType]; - [attachmentbuilder setKey:attachment.encryptionKey]; - [groupBuilder setAvatar:[attachmentbuilder build]]; - processAttachments = NO; - } + if (gThread.groupModel.groupImage != nil && self.attachmentIds.count == 1) { + attachmentWasGroupAvatar = YES; + [groupBuilder setAvatarBuilder:[self attachmentBuilderForAttachmentId:self.attachmentIds[0]]]; } + [groupBuilder setMembersArray:gThread.groupModel.groupMemberIds]; [groupBuilder setName:gThread.groupModel.groupName]; [groupBuilder setType:OWSSignalServiceProtosGroupContextTypeUpdate]; @@ -81,22 +73,12 @@ NS_ASSUME_NONNULL_BEGIN [groupBuilder setId:gThread.groupModel.groupId]; [builder setGroup:groupBuilder.build]; } - if (processAttachments) { + if (!attachmentWasGroupAvatar) { NSMutableArray *attachments = [NSMutableArray new]; for (NSString *attachmentId in self.attachmentIds) { - id dbObject = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; - - if ([dbObject isKindOfClass:[TSAttachmentStream class]]) { - TSAttachmentStream *attachment = (TSAttachmentStream *)dbObject; - - OWSSignalServiceProtosAttachmentPointerBuilder *attachmentbuilder = - [OWSSignalServiceProtosAttachmentPointerBuilder new]; - [attachmentbuilder setId:[attachment.identifier unsignedLongLongValue]]; - [attachmentbuilder setContentType:attachment.contentType]; - [attachmentbuilder setKey:attachment.encryptionKey]; - - [attachments addObject:[attachmentbuilder build]]; - } + OWSSignalServiceProtosAttachmentPointerBuilder *attachmentBuilder = + [self attachmentBuilderForAttachmentId:attachmentId]; + [attachments addObject:[attachmentBuilder build]]; } [builder setAttachmentsArray:attachments]; } @@ -113,6 +95,23 @@ NS_ASSUME_NONNULL_BEGIN return !self.hasSyncedTranscript; } +- (OWSSignalServiceProtosAttachmentPointerBuilder *)attachmentBuilderForAttachmentId:(NSString *)attachmentId +{ + TSAttachment *attachment = [TSAttachmentStream fetchObjectWithUniqueID:attachmentId]; + if (![attachment isKindOfClass:[TSAttachmentStream class]]) { + DDLogError(@"Unexpected type for attachment builder: %@", attachment); + return nil; + } + TSAttachmentStream *attachmentStream = (TSAttachmentStream *)attachment; + + OWSSignalServiceProtosAttachmentPointerBuilder *builder = [OWSSignalServiceProtosAttachmentPointerBuilder new]; + [builder setId:[attachmentStream.identifier unsignedLongLongValue]]; + [builder setContentType:attachmentStream.contentType]; + [builder setKey:attachmentStream.encryptionKey]; + + return builder; +} + @end NS_ASSUME_NONNULL_END