/** * @file llcrashloggermac.cpp * @brief Mac OSX crash logger implementation * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llcrashloggermac.h" #include <Carbon/Carbon.h> #include <iostream> #include <sstream> #include "boost/tokenizer.hpp" #include "indra_constants.h" // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME #include "llerror.h" #include "llfile.h" #include "lltimer.h" #include "llstring.h" #include "lldir.h" #include "llsdserialize.h" #define MAX_LOADSTRING 100 const char* const SETTINGS_FILE_HEADER = "version"; const S32 SETTINGS_FILE_VERSION = 101; // Windows Message Handlers BOOL gFirstDialog = TRUE; // Are we currently handling the Send/Don't Send dialog? LLFILE *gDebugFile = NULL; WindowRef gWindow = NULL; EventHandlerRef gEventHandler = NULL; std::string gUserNotes = ""; bool gSendReport = false; bool gRememberChoice = false; IBNibRef nib = NULL; OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata) { OSStatus result = eventNotHandledErr; OSStatus err; UInt32 evtClass = GetEventClass(event); UInt32 evtKind = GetEventKind(event); if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) { HICommand cmd; err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd); if(err == noErr) { //Get the value of the checkbox ControlID id; ControlRef checkBox = NULL; id.signature = 'remb'; id.id = 0; err = GetControlByID(gWindow, &id, &checkBox); if(err == noErr) { if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue) { gRememberChoice = true; } else { gRememberChoice = false; } } switch(cmd.commandID) { case kHICommandOK: { char buffer[65535]; /* Flawfinder: ignore */ Size size = sizeof(buffer) - 1; ControlRef textField = NULL; id.signature = 'text'; id.id = 0; err = GetControlByID(gWindow, &id, &textField); if(err == noErr) { // Get the user response text err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size); } if(err == noErr) { // Make sure the string is terminated. buffer[size] = 0; gUserNotes = buffer; llinfos << buffer << llendl; } // Send the report. QuitAppModalLoopForWindow(gWindow); gSendReport = true; result = noErr; } break; case kHICommandCancel: QuitAppModalLoopForWindow(gWindow); result = noErr; break; default: result = eventNotHandledErr; } } } return(result); } LLCrashLoggerMac::LLCrashLoggerMac(void) { } LLCrashLoggerMac::~LLCrashLoggerMac(void) { } bool LLCrashLoggerMac::init(void) { bool ok = LLCrashLogger::init(); if(!ok) return false; if(mCrashBehavior != CRASH_BEHAVIOR_ASK) return true; // Real UI... OSStatus err; err = CreateNibReference(CFSTR("CrashReporter"), &nib); if(err == noErr) { err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow); } if(err == noErr) { // Set focus to the edit text area ControlRef textField = NULL; ControlID id; id.signature = 'text'; id.id = 0; // Don't set err if any of this fails, since it's non-critical. if(GetControlByID(gWindow, &id, &textField) == noErr) { SetKeyboardFocus(gWindow, textField, kControlFocusNextPart); } } if(err == noErr) { ShowWindow(gWindow); } if(err == noErr) { // Set up an event handler for the window. EventTypeSpec handlerEvents[] = { { kEventClassCommand, kEventCommandProcess } }; InstallWindowEventHandler( gWindow, NewEventHandlerUPP(dialogHandler), GetEventTypeCount (handlerEvents), handlerEvents, 0, &gEventHandler); } return true; } void LLCrashLoggerMac::gatherPlatformSpecificFiles() { updateApplication("Gathering hardware information..."); } bool LLCrashLoggerMac::mainLoop() { OSStatus err = noErr; if(err == noErr && mCrashBehavior == CRASH_BEHAVIOR_ASK) { RunAppModalLoopForWindow(gWindow); } else if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND) { gSendReport = true; } if(gRememberChoice) { if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND); else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND); } if(gSendReport) { setUserText(gUserNotes); sendCrashLogs(); } if(gWindow != NULL) { DisposeWindow(gWindow); } if(nib != NULL) { DisposeNibReference(nib); } return true; } void LLCrashLoggerMac::updateApplication(const std::string& message) { LLCrashLogger::updateApplication(); } bool LLCrashLoggerMac::cleanup() { return true; }