Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 |