From 757234d309c2e95ebc0b5fdf79d78fa19bf681f1 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 30 Apr 2018 16:42:14 -0400 Subject: [PATCH] Populate contact share protos. --- .../ViewControllers/DebugUI/DebugUIMessages.m | 4 - .../Messages/Interactions/OWSContactShare.h | 8 + .../Messages/Interactions/OWSContactShare.m | 73 ++++++ .../Messages/Interactions/TSOutgoingMessage.m | 220 +++++++++++++++--- 4 files changed, 268 insertions(+), 37 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index eeeb8444d..5f5ce2149 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -3020,10 +3020,6 @@ typedef OWSContactShare * (^OWSContactShareBlock)(void); address2, ]; - // @property (nonatomic, nullable) - // NSArray - // *addresses; - // TODO: Avatar return contactShare; }]]; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContactShare.h b/SignalServiceKit/src/Messages/Interactions/OWSContactShare.h index f4b272574..b952795b4 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContactShare.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContactShare.h @@ -25,6 +25,8 @@ typedef NS_ENUM(NSUInteger, OWSContactSharePhoneType) { @property (nonatomic, readonly) NSString *phoneNumber; +- (BOOL)isValid; + @end #pragma mark - @@ -44,6 +46,8 @@ typedef NS_ENUM(NSUInteger, OWSContactShareEmailType) { @property (nonatomic, readonly) NSString *email; +- (BOOL)isValid; + @end #pragma mark - @@ -68,6 +72,8 @@ typedef NS_ENUM(NSUInteger, OWSContactShareAddressType) { @property (nonatomic, readonly, nullable) NSString *postcode; @property (nonatomic, readonly, nullable) NSString *country; +- (BOOL)isValid; + @end #pragma mark - @@ -94,6 +100,8 @@ typedef NS_ENUM(NSUInteger, OWSContactShareAddressType) { + (OWSContactShare *_Nullable)contactShareForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage transaction:(YapDatabaseReadWriteTransaction *)transaction; +- (BOOL)isValid; + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContactShare.m b/SignalServiceKit/src/Messages/Interactions/OWSContactShare.m index 082d6c2e1..bb4c0c98e 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContactShare.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContactShare.m @@ -3,8 +3,10 @@ // #import "OWSContactShare.h" +#import "NSString+SSK.h" #import "OWSContactShare+Private.h" #import "OWSSignalServiceProtos.pb.h" +#import "PhoneNumber.h" #import "TSAttachment.h" #import @@ -23,6 +25,21 @@ NS_ASSUME_NONNULL_BEGIN @implementation OWSContactSharePhoneNumber +- (BOOL)isValid +{ + if (![PhoneNumber tryParsePhoneNumberFromE164:self.phoneNumber]) { + return NO; + } + switch (self.phoneType) { + case OWSContactSharePhoneType_Home: + case OWSContactSharePhoneType_Mobile: + case OWSContactSharePhoneType_Work: + return YES; + default: + return self.label.ows_stripped.length > 0; + } +} + @end #pragma mark - @@ -40,6 +57,21 @@ NS_ASSUME_NONNULL_BEGIN @implementation OWSContactShareEmail +- (BOOL)isValid +{ + if (self.email.ows_stripped.length < 1) { + return NO; + } + switch (self.emailType) { + case OWSContactShareEmailType_Home: + case OWSContactShareEmailType_Mobile: + case OWSContactShareEmailType_Work: + return YES; + default: + return self.label.ows_stripped.length > 0; + } +} + @end #pragma mark - @@ -63,6 +95,23 @@ NS_ASSUME_NONNULL_BEGIN @implementation OWSContactShareAddress +- (BOOL)isValid +{ + if (self.street.ows_stripped.length < 1 && self.pobox.ows_stripped.length < 1 + && self.neighborhood.ows_stripped.length < 1 && self.city.ows_stripped.length < 1 + && self.region.ows_stripped.length < 1 && self.postcode.ows_stripped.length < 1 + && self.country.ows_stripped.length < 1) { + return NO; + } + switch (self.addressType) { + case OWSContactShareAddressType_Home: + case OWSContactShareAddressType_Work: + return YES; + default: + return self.label.ows_stripped.length > 0; + } +} + @end #pragma mark - @@ -255,6 +304,30 @@ NS_ASSUME_NONNULL_BEGIN return result; } +- (BOOL)isValid +{ + if (self.givenName.ows_stripped.length < 1 && self.familyName.ows_stripped.length) { + return NO; + } + + for (OWSContactSharePhoneNumber *phoneNumber in self.phoneNumbers) { + if (phoneNumber.isValid) { + return YES; + } + } + for (OWSContactShareEmail *email in self.emails) { + if (email.isValid) { + return YES; + } + } + for (OWSContactShareAddress *address in self.addresses) { + if (address.isValid) { + return YES; + } + } + return NO; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 1e5b9c7a5..345743e14 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -4,6 +4,8 @@ #import "TSOutgoingMessage.h" #import "NSDate+OWS.h" +#import "NSString+SSK.h" +#import "OWSContactShare.h" #import "OWSMessageSender.h" #import "OWSOutgoingSyncMessage.h" #import "OWSPrimaryStorage.h" @@ -784,46 +786,198 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt } [builder setAttachmentsArray:attachments]; } - - // Quoted Attachment + + // Quoted Reply + OWSSignalServiceProtosDataMessageQuoteBuilder *_Nullable quotedMessageBuilder = self.quotedMessageBuilder; + if (quotedMessageBuilder) { + [builder setQuoteBuilder:quotedMessageBuilder]; + } + + // Contact Share + OWSSignalServiceProtosDataMessageContact *_Nullable contactShare = self.contactShareBuilder; + if (contactShare) { + [builder addContact:contactShare]; + } + + return builder; +} + +- (nullable OWSSignalServiceProtosDataMessageQuoteBuilder *)quotedMessageBuilder +{ + if (!self.quotedMessage) { + return nil; + } TSQuotedMessage *quotedMessage = self.quotedMessage; - if (quotedMessage) { - OWSSignalServiceProtosDataMessageQuoteBuilder *quoteBuilder = [OWSSignalServiceProtosDataMessageQuoteBuilder new]; - [quoteBuilder setId:quotedMessage.timestamp]; - [quoteBuilder setAuthor:quotedMessage.authorId]; - - BOOL hasQuotedText = NO; - BOOL hasQuotedAttachment = NO; - if (self.quotedMessage.body.length > 0) { - hasQuotedText = YES; - [quoteBuilder setText:quotedMessage.body]; - } - if (quotedMessage.quotedAttachments) { - for (OWSAttachmentInfo *attachment in quotedMessage.quotedAttachments) { - hasQuotedAttachment = YES; - - OWSSignalServiceProtosDataMessageQuoteQuotedAttachmentBuilder *quotedAttachmentBuilder = [OWSSignalServiceProtosDataMessageQuoteQuotedAttachmentBuilder new]; - - quotedAttachmentBuilder.contentType = attachment.contentType; - quotedAttachmentBuilder.fileName = attachment.sourceFilename; - if (attachment.thumbnailAttachmentStreamId) { - quotedAttachmentBuilder.thumbnail = - [self buildProtoForAttachmentId:attachment.thumbnailAttachmentStreamId]; - } + OWSSignalServiceProtosDataMessageQuoteBuilder *quoteBuilder = [OWSSignalServiceProtosDataMessageQuoteBuilder new]; + [quoteBuilder setId:quotedMessage.timestamp]; + [quoteBuilder setAuthor:quotedMessage.authorId]; + + BOOL hasQuotedText = NO; + BOOL hasQuotedAttachment = NO; + if (self.quotedMessage.body.length > 0) { + hasQuotedText = YES; + [quoteBuilder setText:quotedMessage.body]; + } + + if (quotedMessage.quotedAttachments) { + for (OWSAttachmentInfo *attachment in quotedMessage.quotedAttachments) { + hasQuotedAttachment = YES; + + OWSSignalServiceProtosDataMessageQuoteQuotedAttachmentBuilder *quotedAttachmentBuilder = + [OWSSignalServiceProtosDataMessageQuoteQuotedAttachmentBuilder new]; - [quoteBuilder addAttachments:[quotedAttachmentBuilder build]]; + quotedAttachmentBuilder.contentType = attachment.contentType; + quotedAttachmentBuilder.fileName = attachment.sourceFilename; + if (attachment.thumbnailAttachmentStreamId) { + quotedAttachmentBuilder.thumbnail = + [self buildProtoForAttachmentId:attachment.thumbnailAttachmentStreamId]; } + + [quoteBuilder addAttachments:[quotedAttachmentBuilder build]]; } - - if (hasQuotedText || hasQuotedAttachment) { - [builder setQuoteBuilder:quoteBuilder]; - } else { - OWSFail(@"%@ Invalid quoted message data.", self.logTag); + } + + if (hasQuotedText || hasQuotedAttachment) { + return quoteBuilder; + } else { + OWSFail(@"%@ Invalid quoted message data.", self.logTag); + return nil; + } +} + +- (nullable OWSSignalServiceProtosDataMessageContact *)contactShareBuilder +{ + if (!self.contactShare) { + return nil; + } + OWSContactShare *contactShare = self.contactShare; + if (!contactShare.isValid) { + OWSProdLogAndFail(@"%@ contact share is invalid.", self.logTag); + return nil; + } + + OWSSignalServiceProtosDataMessageContactBuilder *contactBuilder = + [OWSSignalServiceProtosDataMessageContactBuilder new]; + + // TODO: Should we normalize/validate values here? + OWSSignalServiceProtosDataMessageContactNameBuilder *nameBuilder = + [OWSSignalServiceProtosDataMessageContactNameBuilder new]; + if (contactShare.givenName.ows_stripped.length > 0) { + nameBuilder.givenName = contactShare.givenName.ows_stripped; + } + if (contactShare.familyName.ows_stripped.length > 0) { + nameBuilder.familyName = contactShare.familyName.ows_stripped; + } + if (contactShare.middleName.ows_stripped.length > 0) { + nameBuilder.middleName = contactShare.middleName.ows_stripped; + } + if (contactShare.namePrefix.ows_stripped.length > 0) { + nameBuilder.prefix = contactShare.namePrefix.ows_stripped; + } + if (contactShare.nameSuffix.ows_stripped.length > 0) { + nameBuilder.suffix = contactShare.nameSuffix.ows_stripped; + } + [contactBuilder setNameBuilder:nameBuilder]; + + for (OWSContactSharePhoneNumber *phoneNumber in contactShare.phoneNumbers) { + if (!phoneNumber.isValid) { + OWSProdLogAndFail(@"%@ phone number is invalid.", self.logTag); + continue; + } + OWSSignalServiceProtosDataMessageContactPhoneBuilder *phoneBuilder = + [OWSSignalServiceProtosDataMessageContactPhoneBuilder new]; + phoneBuilder.value = phoneNumber.phoneNumber; + if (phoneBuilder.label.ows_stripped.length > 0) { + phoneBuilder.label = phoneBuilder.label.ows_stripped; + } + switch (phoneNumber.phoneType) { + case OWSContactSharePhoneType_Home: + phoneBuilder.type = OWSSignalServiceProtosDataMessageContactPhoneTypeHome; + break; + case OWSContactSharePhoneType_Mobile: + phoneBuilder.type = OWSSignalServiceProtosDataMessageContactPhoneTypeMobile; + break; + case OWSContactSharePhoneType_Work: + phoneBuilder.type = OWSSignalServiceProtosDataMessageContactPhoneTypeWork; + break; + default: + phoneBuilder.type = OWSSignalServiceProtosDataMessageContactPhoneTypeCustom; + break; } + [contactBuilder addNumber:phoneBuilder.build]; } - - return builder; + + for (OWSContactShareEmail *email in contactShare.emails) { + if (!email.isValid) { + OWSProdLogAndFail(@"%@ email is invalid.", self.logTag); + continue; + } + OWSSignalServiceProtosDataMessageContactEmailBuilder *emailBuilder = + [OWSSignalServiceProtosDataMessageContactEmailBuilder new]; + emailBuilder.value = email.email; + if (emailBuilder.label.ows_stripped.length > 0) { + emailBuilder.label = emailBuilder.label.ows_stripped; + } + switch (email.emailType) { + case OWSContactShareEmailType_Home: + emailBuilder.type = OWSSignalServiceProtosDataMessageContactEmailTypeHome; + break; + case OWSContactShareEmailType_Mobile: + emailBuilder.type = OWSSignalServiceProtosDataMessageContactEmailTypeMobile; + break; + case OWSContactShareEmailType_Work: + emailBuilder.type = OWSSignalServiceProtosDataMessageContactEmailTypeWork; + break; + default: + emailBuilder.type = OWSSignalServiceProtosDataMessageContactEmailTypeCustom; + break; + } + [contactBuilder addEmail:emailBuilder.build]; + } + + for (OWSContactShareAddress *address in contactShare.addresses) { + if (!address.isValid) { + OWSProdLogAndFail(@"%@ address is invalid.", self.logTag); + continue; + } + OWSSignalServiceProtosDataMessageContactPostalAddressBuilder *addressBuilder = + [OWSSignalServiceProtosDataMessageContactPostalAddressBuilder new]; + if (addressBuilder.label.ows_stripped.length > 0) { + addressBuilder.label = addressBuilder.label.ows_stripped; + } + if (addressBuilder.street.ows_stripped.length > 0) { + addressBuilder.street = addressBuilder.street.ows_stripped; + } + if (addressBuilder.pobox.ows_stripped.length > 0) { + addressBuilder.pobox = addressBuilder.pobox.ows_stripped; + } + if (addressBuilder.neighborhood.ows_stripped.length > 0) { + addressBuilder.neighborhood = addressBuilder.neighborhood.ows_stripped; + } + if (addressBuilder.city.ows_stripped.length > 0) { + addressBuilder.city = addressBuilder.city.ows_stripped; + } + if (addressBuilder.region.ows_stripped.length > 0) { + addressBuilder.region = addressBuilder.region.ows_stripped; + } + if (addressBuilder.postcode.ows_stripped.length > 0) { + addressBuilder.postcode = addressBuilder.postcode.ows_stripped; + } + if (addressBuilder.country.ows_stripped.length > 0) { + addressBuilder.country = addressBuilder.country.ows_stripped; + } + [contactBuilder addAddress:addressBuilder.build]; + } + + // TODO: avatar + + OWSSignalServiceProtosDataMessageContact *contact = [contactBuilder build]; + if (contact.number.count < 1 && contact.email.count < 1 && contact.address.count < 1) { + OWSProdLogAndFail(@"%@ contact has neither phone, email or address.", self.logTag); + return nil; + } + return contact; } // recipientId is nil when building "sent" sync messages for messages sent to groups.