TextSecureKit Refactoring
- Using same clang format file for old and new files. - Moving out all TextSecure code to allow other clients (OS X, iOS) to integrate easily TextSecure functionality. - Use TextSecure API to signup.
This commit is contained in:
parent
37b582beda
commit
c6d44e59e2
|
@ -1,7 +1,11 @@
|
|||
---
|
||||
BasedOnStyle: Chromium
|
||||
AlignTrailingComments: true
|
||||
BreakBeforeBraces: Linux
|
||||
AlignConsecutiveAssignments: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
BreakBeforeBraces: Attach
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 120
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
|
|
|
@ -26,3 +26,5 @@ DerivedData
|
|||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
|
||||
Pods/
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "Pods"]
|
||||
path = Pods
|
||||
url = https://github.com/FredericJacobs/Precompiled-Signal-Dependencies.git
|
|
@ -6,7 +6,7 @@ xcode_sdk: iphonesimulator9.1
|
|||
before_install:
|
||||
- brew update
|
||||
- brew uninstall xctool && brew install --HEAD xctool
|
||||
install: true
|
||||
install: travis_wait pod install
|
||||
|
||||
xcode_workspace: Signal.xcworkspace
|
||||
xcode_scheme: Signal
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "0720"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "0720"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
12
Podfile
12
Podfile
|
@ -1,21 +1,13 @@
|
|||
platform :ios, '8.0'
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
inhibit_all_warnings!
|
||||
link_with ["Signal", "SignalTests"]
|
||||
|
||||
pod 'OpenSSL', '~> 1.0.204.1'
|
||||
pod 'libPhoneNumber-iOS', '~> 0.8.7'
|
||||
pod 'AxolotlKit'
|
||||
pod 'TextSecureKit', :git => 'https://github.com/WhisperSystems/TextSecureKit', :branch => 'master'
|
||||
pod 'OpenSSL', '~> 1.0.205'
|
||||
pod 'PastelogKit', '~> 1.3'
|
||||
pod 'TwistedOakCollapsingFutures','~> 1.0'
|
||||
pod 'AFNetworking', '~> 2.6'
|
||||
pod 'Mantle', '~> 2.0.4'
|
||||
pod 'FFCircularProgressView', '~> 0.5'
|
||||
pod 'SCWaveformView', '~> 1.0'
|
||||
pod 'YapDatabase/SQLCipher', '~> 2.7.2'
|
||||
pod 'iRate', '~> 1.11'
|
||||
pod 'SSKeychain'
|
||||
pod 'DJWActionSheet'
|
||||
|
||||
pod 'SocketRocket', :git => 'https://github.com/FredericJacobs/SocketRocket.git', :commit => 'dd7e47fed78214785d7c032081da94008335fc35'
|
||||
pod 'JSQMessagesViewController', :git => 'https://github.com/WhisperSystems/JSQMessagesViewController', :commit => 'e5582fef8a6b3e35f8070361ef37237222da712b'
|
||||
|
|
101
Podfile.lock
101
Podfile.lock
|
@ -1,27 +1,21 @@
|
|||
PODS:
|
||||
- 25519 (2.0.2)
|
||||
- AFNetworking (2.6.3):
|
||||
- AFNetworking/NSURLConnection (= 2.6.3)
|
||||
- AFNetworking/NSURLSession (= 2.6.3)
|
||||
- AFNetworking/Reachability (= 2.6.3)
|
||||
- AFNetworking/Security (= 2.6.3)
|
||||
- AFNetworking/Serialization (= 2.6.3)
|
||||
- AFNetworking/UIKit (= 2.6.3)
|
||||
- AFNetworking/NSURLConnection (2.6.3):
|
||||
- AFNetworking (3.0.4):
|
||||
- AFNetworking/NSURLSession (= 3.0.4)
|
||||
- AFNetworking/Reachability (= 3.0.4)
|
||||
- AFNetworking/Security (= 3.0.4)
|
||||
- AFNetworking/Serialization (= 3.0.4)
|
||||
- AFNetworking/UIKit (= 3.0.4)
|
||||
- AFNetworking/NSURLSession (3.0.4):
|
||||
- AFNetworking/Reachability
|
||||
- AFNetworking/Security
|
||||
- AFNetworking/Serialization
|
||||
- AFNetworking/NSURLSession (2.6.3):
|
||||
- AFNetworking/Reachability
|
||||
- AFNetworking/Security
|
||||
- AFNetworking/Serialization
|
||||
- AFNetworking/Reachability (2.6.3)
|
||||
- AFNetworking/Security (2.6.3)
|
||||
- AFNetworking/Serialization (2.6.3)
|
||||
- AFNetworking/UIKit (2.6.3):
|
||||
- AFNetworking/NSURLConnection
|
||||
- AFNetworking/Reachability (3.0.4)
|
||||
- AFNetworking/Security (3.0.4)
|
||||
- AFNetworking/Serialization (3.0.4)
|
||||
- AFNetworking/UIKit (3.0.4):
|
||||
- AFNetworking/NSURLSession
|
||||
- AxolotlKit (0.7):
|
||||
- AxolotlKit (0.8):
|
||||
- 25519 (~> 2.0.1)
|
||||
- HKDFKit (~> 0.0.3)
|
||||
- ProtocolBuffers (~> 1.9.8)
|
||||
|
@ -41,65 +35,69 @@ PODS:
|
|||
- JSQSystemSoundPlayer (~> 2.0.1)
|
||||
- JSQSystemSoundPlayer (2.0.1)
|
||||
- libPhoneNumber-iOS (0.8.10)
|
||||
- Mantle (2.0.5):
|
||||
- Mantle/extobjc (= 2.0.5)
|
||||
- Mantle/extobjc (2.0.5)
|
||||
- OpenSSL (1.0.204.1)
|
||||
- Mantle (2.0.6):
|
||||
- Mantle/extobjc (= 2.0.6)
|
||||
- Mantle/extobjc (2.0.6)
|
||||
- OpenSSL (1.0.205)
|
||||
- PastelogKit (1.3):
|
||||
- CocoaLumberjack (~> 2.0)
|
||||
- ProtocolBuffers (1.9.9.2)
|
||||
- SCWaveformView (1.0.0)
|
||||
- SocketRocket (0.4.2)
|
||||
- SQLCipher/common (3.1.0)
|
||||
- SQLCipher/fts (3.1.0):
|
||||
- SocketRocket-PinningPolicy (0.4.3)
|
||||
- SQLCipher/common (3.3.1)
|
||||
- SQLCipher/fts (3.3.1):
|
||||
- SQLCipher/common
|
||||
- SSKeychain (1.2.3)
|
||||
- SSKeychain (1.3.1)
|
||||
- TextSecureKit (0.0.4):
|
||||
- '25519'
|
||||
- AFNetworking
|
||||
- AxolotlKit
|
||||
- CocoaLumberjack
|
||||
- libPhoneNumber-iOS
|
||||
- Mantle
|
||||
- SocketRocket-PinningPolicy
|
||||
- SSKeychain
|
||||
- TwistedOakCollapsingFutures
|
||||
- YapDatabase/SQLCipher
|
||||
- TwistedOakCollapsingFutures (1.0.0):
|
||||
- UnionFind (~> 1.0)
|
||||
- UnionFind (1.0.1)
|
||||
- YapDatabase/SQLCipher (2.7.6):
|
||||
- YapDatabase/SQLCipher (2.7.7):
|
||||
- CocoaLumberjack (~> 2)
|
||||
- SQLCipher/fts
|
||||
|
||||
DEPENDENCIES:
|
||||
- AFNetworking (~> 2.6)
|
||||
- AxolotlKit
|
||||
- DJWActionSheet
|
||||
- FFCircularProgressView (~> 0.5)
|
||||
- iRate (~> 1.11)
|
||||
- JSQMessagesViewController (from `https://github.com/WhisperSystems/JSQMessagesViewController`,
|
||||
commit `e5582fef8a6b3e35f8070361ef37237222da712b`)
|
||||
- libPhoneNumber-iOS (~> 0.8.7)
|
||||
- Mantle (~> 2.0.4)
|
||||
- OpenSSL (~> 1.0.204.1)
|
||||
- OpenSSL (~> 1.0.205)
|
||||
- PastelogKit (~> 1.3)
|
||||
- SCWaveformView (~> 1.0)
|
||||
- SocketRocket (from `https://github.com/FredericJacobs/SocketRocket.git`, commit
|
||||
`dd7e47fed78214785d7c032081da94008335fc35`)
|
||||
- SSKeychain
|
||||
- TwistedOakCollapsingFutures (~> 1.0)
|
||||
- YapDatabase/SQLCipher (~> 2.7.2)
|
||||
- TextSecureKit (from `https://github.com/WhisperSystems/TextSecureKit`, branch
|
||||
`master`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
JSQMessagesViewController:
|
||||
:commit: e5582fef8a6b3e35f8070361ef37237222da712b
|
||||
:git: https://github.com/WhisperSystems/JSQMessagesViewController
|
||||
SocketRocket:
|
||||
:commit: dd7e47fed78214785d7c032081da94008335fc35
|
||||
:git: https://github.com/FredericJacobs/SocketRocket.git
|
||||
TextSecureKit:
|
||||
:branch: master
|
||||
:git: https://github.com/WhisperSystems/TextSecureKit
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
JSQMessagesViewController:
|
||||
:commit: e5582fef8a6b3e35f8070361ef37237222da712b
|
||||
:git: https://github.com/WhisperSystems/JSQMessagesViewController
|
||||
SocketRocket:
|
||||
:commit: dd7e47fed78214785d7c032081da94008335fc35
|
||||
:git: https://github.com/FredericJacobs/SocketRocket.git
|
||||
TextSecureKit:
|
||||
:commit: 8d6ce0b57c2d7de63d4e22f205ea87622432088e
|
||||
:git: https://github.com/WhisperSystems/TextSecureKit
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
'25519': dc4bad7e2dbcbf1efa121068a705a44cd98c80fc
|
||||
AFNetworking: cb8d14a848e831097108418f5d49217339d4eb60
|
||||
AxolotlKit: 8652fca51f4bc8225cbda791b0026c21e912b694
|
||||
AFNetworking: a0075feb321559dc78d9d85b55d11caa19eabb93
|
||||
AxolotlKit: a33962f26943990e5d69d05b30470cea18caeed0
|
||||
CocoaLumberjack: 17fe8581f84914d5d7e6360f7c70022b173c3ae0
|
||||
DJWActionSheet: 2fe54b1298a7f0fe44462233752c76a530e0cd80
|
||||
FFCircularProgressView: 683a4ab1e1bd613246a3dffa61503ffdebcde8d8
|
||||
|
@ -108,16 +106,17 @@ SPEC CHECKSUMS:
|
|||
JSQMessagesViewController: ca11f86fa68ca70835f05e169df9244147c1dc40
|
||||
JSQSystemSoundPlayer: c5850e77a4363ffd374cd851154b9af93264ed8d
|
||||
libPhoneNumber-iOS: 7bfd00f843fdcd82b5182b463e8eb3b27579f41d
|
||||
Mantle: 1912395033f601de5adc8ee91e48f46e4c7051ad
|
||||
OpenSSL: 7f853fcada78e5162c2183b4d90ebbd0aa02f5ac
|
||||
Mantle: 299966b00759634931699f69cb6a30b9239b944d
|
||||
OpenSSL: 162687d7e96a3edeb4cf443ca6ce7cdb2912df7b
|
||||
PastelogKit: 7b475be4cf577713506a943dd940bcc0499c8bca
|
||||
ProtocolBuffers: 7111461618460961e6b7469177ec45ee551b4f0e
|
||||
SCWaveformView: 52a96750255d817e300565a80c81fb643e233e07
|
||||
SocketRocket: ffe08119b00ef982f6c37052a4705a057c8494ad
|
||||
SQLCipher: c44fcca49c31483c2489cfb79aa7a69407f3794a
|
||||
SSKeychain: 3f42991739c6c60a9cf1bbd4dff6c0d3694bcf3d
|
||||
SocketRocket-PinningPolicy: f2ef00c3927bac05cd04d9d5171f82d922b40d3d
|
||||
SQLCipher: d490d2effe735895d2204d25a154b1e722278421
|
||||
SSKeychain: 04c4ec40f4c3deda524e269bc76e5f30e638a174
|
||||
TextSecureKit: b7419cbc792e5be4cbfd93a4da340f7a51d7bc41
|
||||
TwistedOakCollapsingFutures: f359b90f203e9ab13dfb92c9ff41842a7fe1cd0c
|
||||
UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d
|
||||
YapDatabase: 00e5a5d1b5dba1bd540ef644576233b5612e6122
|
||||
YapDatabase: a7a1ae3e0f89c319e3b22615c2351987fbbdbded
|
||||
|
||||
COCOAPODS: 0.39.0
|
||||
|
|
1
Pods
1
Pods
|
@ -1 +0,0 @@
|
|||
Subproject commit e6c803ff3cdb391d5c0dc9a2418f1e2f0797a1a3
|
File diff suppressed because it is too large
Load Diff
|
@ -67,7 +67,8 @@
|
|||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
allowLocationSimulation = "YES"
|
||||
showNonLocalizedStrings = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
|
|
|
@ -5,26 +5,26 @@
|
|||
},
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
|
||||
"5D79A077E31B3FE97A3C6613CBFFDD71C314D14C" : 0,
|
||||
"D74FB800F048CB516BB4BC70047F7CC676D291B9" : 0
|
||||
"37054CE35CE656680D6FFFA9EE19249E0D149C5E" : 0
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "1D917339-756B-4BA2-8BAF-70AFEDF98BC0",
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "D0F297E7-A82D-4657-A941-96B268F80ABC",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
||||
"5D79A077E31B3FE97A3C6613CBFFDD71C314D14C" : "Signal-iOS",
|
||||
"D74FB800F048CB516BB4BC70047F7CC676D291B9" : "Signal-iOSPods"
|
||||
"5D79A077E31B3FE97A3C6613CBFFDD71C314D14C" : "Signal-iOS\/",
|
||||
"37054CE35CE656680D6FFFA9EE19249E0D149C5E" : "TSKit\/"
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "Signal",
|
||||
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
|
||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Signal.xcworkspace",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:FredericJacobs\/TextSecureKit.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "37054CE35CE656680D6FFFA9EE19249E0D149C5E"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:WhisperSystems\/Signal-iOS.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "5D79A077E31B3FE97A3C6613CBFFDD71C314D14C"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:FredericJacobs\/Precompiled-Signal-Dependencies.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "D74FB800F048CB516BB4BC70047F7CC676D291B9"
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
|
@ -38,7 +38,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>2.3.0</string>
|
||||
<string>2.3.0.1</string>
|
||||
<key>LOGS_EMAIL</key>
|
||||
<string>support@whispersystems.org</string>
|
||||
<key>LOGS_URL</key>
|
||||
|
|
|
@ -19,7 +19,4 @@
|
|||
|
||||
#define SignalAlertView(title,msg) [[[UIAlertView alloc] initWithTitle:title message:msg delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"") otherButtonTitles:nil, nil] show]
|
||||
#define SignalReportError [Pastelog reportErrorAndSubmitLogsWithAlertTitle:NSLocalizedString(@"ERROR_WAS_DETECTED_TITLE", @"") alertBody:NSLocalizedString(@"ERROR_WAS_DETECTED_SUBMIT", @"")];
|
||||
|
||||
#define BLOCK_SAFE_RUN(block, ...) block ? dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{block(__VA_ARGS__);}) : nil
|
||||
#define SYNC_BLOCK_SAFE_RUN(block, ...) block ? block(__VA_ARGS__): nil
|
||||
#endif
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
#import "AppDelegate.h"
|
||||
#import "AppStoreRating.h"
|
||||
#import "CategorizingLogger.h"
|
||||
#import "CodeVerificationViewController.h"
|
||||
#import "ContactsManager.h"
|
||||
#import "DebugLogger.h"
|
||||
#import "Environment.h"
|
||||
#import "NotificationsManager.h"
|
||||
#import "PreferencesUtil.h"
|
||||
#import "PushManager.h"
|
||||
#import "Release.h"
|
||||
#import "TSAccountManager.h"
|
||||
#import "TSPreKeyManager.h"
|
||||
#import "TSMessagesManager.h"
|
||||
#import "TSPreKeyManager.h"
|
||||
#import "TSSocketManager.h"
|
||||
#import "TextSecureKitEnv.h"
|
||||
#import "VersionMigrations.h"
|
||||
#import "CodeVerificationViewController.h"
|
||||
|
||||
static NSString *const kStoryboardName = @"Storyboard";
|
||||
static NSString *const kInitialViewControllerIdentifier = @"UserInitialViewController";
|
||||
|
@ -45,17 +47,20 @@ static NSString * const kURLHostVerifyPrefix = @"verify";
|
|||
return YES;
|
||||
}
|
||||
|
||||
// Initializing logger
|
||||
CategorizingLogger *logger = [CategorizingLogger categorizingLogger];
|
||||
[logger addLoggingCallback:^(NSString *category, id details, NSUInteger index) {}];
|
||||
[logger addLoggingCallback:^(NSString *category, id details, NSUInteger index){
|
||||
}];
|
||||
|
||||
// Setting up environment
|
||||
[Environment setCurrent:[Release releaseEnvironmentWithLogging:logger]];
|
||||
|
||||
if ([TSAccountManager isRegistered]) {
|
||||
[Environment.getCurrent.contactsManager doAfterEnvironmentInitSetup];
|
||||
}
|
||||
|
||||
[Environment.getCurrent initCallListener];
|
||||
|
||||
[[TSStorageManager sharedManager] setupDatabase];
|
||||
[self setupTSKitEnv];
|
||||
|
||||
BOOL loggingIsEnabled;
|
||||
|
||||
|
@ -63,25 +68,27 @@ static NSString * const kURLHostVerifyPrefix = @"verify";
|
|||
// Specified at Product -> Scheme -> Edit Scheme -> Test -> Arguments -> Environment to avoid things like
|
||||
// the phone directory being looked up during tests.
|
||||
loggingIsEnabled = TRUE;
|
||||
[DebugLogger.sharedInstance enableTTYLogging];
|
||||
[DebugLogger.sharedLogger enableTTYLogging];
|
||||
#elif RELEASE
|
||||
loggingIsEnabled = Environment.preferences.loggingIsEnabled;
|
||||
#endif
|
||||
[self verifyBackgroundBeforeKeysAvailableLaunch];
|
||||
|
||||
if (loggingIsEnabled) {
|
||||
[DebugLogger.sharedInstance enableFileLogging];
|
||||
[DebugLogger.sharedLogger enableFileLogging];
|
||||
}
|
||||
|
||||
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:kStoryboardName bundle:[NSBundle mainBundle]];
|
||||
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:kInitialViewControllerIdentifier];
|
||||
UIViewController *viewController =
|
||||
[storyboard instantiateViewControllerWithIdentifier:kInitialViewControllerIdentifier];
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
self.window.rootViewController = viewController;
|
||||
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
[VersionMigrations performUpdateCheck]; // this call must be made after environment has been initialized because in general upgrade may depend on environment
|
||||
[VersionMigrations performUpdateCheck]; // this call must be made after environment has been initialized because in
|
||||
// general upgrade may depend on environment
|
||||
|
||||
// Accept push notification when app is not open
|
||||
NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
|
||||
|
@ -108,24 +115,35 @@ static NSString * const kURLHostVerifyPrefix = @"verify";
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
|
||||
- (void)setupTSKitEnv {
|
||||
[TextSecureKitEnv sharedEnv].contactsManager = [Environment getCurrent].contactsManager;
|
||||
[[TSStorageManager sharedManager] setupDatabase];
|
||||
[TextSecureKitEnv sharedEnv].notificationsManager = [[NotificationsManager alloc] init];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application
|
||||
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
|
||||
[PushManager.sharedManager.pushNotificationFutureSource trySetResult:deviceToken];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
|
||||
#ifdef DEBUG
|
||||
DDLogWarn(@"We're in debug mode, and registered a fake push identifier");
|
||||
[PushManager.sharedManager.pushNotificationFutureSource trySetResult:[@"aFakePushIdentifier" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[PushManager.sharedManager.pushNotificationFutureSource trySetResult:@"aFakePushIdentifier"];
|
||||
#else
|
||||
[PushManager.sharedManager.pushNotificationFutureSource trySetFailure:error];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
|
||||
- (void)application:(UIApplication *)application
|
||||
didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
|
||||
[PushManager.sharedManager.userNotificationFutureSource trySetResult:notificationSettings];
|
||||
}
|
||||
|
||||
-(BOOL) application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation {
|
||||
- (BOOL)application:(UIApplication *)application
|
||||
openURL:(NSURL *)url
|
||||
sourceApplication:(NSString *)sourceApplication
|
||||
annotation:(id)annotation {
|
||||
if ([url.scheme isEqualToString:kURLSchemeSGNLKey]) {
|
||||
if ([url.host hasPrefix:kURLHostVerifyPrefix] && ![TSAccountManager isRegistered]) {
|
||||
id signupController = [Environment getCurrent].signUpFlowNavigationController;
|
||||
|
@ -139,9 +157,9 @@ static NSString * const kURLHostVerifyPrefix = @"verify";
|
|||
cvvc.challengeTextField.text = verificationCode;
|
||||
[cvvc verifyChallengeAction:nil];
|
||||
} else {
|
||||
DDLogWarn(@"Not the verification view controller we expected. Got %@ instead", NSStringFromClass(controller.class));
|
||||
DDLogWarn(@"Not the verification view controller we expected. Got %@ instead",
|
||||
NSStringFromClass(controller.class));
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
DDLogWarn(@"Application opened with an unknown URL action: %@", url.host);
|
||||
|
@ -154,7 +172,8 @@ static NSString * const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
if ([TSAccountManager isRegistered]) {
|
||||
// We're double checking that the app is active, to be sure since we can't verify in production env due to code signing.
|
||||
// We're double checking that the app is active, to be sure since we can't verify in production env due to code
|
||||
// signing.
|
||||
[TSSocketManager becomeActiveFromForeground];
|
||||
[[Environment getCurrent].contactsManager verifyABPermission];
|
||||
}
|
||||
|
@ -180,7 +199,6 @@ static NSString * const kURLHostVerifyPrefix = @"verify";
|
|||
[application endBackgroundTask:bgTask];
|
||||
bgTask = UIBackgroundTaskInvalid;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application
|
||||
|
@ -189,11 +207,15 @@ performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
|
|||
if ([TSAccountManager isRegistered]) {
|
||||
[[Environment getCurrent].signalsViewController composeNew];
|
||||
} else {
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"REGISTER_CONTACTS_WELCOME", nil)
|
||||
message:@"Someone's exited to send his first message! Register now to send your first message."
|
||||
UIAlertController *controller = [UIAlertController
|
||||
alertControllerWithTitle:NSLocalizedString(@"REGISTER_CONTACTS_WELCOME", nil)
|
||||
message:
|
||||
@"Someone's exited to send his first message! Register now to send your first message."
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
completionHandler(YES);
|
||||
[self.window.rootViewController presentViewController:controller animated:YES completion:^{
|
||||
[self.window.rootViewController presentViewController:controller
|
||||
animated:YES
|
||||
completion:^{
|
||||
completionHandler(NO);
|
||||
}];
|
||||
}
|
||||
|
@ -208,12 +230,16 @@ performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
|
|||
window.windowLevel = CGFLOAT_MAX;
|
||||
|
||||
// There appears to be no more reliable way to get the launchscreen image from an asset bundle
|
||||
NSDictionary *dict = @{@"320x480" : @"LaunchImage-700",
|
||||
NSDictionary *dict = @{
|
||||
@"320x480" : @"LaunchImage-700",
|
||||
@"320x568" : @"LaunchImage-700-568h",
|
||||
@"375x667" : @"LaunchImage-800-667h",
|
||||
@"414x736" : @"LaunchImage-800-Portrait-736h"};
|
||||
@"414x736" : @"LaunchImage-800-Portrait-736h"
|
||||
};
|
||||
|
||||
NSString *key = [NSString stringWithFormat:@"%dx%d", (int)[UIScreen mainScreen].bounds.size.width, (int)[UIScreen mainScreen].bounds.size.height];
|
||||
NSString *key = [NSString stringWithFormat:@"%dx%d",
|
||||
(int)[UIScreen mainScreen].bounds.size.width,
|
||||
(int)[UIScreen mainScreen].bounds.size.height];
|
||||
UIImage *launchImage = [UIImage imageNamed:dict[key]];
|
||||
UIImageView *imgView = [[UIImageView alloc] initWithImage:launchImage];
|
||||
UIViewController *vc = [[UIViewController alloc] initWithNibName:nil bundle:nil];
|
||||
|
@ -261,7 +287,6 @@ performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
|
|||
[[UISwitch appearance] setOnTintColor:[UIColor ows_materialBlueColor]];
|
||||
|
||||
[[UINavigationBar appearance] setTitleTextAttributes:navbarTitleTextAttributes];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark Push Notifications Delegate Methods
|
||||
|
@ -269,20 +294,38 @@ performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
|
|||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
|
||||
[[PushManager sharedManager] application:application didReceiveRemoteNotification:userInfo];
|
||||
}
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
[[PushManager sharedManager] application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
|
||||
- (void)application:(UIApplication *)application
|
||||
didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
[[PushManager sharedManager] application:application
|
||||
didReceiveRemoteNotification:userInfo
|
||||
fetchCompletionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
|
||||
[[PushManager sharedManager] application:application didReceiveLocalNotification:notification];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
|
||||
[[PushManager sharedManager] application:application handleActionWithIdentifier:identifier forLocalNotification:notification completionHandler:completionHandler];
|
||||
- (void)application:(UIApplication *)application
|
||||
handleActionWithIdentifier:(NSString *)identifier
|
||||
forLocalNotification:(UILocalNotification *)notification
|
||||
completionHandler:(void (^)())completionHandler {
|
||||
[[PushManager sharedManager] application:application
|
||||
handleActionWithIdentifier:identifier
|
||||
forLocalNotification:notification
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler {
|
||||
[[PushManager sharedManager] application:application handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:responseInfo completionHandler:completionHandler];
|
||||
- (void)application:(UIApplication *)application
|
||||
handleActionWithIdentifier:(NSString *)identifier
|
||||
forLocalNotification:(UILocalNotification *)notification
|
||||
withResponseInfo:(NSDictionary *)responseInfo
|
||||
completionHandler:(void (^)())completionHandler {
|
||||
[[PushManager sharedManager] application:application
|
||||
handleActionWithIdentifier:identifier
|
||||
forLocalNotification:notification
|
||||
withResponseInfo:responseInfo
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "NotificationTracker.h"
|
||||
#import "CryptoTools.h"
|
||||
#import "FunctionalUtil.h"
|
||||
#import "NotificationTracker.h"
|
||||
|
||||
#define MAX_NOTIFICATIONS_TO_TRACK 100
|
||||
#define NOTIFICATION_PAYLOAD_KEY @"m"
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="tuk-0x-yCb">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="tuk-0x-yCb">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="Segues with Peek and Pop" minToolsVersion="7.1"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Conversations-->
|
||||
|
@ -19,12 +18,11 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lKc-rv-FH5" userLabel="empty state view">
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lKc-rv-FH5" userLabel="empty state view">
|
||||
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No Messages :( Tap Compose to send a message or invite a friend to Signal" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Srx-i1-WhD">
|
||||
<rect key="frame" x="10" y="57" width="300" height="200"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="200" id="GEd-dY-d8r"/>
|
||||
<constraint firstAttribute="width" constant="300" id="siA-1a-pO1"/>
|
||||
|
@ -34,7 +32,6 @@
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerX" secondItem="Srx-i1-WhD" secondAttribute="centerX" id="JId-fq-hNc"/>
|
||||
|
@ -43,26 +40,7 @@
|
|||
</view>
|
||||
<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelectionDuringEditing="YES" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="PaA-ol-uQT">
|
||||
<rect key="frame" x="0.0" y="64" width="330" height="504"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="cells" id="Ao0-kZ-6Fk">
|
||||
<rect key="frame" x="0.0" y="28" width="330" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Ao0-kZ-6Fk" id="Kzg-Il-hgK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="297" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
<connections>
|
||||
<segue destination="DtA-8O-wrT" kind="push" identifier="showSegue" id="ANb-Oa-vQe">
|
||||
<segue key="commit" inheritsFrom="parent" id="3Aj-hB-zgq"/>
|
||||
<segue key="preview" inheritsFrom="commit" id="ktS-lA-hcf"/>
|
||||
</segue>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<sections/>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="MY2-bB-USa" id="kop-Y6-6DR"/>
|
||||
|
@ -70,7 +48,6 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="PaA-ol-uQT" firstAttribute="leading" secondItem="lKc-rv-FH5" secondAttribute="leading" id="0co-lj-Jsm"/>
|
||||
<constraint firstAttribute="width" secondItem="lKc-rv-FH5" secondAttribute="width" id="Bu7-qv-yue"/>
|
||||
|
@ -105,6 +82,7 @@
|
|||
<outlet property="tableView" destination="PaA-ol-uQT" id="nQU-tR-wbL"/>
|
||||
<segue destination="Duq-aU-MmN" kind="modal" identifier="2.0_6.0_Call_Segue" modalPresentationStyle="fullScreen" modalTransitionStyle="crossDissolve" id="gHJ-y4-zWg"/>
|
||||
<segue destination="lIF-0m-2N3" kind="modal" identifier="showSignupFlow" id="DR8-fx-0PD"/>
|
||||
<segue destination="DtA-8O-wrT" kind="push" identifier="showSegue" id="njS-JT-0Pa"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dE8-zB-mtF" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
@ -122,7 +100,6 @@
|
|||
<view key="view" contentMode="scaleToFill" id="5r3-kq-bbI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Title" id="mLN-DG-4IU">
|
||||
|
@ -168,7 +145,6 @@
|
|||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="AwQ-ec-WBO">
|
||||
<rect key="frame" x="0.0" y="220" width="400" height="1"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="0.61676562499999998" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="yMD-Sw-sDy"/>
|
||||
|
@ -176,7 +152,6 @@
|
|||
</view>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="btnCamera--white" translatesAutoresizingMaskIntoConstraints="NO" id="HyV-ht-MrM">
|
||||
<rect key="frame" x="19" y="73" width="75" height="75"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="75" id="Yxr-T5-Jck"/>
|
||||
<constraint firstAttribute="width" constant="75" id="bRq-v9-94p"/>
|
||||
|
@ -184,7 +159,6 @@
|
|||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Momo's Fingerprint" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ii9-7N-hCc">
|
||||
<rect key="frame" x="115" y="35" width="250" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="21" id="epx-el-0T8"/>
|
||||
</constraints>
|
||||
|
@ -194,7 +168,6 @@
|
|||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="4" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kBW-ix-mdQ">
|
||||
<rect key="frame" x="115" y="73" width="250" height="75"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="75" id="jaw-8F-c1C"/>
|
||||
</constraints>
|
||||
|
@ -208,7 +181,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tap to scan another user's fingerprint" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ge0-8K-A4F">
|
||||
<rect key="frame" x="115" y="160" width="213" height="44"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="HyF-Kt-KmB"/>
|
||||
</constraints>
|
||||
|
@ -217,7 +189,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="HyV-ht-MrM" secondAttribute="trailing" constant="306" id="1XO-7v-R7T"/>
|
||||
|
@ -243,7 +214,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Compare both fingerprints to verify your contact's identity and the integrity of the message." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="3" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DV4-GV-ZPf">
|
||||
<rect key="frame" x="22" y="460" width="356" height="44"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="bif-t1-qQO"/>
|
||||
</constraints>
|
||||
|
@ -256,7 +226,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="WhZ-e0-THb">
|
||||
<rect key="frame" x="0.0" y="220" width="400" height="1"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="0.61676562499999998" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="XgI-5W-uMZ"/>
|
||||
|
@ -264,7 +233,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your Fingerprint" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5De-Jq-XWv">
|
||||
<rect key="frame" x="115" y="35" width="250" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="21" id="475-f9-1TO"/>
|
||||
</constraints>
|
||||
|
@ -274,7 +242,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="btnQRShow--white" highlightedImage="btnQRShow--white-1" translatesAutoresizingMaskIntoConstraints="NO" id="YOs-e5-ee3">
|
||||
<rect key="frame" x="19" y="73" width="75" height="75"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="75" id="5IR-xd-6uL"/>
|
||||
<constraint firstAttribute="height" constant="75" id="Nfl-jf-HzC"/>
|
||||
|
@ -282,7 +249,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tap to display your fingerprint for another user" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9Wg-UP-VDC">
|
||||
<rect key="frame" x="115" y="160" width="208" height="43"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="43" id="xb1-B9-MyR"/>
|
||||
</constraints>
|
||||
|
@ -292,7 +258,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" lineBreakMode="tailTruncation" numberOfLines="4" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e7E-iS-3Oc">
|
||||
<rect key="frame" x="115" y="73" width="250" height="75"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="75" id="k9r-Fg-1QJ"/>
|
||||
</constraints>
|
||||
|
@ -305,7 +270,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<gestureRecognizers/>
|
||||
<constraints>
|
||||
<constraint firstItem="9Wg-UP-VDC" firstAttribute="leading" secondItem="B4o-Rc-z68" secondAttribute="leading" constant="115" id="3zq-WB-ASq"/>
|
||||
|
@ -331,7 +295,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Yoz-ex-1gK">
|
||||
<rect key="frame" x="19" y="492" width="50" height="50"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="50" id="Ie5-wL-XEo"/>
|
||||
<constraint firstAttribute="height" constant="50" id="aq2-hO-WY0"/>
|
||||
|
@ -345,7 +308,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="Yoz-ex-1gK" secondAttribute="bottom" constant="26" id="EVw-Jr-67j"/>
|
||||
<constraint firstAttribute="trailing" secondItem="zFI-eF-Feb" secondAttribute="trailing" id="Jfg-Ac-5SC"/>
|
||||
|
@ -360,11 +322,9 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<constraint firstItem="DV4-GV-ZPf" firstAttribute="top" secondItem="kEV-0h-NsX" secondAttribute="top" constant="460" id="tPa-CI-8ak"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<animations/>
|
||||
<blurEffect style="dark"/>
|
||||
</visualEffectView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="hdo-6G-gXy" firstAttribute="top" secondItem="VCu-vN-Pjg" secondAttribute="bottom" id="1dB-W2-GMz"/>
|
||||
<constraint firstAttribute="centerX" secondItem="VCu-vN-Pjg" secondAttribute="centerX" id="5Wt-QM-aQa"/>
|
||||
|
@ -414,7 +374,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="Fdx-Zk-e27">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="groupMemberCell" id="hyn-Ss-OAa">
|
||||
|
@ -423,9 +382,7 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hyn-Ss-OAa" id="4XE-JO-Upr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
|
@ -453,7 +410,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FVU-rR-RPG">
|
||||
<rect key="frame" x="16" y="510" width="50" height="50"/>
|
||||
<animations/>
|
||||
<state key="normal" image="quit.png">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
|
@ -463,7 +419,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="I4l-hR-EdB">
|
||||
<rect key="frame" x="35" y="159" width="250" height="250"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="250" id="WS4-Wb-iXP"/>
|
||||
<constraint firstAttribute="width" constant="250" id="n5C-hu-0F6"/>
|
||||
|
@ -471,7 +426,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your Fingerprint" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Psg-eI-6bn">
|
||||
<rect key="frame" x="50" y="130" width="220" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="220" id="IoY-EK-Qhk"/>
|
||||
</constraints>
|
||||
|
@ -480,7 +434,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="FVU-rR-RPG" firstAttribute="leading" secondItem="8fX-rK-XSk" secondAttribute="leadingMargin" id="4fp-jK-Pgt"/>
|
||||
|
@ -516,7 +469,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bag-cN-IZy">
|
||||
<rect key="frame" x="16" y="498" width="50" height="50"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="50" id="Odb-rK-4Va"/>
|
||||
<constraint firstAttribute="height" constant="50" id="ZPA-Mg-Y3j"/>
|
||||
|
@ -529,7 +481,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="bag-cN-IZy" firstAttribute="leading" secondItem="Du7-nD-ScY" secondAttribute="leadingMargin" id="vL9-x7-knG"/>
|
||||
|
@ -563,7 +514,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Your Phone Number" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="50y-cV-8aI">
|
||||
<rect key="frame" x="1" y="190" width="320" height="29"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="29" id="T1b-ph-zPv"/>
|
||||
</constraints>
|
||||
|
@ -573,10 +523,8 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="logoSignal" translatesAutoresizingMaskIntoConstraints="NO" id="hle-PK-Ivk">
|
||||
<rect key="frame" x="91" y="43" width="138" height="139"/>
|
||||
<animations/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.12549019607843137" green="0.56470588235294117" blue="0.91764705882352937" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="50y-cV-8aI" secondAttribute="bottom" constant="26" id="9Ep-V2-rAF"/>
|
||||
|
@ -592,7 +540,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="O6t-0o-mk5">
|
||||
<rect key="frame" x="0.0" y="59" width="320" height="1"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.7999122142791748" green="0.80005049705505371" blue="0.7999035120010376" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="gpg-j8-Tjz"/>
|
||||
|
@ -600,7 +547,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</view>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="VvN-1x-NvR">
|
||||
<rect key="frame" x="237" y="17" width="67" height="26"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="67" id="0Oj-m4-j2A"/>
|
||||
<constraint firstAttribute="height" constant="26" id="IlP-zb-7h9"/>
|
||||
|
@ -616,7 +562,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ngV-Kv-6Ax">
|
||||
<rect key="frame" x="20" y="0.0" width="195" height="60"/>
|
||||
<animations/>
|
||||
<rect key="contentStretch" x="1" y="0.0" width="1" height="1"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="LOh-ty-lH1"/>
|
||||
|
@ -630,7 +575,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="4z2-Ss-eUR"/>
|
||||
|
@ -649,7 +593,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vpp-VC-z9v">
|
||||
<rect key="frame" x="0.0" y="59" width="360" height="1"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="SiS-mn-Yud"/>
|
||||
|
@ -657,7 +600,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</view>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Enter Number" textAlignment="right" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="tTJ-pq-Z9L">
|
||||
<rect key="frame" x="128" y="19" width="176" height="26"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="176" id="6Ux-PV-sZk"/>
|
||||
<constraint firstAttribute="height" constant="26" id="bkw-ef-Yt9"/>
|
||||
|
@ -671,7 +613,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</textField>
|
||||
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AbN-AU-yk7">
|
||||
<rect key="frame" x="20" y="18" width="152" height="26"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="26" id="hch-s1-zig"/>
|
||||
<constraint firstAttribute="width" constant="152" id="tZB-hO-p3n"/>
|
||||
|
@ -683,7 +624,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</state>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="tTJ-pq-Z9L" secondAttribute="trailing" constant="16" id="G4f-2B-yOo"/>
|
||||
|
@ -701,7 +641,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7IK-hd-tli">
|
||||
<rect key="frame" x="30" y="1" width="260" height="47"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.067691504955291748" green="0.55628502368927002" blue="0.92999207973480225" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="47" id="foJ-cw-ajR"/>
|
||||
|
@ -718,14 +657,12 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="Uhw-zc-NhO">
|
||||
<rect key="frame" x="250" y="15" width="20" height="20"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="EN0-Kc-yUf"/>
|
||||
<constraint firstAttribute="width" constant="20" id="WRq-AE-2aq"/>
|
||||
</constraints>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="47" id="2UQ-03-3A5"/>
|
||||
|
@ -737,7 +674,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="oS3-t9-5np" firstAttribute="leading" secondItem="Y3I-8Y-pLa" secondAttribute="leadingMargin" constant="-16" id="3EZ-dN-uSz"/>
|
||||
|
@ -781,7 +717,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="fty-2s-xFJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
<color key="barTintColor" red="0.067691504955291748" green="0.55628502368927002" blue="0.92999207973480225" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
|
@ -799,12 +734,10 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="o7w-iD-5XF" userLabel="_1.0__1 Country Code Table">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<searchBar key="tableHeaderView" contentMode="redraw" id="Syd-Xl-kCG" userLabel="__1a Search Bar">
|
||||
<rect key="frame" x="0.0" y="64" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<textInputTraits key="textInputTraits"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="nT9-Zl-5R0" id="dR5-Gb-Tvl"/>
|
||||
|
@ -820,7 +753,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" tag="1" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="United states" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SDz-Ag-lp3">
|
||||
<rect key="frame" x="20" y="11" width="244" height="22"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="244" id="Y66-3d-yJI"/>
|
||||
</constraints>
|
||||
|
@ -830,7 +762,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" tag="2" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="+1" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hl9-0w-DHU">
|
||||
<rect key="frame" x="237" y="12" width="64" height="20"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="64" id="S6t-bW-MMl"/>
|
||||
</constraints>
|
||||
|
@ -839,7 +770,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="SDz-Ag-lp3" firstAttribute="leading" secondItem="gVo-Nw-ff7" secondAttribute="leadingMargin" constant="12" id="aYr-BL-A9N"/>
|
||||
<constraint firstAttribute="centerY" secondItem="SDz-Ag-lp3" secondAttribute="centerY" id="d1E-Q7-R5V"/>
|
||||
|
@ -847,7 +777,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<constraint firstAttribute="trailingMargin" secondItem="hl9-0w-DHU" secondAttribute="trailing" constant="11" id="zEI-fy-DdI"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
<connections>
|
||||
<outlet property="countryCodeLabel" destination="hl9-0w-DHU" id="z7K-fi-Cag"/>
|
||||
<outlet property="countryNameLabel" destination="SDz-Ag-lp3" id="aCl-RV-0Vm"/>
|
||||
|
@ -904,9 +833,7 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" id="32G-1m-e8H">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
</view>
|
||||
<animations/>
|
||||
<blurEffect style="dark"/>
|
||||
</visualEffectView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kYX-We-g3s" userLabel="conversation contact">
|
||||
|
@ -914,7 +841,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="eSg-l3-cbz">
|
||||
<rect key="frame" x="236" y="67" width="62" height="62"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="62" id="SUM-4n-TK8"/>
|
||||
<constraint firstAttribute="height" constant="62" id="cNa-tL-3WW"/>
|
||||
|
@ -922,7 +848,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Moxie Marlinspike" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zMG-vs-mRy">
|
||||
<rect key="frame" x="25" y="56" width="195" height="45"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="45" id="pkz-I0-lQ2"/>
|
||||
</constraints>
|
||||
|
@ -932,7 +857,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="calling mobile ..." lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dbS-Y4-Ge8">
|
||||
<rect key="frame" x="25" y="102" width="275" height="28"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="275" id="Jym-Zt-gVp"/>
|
||||
<constraint firstAttribute="height" constant="28" id="mzl-vA-mVI"/>
|
||||
|
@ -942,7 +866,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="eSg-l3-cbz" firstAttribute="trailing" secondItem="zMG-vs-mRy" secondAttribute="trailing" constant="78" id="98G-fD-P9z"/>
|
||||
<constraint firstItem="eSg-l3-cbz" firstAttribute="top" secondItem="kYX-We-g3s" secondAttribute="top" constant="67" id="Dpw-L2-chG"/>
|
||||
|
@ -956,7 +879,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Conversation Safe Words" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bnt-nc-bE8">
|
||||
<rect key="frame" x="27" y="230" width="265" height="40"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="40" id="DTP-4z-twz"/>
|
||||
</constraints>
|
||||
|
@ -969,7 +891,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cXl-nO-D0h">
|
||||
<rect key="frame" x="0.0" y="44" width="320" height="65"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="65" id="hmt-mu-kI4"/>
|
||||
|
@ -977,7 +898,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</view>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="watchword chambermaid" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.5" adjustsLetterSpacingToFitWidth="YES" translatesAutoresizingMaskIntoConstraints="NO" id="CLR-My-Jfk">
|
||||
<rect key="frame" x="25" y="60" width="320" height="31"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="31" id="HEv-nI-1Sb"/>
|
||||
</constraints>
|
||||
|
@ -986,7 +906,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="130" id="QYb-BI-B5m"/>
|
||||
<constraint firstAttribute="bottom" secondItem="CLR-My-Jfk" secondAttribute="bottom" constant="39" id="W1n-ld-j5e"/>
|
||||
|
@ -1002,7 +921,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="uqh-Gl-dvz" userLabel="Speaker">
|
||||
<rect key="frame" x="200" y="0.0" width="80" height="80"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="80" id="CCC-wz-iw7"/>
|
||||
<constraint firstAttribute="height" constant="80" id="LqQ-FB-t9K"/>
|
||||
|
@ -1017,7 +935,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4OS-z4-ixd" userLabel="Mute Button">
|
||||
<rect key="frame" x="40" y="0.0" width="80" height="80"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="80" id="0QK-nC-B88"/>
|
||||
<constraint firstAttribute="height" constant="80" id="2DL-xO-VaK"/>
|
||||
|
@ -1031,7 +948,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerY" secondItem="4OS-z4-ixd" secondAttribute="centerY" constant="10" id="4ft-7i-1tH"/>
|
||||
<constraint firstItem="4OS-z4-ixd" firstAttribute="leading" secondItem="nsz-Sa-Uh6" secondAttribute="leading" constant="40" id="656-YA-2rx"/>
|
||||
|
@ -1045,7 +961,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="F2a-2h-UK2" userLabel="Hang Up Button">
|
||||
<rect key="frame" x="120" y="0.0" width="80" height="80"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="80" id="ToV-Ks-2i9"/>
|
||||
<constraint firstAttribute="height" constant="80" id="ifY-o4-2Pv"/>
|
||||
|
@ -1058,7 +973,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="100" id="2YR-lI-F8e"/>
|
||||
<constraint firstAttribute="centerY" secondItem="F2a-2h-UK2" secondAttribute="centerY" constant="10" id="PVe-Kc-Bix"/>
|
||||
|
@ -1070,7 +984,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="De1-JJ-Nsi" userLabel="Decline">
|
||||
<rect key="frame" x="40" y="0.0" width="80" height="80"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="80" id="GDu-4c-Hm7"/>
|
||||
<constraint firstAttribute="width" constant="80" id="rKd-Jd-G3l"/>
|
||||
|
@ -1084,7 +997,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="3b2-qR-0Y3" userLabel="Answer">
|
||||
<rect key="frame" x="200" y="0.0" width="80" height="80"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="80" id="amq-H9-Gaa"/>
|
||||
<constraint firstAttribute="width" constant="80" id="wqt-Jl-Jf8"/>
|
||||
|
@ -1097,7 +1009,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerY" secondItem="3b2-qR-0Y3" secondAttribute="centerY" constant="10" id="EMq-Jz-Poy"/>
|
||||
<constraint firstAttribute="height" constant="100" id="G8L-Qh-DIj"/>
|
||||
|
@ -1107,7 +1018,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="87w-Jm-tMc" firstAttribute="centerX" secondItem="vir-2e-LN3" secondAttribute="centerX" id="2gh-0t-obh"/>
|
||||
|
@ -1175,7 +1085,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="top" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Verification" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e8Y-At-xEK">
|
||||
<rect key="frame" x="1" y="191" width="320" height="29"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="29" id="Mem-ez-9kw"/>
|
||||
</constraints>
|
||||
|
@ -1185,10 +1094,8 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="logoSignal" translatesAutoresizingMaskIntoConstraints="NO" id="gVg-vn-tFu">
|
||||
<rect key="frame" x="92" y="44" width="138" height="139"/>
|
||||
<animations/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.12549019610000001" green="0.56470588239999997" blue="0.91764705879999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="245" id="5bj-kr-L4s" userLabel="Height - (245) - _1.1 Registration Screen Title"/>
|
||||
|
@ -1204,7 +1111,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Verification Code" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="yK6-ad-ihc">
|
||||
<rect key="frame" x="-40" y="0.0" width="401" height="32"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="401" id="aPy-KQ-lfQ"/>
|
||||
</constraints>
|
||||
|
@ -1213,14 +1119,12 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</textField>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="260-Dq-fnd">
|
||||
<rect key="frame" x="36" y="26" width="248" height="1"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.80000000000000004" green="0.80000000000000004" blue="0.80000000000000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="1" id="OPE-jg-ZYz"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="260-Dq-fnd" secondAttribute="trailing" constant="36" id="0sO-fC-DMj"/>
|
||||
|
@ -1238,7 +1142,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Nx-nz-ht7">
|
||||
<rect key="frame" x="36" y="0.0" width="248" height="47"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.067691504959999996" green="0.55628502369999999" blue="0.92999207969999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="47" id="ote-hy-MTP"/>
|
||||
|
@ -1254,14 +1157,12 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="vmS-8s-cvA">
|
||||
<rect key="frame" x="249" y="14" width="20" height="20"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="20" id="IkO-na-VRc"/>
|
||||
<constraint firstAttribute="height" constant="20" id="rNO-wM-YcD"/>
|
||||
</constraints>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="5Nx-nz-ht7" firstAttribute="leading" secondItem="95o-ce-XGu" secondAttribute="leading" constant="36" id="1C6-X7-eAN"/>
|
||||
|
@ -1277,7 +1178,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9dl-sl-tZN">
|
||||
<rect key="frame" x="36" y="0.0" width="248" height="47"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="47" id="giC-el-dFa"/>
|
||||
</constraints>
|
||||
|
@ -1292,14 +1192,12 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="utk-2S-Qc7">
|
||||
<rect key="frame" x="250" y="14" width="20" height="20"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="nY2-Ab-Abc"/>
|
||||
<constraint firstAttribute="width" constant="20" id="w86-JO-TiH"/>
|
||||
</constraints>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="utk-2S-Qc7" firstAttribute="top" secondItem="UWb-Di-S2f" secondAttribute="top" constant="14" id="FZK-Y5-nhN"/>
|
||||
|
@ -1315,7 +1213,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IVn-LE-fmp">
|
||||
<rect key="frame" x="0.0" y="3" width="328" height="56"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.90186256170272827" green="0.90201729536056519" blue="0.90185278654098511" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="56" id="qQe-8g-3LR"/>
|
||||
|
@ -1331,10 +1228,8 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<imageView userInteractionEnabled="NO" contentMode="center" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="_arrow_button" translatesAutoresizingMaskIntoConstraints="NO" id="rj8-Z7-7mp">
|
||||
<rect key="frame" x="8" y="17" width="12" height="23"/>
|
||||
<animations/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="IVn-LE-fmp" firstAttribute="width" secondItem="J5A-hy-9hb" secondAttribute="width" constant="8" id="8Dw-FS-ZwO"/>
|
||||
|
@ -1351,7 +1246,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2I5-tm-rMi">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="57"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.70980392156862748" green="0.80392156862745101" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="57" id="3CX-0k-nDf"/>
|
||||
|
@ -1367,7 +1261,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="(555) 555-5555" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wYz-da-3ZB">
|
||||
<rect key="frame" x="129" y="18" width="164" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="164" id="ElJ-Jb-M1R"/>
|
||||
</constraints>
|
||||
|
@ -1377,14 +1270,12 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="lFE-KR-9iN">
|
||||
<rect key="frame" x="149" y="19" width="20" height="20"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="S5y-W0-fAs"/>
|
||||
<constraint firstAttribute="width" constant="20" id="rFK-EJ-Xgu"/>
|
||||
</constraints>
|
||||
</activityIndicatorView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerY" secondItem="wYz-da-3ZB" secondAttribute="centerY" id="21A-bh-r9x"/>
|
||||
|
@ -1398,7 +1289,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="XXt-2F-6KC" firstAttribute="leading" secondItem="Zgb-Uj-73M" secondAttribute="leadingMargin" constant="-16" id="186-I2-PpT"/>
|
||||
|
@ -1451,7 +1341,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="VNq-cN-pk9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
<color key="barTintColor" red="0.067691504955291748" green="0.55628502368927002" blue="0.92999207973480225" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
|
@ -1470,12 +1359,10 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="FhQ-dM-1mj">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.93725490196078431" green="0.93725490196078431" blue="0.95686274509803926" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<view key="tableFooterView" contentMode="scaleToFill" id="Ezq-Cw-na2">
|
||||
<rect key="frame" x="0.0" y="502" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
</view>
|
||||
<sections>
|
||||
<tableViewSection id="2XP-ps-mfi">
|
||||
|
@ -1489,7 +1376,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="1 (708) 000-1234" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ipE-BI-sLL">
|
||||
<rect key="frame" x="0.0" y="58" width="320" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="21" id="hnY-fM-R9C"/>
|
||||
</constraints>
|
||||
|
@ -1499,7 +1385,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tyler Reinhard" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3Pu-Cs-0K2">
|
||||
<rect key="frame" x="0.0" y="28" width="320" height="30"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="MJo-RF-hP8"/>
|
||||
</constraints>
|
||||
|
@ -1509,7 +1394,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="XPv-Ww-lSM">
|
||||
<rect key="frame" x="0.0" y="80" width="320" height="30"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="6VH-TG-7PM"/>
|
||||
</constraints>
|
||||
|
@ -1523,7 +1407,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="XPv-Ww-lSM" firstAttribute="leading" secondItem="gr7-Sm-bcs" secondAttribute="leadingMargin" constant="-8" id="0WW-am-sJq"/>
|
||||
<constraint firstItem="ipE-BI-sLL" firstAttribute="top" secondItem="gr7-Sm-bcs" secondAttribute="topMargin" constant="50" id="4iL-fh-XTs"/>
|
||||
|
@ -1536,7 +1419,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<constraint firstItem="ipE-BI-sLL" firstAttribute="leading" secondItem="gr7-Sm-bcs" secondAttribute="leadingMargin" constant="-8" id="zCd-GH-BpM"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
<inset key="separatorInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
|
@ -1552,7 +1434,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Network Status" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="uNq-FV-lwt">
|
||||
<rect key="frame" x="15" y="11" width="200" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="q6L-Sa-lrA"/>
|
||||
</constraints>
|
||||
|
@ -1562,7 +1443,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Connected" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsLetterSpacingToFitWidth="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tg3-dQ-odw">
|
||||
<rect key="frame" x="105" y="11" width="200" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="Lw2-Fv-sOC"/>
|
||||
<constraint firstAttribute="height" constant="21" id="uvH-QZ-iUw"/>
|
||||
|
@ -1572,7 +1452,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="tg3-dQ-odw" firstAttribute="top" secondItem="hqv-P5-du9" secondAttribute="topMargin" constant="3" id="C7U-ve-FJA"/>
|
||||
<constraint firstItem="uNq-FV-lwt" firstAttribute="leading" secondItem="hqv-P5-du9" secondAttribute="leadingMargin" constant="7" id="ViZ-i6-VOo"/>
|
||||
|
@ -1580,7 +1459,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<constraint firstAttribute="trailingMargin" secondItem="tg3-dQ-odw" secondAttribute="trailing" constant="7" id="xHz-d7-B39"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
|
@ -1595,7 +1473,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Privacy" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="TAs-sK-kbi">
|
||||
<rect key="frame" x="15" y="11" width="200" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="70I-Jg-zQp"/>
|
||||
</constraints>
|
||||
|
@ -1604,13 +1481,11 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="TAs-sK-kbi" firstAttribute="leading" secondItem="vOb-SA-SH2" secondAttribute="leadingMargin" constant="7" id="KQc-S9-6h0"/>
|
||||
<constraint firstAttribute="centerY" secondItem="TAs-sK-kbi" secondAttribute="centerY" id="uj7-Jj-RUr"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="jp5-vZ-AhJ">
|
||||
<rect key="frame" x="0.0" y="270" width="320" height="44"/>
|
||||
|
@ -1621,7 +1496,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Notifications" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="BaC-fn-VoA">
|
||||
<rect key="frame" x="15" y="11" width="200" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="HeG-Yg-7m7"/>
|
||||
</constraints>
|
||||
|
@ -1630,13 +1504,11 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="BaC-fn-VoA" firstAttribute="leading" secondItem="sji-CJ-bhq" secondAttribute="leadingMargin" constant="7" id="Tae-ZO-Fxf"/>
|
||||
<constraint firstAttribute="centerY" secondItem="BaC-fn-VoA" secondAttribute="centerY" id="gMd-UT-AWs"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="Xx7-pz-aLN">
|
||||
<rect key="frame" x="0.0" y="314" width="320" height="44"/>
|
||||
|
@ -1647,7 +1519,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Advanced" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qix-5C-dh1">
|
||||
<rect key="frame" x="15" y="11" width="200" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="QQd-lT-7aN"/>
|
||||
</constraints>
|
||||
|
@ -1656,13 +1527,11 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerY" secondItem="qix-5C-dh1" secondAttribute="centerY" id="LKc-Zd-L2y"/>
|
||||
<constraint firstItem="qix-5C-dh1" firstAttribute="leading" secondItem="pMA-vR-8Ae" secondAttribute="leadingMargin" constant="7" id="oDP-br-7h2"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" id="EI4-kQ-MMA">
|
||||
<rect key="frame" x="0.0" y="358" width="320" height="44"/>
|
||||
|
@ -1673,7 +1542,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="About" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6FV-LR-9Hv">
|
||||
<rect key="frame" x="15" y="11" width="200" height="21"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="200" id="IIS-zH-XcG"/>
|
||||
</constraints>
|
||||
|
@ -1682,13 +1550,11 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="6FV-LR-9Hv" firstAttribute="leading" secondItem="czg-5p-aVz" secondAttribute="leadingMargin" constant="7" id="9MM-zs-eHh"/>
|
||||
<constraint firstAttribute="centerY" secondItem="6FV-LR-9Hv" secondAttribute="centerY" id="Rdb-IM-Koi"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
|
@ -1703,7 +1569,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4Mk-ly-6fq">
|
||||
<rect key="frame" x="15" y="25" width="285" height="50"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="1" green="0.2196078431372549" blue="0.40392156862745099" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="50" id="Pwj-l2-Tav"/>
|
||||
|
@ -1717,14 +1582,12 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstItem="4Mk-ly-6fq" firstAttribute="leading" secondItem="Ok9-fE-WhB" secondAttribute="leadingMargin" constant="7" id="0dH-Hz-wMU"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="4Mk-ly-6fq" secondAttribute="trailing" constant="12" id="Hwq-uT-qGp"/>
|
||||
<constraint firstItem="4Mk-ly-6fq" firstAttribute="top" secondItem="Ok9-fE-WhB" secondAttribute="topMargin" constant="17" id="TQa-bs-YNu"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
|
@ -1770,7 +1633,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="gzw-fh-en2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
<color key="barTintColor" red="0.067691504955291748" green="0.55628502368927002" blue="0.92999207973480225" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
|
@ -1789,7 +1651,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="X9S-Pa-EbX">
|
||||
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ContactTableViewCell" rowHeight="48" id="Ld5-sX-pB8" customClass="ContactTableViewCell">
|
||||
|
@ -1801,13 +1662,11 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="urb-Me-knG">
|
||||
<rect key="frame" x="20" y="4" width="220" height="39"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="urb-Me-knG" secondAttribute="bottom" constant="-4" id="3fF-H3-Spz"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="urb-Me-knG" secondAttribute="trailing" constant="72" id="R9g-GE-nWU"/>
|
||||
|
@ -1815,7 +1674,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<constraint firstItem="urb-Me-knG" firstAttribute="top" secondItem="EqP-87-4hZ" secondAttribute="topMargin" constant="-4" id="iex-zH-iTD"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
<connections>
|
||||
<outlet property="nameLabel" destination="urb-Me-knG" id="2h5-l1-QDQ"/>
|
||||
</connections>
|
||||
|
@ -1858,15 +1716,14 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<viewControllerLayoutGuide type="bottom" id="kH6-9L-pzh"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="P0X-AM-Yjw">
|
||||
<rect key="frame" x="0.0" y="64" width="320" height="504"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ukg-om-VX3">
|
||||
<view contentMode="scaleToFill" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ukg-om-VX3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="100"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ul8-NY-i4c">
|
||||
<rect key="frame" x="8" y="20" width="60" height="60"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="60" id="Fkg-iq-6Ap"/>
|
||||
<constraint firstAttribute="width" constant="60" id="l0W-ug-b1c"/>
|
||||
|
@ -1880,7 +1737,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</button>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Name this group chat" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="gbm-B5-gCc">
|
||||
<rect key="frame" x="86" y="35" width="221" height="30"/>
|
||||
<animations/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="bKM-dc-IsP"/>
|
||||
</constraints>
|
||||
|
@ -1888,7 +1744,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences" returnKeyType="done" enablesReturnKeyAutomatically="YES"/>
|
||||
</textField>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="gbm-B5-gCc" secondAttribute="trailing" constant="13" id="1Pn-JF-Njp"/>
|
||||
|
@ -1899,9 +1754,8 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<constraint firstItem="gbm-B5-gCc" firstAttribute="leading" secondItem="Ul8-NY-i4c" secondAttribute="trailing" constant="18" id="yn3-rt-mGC"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsMultipleSelection="YES" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="cFo-AT-Srf">
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsMultipleSelection="YES" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="cFo-AT-Srf">
|
||||
<rect key="frame" x="0.0" y="108" width="320" height="396"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="ekO-kw-iHV">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
|
@ -1909,13 +1763,11 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Add people:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="daD-wf-IGn">
|
||||
<rect key="frame" x="10" y="274" width="130" height="21"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
|
||||
<color key="textColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="daD-wf-IGn" firstAttribute="leading" secondItem="ekO-kw-iHV" secondAttribute="leading" constant="10" id="00e-AP-Ygd"/>
|
||||
|
@ -1934,15 +1786,12 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="a4j-OQ-ala">
|
||||
<rect key="frame" x="15" y="0.0" width="290" height="59"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="20"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<animations/>
|
||||
</tableViewCellContentView>
|
||||
<animations/>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
|
@ -1951,7 +1800,6 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstItem="cFo-AT-Srf" firstAttribute="centerX" secondItem="P0X-AM-Yjw" secondAttribute="centerX" id="EUd-V6-lGx"/>
|
||||
|
@ -1990,12 +1838,10 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="l1Z-lc-H46">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</navigationBar>
|
||||
<nil name="viewControllers"/>
|
||||
<toolbar key="toolbar" opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="D2L-cq-DaY">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</toolbar>
|
||||
<connections>
|
||||
<segue destination="sL4-Zw-2Og" kind="relationship" relationship="rootViewController" id="zqL-2e-WXU"/>
|
||||
|
@ -2027,8 +1873,7 @@ A0 09 9A FF A8 8A 09 99</string>
|
|||
</resources>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="DR8-fx-0PD"/>
|
||||
<segue reference="ANb-Oa-vQe"/>
|
||||
<segue reference="xo7-5J-BJb"/>
|
||||
<segue reference="D0d-4f-lcI"/>
|
||||
<segue reference="gZ1-lh-srF"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
</document>
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIColor+OWS.h"
|
||||
#import "Cryptography.h"
|
||||
#import "UIColor+OWS.h"
|
||||
|
||||
@implementation UIColor (OWS)
|
||||
|
||||
|
@ -56,7 +56,8 @@
|
|||
}
|
||||
|
||||
+ (UIColor *)backgroundColorForContact:(NSString *)contactIdentifier {
|
||||
NSArray *colors = @[[UIColor colorWithRed:204.f/255.f green:148.f/255.f blue:102.f/255.f alpha:1.f],
|
||||
NSArray *colors = @[
|
||||
[UIColor colorWithRed:204.f / 255.f green:148.f / 255.f blue:102.f / 255.f alpha:1.f],
|
||||
[UIColor colorWithRed:187.f / 255.f green:104.f / 255.f blue:62.f / 255.f alpha:1.f],
|
||||
[UIColor colorWithRed:145.f / 255.f green:78.f / 255.f blue:48.f / 255.f alpha:1.f],
|
||||
[UIColor colorWithRed:122.f / 255.f green:63.f / 255.f blue:41.f / 255.f alpha:1.f],
|
||||
|
@ -76,7 +77,8 @@
|
|||
[UIColor colorWithRed:44.f / 255.f green:165.f / 255.f blue:137.f / 255.f alpha:1.f],
|
||||
[UIColor colorWithRed:137.f / 255.f green:181.f / 255.f blue:48.f / 255.f alpha:1.f],
|
||||
[UIColor colorWithRed:208.f / 255.f green:204.f / 255.f blue:78.f / 255.f alpha:1.f],
|
||||
[UIColor colorWithRed:227.f/255.f green:162.f/255.f blue:150.f/255.f alpha:1.f]];
|
||||
[UIColor colorWithRed:227.f / 255.f green:162.f / 255.f blue:150.f / 255.f alpha:1.f]
|
||||
];
|
||||
NSData *contactData = [contactIdentifier dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
NSUInteger hashingLength = 8;
|
||||
|
@ -88,4 +90,3 @@
|
|||
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -71,8 +71,7 @@ AppAudioManager* sharedAppAudioManager;
|
|||
}
|
||||
|
||||
#pragma mark AudioControl;
|
||||
-(void) respondToProgressChange:(enum CallProgressType) progressType
|
||||
forLocallyInitiatedCall:(BOOL) initiatedLocally {
|
||||
- (void)respondToProgressChange:(enum CallProgressType)progressType forLocallyInitiatedCall:(BOOL)initiatedLocally {
|
||||
switch (progressType) {
|
||||
case CallProgressType_Connecting:
|
||||
[sharedAppAudioManager setAudioEnabled:YES];
|
||||
|
@ -93,21 +92,17 @@ AppAudioManager* sharedAppAudioManager;
|
|||
- (void)respondToTerminationType:(enum CallTerminationType)terminationType {
|
||||
if (terminationType == CallTerminationType_ResponderIsBusy) {
|
||||
[_soundPlayer playSound:[SoundBoard instanceOfBusySound]];
|
||||
}
|
||||
else if([self shouldErrorSoundBePlayedForCallTerminationType:terminationType]){
|
||||
} else if ([self shouldErrorSoundBePlayedForCallTerminationType:terminationType]) {
|
||||
[_soundPlayer playSound:[SoundBoard instanceOfErrorAlert]];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
[_soundPlayer playSound:[SoundBoard instanceOfAlert]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)shouldErrorSoundBePlayedForCallTerminationType:(enum CallTerminationType)type {
|
||||
[_soundPlayer stopAllAudio];
|
||||
if (type == CallTerminationType_RejectedLocal ||
|
||||
type == CallTerminationType_RejectedRemote ||
|
||||
type == CallTerminationType_HangupLocal ||
|
||||
type == CallTerminationType_HangupRemote ||
|
||||
if (type == CallTerminationType_RejectedLocal || type == CallTerminationType_RejectedRemote ||
|
||||
type == CallTerminationType_HangupLocal || type == CallTerminationType_HangupRemote ||
|
||||
type == CallTerminationType_RecipientUnavailable) {
|
||||
return NO;
|
||||
}
|
||||
|
@ -159,7 +154,12 @@ AppAudioManager* sharedAppAudioManager;
|
|||
- (void)requestRequiredPermissionsIfNeededWithCompletion:(PermissionBlock)permissionBlock incoming:(BOOL)isIncoming {
|
||||
[AVAudioSession.sharedInstance requestRecordPermission:^(BOOL granted) {
|
||||
if (!granted) {
|
||||
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"ACTION_REQUIRED_TITLE", @"") message:NSLocalizedString(@"AUDIO_PERMISSION_MESSAGE", @"") delegate:nil cancelButtonTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"") otherButtonTitles:NSLocalizedString(@"SETTINGS_NAV_BAR_TITLE",nil), nil];
|
||||
UIAlertView *alertView =
|
||||
[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"ACTION_REQUIRED_TITLE", @"")
|
||||
message:NSLocalizedString(@"AUDIO_PERMISSION_MESSAGE", @"")
|
||||
delegate:nil
|
||||
cancelButtonTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"")
|
||||
otherButtonTitles:NSLocalizedString(@"SETTINGS_NAV_BAR_TITLE", nil), nil];
|
||||
|
||||
[alertView setDelegate:self];
|
||||
|
||||
|
@ -203,8 +203,7 @@ AppAudioManager* sharedAppAudioManager;
|
|||
#pragma mark Sound Player Delegate
|
||||
|
||||
- (void)didCompleteSoundInstanceOfType:(SoundInstanceType)instanceType {
|
||||
if (instanceType == SoundInstanceTypeBusySound ||
|
||||
instanceType == SoundInstanceTypeErrorAlert ||
|
||||
if (instanceType == SoundInstanceTypeBusySound || instanceType == SoundInstanceTypeErrorAlert ||
|
||||
instanceType == SoundInstanceTypeAlert) {
|
||||
[sharedAppAudioManager setAudioEnabled:NO];
|
||||
}
|
||||
|
|
|
@ -57,5 +57,4 @@ static NSString* SoundFile_Ringtone =@"r.caf";
|
|||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -26,6 +26,5 @@ typedef enum {
|
|||
- (void)setAudioLoopCount:(NSInteger)loopCount;
|
||||
- (void)setCompeletionBlock:(void (^)(SoundInstance *))block;
|
||||
|
||||
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
|
||||
successfully:(BOOL)flag;
|
||||
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag;
|
||||
@end
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
}
|
||||
|
||||
+ (NSURL *)urlToFile:(NSString *)file {
|
||||
return [NSURL fileURLWithPath:
|
||||
[NSString stringWithFormat:@"%@/%@", NSBundle.mainBundle.resourcePath,file]];
|
||||
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", NSBundle.mainBundle.resourcePath, file]];
|
||||
}
|
||||
|
||||
+ (AVAudioPlayer *)createAudioPlayerForFile:(NSString *)audioFile {
|
||||
|
@ -55,7 +54,9 @@
|
|||
|
||||
NSError *error;
|
||||
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
|
||||
if (nil == audioPlayer){ NSLog(@" %@",[error description]);}
|
||||
if (nil == audioPlayer) {
|
||||
NSLog(@" %@", [error description]);
|
||||
}
|
||||
return audioPlayer;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "Queue.h"
|
||||
#import "EncodedAudioFrame.h"
|
||||
#import "EncodedAudioPacket.h"
|
||||
#import "Queue.h"
|
||||
|
||||
#define AUDIO_FRAMES_PER_PACKET 2
|
||||
|
||||
|
@ -18,9 +18,12 @@
|
|||
*
|
||||
*/
|
||||
@interface AudioPacker : NSObject {
|
||||
@private NSMutableArray* framesToSend;
|
||||
@private uint16_t nextSequenceNumber;
|
||||
@private Queue* audioFrameToReceiveQueue;
|
||||
@private
|
||||
NSMutableArray *framesToSend;
|
||||
@private
|
||||
uint16_t nextSequenceNumber;
|
||||
@private
|
||||
Queue *audioFrameToReceiveQueue;
|
||||
}
|
||||
|
||||
+ (AudioPacker *)audioPacker;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "AudioPacker.h"
|
||||
#import "CryptoTools.h"
|
||||
#import "Conversions.h"
|
||||
#import "CryptoTools.h"
|
||||
#import "Util.h"
|
||||
|
||||
@implementation AudioPacker
|
||||
|
@ -13,27 +13,28 @@
|
|||
|
||||
// interop fix:
|
||||
// cut off the high bit (the sign bit), to avoid confusion over signed-ness when peer receives the initial number
|
||||
// also cut off the next bit, so that at least 2^14 packets (instead of 1) must fail to arrive before confusion can be caused
|
||||
// also cut off the next bit, so that at least 2^14 packets (instead of 1) must fail to arrive before confusion can
|
||||
// be caused
|
||||
newAudioPackerInstance->nextSequenceNumber &= 0x3FFF;
|
||||
|
||||
return newAudioPackerInstance;
|
||||
}
|
||||
|
||||
- (void)packFrame:(EncodedAudioFrame *)frame {
|
||||
require(frame != nil);
|
||||
require(!frame.isMissingAudioData);
|
||||
ows_require(frame != nil);
|
||||
ows_require(!frame.isMissingAudioData);
|
||||
[framesToSend addObject:frame.tryGetAudioData];
|
||||
}
|
||||
|
||||
- (EncodedAudioPacket *)tryGetFinishedAudioPacket {
|
||||
if (framesToSend.count < AUDIO_FRAMES_PER_PACKET) return nil;
|
||||
if (framesToSend.count < AUDIO_FRAMES_PER_PACKET)
|
||||
return nil;
|
||||
|
||||
uint16_t sequenceNumber = nextSequenceNumber++;
|
||||
NSData *payload = [framesToSend ows_concatDatas];
|
||||
|
||||
[framesToSend removeAllObjects];
|
||||
return [EncodedAudioPacket encodedAudioPacketWithAudioData:payload
|
||||
andSequenceNumber:sequenceNumber];
|
||||
return [EncodedAudioPacket encodedAudioPacketWithAudioData:payload andSequenceNumber:sequenceNumber];
|
||||
}
|
||||
|
||||
- (void)unpackPotentiallyMissingAudioPacket:(EncodedAudioPacket *)potentiallyMissingPacket {
|
||||
|
@ -52,7 +53,7 @@
|
|||
#pragma mark Private Methods
|
||||
|
||||
- (void)enqueueFramesForPacket:(EncodedAudioPacket *)packet {
|
||||
require(packet != nil);
|
||||
ows_require(packet != nil);
|
||||
|
||||
NSData *audioData = [packet audioData];
|
||||
requireState(audioData.length % AUDIO_FRAMES_PER_PACKET == 0);
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
*
|
||||
**/
|
||||
@interface AudioSocket : NSObject {
|
||||
@private SrtpSocket* srtpSocket;
|
||||
@private bool started;
|
||||
@private
|
||||
SrtpSocket *srtpSocket;
|
||||
@private
|
||||
bool started;
|
||||
}
|
||||
|
||||
+ (AudioSocket *)audioSocketOver:(SrtpSocket *)srtpSocket;
|
||||
|
|
|
@ -3,30 +3,29 @@
|
|||
@implementation AudioSocket
|
||||
|
||||
+ (AudioSocket *)audioSocketOver:(SrtpSocket *)srtpSocket {
|
||||
require(srtpSocket != nil);
|
||||
ows_require(srtpSocket != nil);
|
||||
AudioSocket *p = [AudioSocket new];
|
||||
p->srtpSocket = srtpSocket;
|
||||
return p;
|
||||
}
|
||||
|
||||
- (void)startWithHandler:(PacketHandler *)handler untilCancelled:(TOCCancelToken *)untilCancelledToken {
|
||||
require(handler != nil);
|
||||
ows_require(handler != nil);
|
||||
requireState(!started);
|
||||
started = true;
|
||||
|
||||
PacketHandlerBlock valueHandler = ^(RtpPacket *rtpPacket) {
|
||||
require(rtpPacket != nil);
|
||||
require([rtpPacket isKindOfClass:[RtpPacket class]]);
|
||||
ows_require(rtpPacket != nil);
|
||||
ows_require([rtpPacket isKindOfClass:[RtpPacket class]]);
|
||||
[handler handlePacket:[EncodedAudioPacket encodedAudioPacketWithAudioData:[rtpPacket payload]
|
||||
andSequenceNumber:[rtpPacket sequenceNumber]]];
|
||||
};
|
||||
|
||||
[srtpSocket startWithHandler:[PacketHandler packetHandler:valueHandler
|
||||
withErrorHandler:[handler errorHandler]]
|
||||
[srtpSocket startWithHandler:[PacketHandler packetHandler:valueHandler withErrorHandler:[handler errorHandler]]
|
||||
untilCancelled:untilCancelledToken];
|
||||
}
|
||||
- (void)send:(EncodedAudioPacket *)audioPacket {
|
||||
require(audioPacket != nil);
|
||||
ows_require(audioPacket != nil);
|
||||
|
||||
RtpPacket *rtpPacket = [RtpPacket rtpPacketWithDefaultsAndSequenceNumber:[audioPacket sequenceNumber]
|
||||
andPayload:[audioPacket audioData]];
|
||||
|
|
|
@ -7,18 +7,24 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* CallAudioManager is responsible for creating and managing components related to playing real time audio communicated over a network.
|
||||
* CallAudioManager is responsible for creating and managing components related to playing real time audio communicated
|
||||
*over a network.
|
||||
*
|
||||
* The components are for playing/recording, processing, and transporting audio data.
|
||||
*
|
||||
**/
|
||||
|
||||
@interface CallAudioManager : NSObject <AudioCallbackHandler> {
|
||||
@private RemoteIOAudio* audioInterface;
|
||||
@private AudioProcessor* audioProcessor;
|
||||
@private AudioSocket* audioSocket;
|
||||
@private bool started;
|
||||
@private NSUInteger bytesInPlaybackBuffer;
|
||||
@private
|
||||
RemoteIOAudio *audioInterface;
|
||||
@private
|
||||
AudioProcessor *audioProcessor;
|
||||
@private
|
||||
AudioSocket *audioSocket;
|
||||
@private
|
||||
bool started;
|
||||
@private
|
||||
NSUInteger bytesInPlaybackBuffer;
|
||||
}
|
||||
|
||||
+ (CallAudioManager *)callAudioManagerStartedWithAudioSocket:(AudioSocket *)audioSocket
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
+ (CallAudioManager *)callAudioManagerStartedWithAudioSocket:(AudioSocket *)audioSocket
|
||||
andErrorHandler:(ErrorHandlerBlock)errorHandler
|
||||
untilCancelled:(TOCCancelToken *)untilCancelledToken {
|
||||
require(audioSocket != nil);
|
||||
ows_require(audioSocket != nil);
|
||||
|
||||
AudioProcessor *processor = [AudioProcessor audioProcessor];
|
||||
|
||||
|
@ -22,18 +22,18 @@
|
|||
}
|
||||
|
||||
- (void)startWithErrorHandler:(ErrorHandlerBlock)errorHandler untilCancelled:(TOCCancelToken *)untilCancelledToken {
|
||||
require(errorHandler != nil);
|
||||
require(untilCancelledToken != nil);
|
||||
ows_require(errorHandler != nil);
|
||||
ows_require(untilCancelledToken != nil);
|
||||
@synchronized(self) {
|
||||
requireState(!started);
|
||||
started = true;
|
||||
if (untilCancelledToken.isAlreadyCancelled) return;
|
||||
if (untilCancelledToken.isAlreadyCancelled)
|
||||
return;
|
||||
audioInterface = [RemoteIOAudio remoteIOInterfaceStartedWithDelegate:self untilCancelled:untilCancelledToken];
|
||||
PacketHandlerBlock handler = ^(EncodedAudioPacket *packet) {
|
||||
[audioProcessor receivedPacket:packet];
|
||||
};
|
||||
[audioSocket startWithHandler:[PacketHandler packetHandler:handler
|
||||
withErrorHandler:errorHandler]
|
||||
[audioSocket startWithHandler:[PacketHandler packetHandler:handler withErrorHandler:errorHandler]
|
||||
untilCancelled:untilCancelledToken];
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,8 @@
|
|||
double minSafeBufferSize = MAX(requested, bytesAddedIfPullMore) * SAFETY_FACTOR_FOR_COMPUTE_DELAY;
|
||||
while (bytesInPlaybackBuffer < minSafeBufferSize) {
|
||||
NSData *decodedAudioData = [audioProcessor tryDecodeOrInferFrame];
|
||||
if (decodedAudioData == nil) break;
|
||||
if (decodedAudioData == nil)
|
||||
break;
|
||||
[audioInterface populatePlaybackQueueWithData:decodedAudioData];
|
||||
bytesInPlaybackBuffer += decodedAudioData.length;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
**/
|
||||
|
||||
@interface EncodedAudioFrame : NSObject {
|
||||
@private NSData* audioData;
|
||||
@private
|
||||
NSData *audioData;
|
||||
}
|
||||
|
||||
+ (EncodedAudioFrame *)encodedAudioFrameWithData:(NSData *)audioData;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#import "EncodedAudioFrame.h"
|
||||
#import "Constraints.h"
|
||||
#import "EncodedAudioFrame.h"
|
||||
|
||||
@implementation EncodedAudioFrame
|
||||
|
||||
+ (EncodedAudioFrame *)encodedAudioFrameWithData:(NSData *)audioData {
|
||||
require(audioData != nil);
|
||||
ows_require(audioData != nil);
|
||||
EncodedAudioFrame *frame = [EncodedAudioFrame new];
|
||||
frame->audioData = audioData;
|
||||
return frame;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#import "EncodedAudioPacket.h"
|
||||
#import "Constraints.h"
|
||||
#import "EncodedAudioPacket.h"
|
||||
|
||||
@implementation EncodedAudioPacket
|
||||
|
||||
@synthesize audioData, sequenceNumber;
|
||||
|
||||
+ (EncodedAudioPacket *)encodedAudioPacketWithAudioData:(NSData *)audioData andSequenceNumber:(uint16_t)sequenceNumber {
|
||||
require(audioData != nil);
|
||||
ows_require(audioData != nil);
|
||||
EncodedAudioPacket *p = [EncodedAudioPacket new];
|
||||
p->audioData = audioData;
|
||||
p->sequenceNumber = sequenceNumber;
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AudioCallbackHandler.h"
|
||||
#import "CyclicalBuffer.h"
|
||||
#import "Environment.h"
|
||||
#import "RemoteIOBufferListWrapper.h"
|
||||
#import "Terminable.h"
|
||||
|
||||
enum State {
|
||||
NOT_STARTED,
|
||||
STARTED,
|
||||
TERMINATED
|
||||
};
|
||||
enum State { NOT_STARTED, STARTED, TERMINATED };
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -25,7 +21,6 @@ enum State {
|
|||
*
|
||||
*/
|
||||
@interface RemoteIOAudio : NSObject <AVAudioSessionDelegate> {
|
||||
|
||||
AudioUnit rioAudioUnit;
|
||||
|
||||
BOOL isStreaming;
|
||||
|
@ -45,10 +40,10 @@ enum State {
|
|||
@property (strong) CyclicalBuffer *playbackQueue;
|
||||
@property (assign) AudioUnit rioAudioUnit;
|
||||
|
||||
+(RemoteIOAudio*) remoteIOInterfaceStartedWithDelegate:(id<AudioCallbackHandler>)delegateIn untilCancelled:(TOCCancelToken*)untilCancelledToken;
|
||||
+ (RemoteIOAudio *)remoteIOInterfaceStartedWithDelegate:(id<AudioCallbackHandler>)delegateIn
|
||||
untilCancelled:(TOCCancelToken *)untilCancelledToken;
|
||||
- (void)populatePlaybackQueueWithData:(NSData *)data;
|
||||
- (NSUInteger)getSampleRateInHertz;
|
||||
- (BOOL)toggleMute;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "AppAudioManager.h"
|
||||
#import "Environment.h"
|
||||
#import "Constraints.h"
|
||||
#import "Environment.h"
|
||||
#import "RemoteIOAudio.h"
|
||||
#import "ThreadManager.h"
|
||||
#import "Util.h"
|
||||
|
@ -21,20 +21,25 @@
|
|||
|
||||
static bool doesActiveInstanceExist;
|
||||
|
||||
+(RemoteIOAudio*) remoteIOInterfaceStartedWithDelegate:(id<AudioCallbackHandler>)delegateIn untilCancelled:(TOCCancelToken*)untilCancelledToken {
|
||||
|
||||
checkOperationDescribe(!doesActiveInstanceExist, @"Only one RemoteIOInterfance instance can exist at a time. Adding more will break previous instances.");
|
||||
+ (RemoteIOAudio *)remoteIOInterfaceStartedWithDelegate:(id<AudioCallbackHandler>)delegateIn
|
||||
untilCancelled:(TOCCancelToken *)untilCancelledToken {
|
||||
checkOperationDescribe(
|
||||
!doesActiveInstanceExist,
|
||||
@"Only one RemoteIOInterfance instance can exist at a time. Adding more will break previous instances.");
|
||||
doesActiveInstanceExist = true;
|
||||
|
||||
RemoteIOAudio *newRemoteIoInterface = [RemoteIOAudio new];
|
||||
newRemoteIoInterface->starveLogger = [Environment.logging getOccurrenceLoggerForSender:newRemoteIoInterface withKey:@"starve"];
|
||||
newRemoteIoInterface->starveLogger =
|
||||
[Environment.logging getOccurrenceLoggerForSender:newRemoteIoInterface withKey:@"starve"];
|
||||
newRemoteIoInterface->conditionLogger = [Environment.logging getConditionLoggerForSender:newRemoteIoInterface];
|
||||
newRemoteIoInterface->recordingQueue = [CyclicalBuffer new];
|
||||
newRemoteIoInterface->playbackQueue = [CyclicalBuffer new];
|
||||
newRemoteIoInterface->unusedBuffers = [NSMutableSet set];
|
||||
newRemoteIoInterface->state = NOT_STARTED;
|
||||
newRemoteIoInterface->playbackBufferSizeLogger = [Environment.logging getValueLoggerForValue:@"|playback queue|" from:newRemoteIoInterface];
|
||||
newRemoteIoInterface->recordingQueueSizeLogger = [Environment.logging getValueLoggerForValue:@"|recording queue|" from:newRemoteIoInterface];
|
||||
newRemoteIoInterface->playbackBufferSizeLogger =
|
||||
[Environment.logging getValueLoggerForValue:@"|playback queue|" from:newRemoteIoInterface];
|
||||
newRemoteIoInterface->recordingQueueSizeLogger =
|
||||
[Environment.logging getValueLoggerForValue:@"|recording queue|" from:newRemoteIoInterface];
|
||||
|
||||
while (newRemoteIoInterface->unusedBuffers.count < INITIAL_NUMBER_OF_BUFFERS) {
|
||||
[newRemoteIoInterface addUnusedBuffer];
|
||||
|
@ -114,9 +119,7 @@ static bool doesActiveInstanceExist;
|
|||
d.mBytesPerPacket = SAMPLE_SIZE_IN_BYTES;
|
||||
d.mBytesPerFrame = framesPerPacket * SAMPLE_SIZE_IN_BYTES;
|
||||
d.mReserved = 0;
|
||||
d.mFormatFlags = kAudioFormatFlagIsSignedInteger
|
||||
| kAudioFormatFlagsNativeEndian
|
||||
| kAudioFormatFlagIsPacked;
|
||||
d.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
return d;
|
||||
}
|
||||
- (void)setAudioCallbacks {
|
||||
|
@ -153,18 +156,20 @@ static bool doesActiveInstanceExist;
|
|||
}
|
||||
- (RemoteIOBufferListWrapper *)tryTakeUnusedBuffer {
|
||||
RemoteIOBufferListWrapper *buffer = (RemoteIOBufferListWrapper *)[unusedBuffers anyObject];
|
||||
if (buffer == nil) return nil;
|
||||
if (buffer == nil)
|
||||
return nil;
|
||||
[unusedBuffers removeObject:buffer];
|
||||
return buffer;
|
||||
}
|
||||
- (void)returnUsedBuffer:(RemoteIOBufferListWrapper *)buffer {
|
||||
require(buffer != nil);
|
||||
if (state == TERMINATED) return; // in case a buffer was in use as termination occurred
|
||||
ows_require(buffer != nil);
|
||||
if (state == TERMINATED)
|
||||
return; // in case a buffer was in use as termination occurred
|
||||
[unusedBuffers addObject:buffer];
|
||||
}
|
||||
|
||||
- (void)startWithDelegate:(id<AudioCallbackHandler>)delegateIn untilCancelled:(TOCCancelToken *)untilCancelledToken {
|
||||
require(delegateIn != nil);
|
||||
ows_require(delegateIn != nil);
|
||||
@synchronized(self) {
|
||||
requireState(state == NOT_STARTED);
|
||||
|
||||
|
@ -190,10 +195,7 @@ static OSStatus recordingCallback(void *inRefCon,
|
|||
UInt32 inBusNumber,
|
||||
UInt32 inNumberSamples,
|
||||
AudioBufferList *ioData) {
|
||||
|
||||
|
||||
@autoreleasepool {
|
||||
|
||||
RemoteIOAudio *instance = (__bridge RemoteIOAudio *)inRefCon;
|
||||
|
||||
RemoteIOBufferListWrapper *buffer;
|
||||
|
@ -217,13 +219,13 @@ static OSStatus recordingCallback(void *inRefCon,
|
|||
onThread:[ThreadManager lowLatencyThread]
|
||||
withObject:buffer
|
||||
waitUntilDone:NO];
|
||||
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
- (void)onRecordedDataIntoBuffer:(RemoteIOBufferListWrapper *)buffer {
|
||||
@synchronized(self) {
|
||||
if (state == TERMINATED) return;
|
||||
if (state == TERMINATED)
|
||||
return;
|
||||
NSData *recordedAudioVolatile = [NSData dataWithBytesNoCopy:[buffer audioBufferList]->mBuffers[0].mData
|
||||
length:[buffer sampleCount] * SAMPLE_SIZE_IN_BYTES
|
||||
freeWhenDone:NO];
|
||||
|
@ -236,8 +238,9 @@ static OSStatus recordingCallback(void *inRefCon,
|
|||
}
|
||||
|
||||
- (void)populatePlaybackQueueWithData:(NSData *)data {
|
||||
require(data != nil);
|
||||
if (data.length == 0) return;
|
||||
ows_require(data != nil);
|
||||
if (data.length == 0)
|
||||
return;
|
||||
@synchronized(self) {
|
||||
[playbackQueue enqueueData:data];
|
||||
}
|
||||
|
@ -258,13 +261,15 @@ static OSStatus playbackCallback(void *inRefCon,
|
|||
NSUInteger starveAmount = requestedByteCount - availableByteCount;
|
||||
[instance->starveLogger markOccurrence:@(starveAmount)];
|
||||
} else {
|
||||
NSData* audioToCopyVolatile = [[instance playbackQueue] dequeuePotentialyVolatileDataWithLength:requestedByteCount];
|
||||
NSData *audioToCopyVolatile =
|
||||
[[instance playbackQueue] dequeuePotentialyVolatileDataWithLength:requestedByteCount];
|
||||
memcpy(ioData->mBuffers[0].mData, [audioToCopyVolatile bytes], audioToCopyVolatile.length);
|
||||
}
|
||||
}
|
||||
|
||||
[Operation asyncRun:^{[instance onRequestedPlaybackDataAmount:requestedByteCount
|
||||
andHadAvailableAmount:availableByteCount];}
|
||||
[Operation asyncRun:^{
|
||||
[instance onRequestedPlaybackDataAmount:requestedByteCount andHadAvailableAmount:availableByteCount];
|
||||
}
|
||||
onThread:[ThreadManager lowLatencyThread]];
|
||||
|
||||
if (availableByteCount < requestedByteCount) {
|
||||
|
@ -273,9 +278,11 @@ static OSStatus playbackCallback(void *inRefCon,
|
|||
|
||||
return noErr;
|
||||
}
|
||||
-(void) onRequestedPlaybackDataAmount:(NSUInteger)requestedByteCount andHadAvailableAmount:(NSUInteger)availableByteCount {
|
||||
- (void)onRequestedPlaybackDataAmount:(NSUInteger)requestedByteCount
|
||||
andHadAvailableAmount:(NSUInteger)availableByteCount {
|
||||
@synchronized(self) {
|
||||
if (state == TERMINATED) return;
|
||||
if (state == TERMINATED)
|
||||
return;
|
||||
}
|
||||
NSUInteger consumedByteCount = availableByteCount >= requestedByteCount ? requestedByteCount : 0;
|
||||
NSUInteger remainingByteCount = availableByteCount - consumedByteCount;
|
||||
|
@ -294,7 +301,8 @@ static OSStatus playbackCallback(void *inRefCon,
|
|||
}
|
||||
|
||||
- (void)checkDone:(OSStatus)resultCode {
|
||||
if (resultCode == kAudioSessionNoError) return;
|
||||
if (resultCode == kAudioSessionNoError)
|
||||
return;
|
||||
|
||||
NSString *failure;
|
||||
if (resultCode == kAudioServicesUnsupportedPropertyError) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
*
|
||||
**/
|
||||
@interface SpeexCodec : NSObject {
|
||||
|
||||
void *decodingState;
|
||||
SpeexBits decodingBits;
|
||||
spx_int16_t decodingFrameSize;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#import "Environment.h"
|
||||
#import "Constraints.h"
|
||||
#import "Environment.h"
|
||||
#import "SpeexCodec.h"
|
||||
|
||||
@implementation SpeexCodec
|
||||
|
@ -41,13 +41,14 @@
|
|||
}
|
||||
|
||||
- (NSData *)encode:(NSData *)rawData {
|
||||
require(rawData != nil);
|
||||
require(rawData.length == FRAME_SIZE_IN_SAMPLES*DECODED_SAMPLE_SIZE_IN_BYTES);
|
||||
ows_require(rawData != nil);
|
||||
ows_require(rawData.length == FRAME_SIZE_IN_SAMPLES * DECODED_SAMPLE_SIZE_IN_BYTES);
|
||||
speex_bits_reset(&encodingBits);
|
||||
speex_encode_int(encodingState, (spx_int16_t *)[rawData bytes], &encodingBits);
|
||||
|
||||
NSMutableData *outputBuffer = [NSMutableData dataWithLength:encodingBufferSizeInBytes];
|
||||
int outputSizeInBytes = speex_bits_write(&encodingBits, [outputBuffer mutableBytes], (int)encodingBufferSizeInBytes);
|
||||
int outputSizeInBytes =
|
||||
speex_bits_write(&encodingBits, [outputBuffer mutableBytes], (int)encodingBufferSizeInBytes);
|
||||
checkOperation(outputSizeInBytes > 0);
|
||||
[outputBuffer setLength:(NSUInteger)outputSizeInBytes];
|
||||
|
||||
|
@ -59,7 +60,8 @@
|
|||
if (potentiallyMissingEncodedData == nil) {
|
||||
encodedDataLength = [self decodedFrameSizeInBytes]; // size for infering audio data
|
||||
}
|
||||
if(encodedDataLength == 0) return nil;
|
||||
if (encodedDataLength == 0)
|
||||
return nil;
|
||||
|
||||
SpeexBits *dbits = [self getSpeexBitsFromData:potentiallyMissingEncodedData andDataLength:(int)encodedDataLength];
|
||||
|
||||
|
@ -94,11 +96,17 @@
|
|||
count++;
|
||||
decodingBufferIndex += decodingFrameSize;
|
||||
if (decodingBufferIndex + decodingFrameSize > decodingBufferLength) {
|
||||
[logging logWarning:[NSString stringWithFormat:@"out of space in the decArr buffer, idx=%d, frameSize=%d, length=%d", decodingBufferIndex,decodingFrameSize,decodingBufferLength]];
|
||||
[logging
|
||||
logWarning:[NSString
|
||||
stringWithFormat:@"out of space in the decArr buffer, idx=%d, frameSize=%d, length=%d",
|
||||
decodingBufferIndex,
|
||||
decodingFrameSize,
|
||||
decodingBufferLength]];
|
||||
break;
|
||||
}
|
||||
if (decodingBufferIndex + decodingFrameSize > decodingFrameSize * MAX_FRAMES) {
|
||||
[logging logWarning:[NSString stringWithFormat:@"out of space in the dec_buffer buffer, idx=%d", decodingBufferIndex]];
|
||||
[logging logWarning:[NSString stringWithFormat:@"out of space in the dec_buffer buffer, idx=%d",
|
||||
decodingBufferIndex]];
|
||||
break;
|
||||
}
|
||||
if (dbits == NULL) {
|
||||
|
@ -116,7 +124,6 @@
|
|||
}
|
||||
|
||||
- (void)initiateEncoderAndDecoder {
|
||||
|
||||
encodingState = speex_encoder_init(&speex_nb_mode);
|
||||
decodingState = speex_decoder_init(&speex_nb_mode);
|
||||
|
||||
|
|
|
@ -24,11 +24,16 @@
|
|||
**/
|
||||
|
||||
@interface AudioProcessor : NSObject {
|
||||
@private StretchFactorController* stretchFactorController;
|
||||
@private AudioStretcher* audioStretcher;
|
||||
@private AudioPacker* audioPacker;
|
||||
@private JitterQueue* jitterQueue;
|
||||
@private bool haveReceivedDataYet;
|
||||
@private
|
||||
StretchFactorController *stretchFactorController;
|
||||
@private
|
||||
AudioStretcher *audioStretcher;
|
||||
@private
|
||||
AudioPacker *audioPacker;
|
||||
@private
|
||||
JitterQueue *jitterQueue;
|
||||
@private
|
||||
bool haveReceivedDataYet;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) SpeexCodec *codec;
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
AudioProcessor *newAudioProcessorInstance = [AudioProcessor new];
|
||||
newAudioProcessorInstance->codec = [SpeexCodec speexCodec];
|
||||
newAudioProcessorInstance->stretchFactorController = [StretchFactorController stretchFactorControllerForJitterQueue:jitterQueue];
|
||||
newAudioProcessorInstance->stretchFactorController =
|
||||
[StretchFactorController stretchFactorControllerForJitterQueue:jitterQueue];
|
||||
newAudioProcessorInstance->audioStretcher = [AudioStretcher audioStretcher];
|
||||
newAudioProcessorInstance->jitterQueue = jitterQueue;
|
||||
newAudioProcessorInstance->audioPacker = [AudioPacker audioPacker];
|
||||
|
@ -20,7 +21,7 @@
|
|||
[jitterQueue tryEnqueue:packet];
|
||||
}
|
||||
- (NSArray *)encodeAudioPacketsFromBuffer:(CyclicalBuffer *)buffer {
|
||||
require(buffer != nil);
|
||||
ows_require(buffer != nil);
|
||||
|
||||
NSMutableArray *encodedFrames = [NSMutableArray array];
|
||||
NSUInteger decodedFrameSize = [codec decodedFrameSizeInBytes];
|
||||
|
@ -35,14 +36,16 @@
|
|||
for (EncodedAudioFrame *frame in encodedFrames) {
|
||||
[audioPacker packFrame:frame];
|
||||
EncodedAudioPacket *packet = [audioPacker tryGetFinishedAudioPacket];
|
||||
if (packet != nil) [encodedPackets addObject:packet];
|
||||
if (packet != nil)
|
||||
[encodedPackets addObject:packet];
|
||||
}
|
||||
|
||||
return encodedPackets;
|
||||
}
|
||||
- (EncodedAudioFrame *)pullFrame {
|
||||
EncodedAudioFrame *frame = [audioPacker tryGetReceivedFrame];
|
||||
if (frame != nil) return frame;
|
||||
if (frame != nil)
|
||||
return frame;
|
||||
|
||||
EncodedAudioPacket *potentiallyMissingPacket = [jitterQueue tryDequeue];
|
||||
[audioPacker unpackPotentiallyMissingAudioPacket:potentiallyMissingPacket];
|
||||
|
@ -51,7 +54,8 @@
|
|||
- (NSData *)tryDecodeOrInferFrame {
|
||||
EncodedAudioFrame *frame = [self pullFrame];
|
||||
haveReceivedDataYet |= !frame.isMissingAudioData;
|
||||
if (!haveReceivedDataYet) return nil;
|
||||
if (!haveReceivedDataYet)
|
||||
return nil;
|
||||
|
||||
NSData *raw = [codec decode:frame.tryGetAudioData];
|
||||
double stretch = [stretchFactorController getAndUpdateDesiredStretchFactor];
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
**/
|
||||
|
||||
@interface AudioStretcher : NSObject {
|
||||
@private struct time_scale_state_s timeScaleState;
|
||||
@private
|
||||
struct time_scale_state_s timeScaleState;
|
||||
}
|
||||
|
||||
+ (AudioStretcher *)audioStretcher;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "AudioStretcher.h"
|
||||
#import "Constraints.h"
|
||||
#import "time_scale.h"
|
||||
#import "Util.h"
|
||||
#import "time_scale.h"
|
||||
|
||||
#define MIN_STRETCH_FACTOR 0.1
|
||||
#define MAX_STRETCH_FACTOR 10
|
||||
|
@ -15,10 +15,11 @@
|
|||
}
|
||||
|
||||
- (NSData *)stretchAudioData:(NSData *)audioData stretchFactor:(double)stretchFactor {
|
||||
require(stretchFactor > MIN_STRETCH_FACTOR);
|
||||
require(stretchFactor < MAX_STRETCH_FACTOR);
|
||||
ows_require(stretchFactor > MIN_STRETCH_FACTOR);
|
||||
ows_require(stretchFactor < MAX_STRETCH_FACTOR);
|
||||
|
||||
if (audioData == nil) return nil;
|
||||
if (audioData == nil)
|
||||
return nil;
|
||||
|
||||
checkOperationDescribe(time_scale_rate(&timeScaleState, (float)stretchFactor) == 0, @"Changing time scaling");
|
||||
|
||||
|
@ -35,12 +36,14 @@
|
|||
}
|
||||
|
||||
- (int)getSafeMaxOutputSampleCountFromInputSampleCount:(int)inputSampleCount {
|
||||
// WARNING: In some cases SpanDSP (time_scale.h v 1.20) underestimates how much buffer it will need, so we must pad the result to be safe.
|
||||
// WARNING: In some cases SpanDSP (time_scale.h v 1.20) underestimates how much buffer it will need, so we must pad
|
||||
// the result to be safe.
|
||||
// Issues has been notified upstream and once it is patched the padding can be removed
|
||||
int unsafe_maxOutputSampleCount = time_scale_max_output_len(&timeScaleState, inputSampleCount);
|
||||
const int BUFFER_OVERFLOW_PROTECTION_PAD = 2048;
|
||||
const int BUFFER_OVERFLOW_PROPORTIONAL_MULTIPLIER = 2;
|
||||
int expandedMaxCountToAvoidBufferOverflows = BUFFER_OVERFLOW_PROTECTION_PAD + (unsafe_maxOutputSampleCount * BUFFER_OVERFLOW_PROPORTIONAL_MULTIPLIER);
|
||||
int expandedMaxCountToAvoidBufferOverflows =
|
||||
BUFFER_OVERFLOW_PROTECTION_PAD + (unsafe_maxOutputSampleCount * BUFFER_OVERFLOW_PROPORTIONAL_MULTIPLIER);
|
||||
|
||||
checkOperation(expandedMaxCountToAvoidBufferOverflows >= 0);
|
||||
return expandedMaxCountToAvoidBufferOverflows;
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
#import "DropoutTracker.h"
|
||||
#import "Environment.h"
|
||||
#import "JitterQueue.h"
|
||||
#import "Terminable.h"
|
||||
#import "SpeexCodec.h"
|
||||
#import "Terminable.h"
|
||||
|
||||
/**
|
||||
*
|
||||
* DesiredBufferDepthController is used to determine how much audio should be kept in reserve, in case of network jitter.
|
||||
* DesiredBufferDepthController is used to determine how much audio should be kept in reserve, in case of network
|
||||
*jitter.
|
||||
*
|
||||
* An instance must be registered to receive notifications from the network jitter queue in order to function correctly.
|
||||
* When packets arrive at a consistent rate without dropping, the desired buffer depth tends to decrease.
|
||||
|
@ -17,9 +18,12 @@
|
|||
**/
|
||||
|
||||
@interface DesiredBufferDepthController : NSObject <Terminable, JitterQueueNotificationReceiver> {
|
||||
@private DropoutTracker* dropoutTracker;
|
||||
@private DecayingSampleEstimator* decayingDesiredBufferDepth;
|
||||
@private id<ValueLogger> desiredDelayLogger;
|
||||
@private
|
||||
DropoutTracker *dropoutTracker;
|
||||
@private
|
||||
DecayingSampleEstimator *decayingDesiredBufferDepth;
|
||||
@private
|
||||
id<ValueLogger> desiredDelayLogger;
|
||||
}
|
||||
|
||||
+ (DesiredBufferDepthController *)desiredBufferDepthControllerForJitterQueue:(JitterQueue *)jitterQueue;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "AudioPacker.h"
|
||||
#import "DesiredBufferDepthController.h"
|
||||
#import "PreferencesUtil.h"
|
||||
#import "Util.h"
|
||||
#import "AudioPacker.h"
|
||||
|
||||
#define MAX_DESIRED_FRAME_DELAY 12
|
||||
#define MIN_DESIRED_FRAME_DELAY 0.5
|
||||
|
@ -12,10 +12,10 @@
|
|||
@implementation DesiredBufferDepthController
|
||||
|
||||
+ (DesiredBufferDepthController *)desiredBufferDepthControllerForJitterQueue:(JitterQueue *)jitterQueue {
|
||||
require(jitterQueue != nil);
|
||||
ows_require(jitterQueue != nil);
|
||||
|
||||
NSTimeInterval audioDurationPerPacket = (NSTimeInterval)(AUDIO_FRAMES_PER_PACKET*[SpeexCodec frameSizeInSamples])
|
||||
/ SAMPLE_RATE;
|
||||
NSTimeInterval audioDurationPerPacket =
|
||||
(NSTimeInterval)(AUDIO_FRAMES_PER_PACKET * [SpeexCodec frameSizeInSamples]) / SAMPLE_RATE;
|
||||
double initialDesiredBufferDepth = Environment.preferences.getCachedOrDefaultDesiredBufferDepth;
|
||||
|
||||
DropoutTracker *dropoutTracker = [DropoutTracker dropoutTrackerWithAudioDurationPerPacket:audioDurationPerPacket];
|
||||
|
@ -54,7 +54,9 @@
|
|||
}
|
||||
- (void)notifyResyncFrom:(uint16_t)oldReadHeadSequenceNumber to:(uint16_t)newReadHeadSequenceNumber {
|
||||
}
|
||||
-(void) notifyDiscardOverflow:(uint16_t)sequenceNumber resyncingFrom:(uint16_t)oldReadHeadSequenceNumber to:(uint16_t)newReadHeadSequenceNumber {
|
||||
- (void)notifyDiscardOverflow:(uint16_t)sequenceNumber
|
||||
resyncingFrom:(uint16_t)oldReadHeadSequenceNumber
|
||||
to:(uint16_t)newReadHeadSequenceNumber {
|
||||
}
|
||||
|
||||
- (void)terminate {
|
||||
|
|
|
@ -34,13 +34,20 @@
|
|||
*/
|
||||
|
||||
@interface DropoutTracker : NSObject {
|
||||
@private Queue* priorLatenesses;
|
||||
@private NSMutableArray* lateBins;
|
||||
@private SequenceCounter* sequenceCounter;
|
||||
@private NSTimeInterval audioDurationPerPacket;
|
||||
@private bool startTimeInitialized;
|
||||
@private NSTimeInterval startTime;
|
||||
@private NSTimeInterval drift;
|
||||
@private
|
||||
Queue *priorLatenesses;
|
||||
@private
|
||||
NSMutableArray *lateBins;
|
||||
@private
|
||||
SequenceCounter *sequenceCounter;
|
||||
@private
|
||||
NSTimeInterval audioDurationPerPacket;
|
||||
@private
|
||||
bool startTimeInitialized;
|
||||
@private
|
||||
NSTimeInterval startTime;
|
||||
@private
|
||||
NSTimeInterval drift;
|
||||
}
|
||||
|
||||
+ (DropoutTracker *)dropoutTrackerWithAudioDurationPerPacket:(NSTimeInterval)audioDurationPerPacket;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
@implementation DropoutTracker
|
||||
|
||||
+ (DropoutTracker *)dropoutTrackerWithAudioDurationPerPacket:(NSTimeInterval)audioDurationPerPacket {
|
||||
|
||||
DropoutTracker *d = [DropoutTracker new];
|
||||
|
||||
d->audioDurationPerPacket = audioDurationPerPacket;
|
||||
|
@ -69,7 +68,6 @@
|
|||
[lateBins[lateBin] addEventAtTime:now];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// How many packets would we have needed to buffer to stay below the desired dropout event count
|
||||
|
|
|
@ -1,23 +1,30 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "PriorityQueue.h"
|
||||
#import "EncodedAudioPacket.h"
|
||||
#import "Logging.h"
|
||||
#import "JitterQueueNotificationReceiver.h"
|
||||
#import "BufferDepthMeasure.h"
|
||||
#import "EncodedAudioPacket.h"
|
||||
#import "JitterQueueNotificationReceiver.h"
|
||||
#import "Logging.h"
|
||||
#import "PriorityQueue.h"
|
||||
|
||||
/**
|
||||
*
|
||||
* JitterQueue handles the details of organizing and consuming real-time data, which may fail to arrive on time or arrive out of order.
|
||||
* JitterQueue handles the details of organizing and consuming real-time data, which may fail to arrive on time or
|
||||
*arrive out of order.
|
||||
*
|
||||
**/
|
||||
|
||||
@interface JitterQueue : NSObject <BufferDepthMeasure> {
|
||||
@private PriorityQueue* resultPriorityQueue;
|
||||
@private uint16_t readHeadMin;
|
||||
@private uint16_t readHeadSpan;
|
||||
@private NSMutableSet* idsInJitterQueue;
|
||||
@private NSMutableArray* watchers;
|
||||
@private uint16_t largestLatestEnqueued;
|
||||
@private
|
||||
PriorityQueue *resultPriorityQueue;
|
||||
@private
|
||||
uint16_t readHeadMin;
|
||||
@private
|
||||
uint16_t readHeadSpan;
|
||||
@private
|
||||
NSMutableSet *idsInJitterQueue;
|
||||
@private
|
||||
NSMutableArray *watchers;
|
||||
@private
|
||||
uint16_t largestLatestEnqueued;
|
||||
}
|
||||
|
||||
+ (JitterQueue *)jitterQueue;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import "Environment.h"
|
||||
#import "JitterQueue.h"
|
||||
#import "Util.h"
|
||||
#import "Environment.h"
|
||||
|
||||
#define TRANSITIVE_SAFETY_RANGE 0x4000
|
||||
#define READ_HEAD_MAX_QUEUE_AHEAD 0x1000
|
||||
|
@ -18,7 +18,8 @@
|
|||
}
|
||||
|
||||
- (void)registerWatcher:(id<JitterQueueNotificationReceiver>)watcher {
|
||||
if (watcher == nil) return;
|
||||
if (watcher == nil)
|
||||
return;
|
||||
[watchers addObject:watcher];
|
||||
}
|
||||
|
||||
|
@ -27,7 +28,7 @@
|
|||
}
|
||||
|
||||
- (bool)tryEnqueue:(EncodedAudioPacket *)audioPacket {
|
||||
require(audioPacket != nil);
|
||||
ows_require(audioPacket != nil);
|
||||
|
||||
uint16_t sequenceNumber = [audioPacket sequenceNumber];
|
||||
if (![self tryFitIntoSequence:sequenceNumber]) {
|
||||
|
@ -49,7 +50,8 @@
|
|||
return true;
|
||||
}
|
||||
- (bool)tryFitIntoSequence:(uint16_t)sequenceNumber {
|
||||
int16_t sequenceNumberRelativeToReadHead = [NumberUtil congruentDifferenceMod2ToThe16From:readHeadMin to:sequenceNumber];
|
||||
int16_t sequenceNumberRelativeToReadHead =
|
||||
[NumberUtil congruentDifferenceMod2ToThe16From:readHeadMin to:sequenceNumber];
|
||||
|
||||
enum JitterBadArrivalType badArrivalType;
|
||||
if ([self tryForceSyncIfNecessary:sequenceNumber]) {
|
||||
|
@ -71,7 +73,8 @@
|
|||
return false;
|
||||
}
|
||||
- (bool)tryForceSyncIfNecessary:(uint16_t)sequenceNumber {
|
||||
if (readHeadSpan <= READ_HEAD_BAD_SPAN_THRESHOLD) return false;
|
||||
if (readHeadSpan <= READ_HEAD_BAD_SPAN_THRESHOLD)
|
||||
return false;
|
||||
|
||||
if (resultPriorityQueue != nil) { // (only log resyncs, not the initial sync)
|
||||
for (id<JitterQueueNotificationReceiver> watcher in watchers) {
|
||||
|
@ -88,15 +91,16 @@
|
|||
return true;
|
||||
}
|
||||
+ (PriorityQueue *)makeCyclingPacketPriorityQueue {
|
||||
return [PriorityQueue priorityQueueAscendingWithComparator:^NSComparisonResult(EncodedAudioPacket* obj1, EncodedAudioPacket* obj2) {
|
||||
int16_t d = [NumberUtil congruentDifferenceMod2ToThe16From:[obj2 sequenceNumber]
|
||||
to:[obj1 sequenceNumber]];
|
||||
return [PriorityQueue
|
||||
priorityQueueAscendingWithComparator:^NSComparisonResult(EncodedAudioPacket *obj1, EncodedAudioPacket *obj2) {
|
||||
int16_t d = [NumberUtil congruentDifferenceMod2ToThe16From:[obj2 sequenceNumber] to:[obj1 sequenceNumber]];
|
||||
requireState(abs(d) <= TRANSITIVE_SAFETY_RANGE);
|
||||
return [NumberUtil signOfInt32:d];
|
||||
}];
|
||||
}
|
||||
- (void)discardExcess {
|
||||
if (resultPriorityQueue.count <= MAXIMUM_JITTER_QUEUE_SIZE_BEFORE_DISCARDING) return;
|
||||
if (resultPriorityQueue.count <= MAXIMUM_JITTER_QUEUE_SIZE_BEFORE_DISCARDING)
|
||||
return;
|
||||
|
||||
EncodedAudioPacket *discarded = [resultPriorityQueue dequeue];
|
||||
uint16_t discardedSequenceNumber = [discarded sequenceNumber];
|
||||
|
@ -107,17 +111,13 @@
|
|||
readHeadSpan = 1;
|
||||
|
||||
for (id<JitterQueueNotificationReceiver> e in watchers) {
|
||||
[e notifyDiscardOverflow:discardedSequenceNumber
|
||||
resyncingFrom:oldReadHeadMax
|
||||
to:readHeadMin];
|
||||
[e notifyDiscardOverflow:discardedSequenceNumber resyncingFrom:oldReadHeadMax to:readHeadMin];
|
||||
}
|
||||
}
|
||||
|
||||
- (EncodedAudioPacket *)tryDequeue {
|
||||
if ([self checkReactIfOutOfSyncForDequeue]
|
||||
|| [self checkReactIfEmptyForDequeue]
|
||||
|| [self checkReactIfNoDataUnderReadHeadForDequeue]) {
|
||||
|
||||
if ([self checkReactIfOutOfSyncForDequeue] || [self checkReactIfEmptyForDequeue] ||
|
||||
[self checkReactIfNoDataUnderReadHeadForDequeue]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
@ -152,8 +152,7 @@
|
|||
}
|
||||
- (bool)checkReactIfNoDataUnderReadHeadForDequeue {
|
||||
EncodedAudioPacket *result = resultPriorityQueue.peek;
|
||||
int16_t d = [NumberUtil congruentDifferenceMod2ToThe16From:readHeadMin
|
||||
to:[result sequenceNumber]];
|
||||
int16_t d = [NumberUtil congruentDifferenceMod2ToThe16From:readHeadMin to:[result sequenceNumber]];
|
||||
bool notUnderHead = d < 0 || d >= readHeadSpan;
|
||||
if (notUnderHead) {
|
||||
readHeadSpan += 1;
|
||||
|
@ -165,7 +164,8 @@
|
|||
}
|
||||
|
||||
- (int16_t)currentBufferDepth {
|
||||
if (readHeadSpan > READ_HEAD_BAD_SPAN_THRESHOLD) return 0;
|
||||
if (readHeadSpan > READ_HEAD_BAD_SPAN_THRESHOLD)
|
||||
return 0;
|
||||
return [NumberUtil congruentDifferenceMod2ToThe16From:readHeadMin + readHeadSpan - 1 to:largestLatestEnqueued];
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,16 @@
|
|||
**/
|
||||
|
||||
@interface StretchFactorController : NSObject {
|
||||
@private int currentStretchMode;
|
||||
@private id<BufferDepthMeasure> bufferDepthMeasure;
|
||||
@private DesiredBufferDepthController* desiredBufferDepthController;
|
||||
@private DecayingSampleEstimator* decayingBufferDepthMeasure;
|
||||
@private id<ValueLogger> stretchModeChangeLogger;
|
||||
@private
|
||||
int currentStretchMode;
|
||||
@private
|
||||
id<BufferDepthMeasure> bufferDepthMeasure;
|
||||
@private
|
||||
DesiredBufferDepthController *desiredBufferDepthController;
|
||||
@private
|
||||
DecayingSampleEstimator *decayingBufferDepthMeasure;
|
||||
@private
|
||||
id<ValueLogger> stretchModeChangeLogger;
|
||||
}
|
||||
|
||||
+ (StretchFactorController *)stretchFactorControllerForJitterQueue:(JitterQueue *)jitterQueue;
|
||||
|
|
|
@ -16,8 +16,7 @@ static double STRETCH_MODE_FACTORS[] = {1/0.95, 1, 1/1.05, 0.5};
|
|||
@implementation StretchFactorController
|
||||
|
||||
+ (StretchFactorController *)stretchFactorControllerForJitterQueue:(JitterQueue *)jitterQueue {
|
||||
|
||||
require(jitterQueue != nil);
|
||||
ows_require(jitterQueue != nil);
|
||||
|
||||
DesiredBufferDepthController *desiredBufferDepthController =
|
||||
[DesiredBufferDepthController desiredBufferDepthControllerForJitterQueue:jitterQueue];
|
||||
|
@ -26,7 +25,9 @@ static double STRETCH_MODE_FACTORS[] = {1/0.95, 1, 1/1.05, 0.5};
|
|||
p->desiredBufferDepthController = desiredBufferDepthController;
|
||||
p->currentStretchMode = STRETCH_MODE_NORMAL;
|
||||
p->bufferDepthMeasure = jitterQueue;
|
||||
p->decayingBufferDepthMeasure = [DecayingSampleEstimator decayingSampleEstimatorWithInitialEstimate:0 andDecayPerUnitSample:BUFFER_DEPTH_DECAYING_FACTOR];
|
||||
p->decayingBufferDepthMeasure =
|
||||
[DecayingSampleEstimator decayingSampleEstimatorWithInitialEstimate:0
|
||||
andDecayPerUnitSample:BUFFER_DEPTH_DECAYING_FACTOR];
|
||||
p->stretchModeChangeLogger = [Environment.logging getValueLoggerForValue:@"stretch factor" from:self];
|
||||
return p;
|
||||
}
|
||||
|
@ -41,7 +42,8 @@ static double STRETCH_MODE_FACTORS[] = {1/0.95, 1, 1/1.05, 0.5};
|
|||
|
||||
bool shouldStartSuperShrink = currentBufferDepthDelta > SUPER_SHRINK_THRESHOLD;
|
||||
bool shouldMaintainSuperShrink = currentBufferDepthDelta > 0 && currentStretchMode == STRETCH_MODE_SUPER_SHRINK;
|
||||
bool shouldEndSuperShrinkAndResetEstimate = !shouldMaintainSuperShrink && currentStretchMode == STRETCH_MODE_SUPER_SHRINK;
|
||||
bool shouldEndSuperShrinkAndResetEstimate =
|
||||
!shouldMaintainSuperShrink && currentStretchMode == STRETCH_MODE_SUPER_SHRINK;
|
||||
|
||||
bool shouldStartShrink = decayingBufferDepthDelta > SHRINK_THRESHOLD;
|
||||
bool shouldMaintainShrink = decayingBufferDepthDelta > 0 && currentStretchMode == STRETCH_MODE_SHRINK;
|
||||
|
@ -53,10 +55,14 @@ static double STRETCH_MODE_FACTORS[] = {1/0.95, 1, 1/1.05, 0.5};
|
|||
[decayingBufferDepthMeasure forceEstimateTo:desiredBufferDepth];
|
||||
return STRETCH_MODE_NORMAL;
|
||||
}
|
||||
if (shouldStartSuperShrink) return STRETCH_MODE_SUPER_SHRINK;
|
||||
if (shouldStartShrink) return STRETCH_MODE_SHRINK;
|
||||
if (shouldStartExpand) return STRETCH_MODE_EXPAND;
|
||||
if (shouldMaintainShrink || shouldMaintainExpand || shouldMaintainSuperShrink) return currentStretchMode;
|
||||
if (shouldStartSuperShrink)
|
||||
return STRETCH_MODE_SUPER_SHRINK;
|
||||
if (shouldStartShrink)
|
||||
return STRETCH_MODE_SHRINK;
|
||||
if (shouldStartExpand)
|
||||
return STRETCH_MODE_EXPAND;
|
||||
if (shouldMaintainShrink || shouldMaintainExpand || shouldMaintainSuperShrink)
|
||||
return currentStretchMode;
|
||||
return STRETCH_MODE_NORMAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ enum JitterBadArrivalType {
|
|||
enum JitterBadDequeueType {
|
||||
JitterBadDequeueType_Desynced = 0, // for when so many lack-of-datas have accumulated that the read head can skip
|
||||
JitterBadDequeueType_Empty = 1, // for when there's no data anywhere in the jitter queue
|
||||
JitterBadDequeueType_NoDataUnderReadHead = 2 // for when there's data in the jitter queue, but it's ahead of the read head
|
||||
JitterBadDequeueType_NoDataUnderReadHead =
|
||||
2 // for when there's data in the jitter queue, but it's ahead of the read head
|
||||
};
|
||||
@protocol JitterQueueNotificationReceiver <NSObject>
|
||||
- (void)notifyArrival:(uint16_t)sequenceNumber;
|
||||
|
@ -16,5 +17,7 @@ enum JitterBadDequeueType {
|
|||
- (void)notifyBadArrival:(uint16_t)sequenceNumber ofType:(enum JitterBadArrivalType)arrivalType;
|
||||
- (void)notifyBadDequeueOfType:(enum JitterBadDequeueType)type;
|
||||
- (void)notifyResyncFrom:(uint16_t)oldReadHeadSequenceNumber to:(uint16_t)newReadHeadSequenceNumber;
|
||||
-(void) notifyDiscardOverflow:(uint16_t)discardedSequenceNumber resyncingFrom:(uint16_t)oldReadHeadSequenceNumber to:(uint16_t)newReadHeadSequenceNumber;
|
||||
- (void)notifyDiscardOverflow:(uint16_t)discardedSequenceNumber
|
||||
resyncingFrom:(uint16_t)oldReadHeadSequenceNumber
|
||||
to:(uint16_t)newReadHeadSequenceNumber;
|
||||
@end
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
@interface AnonymousAudioCallbackHandler : NSObject <AudioCallbackHandler>
|
||||
|
||||
@property (readonly, nonatomic, copy) void (^handleNewDataRecordedBlock)(CyclicalBuffer *data);
|
||||
@property (readonly,nonatomic,copy) void (^handlePlaybackOccurredWithBytesRequestedBlock)(NSUInteger requested, NSUInteger bytesRemaining);
|
||||
@property (readonly, nonatomic, copy) void (^handlePlaybackOccurredWithBytesRequestedBlock)
|
||||
(NSUInteger requested, NSUInteger bytesRemaining);
|
||||
|
||||
+(AnonymousAudioCallbackHandler*) anonymousAudioInterfaceDelegateWithRecordingCallback:(void(^)(CyclicalBuffer* data))recordingCallback
|
||||
andPlaybackOccurredCallback:(void(^)(NSUInteger requested, NSUInteger bytesRemaining))playbackCallback;
|
||||
+ (AnonymousAudioCallbackHandler *)
|
||||
anonymousAudioInterfaceDelegateWithRecordingCallback:(void (^)(CyclicalBuffer *data))recordingCallback
|
||||
andPlaybackOccurredCallback:
|
||||
(void (^)(NSUInteger requested, NSUInteger bytesRemaining))playbackCallback;
|
||||
|
||||
@end
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
@implementation AnonymousAudioCallbackHandler
|
||||
|
||||
+(AnonymousAudioCallbackHandler*) anonymousAudioInterfaceDelegateWithRecordingCallback:(void(^)(CyclicalBuffer* data))recordingCallback
|
||||
andPlaybackOccurredCallback:(void(^)(NSUInteger requested, NSUInteger bytesRemaining))playbackCallback {
|
||||
+ (AnonymousAudioCallbackHandler *)
|
||||
anonymousAudioInterfaceDelegateWithRecordingCallback:(void (^)(CyclicalBuffer *data))recordingCallback
|
||||
andPlaybackOccurredCallback:
|
||||
(void (^)(NSUInteger requested, NSUInteger bytesRemaining))playbackCallback {
|
||||
AnonymousAudioCallbackHandler *a = [AnonymousAudioCallbackHandler new];
|
||||
a->_handleNewDataRecordedBlock = recordingCallback;
|
||||
a->_handlePlaybackOccurredWithBytesRequestedBlock = playbackCallback;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <AddressBook/AddressBook.h>
|
||||
#import "PhoneNumber.h"
|
||||
#import "ContactsManager.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <TextSecureKit/TSCall.h>
|
||||
#import "Contact.h"
|
||||
#import "ContactsManager.h"
|
||||
#import "PhoneNumber.h"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -12,11 +13,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
RPRecentCallTypeIncoming = 1,
|
||||
RPRecentCallTypeOutgoing,
|
||||
RPRecentCallTypeMissed,
|
||||
} RPRecentCallType;
|
||||
|
||||
extern NSString *const CALL_TYPE_IMAGE_NAME_INCOMING;
|
||||
extern NSString *const CALL_TYPE_IMAGE_NAME_OUTGOING;
|
||||
|
|
|
@ -17,7 +17,6 @@ NSString *const CALL_TYPE_IMAGE_NAME_OUTGOING = @"outgoing_call_icon";
|
|||
+ (RecentCall *)recentCallWithContactID:(ABRecordID)contactID
|
||||
andNumber:(PhoneNumber *)number
|
||||
andCallType:(RPRecentCallType)type {
|
||||
|
||||
RecentCall *recentCall = [RecentCall new];
|
||||
recentCall->contactRecordID = contactID;
|
||||
recentCall->callType = type;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "RecentCall.h"
|
||||
#import "PhoneManager.h"
|
||||
#import "RecentCall.h"
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -12,8 +12,7 @@
|
|||
|
||||
@interface RecentCallManager : NSObject
|
||||
|
||||
- (void)watchForCallsThrough:(PhoneManager*)phoneManager
|
||||
untilCancelled:(TOCCancelToken*)untilCancelledToken;
|
||||
- (void)watchForCallsThrough:(PhoneManager *)phoneManager untilCancelled:(TOCCancelToken *)untilCancelledToken;
|
||||
|
||||
- (void)addRecentCall:(RecentCall *)recentCall;
|
||||
- (void)addMissedCallDueToBusy:(ResponderSessionDescriptor *)incomingCallDescriptor;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#import <TextSecureKit/TextSecureKitEnv.h>
|
||||
#import "NotificationsManager.h"
|
||||
#import "RecentCallManager.h"
|
||||
#import "TSCall.h"
|
||||
#import "TSMessagesManager.h"
|
||||
|
@ -19,19 +21,20 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)watchForCallsThrough:(PhoneManager*)phoneManager
|
||||
untilCancelled:(TOCCancelToken*)untilCancelledToken {
|
||||
require(phoneManager != nil);
|
||||
- (void)watchForCallsThrough:(PhoneManager *)phoneManager untilCancelled:(TOCCancelToken *)untilCancelledToken {
|
||||
ows_require(phoneManager != nil);
|
||||
|
||||
[phoneManager.currentCallObservable watchLatestValue:^(CallState *latestCall) {
|
||||
if (latestCall != nil) {
|
||||
[self addCall:latestCall];
|
||||
}
|
||||
} onThread:NSThread.currentThread untilCancelled:untilCancelledToken];
|
||||
}
|
||||
onThread:NSThread.currentThread
|
||||
untilCancelled:untilCancelledToken];
|
||||
}
|
||||
|
||||
- (void)addCall:(CallState *)call {
|
||||
require(call != nil);
|
||||
ows_require(call != nil);
|
||||
|
||||
[call.futureTermination finallyDo:^(TOCFuture *interactionCompletion) {
|
||||
bool isOutgoingCall = call.initiatedLocally;
|
||||
|
@ -39,9 +42,8 @@
|
|||
|
||||
Contact *contact = [self tryGetContactForCall:call];
|
||||
|
||||
RPRecentCallType callType = isOutgoingCall ? RPRecentCallTypeOutgoing
|
||||
: isMissedCall ? RPRecentCallTypeMissed
|
||||
: RPRecentCallTypeIncoming;
|
||||
RPRecentCallType callType =
|
||||
isOutgoingCall ? RPRecentCallTypeOutgoing : isMissedCall ? RPRecentCallTypeMissed : RPRecentCallTypeIncoming;
|
||||
|
||||
[self addRecentCall:[RecentCall recentCallWithContactID:contact.recordID
|
||||
andNumber:call.remoteNumber
|
||||
|
@ -62,7 +64,8 @@
|
|||
}
|
||||
|
||||
- (Contact *)tryGetContactForCall:(CallState *)call {
|
||||
if (call.potentiallySpecifiedContact != nil) return call.potentiallySpecifiedContact;
|
||||
if (call.potentiallySpecifiedContact != nil)
|
||||
return call.potentiallySpecifiedContact;
|
||||
return [self tryGetContactForNumber:call.remoteNumber];
|
||||
}
|
||||
|
||||
|
@ -71,7 +74,7 @@
|
|||
}
|
||||
|
||||
- (void)addMissedCallDueToBusy:(ResponderSessionDescriptor *)incomingCallDescriptor {
|
||||
require(incomingCallDescriptor != nil);
|
||||
ows_require(incomingCallDescriptor != nil);
|
||||
|
||||
Contact *contact = [self tryGetContactForNumber:incomingCallDescriptor.initiatorNumber];
|
||||
[self addRecentCall:[RecentCall recentCallWithContactID:contact.recordID
|
||||
|
@ -81,18 +84,25 @@
|
|||
|
||||
- (void)addRecentCall:(RecentCall *)recentCall {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recentCall.phoneNumber.toE164 transaction:transaction];
|
||||
TSContactThread *thread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:recentCall.phoneNumber.toE164 transaction:transaction];
|
||||
|
||||
uint64_t callDateSeconds = (uint64_t)[recentCall.date timeIntervalSince1970];
|
||||
TSCall *call = [[TSCall alloc] initWithTimestamp:callDateSeconds*1000 withCallNumber:recentCall.phoneNumber.toE164 callType:recentCall.callType inThread:thread];
|
||||
TSCall *call = [[TSCall alloc] initWithTimestamp:callDateSeconds * 1000
|
||||
withCallNumber:recentCall.phoneNumber.toE164
|
||||
callType:recentCall.callType
|
||||
inThread:thread];
|
||||
if (recentCall.isArchived) { // for migration only from Signal versions with RedPhone only
|
||||
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(callDateSeconds+60)]; // archive has to happen in the future of the original call
|
||||
NSDate *date =
|
||||
[NSDate dateWithTimeIntervalSince1970:(callDateSeconds +
|
||||
60)]; // archive has to happen in the future of the original call
|
||||
[thread archiveThreadWithTransaction:transaction referenceDate:date];
|
||||
}
|
||||
|
||||
[call saveWithTransaction:transaction];
|
||||
|
||||
[[TSMessagesManager sharedManager] notifyUserForCall:call inThread:thread];
|
||||
NotificationsManager *manager = [TextSecureKitEnv sharedEnv].notificationsManager;
|
||||
[manager notifyUserForCall:call inThread:thread];
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import <AddressBook/AddressBook.h>
|
||||
#import "PhoneNumber.h"
|
||||
|
||||
/**
|
||||
*
|
||||
* Contact represents relevant information related to a contact from the user's contact list.
|
||||
*
|
||||
*/
|
||||
|
||||
@interface Contact : NSObject
|
||||
|
||||
@property (readonly,nonatomic) NSString *firstName;
|
||||
@property (readonly,nonatomic) NSString *lastName;
|
||||
@property (readonly,nonatomic) NSArray *parsedPhoneNumbers;
|
||||
@property (readonly,nonatomic) NSArray *userTextPhoneNumbers;
|
||||
@property (readonly,nonatomic) NSArray *emails;
|
||||
@property (readonly,nonatomic) UIImage *image;
|
||||
@property (readonly,nonatomic) NSString *notes;
|
||||
@property (readonly,nonatomic) ABRecordID recordID;
|
||||
|
||||
+ (Contact*)contactWithFirstName:(NSString*)firstName
|
||||
andLastName:(NSString *)lastName
|
||||
andUserTextPhoneNumbers:(NSArray*)phoneNumbers
|
||||
andEmails:(NSArray*)emails
|
||||
andContactID:(ABRecordID)record;
|
||||
|
||||
+ (Contact*)contactWithFirstName:(NSString*)firstName
|
||||
andLastName:(NSString *)lastName
|
||||
andUserTextPhoneNumbers:(NSArray*)numbers
|
||||
andEmails:(NSArray*)emails
|
||||
andImage:(UIImage *)image
|
||||
andContactID:(ABRecordID)record
|
||||
andNotes:(NSString *)notes;
|
||||
|
||||
- (NSString*)fullName;
|
||||
- (NSString *)allPhoneNumbers;
|
||||
|
||||
- (BOOL)isTextSecureContact;
|
||||
- (BOOL)isRedPhoneContact;
|
||||
|
||||
- (NSArray*)textSecureIdentifiers;
|
||||
- (NSArray*)redPhoneIdentifiers;
|
||||
|
||||
@end
|
|
@ -1,134 +0,0 @@
|
|||
#import "Contact.h"
|
||||
#import "ContactsManager.h"
|
||||
#import "Environment.h"
|
||||
#import "SignalRecipient.h"
|
||||
|
||||
static NSString *const DEFAULTS_KEY_CONTACT = @"DefaultsKeyContact";
|
||||
static NSString *const DEFAULTS_KEY_PHONE_NUMBER = @"DefaultsKeyPhoneNumber";
|
||||
static NSString *const DEFAULTS_KEY_CALL_TYPE = @"DefaultsKeycallType";
|
||||
static NSString *const DEFAULTS_KEY_DATE = @"DefaultsKeyDate";
|
||||
|
||||
@implementation Contact
|
||||
|
||||
@synthesize firstName, lastName, emails, image, recordID, notes, parsedPhoneNumbers, userTextPhoneNumbers;
|
||||
|
||||
+ (Contact*)contactWithFirstName:(NSString*)firstName
|
||||
andLastName:(NSString *)lastName
|
||||
andUserTextPhoneNumbers:(NSArray*)phoneNumbers
|
||||
andEmails:(NSArray*)emails
|
||||
andContactID:(ABRecordID)record {
|
||||
|
||||
Contact* contact = [Contact new];
|
||||
contact->firstName = firstName;
|
||||
contact->lastName = lastName;
|
||||
contact->userTextPhoneNumbers = phoneNumbers;
|
||||
contact->emails = emails;
|
||||
contact->recordID = record;
|
||||
|
||||
NSMutableArray *parsedPhoneNumbers = [NSMutableArray array];
|
||||
|
||||
for (NSString *phoneNumberString in phoneNumbers) {
|
||||
PhoneNumber *phoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumberString];
|
||||
if (phoneNumber) {
|
||||
[parsedPhoneNumbers addObject:phoneNumber];
|
||||
}
|
||||
}
|
||||
|
||||
contact->parsedPhoneNumbers = parsedPhoneNumbers.copy;
|
||||
|
||||
return contact;
|
||||
}
|
||||
|
||||
+ (Contact*)contactWithFirstName:(NSString*)firstName
|
||||
andLastName:(NSString *)lastName
|
||||
andUserTextPhoneNumbers:(NSArray*)numbers
|
||||
andEmails:(NSArray*)emails
|
||||
andImage:(UIImage *)image
|
||||
andContactID:(ABRecordID)record
|
||||
andNotes:(NSString *)notes {
|
||||
|
||||
Contact* contact = [Contact contactWithFirstName:firstName
|
||||
andLastName:lastName
|
||||
andUserTextPhoneNumbers:numbers
|
||||
andEmails:emails
|
||||
andContactID:record];
|
||||
|
||||
contact->image = image;
|
||||
contact->notes = notes;
|
||||
return contact;
|
||||
}
|
||||
|
||||
- (NSString *)fullName {
|
||||
NSMutableString *fullName = [NSMutableString string];
|
||||
if (firstName) [fullName appendString:firstName];
|
||||
if (lastName) {
|
||||
[fullName appendString:[NSString stringWithFormat:@" %@",lastName]];
|
||||
}
|
||||
return fullName;
|
||||
}
|
||||
|
||||
- (NSString *)allPhoneNumbers {
|
||||
NSString * allNumbers = @"";
|
||||
for (PhoneNumber *number in self.parsedPhoneNumbers) {
|
||||
allNumbers = [allNumbers stringByAppendingString:number.toE164];
|
||||
allNumbers = [allNumbers stringByAppendingString:@";"];
|
||||
}
|
||||
return allNumbers;
|
||||
}
|
||||
|
||||
-(NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@ %@: %@", firstName, lastName, userTextPhoneNumbers];
|
||||
}
|
||||
|
||||
- (UIImage *)image {
|
||||
return image;
|
||||
}
|
||||
|
||||
- (BOOL)isTextSecureContact{
|
||||
NSArray *identifiers = [self textSecureIdentifiers];
|
||||
|
||||
if ([identifiers count] > 0) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray*)textSecureIdentifiers{
|
||||
__block NSMutableArray *identifiers = [NSMutableArray array];
|
||||
|
||||
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (PhoneNumber *number in self.parsedPhoneNumbers) {
|
||||
if ([SignalRecipient recipientWithTextSecureIdentifier:number.toE164 withTransaction:transaction]) {
|
||||
[identifiers addObject:number.toE164];
|
||||
}
|
||||
}
|
||||
}];
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
- (BOOL)isRedPhoneContact{
|
||||
NSArray *identifiers = [self redPhoneIdentifiers];
|
||||
|
||||
if ([identifiers count] > 0) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray *)redPhoneIdentifiers{
|
||||
__block NSMutableArray *identifiers = [NSMutableArray array];
|
||||
|
||||
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (PhoneNumber *number in self.parsedPhoneNumbers) {
|
||||
SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:number.toE164 withTransaction:transaction];
|
||||
if (recipient && recipient.supportsVoice) {
|
||||
[identifiers addObject:number.toE164];
|
||||
}
|
||||
}
|
||||
}];
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// ContactsManager+updater.h
|
||||
// Signal
|
||||
//
|
||||
// Created by Frederic Jacobs on 21/11/15.
|
||||
// Copyright © 2015 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SignalRecipient.h"
|
||||
#import "ContactsManager.h"
|
||||
|
||||
@interface ContactsManager (updater)
|
||||
|
||||
#define NOTFOUND_ERROR 777404
|
||||
|
||||
- (void)intersectContacts;
|
||||
- (void)synchronousLookup:(NSString*)identifier
|
||||
success:(void (^)(SignalRecipient*))success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
|
||||
- (void)lookupIdentifier:(NSString*)identifier
|
||||
success:(void (^)(NSSet<NSString*> *matchedIds))success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
|
||||
- (void)updateSignalContactIntersectionWithSuccess:(void (^)())success
|
||||
failure:(void (^)(NSError *error))failure;
|
||||
@end
|
|
@ -1,184 +0,0 @@
|
|||
//
|
||||
// ContactsManager+updater.m
|
||||
// Signal
|
||||
//
|
||||
// Created by Frederic Jacobs on 21/11/15.
|
||||
// Copyright © 2015 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ContactsManager+updater.h"
|
||||
|
||||
#import "Cryptography.h"
|
||||
#import "Environment.h"
|
||||
#import "TSContactsIntersectionRequest.h"
|
||||
#import "TSNetworkManager.h"
|
||||
|
||||
@implementation ContactsManager (updater)
|
||||
|
||||
- (void)synchronousLookup:(NSString*)identifier
|
||||
success:(void (^)(SignalRecipient*))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
__block dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
__block SignalRecipient *recipient = nil;
|
||||
__block NSError *error = nil;
|
||||
|
||||
[self lookupIdentifier:identifier
|
||||
success:^(NSSet<NSString *> *matchedIds) {
|
||||
if ([matchedIds count] == 1) {
|
||||
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
recipient = [SignalRecipient recipientWithTextSecureIdentifier:identifier withTransaction:transaction];
|
||||
}];
|
||||
} else {
|
||||
error = [NSError errorWithDomain:@"contactsmanager.notfound" code:NOTFOUND_ERROR userInfo:nil];
|
||||
}
|
||||
dispatch_semaphore_signal(sema);
|
||||
} failure:^(NSError *blockerror) {
|
||||
error = blockerror;
|
||||
dispatch_semaphore_signal(sema);
|
||||
}];
|
||||
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
if (error) {
|
||||
SYNC_BLOCK_SAFE_RUN(failure, error);
|
||||
} else {
|
||||
SYNC_BLOCK_SAFE_RUN(success, recipient);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)lookupIdentifier:(NSString*)identifier
|
||||
success:(void (^)(NSSet<NSString*> *matchedIds))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
[self contactIntersectionWithSet:[NSSet setWithObject:identifier]
|
||||
success:^(NSSet<NSString *> *matchedIds){
|
||||
BLOCK_SAFE_RUN(success, matchedIds);
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
BLOCK_SAFE_RUN(failure, error);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)intersectContacts {
|
||||
[self updateSignalContactIntersectionWithSuccess:nil failure:^(NSError *error) {
|
||||
[NSTimer scheduledTimerWithTimeInterval:60
|
||||
target:self
|
||||
selector:@selector(intersectContacts)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)updateSignalContactIntersectionWithSuccess:(void (^)())success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
NSArray<Contact*> *abContacts = [[[Environment getCurrent] contactsManager] allContacts];
|
||||
NSMutableSet<NSString*> *abPhoneNumbers = [NSMutableSet set];
|
||||
|
||||
for (Contact *contact in abContacts) {
|
||||
for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) {
|
||||
[abPhoneNumbers addObject:phoneNumber.toE164];
|
||||
}
|
||||
}
|
||||
|
||||
__block NSMutableSet *recipientIds = [NSMutableSet set];
|
||||
[[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction * _Nonnull transaction) {
|
||||
NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
|
||||
[recipientIds addObjectsFromArray:allRecipientKeys];
|
||||
}];
|
||||
|
||||
NSMutableSet<NSString*> *allContacts = [[abPhoneNumbers setByAddingObjectsFromSet:recipientIds] mutableCopy];
|
||||
|
||||
[self contactIntersectionWithSet:allContacts
|
||||
success:^(NSSet<NSString *> *matchedIds) {
|
||||
[recipientIds minusSet:matchedIds];
|
||||
|
||||
// Cleaning up unregistered identifiers
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
|
||||
for (NSString *identifier in recipientIds) {
|
||||
SignalRecipient *recipient = [SignalRecipient fetchObjectWithUniqueID:identifier transaction:transaction];
|
||||
[recipient removeWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
BLOCK_SAFE_RUN(success);
|
||||
} failure:^(NSError *error) {
|
||||
BLOCK_SAFE_RUN(failure, error);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) contactIntersectionWithSet:(NSSet<NSString*>*)idSet
|
||||
success:(void (^)(NSSet<NSString*> *matchedIds))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSMutableDictionary *phoneNumbersByHashes = [NSMutableDictionary dictionary];
|
||||
for (NSString *identifier in idSet) {
|
||||
[phoneNumbersByHashes setObject:identifier
|
||||
forKey:[Cryptography truncatedSHA1Base64EncodedWithoutPadding:identifier]];
|
||||
}
|
||||
NSArray *hashes = [phoneNumbersByHashes allKeys];
|
||||
|
||||
TSRequest *request = [[TSContactsIntersectionRequest alloc] initWithHashesArray:hashes];
|
||||
[[TSNetworkManager sharedManager] queueAuthenticatedRequest:request success:^(NSURLSessionDataTask *tsTask, id responseDict) {
|
||||
NSMutableDictionary *attributesForIdentifier = [NSMutableDictionary dictionary];
|
||||
NSArray *contactsArray = [(NSDictionary*)responseDict objectForKey:@"contacts"];
|
||||
|
||||
// Map attributes to phone numbers
|
||||
if (contactsArray) {
|
||||
for (NSDictionary *dict in contactsArray) {
|
||||
NSString *hash = [dict objectForKey:@"token"];
|
||||
NSString *identifier = [phoneNumbersByHashes objectForKey:hash];
|
||||
|
||||
if (!identifier) {
|
||||
DDLogWarn(@"An interesecting hash wasn't found in the mapping.");
|
||||
break;
|
||||
}
|
||||
|
||||
[attributesForIdentifier setObject:dict forKey:identifier];
|
||||
}
|
||||
}
|
||||
|
||||
// Insert or update contact attributes
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *identifier in attributesForIdentifier) {
|
||||
SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:identifier
|
||||
withTransaction:transaction];
|
||||
if (!recipient) {
|
||||
recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:identifier
|
||||
relay:nil
|
||||
supportsVoice:NO];
|
||||
}
|
||||
|
||||
NSDictionary *attributes = [attributesForIdentifier objectForKey:identifier];
|
||||
|
||||
NSString *relay = [attributes objectForKey:@"relay"];
|
||||
if (relay) {
|
||||
recipient.relay = relay;
|
||||
} else {
|
||||
recipient.relay = nil;
|
||||
}
|
||||
|
||||
BOOL supportsVoice = [[attributes objectForKey:@"voice"] boolValue];
|
||||
if (supportsVoice) {
|
||||
recipient.supportsVoice = YES;
|
||||
} else {
|
||||
recipient.supportsVoice = NO;
|
||||
}
|
||||
|
||||
[recipient saveWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
BLOCK_SAFE_RUN(success, [NSSet setWithArray:attributesForIdentifier.allKeys]);
|
||||
} failure:^(NSURLSessionDataTask *task, NSError *error) {
|
||||
BLOCK_SAFE_RUN(failure, error);
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,8 +1,10 @@
|
|||
#import <Contacts/Contacts.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <TextSecureKit/ContactsManagerProtocol.h>
|
||||
#import <TextSecureKit/PhoneNumber.h>
|
||||
#import "CollapsingFutures.h"
|
||||
#import "Contact.h"
|
||||
#import "ObservableValue.h"
|
||||
#import <Contacts/Contacts.h>
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -19,19 +21,22 @@
|
|||
typedef void (^ABAccessRequestCompletionBlock)(BOOL hasAccess);
|
||||
typedef void (^ABReloadRequestCompletionBlock)(NSArray *contacts);
|
||||
|
||||
@interface ContactsManager : NSObject {
|
||||
@private TOCFuture* futureAddressBook;
|
||||
@private ObservableValueController* observableContactsController;
|
||||
@private ObservableValueController* observableTextSecureUsersController;
|
||||
@private TOCCancelTokenSource* life;
|
||||
@private NSDictionary *latestContactsById;
|
||||
@private NSDictionary *latestWhisperUsersById;
|
||||
@interface ContactsManager : NSObject <ContactsManagerProtocol> {
|
||||
@private
|
||||
TOCFuture *futureAddressBook;
|
||||
@private
|
||||
ObservableValueController *observableContactsController;
|
||||
@private
|
||||
TOCCancelTokenSource *life;
|
||||
@private
|
||||
NSDictionary *latestContactsById;
|
||||
@private
|
||||
NSDictionary *latestWhisperUsersById;
|
||||
}
|
||||
|
||||
@property CNContactStore *contactStore;
|
||||
|
||||
- (ObservableValue *)getObservableContacts;
|
||||
//-(ObservableValue *) getObservableRedPhoneUsers;
|
||||
|
||||
- (NSArray *)getContactsFromAddressBook:(ABAddressBookRef)addressBook;
|
||||
- (Contact *)latestContactWithRecordId:(ABRecordID)recordId;
|
||||
|
@ -40,9 +45,6 @@ typedef void(^ABReloadRequestCompletionBlock)(NSArray *contacts);
|
|||
|
||||
+ (NSDictionary *)groupContactsByFirstLetter:(NSArray *)contacts matchingSearchString:(NSString *)optionalSearchString;
|
||||
|
||||
+(BOOL)name:(NSString *)nameString matchesQuery:(NSString *)queryString;
|
||||
+(BOOL)phoneNumber:(PhoneNumber *)phoneNumber matchesQuery:(NSString *)queryString;
|
||||
|
||||
- (void)verifyABPermission;
|
||||
|
||||
- (NSArray<Contact *> *)allContacts;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#import "ContactsManager+updater.h"
|
||||
#import "ContactsManager.h"
|
||||
#import "ContactsUpdater.h"
|
||||
#import "Environment.h"
|
||||
#import "Util.h"
|
||||
|
||||
|
@ -26,7 +27,8 @@ typedef BOOL (^ContactSearchBlock)(id, NSUInteger, BOOL*);
|
|||
- (void)doAfterEnvironmentInitSetup {
|
||||
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(_iOS_9)) {
|
||||
self.contactStore = [[CNContactStore alloc] init];
|
||||
[self.contactStore requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
|
||||
[self.contactStore requestAccessForEntityType:CNEntityTypeContacts
|
||||
completionHandler:^(BOOL granted, NSError *_Nullable error) {
|
||||
if (!granted) {
|
||||
// We're still using the old addressbook API.
|
||||
// User warned if permission not granted in that setup.
|
||||
|
@ -40,7 +42,8 @@ typedef BOOL (^ContactSearchBlock)(id, NSUInteger, BOOL*);
|
|||
@synchronized(self) {
|
||||
[self setupLatestContacts:latestContacts];
|
||||
}
|
||||
} untilCancelled:life.token];
|
||||
}
|
||||
untilCancelled:life.token];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
|
@ -80,6 +83,19 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
});
|
||||
}
|
||||
|
||||
- (void)intersectContacts {
|
||||
[[ContactsUpdater sharedUpdater] updateSignalContactIntersectionWithABContacts:self.allContacts
|
||||
success:^{
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
[NSTimer scheduledTimerWithTimeInterval:60
|
||||
target:self
|
||||
selector:@selector(intersectContacts)
|
||||
userInfo:nil
|
||||
repeats:NO];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)pullLatestAddressBook {
|
||||
CFErrorRef creationError = nil;
|
||||
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &creationError);
|
||||
|
@ -101,32 +117,43 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
+ (void)blockingContactDialog {
|
||||
switch (ABAddressBookGetAuthorizationStatus()) {
|
||||
case kABAuthorizationStatusRestricted: {
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_TITLE", nil)
|
||||
UIAlertController *controller =
|
||||
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_TITLE", nil)
|
||||
message:NSLocalizedString(@"ADDRESSBOOK_RESTRICTED_ALERT_BODY", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"ADDRESSBOOK_RESTRICTED_ALERT_BUTTON", nil)
|
||||
[controller
|
||||
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"ADDRESSBOOK_RESTRICTED_ALERT_BUTTON", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
exit(0);
|
||||
}]];
|
||||
|
||||
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
|
||||
[[UIApplication sharedApplication]
|
||||
.keyWindow.rootViewController presentViewController:controller
|
||||
animated:YES
|
||||
completion:nil];
|
||||
|
||||
break;
|
||||
}
|
||||
case kABAuthorizationStatusDenied: {
|
||||
UIAlertController *controller = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_TITLE", nil)
|
||||
UIAlertController *controller =
|
||||
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_TITLE", nil)
|
||||
message:NSLocalizedString(@"AB_PERMISSION_MISSING_BODY", nil)
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_ACTION", nil)
|
||||
[controller addAction:[UIAlertAction
|
||||
actionWithTitle:NSLocalizedString(@"AB_PERMISSION_MISSING_ACTION", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
|
||||
[[UIApplication sharedApplication]
|
||||
openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
|
||||
}]];
|
||||
|
||||
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController:controller animated:YES completion:nil];
|
||||
[[[UIApplication sharedApplication] keyWindow]
|
||||
.rootViewController presentViewController:controller
|
||||
animated:YES
|
||||
completion:nil];
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -188,10 +215,11 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
|
||||
- (NSArray *)getContactsFromAddressBook:(ABAddressBookRef)addressBook {
|
||||
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
|
||||
CFMutableArrayRef allPeopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault,
|
||||
CFArrayGetCount(allPeople),allPeople);
|
||||
CFMutableArrayRef allPeopleMutable =
|
||||
CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(allPeople), allPeople);
|
||||
|
||||
CFArraySortValues(allPeopleMutable,CFRangeMake(0, CFArrayGetCount(allPeopleMutable)),
|
||||
CFArraySortValues(allPeopleMutable,
|
||||
CFRangeMake(0, CFArrayGetCount(allPeopleMutable)),
|
||||
(CFComparatorFunction)ABPersonComparePeopleByName,
|
||||
(void *)(unsigned long)ABPersonGetSortOrdering());
|
||||
|
||||
|
@ -245,18 +273,16 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
}
|
||||
}
|
||||
|
||||
NSString *notes = (__bridge_transfer NSString*)ABRecordCopyValue(record, kABPersonNoteProperty);
|
||||
NSArray *emails = [ContactsManager emailsForRecord:record];
|
||||
NSData *image = (__bridge_transfer NSData*)ABPersonCopyImageDataWithFormat(record, kABPersonImageFormatThumbnail);
|
||||
UIImage *img = [UIImage imageWithData:image];
|
||||
// NSString *notes = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonNoteProperty);
|
||||
// NSArray *emails = [ContactsManager emailsForRecord:record];
|
||||
// NSData *image = (__bridge_transfer NSData *)ABPersonCopyImageDataWithFormat(record,
|
||||
// kABPersonImageFormatThumbnail);
|
||||
// UIImage *img = [UIImage imageWithData:image];
|
||||
|
||||
return [Contact contactWithFirstName:firstName
|
||||
return [[Contact alloc] initWithContactWithFirstName:firstName
|
||||
andLastName:lastName
|
||||
andUserTextPhoneNumbers:phoneNumbers
|
||||
andEmails:emails
|
||||
andImage:img
|
||||
andContactID:recordID
|
||||
andNotes:notes];
|
||||
andContactID:recordID];
|
||||
}
|
||||
|
||||
- (Contact *)latestContactForPhoneNumber:(PhoneNumber *)phoneNumber {
|
||||
|
@ -264,7 +290,6 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
|
||||
ContactSearchBlock searchBlock = ^BOOL(Contact *contact, NSUInteger idx, BOOL *stop) {
|
||||
for (PhoneNumber *number in contact.parsedPhoneNumbers) {
|
||||
|
||||
if ([self phoneNumber:number matchesNumber:phoneNumber]) {
|
||||
*stop = YES;
|
||||
return YES;
|
||||
|
@ -292,7 +317,8 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
@try {
|
||||
NSArray *phoneNumbers = (__bridge_transfer NSArray *)ABMultiValueCopyArrayOfAllValues(numberRefs);
|
||||
|
||||
if (phoneNumbers == nil) phoneNumbers = @[];
|
||||
if (phoneNumbers == nil)
|
||||
phoneNumbers = @[];
|
||||
|
||||
NSMutableArray *numbers = [NSMutableArray array];
|
||||
|
||||
|
@ -316,7 +342,8 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
@try {
|
||||
NSArray *emails = (__bridge_transfer NSArray *)ABMultiValueCopyArrayOfAllValues(emailRefs);
|
||||
|
||||
if (emails == nil) emails = @[];
|
||||
if (emails == nil)
|
||||
emails = @[];
|
||||
|
||||
return emails;
|
||||
|
||||
|
@ -328,7 +355,7 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
}
|
||||
|
||||
+ (NSDictionary *)groupContactsByFirstLetter:(NSArray *)contacts matchingSearchString:(NSString *)optionalSearchString {
|
||||
require(contacts != nil);
|
||||
assert(contacts != nil);
|
||||
|
||||
NSArray *matchingContacts = [contacts filter:^int(Contact *contact) {
|
||||
return optionalSearchString.length == 0 || [self name:contact.fullName matchesQuery:optionalSearchString];
|
||||
|
@ -398,7 +425,8 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
NSArray *nameStrings = [nameString componentsSeparatedByCharactersInSet:whitespaceSet];
|
||||
|
||||
return [queryStrings all:^int(NSString *query) {
|
||||
if (query.length == 0) return YES;
|
||||
if (query.length == 0)
|
||||
return YES;
|
||||
return [nameStrings any:^int(NSString *nameWord) {
|
||||
NSStringCompareOptions searchOpts = NSCaseInsensitiveSearch | NSAnchoredSearch;
|
||||
return [nameWord rangeOfString:query options:searchOpts].location != NSNotFound;
|
||||
|
@ -410,7 +438,8 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in
|
|||
NSString *phoneNumberString = phoneNumber.localizedDescriptionForUser;
|
||||
NSString *searchString = phoneNumberString.digitsOnly;
|
||||
|
||||
if (queryString.length == 0) return YES;
|
||||
if (queryString.length == 0)
|
||||
return YES;
|
||||
NSStringCompareOptions searchOpts = NSCaseInsensitiveSearch | NSAnchoredSearch;
|
||||
return [searchString rangeOfString:queryString options:searchOpts].location != NSNotFound;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
- (NSData *)decryptWithAesInCounterModeWithKey:(NSData *)key andIv:(NSData *)iv;
|
||||
|
||||
/// Determines if two data vectors contain the same information.
|
||||
/// Avoids short-circuiting or data-dependent branches, so that early returns can't be used to infer where the difference is.
|
||||
/// Avoids short-circuiting or data-dependent branches, so that early returns can't be used to infer where the
|
||||
/// difference is.
|
||||
/// Returns early if data is of different length.
|
||||
- (bool)isEqualToData_TimingSafe:(NSData *)other;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
}
|
||||
|
||||
+ (NSString *)computeOtpWithPassword:(NSString *)password andCounter:(int64_t)counter {
|
||||
require(password != nil);
|
||||
ows_require(password != nil);
|
||||
|
||||
NSData *d = [[@(counter) stringValue] encodedAsUtf8];
|
||||
NSData *h = [d hmacWithSha1WithKey:password.encodedAsUtf8];
|
||||
|
@ -69,9 +69,11 @@
|
|||
return [EvpMessageDigest hashWithSha256:self];
|
||||
}
|
||||
- (bool)isEqualToData_TimingSafe:(NSData *)other {
|
||||
if (other == nil) return false;
|
||||
if (other == nil)
|
||||
return false;
|
||||
NSUInteger n = self.length;
|
||||
if (other.length != n) return false;
|
||||
if (other.length != n)
|
||||
return false;
|
||||
bool equal = true;
|
||||
for (NSUInteger i = 0; i < n; i++)
|
||||
equal &= [self uint8At:i] == [other uint8At:i];
|
||||
|
|
|
@ -15,27 +15,24 @@
|
|||
unsigned char digestBuffer[expectedDigestLength];
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
require(NULL != ctx);
|
||||
ows_require(NULL != ctx);
|
||||
@try {
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_DigestInit_ex(ctx, digest, NULL));
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_DigestUpdate(ctx, data.bytes, data.length));
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_DigestFinal_ex(ctx, digestBuffer, &digestLength));
|
||||
}
|
||||
@finally {
|
||||
} @finally {
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
}
|
||||
|
||||
require(digestLength == expectedDigestLength);
|
||||
ows_require(digestLength == expectedDigestLength);
|
||||
return [NSData dataWithBytes:digestBuffer length:digestLength];
|
||||
}
|
||||
|
||||
+ (NSData *)hmacWithData:(NSData *)data andKey:(NSData *)key andDigest:(const EVP_MD *)md {
|
||||
NSUInteger digestLength = [NumberUtil assertConvertIntToNSUInteger:EVP_MD_size(md)];
|
||||
|
||||
unsigned char* digest = HMAC(md,
|
||||
[key bytes], [NumberUtil assertConvertNSUIntegerToInt:key.length],
|
||||
[data bytes], data.length,
|
||||
NULL, NULL);
|
||||
unsigned char *digest = HMAC(
|
||||
md, [key bytes], [NumberUtil assertConvertNSUIntegerToInt:key.length], [data bytes], data.length, NULL, NULL);
|
||||
|
||||
return [NSData dataWithBytes:digest length:digestLength];
|
||||
}
|
||||
|
|
|
@ -6,7 +6,10 @@
|
|||
|
||||
@implementation EvpSymetricUtil
|
||||
|
||||
+(NSData*) encryptMessage:(NSData *)message usingCipher:(const EVP_CIPHER*) cipher andKey:(NSData *)key andIv:(NSData *)iv {
|
||||
+ (NSData *)encryptMessage:(NSData *)message
|
||||
usingCipher:(const EVP_CIPHER *)cipher
|
||||
andKey:(NSData *)key
|
||||
andIv:(NSData *)iv {
|
||||
[self assertKey:key andIv:iv lengthsAgainstCipher:cipher];
|
||||
|
||||
int messageLength = [NumberUtil assertConvertNSUIntegerToInt:message.length];
|
||||
|
@ -18,20 +21,22 @@
|
|||
unsigned char cipherText[bufferLength];
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
if(!ctx) { RAISE_EXCEPTION;}
|
||||
if (!ctx) {
|
||||
RAISE_EXCEPTION;
|
||||
}
|
||||
|
||||
@try {
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_EncryptInit_ex(ctx, cipher, NULL, [key bytes], [iv bytes]))
|
||||
RAISE_EXCEPTION_ON_FAILURE( EVP_EncryptUpdate(ctx, cipherText, &cipherTextLength, [message bytes], messageLength))
|
||||
RAISE_EXCEPTION_ON_FAILURE(
|
||||
EVP_EncryptUpdate(ctx, cipherText, &cipherTextLength, [message bytes], messageLength))
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_EncryptFinal_ex(ctx, cipherText + cipherTextLength, &paddingLength))
|
||||
|
||||
cipherTextLength += paddingLength;
|
||||
}
|
||||
@finally {
|
||||
} @finally {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
require(cipherTextLength <= bufferLength);
|
||||
ows_require(cipherTextLength <= bufferLength);
|
||||
|
||||
return [NSData dataWithBytes:cipherText length:[NumberUtil assertConvertIntToNSUInteger:cipherTextLength]];
|
||||
}
|
||||
|
@ -40,12 +45,14 @@
|
|||
int cipherKeyLength = EVP_CIPHER_key_length(cipher);
|
||||
int cipherIvLength = EVP_CIPHER_iv_length(cipher);
|
||||
|
||||
require(key.length == [NumberUtil assertConvertIntToNSUInteger:cipherKeyLength]);
|
||||
require(iv.length == [NumberUtil assertConvertIntToNSUInteger:cipherIvLength]);
|
||||
ows_require(key.length == [NumberUtil assertConvertIntToNSUInteger:cipherKeyLength]);
|
||||
ows_require(iv.length == [NumberUtil assertConvertIntToNSUInteger:cipherIvLength]);
|
||||
}
|
||||
|
||||
+(NSData*) decryptMessage:(NSData *)cipherText usingCipher:(const EVP_CIPHER*) cipher andKey:(NSData *)key andIv:(NSData *)iv {
|
||||
|
||||
+ (NSData *)decryptMessage:(NSData *)cipherText
|
||||
usingCipher:(const EVP_CIPHER *)cipher
|
||||
andKey:(NSData *)key
|
||||
andIv:(NSData *)iv {
|
||||
[self assertKey:key andIv:iv lengthsAgainstCipher:cipher];
|
||||
|
||||
int cipherTextLength = [NumberUtil assertConvertNSUIntegerToInt:cipherText.length];
|
||||
|
@ -57,20 +64,22 @@
|
|||
unsigned char plainText[bufferLength];
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
if(!ctx) { RAISE_EXCEPTION;}
|
||||
if (!ctx) {
|
||||
RAISE_EXCEPTION;
|
||||
}
|
||||
|
||||
@try {
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_DecryptInit_ex(ctx, cipher, NULL, [key bytes], [iv bytes]))
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_DecryptUpdate( ctx, plainText, &plainTextLength, [cipherText bytes], cipherTextLength))
|
||||
RAISE_EXCEPTION_ON_FAILURE(
|
||||
EVP_DecryptUpdate(ctx, plainText, &plainTextLength, [cipherText bytes], cipherTextLength))
|
||||
RAISE_EXCEPTION_ON_FAILURE(EVP_DecryptFinal_ex(ctx, plainText + plainTextLength, &paddingLength))
|
||||
|
||||
plainTextLength += paddingLength;
|
||||
}
|
||||
@finally {
|
||||
} @finally {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
|
||||
require(plainTextLength <= bufferLength);
|
||||
ows_require(plainTextLength <= bufferLength);
|
||||
|
||||
return [NSData dataWithBytes:plainText length:[NumberUtil assertConvertIntToNSUInteger:plainTextLength]];
|
||||
}
|
||||
|
@ -96,4 +105,5 @@
|
|||
return [self decryptMessage:message usingCipher:EVP_aes_128_ctr() andKey:key andIv:iv];
|
||||
}
|
||||
|
||||
@end;
|
||||
@end
|
||||
;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define RAISE_EXCEPTION [NSException raise:@"OPENSSL_Exception" format:@"Line:%d File:%s ", __LINE__, __FILE__]
|
||||
#define RAISE_EXCEPTION_ON_FAILURE(X) if( 1 != X){ RAISE_EXCEPTION;}
|
||||
#define RAISE_EXCEPTION_ON_FAILURE(X) \
|
||||
if (1 != X) { \
|
||||
RAISE_EXCEPTION; \
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
@interface DebugLogger : NSObject
|
||||
|
||||
MacrosSingletonInterface
|
||||
+ (instancetype)sharedLogger;
|
||||
|
||||
- (void)enableFileLogging;
|
||||
|
||||
|
|
|
@ -18,10 +18,19 @@
|
|||
|
||||
@implementation DebugLogger
|
||||
|
||||
MacrosSingletonImplemention
|
||||
+ (instancetype)sharedLogger {
|
||||
static DebugLogger *sharedManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedManager = [self new];
|
||||
});
|
||||
return sharedManager;
|
||||
}
|
||||
|
||||
|
||||
- (void)enableFileLogging {
|
||||
self.fileLogger = [[DDFileLogger alloc] init]; //Logging to file, because it's in the Cache folder, they are not uploaded in iTunes/iCloud backups.
|
||||
self.fileLogger = [[DDFileLogger alloc]
|
||||
init]; // Logging to file, because it's in the Cache folder, they are not uploaded in iTunes/iCloud backups.
|
||||
self.fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling.
|
||||
self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; // Keep three days of logs.
|
||||
[DDLog addLogger:self.fileLogger];
|
||||
|
@ -66,7 +75,10 @@ MacrosSingletonImplemention
|
|||
if (![[NSFileManager defaultManager] fileExistsAtPath:logsDirectory]) {
|
||||
NSError *error;
|
||||
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:logsDirectory withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:logsDirectory
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:nil];
|
||||
|
||||
if (error) {
|
||||
DDLogError(@"Log folder couldn't be created. %@", error.description);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "Logging.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "PacketHandler.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "SecureEndPoint.h"
|
||||
#import "TSGroupModel.h"
|
||||
#import "TSStorageHeaders.h"
|
||||
|
@ -20,7 +20,8 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue";
|
|||
|
||||
#define ENVIRONMENT_TESTING_OPTION_LOSE_CONF_ACK_ON_PURPOSE @"LoseConfAck"
|
||||
#define ENVIRONMENT_TESTING_OPTION_ALLOW_NETWORK_STREAM_TO_NON_SECURE_END_POINTS @"AllowTcpWithoutTls"
|
||||
#define ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER @"LegacyAndroidInterop_1"
|
||||
#define ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER \
|
||||
@"LegacyAndroidInterop_1"
|
||||
#define TESTING_OPTION_USE_DH_FOR_HANDSHAKE @"DhKeyAgreementOnly"
|
||||
|
||||
@class RecentCallManager;
|
||||
|
@ -37,7 +38,6 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue";
|
|||
@property (nonatomic, readonly) NSString *relayServerHostNameSuffix;
|
||||
@property (nonatomic, readonly) NSArray *keyAgreementProtocolsInDescendingPriority;
|
||||
@property (nonatomic, readonly) ErrorHandlerBlock errorNoter;
|
||||
@property (nonatomic, readonly) NSString* currentRegionCodeForPhoneNumbers;
|
||||
@property (nonatomic, readonly) PhoneManager *phoneManager;
|
||||
@property (nonatomic, readonly) RecentCallManager *recentCallManager;
|
||||
@property (nonatomic, readonly) NSArray *testingAndLegacyOptions;
|
||||
|
@ -59,7 +59,6 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue";
|
|||
andDefaultRelayName:(NSString *)defaultRelayName
|
||||
andRelayServerHostNameSuffix:(NSString *)relayServerHostNameSuffix
|
||||
andCertificate:(Certificate *)certificate
|
||||
andCurrentRegionCodeForPhoneNumbers:(NSString*)currentRegionCodeForPhoneNumbers
|
||||
andSupportedKeyAgreementProtocols:(NSArray *)keyAgreementProtocolsInDescendingPriority
|
||||
andPhoneManager:(PhoneManager *)phoneManager
|
||||
andRecentCallManager:(RecentCallManager *)recentCallManager
|
||||
|
@ -73,7 +72,6 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue";
|
|||
+ (id<Logging>)logging;
|
||||
+ (NSString *)relayServerNameToHostName:(NSString *)name;
|
||||
+ (ErrorHandlerBlock)errorNoter;
|
||||
+(NSString*) currentRegionCodeForPhoneNumbers;
|
||||
+ (bool)hasEnabledTestingOrLegacyOption:(NSString *)flag;
|
||||
+ (PhoneManager *)phoneManager;
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#import "Constraints.h"
|
||||
#import "DH3KKeyAgreementProtocol.h"
|
||||
#import "DebugLogger.h"
|
||||
#import "Environment.h"
|
||||
#import "Constraints.h"
|
||||
#import "FunctionalUtil.h"
|
||||
#import "KeyAgreementProtocol.h"
|
||||
#import "DH3KKeyAgreementProtocol.h"
|
||||
#import "RecentCallManager.h"
|
||||
#import "MessagesViewController.h"
|
||||
#import "RecentCallManager.h"
|
||||
#import "SignalKeyingStorage.h"
|
||||
#import "SignalsViewController.h"
|
||||
#import "TSContactThread.h"
|
||||
|
@ -17,28 +17,12 @@ static Environment* environment = nil;
|
|||
|
||||
@implementation Environment
|
||||
|
||||
@synthesize testingAndLegacyOptions,
|
||||
currentRegionCodeForPhoneNumbers,
|
||||
errorNoter,
|
||||
keyAgreementProtocolsInDescendingPriority,
|
||||
logging,
|
||||
masterServerSecureEndPoint,
|
||||
defaultRelayName,
|
||||
relayServerHostNameSuffix,
|
||||
certificate,
|
||||
serverPort,
|
||||
zrtpClientId,
|
||||
zrtpVersionId,
|
||||
phoneManager,
|
||||
recentCallManager,
|
||||
contactsManager;
|
||||
|
||||
+(NSString*) currentRegionCodeForPhoneNumbers {
|
||||
return self.getCurrent.currentRegionCodeForPhoneNumbers;
|
||||
}
|
||||
@synthesize testingAndLegacyOptions, errorNoter, keyAgreementProtocolsInDescendingPriority, logging,
|
||||
masterServerSecureEndPoint, defaultRelayName, relayServerHostNameSuffix, certificate, serverPort, zrtpClientId,
|
||||
zrtpVersionId, phoneManager, recentCallManager, contactsManager;
|
||||
|
||||
+ (Environment *)getCurrent {
|
||||
require(environment != nil);
|
||||
NSAssert((environment != nil), @"Environment is not defined.");
|
||||
return environment;
|
||||
}
|
||||
|
||||
|
@ -53,9 +37,7 @@ contactsManager;
|
|||
}
|
||||
|
||||
+ (NSString *)relayServerNameToHostName:(NSString *)name {
|
||||
return [NSString stringWithFormat:@"%@.%@",
|
||||
name,
|
||||
Environment.getCurrent.relayServerHostNameSuffix];
|
||||
return [NSString stringWithFormat:@"%@.%@", name, Environment.getCurrent.relayServerHostNameSuffix];
|
||||
}
|
||||
+ (SecureEndPoint *)getMasterServerSecureEndPoint {
|
||||
return Environment.getCurrent.masterServerSecureEndPoint;
|
||||
|
@ -64,7 +46,7 @@ contactsManager;
|
|||
return [Environment getSecureEndPointToSignalingServerNamed:Environment.getCurrent.defaultRelayName];
|
||||
}
|
||||
+ (SecureEndPoint *)getSecureEndPointToSignalingServerNamed:(NSString *)name {
|
||||
require(name != nil);
|
||||
ows_require(name != nil);
|
||||
Environment *env = Environment.getCurrent;
|
||||
|
||||
NSString *hostName = [self relayServerNameToHostName:name];
|
||||
|
@ -79,7 +61,6 @@ contactsManager;
|
|||
andDefaultRelayName:(NSString *)defaultRelayName
|
||||
andRelayServerHostNameSuffix:(NSString *)relayServerHostNameSuffix
|
||||
andCertificate:(Certificate *)certificate
|
||||
andCurrentRegionCodeForPhoneNumbers:(NSString*)currentRegionCodeForPhoneNumbers
|
||||
andSupportedKeyAgreementProtocols:(NSArray *)keyAgreementProtocolsInDescendingPriority
|
||||
andPhoneManager:(PhoneManager *)phoneManager
|
||||
andRecentCallManager:(RecentCallManager *)recentCallManager
|
||||
|
@ -87,19 +68,17 @@ contactsManager;
|
|||
andZrtpClientId:(NSData *)zrtpClientId
|
||||
andZrtpVersionId:(NSData *)zrtpVersionId
|
||||
andContactsManager:(ContactsManager *)contactsManager {
|
||||
|
||||
require(errorNoter != nil);
|
||||
require(zrtpClientId != nil);
|
||||
require(zrtpVersionId != nil);
|
||||
require(testingAndLegacyOptions != nil);
|
||||
require(currentRegionCodeForPhoneNumbers != nil);
|
||||
require(keyAgreementProtocolsInDescendingPriority != nil);
|
||||
require([keyAgreementProtocolsInDescendingPriority all:^int(id p) {
|
||||
ows_require(errorNoter != nil);
|
||||
ows_require(zrtpClientId != nil);
|
||||
ows_require(zrtpVersionId != nil);
|
||||
ows_require(testingAndLegacyOptions != nil);
|
||||
ows_require(keyAgreementProtocolsInDescendingPriority != nil);
|
||||
ows_require([keyAgreementProtocolsInDescendingPriority all:^int(id p) {
|
||||
return [p conformsToProtocol:@protocol(KeyAgreementProtocol)];
|
||||
}]);
|
||||
|
||||
// must support DH3k
|
||||
require([keyAgreementProtocolsInDescendingPriority any:^int(id p) {
|
||||
ows_require([keyAgreementProtocolsInDescendingPriority any:^int(id p) {
|
||||
return [p isKindOfClass:DH3KKeyAgreementProtocol.class];
|
||||
}]);
|
||||
|
||||
|
@ -108,14 +87,13 @@ contactsManager;
|
|||
e->logging = logging;
|
||||
e->testingAndLegacyOptions = testingAndLegacyOptions;
|
||||
e->serverPort = serverPort;
|
||||
e->masterServerSecureEndPoint = [SecureEndPoint secureEndPointForHost:[HostNameEndPoint hostNameEndPointWithHostName:masterServerHostName
|
||||
andPort:serverPort]
|
||||
e->masterServerSecureEndPoint = [SecureEndPoint
|
||||
secureEndPointForHost:[HostNameEndPoint hostNameEndPointWithHostName:masterServerHostName andPort:serverPort]
|
||||
identifiedByCertificate:certificate];
|
||||
e->defaultRelayName = defaultRelayName;
|
||||
e->certificate = certificate;
|
||||
e->relayServerHostNameSuffix = relayServerHostNameSuffix;
|
||||
e->keyAgreementProtocolsInDescendingPriority = keyAgreementProtocolsInDescendingPriority;
|
||||
e->currentRegionCodeForPhoneNumbers = currentRegionCodeForPhoneNumbers;
|
||||
e->phoneManager = phoneManager;
|
||||
e->recentCallManager = recentCallManager;
|
||||
e->zrtpClientId = zrtpClientId;
|
||||
|
@ -123,10 +101,10 @@ contactsManager;
|
|||
e->contactsManager = contactsManager;
|
||||
|
||||
if (recentCallManager != nil) {
|
||||
// recentCallManagers are nil in unit tests because they would require unnecessary allocations. Detailed explanation: https://github.com/WhisperSystems/Signal-iOS/issues/62#issuecomment-51482195
|
||||
// recentCallManagers are nil in unit tests because they would require unnecessary allocations. Detailed
|
||||
// explanation: https://github.com/WhisperSystems/Signal-iOS/issues/62#issuecomment-51482195
|
||||
|
||||
[recentCallManager watchForCallsThrough:phoneManager
|
||||
untilCancelled:nil];
|
||||
[recentCallManager watchForCallsThrough:phoneManager untilCancelled:nil];
|
||||
}
|
||||
|
||||
return e;
|
||||
|
@ -138,7 +116,8 @@ contactsManager;
|
|||
+ (id<Logging>)logging {
|
||||
// Many tests create objects that rely on Environment only for logging.
|
||||
// So we bypass the nil check in getCurrent and silently don't log during unit testing, instead of failing hard.
|
||||
if (environment == nil) return nil;
|
||||
if (environment == nil)
|
||||
return nil;
|
||||
|
||||
return Environment.getCurrent.logging;
|
||||
}
|
||||
|
@ -163,7 +142,9 @@ contactsManager;
|
|||
[vc dismissViewControllerAnimated:NO completion:nil];
|
||||
vc.latestCall = latestCall;
|
||||
[vc performSegueWithIdentifier:kCallSegue sender:self];
|
||||
} onThread:NSThread.mainThread untilCancelled:nil];
|
||||
}
|
||||
onThread:NSThread.mainThread
|
||||
untilCancelled:nil];
|
||||
}
|
||||
|
||||
+ (PropertyListPreferences *)preferences {
|
||||
|
@ -247,7 +228,8 @@ contactsManager;
|
|||
+ (void)resetAppData {
|
||||
[[TSStorageManager sharedManager] wipeSignalStorage];
|
||||
[Environment.preferences clear];
|
||||
[DebugLogger.sharedInstance wipeLogs];
|
||||
[DebugLogger.sharedLogger wipeLogs];
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "CallTermination.h"
|
||||
#import "CallProgress.h"
|
||||
#import "CallTermination.h"
|
||||
|
||||
#define TXT_IN_CALL_CONNECTING NSLocalizedString(@"IN_CALL_CONNECTING", @"")
|
||||
#define TXT_IN_CALL_RINGING NSLocalizedString(@"IN_CALL_RINGING", @"")
|
||||
|
@ -24,11 +24,6 @@
|
|||
#define TXT_END_CALL_MESSAGE_FROM_SERVER_PREFIX NSLocalizedString(@"END_CALL_MESSAGE_FROM_SERVER_PREFIX", @"")
|
||||
|
||||
#pragma mark - View Controller Titles
|
||||
|
||||
#define WHISPER_NAV_BAR_TITLE NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", @"Title for home feed view controller")
|
||||
#define CONTACT_BROWSE_NAV_BAR_TITLE NSLocalizedString(@"CONTACT_BROWSE_NAV_BAR_TITLE", @"Title for contact browse view controller")
|
||||
#define KEYPAD_NAV_BAR_TITLE NSLocalizedString(@"KEYPAD_NAV_BAR_TITLE", @"Title for keypad view controller")
|
||||
#define RECENT_NAV_BAR_TITLE NSLocalizedString(@"RECENT_NAV_BAR_TITLE", @"Title for recent calls view controller")
|
||||
#define SETTINGS_NAV_BAR_TITLE NSLocalizedString(@"SETTINGS_NAV_BAR_TITLE", @"Title for recent calls view controller")
|
||||
#define FAVOURITES_NAV_BAR_TITLE NSLocalizedString(@"FAVOURITES_NAV_BAR_TITLE", @"Title for favourites view controller")
|
||||
|
||||
|
@ -83,7 +78,6 @@
|
|||
#define REGISTER_CC_ERR_ALERT_VIEW_DISMISS NSLocalizedString(@"OK", @"")
|
||||
#define CONTINUE_TO_WHISPER_TITLE NSLocalizedString(@"CONTINUE_TO_WHISPER_TITLE", @"")
|
||||
|
||||
#define REGISTER_BUTTON_TITLE NSLocalizedString(@"REGISTER_BUTTON_TITLE", @"")
|
||||
#define CHALLENGE_CODE_BUTTON_TITLE NSLocalizedString(@"CHALLENGE_CODE_BUTTON_TITLE", @"")
|
||||
|
||||
#define END_CALL_BUTTON_TITLE NSLocalizedString(@"END_CALL_BUTTON_TITLE", @"")
|
||||
|
@ -116,4 +110,3 @@
|
|||
|
||||
NSDictionary *makeCallProgressLocalizedTextDictionary(void);
|
||||
NSDictionary *makeCallTerminationLocalizedTextDictionary(void);
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ NSDictionary* makeCallProgressLocalizedTextDictionary(void) {
|
|||
cp(CallProgressType_Talking) : TXT_IN_CALL_TALKING,
|
||||
cp(CallProgressType_Terminated) : TXT_IN_CALL_TERMINATED
|
||||
};
|
||||
|
||||
}
|
||||
NSDictionary *makeCallTerminationLocalizedTextDictionary(void) {
|
||||
return @{
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// NotificationsManager.h
|
||||
// Signal
|
||||
//
|
||||
// Created by Frederic Jacobs on 22/12/15.
|
||||
// Copyright © 2015 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <TextSecureKit/NotificationsProtocol.h>
|
||||
|
||||
@class TSCall;
|
||||
|
||||
@interface NotificationsManager : NSObject <NotificationsProtocol>
|
||||
|
||||
- (void)notifyUserForCall:(TSCall *)call inThread:(TSThread *)thread;
|
||||
|
||||
@end
|
|
@ -0,0 +1,150 @@
|
|||
//
|
||||
// NotificationsManager.m
|
||||
// Signal
|
||||
//
|
||||
// Created by Frederic Jacobs on 22/12/15.
|
||||
// Copyright © 2015 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AudioToolbox/AudioServices.h>
|
||||
#import <TextSecureKit/TSCall.h>
|
||||
#import <TextSecureKit/TSContactThread.h>
|
||||
#import <TextSecureKit/TSErrorMessage.h>
|
||||
#import <TextSecureKit/TSIncomingMessage.h>
|
||||
#import <TextSecureKit/TextSecureKitEnv.h>
|
||||
#import "Environment.h"
|
||||
#import "NotificationsManager.h"
|
||||
#import "PreferencesUtil.h"
|
||||
#import "PushManager.h"
|
||||
|
||||
@interface NotificationsManager ()
|
||||
|
||||
@property SystemSoundID newMessageSound;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NotificationsManager
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
|
||||
if (self) {
|
||||
NSURL *newMessageSound =
|
||||
[NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"NewMessage" ofType:@"aifc"]];
|
||||
self.newMessageSound = AudioServicesCreateSystemSoundID((__bridge CFURLRef)newMessageSound, &_newMessageSound);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)notifyUserForCall:(TSCall *)call inThread:(TSThread *)thread {
|
||||
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
|
||||
// Remove previous notification of call and show missed notification.
|
||||
UILocalNotification *notif = [[PushManager sharedManager] closeVOIPBackgroundTask];
|
||||
TSContactThread *cThread = (TSContactThread *)thread;
|
||||
|
||||
if (call.callType == RPRecentCallTypeMissed) {
|
||||
if (notif) {
|
||||
[[UIApplication sharedApplication] cancelLocalNotification:notif];
|
||||
}
|
||||
|
||||
UILocalNotification *notification = [[UILocalNotification alloc] init];
|
||||
notification.category = Signal_CallBack_Category;
|
||||
notification.userInfo = @{Signal_Call_UserInfo_Key : cThread.contactIdentifier};
|
||||
notification.soundName = @"NewMessage.aifc";
|
||||
notification.alertBody =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"MSGVIEW_MISSED_CALL", nil), [thread name]];
|
||||
|
||||
[[PushManager sharedManager] presentNotification:notification];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notifyUserForErrorMessage:(TSErrorMessage *)message inThread:(TSThread *)thread {
|
||||
NSString *messageDescription = message.description;
|
||||
|
||||
if (([UIApplication sharedApplication].applicationState != UIApplicationStateActive) && messageDescription) {
|
||||
UILocalNotification *notification = [[UILocalNotification alloc] init];
|
||||
notification.userInfo = @{Signal_Thread_UserInfo_Key : thread.uniqueId};
|
||||
notification.soundName = @"NewMessage.aifc";
|
||||
|
||||
NSString *alertBodyString = @"";
|
||||
|
||||
NSString *authorName = [thread name];
|
||||
switch ([[Environment preferences] notificationPreviewType]) {
|
||||
case NotificationNamePreview:
|
||||
case NotificationNameNoPreview:
|
||||
alertBodyString = [NSString stringWithFormat:@"%@: %@", authorName, messageDescription];
|
||||
break;
|
||||
case NotificationNoNameNoPreview:
|
||||
alertBodyString = messageDescription;
|
||||
break;
|
||||
}
|
||||
notification.alertBody = alertBodyString;
|
||||
|
||||
[[PushManager sharedManager] presentNotification:notification];
|
||||
} else {
|
||||
if ([Environment.preferences soundInForeground]) {
|
||||
AudioServicesPlayAlertSound(_newMessageSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notifyUserForIncomingMessage:(TSIncomingMessage *)message from:(NSString *)name inThread:(TSThread *)thread {
|
||||
NSString *messageDescription = message.description;
|
||||
|
||||
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive && messageDescription) {
|
||||
UILocalNotification *notification = [[UILocalNotification alloc] init];
|
||||
notification.soundName = @"NewMessage.aifc";
|
||||
|
||||
switch ([[Environment preferences] notificationPreviewType]) {
|
||||
case NotificationNamePreview:
|
||||
notification.category = Signal_Full_New_Message_Category;
|
||||
notification.userInfo =
|
||||
@{Signal_Thread_UserInfo_Key : thread.uniqueId, Signal_Message_UserInfo_Key : message.uniqueId};
|
||||
|
||||
if ([thread isGroupThread]) {
|
||||
NSString *sender =
|
||||
[[TextSecureKitEnv sharedEnv].contactsManager nameStringForPhoneIdentifier:message.authorId];
|
||||
if (!sender) {
|
||||
sender = message.authorId;
|
||||
}
|
||||
|
||||
NSString *threadName = [NSString stringWithFormat:@"\"%@\"", name];
|
||||
notification.alertBody =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"APN_MESSAGE_IN_GROUP_DETAILED", nil),
|
||||
sender,
|
||||
threadName,
|
||||
messageDescription];
|
||||
} else {
|
||||
notification.alertBody = [NSString stringWithFormat:@"%@: %@", name, messageDescription];
|
||||
}
|
||||
break;
|
||||
case NotificationNameNoPreview: {
|
||||
notification.userInfo = @{Signal_Thread_UserInfo_Key : thread.uniqueId};
|
||||
if ([thread isGroupThread]) {
|
||||
notification.alertBody =
|
||||
[NSString stringWithFormat:@"%@ \"%@\"", NSLocalizedString(@"APN_MESSAGE_IN_GROUP", nil), name];
|
||||
} else {
|
||||
notification.alertBody =
|
||||
[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"APN_MESSAGE_FROM", nil), name];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NotificationNoNameNoPreview:
|
||||
notification.alertBody = NSLocalizedString(@"APN_Message", nil);
|
||||
break;
|
||||
default:
|
||||
notification.alertBody = NSLocalizedString(@"APN_Message", nil);
|
||||
break;
|
||||
}
|
||||
|
||||
[[PushManager sharedManager] presentNotification:notification];
|
||||
} else {
|
||||
if ([Environment.preferences soundInForeground]) {
|
||||
AudioServicesPlayAlertSound(_newMessageSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -1,5 +1,5 @@
|
|||
#import "PreferencesUtil.h"
|
||||
#import "Constraints.h"
|
||||
#import "PreferencesUtil.h"
|
||||
|
||||
#define CALL_STREAM_DES_BUFFER_LEVEL_KEY @"CallStreamDesiredBufferLevel"
|
||||
|
||||
|
@ -27,11 +27,12 @@
|
|||
|
||||
- (NSTimeInterval)getCachedOrDefaultDesiredBufferDepth {
|
||||
id v = [self tryGetValueForKey:CALL_STREAM_DES_BUFFER_LEVEL_KEY];
|
||||
if (v == nil) return DEFAULT_CALL_STREAM_DES_BUFFER_LEVEL;
|
||||
if (v == nil)
|
||||
return DEFAULT_CALL_STREAM_DES_BUFFER_LEVEL;
|
||||
return [v doubleValue];
|
||||
}
|
||||
- (void)setCachedDesiredBufferDepth:(double)value {
|
||||
require(value >= 0);
|
||||
ows_require(value >= 0);
|
||||
[self setValueForKey:CALL_STREAM_DES_BUFFER_LEVEL_KEY toValue:@(value)];
|
||||
}
|
||||
|
||||
|
@ -93,7 +94,6 @@
|
|||
} else {
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)getHasArchivedAMessage {
|
||||
|
@ -103,7 +103,6 @@
|
|||
} else {
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (BOOL)hasRegisteredVOIPPush {
|
||||
|
@ -113,7 +112,6 @@
|
|||
} else {
|
||||
return YES;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (TSImageQuality)imageUploadQuality {
|
||||
|
@ -171,7 +169,8 @@
|
|||
}
|
||||
|
||||
- (NSString *)setAndGetCurrentVersion {
|
||||
NSString *currentVersion = [NSString stringWithFormat:@"%@", NSBundle.mainBundle.infoDictionary[@"CFBundleVersion"]];
|
||||
NSString *currentVersion =
|
||||
[NSString stringWithFormat:@"%@", NSBundle.mainBundle.infoDictionary[@"CFBundleVersion"]];
|
||||
[NSUserDefaults.standardUserDefaults setObject:currentVersion forKey:kSignalVersionKey];
|
||||
[NSUserDefaults.standardUserDefaults synchronize];
|
||||
return currentVersion;
|
||||
|
@ -192,8 +191,7 @@
|
|||
[self setValueForKey:PLAY_SOUND_IN_FOREGROUND_KEY toValue:@(enabled)];
|
||||
}
|
||||
|
||||
-(void)setNotificationPreviewType:(NotificationType)type
|
||||
{
|
||||
- (void)setNotificationPreviewType:(NotificationType)type {
|
||||
[self setValueForKey:NOTIFICATION_PREVIEW_TYPE_KEY toValue:@(type)];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#import "PropertyListPreferences.h"
|
||||
#import "Constraints.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "TSStorageHeaders.h"
|
||||
|
||||
#define SignalDatabaseCollection @"SignalPreferences"
|
||||
|
@ -15,17 +15,17 @@
|
|||
}
|
||||
|
||||
- (id)tryGetValueForKey:(NSString *)key {
|
||||
require(key != nil);
|
||||
ows_require(key != nil);
|
||||
return [TSStorageManager.sharedManager objectForKey:key inCollection:SignalDatabaseCollection];
|
||||
}
|
||||
- (void)setValueForKey:(NSString *)key toValue:(id)value {
|
||||
require(key != nil);
|
||||
ows_require(key != nil);
|
||||
|
||||
[TSStorageManager.sharedManager setObject:value forKey:key inCollection:SignalDatabaseCollection];
|
||||
}
|
||||
- (id)adjustAndTryGetNewValueForKey:(NSString *)key afterAdjuster:(id (^)(id))adjuster {
|
||||
require(key != nil);
|
||||
require(adjuster != nil);
|
||||
ows_require(key != nil);
|
||||
ows_require(adjuster != nil);
|
||||
@synchronized(self) {
|
||||
id oldValue = [self tryGetValueForKey:key];
|
||||
id newValue = adjuster(oldValue);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#import "Environment.h"
|
||||
#import "DH3KKeyAgreementProtocol.h"
|
||||
#import "EC25KeyAgreementProtocol.h"
|
||||
#import "Environment.h"
|
||||
|
||||
@interface Release : NSObject
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#import "Release.h"
|
||||
#import "DiscardingLog.h"
|
||||
#import "PhoneManager.h"
|
||||
#import "PhoneNumberUtil.h"
|
||||
#import "RecentCallManager.h"
|
||||
#import "Release.h"
|
||||
|
||||
#define RELEASE_ZRTP_CLIENT_ID @"Whisper 000 ".encodedAsAscii
|
||||
#define RELEASE_ZRTP_VERSION_ID @"1.10".encodedAsAscii
|
||||
|
@ -11,101 +11,75 @@
|
|||
#define TESTING_ZRTP_VERSION_ID @"1.10".encodedAsAscii
|
||||
|
||||
static unsigned char DH3K_PRIME[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,
|
||||
0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,
|
||||
0xCC,0x74,0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,
|
||||
0x34,0x04,0xDD,0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
|
||||
0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,
|
||||
0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,0xA6,0x37,0xED,0x6B,0x0B,0xFF,
|
||||
0x5C,0xB6,0xF4,0x06,0xB7,0xED,0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,
|
||||
0x9F,0x24,0x11,0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
|
||||
0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,0x1C,0x55,0xD3,
|
||||
0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,0x83,0x65,0x5D,0x23,0xDC,0xA3,
|
||||
0xAD,0x96,0x1C,0x62,0xF3,0x56,0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,
|
||||
0x96,0x96,0x6D,0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
|
||||
0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,0xE3,0x9E,0x77,
|
||||
0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,0xEC,0x07,0xA2,0x8F,0xB5,0xC5,
|
||||
0x5D,0xF0,0x6F,0x4C,0x52,0xC9,0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,
|
||||
0x95,0x49,0x7C,0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
|
||||
0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,0x04,0x50,0x7A,
|
||||
0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,0xEC,0xFB,0x85,0x04,0x58,0xDB,
|
||||
0xEF,0x0A,0x8A,0xEA,0x71,0x57,0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,
|
||||
0xE1,0xE4,0xC7,0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,
|
||||
0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,0xF1,0x2F,0xFA,
|
||||
0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,0x3E,0xC8,0x6A,0x64,0x52,0x1F,
|
||||
0x2B,0x18,0x17,0x7B,0x20,0x0C,0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,
|
||||
0x09,0x88,0xC0,0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,
|
||||
0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,0xA9,0x3A,0xD2,
|
||||
0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
};
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62,
|
||||
0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13,
|
||||
0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30,
|
||||
0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76,
|
||||
0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7,
|
||||
0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28,
|
||||
0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C,
|
||||
0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
|
||||
0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35,
|
||||
0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36,
|
||||
0xCE, 0x3B, 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5,
|
||||
0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7C,
|
||||
0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4,
|
||||
0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB,
|
||||
0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6,
|
||||
0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
|
||||
0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02,
|
||||
0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61,
|
||||
0x5D, 0x6C, 0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, 0x43,
|
||||
0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF};
|
||||
#define DH3K_GENERATOR 2
|
||||
|
||||
@implementation Release
|
||||
|
||||
+ (Environment *)releaseEnvironmentWithLogging:(id<Logging>)logging {
|
||||
// ErrorHandlerBlock errorDiscarder = ^(id error, id relatedInfo, bool causedTermination) {};
|
||||
ErrorHandlerBlock errorNoter = ^(id error, id relatedInfo, bool causedTermination) {DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination); };
|
||||
ErrorHandlerBlock errorNoter = ^(id error, id relatedInfo, bool causedTermination) {
|
||||
DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination);
|
||||
};
|
||||
|
||||
NSString *defaultRegion;
|
||||
#if TARGET_OS_IPHONE
|
||||
defaultRegion = [[PhoneNumberUtil sharedInstance].nbPhoneNumberUtil countryCodeByCarrier];
|
||||
|
||||
if ([defaultRegion isEqualToString:@"ZZ"]) {
|
||||
defaultRegion = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||||
}
|
||||
#else
|
||||
defaultRegion = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||||
#endif
|
||||
|
||||
|
||||
NSAssert([defaultRegion isKindOfClass:[NSString class]], @"");
|
||||
|
||||
return [Environment environmentWithLogging:logging
|
||||
return [Environment
|
||||
environmentWithLogging:logging
|
||||
andErrorNoter:errorNoter
|
||||
andServerPort:31337
|
||||
andMasterServerHostName:@"master.whispersystems.org"
|
||||
andDefaultRelayName:@"relay"
|
||||
andRelayServerHostNameSuffix:@"whispersystems.org"
|
||||
andCertificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
||||
andCurrentRegionCodeForPhoneNumbers:defaultRegion
|
||||
andSupportedKeyAgreementProtocols:[self supportedKeyAgreementProtocols]
|
||||
andPhoneManager:[PhoneManager phoneManagerWithErrorHandler:errorNoter]
|
||||
andRecentCallManager:[RecentCallManager new]
|
||||
andTestingAndLegacyOptions:@[ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER]
|
||||
andTestingAndLegacyOptions:@[
|
||||
ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER
|
||||
]
|
||||
andZrtpClientId:RELEASE_ZRTP_CLIENT_ID
|
||||
andZrtpVersionId:RELEASE_ZRTP_VERSION_ID
|
||||
andContactsManager:[ContactsManager new]];
|
||||
}
|
||||
|
||||
+ (Environment *)stagingEnvironmentWithLogging:(id<Logging>)logging {
|
||||
ErrorHandlerBlock errorNoter = ^(id error, id relatedInfo, bool causedTermination) {DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination); };
|
||||
ErrorHandlerBlock errorNoter = ^(id error, id relatedInfo, bool causedTermination) {
|
||||
DDLogError(@"%@: %@, %d", error, relatedInfo, causedTermination);
|
||||
};
|
||||
|
||||
NSString *defaultRegion;
|
||||
#if TARGET_OS_IPHONE
|
||||
defaultRegion = [[PhoneNumberUtil sharedInstance].nbPhoneNumberUtil countryCodeByCarrier];
|
||||
|
||||
if ([defaultRegion isEqualToString:@"ZZ"]) {
|
||||
defaultRegion = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||||
}
|
||||
#else
|
||||
defaultRegion = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode];
|
||||
#endif
|
||||
|
||||
|
||||
NSAssert([defaultRegion isKindOfClass:[NSString class]], @"");
|
||||
|
||||
return [Environment environmentWithLogging:logging
|
||||
return [Environment
|
||||
environmentWithLogging:logging
|
||||
andErrorNoter:errorNoter
|
||||
andServerPort:31337
|
||||
andMasterServerHostName:@"redphone-staging.whispersystems.org"
|
||||
andDefaultRelayName:@"redphone-staging-relay"
|
||||
andRelayServerHostNameSuffix:@"whispersystems.org"
|
||||
andCertificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
||||
andCurrentRegionCodeForPhoneNumbers:defaultRegion
|
||||
andSupportedKeyAgreementProtocols:[self supportedKeyAgreementProtocols]
|
||||
andPhoneManager:[PhoneManager phoneManagerWithErrorHandler:errorNoter]
|
||||
andRecentCallManager:[RecentCallManager new]
|
||||
andTestingAndLegacyOptions:@[ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER]
|
||||
andTestingAndLegacyOptions:@[
|
||||
ENVIRONMENT_LEGACY_OPTION_RTP_PADDING_BIT_IMPLIES_EXTENSION_BIT_AND_TWELVE_EXTRA_ZERO_BYTES_IN_HEADER
|
||||
]
|
||||
andZrtpClientId:RELEASE_ZRTP_CLIENT_ID
|
||||
andZrtpVersionId:RELEASE_ZRTP_VERSION_ID
|
||||
andContactsManager:[ContactsManager new]];
|
||||
|
@ -118,13 +92,13 @@ static unsigned char DH3K_PRIME[]={
|
|||
}
|
||||
|
||||
return [Environment environmentWithLogging:[DiscardingLog discardingLog]
|
||||
andErrorNoter:^(id error, id relatedInfo, bool causedTermination) {}
|
||||
andErrorNoter:^(id error, id relatedInfo, bool causedTermination) {
|
||||
}
|
||||
andServerPort:31337
|
||||
andMasterServerHostName:@"master.whispersystems.org"
|
||||
andDefaultRelayName:@"relay"
|
||||
andRelayServerHostNameSuffix:@"whispersystems.org"
|
||||
andCertificate:[Certificate certificateFromResourcePath:@"redphone" ofType:@"cer"]
|
||||
andCurrentRegionCodeForPhoneNumbers:@"US"
|
||||
andSupportedKeyAgreementProtocols:keyAgreementProtocols
|
||||
andPhoneManager:nil
|
||||
andRecentCallManager:nil
|
||||
|
@ -135,10 +109,7 @@ static unsigned char DH3K_PRIME[]={
|
|||
}
|
||||
|
||||
+ (NSArray *)supportedKeyAgreementProtocols {
|
||||
return @[
|
||||
[EC25KeyAgreementProtocol new],
|
||||
[Release supportedDH3KKeyAgreementProtocol]
|
||||
];
|
||||
return @[ [EC25KeyAgreementProtocol new], [Release supportedDH3KKeyAgreementProtocol] ];
|
||||
}
|
||||
|
||||
+ (DH3KKeyAgreementProtocol *)supportedDH3KKeyAgreementProtocol {
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#define SAVED_PASSWORD_KEY @"Password"
|
||||
#define SIGNALING_MAC_KEY @"Signaling Mac Key"
|
||||
#define SIGNALING_CIPHER_KEY @"Signaling Cipher Key"
|
||||
#define ZID_KEY @"ZID"
|
||||
#define ZID_LENGTH 12
|
||||
#define SIGNALING_EXTRA_KEY @"Signaling Extra Key"
|
||||
|
||||
@interface SignalKeyingStorage : NSObject
|
||||
|
@ -24,19 +22,10 @@
|
|||
+ (void)generateSignaling;
|
||||
+ (void)generateServerAuthPassword;
|
||||
|
||||
#pragma mark Registered Phone Number
|
||||
|
||||
+(PhoneNumber*)localNumber;
|
||||
+(void)setLocalNumberTo:(PhoneNumber*)localNumber;
|
||||
|
||||
#pragma mark Signaling Key
|
||||
|
||||
+ (int64_t)getAndIncrementOneTimeCounter;
|
||||
|
||||
#pragma mark Zid
|
||||
|
||||
+(Zid*)zid;
|
||||
|
||||
#pragma mark Server Auth
|
||||
|
||||
+ (NSString *)serverAuthPassword;
|
||||
|
@ -48,7 +37,8 @@
|
|||
|
||||
/**
|
||||
* Returns the extra keying material generated at registration.
|
||||
⚠️ Warning: Users of older versions of Signal (<= 2.1.1) might have the signaling cipher key as extra keing material.
|
||||
⚠️ Warning: Users of older versions of Signal (<= 2.1.1) might have the signaling cipher key as extra keing
|
||||
material.
|
||||
*
|
||||
* @return Extra keying material from registration time
|
||||
*/
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
// Created by Frederic Jacobs on 09/07/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
#import "Constraints.h"
|
||||
#import "CryptoTools.h"
|
||||
#import "SignalKeyingStorage.h"
|
||||
#import "Constraints.h"
|
||||
#import "TSStorageManager.h"
|
||||
#import "Util.h"
|
||||
|
||||
|
@ -21,14 +21,14 @@
|
|||
@implementation SignalKeyingStorage
|
||||
|
||||
+ (void)generateServerAuthPassword {
|
||||
[self storeString:[[CryptoTools generateSecureRandomData:SAVED_PASSWORD_LENGTH] encodedAsBase64] forKey:SAVED_PASSWORD_KEY];
|
||||
[self storeString:[[CryptoTools generateSecureRandomData:SAVED_PASSWORD_LENGTH] encodedAsBase64]
|
||||
forKey:SAVED_PASSWORD_KEY];
|
||||
}
|
||||
|
||||
+ (void)generateSignaling {
|
||||
[self storeData:[CryptoTools generateSecureRandomData:SIGNALING_MAC_KEY_LENGTH] forKey:SIGNALING_MAC_KEY];
|
||||
[self storeData:[CryptoTools generateSecureRandomData:SIGNALING_CIPHER_KEY_LENGTH] forKey:SIGNALING_CIPHER_KEY];
|
||||
[self storeData:[CryptoTools generateSecureRandomData:SIGNALING_EXTRA_KEY_LENGTH] forKey:SIGNALING_EXTRA_KEY];
|
||||
[self storeData:[CryptoTools generateSecureRandomData:ZID_LENGTH] forKey:ZID_KEY];
|
||||
}
|
||||
|
||||
+ (int64_t)getAndIncrementOneTimeCounter {
|
||||
|
@ -39,31 +39,6 @@
|
|||
return newCounter;
|
||||
}
|
||||
|
||||
+ (void)setLocalNumberTo:(PhoneNumber *)localNumber{
|
||||
require(localNumber != nil);
|
||||
require(localNumber.toE164!= nil);
|
||||
|
||||
NSString *e164 = localNumber.toE164;
|
||||
[self storeString:e164 forKey:LOCAL_NUMBER_KEY];
|
||||
}
|
||||
|
||||
+ (PhoneNumber *)localNumber{
|
||||
NSString *lnString = [self stringForKey:LOCAL_NUMBER_KEY];
|
||||
checkOperation(lnString != nil );
|
||||
PhoneNumber *num = [PhoneNumber tryParsePhoneNumberFromE164:lnString];
|
||||
return lnString?num:nil;
|
||||
}
|
||||
|
||||
+(Zid *)zid{
|
||||
NSData *data = [self dataForKey:ZID_KEY];
|
||||
if (data.length != ZID_LENGTH) {
|
||||
DDLogError(@"ZID length is incorrect. Is %lu, should be %d", (unsigned long)data.length, ZID_LENGTH);
|
||||
}
|
||||
Zid *zid = [Zid zidWithData:data];
|
||||
return zid;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)signalingCipherKey {
|
||||
return [self dataForKey:SIGNALING_CIPHER_KEY andVerifyLength:SIGNALING_CIPHER_KEY_LENGTH];
|
||||
}
|
||||
|
@ -80,7 +55,9 @@
|
|||
NSString *password = [self stringForKey:SAVED_PASSWORD_KEY];
|
||||
NSData *data = [password decodedAsBase64Data];
|
||||
if (data.length != SAVED_PASSWORD_LENGTH) {
|
||||
DDLogError(@"The server password has incorrect length. Is %lu but should be %d", (unsigned long)data.length, SAVED_PASSWORD_LENGTH);
|
||||
DDLogError(@"The server password has incorrect length. Is %lu but should be %d",
|
||||
(unsigned long)data.length,
|
||||
SAVED_PASSWORD_LENGTH);
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
#import "LockInteractionController.h"
|
||||
#import "PreferencesUtil.h"
|
||||
#import "PushManager.h"
|
||||
#import "TSAccountManager.h"
|
||||
#import "TSNetworkManager.h"
|
||||
#import "RecentCallManager.h"
|
||||
#import "SignalKeyingStorage.h"
|
||||
#import "TSAccountManager.h"
|
||||
#import "TSNetworkManager.h"
|
||||
|
||||
#define NEEDS_TO_REGISTER_PUSH_KEY @"Register For Push"
|
||||
#define NEEDS_TO_REGISTER_ATTRIBUTES @"Register Attributes"
|
||||
|
@ -33,8 +33,8 @@
|
|||
+ (void)performUpdateCheck {
|
||||
NSString *previousVersion = Environment.preferences.lastRanVersion;
|
||||
NSString *currentVersion = [Environment.preferences setAndGetCurrentVersion];
|
||||
BOOL VOIPRegistration = [[PushManager sharedManager] supportsVOIPPush]
|
||||
&& ![Environment.preferences hasRegisteredVOIPPush];
|
||||
BOOL VOIPRegistration =
|
||||
[[PushManager sharedManager] supportsVOIPPush] && ![Environment.preferences hasRegisteredVOIPPush];
|
||||
|
||||
if (!previousVersion) {
|
||||
DDLogError(@"No previous version found. Possibly first launch since install.");
|
||||
|
@ -63,14 +63,18 @@
|
|||
NSArray *cachesDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||
NSString *bloomFilterPath = [[cachesDir objectAtIndex:0] stringByAppendingPathComponent:@"bloomfilter"];
|
||||
[fm removeItemAtPath:bloomFilterPath error:nil];
|
||||
[[TSStorageManager sharedManager].dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
|
||||
[[TSStorageManager sharedManager]
|
||||
.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[transaction removeAllObjectsInCollection:@"TSRecipient"];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL) isVersion:(NSString *)thisVersionString atLeast:(NSString *)openLowerBoundVersionString andLessThan:(NSString *)closedUpperBoundVersionString {
|
||||
return [self isVersion:thisVersionString atLeast:openLowerBoundVersionString] && [self isVersion:thisVersionString lessThan:closedUpperBoundVersionString];
|
||||
+ (BOOL)isVersion:(NSString *)thisVersionString
|
||||
atLeast:(NSString *)openLowerBoundVersionString
|
||||
andLessThan:(NSString *)closedUpperBoundVersionString {
|
||||
return [self isVersion:thisVersionString atLeast:openLowerBoundVersionString] &&
|
||||
[self isVersion:thisVersionString lessThan:closedUpperBoundVersionString];
|
||||
}
|
||||
|
||||
+ (BOOL)isVersion:(NSString *)thisVersionString atLeast:(NSString *)thatVersionString {
|
||||
|
@ -84,15 +88,18 @@
|
|||
#pragma mark Upgrading to 2.1 - Needs to register VOIP token + Removing video cache folder
|
||||
|
||||
+ (void)nonBlockingPushRegistration {
|
||||
__block failedVerificationBlock failedBlock = ^(NSError *error) {
|
||||
__block failedBlock failedBlock = ^(NSError *error) {
|
||||
DDLogError(@"Failed to register VOIP push token: %@", error.debugDescription);
|
||||
};
|
||||
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSData *pushToken, NSData *voipToken) {
|
||||
[TSAccountManager registerForPushNotifications:pushToken voipToken:voipToken success:^{
|
||||
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSString *pushToken, NSString *voipToken) {
|
||||
[TSAccountManager registerForPushNotifications:pushToken
|
||||
voipToken:voipToken
|
||||
success:^{
|
||||
DDLogWarn(@"Registered for VOIP Push.");
|
||||
} failure:failedBlock];
|
||||
} failure:failedBlock];
|
||||
|
||||
}
|
||||
failure:failedBlock];
|
||||
}
|
||||
failure:failedBlock];
|
||||
}
|
||||
|
||||
+ (void)blockingPushRegistration {
|
||||
|
@ -103,17 +110,21 @@
|
|||
|
||||
__block BOOL success;
|
||||
|
||||
__block failedVerificationBlock failedBlock = ^(NSError *error) {
|
||||
__block failedBlock failedBlock = ^(NSError *error) {
|
||||
success = NO;
|
||||
dispatch_semaphore_signal(sema);
|
||||
};
|
||||
|
||||
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSData *pushToken, NSData *voipToken) {
|
||||
[TSAccountManager registerForPushNotifications:pushToken voipToken:voipToken success:^{
|
||||
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSString *pushToken, NSString *voipToken) {
|
||||
[TSAccountManager registerForPushNotifications:pushToken
|
||||
voipToken:voipToken
|
||||
success:^{
|
||||
success = YES;
|
||||
dispatch_semaphore_signal(sema);
|
||||
} failure:failedBlock];
|
||||
} failure:failedBlock];
|
||||
}
|
||||
failure:failedBlock];
|
||||
}
|
||||
failure:failedBlock];
|
||||
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
|
||||
|
@ -129,7 +140,6 @@
|
|||
}
|
||||
retryBlock:retryBlock
|
||||
usesNetwork:YES];
|
||||
|
||||
}
|
||||
|
||||
+ (BOOL)needsRegisterPush {
|
||||
|
@ -166,11 +176,13 @@
|
|||
|
||||
__block BOOL success;
|
||||
|
||||
TSUpdateAttributesRequest *request = [[TSUpdateAttributesRequest alloc] initWithUpdatedAttributes];
|
||||
[[TSNetworkManager sharedManager] queueAuthenticatedRequest:request success:^(NSURLSessionDataTask *task, id responseObject) {
|
||||
TSUpdateAttributesRequest *request = [[TSUpdateAttributesRequest alloc] initWithUpdatedAttributesWithVoice:YES];
|
||||
[[TSNetworkManager sharedManager] makeRequest:request
|
||||
success:^(NSURLSessionDataTask *task, id responseObject) {
|
||||
success = YES;
|
||||
dispatch_semaphore_signal(sema);
|
||||
} failure:^(NSURLSessionDataTask *task, NSError *error) {
|
||||
}
|
||||
failure:^(NSURLSessionDataTask *task, NSError *error) {
|
||||
success = NO;
|
||||
DDLogError(@"Updating attributess failed with error: %@", error.description);
|
||||
dispatch_semaphore_signal(sema);
|
||||
|
@ -191,7 +203,6 @@
|
|||
}
|
||||
retryBlock:retryBlock
|
||||
usesNetwork:YES];
|
||||
|
||||
}
|
||||
|
||||
#pragma mark Util
|
||||
|
|
|
@ -100,21 +100,3 @@
|
|||
#ifdef NSFoundationVersionNumber_iOS_9
|
||||
#define _iOS_9 NSFoundationVersionNumber_iOS_9
|
||||
#endif
|
||||
|
||||
/**
|
||||
Add a Singelton implementation to the .m File
|
||||
*/
|
||||
|
||||
#define MacrosSingletonImplemention \
|
||||
+ (instancetype)sharedInstance { \
|
||||
\
|
||||
static dispatch_once_t onceToken; \
|
||||
static id sharedInstance = nil; \
|
||||
dispatch_once(&onceToken, ^{ \
|
||||
sharedInstance = [self.class new]; \
|
||||
}); \
|
||||
\
|
||||
return sharedInstance; \
|
||||
}
|
||||
|
||||
#define MacrosSingletonInterface + (instancetype)sharedInstance;
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
//
|
||||
// AFSecurityPolicyNone.h
|
||||
// Signal
|
||||
//
|
||||
// Created by Fred on 01/09/15.
|
||||
// Copyright © 2015 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AFSecurityPolicy.h"
|
||||
#import <SocketRocket/SRWebSocket.h>
|
||||
|
||||
@interface AFSecurityOWSPolicy : AFSecurityPolicy <CertificateVerifier>
|
||||
|
||||
+ (instancetype)OWS_PinningPolicy;
|
||||
|
||||
@end
|
|
@ -1,100 +0,0 @@
|
|||
//
|
||||
// AFSecurityPolicyNone.m
|
||||
// Signal
|
||||
//
|
||||
// Created by Fred on 01/09/15.
|
||||
// Copyright © 2015 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AFSecurityOWSPolicy.h"
|
||||
#import <AssertMacros.h>
|
||||
|
||||
@implementation AFSecurityOWSPolicy
|
||||
|
||||
+ (instancetype)OWS_PinningPolicy {
|
||||
static AFSecurityOWSPolicy *sharedMyManager = nil;
|
||||
@synchronized(self) {
|
||||
if (sharedMyManager == nil)
|
||||
sharedMyManager = [[self alloc] initWithOWSPolicy];
|
||||
}
|
||||
return sharedMyManager;
|
||||
}
|
||||
|
||||
- (instancetype)initWithOWSPolicy {
|
||||
self = [[super class] defaultPolicy];
|
||||
|
||||
if (self) {
|
||||
self.pinnedCertificates = @[[self certificateDataForService:@"textsecure"],
|
||||
[self certificateDataForService:@"redphone"]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSArray*)certs {
|
||||
return @[(__bridge id)[self certificateForService:@"textsecure"]];
|
||||
}
|
||||
|
||||
- (NSData*)certificateDataForService:(NSString*)service
|
||||
{
|
||||
SecCertificateRef certRef = [self certificateForService:service];
|
||||
return (__bridge_transfer NSData *)SecCertificateCopyData(certRef);
|
||||
}
|
||||
|
||||
- (SecCertificateRef)certificateForService:(NSString*)service {
|
||||
NSString *path = [NSBundle.mainBundle pathForResource:service ofType:@"cer"];
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
@throw [NSException exceptionWithName:@"Missing server certificate"
|
||||
reason:[NSString stringWithFormat:@"Missing signing certificate for service %@", service]
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
NSData *certificateData = [NSData dataWithContentsOfFile:path];
|
||||
return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certificateData));
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
|
||||
forDomain:(NSString *)domain
|
||||
{
|
||||
NSMutableArray *policies = [NSMutableArray array];
|
||||
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
|
||||
|
||||
if (SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies) != errSecSuccess){
|
||||
DDLogError(@"The trust policy couldn't be set.");
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSMutableArray *pinnedCertificates = [NSMutableArray array];
|
||||
for (NSData *certificateData in self.pinnedCertificates) {
|
||||
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
|
||||
}
|
||||
|
||||
if (SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates) != errSecSuccess){
|
||||
DDLogError(@"The anchor certificates couldn't be set.");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!AFServerTrustIsValid(serverTrust)) {
|
||||
NSLog(@"Fuck it, not trusted");
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
|
||||
BOOL isValid = NO;
|
||||
SecTrustResultType result;
|
||||
__Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out);
|
||||
|
||||
isValid = (result == kSecTrustResultUnspecified);
|
||||
|
||||
_out:
|
||||
return isValid;
|
||||
}
|
||||
|
||||
@end
|
|
@ -10,20 +10,20 @@
|
|||
return [IpAddress ipv4AddressFromString:LOCAL_HOST_IP];
|
||||
}
|
||||
+(IpAddress*) ipAddressFromString:(NSString*)text {
|
||||
require(text != nil);
|
||||
ows_require(text != nil);
|
||||
if ([IpAddress isIpv4Text:text]) return [IpAddress ipv4AddressFromString:text];
|
||||
if ([IpAddress isIpv6Text:text]) return [IpAddress ipv6AddressFromString:text];
|
||||
[BadArgument raise:[NSString stringWithFormat:@"Invalid IP address: %@", text]];
|
||||
return nil;
|
||||
}
|
||||
+(IpAddress*) tryGetIpAddressFromString:(NSString*)text {
|
||||
require(text != nil);
|
||||
ows_require(text != nil);
|
||||
if ([IpAddress isIpv4Text:text]) return [IpAddress ipv4AddressFromString:text];
|
||||
if ([IpAddress isIpv6Text:text]) return [IpAddress ipv6AddressFromString:text];
|
||||
return nil;
|
||||
}
|
||||
+(IpAddress*) ipv4AddressFromString:(NSString*)text {
|
||||
require(text != nil);
|
||||
ows_require(text != nil);
|
||||
|
||||
IpAddress* a = [IpAddress new];
|
||||
|
||||
|
@ -45,7 +45,7 @@
|
|||
return a;
|
||||
}
|
||||
+(IpAddress*) ipv6AddressFromString:(NSString*)text {
|
||||
require(text != nil);
|
||||
ows_require(text != nil);
|
||||
|
||||
IpAddress* a = [IpAddress new];
|
||||
|
||||
|
@ -112,12 +112,12 @@
|
|||
}
|
||||
|
||||
+(bool) isIpv4Text:(NSString*)text {
|
||||
require(text != nil);
|
||||
ows_require(text != nil);
|
||||
struct sockaddr_in s;
|
||||
return inet_pton(AF_INET, [text UTF8String], &(s.sin_addr)) == 1;
|
||||
}
|
||||
+(bool) isIpv6Text:(NSString*)text {
|
||||
require(text != nil);
|
||||
ows_require(text != nil);
|
||||
struct sockaddr_in6 s;
|
||||
return inet_pton(AF_INET6, [text UTF8String], &(s.sin6_addr)) == 1;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
+(IpEndPoint*) ipEndPointAtAddress:(IpAddress*)address
|
||||
onPort:(in_port_t)port {
|
||||
require(address != nil);
|
||||
ows_require(address != nil);
|
||||
IpEndPoint* p = [IpEndPoint new];
|
||||
p->address = address;
|
||||
p->port = port;
|
||||
|
@ -28,8 +28,8 @@
|
|||
}
|
||||
|
||||
+(IpEndPoint*) ipEndPointFromSockaddrData:(NSData*)sockaddrData {
|
||||
require(sockaddrData != nil);
|
||||
require(sockaddrData.length >= sizeof(struct sockaddr));
|
||||
ows_require(sockaddrData != nil);
|
||||
ows_require(sockaddrData.length >= sizeof(struct sockaddr));
|
||||
|
||||
struct sockaddr s;
|
||||
memcpy(&s, [sockaddrData bytes], sizeof(struct sockaddr));
|
||||
|
@ -41,8 +41,8 @@
|
|||
return nil;
|
||||
}
|
||||
+(IpEndPoint*) ipv4EndPointFromSockaddrData:(NSData*)sockaddrData {
|
||||
require(sockaddrData != nil);
|
||||
require(sockaddrData.length >= sizeof(struct sockaddr_in));
|
||||
ows_require(sockaddrData != nil);
|
||||
ows_require(sockaddrData.length >= sizeof(struct sockaddr_in));
|
||||
|
||||
struct sockaddr_in s;
|
||||
memcpy(&s, [sockaddrData bytes], sizeof(struct sockaddr_in));
|
||||
|
@ -50,8 +50,8 @@
|
|||
return [[IpAddress ipv4AddressFromSockaddr:s] withPort:ntohs(s.sin_port)];
|
||||
}
|
||||
+(IpEndPoint*) ipv6EndPointFromSockaddrData:(NSData*)sockaddrData {
|
||||
require(sockaddrData != nil);
|
||||
require(sockaddrData.length >= sizeof(struct sockaddr_in6));
|
||||
ows_require(sockaddrData != nil);
|
||||
ows_require(sockaddrData.length >= sizeof(struct sockaddr_in6));
|
||||
|
||||
struct sockaddr_in6 s;
|
||||
memcpy(&s, [sockaddrData bytes], sizeof(struct sockaddr_in6));
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
+(PacketHandler*) packetHandler:(PacketHandlerBlock)dataHandler
|
||||
withErrorHandler:(ErrorHandlerBlock)errorHandler {
|
||||
|
||||
require(dataHandler != nil);
|
||||
require(errorHandler != nil);
|
||||
ows_require(dataHandler != nil);
|
||||
ows_require(errorHandler != nil);
|
||||
|
||||
PacketHandler* p = [PacketHandler new];
|
||||
p->dataHandler = [dataHandler copy];
|
||||
|
|
|
@ -27,8 +27,7 @@
|
|||
#define Signal_Message_MarkAsRead_Identifier @"Signal_Message_MarkAsRead"
|
||||
|
||||
typedef void (^failedPushRegistrationBlock)(NSError *error);
|
||||
typedef void (^pushTokensSuccessBlock)(NSData *pushToken, NSData *voipToken);
|
||||
typedef void (^registrationTokensSuccessBlock)(NSData *pushToken, NSData *voipToken, NSString *signupToken);
|
||||
typedef void (^pushTokensSuccessBlock)(NSString *pushToken, NSString *voipToken);
|
||||
|
||||
/**
|
||||
* The Push Manager is responsible for registering the device for Signal push notifications.
|
||||
|
@ -38,15 +37,6 @@ typedef void (^registrationTokensSuccessBlock)(NSData *pushToken, NSData *voipTo
|
|||
|
||||
+ (PushManager *)sharedManager;
|
||||
|
||||
/**
|
||||
* Registers the push token with the RedPhone server, then returns the push token and a signup token to be used to register with TextSecure.
|
||||
*
|
||||
* @param success Success completion block - registering with TextSecure server
|
||||
* @param failure Failure completion block
|
||||
*/
|
||||
|
||||
- (void)registrationAndRedPhoneTokenRequestWithSuccess:(registrationTokensSuccessBlock)success failure:(failedPushRegistrationBlock)failure;
|
||||
|
||||
/**
|
||||
* Returns the Push Notification Token of this device
|
||||
*
|
||||
|
@ -57,7 +47,8 @@ typedef void (^registrationTokensSuccessBlock)(NSData *pushToken, NSData *voipTo
|
|||
- (void)requestPushTokenWithSuccess:(pushTokensSuccessBlock)success failure:(void (^)(NSError *))failure;
|
||||
|
||||
/**
|
||||
* Registers for Users Notifications. By doing this on launch, we are sure that the correct categories of user notifications is registered.
|
||||
* Registers for Users Notifications. By doing this on launch, we are sure that the correct categories of user
|
||||
* notifications is registered.
|
||||
*/
|
||||
|
||||
- (void)validateUserNotificationSettings;
|
||||
|
@ -78,9 +69,18 @@ typedef void (^registrationTokensSuccessBlock)(NSData *pushToken, NSData *voipTo
|
|||
#pragma mark Push Notifications Delegate Methods
|
||||
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
|
||||
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler;
|
||||
- (void)application:(UIApplication *)application
|
||||
didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
|
||||
- (void)application:(UIApplication *)application
|
||||
handleActionWithIdentifier:(NSString *)identifier
|
||||
forLocalNotification:(UILocalNotification *)notification
|
||||
completionHandler:(void (^)())completionHandler;
|
||||
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification;
|
||||
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler;
|
||||
- (void)application:(UIApplication *)application
|
||||
handleActionWithIdentifier:(NSString *)identifier
|
||||
forLocalNotification:(UILocalNotification *)notification
|
||||
withResponseInfo:(NSDictionary *)responseInfo
|
||||
completionHandler:(void (^)())completionHandler;
|
||||
|
||||
@end
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
#import "AppDelegate.h"
|
||||
#import "ContactsManager.h"
|
||||
#import "InCallViewController.h"
|
||||
#import "NSData+ows_StripToken.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "TSMessagesManager+sendMessages.h"
|
||||
#import "NotificationTracker.h"
|
||||
|
||||
#import "PreferencesUtil.h"
|
||||
#import "PushManager.h"
|
||||
#import "RPServerRequestsManager.h"
|
||||
#import "TSMessagesManager+sendMessages.h"
|
||||
#import "TSSocketManager.h"
|
||||
|
||||
#define pushManagerDomain @"org.whispersystems.pushmanager"
|
||||
|
@ -35,8 +35,7 @@
|
|||
|
||||
@implementation PushManager
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
+ (instancetype)sharedManager {
|
||||
static PushManager *sharedManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
|
@ -45,8 +44,7 @@
|
|||
return sharedManager;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.notificationTracker = [NotificationTracker notificationTracker];
|
||||
|
@ -98,9 +96,12 @@
|
|||
notification.alertBody = @"☎️ ";
|
||||
|
||||
if ([prefs notificationPreviewType] == NotificationNoNameNoPreview) {
|
||||
notification.alertBody = [notification.alertBody stringByAppendingString:NSLocalizedString(@"INCOMING_CALL", nil)];
|
||||
notification.alertBody =
|
||||
[notification.alertBody stringByAppendingString:NSLocalizedString(@"INCOMING_CALL", nil)];
|
||||
} else {
|
||||
notification.alertBody = [notification.alertBody stringByAppendingString:[NSString stringWithFormat:NSLocalizedString(@"INCOMING_CALL_FROM", nil), displayName]];
|
||||
notification.alertBody = [notification.alertBody
|
||||
stringByAppendingString:[NSString stringWithFormat:NSLocalizedString(@"INCOMING_CALL_FROM", nil),
|
||||
displayName]];
|
||||
}
|
||||
|
||||
notification.category = Signal_Call_Category;
|
||||
|
@ -134,17 +135,19 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* This code should in principle never be called. The only cases where it would be called are with the old-style "content-available:1" pushes if there is no "voip" token registered
|
||||
* This code should in principle never be called. The only cases where it would be called are with the old-style
|
||||
* "content-available:1" pushes if there is no "voip" token registered
|
||||
*
|
||||
*/
|
||||
|
||||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
- (void)application:(UIApplication *)application
|
||||
didReceiveRemoteNotification:(NSDictionary *)userInfo
|
||||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
if ([self isRedPhonePush:userInfo]) {
|
||||
[self application:application didReceiveRemoteNotification:userInfo];
|
||||
}
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC),
|
||||
dispatch_get_main_queue(), ^{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
completionHandler(UIBackgroundFetchResultNewData);
|
||||
});
|
||||
}
|
||||
|
@ -156,25 +159,42 @@
|
|||
}
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
|
||||
[self application:application handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:@{} completionHandler:completionHandler];
|
||||
- (void)application:(UIApplication *)application
|
||||
handleActionWithIdentifier:(NSString *)identifier
|
||||
forLocalNotification:(UILocalNotification *)notification
|
||||
completionHandler:(void (^)())completionHandler {
|
||||
[self application:application
|
||||
handleActionWithIdentifier:identifier
|
||||
forLocalNotification:notification
|
||||
withResponseInfo:@{}
|
||||
completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler {
|
||||
|
||||
|
||||
- (void)application:(UIApplication *)application
|
||||
handleActionWithIdentifier:(NSString *)identifier
|
||||
forLocalNotification:(UILocalNotification *)notification
|
||||
withResponseInfo:(NSDictionary *)responseInfo
|
||||
completionHandler:(void (^)())completionHandler {
|
||||
if ([identifier isEqualToString:Signal_Message_Reply_Identifier]) {
|
||||
NSString *threadId = notification.userInfo[Signal_Thread_UserInfo_Key];
|
||||
|
||||
if (threadId) {
|
||||
TSThread *thread = [TSThread fetchObjectWithUniqueID:threadId];
|
||||
TSOutgoingMessage *message = [[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread messageBody:responseInfo[UIUserNotificationActionResponseTypedTextKey] attachments:nil];
|
||||
[[TSMessagesManager sharedManager] sendMessage:message inThread:thread success:^{
|
||||
TSOutgoingMessage *message =
|
||||
[[TSOutgoingMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
inThread:thread
|
||||
messageBody:responseInfo[UIUserNotificationActionResponseTypedTextKey]
|
||||
attachments:nil];
|
||||
[[TSMessagesManager sharedManager] sendMessage:message
|
||||
inThread:thread
|
||||
success:^{
|
||||
[self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler];
|
||||
[[[[Environment getCurrent] signalsViewController] tableView] reloadData];
|
||||
} failure:^{
|
||||
}
|
||||
failure:^{
|
||||
UILocalNotification *failedSendNotif = [[UILocalNotification alloc] init];
|
||||
failedSendNotif.alertBody = [NSString stringWithFormat:NSLocalizedString(@"NOTIFICATION_SEND_FAILED", nil), [thread name]];
|
||||
failedSendNotif.alertBody =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"NOTIFICATION_SEND_FAILED", nil), [thread name]];
|
||||
failedSendNotif.userInfo = @{Signal_Thread_UserInfo_Key : thread.uniqueId};
|
||||
[[PushManager sharedManager] presentNotification:failedSendNotif];
|
||||
completionHandler();
|
||||
|
@ -187,8 +207,7 @@
|
|||
} else if ([identifier isEqualToString:Signal_Call_Decline_Identifier]) {
|
||||
[Environment.phoneManager hangupOrDenyCall];
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC),
|
||||
dispatch_get_main_queue(), ^{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
|
||||
completionHandler();
|
||||
});
|
||||
} else if ([identifier isEqualToString:Signal_CallBack_Identifier]) {
|
||||
|
@ -203,16 +222,17 @@
|
|||
[Environment messageThreadId:threadId];
|
||||
completionHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)markAllInThreadAsRead:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler {
|
||||
NSString *threadId = userInfo[Signal_Thread_UserInfo_Key];
|
||||
|
||||
TSThread *thread = [TSThread fetchObjectWithUniqueID:threadId];
|
||||
[[TSStorageManager sharedManager].dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
|
||||
[[TSStorageManager sharedManager]
|
||||
.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[thread markAllAsReadWithTransaction:transaction];
|
||||
} completionBlock:^{
|
||||
}
|
||||
completionBlock:^{
|
||||
[[[Environment getCurrent] signalsViewController] updateInboxCountLabel];
|
||||
[self cancelNotificationsWithThreadId:threadId];
|
||||
|
||||
|
@ -233,13 +253,15 @@
|
|||
|
||||
#pragma mark PushKit
|
||||
|
||||
- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type
|
||||
{
|
||||
[[PushManager sharedManager].pushKitNotificationFutureSource trySetResult:credentials.token];
|
||||
- (void)pushRegistry:(PKPushRegistry *)registry
|
||||
didUpdatePushCredentials:(PKPushCredentials *)credentials
|
||||
forType:(NSString *)type {
|
||||
[[PushManager sharedManager].pushKitNotificationFutureSource trySetResult:[credentials.token ows_tripToken]];
|
||||
}
|
||||
|
||||
-(void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type
|
||||
{
|
||||
- (void)pushRegistry:(PKPushRegistry *)registry
|
||||
didReceiveIncomingPushWithPayload:(PKPushPayload *)payload
|
||||
forType:(NSString *)type {
|
||||
[self application:[UIApplication sharedApplication] didReceiveRemoteNotification:payload.dictionaryPayload];
|
||||
}
|
||||
|
||||
|
@ -268,101 +290,47 @@
|
|||
|
||||
#pragma mark Register device for Push Notification locally
|
||||
|
||||
- (TOCFuture *)registerPushNotificationFuture
|
||||
{
|
||||
- (TOCFuture *)registerPushNotificationFuture {
|
||||
self.pushNotificationFutureSource = [TOCFutureSource new];
|
||||
[UIApplication.sharedApplication registerForRemoteNotifications];
|
||||
|
||||
return self.pushNotificationFutureSource.future;
|
||||
}
|
||||
|
||||
- (void)requestPushTokenWithSuccess:(pushTokensSuccessBlock)success failure:(failedPushRegistrationBlock)failure
|
||||
{
|
||||
- (void)requestPushTokenWithSuccess:(pushTokensSuccessBlock)success failure:(failedPushRegistrationBlock)failure {
|
||||
if (!self.wantRemoteNotifications) {
|
||||
success(@"FakeToken", @"FakePushToken");
|
||||
return;
|
||||
}
|
||||
|
||||
TOCFuture *requestPushTokenFuture = [self registerPushNotificationFuture];
|
||||
|
||||
[requestPushTokenFuture catchDo:^(id failureObj) {
|
||||
[self.missingPermissionsAlertView show];
|
||||
failure(failureObj);
|
||||
DDLogError(@"This should not happen on iOS8. No push token was provided");
|
||||
[requestPushTokenFuture thenDo:^(NSData *pushTokenData) {
|
||||
NSString *pushToken = [pushTokenData ows_tripToken];
|
||||
TOCFuture *pushKit = [self registerPushKitNotificationFuture];
|
||||
|
||||
[pushKit thenDo:^(NSString *voipToken) {
|
||||
success(pushToken, voipToken);
|
||||
}];
|
||||
|
||||
[requestPushTokenFuture thenDo:^(NSData *pushToken) {
|
||||
TOCFuture *voipPushTokenFuture = [self registerPushKitNotificationFuture];
|
||||
|
||||
[voipPushTokenFuture finallyDo:^(TOCFuture *completed) {
|
||||
NSData *voipPushToken = completed.hasResult?completed.forceGetResult:nil;
|
||||
|
||||
TOCFuture *registerPushTokenFuture = [self registerForPushFutureWithToken:pushToken voipToken:voipPushToken];
|
||||
|
||||
[registerPushTokenFuture catchDo:^(id failureObj) {
|
||||
failure(failureObj);
|
||||
}];
|
||||
|
||||
[registerPushTokenFuture thenDo:^(id value) {
|
||||
TOCFuture *userRegistration = [self registerForUserNotificationsFuture];
|
||||
|
||||
[userRegistration thenDo:^(UIUserNotificationSettings *userNotificationSettings) {
|
||||
success(pushToken, voipPushToken);
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)registrationAndRedPhoneTokenRequestWithSuccess:(registrationTokensSuccessBlock)success
|
||||
failure:(failedPushRegistrationBlock)failure
|
||||
{
|
||||
if (!self.wantRemoteNotifications) {
|
||||
NSData *fakeToken = [@"Fake PushToken" dataUsingEncoding:NSUTF8StringEncoding];
|
||||
[self registerTokenWithRedPhoneServer:fakeToken
|
||||
voipToken:fakeToken
|
||||
withSuccess:success
|
||||
failure:failure];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
[self requestPushTokenWithSuccess:^(NSData *pushToken, NSData *voipToken) {
|
||||
[self registerTokenWithRedPhoneServer:pushToken voipToken:voipToken withSuccess:success failure:failure];
|
||||
} failure:^(NSError *error) {
|
||||
[self.missingPermissionsAlertView show];
|
||||
failure([NSError errorWithDomain:pushManagerDomain code:400 userInfo:@{}]);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)registerTokenWithRedPhoneServer:(NSData*)pushToken
|
||||
voipToken:(NSData*)voipToken
|
||||
withSuccess:(registrationTokensSuccessBlock)success
|
||||
failure:(failedPushRegistrationBlock)failure
|
||||
{
|
||||
[RPServerRequestsManager.sharedInstance performRequest:[RPAPICall requestTextSecureVerificationCode]
|
||||
success:^(NSURLSessionDataTask *task, id responseObject) {
|
||||
NSError *error;
|
||||
|
||||
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:&error];
|
||||
NSString *tsToken = dictionary[@"token"];
|
||||
|
||||
if (!tsToken || !pushToken || error) {
|
||||
[pushKit catchDo:^(NSError *error) {
|
||||
failure(error);
|
||||
return;
|
||||
}
|
||||
}];
|
||||
}];
|
||||
|
||||
success(pushToken, voipToken, tsToken);
|
||||
}
|
||||
failure:^(NSURLSessionDataTask *task, NSError *error) {
|
||||
[requestPushTokenFuture catchDo:^(NSError *error) {
|
||||
failure(error);
|
||||
}];
|
||||
}
|
||||
|
||||
- (TOCFuture *)registerForUserNotificationsFuture
|
||||
{
|
||||
- (TOCFuture *)registerForUserNotificationsFuture {
|
||||
self.userNotificationFutureSource = [TOCFutureSource new];
|
||||
|
||||
UIUserNotificationSettings *settings =
|
||||
[UIUserNotificationSettings settingsForTypes:(UIUserNotificationType)[self allNotificationTypes]
|
||||
categories:[NSSet setWithObjects:[self userNotificationsCallCategory],
|
||||
[self fullNewMessageNotificationCategory],
|
||||
[self userNotificationsCallBackCategory], nil]];
|
||||
[self userNotificationsCallBackCategory],
|
||||
nil]];
|
||||
|
||||
[UIApplication.sharedApplication registerUserNotificationSettings:settings];
|
||||
return self.userNotificationFutureSource.future;
|
||||
|
@ -435,64 +403,28 @@
|
|||
return callCategory;
|
||||
}
|
||||
|
||||
- (BOOL)needToRegisterForRemoteNotifications
|
||||
{
|
||||
- (BOOL)needToRegisterForRemoteNotifications {
|
||||
return self.wantRemoteNotifications && (!UIApplication.sharedApplication.isRegisteredForRemoteNotifications);
|
||||
}
|
||||
|
||||
- (BOOL)wantRemoteNotifications
|
||||
{
|
||||
BOOL isSimulator = [UIDevice.currentDevice.model.lowercaseString rangeOfString:@"simulator"].location != NSNotFound;
|
||||
|
||||
if (isSimulator) {
|
||||
// Simulator is used for debugging but can't receive push notifications, so don't bother trying to get them
|
||||
- (BOOL)wantRemoteNotifications {
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
return NO;
|
||||
}
|
||||
|
||||
#else
|
||||
return YES;
|
||||
#endif
|
||||
}
|
||||
|
||||
- (int)allNotificationTypes
|
||||
{
|
||||
- (int)allNotificationTypes {
|
||||
return UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge;
|
||||
}
|
||||
|
||||
- (void)validateUserNotificationSettings
|
||||
{
|
||||
- (void)validateUserNotificationSettings {
|
||||
[[self registerForUserNotificationsFuture] thenDo:^(id value){
|
||||
// Nothing to do, just making sure we are registered for User Notifications.
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark Register Push Notification Token with RedPhone server
|
||||
|
||||
- (TOCFuture *)registerForPushFutureWithToken:(NSData *)pushToken voipToken:(NSData*)voipToken
|
||||
{
|
||||
self.registerWithServerFutureSource = [TOCFutureSource new];
|
||||
|
||||
[RPServerRequestsManager.sharedInstance performRequest:[RPAPICall registerPushNotificationWithPushToken:pushToken voipToken:voipToken]
|
||||
success:^(NSURLSessionDataTask *task, id responseObject) {
|
||||
if ([task.response isKindOfClass:NSHTTPURLResponse.class]) {
|
||||
NSInteger statusCode = [(NSHTTPURLResponse *)task.response statusCode];
|
||||
if (statusCode == 200) {
|
||||
[self.registerWithServerFutureSource trySetResult:@YES];
|
||||
} else {
|
||||
DDLogError(@"The server returned %@ instead of a 200 status code", task.response);
|
||||
[self.registerWithServerFutureSource
|
||||
trySetFailure:[NSError errorWithDomain:pushManagerDomain code:500 userInfo:nil]];
|
||||
}
|
||||
} else {
|
||||
[self.registerWithServerFutureSource trySetFailure:task.response];
|
||||
}
|
||||
|
||||
}
|
||||
failure:^(NSURLSessionDataTask *task, NSError *error) {
|
||||
[self.registerWithServerFutureSource trySetFailure:error];
|
||||
}];
|
||||
|
||||
return self.registerWithServerFutureSource.future;
|
||||
}
|
||||
|
||||
- (BOOL)applicationIsActive {
|
||||
UIApplication *app = [UIApplication sharedApplication];
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ void handleDnsCompleted(CFHostRef hostRef, CFHostInfoType typeInfo, const CFStre
|
|||
|
||||
+(TOCFuture*) asyncQueryAddressesForDomainName:(NSString*)domainName
|
||||
unlessCancelled:(TOCCancelToken*)unlessCancelledToken {
|
||||
require(domainName != nil);
|
||||
ows_require(domainName != nil);
|
||||
|
||||
CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFStringRef)domainName);
|
||||
checkOperation(hostRef != nil);
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
+(HostNameEndPoint*) hostNameEndPointWithHostName:(NSString*)hostname
|
||||
andPort:(in_port_t)port {
|
||||
require(hostname != nil);
|
||||
require(port > 0);
|
||||
ows_require(hostname != nil);
|
||||
ows_require(port > 0);
|
||||
|
||||
HostNameEndPoint* h = [HostNameEndPoint new];
|
||||
h->hostname = hostname.copy; // avoid mutability
|
||||
|
|
|
@ -24,26 +24,23 @@
|
|||
parameters:(id)parameters
|
||||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure {
|
||||
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"BUSY" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
NSURLSessionDataTask *dataTask =
|
||||
[self dataTaskWithHTTPMethod:@"BUSY" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
[dataTask resume];
|
||||
|
||||
return dataTask;
|
||||
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)RING:(NSString *)URLString
|
||||
parameters:(id)parameters
|
||||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure {
|
||||
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"RING" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
NSURLSessionDataTask *dataTask =
|
||||
[self dataTaskWithHTTPMethod:@"RING" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
[dataTask resume];
|
||||
|
||||
return dataTask;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
+(HttpManager*) httpManagerFor:(HttpSocket*)httpSocket
|
||||
untilCancelled:(TOCCancelToken*)untilCancelledToken {
|
||||
require(httpSocket != nil);
|
||||
ows_require(httpSocket != nil);
|
||||
|
||||
HttpManager* m = [HttpManager new];
|
||||
m->httpChannel = httpSocket;
|
||||
|
@ -16,7 +16,7 @@
|
|||
}
|
||||
+(HttpManager*) startWithEndPoint:(id<NetworkEndPoint>)endPoint
|
||||
untilCancelled:(TOCCancelToken*)untilCancelledToken {
|
||||
require(endPoint != nil);
|
||||
ows_require(endPoint != nil);
|
||||
|
||||
NetworkStream* dataChannel = [NetworkStream networkStreamToEndPoint:endPoint];
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
|||
-(TOCFuture*) asyncResponseForRequest:(HttpRequest*)request
|
||||
unlessCancelled:(TOCCancelToken*)unlessCancelledToken {
|
||||
|
||||
require(request != nil);
|
||||
ows_require(request != nil);
|
||||
requireState(isStarted);
|
||||
|
||||
@try {
|
||||
|
@ -48,8 +48,8 @@
|
|||
+(TOCFuture*) asyncOkResponseFromMasterServer:(HttpRequest*)request
|
||||
unlessCancelled:(TOCCancelToken*)unlessCancelledToken
|
||||
andErrorHandler:(ErrorHandlerBlock)errorHandler {
|
||||
require(request != nil);
|
||||
require(errorHandler != nil);
|
||||
ows_require(request != nil);
|
||||
ows_require(errorHandler != nil);
|
||||
|
||||
HttpManager* manager = [HttpManager startWithEndPoint:Environment.getMasterServerSecureEndPoint
|
||||
untilCancelled:unlessCancelledToken];
|
||||
|
@ -67,7 +67,7 @@
|
|||
-(TOCFuture*) asyncOkResponseForRequest:(HttpRequest*)request
|
||||
unlessCancelled:(TOCCancelToken*)unlessCancelledToken {
|
||||
|
||||
require(request != nil);
|
||||
ows_require(request != nil);
|
||||
|
||||
TOCFuture* futureResponse = [self asyncResponseForRequest:request
|
||||
unlessCancelled:unlessCancelledToken];
|
||||
|
@ -79,7 +79,7 @@
|
|||
}
|
||||
-(void) startWithRejectingRequestHandlerAndErrorHandler:(ErrorHandlerBlock)errorHandler
|
||||
untilCancelled:(TOCCancelToken*)untilCancelledToken {
|
||||
require(errorHandler != nil);
|
||||
ows_require(errorHandler != nil);
|
||||
|
||||
HttpResponse*(^requestHandler)(HttpRequest* remoteRequest) = ^(HttpRequest* remoteRequest) {
|
||||
errorHandler(@"Rejecting Requests", remoteRequest, false);
|
||||
|
@ -95,8 +95,8 @@
|
|||
andErrorHandler:(ErrorHandlerBlock)errorHandler
|
||||
untilCancelled:(TOCCancelToken*)untilCancelledToken {
|
||||
|
||||
require(requestHandler != nil);
|
||||
require(errorHandler != nil);
|
||||
ows_require(requestHandler != nil);
|
||||
ows_require(errorHandler != nil);
|
||||
|
||||
@synchronized(self) {
|
||||
requireState(!isStarted);
|
||||
|
@ -109,8 +109,8 @@
|
|||
};
|
||||
|
||||
PacketHandlerBlock httpHandler = ^(HttpRequestOrResponse* requestOrResponse) {
|
||||
require(requestOrResponse != nil);
|
||||
require([requestOrResponse isKindOfClass:HttpRequestOrResponse.class]);
|
||||
ows_require(requestOrResponse != nil);
|
||||
ows_require([requestOrResponse isKindOfClass:HttpRequestOrResponse.class]);
|
||||
@synchronized (self) {
|
||||
if (requestOrResponse.isRequest) {
|
||||
HttpResponse* response = requestHandler([requestOrResponse request]);
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
+ (HttpRequest *)httpRequestWithBasicAuthenticationAndMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
andOptionalBody:(NSString *)optionalBody
|
||||
andLocalNumber:(PhoneNumber*)localNumber
|
||||
andLocalNumber:(NSString *)localNumber
|
||||
andPassword:(NSString *)password;
|
||||
|
||||
+ (HttpRequest *)httpRequestWithOtpAuthenticationAndMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
andOptionalBody:(NSString *)optionalBody
|
||||
andLocalNumber:(PhoneNumber*)localNumber
|
||||
andLocalNumber:(NSString *)localNumber
|
||||
andPassword:(NSString *)password
|
||||
andCounter:(int64_t)counter;
|
||||
|
||||
|
@ -35,11 +35,10 @@
|
|||
|
||||
- (bool)isEqualToHttpRequest:(HttpRequest *)other;
|
||||
|
||||
+(NSString*) computeOtpAuthorizationTokenForLocalNumber:(PhoneNumber*)localNumber
|
||||
+ (NSString *)computeOtpAuthorizationTokenForLocalNumber:(NSString *)localNumber
|
||||
andCounterValue:(int64_t)counterValue
|
||||
andPassword:(NSString *)password;
|
||||
|
||||
+(NSString*) computeBasicAuthorizationTokenForLocalNumber:(PhoneNumber*)localNumber
|
||||
andPassword:(NSString*)password;
|
||||
+ (NSString *)computeBasicAuthorizationTokenForLocalNumber:(NSString *)localNumber andPassword:(NSString *)password;
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#import "HttpRequest.h"
|
||||
#import "Util.h"
|
||||
#import "CryptoTools.h"
|
||||
#import "HttpRequest.h"
|
||||
#import "HttpRequestOrResponse.h"
|
||||
#import "Util.h"
|
||||
|
||||
@interface HttpRequest ()
|
||||
@property NSString *method;
|
||||
|
@ -13,12 +13,15 @@
|
|||
|
||||
@implementation HttpRequest
|
||||
|
||||
+(HttpRequest*)httpRequestWithMethod:(NSString*)method andLocation:(NSString*)location andHeaders:(NSDictionary*)headers andOptionalBody:(NSString*)optionalBody {
|
||||
require(method != nil);
|
||||
require(location != nil);
|
||||
require(headers != nil);
|
||||
require((optionalBody == nil) == (headers[@"Content-Length"] == nil));
|
||||
require(optionalBody == nil || [[@(optionalBody.length) description] isEqualToString:headers[@"Content-Length"]]);
|
||||
+ (HttpRequest *)httpRequestWithMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
andHeaders:(NSDictionary *)headers
|
||||
andOptionalBody:(NSString *)optionalBody {
|
||||
ows_require(method != nil);
|
||||
ows_require(location != nil);
|
||||
ows_require(headers != nil);
|
||||
ows_require((optionalBody == nil) == (headers[@"Content-Length"] == nil));
|
||||
ows_require(optionalBody == nil || [[@(optionalBody.length) description] isEqualToString:headers[@"Content-Length"]]);
|
||||
|
||||
HttpRequest *s = [HttpRequest new];
|
||||
s->_method = method;
|
||||
|
@ -30,8 +33,8 @@
|
|||
+ (HttpRequest *)httpRequestUnauthenticatedWithMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
andOptionalBody:(NSString *)optionalBody {
|
||||
require(method != nil);
|
||||
require(location != nil);
|
||||
ows_require(method != nil);
|
||||
ows_require(location != nil);
|
||||
|
||||
NSMutableDictionary *headers = [NSMutableDictionary dictionary];
|
||||
if (optionalBody != nil) {
|
||||
|
@ -48,18 +51,19 @@
|
|||
+ (HttpRequest *)httpRequestWithBasicAuthenticationAndMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
andOptionalBody:(NSString *)optionalBody
|
||||
andLocalNumber:(PhoneNumber*)localNumber
|
||||
andLocalNumber:(NSString *)localNumber
|
||||
andPassword:(NSString *)password {
|
||||
require(method != nil);
|
||||
require(location != nil);
|
||||
require(password != nil);
|
||||
require(localNumber != nil);
|
||||
ows_require(method != nil);
|
||||
ows_require(location != nil);
|
||||
ows_require(password != nil);
|
||||
ows_require(localNumber != nil);
|
||||
|
||||
NSMutableDictionary *headers = [NSMutableDictionary dictionary];
|
||||
if (optionalBody != nil) {
|
||||
headers[@"Content-Length"] = [@(optionalBody.length) stringValue];
|
||||
}
|
||||
headers[@"Authorization"] = [HttpRequest computeBasicAuthorizationTokenForLocalNumber:localNumber andPassword:password];
|
||||
headers[@"Authorization"] =
|
||||
[HttpRequest computeBasicAuthorizationTokenForLocalNumber:localNumber andPassword:password];
|
||||
|
||||
HttpRequest *s = [HttpRequest new];
|
||||
s->_method = method;
|
||||
|
@ -71,18 +75,20 @@
|
|||
+ (HttpRequest *)httpRequestWithOtpAuthenticationAndMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
andOptionalBody:(NSString *)optionalBody
|
||||
andLocalNumber:(PhoneNumber*)localNumber
|
||||
andLocalNumber:(NSString *)localNumber
|
||||
andPassword:(NSString *)password
|
||||
andCounter:(int64_t)counter {
|
||||
require(method != nil);
|
||||
require(location != nil);
|
||||
require(password != nil);
|
||||
ows_require(method != nil);
|
||||
ows_require(location != nil);
|
||||
ows_require(password != nil);
|
||||
|
||||
NSMutableDictionary *headers = [NSMutableDictionary dictionary];
|
||||
if (optionalBody != nil) {
|
||||
headers[@"Content-Length"] = [@(optionalBody.length) stringValue];
|
||||
}
|
||||
headers[@"Authorization"] = [HttpRequest computeOtpAuthorizationTokenForLocalNumber:localNumber andCounterValue:counter andPassword:password];
|
||||
headers[@"Authorization"] = [HttpRequest computeOtpAuthorizationTokenForLocalNumber:localNumber
|
||||
andCounterValue:counter
|
||||
andPassword:password];
|
||||
|
||||
HttpRequest *s = [HttpRequest new];
|
||||
s->_method = method;
|
||||
|
@ -93,7 +99,7 @@
|
|||
}
|
||||
|
||||
+ (HttpRequest *)httpRequestFromData:(NSData *)data {
|
||||
require(data != nil);
|
||||
ows_require(data != nil);
|
||||
NSUInteger requestSize;
|
||||
HttpRequestOrResponse *http = [HttpRequestOrResponse tryExtractFromPartialData:data usedLengthOut:&requestSize];
|
||||
checkOperation(http.isRequest && requestSize == data.length);
|
||||
|
@ -103,19 +109,18 @@
|
|||
+ (NSString *)computeOtpAuthorizationTokenForLocalNumber:(PhoneNumber *)localNumber
|
||||
andCounterValue:(int64_t)counterValue
|
||||
andPassword:(NSString *)password {
|
||||
require(localNumber != nil);
|
||||
require(password != nil);
|
||||
ows_require(localNumber != nil);
|
||||
ows_require(password != nil);
|
||||
|
||||
NSString* rawToken = [NSString stringWithFormat:@"%@:%@:%lld",
|
||||
localNumber.toE164,
|
||||
NSString *rawToken =
|
||||
[NSString stringWithFormat:@"%@:%@:%lld",
|
||||
localNumber,
|
||||
[CryptoTools computeOtpWithPassword:password andCounter:counterValue],
|
||||
counterValue];
|
||||
return [@"OTP " stringByAppendingString:rawToken.encodedAsUtf8.encodedAsBase64];
|
||||
}
|
||||
+(NSString*) computeBasicAuthorizationTokenForLocalNumber:(PhoneNumber*)localNumber andPassword:(NSString*)password {
|
||||
NSString* rawToken = [NSString stringWithFormat:@"%@:%@",
|
||||
localNumber.toE164,
|
||||
password];
|
||||
+ (NSString *)computeBasicAuthorizationTokenForLocalNumber:(NSString *)localNumber andPassword:(NSString *)password {
|
||||
NSString *rawToken = [NSString stringWithFormat:@"%@:%@", localNumber, password];
|
||||
return [@"Basic " stringByAppendingString:rawToken.encodedAsUtf8.encodedAsBase64];
|
||||
}
|
||||
|
||||
|
@ -135,7 +140,8 @@
|
|||
}
|
||||
|
||||
[r addObject:@"\r\n"];
|
||||
if (self.optionalBody != nil) [r addObject:self.optionalBody];
|
||||
if (self.optionalBody != nil)
|
||||
[r addObject:self.optionalBody];
|
||||
|
||||
return [r componentsJoinedByString:@""];
|
||||
}
|
||||
|
@ -143,19 +149,18 @@
|
|||
return self.toHttp.encodedAsUtf8;
|
||||
}
|
||||
- (bool)isEqualToHttpRequest:(HttpRequest *)other {
|
||||
return [self.toHttp isEqualToString:other.toHttp]
|
||||
&& [self.method isEqualToString:other.method]
|
||||
&& [self.location isEqualToString:other.location]
|
||||
&& (self.optionalBody == other.optionalBody || [self.optionalBody isEqualToString:[other optionalBody]])
|
||||
&& [self.headers isEqualToDictionary:other.headers];
|
||||
return [self.toHttp isEqualToString:other.toHttp] && [self.method isEqualToString:other.method] &&
|
||||
[self.location isEqualToString:other.location] &&
|
||||
(self.optionalBody == other.optionalBody || [self.optionalBody isEqualToString:[other optionalBody]]) &&
|
||||
[self.headers isEqualToDictionary:other.headers];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"%@ %@%@",
|
||||
return
|
||||
[NSString stringWithFormat:@"%@ %@%@",
|
||||
self.method,
|
||||
self.location,
|
||||
self.optionalBody == nil ? @""
|
||||
: self.optionalBody.length == 0 ? @" [empty body]"
|
||||
self.optionalBody == nil ? @"" : self.optionalBody.length == 0 ? @" [empty body]"
|
||||
: @" [...body...]"];
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
@implementation HttpRequestOrResponse
|
||||
|
||||
+(HttpRequestOrResponse*) httpRequestOrResponse:(id)requestOrResponse {
|
||||
require(requestOrResponse != nil);
|
||||
ows_require(requestOrResponse != nil);
|
||||
|
||||
HttpRequestOrResponse* h = [HttpRequestOrResponse new];
|
||||
h->requestOrResponse = requestOrResponse;
|
||||
require(h.isResponse || h.isRequest);
|
||||
ows_require(h.isResponse || h.isRequest);
|
||||
return h;
|
||||
}
|
||||
-(bool) isRequest {
|
||||
|
@ -31,7 +31,7 @@
|
|||
}
|
||||
|
||||
+(HttpRequestOrResponse*) tryExtractFromPartialData:(NSData*)data usedLengthOut:(NSUInteger*)usedLengthPtr {
|
||||
require(data != nil);
|
||||
ows_require(data != nil);
|
||||
|
||||
// first line should contain HTTP
|
||||
checkOperation([data tryFindIndexOf:@"\r\n".encodedAsAscii] == nil || [data tryFindIndexOf:@"HTTP".encodedAsAscii] != nil);
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
#import "HttpRequestUtil.h"
|
||||
#import "SignalKeyingStorage.h"
|
||||
#import "TSAccountManager.h"
|
||||
|
||||
@implementation HttpRequest (HttpRequestUtil)
|
||||
|
||||
+(HttpRequest*)httpRequestWithBasicAuthenticationAndMethod:(NSString*)method
|
||||
andLocation:(NSString*)location {
|
||||
return [HttpRequest httpRequestWithBasicAuthenticationAndMethod:method
|
||||
andLocation:location
|
||||
andOptionalBody:nil];
|
||||
+ (HttpRequest *)httpRequestWithBasicAuthenticationAndMethod:(NSString *)method andLocation:(NSString *)location {
|
||||
return [HttpRequest httpRequestWithBasicAuthenticationAndMethod:method andLocation:location andOptionalBody:nil];
|
||||
}
|
||||
+ (HttpRequest *)httpRequestWithBasicAuthenticationAndMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
|
@ -15,14 +13,11 @@
|
|||
return [HttpRequest httpRequestWithBasicAuthenticationAndMethod:method
|
||||
andLocation:location
|
||||
andOptionalBody:optionalBody
|
||||
andLocalNumber:SignalKeyingStorage.localNumber
|
||||
andLocalNumber:[TSAccountManager localNumber]
|
||||
andPassword:SignalKeyingStorage.serverAuthPassword];
|
||||
}
|
||||
+(HttpRequest*)httpRequestWithOtpAuthenticationAndMethod:(NSString*)method
|
||||
andLocation:(NSString*)location {
|
||||
return [HttpRequest httpRequestWithOtpAuthenticationAndMethod:method
|
||||
andLocation:location
|
||||
andOptionalBody:nil];
|
||||
+ (HttpRequest *)httpRequestWithOtpAuthenticationAndMethod:(NSString *)method andLocation:(NSString *)location {
|
||||
return [HttpRequest httpRequestWithOtpAuthenticationAndMethod:method andLocation:location andOptionalBody:nil];
|
||||
}
|
||||
+ (HttpRequest *)httpRequestWithOtpAuthenticationAndMethod:(NSString *)method
|
||||
andLocation:(NSString *)location
|
||||
|
@ -30,15 +25,12 @@
|
|||
return [HttpRequest httpRequestWithOtpAuthenticationAndMethod:method
|
||||
andLocation:location
|
||||
andOptionalBody:optionalBody
|
||||
andLocalNumber:SignalKeyingStorage.localNumber
|
||||
andLocalNumber:[TSAccountManager localNumber]
|
||||
andPassword:SignalKeyingStorage.serverAuthPassword
|
||||
andCounter:[SignalKeyingStorage getAndIncrementOneTimeCounter]];
|
||||
}
|
||||
+(HttpRequest*)httpRequestUnauthenticatedWithMethod:(NSString*)method
|
||||
andLocation:(NSString*)location {
|
||||
return [HttpRequest httpRequestUnauthenticatedWithMethod:method
|
||||
andLocation:location
|
||||
andOptionalBody:nil];
|
||||
+ (HttpRequest *)httpRequestUnauthenticatedWithMethod:(NSString *)method andLocation:(NSString *)location {
|
||||
return [HttpRequest httpRequestUnauthenticatedWithMethod:method andLocation:location andOptionalBody:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
andHeaders:(NSDictionary*)headers
|
||||
andOptionalBodyText:(NSString*)optionalBody {
|
||||
|
||||
require(headers != nil);
|
||||
require(statusText != nil);
|
||||
require(headers != nil);
|
||||
ows_require(headers != nil);
|
||||
ows_require(statusText != nil);
|
||||
ows_require(headers != nil);
|
||||
|
||||
HttpResponse* s = [HttpResponse new];
|
||||
s->statusCode = statusCode;
|
||||
|
@ -25,9 +25,9 @@
|
|||
andHeaders:(NSDictionary*)headers
|
||||
andOptionalBodyData:(NSData*)optionalBody {
|
||||
|
||||
require(headers != nil);
|
||||
require(statusText != nil);
|
||||
require(headers != nil);
|
||||
ows_require(headers != nil);
|
||||
ows_require(statusText != nil);
|
||||
ows_require(headers != nil);
|
||||
|
||||
HttpResponse* s = [HttpResponse new];
|
||||
s->statusCode = statusCode;
|
||||
|
@ -37,7 +37,7 @@
|
|||
return s;
|
||||
}
|
||||
+(HttpResponse*) httpResponseFromData:(NSData*)data {
|
||||
require(data != nil);
|
||||
ows_require(data != nil);
|
||||
NSUInteger responseSize;
|
||||
HttpRequestOrResponse* http = [HttpRequestOrResponse tryExtractFromPartialData:data usedLengthOut:&responseSize];
|
||||
checkOperation(http.isResponse && responseSize == data.length);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
@implementation HttpSocket
|
||||
|
||||
+(HttpSocket*) httpSocketOver:(NetworkStream*)rawDataChannel {
|
||||
require(rawDataChannel != nil);
|
||||
ows_require(rawDataChannel != nil);
|
||||
|
||||
HttpSocket* h = [HttpSocket new];
|
||||
h->rawDataChannelTcp = rawDataChannel;
|
||||
|
@ -16,7 +16,7 @@
|
|||
return h;
|
||||
}
|
||||
+(HttpSocket*) httpSocketOverUdp:(UdpSocket*)rawDataChannel {
|
||||
require(rawDataChannel != nil);
|
||||
ows_require(rawDataChannel != nil);
|
||||
|
||||
HttpSocket* h = [HttpSocket new];
|
||||
h->rawDataChannelUdp = rawDataChannel;
|
||||
|
@ -27,7 +27,7 @@
|
|||
}
|
||||
|
||||
-(void) sendHttpRequestOrResponse:(HttpRequestOrResponse*)requestOrResponse {
|
||||
require(requestOrResponse != nil);
|
||||
ows_require(requestOrResponse != nil);
|
||||
requireState(httpSignalResponseHandler != nil);
|
||||
[sentPacketsLogger markOccurrence:requestOrResponse];
|
||||
NSData* data = [requestOrResponse serialize];
|
||||
|
@ -38,29 +38,29 @@
|
|||
}
|
||||
}
|
||||
-(void) sendHttpRequest:(HttpRequest*)request {
|
||||
require(request != nil);
|
||||
ows_require(request != nil);
|
||||
[self sendHttpRequestOrResponse:[HttpRequestOrResponse httpRequestOrResponse:request]];
|
||||
}
|
||||
-(void) sendHttpResponse:(HttpResponse*)response {
|
||||
require(response != nil);
|
||||
ows_require(response != nil);
|
||||
[self sendHttpRequestOrResponse:[HttpRequestOrResponse httpRequestOrResponse:response]];
|
||||
}
|
||||
-(void) send:(HttpRequestOrResponse*)packet {
|
||||
require(packet != nil);
|
||||
ows_require(packet != nil);
|
||||
[self sendHttpRequestOrResponse:packet];
|
||||
}
|
||||
-(void) startWithHandler:(PacketHandler*)handler
|
||||
untilCancelled:(TOCCancelToken*)untilCancelledToken {
|
||||
|
||||
require(handler != nil);
|
||||
ows_require(handler != nil);
|
||||
requireState(httpSignalResponseHandler == nil);
|
||||
httpSignalResponseHandler = handler;
|
||||
|
||||
TOCCancelTokenSource* lifetime = [TOCCancelTokenSource cancelTokenSourceUntil:untilCancelledToken];
|
||||
|
||||
PacketHandler* packetHandler = [PacketHandler packetHandler:^(id packet) {
|
||||
require(packet != nil);
|
||||
require([packet isKindOfClass:NSData.class]);
|
||||
ows_require(packet != nil);
|
||||
ows_require([packet isKindOfClass:NSData.class]);
|
||||
NSData* data = packet;
|
||||
|
||||
[partialDataBuffer replaceBytesInRange:NSMakeRange(partialDataBuffer.length, data.length) withBytes:[data bytes]];
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue