diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index d21e5a708..39c97a1d8 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -85,6 +85,27 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess #pragma mark - Durable Message Enqueue +// Loki: TODO We may change this? ++ (TSOutgoingMessage *)enqueueFriendRequestAcceptMessageInThread:(TSThread *)thread +{ + TSOutgoingMessage *message = + [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] + inThread:thread + messageBody:@"" + attachmentIds:[NSMutableArray new] + expiresInSeconds:0 + expireStartedAt:0 + isVoiceMessage:NO + groupMetaMessage:TSGroupMetaMessageUnspecified + quotedMessage:nil + contactShare:nil + linkPreview:nil]; + [self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self.messageSenderJobQueue addMessage:message transaction:transaction]; + }]; + return message; +} + + (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)fullMessageText inThread:(TSThread *)thread quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel @@ -129,6 +150,7 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess }]; } +// Loki: TODO Disable attachment and link preview for now + (TSOutgoingMessage *)buildOutgoingMessageWithText:(nullable NSString *)fullMessageText mediaAttachments:(NSArray *)mediaAttachments thread:(TSThread *)thread @@ -172,19 +194,24 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess } BOOL isVoiceMessage = (attachments.count == 1 && attachments.lastObject.isVoiceMessage); - + + // Loki: If we're not friends then always set the message to a friend request message + // If we're friends then the assumption is that we have the other users pre-key bundle + NSString *messageClassString = [thread isFriend] ? @"TSOutgoingMessage" : @"OWSFriendRequestMessage"; + Class messageClass = NSClassFromString(messageClassString); + TSOutgoingMessage *message = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:truncatedText - attachmentIds:[NSMutableArray new] - expiresInSeconds:expiresInSeconds - expireStartedAt:0 - isVoiceMessage:isVoiceMessage - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:[quotedReplyModel buildQuotedMessageForSending] - contactShare:nil - linkPreview:nil]; + [[messageClass alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] + inThread:thread + messageBody:truncatedText + attachmentIds:[NSMutableArray new] + expiresInSeconds:expiresInSeconds + expireStartedAt:0 + isVoiceMessage:isVoiceMessage + groupMetaMessage:TSGroupMetaMessageUnspecified + quotedMessage:[quotedReplyModel buildQuotedMessageForSending] + contactShare:nil + linkPreview:nil]; [BenchManager benchAsyncWithTitle:@"Saving outgoing message" diff --git a/SignalServiceKit/src/Contacts/TSThread.h b/SignalServiceKit/src/Contacts/TSThread.h index fa4527b12..1d5a7a4bf 100644 --- a/SignalServiceKit/src/Contacts/TSThread.h +++ b/SignalServiceKit/src/Contacts/TSThread.h @@ -29,6 +29,22 @@ extern ConversationColorName const ConversationColorNameSteel; extern ConversationColorName const kConversationColorName_Default; +// Loki: Friend request state +typedef NS_ENUM(NSInteger, TSThreadFriendRequestState) { + // New conversation, no messages sent or received + TSThreadFriendRequestStateNone, + // This state is used to lock the input early while sending + TSThreadFriendRequestStatePendingSend, + // Friend request send, awaiting response + TSThreadFriendRequestStateRequestSent, + // Friend request received, awaiting user input + TSThreadFriendRequestStateRequestReceived, + // We are friends with the user of this thread + TSThreadFriendRequestStateFriends, + // Friend request sent but it timed out (user didn't accept within x time) + TSThreadFriendRequestStateRequestExpired, +}; + /** * TSThread is the superclass of TSContactThread and TSGroupThread */ @@ -38,6 +54,9 @@ extern ConversationColorName const kConversationColorName_Default; @property (nonatomic, readonly) NSDate *creationDate; @property (nonatomic, readonly) BOOL isArchivedByLegacyTimestampForSorting; +// Loki: The current friend request state with this thread +@property (atomic, readonly) TSThreadFriendRequestState friendRequestState; + /** * Whether the object is a group thread or not. * @@ -170,6 +189,21 @@ extern ConversationColorName const kConversationColorName_Default; - (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction; +#pragma mark - Loki Friend Request + +/// Check if this thread is a friend +- (BOOL)isFriend; + +/// Check if a friend request is pending +- (BOOL)isPendingFriendRequest; + +/// Check if a friend request has been sent to this thread +- (BOOL)hasSentFriendRequest; + +/// Check if a friend request has been received from this thread +- (BOOL)hasReceivedFriendRequest; + @end + NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index 744e7c655..895985a66 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -50,6 +50,8 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa @property (nonatomic, copy, nullable) NSString *messageDraft; @property (atomic, nullable) NSDate *mutedUntilDate; +@property (atomic) TSThreadFriendRequestState friendRequestState; + // DEPRECATED - not used since migrating to sortId // but keeping these properties around to ease any pain in the back-forth // migration while testing. Eventually we can safely delete these as they aren't used anywhere. @@ -84,6 +86,9 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa if (self) { _creationDate = [NSDate date]; _messageDraft = nil; + + // We are initially not friends + _friendRequestState = TSThreadFriendRequestStateNone; NSString *_Nullable contactId = self.contactIdentifier; if (contactId.length > 0) { @@ -694,6 +699,35 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa }]; } +# pragma mark - Loki Friend Request + +- (BOOL)isFriend +{ + return _friendRequestState == TSThreadFriendRequestStateFriends; +} + +- (BOOL)isPendingFriendRequest +{ + return ( + _friendRequestState == TSThreadFriendRequestStatePendingSend || + _friendRequestState == TSThreadFriendRequestStateRequestSent || + _friendRequestState == TSThreadFriendRequestStateRequestReceived + ); +} + +- (BOOL)hasSentFriendRequest +{ + return ( + _friendRequestState == TSThreadFriendRequestStateRequestSent || + _friendRequestState == TSThreadFriendRequestStateRequestExpired + ); +} + +- (BOOL)hasReceivedFriendRequest +{ + return _friendRequestState == TSThreadFriendRequestStateRequestReceived; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 22975ca86..9b0b7052f 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1547,9 +1547,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; @try { // This may involve blocking network requests, so we do it _before_ // we open a transaction. - // TODO: Replace this when we add in friend request stuff - // Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; - Boolean isFriendRequest = true; + + // Friend requests means we don't have a session with the person + // There's no point to check for it + Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; if (!isFriendRequest) { [self throws_ensureRecipientHasSessionForMessageSend:messageSend deviceId:deviceId]; } @@ -1784,9 +1785,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; NSString *recipientId = recipient.recipientId; OWSAssertDebug(recipientId.length > 0); - // TODO: Change this when we have friend request support - // Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; - Boolean isFriendRequest = true; + // Loki: Handle friend requests differently + Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; if (isFriendRequest) { return [self throws_encryptedFriendMessageForMessageSend:messageSend deviceId:deviceId plainText:plainText]; }