Merge branch 'mkirk/contact-sharing-via-sae'

pull/1/head
Michael Kirk 7 years ago
commit 6ecaf01b95

@ -31,6 +31,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
@property (nonatomic) TSThread *thread;
@property (nonatomic, readonly, weak) id<ShareViewDelegate> shareViewDelegate;
@property (nonatomic, readonly) UIProgressView *progressView;
@property (nonatomic, readonly) YapDatabaseConnection *editingDBConnection;
@property (atomic, nullable) TSOutgoingMessage *outgoingMessage;
@end
@ -46,6 +47,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
return self;
}
_editingDBConnection = [OWSPrimaryStorage.sharedManager newDatabaseConnection];
_shareViewDelegate = shareViewDelegate;
self.selectThreadViewDelegate = self;
@ -148,22 +150,30 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
if (self.attachment.isConvertibleToContactShare) {
NSData *data = self.attachment.data;
OWSContact *_Nullable contact = [OWSContacts contactForVCardData:data];
if (!contact) {
// This should never happen since we verify that the contact can be parsed when building the attachment.
OWSFail(@"%@ could not parse contact share.", self.logTag);
[self.shareViewDelegate shareViewWasCancelled];
Contact *_Nullable contact = [Contact contactWithVCardData:data];
OWSContact *_Nullable contactShareRecord = [OWSContacts contactForSystemContact:contact.cnContact];
if (!contactShareRecord) {
DDLogError(@"%@ Could not convert system contact.", self.logTag);
return;
}
// TODO: Populate avatar image.
BOOL isProfileAvatar = NO;
NSData *_Nullable avatarImageData = nil;
contact.isProfileAvatar = isProfileAvatar;
NSData *_Nullable avatarImageData = contact.imageData;
for (NSString *recipientId in contact.textSecureIdentifiers) {
if (avatarImageData) {
break;
}
avatarImageData = [self.contactsManager profileImageDataForPhoneIdentifier:recipientId];
if (avatarImageData) {
isProfileAvatar = YES;
}
}
contactShareRecord.isProfileAvatar = isProfileAvatar;
ContactShareViewModel *contactShare =
[[ContactShareViewModel alloc] initWithContactShareRecord:contact avatarImageData:avatarImageData];
[[ContactShareViewModel alloc] initWithContactShareRecord:contactShareRecord
avatarImageData:avatarImageData];
ApproveContactShareViewController *approvalVC =
[[ApproveContactShareViewController alloc] initWithContactShare:contactShare
@ -282,29 +292,37 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
#pragma mark - ApproveContactShareViewControllerDelegate
- (void)approveContactShare:(ApproveContactShareViewController *)approvalViewController
didApproveContactShare:(OWSContact *)contactShare
didApproveContactShare:(ContactShareViewModel *)contactShare
{
DDLogInfo(@"%@ in %s", self.logTag, __PRETTY_FUNCTION__);
[ThreadUtil addThreadToProfileWhitelistIfEmptyContactThread:self.thread];
[self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) {
OWSAssertIsOnMainThread();
__block TSOutgoingMessage *outgoingMessage = nil;
outgoingMessage = [ThreadUtil sendMessageWithContactShare:contactShare
inThread:self.thread
messageSender:self.messageSender
completion:^(NSError *_Nullable error) {
sendCompletion(error, outgoingMessage);
}];
// This is necessary to show progress.
self.outgoingMessage = outgoingMessage;
[self.editingDBConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
if (contactShare.avatarImage) {
[contactShare.dbRecord saveAvatarImage:contactShare.avatarImage transaction:transaction];
}
}
completionBlock:^{
__block TSOutgoingMessage *outgoingMessage = nil;
outgoingMessage = [ThreadUtil sendMessageWithContactShare:contactShare.dbRecord
inThread:self.thread
messageSender:self.messageSender
completion:^(NSError *_Nullable error) {
sendCompletion(error, outgoingMessage);
}];
// This is necessary to show progress.
self.outgoingMessage = outgoingMessage;
}];
}
fromViewController:approvalViewController];
}
- (void)approveContactShare:(ApproveContactShareViewController *)approvalViewController
didCancelContactShare:(OWSContact *)contactShare
didCancelContactShare:(ContactShareViewModel *)contactShare
{
DDLogInfo(@"%@ in %s", self.logTag, __PRETTY_FUNCTION__);

@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
#if TARGET_OS_IOS
- (instancetype)initWithSystemContact:(CNContact *)contact NS_AVAILABLE_IOS(9_0);
+ (nullable Contact *)contactWithVCardData:(NSData *)data;
- (NSString *)nameForPhoneNumber:(NSString *)recipientId;

@ -106,11 +106,25 @@ NS_ASSUME_NONNULL_BEGIN
if (contact.thumbnailImageData) {
_imageData = [contact.thumbnailImageData copy];
} else if (contact.imageData) {
// This only occurs when sharing a contact via the share extension
_imageData = [contact.imageData copy];
}
return self;
}
+ (nullable Contact *)contactWithVCardData:(NSData *)data
{
CNContact *_Nullable cnContact = [self cnContactWithVCardData:data];
if (!cnContact) {
return nil;
}
return [[self alloc] initWithSystemContact:cnContact];
}
- (nullable UIImage *)image
{
if (_image) {
@ -290,6 +304,28 @@ NS_ASSUME_NONNULL_BEGIN
return hash;
}
#pragma mark - CNContactConverters
+ (nullable CNContact *)cnContactWithVCardData:(NSData *)data
{
OWSAssert(data);
NSError *error;
NSArray<CNContact *> *_Nullable contacts = [CNContactVCardSerialization contactsWithData:data error:&error];
if (!contacts || error) {
OWSProdLogAndFail(@"%@ could not parse vcard: %@", self.logTag, error);
return nil;
}
if (contacts.count < 1) {
OWSProdLogAndFail(@"%@ empty vcard: %@", self.logTag, error);
return nil;
}
if (contacts.count > 1) {
OWSProdLogAndFail(@"%@ more than one contact in vcard: %@", self.logTag, error);
}
return contacts.firstObject;
}
- (CNContact *)buildCNContactMergedWithNewContact:(CNContact *)newCNContact
{
CNMutableContact *_Nullable mergedCNContact = [self.cnContact mutableCopy];

@ -160,20 +160,12 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value);
// TODO: Move to separate source file, rename to OWSContactConversion.
@interface OWSContacts : NSObject
#pragma mark - VCard Serialization
+ (nullable CNContact *)systemContactForVCardData:(NSData *)data;
+ (nullable NSData *)vCardDataForSystemContact:(CNContact *)systemContact;
#pragma mark - System Contact Conversion
// `contactForSystemContact` does *not* handle avatars. That must be delt with by the caller
+ (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact;
+ (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData;
#pragma mark -
+ (nullable OWSContact *)contactForVCardData:(NSData *)data;
+ (nullable NSData *)vCardDataContact:(OWSContact *)contact;
+ (nullable CNContact *)systemContactForContact:(OWSContact *)contact imageData:(nullable NSData *)imageData;
#pragma mark - Proto Serialization

@ -556,50 +556,9 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
@implementation OWSContacts
#pragma mark - VCard Serialization
+ (nullable CNContact *)systemContactForVCardData:(NSData *)data
{
OWSAssert(data);
NSError *error;
NSArray<CNContact *> *_Nullable contacts = [CNContactVCardSerialization contactsWithData:data error:&error];
if (!contacts || error) {
OWSProdLogAndFail(@"%@ could not parse vcard: %@", self.logTag, error);
return nil;
}
if (contacts.count < 1) {
OWSProdLogAndFail(@"%@ empty vcard: %@", self.logTag, error);
return nil;
}
if (contacts.count > 1) {
OWSProdLogAndFail(@"%@ more than one contact in vcard: %@", self.logTag, error);
}
return contacts.firstObject;
}
+ (nullable NSData *)vCardDataForSystemContact:(CNContact *)systemContact
{
OWSAssert(systemContact);
NSError *error;
NSData *_Nullable data = [CNContactVCardSerialization dataWithContacts:@[
systemContact,
]
error:&error];
if (!data || error) {
OWSProdLogAndFail(@"%@ could not serialize to vcard: %@", self.logTag, error);
return nil;
}
if (data.length < 1) {
OWSProdLogAndFail(@"%@ empty vcard data: %@", self.logTag, error);
return nil;
}
return data;
}
#pragma mark - System Contact Conversion
// `contactForSystemContact` does *not* handle avatars. That must be delt with by the caller
+ (nullable OWSContact *)contactForSystemContact:(CNContact *)systemContact
{
if (!systemContact) {
@ -690,11 +649,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
}
contact.addresses = addresses;
// TODO: Avatar
// @property (readonly, copy, nullable, NS_NONATOMIC_IOSONLY) NSData *imageData;
// @property (readonly, copy, nullable, NS_NONATOMIC_IOSONLY) NSData *thumbnailImageData;
[contact ensureDisplayName];
return contact;
@ -802,31 +756,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
return systemContact;
}
#pragma mark -
+ (nullable OWSContact *)contactForVCardData:(NSData *)data
{
OWSAssert(data);
CNContact *_Nullable systemContact = [self systemContactForVCardData:data];
if (!systemContact) {
return nil;
}
return [self contactForSystemContact:systemContact];
}
+ (nullable NSData *)vCardDataContact:(OWSContact *)contact
{
OWSAssert(contact);
// TODO pass in image for vcard
CNContact *_Nullable systemContact = [self systemContactForContact:contact imageData:nil];
if (!systemContact) {
return nil;
}
return [self vCardDataForSystemContact:systemContact];
}
#pragma mark - Proto Serialization
+ (nullable OWSSignalServiceProtosDataMessageContact *)protoForContact:(OWSContact *)contact

@ -721,7 +721,7 @@ public class ShareViewController: UIViewController, ShareViewDelegate, SAEFailed
utiType: kUTTypeVCard as String) {
customFileName = "Contact.vcf"
if let contactShare = OWSContacts.contact(forVCardData: data) {
if Contact(vCardData: data) != nil {
isConvertibleToContactShare = true
} else {
Logger.error("\(strongSelf.logTag) could not parse vcard.")

Loading…
Cancel
Save