--- a/Adium.xcodeproj/project.pbxproj Sat Jul 13 12:46:57 2013 -0400
+++ b/Adium.xcodeproj/project.pbxproj Wed Jul 17 20:55:11 2013 -0400
@@ -1027,6 +1027,9 @@
5A1E3A1214DCE60400724574 /* Preferences-Xtras.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5A1E3A1114DCE60400724574 /* Preferences-Xtras.xib */; };
5A22D6E214834F44004E15F7 /* AIFacebookXMPPAccountView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5A22D6E014834F44004E15F7 /* AIFacebookXMPPAccountView.xib */; };
5A27FA7E14A272330063489D /* pref-messagestyle.png in Resources */ = {isa = PBXBuildFile; fileRef = 5A27FA7A14A272330063489D /* pref-messagestyle.png */; };
+ 5A2FF9B81797336100C2EF12 /* crashDuck.icns in Resources */ = {isa = PBXBuildFile; fileRef = 5A72C1A117013D9400075BBA /* crashDuck.icns */; }; + 5A2FF9BC1797337200C2EF12 /* CrashReporter.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5A72C1A517013D9400075BBA /* CrashReporter.xib */; }; + 5A2FF9BD1797351500C2EF12 /* AICrashReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A72C1AD17013D9400075BBA /* AICrashReporter.m */; }; 5A3B4D7916D878AC00903E40 /* NSString+STTwitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A3B4D6C16D878AB00903E40 /* NSString+STTwitter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
5A3B4D7A16D878AC00903E40 /* STTwitterAPIWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A3B4D6E16D878AB00903E40 /* STTwitterAPIWrapper.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
5A3B4D7C16D878AC00903E40 /* STTwitterOAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A3B4D7216D878AB00903E40 /* STTwitterOAuth.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
@@ -3934,6 +3937,14 @@
5A5F8BBB12D560E400019727 /* AIDockNameOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIDockNameOverlay.h; path = "Plugins/Dock Icon Badging/AIDockNameOverlay.h"; sourceTree = "<group>"; };
5A5F8BBC12D560E400019727 /* AIDockNameOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIDockNameOverlay.m; path = "Plugins/Dock Icon Badging/AIDockNameOverlay.m"; sourceTree = "<group>"; };
5A675E8D13C00AEA006192C5 /* Preferences-General.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "Preferences-General.xib"; path = "Resources/Preferences-General.xib"; sourceTree = "<group>"; };
+ 5A72C1A117013D9400075BBA /* crashDuck.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = crashDuck.icns; sourceTree = "<group>"; }; + 5A72C1A217013D9400075BBA /* crashDuck.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = crashDuck.png; sourceTree = "<group>"; }; + 5A72C1A617013D9400075BBA /* cs */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = cs; path = cs.lproj/CrashReporter.xib; sourceTree = "<group>"; }; + 5A72C1A817013D9400075BBA /* de */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = de; path = de.lproj/CrashReporter.xib; sourceTree = "<group>"; }; + 5A72C1AA17013D9400075BBA /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/CrashReporter.xib; sourceTree = "<group>"; }; + 5A72C1AC17013D9400075BBA /* fr */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = fr; path = fr.lproj/CrashReporter.xib; sourceTree = "<group>"; }; + 5A72C1AD17013D9400075BBA /* AICrashReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AICrashReporter.m; path = "Other/Adium Crash Reporter/AICrashReporter.m"; sourceTree = "<group>"; }; + 5A72C1AE17013D9400075BBA /* AICrashReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AICrashReporter.h; path = "Other/Adium Crash Reporter/AICrashReporter.h"; sourceTree = "<group>"; }; 5A7642A811E044B900E5E0AF /* sk_SK */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xib; name = sk_SK; path = Resources/sk_SK.lproj/AccountProxy.xib; sourceTree = "<group>"; };
5A7642A911E044B900E5E0AF /* sk_SK */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xib; name = sk_SK; path = Resources/sk_SK.lproj/AIAdvancedInspectorPane.xib; sourceTree = "<group>"; };
5A7642AB11E044B900E5E0AF /* sk_SK */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = sk_SK; path = Resources/sk_SK.lproj/Buttons.strings; sourceTree = "<group>"; };
@@ -7120,6 +7131,7 @@
4BCAC53407B59F9C006641B9 /* Other */ = {
+ 5A72C19C17013B1A00075BBA /* Crash Reporter */, 11BE28E30FCC7DA8000E6A10 /* Image Uploading */,
34FDD6E305632BFD00F5B30F /* ESFileTransferController.h */,
34FDD6E405632BFD00F5B30F /* ESFileTransferController.m */,
@@ -7406,6 +7418,27 @@
+ 5A72C19C17013B1A00075BBA /* Crash Reporter */ = { + 5A72C1A017013D9400075BBA /* Resources */, + 5A72C1AD17013D9400075BBA /* AICrashReporter.m */, + 5A72C1AE17013D9400075BBA /* AICrashReporter.h */, + name = "Crash Reporter"; + sourceTree = "<group>"; + 5A72C1A017013D9400075BBA /* Resources */ = { + 5A72C1A117013D9400075BBA /* crashDuck.icns */, + 5A72C1A217013D9400075BBA /* crashDuck.png */, + 5A72C1A517013D9400075BBA /* CrashReporter.xib */, + path = "Other/Adium Crash Reporter/Resources"; + sourceTree = "<group>"; 5A8A6A46124456B1004965A8 /* Segmented control with menu popup */ = {
@@ -9814,6 +9847,7 @@
110763FA08676D05005987A5 /* BlockEditorWindow.xib in Resources */,
EE147A6D0896B18800A21377 /* ABSearch.png in Resources */,
EE147A790896B32400A21377 /* ABSearch.xib in Resources */,
+ 5A2FF9BC1797337200C2EF12 /* CrashReporter.xib in Resources */, 63C120750910A0DD00C9DB57 /* DefaultXtraReadme.rtf in Resources */,
348F579E0936FA6D00288E41 /* EditStatusGroup.xib in Resources */,
6333699409497DB000970871 /* EmoticonPreviewView.xib in Resources */,
@@ -9878,6 +9912,7 @@
317D83680E89F40500298BDB /* msg-bookmark-chat.tiff in Resources */,
11BD73D30F5A54BB007D438A /* twitter-small.png in Resources */,
11BD73D40F5A54BB007D438A /* twitter.png in Resources */,
+ 5A2FF9B81797336100C2EF12 /* crashDuck.icns in Resources */, 1109634C0F61C1D00064CA0E /* AITwitterReplyWindow.xib in Resources */,
113892270F6B70CA00A7D7DC /* laconica-small.png in Resources */,
113892280F6B70CA00A7D7DC /* laconica.png in Resources */,
@@ -10532,6 +10567,7 @@
34DC88410A7EEE2E003E1636 /* AdiumPreferredAccounts.m in Sources */,
34DC88430A7EEE2E003E1636 /* AdiumServices.m in Sources */,
34DC88450A7EEE2E003E1636 /* AdiumApplescriptRunner.m in Sources */,
+ 5A2FF9BD1797351500C2EF12 /* AICrashReporter.m in Sources */, 34DC884C0A7EEE2E003E1636 /* AdiumContentFiltering.m in Sources */,
34DC884E0A7EEE2E003E1636 /* AdiumFormatting.m in Sources */,
34DC88510A7EEE2E003E1636 /* AdiumTyping.m in Sources */,
@@ -12322,6 +12358,17 @@
name = SearchTerms.plist;
+ 5A72C1A517013D9400075BBA /* CrashReporter.xib */ = { + 5A72C1A617013D9400075BBA /* cs */, + 5A72C1A817013D9400075BBA /* de */, + 5A72C1AA17013D9400075BBA /* en */, + 5A72C1AC17013D9400075BBA /* fr */, + name = CrashReporter.xib; + sourceTree = "<group>"; 633D50ED0F9D31BD004F491E /* InfoPlist.strings */ = {
--- a/Other/Adium Crash Reporter/AICrashReporter.h Sat Jul 13 12:46:57 2013 -0400
+++ b/Other/Adium Crash Reporter/AICrashReporter.h Wed Jul 17 20:55:11 2013 -0400
@@ -14,50 +14,27 @@
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#define RELATIVE_PATH_TO_CRASH_REPORTER @"/Contents/Resources/Adium Crash Reporter.app"
-#define EXCEPTIONS_PATH [@"~/Library/Logs/CrashReporter/Adium.exception.log" stringByExpandingTildeInPath]
-#define CRASHES_PATH [[NSString stringWithFormat:@"~/Library/Logs/CrashReporter/%@.crash.log", \
- [[NSProcessInfo processInfo] processName]] stringByExpandingTildeInPath]
-@class AIAutoScrollView, AITextViewWithPlaceholder, SUStatusChecker;
-@protocol SUStatusCheckerDelegate;
+@class AIAutoScrollView, AITextViewWithPlaceholder; -@interface AICrashReporter : NSObject <SUStatusCheckerDelegate> {
- IBOutlet NSWindow *window_MainWindow;
- IBOutlet NSTextField *textField_emailAddress;
- IBOutlet NSTextField *textField_accountIM;
- IBOutlet NSTextField *textField_description;
+@interface AICrashReporter : NSWindowController <NSWindowDelegate> { IBOutlet AIAutoScrollView *scrollView_details;
- IBOutlet AITextViewWithPlaceholder *textView_details;
+ IBOutlet AITextViewWithPlaceholder *textView_details; - IBOutlet NSProgressIndicator *progress_sending;
IBOutlet NSButton *button_close;
IBOutlet NSPanel *panel_privacySheet;
IBOutlet NSTextView *textView_crashLog;
- NSString *crashLog; //Current crash log
- NSString *buildNumber, *buildUser;
- NSAppleScript *slayerScript;
- SUStatusChecker *statusChecker;
+@property (retain) NSString *crashLog; - (IBAction)showPrivacyDetails:(id)sender;
- (IBAction)closePrivacyDetails:(id)sender;
-- (BOOL)reportCrashForLogAtPath:(NSString *)inPath;
-- (void)sendReport:(NSDictionary *)crashReport;
- (IBAction)send:(id)sender;
-- (void)_loadBuildInformation;
--- a/Other/Adium Crash Reporter/AICrashReporter.m Sat Jul 13 12:46:57 2013 -0400
+++ b/Other/Adium Crash Reporter/AICrashReporter.m Wed Jul 17 20:55:11 2013 -0400
@@ -20,180 +20,96 @@
#import <AIUtilities/AIFileManagerAdditions.h>
#import <AIUtilities/AIApplicationAdditions.h>
#import <AIUtilities/AIAutoScrollView.h>
-#import <Sparkle/Sparkle.h>
-#define CRASH_REPORT_URL @"http://www.visualdistortion.org/crash/post.jsp"
-#define KEY_CRASH_EMAIL_ADDRESS @"AdiumCrashReporterEmailAddress"
-#define KEY_CRASH_AIM_ACCOUNT @"AdiumCrashReporterAIMAccount"
-#define CRASH_REPORT_SLAY_ATTEMPTS 100
-#define CRASH_REPORT_SLAY_INTERVAL 0.1
+#define CRASH_REPORT_URL @"https://sdk.hockeyapp.net/" +#define HOCKEY_APP_ID @"a703119f260a58377333db4a07fecadb" -#define CRASH_LOG_WAIT_ATTEMPTS 100
-#define CRASH_LOG_WAIT_INTERVAL 0.2
-#define ADIUM_UPDATE_URL @"http://download.adiumx.com/"
-#define ADIUM_UPDATE_BETA_URL @"http://beta.adiumx.com/"
+#define LAST_CRASH_DATE @"lastKnownCrashDate" +#define CRASH_LOG_DIRECTORY [@"~/Library/Logs/DiagnosticReports" stringByStandardizingPath] #define UNABLE_TO_SEND AILocalizedString(@"Unable to send crash report",nil)
-@interface AICrashReporter (PRIVATE)
-- (void)performVersionChecking;
+@implementation AICrashReporter -@implementation AICrashReporter
+ AICrashReporter *reporter = [[AICrashReporter alloc] init]; + [reporter _checkForCrash];
- if ((self = [super init])) {
- slayerScript = [[NSAppleScript alloc] initWithSource:@"tell application \"UserNotificationCenter\" to quit"];
+ // get a list of files beginning with 'Adium' from the crash reporter folder + NSFileManager *fm = [[[NSFileManager alloc] init] autorelease]; + NSArray *files = [fm contentsOfDirectoryAtPath:CRASH_LOG_DIRECTORY error:nil]; + NSArray *filteredFiles = [files filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF BEGINSWITH[c] 'Adium'"]]; + NSDate *mostRecentCrashDate = [NSDate distantPast]; + // Enumerate crash files to find most recent crash report + for (NSString *file in filteredFiles) { + NSDate *date = [[fm attributesOfItemAtPath:[CRASH_LOG_DIRECTORY stringByAppendingPathComponent:file] error:nil] objectForKey:NSFileCreationDate]; + if ([date compare:mostRecentCrashDate] == NSOrderedDescending) { + mostRecentCrashDate = date; + [self setCrashLog:file]; + [self setCrashLog:file]; + // obtain the last known crash date from the prefs + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSDate *lastKnownCrashDate = [defaults objectForKey:LAST_CRASH_DATE]; + // check to see if Adium crashed since the last crash (there's a newer crash report) + if (lastKnownCrashDate && [mostRecentCrashDate compare:lastKnownCrashDate] == NSOrderedDescending) { + [NSBundle loadNibNamed:@"CrashReporter" owner:self]; + // save last crash date + [defaults setObject:mostRecentCrashDate forKey:LAST_CRASH_DATE];
- [slayerScript release];
- [statusChecker release];
- [textView_details setPlaceholderString:AILocalizedString(@"A detailed explanation of what you were doing when Adium crashed (optional)",nil)];
+ [textView_details setPlaceholderString:AILocalizedString(@"A detailed explanation of what you were doing when Adium crashed (optional)", nil)]; [scrollView_details setAlwaysDrawFocusRingIfFocused:YES];
- //Search for an exception log
- if ([[NSFileManager defaultManager] fileExistsAtPath:EXCEPTIONS_PATH]) {
- [self reportCrashForLogAtPath:EXCEPTIONS_PATH];
- //Kill the apple crash reporter
- [NSTimer scheduledTimerWithTimeInterval:CRASH_REPORT_SLAY_INTERVAL
- selector:@selector(appleCrashReportSlayer:)
- //Wait for a valid crash log to appear
- [NSTimer scheduledTimerWithTimeInterval:CRASH_LOG_WAIT_INTERVAL
- selector:@selector(delayedCrashLogDiscovery:)
- if ([progress_sending respondsToSelector:@selector(setHidden:)]) {
- [progress_sending setHidden:YES];
-- (BOOL)application:(NSApplication *)app openFile:(NSString *)path {
- adiumPath = [path retain];
-//Actively tries to kill Apple's "Report this crash" dialog
-- (void)appleCrashReportSlayer:(NSTimer *)inTimer
- static int countdown = CRASH_REPORT_SLAY_ATTEMPTS;
- //Kill the notification app if it's open
- if (countdown-- == 0 || ![[slayerScript executeAndReturnError:nil] booleanValue]) {
+ [self.window makeKeyAndOrderFront:self]; -#pragma mark Crash log loading
-//Waits for a crash log to be written
-- (void)delayedCrashLogDiscovery:(NSTimer *)inTimer
- static int countdown = CRASH_LOG_WAIT_ATTEMPTS;
- //Kill the notification app if it's open
- if (countdown-- == 0 ||
- [self reportCrashForLogAtPath:[@"~/Library/Logs/CrashReporter/Adium.real.crash.log" stringByExpandingTildeInPath]] ||
- [self reportCrashForLogAtPath:[@"~/Library/Logs/CrashReporter/Adium.crash.log" stringByExpandingTildeInPath]]) {
-//Display the report crash window for the passed log
-- (BOOL)reportCrashForLogAtPath:(NSString *)inPath
+- (void)windowWillClose:(id)sender - NSString *emailAddress, *aimAccount;
- if ([[NSFileManager defaultManager] fileExistsAtPath:inPath]) {
- NSString *newLog = [NSString stringWithContentsOfFile:inPath];
- if (newLog && [newLog length]) {
- //Hang onto and delete the log
- crashLog = [newLog retain];
- [[NSFileManager defaultManager] trashFileAtPath:inPath];
- //Strip off PPC thread state and binary descriptions.. we don't need to send all that
- binaryRange = [crashLog rangeOfString:@"PPC Thread State:"];
- if (binaryRange.location != NSNotFound) {
- NSString *shortLog = [crashLog substringToIndex:binaryRange.location];
- [crashLog release]; crashLog = [shortLog retain];
- //Restore the user's email address and account if they've entered it previously
- if ((emailAddress = [[NSUserDefaults standardUserDefaults] objectForKey:KEY_CRASH_EMAIL_ADDRESS])) {
- [textField_emailAddress setStringValue:emailAddress];
- if ((aimAccount = [[NSUserDefaults standardUserDefaults] objectForKey:KEY_CRASH_AIM_ACCOUNT])) {
- [textField_accountIM setStringValue:aimAccount];
- //Highlight the existing details text
- [textView_details setSelectedRange:NSMakeRange(0, [[textView_details textStorage] length])
- affinity:NSSelectionAffinityUpstream
- [window_MainWindow makeKeyAndOrderFront:nil];
#pragma mark Privacy Details
//Display privacy information sheet
- (IBAction)showPrivacyDetails:(id)sender
- NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:11]
- forKey:NSFontAttributeName];
- NSAttributedString *attrLogString = [[[NSAttributedString alloc] initWithString:crashLog
- attributes:attributes] autorelease];
- [[textView_crashLog textStorage] setAttributedString:attrLogString];
- [NSApp beginSheet:panel_privacySheet
- modalForWindow:window_MainWindow
+ NSDictionary *attributes = [NSDictionary dictionaryWithObject:[NSFont systemFontOfSize:11] + forKey:NSFontAttributeName]; + NSString *file = [NSString stringWithContentsOfFile:[CRASH_LOG_DIRECTORY stringByAppendingPathComponent:self.crashLog] + encoding:NSUTF8StringEncoding error:nil]; + NSAttributedString *attrLogString = [[[NSAttributedString alloc] initWithString:file + attributes:attributes] autorelease]; + [[textView_crashLog textStorage] setAttributedString:attrLogString]; + [NSApp beginSheet:panel_privacySheet + modalForWindow:self.window //Close the privacy details sheet
@@ -204,284 +120,151 @@
#pragma mark Report sending
- * @brief Disable the close button and begin spinning the indeterminate progress indicator
-- (void)activateProgressIndicator
- [button_close setHidden:YES];
- //Display immediately since we need it for this run loop.
- [[button_close superview] display];
- [progress_sending setHidden:NO];
- //start the progress spinner (using multi-threading)
- [progress_sending setUsesThreadedAnimation:YES];
- [progress_sending startAnimation:nil];
* @brief User wants to send the report
- (IBAction)send:(id)sender
- if ([[textField_emailAddress stringValue] isEqualToString:@""] &&
- [[textField_accountIM stringValue] isEqualToString:@""]) {
- NSBeginCriticalAlertSheet(AILocalizedString(@"Contact Information Required",nil),
- @"OK", nil, nil, window_MainWindow, nil, nil, nil, NULL,
- AILocalizedString(@"Please provide either your email address or IM name in case we need to contact you for additional information (or to suggest a solution).",nil));
- //Begin showing progress
- [self activateProgressIndicator];
- //Load the build information
- [self _loadBuildInformation];
- //Perform version checking; when it is complete or fails, the submission process wil continue
- [self performVersionChecking];
- * @brief Build the crash report and associated information, then pass it to sendReport:
-- (void)buildAndSendReport
- //If we already sent the crash log, do nothing and just return
- if (sentCrashLog) return;
- NSString *shortDescription = [textField_description stringValue];
+ [self.window orderOut:nil]; - //Truncate description field to 300 characters
- if ([shortDescription length] > 300) {
- shortDescription = [shortDescription substringToIndex:300];
- NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] initWithDateFormat:@"%m-%d"
- allowNaturalLanguage:NO] autorelease];
- NSString *buildDateAndInfo = [NSString stringWithFormat:@"%@ (%@)",
- [dateFormatter stringForObjectValue:buildDate],
- (buildUser ? [NSString stringWithFormat:@"%@.%@",buildNumber,buildUser] : buildNumber)];
- NSDictionary *crashReport = [NSDictionary dictionaryWithObjectsAndKeys:
- buildDateAndInfo, @"build",
- [textField_emailAddress stringValue], @"email",
- [textField_accountIM stringValue], @"service_name",
- shortDescription, @"short_desc",
- [textView_details string], @"desc",
- [self sendReport:crashReport];
* @brief Send a crash report to the crash reporter web site
-- (void)sendReport:(NSDictionary *)crashReport
- NSMutableString *reportString = [[[NSMutableString alloc] init] autorelease];
- NSEnumerator *enumerator;
- //Compact the fields of the report into a long URL string
- enumerator = [[crashReport allKeys] objectEnumerator];
- while ((key = [enumerator nextObject])) {
- if ([reportString length] != 0) [reportString appendString:@"&"];
- [reportString appendFormat:@"%@=%@", key, [[crashReport objectForKey:key] stringByEncodingURLEscapes]];
- while (!data || [data length] == 0) {
- NSMutableURLRequest *request;
- //Build the URL request
- request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:CRASH_REPORT_URL]
- cachePolicy:NSURLRequestReloadIgnoringCacheData
- [request addValue:@"Adium 2.0a" forHTTPHeaderField:@"X-Adium-Bug-Report"];
- [request setHTTPMethod:@"POST"];
- [request setHTTPBody:[reportString dataUsingEncoding:NSUTF8StringEncoding]];
+ NSString *reportString = [NSString stringWithContentsOfFile:[CRASH_LOG_DIRECTORY stringByAppendingPathComponent:self.crashLog] + encoding:NSUTF8StringEncoding error:nil]; + NSXMLDocument *doc = [[NSXMLDocument alloc] initWithRootElement:[NSXMLElement elementWithName:@"crashes"]]; + NSXMLElement *crash = [NSXMLElement elementWithName:@"crash"]; + [crash addChild:[NSXMLElement elementWithName:@"applicationname" stringValue:[self applicationName]]]; + [crash addChild:[NSXMLElement elementWithName:@"bundleidentifier" stringValue:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]]]; + [crash addChild:[NSXMLElement elementWithName:@"systemversion" stringValue:[self OSVersion]]]; + [crash addChild:[NSXMLElement elementWithName:@"senderversion" stringValue:[self applicationVersion]]]; + [crash addChild:[NSXMLElement elementWithName:@"version" stringValue:[self applicationVersion]]]; + [crash addChild:[NSXMLElement elementWithName:@"platform" stringValue:[self modelVersion]]]; + [crash addChild:[NSXMLElement elementWithName:@"description" stringValue:[textView_details string]]]; + [crash addChild:[NSXMLElement elementWithName:@"log" stringValue:reportString]]; + [[doc rootElement] addChild:crash]; + NSMutableURLRequest *request = nil; + NSString *boundary = @"----FOO"; + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes?sdk=%@&sdk_version=%@&feedbackEnabled=no", + [HOCKEY_APP_ID stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], + request = [NSMutableURLRequest requestWithURL:url]; + [request setValue:@"Adium" forHTTPHeaderField:@"User-Agent"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + [request setTimeoutInterval:15]; + [request setHTTPMethod:@"POST"]; + NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; + [request setValue:contentType forHTTPHeaderField:@"Content-type"]; + NSMutableData *postBody = [NSMutableData data]; + [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[@"Content-Disposition: form-data; name=\"xml\"; filename=\"crash.xml\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[[NSString stringWithFormat:@"Content-Type: text/xml\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; - //Attempt to send report
- data = [NSURLConnection sendSynchronousRequest:request returningResponse:&reply error:&error];
- //stop the progress spinner
- [progress_sending stopAnimation:nil];
- //Alert on failure, and offer the option to quit or retry
- if (!data || [data length] == 0) {
- if (NSRunAlertPanel(UNABLE_TO_SEND,
- [error localizedDescription],
- AILocalizedString(@"Try Again",nil),
- AILocalizedString(@"Quit",nil),
- nil) == NSAlertAlternateReturn) {
+ [postBody appendData:[doc XMLData]]; + [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [request setHTTPBody:postBody]; + NSHTTPURLResponse *response = nil; + [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; + //Check for success and offer to try once more if there was an error sending + if ([response statusCode] != 201) { + NSString *reason = [NSString stringWithFormat:@"%lu: %@\n%@", response.statusCode, [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], [error localizedDescription] ?: @""]; + if (NSRunAlertPanel(UNABLE_TO_SEND, + AILocalizedString(@"Try Again", nil), + AILocalizedString(@"Close", nil), + nil) == NSAlertDefaultReturn) { + [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; + if ([response statusCode] != 201) { + reason = [NSString stringWithFormat:@"%lu: %@\n%@", response.statusCode, [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], [error localizedDescription] ?: @""]; + NSRunAlertPanel(UNABLE_TO_SEND, reason, nil, nil, nil);
-#pragma mark Closing behavior
-//Save some of the information for next time on quit
-- (void)windowWillClose:(id)sender
- //Remember the user's email address, account name
- [[NSUserDefaults standardUserDefaults] setObject:[textField_emailAddress stringValue]
- forKey:KEY_CRASH_EMAIL_ADDRESS];
- [[NSUserDefaults standardUserDefaults] setObject:[textField_accountIM stringValue]
- forKey:KEY_CRASH_AIM_ACCOUNT];
-//Terminate if our window is closed
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
-#pragma mark Build information
-//Load the current build date and our svn revision
-- (void)_loadBuildInformation
- //Grab the info from our buildnum script
- char *path, unixDate[256], num[256],whoami[256];
- if ((path = (char *)[[[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/../../../buildnum"] fileSystemRepresentation]) &&
- ([[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithUTF8String:path]]) &&
- (f= fopen(path, "r"))) {
- fscanf(f, "%s | %s | %s", num, unixDate, whoami);
+#pragma mark - System/Application Information +- (NSString *) applicationName { + NSString *applicationName = [[[NSBundle mainBundle] localizedInfoDictionary] valueForKey: @"CFBundleExecutable"]; + applicationName = [[[NSBundle mainBundle] infoDictionary] valueForKey: @"CFBundleExecutable"]; + return applicationName; +- (NSString*) applicationVersionString { + NSString* string = [[[NSBundle mainBundle] localizedInfoDictionary] valueForKey: @"CFBundleShortVersionString"]; + string = [[[NSBundle mainBundle] infoDictionary] valueForKey: @"CFBundleShortVersionString"]; +- (NSString *) applicationVersion { + NSString* string = [[[NSBundle mainBundle] localizedInfoDictionary] valueForKey: @"CFBundleVersion"]; + string = [[[NSBundle mainBundle] infoDictionary] valueForKey: @"CFBundleVersion"]; +- (NSString *) OSVersion { + SInt32 versionMajor, versionMinor, versionBugFix; + if (Gestalt(gestaltSystemVersionMajor, &versionMajor) != noErr) versionMajor = 0; + if (Gestalt(gestaltSystemVersionMinor, &versionMinor) != noErr) versionMinor= 0; + if (Gestalt(gestaltSystemVersionBugFix, &versionBugFix) != noErr) versionBugFix = 0; + return [NSString stringWithFormat:@"%i.%i.%i", versionMajor, versionMinor, versionBugFix]; +- (NSString *) modelVersion { + NSString * modelString = nil; + int modelInfo[2] = { CTL_HW, HW_MODEL }; + void * modelData = malloc(modelSize);
- buildNumber = [[NSString stringWithFormat:@"%s", num] retain];
- buildDate = [[NSDate dateWithTimeIntervalSince1970:[[NSString stringWithCString:unixDate] doubleValue]] retain];
- //If the application was built by one of these people, we assume that it is a release, which means we should not show their username in the crash log.
- //Otherwise, this is somebody's custom build, and including the username marks it as such.
- buildUser = [[NSString stringWithFormat:@"%s", whoami] retain];
- if ([buildUser isEqualToString:@"adamiser"] ||
- [buildUser isEqualToString:@"evands"] ||
- [buildUser isEqualToString:@"jmelloy"] ||
- [buildUser isEqualToString:@"durin"] ||
- [buildUser isEqualToString:@"rfackler"] ||
- [buildUser isEqualToString:@"david"]) {
+ modelString = [NSString stringWithUTF8String:modelData];
- NSLog(@"Unable to open the buildnum file.");
- //Default to empty strings if something goes wrong
- if (!buildDate) buildDate = [@"" retain];
- if (!buildNumber) buildNumber = [@"" retain];
- * @brief Invoked when version information is received
-- (void)finishWithAcceptableVersion:(BOOL)allowReport newVersionString:(NSString *)versionString
- BOOL shouldRelaunchAdium = YES;
- [self buildAndSendReport];
- if (NSRunAlertPanel(UNABLE_TO_SEND,
- [NSString stringWithFormat:AILocalizedString(@"Your version of Adium is out of date, so crash reporting has been disabled. Your version is %@; the current version is %@. Please update to the latest version, as your crash may have already been fixed.",nil),
- [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
- AILocalizedString(@"Update Now",nil),
- AILocalizedString(@"Cancel",nil),
- nil) == NSAlertDefaultReturn) {
- shouldRelaunchAdium = NO;
- [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:ADIUM_UPDATE_BETA_URL]];
- [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:ADIUM_UPDATE_URL]];
- //Relaunch Adium if appropriate
- if (shouldRelaunchAdium) {
- [[NSWorkspace sharedWorkspace] openFile:adiumPath];
- [[NSWorkspace sharedWorkspace] launchApplication:@"Adium"];
- //Close our window to terminate
- [window_MainWindow performClose:nil];
-- (void)versionCheckingTimedOut
- [self statusChecker:nil foundVersion:nil isNewVersion:NO];
- * @brief Returns the date of the most recent Adium build (contacts adiumx.com asynchronously)
-- (void)performVersionChecking
- statusChecker = [[SUStatusChecker statusCheckerForDelegate:self] retain];
- [self performSelector:@selector(versionCheckingTimedOut)
-- (void)statusChecker:(SUStatusChecker *)statusChecker foundVersion:(NSString *)versionString isNewVersion:(BOOL)isNewVersion
- //Only send the report if there is not a new version
- NSLog(@"Adium Crash Reporter warning: Could not retrieve version information from the server. Perhaps it is blocked? Allowing the crash reporter anyways.");
- [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(versionCheckingTimedOut) object:nil];
- [self finishWithAcceptableVersion:!isNewVersion newVersionString:versionString];
-#define UPDATE_TYPE_DICT [NSDictionary dictionaryWithObjectsAndKeys:@"type", @"key", @"Update Type", @"visibleKey", @"beta", @"value", @"Beta or Release Versions", @"visibleValue", nil]
-#define UPDATE_TYPE_DICT [NSDictionary dictionaryWithObjectsAndKeys:@"type", @"key", @"Update Type", @"visibleKey", @"release", @"value", @"Release Versions Only", @"visibleValue", nil]
-/* This method gives the delegate the opportunity to customize the information that will
-* be included with update checks. Add or remove items from the dictionary as desired.
-* Each entry in profileInfo is an NSDictionary with the following keys:
-* key: The key to be used when reporting data to the server
-* visibleKey: Alternate version of key to be used in UI displays of profile information
-* value: Value to be used when reporting data to the server
-* visibleValue: Alternate version of value to be used in UI displays of profile information.
-- (NSMutableArray *)updaterCustomizeProfileInfo:(NSMutableArray *)profileInfo
- return [NSMutableArray arrayWithObject:UPDATE_TYPE_DICT];
--- a/Source/AIAdium.m Sat Jul 13 12:46:57 2013 -0400
+++ b/Source/AIAdium.m Wed Jul 17 20:55:11 2013 -0400
@@ -22,10 +22,9 @@
#import "AIContentController.h"
#import "AICoreComponentLoader.h"
#import "AICorePluginLoader.h"
-//#import "AICrashController.h"
+#import "AICrashReporter.h" #import "AIDockController.h"
#import "AIEmoticonController.h"
-//#import "AIExceptionController.h"
#import "AIInterfaceController.h"
#import "AILoginController.h"
#import "AIMenuController.h"
@@ -121,14 +120,9 @@
- //Load the crash reporter
-#warning Crash reporter enabled.
- [AICrashController enableCrashCatching];
- [AIExceptionController enableExceptionCatching];
+ //Check for a recent crash log + [AICrashReporter checkForCrash]; //Ignore SIGPIPE, which is a harmless error signal
//sent when write() or similar function calls fail due to a broken pipe in the network connection
signal(SIGPIPE, SIG_IGN);