Merge tag '2.21.0.1'
This commit is contained in:
commit
1ff2f3f42e
|
@ -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
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.21.0.0</string>
|
<string>2.21.0.1</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LOGS_EMAIL</key>
|
<key>LOGS_EMAIL</key>
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#import <SignalServiceKit/TSStorageManager+Calling.h>
|
#import <SignalServiceKit/TSStorageManager+Calling.h>
|
||||||
#import <SignalServiceKit/TextSecureKitEnv.h>
|
#import <SignalServiceKit/TextSecureKitEnv.h>
|
||||||
#import <YapDatabase/YapDatabaseCryptoUtils.h>
|
#import <YapDatabase/YapDatabaseCryptoUtils.h>
|
||||||
|
#import <sys/sysctl.h>
|
||||||
|
|
||||||
@import WebRTC;
|
@import WebRTC;
|
||||||
@import Intents;
|
@import Intents;
|
||||||
|
@ -324,7 +325,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil)
|
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil)
|
||||||
style:UIAlertActionStyleDefault
|
style:UIAlertActionStyleDefault
|
||||||
handler:^(UIAlertAction *_Nonnull action) {
|
handler:^(UIAlertAction *_Nonnull action) {
|
||||||
[Pastelog submitLogsWithShareCompletion:^{
|
[Pastelog submitLogsWithCompletion:^{
|
||||||
DDLogInfo(
|
DDLogInfo(
|
||||||
@"%@ exiting after sharing debug logs.", self.logTag);
|
@"%@ exiting after sharing debug logs.", self.logTag);
|
||||||
[DDLog flushLog];
|
[DDLog flushLog];
|
||||||
|
@ -396,6 +397,15 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||||
if (languageCode.length > 0) {
|
if (languageCode.length > 0) {
|
||||||
DDLogInfo(@"Language Code: %@", languageCode);
|
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
|
- (UIViewController *)loadingRootViewController
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#import "OWSTableViewController.h"
|
#import "OWSTableViewController.h"
|
||||||
#import "Signal-Swift.h"
|
#import "Signal-Swift.h"
|
||||||
#import "ThreadUtil.h"
|
#import "ThreadUtil.h"
|
||||||
#import <AFNetworking/AFNetworking.h>
|
|
||||||
#import <AxolotlKit/PreKeyBundle.h>
|
#import <AxolotlKit/PreKeyBundle.h>
|
||||||
#import <Curve25519Kit/Randomness.h>
|
#import <Curve25519Kit/Randomness.h>
|
||||||
#import <SignalMessaging/Environment.h>
|
#import <SignalMessaging/Environment.h>
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#import "RegistrationViewController.h"
|
#import "RegistrationViewController.h"
|
||||||
#import "Signal-Swift.h"
|
#import "Signal-Swift.h"
|
||||||
#import "ThreadUtil.h"
|
#import "ThreadUtil.h"
|
||||||
#import <AFNetworking/AFNetworking.h>
|
|
||||||
#import <AxolotlKit/PreKeyBundle.h>
|
#import <AxolotlKit/PreKeyBundle.h>
|
||||||
#import <SignalMessaging/AttachmentSharing.h>
|
#import <SignalMessaging/AttachmentSharing.h>
|
||||||
#import <SignalMessaging/Environment.h>
|
#import <SignalMessaging/Environment.h>
|
||||||
|
|
|
@ -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"
|
#import "DebugUISyncMessages.h"
|
||||||
|
@ -7,7 +7,6 @@
|
||||||
#import "OWSTableViewController.h"
|
#import "OWSTableViewController.h"
|
||||||
#import "Signal-Swift.h"
|
#import "Signal-Swift.h"
|
||||||
#import "ThreadUtil.h"
|
#import "ThreadUtil.h"
|
||||||
#import <AFNetworking/AFNetworking.h>
|
|
||||||
#import <AxolotlKit/PreKeyBundle.h>
|
#import <AxolotlKit/PreKeyBundle.h>
|
||||||
#import <Curve25519Kit/Randomness.h>
|
#import <Curve25519Kit/Randomness.h>
|
||||||
#import <SignalMessaging/Environment.h>
|
#import <SignalMessaging/Environment.h>
|
||||||
|
|
|
@ -74,13 +74,25 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
for (NSNumber *nsValue in allSounds) {
|
for (NSNumber *nsValue in allSounds) {
|
||||||
OWSSound sound = (OWSSound)nsValue.intValue;
|
OWSSound sound = (OWSSound)nsValue.intValue;
|
||||||
OWSTableItem *item;
|
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) {
|
if (sound == self.currentSound) {
|
||||||
item = [OWSTableItem checkmarkItemWithText:[OWSSounds displayNameForSound:sound]
|
item = [OWSTableItem checkmarkItemWithText:soundLabelText
|
||||||
actionBlock:^{
|
actionBlock:^{
|
||||||
[weakSelf soundWasSelected:sound];
|
[weakSelf soundWasSelected:sound];
|
||||||
}];
|
}];
|
||||||
} else {
|
} else {
|
||||||
item = [OWSTableItem actionItemWithText:[OWSSounds displayNameForSound:sound]
|
item = [OWSTableItem actionItemWithText:soundLabelText
|
||||||
actionBlock:^{
|
actionBlock:^{
|
||||||
[weakSelf soundWasSelected:sound];
|
[weakSelf soundWasSelected:sound];
|
||||||
}];
|
}];
|
||||||
|
|
|
@ -2,14 +2,17 @@
|
||||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
typedef void (^SubmitDebugLogsCompletion)(void);
|
||||||
|
|
||||||
@interface Pastelog : NSObject
|
@interface Pastelog : NSObject
|
||||||
|
|
||||||
typedef void (^DebugLogsUploadedBlock)(NSError *error, NSString *urlString);
|
- (instancetype)init NS_UNAVAILABLE;
|
||||||
typedef void (^DebugLogsSharedBlock)(void);
|
|
||||||
|
|
||||||
+(void)submitLogs;
|
+ (void)submitLogs;
|
||||||
+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)block;
|
+ (void)submitLogsWithCompletion:(nullable SubmitDebugLogsCompletion)completion;
|
||||||
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block;
|
|
||||||
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
#import "Pastelog.h"
|
#import "Pastelog.h"
|
||||||
#import "Signal-Swift.h"
|
#import "Signal-Swift.h"
|
||||||
#import "ThreadUtil.h"
|
#import "ThreadUtil.h"
|
||||||
|
#import "zlib.h"
|
||||||
|
#import <AFNetworking/AFNetworking.h>
|
||||||
|
#import <SSZipArchive/SSZipArchive.h>
|
||||||
|
#import <SignalMessaging/AttachmentSharing.h>
|
||||||
#import <SignalMessaging/DebugLogger.h>
|
#import <SignalMessaging/DebugLogger.h>
|
||||||
#import <SignalMessaging/Environment.h>
|
#import <SignalMessaging/Environment.h>
|
||||||
#import <SignalServiceKit/AppContext.h>
|
#import <SignalServiceKit/AppContext.h>
|
||||||
|
@ -12,13 +16,227 @@
|
||||||
#import <SignalServiceKit/TSContactThread.h>
|
#import <SignalServiceKit/TSContactThread.h>
|
||||||
#import <SignalServiceKit/TSStorageManager.h>
|
#import <SignalServiceKit/TSStorageManager.h>
|
||||||
#import <SignalServiceKit/Threading.h>
|
#import <SignalServiceKit/Threading.h>
|
||||||
#import <sys/sysctl.h>
|
|
||||||
|
|
||||||
@interface Pastelog () <NSURLConnectionDelegate, NSURLConnectionDataDelegate, UIAlertViewDelegate>
|
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<AFMultipartFormData> 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 () <UIAlertViewDelegate>
|
||||||
|
|
||||||
@property (nonatomic) UIAlertController *loadingAlert;
|
@property (nonatomic) UIAlertController *loadingAlert;
|
||||||
@property (nonatomic) NSMutableData *responseData;
|
|
||||||
@property (nonatomic) DebugLogsUploadedBlock block;
|
@property (nonatomic) DebugLogUploader *currentUploader;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -26,237 +244,244 @@
|
||||||
|
|
||||||
@implementation Pastelog
|
@implementation Pastelog
|
||||||
|
|
||||||
+(void)submitLogs {
|
+ (instancetype)sharedManager
|
||||||
[self submitLogsWithShareCompletion:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)shareCompletionParam
|
|
||||||
{
|
{
|
||||||
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<NSString *> *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 Pastelog *sharedMyManager = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
sharedMyManager = [[self alloc] init];
|
sharedMyManager = [[self alloc] initDefault];
|
||||||
});
|
});
|
||||||
return sharedMyManager;
|
return sharedMyManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
-(instancetype)init {
|
- (instancetype)initDefault
|
||||||
if (self = [super init]) {
|
{
|
||||||
self.responseData = [NSMutableData data];
|
self = [super init];
|
||||||
|
|
||||||
OWSSingletonAssert();
|
if (!self) {
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OWSSingletonAssert();
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
+(NSString*)gistDescription{
|
+ (void)submitLogs
|
||||||
size_t size;
|
{
|
||||||
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
|
[self submitLogsWithCompletion:nil];
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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 uploadLogsWithSuccess:^(NSURL *url) {
|
||||||
[self.responseData appendData:data];
|
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 {
|
+ (void)uploadLogsWithSuccess:(nullable UploadDebugLogsSuccess)success
|
||||||
[self.loadingAlert
|
{
|
||||||
dismissViewControllerAnimated:NO
|
OWSAssert(success);
|
||||||
completion:^{
|
|
||||||
NSError *error;
|
[[self sharedManager] uploadLogsWithSuccess:success
|
||||||
NSDictionary *dict =
|
failure:^(NSString *localizedErrorMessage) {
|
||||||
[NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error];
|
[Pastelog showFailureAlertWithMessage:localizedErrorMessage];
|
||||||
if (!error) {
|
}];
|
||||||
self.block(nil, [dict objectForKey:@"html_url"]);
|
|
||||||
} else {
|
|
||||||
DDLogError(@"Error on debug response: %@", error);
|
|
||||||
self.block(error, nil);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
self.loadingAlert = nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (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) {
|
// Phase 1. Make a local copy of all of the log files.
|
||||||
DDLogError(@"Failed to submit debug log: %@", httpResponse.debugDescription);
|
NSDateFormatter *dateFormatter = [NSDateFormatter new];
|
||||||
[self.loadingAlert
|
[dateFormatter setLocale:[NSLocale currentLocale]];
|
||||||
dismissViewControllerAnimated:NO
|
[dateFormatter setDateFormat:@"yyyy.MM.dd hh.mm.ss"];
|
||||||
completion:^{
|
NSString *dateString = [dateFormatter stringFromDate:[NSDate new]];
|
||||||
[connection cancel];
|
NSString *logsName = [[dateString stringByAppendingString:@" "] stringByAppendingString:NSUUID.UUID.UUIDString];
|
||||||
self.block([NSError errorWithDomain:@"PastelogKit" code:10001 userInfo:@{}], nil);
|
NSString *tempDirectory = NSTemporaryDirectory();
|
||||||
}];
|
NSString *zipFilePath =
|
||||||
self.loadingAlert = nil;
|
[tempDirectory stringByAppendingPathComponent:[logsName stringByAppendingPathExtension:@"zip"]];
|
||||||
|
NSString *zipDirPath = [tempDirectory stringByAppendingPathComponent:logsName];
|
||||||
|
[OWSFileSystem ensureDirectoryExists:zipDirPath];
|
||||||
|
[OWSFileSystem protectFileOrFolderAtPath:zipDirPath];
|
||||||
|
|
||||||
|
NSArray<NSString *> *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 {
|
+ (void)showFailureAlertWithMessage:(NSString *)message
|
||||||
[self.loadingAlert dismissViewControllerAnimated:NO
|
{
|
||||||
completion:^{
|
UIAlertController *alert = [UIAlertController
|
||||||
DDLogError(@"Uploading logs failed with error: %@", error);
|
alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE",
|
||||||
self.block(error, nil);
|
@"Title of the alert shown for failures while uploading debug logs.")
|
||||||
}];
|
message:message
|
||||||
self.loadingAlert = nil;
|
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
|
#pragma mark Logs submission
|
||||||
|
|
||||||
- (void)submitEmail:(NSString*)url {
|
- (void)submitEmail:(NSURL *)url
|
||||||
|
{
|
||||||
NSString *emailAddress = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"LOGS_EMAIL"];
|
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];
|
UIPasteboard *pb = [UIPasteboard generalPasteboard];
|
||||||
[pb setString:url];
|
[pb setString:url.absoluteString];
|
||||||
|
|
||||||
UIAlertController *alert =
|
UIAlertController *alert =
|
||||||
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE",
|
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE",
|
||||||
|
@ -267,18 +492,18 @@
|
||||||
[alert addAction:[UIAlertAction
|
[alert addAction:[UIAlertAction
|
||||||
actionWithTitle:NSLocalizedString(@"OK", @"")
|
actionWithTitle:NSLocalizedString(@"OK", @"")
|
||||||
style:UIAlertActionStyleDefault
|
style:UIAlertActionStyleDefault
|
||||||
handler:^(UIAlertAction *_Nonnull action) {
|
handler:^(UIAlertAction *action) {
|
||||||
[UIApplication.sharedApplication
|
[UIApplication.sharedApplication
|
||||||
openURL:[NSURL URLWithString:[[NSBundle mainBundle]
|
openURL:[NSURL URLWithString:[[NSBundle mainBundle]
|
||||||
objectForInfoDictionaryKey:@"LOGS_URL"]]];
|
objectForInfoDictionaryKey:@"LOGS_URL"]]];
|
||||||
|
|
||||||
shareCompletion();
|
completion();
|
||||||
}]];
|
}]];
|
||||||
UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
|
UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
|
||||||
[presentingViewController presentViewController:alert animated:NO completion:nil];
|
[presentingViewController presentViewController:alert animated:NO completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendToSelf:(NSString *)url
|
- (void)sendToSelf:(NSURL *)url
|
||||||
{
|
{
|
||||||
if (![TSAccountManager isRegistered]) {
|
if (![TSAccountManager isRegistered]) {
|
||||||
return;
|
return;
|
||||||
|
@ -288,35 +513,39 @@
|
||||||
|
|
||||||
DispatchMainThreadSafe(^{
|
DispatchMainThreadSafe(^{
|
||||||
__block TSThread *thread = nil;
|
__block TSThread *thread = nil;
|
||||||
[TSStorageManager.dbReadWriteConnection
|
[TSStorageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
|
||||||
thread = [TSContactThread getOrCreateThreadWithContactId:recipientId transaction:transaction];
|
}];
|
||||||
}];
|
[ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender];
|
||||||
[ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also copy to pasteboard.
|
// Also copy to pasteboard.
|
||||||
[[UIPasteboard generalPasteboard] setString:url];
|
[[UIPasteboard generalPasteboard] setString:url.absoluteString];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendToMostRecentThread:(NSString *)url
|
- (void)sendToMostRecentThread:(NSURL *)url
|
||||||
{
|
{
|
||||||
if (![TSAccountManager isRegistered]) {
|
if (![TSAccountManager isRegistered]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OWSMessageSender *messageSender = Environment.current.messageSender;
|
|
||||||
|
|
||||||
|
__block TSThread *thread = nil;
|
||||||
|
[TSStorageManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||||
|
thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:TSInboxGroup];
|
||||||
|
}];
|
||||||
DispatchMainThreadSafe(^{
|
DispatchMainThreadSafe(^{
|
||||||
__block TSThread *thread = nil;
|
if (thread) {
|
||||||
[TSStorageManager.dbReadWriteConnection
|
OWSMessageSender *messageSender = Environment.current.messageSender;
|
||||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
[ThreadUtil sendMessageWithText:url.absoluteString inThread:thread messageSender:messageSender];
|
||||||
thread = [[transaction ext:TSThreadDatabaseViewExtensionName] firstObjectInGroup:[TSThread collection]];
|
} else {
|
||||||
}];
|
[Pastelog showFailureAlertWithMessage:@"Could not find last thread."];
|
||||||
[ThreadUtil sendMessageWithText:url inThread:thread messageSender:messageSender];
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Also copy to pasteboard.
|
// Also copy to pasteboard.
|
||||||
[[UIPasteboard generalPasteboard] setString:url];
|
[[UIPasteboard generalPasteboard] setString:url.absoluteString];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -502,12 +502,21 @@
|
||||||
/* The day before today. */
|
/* The day before today. */
|
||||||
"DATE_YESTERDAY" = "Yesterday";
|
"DATE_YESTERDAY" = "Yesterday";
|
||||||
|
|
||||||
/* Message indicating that the debug log is being uploaded. */
|
/* Error indicating that the debug logs could not be copied. */
|
||||||
"DEBUG_LOG_ACTIVITY_INDICATOR" = "Sending Debug Log...";
|
"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. */
|
/* Message of the debug log alert. */
|
||||||
"DEBUG_LOG_ALERT_MESSAGE" = "What would you like to do with the link to your debug log?";
|
"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. */
|
/* Label for the 'Open a Bug Report' option of the the debug log alert. */
|
||||||
"DEBUG_LOG_ALERT_OPTION_BUG_REPORT" = "Open a Bug Report";
|
"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. */
|
/* Label for the 'send to self' option of the the debug log alert. */
|
||||||
"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF" = "Send to Self";
|
"DEBUG_LOG_ALERT_OPTION_SEND_TO_SELF" = "Send to Self";
|
||||||
|
|
||||||
/* Title of the debug log alert. */
|
/* Label for the 'Share' option of the the debug log alert. */
|
||||||
"DEBUG_LOG_ALERT_TITLE" = "One More Step";
|
"DEBUG_LOG_ALERT_OPTION_SHARE" = "Share";
|
||||||
|
|
||||||
/* Title of the alert indicating the debug log upload failed. */
|
/* Title of the alert shown for failures while uploading debug logs.
|
||||||
"DEBUG_LOG_FAILURE_ALERT_TITLE" = "Failed to Submit Debug Log";
|
Title of the debug log alert. */
|
||||||
|
"DEBUG_LOG_ALERT_TITLE" = "One More Step";
|
||||||
|
|
||||||
/* Message of the alert before redirecting to Github Issues. */
|
/* 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.";
|
"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. */
|
/* No comment provided by engineer. */
|
||||||
"SETTINGS_ADVANCED_TITLE" = "Advanced";
|
"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. */
|
/* A label for the 'add phone number' button in the block list table. */
|
||||||
"SETTINGS_BLOCK_LIST_ADD_BUTTON" = "Add…";
|
"SETTINGS_BLOCK_LIST_ADD_BUTTON" = "Add…";
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,28 @@
|
||||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@class TSAttachmentStream;
|
@class TSAttachmentStream;
|
||||||
|
|
||||||
|
typedef void (^AttachmentSharingCompletion)(void);
|
||||||
|
|
||||||
@interface AttachmentSharing : NSObject
|
@interface AttachmentSharing : NSObject
|
||||||
|
|
||||||
+ (void)showShareUIForAttachment:(TSAttachmentStream *)stream;
|
+ (void)showShareUIForAttachment:(TSAttachmentStream *)stream;
|
||||||
|
|
||||||
+ (void)showShareUIForURL:(NSURL *)url;
|
+ (void)showShareUIForURL:(NSURL *)url;
|
||||||
|
|
||||||
|
+ (void)showShareUIForURL:(NSURL *)url completion:(nullable AttachmentSharingCompletion)completion;
|
||||||
|
|
||||||
+ (void)showShareUIForText:(NSString *)text;
|
+ (void)showShareUIForText:(NSString *)text;
|
||||||
|
|
||||||
|
+ (void)showShareUIForText:(NSString *)text completion:(nullable AttachmentSharingCompletion)completion;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
+ (void)showShareUIForUIImage:(UIImage *)image;
|
+ (void)showShareUIForUIImage:(UIImage *)image;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#import <SignalServiceKit/TSAttachmentStream.h>
|
#import <SignalServiceKit/TSAttachmentStream.h>
|
||||||
#import <SignalServiceKit/Threading.h>
|
#import <SignalServiceKit/Threading.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@implementation AttachmentSharing
|
@implementation AttachmentSharing
|
||||||
|
|
||||||
+ (void)showShareUIForAttachment:(TSAttachmentStream *)stream
|
+ (void)showShareUIForAttachment:(TSAttachmentStream *)stream
|
||||||
|
@ -18,21 +20,33 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)showShareUIForURL:(NSURL *)url
|
+ (void)showShareUIForURL:(NSURL *)url
|
||||||
|
{
|
||||||
|
[self showShareUIForURL:url completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)showShareUIForURL:(NSURL *)url completion:(nullable AttachmentSharingCompletion)completion
|
||||||
{
|
{
|
||||||
OWSAssert(url);
|
OWSAssert(url);
|
||||||
|
|
||||||
[AttachmentSharing showShareUIForActivityItems:@[
|
[AttachmentSharing showShareUIForActivityItems:@[
|
||||||
url,
|
url,
|
||||||
]];
|
]
|
||||||
|
completion:completion];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)showShareUIForText:(NSString *)text
|
+ (void)showShareUIForText:(NSString *)text
|
||||||
|
{
|
||||||
|
[self showShareUIForText:text completion:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void)showShareUIForText:(NSString *)text completion:(nullable AttachmentSharingCompletion)completion
|
||||||
{
|
{
|
||||||
OWSAssert(text);
|
OWSAssert(text);
|
||||||
|
|
||||||
[AttachmentSharing showShareUIForActivityItems:@[
|
[AttachmentSharing showShareUIForActivityItems:@[
|
||||||
text,
|
text,
|
||||||
]];
|
]
|
||||||
|
completion:completion];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -42,11 +56,12 @@
|
||||||
|
|
||||||
[AttachmentSharing showShareUIForActivityItems:@[
|
[AttachmentSharing showShareUIForActivityItems:@[
|
||||||
image,
|
image,
|
||||||
]];
|
]
|
||||||
|
completion:nil];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
+ (void)showShareUIForActivityItems:(NSArray *)activityItems
|
+ (void)showShareUIForActivityItems:(NSArray *)activityItems completion:(nullable AttachmentSharingCompletion)completion
|
||||||
{
|
{
|
||||||
OWSAssert(activityItems);
|
OWSAssert(activityItems);
|
||||||
|
|
||||||
|
@ -67,6 +82,10 @@
|
||||||
} else if (completed) {
|
} else if (completed) {
|
||||||
DDLogInfo(@"%@ Did share with activityType: %@", self.logTag, activityType);
|
DDLogInfo(@"%@ Did share with activityType: %@", self.logTag, activityType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (completion) {
|
||||||
|
DispatchMainThreadSafe(completion);
|
||||||
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
UIViewController *fromViewController = CurrentAppContext().frontmostViewController;
|
UIViewController *fromViewController = CurrentAppContext().frontmostViewController;
|
||||||
|
@ -84,3 +103,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -62,8 +62,9 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
|
||||||
+ (NSArray<NSNumber *> *)allNotificationSounds
|
+ (NSArray<NSNumber *> *)allNotificationSounds
|
||||||
{
|
{
|
||||||
return @[
|
return @[
|
||||||
// None should be first.
|
// None and Note (default) should be first.
|
||||||
@(OWSSound_None),
|
@(OWSSound_None),
|
||||||
|
@(OWSSound_Note),
|
||||||
|
|
||||||
@(OWSSound_Aurora),
|
@(OWSSound_Aurora),
|
||||||
@(OWSSound_Bamboo),
|
@(OWSSound_Bamboo),
|
||||||
|
@ -74,7 +75,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
|
||||||
@(OWSSound_Hello),
|
@(OWSSound_Hello),
|
||||||
@(OWSSound_Input),
|
@(OWSSound_Input),
|
||||||
@(OWSSound_Keys),
|
@(OWSSound_Keys),
|
||||||
@(OWSSound_Note),
|
|
||||||
@(OWSSound_Popcorn),
|
@(OWSSound_Popcorn),
|
||||||
@(OWSSound_Pulse),
|
@(OWSSound_Pulse),
|
||||||
@(OWSSound_Synth),
|
@(OWSSound_Synth),
|
||||||
|
@ -89,7 +89,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
|
||||||
OWSFail(@"%@ invalid argument.", self.logTag);
|
OWSFail(@"%@ invalid argument.", self.logTag);
|
||||||
return @"";
|
return @"";
|
||||||
|
|
||||||
// Notification Sounds
|
// Notification Sounds
|
||||||
case OWSSound_Aurora:
|
case OWSSound_Aurora:
|
||||||
return @"Aurora";
|
return @"Aurora";
|
||||||
case OWSSound_Bamboo:
|
case OWSSound_Bamboo:
|
||||||
|
@ -117,11 +117,9 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
|
||||||
case OWSSound_ClassicNotification:
|
case OWSSound_ClassicNotification:
|
||||||
return @"Classic";
|
return @"Classic";
|
||||||
|
|
||||||
// Ringtone Sounds
|
// Call Audio
|
||||||
case OWSSound_Opening:
|
case OWSSound_Opening:
|
||||||
return @"Opening";
|
return @"Opening";
|
||||||
|
|
||||||
// Calls
|
|
||||||
case OWSSound_CallConnecting:
|
case OWSSound_CallConnecting:
|
||||||
return @"Call Connecting";
|
return @"Call Connecting";
|
||||||
case OWSSound_CallOutboundRinging:
|
case OWSSound_CallOutboundRinging:
|
||||||
|
@ -131,7 +129,7 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
|
||||||
case OWSSound_CallFailure:
|
case OWSSound_CallFailure:
|
||||||
return @"Call Failure";
|
return @"Call Failure";
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
case OWSSound_None:
|
case OWSSound_None:
|
||||||
return NSLocalizedString(@"SOUNDS_NONE",
|
return NSLocalizedString(@"SOUNDS_NONE",
|
||||||
@"Label for the 'no sound' option that allows users to disable sounds for notifications, "
|
@"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
|
+ (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
|
// 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
|
// on the server. Instead, we create a file with the same name as the default to be played when receiving
|
||||||
// a fallback notification.
|
// a fallback notification.
|
||||||
|
@ -276,16 +295,6 @@ NSString *const kOWSSoundsStorageGlobalNotificationKey = @"kOWSSoundsStorageGlob
|
||||||
return;
|
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)
|
[transaction setObject:@(sound)
|
||||||
forKey:kOWSSoundsStorageGlobalNotificationKey
|
forKey:kOWSSoundsStorageGlobalNotificationKey
|
||||||
inCollection:kOWSSoundsStorageNotificationCollection];
|
inCollection:kOWSSoundsStorageNotificationCollection];
|
||||||
|
|
|
@ -65,10 +65,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
NSMutableArray<OWSDatabaseMigration *> *migrationsToRun = [NSMutableArray new];
|
NSMutableArray<OWSDatabaseMigration *> *migrationsToRun = [NSMutableArray new];
|
||||||
for (OWSDatabaseMigration *migration in migrations) {
|
for (OWSDatabaseMigration *migration in migrations) {
|
||||||
if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId]) {
|
if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId] == nil) {
|
||||||
DDLogDebug(@"%@ Skipping previously run migration: %@", self.logTag, migration);
|
|
||||||
} else {
|
|
||||||
DDLogWarn(@"%@ Running migration: %@", self.logTag, migration);
|
|
||||||
[migrationsToRun addObject:migration];
|
[migrationsToRun addObject:migration];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#import "NSString+OWS.h"
|
#import "NSString+OWS.h"
|
||||||
#import "OWSUserProfile.h"
|
#import "OWSUserProfile.h"
|
||||||
#import "UIImage+OWS.h"
|
#import "UIImage+OWS.h"
|
||||||
#import <AFNetworking/AFNetworking.h>
|
|
||||||
#import <SignalMessaging/SignalMessaging-Swift.h>
|
#import <SignalMessaging/SignalMessaging-Swift.h>
|
||||||
#import <SignalServiceKit/AppContext.h>
|
#import <SignalServiceKit/AppContext.h>
|
||||||
#import <SignalServiceKit/Cryptography.h>
|
#import <SignalServiceKit/Cryptography.h>
|
||||||
|
@ -784,12 +783,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfileParameter
|
- (void)downloadAvatarForUserProfile:(OWSUserProfile *)userProfile
|
||||||
{
|
{
|
||||||
OWSAssert(userProfileParameter);
|
OWSAssert(userProfile);
|
||||||
|
|
||||||
// Make a local copy.
|
|
||||||
OWSUserProfile *userProfile = [userProfileParameter copy];
|
|
||||||
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
if (userProfile.avatarUrlPath.length < 1) {
|
if (userProfile.avatarUrlPath.length < 1) {
|
||||||
|
@ -816,6 +812,8 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
||||||
[self.currentAvatarDownloads addObject:userProfile.recipientId];
|
[self.currentAvatarDownloads addObject:userProfile.recipientId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DDLogVerbose(@"%@ downloading profile avatar: %@", self.logTag, userProfile.uniqueId);
|
||||||
|
|
||||||
NSString *tempDirectory = NSTemporaryDirectory();
|
NSString *tempDirectory = NSTemporaryDirectory();
|
||||||
NSString *tempFilePath = [tempDirectory stringByAppendingPathComponent:fileName];
|
NSString *tempFilePath = [tempDirectory stringByAppendingPathComponent:fileName];
|
||||||
|
|
||||||
|
@ -919,7 +917,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
||||||
|
|
||||||
[userProfile updateWithProfileName:profileName
|
[userProfile updateWithProfileName:profileName
|
||||||
avatarUrlPath:avatarUrlPath
|
avatarUrlPath:avatarUrlPath
|
||||||
avatarFileName:userProfile.avatarFileName // use existing file name if already downloaded
|
|
||||||
dbConnection:self.dbConnection
|
dbConnection:self.dbConnection
|
||||||
completion:nil];
|
completion:nil];
|
||||||
|
|
||||||
|
@ -930,18 +927,17 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
|
||||||
OWSUserProfile *localUserProfile = self.localUserProfile;
|
OWSUserProfile *localUserProfile = self.localUserProfile;
|
||||||
OWSAssert(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
|
[localUserProfile updateWithProfileName:profileName
|
||||||
avatarUrlPath:avatarUrlPath
|
avatarUrlPath:avatarUrlPath
|
||||||
dbConnection:self.dbConnection
|
dbConnection:self.dbConnection
|
||||||
completion:nil];
|
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];
|
[self downloadAvatarForUserProfile:userProfile];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <SignalServiceKit/TSYapDatabaseObject.h>
|
#import <SignalServiceKit/TSYapDatabaseObject.h>
|
||||||
|
|
|
@ -109,12 +109,14 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
||||||
BOOL didChange;
|
BOOL didChange;
|
||||||
if (_avatarUrlPath == nil && avatarUrlPath == nil) {
|
if (_avatarUrlPath == nil && avatarUrlPath == nil) {
|
||||||
didChange = NO;
|
didChange = NO;
|
||||||
} else if (_avatarUrlPath != nil && avatarUrlPath != nil) {
|
} else if (_avatarUrlPath != nil || avatarUrlPath != nil) {
|
||||||
didChange = YES;
|
didChange = YES;
|
||||||
} else {
|
} else {
|
||||||
didChange = [_avatarUrlPath isEqualToString:avatarUrlPath];
|
didChange = [_avatarUrlPath isEqualToString:avatarUrlPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_avatarUrlPath = avatarUrlPath;
|
||||||
|
|
||||||
if (didChange) {
|
if (didChange) {
|
||||||
// If the avatarURL changed, the avatarFileName can't be valid.
|
// If the avatarURL changed, the avatarFileName can't be valid.
|
||||||
// Clear it.
|
// Clear it.
|
||||||
|
@ -137,7 +139,9 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
||||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||||
completion:(nullable OWSUserProfileCompletion)completion
|
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);
|
changeBlock(self);
|
||||||
|
|
||||||
|
@ -146,12 +150,21 @@ NSString *const kLocalProfileUniqueId = @"kLocalProfileUniqueId";
|
||||||
NSString *collection = [[self class] collection];
|
NSString *collection = [[self class] collection];
|
||||||
OWSUserProfile *_Nullable latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
|
OWSUserProfile *_Nullable latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection];
|
||||||
if (latestInstance) {
|
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);
|
changeBlock(latestInstance);
|
||||||
|
|
||||||
NSDictionary *afterSnapshot = latestInstance.dictionaryValue;
|
NSDictionary *afterSnapshot = [latestInstance.dictionaryValue copy];
|
||||||
|
|
||||||
if ([beforeSnapshot isEqual:afterSnapshot]) {
|
if ([beforeSnapshot isEqual:afterSnapshot]) {
|
||||||
DDLogVerbose(
|
DDLogVerbose(@"%@ Ignoring redundant update in %s: %@",
|
||||||
@"%@ Ignoring redundant update in %s: %@", self.logTag, functionName, self.debugDescription);
|
self.logTag,
|
||||||
|
functionName,
|
||||||
|
self.debugDescription);
|
||||||
didChange = NO;
|
didChange = NO;
|
||||||
} else {
|
} else {
|
||||||
[latestInstance saveWithTransaction:transaction];
|
[latestInstance saveWithTransaction:transaction];
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <CocoaLumberjack/DDFileLogger.h>
|
#import <CocoaLumberjack/DDFileLogger.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface DebugLogger : NSObject
|
@interface DebugLogger : NSObject
|
||||||
|
|
||||||
+ (instancetype)sharedLogger;
|
+ (instancetype)sharedLogger;
|
||||||
|
@ -19,3 +21,5 @@
|
||||||
- (NSArray<NSString *> *)allLogFilePaths;
|
- (NSArray<NSString *> *)allLogFilePaths;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -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.
|
#pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging.
|
||||||
#import <CocoaLumberjack/DDTTYLogger.h>
|
#import <CocoaLumberjack/DDTTYLogger.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
const NSUInteger kMaxDebugLogFileSize = 1024 * 1024 * 3;
|
||||||
|
|
||||||
@interface DebugLogger ()
|
@interface DebugLogger ()
|
||||||
|
|
||||||
@property (nonatomic) DDFileLogger *fileLogger;
|
@property (nonatomic, nullable) DDFileLogger *fileLogger;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -67,8 +71,7 @@
|
||||||
self.fileLogger.rollingFrequency = kDayInterval;
|
self.fileLogger.rollingFrequency = kDayInterval;
|
||||||
// Keep last 3 days of logs - or last 3 logs (if logs rollover due to max file size).
|
// Keep last 3 days of logs - or last 3 logs (if logs rollover due to max file size).
|
||||||
self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3;
|
self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3;
|
||||||
// Raise the max file size per log file to 3 MB.
|
self.fileLogger.maximumFileSize = kMaxDebugLogFileSize;
|
||||||
self.fileLogger.maximumFileSize = 1024 * 1024 * 3;
|
|
||||||
self.fileLogger.logFormatter = [OWSScrubbingLogFormatter new];
|
self.fileLogger.logFormatter = [OWSScrubbingLogFormatter new];
|
||||||
|
|
||||||
[DDLog addLogger:self.fileLogger];
|
[DDLog addLogger:self.fileLogger];
|
||||||
|
@ -133,3 +136,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
@ -29,7 +29,8 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
|
||||||
OWSErrorCodeMessageDeletedBeforeSent = 777410,
|
OWSErrorCodeMessageDeletedBeforeSent = 777410,
|
||||||
OWSErrorCodeDatabaseConversionFatalError = 777411,
|
OWSErrorCodeDatabaseConversionFatalError = 777411,
|
||||||
OWSErrorCodeMoveFileToSharedDataContainerError = 777412,
|
OWSErrorCodeMoveFileToSharedDataContainerError = 777412,
|
||||||
OWSErrorCodeRegistrationMissing2FAPIN = 777413
|
OWSErrorCodeRegistrationMissing2FAPIN = 777413,
|
||||||
|
OWSErrorCodeDebugLogUploadFailed = 777414,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NSString *const OWSErrorRecipientIdentifierKey;
|
extern NSString *const OWSErrorRecipientIdentifierKey;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>2.21.0</string>
|
<string>2.21.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>2.21.0.0</string>
|
<string>2.21.0.1</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
|
|
Loading…
Reference in New Issue