From 2a58c03b9f8ef0cc9282c775619341a201160e68 Mon Sep 17 00:00:00 2001 From: Frederic Jacobs Date: Thu, 3 Jul 2014 03:12:34 +0200 Subject: [PATCH] Localized sign up messages and gist log upload --- Signal.xcodeproj/project.pbxproj | 6 + Signal/src/AppDelegate.h | 6 + Signal/src/AppDelegate.m | 18 ++- Signal/src/environment/LocalizableText.h | 12 ++ Signal/src/profiling/LogSubmit.h | 19 +++ Signal/src/profiling/LogSubmit.m | 114 ++++++++++++++++++ .../view controllers/RegisterViewController.m | 4 +- .../view controllers/SettingsViewController.h | 3 +- .../view controllers/SettingsViewController.m | 44 ++++++- .../xibs/SettingsViewController.xib | 31 ++++- .../translations/en.lproj/Localizable.strings | 8 ++ 11 files changed, 247 insertions(+), 18 deletions(-) create mode 100644 Signal/src/profiling/LogSubmit.h create mode 100644 Signal/src/profiling/LogSubmit.m diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7ec563b4a..fc197b747 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -380,6 +380,7 @@ A1C32D5017A06538000A904E /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1C32D4F17A06537000A904E /* AddressBookUI.framework */; }; A1C32D5117A06544000A904E /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1C32D4D17A0652C000A904E /* AddressBook.framework */; }; AA0C8E498E2046B0B81EEE6E /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313AE91B4954215858A5662 /* libPods.a */; }; + B62686301964AE3D00D2D697 /* LogSubmit.m in Sources */ = {isa = PBXBuildFile; fileRef = B626862F1964AE3D00D2D697 /* LogSubmit.m */; }; B67EBF5D19194AC60084CCFD /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B67EBF5C19194AC60084CCFD /* Settings.bundle */; }; B6B6C3C71919440C00C0B76B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6B6C3C51919440C00C0B76B /* Localizable.strings */; }; B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; }; @@ -1087,6 +1088,8 @@ A1C32D4D17A0652C000A904E /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; A1C32D4F17A06537000A904E /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; A1FDCBEE16DAA6C300868894 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + B626862E1964AE3D00D2D697 /* LogSubmit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogSubmit.h; sourceTree = ""; }; + B626862F1964AE3D00D2D697 /* LogSubmit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LogSubmit.m; sourceTree = ""; }; B657DDC91911A40500F45B0C /* Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Signal.entitlements; sourceTree = ""; }; B67EBF5C19194AC60084CCFD /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = SettingsBundle/Settings.bundle; sourceTree = SOURCE_ROOT; }; B6B6C3C61919440C00C0B76B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; @@ -1951,6 +1954,8 @@ 76EB04B518170B33006006FC /* DecayingSampleEstimator.m */, 76EB04B618170B33006006FC /* EventWindow.h */, 76EB04B718170B33006006FC /* EventWindow.m */, + B626862E1964AE3D00D2D697 /* LogSubmit.h */, + B626862F1964AE3D00D2D697 /* LogSubmit.m */, 76EB04B818170B33006006FC /* LoggingUtil.h */, 76EB04B918170B33006006FC /* LoggingUtil.m */, 76EB04BA18170B33006006FC /* protocols */, @@ -3033,6 +3038,7 @@ 70B8010C190C55660042E3F0 /* AbstractMessage.m in Sources */, E197B61618BBEC1A00F073E5 /* StretchFactorController.m in Sources */, 76EB065018170B34006006FC /* DialerViewController.m in Sources */, + B62686301964AE3D00D2D697 /* LogSubmit.m in Sources */, 701231B518ECAA4500D456C4 /* EvpMessageDigest.m in Sources */, 76EB062218170B33006006FC /* CyclicalBuffer.m in Sources */, 76EB063C18170B33006006FC /* NumberUtil.m in Sources */, diff --git a/Signal/src/AppDelegate.h b/Signal/src/AppDelegate.h index dd17a2be2..dcb2b102d 100644 --- a/Signal/src/AppDelegate.h +++ b/Signal/src/AppDelegate.h @@ -1,8 +1,14 @@ #import #import "FutureSource.h" +#pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging. + +#import +#import + @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; +@property (nonatomic, readonly) DDFileLogger *fileLogger; @end diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 46451e211..e7f1f3a8f 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -16,11 +16,6 @@ #import "Util.h" #import -#pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging. - -#import -#import - #define kSignalVersionKey @"SignalUpdateVersionKey" #ifdef __APPLE__ @@ -31,6 +26,7 @@ @property (nonatomic, strong) MMDrawerController *drawerController; @property (nonatomic, strong) NotificationTracker *notificationTracker; +@property (nonatomic) DDFileLogger *fileLogger; @end @@ -75,13 +71,14 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [DDLog addLogger:[DDTTYLogger sharedInstance]]; - DDFileLogger *fileLogger = [[DDFileLogger alloc] init]; - fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling. - fileLogger.logFileManager.maximumNumberOfLogFiles = 3; // Keep three days of logs. - [DDLog addLogger:fileLogger]; + self.fileLogger = [[DDFileLogger alloc] init]; //Logging to file, because it's in the Cache folder, they are not uploaded in iTunes/iCloud backups. + self.fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling. + self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; // Keep three days of logs. + [DDLog addLogger:self.fileLogger]; [self performUpdateCheck]; [self disableCallLogBackup]; + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.notificationTracker = [NotificationTracker notificationTracker]; @@ -102,8 +99,7 @@ leftSideMenuViewController.centerTabBarViewController.inboxFeedViewController.apnId = futureApnIdSource; leftSideMenuViewController.centerTabBarViewController.settingsViewController.apnId = futureApnIdSource; - self.drawerController = [[MMDrawerController alloc] initWithCenterViewController:leftSideMenuViewController.centerTabBarViewController - leftDrawerViewController:leftSideMenuViewController]; + self.drawerController = [[MMDrawerController alloc] initWithCenterViewController:leftSideMenuViewController.centerTabBarViewController leftDrawerViewController:leftSideMenuViewController]; self.window.rootViewController = _drawerController; [self.window makeKeyAndVisible]; diff --git a/Signal/src/environment/LocalizableText.h b/Signal/src/environment/LocalizableText.h index a7d9c7ac1..162141c13 100644 --- a/Signal/src/environment/LocalizableText.h +++ b/Signal/src/environment/LocalizableText.h @@ -102,6 +102,18 @@ #define SETTINGS_LOG_CLEAR_MESSAGE NSLocalizedString(@"SETTINGS_LOG_CLEAR_MESSAGE", @"") #define SETTINGS_LOG_CLEAR_CONFIRM NSLocalizedString(@"OK", @"") +#define SETTINGS_SENDLOG NSLocalizedString(@"SETTINGS_SENDLOG", @"") + +#define SETTINGS_SENDLOG_WAITING NSLocalizedString(@"SETTINGS_SENDLOGS_WAITING", @"") +#define SETTINGS_SENDLOG_ALERT_TITLE NSLocalizedString(@"SETTINGS_SENDLOG_ALERT_TITLE", @"") +#define SETTINGS_SENDLOG_ALERT_BODY NSLocalizedString(@"SETTINGS_SENDLOG_ALERT_BODY",@"") +#define SETTINGS_SENDLOG_ALERT_PASTE NSLocalizedString(@"SETTINGS_SENDLOG_ALERT_PASTE", @"") +#define SETTINGS_SENDLOG_ALERT_EMAIL NSLocalizedString(@"SETTINGS_SENDLOG_ALERT_EMAIL", @"") +#define SETTINGS_SENDLOG_FAILED_TITLE NSLocalizedString(@"SETTINGS_SENDLOG_FAILED_TITLE", @"") +#define SETTINGS_SENDLOG_FAILED_BODY NSLocalizedString(@"SETTINGS_SENDLOG_FAILED_BODY", @"") +#define SETTINGS_SENDLOG_FAILED_DISMISS NSLocalizedString(@"OK", @"") + + #pragma mark - Registration #define REGISTER_CC_ERR_ALERT_VIEW_TITLE NSLocalizedString(@"REGISTER_CC_ERR_ALERT_VIEW_TITLE", @"") diff --git a/Signal/src/profiling/LogSubmit.h b/Signal/src/profiling/LogSubmit.h new file mode 100644 index 000000000..597969b69 --- /dev/null +++ b/Signal/src/profiling/LogSubmit.h @@ -0,0 +1,19 @@ +// +// LogSubmit.h +// Signal +// +// Created by Frederic Jacobs on 02/07/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import + +@interface LogSubmit : NSObject + +typedef void (^successBlock)(BOOL success, NSString *urlString); + ++(void)submitLogsWithCompletion:(successBlock)block; + +@property (nonatomic)NSMutableData *responseData; + +@end diff --git a/Signal/src/profiling/LogSubmit.m b/Signal/src/profiling/LogSubmit.m new file mode 100644 index 000000000..2b5e50a45 --- /dev/null +++ b/Signal/src/profiling/LogSubmit.m @@ -0,0 +1,114 @@ +// +// LogSubmit.m +// Signal +// +// Created by Frederic Jacobs on 02/07/14. +// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// + +#import "LogSubmit.h" +#import "AppDelegate.h" +#include +#include + +@interface LogSubmit () + + +@property (nonatomic, copy)successBlock block; + +@end + +@implementation LogSubmit + ++(void)submitLogsWithCompletion:(successBlock)block{ + AppDelegate *delegate = [[UIApplication sharedApplication]delegate]; + + NSArray *fileNames = delegate.fileLogger.logFileManager.sortedLogFileNames; + NSArray *filePaths = delegate.fileLogger.logFileManager.sortedLogFilePaths; + + NSMutableDictionary *gistFiles = [@{} mutableCopy]; + + for (unsigned int i = 0; i < [filePaths count]; i++) { + [gistFiles setObject:@{@"content":[NSString stringWithContentsOfFile:[filePaths objectAtIndex:i] encoding:NSUTF8StringEncoding error:nil]} forKey:[fileNames objectAtIndex:i]]; + } + + 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:NSURLCacheStorageNotAllowed 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]; + +} + ++ (id)sharedManager { + static LogSubmit *sharedMyManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedMyManager = [[self alloc] init]; + }); + return sharedMyManager; +} + +- (id)init { + if (self = [super init]) { + self.responseData = [NSMutableData data]; + } + return self; +} + +-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ + [self.responseData appendData:data]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection{ + + NSError *error; + NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error]; + if (!error) { + self.block(true, [dict objectForKey:@"html_url"]); + } else{ + DDLogError(@"Error on debug response: %@", error); + self.block(false, nil); + } +} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ + DDLogError(@"Uploading logs failed with error: %@", error); + self.block(false,nil); +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ + + NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; + + if ( [httpResponse statusCode] != 201) { + DDLogError(@"Failed to submit debug log: %@", httpResponse.debugDescription); + self.block(false,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); + + NSString *gistDesc = [NSString stringWithFormat:@"iPhone Version: %@, iOS Version: %@", platform,[UIDevice currentDevice].systemVersion]; + + return gistDesc; +} + +@end diff --git a/Signal/src/view controllers/RegisterViewController.m b/Signal/src/view controllers/RegisterViewController.m index a7e73be64..6defab2a5 100644 --- a/Signal/src/view controllers/RegisterViewController.m +++ b/Signal/src/view controllers/RegisterViewController.m @@ -128,7 +128,7 @@ andErrorHandler:[Environment errorNoter]]; }; Future *futurePhoneRegistrationStarted = [AsyncUtil raceCancellableOperation:regStarter - againstTimeout:30.0 + againstTimeout:20.0 untilCancelled:cancelToken]; Future *futurePhoneRegistrationVerified = [futurePhoneRegistrationStarted then:^(id _) { @@ -201,13 +201,13 @@ if ([error isKindOfClass:[HttpResponse class]]) { HttpResponse* badResponse = error; if ([badResponse getStatusCode] == 401) { +#warning localize this alert UIAlertView *incorrectChallengeCodeAV = [[UIAlertView alloc]initWithTitle:@"Registration error" message:@"The challenge code you entered is incorrect." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; [incorrectChallengeCodeAV show]; return; } } [Environment errorNoter](error, @"While Verifying Challenge.", NO); -#warning add implementation }]; [futureDone thenDo:^(id result) { diff --git a/Signal/src/view controllers/SettingsViewController.h b/Signal/src/view controllers/SettingsViewController.h index da8f0dc70..d4f170dcb 100644 --- a/Signal/src/view controllers/SettingsViewController.h +++ b/Signal/src/view controllers/SettingsViewController.h @@ -14,7 +14,7 @@ * */ -@interface SettingsViewController : UIViewController +@interface SettingsViewController : UIViewController @property (nonatomic, strong) IBOutlet UITableView *settingsTableView; @property (nonatomic, strong) IBOutlet UILabel *phoneNumberLabel; @@ -39,6 +39,7 @@ @property (nonatomic, strong) IBOutlet UITableViewCell *directoryUpdateCell; @property (nonatomic, strong) IBOutlet UIButton *sendFeedbackButton; +@property (nonatomic, strong) IBOutlet UITableViewCell *sendDebugLog; @property (nonatomic, assign) FutureSource *apnId; diff --git a/Signal/src/view controllers/SettingsViewController.m b/Signal/src/view controllers/SettingsViewController.m index db5ab2fbb..ccdc0b0e0 100644 --- a/Signal/src/view controllers/SettingsViewController.m +++ b/Signal/src/view controllers/SettingsViewController.m @@ -8,6 +8,7 @@ #import "RecentCallManager.h" #import "RegisterViewController.h" #import "SettingsViewController.h" +#import "LogSubmit.h" #import "UIViewController+MMDrawerController.h" @@ -24,6 +25,8 @@ static NSString *const CHECKBOX_EMPTY_IMAGE_NAME = @"checkbox_empty"; NSArray *_privacyTableViewCells; NSArray *_localizationTableViewCells; NSArray *_callQualityTableViewCells; + + NSString *gistURL; } @end @@ -145,7 +148,8 @@ static NSString *const CHECKBOX_EMPTY_IMAGE_NAME = @"checkbox_empty"; return @[_hideContactImagesCell, _disableAutocorrectCell, _disableHistoryCell, - _clearHistoryLogCell]; + _clearHistoryLogCell, + _sendDebugLog]; } - (NSArray *)localizationCells { @@ -295,6 +299,44 @@ static NSString *const CHECKBOX_EMPTY_IMAGE_NAME = @"checkbox_empty"; if (cell == _dateFormatCell) { [self showDateFormatPicker]; } + + if (cell == _sendDebugLog) { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:SETTINGS_SENDLOG_WAITING + message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil]; + + [alert show]; + + [LogSubmit submitLogsWithCompletion:^(BOOL success, NSString *urlString) { + [alert dismissWithClickedButtonIndex:0 animated:YES]; + if (success) { + gistURL = urlString; + UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:SETTINGS_SENDLOG_ALERT_TITLE message:SETTINGS_SENDLOG_ALERT_BODY delegate:self cancelButtonTitle:SETTINGS_SENDLOG_ALERT_PASTE otherButtonTitles:SETTINGS_SENDLOG_ALERT_EMAIL, nil]; + [alertView show]; + + } else{ + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:SETTINGS_SENDLOG_FAILED_TITLE message:SETTINGS_SENDLOG_FAILED_BODY delegate:nil cancelButtonTitle:SETTINGS_SENDLOG_FAILED_DISMISS otherButtonTitles:nil, nil]; + [alertView show]; + } + }]; + } +} + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{ + if (buttonIndex == 0) { + [self pasteBoardCopy:gistURL]; + } else{ + [self submitEmail:gistURL]; + } +} + +- (void)submitEmail:(NSString*)url{ + NSString *urlString = [NSString stringWithString: [@"mailto:support@whispersystems.org?subject=iOS%20Debug%20Log&body=" stringByAppendingString:[[NSString stringWithFormat:@"Log URL: %@ \n Tell us about the issue: ", url]stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]]]; + [[UIApplication sharedApplication] openURL: [NSURL URLWithString: urlString]]; +} + +- (void)pasteBoardCopy:(NSString*)url{ + UIPasteboard *pb = [UIPasteboard generalPasteboard]; + [pb setString:url]; } - (void)findAndLocalizeLabelsForView:(UIView *)view { diff --git a/Signal/src/view controllers/xibs/SettingsViewController.xib b/Signal/src/view controllers/xibs/SettingsViewController.xib index caa97d4ec..8f9e0665d 100644 --- a/Signal/src/view controllers/xibs/SettingsViewController.xib +++ b/Signal/src/view controllers/xibs/SettingsViewController.xib @@ -1,7 +1,7 @@ - + - + @@ -21,6 +21,7 @@ + @@ -556,6 +557,30 @@ + + + + + + + + + + + + + + + + @@ -564,4 +589,4 @@ - \ No newline at end of file + diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 7e4bf23fa..a8054ae34 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -121,6 +121,14 @@ "SETTINGS_NUMBER_PREFIX" = "Your Number:"; "SETTINGS_PRIVACY_AND_SECURITY" = "Privacy and Security"; "SETTINGS_RINGTONE" = "Ringtone"; +"SETTINGS_SENDLOG" = "Submit Debug Log"; +"SETTINGS_SENDLOGS_WAITING" = "Sending anonymized log file\n Please wait..."; +"SETTINGS_SENDLOG_ALERT_TITLE" = "Submit debug log"; +"SETTINGS_SENDLOG_ALERT_BODY" = "Do you want to copy the log URL to the pasteboard or submit it by email?"; +"SETTINGS_SENDLOG_ALERT_PASTE" = "Pasteboard"; +"SETTINGS_SENDLOG_ALERT_EMAIL" = "Email"; +"SETTINGS_SENDLOG_FAILED_TITLE" = "Failed to submit debug log"; +"SETTINGS_SENDLOG_FAILED_BODY" = "The debug log could not be submitted. Please try again."; "SETTINGS_VIBRATE_ON_RING" = "Vibrate on Ring"; "SETTINGS_VIBRATE_ON_SILENT" = "Vibrate on Silent"; "SPEAKER_BUTTON_TITLE" = "Speaker";