From 2a58c03b9f8ef0cc9282c775619341a201160e68 Mon Sep 17 00:00:00 2001
From: Frederic Jacobs <github@fredericjacobs.com>
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 = "<group>"; };
+		B626862F1964AE3D00D2D697 /* LogSubmit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LogSubmit.m; sourceTree = "<group>"; };
 		B657DDC91911A40500F45B0C /* Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Signal.entitlements; sourceTree = "<group>"; };
 		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 = "<group>"; };
@@ -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 <UIKit/UIKit.h>
 #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 <CocoaLumberjack/DDTTYLogger.h>
+#import <CocoaLumberjack/DDFileLogger.h>
+
 @interface AppDelegate : UIResponder <UIApplicationDelegate> 
 
 @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 <UICKeyChainStore/UICKeyChainStore.h>
 
-#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/DDFileLogger.h>
-
 #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 <Foundation/Foundation.h>
+
+@interface LogSubmit : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
+
+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 <sys/types.h>
+#include <sys/sysctl.h>
+
+@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 <UITableViewDelegate, UITableViewDataSource>
+@interface SettingsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UIAlertViewDelegate>
 
 @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 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="4510" systemVersion="13A603" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="5056" systemVersion="13E28" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES">
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3742"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
     </dependencies>
     <objects>
         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SettingsViewController">
@@ -21,6 +21,7 @@
                 <outlet property="locationOverridesHeaderView" destination="9Ou-py-Aq1" id="nC3-ta-AyD"/>
                 <outlet property="phoneNumberLabel" destination="G77-lz-XM0" id="adE-bu-2Kn"/>
                 <outlet property="privacyAndSecurityHeaderView" destination="XIa-5u-rk1" id="kap-XQ-9AL"/>
+                <outlet property="sendDebugLog" destination="Yc0-ZL-RM6" id="wyq-HF-B9c"/>
                 <outlet property="sendFeedbackButton" destination="cqe-Lt-yoW" id="yOB-Zk-xpw"/>
                 <outlet property="settingsTableView" destination="ajL-B0-V0M" id="0zr-QP-yQl"/>
                 <outlet property="titleLabel" destination="X1p-jb-cMh" id="Duc-Ac-qHm"/>
@@ -556,6 +557,30 @@
                 </constraints>
             </tableViewCellContentView>
         </tableViewCell>
+        <tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="SettingsTableViewCell" id="Yc0-ZL-RM6">
+            <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+            <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Yc0-ZL-RM6" id="S9z-bI-5FI">
+                <rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Submit Debug Log" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cPQ-gV-EF9" customClass="HelveticaNeueLTStdMedLabel">
+                        <rect key="frame" x="20" y="11" width="223" height="21"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <fontDescription key="fontDescription" type="system" pointSize="13"/>
+                        <nil key="highlightedColor"/>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="string" keyPath="localizationKey" value="SETTINGS_SENDLOG"/>
+                        </userDefinedRuntimeAttributes>
+                    </label>
+                    <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rLV-oR-lWh" userLabel="Seperator View">
+                        <rect key="frame" x="15" y="42" width="290" height="1"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <color key="backgroundColor" red="0.7843137255" green="0.7843137255" blue="0.7843137255" alpha="1" colorSpace="calibratedRGB"/>
+                    </view>
+                </subviews>
+            </tableViewCellContentView>
+        </tableViewCell>
     </objects>
     <resources>
         <image name="checkbox_empty.png" width="19" height="19"/>
@@ -564,4 +589,4 @@
         <image name="volume_high.png" width="19" height="19"/>
         <image name="volume_low.png" width="12" height="12"/>
     </resources>
-</document>
\ No newline at end of file
+</document>
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";