@ -5,7 +5,6 @@
#import "Pastelog . h "
#import "Signal - Swift . h "
#import "ThreadUtil . h "
#import < SSZipArchive / SSZipArchive . h >
#import < SignalMessaging / DebugLogger . h >
#import < SignalMessaging / Environment . h >
#import < SignalServiceKit / AppContext . h >
@ -13,426 +12,251 @@
#import < SignalServiceKit / TSContactThread . h >
#import < SignalServiceKit / TSStorageManager . h >
#import < SignalServiceKit / Threading . h >
#import < sys / sysctl . h >
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 < NSURLConnectionDelegate , NSURLConnectionDataDelegate >
@ interface Pastelog ( ) < NSURLConnectionDelegate , NSURLConnectionDataDelegate , UIAlertViewDelegate >
@ property ( nonatomic ) UIAlertController * loadingAlert ;
@ property ( nonatomic ) NSMutableData * responseData ;
@ property ( nonatomic , nullable ) DebugLogUploadSuccess success ;
@ property ( nonatomic , nullable ) DebugLogUploadFailure failure ;
@ property ( nonatomic ) DebugLogsUploadedBlock block ;
@ end
#pragma mark -
@ implementation DebugLogUploader
- ( void ) dealloc
{
DDLogVerbose ( @ "Dealloc : %@", self.logTag);
}
- ( void ) uploadFileWithURL : ( NSURL * ) fileUrl success : ( DebugLogUploadSuccess ) success failure : ( DebugLogUploadFailure ) failure
{
OWSAssert ( fileUrl ) ;
OWSAssert ( success ) ;
OWSAssert ( failure ) ;
self . success = success ;
self . failure = failure ;
self . responseData = [ NSMutableData new ] ;
NSURL * url = [ NSURL URLWithString : @ "https : / / filebin . net "] ;
NSMutableURLRequest * request = [ [ NSMutableURLRequest alloc ] initWithURL : url
cachePolicy : NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval : 30 ] ;
[ request setHTTPMethod : @ "POST "] ;
[ request addValue : fileUrl . lastPathComponent forHTTPHeaderField : @ "filename "] ;
[ request addValue : @ "application / zip " forHTTPHeaderField : @ "Content - Type "] ;
NSData * _Nullable data = [ NSData dataWithContentsOfURL : fileUrl ] ;
if ( !data ) {
[ self failWithError : [ NSError errorWithDomain : @ "PastelogKit "
code : 10002
userInfo : @ { NSLocalizedDescriptionKey : @ "Could not load data . " } ] ] ;
return ;
}
/ / TODO :
[ request setHTTPBody : data ] ;
NSURLConnection * connection = [ NSURLConnection connectionWithRequest : request delegate : self ] ;
[ connection start ] ;
}
#pragma mark - Delegate Methods
- ( void ) connection : ( NSURLConnection * ) connection didReceiveData : ( NSData * ) data
{
DDLogVerbose ( @ "%@ %s", self.logTag, __PRETTY_FUNCTION__);
@ implementation Pastelog
[ self . responseData appendData : data ] ;
+ ( void ) submitLogs {
[ self submitLogsWithShareCompletion : nil ] ;
}
- ( void ) connectionDidFinishLoading : ( NSURLConnection * ) connection
+ ( void ) submitLogsWithShareCompletion : ( nullable DebugLogsSharedBlock ) shareCompletionParam
{
DDLogVerbose ( @ "%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSError * error ;
NSDictionary * _Nullable dict = [ NSJSONSerialization JSONObjectWithData : self . responseData options : 0 error : & error ] ;
if ( error ) {
DDLogError ( @ "%@ response length: %zd", self.logTag, self.responseData.length);
[ self failWithError : error ] ;
return ;
}
if ( ![ dict isKindOfClass : [ NSDictionary class ] ] ) {
DDLogError ( @ "%@ response (1): %@", self.logTag, dict);
[ self failWithError : [ NSError errorWithDomain : @ "PastelogKit "
code : 10003
userInfo : @ { NSLocalizedDescriptionKey : @ "Malformed response ( root ) . " } ] ] ;
return ;
}
NSArray < id > * _Nullable links = [ dict objectForKey : @ "links "] ;
if ( ![ links isKindOfClass : [ NSArray class ] ] ) {
DDLogError ( @ "%@ response (2): %@", self.logTag, dict);
[ self failWithError : [ NSError errorWithDomain : @ "PastelogKit "
code : 10004
userInfo : @ { NSLocalizedDescriptionKey : @ "Malformed response ( links ) . " } ] ] ;
return ;
}
NSString * _Nullable urlString = nil ;
for ( NSDictionary * linkMap in links ) {
if ( ![ linkMap isKindOfClass : [ NSDictionary class ] ] ) {
DDLogError ( @ "%@ response (2): %@", self.logTag, dict);
[ self failWithError : [ NSError
errorWithDomain : @ "PastelogKit "
code : 10005
userInfo : @ { NSLocalizedDescriptionKey : @ "Malformed response ( linkMap ) . " } ] ] ;
return ;
}
NSString * _Nullable linkRel = [ linkMap objectForKey : @ "rel "] ;
if ( ![ linkRel isKindOfClass : [ NSString class ] ] ) {
DDLogError ( @ "%@ response (linkRel): %@", self.logTag, dict);
continue ;
}
if ( ![ linkRel isEqualToString : @ "file "] ) {
DDLogError ( @ "%@ response (linkRel value): %@", self.logTag, dict);
continue ;
}
NSString * _Nullable linkHref = [ linkMap objectForKey : @ "href "] ;
if ( ![ linkHref isKindOfClass : [ NSString class ] ] ) {
DDLogError ( @ "%@ response (linkHref): %@", self.logTag, dict);
continue ;
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 ) ;
}
urlString = linkHref ;
break ;
}
[ self succeedWithUrl : [ NSURL URLWithString : urlString ] ] ;
}
} ;
- ( void ) connection : ( NSURLConnection * ) connection didReceiveResponse : ( NSURLResponse * ) response
{
NSHTTPURLResponse * httpResponse = ( NSHTTPURLResponse * ) response ;
NSInteger statusCode = httpResponse . statusCode ;
/ / We ' ll accept any 2 xx 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 . " } ] ] ;
}
[ 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 ) connection : ( NSURLConnection * ) connection didFailWithError : ( NSError * ) error
+ ( void ) submitLogsWithUploadCompletion : ( DebugLogsUploadedBlock ) block
{
DDLogVerbose ( @ "%@ %s", self.logTag, __PRETTY_FUNCTION__);
[ self failWithError : error ] ;
[ self submitLogsWithUploadCompletion : block forFileLogger : [ [ DDFileLogger alloc ] init ] ] ;
}
- ( void ) failWithError : ( NSError * ) error
+ ( void ) submitLogsWithUploadCompletion : ( DebugLogsUploadedBlock ) block forFileLogger : ( DDFileLogger * ) fileLogge r
{
OWSAssert ( error ) ;
DDLogError ( @ "%@ %s %@", self.logTag, __PRETTY_FUNCTION__, error);
[ self sharedManager ] . block = block ;
DispatchMainThreadSafe ( ^{
/ / Call the completions exactly once .
if ( self . failure ) {
self . failure ( self , error ) ;
}
self . success = nil ;
self . failure = nil ;
} ) ;
}
[ 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 ] ;
- ( void ) succeedWithUrl : ( NSURL * ) url
{
OWSAssert ( url ) ;
NSArray < NSString * > * logFilePaths = DebugLogger . sharedLogger . allLogFilePaths ;
DDLogVerbose ( @ "%@ %s %@", self.logTag, __PRETTY_FUNCTION__, url);
NSMutableDictionary * gistFiles = [ NSMutableDictionary new ] ;
DispatchMainThreadSafe ( ^{
/ / Call the completions exactly once .
if ( self . success ) {
self . success ( self , url ) ;
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 ;
}
self . success = nil ;
self . failure = nil ;
} ) ;
}
gistFiles[ logFilePath . lastPathComponent ] = @ {
@ "content " : logContents ,
} ;
}
@ end
NSDictionary * gistDict = @ { @ "description ": [ self gistDescription ] , @ "files ": gistFiles } ;
#pragma mark -
NSData * postData = [ NSJSONSerialization dataWithJSONObject : gistDict options : 0 error : nil ] ;
@ interface Pastelog ( ) < UIAlertViewDelegate >
NSMutableURLRequest * request = [ [ NSMutableURLRequest alloc ] initWithURL : [ [ NSURL alloc ] initWithString : @ "https : / / api . github . com / gists "] cachePolicy : NSURLRequestReloadIgnoringLocalCacheData timeoutInterval : 30 ] ;
@ property ( nonatomic ) UIAlertController * loadingAlert ;
[ [ self sharedManager ] setResponseData : [ NSMutableData data ] ] ;
[ [ self sharedManager ] setBlock : block ] ;
@ property ( nonatomic ) DebugLogUploader * currentUploader ;
[ request setHTTPMethod : @ "POST "] ;
[ request setHTTPBody : postData ] ;
@ end
NSURLConnection * connection = [ NSURLConnection connectionWithRequest : request delegate : [ self sharedManager ] ] ;
#pragma mark -
[ connection start ] ;
@implementation Pastelog
}
+ ( instancetype ) sharedManager
{
+ ( Pastelog * ) sharedManager {
static Pastelog * sharedMyManager = nil ;
static dispatch_once_t onceToken ;
dispatch_once ( & onceToken , ^{
sharedMyManager = [ [ self alloc ] init Default ] ;
sharedMyManager = [ [ self alloc ] init ] ;
} ) ;
return sharedMyManager ;
}
- ( instancetype ) initDefault
{
self = [ super init ] ;
- ( instancetype ) init {
if ( self = [ super init ] ) {
self . responseData = [ NSMutableData data ] ;
if ( !self ) {
return self ;
OWSSingletonAssert ( ) ;
}
OWSSingletonAssert ( ) ;
return self ;
}
+ ( void ) submitLogs
{
[ self submitLogsWithCompletion : nil ] ;
}
+ ( 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 ) ;
+ ( 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 ) ;
}
} ;
NSString * gistDesc = [ NSString stringWithFormat : @ "iPhone Version : %@, iOS Version: %@", platform,[UIDevice currentDevice].systemVersion];
[ 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 * _Nonnull 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 * _Nonnull 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 * _Nonnull 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 * _Nonnull 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 : UIAlertActionStyleCancel
handler : ^( UIAlertAction * _Nonnull action ) {
[ Pastelog . sharedManager prepareRedirection : url completion : completion ] ;
} ] ] ;
UIViewController * presentingViewController
= UIApplication . sharedApplication . frontmostViewControllerIgnoringAlerts ;
[ presentingViewController presentViewController : alert animated : NO completion : nil ] ;
} ] ;
return gistDesc ;
}
+ ( void ) uploadLogsWithSuccess : ( nullable UploadDebugLogsSuccess ) success
{
OWSAssert ( success ) ;
#pragma mark Network delegates
[ [ self sharedManager ] uploadLogsWithSuccess : success
failure : ^( NSString * localizedErrorMessage ) {
[ Pastelog showFailureAlertWithMessage : localizedErrorMessage ] ;
} ] ;
- ( void ) connection : ( NSURLConnection * ) connection didReceiveData : ( NSData * ) data {
[ self . responseData appendData : data ] ;
}
- ( void ) uploadLogsWithSuccess : ( nullable UploadDebugLogsSuccess ) successParam failure : ( UploadDebugLogsFailure ) failureParam
{
OWSAssert ( successParam ) ;
OWSAssert ( failureParam ) ;
/ / 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 ) ;
} ) ;
} ;
- ( 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 ;
}
/ / 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 ] ;
- ( void ) connection : ( NSURLConnection * ) connection didReceiveResponse : ( NSURLResponse * ) response {
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 ;
}
NSHTTPURLResponse * httpResponse = ( NSHTTPURLResponse * ) response ;
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 withPassword : nil ] ;
if ( !zipSuccess ) {
failure ( NSLocalizedString (
@ "DEBUG_LOG_ALERT_COULD_NOT_PACKAGE_LOGS ", @ "Error indicating that the debug logs could not be packaged . ") ) ;
return ;
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 ;
}
[ 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 ]
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 ) 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 ] ;
- ( 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 ;
}
#pragma mark Logs submission
- ( void ) submitEmail : ( NSURL * ) url
{
- ( void ) submitEmail : ( NSString * ) 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]]];
[ UIApplication . sharedApplication openURL : [ NSURL URLWithString : urlString ] ] ;
[ UIApplication . sharedApplication openURL : [ NSURL URLWithString : urlString ] ] ;
}
- ( void ) prepareRedirection : ( NS URL * ) url completion : ( SubmitDebugLogsCompletion ) c ompletion
- ( void ) prepareRedirection : ( NSString * ) url shareCompletion : ( DebugLogsSharedBlock ) shareCompletion
{
OWSAssert ( c ompletion) ;
OWSAssert ( shareCompletion ) ;
UIPasteboard * pb = [ UIPasteboard generalPasteboard ] ;
[ pb setString : url .absoluteString ];
[ pb setString : url ];
UIAlertController * alert =
[ UIAlertController alertControllerWithTitle : NSLocalizedString ( @ "DEBUG_LOG_GITHUB_ISSUE_ALERT_TITLE ",
@ -448,13 +272,13 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error
openURL : [ NSURL URLWithString : [ [ NSBundle mainBundle ]
objectForInfoDictionaryKey : @ "LOGS_URL "] ] ] ;
c ompletion( ) ;
shareC ompletion( ) ;
} ] ] ;
UIViewController * presentingViewController = UIApplication . sharedApplication . frontmostViewControllerIgnoringAlerts ;
[ presentingViewController presentViewController : alert animated : NO completion : nil ] ;
}
- ( void ) sendToSelf : ( NS URL * ) url
- ( void ) sendToSelf : ( NS String * ) url
{
if ( ![ TSAccountManager isRegistered ] ) {
return ;
@ -468,14 +292,14 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error
readWriteWithBlock : ^( YapDatabaseReadWriteTransaction * _Nonnull 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 .
[ [ UIPasteboard generalPasteboard ] setString : url .absoluteString ];
[ [ UIPasteboard generalPasteboard ] setString : url ];
}
- ( void ) sendToMostRecentThread : ( NS URL * ) url
- ( void ) sendToMostRecentThread : ( NS String * ) url
{
if ( ![ TSAccountManager isRegistered ] ) {
return ;
@ -488,13 +312,11 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error
readWriteWithBlock : ^( YapDatabaseReadWriteTransaction * _Nonnull transaction ) {
thread = [ [ transaction ext : TSThreadDatabaseViewExtensionName ] firstObjectInGroup : [ TSThread collection ] ] ;
} ] ;
[ ThreadUtil sendMessageWithText : url . absoluteString inThread : thread messageSender : messageSender ] ;
[ ThreadUtil sendMessageWithText : url inThread : thread messageSender : messageSender ] ;
} ) ;
/ / Also copy to pasteboard .
[ [ UIPasteboard generalPasteboard ] setString : url .absoluteString ];
[ [ UIPasteboard generalPasteboard ] setString : url ];
}
@ end
NS_ASSUME_NONNULL_END