00001
00032
00033
00034
00035
00036 #include "stdafx.h"
00037
00038 #include "linden_common.h"
00039 #include "llcontrol.h"
00040 #include "resource.h"
00041
00042 #include <direct.h>
00043 #include <sys/types.h>
00044 #include <sys/stat.h>
00045 #include <wininet.h>
00046
00047 #include "indra_constants.h"
00048 #include "llerror.h"
00049 #include "lltimer.h"
00050 #include "lldir.h"
00051
00052 #include "llstring.h"
00053 #include "lldxhardware.h"
00054
00055 LLControlGroup gCrashSettings;
00056
00057
00058 #define MAX_LOADSTRING 100
00059 const char* const SETTINGS_FILE_HEADER = "version";
00060 const S32 SETTINGS_FILE_VERSION = 101;
00061
00062
00063 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
00064 bool handle_button_click(WORD button_id);
00065 S32 load_crash_behavior_setting();
00066 bool save_crash_behavior_setting(S32 crash_behavior);
00067 void send_crash_report();
00068 void write_debug(const char *str);
00069 void write_debug(std::string& str);
00070
00071
00072 HINSTANCE hInst= NULL;
00073 TCHAR szTitle[MAX_LOADSTRING];
00074 TCHAR szWindowClass[MAX_LOADSTRING];
00075
00076 LLString gUserText;
00077 time_t gStartTime = 0;
00078 HWND gHwndReport = NULL;
00079 HWND gHwndProgress = NULL;
00080 HCURSOR gCursorArrow = NULL;
00081 HCURSOR gCursorWait = NULL;
00082 BOOL gFirstDialog = TRUE;
00083 BOOL gCrashInPreviousExec = FALSE;
00084 FILE *gDebugFile = NULL;
00085 LLString gUserserver;
00086 WCHAR gProductName[512];
00087
00088
00089
00090
00091
00092
00093 void ProcessCaption(HWND hWnd)
00094 {
00095 TCHAR templateText[1024];
00096 TCHAR finalText[2048];
00097 GetWindowText(hWnd, templateText, sizeof(templateText));
00098 swprintf(finalText, templateText, gProductName);
00099 SetWindowText(hWnd, finalText);
00100 }
00101
00102
00103
00104 void ProcessDlgItemText(HWND hWnd, int nIDDlgItem)
00105 {
00106 TCHAR templateText[1024];
00107 TCHAR finalText[2048];
00108 GetDlgItemText(hWnd, nIDDlgItem, templateText, sizeof(templateText));
00109 swprintf(finalText, templateText, gProductName);
00110 SetDlgItemText(hWnd, nIDDlgItem, finalText);
00111 }
00112
00113 int APIENTRY WinMain(HINSTANCE hInstance,
00114 HINSTANCE hPrevInstance,
00115 LPSTR lpCmdLine,
00116 int nCmdShow)
00117 {
00118 llinfos << "Starting crash reporter" << llendl;
00119
00120 gDirUtilp->initAppDirs("SecondLife");
00121
00122
00123 swprintf(gProductName, L"Second Life");
00124
00125 gCrashSettings.declareS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ASK, "Controls behavior when viewer crashes "
00126 "(0 = ask before sending crash report, 1 = always send crash report, 2 = never send crash report)");
00127
00128 llinfos << "Loading crash behavior setting" << llendl;
00129 S32 crash_behavior = load_crash_behavior_setting();
00130
00131
00132
00133
00134
00135
00136
00137 llinfos << "Processing command line" << llendl;
00138 LPSTR cmd_line_including_exe_name = GetCommandLineA();
00139
00140 const S32 MAX_ARGS = 100;
00141 int argc = 0;
00142 char *argv[MAX_ARGS];
00143
00144 char *token = NULL;
00145 if( cmd_line_including_exe_name[0] == '\"' )
00146 {
00147
00148 token = strtok( cmd_line_including_exe_name, "\"" );
00149 argv[argc++] = token;
00150 token = strtok( NULL, " \t," );
00151 }
00152 else
00153 {
00154
00155 token = strtok( cmd_line_including_exe_name, " \t," );
00156 }
00157
00158 while( (token != NULL) && (argc < MAX_ARGS) )
00159 {
00160 argv[argc++] = token;
00161
00162 if (*(token + strlen(token) + 1) == '\"')
00163 {
00164 token = strtok( NULL, "\"");
00165 }
00166 else
00167 {
00168 token = strtok( NULL, " \t," );
00169 }
00170 }
00171
00172 S32 i;
00173 for (i=0; i<argc; i++)
00174 {
00175 if(!strcmp(argv[i], "-previous"))
00176 {
00177 llinfos << "Previous execution did not remove SecondLife.exec_marker" << llendl;
00178 gCrashInPreviousExec = TRUE;
00179 }
00180
00181 if(!strcmp(argv[i], "-dialog"))
00182 {
00183 llinfos << "Show the user dialog" << llendl;
00184 crash_behavior = CRASH_BEHAVIOR_ASK;
00185 }
00186
00187 if(!strcmp(argv[i], "-user"))
00188 {
00189 if ((i + 1) < argc)
00190 {
00191 i++;
00192 gUserserver = argv[i];
00193 llinfos << "Got userserver " << gUserserver << llendl;
00194 }
00195 }
00196
00197 if(!strcmp(argv[i], "-name"))
00198 {
00199 if ((i + 1) < argc)
00200 {
00201 i++;
00202
00203 mbstowcs(gProductName, argv[i], sizeof(gProductName)/sizeof(gProductName[0]));
00204 gProductName[ sizeof(gProductName)/sizeof(gProductName[0]) - 1 ] = 0;
00205 llinfos << "Got product name " << argv[i] << llendl;
00206 }
00207 }
00208 }
00209
00210
00211 if (crash_behavior == CRASH_BEHAVIOR_NEVER_SEND)
00212 {
00213 llinfos << "Crash behavior is never_send, quitting" << llendl;
00214 return 0;
00215 }
00216
00217
00218 time(&gStartTime);
00219
00220 llinfos << "Loading dialogs" << llendl;
00221
00222
00223 hInst = hInstance;
00224
00225
00226 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
00227 LoadString(hInstance, IDC_WIN_CRASH_LOGGER, szWindowClass, MAX_LOADSTRING);
00228
00229 gCursorArrow = LoadCursor(NULL, IDC_ARROW);
00230 gCursorWait = LoadCursor(NULL, IDC_WAIT);
00231
00232
00233 WNDCLASS wndclass;
00234 wndclass.style = CS_HREDRAW | CS_VREDRAW;
00235 wndclass.lpfnWndProc = WndProc;
00236 wndclass.cbClsExtra = 0;
00237 wndclass.cbWndExtra = DLGWINDOWEXTRA;
00238 wndclass.hInstance = hInst;
00239 wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE( IDI_WIN_CRASH_LOGGER ) );
00240 wndclass.hCursor = gCursorArrow;
00241 wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
00242 wndclass.lpszMenuName = NULL;
00243 wndclass.lpszClassName = szWindowClass;
00244 RegisterClass( &wndclass );
00245
00246
00247
00248
00249
00250 gHwndProgress = CreateDialog(hInst, MAKEINTRESOURCE(IDD_PROGRESS), 0, NULL);
00251 ProcessCaption(gHwndProgress);
00252 ShowWindow(gHwndProgress, SW_HIDE );
00253
00254 if (crash_behavior == CRASH_BEHAVIOR_ALWAYS_SEND)
00255 {
00256 ShowWindow(gHwndProgress, SW_SHOW );
00257 send_crash_report();
00258 return 0;
00259 }
00260
00261 if (crash_behavior == CRASH_BEHAVIOR_ASK)
00262 {
00263 gHwndReport = CreateDialog(hInst, MAKEINTRESOURCE(IDD_REPORT), 0, NULL);
00264
00265
00266 ProcessCaption(gHwndReport);
00267 ProcessDlgItemText(gHwndReport, IDC_STATIC_WHATINFO);
00268 ProcessDlgItemText(gHwndReport, IDC_STATIC_MOTIVATION);
00269
00270
00271 WCHAR header[2048];
00272 if (gCrashInPreviousExec)
00273 {
00274 swprintf(header, L"%s appears to have crashed or frozen the last time it ran.", gProductName);
00275 }
00276 else
00277 {
00278 swprintf(header, L"%s appears to have crashed.", gProductName);
00279 }
00280 SetDlgItemText(gHwndReport, IDC_STATIC_HEADER, header);
00281 ShowWindow(gHwndReport, SW_SHOW );
00282
00283 MSG msg;
00284 while (GetMessage(&msg, NULL, 0, 0))
00285 {
00286 TranslateMessage(&msg);
00287 DispatchMessage(&msg);
00288 }
00289 return msg.wParam;
00290 }
00291 else
00292 {
00293 llwarns << "Unknown crash behavior " << crash_behavior << llendl;
00294 return 1;
00295 }
00296 }
00297
00298
00299 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
00300 {
00301 switch( message )
00302 {
00303 case WM_CREATE:
00304 return 0;
00305
00306 case WM_COMMAND:
00307 if( gFirstDialog )
00308 {
00309 WORD button_id = LOWORD(wParam);
00310 bool handled = handle_button_click(button_id);
00311 if (handled)
00312 {
00313 return 0;
00314 }
00315 }
00316 break;
00317
00318 case WM_DESTROY:
00319
00320 PostQuitMessage(0);
00321 return 0;
00322 }
00323
00324 return DefWindowProc(hwnd, message, wParam, lParam);
00325 }
00326
00327
00328 bool handle_button_click(WORD button_id)
00329 {
00330
00331 if (button_id != IDOK
00332 && button_id != IDCANCEL)
00333 {
00334 return false;
00335 }
00336
00337
00338 S32 crash_behavior = CRASH_BEHAVIOR_ASK;
00339 LRESULT result = SendDlgItemMessage(gHwndReport, IDC_CHECK_AUTO, BM_GETCHECK, 0, 0);
00340 if (result == BST_CHECKED)
00341 {
00342 if (button_id == IDOK)
00343 {
00344 crash_behavior = CRASH_BEHAVIOR_ALWAYS_SEND;
00345 }
00346 else if (button_id == IDCANCEL)
00347 {
00348 crash_behavior = CRASH_BEHAVIOR_NEVER_SEND;
00349 }
00350 }
00351 bool success = save_crash_behavior_setting(crash_behavior);
00352 if (!success)
00353 {
00354 llwarns << "Failed to save crash settings" << llendl;
00355 }
00356
00357
00358 gFirstDialog = FALSE;
00359
00360
00361 if (button_id == IDOK)
00362 {
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 ShowWindow(gHwndProgress, SW_SHOW);
00376
00377 ShowWindow(gHwndReport, SW_HIDE);
00378
00379 send_crash_report();
00380 }
00381
00382
00383 PostQuitMessage(0);
00384
00385 return true;
00386 }
00387
00388
00389 class LLFileEncoder
00390 {
00391 public:
00392 LLFileEncoder(const char *formname, const char *filename);
00393 ~LLFileEncoder();
00394
00395 BOOL isValid() const { return mIsValid; }
00396 LLString encodeURL(const S32 max_length = 0);
00397 public:
00398 BOOL mIsValid;
00399 LLString mFilename;
00400 LLString mFormname;
00401 S32 mBufLength;
00402 U8 *mBuf;
00403 };
00404
00405 LLString encode_string(const char *formname, const LLString &str);
00406
00407 void update_messages()
00408 {
00409 MSG msg;
00410 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
00411 {
00412 if (msg.message == WM_QUIT)
00413 {
00414 exit(0);
00415 }
00416 TranslateMessage(&msg);
00417 DispatchMessage(&msg);
00418 }
00419 }
00420
00421 void sleep_and_pump_messages( U32 seconds )
00422 {
00423 const U32 CYCLES_PER_SECOND = 10;
00424 U32 cycles = seconds * CYCLES_PER_SECOND;
00425 while( cycles-- )
00426 {
00427 update_messages();
00428 ms_sleep(1000 / CYCLES_PER_SECOND);
00429 }
00430 }
00431
00432
00433 void show_progress(const char* message)
00434 {
00435 std::wstring msg = wstring_to_utf16str(utf8str_to_wstring(message));
00436 if (gHwndProgress)
00437 {
00438 SendDlgItemMessage(gHwndProgress,
00439 IDC_LOG,
00440 WM_SETTEXT,
00441 FALSE,
00442 (LPARAM)msg.c_str());
00443 }
00444 }
00445
00446
00447 void send_crash_report()
00448 {
00449 update_messages();
00450 show_progress("Starting up...");
00451 update_messages();
00452
00453 const S32 SL_MAX_SIZE = 100000;
00454
00455 update_messages();
00456
00457
00458 std::string db_file_name;
00459 std::string sl_file_name;
00460 std::string md_file_name;
00461 std::string st_file_name;
00462 std::string si_file_name;
00463 std::string ml_file_name;
00464
00465 LLFileEncoder *db_filep = NULL;
00466 LLFileEncoder *sl_filep = NULL;
00467 LLFileEncoder *st_filep = NULL;
00468 LLFileEncoder *md_filep = NULL;
00469 LLFileEncoder *si_filep = NULL;
00470 LLFileEncoder *ml_filep = NULL;
00471
00472
00473 SetCursor(gCursorWait);
00474
00475
00476
00477 update_messages();
00478 show_progress("Detecting hardware, please wait...");
00479 update_messages();
00480 gDXHardware.setWriteDebugFunc(write_debug);
00481 gDXHardware.getInfo(FALSE);
00482 update_messages();
00483 gDXHardware.dumpDevices();
00484 update_messages();
00485 fclose(gDebugFile);
00486 gDebugFile = NULL;
00487
00488
00489 SetCursor(gCursorArrow);
00490
00492
00493
00494
00495
00496
00497
00498 db_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
00499 db_filep = new LLFileEncoder("DB", db_file_name.c_str());
00500
00501
00502
00503 char tmp_sl_name[256];
00504 tmp_sl_name[0] = '\0';
00505
00506 update_messages();
00507 show_progress("Looking for files...");
00508 update_messages();
00509
00510
00511 if (db_filep->isValid())
00512 {
00513 sscanf(
00514 (const char*)db_filep->mBuf,
00515 "SL Log: %255[^\r\n]",
00516 tmp_sl_name);
00517 }
00518 else
00519 {
00520 delete db_filep;
00521 db_filep = NULL;
00522 }
00523
00524 if (gCrashInPreviousExec)
00525 {
00526
00527
00528 sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old");
00529 }
00530 else if (tmp_sl_name[0])
00531 {
00532
00533 sl_file_name = tmp_sl_name;
00534 llinfos << "Using log file from debug log " << sl_file_name << llendl;
00535 }
00536 else
00537 {
00538
00539 sl_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.log");
00540 }
00541
00542
00543 sl_filep = new LLFileEncoder("SL", sl_file_name.c_str());
00544 if (!sl_filep->isValid())
00545 {
00546 delete sl_filep;
00547 sl_filep = NULL;
00548 }
00549
00550 update_messages();
00551 show_progress("Looking for stats file...");
00552 update_messages();
00553
00554 st_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stats.log");
00555 st_filep = new LLFileEncoder("ST", st_file_name.c_str());
00556 if (!st_filep->isValid())
00557 {
00558 delete st_filep;
00559 st_filep = NULL;
00560 }
00561
00562 si_file_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings.ini");
00563 si_filep = new LLFileEncoder("SI", si_file_name.c_str());
00564 if (!si_filep->isValid())
00565 {
00566 delete si_filep;
00567 si_filep = NULL;
00568 }
00569
00570
00571 md_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.dmp");
00572 md_filep = new LLFileEncoder("MD", md_file_name.c_str());
00573 if (!md_filep->isValid())
00574 {
00575 delete md_filep;
00576 md_filep = NULL;
00577 }
00578
00579
00580 ml_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"message.log");
00581 ml_filep = new LLFileEncoder("ML", ml_file_name.c_str());
00582 if (!ml_filep->isValid())
00583 {
00584 delete ml_filep;
00585 ml_filep = NULL;
00586 }
00587
00588 LLString post_data;
00589 LLString tmp_url_buf;
00590
00591
00592 tmp_url_buf = encode_string("USER", gUserserver);
00593 post_data += tmp_url_buf;
00594 llinfos << "PostData:" << post_data << llendl;
00595
00596 if (gCrashInPreviousExec)
00597 {
00598 post_data.append(1, '&');
00599 tmp_url_buf = encode_string("EF", "Y");
00600 post_data += tmp_url_buf;
00601 }
00602
00603 update_messages();
00604 show_progress("Encoding data");
00605 update_messages();
00606 if (db_filep)
00607 {
00608 post_data.append(1, '&');
00609 tmp_url_buf = db_filep->encodeURL();
00610 post_data += tmp_url_buf;
00611 llinfos << "Sending DB log file" << llendl;
00612 }
00613 else
00614 {
00615 llinfos << "Not sending DB log file" << llendl;
00616 }
00617 show_progress("Encoding data.");
00618 update_messages();
00619
00620 if (sl_filep)
00621 {
00622 post_data.append(1, '&');
00623 tmp_url_buf = sl_filep->encodeURL(SL_MAX_SIZE);
00624 post_data += tmp_url_buf;
00625 llinfos << "Sending SL log file" << llendl;
00626 }
00627 else
00628 {
00629 llinfos << "Not sending SL log file" << llendl;
00630 }
00631 show_progress("Encoding data..");
00632 update_messages();
00633
00634 if (st_filep)
00635 {
00636 post_data.append(1, '&');
00637 tmp_url_buf = st_filep->encodeURL(SL_MAX_SIZE);
00638 post_data += tmp_url_buf;
00639 llinfos << "Sending stats log file" << llendl;
00640 }
00641 else
00642 {
00643 llinfos << "Not sending stats log file" << llendl;
00644 }
00645 show_progress("Encoding data...");
00646 update_messages();
00647
00648 if (md_filep)
00649 {
00650 post_data.append(1, '&');
00651 tmp_url_buf = md_filep->encodeURL();
00652 post_data += tmp_url_buf;
00653 llinfos << "Sending minidump log file" << llendl;
00654 }
00655 else
00656 {
00657 llinfos << "Not sending minidump log file" << llendl;
00658 }
00659 show_progress("Encoding data....");
00660 update_messages();
00661
00662 if (si_filep)
00663 {
00664 post_data.append(1, '&');
00665 tmp_url_buf = si_filep->encodeURL();
00666 post_data += tmp_url_buf;
00667 llinfos << "Sending settings log file" << llendl;
00668 }
00669 else
00670 {
00671 llinfos << "Not sending settings.ini file" << llendl;
00672 }
00673 show_progress("Encoding data....");
00674 update_messages();
00675
00676 if (ml_filep)
00677 {
00678 post_data.append(1, '&');
00679 tmp_url_buf = ml_filep->encodeURL(SL_MAX_SIZE);
00680 post_data += tmp_url_buf;
00681 llinfos << "Sending message log file" << llendl;
00682 }
00683 else
00684 {
00685 llinfos << "Not sending message.log file" << llendl;
00686 }
00687 show_progress("Encoding data....");
00688 update_messages();
00689
00690 if (gUserText.size())
00691 {
00692 post_data.append(1, '&');
00693 tmp_url_buf = encode_string("UN", gUserText);
00694 post_data += tmp_url_buf;
00695 }
00696
00697 delete db_filep;
00698 db_filep = NULL;
00699 delete sl_filep;
00700 sl_filep = NULL;
00701 delete md_filep;
00702 md_filep = NULL;
00703
00704
00705 const S32 BUFSIZE = 65536;
00706 HINTERNET hinet, hsession, hrequest;
00707 char data[BUFSIZE];
00708 unsigned long bytes_read;
00709
00710 llinfos << "Connecting to crash report server" << llendl;
00711 update_messages();
00712 show_progress("Connecting to server...");
00713 update_messages();
00714
00715
00716 hinet = InternetOpen(L"LindenCrashReporter", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
00717 if (hinet == NULL)
00718 {
00719 llinfos << "Couldn't open connection" << llendl;
00720 sleep_and_pump_messages( 5 );
00721
00722 }
00723
00724 hsession = InternetConnect(hinet,
00725 L"sl.daleglass.net",
00726 INTERNET_DEFAULT_HTTP_PORT,
00727 NULL,
00728 NULL,
00729 INTERNET_SERVICE_HTTP,
00730 NULL,
00731 NULL);
00732
00733 if (!hsession)
00734 {
00735 llinfos << "Couldn't talk to crash report server" << llendl;
00736 }
00737
00738 hrequest = HttpOpenRequest(hsession, L"POST", L"/viewer_crash_reporter", NULL, L"", NULL, 0, 0);
00739 if (!hrequest)
00740 {
00741 llinfos << "Couldn't open crash report URL!" << llendl;
00742 }
00743
00744 llinfos << "Transmitting data" << llendl;
00745 llinfos << "Bytes: " << (post_data.size()) << llendl;
00746
00747 update_messages();
00748 show_progress("Transmitting data...");
00749 update_messages();
00750
00751 BOOL ok = HttpSendRequest(hrequest, NULL, 0, (void *)(post_data.c_str()), post_data.size());
00752 if (!ok)
00753 {
00754 llinfos << "Error posting data!" << llendl;
00755 sleep_and_pump_messages( 5 );
00756 }
00757
00758 llinfos << "Response from crash report server:" << llendl;
00759 do
00760 {
00761 if (InternetReadFile(hrequest, data, BUFSIZE, &bytes_read))
00762 {
00763 if (bytes_read == 0)
00764 {
00765
00766
00767 break;
00768 }
00769 else
00770 {
00771 data[bytes_read] = 0;
00772 llinfos << data << llendl;
00773 }
00774 }
00775 else
00776 {
00777 llinfos << "Couldn't read file!" << llendl;
00778 sleep_and_pump_messages( 5 );
00779
00780 }
00781 } while(TRUE);
00782
00783 InternetCloseHandle(hrequest);
00784 InternetCloseHandle(hsession);
00785 InternetCloseHandle(hinet);
00786 update_messages();
00787 show_progress("Done.");
00788 sleep_and_pump_messages( 3 );
00789
00790 }
00791
00792 LLFileEncoder::LLFileEncoder(const char *form_name, const char *filename)
00793 {
00794 mFormname = form_name;
00795 mFilename = filename;
00796 mIsValid = FALSE;
00797 mBuf = NULL;
00798
00799 int res;
00800
00801 llstat stat_data;
00802 res = LLFile::stat(mFilename.c_str(), &stat_data);
00803 if (res)
00804 {
00805 llwarns << "File " << mFilename << " is missing!" << llendl;
00806 return;
00807 }
00808
00809 FILE *fp = NULL;
00810 S32 buf_size = 0;
00811 S32 count = 0;
00812 while (count < 5)
00813 {
00814 buf_size = stat_data.st_size;
00815 fp = LLFile::fopen(mFilename.c_str(), "rb");
00816 if (!fp)
00817 {
00818 llwarns << "Can't open file " << mFilename << ", wait for a second" << llendl;
00819
00820 count++;
00821 ms_sleep(1000);
00822 }
00823 else
00824 {
00825 break;
00826 }
00827 }
00828 if (!fp)
00829 {
00830 return;
00831 }
00832 U8 *buf = new U8[buf_size + 1];
00833 fread(buf, 1, buf_size, fp);
00834 fclose(fp);
00835
00836 mBuf = buf;
00837 mBufLength = buf_size;
00838
00839 mIsValid = TRUE;
00840 }
00841
00842 LLFileEncoder::~LLFileEncoder()
00843 {
00844 if (mBuf)
00845 {
00846 delete mBuf;
00847 mBuf = NULL;
00848 }
00849 }
00850
00851 LLString LLFileEncoder::encodeURL(const S32 max_length)
00852 {
00853 LLString result = mFormname;
00854 result.append(1, '=');
00855
00856 S32 i = 0;
00857
00858 if (max_length)
00859 {
00860 if (mBufLength > max_length)
00861 {
00862 i = mBufLength - max_length;
00863 }
00864 }
00865
00866 S32 url_buf_size = 3*mBufLength + 1;
00867 char *url_buf = new char[url_buf_size];
00868
00869 S32 cur_pos = 0;
00870 for (; i < mBufLength; i++)
00871 {
00872 S32 byte_val = mBuf[i];
00873 sprintf(url_buf + cur_pos, "%%%02x", byte_val);
00874 cur_pos += 3;
00875 }
00876 url_buf[i*3] = 0;
00877
00878 result.append(url_buf);
00879 delete[] url_buf;
00880 return result;
00881 }
00882
00883 LLString encode_string(const char *formname, const LLString &str)
00884 {
00885 LLString result = formname;
00886 result.append(1, '=');
00887
00888 S32 buf_size = str.size();
00889 S32 url_buf_size = 3*str.size() + 1;
00890 char *url_buf = new char[url_buf_size];
00891
00892 S32 cur_pos = 0;
00893 S32 i;
00894 for (i = 0; i < buf_size; i++)
00895 {
00896 sprintf(url_buf + cur_pos, "%%%02x", str[i]);
00897 cur_pos += 3;
00898 }
00899 url_buf[i*3] = 0;
00900
00901 result.append(url_buf);
00902 delete[] url_buf;
00903 return result;
00904 }
00905
00906 void write_debug(const char *str)
00907 {
00908 if (!gDebugFile)
00909 {
00910 std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
00911 llinfos << "Opening debug file " << debug_filename << llendl;
00912 gDebugFile = LLFile::fopen(debug_filename.c_str(), "a+");
00913 if (!gDebugFile)
00914 {
00915 fprintf(stderr, "Couldn't open %s: debug log to stderr instead.\n", debug_filename.c_str());
00916 gDebugFile = stderr;
00917 }
00918 }
00919 fprintf(gDebugFile, str);
00920 fflush(gDebugFile);
00921 }
00922
00923 void write_debug(std::string& str)
00924 {
00925 write_debug(str.c_str());
00926 }
00927
00928 S32 load_crash_behavior_setting()
00929 {
00930 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
00931
00932 gCrashSettings.loadFromFile(filename);
00933
00934 S32 value = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
00935
00936 if (value < CRASH_BEHAVIOR_ASK || CRASH_BEHAVIOR_NEVER_SEND < value) return CRASH_BEHAVIOR_ASK;
00937
00938 return value;
00939 }
00940
00941 bool save_crash_behavior_setting(S32 crash_behavior)
00942 {
00943 if (crash_behavior < CRASH_BEHAVIOR_ASK) return false;
00944 if (crash_behavior > CRASH_BEHAVIOR_NEVER_SEND) return false;
00945
00946 gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, crash_behavior);
00947 std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
00948
00949 gCrashSettings.saveToFile(filename, FALSE);
00950
00951 return true;
00952 }