llcrashloggermac.cpp

Go to the documentation of this file.
00001 
00033 #include "llcrashloggermac.h"
00034 
00035 #include <Carbon/Carbon.h>
00036 #include <iostream>
00037 #include <sstream>
00038 
00039 #include "boost/tokenizer.hpp"
00040 
00041 #include "indra_constants.h"    // CRASH_BEHAVIOR_ASK, CRASH_SETTING_NAME
00042 #include "llerror.h"
00043 #include "llfile.h"
00044 #include "lltimer.h"
00045 #include "llstring.h"
00046 #include "lldir.h"
00047 #include "llsdserialize.h"
00048 
00049 #define MAX_LOADSTRING 100
00050 const char* const SETTINGS_FILE_HEADER = "version";
00051 const S32 SETTINGS_FILE_VERSION = 101;
00052 
00053 // Windows Message Handlers
00054 
00055 BOOL gFirstDialog = TRUE;       // Are we currently handling the Send/Don't Send dialog?
00056 LLFILE *gDebugFile = NULL;
00057 
00058 WindowRef gWindow = NULL;
00059 EventHandlerRef gEventHandler = NULL;
00060 LLString gUserNotes = "";
00061 bool gSendReport = false;
00062 bool gRememberChoice = false;
00063 IBNibRef nib = NULL;
00064 
00065 OSStatus dialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
00066 {
00067         OSStatus result = eventNotHandledErr;
00068         OSStatus err;
00069         UInt32 evtClass = GetEventClass(event);
00070         UInt32 evtKind = GetEventKind(event);
00071         if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
00072         {
00073                 HICommand cmd;
00074                 err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
00075                 
00076 
00077                 
00078                 if(err == noErr)
00079                 {
00080                         //Get the value of the checkbox
00081                         ControlID id;
00082                         ControlRef checkBox = NULL;
00083                         id.signature = 'remb';
00084                         id.id = 0;
00085                         err = GetControlByID(gWindow, &id, &checkBox);
00086                         
00087                         if(err == noErr)
00088                         {
00089                                 if(GetControl32BitValue(checkBox) == kControlCheckBoxCheckedValue)
00090                                 {
00091                                         gRememberChoice = true;
00092                                 }
00093                                 else
00094                                 {
00095                                         gRememberChoice = false;
00096                                 }
00097                         }       
00098                         switch(cmd.commandID)
00099                         {
00100                                 case kHICommandOK:
00101                                 {
00102                                         char buffer[65535];             /* Flawfinder: ignore */
00103                                         Size size = sizeof(buffer) - 1;
00104                                         ControlRef textField = NULL;
00105 
00106                                         id.signature = 'text';
00107                                         id.id = 0;
00108 
00109                                         err = GetControlByID(gWindow, &id, &textField);
00110                                         if(err == noErr)
00111                                         {
00112                                                 // Get the user response text
00113                                                 err = GetControlData(textField, kControlNoPart, kControlEditTextTextTag, size, (Ptr)buffer, &size);
00114                                         }
00115                                         if(err == noErr)
00116                                         {
00117                                                 // Make sure the string is terminated.
00118                                                 buffer[size] = 0;
00119                                                 gUserNotes = buffer;
00120 
00121                                                 llinfos << buffer << llendl;
00122                                         }
00123                                         
00124                                         // Send the report.
00125 
00126                                         QuitAppModalLoopForWindow(gWindow);
00127                                         gSendReport = true;
00128                                         result = noErr;
00129                                 }
00130                                 break;
00131                                 
00132                                 case kHICommandCancel:
00133                                         QuitAppModalLoopForWindow(gWindow);
00134                                         result = noErr;
00135                                 break;
00136                         }
00137                 }
00138         }
00139 
00140         return(result);
00141 }
00142 
00143 
00144 LLCrashLoggerMac::LLCrashLoggerMac(void)
00145 {
00146 }
00147 
00148 LLCrashLoggerMac::~LLCrashLoggerMac(void)
00149 {
00150 }
00151 
00152 bool LLCrashLoggerMac::init(void)
00153 {       
00154         bool ok = LLCrashLogger::init();
00155         if(!ok) return false;
00156         if(mCrashBehavior != CRASH_BEHAVIOR_ASK) return true;
00157         
00158         // Real UI...
00159         OSStatus err;
00160         
00161         err = CreateNibReference(CFSTR("CrashReporter"), &nib);
00162         
00163         if(err == noErr)
00164         {
00165                 err = CreateWindowFromNib(nib, CFSTR("CrashReporter"), &gWindow);
00166         }
00167 
00168         if(err == noErr)
00169         {
00170                 // Set focus to the edit text area
00171                 ControlRef textField = NULL;
00172                 ControlID id;
00173 
00174                 id.signature = 'text';
00175                 id.id = 0;
00176                 
00177                 // Don't set err if any of this fails, since it's non-critical.
00178                 if(GetControlByID(gWindow, &id, &textField) == noErr)
00179                 {
00180                         SetKeyboardFocus(gWindow, textField, kControlFocusNextPart);
00181                 }
00182         }
00183         
00184         if(err == noErr)
00185         {
00186                 ShowWindow(gWindow);
00187         }
00188         
00189         if(err == noErr)
00190         {
00191                 // Set up an event handler for the window.
00192                 EventTypeSpec handlerEvents[] = 
00193                 {
00194                         { kEventClassCommand, kEventCommandProcess }
00195                 };
00196 
00197                 InstallWindowEventHandler(
00198                                 gWindow, 
00199                                 NewEventHandlerUPP(dialogHandler), 
00200                                 GetEventTypeCount (handlerEvents), 
00201                                 handlerEvents, 
00202                                 0, 
00203                                 &gEventHandler);
00204         }
00205         return true;
00206 }
00207 
00208 void LLCrashLoggerMac::gatherPlatformSpecificFiles()
00209 {
00210         updateApplication("Gathering hardware information...");
00211         char path[MAX_PATH];            
00212         FSRef folder;
00213         
00214         if(FSFindFolder(kUserDomain, kLogsFolderType, false, &folder) == noErr)
00215         {
00216                 // folder is an FSRef to ~/Library/Logs/
00217                 if(FSRefMakePath(&folder, (UInt8*)&path, sizeof(path)) == noErr)
00218                 {
00219                         struct stat dw_stat;
00220                         LLString mBuf;
00221                         bool isLeopard = false;
00222                         // Try the 10.3 path first...
00223                         LLString dw_file_name = LLString(path) + LLString("/CrashReporter/Second Life.crash.log");
00224                         int res = stat(dw_file_name.c_str(), &dw_stat);
00225 
00226                         if (res)
00227                         {
00228                                 // Try the 10.2 one next...
00229                                 dw_file_name = LLString(path) + LLString("/Second Life.crash.log");
00230                                 res = stat(dw_file_name.c_str(), &dw_stat);
00231                         }
00232         
00233                         if(res)
00234                         {
00235                                 //10.5: Like 10.3+, except it puts the crash time in the file instead of dividing it up
00236                                 //using asterisks. Get a directory listing, search for files starting with second life,
00237                                 //use the last one found.
00238                                 LLString old_file_name, current_file_name, pathname, mask;
00239                                 pathname = LLString(path) + LLString("/CrashReporter/");
00240                                 mask = "Second Life*";
00241                                 while(gDirUtilp->getNextFileInDir(pathname, mask, current_file_name, false))
00242                                 {
00243                                         old_file_name = current_file_name;
00244                                 }
00245                                 if(old_file_name != "")
00246                                 {
00247                                         dw_file_name = pathname + old_file_name;
00248                                         res=stat(dw_file_name.c_str(), &dw_stat);
00249                                         isLeopard = true;
00250                                 }
00251                         }
00252                         
00253                         if (!res)
00254                         {
00255                                 std::ifstream fp(dw_file_name.c_str());
00256                                 std::stringstream str;
00257                                 if(!fp.is_open()) return;
00258                                 str << fp.rdbuf();
00259                                 mBuf = str.str();
00260                                 
00261                                 if(!isLeopard)
00262                                 {
00263                                         // Crash logs consist of a number of entries, one per crash.
00264                                         // Each entry is preceeded by "**********" on a line by itself.
00265                                         // We want only the most recent (i.e. last) one.
00266                                         const char *sep = "**********";
00267                                         const char *start = mBuf.c_str();
00268                                         const char *cur = start;
00269                                         const char *temp = strstr(cur, sep);
00270                                 
00271                                         while(temp != NULL)
00272                                         {
00273                                                 // Skip past the marker we just found
00274                                                 cur = temp + strlen(sep);               /* Flawfinder: ignore */
00275                                                 
00276                                                 // and try to find another
00277                                                 temp = strstr(cur, sep);
00278                                         }
00279                                 
00280                                         // If there's more than one entry in the log file, strip all but the last one.
00281                                         if(cur != start)
00282                                         {
00283                                                 mBuf.erase(0, cur - start);
00284                                         }
00285                                 }
00286                                 mCrashInfo["CrashLog"] = mBuf;
00287                         }
00288                         else
00289                         {
00290                                 llwarns << "Couldn't find any CrashReporter files..." << llendl;
00291                         }
00292                 }
00293         }
00294 }
00295 
00296 bool LLCrashLoggerMac::mainLoop()
00297 {
00298         OSStatus err = noErr;
00299                                 
00300         if(err == noErr && mCrashBehavior == CRASH_BEHAVIOR_ASK)
00301         {
00302                 RunAppModalLoopForWindow(gWindow);
00303         }
00304         else if (mCrashBehavior == CRASH_BEHAVIOR_ALWAYS_SEND)
00305         {
00306                 gSendReport = true;
00307         }
00308         
00309         if(gRememberChoice)
00310         {
00311                 if(gSendReport) saveCrashBehaviorSetting(CRASH_BEHAVIOR_ALWAYS_SEND);
00312                 else saveCrashBehaviorSetting(CRASH_BEHAVIOR_NEVER_SEND);
00313         }
00314         
00315         if(gSendReport)
00316         {
00317                 setUserText(gUserNotes);
00318                 sendCrashLogs();
00319         }               
00320         
00321         if(gWindow != NULL)
00322         {
00323                 DisposeWindow(gWindow);
00324         }
00325         
00326         if(nib != NULL)
00327         {
00328                 DisposeNibReference(nib);
00329         }
00330         
00331         return true;
00332 }
00333 
00334 void LLCrashLoggerMac::updateApplication(LLString message)
00335 {
00336         LLCrashLogger::updateApplication();
00337 }
00338 
00339 bool LLCrashLoggerMac::cleanup()
00340 {
00341         return true;
00342 }

Generated on Fri May 16 08:33:12 2008 for SecondLife by  doxygen 1.5.5