mirror of https://github.com/oxen-io/session-ios
Sync Contacts with Desktop
* TODO refactor attachment sending to work without thread/message * TODO de-dupe attachment pointer building code // FREEBIEpull/1/head
parent
fe7171dd93
commit
98d1c59bfc
@ -0,0 +1,12 @@
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "ContactsManagerProtocol.h"
|
||||
#import "OWSOutgoingSyncMessage.h"
|
||||
|
||||
@interface OWSSyncContactsMessage : OWSOutgoingSyncMessage
|
||||
|
||||
- (instancetype)initWithContactsManager:(id<ContactsManagerProtocol>)contactsManager;
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (NSData *)buildPlainTextAttachmentData;
|
||||
|
||||
@end
|
@ -0,0 +1,124 @@
|
||||
// Copyright © 2016 Open Whisper Systems. All rights reserved.
|
||||
|
||||
#import "OWSSyncContactsMessage.h"
|
||||
#import "Contact.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "OWSSignalServiceProtos.pb.h"
|
||||
#import "TSAttachment.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import <ProtocolBuffers/CodedOutputStream.h>
|
||||
|
||||
@interface OWSSyncContactsMessage ()
|
||||
|
||||
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OWSSyncContactsMessage
|
||||
|
||||
- (instancetype)initWithContactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
{
|
||||
self = [super initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:nil messageBody:nil attachmentIds:@[]];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_contactsManager = contactsManager;
|
||||
|
||||
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];
|
||||
|
||||
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 setBlob:[attachmentBuilder build]];
|
||||
|
||||
[syncMessageBuilder setContacts:[contactsBuilder build]];
|
||||
|
||||
return [syncMessageBuilder build];
|
||||
}
|
||||
|
||||
- (NSData *)buildPlainTextAttachmentData
|
||||
{
|
||||
NSString *fileName =
|
||||
[NSString stringWithFormat:@"%@_%@", [[NSProcessInfo processInfo] globallyUniqueString], @"contacts.dat"];
|
||||
NSURL *fileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:fileName]];
|
||||
NSOutputStream *fileOutputStream = [NSOutputStream outputStreamWithURL:fileURL append:NO];
|
||||
[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];
|
||||
|
||||
NSData *avatarPng;
|
||||
if (contact.image) {
|
||||
OWSSignalServiceProtosContactDetailsAvatarBuilder *avatarBuilder =
|
||||
[OWSSignalServiceProtosContactDetailsAvatarBuilder new];
|
||||
|
||||
[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]];
|
||||
}
|
||||
|
||||
NSData *contactData = [[contactBuilder build] data];
|
||||
|
||||
uint32_t contactDataLength = (uint32_t)contactData.length;
|
||||
[outputStream writeRawVarint32:contactDataLength];
|
||||
[outputStream writeRawData:contactData];
|
||||
|
||||
if (contact.image) {
|
||||
[outputStream writeRawData:avatarPng];
|
||||
}
|
||||
}
|
||||
[outputStream flush];
|
||||
[fileOutputStream close];
|
||||
|
||||
// TODO pass stream to builder rather than data as a singular hulk.
|
||||
[NSInputStream inputStreamWithURL:fileURL];
|
||||
NSError *error;
|
||||
NSData *data = [NSData dataWithContentsOfURL:fileURL options:NSDataReadingMappedIfSafe error:&error];
|
||||
if (error) {
|
||||
DDLogError(@"Failed to read back contact data after writing it to %@ with error:%@", fileURL, error);
|
||||
}
|
||||
return data;
|
||||
|
||||
// TODO delete contacts file.
|
||||
// NSError *error;
|
||||
// NSFileManager *manager = [NSFileManager defaultManager];
|
||||
// [manager removeItemAtURL:fileURL error:&error];
|
||||
// if (error) {
|
||||
// DDLogError(@"Failed removing temp file at url:%@ with error:%@", fileURL, error);
|
||||
// }
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in New Issue