diff --git a/Signal/Signal-Prefix.pch b/Signal/Signal-Prefix.pch index 746c8e9e7..e9d10ecf2 100644 --- a/Signal/Signal-Prefix.pch +++ b/Signal/Signal-Prefix.pch @@ -20,5 +20,6 @@ #import #import #import + #import #import #endif diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index b9055220a..aab06232a 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -52,6 +52,17 @@ public final class LokiAPI : NSObject { self.hexEncodedPublicKey = hexEncodedPublicKey self.objc_kind = kind } + + override public func isEqual(_ other: Any?) -> Bool { + guard let other = other as? Destination else { return false } + return hexEncodedPublicKey == other.hexEncodedPublicKey && kind == other.kind + } + + override public var hash: Int { // Override NSObject.hash and not Hashable.hashValue or Hashable.hash(into:) + return hexEncodedPublicKey.hashValue ^ kind.hashValue + } + + override public var description: String { return "\(kind.rawValue)(\(hexEncodedPublicKey))" } } public typealias MessageListPromise = Promise<[SSKProtoEnvelope]> diff --git a/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.h b/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.h index bec1fd9ea..bffdfe76a 100644 --- a/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.h +++ b/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.h @@ -2,5 +2,6 @@ @interface NSArray (Functional) - (NSArray *)filtered:(BOOL (^)(NSObject *))isIncluded; +- (NSArray *)map:(NSObject *(^)(NSObject *))transform; @end diff --git a/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.m b/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.m index 296c041ee..309e33914 100644 --- a/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.m +++ b/SignalServiceKit/src/Loki/Utilities/NSArray+Functional.m @@ -12,4 +12,13 @@ return result; } +- (NSArray *)map:(NSObject *(^)(NSObject *))transform { + NSMutableArray *result = [NSMutableArray new]; + for (NSObject *object in self) { + NSObject *transformedObject = transform(object); + [result addObject:transformedObject]; + } + return result; +} + @end diff --git a/SignalServiceKit/src/Loki/Utilities/NSSet+Functional.h b/SignalServiceKit/src/Loki/Utilities/NSSet+Functional.h new file mode 100644 index 000000000..9808cc05f --- /dev/null +++ b/SignalServiceKit/src/Loki/Utilities/NSSet+Functional.h @@ -0,0 +1,7 @@ + +@interface NSSet (Functional) + +- (BOOL)contains:(BOOL (^)(NSObject *))predicate; +- (NSSet *)filtered:(BOOL (^)(NSObject *))isIncluded; + +@end diff --git a/SignalServiceKit/src/Loki/Utilities/NSSet+Functional.m b/SignalServiceKit/src/Loki/Utilities/NSSet+Functional.m new file mode 100644 index 000000000..8d45bc498 --- /dev/null +++ b/SignalServiceKit/src/Loki/Utilities/NSSet+Functional.m @@ -0,0 +1,23 @@ +#import "NSSet+Functional.h" + +@implementation NSSet (Functional) + +-(BOOL)contains:(BOOL (^)(NSObject *))predicate { + for (NSObject *object in self) { + BOOL isPredicateSatisfied = predicate(object); + if (isPredicateSatisfied) { return YES; } + } + return NO; +} + +- (NSSet *)filtered:(BOOL (^)(NSObject *))isIncluded { + NSMutableSet *result = [NSMutableSet new]; + for (NSObject *object in self) { + if (isIncluded(object)) { + [result addObject:object]; + } + } + return result; +} + +@end diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 03926c4b4..cd3698f46 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -901,6 +901,22 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return deviceMessages; } +- (LKFriendRequestMessage *)getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:(NSString *)hexEncodedPublicKey +{ + TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:hexEncodedPublicKey]; + return [[LKFriendRequestMessage alloc] initOutgoingMessageWithTimestamp:NSDate.ows_millisecondTimeStamp + inThread:thread + messageBody:@"Test" + attachmentIds:[NSMutableArray new] + expiresInSeconds:0 + expireStartedAt:0 + isVoiceMessage:NO + groupMetaMessage:TSGroupMetaMessageUnspecified + quotedMessage:nil + contactShare:nil + linkPreview:nil]; +} + - (void)sendMessageToRecipient:(OWSMessageSend *)messageSend { if (messageSend.thread.isGroupThread) { @@ -914,16 +930,28 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return [destination.kind isEqual:@"slave"]; }]; for (LKDestination *slaveDestination in slaveDestinations) { - OWSMessageSend *messageSendCopy = [messageSend copyWithDestination:slaveDestination]; - [self sendMessage:messageSendCopy]; + TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:slaveDestination.hexEncodedPublicKey]; + if (thread.isContactFriend) { + OWSMessageSend *messageSendCopy = [messageSend copyWithDestination:slaveDestination]; + [self sendMessage:messageSendCopy]; + } else { + LKFriendRequestMessage *friendRequestMessage = [self getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:slaveDestination.hexEncodedPublicKey]; + [self sendMessage:friendRequestMessage success:^{ } failure:^(NSError *error) { }]; + } } LKDestination *masterDestination = [destinations filtered:^BOOL(NSObject *object) { LKDestination *destination = [object as:LKDestination.class]; return [destination.kind isEqual:@"master"]; }].firstObject; if (masterDestination != nil) { - OWSMessageSend *messageSendCopy = [messageSend copyWithDestination:masterDestination]; - [self sendMessage:messageSendCopy]; + TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:masterDestination.hexEncodedPublicKey]; + if (thread.isContactFriend) { + OWSMessageSend *messageSendCopy = [messageSend copyWithDestination:masterDestination]; + [self sendMessage:messageSendCopy]; + } else { + LKFriendRequestMessage *friendRequestMessage = [self getMultiDeviceFriendRequestMessageForHexEncodedPublicKey:masterDestination.hexEncodedPublicKey]; + [self sendMessage:friendRequestMessage success:messageSend.success failure:messageSend.failure]; + } } }) .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { diff --git a/SignalServiceKit/src/TSPrefix.h b/SignalServiceKit/src/TSPrefix.h index a2445591c..fce828264 100644 --- a/SignalServiceKit/src/TSPrefix.h +++ b/SignalServiceKit/src/TSPrefix.h @@ -13,6 +13,7 @@ static const NSUInteger ddLogLevel = DDLogLevelInfo; #endif #import "OWSAnalytics.h" #import "NSArray+Functional.h" +#import "NSSet+Functional.h" #import "NSObject+Casting.h" #import "SSKAsserts.h" #import "TSConstants.h"