Merge branch 'charlesmchen/contactOffers'

pull/1/head
Matthew Chen 8 years ago
commit 72c983e4a0

@ -43,7 +43,7 @@ PODS:
- Reachability (3.2)
- SAMKeychain (1.5.2)
- SignalServiceKit (0.9.0):
- 25519
- '25519'
- AFNetworking
- AxolotlKit
- CocoaLumberjack
@ -149,7 +149,7 @@ CHECKOUT OPTIONS:
:git: https://github.com/facebook/SocketRocket.git
SPEC CHECKSUMS:
25519: dc4bad7e2dbcbf1efa121068a705a44cd98c80fc
'25519': dc4bad7e2dbcbf1efa121068a705a44cd98c80fc
AFNetworking: 5e0e199f73d8626b11e79750991f5d173d1f8b67
ATAppUpdater: a9f7027060959d47e58733d3b48f6b9a28cb8de1
AxolotlKit: ba0ab24b879d34559a68e1270b079cc9bd7b3417
@ -173,4 +173,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 2f847bb25e70d1d376f38cf21ae08624fa6ed67d
COCOAPODS: 1.3.1
COCOAPODS: 1.2.1

@ -75,6 +75,9 @@
34B3F89F1E8DF5490035BE1A /* OWSTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F89E1E8DF5490035BE1A /* OWSTableViewController.m */; };
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */; };
34C42D5B1F45F7A80072EC04 /* OWSNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D5A1F45F7A80072EC04 /* OWSNavigationController.m */; };
34C42D611F4734CA0072EC04 /* OWSContactOffersCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D601F4734CA0072EC04 /* OWSContactOffersCell.m */; };
34C42D661F4734ED0072EC04 /* OWSContactOffersInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */; };
34C42D671F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */; };
34CCAF381F0C0599004084F4 /* AppUpdateNag.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CCAF371F0C0599004084F4 /* AppUpdateNag.m */; };
34CCAF3B1F0C2748004084F4 /* OWSAddToContactViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CCAF3A1F0C2748004084F4 /* OWSAddToContactViewController.m */; };
34CE88E71F2FB9A10098030F /* ProfileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CE88E61F2FB9A10098030F /* ProfileViewController.m */; };
@ -94,7 +97,6 @@
34E3EF0D1EFC235B007F6822 /* DebugUIDiskUsage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0C1EFC235B007F6822 /* DebugUIDiskUsage.m */; };
34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */; };
34E8BF381EE9E2FD00F5F4CA /* FingerprintViewScanController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34E8BF371EE9E2FD00F5F4CA /* FingerprintViewScanController.m */; };
34F3089C1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F3089B1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m */; };
34F3089F1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F3089E1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m */; };
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; };
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; };
@ -508,6 +510,12 @@
34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewControllerUtils.m; sourceTree = "<group>"; };
34C42D591F45F7A80072EC04 /* OWSNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSNavigationController.h; sourceTree = "<group>"; };
34C42D5A1F45F7A80072EC04 /* OWSNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSNavigationController.m; sourceTree = "<group>"; };
34C42D5F1F4734CA0072EC04 /* OWSContactOffersCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactOffersCell.h; sourceTree = "<group>"; };
34C42D601F4734CA0072EC04 /* OWSContactOffersCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactOffersCell.m; sourceTree = "<group>"; };
34C42D621F4734ED0072EC04 /* OWSContactOffersInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactOffersInteraction.h; sourceTree = "<group>"; };
34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactOffersInteraction.m; sourceTree = "<group>"; };
34C42D641F4734ED0072EC04 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSUnreadIndicatorInteraction.h; sourceTree = "<group>"; };
34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSUnreadIndicatorInteraction.m; sourceTree = "<group>"; };
34CCAF361F0C0599004084F4 /* AppUpdateNag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppUpdateNag.h; sourceTree = "<group>"; };
34CCAF371F0C0599004084F4 /* AppUpdateNag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppUpdateNag.m; sourceTree = "<group>"; };
34CCAF391F0C2748004084F4 /* OWSAddToContactViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAddToContactViewController.h; sourceTree = "<group>"; };
@ -545,8 +553,6 @@
34E3EF0F1EFC2684007F6822 /* DebugUIPage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugUIPage.m; sourceTree = "<group>"; };
34E8BF361EE9E2FD00F5F4CA /* FingerprintViewScanController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FingerprintViewScanController.h; sourceTree = "<group>"; };
34E8BF371EE9E2FD00F5F4CA /* FingerprintViewScanController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FingerprintViewScanController.m; sourceTree = "<group>"; };
34F3089A1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSUnreadIndicatorInteraction.h; sourceTree = "<group>"; };
34F3089B1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSUnreadIndicatorInteraction.m; sourceTree = "<group>"; };
34F3089D1ECA580B00BB7697 /* OWSUnreadIndicatorCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = OWSUnreadIndicatorCell.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
34F3089E1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = OWSUnreadIndicatorCell.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBezierPathView.h; sourceTree = "<group>"; };
@ -1212,6 +1218,8 @@
45C681B61D305A580050903A /* OWSCall.m */,
45855F351D9498A40084F340 /* OWSContactAvatarBuilder.h */,
45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */,
34C42D621F4734ED0072EC04 /* OWSContactOffersInteraction.h */,
34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */,
458E38351D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.h */,
458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */,
45666EC71D994C0D008FE134 /* OWSGroupAvatarBuilder.h */,
@ -1219,6 +1227,8 @@
453D28B81D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.h */,
453D28B91D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m */,
B62D53F41A23CC8B009AAF82 /* TSMessageAdapters */,
34C42D641F4734ED0072EC04 /* TSUnreadIndicatorInteraction.h */,
34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */,
);
path = Models;
sourceTree = "<group>";
@ -1457,6 +1467,8 @@
3453D8E91EC0D4ED003F9E6F /* OWSAlerts.swift */,
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */,
34F308A11ECB469700BB7697 /* OWSBezierPathView.m */,
34C42D5F1F4734CA0072EC04 /* OWSContactOffersCell.h */,
34C42D601F4734CA0072EC04 /* OWSContactOffersCell.m */,
459311FA1D75C948008DD4F0 /* OWSDeviceTableViewCell.h */,
459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */,
450873C91D9D86F4006B54F2 /* OWSExpirableMessageView.h */,
@ -1476,8 +1488,6 @@
34F3089D1ECA580B00BB7697 /* OWSUnreadIndicatorCell.h */,
34F3089E1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m */,
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
34F3089A1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.h */,
34F3089B1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m */,
);
name = Views;
path = views;
@ -2024,7 +2034,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
3465F381B1856CC06933B3A8 /* [CP] Copy Pods Resources */ = {
@ -2132,7 +2142,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
B4E9B04E862FB64FC9A8F79B /* [CP] Embed Pods Frameworks */ = {
@ -2269,6 +2279,7 @@
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */,
45666EC61D99483D008FE134 /* OWSAvatarBuilder.m in Sources */,
45E615161E8C590B0018AD52 /* DisplayableTextFilter.swift in Sources */,
34C42D611F4734CA0072EC04 /* OWSContactOffersCell.m in Sources */,
34B3F88A1E8DF1700035BE1A /* OWSLinkDeviceViewController.m in Sources */,
76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
3497DBEF1ECE2E4700DB2605 /* DomainFrontingCountryViewController.m in Sources */,
@ -2339,6 +2350,7 @@
34B3F8721E8DF1700035BE1A /* AdvancedSettingsTableViewController.m in Sources */,
45F170D61E315310003FC1F2 /* Weak.swift in Sources */,
34B3F8891E8DF1700035BE1A /* OWSConversationSettingsViewController.m in Sources */,
34C42D671F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m in Sources */,
34B3F87E1E8DF1700035BE1A /* InboxTableViewCell.m in Sources */,
34B3F8731E8DF1700035BE1A /* AttachmentApprovalViewController.swift in Sources */,
B6B1013C196D213F007E3930 /* SignalKeyingStorage.m in Sources */,
@ -2349,6 +2361,7 @@
45666F7E1D9C0814008FE134 /* OWSDatabaseMigrationRunner.m in Sources */,
4579431E1E7C8CE9008ED0C0 /* Pastelog.m in Sources */,
34D99C941F2937CC00D284D6 /* OWSSwiftUtils.swift in Sources */,
34C42D661F4734ED0072EC04 /* OWSContactOffersInteraction.m in Sources */,
34B3F8941E8DF1710035BE1A /* SignalsViewController.m in Sources */,
34E8BF381EE9E2FD00F5F4CA /* FingerprintViewScanController.m in Sources */,
76EB058818170B33006006FC /* PropertyListPreferences.m in Sources */,
@ -2356,7 +2369,6 @@
34B3F87D1E8DF1700035BE1A /* FullImageViewController.m in Sources */,
45666F7B1D9C0533008FE134 /* OWSDatabaseMigration.m in Sources */,
B90418E6183E9DD40038554A /* DateUtil.m in Sources */,
34F3089C1ECA4CDB00BB7697 /* TSUnreadIndicatorInteraction.m in Sources */,
459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

@ -177,7 +177,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
// we need to bump this constant.
//
// We added a number of database views in v2.13.0.
NSString *kLastVersionWithDatabaseViewChange = @"2.16.0";
NSString *kLastVersionWithDatabaseViewChange = @"2.13.0";
BOOL mayNeedUpgrade = ([TSAccountManager isRegistered] && lastLaunchedAppVersion
&& (!lastCompletedLaunchAppVersion ||
[VersionMigrations isVersion:lastCompletedLaunchAppVersion

@ -0,0 +1,27 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <SignalServiceKit/TSInteraction.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSContactOffersInteraction : TSInteraction
@property (nonatomic, readonly) BOOL hasBlockOffer;
@property (nonatomic, readonly) BOOL hasAddToContactsOffer;
@property (nonatomic, readonly) BOOL hasAddToProfileWhitelistOffer;
@property (nonatomic, readonly) NSString *recipientId;
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTimestamp:(uint64_t)timestamp
thread:(TSThread *)thread
hasBlockOffer:(BOOL)hasBlockOffer
hasAddToContactsOffer:(BOOL)hasAddToContactsOffer
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
recipientId:(NSString *)recipientId NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,52 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSContactOffersInteraction.h"
NS_ASSUME_NONNULL_BEGIN
@implementation OWSContactOffersInteraction
- (instancetype)initWithCoder:(NSCoder *)coder
{
return [super initWithCoder:coder];
}
- (instancetype)initWithTimestamp:(uint64_t)timestamp
thread:(TSThread *)thread
hasBlockOffer:(BOOL)hasBlockOffer
hasAddToContactsOffer:(BOOL)hasAddToContactsOffer
hasAddToProfileWhitelistOffer:(BOOL)hasAddToProfileWhitelistOffer
recipientId:(NSString *)recipientId
{
self = [super initWithTimestamp:timestamp inThread:thread];
if (!self) {
return self;
}
_hasBlockOffer = hasBlockOffer;
_hasAddToContactsOffer = hasAddToContactsOffer;
_hasAddToProfileWhitelistOffer = hasAddToProfileWhitelistOffer;
OWSAssert(recipientId.length > 0);
_recipientId = recipientId;
return self;
}
- (BOOL)shouldUseReceiptDateForSorting
{
// Use the timestamp, not the "received at" timestamp to sort,
// since we're creating these interactions after the fact and back-dating them.
return NO;
}
- (BOOL)isDynamicInteraction
{
return YES;
}
@end
NS_ASSUME_NONNULL_END

@ -4,6 +4,8 @@
#import "OWSMessagesBubblesSizeCalculator.h"
#import "OWSCall.h"
#import "OWSContactOffersCell.h"
#import "OWSContactOffersInteraction.h"
#import "OWSSystemMessageCell.h"
#import "OWSUnreadIndicatorCell.h"
#import "TSGenericAttachmentAdapter.h"
@ -40,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) OWSSystemMessageCell *referenceSystemMessageCell;
@property (nonatomic, readonly) OWSUnreadIndicatorCell *referenceUnreadIndicatorCell;
@property (nonatomic, readonly) OWSContactOffersCell *referenceContactOffersCell;
@end
@ -52,6 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
if (self = [super init]) {
_referenceSystemMessageCell = [OWSSystemMessageCell new];
_referenceUnreadIndicatorCell = [OWSUnreadIndicatorCell new];
_referenceContactOffersCell = [OWSContactOffersCell new];
}
return self;
}
@ -88,6 +92,12 @@ NS_ASSUME_NONNULL_BEGIN
= (TSUnreadIndicatorInteraction *)((TSMessageAdapter *)messageData).interaction;
return [self sizeForUnreadIndicator:interaction cacheKey:cacheKey layout:layout];
}
case OWSContactOffersAdapter: {
id cacheKey = [self cacheKeyForMessageData:messageData];
OWSContactOffersInteraction *interaction
= (OWSContactOffersInteraction *)((TSMessageAdapter *)messageData).interaction;
return [self sizeForContactOffers:interaction cacheKey:cacheKey layout:layout];
}
case TSIncomingMessageAdapter:
case TSOutgoingMessageAdapter:
break;
@ -156,6 +166,26 @@ NS_ASSUME_NONNULL_BEGIN
return result;
}
- (CGSize)sizeForContactOffers:(OWSContactOffersInteraction *)interaction
cacheKey:(id)cacheKey
layout:(JSQMessagesCollectionViewFlowLayout *)layout
{
OWSAssert(interaction);
OWSAssert(cacheKey);
NSValue *cachedSize = [self.cache objectForKey:cacheKey];
if (cachedSize != nil) {
return [cachedSize CGSizeValue];
}
CGSize result = [self.referenceContactOffersCell bubbleSizeForInteraction:interaction
collectionViewWidth:layout.collectionView.width];
[self.cache setObject:[NSValue valueWithCGSize:result] forKey:cacheKey];
return result;
}
/**
* Emoji sizing bug only affects iOS10. Unfortunately the "fix" for emoji font breaks some other fonts, so it's
* important

@ -16,6 +16,7 @@ typedef NS_ENUM(NSInteger, TSMessageAdapterType) {
TSMediaAttachmentAdapter,
TSGenericTextMessageAdapter, // Used when message direction is unknown (outgoing or incoming)
TSUnreadIndicatorAdapter,
OWSContactOffersAdapter,
};
@protocol OWSMessageData <JSQMessageData, OWSMessageEditing>

@ -5,6 +5,7 @@
#import "TSMessageAdapter.h"
#import "AttachmentSharing.h"
#import "OWSCall.h"
#import "OWSContactOffersInteraction.h"
#import "Signal-Swift.h"
#import "TSAttachmentPointer.h"
#import "TSAttachmentStream.h"
@ -226,6 +227,8 @@ NS_ASSUME_NONNULL_BEGIN
adapter.messageType = TSInfoMessageAdapter;
} else if ([interaction isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
adapter.messageType = TSUnreadIndicatorAdapter;
} else if ([interaction isKindOfClass:[OWSContactOffersInteraction class]]) {
adapter.messageType = OWSContactOffersAdapter;
} else if ([interaction isKindOfClass:[TSErrorMessage class]]) {
TSErrorMessage *errorMessage = (TSErrorMessage *)interaction;
adapter.errorMessageType = errorMessage.errorType;
@ -315,11 +318,10 @@ NS_ASSUME_NONNULL_BEGIN
// Shouldn't get here, as only supported actions should be exposed via canPerformEditingAction
NSString *actionString = NSStringFromSelector(action);
DDLogError(@"'%@' action unsupported for TSInteraction: uniqueId=%@, mediaType=%@",
OWSFail(@"'%@' action unsupported for TSInteraction: uniqueId=%@, mediaType=%@",
actionString,
self.interaction.uniqueId,
[self.mediaItem class]);
OWSAssert(NO);
}
- (TSAttachmentStream *)attachmentStream

@ -155,8 +155,7 @@ NS_ASSUME_NONNULL_BEGIN
}
// Shouldn't get here, as only supported actions should be exposed via canPerformEditingAction
DDLogError(@"'%@' action unsupported for %@: attachmentId=%@", actionString, self.class, self.attachmentId);
OWSAssert(NO);
OWSFail(@"'%@' action unsupported for %@: attachmentId=%@", actionString, self.class, self.attachmentId);
}
#pragma mark - OWSMessageMediaAdapter

@ -435,9 +435,8 @@ NS_ASSUME_NONNULL_BEGIN
} else {
// Shouldn't get here, as only supported actions should be exposed via canPerformEditingAction
NSString *actionString = NSStringFromSelector(action);
DDLogError(
OWSFail(
@"Unexpected action: %@ for VideoAttachmentAdapter with contentType: %@", actionString, self.contentType);
OWSAssert(NO);
}
}

@ -347,9 +347,8 @@ NS_ASSUME_NONNULL_BEGIN
SignalAccount *signalAccount = [self signalAccountForRecipientId:recipientId];
if (!self.contactsManager.supportsContactEditing) {
DDLogError(@"%@ Contact editing not supported.", self.tag);
// Should not expose UI that lets the user get here.
OWSAssert(NO);
OWSFail(@"%@ Contact editing not supported.", self.tag);
return;
}

@ -16,6 +16,8 @@
#import "NewGroupViewController.h"
#import "OWSAudioAttachmentPlayer.h"
#import "OWSCall.h"
#import "OWSContactOffersCell.h"
#import "OWSContactOffersInteraction.h"
#import "OWSContactsManager.h"
#import "OWSConversationSettingsViewController.h"
#import "OWSConversationSettingsViewDelegate.h"
@ -76,7 +78,6 @@
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
#import <SignalServiceKit/OWSIdentityManager.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/OWSUnknownContactBlockOfferMessage.h>
#import <SignalServiceKit/OWSVerificationStateChangeMessage.h>
#import <SignalServiceKit/SignalRecipient.h>
#import <SignalServiceKit/TSAccountManager.h>
@ -154,6 +155,7 @@ typedef enum : NSUInteger {
OWSConversationSettingsViewDelegate,
OWSMessagesCollectionViewFlowLayoutDelegate,
OWSSystemMessageCellDelegate,
OWSContactOffersCellDelegate,
OWSTextViewPasteDelegate,
OWSVoiceMemoGestureDelegate,
UIDocumentMenuDelegate,
@ -481,6 +483,9 @@ typedef enum : NSUInteger {
[self.collectionView registerClass:[OWSUnreadIndicatorCell class]
forCellWithReuseIdentifier:[OWSUnreadIndicatorCell cellReuseIdentifier]];
[self.collectionView registerClass:[OWSContactOffersCell class]
forCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]];
self.outgoingCellIdentifier = [OWSOutgoingMessageCollectionViewCell cellReuseIdentifier];
[self.collectionView registerNib:[OWSOutgoingMessageCollectionViewCell nib]
forCellWithReuseIdentifier:[OWSOutgoingMessageCollectionViewCell cellReuseIdentifier]];
@ -1649,6 +1654,10 @@ typedef enum : NSUInteger {
cell = [self loadUnreadIndicatorCell:indexPath interaction:message.interaction];
break;
}
case OWSContactOffersAdapter: {
cell = [self loadContactOffersCell:indexPath interaction:message.interaction];
break;
}
default: {
OWSFail(@"using default cell constructor for message: %@", message);
cell = (JSQMessagesCollectionViewCell *)[super collectionView:collectionView
@ -1737,6 +1746,24 @@ typedef enum : NSUInteger {
return cell;
}
- (JSQMessagesCollectionViewCell *)loadContactOffersCell:(NSIndexPath *)indexPath
interaction:(TSInteraction *)interaction
{
OWSAssert(indexPath);
OWSAssert(interaction);
OWSAssert([interaction isKindOfClass:[OWSContactOffersInteraction class]]);
OWSContactOffersInteraction *offersInteraction = (OWSContactOffersInteraction *)interaction;
OWSContactOffersCell *cell =
[self.collectionView dequeueReusableCellWithReuseIdentifier:[OWSContactOffersCell cellReuseIdentifier]
forIndexPath:indexPath];
cell.contactOffersCellDelegate = self;
[cell configureWithInteraction:offersInteraction];
return cell;
}
- (OWSSystemMessageCell *)loadSystemMessageCell:(NSIndexPath *)indexPath interaction:(TSInteraction *)interaction
{
OWSAssert(indexPath);
@ -1822,8 +1849,10 @@ typedef enum : NSUInteger {
id<OWSMessageData> previousMessage =
[self messageAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row - 1 inSection:indexPath.section]];
if ([previousMessage.interaction isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
// Always show timestamp between unread indicator and the following interaction
if ([previousMessage.interaction isKindOfClass:[TSUnreadIndicatorInteraction class]] ||
[previousMessage.interaction isKindOfClass:[OWSContactOffersInteraction class]]) {
// Always show timestamp between unread indicator / contacts offers
// and the following interaction.
return YES;
}
@ -2140,10 +2169,9 @@ typedef enum : NSUInteger {
// Restart failed downloads
if (attachmentPointer.state == TSAttachmentPointerStateFailed) {
if (![interaction isKindOfClass:[TSMessage class]]) {
DDLogError(@"%@ Expected attachment downloads from an instance of message, but found: %@",
OWSFail(@"%@ Expected attachment downloads from an instance of message, but found: %@",
self.tag,
interaction);
OWSAssert(NO);
return;
}
TSMessage *message = (TSMessage *)interaction;
@ -2165,6 +2193,9 @@ typedef enum : NSUInteger {
case TSUnreadIndicatorAdapter:
OWSFail(@"Unexpected tap for system message.");
break;
case OWSContactOffersAdapter:
OWSFail(@"Unexpected tap for contacts offer.");
break;
default:
DDLogDebug(@"Unhandled bubble touch for interaction: %@.", interaction);
break;
@ -2420,8 +2451,8 @@ typedef enum : NSUInteger {
case TSErrorMessageInvalidVersion:
break;
case TSErrorMessageUnknownContactBlockOffer:
OWSAssert([message isKindOfClass:[OWSUnknownContactBlockOfferMessage class]]);
[self tappedUnknownContactBlockOfferMessage:(OWSUnknownContactBlockOfferMessage *)message];
// Unused.
OWSFail(@"TSErrorMessageUnknownContactBlockOffer");
return;
case TSErrorMessageGroupCreationFailed:
[self resendGroupUpdateForErrorMessage:message];
@ -2462,13 +2493,16 @@ typedef enum : NSUInteger {
// Unused.
break;
case TSInfoMessageAddToContactsOffer:
OWSAssert([message isKindOfClass:[OWSAddToContactsOfferMessage class]]);
[self tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)message];
// Unused.
OWSFail(@"TSInfoMessageAddToContactsOffer");
return;
case TSInfoMessageAddUserToProfileWhitelistOffer:
// Unused.
OWSFail(@"TSInfoMessageAddUserToProfileWhitelistOffer");
return;
case TSInfoMessageAddGroupToProfileWhitelistOffer:
OWSAssert([message isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]);
[self tappedAddToProfileWhitelistOfferMessage:(OWSAddToProfileWhitelistOfferMessage *)message];
// Unused.
OWSFail(@"TSInfoMessageAddGroupToProfileWhitelistOffer");
return;
case TSInfoMessageTypeGroupUpdate:
[self showConversationSettings];
@ -2562,9 +2596,51 @@ typedef enum : NSUInteger {
[self presentViewController:actionSheetController animated:YES completion:nil];
}
- (void)tappedUnknownContactBlockOfferMessage:(OWSUnknownContactBlockOfferMessage *)errorMessage
- (void)handleCallTap:(TSCall *)call
{
NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:errorMessage.contactId];
OWSAssert(call);
if (![self.thread isKindOfClass:[TSContactThread class]]) {
OWSFail(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
return;
}
TSContactThread *contactThread = (TSContactThread *)self.thread;
NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:contactThread.contactIdentifier];
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:[CallStrings callBackAlertTitle]
message:[NSString stringWithFormat:[CallStrings callBackAlertMessageFormat], displayName]
preferredStyle:UIAlertControllerStyleAlert];
__weak MessagesViewController *weakSelf = self;
UIAlertAction *callAction = [UIAlertAction actionWithTitle:[CallStrings callBackAlertCallButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[weakSelf callAction:nil];
}];
[alertController addAction:callAction];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil)
style:UIAlertActionStyleCancel
handler:nil];
[alertController addAction:dismissAction];
[[UIApplication sharedApplication].frontmostViewController presentViewController:alertController
animated:YES
completion:nil];
}
#pragma mark - OWSContactOffersCellDelegate
- (void)tappedUnknownContactBlockOfferMessage:(OWSContactOffersInteraction *)interaction
{
if (![self.thread isKindOfClass:[TSContactThread class]]) {
OWSFail(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
return;
}
TSContactThread *contactThread = (TSContactThread *)self.thread;
NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:interaction.recipientId];
NSString *title =
[NSString stringWithFormat:NSLocalizedString(@"BLOCK_OFFER_ACTIONSHEET_TITLE_FORMAT",
@"Title format for action sheet that offers to block an unknown user."
@ -2585,11 +2661,13 @@ typedef enum : NSUInteger {
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
DDLogInfo(@"%@ Blocking an unknown user.", self.tag);
[self.blockingManager addBlockedPhoneNumber:errorMessage.contactId];
// Delete the block offer.
[self.blockingManager addBlockedPhoneNumber:interaction.recipientId];
// Delete the offers.
[self.editingDatabaseConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[errorMessage removeWithTransaction:transaction];
contactThread.hasDismissedOffers = YES;
[contactThread saveWithTransaction:transaction];
[interaction removeWithTransaction:transaction];
}];
}];
[actionSheetController addAction:blockAction];
@ -2597,27 +2675,37 @@ typedef enum : NSUInteger {
[self presentViewController:actionSheetController animated:YES completion:nil];
}
- (void)tappedAddToContactsOfferMessage:(OWSAddToContactsOfferMessage *)message
- (void)tappedAddToContactsOfferMessage:(OWSContactOffersInteraction *)interaction
{
if (!self.contactsManager.supportsContactEditing) {
DDLogError(@"%@ Contact editing not supported", self.tag);
OWSAssert(NO);
OWSFail(@"%@ Contact editing not supported", self.tag);
return;
}
if (![self.thread isKindOfClass:[TSContactThread class]]) {
DDLogError(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
OWSAssert(NO);
OWSFail(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
return;
}
TSContactThread *contactThread = (TSContactThread *)self.thread;
[self.contactsViewHelper presentContactViewControllerForRecipientId:contactThread.contactIdentifier
fromViewController:self
editImmediately:YES];
// Delete the offers.
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
contactThread.hasDismissedOffers = YES;
[contactThread saveWithTransaction:transaction];
[interaction removeWithTransaction:transaction];
}];
}
- (void)tappedAddToProfileWhitelistOfferMessage:(OWSAddToProfileWhitelistOfferMessage *)message
- (void)tappedAddToProfileWhitelistOfferMessage:(OWSContactOffersInteraction *)interaction
{
if (![self.thread isKindOfClass:[TSContactThread class]]) {
OWSFail(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
return;
}
TSContactThread *contactThread = (TSContactThread *)self.thread;
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
@ -2628,7 +2716,12 @@ typedef enum : NSUInteger {
handler:^(UIAlertAction *_Nonnull action) {
[OWSProfileManager.sharedManager addThreadToProfileWhitelist:self.thread];
[self ensureDynamicInteractions];
// Delete the offers.
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
contactThread.hasDismissedOffers = YES;
[contactThread saveWithTransaction:transaction];
[interaction removeWithTransaction:transaction];
}];
}];
[alertController addAction:leaveAction];
@ -2642,41 +2735,6 @@ typedef enum : NSUInteger {
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)handleCallTap:(TSCall *)call
{
OWSAssert(call);
if (![self.thread isKindOfClass:[TSContactThread class]]) {
DDLogError(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
OWSAssert(NO);
return;
}
TSContactThread *contactThread = (TSContactThread *)self.thread;
NSString *displayName = [self.contactsManager displayNameForPhoneIdentifier:contactThread.contactIdentifier];
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:[CallStrings callBackAlertTitle]
message:[NSString stringWithFormat:[CallStrings callBackAlertMessageFormat], displayName]
preferredStyle:UIAlertControllerStyleAlert];
__weak MessagesViewController *weakSelf = self;
UIAlertAction *callAction = [UIAlertAction actionWithTitle:[CallStrings callBackAlertCallButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[weakSelf callAction:nil];
}];
[alertController addAction:callAction];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil)
style:UIAlertActionStyleCancel
handler:nil];
[alertController addAction:dismissAction];
[[UIApplication sharedApplication].frontmostViewController presentViewController:alertController
animated:YES
completion:nil];
}
#pragma mark - OWSSystemMessageCellDelegate
- (void)didTapSystemMessageWithInteraction:(TSInteraction *)interaction
@ -2909,13 +2967,10 @@ typedef enum : NSUInteger {
NSError *typeError;
[url getResourceValue:&type forKey:NSURLTypeIdentifierKey error:&typeError];
if (typeError) {
DDLogError(
@"%@ Determining type of picked document at url: %@ failed with error: %@", self.tag, url, typeError);
OWSAssert(NO);
OWSFail(@"%@ Determining type of picked document at url: %@ failed with error: %@", self.tag, url, typeError);
}
if (!type) {
DDLogDebug(@"%@ falling back to default filetype for picked document at url: %@", self.tag, url);
OWSAssert(NO);
OWSFail(@"%@ falling back to default filetype for picked document at url: %@", self.tag, url);
type = (__bridge NSString *)kUTTypeData;
}
@ -2923,11 +2978,10 @@ typedef enum : NSUInteger {
NSError *isDirectoryError;
[url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&isDirectoryError];
if (isDirectoryError) {
DDLogError(@"%@ Determining if picked document at url: %@ was a directory failed with error: %@",
OWSFail(@"%@ Determining if picked document at url: %@ was a directory failed with error: %@",
self.tag,
url,
isDirectoryError);
OWSAssert(NO);
} else if ([isDirectory boolValue]) {
DDLogInfo(@"%@ User picked directory at url: %@", self.tag, url);
UIAlertController *alertController = [UIAlertController
@ -2951,15 +3005,13 @@ typedef enum : NSUInteger {
NSString *filename = url.lastPathComponent;
if (!filename) {
DDLogDebug(@"%@ Unable to determine filename from url: %@", self.tag, url);
OWSAssert(NO);
OWSFail(@"%@ Unable to determine filename from url: %@", self.tag, url);
filename = NSLocalizedString(
@"ATTACHMENT_DEFAULT_FILENAME", @"Generic filename for an attachment with no known name");
}
if (!attachmentData || attachmentData.length == 0) {
DDLogError(@"%@ attachment data was unexpectedly empty for picked document url: %@", self.tag, url);
OWSAssert(NO);
OWSFail(@"%@ attachment data was unexpectedly empty for picked document url: %@", self.tag, url);
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:NSLocalizedString(@"ATTACHMENT_PICKER_DOCUMENTS_FAILED_ALERT_TITLE",
@"Alert title when picking a document fails for an unknown reason")
@ -4198,9 +4250,10 @@ typedef enum : NSUInteger {
- (BOOL)shouldShowCellDecorationsAtIndexPath:(NSIndexPath *)indexPath
{
TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
// Show any top/bottom labels for all but the unread indicator
return ![interaction isKindOfClass:[TSUnreadIndicatorInteraction class]];
return !([interaction isKindOfClass:[TSUnreadIndicatorInteraction class]] ||
[interaction isKindOfClass:[OWSContactOffersInteraction class]]);
}
#pragma mark - Database Observation

@ -63,6 +63,10 @@ NS_ASSUME_NONNULL_BEGIN
[OWSProfileManager.sharedManager logProfileWhitelist];
}]];
#endif
[items addObject:[OWSTableItem itemWithTitle:@"Clear hasDismissedOffers"
actionBlock:^{
[DebugUIMisc clearHasDismissedOffers];
}]];
return [OWSTableSection sectionWithTitle:self.name items:items];
}
@ -93,6 +97,30 @@ NS_ASSUME_NONNULL_BEGIN
OWSSignalService.sharedInstance.isCensorshipCircumventionManuallyActivated = isEnabled;
}
+ (void)clearHasDismissedOffers
{
[TSStorageManager.sharedManager.dbReadWriteConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
NSMutableArray<TSContactThread *> *contactThreads = [NSMutableArray new];
[transaction
enumerateKeysAndObjectsInCollection:[TSThread collection]
usingBlock:^(NSString *_Nonnull key, id _Nonnull object, BOOL *_Nonnull stop) {
TSThread *thread = object;
if (thread.isGroupThread) {
return;
}
TSContactThread *contactThread = object;
[contactThreads addObject:contactThread];
}];
for (TSContactThread *contactThread in contactThreads) {
if (contactThread.hasDismissedOffers) {
contactThread.hasDismissedOffers = NO;
[contactThread saveWithTransaction:transaction];
}
}
}];
}
@end
NS_ASSUME_NONNULL_END

@ -195,8 +195,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert(self.recipientId);
if (!self.contactsManager.supportsContactEditing) {
DDLogError(@"%@ Contact editing not supported", self.tag);
OWSAssert(NO);
OWSFail(@"%@ Contact editing not supported", self.tag);
return;
}
[self.contactsViewHelper presentContactViewControllerForRecipientId:self.recipientId

@ -833,13 +833,11 @@ NS_ASSUME_NONNULL_BEGIN
- (void)presentContactViewController
{
if (!self.contactsManager.supportsContactEditing) {
DDLogError(@"%@ Contact editing not supported", self.tag);
OWSAssert(NO);
OWSFail(@"%@ Contact editing not supported", self.tag);
return;
}
if (![self.thread isKindOfClass:[TSContactThread class]]) {
DDLogError(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
OWSAssert(NO);
OWSFail(@"%@ unexpected thread: %@ in %s", self.tag, self.thread, __PRETTY_FUNCTION__);
return;
}

@ -24,8 +24,7 @@ static NSString *const OWS101ExistingUsersBlockOnIdentityChangeMigrationId = @"1
- (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
DDLogWarn(@"[OWS101ExistingUsersBlockOnIdentityChange] has been obviated.");
OWSAssert(NO);
OWSFail(@"[OWS101ExistingUsersBlockOnIdentityChange] has been obviated.");
}
@end

@ -36,12 +36,11 @@ static NSString *const OWS104CreateRecipientIdentitiesMigrationId = @"104";
usingBlock:^(
NSString *_Nonnull recipientId, id _Nonnull object, BOOL *_Nonnull stop) {
if (![object isKindOfClass:[NSData class]]) {
DDLogError(
OWSFail(
@"%@ Unexpected object in trusted keys collection key: %@ object: %@",
self.tag,
recipientId,
object);
OWSAssert(NO);
return;
}
NSData *identityKey = (NSData *)object;

@ -12,7 +12,6 @@ NS_ASSUME_NONNULL_BEGIN
@class TSInteraction;
@class YapDatabaseConnection;
@class TSThread;
@class TSUnreadIndicatorInteraction;
@interface ThreadDynamicInteractions : NSObject

@ -3,6 +3,7 @@
//
#import "ThreadUtil.h"
#import "OWSContactOffersInteraction.h"
#import "OWSContactsManager.h"
#import "OWSProfileManager.h"
#import "Signal-Swift.h"
@ -152,30 +153,47 @@ NS_ASSUME_NONNULL_BEGIN
const int kMaxBlockOfferOutgoingMessageCount = 10;
// Find any "dynamic" interactions and safety number changes.
__block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil;
__block OWSAddToProfileWhitelistOfferMessage *existingOWSAddToProfileWhitelistOffer = nil;
__block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil;
//
// We use different views for performance reasons.
__block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil;
__block OWSContactOffersInteraction *existingContactOffers = nil;
NSMutableArray<TSInvalidIdentityKeyErrorMessage *> *blockingSafetyNumberChanges = [NSMutableArray new];
NSMutableArray<TSInteraction *> *nonBlockingSafetyNumberChanges = [NSMutableArray new];
// We use different views for performance reasons.
// We want to delete legacy and duplicate interactions.
NSMutableArray<TSInteraction *> *interactionsToDelete = [NSMutableArray new];
[[TSDatabaseView threadSpecialMessagesDatabaseView:transaction]
enumerateRowsInGroup:thread.uniqueId
usingBlock:^(
NSString *collection, NSString *key, id object, id metadata, NSUInteger index, BOOL *stop) {
if ([object isKindOfClass:[OWSUnknownContactBlockOfferMessage class]]) {
OWSAssert(!existingBlockOffer);
existingBlockOffer = (OWSUnknownContactBlockOfferMessage *)object;
// Delete this legacy interactions, which has been superseded by
// the OWSContactOffersInteraction.
[interactionsToDelete addObject:object];
} else if ([object isKindOfClass:[OWSAddToContactsOfferMessage class]]) {
OWSAssert(!existingAddToContactsOffer);
existingAddToContactsOffer = (OWSAddToContactsOfferMessage *)object;
// Delete this legacy interactions, which has been superseded by
// the OWSContactOffersInteraction.
[interactionsToDelete addObject:object];
} else if ([object isKindOfClass:[OWSAddToProfileWhitelistOfferMessage class]]) {
OWSAssert(!existingOWSAddToProfileWhitelistOffer);
existingOWSAddToProfileWhitelistOffer = (OWSAddToProfileWhitelistOfferMessage *)object;
// Delete this legacy interactions, which has been superseded by
// the OWSContactOffersInteraction.
[interactionsToDelete addObject:object];
} else if ([object isKindOfClass:[TSUnreadIndicatorInteraction class]]) {
OWSAssert(!existingUnreadIndicator);
if (existingUnreadIndicator) {
// There should never be more than one unread indicator in
// a given thread, but if there is, discard all but one.
[interactionsToDelete addObject:existingUnreadIndicator];
}
existingUnreadIndicator = (TSUnreadIndicatorInteraction *)object;
} else if ([object isKindOfClass:[OWSContactOffersInteraction class]]) {
OWSAssert(!existingContactOffers);
if (existingContactOffers) {
// There should never be more than one "contact offers" in
// a given thread, but if there is, discard all but one.
[interactionsToDelete addObject:existingContactOffers];
}
existingContactOffers = (OWSContactOffersInteraction *)object;
} else if ([object isKindOfClass:[TSInvalidIdentityKeyErrorMessage class]]) {
[blockingSafetyNumberChanges addObject:object];
} else if ([object isKindOfClass:[TSErrorMessage class]]) {
@ -188,6 +206,11 @@ NS_ASSUME_NONNULL_BEGIN
}
}];
for (TSInteraction *interaction in interactionsToDelete) {
DDLogDebug(@"Cleaning up interaction: %@", [interaction class]);
[interaction removeWithTransaction:transaction];
}
// Determine if there are "unread" messages in this conversation.
// If we've been passed a firstUnseenInteractionTimestampParameter,
// just use that value in order to preserve continuity of the
@ -205,7 +228,7 @@ NS_ASSUME_NONNULL_BEGIN
}
}
__block TSMessage *firstMessage = nil;
__block TSInteraction *firstCallOrMessage = nil;
[[transaction ext:TSMessageDatabaseViewExtensionName]
enumerateRowsInGroup:thread.uniqueId
usingBlock:^(
@ -214,8 +237,9 @@ NS_ASSUME_NONNULL_BEGIN
OWSAssert([object isKindOfClass:[TSInteraction class]]);
if ([object isKindOfClass:[TSIncomingMessage class]] ||
[object isKindOfClass:[TSOutgoingMessage class]]) {
firstMessage = (TSMessage *)object;
[object isKindOfClass:[TSOutgoingMessage class]] ||
[object isKindOfClass:[TSCall class]]) {
firstCallOrMessage = object;
*stop = YES;
}
}];
@ -325,6 +349,8 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveAddToContactsOffer = NO;
// Only create block offers in 1:1 conversations.
shouldHaveBlockOffer = NO;
// Only create profile whitelist offers in 1:1 conversations.
shouldHaveAddToProfileWhitelistOffer = NO;
} else {
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
@ -351,13 +377,16 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveAddToContactsOffer = NO;
// Only create block offers for non-contacts.
shouldHaveBlockOffer = NO;
// Don't create profile whitelist offers for non-contacts.
shouldHaveAddToProfileWhitelistOffer = NO;
}
}
}
if (!firstMessage) {
if (!firstCallOrMessage) {
shouldHaveAddToContactsOffer = NO;
shouldHaveBlockOffer = NO;
shouldHaveAddToProfileWhitelistOffer = NO;
}
if (outgoingMessageCount > kMaxBlockOfferOutgoingMessageCount) {
@ -365,7 +394,12 @@ NS_ASSUME_NONNULL_BEGIN
shouldHaveBlockOffer = NO;
}
BOOL hasOutgoingBeforeIncomingInteraction = [firstMessage isKindOfClass:[TSOutgoingMessage class]];
BOOL hasOutgoingBeforeIncomingInteraction = [firstCallOrMessage isKindOfClass:[TSOutgoingMessage class]];
if ([firstCallOrMessage isKindOfClass:[TSCall class]]) {
TSCall *call = (TSCall *)firstCallOrMessage;
hasOutgoingBeforeIncomingInteraction
= (call.callType == RPRecentCallTypeOutgoing || call.callType == RPRecentCallTypeOutgoingIncomplete);
}
if (hasOutgoingBeforeIncomingInteraction) {
// If there is an outgoing message before an incoming message
// the local user initiated this conversation, don't show a block offer.
@ -392,87 +426,64 @@ NS_ASSUME_NONNULL_BEGIN
}
}
BOOL shouldHaveContactOffers
= (shouldHaveBlockOffer || shouldHaveAddToContactsOffer || shouldHaveAddToProfileWhitelistOffer);
if (isContactThread) {
TSContactThread *contactThread = (TSContactThread *)thread;
if (contactThread.hasDismissedOffers) {
shouldHaveContactOffers = NO;
}
}
// We use these offset to control the ordering of the offers and indicators.
const int kAddToProfileWhitelistOfferOffset = -4;
const int kBlockOfferOffset = -3;
const int kAddToContactsOfferOffset = -2;
const int kUnreadIndicatorOfferOffset = -1;
const int kUnreadIndicatorOffset = -1;
// We want the offers to be the first interactions in their
// conversation's timeline, so we back-date them to slightly before
// the first message - or at an aribtrary old timestamp if the
// conversation has no messages.
long long startOfConversationTimestamp
= (long long)(firstMessage ? firstMessage.timestampForSorting : 1000);
if (existingBlockOffer && !shouldHaveBlockOffer) {
DDLogInfo(@"%@ Removing block offer: %@ (%llu)",
self.tag,
existingBlockOffer.uniqueId,
existingBlockOffer.timestampForSorting);
[existingBlockOffer removeWithTransaction:transaction];
} else if (!existingBlockOffer && shouldHaveBlockOffer) {
DDLogInfo(@"Creating block offer for unknown contact");
uint64_t blockOfferTimestamp = (uint64_t)(startOfConversationTimestamp + kBlockOfferOffset);
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
TSMessage *offerMessage =
[OWSUnknownContactBlockOfferMessage unknownContactBlockOfferMessage:blockOfferTimestamp
thread:thread
contactId:recipientId];
[offerMessage saveWithTransaction:transaction];
DDLogInfo(@"%@ Creating block offer: %@ (%llu)",
self.tag,
offerMessage.uniqueId,
offerMessage.timestampForSorting);
uint64_t contactOffersTimestamp = [NSDate ows_millisecondTimeStamp];
// If the contact offers' properties have changed, discard the current
// one and create a new one.
if (existingContactOffers) {
if (existingContactOffers.hasBlockOffer != shouldHaveBlockOffer
|| existingContactOffers.hasAddToContactsOffer != shouldHaveAddToContactsOffer
|| existingContactOffers.hasAddToProfileWhitelistOffer != shouldHaveAddToProfileWhitelistOffer) {
DDLogInfo(@"%@ Removing stale contact offers: %@ (%llu)",
self.tag,
existingContactOffers.uniqueId,
existingContactOffers.timestampForSorting);
// Preserve the timestamp of the existing "contact offers" so that
// we replace it in the same position in the timeline.
contactOffersTimestamp = existingContactOffers.timestamp;
[existingContactOffers removeWithTransaction:transaction];
existingContactOffers = nil;
}
}
if (existingAddToContactsOffer && !shouldHaveAddToContactsOffer) {
DDLogInfo(@"%@ Removing 'add to contacts' offer: %@ (%llu)",
if (existingContactOffers && !shouldHaveContactOffers) {
DDLogInfo(@"%@ Removing contact offers: %@ (%llu)",
self.tag,
existingAddToContactsOffer.uniqueId,
existingAddToContactsOffer.timestampForSorting);
[existingAddToContactsOffer removeWithTransaction:transaction];
} else if (!existingAddToContactsOffer && shouldHaveAddToContactsOffer) {
DDLogInfo(@"%@ Creating 'add to contacts' offer for unknown contact", self.tag);
uint64_t offerTimestamp = (uint64_t)(startOfConversationTimestamp + kAddToContactsOfferOffset);
existingContactOffers.uniqueId,
existingContactOffers.timestampForSorting);
[existingContactOffers removeWithTransaction:transaction];
} else if (!existingContactOffers && shouldHaveContactOffers) {
NSString *recipientId = ((TSContactThread *)thread).contactIdentifier;
TSMessage *offerMessage = [OWSAddToContactsOfferMessage addToContactsOfferMessage:offerTimestamp
thread:thread
contactId:recipientId];
[offerMessage saveWithTransaction:transaction];
DDLogInfo(@"%@ Creating 'add to contacts' offer: %@ (%llu)",
self.tag,
offerMessage.uniqueId,
offerMessage.timestampForSorting);
}
if (existingOWSAddToProfileWhitelistOffer && !shouldHaveAddToProfileWhitelistOffer) {
DDLogInfo(@"%@ Removing 'add to profile whitelist' offer: %@ (%llu)",
self.tag,
existingOWSAddToProfileWhitelistOffer.uniqueId,
existingOWSAddToProfileWhitelistOffer.timestampForSorting);
[existingOWSAddToProfileWhitelistOffer removeWithTransaction:transaction];
} else if (!existingOWSAddToProfileWhitelistOffer && shouldHaveAddToProfileWhitelistOffer) {
DDLogInfo(@"%@ Creating 'add to profile whitelist' offer", self.tag);
uint64_t offerTimestamp = (uint64_t)(startOfConversationTimestamp + kAddToProfileWhitelistOfferOffset);
TSMessage *offerMessage =
[OWSAddToProfileWhitelistOfferMessage addToProfileWhitelistOfferMessage:offerTimestamp thread:thread];
[offerMessage saveWithTransaction:transaction];
TSInteraction *offersMessage =
[[OWSContactOffersInteraction alloc] initWithTimestamp:contactOffersTimestamp
thread:thread
hasBlockOffer:shouldHaveBlockOffer
hasAddToContactsOffer:shouldHaveAddToContactsOffer
hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer
recipientId:recipientId];
[offersMessage saveWithTransaction:transaction];
DDLogInfo(@"%@ Creating 'add to profile whitelist' offer: %@ (%llu)",
DDLogInfo(@"%@ Creating contact offers: %@ (%llu)",
self.tag,
offerMessage.uniqueId,
offerMessage.timestampForSorting);
offersMessage.uniqueId,
offersMessage.timestampForSorting);
}
BOOL shouldHaveUnreadIndicator
@ -489,8 +500,8 @@ NS_ASSUME_NONNULL_BEGIN
// message in the conversation timeline...
//
// ...unless we have a fixed timestamp for the unread indicator.
uint64_t indicatorTimestamp = (uint64_t)(
(long long)interactionAfterUnreadIndicator.timestampForSorting + kUnreadIndicatorOfferOffset);
uint64_t indicatorTimestamp
= (uint64_t)((long long)interactionAfterUnreadIndicator.timestampForSorting + kUnreadIndicatorOffset);
if (indicatorTimestamp && existingUnreadIndicator.timestampForSorting == indicatorTimestamp) {
// Keep the existing indicator; it is in the correct position.

@ -0,0 +1,35 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <JSQMessagesViewController/JSQMessagesCollectionViewCell.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class OWSContactOffersInteraction;
@protocol OWSContactOffersCellDelegate <NSObject>
- (void)tappedUnknownContactBlockOfferMessage:(OWSContactOffersInteraction *)interaction;
- (void)tappedAddToContactsOfferMessage:(OWSContactOffersInteraction *)interaction;
- (void)tappedAddToProfileWhitelistOfferMessage:(OWSContactOffersInteraction *)interaction;
@end
#pragma mark -
@interface OWSContactOffersCell : JSQMessagesCollectionViewCell
@property (nonatomic, weak) id<OWSContactOffersCellDelegate> contactOffersCellDelegate;
@property (nonatomic, nullable, readonly) OWSContactOffersInteraction *interaction;
- (void)configureWithInteraction:(OWSContactOffersInteraction *)interaction;
- (CGSize)bubbleSizeForInteraction:(OWSContactOffersInteraction *)interaction
collectionViewWidth:(CGFloat)collectionViewWidth;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,236 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSContactOffersCell.h"
#import "NSBundle+JSQMessages.h"
#import "OWSContactOffersInteraction.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
#import "UIView+OWS.h"
#import <JSQMessagesViewController/UIView+JSQMessages.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSContactOffersCell ()
@property (nonatomic, nullable) OWSContactOffersInteraction *interaction;
@property (nonatomic) UILabel *titleLabel;
@property (nonatomic) UIButton *addToContactsButton;
@property (nonatomic) UIButton *addToProfileWhitelistButton;
@property (nonatomic) UIButton *blockButton;
@end
#pragma mark -
@implementation OWSContactOffersCell
// `[UIView init]` invokes `[self initWithFrame:...]`.
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self commontInit];
}
return self;
}
- (void)commontInit
{
OWSAssert(!self.titleLabel);
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.titleLabel = [UILabel new];
self.titleLabel.textColor = [UIColor blackColor];
self.titleLabel.font = [self titleFont];
self.titleLabel.text = NSLocalizedString(@"CONVERSATION_VIEW_CONTACTS_OFFER_TITLE",
@"Title for the group of buttons show for unknown contacts offering to add them to contacts, etc.");
self.titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
self.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.contentView addSubview:self.titleLabel];
self.addToContactsButton = [self
createButtonWithTitle:
NSLocalizedString(@"CONVERSATION_VIEW_ADD_TO_CONTACTS_OFFER",
@"Message shown in conversation view that offers to add an unknown user to your phone's contacts.")
selector:@selector(addToContacts)];
self.addToProfileWhitelistButton = [self
createButtonWithTitle:NSLocalizedString(@"CONVERSATION_VIEW_ADD_USER_TO_PROFILE_WHITELIST_OFFER",
@"Message shown in conversation view that offers to share your profile with a user.")
selector:@selector(addToProfileWhitelist)];
self.blockButton =
[self createButtonWithTitle:NSLocalizedString(@"CONVERSATION_VIEW_UNKNOWN_CONTACT_BLOCK_OFFER",
@"Message shown in conversation view that offers to block an unknown user.")
selector:@selector(block)];
}
- (UIButton *)createButtonWithTitle:(NSString *)title selector:(SEL)selector
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:[UIColor ows_materialBlueColor] forState:UIControlStateNormal];
button.titleLabel.font = self.buttonFont;
button.titleLabel.textAlignment = NSTextAlignmentCenter;
[button setBackgroundColor:[UIColor colorWithRGBHex:0xf5f5f5]];
button.layer.cornerRadius = 5.f;
[button addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:button];
return button;
}
+ (NSString *)cellReuseIdentifier
{
return NSStringFromClass([self class]);
}
- (void)configureWithInteraction:(OWSContactOffersInteraction *)interaction;
{
OWSAssert(interaction);
_interaction = interaction;
OWSAssert(
interaction.hasBlockOffer || interaction.hasAddToContactsOffer || interaction.hasAddToProfileWhitelistOffer);
[self setNeedsLayout];
}
- (UIFont *)titleFont
{
return [UIFont ows_mediumFontWithSize:16.f];
}
- (UIFont *)buttonFont
{
return [UIFont ows_regularFontWithSize:14.f];
}
- (CGFloat)hMargin
{
return 10.f;
}
- (CGFloat)topVMargin
{
return 5.f;
}
- (CGFloat)bottomVMargin
{
return 5.f;
}
- (CGFloat)buttonVPadding
{
return 5.f;
}
- (CGFloat)buttonVSpacing
{
return 5.f;
}
- (void)layoutSubviews
{
[super layoutSubviews];
// We're using a bit of a hack to get JSQ to layout this and the unread indicator as
// "full width" cells. These cells will end up with an erroneous left margin that we
// want to reverse.
CGFloat contentWidth = self.width;
CGFloat left = -self.left;
CGRect titleFrame = self.contentView.bounds;
titleFrame.origin = CGPointMake(left + self.hMargin, self.topVMargin);
titleFrame.size.width = contentWidth - 2 * self.hMargin;
titleFrame.size.height = ceil([self.titleLabel sizeThatFits:CGSizeZero].height);
self.titleLabel.frame = titleFrame;
__block CGFloat y = round(self.titleLabel.bottom + self.buttonVSpacing);
void (^layoutButton)(UIButton *, BOOL) = ^(UIButton *button, bool isVisible) {
if (isVisible) {
button.hidden = NO;
button.frame = CGRectMake(round(left + self.hMargin),
round(y),
floor(contentWidth - 2 * self.hMargin),
ceil([button sizeThatFits:CGSizeZero].height + self.buttonVPadding));
y = round(button.bottom + self.buttonVSpacing);
} else {
button.hidden = YES;
}
};
layoutButton(self.addToContactsButton, self.interaction.hasAddToContactsOffer);
layoutButton(self.addToProfileWhitelistButton, self.interaction.hasAddToProfileWhitelistOffer);
layoutButton(self.blockButton, self.interaction.hasBlockOffer);
}
- (CGSize)bubbleSizeForInteraction:(OWSContactOffersInteraction *)interaction
collectionViewWidth:(CGFloat)collectionViewWidth
{
CGSize result = CGSizeMake(collectionViewWidth, 0);
result.height += self.topVMargin;
result.height += self.bottomVMargin;
result.height += ceil([self.titleLabel sizeThatFits:CGSizeZero].height);
int buttonCount = ((interaction.hasBlockOffer ? 1 : 0) + (interaction.hasAddToContactsOffer ? 1 : 0)
+ (interaction.hasAddToProfileWhitelistOffer ? 1 : 0));
result.height += buttonCount
* (self.buttonVPadding + self.buttonVSpacing + ceil([self.addToContactsButton sizeThatFits:CGSizeZero].height));
return result;
}
- (void)prepareForReuse
{
[super prepareForReuse];
self.interaction = nil;
}
#pragma mark - Events
- (void)addToContacts
{
OWSAssert(self.contactOffersCellDelegate);
OWSAssert(self.interaction);
[self.contactOffersCellDelegate tappedAddToContactsOfferMessage:self.interaction];
}
- (void)addToProfileWhitelist
{
OWSAssert(self.contactOffersCellDelegate);
OWSAssert(self.interaction);
[self.contactOffersCellDelegate tappedAddToProfileWhitelistOfferMessage:self.interaction];
}
- (void)block
{
OWSAssert(self.contactOffersCellDelegate);
OWSAssert(self.interaction);
[self.contactOffersCellDelegate tappedUnknownContactBlockOfferMessage:self.interaction];
}
#pragma mark - Logging
+ (NSString *)logTag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)logTag
{
return self.class.logTag;
}
@end
NS_ASSUME_NONNULL_END

@ -6,7 +6,6 @@
#import "Environment.h"
#import "NSBundle+JSQMessages.h"
#import "OWSContactsManager.h"
#import "TSUnreadIndicatorInteraction.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
#import "UIView+OWS.h"
@ -315,11 +314,13 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Gesture recognizers
- (void)handleTapGesture:(UITapGestureRecognizer *)tap
- (void)handleTapGesture:(UITapGestureRecognizer *)sender
{
OWSAssert(self.interaction);
[self.systemMessageCellDelegate didTapSystemMessageWithInteraction:self.interaction];
if (sender.state == UIGestureRecognizerStateRecognized) {
[self.systemMessageCellDelegate didTapSystemMessageWithInteraction:self.interaction];
}
}
- (void)handleLongPressGesture:(UILongPressGestureRecognizer *)longPress

@ -364,6 +364,18 @@
/* Action that shares user profile with a user. */
"CONVERSATION_SETTINGS_VIEW_SHARE_PROFILE_WITH_USER" = "Share Your Profile";
/* Message shown in conversation view that offers to add an unknown user to your phone's contacts. */
"CONVERSATION_VIEW_ADD_TO_CONTACTS_OFFER" = "Add to Contacts";
/* Message shown in conversation view that offers to share your profile with a user. */
"CONVERSATION_VIEW_ADD_USER_TO_PROFILE_WHITELIST_OFFER" = "Share Your Profile With This User";
/* Title for the group of buttons show for unknown contacts offering to add them to contacts, etc. */
"CONVERSATION_VIEW_CONTACTS_OFFER_TITLE" = "This user is not in your contacts.";
/* Message shown in conversation view that offers to block an unknown user. */
"CONVERSATION_VIEW_UNKNOWN_CONTACT_BLOCK_OFFER" = "Block This User";
/* ActionSheet title */
"CORRUPTED_SESSION_DESCRIPTION" = "Resetting your session will allow you to receive future messages from %@, but it will not recover any already corrupted messages.";

@ -342,8 +342,7 @@ static const NSTimeInterval kSignedPreKeyUpdateFailureMaxFailureDuration = 10 *
+ (void)clearSignedPreKeyRecordsWithKeyId:(NSNumber *)keyId success:(void (^_Nullable)())successHandler
{
if (!keyId) {
OWSAssert(NO);
DDLogError(@"%@ Ignoring request to clear signed preKeys since no keyId was specified", self.tag);
OWSFail(@"%@ Ignoring request to clear signed preKeys since no keyId was specified", self.tag);
return;
}

@ -69,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
{
// This should never happen according to nullability annotations... but IIRC it does. =/
if (!identifier) {
OWSAssert(NO);
OWSFail(@"%@ Cannot lookup nil identifier", self.tag);
failure(OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup nil identifier"));
return;
}
@ -90,7 +90,7 @@ NS_ASSUME_NONNULL_BEGIN
failure:(void (^)(NSError *error))failure
{
if (identifiers.count < 1) {
OWSAssert(NO);
OWSFail(@"%@ Cannot lookup zero identifiers", self.tag);
failure(OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup zero identifiers"));
return;
}

@ -1,5 +1,6 @@
// Created by Frederic Jacobs on 16/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSThread.h"
@ -7,6 +8,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface TSContactThread : TSThread
@property (nonatomic) BOOL hasDismissedOffers;
+ (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId NS_SWIFT_NAME(getOrCreateThread(contactId:));
+ (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId

@ -329,12 +329,11 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
if ([[self identityKeyPair].publicKey isEqualToData:identityKey]) {
return YES;
} else {
DDLogError(@"%@ Wrong identity: %@ for local key: %@, recipientId: %@",
OWSFail(@"%@ Wrong identity: %@ for local key: %@, recipientId: %@",
self.tag,
identityKey,
[self identityKeyPair].publicKey,
recipientId);
OWSAssert(NO);
return NO;
}
}
@ -348,8 +347,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
return [self isTrustedKey:identityKey forSendingToIdentity:existingIdentity];
}
default: {
DDLogError(@"%@ unexpected message direction: %ld", self.tag, (long)direction);
OWSAssert(NO);
OWSFail(@"%@ unexpected message direction: %ld", self.tag, (long)direction);
return NO;
}
}

@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
NSData *_Nullable theirIdentityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientId:theirSignalId];
if (theirIdentityKey == nil) {
OWSAssert(NO);
OWSFail(@"%@ Missing their identity key", self.tag);
return nil;
}
@ -60,6 +60,18 @@ NS_ASSUME_NONNULL_BEGIN
theirName:theirName];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

@ -132,8 +132,7 @@ OWSSignalServiceProtosVerifiedState OWSVerificationStateToProtoState(OWSVerifica
[self enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) {
count++;
if (![obj isKindOfClass:[self class]]) {
DDLogError(@"%@ unexpected object in collection: %@", self.tag, obj);
OWSAssert(NO);
OWSFail(@"%@ unexpected object in collection: %@", self.tag, obj);
return;
}
OWSRecipientIdentity *recipientIdentity = (OWSRecipientIdentity *)obj;

@ -72,7 +72,7 @@ void AssertIsOnSessionStoreQueue()
{
// Deprecated. We aren't currently using this anywhere, but it's "required" by the SessionStore protocol.
// If we are going to start using it I'd want to re-verify it works as intended.
OWSAssert(NO);
OWSFail(@"%@ subDevicesSessions is deprecated", self.tag);
AssertIsOnSessionStoreQueue();
__block NSDictionary *dictionary;
@ -202,8 +202,7 @@ void AssertIsOnSessionStoreQueue()
id _Nonnull deviceSessionsObject,
BOOL *_Nonnull stop) {
if (![deviceSessionsObject isKindOfClass:[NSDictionary class]]) {
OWSAssert(NO);
DDLogError(
OWSFail(
@"%@ Unexpected type: %@ in collection.", tag, deviceSessionsObject);
return;
}
@ -213,8 +212,7 @@ void AssertIsOnSessionStoreQueue()
[deviceSessions enumerateKeysAndObjectsUsingBlock:^(
id _Nonnull key, id _Nonnull sessionRecordObject, BOOL *_Nonnull stop) {
if (![sessionRecordObject isKindOfClass:[SessionRecord class]]) {
OWSAssert(NO);
DDLogError(@"%@ Unexpected type: %@ in collection.",
OWSFail(@"%@ Unexpected type: %@ in collection.",
tag,
sessionRecordObject);
return;
@ -235,4 +233,16 @@ void AssertIsOnSessionStoreQueue()
}];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end

@ -165,10 +165,9 @@ NSString *const TSStorageManagerKeyPrekeyCurrentSignedPrekeyId = @"currentSigned
NSString *_Nonnull key, id _Nonnull signedPreKeyObject, BOOL *_Nonnull stop) {
i++;
if (![signedPreKeyObject isKindOfClass:[SignedPreKeyRecord class]]) {
DDLogError(@"%@ Was expecting SignedPreKeyRecord, but found: %@",
OWSFail(@"%@ Was expecting SignedPreKeyRecord, but found: %@",
tag,
signedPreKeyObject);
OWSAssert(NO);
return;
}
SignedPreKeyRecord *signedPreKeyRecord

@ -116,8 +116,7 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess
sourceDeviceId:(uint32_t)sourceDeviceId
{
if (![self.database registeredExtension:OWSIncomingMessageFinderExtensionName]) {
DDLogError(@"%@ in %s but extension is not registered", self.tag, __PRETTY_FUNCTION__);
OWSAssert(NO);
OWSFail(@"%@ in %s but extension is not registered", self.tag, __PRETTY_FUNCTION__);
// we should be initializing this at startup rather than have an unexpectedly slow lazy setup at random.
[self registerExtension];
@ -138,7 +137,7 @@ NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMess
}];
if (!success) {
OWSAssert(NO);
OWSFail(@"%@ Could not execute query", self.tag);
return NO;
}

@ -144,7 +144,7 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic
[self registerMessageDatabaseViewWithName:TSUnseenDatabaseViewExtensionName
viewGrouping:viewGrouping
version:@"2"
version:@"1"
async:YES];
}

@ -452,8 +452,7 @@ NSString *const OWSMimeTypeUnknownForTests = @"unknown/mimetype";
for (NSString *mimeType in mimeTypes) {
NSString *_Nullable utiType = [self utiTypeForMIMEType:mimeType];
if (!utiType) {
DDLogError(@"%@ unknown utiType for mimetype: %@", self.tag, mimeType);
OWSAssert(NO);
OWSFail(@"%@ unknown utiType for mimetype: %@", self.tag, mimeType);
continue;
}
[result addObject:utiType];

Loading…
Cancel
Save