toolkit/crashreporter/client/crashreporter.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/client/crashreporter.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,620 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "crashreporter.h"
    1.10 +
    1.11 +#ifdef _MSC_VER
    1.12 +// Disable exception handler warnings.
    1.13 +# pragma warning( disable : 4530 )
    1.14 +#endif
    1.15 +
    1.16 +#include <fstream>
    1.17 +#include <sstream>
    1.18 +#include <memory>
    1.19 +#include <time.h>
    1.20 +#include <stdlib.h>
    1.21 +#include <string.h>
    1.22 +#include "mozilla/NullPtr.h"
    1.23 +
    1.24 +using std::string;
    1.25 +using std::istream;
    1.26 +using std::ifstream;
    1.27 +using std::istringstream;
    1.28 +using std::ostringstream;
    1.29 +using std::ostream;
    1.30 +using std::ofstream;
    1.31 +using std::vector;
    1.32 +using std::auto_ptr;
    1.33 +
    1.34 +namespace CrashReporter {
    1.35 +
    1.36 +StringTable  gStrings;
    1.37 +string       gSettingsPath;
    1.38 +int          gArgc;
    1.39 +char**       gArgv;
    1.40 +
    1.41 +static auto_ptr<ofstream> gLogStream(nullptr);
    1.42 +static string             gReporterDumpFile;
    1.43 +static string             gExtraFile;
    1.44 +
    1.45 +static string kExtraDataExtension = ".extra";
    1.46 +
    1.47 +void UIError(const string& message)
    1.48 +{
    1.49 +  string errorMessage;
    1.50 +  if (!gStrings[ST_CRASHREPORTERERROR].empty()) {
    1.51 +    char buf[2048];
    1.52 +    UI_SNPRINTF(buf, 2048,
    1.53 +                gStrings[ST_CRASHREPORTERERROR].c_str(),
    1.54 +                message.c_str());
    1.55 +    errorMessage = buf;
    1.56 +  } else {
    1.57 +    errorMessage = message;
    1.58 +  }
    1.59 +
    1.60 +  UIError_impl(errorMessage);
    1.61 +}
    1.62 +
    1.63 +static string Unescape(const string& str)
    1.64 +{
    1.65 +  string ret;
    1.66 +  for (string::const_iterator iter = str.begin();
    1.67 +       iter != str.end();
    1.68 +       iter++) {
    1.69 +    if (*iter == '\\') {
    1.70 +      iter++;
    1.71 +      if (*iter == '\\'){
    1.72 +        ret.push_back('\\');
    1.73 +      } else if (*iter == 'n') {
    1.74 +        ret.push_back('\n');
    1.75 +      } else if (*iter == 't') {
    1.76 +        ret.push_back('\t');
    1.77 +      }
    1.78 +    } else {
    1.79 +      ret.push_back(*iter);
    1.80 +    }
    1.81 +  }
    1.82 +
    1.83 +  return ret;
    1.84 +}
    1.85 +
    1.86 +static string Escape(const string& str)
    1.87 +{
    1.88 +  string ret;
    1.89 +  for (string::const_iterator iter = str.begin();
    1.90 +       iter != str.end();
    1.91 +       iter++) {
    1.92 +    if (*iter == '\\') {
    1.93 +      ret += "\\\\";
    1.94 +    } else if (*iter == '\n') {
    1.95 +      ret += "\\n";
    1.96 +    } else if (*iter == '\t') {
    1.97 +      ret += "\\t";
    1.98 +    } else {
    1.99 +      ret.push_back(*iter);
   1.100 +    }
   1.101 +  }
   1.102 +
   1.103 +  return ret;
   1.104 +}
   1.105 +
   1.106 +bool ReadStrings(istream& in, StringTable& strings, bool unescape)
   1.107 +{
   1.108 +  string currentSection;
   1.109 +  while (!in.eof()) {
   1.110 +    string line;
   1.111 +    std::getline(in, line);
   1.112 +    int sep = line.find('=');
   1.113 +    if (sep >= 0) {
   1.114 +      string key, value;
   1.115 +      key = line.substr(0, sep);
   1.116 +      value = line.substr(sep + 1);
   1.117 +      if (unescape)
   1.118 +        value = Unescape(value);
   1.119 +      strings[key] = value;
   1.120 +    }
   1.121 +  }
   1.122 +
   1.123 +  return true;
   1.124 +}
   1.125 +
   1.126 +bool ReadStringsFromFile(const string& path,
   1.127 +                         StringTable& strings,
   1.128 +                         bool unescape)
   1.129 +{
   1.130 +  ifstream* f = UIOpenRead(path);
   1.131 +  bool success = false;
   1.132 +  if (f->is_open()) {
   1.133 +    success = ReadStrings(*f, strings, unescape);
   1.134 +    f->close();
   1.135 +  }
   1.136 +
   1.137 +  delete f;
   1.138 +  return success;
   1.139 +}
   1.140 +
   1.141 +bool WriteStrings(ostream& out,
   1.142 +                  const string& header,
   1.143 +                  StringTable& strings,
   1.144 +                  bool escape)
   1.145 +{
   1.146 +  out << "[" << header << "]" << std::endl;
   1.147 +  for (StringTable::iterator iter = strings.begin();
   1.148 +       iter != strings.end();
   1.149 +       iter++) {
   1.150 +    out << iter->first << "=";
   1.151 +    if (escape)
   1.152 +      out << Escape(iter->second);
   1.153 +    else
   1.154 +      out << iter->second;
   1.155 +
   1.156 +    out << std::endl;
   1.157 +  }
   1.158 +
   1.159 +  return true;
   1.160 +}
   1.161 +
   1.162 +bool WriteStringsToFile(const string& path,
   1.163 +                        const string& header,
   1.164 +                        StringTable& strings,
   1.165 +                        bool escape)
   1.166 +{
   1.167 +  ofstream* f = UIOpenWrite(path.c_str());
   1.168 +  bool success = false;
   1.169 +  if (f->is_open()) {
   1.170 +    success = WriteStrings(*f, header, strings, escape);
   1.171 +    f->close();
   1.172 +  }
   1.173 +
   1.174 +  delete f;
   1.175 +  return success;
   1.176 +}
   1.177 +
   1.178 +void LogMessage(const std::string& message)
   1.179 +{
   1.180 +  if (gLogStream.get()) {
   1.181 +    char date[64];
   1.182 +    time_t tm;
   1.183 +    time(&tm);
   1.184 +    if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0)
   1.185 +        date[0] = '\0';
   1.186 +    (*gLogStream) << "[" << date << "] " << message << std::endl;
   1.187 +  }
   1.188 +}
   1.189 +
   1.190 +static void OpenLogFile()
   1.191 +{
   1.192 +  string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log";
   1.193 +  gLogStream.reset(UIOpenWrite(logPath.c_str(), true));
   1.194 +}
   1.195 +
   1.196 +static bool ReadConfig()
   1.197 +{
   1.198 +  string iniPath;
   1.199 +  if (!UIGetIniPath(iniPath))
   1.200 +    return false;
   1.201 +
   1.202 +  if (!ReadStringsFromFile(iniPath, gStrings, true))
   1.203 +    return false;
   1.204 +
   1.205 +  // See if we have a string override file, if so process it
   1.206 +  char* overrideEnv = getenv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE");
   1.207 +  if (overrideEnv && *overrideEnv && UIFileExists(overrideEnv))
   1.208 +    ReadStringsFromFile(overrideEnv, gStrings, true);
   1.209 +
   1.210 +  return true;
   1.211 +}
   1.212 +
   1.213 +static string GetExtraDataFilename(const string& dumpfile)
   1.214 +{
   1.215 +  string filename(dumpfile);
   1.216 +  int dot = filename.rfind('.');
   1.217 +  if (dot < 0)
   1.218 +    return "";
   1.219 +
   1.220 +  filename.replace(dot, filename.length() - dot, kExtraDataExtension);
   1.221 +  return filename;
   1.222 +}
   1.223 +
   1.224 +static string Basename(const string& file)
   1.225 +{
   1.226 +  int slashIndex = file.rfind(UI_DIR_SEPARATOR);
   1.227 +  if (slashIndex >= 0)
   1.228 +    return file.substr(slashIndex + 1);
   1.229 +  else
   1.230 +    return file;
   1.231 +}
   1.232 +
   1.233 +static bool MoveCrashData(const string& toDir,
   1.234 +                          string& dumpfile,
   1.235 +                          string& extrafile)
   1.236 +{
   1.237 +  if (!UIEnsurePathExists(toDir)) {
   1.238 +    UIError(gStrings[ST_ERROR_CREATEDUMPDIR]);
   1.239 +    return false;
   1.240 +  }
   1.241 +
   1.242 +  string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile);
   1.243 +  string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile);
   1.244 +
   1.245 +  if (!UIMoveFile(dumpfile, newDump)) {
   1.246 +    UIError(gStrings[ST_ERROR_DUMPFILEMOVE]);
   1.247 +    return false;
   1.248 +  }
   1.249 +
   1.250 +  if (!UIMoveFile(extrafile, newExtra)) {
   1.251 +    UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]);
   1.252 +    return false;
   1.253 +  }
   1.254 +
   1.255 +  dumpfile = newDump;
   1.256 +  extrafile = newExtra;
   1.257 +
   1.258 +  return true;
   1.259 +}
   1.260 +
   1.261 +static bool AddSubmittedReport(const string& serverResponse)
   1.262 +{
   1.263 +  StringTable responseItems;
   1.264 +  istringstream in(serverResponse);
   1.265 +  ReadStrings(in, responseItems, false);
   1.266 +
   1.267 +  if (responseItems.find("StopSendingReportsFor") != responseItems.end()) {
   1.268 +    // server wants to tell us to stop sending reports for a certain version
   1.269 +    string reportPath =
   1.270 +      gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" +
   1.271 +      responseItems["StopSendingReportsFor"];
   1.272 +
   1.273 +    ofstream* reportFile = UIOpenWrite(reportPath);
   1.274 +    if (reportFile->is_open()) {
   1.275 +      // don't really care about the contents
   1.276 +      *reportFile << 1 << "\n";
   1.277 +      reportFile->close();
   1.278 +    }
   1.279 +    delete reportFile;
   1.280 +  }
   1.281 +
   1.282 +  if (responseItems.find("Discarded") != responseItems.end()) {
   1.283 +    // server discarded this report... save it so the user can resubmit it
   1.284 +    // manually
   1.285 +    return false;
   1.286 +  }
   1.287 +
   1.288 +  if (responseItems.find("CrashID") == responseItems.end())
   1.289 +    return false;
   1.290 +
   1.291 +  string submittedDir =
   1.292 +    gSettingsPath + UI_DIR_SEPARATOR + "submitted";
   1.293 +  if (!UIEnsurePathExists(submittedDir)) {
   1.294 +    return false;
   1.295 +  }
   1.296 +
   1.297 +  string path = submittedDir + UI_DIR_SEPARATOR +
   1.298 +    responseItems["CrashID"] + ".txt";
   1.299 +
   1.300 +  ofstream* file = UIOpenWrite(path);
   1.301 +  if (!file->is_open()) {
   1.302 +    delete file;
   1.303 +    return false;
   1.304 +  }
   1.305 +
   1.306 +  char buf[1024];
   1.307 +  UI_SNPRINTF(buf, 1024,
   1.308 +              gStrings["CrashID"].c_str(),
   1.309 +              responseItems["CrashID"].c_str());
   1.310 +  *file << buf << "\n";
   1.311 +
   1.312 +  if (responseItems.find("ViewURL") != responseItems.end()) {
   1.313 +    UI_SNPRINTF(buf, 1024,
   1.314 +                gStrings["CrashDetailsURL"].c_str(),
   1.315 +                responseItems["ViewURL"].c_str());
   1.316 +    *file << buf << "\n";
   1.317 +  }
   1.318 +
   1.319 +  file->close();
   1.320 +  delete file;
   1.321 +
   1.322 +  return true;
   1.323 +}
   1.324 +
   1.325 +void DeleteDump()
   1.326 +{
   1.327 +  const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP");
   1.328 +  if (!noDelete || *noDelete == '\0') {
   1.329 +    if (!gReporterDumpFile.empty())
   1.330 +      UIDeleteFile(gReporterDumpFile);
   1.331 +    if (!gExtraFile.empty())
   1.332 +      UIDeleteFile(gExtraFile);
   1.333 +  }
   1.334 +}
   1.335 +
   1.336 +void SendCompleted(bool success, const string& serverResponse)
   1.337 +{
   1.338 +  if (success) {
   1.339 +    if (AddSubmittedReport(serverResponse)) {
   1.340 +      DeleteDump();
   1.341 +    }
   1.342 +    else {
   1.343 +      string directory = gReporterDumpFile;
   1.344 +      int slashpos = directory.find_last_of("/\\");
   1.345 +      if (slashpos < 2)
   1.346 +        return;
   1.347 +      directory.resize(slashpos);
   1.348 +      UIPruneSavedDumps(directory);
   1.349 +    }
   1.350 +  }
   1.351 +}
   1.352 +
   1.353 +bool ShouldEnableSending()
   1.354 +{
   1.355 +  srand(time(0));
   1.356 +  return ((rand() % 100) < MOZ_CRASHREPORTER_ENABLE_PERCENT);
   1.357 +}
   1.358 +
   1.359 +} // namespace CrashReporter
   1.360 +
   1.361 +using namespace CrashReporter;
   1.362 +
   1.363 +void RewriteStrings(StringTable& queryParameters)
   1.364 +{
   1.365 +  // rewrite some UI strings with the values from the query parameters
   1.366 +  string product = queryParameters["ProductName"];
   1.367 +  string vendor = queryParameters["Vendor"];
   1.368 +  if (vendor.empty()) {
   1.369 +    // Assume Mozilla if no vendor is specified
   1.370 +    vendor = "Mozilla";
   1.371 +  }
   1.372 +
   1.373 +  char buf[4096];
   1.374 +  UI_SNPRINTF(buf, sizeof(buf),
   1.375 +              gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(),
   1.376 +              vendor.c_str());
   1.377 +  gStrings[ST_CRASHREPORTERTITLE] = buf;
   1.378 +
   1.379 +
   1.380 +  string str = gStrings[ST_CRASHREPORTERPRODUCTERROR];
   1.381 +  // Only do the replacement here if the string has two
   1.382 +  // format specifiers to start.  Otherwise
   1.383 +  // we assume it has the product name hardcoded.
   1.384 +  string::size_type pos = str.find("%s");
   1.385 +  if (pos != string::npos)
   1.386 +    pos = str.find("%s", pos+2);
   1.387 +  if (pos != string::npos) {
   1.388 +    // Leave a format specifier for UIError to fill in
   1.389 +    UI_SNPRINTF(buf, sizeof(buf),
   1.390 +                gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(),
   1.391 +                product.c_str(),
   1.392 +                "%s");
   1.393 +    gStrings[ST_CRASHREPORTERERROR] = buf;
   1.394 +  }
   1.395 +  else {
   1.396 +    // product name is hardcoded
   1.397 +    gStrings[ST_CRASHREPORTERERROR] = str;
   1.398 +  }
   1.399 +
   1.400 +  UI_SNPRINTF(buf, sizeof(buf),
   1.401 +              gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(),
   1.402 +              product.c_str());
   1.403 +  gStrings[ST_CRASHREPORTERDESCRIPTION] = buf;
   1.404 +
   1.405 +  UI_SNPRINTF(buf, sizeof(buf),
   1.406 +              gStrings[ST_CHECKSUBMIT].c_str(),
   1.407 +              vendor.c_str());
   1.408 +  gStrings[ST_CHECKSUBMIT] = buf;
   1.409 +
   1.410 +  UI_SNPRINTF(buf, sizeof(buf),
   1.411 +              gStrings[ST_CHECKEMAIL].c_str(),
   1.412 +              vendor.c_str());
   1.413 +  gStrings[ST_CHECKEMAIL] = buf;
   1.414 +
   1.415 +  UI_SNPRINTF(buf, sizeof(buf),
   1.416 +              gStrings[ST_RESTART].c_str(),
   1.417 +              product.c_str());
   1.418 +  gStrings[ST_RESTART] = buf;
   1.419 +
   1.420 +  UI_SNPRINTF(buf, sizeof(buf),
   1.421 +              gStrings[ST_QUIT].c_str(),
   1.422 +              product.c_str());
   1.423 +  gStrings[ST_QUIT] = buf;
   1.424 +
   1.425 +  UI_SNPRINTF(buf, sizeof(buf),
   1.426 +              gStrings[ST_ERROR_ENDOFLIFE].c_str(),
   1.427 +              product.c_str());
   1.428 +  gStrings[ST_ERROR_ENDOFLIFE] = buf;
   1.429 +}
   1.430 +
   1.431 +bool CheckEndOfLifed(string version)
   1.432 +{
   1.433 +  string reportPath =
   1.434 +    gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + version;
   1.435 +  return UIFileExists(reportPath);
   1.436 +}
   1.437 +
   1.438 +int main(int argc, char** argv)
   1.439 +{
   1.440 +  gArgc = argc;
   1.441 +  gArgv = argv;
   1.442 +
   1.443 +  if (!ReadConfig()) {
   1.444 +    UIError("Couldn't read configuration.");
   1.445 +    return 0;
   1.446 +  }
   1.447 +
   1.448 +  if (!UIInit())
   1.449 +    return 0;
   1.450 +
   1.451 +  if (argc > 1) {
   1.452 +    gReporterDumpFile = argv[1];
   1.453 +  }
   1.454 +
   1.455 +  if (gReporterDumpFile.empty()) {
   1.456 +    // no dump file specified, run the default UI
   1.457 +    UIShowDefaultUI();
   1.458 +  } else {
   1.459 +    gExtraFile = GetExtraDataFilename(gReporterDumpFile);
   1.460 +    if (gExtraFile.empty()) {
   1.461 +      UIError(gStrings[ST_ERROR_BADARGUMENTS]);
   1.462 +      return 0;
   1.463 +    }
   1.464 +
   1.465 +    if (!UIFileExists(gExtraFile)) {
   1.466 +      UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]);
   1.467 +      return 0;
   1.468 +    }
   1.469 +
   1.470 +    StringTable queryParameters;
   1.471 +    if (!ReadStringsFromFile(gExtraFile, queryParameters, true)) {
   1.472 +      UIError(gStrings[ST_ERROR_EXTRAFILEREAD]);
   1.473 +      return 0;
   1.474 +    }
   1.475 +
   1.476 +    if (queryParameters.find("ProductName") == queryParameters.end()) {
   1.477 +      UIError(gStrings[ST_ERROR_NOPRODUCTNAME]);
   1.478 +      return 0;
   1.479 +    }
   1.480 +
   1.481 +    // There is enough information in the extra file to rewrite strings
   1.482 +    // to be product specific
   1.483 +    RewriteStrings(queryParameters);
   1.484 +
   1.485 +    if (queryParameters.find("ServerURL") == queryParameters.end()) {
   1.486 +      UIError(gStrings[ST_ERROR_NOSERVERURL]);
   1.487 +      return 0;
   1.488 +    }
   1.489 +
   1.490 +    // Hopefully the settings path exists in the environment. Try that before
   1.491 +    // asking the platform-specific code to guess.
   1.492 +#ifdef XP_WIN32
   1.493 +    static const wchar_t kDataDirKey[] = L"MOZ_CRASHREPORTER_DATA_DIRECTORY";
   1.494 +    const wchar_t *settingsPath = _wgetenv(kDataDirKey);
   1.495 +    if (settingsPath && *settingsPath) {
   1.496 +      gSettingsPath = WideToUTF8(settingsPath);
   1.497 +    }
   1.498 +#else
   1.499 +    static const char kDataDirKey[] = "MOZ_CRASHREPORTER_DATA_DIRECTORY";
   1.500 +    const char *settingsPath = getenv(kDataDirKey);
   1.501 +    if (settingsPath && *settingsPath) {
   1.502 +      gSettingsPath = settingsPath;
   1.503 +    }
   1.504 +#endif
   1.505 +    else {
   1.506 +      string product = queryParameters["ProductName"];
   1.507 +      string vendor = queryParameters["Vendor"];
   1.508 +      if (!UIGetSettingsPath(vendor, product, gSettingsPath)) {
   1.509 +        gSettingsPath.clear();
   1.510 +      }
   1.511 +    }
   1.512 +
   1.513 +    if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) {
   1.514 +      UIError(gStrings[ST_ERROR_NOSETTINGSPATH]);
   1.515 +      return 0;
   1.516 +    }
   1.517 +
   1.518 +    OpenLogFile();
   1.519 +
   1.520 +    if (!UIFileExists(gReporterDumpFile)) {
   1.521 +      UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]);
   1.522 +      return 0;
   1.523 +    }
   1.524 +
   1.525 +    string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
   1.526 +    if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile)) {
   1.527 +      return 0;
   1.528 +    }
   1.529 +
   1.530 +    string sendURL = queryParameters["ServerURL"];
   1.531 +    // we don't need to actually send this
   1.532 +    queryParameters.erase("ServerURL");
   1.533 +
   1.534 +    queryParameters["Throttleable"] = "1";
   1.535 +
   1.536 +    // re-set XUL_APP_FILE for xulrunner wrapped apps
   1.537 +    const char *appfile = getenv("MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE");
   1.538 +    if (appfile && *appfile) {
   1.539 +      const char prefix[] = "XUL_APP_FILE=";
   1.540 +      char *env = (char*) malloc(strlen(appfile) + strlen(prefix) + 1);
   1.541 +      if (!env) {
   1.542 +        UIError("Out of memory");
   1.543 +        return 0;
   1.544 +      }
   1.545 +      strcpy(env, prefix);
   1.546 +      strcat(env, appfile);
   1.547 +      putenv(env);
   1.548 +      free(env);
   1.549 +    }
   1.550 +
   1.551 +    vector<string> restartArgs;
   1.552 +
   1.553 +    ostringstream paramName;
   1.554 +    int i = 0;
   1.555 +    paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
   1.556 +    const char *param = getenv(paramName.str().c_str());
   1.557 +    while (param && *param) {
   1.558 +      restartArgs.push_back(param);
   1.559 +
   1.560 +      paramName.str("");
   1.561 +      paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++;
   1.562 +      param = getenv(paramName.str().c_str());
   1.563 +    };
   1.564 +
   1.565 +    // allow override of the server url via environment variable
   1.566 +    //XXX: remove this in the far future when our robot
   1.567 +    // masters force everyone to use XULRunner
   1.568 +    char* urlEnv = getenv("MOZ_CRASHREPORTER_URL");
   1.569 +    if (urlEnv && *urlEnv) {
   1.570 +      sendURL = urlEnv;
   1.571 +    }
   1.572 +
   1.573 +     // see if this version has been end-of-lifed
   1.574 +     if (queryParameters.find("Version") != queryParameters.end() &&
   1.575 +         CheckEndOfLifed(queryParameters["Version"])) {
   1.576 +       UIError(gStrings[ST_ERROR_ENDOFLIFE]);
   1.577 +       DeleteDump();
   1.578 +       return 0;
   1.579 +     }
   1.580 +
   1.581 +    if (!UIShowCrashUI(gReporterDumpFile, queryParameters, sendURL, restartArgs))
   1.582 +      DeleteDump();
   1.583 +  }
   1.584 +
   1.585 +  UIShutdown();
   1.586 +
   1.587 +  return 0;
   1.588 +}
   1.589 +
   1.590 +#if defined(XP_WIN) && !defined(__GNUC__)
   1.591 +#include <windows.h>
   1.592 +
   1.593 +// We need WinMain in order to not be a console app.  This function is unused
   1.594 +// if we are a console application.
   1.595 +int WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR args, int )
   1.596 +{
   1.597 +  // Remove everything except close window from the context menu
   1.598 +  {
   1.599 +    HKEY hkApp;
   1.600 +    RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", 0,
   1.601 +                    nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr,
   1.602 +                    &hkApp, nullptr);
   1.603 +    RegCloseKey(hkApp);
   1.604 +    if (RegCreateKeyExW(HKEY_CURRENT_USER,
   1.605 +                        L"Software\\Classes\\Applications\\crashreporter.exe",
   1.606 +                        0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE,
   1.607 +                        nullptr, &hkApp, nullptr) == ERROR_SUCCESS) {
   1.608 +      RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0);
   1.609 +      RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0);
   1.610 +      RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0);
   1.611 +      RegCloseKey(hkApp);
   1.612 +    }
   1.613 +  }
   1.614 +
   1.615 +  char** argv = static_cast<char**>(malloc(__argc * sizeof(char*)));
   1.616 +  for (int i = 0; i < __argc; i++) {
   1.617 +    argv[i] = strdup(WideToUTF8(__wargv[i]).c_str());
   1.618 +  }
   1.619 +
   1.620 +  // Do the real work.
   1.621 +  return main(__argc, argv);
   1.622 +}
   1.623 +#endif

mercurial