diff --git a/Scripts/debug_log_upload.py b/Scripts/debug_log_upload.py
new file mode 100755
index 0000000000..0c26aafb4e
--- /dev/null
+++ b/Scripts/debug_log_upload.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+import sys
+import os
+import re
+import commands
+import subprocess
+import argparse
+import inspect
+import urllib2
+import json
+
+def fail(message):
+ file_name = __file__
+ current_line_no = inspect.stack()[1][2]
+ current_function_name = inspect.stack()[1][3]
+ print 'Failure in:', file_name, current_line_no, current_function_name
+ print message
+ sys.exit(1)
+
+
+def execute_command(command):
+ try:
+ print ' '.join(command)
+ output = subprocess.check_output(command)
+ if output:
+ print output
+ except subprocess.CalledProcessError as e:
+ print e.output
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Precommit cleanup script.')
+ parser.add_argument('--file', help='used for starting a new version.')
+
+ args = parser.parse_args()
+
+ params_response = urllib2.urlopen("https://debuglogs.org/").read()
+
+ params = json.loads(params_response)
+
+ upload_url = params['url']
+ upload_fields = params['fields']
+ upload_key = upload_fields['key']
+ upload_key = upload_key + os.path.splitext(args.file)[1]
+ upload_fields['key'] = upload_key
+
+ download_url = 'https://debuglogs.org/' + upload_key
+ print 'download_url:', download_url
+
+ curl_command = ['curl', '-v', '-i', '-X', 'POST']
+ for field_name in upload_fields:
+ field_value = upload_fields[field_name]
+ curl_command.append('-F')
+ curl_command.append("'%s=%s'" % (field_name, field_value, ))
+ curl_command.append('-F')
+ curl_command.append("'file=@%s'" % (args.file,))
+ curl_command.append(upload_url)
+
+ # execute_command(curl_command)
+ print ' '.join(curl_command)
+
+ print 'download_url:', download_url
+
\ No newline at end of file
diff --git a/Signal/Signal-Info.plist b/Signal/Signal-Info.plist
index c1ce8c5553..8caf76b204 100644
--- a/Signal/Signal-Info.plist
+++ b/Signal/Signal-Info.plist
@@ -38,7 +38,7 @@
CFBundleVersion
- 2.21.0.0
+ 2.21.0.1
ITSAppUsesNonExemptEncryption
LOGS_EMAIL
diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m
index 4de216e562..254dc626db 100644
--- a/Signal/src/AppDelegate.m
+++ b/Signal/src/AppDelegate.m
@@ -46,6 +46,7 @@
#import
#import
#import
+#import
@import WebRTC;
@import Intents;
@@ -324,7 +325,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
- [Pastelog submitLogsWithShareCompletion:^{
+ [Pastelog submitLogsWithCompletion:^{
DDLogInfo(
@"%@ exiting after sharing debug logs.", self.logTag);
[DDLog flushLog];
@@ -396,6 +397,15 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
if (languageCode.length > 0) {
DDLogInfo(@"Language Code: %@", languageCode);
}
+
+ size_t size;
+ sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+ char *machine = malloc(size);
+ sysctlbyname("hw.machine", machine, &size, NULL, 0);
+ NSString *platform = [NSString stringWithUTF8String:machine];
+ free(machine);
+
+ DDLogInfo(@"iPhone Version: %@", platform);
}
- (UIViewController *)loadingRootViewController
diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m
index dde2caf405..53f33f1729 100644
--- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m
+++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m
@@ -7,7 +7,6 @@
#import "OWSTableViewController.h"
#import "Signal-Swift.h"
#import "ThreadUtil.h"
-#import
#import
#import
#import
diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m b/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m
index 41ecfa7e98..40eb0cce60 100644
--- a/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m
+++ b/Signal/src/ViewControllers/DebugUI/DebugUIMisc.m
@@ -10,7 +10,6 @@
#import "RegistrationViewController.h"
#import "Signal-Swift.h"
#import "ThreadUtil.h"
-#import
#import
#import
#import
diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m
index 51cb890db1..dd033379af 100644
--- a/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m
+++ b/Signal/src/ViewControllers/DebugUI/DebugUISyncMessages.m
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
+// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "DebugUISyncMessages.h"
@@ -7,7 +7,6 @@
#import "OWSTableViewController.h"
#import "Signal-Swift.h"
#import "ThreadUtil.h"
-#import
#import
#import
#import
diff --git a/Signal/src/ViewControllers/OWSSoundSettingsViewController.m b/Signal/src/ViewControllers/OWSSoundSettingsViewController.m
index ce7be75b2d..0246644e1e 100644
--- a/Signal/src/ViewControllers/OWSSoundSettingsViewController.m
+++ b/Signal/src/ViewControllers/OWSSoundSettingsViewController.m
@@ -74,13 +74,25 @@ NS_ASSUME_NONNULL_BEGIN
for (NSNumber *nsValue in allSounds) {
OWSSound sound = (OWSSound)nsValue.intValue;
OWSTableItem *item;
+
+ NSString *soundLabelText = ^{
+ NSString *baseName = [OWSSounds displayNameForSound:sound];
+ if (sound == OWSSound_Note) {
+ NSString *noteStringFormat = NSLocalizedString(@"SETTINGS_AUDIO_DEFAULT_TONE_LABEL_FORMAT",
+ @"Format string for the default 'Note' sound. Embeds the system {{sound name}}.");
+ return [NSString stringWithFormat:noteStringFormat, baseName];
+ } else {
+ return [OWSSounds displayNameForSound:sound];
+ }
+ }();
+
if (sound == self.currentSound) {
- item = [OWSTableItem checkmarkItemWithText:[OWSSounds displayNameForSound:sound]
+ item = [OWSTableItem checkmarkItemWithText:soundLabelText
actionBlock:^{
[weakSelf soundWasSelected:sound];
}];
} else {
- item = [OWSTableItem actionItemWithText:[OWSSounds displayNameForSound:sound]
+ item = [OWSTableItem actionItemWithText:soundLabelText
actionBlock:^{
[weakSelf soundWasSelected:sound];
}];
diff --git a/Signal/src/util/Pastelog.h b/Signal/src/util/Pastelog.h
index 99356aa0e2..0d46da066e 100644
--- a/Signal/src/util/Pastelog.h
+++ b/Signal/src/util/Pastelog.h
@@ -2,14 +2,17 @@
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void (^SubmitDebugLogsCompletion)(void);
+
@interface Pastelog : NSObject
-typedef void (^DebugLogsUploadedBlock)(NSError *error, NSString *urlString);
-typedef void (^DebugLogsSharedBlock)(void);
+- (instancetype)init NS_UNAVAILABLE;
-+(void)submitLogs;
-+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)block;
-+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block;
-+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger;
++ (void)submitLogs;
++ (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completion;
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Signal/src/util/Pastelog.m b/Signal/src/util/Pastelog.m
index d6dc5b7cb3..17dda81a09 100644
--- a/Signal/src/util/Pastelog.m
+++ b/Signal/src/util/Pastelog.m
@@ -5,6 +5,10 @@
#import "Pastelog.h"
#import "Signal-Swift.h"
#import "ThreadUtil.h"
+#import "zlib.h"
+#import
+#import
+#import
#import
#import
#import
@@ -12,13 +16,227 @@
#import
#import
#import
-#import
-@interface Pastelog ()
+NS_ASSUME_NONNULL_BEGIN
+
+typedef void (^UploadDebugLogsSuccess)(NSURL *url);
+typedef void (^UploadDebugLogsFailure)(NSString *localizedErrorMessage);
+
+#pragma mark -
+
+@class DebugLogUploader;
+
+typedef void (^DebugLogUploadSuccess)(DebugLogUploader *uploader, NSURL *url);
+typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error);
+
+@interface DebugLogUploader : NSObject
+
+@property (nonatomic) NSURL *fileUrl;
+@property (nonatomic) NSString *mimeType;
+@property (nonatomic, nullable) DebugLogUploadSuccess success;
+@property (nonatomic, nullable) DebugLogUploadFailure failure;
+
+@end
+
+#pragma mark -
+
+@implementation DebugLogUploader
+
+- (void)dealloc
+{
+ DDLogVerbose(@"Dealloc: %@", self.logTag);
+}
+
+- (void)uploadFileWithURL:(NSURL *)fileUrl
+ mimeType:(NSString *)mimeType
+ success:(DebugLogUploadSuccess)success
+ failure:(DebugLogUploadFailure)failure
+{
+ OWSAssert(fileUrl);
+ OWSAssert(mimeType.length > 0);
+ OWSAssert(success);
+ OWSAssert(failure);
+
+ self.fileUrl = fileUrl;
+ self.mimeType = mimeType;
+ self.success = success;
+ self.failure = failure;
+
+ [self getUploadParameters];
+}
+
+- (void)getUploadParameters
+{
+ __weak DebugLogUploader *weakSelf = self;
+
+ NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration;
+ AFHTTPSessionManager *sessionManager =
+ [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf];
+ sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
+ sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];
+ NSString *urlString = @"https://debuglogs.org/";
+ [sessionManager GET:urlString
+ parameters:nil
+ progress:nil
+ success:^(NSURLSessionDataTask *task, id _Nullable responseObject) {
+ if (![responseObject isKindOfClass:[NSDictionary class]]) {
+ DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject);
+ [weakSelf
+ failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")];
+ return;
+ }
+ NSString *uploadUrl = responseObject[@"url"];
+ if (![uploadUrl isKindOfClass:[NSString class]] || uploadUrl.length < 1) {
+ DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject);
+ [weakSelf
+ failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")];
+ return;
+ }
+ NSDictionary *fields = responseObject[@"fields"];
+ if (![fields isKindOfClass:[NSDictionary class]] || fields.count < 1) {
+ DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject);
+ [weakSelf
+ failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")];
+ return;
+ }
+ for (NSString *fieldName in fields) {
+ NSString *fieldValue = fields[fieldName];
+ if (![fieldName isKindOfClass:[NSString class]] || fieldName.length < 1
+ || ![fieldValue isKindOfClass:[NSString class]] || fieldValue.length < 1) {
+ DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject);
+ [weakSelf failWithError:OWSErrorWithCodeDescription(
+ OWSErrorCodeDebugLogUploadFailed, @"Invalid response")];
+ return;
+ }
+ }
+ NSString *_Nullable uploadKey = fields[@"key"];
+ if (![uploadKey isKindOfClass:[NSString class]] || uploadKey.length < 1) {
+ DDLogError(@"%@ Invalid response: %@, %@", weakSelf.logTag, urlString, responseObject);
+ [weakSelf
+ failWithError:OWSErrorWithCodeDescription(OWSErrorCodeDebugLogUploadFailed, @"Invalid response")];
+ return;
+ }
+
+ // Add a file extension to the upload's key.
+ NSString *fileExtension = weakSelf.fileUrl.lastPathComponent.pathExtension;
+ uploadKey = [uploadKey stringByAppendingPathExtension:fileExtension];
+ NSMutableDictionary *updatedFields = [fields mutableCopy];
+ updatedFields[@"key"] = uploadKey;
+
+ [weakSelf uploadFileWithUploadUrl:uploadUrl fields:updatedFields uploadKey:uploadKey];
+ }
+ failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) {
+ DDLogError(@"%@ failed: %@", weakSelf.logTag, urlString);
+ [weakSelf failWithError:error];
+ }];
+}
+
+- (void)uploadFileWithUploadUrl:(NSString *)uploadUrl fields:(NSDictionary *)fields uploadKey:(NSString *)uploadKey
+{
+ OWSAssert(uploadUrl.length > 0);
+ OWSAssert(fields);
+ OWSAssert(uploadKey.length > 0);
+
+ __weak DebugLogUploader *weakSelf = self;
+ NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration;
+ AFHTTPSessionManager *sessionManager =
+ [[AFHTTPSessionManager alloc] initWithBaseURL:nil sessionConfiguration:sessionConf];
+ sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
+ sessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
+ [sessionManager POST:uploadUrl
+ parameters:@{}
+ constructingBodyWithBlock:^(id formData) {
+ for (NSString *fieldName in fields) {
+ NSString *fieldValue = fields[fieldName];
+ [formData appendPartWithFormData:[fieldValue dataUsingEncoding:NSUTF8StringEncoding] name:fieldName];
+ }
+ NSError *error;
+ BOOL success = [formData appendPartWithFileURL:weakSelf.fileUrl
+ name:@"file"
+ fileName:weakSelf.fileUrl.lastPathComponent
+ mimeType:weakSelf.mimeType
+ error:&error];
+ if (!success || error) {
+ DDLogError(@"%@ failed: %@, error: %@", weakSelf.logTag, uploadUrl, error);
+ }
+ }
+ progress:nil
+ success:^(NSURLSessionDataTask *task, id _Nullable responseObject) {
+ DDLogVerbose(@"%@ Response: %@, %@", weakSelf.logTag, uploadUrl, responseObject);
+
+ NSString *urlString = [NSString stringWithFormat:@"https://debuglogs.org/%@", uploadKey];
+ [self succeedWithUrl:[NSURL URLWithString:urlString]];
+ }
+ failure:^(NSURLSessionDataTask *_Nullable task, NSError *error) {
+ DDLogError(@"%@ failed: %@", weakSelf.logTag, uploadUrl);
+ [weakSelf failWithError:error];
+ }];
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
+{
+ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
+
+ NSInteger statusCode = httpResponse.statusCode;
+ // We'll accept any 2xx status code.
+ NSInteger statusCodeClass = statusCode - (statusCode % 100);
+ if (statusCodeClass != 200) {
+ DDLogError(@"%@ statusCode: %zd, %zd", self.logTag, statusCode, statusCodeClass);
+ DDLogError(@"%@ headers: %@", self.logTag, httpResponse.allHeaderFields);
+ [self failWithError:[NSError errorWithDomain:@"PastelogKit"
+ code:10001
+ userInfo:@{ NSLocalizedDescriptionKey : @"Invalid response code." }]];
+ }
+}
+
+- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
+{
+ DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
+
+ [self failWithError:error];
+}
+
+- (void)failWithError:(NSError *)error
+{
+ OWSAssert(error);
+
+ DDLogError(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, error);
+
+ DispatchMainThreadSafe(^{
+ // Call the completions exactly once.
+ if (self.failure) {
+ self.failure(self, error);
+ }
+ self.success = nil;
+ self.failure = nil;
+ });
+}
+
+- (void)succeedWithUrl:(NSURL *)url
+{
+ OWSAssert(url);
+
+ DDLogVerbose(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, url);
+
+ DispatchMainThreadSafe(^{
+ // Call the completions exactly once.
+ if (self.success) {
+ self.success(self, url);
+ }
+ self.success = nil;
+ self.failure = nil;
+ });
+}
+
+@end
+
+#pragma mark -
+
+@interface Pastelog ()
@property (nonatomic) UIAlertController *loadingAlert;
-@property (nonatomic) NSMutableData *responseData;
-@property (nonatomic) DebugLogsUploadedBlock block;
+
+@property (nonatomic) DebugLogUploader *currentUploader;
@end
@@ -26,237 +244,244 @@
@implementation Pastelog
-+(void)submitLogs {
- [self submitLogsWithShareCompletion:nil];
-}
-
-+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)shareCompletionParam
++ (instancetype)sharedManager
{
- DebugLogsSharedBlock shareCompletion = ^{
- if (shareCompletionParam) {
- // Wait a moment. If PasteLog opens a URL, it needs a moment to complete.
- dispatch_after(
- dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), shareCompletionParam);
- }
- };
-
- [self submitLogsWithUploadCompletion:^(NSError *error, NSString *urlString) {
- if (!error) {
- UIAlertController *alert = [UIAlertController
- alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.")
- message:NSLocalizedString(
- @"DEBUG_LOG_ALERT_MESSAGE", @"Message of the debug log alert.")
- preferredStyle:UIAlertControllerStyleAlert];
- [alert
- addAction:[UIAlertAction
- actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL",
- @"Label for the 'email debug log' option of the the debug log alert.")
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction *_Nonnull action) {
- [Pastelog.sharedManager submitEmail:urlString];
-
- shareCompletion();
- }]];
- [alert addAction:[UIAlertAction
- actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK",
- @"Label for the 'copy link' option of the the debug log alert.")
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction *_Nonnull action) {
- UIPasteboard *pb = [UIPasteboard generalPasteboard];
- [pb setString:urlString];
-
- shareCompletion();
- }]];
-#ifdef DEBUG
- [alert addAction:[UIAlertAction
- actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF",
- @"Label for the 'send to self' option of the the debug log alert.")
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction *_Nonnull action) {
- [Pastelog.sharedManager sendToSelf:urlString];
- }]];
- [alert addAction:[UIAlertAction
- actionWithTitle:
- NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD",
- @"Label for the 'send to last thread' option of the the debug log alert.")
- style:UIAlertActionStyleDefault
- handler:^(UIAlertAction *_Nonnull action) {
- [Pastelog.sharedManager sendToMostRecentThread:urlString];
- }]];
-#endif
- [alert addAction:
- [UIAlertAction
- actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT",
- @"Label for the 'Open a Bug Report' option of the the debug log alert.")
- style:UIAlertActionStyleCancel
- handler:^(UIAlertAction *_Nonnull action) {
- [Pastelog.sharedManager prepareRedirection:urlString
- shareCompletion:shareCompletion];
- }]];
- UIViewController *presentingViewController
- = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
- [presentingViewController presentViewController:alert animated:NO completion:nil];
- } else{
- UIAlertView *alertView =
- [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"DEBUG_LOG_FAILURE_ALERT_TITLE",
- @"Title of the alert indicating the debug log upload failed.")
- message:error.localizedDescription
- delegate:nil
- cancelButtonTitle:@"OK"
- otherButtonTitles:nil, nil];
- [alertView show];
- }
- }];
-}
-
-+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block
-{
- [self submitLogsWithUploadCompletion:block forFileLogger:[[DDFileLogger alloc] init]];
-}
-
-+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger
-{
-
- [self sharedManager].block = block;
-
- [self sharedManager].loadingAlert =
- [UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ACTIVITY_INDICATOR",
- @"Message indicating that the debug log is being uploaded.")
- message:nil
- preferredStyle:UIAlertControllerStyleAlert];
- UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
- [presentingViewController presentViewController:[self sharedManager].loadingAlert animated:NO completion:nil];
-
- NSArray *logFilePaths = DebugLogger.sharedLogger.allLogFilePaths;
-
- NSMutableDictionary *gistFiles = [NSMutableDictionary new];
-
- for (NSString *logFilePath in logFilePaths) {
- NSError *error;
- NSString *logContents =
- [NSString stringWithContentsOfFile:logFilePath encoding:NSUTF8StringEncoding error:&error];
- if (error) {
- OWSFail(@"%@ Error loading log file contents: %@", self.logTag, error);
- continue;
- }
- gistFiles[logFilePath.lastPathComponent] = @{
- @"content" : logContents,
- };
- }
-
- NSDictionary *gistDict = @{@"description":[self gistDescription], @"files":gistFiles};
-
- NSData *postData = [NSJSONSerialization dataWithJSONObject:gistDict options:0 error:nil];
-
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"https://api.github.com/gists"] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30];
-
- [[self sharedManager] setResponseData:[NSMutableData data]];
- [[self sharedManager] setBlock:block];
-
- [request setHTTPMethod:@"POST"];
- [request setHTTPBody:postData];
-
- NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:[self sharedManager]];
-
- [connection start];
-
-}
-
-+(Pastelog*)sharedManager {
static Pastelog *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
- sharedMyManager = [[self alloc] init];
+ sharedMyManager = [[self alloc] initDefault];
});
return sharedMyManager;
}
--(instancetype)init {
- if (self = [super init]) {
- self.responseData = [NSMutableData data];
+- (instancetype)initDefault
+{
+ self = [super init];
- OWSSingletonAssert();
+ if (!self) {
+ return self;
}
+
+ OWSSingletonAssert();
+
return self;
}
-+(NSString*)gistDescription{
- size_t size;
- sysctlbyname("hw.machine", NULL, &size, NULL, 0);
- char *machine = malloc(size);
- sysctlbyname("hw.machine", machine, &size, NULL, 0);
- NSString *platform = [NSString stringWithUTF8String:machine];
- free(machine);
-
- NSString *gistDesc = [NSString stringWithFormat:@"iPhone Version: %@, iOS Version: %@", platform,[UIDevice currentDevice].systemVersion];
-
- return gistDesc;
++ (void)submitLogs
+{
+ [self submitLogsWithCompletion:nil];
}
-#pragma mark Network delegates
++ (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completionParam
+{
+ SubmitDebugLogsCompletion completion = ^{
+ if (completionParam) {
+ // Wait a moment. If PasteLog opens a URL, it needs a moment to complete.
+ dispatch_after(
+ dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), completionParam);
+ }
+ };
--(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
- [self.responseData appendData:data];
+ [self uploadLogsWithSuccess:^(NSURL *url) {
+ UIAlertController *alert = [UIAlertController
+ alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.")
+ message:NSLocalizedString(@"DEBUG_LOG_ALERT_MESSAGE", @"Message of the debug log alert.")
+ preferredStyle:UIAlertControllerStyleAlert];
+ [alert addAction:[UIAlertAction
+ actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_EMAIL",
+ @"Label for the 'email debug log' option of the the debug log alert.")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction *action) {
+ [Pastelog.sharedManager submitEmail:url];
+
+ completion();
+ }]];
+ [alert addAction:[UIAlertAction
+ actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK",
+ @"Label for the 'copy link' option of the the debug log alert.")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction *action) {
+ UIPasteboard *pb = [UIPasteboard generalPasteboard];
+ [pb setString:url.absoluteString];
+
+ completion();
+ }]];
+#ifdef DEBUG
+ [alert addAction:[UIAlertAction
+ actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF",
+ @"Label for the 'send to self' option of the the debug log alert.")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction *action) {
+ [Pastelog.sharedManager sendToSelf:url];
+ }]];
+ [alert
+ addAction:[UIAlertAction
+ actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SEND_TO_LAST_THREAD",
+ @"Label for the 'send to last thread' option of the the debug log alert.")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction *action) {
+ [Pastelog.sharedManager sendToMostRecentThread:url];
+ }]];
+#endif
+ [alert
+ addAction:[UIAlertAction
+ actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_BUG_REPORT",
+ @"Label for the 'Open a Bug Report' option of the the debug log alert.")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction *action) {
+ [Pastelog.sharedManager prepareRedirection:url completion:completion];
+ }]];
+ [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_SHARE",
+ @"Label for the 'Share' option of the the debug log alert.")
+ style:UIAlertActionStyleDefault
+ handler:^(UIAlertAction *action) {
+ [AttachmentSharing showShareUIForText:url.absoluteString
+ completion:completion];
+ }]];
+ [alert addAction:[OWSAlerts cancelAction]];
+ UIViewController *presentingViewController
+ = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
+ [presentingViewController presentViewController:alert animated:NO completion:nil];
+ }];
}
-- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
- [self.loadingAlert
- dismissViewControllerAnimated:NO
- completion:^{
- NSError *error;
- NSDictionary *dict =
- [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error];
- if (!error) {
- self.block(nil, [dict objectForKey:@"html_url"]);
- } else {
- DDLogError(@"Error on debug response: %@", error);
- self.block(error, nil);
- }
- }];
- self.loadingAlert = nil;
++ (void)uploadLogsWithSuccess:(nullable UploadDebugLogsSuccess)success
+{
+ OWSAssert(success);
+
+ [[self sharedManager] uploadLogsWithSuccess:success
+ failure:^(NSString *localizedErrorMessage) {
+ [Pastelog showFailureAlertWithMessage:localizedErrorMessage];
+ }];
}
-- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+- (void)uploadLogsWithSuccess:(nullable UploadDebugLogsSuccess)successParam failure:(UploadDebugLogsFailure)failureParam
+{
+ OWSAssert(successParam);
+ OWSAssert(failureParam);
- NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
+ // Ensure that we call the completions on the main thread.
+ UploadDebugLogsSuccess success = ^(NSURL *url) {
+ if (successParam) {
+ DispatchMainThreadSafe(^{
+ successParam(url);
+ });
+ }
+ };
+ UploadDebugLogsFailure failure = ^(NSString *localizedErrorMessage) {
+ DispatchMainThreadSafe(^{
+ failureParam(localizedErrorMessage);
+ });
+ };
- if ( [httpResponse statusCode] != 201) {
- DDLogError(@"Failed to submit debug log: %@", httpResponse.debugDescription);
- [self.loadingAlert
- dismissViewControllerAnimated:NO
- completion:^{
- [connection cancel];
- self.block([NSError errorWithDomain:@"PastelogKit" code:10001 userInfo:@{}], nil);
- }];
- self.loadingAlert = nil;
+ // Phase 1. Make a local copy of all of the log files.
+ NSDateFormatter *dateFormatter = [NSDateFormatter new];
+ [dateFormatter setLocale:[NSLocale currentLocale]];
+ [dateFormatter setDateFormat:@"yyyy.MM.dd hh.mm.ss"];
+ NSString *dateString = [dateFormatter stringFromDate:[NSDate new]];
+ NSString *logsName = [[dateString stringByAppendingString:@" "] stringByAppendingString:NSUUID.UUID.UUIDString];
+ NSString *tempDirectory = NSTemporaryDirectory();
+ NSString *zipFilePath =
+ [tempDirectory stringByAppendingPathComponent:[logsName stringByAppendingPathExtension:@"zip"]];
+ NSString *zipDirPath = [tempDirectory stringByAppendingPathComponent:logsName];
+ [OWSFileSystem ensureDirectoryExists:zipDirPath];
+ [OWSFileSystem protectFileOrFolderAtPath:zipDirPath];
+
+ NSArray *logFilePaths = DebugLogger.sharedLogger.allLogFilePaths;
+ if (logFilePaths.count < 1) {
+ failure(NSLocalizedString(@"DEBUG_LOG_ALERT_NO_LOGS", @"Error indicating that no debug logs could be found."));
+ return;
}
+
+ for (NSString *logFilePath in logFilePaths) {
+ NSString *copyFilePath = [zipDirPath stringByAppendingPathComponent:logFilePath.lastPathComponent];
+ NSError *error;
+ [[NSFileManager defaultManager] copyItemAtPath:logFilePath toPath:copyFilePath error:&error];
+ if (error) {
+ failure(NSLocalizedString(
+ @"DEBUG_LOG_ALERT_COULD_NOT_COPY_LOGS", @"Error indicating that the debug logs could not be copied."));
+ return;
+ }
+ [OWSFileSystem protectFileOrFolderAtPath:copyFilePath];
+ }
+
+ // Phase 2. Zip up the log files.
+ BOOL zipSuccess = [SSZipArchive createZipFileAtPath:zipFilePath
+ withContentsOfDirectory:zipDirPath
+ keepParentDirectory:YES
+ compressionLevel:Z_DEFAULT_COMPRESSION
+ password:nil
+ AES:NO
+ progressHandler:nil];
+ if (!zipSuccess) {
+ failure(NSLocalizedString(
+ @"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS", @"Error indicating that the debug logs could not be packaged."));
+ return;
+ }
+
+ [OWSFileSystem protectFileOrFolderAtPath:zipFilePath];
+ [OWSFileSystem deleteFile:zipDirPath];
+
+ // Phase 3. Upload the log files.
+
+ __weak Pastelog *weakSelf = self;
+ self.currentUploader = [DebugLogUploader new];
+ [self.currentUploader uploadFileWithURL:[NSURL fileURLWithPath:zipFilePath]
+ mimeType:@"application/zip"
+ success:^(DebugLogUploader *uploader, NSURL *url) {
+ if (uploader != weakSelf.currentUploader) {
+ // Ignore events from obsolete uploaders.
+ return;
+ }
+ [OWSFileSystem deleteFile:zipFilePath];
+ success(url);
+ }
+ failure:^(DebugLogUploader *uploader, NSError *error) {
+ if (uploader != weakSelf.currentUploader) {
+ // Ignore events from obsolete uploaders.
+ return;
+ }
+ [OWSFileSystem deleteFile:zipFilePath];
+ failure(NSLocalizedString(
+ @"DEBUG_LOG_ALERT_ERROR_UPLOADING_LOG", @"Error indicating that a debug log could not be uploaded."));
+ }];
}
-- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
- [self.loadingAlert dismissViewControllerAnimated:NO
- completion:^{
- DDLogError(@"Uploading logs failed with error: %@", error);
- self.block(error, nil);
- }];
- self.loadingAlert = nil;
++ (void)showFailureAlertWithMessage:(NSString *)message
+{
+ UIAlertController *alert = [UIAlertController
+ alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE",
+ @"Title of the alert shown for failures while uploading debug logs.")
+ message:message
+ preferredStyle:UIAlertControllerStyleAlert];
+ [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"")
+ style:UIAlertActionStyleDefault
+ handler:nil]];
+ UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
+ [presentingViewController presentViewController:alert animated:NO completion:nil];
}
#pragma mark Logs submission
-- (void)submitEmail:(NSString*)url {
+- (void)submitEmail:(NSURL *)url
+{
NSString *emailAddress = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_EMAIL"];
- NSString *urlString = [NSString stringWithString: [[NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=", emailAddress] stringByAppendingString:[[NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url]stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]];
+ NSString *body = [NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url];
+ NSString *escapedBody =
+ [body stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
+ NSString *urlString =
+ [NSString stringWithFormat:@"mailto:%@?subject=iOS%%20Debug%%20Log&body=%@", emailAddress, escapedBody];
- [UIApplication.sharedApplication openURL: [NSURL URLWithString: urlString]];
+ [UIApplication.sharedApplication openURL:[NSURL URLWithString:urlString]];
}
-- (void)prepareRedirection:(NSString *)url shareCompletion:(DebugLogsSharedBlock)shareCompletion
+- (void)prepareRedirection:(NSURL *)url completion:(SubmitDebugLogsCompletion)completion
{
- OWSAssert(shareCompletion);
+ OWSAssert(completion);
UIPasteboard *pb = [UIPasteboard generalPasteboard];
- [pb setString:url];
+ [pb setString:url.absoluteString];
UIAlertController *alert =
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE",
@@ -267,18 +492,18 @@
[alert addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"OK", @"")
style:UIAlertActionStyleDefault
- handler:^(UIAlertAction *_Nonnull action) {
+ handler:^(UIAlertAction *action) {
[UIApplication.sharedApplication
openURL:[NSURL URLWithString:[[NSBundle mainBundle]
objectForInfoDictionaryKey:@"LOGS_URL"]]];
- shareCompletion();
+ completion();
}]];
UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
[presentingViewController presentViewController:alert animated:NO completion:nil];
}
-- (void)sendToSelf:(NSString *)url
+- (void)sendToSelf:(NSURL *)url
{
if (![TSAccountManager isRegistered]) {
return;
@@ -288,35 +513,39 @@
DispatchMainThreadSafe(^{
__block TSThread *thread = nil;
- [TSStorageManager.dbReadWriteConnection
- readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
- thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
- }];
- [ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender];
+ [TSStorageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
+ thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
+ }];
+ [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender];
});
// Also copy to pasteboard.
- [[UIPasteboard generalPasteboard] setString:url];
+ [[UIPasteboard generalPasteboard] setString:url.absoluteString];
}
-- (void)sendToMostRecentThread:(NSString *)url
+- (void)sendToMostRecentThread:(NSURL *)url
{
if (![TSAccountManager isRegistered]) {
return;
}
- OWSMessageSender *messageSender = Environment.current.messageSender;
+ __block TSThread *thread = nil;
+ [TSStorageManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
+ thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:TSInboxGroup];
+ }];
DispatchMainThreadSafe(^{
- __block TSThread *thread = nil;
- [TSStorageManager.dbReadWriteConnection
- readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
- thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:[TSThread collection]];
- }];
- [ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender];
+ if (thread) {
+ OWSMessageSender *messageSender = Environment.current.messageSender;
+ [ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender];
+ } else {
+ [Pastelog showFailureAlertWithMessage:@"Could not find last thread."];
+ }
});
// Also copy to pasteboard.
- [[UIPasteboard generalPasteboard] setString:url];
+ [[UIPasteboard generalPasteboard] setString:url.absoluteString];
}
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings
index 9bf4624a8c..bbd9fdf006 100644
--- a/Signal/translations/en.lproj/Localizable.strings
+++ b/Signal/translations/en.lproj/Localizable.strings
@@ -502,12 +502,21 @@
/* The day before today. */
"DATE_YESTERDAY" = "Yesterday";
-/* Message indicating that the debug log is being uploaded. */
-"DEBUG_LOG_ACTIVITY_INDICATOR" = "Sending Debug Log...";
+/* Error indicating that the debug logs could not be copied. */
+"DEBUG_LOG_ALERT_COULD_NOT_COPY_LOGS" = "Could not copy logs.";
+
+/* Error indicating that the debug logs could not be packaged. */
+"DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS" = "Could not package logs.";
+
+/* Error indicating that a debug log could not be uploaded. */
+"DEBUG_LOG_ALERT_ERROR_UPLOADING_LOG" = "Could not upload logs.";
/* Message of the debug log alert. */
"DEBUG_LOG_ALERT_MESSAGE" = "What would you like to do with the link to your debug log?";
+/* Error indicating that no debug logs could be found. */
+"DEBUG_LOG_ALERT_NO_LOGS" = "Could not find any logs.";
+
/* Label for the 'Open a Bug Report' option of the the debug log alert. */
"DEBUG_LOG_ALERT_OPTION_BUG_REPORT" = "Open a Bug Report";
@@ -523,11 +532,12 @@
/* Label for the 'send to self' option of the the debug log alert. */
"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF" = "Send to Self";
-/* Title of the debug log alert. */
-"DEBUG_LOG_ALERT_TITLE" = "One More Step";
+/* Label for the 'Share' option of the the debug log alert. */
+"DEBUG_LOG_ALERT_OPTION_SHARE" = "Share";
-/* Title of the alert indicating the debug log upload failed. */
-"DEBUG_LOG_FAILURE_ALERT_TITLE" = "Failed to Submit Debug Log";
+/* Title of the alert shown for failures while uploading debug logs.
+ Title of the debug log alert. */
+"DEBUG_LOG_ALERT_TITLE" = "One More Step";
/* Message of the alert before redirecting to Github Issues. */
"DEBUG_LOG_GITHUB_ISSUE_ALERT_MESSAGE" = "The gist link was copied in your clipboard. You are about to be redirected to the GitHub issue list.";
@@ -1563,6 +1573,9 @@
/* No comment provided by engineer. */
"SETTINGS_ADVANCED_TITLE" = "Advanced";
+/* Format string for the default 'Note' sound. Embeds the system {{sound name}}. */
+"SETTINGS_AUDIO_DEFAULT_TONE_LABEL_FORMAT" = "%@ (default)";
+
/* A label for the 'add phone number' button in the block list table. */
"SETTINGS_BLOCK_LIST_ADD_BUTTON" = "Add…";
diff --git a/SignalMessaging/attachments/AttachmentSharing.h b/SignalMessaging/attachments/AttachmentSharing.h
index 66bf2b833a..712c77157a 100644
--- a/SignalMessaging/attachments/AttachmentSharing.h
+++ b/SignalMessaging/attachments/AttachmentSharing.h
@@ -2,18 +2,28 @@
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
+NS_ASSUME_NONNULL_BEGIN
+
@class TSAttachmentStream;
+typedef void (^AttachmentSharingCompletion)(void);
+
@interface AttachmentSharing : NSObject
+ (void)showShareUIForAttachment:(TSAttachmentStream *)stream;
+ (void)showShareUIForURL:(NSURL *)url;
++ (void)showShareUIForURL:(NSURL *)url completion:(nullable AttachmentSharingCompletion)completion;
+
+ (void)showShareUIForText:(NSString *)text;
++ (void)showShareUIForText:(NSString *)text completion:(nullable AttachmentSharingCompletion)completion;
+
#ifdef DEBUG
+ (void)showShareUIForUIImage:(UIImage *)image;
#endif
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SignalMessaging/attachments/AttachmentSharing.m b/SignalMessaging/attachments/AttachmentSharing.m
index 7508a3645f..c648ccd18b 100644
--- a/SignalMessaging/attachments/AttachmentSharing.m
+++ b/SignalMessaging/attachments/AttachmentSharing.m
@@ -8,6 +8,8 @@
#import
#import
+NS_ASSUME_NONNULL_BEGIN
+
@implementation AttachmentSharing
+ (void)showShareUIForAttachment:(TSAttachmentStream *)stream
@@ -18,21 +20,33 @@
}
+ (void)showShareUIForURL:(NSURL *)url
+{
+ [self showShareUIForURL:url completion:nil];
+}
+
++ (void)showShareUIForURL:(NSURL *)url completion:(nullable AttachmentSharingCompletion)completion
{
OWSAssert(url);
[AttachmentSharing showShareUIForActivityItems:@[
url,
- ]];
+ ]
+ completion:completion];
}
+ (void)showShareUIForText:(NSString *)text
+{
+ [self showShareUIForText:text completion:nil];
+}
+
++ (void)showShareUIForText:(NSString *)text completion:(nullable AttachmentSharingCompletion)completion
{
OWSAssert(text);
[AttachmentSharing showShareUIForActivityItems:@[
text,
- ]];
+ ]
+ completion:completion];
}
#ifdef DEBUG
@@ -42,11 +56,12 @@
[AttachmentSharing showShareUIForActivityItems:@[
image,
- ]];
+ ]
+ completion:nil];
}
#endif
-+ (void)showShareUIForActivityItems:(NSArray *)activityItems
++ (void)showShareUIForActivityItems:(NSArray *)activityItems completion:(nullable AttachmentSharingCompletion)completion
{
OWSAssert(activityItems);
@@ -67,6 +82,10 @@
} else if (completed) {
DDLogInfo(@"%@ Did share with activityType: %@", self.logTag, activityType);
}
+
+ if (completion) {
+ DispatchMainThreadSafe(completion);
+ }
}];
UIViewController *fromViewController = CurrentAppContext().frontmostViewController;
@@ -84,3 +103,5 @@
}
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SignalMessaging/environment/OWSSounds.m b/SignalMessaging/environment/OWSSounds.m
index 54140475b9..bf48527d9c 100644
--- a/SignalMessaging/environment/OWSSounds.m
+++ b/SignalMessaging/environment/OWSSounds.m
@@ -62,8 +62,9 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
+ (NSArray *)allNotificationSounds
{
return @[
- // None should be first.
+ // None and Note (default) should be first.
@(OWSSound_None),
+ @(OWSSound_Note),
@(OWSSound_Aurora),
@(OWSSound_Bamboo),
@@ -74,7 +75,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
@(OWSSound_Hello),
@(OWSSound_Input),
@(OWSSound_Keys),
- @(OWSSound_Note),
@(OWSSound_Popcorn),
@(OWSSound_Pulse),
@(OWSSound_Synth),
@@ -89,7 +89,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
OWSFail(@"%@ invalid argument.", self.logTag);
return @"";
- // Notification Sounds
+ // Notification Sounds
case OWSSound_Aurora:
return @"Aurora";
case OWSSound_Bamboo:
@@ -117,11 +117,9 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
case OWSSound_ClassicNotification:
return @"Classic";
- // Ringtone Sounds
+ // Call Audio
case OWSSound_Opening:
return @"Opening";
-
- // Calls
case OWSSound_CallConnecting:
return @"Call Connecting";
case OWSSound_CallOutboundRinging:
@@ -131,7 +129,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
case OWSSound_CallFailure:
return @"Call Failure";
- // Other
+ // Other
case OWSSound_None:
return NSLocalizedString(@"SOUNDS_NONE",
@"Label for the 'no sound' option that allows users to disable sounds for notifications, "
@@ -246,6 +244,27 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
+ (void)setGlobalNotificationSound:(OWSSound)sound
{
+ [self.sharedManager setGlobalNotificationSound:sound];
+}
+
+- (void)setGlobalNotificationSound:(OWSSound)sound
+{
+ [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
+ [self setGlobalNotificationSound:sound transaction:transaction];
+ }];
+}
+
++ (void)setGlobalNotificationSound:(OWSSound)sound transaction:(YapDatabaseReadWriteTransaction *)transaction
+{
+ [self.sharedManager setGlobalNotificationSound:sound transaction:transaction];
+}
+
+- (void)setGlobalNotificationSound:(OWSSound)sound transaction:(YapDatabaseReadWriteTransaction *)transaction
+{
+ OWSAssert(transaction);
+
+ DDLogInfo(@"%@ Setting global notification sound to: %@", self.logTag, [[self class] displayNameForSound:sound]);
+
// Fallback push notifications play a sound specified by the server, but we don't want to store this configuration
// on the server. Instead, we create a file with the same name as the default to be played when receiving
// a fallback notification.
@@ -276,16 +295,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
return;
}
- OWSSounds *instance = OWSSounds.sharedManager;
- [instance.dbConnection setObject:@(sound)
- forKey:kOWSSoundsStorageGlobalNotificationKey
- inCollection:kOWSSoundsStorageNotificationCollection];
-}
-
-+ (void)setGlobalNotificationSound:(OWSSound)sound transaction:(YapDatabaseReadWriteTransaction *)transaction
-{
- OWSAssert(transaction);
-
[transaction setObject:@(sound)
forKey:kOWSSoundsStorageGlobalNotificationKey
inCollection:kOWSSoundsStorageNotificationCollection];
diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m
index cfec11736d..8ae0f01eb8 100644
--- a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m
+++ b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m
@@ -65,10 +65,7 @@ NS_ASSUME_NONNULL_BEGIN
NSMutableArray *migrationsToRun = [NSMutableArray new];
for (OWSDatabaseMigration *migration in migrations) {
- if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId]) {
- DDLogDebug(@"%@ Skipping previously run migration: %@", self.logTag, migration);
- } else {
- DDLogWarn(@"%@ Running migration: %@", self.logTag, migration);
+ if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId] == nil) {
[migrationsToRun addObject:migration];
}
}
diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m
index b0aecb3a19..76c9a1428b 100644
--- a/SignalMessaging/profiles/OWSProfileManager.m
+++ b/SignalMessaging/profiles/OWSProfileManager.m
@@ -7,7 +7,6 @@
#import "NSString+OWS.h"
#import "OWSUserProfile.h"
#import "UIImage+OWS.h"
-#import
#import
#import
#import
@@ -784,12 +783,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
return nil;
}
-- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfileParameter
+- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfile
{
- OWSAssert(userProfileParameter);
-
- // Make a local copy.
- OWSUserProfile *userProfile = [userProfileParameter copy];
+ OWSAssert(userProfile);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (userProfile.avatarUrlPath.length < 1) {
@@ -816,6 +812,8 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
[self.currentAvatarDownloads addObject:userProfile.recipientId];
}
+ DDLogVerbose(@"%@ downloading profile avatar: %@", self.logTag, userProfile.uniqueId);
+
NSString *tempDirectory = NSTemporaryDirectory();
NSString *tempFilePath = [tempDirectory stringByAppendingPathComponent:fileName];
@@ -919,7 +917,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
[userProfile updateWithProfileName:profileName
avatarUrlPath:avatarUrlPath
- avatarFileName:userProfile.avatarFileName // use existing file name if already downloaded
dbConnection:self.dbConnection
completion:nil];
@@ -930,18 +927,17 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
OWSUserProfile *localUserProfile = self.localUserProfile;
OWSAssert(localUserProfile);
- // Don't clear avatarFileName optimistically.
- // * The profile avatar probably isn't out of sync.
- // * If the profile avatar is out of sync, it can be synced on next app launch.
- // * We don't want to touch local avatar state until we've
- // downloaded the latest avatar by downloadAvatarForUserProfile.
[localUserProfile updateWithProfileName:profileName
avatarUrlPath:avatarUrlPath
dbConnection:self.dbConnection
completion:nil];
}
- if (userProfile.avatarUrlPath.length > 0 && userProfile.avatarFileName.length == 0) {
+ // Whenever we change avatarUrlPath, OWSUserProfile clears avatarFileName.
+ // So if avatarUrlPath is set and avatarFileName is not set, we should to
+ // download this avatar. downloadAvatarForUserProfile will de-bounce
+ // downloads.
+ if (userProfile.avatarUrlPath.length > 0 && userProfile.avatarFileName.length < 1) {
[self downloadAvatarForUserProfile:userProfile];
}
});
diff --git a/SignalMessaging/profiles/OWSUserProfile.h b/SignalMessaging/profiles/OWSUserProfile.h
index c58e59e792..35402fff14 100644
--- a/SignalMessaging/profiles/OWSUserProfile.h
+++ b/SignalMessaging/profiles/OWSUserProfile.h
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
+// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import
diff --git a/SignalMessaging/profiles/OWSUserProfile.m b/SignalMessaging/profiles/OWSUserProfile.m
index ef56f4a057..f1942d0878 100644
--- a/SignalMessaging/profiles/OWSUserProfile.m
+++ b/SignalMessaging/profiles/OWSUserProfile.m
@@ -109,12 +109,14 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
BOOL didChange;
if (_avatarUrlPath == nil && avatarUrlPath == nil) {
didChange = NO;
- } else if (_avatarUrlPath != nil && avatarUrlPath != nil) {
+ } else if (_avatarUrlPath != nil || avatarUrlPath != nil) {
didChange = YES;
} else {
didChange = [_avatarUrlPath isEqualToString:avatarUrlPath];
}
+ _avatarUrlPath = avatarUrlPath;
+
if (didChange) {
// If the avatarURL changed, the avatarFileName can't be valid.
// Clear it.
@@ -137,7 +139,9 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
dbConnection:(YapDatabaseConnection *)dbConnection
completion:(nullable OWSUserProfileCompletion)completion
{
- NSDictionary *beforeSnapshot = self.dictionaryValue;
+ // self might be the latest instance, so take a "before" snapshot
+ // before any changes have been made.
+ __block NSDictionary *beforeSnapshot = [self.dictionaryValue copy];
changeBlock(self);
@@ -146,12 +150,21 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
NSString *collection = [[self class] collection];
OWSUserProfile *_Nullable latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
if (latestInstance) {
+ // If self is NOT the latest instance, take a new "before" snapshot
+ // before updating.
+ if (self != latestInstance) {
+ beforeSnapshot = [latestInstance.dictionaryValue copy];
+ }
+
changeBlock(latestInstance);
- NSDictionary *afterSnapshot = latestInstance.dictionaryValue;
+ NSDictionary *afterSnapshot = [latestInstance.dictionaryValue copy];
+
if ([beforeSnapshot isEqual:afterSnapshot]) {
- DDLogVerbose(
- @"%@ Ignoring redundant update in %s: %@", self.logTag, functionName, self.debugDescription);
+ DDLogVerbose(@"%@ Ignoring redundant update in %s: %@",
+ self.logTag,
+ functionName,
+ self.debugDescription);
didChange = NO;
} else {
[latestInstance saveWithTransaction:transaction];
diff --git a/SignalMessaging/utils/DebugLogger.h b/SignalMessaging/utils/DebugLogger.h
index a3ec93bfbf..a08037e981 100644
--- a/SignalMessaging/utils/DebugLogger.h
+++ b/SignalMessaging/utils/DebugLogger.h
@@ -1,9 +1,11 @@
//
-// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
+// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import
+NS_ASSUME_NONNULL_BEGIN
+
@interface DebugLogger : NSObject
+ (instancetype)sharedLogger;
@@ -19,3 +21,5 @@
- (NSArray *)allLogFilePaths;
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SignalMessaging/utils/DebugLogger.m b/SignalMessaging/utils/DebugLogger.m
index cb38f4f8ff..9d859c6e52 100644
--- a/SignalMessaging/utils/DebugLogger.m
+++ b/SignalMessaging/utils/DebugLogger.m
@@ -11,9 +11,13 @@
#pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging.
#import
+NS_ASSUME_NONNULL_BEGIN
+
+const NSUInteger kMaxDebugLogFileSize = 1024 * 1024 * 3;
+
@interface DebugLogger ()
-@property (nonatomic) DDFileLogger *fileLogger;
+@property (nonatomic, nullable) DDFileLogger *fileLogger;
@end
@@ -67,8 +71,7 @@
self.fileLogger.rollingFrequency = kDayInterval;
// Keep last 3 days of logs - or last 3 logs (if logs rollover due to max file size).
self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3;
- // Raise the max file size per log file to 3 MB.
- self.fileLogger.maximumFileSize = 1024 * 1024 * 3;
+ self.fileLogger.maximumFileSize = kMaxDebugLogFileSize;
self.fileLogger.logFormatter = [OWSScrubbingLogFormatter new];
[DDLog addLogger:self.fileLogger];
@@ -133,3 +136,5 @@
}
@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SignalServiceKit/src/Util/OWSError.h b/SignalServiceKit/src/Util/OWSError.h
index ad252ec2c8..03c96a95a0 100644
--- a/SignalServiceKit/src/Util/OWSError.h
+++ b/SignalServiceKit/src/Util/OWSError.h
@@ -29,7 +29,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
OWSErrorCodeMessageDeletedBeforeSent = 777410,
OWSErrorCodeDatabaseConversionFatalError = 777411,
OWSErrorCodeMoveFileToSharedDataContainerError = 777412,
- OWSErrorCodeRegistrationMissing2FAPIN = 777413
+ OWSErrorCodeRegistrationMissing2FAPIN = 777413,
+ OWSErrorCodeDebugLogUploadFailed = 777414,
};
extern NSString *const OWSErrorRecipientIdentifierKey;
diff --git a/SignalShareExtension/Info.plist b/SignalShareExtension/Info.plist
index 72464dc245..b81d29e0d7 100644
--- a/SignalShareExtension/Info.plist
+++ b/SignalShareExtension/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
2.21.0
CFBundleVersion
- 2.21.0.0
+ 2.21.0.1
ITSAppUsesNonExemptEncryption
NSAppTransportSecurity