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:
Frederic Jacobs 2015-12-22 12:45:09 +01:00
parent 37b582beda
commit c6d44e59e2
473 changed files with 10469 additions and 22905 deletions

View File

@ -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

2
.gitignore vendored
View File

@ -26,3 +26,5 @@ DerivedData
*.hmap
*.ipa
*.xcuserstate
Pods/

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "Pods"]
path = Pods
url = https://github.com/FredericJacobs/Precompiled-Signal-Dependencies.git

View File

@ -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

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0720"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

12
Podfile
View File

@ -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'

View File

@ -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 +0,0 @@
Subproject commit e6c803ff3cdb391d5c0dc9a2418f1e2f0797a1a3

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,8 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
allowLocationSimulation = "YES"
showNonLocalizedStrings = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference

View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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];
}
/**

View File

@ -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"

View File

@ -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>

View File

@ -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

View File

@ -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];
}

View File

@ -57,5 +57,4 @@ static NSString* SoundFile_Ringtone =@"r.caf";
}
@end

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -9,8 +9,10 @@
*
**/
@interface AudioSocket : NSObject {
@private SrtpSocket* srtpSocket;
@private bool started;
@private
SrtpSocket *srtpSocket;
@private
bool started;
}
+ (AudioSocket *)audioSocketOver:(SrtpSocket *)srtpSocket;

View File

@ -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]];

View File

@ -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

View File

@ -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;
}

View File

@ -8,7 +8,8 @@
**/
@interface EncodedAudioFrame : NSObject {
@private NSData* audioData;
@private
NSData *audioData;
}
+ (EncodedAudioFrame *)encodedAudioFrameWithData:(NSData *)audioData;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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) {

View File

@ -1,6 +1,6 @@
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
#import <Foundation/Foundation.h>
/**
*

View File

@ -9,7 +9,6 @@
*
**/
@interface SpeexCodec : NSObject {
void *decodingState;
SpeexBits decodingBits;
spx_int16_t decodingFrameSize;

View File

@ -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);

View File

@ -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;

View File

@ -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];

View File

@ -12,7 +12,8 @@
**/
@interface AudioStretcher : NSObject {
@private struct time_scale_state_s timeScaleState;
@private
struct time_scale_state_s timeScaleState;
}
+ (AudioStretcher *)audioStretcher;

View File

@ -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;

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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];
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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];
}];
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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];

View File

@ -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];
}

View File

@ -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
;

View File

@ -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; \
}

View File

@ -12,7 +12,7 @@
@interface DebugLogger : NSObject
MacrosSingletonInterface
+ (instancetype)sharedLogger;
- (void)enableFileLogging;

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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 @{

View File

@ -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

View File

@ -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

View File

@ -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)];
}

View File

@ -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);

View File

@ -1,7 +1,7 @@
#import <Foundation/Foundation.h>
#import "Environment.h"
#import "DH3KKeyAgreementProtocol.h"
#import "EC25KeyAgreementProtocol.h"
#import "Environment.h"
@interface Release : NSObject

View File

@ -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 {

View File

@ -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
*/

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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));

View File

@ -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];

View File

@ -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

View File

@ -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];

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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]);

View File

@ -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

View File

@ -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...]"];
}

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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