toolkit/crashreporter/client/crashreporter.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "crashreporter.h"
michael@0 7
michael@0 8 #ifdef _MSC_VER
michael@0 9 // Disable exception handler warnings.
michael@0 10 # pragma warning( disable : 4530 )
michael@0 11 #endif
michael@0 12
michael@0 13 #include <fstream>
michael@0 14 #include <sstream>
michael@0 15 #include <memory>
michael@0 16 #include <time.h>
michael@0 17 #include <stdlib.h>
michael@0 18 #include <string.h>
michael@0 19 #include "mozilla/NullPtr.h"
michael@0 20
michael@0 21 using std::string;
michael@0 22 using std::istream;
michael@0 23 using std::ifstream;
michael@0 24 using std::istringstream;
michael@0 25 using std::ostringstream;
michael@0 26 using std::ostream;
michael@0 27 using std::ofstream;
michael@0 28 using std::vector;
michael@0 29 using std::auto_ptr;
michael@0 30
michael@0 31 namespace CrashReporter {
michael@0 32
michael@0 33 StringTable gStrings;
michael@0 34 string gSettingsPath;
michael@0 35 int gArgc;
michael@0 36 char** gArgv;
michael@0 37
michael@0 38 static auto_ptr<ofstream> gLogStream(nullptr);
michael@0 39 static string gReporterDumpFile;
michael@0 40 static string gExtraFile;
michael@0 41
michael@0 42 static string kExtraDataExtension = ".extra";
michael@0 43
michael@0 44 void UIError(const string& message)
michael@0 45 {
michael@0 46 string errorMessage;
michael@0 47 if (!gStrings[ST_CRASHREPORTERERROR].empty()) {
michael@0 48 char buf[2048];
michael@0 49 UI_SNPRINTF(buf, 2048,
michael@0 50 gStrings[ST_CRASHREPORTERERROR].c_str(),
michael@0 51 message.c_str());
michael@0 52 errorMessage = buf;
michael@0 53 } else {
michael@0 54 errorMessage = message;
michael@0 55 }
michael@0 56
michael@0 57 UIError_impl(errorMessage);
michael@0 58 }
michael@0 59
michael@0 60 static string Unescape(const string& str)
michael@0 61 {
michael@0 62 string ret;
michael@0 63 for (string::const_iterator iter = str.begin();
michael@0 64 iter != str.end();
michael@0 65 iter++) {
michael@0 66 if (*iter == '\\') {
michael@0 67 iter++;
michael@0 68 if (*iter == '\\'){
michael@0 69 ret.push_back('\\');
michael@0 70 } else if (*iter == 'n') {
michael@0 71 ret.push_back('\n');
michael@0 72 } else if (*iter == 't') {
michael@0 73 ret.push_back('\t');
michael@0 74 }
michael@0 75 } else {
michael@0 76 ret.push_back(*iter);
michael@0 77 }
michael@0 78 }
michael@0 79
michael@0 80 return ret;
michael@0 81 }
michael@0 82
michael@0 83 static string Escape(const string& str)
michael@0 84 {
michael@0 85 string ret;
michael@0 86 for (string::const_iterator iter = str.begin();
michael@0 87 iter != str.end();
michael@0 88 iter++) {
michael@0 89 if (*iter == '\\') {
michael@0 90 ret += "\\\\";
michael@0 91 } else if (*iter == '\n') {
michael@0 92 ret += "\\n";
michael@0 93 } else if (*iter == '\t') {
michael@0 94 ret += "\\t";
michael@0 95 } else {
michael@0 96 ret.push_back(*iter);
michael@0 97 }
michael@0 98 }
michael@0 99
michael@0 100 return ret;
michael@0 101 }
michael@0 102
michael@0 103 bool ReadStrings(istream& in, StringTable& strings, bool unescape)
michael@0 104 {
michael@0 105 string currentSection;
michael@0 106 while (!in.eof()) {
michael@0 107 string line;
michael@0 108 std::getline(in, line);
michael@0 109 int sep = line.find('=');
michael@0 110 if (sep >= 0) {
michael@0 111 string key, value;
michael@0 112 key = line.substr(0, sep);
michael@0 113 value = line.substr(sep + 1);
michael@0 114 if (unescape)
michael@0 115 value = Unescape(value);
michael@0 116 strings[key] = value;
michael@0 117 }
michael@0 118 }
michael@0 119
michael@0 120 return true;
michael@0 121 }
michael@0 122
michael@0 123 bool ReadStringsFromFile(const string& path,
michael@0 124 StringTable& strings,
michael@0 125 bool unescape)
michael@0 126 {
michael@0 127 ifstream* f = UIOpenRead(path);
michael@0 128 bool success = false;
michael@0 129 if (f->is_open()) {
michael@0 130 success = ReadStrings(*f, strings, unescape);
michael@0 131 f->close();
michael@0 132 }
michael@0 133
michael@0 134 delete f;
michael@0 135 return success;
michael@0 136 }
michael@0 137
michael@0 138 bool WriteStrings(ostream& out,
michael@0 139 const string& header,
michael@0 140 StringTable& strings,
michael@0 141 bool escape)
michael@0 142 {
michael@0 143 out << "[" << header << "]" << std::endl;
michael@0 144 for (StringTable::iterator iter = strings.begin();
michael@0 145 iter != strings.end();
michael@0 146 iter++) {
michael@0 147 out << iter->first << "=";
michael@0 148 if (escape)
michael@0 149 out << Escape(iter->second);
michael@0 150 else
michael@0 151 out << iter->second;
michael@0 152
michael@0 153 out << std::endl;
michael@0 154 }
michael@0 155
michael@0 156 return true;
michael@0 157 }
michael@0 158
michael@0 159 bool WriteStringsToFile(const string& path,
michael@0 160 const string& header,
michael@0 161 StringTable& strings,
michael@0 162 bool escape)
michael@0 163 {
michael@0 164 ofstream* f = UIOpenWrite(path.c_str());
michael@0 165 bool success = false;
michael@0 166 if (f->is_open()) {
michael@0 167 success = WriteStrings(*f, header, strings, escape);
michael@0 168 f->close();
michael@0 169 }
michael@0 170
michael@0 171 delete f;
michael@0 172 return success;
michael@0 173 }
michael@0 174
michael@0 175 void LogMessage(const std::string& message)
michael@0 176 {
michael@0 177 if (gLogStream.get()) {
michael@0 178 char date[64];
michael@0 179 time_t tm;
michael@0 180 time(&tm);
michael@0 181 if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0)
michael@0 182 date[0] = '\0';
michael@0 183 (*gLogStream) << "[" << date << "] " << message << std::endl;
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 static void OpenLogFile()
michael@0 188 {
michael@0 189 string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log";
michael@0 190 gLogStream.reset(UIOpenWrite(logPath.c_str(), true));
michael@0 191 }
michael@0 192
michael@0 193 static bool ReadConfig()
michael@0 194 {
michael@0 195 string iniPath;
michael@0 196 if (!UIGetIniPath(iniPath))
michael@0 197 return false;
michael@0 198
michael@0 199 if (!ReadStringsFromFile(iniPath, gStrings, true))
michael@0 200 return false;
michael@0 201
michael@0 202 // See if we have a string override file, if so process it
michael@0 203 char* overrideEnv = getenv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE");
michael@0 204 if (overrideEnv && *overrideEnv && UIFileExists(overrideEnv))
michael@0 205 ReadStringsFromFile(overrideEnv, gStrings, true);
michael@0 206
michael@0 207 return true;
michael@0 208 }
michael@0 209
michael@0 210 static string GetExtraDataFilename(const string& dumpfile)
michael@0 211 {
michael@0 212 string filename(dumpfile);
michael@0 213 int dot = filename.rfind('.');
michael@0 214 if (dot < 0)
michael@0 215 return "";
michael@0 216
michael@0 217 filename.replace(dot, filename.length() - dot, kExtraDataExtension);
michael@0 218 return filename;
michael@0 219 }
michael@0 220
michael@0 221 static string Basename(const string& file)
michael@0 222 {
michael@0 223 int slashIndex = file.rfind(UI_DIR_SEPARATOR);
michael@0 224 if (slashIndex >= 0)
michael@0 225 return file.substr(slashIndex + 1);
michael@0 226 else
michael@0 227 return file;
michael@0 228 }
michael@0 229
michael@0 230 static bool MoveCrashData(const string& toDir,
michael@0 231 string& dumpfile,
michael@0 232 string& extrafile)
michael@0 233 {
michael@0 234 if (!UIEnsurePathExists(toDir)) {
michael@0 235 UIError(gStrings[ST_ERROR_CREATEDUMPDIR]);
michael@0 236 return false;
michael@0 237 }
michael@0 238
michael@0 239 string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile);
michael@0 240 string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile);
michael@0 241
michael@0 242 if (!UIMoveFile(dumpfile, newDump)) {
michael@0 243 UIError(gStrings[ST_ERROR_DUMPFILEMOVE]);
michael@0 244 return false;
michael@0 245 }
michael@0 246
michael@0 247 if (!UIMoveFile(extrafile, newExtra)) {
michael@0 248 UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]);
michael@0 249 return false;
michael@0 250 }
michael@0 251
michael@0 252 dumpfile = newDump;
michael@0 253 extrafile = newExtra;
michael@0 254
michael@0 255 return true;
michael@0 256 }
michael@0 257
michael@0 258 static bool AddSubmittedReport(const string& serverResponse)
michael@0 259 {
michael@0 260 StringTable responseItems;
michael@0 261 istringstream in(serverResponse);
michael@0 262 ReadStrings(in, responseItems, false);
michael@0 263
michael@0 264 if (responseItems.find("StopSendingReportsFor") != responseItems.end()) {
michael@0 265 // server wants to tell us to stop sending reports for a certain version
michael@0 266 string reportPath =
michael@0 267 gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" +
michael@0 268 responseItems["StopSendingReportsFor"];
michael@0 269
michael@0 270 ofstream* reportFile = UIOpenWrite(reportPath);
michael@0 271 if (reportFile->is_open()) {
michael@0 272 // don't really care about the contents
michael@0 273 *reportFile << 1 << "\n";
michael@0 274 reportFile->close();
michael@0 275 }
michael@0 276 delete reportFile;
michael@0 277 }
michael@0 278
michael@0 279 if (responseItems.find("Discarded") != responseItems.end()) {
michael@0 280 // server discarded this report... save it so the user can resubmit it
michael@0 281 // manually
michael@0 282 return false;
michael@0 283 }
michael@0 284
michael@0 285 if (responseItems.find("CrashID") == responseItems.end())
michael@0 286 return false;
michael@0 287
michael@0 288 string submittedDir =
michael@0 289 gSettingsPath + UI_DIR_SEPARATOR + "submitted";
michael@0 290 if (!UIEnsurePathExists(submittedDir)) {
michael@0 291 return false;
michael@0 292 }
michael@0 293
michael@0 294 string path = submittedDir + UI_DIR_SEPARATOR +
michael@0 295 responseItems["CrashID"] + ".txt";
michael@0 296
michael@0 297 ofstream* file = UIOpenWrite(path);
michael@0 298 if (!file->is_open()) {
michael@0 299 delete file;
michael@0 300 return false;
michael@0 301 }
michael@0 302
michael@0 303 char buf[1024];
michael@0 304 UI_SNPRINTF(buf, 1024,
michael@0 305 gStrings["CrashID"].c_str(),
michael@0 306 responseItems["CrashID"].c_str());
michael@0 307 *file << buf << "\n";
michael@0 308
michael@0 309 if (responseItems.find("ViewURL") != responseItems.end()) {
michael@0 310 UI_SNPRINTF(buf, 1024,
michael@0 311 gStrings["CrashDetailsURL"].c_str(),
michael@0 312 responseItems["ViewURL"].c_str());
michael@0 313 *file << buf << "\n";
michael@0 314 }
michael@0 315
michael@0 316 file->close();
michael@0 317 delete file;
michael@0 318
michael@0 319 return true;
michael@0 320 }
michael@0 321
michael@0 322 void DeleteDump()
michael@0 323 {
michael@0 324 const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP");
michael@0 325 if (!noDelete || *noDelete == '\0') {
michael@0 326 if (!gReporterDumpFile.empty())
michael@0 327 UIDeleteFile(gReporterDumpFile);
michael@0 328 if (!gExtraFile.empty())
michael@0 329 UIDeleteFile(gExtraFile);
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 void SendCompleted(bool success, const string& serverResponse)
michael@0 334 {
michael@0 335 if (success) {
michael@0 336 if (AddSubmittedReport(serverResponse)) {
michael@0 337 DeleteDump();
michael@0 338 }
michael@0 339 else {
michael@0 340 string directory = gReporterDumpFile;
michael@0 341 int slashpos = directory.find_last_of("/\\");
michael@0 342 if (slashpos < 2)
michael@0 343 return;
michael@0 344 directory.resize(slashpos);
michael@0 345 UIPruneSavedDumps(directory);
michael@0 346 }
michael@0 347 }
michael@0 348 }
michael@0 349
michael@0 350 bool ShouldEnableSending()
michael@0 351 {
michael@0 352 srand(time(0));
michael@0 353 return ((rand() % 100) < MOZ_CRASHREPORTER_ENABLE_PERCENT);
michael@0 354 }
michael@0 355
michael@0 356 } // namespace CrashReporter
michael@0 357
michael@0 358 using namespace CrashReporter;
michael@0 359
michael@0 360 void RewriteStrings(StringTable& queryParameters)
michael@0 361 {
michael@0 362 // rewrite some UI strings with the values from the query parameters
michael@0 363 string product = queryParameters["ProductName"];
michael@0 364 string vendor = queryParameters["Vendor"];
michael@0 365 if (vendor.empty()) {
michael@0 366 // Assume Mozilla if no vendor is specified
michael@0 367 vendor = "Mozilla";
michael@0 368 }
michael@0 369
michael@0 370 char buf[4096];
michael@0 371 UI_SNPRINTF(buf, sizeof(buf),
michael@0 372 gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(),
michael@0 373 vendor.c_str());
michael@0 374 gStrings[ST_CRASHREPORTERTITLE] = buf;
michael@0 375
michael@0 376
michael@0 377 string str = gStrings[ST_CRASHREPORTERPRODUCTERROR];
michael@0 378 // Only do the replacement here if the string has two
michael@0 379 // format specifiers to start. Otherwise
michael@0 380 // we assume it has the product name hardcoded.
michael@0 381 string::size_type pos = str.find("%s");
michael@0 382 if (pos != string::npos)
michael@0 383 pos = str.find("%s", pos+2);
michael@0 384 if (pos != string::npos) {
michael@0 385 // Leave a format specifier for UIError to fill in
michael@0 386 UI_SNPRINTF(buf, sizeof(buf),
michael@0 387 gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(),
michael@0 388 product.c_str(),
michael@0 389 "%s");
michael@0 390 gStrings[ST_CRASHREPORTERERROR] = buf;
michael@0 391 }
michael@0 392 else {
michael@0 393 // product name is hardcoded
michael@0 394 gStrings[ST_CRASHREPORTERERROR] = str;
michael@0 395 }
michael@0 396
michael@0 397 UI_SNPRINTF(buf, sizeof(buf),
michael@0 398 gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
michael@0 399 product.c_str());
michael@0 400 gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
michael@0 401
michael@0 402 UI_SNPRINTF(buf, sizeof(buf),
michael@0 403 gStrings[ST_CHECKSUBMIT].c_str(),
michael@0 404 vendor.c_str());
michael@0 405 gStrings[ST_CHECKSUBMIT] = buf;
michael@0 406
michael@0 407 UI_SNPRINTF(buf, sizeof(buf),
michael@0 408 gStrings[ST_CHECKEMAIL].c_str(),
michael@0 409 vendor.c_str());
michael@0 410 gStrings[ST_CHECKEMAIL] = buf;
michael@0 411
michael@0 412 UI_SNPRINTF(buf, sizeof(buf),
michael@0 413 gStrings[ST_RESTART].c_str(),
michael@0 414 product.c_str());
michael@0 415 gStrings[ST_RESTART] = buf;
michael@0 416
michael@0 417 UI_SNPRINTF(buf, sizeof(buf),
michael@0 418 gStrings[ST_QUIT].c_str(),
michael@0 419 product.c_str());
michael@0 420 gStrings[ST_QUIT] = buf;
michael@0 421
michael@0 422 UI_SNPRINTF(buf, sizeof(buf),
michael@0 423 gStrings[ST_ERROR_ENDOFLIFE].c_str(),
michael@0 424 product.c_str());
michael@0 425 gStrings[ST_ERROR_ENDOFLIFE] = buf;
michael@0 426 }
michael@0 427
michael@0 428 bool CheckEndOfLifed(string version)
michael@0 429 {
michael@0 430 string reportPath =
michael@0 431 gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + version;
michael@0 432 return UIFileExists(reportPath);
michael@0 433 }
michael@0 434
michael@0 435 int main(int argc, char** argv)
michael@0 436 {
michael@0 437 gArgc = argc;
michael@0 438 gArgv = argv;
michael@0 439
michael@0 440 if (!ReadConfig()) {
michael@0 441 UIError("Couldn't read configuration.");
michael@0 442 return 0;
michael@0 443 }
michael@0 444
michael@0 445 if (!UIInit())
michael@0 446 return 0;
michael@0 447
michael@0 448 if (argc > 1) {
michael@0 449 gReporterDumpFile = argv[1];
michael@0 450 }
michael@0 451
michael@0 452 if (gReporterDumpFile.empty()) {
michael@0 453 // no dump file specified, run the default UI
michael@0 454 UIShowDefaultUI();
michael@0 455 } else {
michael@0 456 gExtraFile = GetExtraDataFilename(gReporterDumpFile);
michael@0 457 if (gExtraFile.empty()) {
michael@0 458 UIError(gStrings[ST_ERROR_BADARGUMENTS]);
michael@0 459 return 0;
michael@0 460 }
michael@0 461
michael@0 462 if (!UIFileExists(gExtraFile)) {
michael@0 463 UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]);
michael@0 464 return 0;
michael@0 465 }
michael@0 466
michael@0 467 StringTable queryParameters;
michael@0 468 if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) {
michael@0 469 UIError(gStrings[ST_ERROR_EXTRAFILEREAD]);
michael@0 470 return 0;
michael@0 471 }
michael@0 472
michael@0 473 if (queryParameters.find("ProductName") == queryParameters.end()) {
michael@0 474 UIError(gStrings[ST_ERROR_NOPRODUCTNAME]);
michael@0 475 return 0;
michael@0 476 }
michael@0 477
michael@0 478 // There is enough information in the extra file to rewrite strings
michael@0 479 // to be product specific
michael@0 480 RewriteStrings(queryParameters);
michael@0 481
michael@0 482 if (queryParameters.find("ServerURL") == queryParameters.end()) {
michael@0 483 UIError(gStrings[ST_ERROR_NOSERVERURL]);
michael@0 484 return 0;
michael@0 485 }
michael@0 486
michael@0 487 // Hopefully the settings path exists in the environment. Try that before
michael@0 488 // asking the platform-specific code to guess.
michael@0 489 #ifdef XP_WIN32
michael@0 490 static const wchar_t kDataDirKey[] = L"MOZ_CRASHREPORTER_DATA_DIRECTORY";
michael@0 491 const wchar_t *settingsPath = _wgetenv(kDataDirKey);
michael@0 492 if (settingsPath && *settingsPath) {
michael@0 493 gSettingsPath = WideToUTF8(settingsPath);
michael@0 494 }
michael@0 495 #else
michael@0 496 static const char kDataDirKey[] = "MOZ_CRASHREPORTER_DATA_DIRECTORY";
michael@0 497 const char *settingsPath = getenv(kDataDirKey);
michael@0 498 if (settingsPath && *settingsPath) {
michael@0 499 gSettingsPath = settingsPath;
michael@0 500 }
michael@0 501 #endif
michael@0 502 else {
michael@0 503 string product = queryParameters["ProductName"];
michael@0 504 string vendor = queryParameters["Vendor"];
michael@0 505 if (!UIGetSettingsPath(vendor, product, gSettingsPath)) {
michael@0 506 gSettingsPath.clear();
michael@0 507 }
michael@0 508 }
michael@0 509
michael@0 510 if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) {
michael@0 511 UIError(gStrings[ST_ERROR_NOSETTINGSPATH]);
michael@0 512 return 0;
michael@0 513 }
michael@0 514
michael@0 515 OpenLogFile();
michael@0 516
michael@0 517 if (!UIFileExists(gReporterDumpFile)) {
michael@0 518 UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]);
michael@0 519 return 0;
michael@0 520 }
michael@0 521
michael@0 522 string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
michael@0 523 if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile)) {
michael@0 524 return 0;
michael@0 525 }
michael@0 526
michael@0 527 string sendURL = queryParameters["ServerURL"];
michael@0 528 // we don't need to actually send this
michael@0 529 queryParameters.erase("ServerURL");
michael@0 530
michael@0 531 queryParameters["Throttleable"] = "1";
michael@0 532
michael@0 533 // re-set XUL_APP_FILE for xulrunner wrapped apps
michael@0 534 const char *appfile = getenv("MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE");
michael@0 535 if (appfile && *appfile) {
michael@0 536 const char prefix[] = "XUL_APP_FILE=";
michael@0 537 char *env = (char*) malloc(strlen(appfile) + strlen(prefix) + 1);
michael@0 538 if (!env) {
michael@0 539 UIError("Out of memory");
michael@0 540 return 0;
michael@0 541 }
michael@0 542 strcpy(env, prefix);
michael@0 543 strcat(env, appfile);
michael@0 544 putenv(env);
michael@0 545 free(env);
michael@0 546 }
michael@0 547
michael@0 548 vector<string> restartArgs;
michael@0 549
michael@0 550 ostringstream paramName;
michael@0 551 int i = 0;
michael@0 552 paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
michael@0 553 const char *param = getenv(paramName.str().c_str());
michael@0 554 while (param && *param) {
michael@0 555 restartArgs.push_back(param);
michael@0 556
michael@0 557 paramName.str("");
michael@0 558 paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
michael@0 559 param = getenv(paramName.str().c_str());
michael@0 560 };
michael@0 561
michael@0 562 // allow override of the server url via environment variable
michael@0 563 //XXX: remove this in the far future when our robot
michael@0 564 // masters force everyone to use XULRunner
michael@0 565 char* urlEnv = getenv("MOZ_CRASHREPORTER_URL");
michael@0 566 if (urlEnv && *urlEnv) {
michael@0 567 sendURL = urlEnv;
michael@0 568 }
michael@0 569
michael@0 570 // see if this version has been end-of-lifed
michael@0 571 if (queryParameters.find("Version") != queryParameters.end() &&
michael@0 572 CheckEndOfLifed(queryParameters["Version"])) {
michael@0 573 UIError(gStrings[ST_ERROR_ENDOFLIFE]);
michael@0 574 DeleteDump();
michael@0 575 return 0;
michael@0 576 }
michael@0 577
michael@0 578 if (!UIShowCrashUI(gReporterDumpFile, queryParameters, sendURL, restartArgs))
michael@0 579 DeleteDump();
michael@0 580 }
michael@0 581
michael@0 582 UIShutdown();
michael@0 583
michael@0 584 return 0;
michael@0 585 }
michael@0 586
michael@0 587 #if defined(XP_WIN) && !defined(__GNUC__)
michael@0 588 #include <windows.h>
michael@0 589
michael@0 590 // We need WinMain in order to not be a console app. This function is unused
michael@0 591 // if we are a console application.
michael@0 592 int WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR args, int )
michael@0 593 {
michael@0 594 // Remove everything except close window from the context menu
michael@0 595 {
michael@0 596 HKEY hkApp;
michael@0 597 RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", 0,
michael@0 598 nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr,
michael@0 599 &hkApp, nullptr);
michael@0 600 RegCloseKey(hkApp);
michael@0 601 if (RegCreateKeyExW(HKEY_CURRENT_USER,
michael@0 602 L"Software\\Classes\\Applications\\crashreporter.exe",
michael@0 603 0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE,
michael@0 604 nullptr, &hkApp, nullptr) == ERROR_SUCCESS) {
michael@0 605 RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0);
michael@0 606 RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0);
michael@0 607 RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0);
michael@0 608 RegCloseKey(hkApp);
michael@0 609 }
michael@0 610 }
michael@0 611
michael@0 612 char** argv = static_cast<char**>(malloc(__argc * sizeof(char*)));
michael@0 613 for (int i = 0; i < __argc; i++) {
michael@0 614 argv[i] = strdup(WideToUTF8(__wargv[i]).c_str());
michael@0 615 }
michael@0 616
michael@0 617 // Do the real work.
michael@0 618 return main(__argc, argv);
michael@0 619 }
michael@0 620 #endif

mercurial