diff --git a/Cargo.toml b/Cargo.toml index 20f93e9589c8..7b26009e165d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ "security/manager/ssl/osclientcerts", "testing/geckodriver", "toolkit/components/uniffi-bindgen-gecko-js", - "toolkit/crashreporter/client-rust/app", + "toolkit/crashreporter/client/app", "toolkit/crashreporter/mozwer-rust", "toolkit/crashreporter/rust_minidump_writer_linux", "toolkit/library/gtest/rust", diff --git a/toolkit/crashreporter/client/Makefile.in b/toolkit/crashreporter/client/Makefile.in deleted file mode 100644 index 2d3ef1bee914..000000000000 --- a/toolkit/crashreporter/client/Makefile.in +++ /dev/null @@ -1,19 +0,0 @@ -# vim:set ts=8 sw=8 sts=8 noet: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -ifeq ($(OS_ARCH),WINNT) -MOZ_WINCONSOLE = 0 -endif - -include $(topsrcdir)/config/rules.mk - -ifeq ($(OS_ARCH),Darwin) -libs:: - $(NSINSTALL) -D $(DIST)/bin/crashreporter.app - rsync -a -C --exclude '*.in' $(srcdir)/macbuild/Contents $(DIST)/bin/crashreporter.app - $(call py_action,preprocessor crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings,-Fsubstitution --output-encoding utf-16 -DAPP_NAME='$(MOZ_APP_DISPLAYNAME)' $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in -o $(DIST)/bin/crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings) - $(NSINSTALL) -D $(DIST)/bin/crashreporter.app/Contents/MacOS - $(NSINSTALL) $(DIST)/bin/crashreporter $(DIST)/bin/crashreporter.app/Contents/MacOS -endif diff --git a/toolkit/crashreporter/client/Throbber-small.avi b/toolkit/crashreporter/client/Throbber-small.avi deleted file mode 100644 index 640ea62c0eaf..000000000000 Binary files a/toolkit/crashreporter/client/Throbber-small.avi and /dev/null differ diff --git a/toolkit/crashreporter/client/Throbber-small.gif b/toolkit/crashreporter/client/Throbber-small.gif deleted file mode 100644 index cce32f20f473..000000000000 Binary files a/toolkit/crashreporter/client/Throbber-small.gif and /dev/null differ diff --git a/toolkit/crashreporter/client-rust/app/Cargo.toml b/toolkit/crashreporter/client/app/Cargo.toml similarity index 100% rename from toolkit/crashreporter/client-rust/app/Cargo.toml rename to toolkit/crashreporter/client/app/Cargo.toml diff --git a/toolkit/crashreporter/client-rust/app/Makefile.in b/toolkit/crashreporter/client/app/Makefile.in similarity index 100% rename from toolkit/crashreporter/client-rust/app/Makefile.in rename to toolkit/crashreporter/client/app/Makefile.in diff --git a/toolkit/crashreporter/client-rust/app/build.rs b/toolkit/crashreporter/client/app/build.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/build.rs rename to toolkit/crashreporter/client/app/build.rs diff --git a/toolkit/crashreporter/client-rust/app/macos_app_bundle/Info.plist b/toolkit/crashreporter/client/app/macos_app_bundle/Info.plist similarity index 100% rename from toolkit/crashreporter/client-rust/app/macos_app_bundle/Info.plist rename to toolkit/crashreporter/client/app/macos_app_bundle/Info.plist diff --git a/toolkit/crashreporter/client-rust/app/macos_app_bundle/PkgInfo b/toolkit/crashreporter/client/app/macos_app_bundle/PkgInfo similarity index 100% rename from toolkit/crashreporter/client-rust/app/macos_app_bundle/PkgInfo rename to toolkit/crashreporter/client/app/macos_app_bundle/PkgInfo diff --git a/toolkit/crashreporter/client-rust/app/macos_app_bundle/Resources/English.lproj/InfoPlist.strings.in b/toolkit/crashreporter/client/app/macos_app_bundle/Resources/English.lproj/InfoPlist.strings.in similarity index 100% rename from toolkit/crashreporter/client-rust/app/macos_app_bundle/Resources/English.lproj/InfoPlist.strings.in rename to toolkit/crashreporter/client/app/macos_app_bundle/Resources/English.lproj/InfoPlist.strings.in diff --git a/toolkit/crashreporter/client-rust/app/macos_app_bundle/Resources/crashreporter.icns b/toolkit/crashreporter/client/app/macos_app_bundle/Resources/crashreporter.icns similarity index 100% rename from toolkit/crashreporter/client-rust/app/macos_app_bundle/Resources/crashreporter.icns rename to toolkit/crashreporter/client/app/macos_app_bundle/Resources/crashreporter.icns diff --git a/toolkit/crashreporter/client-rust/app/moz.build b/toolkit/crashreporter/client/app/moz.build similarity index 100% rename from toolkit/crashreporter/client-rust/app/moz.build rename to toolkit/crashreporter/client/app/moz.build diff --git a/toolkit/crashreporter/client-rust/app/src/async_task.rs b/toolkit/crashreporter/client/app/src/async_task.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/async_task.rs rename to toolkit/crashreporter/client/app/src/async_task.rs diff --git a/toolkit/crashreporter/client-rust/app/src/config.rs b/toolkit/crashreporter/client/app/src/config.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/config.rs rename to toolkit/crashreporter/client/app/src/config.rs diff --git a/toolkit/crashreporter/client-rust/app/src/data.rs b/toolkit/crashreporter/client/app/src/data.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/data.rs rename to toolkit/crashreporter/client/app/src/data.rs diff --git a/toolkit/crashreporter/client-rust/app/src/lang/language_info.rs b/toolkit/crashreporter/client/app/src/lang/language_info.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/lang/language_info.rs rename to toolkit/crashreporter/client/app/src/lang/language_info.rs diff --git a/toolkit/crashreporter/client-rust/app/src/lang/mod.rs b/toolkit/crashreporter/client/app/src/lang/mod.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/lang/mod.rs rename to toolkit/crashreporter/client/app/src/lang/mod.rs diff --git a/toolkit/crashreporter/client-rust/app/src/lang/omnijar.rs b/toolkit/crashreporter/client/app/src/lang/omnijar.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/lang/omnijar.rs rename to toolkit/crashreporter/client/app/src/lang/omnijar.rs diff --git a/toolkit/crashreporter/client-rust/app/src/logging.rs b/toolkit/crashreporter/client/app/src/logging.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/logging.rs rename to toolkit/crashreporter/client/app/src/logging.rs diff --git a/toolkit/crashreporter/client-rust/app/src/logic.rs b/toolkit/crashreporter/client/app/src/logic.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/logic.rs rename to toolkit/crashreporter/client/app/src/logic.rs diff --git a/toolkit/crashreporter/client-rust/app/src/main.rs b/toolkit/crashreporter/client/app/src/main.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/main.rs rename to toolkit/crashreporter/client/app/src/main.rs diff --git a/toolkit/crashreporter/client-rust/app/src/net/legacy_telemetry.rs b/toolkit/crashreporter/client/app/src/net/legacy_telemetry.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/net/legacy_telemetry.rs rename to toolkit/crashreporter/client/app/src/net/legacy_telemetry.rs diff --git a/toolkit/crashreporter/client-rust/app/src/net/libcurl.rs b/toolkit/crashreporter/client/app/src/net/libcurl.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/net/libcurl.rs rename to toolkit/crashreporter/client/app/src/net/libcurl.rs diff --git a/toolkit/crashreporter/client-rust/app/src/net/mod.rs b/toolkit/crashreporter/client/app/src/net/mod.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/net/mod.rs rename to toolkit/crashreporter/client/app/src/net/mod.rs diff --git a/toolkit/crashreporter/client-rust/app/src/net/report.rs b/toolkit/crashreporter/client/app/src/net/report.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/net/report.rs rename to toolkit/crashreporter/client/app/src/net/report.rs diff --git a/toolkit/crashreporter/client-rust/app/src/process.rs b/toolkit/crashreporter/client/app/src/process.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/process.rs rename to toolkit/crashreporter/client/app/src/process.rs diff --git a/toolkit/crashreporter/client-rust/app/src/settings.rs b/toolkit/crashreporter/client/app/src/settings.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/settings.rs rename to toolkit/crashreporter/client/app/src/settings.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/env.rs b/toolkit/crashreporter/client/app/src/std/env.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/env.rs rename to toolkit/crashreporter/client/app/src/std/env.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/fs.rs b/toolkit/crashreporter/client/app/src/std/fs.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/fs.rs rename to toolkit/crashreporter/client/app/src/std/fs.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/mock.rs b/toolkit/crashreporter/client/app/src/std/mock.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/mock.rs rename to toolkit/crashreporter/client/app/src/std/mock.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/mock_stub.rs b/toolkit/crashreporter/client/app/src/std/mock_stub.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/mock_stub.rs rename to toolkit/crashreporter/client/app/src/std/mock_stub.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/mod.rs b/toolkit/crashreporter/client/app/src/std/mod.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/mod.rs rename to toolkit/crashreporter/client/app/src/std/mod.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/net.rs b/toolkit/crashreporter/client/app/src/std/net.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/net.rs rename to toolkit/crashreporter/client/app/src/std/net.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/path.rs b/toolkit/crashreporter/client/app/src/std/path.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/path.rs rename to toolkit/crashreporter/client/app/src/std/path.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/process.rs b/toolkit/crashreporter/client/app/src/std/process.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/process.rs rename to toolkit/crashreporter/client/app/src/std/process.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/thread.rs b/toolkit/crashreporter/client/app/src/std/thread.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/thread.rs rename to toolkit/crashreporter/client/app/src/std/thread.rs diff --git a/toolkit/crashreporter/client-rust/app/src/std/time.rs b/toolkit/crashreporter/client/app/src/std/time.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/std/time.rs rename to toolkit/crashreporter/client/app/src/std/time.rs diff --git a/toolkit/crashreporter/client-rust/app/src/test.rs b/toolkit/crashreporter/client/app/src/test.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/test.rs rename to toolkit/crashreporter/client/app/src/test.rs diff --git a/toolkit/crashreporter/client-rust/app/src/thread_bound.rs b/toolkit/crashreporter/client/app/src/thread_bound.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/thread_bound.rs rename to toolkit/crashreporter/client/app/src/thread_bound.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/gtk.rs b/toolkit/crashreporter/client/app/src/ui/gtk.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/gtk.rs rename to toolkit/crashreporter/client/app/src/ui/gtk.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/macos/mod.rs b/toolkit/crashreporter/client/app/src/ui/macos/mod.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/macos/mod.rs rename to toolkit/crashreporter/client/app/src/ui/macos/mod.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/macos/objc.rs b/toolkit/crashreporter/client/app/src/ui/macos/objc.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/macos/objc.rs rename to toolkit/crashreporter/client/app/src/ui/macos/objc.rs diff --git a/toolkit/crashreporter/client/macbuild/Contents/Info.plist b/toolkit/crashreporter/client/app/src/ui/macos/plist.rs similarity index 52% rename from toolkit/crashreporter/client/macbuild/Contents/Info.plist rename to toolkit/crashreporter/client/app/src/ui/macos/plist.rs index 51d6c4de3717..a5bbe0aa0a0e 100644 --- a/toolkit/crashreporter/client/macbuild/Contents/Info.plist +++ b/toolkit/crashreporter/client/app/src/ui/macos/plist.rs @@ -1,36 +1,44 @@ - +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! The embedded Info.plist file. + +const DATA: &[u8] = br#" CFBundleDevelopmentRegion English CFBundleDisplayName - crashreporter + Crash Reporter CFBundleExecutable crashreporter - CFBundleIconFile - crashreporter.icns CFBundleIdentifier org.mozilla.crashreporter CFBundleInfoDictionaryVersion 6.0 CFBundleName - crashreporter + Crash Reporter CFBundlePackageType APPL - CFBundleSignature - ???? CFBundleVersion 1.0 LSHasLocalizedDisplayName - NSMainNibFile - MainMenu NSRequiresAquaSystemAppearance NSPrincipalClass NSApplication - LSUIElement - - +"#; + +const N: usize = DATA.len(); + +const PTR: *const [u8; N] = DATA.as_ptr() as *const [u8; N]; + +#[used] +#[link_section = "__TEXT,__info_plist"] +// # Safety +// The array pointer is created from `DATA` (a slice pointer) with `DATA.len()` as the length. +static PLIST: [u8; N] = unsafe { *PTR }; diff --git a/toolkit/crashreporter/client-rust/app/src/ui/mod.rs b/toolkit/crashreporter/client/app/src/ui/mod.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/mod.rs rename to toolkit/crashreporter/client/app/src/ui/mod.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/button.rs b/toolkit/crashreporter/client/app/src/ui/model/button.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/button.rs rename to toolkit/crashreporter/client/app/src/ui/model/button.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/checkbox.rs b/toolkit/crashreporter/client/app/src/ui/model/checkbox.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/checkbox.rs rename to toolkit/crashreporter/client/app/src/ui/model/checkbox.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/hbox.rs b/toolkit/crashreporter/client/app/src/ui/model/hbox.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/hbox.rs rename to toolkit/crashreporter/client/app/src/ui/model/hbox.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/label.rs b/toolkit/crashreporter/client/app/src/ui/model/label.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/label.rs rename to toolkit/crashreporter/client/app/src/ui/model/label.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/mod.rs b/toolkit/crashreporter/client/app/src/ui/model/mod.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/mod.rs rename to toolkit/crashreporter/client/app/src/ui/model/mod.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/progress.rs b/toolkit/crashreporter/client/app/src/ui/model/progress.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/progress.rs rename to toolkit/crashreporter/client/app/src/ui/model/progress.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/scroll.rs b/toolkit/crashreporter/client/app/src/ui/model/scroll.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/scroll.rs rename to toolkit/crashreporter/client/app/src/ui/model/scroll.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/textbox.rs b/toolkit/crashreporter/client/app/src/ui/model/textbox.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/textbox.rs rename to toolkit/crashreporter/client/app/src/ui/model/textbox.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/vbox.rs b/toolkit/crashreporter/client/app/src/ui/model/vbox.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/vbox.rs rename to toolkit/crashreporter/client/app/src/ui/model/vbox.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/model/window.rs b/toolkit/crashreporter/client/app/src/ui/model/window.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/model/window.rs rename to toolkit/crashreporter/client/app/src/ui/model/window.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/test.rs b/toolkit/crashreporter/client/app/src/ui/test.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/test.rs rename to toolkit/crashreporter/client/app/src/ui/test.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/font.rs b/toolkit/crashreporter/client/app/src/ui/windows/font.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/font.rs rename to toolkit/crashreporter/client/app/src/ui/windows/font.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/gdi.rs b/toolkit/crashreporter/client/app/src/ui/windows/gdi.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/gdi.rs rename to toolkit/crashreporter/client/app/src/ui/windows/gdi.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/layout.rs b/toolkit/crashreporter/client/app/src/ui/windows/layout.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/layout.rs rename to toolkit/crashreporter/client/app/src/ui/windows/layout.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/mod.rs b/toolkit/crashreporter/client/app/src/ui/windows/mod.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/mod.rs rename to toolkit/crashreporter/client/app/src/ui/windows/mod.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/quit_token.rs b/toolkit/crashreporter/client/app/src/ui/windows/quit_token.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/quit_token.rs rename to toolkit/crashreporter/client/app/src/ui/windows/quit_token.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/twoway.rs b/toolkit/crashreporter/client/app/src/ui/windows/twoway.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/twoway.rs rename to toolkit/crashreporter/client/app/src/ui/windows/twoway.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/widestring.rs b/toolkit/crashreporter/client/app/src/ui/windows/widestring.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/widestring.rs rename to toolkit/crashreporter/client/app/src/ui/windows/widestring.rs diff --git a/toolkit/crashreporter/client-rust/app/src/ui/windows/window.rs b/toolkit/crashreporter/client/app/src/ui/windows/window.rs similarity index 100% rename from toolkit/crashreporter/client-rust/app/src/ui/windows/window.rs rename to toolkit/crashreporter/client/app/src/ui/windows/window.rs diff --git a/toolkit/crashreporter/client-rust/cocoabind/Cargo.toml b/toolkit/crashreporter/client/cocoabind/Cargo.toml similarity index 100% rename from toolkit/crashreporter/client-rust/cocoabind/Cargo.toml rename to toolkit/crashreporter/client/cocoabind/Cargo.toml diff --git a/toolkit/crashreporter/client-rust/cocoabind/build.rs b/toolkit/crashreporter/client/cocoabind/build.rs similarity index 100% rename from toolkit/crashreporter/client-rust/cocoabind/build.rs rename to toolkit/crashreporter/client/cocoabind/build.rs diff --git a/toolkit/crashreporter/client-rust/cocoabind/src/lib.rs b/toolkit/crashreporter/client/cocoabind/src/lib.rs similarity index 100% rename from toolkit/crashreporter/client-rust/cocoabind/src/lib.rs rename to toolkit/crashreporter/client/cocoabind/src/lib.rs diff --git a/toolkit/crashreporter/client/crashreporter.cpp b/toolkit/crashreporter/client/crashreporter.cpp deleted file mode 100644 index 2887b16170f7..000000000000 --- a/toolkit/crashreporter/client/crashreporter.cpp +++ /dev/null @@ -1,852 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "crashreporter.h" - -#ifdef _MSC_VER -// Disable exception handler warnings. -# pragma warning(disable : 4530) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef XP_LINUX -# include -#endif - -#include "json/json.h" -#include "nss.h" -#include "sechash.h" - -using std::ifstream; -using std::ios; -using std::istream; -using std::istringstream; -using std::ofstream; -using std::ostream; -using std::ostringstream; -using std::string; -using std::unique_ptr; -using std::vector; - -namespace CrashReporter { - -StringTable gStrings; -Json::Value gData; -string gSettingsPath; -string gEventsPath; -string gPingPath; -int gArgc; -char** gArgv; -bool gAutoSubmit; - -enum SubmissionResult { Succeeded, Failed }; - -static unique_ptr gLogStream(nullptr); -static string gReporterDumpFile; -static string gExtraFile; -static string gMemoryFile; - -static const char kExtraDataExtension[] = ".extra"; -static const char kMemoryReportExtension[] = ".memory.json.gz"; - -void UIError(const string& message) { - if (gAutoSubmit) { - return; - } - - string errorMessage; - if (!gStrings[ST_CRASHREPORTERERROR].empty()) { - char buf[2048]; - snprintf(buf, 2048, gStrings[ST_CRASHREPORTERERROR].c_str(), - message.c_str()); - errorMessage = buf; - } else { - errorMessage = message; - } - - UIError_impl(errorMessage); -} - -static string Unescape(const string& str) { - string ret; - for (string::const_iterator iter = str.begin(); iter != str.end(); iter++) { - if (*iter == '\\') { - iter++; - if (*iter == '\\') { - ret.push_back('\\'); - } else if (*iter == 'n') { - ret.push_back('\n'); - } else if (*iter == 't') { - ret.push_back('\t'); - } - } else { - ret.push_back(*iter); - } - } - - return ret; -} - -bool ReadStrings(istream& in, StringTable& strings, bool unescape) { - while (!in.eof()) { - string line; - std::getline(in, line); - int sep = line.find('='); - if (sep >= 0) { - string key, value; - key = line.substr(0, sep); - value = line.substr(sep + 1); - if (unescape) value = Unescape(value); - strings[key] = value; - } - } - - return true; -} - -bool ReadStringsFromFile(const string& path, StringTable& strings, - bool unescape) { - ifstream* f = UIOpenRead(path, ios::in); - bool success = false; - if (f->is_open()) { - success = ReadStrings(*f, strings, unescape); - f->close(); - } - - delete f; - return success; -} - -static bool ReadExtraFile(const string& aExtraDataPath, Json::Value& aExtra) { - bool success = false; - ifstream* f = UIOpenRead(aExtraDataPath, ios::in); - if (f->is_open()) { - Json::CharReaderBuilder builder; - success = parseFromStream(builder, *f, &aExtra, nullptr); - } - - delete f; - return success; -} - -static string Basename(const string& file) { - string::size_type slashIndex = file.rfind(UI_DIR_SEPARATOR); - if (slashIndex != string::npos) { - return file.substr(slashIndex + 1); - } - return file; -} - -static bool ReadEventFile(const string& aPath, string& aEventVersion, - string& aTime, string& aUuid, Json::Value& aData) { - bool res = false; - ifstream* f = UIOpenRead(aPath, ios::binary); - - if (f->is_open()) { - std::getline(*f, aEventVersion, '\n'); - res = f->good(); - std::getline(*f, aTime, '\n'); - res &= f->good(); - std::getline(*f, aUuid, '\n'); - res &= f->good(); - - if (res) { - Json::CharReaderBuilder builder; - res = parseFromStream(builder, *f, &aData, nullptr); - } - } - - delete f; - return res; -} - -static void OverwriteEventFile(const string& aPath, const string& aEventVersion, - const string& aTime, const string& aUuid, - const Json::Value& aData) { - ofstream* f = UIOpenWrite(aPath, ios::binary | ios::trunc); - if (f->is_open()) { - f->write(aEventVersion.c_str(), aEventVersion.length()) << '\n'; - f->write(aTime.c_str(), aTime.length()) << '\n'; - f->write(aUuid.c_str(), aUuid.length()) << '\n'; - - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - std::unique_ptr writer(builder.newStreamWriter()); - writer->write(aData, f); - *f << "\n"; - } - - delete f; -} - -static void UpdateEventFile(const Json::Value& aExtraData, const string& aHash, - const string& aPingUuid) { - if (gEventsPath.empty()) { - // If there is no path for finding the crash event, skip this step. - return; - } - - string localId = CrashReporter::GetDumpLocalID(); - string path = gEventsPath + UI_DIR_SEPARATOR + localId; - string eventVersion; - string crashTime; - string crashUuid; - Json::Value eventData; - - if (!ReadEventFile(path, eventVersion, crashTime, crashUuid, eventData)) { - return; - } - - if (!aHash.empty()) { - eventData["MinidumpSha256Hash"] = aHash; - } - - if (!aPingUuid.empty()) { - eventData["CrashPingUUID"] = aPingUuid; - } - - if (aExtraData.isMember("StackTraces")) { - eventData["StackTraces"] = aExtraData["StackTraces"]; - } - - OverwriteEventFile(path, eventVersion, crashTime, crashUuid, eventData); -} - -static void WriteSubmissionEvent(SubmissionResult result, - const string& remoteId) { - if (gEventsPath.empty()) { - // If there is no path for writing the submission event, skip it. - return; - } - - string localId = CrashReporter::GetDumpLocalID(); - string fpath = gEventsPath + UI_DIR_SEPARATOR + localId + "-submission"; - ofstream* f = UIOpenWrite(fpath, ios::binary); - time_t tm; - time(&tm); - - if (f->is_open()) { - *f << "crash.submission.1\n"; - *f << tm << "\n"; - *f << localId << "\n"; - *f << (result == Succeeded ? "true" : "false") << "\n"; - *f << remoteId; - - f->close(); - } - - delete f; -} - -void LogMessage(const std::string& message) { - if (gLogStream.get()) { - char date[64]; - time_t tm; - time(&tm); - if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0) - date[0] = '\0'; - (*gLogStream) << "[" << date << "] " << message << '\n'; - } -} - -static void OpenLogFile() { - string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log"; - gLogStream.reset(UIOpenWrite(logPath, ios::app)); -} - -static bool ReadConfig() { - string iniPath; - if (!UIGetIniPath(iniPath)) { - return false; - } - - if (!ReadStringsFromFile(iniPath, gStrings, true)) return false; - - // See if we have a string override file, if so process it - char* overrideEnv = getenv("MOZ_CRASHREPORTER_STRINGS_OVERRIDE"); - if (overrideEnv && *overrideEnv && UIFileExists(overrideEnv)) - ReadStringsFromFile(overrideEnv, gStrings, true); - - return true; -} - -static string GetAdditionalFilename(const string& dumpfile, - const char* extension) { - string filename(dumpfile); - int dot = filename.rfind('.'); - if (dot < 0) return ""; - - filename.replace(dot, filename.length() - dot, extension); - return filename; -} - -static bool MoveCrashData(const string& toDir, string& dumpfile, - string& extrafile, string& memoryfile) { - if (!UIEnsurePathExists(toDir)) { - UIError(gStrings[ST_ERROR_CREATEDUMPDIR]); - return false; - } - - string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile); - string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile); - string newMemory = toDir + UI_DIR_SEPARATOR + Basename(memoryfile); - - if (!UIMoveFile(dumpfile, newDump)) { - UIError(gStrings[ST_ERROR_DUMPFILEMOVE]); - return false; - } - - if (!UIMoveFile(extrafile, newExtra)) { - UIError(gStrings[ST_ERROR_EXTRAFILEMOVE]); - return false; - } - - if (!memoryfile.empty()) { - // Ignore errors from moving the memory file - if (!UIMoveFile(memoryfile, newMemory)) { - UIDeleteFile(memoryfile); - newMemory.erase(); - } - memoryfile = newMemory; - } - - dumpfile = newDump; - extrafile = newExtra; - - return true; -} - -static bool AddSubmittedReport(const string& serverResponse) { - StringTable responseItems; - istringstream in(serverResponse); - ReadStrings(in, responseItems, false); - - if (responseItems.find("StopSendingReportsFor") != responseItems.end()) { - // server wants to tell us to stop sending reports for a certain version - string reportPath = gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + - responseItems["StopSendingReportsFor"]; - - ofstream* reportFile = UIOpenWrite(reportPath, ios::trunc); - if (reportFile->is_open()) { - // don't really care about the contents - *reportFile << 1 << "\n"; - reportFile->close(); - } - delete reportFile; - } - - if (responseItems.find("Discarded") != responseItems.end()) { - // server discarded this report... save it so the user can resubmit it - // manually - return false; - } - - if (responseItems.find("CrashID") == responseItems.end()) return false; - - string submittedDir = gSettingsPath + UI_DIR_SEPARATOR + "submitted"; - if (!UIEnsurePathExists(submittedDir)) { - return false; - } - - string path = - submittedDir + UI_DIR_SEPARATOR + responseItems["CrashID"] + ".txt"; - - ofstream* file = UIOpenWrite(path, ios::trunc); - if (!file->is_open()) { - delete file; - return false; - } - - char buf[1024]; - snprintf(buf, 1024, gStrings["CrashID"].c_str(), - responseItems["CrashID"].c_str()); - *file << buf << "\n"; - - if (responseItems.find("ViewURL") != responseItems.end()) { - snprintf(buf, 1024, gStrings["CrashDetailsURL"].c_str(), - responseItems["ViewURL"].c_str()); - *file << buf << "\n"; - } - - file->close(); - delete file; - - WriteSubmissionEvent(Succeeded, responseItems["CrashID"]); - return true; -} - -void DeleteDump() { - const char* noDelete = getenv("MOZ_CRASHREPORTER_NO_DELETE_DUMP"); - if (!noDelete || *noDelete == '\0') { - if (!gReporterDumpFile.empty()) UIDeleteFile(gReporterDumpFile); - if (!gExtraFile.empty()) UIDeleteFile(gExtraFile); - if (!gMemoryFile.empty()) UIDeleteFile(gMemoryFile); - } -} - -void SendCompleted(bool success, const string& serverResponse) { - if (success) { - if (AddSubmittedReport(serverResponse)) { - DeleteDump(); - } else { - string directory = gReporterDumpFile; - int slashpos = directory.find_last_of("/\\"); - if (slashpos < 2) return; - directory.resize(slashpos); - UIPruneSavedDumps(directory); - WriteSubmissionEvent(Failed, ""); - } - } else { - WriteSubmissionEvent(Failed, ""); - } -} - -static string ComputeDumpHash() { -#ifdef XP_LINUX - // On Linux we rely on the system-provided libcurl which uses nss so we have - // to also use the system-provided nss instead of the ones we have bundled. - const char* libnssNames[] = { - "libnss3.so", -# ifndef HAVE_64BIT_BUILD - // 32-bit versions on 64-bit hosts - "/usr/lib32/libnss3.so", -# endif - }; - void* lib = nullptr; - - for (const char* libname : libnssNames) { - lib = dlopen(libname, RTLD_NOW); - - if (lib) { - break; - } - } - - if (!lib) { - return ""; - } - - SECStatus (*NSS_Initialize)(const char*, const char*, const char*, - const char*, PRUint32); - HASHContext* (*HASH_Create)(HASH_HashType); - void (*HASH_Destroy)(HASHContext*); - void (*HASH_Begin)(HASHContext*); - void (*HASH_Update)(HASHContext*, const unsigned char*, unsigned int); - void (*HASH_End)(HASHContext*, unsigned char*, unsigned int*, unsigned int); - - *(void**)(&NSS_Initialize) = dlsym(lib, "NSS_Initialize"); - *(void**)(&HASH_Create) = dlsym(lib, "HASH_Create"); - *(void**)(&HASH_Destroy) = dlsym(lib, "HASH_Destroy"); - *(void**)(&HASH_Begin) = dlsym(lib, "HASH_Begin"); - *(void**)(&HASH_Update) = dlsym(lib, "HASH_Update"); - *(void**)(&HASH_End) = dlsym(lib, "HASH_End"); - - if (!HASH_Create || !HASH_Destroy || !HASH_Begin || !HASH_Update || - !HASH_End) { - return ""; - } -#endif - // Minimal NSS initialization so we can use the hash functions - const PRUint32 kNssFlags = NSS_INIT_READONLY | NSS_INIT_NOROOTINIT | - NSS_INIT_NOMODDB | NSS_INIT_NOCERTDB; - if (NSS_Initialize(nullptr, "", "", "", kNssFlags) != SECSuccess) { - return ""; - } - - HASHContext* hashContext = HASH_Create(HASH_AlgSHA256); - - if (!hashContext) { - return ""; - } - - HASH_Begin(hashContext); - - ifstream* f = UIOpenRead(gReporterDumpFile, ios::binary); - bool error = false; - - // Read the minidump contents - if (f->is_open()) { - uint8_t buff[4096]; - - do { - f->read((char*)buff, sizeof(buff)); - - if (f->bad()) { - error = true; - break; - } - - HASH_Update(hashContext, buff, f->gcount()); - } while (!f->eof()); - - f->close(); - } else { - error = true; - } - - delete f; - - // Finalize the hash computation - uint8_t result[SHA256_LENGTH]; - uint32_t resultLen = 0; - - HASH_End(hashContext, result, &resultLen, SHA256_LENGTH); - - if (resultLen != SHA256_LENGTH) { - error = true; - } - - HASH_Destroy(hashContext); - - if (!error) { - ostringstream hash; - - for (size_t i = 0; i < SHA256_LENGTH; i++) { - hash << std::setw(2) << std::setfill('0') << std::hex - << static_cast(result[i]); - } - - return hash.str(); - } - return ""; // If we encountered an error, return an empty hash -} - -string GetDumpLocalID() { - string localId = Basename(gReporterDumpFile); - string::size_type dot = localId.rfind('.'); - - if (dot == string::npos) return ""; - - return localId.substr(0, dot); -} - -string GetProgramPath(const string& exename) { - string path = gArgv[0]; - size_t pos = path.rfind(UI_CRASH_REPORTER_FILENAME BIN_SUFFIX); - path.erase(pos); -#ifdef XP_MACOSX - // On macOS the crash reporter client is shipped as an application bundle - // contained within Firefox' main application bundle. So when it's invoked - // its current working directory looks like: - // Firefox.app/Contents/MacOS/crashreporter.app/Contents/MacOS/ - // The other applications we ship with Firefox are stored in the main bundle - // (Firefox.app/Contents/MacOS/) so we we need to go back three directories - // to reach them. - path.erase(pos - 1); - for (size_t i = 0; i < 3; i++) { - pos = path.rfind(UI_DIR_SEPARATOR, pos - 1); - } - - path.erase(pos + 1); -#endif // XP_MACOSX - path.append(exename + BIN_SUFFIX); - - return path; -} - -} // namespace CrashReporter - -using namespace CrashReporter; - -Json::Value kEmptyJsonString(""); - -void RewriteStrings(Json::Value& aExtraData) { - // rewrite some UI strings with the values from the query parameters - string product = aExtraData.get("ProductName", kEmptyJsonString).asString(); - Json::Value mozilla("Mozilla"); - string vendor = aExtraData.get("Vendor", mozilla).asString(); - - char buf[4096]; - snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERVENDORTITLE].c_str(), - vendor.c_str()); - gStrings[ST_CRASHREPORTERTITLE] = buf; - - string str = gStrings[ST_CRASHREPORTERPRODUCTERROR]; - // Only do the replacement here if the string has two - // format specifiers to start. Otherwise - // we assume it has the product name hardcoded. - string::size_type pos = str.find("%s"); - if (pos != string::npos) pos = str.find("%s", pos + 2); - if (pos != string::npos) { - // Leave a format specifier for UIError to fill in - snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERPRODUCTERROR].c_str(), - product.c_str(), "%s"); - gStrings[ST_CRASHREPORTERERROR] = buf; - } else { - // product name is hardcoded - gStrings[ST_CRASHREPORTERERROR] = str; - } - - snprintf(buf, sizeof(buf), gStrings[ST_CRASHREPORTERDESCRIPTION].c_str(), - product.c_str()); - gStrings[ST_CRASHREPORTERDESCRIPTION] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_CHECKSUBMIT].c_str(), vendor.c_str()); - gStrings[ST_CHECKSUBMIT] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_RESTART].c_str(), product.c_str()); - gStrings[ST_RESTART] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_QUIT].c_str(), product.c_str()); - gStrings[ST_QUIT] = buf; - - snprintf(buf, sizeof(buf), gStrings[ST_ERROR_ENDOFLIFE].c_str(), - product.c_str()); - gStrings[ST_ERROR_ENDOFLIFE] = buf; -} - -bool CheckEndOfLifed(const Json::Value& aVersion) { - if (!aVersion.isString()) { - return false; - } - - string reportPath = - gSettingsPath + UI_DIR_SEPARATOR + "EndOfLife" + aVersion.asString(); - return UIFileExists(reportPath); -} - -int main(int argc, char** argv) { - gArgc = argc; - gArgv = argv; - - string autoSubmitEnv = UIGetEnv("MOZ_CRASHREPORTER_AUTO_SUBMIT"); - gAutoSubmit = !autoSubmitEnv.empty(); - - if (!ReadConfig()) { - UIError("Couldn't read configuration."); - return 0; - } - - if (!UIInit()) { - return 0; - } - - if (argc > 1) { - gReporterDumpFile = argv[1]; - } - - if (gReporterDumpFile.empty()) { - // no dump file specified, run the default UI - if (!gAutoSubmit) { - UIShowDefaultUI(); - } - } else { - // Start by running minidump analyzer to gather stack traces. - string reporterDumpFile = gReporterDumpFile; - vector args = {reporterDumpFile}; - string dumpAllThreadsEnv = UIGetEnv("MOZ_CRASHREPORTER_DUMP_ALL_THREADS"); - if (!dumpAllThreadsEnv.empty()) { - args.insert(args.begin(), "--full"); - } - UIRunProgram(CrashReporter::GetProgramPath(UI_MINIDUMP_ANALYZER_FILENAME), - args, - /* wait */ true); - - // go ahead with the crash reporter - gExtraFile = GetAdditionalFilename(gReporterDumpFile, kExtraDataExtension); - if (gExtraFile.empty()) { - UIError(gStrings[ST_ERROR_BADARGUMENTS]); - return 0; - } - - if (!UIFileExists(gExtraFile)) { - UIError(gStrings[ST_ERROR_EXTRAFILEEXISTS]); - return 0; - } - - gMemoryFile = - GetAdditionalFilename(gReporterDumpFile, kMemoryReportExtension); - if (!UIFileExists(gMemoryFile)) { - gMemoryFile.erase(); - } - - Json::Value extraData; - if (!ReadExtraFile(gExtraFile, extraData)) { - UIError(gStrings[ST_ERROR_EXTRAFILEREAD]); - return 0; - } - - if (!extraData.isMember("ProductName")) { - UIError(gStrings[ST_ERROR_NOPRODUCTNAME]); - return 0; - } - - // There is enough information in the extra file to rewrite strings - // to be product specific - RewriteStrings(extraData); - - if (!extraData.isMember("ServerURL")) { - UIError(gStrings[ST_ERROR_NOSERVERURL]); - return 0; - } - - // Hopefully the settings path exists in the environment. Try that before - // asking the platform-specific code to guess. - gSettingsPath = UIGetEnv("MOZ_CRASHREPORTER_DATA_DIRECTORY"); - if (gSettingsPath.empty()) { - string product = - extraData.get("ProductName", kEmptyJsonString).asString(); - string vendor = extraData.get("Vendor", kEmptyJsonString).asString(); - - if (!UIGetSettingsPath(vendor, product, gSettingsPath)) { - gSettingsPath.clear(); - } - } - - if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) { - UIError(gStrings[ST_ERROR_NOSETTINGSPATH]); - return 0; - } - - OpenLogFile(); - - gEventsPath = UIGetEnv("MOZ_CRASHREPORTER_EVENTS_DIRECTORY"); - gPingPath = UIGetEnv("MOZ_CRASHREPORTER_PING_DIRECTORY"); - - // Assemble and send the crash ping - string hash = ComputeDumpHash(); - - string pingUuid; - SendCrashPing(extraData, hash, pingUuid, gPingPath); - UpdateEventFile(extraData, hash, pingUuid); - - if (!UIFileExists(gReporterDumpFile)) { - UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]); - return 0; - } - - string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending"; - if (!MoveCrashData(pendingDir, gReporterDumpFile, gExtraFile, - gMemoryFile)) { - return 0; - } - - string sendURL = extraData.get("ServerURL", kEmptyJsonString).asString(); - // we don't need to actually send these - extraData.removeMember("ServerURL"); - extraData.removeMember("StackTraces"); - - extraData["SubmittedFrom"] = "Client"; - extraData["Throttleable"] = "1"; - - // re-set XUL_APP_FILE for xulrunner wrapped apps - const char* appfile = getenv("MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE"); - if (appfile && *appfile) { - const char prefix[] = "XUL_APP_FILE="; - char* env = (char*)malloc(strlen(appfile) + strlen(prefix) + 1); - if (!env) { - UIError("Out of memory"); - return 0; - } - strcpy(env, prefix); - strcat(env, appfile); - putenv(env); - free(env); - } - - vector restartArgs; - - if (!extraData.isMember("WindowsErrorReporting")) { - // We relaunch the application associated with the client, but only when - // we encountered a crash caught by the exception handler. Crashes handled - // by WER are prevented from directly restarting the application. - string programPath = GetProgramPath(MOZ_APP_NAME); -#ifndef XP_WIN - const char* moz_app_launcher = getenv("MOZ_APP_LAUNCHER"); - if (moz_app_launcher) { - programPath = moz_app_launcher; - } -#endif // XP_WIN - - restartArgs.push_back(programPath); - - ostringstream paramName; - int i = 1; - paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++; - const char* param = getenv(paramName.str().c_str()); - while (param && *param) { - restartArgs.push_back(param); - - paramName.str(""); - paramName << "MOZ_CRASHREPORTER_RESTART_ARG_" << i++; - param = getenv(paramName.str().c_str()); - } - } - - // allow override of the server url via environment variable - // XXX: remove this in the far future when our robot - // masters force everyone to use XULRunner - char* urlEnv = getenv("MOZ_CRASHREPORTER_URL"); - if (urlEnv && *urlEnv) { - sendURL = urlEnv; - } - - // see if this version has been end-of-lifed - - if (extraData.isMember("Version") && - CheckEndOfLifed(extraData["Version"])) { - UIError(gStrings[ST_ERROR_ENDOFLIFE]); - DeleteDump(); - return 0; - } - - StringTable files; - files["upload_file_minidump"] = gReporterDumpFile; - if (!gMemoryFile.empty()) { - files["memory_report"] = gMemoryFile; - } - - if (!UIShowCrashUI(files, extraData, sendURL, restartArgs)) { - DeleteDump(); - } - } - - UIShutdown(); - - return 0; -} - -#if defined(XP_WIN) && !defined(__GNUC__) -# include - -// We need WinMain in order to not be a console app. This function is unused -// if we are a console application. -int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR args, int) { - // Remove everything except close window from the context menu - { - HKEY hkApp; - RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications", 0, - nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr, - &hkApp, nullptr); - RegCloseKey(hkApp); - if (RegCreateKeyExW(HKEY_CURRENT_USER, - L"Software\\Classes\\Applications\\crashreporter.exe", - 0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE, nullptr, - &hkApp, nullptr) == ERROR_SUCCESS) { - RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0); - RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0); - RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0); - RegCloseKey(hkApp); - } - } - - char** argv = static_cast(malloc(__argc * sizeof(char*))); - for (int i = 0; i < __argc; i++) { - argv[i] = strdup(WideToUTF8(__wargv[i]).c_str()); - } - - // Do the real work. - return main(__argc, argv); -} -#endif diff --git a/toolkit/crashreporter/client/crashreporter.exe.manifest b/toolkit/crashreporter/client/crashreporter.exe.manifest deleted file mode 100644 index 81aa1465c6e7..000000000000 --- a/toolkit/crashreporter/client/crashreporter.exe.manifest +++ /dev/null @@ -1,42 +0,0 @@ - - - -Crash Reporter - - - - - - - - - - - - - - - true - - - - - - - - - - - diff --git a/toolkit/crashreporter/client/crashreporter.h b/toolkit/crashreporter/client/crashreporter.h deleted file mode 100644 index fa7085da1855..000000000000 --- a/toolkit/crashreporter/client/crashreporter.h +++ /dev/null @@ -1,158 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef CRASHREPORTER_H__ -#define CRASHREPORTER_H__ - -#ifdef _MSC_VER -# pragma warning(push) -// Disable exception handler warnings. -# pragma warning(disable : 4530) -#endif - -#include -#include -#include -#include -#include -#include - -#define MAX_COMMENT_LENGTH 10000 - -#if defined(XP_WIN) - -# include - -# define UI_DIR_SEPARATOR "\\" - -std::string WideToUTF8(const std::wstring& wide, bool* success = 0); - -#else - -# define UI_DIR_SEPARATOR "/" - -#endif - -#include "json/json.h" - -#define UI_CRASH_REPORTER_FILENAME "crashreporter" -#define UI_MINIDUMP_ANALYZER_FILENAME "minidump-analyzer" -#define UI_PING_SENDER_FILENAME "pingsender" - -typedef std::map StringTable; - -#define ST_CRASHREPORTERTITLE "CrashReporterTitle" -#define ST_CRASHREPORTERVENDORTITLE "CrashReporterVendorTitle" -#define ST_CRASHREPORTERERROR "CrashReporterErrorText" -#define ST_CRASHREPORTERPRODUCTERROR "CrashReporterProductErrorText2" -#define ST_CRASHREPORTERHEADER "CrashReporterSorry" -#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescriptionText2" -#define ST_CRASHREPORTERDEFAULT "CrashReporterDefault" -#define ST_VIEWREPORT "Details" -#define ST_VIEWREPORTTITLE "ViewReportTitle" -#define ST_COMMENTGRAYTEXT "CommentGrayText" -#define ST_EXTRAREPORTINFO "ExtraReportInfo" -#define ST_CHECKSUBMIT "CheckSendReport" -#define ST_CHECKURL "CheckIncludeURL" -#define ST_REPORTPRESUBMIT "ReportPreSubmit2" -#define ST_REPORTDURINGSUBMIT "ReportDuringSubmit2" -#define ST_REPORTSUBMITSUCCESS "ReportSubmitSuccess" -#define ST_SUBMITFAILED "ReportSubmitFailed" -#define ST_QUIT "Quit2" -#define ST_RESTART "Restart" -#define ST_OK "Ok" -#define ST_CLOSE "Close" - -#define ST_ERROR_BADARGUMENTS "ErrorBadArguments" -#define ST_ERROR_EXTRAFILEEXISTS "ErrorExtraFileExists" -#define ST_ERROR_EXTRAFILEREAD "ErrorExtraFileRead" -#define ST_ERROR_EXTRAFILEMOVE "ErrorExtraFileMove" -#define ST_ERROR_DUMPFILEEXISTS "ErrorDumpFileExists" -#define ST_ERROR_DUMPFILEMOVE "ErrorDumpFileMove" -#define ST_ERROR_NOPRODUCTNAME "ErrorNoProductName" -#define ST_ERROR_NOSERVERURL "ErrorNoServerURL" -#define ST_ERROR_NOSETTINGSPATH "ErrorNoSettingsPath" -#define ST_ERROR_CREATEDUMPDIR "ErrorCreateDumpDir" -#define ST_ERROR_ENDOFLIFE "ErrorEndOfLife" - -//============================================================================= -// implemented in crashreporter.cpp and ping.cpp -//============================================================================= - -namespace CrashReporter { -extern StringTable gStrings; -extern std::string gSettingsPath; -extern std::string gEventsPath; -extern int gArgc; -extern char** gArgv; -extern bool gAutoSubmit; - -void UIError(const std::string& message); - -// The UI finished sending the report -void SendCompleted(bool success, const std::string& serverResponse); - -bool ReadStrings(std::istream& in, StringTable& strings, bool unescape); -bool ReadStringsFromFile(const std::string& path, StringTable& strings, - bool unescape); -void LogMessage(const std::string& message); -void DeleteDump(); - -std::string GetDumpLocalID(); -std::string GetProgramPath(const std::string& exename); - -// Telemetry ping -bool SendCrashPing(Json::Value& extra, const std::string& hash, - std::string& pingUuid, const std::string& pingDir); - -static const unsigned int kSaveCount = 10; -} // namespace CrashReporter - -//============================================================================= -// implemented in the platform-specific files -//============================================================================= - -bool UIInit(); -void UIShutdown(); - -// Run the UI for when the app was launched without a dump file -void UIShowDefaultUI(); - -// Run the UI for when the app was launched with a dump file -// Return true if the user sent (or tried to send) the crash report, -// false if they chose not to, and it should be deleted. -bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, - const std::string& sendURL, - const std::vector& restartArgs); - -void UIError_impl(const std::string& message); - -bool UIGetIniPath(std::string& path); -bool UIGetSettingsPath(const std::string& vendor, const std::string& product, - std::string& settingsPath); -bool UIEnsurePathExists(const std::string& path); -bool UIFileExists(const std::string& path); -bool UIMoveFile(const std::string& oldfile, const std::string& newfile); -bool UIDeleteFile(const std::string& oldfile); -std::ifstream* UIOpenRead(const std::string& filename, - std::ios_base::openmode mode); -std::ofstream* UIOpenWrite(const std::string& filename, - std::ios_base::openmode mode); -void UIPruneSavedDumps(const std::string& directory); - -// Run the program specified by exename, passing it the parameters in arg. -// If wait is true, wait for the program to terminate execution before -// returning. Returns true if the program was launched correctly, false -// otherwise. -bool UIRunProgram(const std::string& exename, - const std::vector& args, bool wait = false); - -// Read the environment variable specified by name -std::string UIGetEnv(const std::string& name); - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#endif diff --git a/toolkit/crashreporter/client/crashreporter.ico b/toolkit/crashreporter/client/crashreporter.ico deleted file mode 100644 index 29ac3c618998..000000000000 Binary files a/toolkit/crashreporter/client/crashreporter.ico and /dev/null differ diff --git a/toolkit/crashreporter/client/crashreporter.rc b/toolkit/crashreporter/client/crashreporter.rc deleted file mode 100755 index f6042bf2e568..000000000000 --- a/toolkit/crashreporter/client/crashreporter.rc +++ /dev/null @@ -1,143 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winresrc.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winresrc.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_MAINICON ICON "crashreporter.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// AVI -// - -IDR_THROBBER AVI "Throbber-small.avi" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_SENDDIALOG DIALOGEX 0, 0, 241, 187 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_APPWINDOW -CAPTION "Sending Crash Report..." -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_DESCRIPTIONTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY,8,7,226,12,WS_EX_TRANSPARENT - CONTROL "tell mozilla about this crash so they can fix it",IDC_SUBMITREPORTCHECK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,25,222,10 - CHECKBOX "details...",IDC_VIEWREPORTBUTTON,24,40,54,14,BS_PUSHLIKE - EDITTEXT IDC_COMMENTTEXT,24,59,210,43,ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL - CONTROL "include the address of the page i was on",IDC_INCLUDEURLCHECK, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,107,210,10 - CONTROL "",IDC_THROBBER,"SysAnimate32",ACS_TRANSPARENT | NOT WS_VISIBLE | WS_TABSTOP,4,152,16,16 - LTEXT "your crash report will be submitted when you restart",IDC_PROGRESSTEXT,24,152,210,10,SS_NOPREFIX - DEFPUSHBUTTON "restart firefox",IDC_RESTARTBUTTON,84,166,68,14 - PUSHBUTTON "quit without sending",IDC_CLOSEBUTTON,157,166,77,14 -END - -IDD_VIEWREPORTDIALOG DIALOGEX 0, 0, 208, 126 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION -CAPTION "view report" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_VIEWREPORTTEXT,"RICHEDIT50W",ES_MULTILINE | ES_READONLY | WS_BORDER | WS_VSCROLL | WS_TABSTOP,7,7,194,92 - DEFPUSHBUTTON "OK",IDOK,151,105,50,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_SENDDIALOG, DIALOG - BEGIN - LEFTMARGIN, 8 - RIGHTMARGIN, 234 - TOPMARGIN, 7 - BOTTOMMARGIN, 180 - END - - IDD_VIEWREPORTDIALOG, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 201 - TOPMARGIN, 7 - BOTTOMMARGIN, 119 - END -END -#endif // APSTUDIO_INVOKED - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp b/toolkit/crashreporter/client/crashreporter_gtk_common.cpp deleted file mode 100644 index b9a957cfd98a..000000000000 --- a/toolkit/crashreporter/client/crashreporter_gtk_common.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "common/linux/http_upload.h" -#include "crashreporter.h" -#include "crashreporter_gtk_common.h" - -#ifndef GDK_KEY_Escape -# define GDK_KEY_Escape GDK_Escape -#endif - -using std::string; -using std::vector; - -using namespace CrashReporter; - -GtkWidget* gWindow = 0; -GtkWidget* gSubmitReportCheck = 0; -GtkWidget* gIncludeURLCheck = 0; -GtkWidget* gThrobber = 0; -GtkWidget* gProgressLabel = 0; -GtkWidget* gCloseButton = 0; -GtkWidget* gRestartButton = 0; - -bool gInitialized = false; -bool gDidTrySend = false; -StringTable gFiles; -Json::Value gQueryParameters; -string gHttpProxy; -string gAuth; -string gCACertificateFile; -string gSendURL; -string gURLParameter; -vector gRestartArgs; -GThread* gSendThreadID; - -// From crashreporter_linux.cpp -void SendReport(); -void DisableGUIAndSendReport(); -void TryInitGnome(); -void UpdateSubmit(); - -static bool RestartApplication() { - char** argv = reinterpret_cast( - malloc(sizeof(char*) * (gRestartArgs.size() + 1))); - - if (!argv) return false; - - unsigned int i; - for (i = 0; i < gRestartArgs.size(); i++) { - argv[i] = (char*)gRestartArgs[i].c_str(); - } - argv[i] = 0; - - pid_t pid = fork(); - if (pid == -1) { - free(argv); - return false; - } - - if (pid == 0) { - (void)execv(argv[0], argv); - _exit(1); - } - - free(argv); - - return true; -} - -// Quit the app, used as a timeout callback -gboolean CloseApp(gpointer data) { - if (!gAutoSubmit) { - gtk_main_quit(); - } - g_thread_join(gSendThreadID); - return FALSE; -} - -static gboolean ReportCompleted(gpointer success) { - gtk_widget_hide(gThrobber); - string str = - success ? gStrings[ST_REPORTSUBMITSUCCESS] : gStrings[ST_SUBMITFAILED]; - gtk_label_set_text(GTK_LABEL(gProgressLabel), str.c_str()); - g_timeout_add(5000, CloseApp, 0); - return FALSE; -} - -#define HTTP_PROXY_DIR "/system/http_proxy" - -void LoadProxyinfo() { - class GConfClient; - typedef GConfClient* (*_gconf_default_fn)(); - typedef gboolean (*_gconf_bool_fn)(GConfClient*, const gchar*, GError**); - typedef gint (*_gconf_int_fn)(GConfClient*, const gchar*, GError**); - typedef gchar* (*_gconf_string_fn)(GConfClient*, const gchar*, GError**); - - if (getenv("http_proxy")) - return; // libcurl can use the value from the environment - - static void* gconfLib = dlopen("libgconf-2.so.4", RTLD_LAZY); - if (!gconfLib) return; - - _gconf_default_fn gconf_client_get_default = - (_gconf_default_fn)dlsym(gconfLib, "gconf_client_get_default"); - _gconf_bool_fn gconf_client_get_bool = - (_gconf_bool_fn)dlsym(gconfLib, "gconf_client_get_bool"); - _gconf_int_fn gconf_client_get_int = - (_gconf_int_fn)dlsym(gconfLib, "gconf_client_get_int"); - _gconf_string_fn gconf_client_get_string = - (_gconf_string_fn)dlsym(gconfLib, "gconf_client_get_string"); - - if (!(gconf_client_get_default && gconf_client_get_bool && - gconf_client_get_int && gconf_client_get_string)) { - dlclose(gconfLib); - return; - } - - GConfClient* conf = gconf_client_get_default(); - - if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_http_proxy", nullptr)) { - gint port; - gchar *host = nullptr, *httpproxy = nullptr; - - host = gconf_client_get_string(conf, HTTP_PROXY_DIR "/host", nullptr); - port = gconf_client_get_int(conf, HTTP_PROXY_DIR "/port", nullptr); - - if (port && host && *host != '\0') { - httpproxy = g_strdup_printf("http://%s:%d/", host, port); - gHttpProxy = httpproxy; - } - - g_free(host); - g_free(httpproxy); - - if (gconf_client_get_bool(conf, HTTP_PROXY_DIR "/use_authentication", - nullptr)) { - gchar *user, *password, *auth = nullptr; - - user = gconf_client_get_string( - conf, HTTP_PROXY_DIR "/authentication_user", nullptr); - password = gconf_client_get_string( - conf, HTTP_PROXY_DIR "/authentication_password", nullptr); - - if (user && password) { - auth = g_strdup_printf("%s:%s", user, password); - gAuth = auth; - } - - g_free(user); - g_free(password); - g_free(auth); - } - } - - g_object_unref(conf); - - // Don't dlclose gconfLib as libORBit-2 uses atexit(). -} - -gpointer SendThread(gpointer args) { - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - string parameters(writeString(builder, gQueryParameters)); - - string response, error; - long response_code; - - bool success = google_breakpad::HTTPUpload::SendRequest( - gSendURL, parameters, gFiles, gHttpProxy, gAuth, gCACertificateFile, - &response, &response_code, &error); - if (success) { - LogMessage("Crash report submitted successfully"); - } else { - LogMessage("Crash report submission failed: " + error); - } - - SendCompleted(success, response); - - if (!gAutoSubmit) { - // Apparently glib is threadsafe, and will schedule this - // on the main thread, see: - // http://library.gnome.org/devel/gtk-faq/stable/x499.html - g_idle_add(ReportCompleted, (gpointer)success); - } - - return nullptr; -} - -gboolean WindowDeleted(GtkWidget* window, GdkEvent* event, gpointer userData) { - SaveSettings(); - gtk_main_quit(); - return TRUE; -} - -gboolean check_escape(GtkWidget* window, GdkEventKey* event, - gpointer userData) { - if (event->keyval == GDK_KEY_Escape) { - gtk_main_quit(); - return TRUE; - } - return FALSE; -} - -static void MaybeSubmitReport() { - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) { - gDidTrySend = true; - DisableGUIAndSendReport(); - } else { - gtk_main_quit(); - } -} - -void CloseClicked(GtkButton* button, gpointer userData) { - SaveSettings(); - MaybeSubmitReport(); -} - -void RestartClicked(GtkButton* button, gpointer userData) { - SaveSettings(); - RestartApplication(); - MaybeSubmitReport(); -} - -static void UpdateURL() { - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck))) { - gQueryParameters["URL"] = gURLParameter; - } else { - gQueryParameters.removeMember("URL"); - } -} - -void SubmitReportChecked(GtkButton* sender, gpointer userData) { - UpdateSubmit(); -} - -void IncludeURLClicked(GtkButton* sender, gpointer userData) { UpdateURL(); } - -/* === Crashreporter UI Functions === */ - -bool UIInit() { - // breakpad probably left us with blocked signals, unblock them here - sigset_t signals, old; - sigfillset(&signals); - sigprocmask(SIG_UNBLOCK, &signals, &old); - - // tell glib we're going to use threads - g_thread_init(nullptr); - - if (gtk_init_check(&gArgc, &gArgv)) { - gInitialized = true; - - if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") - gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL); - - return true; - } - - return false; -} - -void UIShowDefaultUI() { - GtkWidget* errorDialog = gtk_message_dialog_new( - nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", - gStrings[ST_CRASHREPORTERDEFAULT].c_str()); - - gtk_window_set_title(GTK_WINDOW(errorDialog), - gStrings[ST_CRASHREPORTERTITLE].c_str()); - gtk_dialog_run(GTK_DIALOG(errorDialog)); -} - -void UIError_impl(const string& message) { - if (!gInitialized) { - // Didn't initialize, this is the best we can do - printf("Error: %s\n", message.c_str()); - return; - } - - GtkWidget* errorDialog = - gtk_message_dialog_new(nullptr, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, "%s", message.c_str()); - - gtk_window_set_title(GTK_WINDOW(errorDialog), - gStrings[ST_CRASHREPORTERTITLE].c_str()); - gtk_dialog_run(GTK_DIALOG(errorDialog)); -} - -bool UIGetIniPath(string& path) { - path = gArgv[0]; - path.append(".ini"); - - return true; -} - -/* - * Settings are stored in ~/.vendor/product, or - * ~/.product if vendor is empty. - */ -bool UIGetSettingsPath(const string& vendor, const string& product, - string& settingsPath) { - char* home = getenv("HOME"); - - if (!home) return false; - - settingsPath = home; - settingsPath += "/."; - if (!vendor.empty()) { - string lc_vendor; - std::transform(vendor.begin(), vendor.end(), back_inserter(lc_vendor), - (int (*)(int))std::tolower); - settingsPath += lc_vendor + "/"; - } - string lc_product; - std::transform(product.begin(), product.end(), back_inserter(lc_product), - (int (*)(int))std::tolower); - settingsPath += lc_product + "/Crash Reports"; - return true; -} - -bool UIMoveFile(const string& file, const string& newfile) { - if (!rename(file.c_str(), newfile.c_str())) return true; - if (errno != EXDEV) return false; - - // use system /bin/mv instead, time to fork - pid_t pID = vfork(); - if (pID < 0) { - // Failed to fork - return false; - } - if (pID == 0) { - char* const args[4] = {const_cast("mv"), strdup(file.c_str()), - strdup(newfile.c_str()), 0}; - if (args[1] && args[2]) execve("/bin/mv", args, 0); - free(args[1]); - free(args[2]); - exit(-1); - } - int status; - waitpid(pID, &status, 0); - return UIFileExists(newfile); -} diff --git a/toolkit/crashreporter/client/crashreporter_gtk_common.h b/toolkit/crashreporter/client/crashreporter_gtk_common.h deleted file mode 100644 index 208c7ba6b0b7..000000000000 --- a/toolkit/crashreporter/client/crashreporter_gtk_common.h +++ /dev/null @@ -1,50 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef CRASHREPORTER_GTK_COMMON_H__ -#define CRASHREPORTER_GTK_COMMON_H__ - -#include -#include - -#include -#include - -#include "json/json.h" - -const char kIniFile[] = "crashreporter.ini"; - -extern GtkWidget* gWindow; -extern GtkWidget* gSubmitReportCheck; -extern GtkWidget* gIncludeURLCheck; -extern GtkWidget* gThrobber; -extern GtkWidget* gProgressLabel; -extern GtkWidget* gCloseButton; -extern GtkWidget* gRestartButton; - -extern std::vector gRestartArgs; -extern GThread* gSendThreadID; - -extern bool gInitialized; -extern bool gDidTrySend; -extern StringTable gFiles; -extern Json::Value gQueryParameters; -extern std::string gHttpProxy; -extern std::string gAuth; -extern std::string gCACertificateFile; -extern std::string gSendURL; -extern std::string gURLParameter; - -void LoadProxyinfo(); -gboolean CloseApp(gpointer data); -gpointer SendThread(gpointer args); -gboolean WindowDeleted(GtkWidget* window, GdkEvent* event, gpointer userData); -gboolean check_escape(GtkWidget* window, GdkEventKey* event, gpointer data); -void SubmitReportChecked(GtkButton* sender, gpointer userData); -void IncludeURLClicked(GtkButton* sender, gpointer userData); -void CloseClicked(GtkButton* button, gpointer userData); -void RestartClicked(GtkButton* button, gpointer userData); -void SaveSettings(void); - -#endif // CRASHREPORTER_GTK_COMMON_H__ diff --git a/toolkit/crashreporter/client/crashreporter_linux.cpp b/toolkit/crashreporter/client/crashreporter_linux.cpp deleted file mode 100644 index 644b34654e70..000000000000 --- a/toolkit/crashreporter/client/crashreporter_linux.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include -#include -#include -#include - -#include - -#include "crashreporter.h" -#include "crashreporter_gtk_common.h" - -#define LABEL_MAX_CHAR_WIDTH 48 - -using std::ios; -using std::string; -using std::vector; - -using namespace CrashReporter; - -static GtkWidget* gViewReportButton = 0; -static GtkWidget* gCommentTextLabel = 0; -static GtkWidget* gCommentText = 0; - -static bool gCommentFieldHint = true; - -// handle from dlopen'ing libgnome -static void* gnomeLib = nullptr; -// handle from dlopen'ing libgnomeui -static void* gnomeuiLib = nullptr; - -static void LoadSettings() { - /* - * NOTE! This code needs to stay in sync with the preference checking - * code in in nsExceptionHandler.cpp. - */ - - bool includeURL = true; - bool submitReport = true; - StringTable settings; - if (ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true)) { - if (settings.find("IncludeURL") != settings.end()) { - includeURL = settings["IncludeURL"][0] != '0'; - } - if (settings.find("SubmitReport") != settings.end()) { - submitReport = settings["SubmitReport"][0] != '0'; - } - } - - if (gIncludeURLCheck) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), - includeURL); - } - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck), - submitReport); -} - -static string Escape(const string& str) { - string ret; - for (auto c : str) { - if (c == '\\') { - ret += "\\\\"; - } else if (c == '\n') { - ret += "\\n"; - } else if (c == '\t') { - ret += "\\t"; - } else { - ret.push_back(c); - } - } - - return ret; -} - -static bool WriteStrings(std::ostream& out, const string& header, - StringTable& strings, bool escape) { - out << "[" << header << "]\n"; - for (const auto& iter : strings) { - out << iter.first << "="; - if (escape) { - out << Escape(iter.second); - } else { - out << iter.second; - } - - out << '\n'; - } - - return true; -} - -static bool WriteStringsToFile(const string& path, const string& header, - StringTable& strings, bool escape) { - std::ofstream* f = UIOpenWrite(path, ios::trunc); - bool success = false; - if (f->is_open()) { - success = WriteStrings(*f, header, strings, escape); - f->close(); - } - - delete f; - return success; -} - -void SaveSettings() { - /* - * NOTE! This code needs to stay in sync with the preference setting - * code in in nsExceptionHandler.cpp. - */ - - StringTable settings; - - ReadStringsFromFile(gSettingsPath + "/" + kIniFile, settings, true); - if (gIncludeURLCheck != 0) - settings["IncludeURL"] = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck)) ? "1" - : "0"; - settings["SubmitReport"] = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck)) ? "1" - : "0"; - - WriteStringsToFile(gSettingsPath + "/" + kIniFile, "Crash Reporter", settings, - true); -} - -void SendReport() { - LoadProxyinfo(); - - // spawn a thread to do the sending - gSendThreadID = g_thread_create(SendThread, nullptr, TRUE, nullptr); -} - -void DisableGUIAndSendReport() { - // disable all our gui controls, show the throbber + change the progress text - gtk_widget_set_sensitive(gSubmitReportCheck, FALSE); - gtk_widget_set_sensitive(gViewReportButton, FALSE); - gtk_widget_set_sensitive(gCommentText, FALSE); - if (gIncludeURLCheck) gtk_widget_set_sensitive(gIncludeURLCheck, FALSE); - gtk_widget_set_sensitive(gCloseButton, FALSE); - if (gRestartButton) gtk_widget_set_sensitive(gRestartButton, FALSE); - gtk_widget_show_all(gThrobber); - gtk_label_set_text(GTK_LABEL(gProgressLabel), - gStrings[ST_REPORTDURINGSUBMIT].c_str()); - - SendReport(); -} - -static void ShowReportInfo(GtkTextView* viewReportTextView) { - GtkTextBuffer* buffer = gtk_text_view_get_buffer(viewReportTextView); - - GtkTextIter start, end; - gtk_text_buffer_get_start_iter(buffer, &start); - gtk_text_buffer_get_end_iter(buffer, &end); - - gtk_text_buffer_delete(buffer, &start, &end); - - for (Json::ValueConstIterator iter = gQueryParameters.begin(); - iter != gQueryParameters.end(); ++iter) { - gtk_text_buffer_insert(buffer, &end, iter.name().c_str(), - iter.name().length()); - gtk_text_buffer_insert(buffer, &end, ": ", -1); - string value; - if (iter->isString()) { - value = iter->asString(); - } else { - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - value = writeString(builder, *iter); - } - gtk_text_buffer_insert(buffer, &end, value.c_str(), value.length()); - gtk_text_buffer_insert(buffer, &end, "\n", -1); - } - - gtk_text_buffer_insert(buffer, &end, "\n", -1); - gtk_text_buffer_insert(buffer, &end, gStrings[ST_EXTRAREPORTINFO].c_str(), - -1); -} - -void UpdateSubmit() { - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gSubmitReportCheck))) { - gtk_widget_set_sensitive(gViewReportButton, TRUE); - gtk_widget_set_sensitive(gCommentText, TRUE); - if (gIncludeURLCheck) gtk_widget_set_sensitive(gIncludeURLCheck, TRUE); - gtk_label_set_text(GTK_LABEL(gProgressLabel), - gStrings[ST_REPORTPRESUBMIT].c_str()); - } else { - gtk_widget_set_sensitive(gViewReportButton, FALSE); - gtk_widget_set_sensitive(gCommentText, FALSE); - if (gIncludeURLCheck) gtk_widget_set_sensitive(gIncludeURLCheck, FALSE); - gtk_label_set_text(GTK_LABEL(gProgressLabel), ""); - } -} - -static void ViewReportClicked(GtkButton* button, gpointer userData) { - GtkDialog* dialog = GTK_DIALOG(gtk_dialog_new_with_buttons( - gStrings[ST_VIEWREPORTTITLE].c_str(), GTK_WINDOW(gWindow), - GTK_DIALOG_MODAL, GTK_STOCK_OK, GTK_RESPONSE_OK, nullptr)); - - GtkWidget* scrolled = gtk_scrolled_window_new(0, 0); - gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(dialog)), - scrolled); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), - GTK_SHADOW_IN); - gtk_widget_set_vexpand(scrolled, TRUE); - - GtkWidget* viewReportTextView = gtk_text_view_new(); - gtk_container_add(GTK_CONTAINER(scrolled), viewReportTextView); - gtk_text_view_set_editable(GTK_TEXT_VIEW(viewReportTextView), FALSE); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(viewReportTextView), GTK_WRAP_WORD); - gtk_widget_set_size_request(GTK_WIDGET(viewReportTextView), -1, 100); - - ShowReportInfo(GTK_TEXT_VIEW(viewReportTextView)); - - gtk_dialog_set_default_response(dialog, GTK_RESPONSE_OK); - gtk_widget_set_size_request(GTK_WIDGET(dialog), 400, 200); - gtk_widget_show_all(GTK_WIDGET(dialog)); - gtk_dialog_run(dialog); - gtk_widget_destroy(GTK_WIDGET(dialog)); -} - -static void CommentChanged(GtkTextBuffer* buffer, gpointer userData) { - GtkTextIter start, end; - gtk_text_buffer_get_start_iter(buffer, &start); - gtk_text_buffer_get_end_iter(buffer, &end); - const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); - if (comment[0] == '\0' || gCommentFieldHint) { - gQueryParameters.removeMember("Comments"); - } else { - gQueryParameters["Comments"] = comment; - } -} - -static void CommentInsert(GtkTextBuffer* buffer, GtkTextIter* location, - gchar* text, gint len, gpointer userData) { - GtkTextIter start, end; - gtk_text_buffer_get_start_iter(buffer, &start); - gtk_text_buffer_get_end_iter(buffer, &end); - const char* comment = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); - - // limit to 500 bytes in utf-8 - if (strlen(comment) + len > MAX_COMMENT_LENGTH) { - g_signal_stop_emission_by_name(buffer, "insert-text"); - } -} - -static void UpdateHintText(GtkWidget* widget, gboolean gainedFocus, - bool* hintShowing, const char* hintText) { - GtkTextBuffer* buffer = nullptr; - if (GTK_IS_TEXT_VIEW(widget)) - buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); - - if (gainedFocus) { - if (*hintShowing) { - if (buffer == nullptr) { // sort of cheating - gtk_entry_set_text(GTK_ENTRY(widget), ""); - } else { // GtkTextView - gtk_text_buffer_set_text(buffer, "", 0); - } - gtk_widget_modify_text(widget, GTK_STATE_NORMAL, nullptr); - *hintShowing = false; - } - } else { - // lost focus - const char* text = nullptr; - if (buffer == nullptr) { - text = gtk_entry_get_text(GTK_ENTRY(widget)); - } else { - GtkTextIter start, end; - gtk_text_buffer_get_start_iter(buffer, &start); - gtk_text_buffer_get_end_iter(buffer, &end); - text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); - } - - if (text == nullptr || text[0] == '\0') { - *hintShowing = true; - - if (buffer == nullptr) { - gtk_entry_set_text(GTK_ENTRY(widget), hintText); - } else { - gtk_text_buffer_set_text(buffer, hintText, -1); - } - - gtk_widget_modify_text( - widget, GTK_STATE_NORMAL, - >k_widget_get_style(widget)->text[GTK_STATE_INSENSITIVE]); - } - } -} - -static gboolean CommentFocusChange(GtkWidget* widget, GdkEventFocus* event, - gpointer userData) { - UpdateHintText(widget, event->in, &gCommentFieldHint, - gStrings[ST_COMMENTGRAYTEXT].c_str()); - - return FALSE; -} - -typedef struct _GnomeProgram GnomeProgram; -typedef struct _GnomeModuleInfo GnomeModuleInfo; -typedef GnomeProgram* (*_gnome_program_init_fn)(const char*, const char*, - const GnomeModuleInfo*, int, - char**, const char*, ...); -typedef const GnomeModuleInfo* (*_libgnomeui_module_info_get_fn)(); - -void TryInitGnome() { - gnomeLib = dlopen("libgnome-2.so.0", RTLD_LAZY); - if (!gnomeLib) return; - - gnomeuiLib = dlopen("libgnomeui-2.so.0", RTLD_LAZY); - if (!gnomeuiLib) return; - - _gnome_program_init_fn gnome_program_init = - (_gnome_program_init_fn)(dlsym(gnomeLib, "gnome_program_init")); - _libgnomeui_module_info_get_fn libgnomeui_module_info_get = - (_libgnomeui_module_info_get_fn)(dlsym(gnomeuiLib, - "libgnomeui_module_info_get")); - - if (gnome_program_init && libgnomeui_module_info_get) { - gnome_program_init("crashreporter", "1.0", libgnomeui_module_info_get(), - gArgc, gArgv, nullptr); - } -} - -/* === Crashreporter UI Functions === */ - -/* - * Anything not listed here is in crashreporter_gtk_common.cpp: - * UIInit - * UIShowDefaultUI - * UIError_impl - * UIGetIniPath - * UIGetSettingsPath - * UIEnsurePathExists - * UIFileExists - * UIMoveFile - * UIDeleteFile - * UIOpenRead - * UIOpenWrite - */ - -void UIShutdown() { - if (gnomeuiLib) dlclose(gnomeuiLib); - // Don't dlclose gnomeLib as libgnomevfs and libORBit-2 use atexit(). -} - -bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, - const string& sendURL, const vector& restartArgs) { - gFiles = files; - gQueryParameters = queryParameters; - gSendURL = sendURL; - gRestartArgs = restartArgs; - if (gQueryParameters.isMember("URL")) { - gURLParameter = gQueryParameters["URL"].asString(); - } - - if (gAutoSubmit) { - SendReport(); - CloseApp(nullptr); - return true; - } - - gWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(gWindow), - gStrings[ST_CRASHREPORTERTITLE].c_str()); - gtk_window_set_resizable(GTK_WINDOW(gWindow), FALSE); - gtk_window_set_position(GTK_WINDOW(gWindow), GTK_WIN_POS_CENTER); - gtk_container_set_border_width(GTK_CONTAINER(gWindow), 12); - g_signal_connect(gWindow, "delete-event", G_CALLBACK(WindowDeleted), 0); - g_signal_connect(gWindow, "key_press_event", G_CALLBACK(check_escape), - nullptr); - - GtkWidget* vbox = gtk_vbox_new(FALSE, 6); - gtk_container_add(GTK_CONTAINER(gWindow), vbox); - - GtkWidget* titleLabel = gtk_label_new(""); - gtk_box_pack_start(GTK_BOX(vbox), titleLabel, FALSE, FALSE, 0); - gtk_misc_set_alignment(GTK_MISC(titleLabel), 0, 0.5); - char* markup = - g_strdup_printf("%s", gStrings[ST_CRASHREPORTERHEADER].c_str()); - gtk_label_set_markup(GTK_LABEL(titleLabel), markup); - g_free(markup); - - GtkWidget* descriptionLabel = - gtk_label_new(gStrings[ST_CRASHREPORTERDESCRIPTION].c_str()); - gtk_box_pack_start(GTK_BOX(vbox), descriptionLabel, TRUE, TRUE, 0); - // force the label to line wrap - gtk_label_set_max_width_chars(GTK_LABEL(descriptionLabel), - LABEL_MAX_CHAR_WIDTH); - gtk_label_set_line_wrap(GTK_LABEL(descriptionLabel), TRUE); - gtk_label_set_selectable(GTK_LABEL(descriptionLabel), TRUE); - gtk_misc_set_alignment(GTK_MISC(descriptionLabel), 0, 0.5); - - // this is honestly how they suggest you indent a section - GtkWidget* indentBox = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), indentBox, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(indentBox), gtk_label_new(""), FALSE, FALSE, 6); - - GtkWidget* innerVBox1 = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(indentBox), innerVBox1, TRUE, TRUE, 0); - - gSubmitReportCheck = - gtk_check_button_new_with_label(gStrings[ST_CHECKSUBMIT].c_str()); - gtk_box_pack_start(GTK_BOX(innerVBox1), gSubmitReportCheck, FALSE, FALSE, 0); - g_signal_connect(gSubmitReportCheck, "clicked", - G_CALLBACK(SubmitReportChecked), 0); - - // indent again, below the "submit report" checkbox - GtkWidget* indentBox2 = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(innerVBox1), indentBox2, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(indentBox2), gtk_label_new(""), FALSE, FALSE, 6); - - GtkWidget* innerVBox = gtk_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(indentBox2), innerVBox, TRUE, TRUE, 0); - gtk_box_set_spacing(GTK_BOX(innerVBox), 6); - - GtkWidget* viewReportButtonBox = gtk_hbutton_box_new(); - gtk_box_pack_start(GTK_BOX(innerVBox), viewReportButtonBox, FALSE, FALSE, 0); - gtk_box_set_spacing(GTK_BOX(viewReportButtonBox), 6); - gtk_button_box_set_layout(GTK_BUTTON_BOX(viewReportButtonBox), - GTK_BUTTONBOX_START); - - gViewReportButton = - gtk_button_new_with_label(gStrings[ST_VIEWREPORT].c_str()); - gtk_box_pack_start(GTK_BOX(viewReportButtonBox), gViewReportButton, FALSE, - FALSE, 0); - g_signal_connect(gViewReportButton, "clicked", G_CALLBACK(ViewReportClicked), - 0); - - GtkWidget* scrolled = gtk_scrolled_window_new(0, 0); - gtk_container_add(GTK_CONTAINER(innerVBox), scrolled); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), - GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), - GTK_SHADOW_IN); - gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scrolled), - 100); - - gCommentTextLabel = gtk_label_new(gStrings[ST_COMMENTGRAYTEXT].c_str()); - gCommentText = gtk_text_view_new(); - gtk_label_set_mnemonic_widget(GTK_LABEL(gCommentTextLabel), gCommentText); - gtk_text_view_set_accepts_tab(GTK_TEXT_VIEW(gCommentText), FALSE); - g_signal_connect(gCommentText, "focus-in-event", - G_CALLBACK(CommentFocusChange), 0); - g_signal_connect(gCommentText, "focus-out-event", - G_CALLBACK(CommentFocusChange), 0); - - GtkTextBuffer* commentBuffer = - gtk_text_view_get_buffer(GTK_TEXT_VIEW(gCommentText)); - g_signal_connect(commentBuffer, "changed", G_CALLBACK(CommentChanged), 0); - g_signal_connect(commentBuffer, "insert-text", G_CALLBACK(CommentInsert), 0); - - gtk_container_add(GTK_CONTAINER(scrolled), gCommentText); - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gCommentText), GTK_WRAP_WORD_CHAR); - gtk_widget_set_size_request(GTK_WIDGET(gCommentText), -1, 100); - - if (gQueryParameters.isMember("URL")) { - gIncludeURLCheck = - gtk_check_button_new_with_label(gStrings[ST_CHECKURL].c_str()); - gtk_box_pack_start(GTK_BOX(innerVBox), gIncludeURLCheck, FALSE, FALSE, 0); - g_signal_connect(gIncludeURLCheck, "clicked", G_CALLBACK(IncludeURLClicked), - 0); - // on by default - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gIncludeURLCheck), TRUE); - } - - GtkWidget* progressBox = gtk_hbox_new(FALSE, 6); - gtk_box_pack_start(GTK_BOX(vbox), progressBox, TRUE, TRUE, 0); - - // Get the throbber image from alongside the executable - char* dir = g_path_get_dirname(gArgv[0]); - char* path = g_build_filename(dir, "Throbber-small.gif", nullptr); - g_free(dir); - gThrobber = gtk_image_new_from_file(path); - gtk_box_pack_start(GTK_BOX(progressBox), gThrobber, FALSE, FALSE, 0); - - gProgressLabel = gtk_label_new(gStrings[ST_REPORTPRESUBMIT].c_str()); - gtk_box_pack_start(GTK_BOX(progressBox), gProgressLabel, TRUE, TRUE, 0); - // force the label to line wrap - gtk_label_set_max_width_chars(GTK_LABEL(gProgressLabel), - LABEL_MAX_CHAR_WIDTH); - gtk_label_set_line_wrap(GTK_LABEL(gProgressLabel), TRUE); - - GtkWidget* buttonBox = gtk_hbutton_box_new(); - gtk_box_pack_end(GTK_BOX(vbox), buttonBox, FALSE, FALSE, 0); - gtk_box_set_spacing(GTK_BOX(buttonBox), 6); - gtk_button_box_set_layout(GTK_BUTTON_BOX(buttonBox), GTK_BUTTONBOX_END); - - gCloseButton = gtk_button_new_with_label(gStrings[ST_QUIT].c_str()); - gtk_box_pack_start(GTK_BOX(buttonBox), gCloseButton, FALSE, FALSE, 0); - gtk_widget_set_can_default(gCloseButton, TRUE); - g_signal_connect(gCloseButton, "clicked", G_CALLBACK(CloseClicked), 0); - - gRestartButton = 0; - if (!restartArgs.empty()) { - gRestartButton = gtk_button_new_with_label(gStrings[ST_RESTART].c_str()); - gtk_box_pack_start(GTK_BOX(buttonBox), gRestartButton, FALSE, FALSE, 0); - gtk_widget_set_can_default(gRestartButton, TRUE); - g_signal_connect(gRestartButton, "clicked", G_CALLBACK(RestartClicked), 0); - } - - gtk_widget_grab_focus(gSubmitReportCheck); - - gtk_widget_grab_default(gRestartButton ? gRestartButton : gCloseButton); - - LoadSettings(); - - UpdateSubmit(); - - UpdateHintText(gCommentText, FALSE, &gCommentFieldHint, - gStrings[ST_COMMENTGRAYTEXT].c_str()); - - gtk_widget_show_all(gWindow); - // stick this here to avoid the show_all above... - gtk_widget_hide(gThrobber); - - gtk_main(); - - return gDidTrySend; -} diff --git a/toolkit/crashreporter/client/crashreporter_osx.h b/toolkit/crashreporter/client/crashreporter_osx.h deleted file mode 100644 index d9aeddb4b029..000000000000 --- a/toolkit/crashreporter/client/crashreporter_osx.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef CRASHREPORTER_OSX_H__ -#define CRASHREPORTER_OSX_H__ - -#include -#include "HTTPMultipartUpload.h" -#include "crashreporter.h" -#include "json/json.h" - -// Defined below -@class TextViewWithPlaceHolder; - -@interface CrashReporterUI : NSObject { - IBOutlet NSWindow* mWindow; - - /* Crash reporter view */ - IBOutlet NSTextField* mHeaderLabel; - IBOutlet NSTextField* mDescriptionLabel; - IBOutlet NSButton* mViewReportButton; - IBOutlet NSScrollView* mCommentScrollView; - IBOutlet TextViewWithPlaceHolder* mCommentText; - IBOutlet NSButton* mSubmitReportButton; - IBOutlet NSButton* mIncludeURLButton; - IBOutlet NSButton* mEmailMeButton; - IBOutlet NSTextField* mEmailText; - IBOutlet NSButton* mCloseButton; - IBOutlet NSButton* mRestartButton; - IBOutlet NSProgressIndicator* mProgressIndicator; - IBOutlet NSTextField* mProgressText; - - /* Error view */ - IBOutlet NSView* mErrorView; - IBOutlet NSTextField* mErrorHeaderLabel; - IBOutlet NSTextField* mErrorLabel; - IBOutlet NSButton* mErrorCloseButton; - - /* For "show info" alert */ - IBOutlet NSWindow* mViewReportWindow; - IBOutlet NSTextView* mViewReportTextView; - IBOutlet NSButton* mViewReportOkButton; - - HTTPMultipartUpload* mPost; -} - -- (void)showCrashUI:(const StringTable&)files - queryParameters:(const Json::Value&)queryParameters - sendURL:(const std::string&)sendURL; -- (void)showErrorUI:(const std::string&)message; -- (void)showReportInfo; -- (void)maybeSubmitReport; -- (void)closeMeDown:(id)unused; - -- (IBAction)submitReportClicked:(id)sender; -- (IBAction)viewReportClicked:(id)sender; -- (IBAction)viewReportOkClicked:(id)sender; -- (IBAction)closeClicked:(id)sender; -- (IBAction)restartClicked:(id)sender; -- (IBAction)includeURLClicked:(id)sender; - -- (void)textDidChange:(NSNotification*)aNotification; -- (BOOL)textView:(NSTextView*)aTextView - shouldChangeTextInRange:(NSRange)affectedCharRange - replacementString:(NSString*)replacementString; - -- (void)doInitialResizing; -- (float)setStringFitVertically:(NSControl*)control - string:(NSString*)str - resizeWindow:(BOOL)resizeWindow; -- (void)setView:(NSView*)v animate:(BOOL)animate; -- (void)enableControls:(BOOL)enabled; -- (void)updateSubmit; -- (void)updateURL; -- (void)updateEmail; -- (void)sendReport; -- (bool)setupPost; -- (void)uploadThread:(HTTPMultipartUpload*)post; -- (void)uploadComplete:(NSData*)data; - -- (BOOL)applicationShouldTerminateAfterLastWindowClosed: - (NSApplication*)theApplication; -- (void)applicationWillTerminate:(NSNotification*)aNotification; - -@end - -/* - * Subclass NSTextView to provide a text view with placeholder text. - * Also provide a setEnabled implementation. - */ -@interface TextViewWithPlaceHolder : NSTextView { - NSMutableAttributedString* mPlaceHolderString; -} - -- (BOOL)becomeFirstResponder; -- (void)drawRect:(NSRect)rect; -- (BOOL)resignFirstResponder; -- (void)setPlaceholder:(NSString*)placeholder; -- (void)insertTab:(id)sender; -- (void)insertBacktab:(id)sender; -- (void)setEnabled:(BOOL)enabled; -- (void)dealloc; - -@end - -#endif diff --git a/toolkit/crashreporter/client/crashreporter_osx.mm b/toolkit/crashreporter/client/crashreporter_osx.mm deleted file mode 100644 index b6d5d8ac6fce..000000000000 --- a/toolkit/crashreporter/client/crashreporter_osx.mm +++ /dev/null @@ -1,805 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#import -#import -#include "crashreporter.h" -#include "crashreporter_osx.h" -#include -#include -#include -#include -#include -#include - -using std::ostringstream; -using std::string; -using std::vector; - -using namespace CrashReporter; - -static NSAutoreleasePool* gMainPool; -static CrashReporterUI* gUI = 0; -static StringTable gFiles; -static Json::Value gQueryParameters; -static string gURLParameter; -static string gSendURL; -static vector gRestartArgs; -static bool gDidTrySend = false; -static bool gRTLlayout = false; - -static cpu_type_t pref_cpu_types[2] = { -#if defined(__i386__) - CPU_TYPE_X86, -#elif defined(__x86_64__) - CPU_TYPE_X86_64, -#elif defined(__ppc__) - CPU_TYPE_POWERPC, -#elif defined(__aarch64__) - CPU_TYPE_ARM64, -#endif - CPU_TYPE_ANY}; - -#define NSSTR(s) [NSString stringWithUTF8String:(s).c_str()] - -static NSString* Str(const char* aName) { - string str = gStrings[aName]; - if (str.empty()) str = "?"; - return NSSTR(str); -} - -static bool RestartApplication() { - vector argv(gRestartArgs.size() + 1); - - posix_spawnattr_t spawnattr; - if (posix_spawnattr_init(&spawnattr) != 0) { - return false; - } - - // Set spawn attributes. - size_t attr_count = sizeof(pref_cpu_types) / sizeof(pref_cpu_types[0]); - size_t attr_ocount = 0; - if (posix_spawnattr_setbinpref_np(&spawnattr, attr_count, pref_cpu_types, - &attr_ocount) != 0 || - attr_ocount != attr_count) { - posix_spawnattr_destroy(&spawnattr); - return false; - } - - unsigned int i; - for (i = 0; i < gRestartArgs.size(); i++) { - argv[i] = (char*)gRestartArgs[i].c_str(); - } - argv[i] = 0; - - char** env = NULL; - char*** nsEnv = _NSGetEnviron(); - if (nsEnv) env = *nsEnv; - int result = posix_spawnp(NULL, argv[0], NULL, &spawnattr, &argv[0], env); - - posix_spawnattr_destroy(&spawnattr); - - return result == 0; -} - -@implementation CrashReporterUI - -- (void)awakeFromNib { - gUI = self; - [mWindow center]; - - [mWindow setTitle:[[NSBundle mainBundle] - objectForInfoDictionaryKey:@"CFBundleName"]]; - [NSApp activateIgnoringOtherApps:YES]; -} - -- (void)showCrashUI:(const StringTable&)files - queryParameters:(const Json::Value&)queryParameters - sendURL:(const string&)sendURL { - gFiles = files; - gQueryParameters = queryParameters; - gSendURL = sendURL; - - if (gAutoSubmit) { - gDidTrySend = true; - [self sendReport]; - return; - } - - [mWindow setTitle:Str(ST_CRASHREPORTERTITLE)]; - [mHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)]; - - NSRect viewReportFrame = [mViewReportButton frame]; - [mViewReportButton setTitle:Str(ST_VIEWREPORT)]; - [mViewReportButton sizeToFit]; - if (gRTLlayout) { - // sizeToFit will keep the left side fixed, so realign - float oldWidth = viewReportFrame.size.width; - viewReportFrame = [mViewReportButton frame]; - viewReportFrame.origin.x += oldWidth - viewReportFrame.size.width; - [mViewReportButton setFrame:viewReportFrame]; - } - - [mSubmitReportButton setTitle:Str(ST_CHECKSUBMIT)]; - [mIncludeURLButton setTitle:Str(ST_CHECKURL)]; - [mViewReportOkButton setTitle:Str(ST_OK)]; - - [mCommentText setPlaceholder:Str(ST_COMMENTGRAYTEXT)]; - if (gRTLlayout) [mCommentText toggleBaseWritingDirection:self]; - - if (gQueryParameters.isMember("URL")) { - // save the URL value in case the checkbox gets unchecked - gURLParameter = gQueryParameters["URL"].asString(); - } else { - // no URL specified, hide checkbox - [mIncludeURLButton removeFromSuperview]; - // shrink window to fit - NSRect frame = [mWindow frame]; - NSRect includeURLFrame = [mIncludeURLButton frame]; - NSRect emailFrame = [mEmailMeButton frame]; - int buttonMask = [mViewReportButton autoresizingMask]; - int checkMask = [mSubmitReportButton autoresizingMask]; - int commentScrollMask = [mCommentScrollView autoresizingMask]; - - [mViewReportButton setAutoresizingMask:NSViewMinYMargin]; - [mSubmitReportButton setAutoresizingMask:NSViewMinYMargin]; - [mCommentScrollView setAutoresizingMask:NSViewMinYMargin]; - - // remove all the space in between - frame.size.height -= includeURLFrame.origin.y - emailFrame.origin.y; - [mWindow setFrame:frame display:true animate:NO]; - - [mViewReportButton setAutoresizingMask:buttonMask]; - [mSubmitReportButton setAutoresizingMask:checkMask]; - [mCommentScrollView setAutoresizingMask:commentScrollMask]; - } - - // resize some buttons horizontally and possibly some controls vertically - [self doInitialResizing]; - - // load default state of submit checkbox - // we don't just do this via IB because we want the default to be - // off a certain percentage of the time - BOOL submitChecked = YES; - NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; - if (nil != [userDefaults objectForKey:@"submitReport"]) { - submitChecked = [userDefaults boolForKey:@"submitReport"]; - } else { - [userDefaults setBool:submitChecked forKey:@"submitReport"]; - } - [mSubmitReportButton setState:(submitChecked ? NSOnState : NSOffState)]; - - // load default state of include URL checkbox - BOOL includeChecked = YES; - if (nil != [userDefaults objectForKey:@"IncludeURL"]) { - includeChecked = [userDefaults boolForKey:@"IncludeURL"]; - } else { - [userDefaults setBool:includeChecked forKey:@"IncludeURL"]; - } - [mIncludeURLButton setState:(includeChecked ? NSOnState : NSOffState)]; - - [self updateSubmit]; - [self updateURL]; - [self updateEmail]; - - [mWindow makeKeyAndOrderFront:nil]; -} - -- (void)showErrorUI:(const string&)message { - [self setView:mErrorView animate:NO]; - - [mErrorHeaderLabel setStringValue:Str(ST_CRASHREPORTERHEADER)]; - [self setStringFitVertically:mErrorLabel - string:NSSTR(message) - resizeWindow:YES]; - [mErrorCloseButton setTitle:Str(ST_OK)]; - - [mErrorCloseButton setKeyEquivalent:@"\r"]; - [mWindow makeFirstResponder:mErrorCloseButton]; - [mWindow makeKeyAndOrderFront:nil]; -} - -- (void)showReportInfo { - NSDictionary* boldAttr = @{ - NSFontAttributeName : - [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]], - NSForegroundColorAttributeName : NSColor.textColor, - }; - NSDictionary* normalAttr = @{ - NSFontAttributeName : - [NSFont systemFontOfSize:[NSFont smallSystemFontSize]], - NSForegroundColorAttributeName : NSColor.textColor, - }; - - [mViewReportTextView setString:@""]; - for (Json::ValueConstIterator iter = gQueryParameters.begin(); - iter != gQueryParameters.end(); ++iter) { - NSAttributedString* key = - [[NSAttributedString alloc] initWithString:NSSTR(iter.name() + ": ") - attributes:boldAttr]; - string str; - if (iter->isString()) { - str = iter->asString(); - } else { - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - str = writeString(builder, *iter); - } - NSAttributedString* value = - [[NSAttributedString alloc] initWithString:NSSTR(str + "\n") - attributes:normalAttr]; - [[mViewReportTextView textStorage] appendAttributedString:key]; - [[mViewReportTextView textStorage] appendAttributedString:value]; - [key release]; - [value release]; - } - - NSAttributedString* extra = [[NSAttributedString alloc] - initWithString:NSSTR("\n" + gStrings[ST_EXTRAREPORTINFO]) - attributes:normalAttr]; - [[mViewReportTextView textStorage] appendAttributedString:extra]; - [extra release]; -} - -- (void)maybeSubmitReport { - if ([mSubmitReportButton state] == NSOnState) { - [self setStringFitVertically:mProgressText - string:Str(ST_REPORTDURINGSUBMIT) - resizeWindow:YES]; - // disable all the controls - [self enableControls:NO]; - [mSubmitReportButton setEnabled:NO]; - [mRestartButton setEnabled:NO]; - [mCloseButton setEnabled:NO]; - [mProgressIndicator startAnimation:self]; - gDidTrySend = true; - [self sendReport]; - } else { - [NSApp terminate:self]; - } -} - -- (void)closeMeDown:(id)unused { - [NSApp terminate:self]; -} - -- (IBAction)submitReportClicked:(id)sender { - [self updateSubmit]; - NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; - [userDefaults setBool:([mSubmitReportButton state] == NSOnState) - forKey:@"submitReport"]; - [userDefaults synchronize]; -} - -- (IBAction)viewReportClicked:(id)sender { - [self showReportInfo]; - [NSApp beginSheet:mViewReportWindow - modalForWindow:mWindow - modalDelegate:nil - didEndSelector:nil - contextInfo:nil]; -} - -- (IBAction)viewReportOkClicked:(id)sender { - [mViewReportWindow orderOut:nil]; - [NSApp endSheet:mViewReportWindow]; -} - -- (IBAction)closeClicked:(id)sender { - [self maybeSubmitReport]; -} - -- (IBAction)restartClicked:(id)sender { - RestartApplication(); - [self maybeSubmitReport]; -} - -- (IBAction)includeURLClicked:(id)sender { - [self updateURL]; - NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults]; - [userDefaults setBool:([mIncludeURLButton state] == NSOnState) - forKey:@"IncludeURL"]; - [userDefaults synchronize]; -} - -- (void)textDidChange:(NSNotification*)aNotification { - // update comment parameter - if ([[[mCommentText textStorage] mutableString] length] > 0) - gQueryParameters["Comments"] = - [[[mCommentText textStorage] mutableString] UTF8String]; - else - gQueryParameters.removeMember("Comments"); -} - -// Limit the comment field to 500 bytes in UTF-8 -- (BOOL)textView:(NSTextView*)aTextView - shouldChangeTextInRange:(NSRange)affectedCharRange - replacementString:(NSString*)replacementString { - // current string length + replacement text length - replaced range length - if (([[aTextView string] lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + - [replacementString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] - - [[[aTextView string] substringWithRange:affectedCharRange] - lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) > - MAX_COMMENT_LENGTH) { - return NO; - } - return YES; -} - -- (void)doInitialResizing { - NSRect windowFrame = [mWindow frame]; - NSRect restartFrame = [mRestartButton frame]; - NSRect closeFrame = [mCloseButton frame]; - // resize close button to fit text - float oldCloseWidth = closeFrame.size.width; - [mCloseButton setTitle:Str(ST_QUIT)]; - [mCloseButton sizeToFit]; - closeFrame = [mCloseButton frame]; - // move close button left if it grew - if (!gRTLlayout) { - closeFrame.origin.x -= closeFrame.size.width - oldCloseWidth; - } - - if (gRestartArgs.size() == 0) { - [mRestartButton removeFromSuperview]; - if (!gRTLlayout) { - closeFrame.origin.x = restartFrame.origin.x + - (restartFrame.size.width - closeFrame.size.width); - } else { - closeFrame.origin.x = restartFrame.origin.x; - } - [mCloseButton setFrame:closeFrame]; - [mCloseButton setKeyEquivalent:@"\r"]; - } else { - [mRestartButton setTitle:Str(ST_RESTART)]; - // resize "restart" button - float oldRestartWidth = restartFrame.size.width; - [mRestartButton sizeToFit]; - restartFrame = [mRestartButton frame]; - if (!gRTLlayout) { - // move left by the amount that the button grew - restartFrame.origin.x -= restartFrame.size.width - oldRestartWidth; - closeFrame.origin.x -= restartFrame.size.width - oldRestartWidth; - } else { - // shift the close button right in RTL - closeFrame.origin.x += restartFrame.size.width - oldRestartWidth; - } - [mRestartButton setFrame:restartFrame]; - [mCloseButton setFrame:closeFrame]; - // possibly resize window if both buttons no longer fit - // leave 20 px from either side of the window, and 12 px - // between the buttons - float neededWidth = - closeFrame.size.width + restartFrame.size.width + 2 * 20 + 12; - - if (neededWidth > windowFrame.size.width) { - windowFrame.size.width = neededWidth; - [mWindow setFrame:windowFrame display:true animate:NO]; - } - [mRestartButton setKeyEquivalent:@"\r"]; - } - - NSButton* checkboxes[] = {mSubmitReportButton, mIncludeURLButton}; - - for (auto checkbox : checkboxes) { - NSRect frame = [checkbox frame]; - [checkbox sizeToFit]; - if (gRTLlayout) { - // sizeToFit will keep the left side fixed, so realign - float oldWidth = frame.size.width; - frame = [checkbox frame]; - frame.origin.x += oldWidth - frame.size.width; - [checkbox setFrame:frame]; - } - // keep existing spacing on left side, + 20 px spare on right - float neededWidth = - frame.origin.x + checkbox.intrinsicContentSize.width + 20; - if (neededWidth > windowFrame.size.width) { - windowFrame.size.width = neededWidth; - [mWindow setFrame:windowFrame display:true animate:NO]; - } - } - - // do this down here because we may have made the window wider - // up above - [self setStringFitVertically:mDescriptionLabel - string:Str(ST_CRASHREPORTERDESCRIPTION) - resizeWindow:YES]; - - // now pin all the controls (except quit/submit) in place, - // if we lengthen the window after this, it's just to lengthen - // the progress text, so nothing above that text should move. - NSView* views[] = {mSubmitReportButton, mViewReportButton, - mCommentScrollView, mIncludeURLButton, - mProgressIndicator, mProgressText}; - for (auto view : views) { - [view setAutoresizingMask:NSViewMinYMargin]; - } -} - -- (float)setStringFitVertically:(NSControl*)control - string:(NSString*)str - resizeWindow:(BOOL)resizeWindow { - // hack to make the text field grow vertically - NSRect frame = [control frame]; - float oldHeight = frame.size.height; - - frame.size.height = 10000; - NSSize oldCellSize = [[control cell] cellSizeForBounds:frame]; - [control setStringValue:str]; - NSSize newCellSize = [[control cell] cellSizeForBounds:frame]; - - float delta = newCellSize.height - oldCellSize.height; - frame.origin.y -= delta; - frame.size.height = oldHeight + delta; - [control setFrame:frame]; - - if (resizeWindow) { - NSRect frame = [mWindow frame]; - frame.origin.y -= delta; - frame.size.height += delta; - [mWindow setFrame:frame display:true animate:NO]; - } - - return delta; -} - -- (void)setView:(NSView*)v animate:(BOOL)animate { - NSRect frame = [mWindow frame]; - - NSRect oldViewFrame = [[mWindow contentView] frame]; - NSRect newViewFrame = [v frame]; - - frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height; - frame.size.height -= oldViewFrame.size.height - newViewFrame.size.height; - - frame.origin.x += oldViewFrame.size.width - newViewFrame.size.width; - frame.size.width -= oldViewFrame.size.width - newViewFrame.size.width; - - [mWindow setContentView:v]; - [mWindow setFrame:frame display:true animate:animate]; -} - -- (void)enableControls:(BOOL)enabled { - [mViewReportButton setEnabled:enabled]; - [mIncludeURLButton setEnabled:enabled]; - [mCommentText setEnabled:enabled]; - [mCommentScrollView setHasVerticalScroller:enabled]; -} - -- (void)updateSubmit { - if ([mSubmitReportButton state] == NSOnState) { - [self setStringFitVertically:mProgressText - string:Str(ST_REPORTPRESUBMIT) - resizeWindow:YES]; - [mProgressText setHidden:NO]; - // enable all the controls - [self enableControls:YES]; - } else { - // not submitting, disable all the controls under - // the submit checkbox, and hide the status text - [mProgressText setHidden:YES]; - [self enableControls:NO]; - } -} - -- (void)updateURL { - if ([mIncludeURLButton state] == NSOnState && !gURLParameter.empty()) { - gQueryParameters["URL"] = gURLParameter; - } else { - gQueryParameters.removeMember("URL"); - } -} - -- (void)updateEmail { - // In order to remove the email fields, we have to edit the .nib files which - // we can't do with current xcode so we make them hidden; updating the - // crashreporter interface for mac is covered in bug #1696164 - [mEmailMeButton setHidden:YES]; - [mEmailText setHidden:YES]; -} - -- (void)sendReport { - if (![self setupPost]) { - LogMessage("Crash report submission failed: could not set up POST data"); - - if (gAutoSubmit) { - [NSApp terminate:self]; - } - - [self setStringFitVertically:mProgressText - string:Str(ST_SUBMITFAILED) - resizeWindow:YES]; - // quit after 5 seconds - [self performSelector:@selector(closeMeDown:) - withObject:nil - afterDelay:5.0]; - } - - [NSThread detachNewThreadSelector:@selector(uploadThread:) - toTarget:self - withObject:mPost]; -} - -- (bool)setupPost { - NSURL* url = [NSURL - URLWithString:[NSSTR(gSendURL) stringByAddingPercentEscapesUsingEncoding: - NSUTF8StringEncoding]]; - if (!url) return false; - - mPost = [[HTTPMultipartUpload alloc] initWithURL:url]; - if (!mPost) return false; - - for (StringTable::const_iterator i = gFiles.begin(); i != gFiles.end(); i++) { - [mPost addFileAtPath:NSSTR(i->second) name:NSSTR(i->first)]; - } - - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - string output = writeString(builder, gQueryParameters).append("\r\n"); - NSMutableString* parameters = - [[NSMutableString alloc] initWithUTF8String:output.c_str()]; - - [mPost setParameters:parameters]; - [parameters release]; - - return true; -} - -- (void)uploadComplete:(NSData*)data { - NSHTTPURLResponse* response = [mPost response]; - [mPost release]; - - bool success; - string reply; - if (!data || !response || [response statusCode] != 200) { - success = false; - reply = ""; - - // if data is nil, we probably logged an error in uploadThread - if (data != nil && response != nil) { - ostringstream message; - message << "Crash report submission failed: server returned status " - << [response statusCode]; - LogMessage(message.str()); - } - } else { - success = true; - LogMessage("Crash report submitted successfully"); - - NSString* encodingName = [response textEncodingName]; - NSStringEncoding encoding; - if (encodingName) { - encoding = CFStringConvertEncodingToNSStringEncoding( - CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName)); - } else { - encoding = NSISOLatin1StringEncoding; - } - NSString* r = [[NSString alloc] initWithData:data encoding:encoding]; - reply = [r UTF8String]; - [r release]; - } - - SendCompleted(success, reply); - - if (gAutoSubmit) { - [NSApp terminate:self]; - } - - [mProgressIndicator stopAnimation:self]; - if (success) { - [self setStringFitVertically:mProgressText - string:Str(ST_REPORTSUBMITSUCCESS) - resizeWindow:YES]; - } else { - [self setStringFitVertically:mProgressText - string:Str(ST_SUBMITFAILED) - resizeWindow:YES]; - } - // quit after 5 seconds - [self performSelector:@selector(closeMeDown:) withObject:nil afterDelay:5.0]; -} - -- (void)uploadThread:(HTTPMultipartUpload*)post { - NSAutoreleasePool* autoreleasepool = [[NSAutoreleasePool alloc] init]; - NSError* error = nil; - NSData* data = [post send:&error]; - if (error) { - data = nil; - NSString* errorDesc = [error localizedDescription]; - string message = [errorDesc UTF8String]; - LogMessage("Crash report submission failed: " + message); - } - - [self performSelectorOnMainThread:@selector(uploadComplete:) - withObject:data - waitUntilDone:YES]; - - [autoreleasepool release]; -} - -// to get auto-quit when we close the window -- (BOOL)applicationShouldTerminateAfterLastWindowClosed: - (NSApplication*)theApplication { - return YES; -} - -- (void)applicationWillTerminate:(NSNotification*)aNotification { - // since we use [NSApp terminate:] we never return to main, - // so do our cleanup here - if (!gDidTrySend) DeleteDump(); -} - -@end - -@implementation TextViewWithPlaceHolder - -- (BOOL)becomeFirstResponder { - [self setNeedsDisplay:YES]; - return [super becomeFirstResponder]; -} - -- (void)drawRect:(NSRect)rect { - [super drawRect:rect]; - if (mPlaceHolderString && [[self string] isEqualToString:@""] && - self != [[self window] firstResponder]) - [mPlaceHolderString drawInRect:[self frame]]; -} - -- (BOOL)resignFirstResponder { - [self setNeedsDisplay:YES]; - return [super resignFirstResponder]; -} - -- (void)setPlaceholder:(NSString*)placeholder { - NSColor* txtColor = [NSColor disabledControlTextColor]; - NSDictionary* txtDict = [NSDictionary - dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, - nil]; - mPlaceHolderString = - [[NSMutableAttributedString alloc] initWithString:placeholder - attributes:txtDict]; - if (gRTLlayout) - [mPlaceHolderString setAlignment:NSTextAlignmentRight - range:NSMakeRange(0, [placeholder length])]; -} - -- (void)insertTab:(id)sender { - // don't actually want to insert tabs, just tab to next control - [[self window] selectNextKeyView:sender]; -} - -- (void)insertBacktab:(id)sender { - [[self window] selectPreviousKeyView:sender]; -} - -- (void)setEnabled:(BOOL)enabled { - [self setSelectable:enabled]; - [self setEditable:enabled]; - if (![[self string] isEqualToString:@""]) { - NSAttributedString* colorString; - NSColor* txtColor; - if (enabled) - txtColor = [NSColor textColor]; - else - txtColor = [NSColor disabledControlTextColor]; - NSDictionary* txtDict = [NSDictionary - dictionaryWithObjectsAndKeys:txtColor, NSForegroundColorAttributeName, - nil]; - colorString = [[NSAttributedString alloc] initWithString:[self string] - attributes:txtDict]; - [[self textStorage] setAttributedString:colorString]; - [self setInsertionPointColor:txtColor]; - [colorString release]; - } -} - -- (void)dealloc { - [mPlaceHolderString release]; - [super dealloc]; -} - -@end - -/* === Crashreporter UI Functions === */ - -bool UIInit() { - gMainPool = [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; - - if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") - gRTLlayout = true; - - if (gAutoSubmit) { - gUI = [[CrashReporterUI alloc] init]; - } else { - [[NSBundle mainBundle] - loadNibNamed:(gRTLlayout ? @"MainMenuRTL" : @"MainMenu") - owner:NSApp - topLevelObjects:nil]; - } - - return true; -} - -void UIShutdown() { [gMainPool release]; } - -void UIShowDefaultUI() { - [gUI showErrorUI:gStrings[ST_CRASHREPORTERDEFAULT]]; - [NSApp run]; -} - -bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, - const string& sendURL, const vector& restartArgs) { - gRestartArgs = restartArgs; - - [gUI showCrashUI:files queryParameters:queryParameters sendURL:sendURL]; - [NSApp run]; - - return gDidTrySend; -} - -void UIError_impl(const string& message) { - if (!gUI) { - // UI failed to initialize, printing is the best we can do - printf("Error: %s\n", message.c_str()); - return; - } - - [gUI showErrorUI:message]; - [NSApp run]; -} - -bool UIGetIniPath(string& path) { - NSString* tmpPath = [NSString stringWithUTF8String:gArgv[0]]; - NSString* iniName = [tmpPath lastPathComponent]; - iniName = [iniName stringByAppendingPathExtension:@"ini"]; - tmpPath = [tmpPath stringByDeletingLastPathComponent]; - tmpPath = [tmpPath stringByDeletingLastPathComponent]; - tmpPath = [tmpPath stringByAppendingPathComponent:@"Resources"]; - tmpPath = [tmpPath stringByAppendingPathComponent:iniName]; - path = [tmpPath UTF8String]; - return true; -} - -bool UIGetSettingsPath(const string& vendor, const string& product, - string& settingsPath) { - NSArray* paths = NSSearchPathForDirectoriesInDomains( - NSApplicationSupportDirectory, NSUserDomainMask, YES); - NSString* destPath = [paths firstObject]; - - // Note that MacOS ignores the vendor when creating the profile hierarchy - - // all application preferences directories live alongside one another in - // ~/Library/Application Support/ - destPath = [destPath stringByAppendingPathComponent:NSSTR(product)]; - // Thunderbird stores its profile in ~/Library/Thunderbird, - // but we're going to put stuff in ~/Library/Application Support/Thunderbird - // anyway, so we have to ensure that path exists. - string tempPath = [destPath UTF8String]; - if (!UIEnsurePathExists(tempPath)) return false; - - destPath = [destPath stringByAppendingPathComponent:@"Crash Reports"]; - - settingsPath = [destPath UTF8String]; - - return true; -} - -bool UIMoveFile(const string& file, const string& newfile) { - if (!rename(file.c_str(), newfile.c_str())) return true; - if (errno != EXDEV) return false; - - NSFileManager* fileManager = [NSFileManager defaultManager]; - NSString* source = - [fileManager stringWithFileSystemRepresentation:file.c_str() - length:file.length()]; - NSString* dest = - [fileManager stringWithFileSystemRepresentation:newfile.c_str() - length:newfile.length()]; - if (!source || !dest) return false; - - [fileManager moveItemAtPath:source toPath:dest error:NULL]; - return UIFileExists(newfile); -} diff --git a/toolkit/crashreporter/client/crashreporter_unix_common.cpp b/toolkit/crashreporter/client/crashreporter_unix_common.cpp deleted file mode 100644 index e6514d44236e..000000000000 --- a/toolkit/crashreporter/client/crashreporter_unix_common.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "crashreporter.h" - -#include -#include - -#include -#include -#include -#include - -using namespace CrashReporter; -using std::ios_base; -using std::sort; -using std::string; -using std::vector; - -struct FileData { - time_t timestamp; - string path; -}; - -static bool CompareFDTime(const FileData& fd1, const FileData& fd2) { - return fd1.timestamp > fd2.timestamp; -} - -void UIPruneSavedDumps(const string& directory) { - DIR* dirfd = opendir(directory.c_str()); - if (!dirfd) return; - - vector dumpfiles; - - while (dirent* dir = readdir(dirfd)) { - FileData fd; - fd.path = directory + '/' + dir->d_name; - if (fd.path.size() < 5) continue; - - if (fd.path.compare(fd.path.size() - 4, 4, ".dmp") != 0) continue; - - struct stat st; - if (stat(fd.path.c_str(), &st)) { - closedir(dirfd); - return; - } - - fd.timestamp = st.st_mtime; - - dumpfiles.push_back(fd); - } - - closedir(dirfd); - - sort(dumpfiles.begin(), dumpfiles.end(), CompareFDTime); - - while (dumpfiles.size() > kSaveCount) { - // get the path of the oldest file - string path = dumpfiles[dumpfiles.size() - 1].path; - UIDeleteFile(path); - - // s/.dmp/.extra/ - path.replace(path.size() - 4, 4, ".extra"); - UIDeleteFile(path); - - dumpfiles.pop_back(); - } -} - -bool UIRunProgram(const string& exename, const vector& args, - bool wait) { - pid_t pid = fork(); - - if (pid == -1) { - return false; - } else if (pid == 0) { - // Child - size_t argvLen = args.size() + 2; - vector argv(argvLen); - - argv[0] = const_cast(exename.c_str()); - - for (size_t i = 0; i < args.size(); i++) { - argv[i + 1] = const_cast(args[i].c_str()); - } - - argv[argvLen - 1] = nullptr; - - // Run the program - int rv = execv(exename.c_str(), argv.data()); - - if (rv == -1) { - exit(EXIT_FAILURE); - } - } else { - // Parent - if (wait) { - waitpid(pid, nullptr, 0); - } - } - - return true; -} - -bool UIEnsurePathExists(const string& path) { - int ret = mkdir(path.c_str(), S_IRWXU); - int e = errno; - if (ret == -1 && e != EEXIST) return false; - - return true; -} - -bool UIFileExists(const string& path) { - struct stat sb; - int ret = stat(path.c_str(), &sb); - if (ret == -1 || !(sb.st_mode & S_IFREG)) return false; - - return true; -} - -bool UIDeleteFile(const string& file) { return (unlink(file.c_str()) != -1); } - -std::ifstream* UIOpenRead(const string& filename, ios_base::openmode mode) { - return new std::ifstream(filename.c_str(), mode); -} - -std::ofstream* UIOpenWrite(const string& filename, ios_base::openmode mode) { - return new std::ofstream(filename.c_str(), mode); -} - -string UIGetEnv(const string& name) { - const char* var = getenv(name.c_str()); - if (var && *var) { - return var; - } - - return ""; -} diff --git a/toolkit/crashreporter/client/crashreporter_win.cpp b/toolkit/crashreporter/client/crashreporter_win.cpp deleted file mode 100644 index 35018bda4af1..000000000000 --- a/toolkit/crashreporter/client/crashreporter_win.cpp +++ /dev/null @@ -1,1266 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifdef WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif - -#include "crashreporter.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "resource.h" -#include "windows/sender/crash_report_sender.h" -#include "common/windows/string_utils-inl.h" - -#define SUBMIT_REPORT_VALUE L"SubmitCrashReport" -#define INCLUDE_URL_VALUE L"IncludeURL" - -#define WM_UPLOADCOMPLETE WM_APP - -// Thanks, Windows.h :( -#undef min -#undef max - -using std::ifstream; -using std::ios; -using std::ios_base; -using std::map; -using std::ofstream; -using std::set; -using std::string; -using std::vector; -using std::wstring; - -using namespace CrashReporter; - -typedef struct { - HWND hDlg; - Json::Value queryParameters; - map files; - wstring sendURL; - - wstring serverResponse; -} SendThreadData; - -/* - * Per http://msdn2.microsoft.com/en-us/library/ms645398(VS.85).aspx - * "The DLGTEMPLATEEX structure is not defined in any standard header file. - * The structure definition is provided here to explain the format of an - * extended template for a dialog box. - */ -typedef struct { - WORD dlgVer; - WORD signature; - DWORD helpID; - DWORD exStyle; - // There's more to this struct, but it has weird variable-length - // members, and I only actually need to touch exStyle on an existing - // instance, so I've omitted the rest. -} DLGTEMPLATEEX; - -static HANDLE gThreadHandle; -static SendThreadData gSendData = { - 0, -}; -static vector gRestartArgs; -static Json::Value gQueryParameters; -static wstring gCrashReporterKey(L"Software\\Mozilla\\Crash Reporter"); -static string gURLParameter; -static int gCheckboxPadding = 6; -static bool gRTLlayout = false; - -// When vertically resizing the dialog, these items should move down -static set gAttachedBottom; - -// Default set of items for gAttachedBottom -static const UINT kDefaultAttachedBottom[] = { - IDC_SUBMITREPORTCHECK, IDC_VIEWREPORTBUTTON, IDC_COMMENTTEXT, - IDC_INCLUDEURLCHECK, IDC_PROGRESSTEXT, IDC_THROBBER, - IDC_CLOSEBUTTON, IDC_RESTARTBUTTON, -}; - -static wstring UTF8ToWide(const string& utf8, bool* success = 0); -static DWORD WINAPI SendThreadProc(LPVOID param); - -static wstring Str(const char* key) { return UTF8ToWide(gStrings[key]); } - -/* === win32 helper functions === */ - -static void DoInitCommonControls() { - INITCOMMONCONTROLSEX ic; - ic.dwSize = sizeof(INITCOMMONCONTROLSEX); - ic.dwICC = ICC_PROGRESS_CLASS; - InitCommonControlsEx(&ic); - // also get the rich edit control - LoadLibrary(L"Msftedit.dll"); -} - -static bool GetBoolValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value) { - DWORD type, dataSize; - dataSize = sizeof(DWORD); - if (RegQueryValueEx(hRegKey, valueName, nullptr, &type, (LPBYTE)value, - &dataSize) == ERROR_SUCCESS && - type == REG_DWORD) - return true; - - return false; -} - -static bool CheckBoolKey(const wchar_t* key, const wchar_t* valueName, - bool* enabled) { - /* - * NOTE! This code needs to stay in sync with the preference checking - * code in in nsExceptionHandler.cpp. - */ - *enabled = false; - bool found = false; - HKEY hRegKey; - DWORD val; - // see if our reg key is set globally - if (RegOpenKey(HKEY_LOCAL_MACHINE, key, &hRegKey) == ERROR_SUCCESS) { - if (GetBoolValue(hRegKey, valueName, &val)) { - *enabled = (val == 1); - found = true; - } - RegCloseKey(hRegKey); - } else { - // look for it in user settings - if (RegOpenKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) { - if (GetBoolValue(hRegKey, valueName, &val)) { - *enabled = (val == 1); - found = true; - } - RegCloseKey(hRegKey); - } - } - - return found; -} - -static void SetBoolKey(const wchar_t* key, const wchar_t* value, bool enabled) { - /* - * NOTE! This code needs to stay in sync with the preference setting - * code in in nsExceptionHandler.cpp. - */ - HKEY hRegKey; - - if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) { - DWORD data = (enabled ? 1 : 0); - RegSetValueEx(hRegKey, value, 0, REG_DWORD, (LPBYTE)&data, sizeof(data)); - RegCloseKey(hRegKey); - } -} - -static string FormatLastError() { - DWORD err = GetLastError(); - LPWSTR s; - string message = "Crash report submission failed: "; - // odds are it's a WinInet error - HANDLE hInetModule = GetModuleHandle(L"WinInet.dll"); - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_FROM_HMODULE, - hInetModule, err, 0, (LPWSTR)&s, 0, nullptr) != 0) { - message += WideToUTF8(s, nullptr); - LocalFree(s); - // strip off any trailing newlines - string::size_type n = message.find_last_not_of("\r\n"); - if (n < message.size() - 1) { - message.erase(n + 1); - } - } else { - char buf[64]; - sprintf(buf, "Unknown error, error code: 0x%08x", - static_cast(err)); - message += buf; - } - return message; -} - -#define TS_DRAW 2 -#define BP_CHECKBOX 3 - -typedef HANDLE(WINAPI* OpenThemeDataPtr)(HWND hwnd, LPCWSTR pszClassList); -typedef HRESULT(WINAPI* CloseThemeDataPtr)(HANDLE hTheme); -typedef HRESULT(WINAPI* GetThemePartSizePtr)(HANDLE hTheme, HDC hdc, - int iPartId, int iStateId, - RECT* prc, int ts, SIZE* psz); -typedef HRESULT(WINAPI* GetThemeContentRectPtr)(HANDLE hTheme, HDC hdc, - int iPartId, int iStateId, - const RECT* pRect, - RECT* pContentRect); - -static void GetThemeSizes(HWND hwnd) { - HMODULE themeDLL = LoadLibrary(L"uxtheme.dll"); - - if (!themeDLL) return; - - OpenThemeDataPtr openTheme = - (OpenThemeDataPtr)GetProcAddress(themeDLL, "OpenThemeData"); - CloseThemeDataPtr closeTheme = - (CloseThemeDataPtr)GetProcAddress(themeDLL, "CloseThemeData"); - GetThemePartSizePtr getThemePartSize = - (GetThemePartSizePtr)GetProcAddress(themeDLL, "GetThemePartSize"); - - if (!openTheme || !closeTheme || !getThemePartSize) { - FreeLibrary(themeDLL); - return; - } - - HANDLE buttonTheme = openTheme(hwnd, L"Button"); - if (!buttonTheme) { - FreeLibrary(themeDLL); - return; - } - HDC hdc = GetDC(hwnd); - SIZE s; - getThemePartSize(buttonTheme, hdc, BP_CHECKBOX, 0, nullptr, TS_DRAW, &s); - gCheckboxPadding = s.cx; - closeTheme(buttonTheme); - FreeLibrary(themeDLL); -} - -// Gets the position of a window relative to another window's client area -static void GetRelativeRect(HWND hwnd, HWND hwndParent, RECT* r) { - GetWindowRect(hwnd, r); - MapWindowPoints(nullptr, hwndParent, (POINT*)r, 2); -} - -static void SetDlgItemVisible(HWND hwndDlg, UINT item, bool visible) { - HWND hwnd = GetDlgItem(hwndDlg, item); - - ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE); -} - -/* === Crash Reporting Dialog === */ - -static void StretchDialog(HWND hwndDlg, int ydiff) { - RECT r; - GetWindowRect(hwndDlg, &r); - r.bottom += ydiff; - MoveWindow(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); -} - -static void ReflowDialog(HWND hwndDlg, int ydiff) { - // Move items attached to the bottom down/up by as much as - // the window resize - for (set::const_iterator item = gAttachedBottom.begin(); - item != gAttachedBottom.end(); item++) { - RECT r; - HWND hwnd = GetDlgItem(hwndDlg, *item); - GetRelativeRect(hwnd, hwndDlg, &r); - r.top += ydiff; - r.bottom += ydiff; - MoveWindow(hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE); - } -} - -static DWORD WINAPI SendThreadProc(LPVOID param) { - bool finishedOk; - SendThreadData* td = (SendThreadData*)param; - - if (td->sendURL.empty()) { - finishedOk = false; - LogMessage("No server URL, not sending report"); - } else { - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - string parameters(Json::writeString(builder, td->queryParameters)); - google_breakpad::CrashReportSender sender(L""); - finishedOk = (sender.SendCrashReport(td->sendURL, parameters, td->files, - &td->serverResponse) == - google_breakpad::RESULT_SUCCEEDED); - if (finishedOk) { - LogMessage("Crash report submitted successfully"); - } else { - // get an error string and print it to the log - // XXX: would be nice to get the HTTP status code here, filed: - // http://code.google.com/p/google-breakpad/issues/detail?id=220 - LogMessage(FormatLastError()); - } - } - - if (gAutoSubmit) { - // Ordinarily this is done on the main thread in CrashReporterDialogProc, - // for auto submit we don't run that and it should be safe to finish up - // here as is done on other platforms. - SendCompleted(finishedOk, WideToUTF8(gSendData.serverResponse)); - } else { - PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0); - } - - return 0; -} - -static void EndCrashReporterDialog(HWND hwndDlg, int code) { - // Save the current values to the registry - SetBoolKey(gCrashReporterKey.c_str(), INCLUDE_URL_VALUE, - IsDlgButtonChecked(hwndDlg, IDC_INCLUDEURLCHECK) != 0); - SetBoolKey(gCrashReporterKey.c_str(), SUBMIT_REPORT_VALUE, - IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0); - - EndDialog(hwndDlg, code); -} - -static void MaybeResizeProgressText(HWND hwndDlg) { - HWND hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESSTEXT); - HDC hdc = GetDC(hwndProgress); - HFONT hfont = (HFONT)SendMessage(hwndProgress, WM_GETFONT, 0, 0); - if (hfont) SelectObject(hdc, hfont); - SIZE size; - RECT rect; - GetRelativeRect(hwndProgress, hwndDlg, &rect); - - wchar_t text[1024]; - GetWindowText(hwndProgress, text, 1024); - - if (!GetTextExtentPoint32(hdc, text, wcslen(text), &size)) return; - - if (size.cx < (rect.right - rect.left)) return; - - // Figure out how much we need to resize things vertically - // This is sort of a fudge, but it should be good enough. - int wantedHeight = - size.cy * (int)ceil((float)size.cx / (float)(rect.right - rect.left)); - int diff = wantedHeight - (rect.bottom - rect.top); - if (diff <= 0) return; - - MoveWindow(hwndProgress, rect.left, rect.top, rect.right - rect.left, - wantedHeight, TRUE); - - gAttachedBottom.clear(); - gAttachedBottom.insert(IDC_CLOSEBUTTON); - gAttachedBottom.insert(IDC_RESTARTBUTTON); - - StretchDialog(hwndDlg, diff); - - for (size_t i = 0; i < sizeof(kDefaultAttachedBottom) / sizeof(UINT); i++) { - gAttachedBottom.insert(kDefaultAttachedBottom[i]); - } -} - -static void MaybeSendReport(HWND hwndDlg) { - if (!IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK)) { - EndCrashReporterDialog(hwndDlg, 0); - return; - } - - // disable all the form controls - EnableWindow(GetDlgItem(hwndDlg, IDC_SUBMITREPORTCHECK), false); - EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWREPORTBUTTON), false); - EnableWindow(GetDlgItem(hwndDlg, IDC_COMMENTTEXT), false); - EnableWindow(GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK), false); - EnableWindow(GetDlgItem(hwndDlg, IDC_CLOSEBUTTON), false); - EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTBUTTON), false); - - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, Str(ST_REPORTDURINGSUBMIT).c_str()); - MaybeResizeProgressText(hwndDlg); - // start throbber - // play entire AVI, and loop - Animate_Play(GetDlgItem(hwndDlg, IDC_THROBBER), 0, -1, -1); - SetDlgItemVisible(hwndDlg, IDC_THROBBER, true); - gThreadHandle = nullptr; - gSendData.hDlg = hwndDlg; - gSendData.queryParameters = gQueryParameters; - - gThreadHandle = - CreateThread(nullptr, 0, SendThreadProc, &gSendData, 0, nullptr); -} - -static void RestartApplication() { - wstring cmdLine; - - for (unsigned int i = 0; i < gRestartArgs.size(); i++) { - cmdLine += L"\"" + UTF8ToWide(gRestartArgs[i]) + L"\" "; - } - - STARTUPINFO si; - PROCESS_INFORMATION pi; - - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_SHOWNORMAL; - ZeroMemory(&pi, sizeof(pi)); - - if (CreateProcess(nullptr, (LPWSTR)cmdLine.c_str(), nullptr, nullptr, FALSE, - 0, nullptr, nullptr, &si, &pi)) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } -} - -static void ShowReportInfo(HWND hwndDlg) { - wstring description; - - for (Json::ValueConstIterator iter = gQueryParameters.begin(); - iter != gQueryParameters.end(); ++iter) { - description += UTF8ToWide(iter.name()); - description += L": "; - string value; - if (iter->isString()) { - value = iter->asString(); - } else { - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - value = Json::writeString(builder, *iter); - } - description += UTF8ToWide(value); - description += L"\n"; - } - - description += L"\n"; - description += Str(ST_EXTRAREPORTINFO); - - SetDlgItemText(hwndDlg, IDC_VIEWREPORTTEXT, description.c_str()); -} - -static void UpdateURL(HWND hwndDlg) { - if (IsDlgButtonChecked(hwndDlg, IDC_INCLUDEURLCHECK)) { - gQueryParameters["URL"] = gURLParameter; - } else { - gQueryParameters.removeMember("URL"); - } -} - -static void UpdateComment(HWND hwndDlg) { - wchar_t comment[MAX_COMMENT_LENGTH + 1]; - GetDlgItemTextW(hwndDlg, IDC_COMMENTTEXT, comment, - sizeof(comment) / sizeof(comment[0])); - if (wcslen(comment) > 0) - gQueryParameters["Comments"] = WideToUTF8(comment); - else - gQueryParameters.removeMember("Comments"); -} - -/* - * Dialog procedure for the "view report" dialog. - */ -static BOOL CALLBACK ViewReportDialogProc(HWND hwndDlg, UINT message, - WPARAM wParam, LPARAM lParam) { - switch (message) { - case WM_INITDIALOG: { - SetWindowText(hwndDlg, Str(ST_VIEWREPORTTITLE).c_str()); - SetDlgItemText(hwndDlg, IDOK, Str(ST_OK).c_str()); - SendDlgItemMessage(hwndDlg, IDC_VIEWREPORTTEXT, EM_SETTARGETDEVICE, - (WPARAM) nullptr, 0); - ShowReportInfo(hwndDlg); - SetFocus(GetDlgItem(hwndDlg, IDOK)); - return FALSE; - } - - case WM_COMMAND: { - if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK) - EndDialog(hwndDlg, 0); - return FALSE; - } - } - return FALSE; -} - -// Return the number of bytes this string will take encoded -// in UTF-8 -static inline int BytesInUTF8(wchar_t* str) { - // Just count size of buffer for UTF-8, minus one - // (we don't need to count the null terminator) - return WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, nullptr, - nullptr) - - 1; -} - -// Calculate the length of the text in this edit control (in bytes, -// in the UTF-8 encoding) after replacing the current selection -// with |insert|. -static int NewTextLength(HWND hwndEdit, wchar_t* insert) { - wchar_t current[MAX_COMMENT_LENGTH + 1]; - - GetWindowText(hwndEdit, current, MAX_COMMENT_LENGTH + 1); - DWORD selStart, selEnd; - SendMessage(hwndEdit, EM_GETSEL, (WPARAM)&selStart, (LPARAM)&selEnd); - - int selectionLength = 0; - if (selEnd - selStart > 0) { - wchar_t selection[MAX_COMMENT_LENGTH + 1]; - google_breakpad::WindowsStringUtils::safe_wcsncpy( - selection, MAX_COMMENT_LENGTH + 1, current + selStart, - selEnd - selStart); - selection[selEnd - selStart] = '\0'; - selectionLength = BytesInUTF8(selection); - } - - // current string length + replacement text length - // - replaced selection length - return BytesInUTF8(current) + BytesInUTF8(insert) - selectionLength; -} - -// Window procedure for subclassing edit controls -static LRESULT CALLBACK EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, - LPARAM lParam) { - static WNDPROC super = nullptr; - - if (super == nullptr) super = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); - - switch (uMsg) { - case WM_PAINT: { - HDC hdc; - PAINTSTRUCT ps; - RECT r; - wchar_t windowText[1024]; - - GetWindowText(hwnd, windowText, 1024); - // if the control contains text or is focused, draw it normally - if (GetFocus() == hwnd || windowText[0] != '\0') - return CallWindowProc(super, hwnd, uMsg, wParam, lParam); - - GetClientRect(hwnd, &r); - hdc = BeginPaint(hwnd, &ps); - FillRect(hdc, &r, - GetSysColorBrush(IsWindowEnabled(hwnd) ? COLOR_WINDOW - : COLOR_BTNFACE)); - SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); - SelectObject(hdc, (HFONT)GetStockObject(DEFAULT_GUI_FONT)); - SetBkMode(hdc, TRANSPARENT); - wchar_t* txt = (wchar_t*)GetProp(hwnd, L"PROP_GRAYTEXT"); - // Get the actual edit control rect - CallWindowProc(super, hwnd, EM_GETRECT, 0, (LPARAM)&r); - UINT format = DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK | DT_INTERNAL; - if (gRTLlayout) format |= DT_RIGHT; - if (txt) DrawText(hdc, txt, wcslen(txt), &r, format); - EndPaint(hwnd, &ps); - return 0; - } - - // We handle WM_CHAR and WM_PASTE to limit the comment box to 500 - // bytes in UTF-8. - case WM_CHAR: { - // Leave accelerator keys and non-printing chars (except LF) alone - if (wParam & (1 << 24) || wParam & (1 << 29) || - (wParam < ' ' && wParam != '\n')) - break; - - wchar_t ch[2] = {(wchar_t)wParam, 0}; - if (NewTextLength(hwnd, ch) > MAX_COMMENT_LENGTH) return 0; - - break; - } - - case WM_PASTE: { - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(hwnd)) { - HGLOBAL hg = GetClipboardData(CF_UNICODETEXT); - wchar_t* pastedText = (wchar_t*)GlobalLock(hg); - int newSize = 0; - - if (pastedText) newSize = NewTextLength(hwnd, pastedText); - - GlobalUnlock(hg); - CloseClipboard(); - - if (newSize > MAX_COMMENT_LENGTH) return 0; - } - break; - } - - case WM_SETFOCUS: - case WM_KILLFOCUS: { - RECT r; - GetClientRect(hwnd, &r); - InvalidateRect(hwnd, &r, TRUE); - break; - } - - case WM_DESTROY: { - // cleanup our property - HGLOBAL hData = RemoveProp(hwnd, L"PROP_GRAYTEXT"); - if (hData) GlobalFree(hData); - } - } - - return CallWindowProc(super, hwnd, uMsg, wParam, lParam); -} - -// Resize a control to fit this text -static int ResizeControl(HWND hwndButton, RECT& rect, wstring text, - bool shiftLeft, int userDefinedPadding) { - HDC hdc = GetDC(hwndButton); - HFONT hfont = (HFONT)SendMessage(hwndButton, WM_GETFONT, 0, 0); - if (hfont) SelectObject(hdc, hfont); - SIZE size, oldSize; - int sizeDiff = 0; - - wchar_t oldText[1024]; - GetWindowText(hwndButton, oldText, 1024); - - if (GetTextExtentPoint32(hdc, text.c_str(), text.length(), &size) - // default text on the button - && GetTextExtentPoint32(hdc, oldText, wcslen(oldText), &oldSize)) { - /* - Expand control widths to accomidate wider text strings. For most - controls (including buttons) the text padding is defined by the - dialog's rc file. Some controls (such as checkboxes) have padding - that extends to the end of the dialog, in which case we ignore the - rc padding and rely on a user defined value passed in through - userDefinedPadding. - */ - int textIncrease = size.cx - oldSize.cx; - if (textIncrease < 0) return 0; - int existingTextPadding; - if (userDefinedPadding == 0) - existingTextPadding = (rect.right - rect.left) - oldSize.cx; - else - existingTextPadding = userDefinedPadding; - sizeDiff = textIncrease + existingTextPadding; - - if (shiftLeft) { - // shift left by the amount the button should grow - rect.left -= sizeDiff; - } else { - // grow right instead - rect.right += sizeDiff; - } - MoveWindow(hwndButton, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return sizeDiff; -} - -// The window was resized horizontally, so widen some of our -// controls to make use of the space -static void StretchControlsToFit(HWND hwndDlg) { - int controls[] = {IDC_DESCRIPTIONTEXT, IDC_SUBMITREPORTCHECK, IDC_COMMENTTEXT, - IDC_INCLUDEURLCHECK, IDC_PROGRESSTEXT}; - - RECT dlgRect; - GetClientRect(hwndDlg, &dlgRect); - - for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); i++) { - RECT r; - HWND hwndControl = GetDlgItem(hwndDlg, controls[i]); - GetRelativeRect(hwndControl, hwndDlg, &r); - // 6 pixel spacing on the right - if (r.right + 6 != dlgRect.right) { - r.right = dlgRect.right - 6; - MoveWindow(hwndControl, r.left, r.top, r.right - r.left, r.bottom - r.top, - TRUE); - } - } -} - -static void SubmitReportChecked(HWND hwndDlg) { - bool enabled = (IsDlgButtonChecked(hwndDlg, IDC_SUBMITREPORTCHECK) != 0); - EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWREPORTBUTTON), enabled); - EnableWindow(GetDlgItem(hwndDlg, IDC_COMMENTTEXT), enabled); - EnableWindow(GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK), enabled); - SetDlgItemVisible(hwndDlg, IDC_PROGRESSTEXT, enabled); -} - -static INT_PTR DialogBoxParamMaybeRTL(UINT idd, HWND hwndParent, - DLGPROC dlgProc, LPARAM param) { - INT_PTR rv = 0; - if (gRTLlayout) { - // We need to toggle the WS_EX_LAYOUTRTL style flag on the dialog - // template. - HRSRC hDialogRC = FindResource(nullptr, MAKEINTRESOURCE(idd), RT_DIALOG); - HGLOBAL hDlgTemplate = LoadResource(nullptr, hDialogRC); - DLGTEMPLATEEX* pDlgTemplate = (DLGTEMPLATEEX*)LockResource(hDlgTemplate); - unsigned long sizeDlg = SizeofResource(nullptr, hDialogRC); - HGLOBAL hMyDlgTemplate = GlobalAlloc(GPTR, sizeDlg); - DLGTEMPLATEEX* pMyDlgTemplate = (DLGTEMPLATEEX*)GlobalLock(hMyDlgTemplate); - memcpy(pMyDlgTemplate, pDlgTemplate, sizeDlg); - - pMyDlgTemplate->exStyle |= WS_EX_LAYOUTRTL; - - rv = DialogBoxIndirectParam(nullptr, (LPCDLGTEMPLATE)pMyDlgTemplate, - hwndParent, dlgProc, param); - GlobalUnlock(hMyDlgTemplate); - GlobalFree(hMyDlgTemplate); - } else { - rv = DialogBoxParam(nullptr, MAKEINTRESOURCE(idd), hwndParent, dlgProc, - param); - } - - return rv; -} - -static BOOL CALLBACK CrashReporterDialogProc(HWND hwndDlg, UINT message, - WPARAM wParam, LPARAM lParam) { - static int sHeight = 0; - - bool success; - bool enabled; - - switch (message) { - case WM_INITDIALOG: { - GetThemeSizes(hwndDlg); - RECT r; - GetClientRect(hwndDlg, &r); - sHeight = r.bottom - r.top; - - SetWindowText(hwndDlg, Str(ST_CRASHREPORTERTITLE).c_str()); - HICON hIcon = - LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_MAINICON)); - SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon); - SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); - - // resize the "View Report" button based on the string length - RECT rect; - HWND hwnd = GetDlgItem(hwndDlg, IDC_VIEWREPORTBUTTON); - GetRelativeRect(hwnd, hwndDlg, &rect); - ResizeControl(hwnd, rect, Str(ST_VIEWREPORT), false, 0); - SetDlgItemText(hwndDlg, IDC_VIEWREPORTBUTTON, Str(ST_VIEWREPORT).c_str()); - - hwnd = GetDlgItem(hwndDlg, IDC_SUBMITREPORTCHECK); - GetRelativeRect(hwnd, hwndDlg, &rect); - long maxdiff = ResizeControl(hwnd, rect, Str(ST_CHECKSUBMIT), false, - gCheckboxPadding); - SetDlgItemText(hwndDlg, IDC_SUBMITREPORTCHECK, - Str(ST_CHECKSUBMIT).c_str()); - - if (!CheckBoolKey(gCrashReporterKey.c_str(), SUBMIT_REPORT_VALUE, - &enabled)) - enabled = true; - - CheckDlgButton(hwndDlg, IDC_SUBMITREPORTCHECK, - enabled ? BST_CHECKED : BST_UNCHECKED); - SubmitReportChecked(hwndDlg); - - HWND hwndComment = GetDlgItem(hwndDlg, IDC_COMMENTTEXT); - WNDPROC OldWndProc = (WNDPROC)SetWindowLongPtr( - hwndComment, GWLP_WNDPROC, (LONG_PTR)EditSubclassProc); - - // Subclass comment edit control to get placeholder text - SetWindowLongPtr(hwndComment, GWLP_USERDATA, (LONG_PTR)OldWndProc); - wstring commentGrayText = Str(ST_COMMENTGRAYTEXT); - wchar_t* hMem = (wchar_t*)GlobalAlloc( - GPTR, (commentGrayText.length() + 1) * sizeof(wchar_t)); - wcscpy(hMem, commentGrayText.c_str()); - SetProp(hwndComment, L"PROP_GRAYTEXT", hMem); - - hwnd = GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK); - GetRelativeRect(hwnd, hwndDlg, &rect); - long diff = - ResizeControl(hwnd, rect, Str(ST_CHECKURL), false, gCheckboxPadding); - maxdiff = std::max(diff, maxdiff); - SetDlgItemText(hwndDlg, IDC_INCLUDEURLCHECK, Str(ST_CHECKURL).c_str()); - - // want this on by default - if (CheckBoolKey(gCrashReporterKey.c_str(), INCLUDE_URL_VALUE, - &enabled) && - !enabled) { - CheckDlgButton(hwndDlg, IDC_INCLUDEURLCHECK, BST_UNCHECKED); - } else { - CheckDlgButton(hwndDlg, IDC_INCLUDEURLCHECK, BST_CHECKED); - } - - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, - Str(ST_REPORTPRESUBMIT).c_str()); - - RECT closeRect; - HWND hwndClose = GetDlgItem(hwndDlg, IDC_CLOSEBUTTON); - GetRelativeRect(hwndClose, hwndDlg, &closeRect); - - RECT restartRect; - HWND hwndRestart = GetDlgItem(hwndDlg, IDC_RESTARTBUTTON); - GetRelativeRect(hwndRestart, hwndDlg, &restartRect); - - // set the close button text and shift the buttons around - // since the size may need to change - int sizeDiff = ResizeControl(hwndClose, closeRect, Str(ST_QUIT), true, 0); - restartRect.left -= sizeDiff; - restartRect.right -= sizeDiff; - SetDlgItemText(hwndDlg, IDC_CLOSEBUTTON, Str(ST_QUIT).c_str()); - - if (gRestartArgs.size() > 0) { - // Resize restart button to fit text - ResizeControl(hwndRestart, restartRect, Str(ST_RESTART), true, 0); - SetDlgItemText(hwndDlg, IDC_RESTARTBUTTON, Str(ST_RESTART).c_str()); - } else { - // No restart arguments, so just hide the restart button - SetDlgItemVisible(hwndDlg, IDC_RESTARTBUTTON, false); - } - // See if we need to widen the window - // Leave 6 pixels on either side + 6 pixels between the buttons - int neededSize = closeRect.right - closeRect.left + restartRect.right - - restartRect.left + 6 * 3; - GetClientRect(hwndDlg, &r); - // We may already have resized one of the checkboxes above - maxdiff = std::max(maxdiff, neededSize - (r.right - r.left)); - - if (maxdiff > 0) { - // widen window - GetWindowRect(hwndDlg, &r); - r.right += maxdiff; - MoveWindow(hwndDlg, r.left, r.top, r.right - r.left, r.bottom - r.top, - TRUE); - // shift both buttons right - if (restartRect.left + maxdiff < 6) maxdiff += 6; - closeRect.left += maxdiff; - closeRect.right += maxdiff; - restartRect.left += maxdiff; - restartRect.right += maxdiff; - MoveWindow(hwndClose, closeRect.left, closeRect.top, - closeRect.right - closeRect.left, - closeRect.bottom - closeRect.top, TRUE); - StretchControlsToFit(hwndDlg); - } - // need to move the restart button regardless - MoveWindow(hwndRestart, restartRect.left, restartRect.top, - restartRect.right - restartRect.left, - restartRect.bottom - restartRect.top, TRUE); - - // Resize the description text last, in case the window was resized - // before this. - SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETEVENTMASK, - (WPARAM) nullptr, ENM_REQUESTRESIZE); - - wstring description = Str(ST_CRASHREPORTERHEADER); - description += L"\n\n"; - description += Str(ST_CRASHREPORTERDESCRIPTION); - SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, description.c_str()); - - // Make the title bold. - CHARFORMAT fmt = { - 0, - }; - fmt.cbSize = sizeof(fmt); - fmt.dwMask = CFM_BOLD; - fmt.dwEffects = CFE_BOLD; - SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL, 0, - Str(ST_CRASHREPORTERHEADER).length()); - SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETCHARFORMAT, - SCF_SELECTION, (LPARAM)&fmt); - SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETSEL, 0, 0); - // Force redraw. - SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETTARGETDEVICE, - (WPARAM) nullptr, 0); - // Force resize. - SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_REQUESTRESIZE, 0, 0); - - // if no URL was given, hide the URL checkbox - if (!gQueryParameters.isMember("URL")) { - RECT urlCheckRect; - GetWindowRect(GetDlgItem(hwndDlg, IDC_INCLUDEURLCHECK), &urlCheckRect); - - SetDlgItemVisible(hwndDlg, IDC_INCLUDEURLCHECK, false); - - gAttachedBottom.erase(IDC_VIEWREPORTBUTTON); - gAttachedBottom.erase(IDC_SUBMITREPORTCHECK); - gAttachedBottom.erase(IDC_COMMENTTEXT); - - StretchDialog(hwndDlg, urlCheckRect.top - urlCheckRect.bottom); - - gAttachedBottom.insert(IDC_VIEWREPORTBUTTON); - gAttachedBottom.insert(IDC_SUBMITREPORTCHECK); - gAttachedBottom.insert(IDC_COMMENTTEXT); - } - - MaybeResizeProgressText(hwndDlg); - - // Open the AVI resource for the throbber - Animate_Open(GetDlgItem(hwndDlg, IDC_THROBBER), - MAKEINTRESOURCE(IDR_THROBBER)); - - UpdateURL(hwndDlg); - - SetFocus(GetDlgItem(hwndDlg, IDC_SUBMITREPORTCHECK)); - return FALSE; - } - case WM_SIZE: { - ReflowDialog(hwndDlg, HIWORD(lParam) - sHeight); - sHeight = HIWORD(lParam); - InvalidateRect(hwndDlg, nullptr, TRUE); - return FALSE; - } - case WM_NOTIFY: { - NMHDR* notification = reinterpret_cast(lParam); - if (notification->code == EN_REQUESTRESIZE) { - // Resizing the rich edit control to fit the description text. - REQRESIZE* reqresize = reinterpret_cast(lParam); - RECT newSize = reqresize->rc; - RECT oldSize; - GetRelativeRect(notification->hwndFrom, hwndDlg, &oldSize); - - // resize the text box as requested - MoveWindow(notification->hwndFrom, newSize.left, newSize.top, - newSize.right - newSize.left, newSize.bottom - newSize.top, - TRUE); - - // Resize the dialog to fit (the WM_SIZE handler will move the controls) - StretchDialog(hwndDlg, newSize.bottom - oldSize.bottom); - } - return FALSE; - } - case WM_COMMAND: { - if (HIWORD(wParam) == BN_CLICKED) { - switch (LOWORD(wParam)) { - case IDC_VIEWREPORTBUTTON: - DialogBoxParamMaybeRTL(IDD_VIEWREPORTDIALOG, hwndDlg, - (DLGPROC)ViewReportDialogProc, 0); - break; - case IDC_SUBMITREPORTCHECK: - SubmitReportChecked(hwndDlg); - break; - case IDC_INCLUDEURLCHECK: - UpdateURL(hwndDlg); - break; - case IDC_CLOSEBUTTON: - MaybeSendReport(hwndDlg); - break; - case IDC_RESTARTBUTTON: - RestartApplication(); - MaybeSendReport(hwndDlg); - break; - } - } else if (HIWORD(wParam) == EN_CHANGE) { - switch (LOWORD(wParam)) { - case IDC_COMMENTTEXT: - UpdateComment(hwndDlg); - } - } - - return FALSE; - } - case WM_UPLOADCOMPLETE: { - WaitForSingleObject(gThreadHandle, INFINITE); - success = (wParam == 1); - SendCompleted(success, WideToUTF8(gSendData.serverResponse)); - // hide throbber - Animate_Stop(GetDlgItem(hwndDlg, IDC_THROBBER)); - SetDlgItemVisible(hwndDlg, IDC_THROBBER, false); - - SetDlgItemText(hwndDlg, IDC_PROGRESSTEXT, - success ? Str(ST_REPORTSUBMITSUCCESS).c_str() - : Str(ST_SUBMITFAILED).c_str()); - MaybeResizeProgressText(hwndDlg); - // close dialog after 5 seconds - SetTimer(hwndDlg, 0, 5000, nullptr); - // - return TRUE; - } - - case WM_TIMER: { - // The "1" gets used down in UIShowCrashUI to indicate that we at least - // tried to send the report. - EndCrashReporterDialog(hwndDlg, 1); - return FALSE; - } - - case WM_CLOSE: { - EndCrashReporterDialog(hwndDlg, 0); - return FALSE; - } - } - return FALSE; -} - -static wstring UTF8ToWide(const string& utf8, bool* success) { - wchar_t* buffer = nullptr; - int buffer_size = - MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, nullptr, 0); - if (buffer_size == 0) { - if (success) *success = false; - return L""; - } - - buffer = new wchar_t[buffer_size]; - if (buffer == nullptr) { - if (success) *success = false; - return L""; - } - - MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buffer, buffer_size); - wstring str = buffer; - delete[] buffer; - - if (success) *success = true; - - return str; -} - -static string WideToMBCP(const wstring& wide, unsigned int cp, - bool* success = nullptr) { - char* buffer = nullptr; - int buffer_size = WideCharToMultiByte(cp, 0, wide.c_str(), -1, nullptr, 0, - nullptr, nullptr); - if (buffer_size == 0) { - if (success) *success = false; - return ""; - } - - buffer = new char[buffer_size]; - if (buffer == nullptr) { - if (success) *success = false; - return ""; - } - - WideCharToMultiByte(cp, 0, wide.c_str(), -1, buffer, buffer_size, nullptr, - nullptr); - string mb = buffer; - delete[] buffer; - - if (success) *success = true; - - return mb; -} - -string WideToUTF8(const wstring& wide, bool* success) { - return WideToMBCP(wide, CP_UTF8, success); -} - -/* === Crashreporter UI Functions === */ - -bool UIInit() { - for (size_t i = 0; i < sizeof(kDefaultAttachedBottom) / sizeof(UINT); i++) { - gAttachedBottom.insert(kDefaultAttachedBottom[i]); - } - - DoInitCommonControls(); - - return true; -} - -void UIShutdown() {} - -void UIShowDefaultUI() { - MessageBox(nullptr, Str(ST_CRASHREPORTERDEFAULT).c_str(), L"Crash Reporter", - MB_OK | MB_ICONSTOP); -} - -bool UIShowCrashUI(const StringTable& files, const Json::Value& queryParameters, - const string& sendURL, const vector& restartArgs) { - gSendData.hDlg = nullptr; - gSendData.sendURL = UTF8ToWide(sendURL); - - for (StringTable::const_iterator i = files.begin(); i != files.end(); i++) { - gSendData.files[UTF8ToWide(i->first)] = UTF8ToWide(i->second); - } - - gQueryParameters = queryParameters; - - if (gQueryParameters.isMember("Vendor")) { - gCrashReporterKey = L"Software\\"; - string vendor = gQueryParameters["Vendor"].asString(); - if (!vendor.empty()) { - gCrashReporterKey += UTF8ToWide(vendor) + L"\\"; - } - string productName = gQueryParameters["ProductName"].asString(); - gCrashReporterKey += UTF8ToWide(productName) + L"\\Crash Reporter"; - } - - if (gQueryParameters.isMember("URL")) { - gURLParameter = gQueryParameters["URL"].asString(); - } - - gRestartArgs = restartArgs; - - if (gStrings.find("isRTL") != gStrings.end() && gStrings["isRTL"] == "yes") - gRTLlayout = true; - - if (gAutoSubmit) { - gSendData.queryParameters = gQueryParameters; - - gThreadHandle = - CreateThread(nullptr, 0, SendThreadProc, &gSendData, 0, nullptr); - WaitForSingleObject(gThreadHandle, INFINITE); - // SendCompleted was called from SendThreadProc - return true; - } - - return 1 == DialogBoxParamMaybeRTL(IDD_SENDDIALOG, nullptr, - (DLGPROC)CrashReporterDialogProc, 0); -} - -void UIError_impl(const string& message) { - wstring title = Str(ST_CRASHREPORTERTITLE); - if (title.empty()) title = L"Crash Reporter Error"; - - MessageBox(nullptr, UTF8ToWide(message).c_str(), title.c_str(), - MB_OK | MB_ICONSTOP); -} - -bool UIGetIniPath(string& path) { - wchar_t fileName[MAX_PATH]; - if (GetModuleFileName(nullptr, fileName, MAX_PATH)) { - // get crashreporter ini - wchar_t* s = wcsrchr(fileName, '.'); - if (s) { - wcscpy(s, L".ini"); - path = WideToUTF8(fileName); - return true; - } - } - - return false; -} - -bool UIGetSettingsPath(const string& vendor, const string& product, - string& settings_path) { - wchar_t path[MAX_PATH] = {}; - HRESULT hRes = SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, 0, path); - if (FAILED(hRes)) { - // This provides a fallback for getting the path to APPDATA by querying the - // registry when the call to SHGetFolderPath is unable to provide this path - // (Bug 513958). - HKEY key; - DWORD type, dwRes; - DWORD size = sizeof(path) - 1; - dwRes = ::RegOpenKeyExW(HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\CurrentVersion\\Exp" - L"lorer\\Shell Folders", - 0, KEY_READ, &key); - if (dwRes != ERROR_SUCCESS) return false; - - dwRes = - RegQueryValueExW(key, L"AppData", nullptr, &type, (LPBYTE)&path, &size); - ::RegCloseKey(key); - // The call to RegQueryValueExW must succeed, the type must be REG_SZ, the - // buffer size must not equal 0, and the buffer size be a multiple of 2. - if (dwRes != ERROR_SUCCESS || type != REG_SZ || size == 0 || size % 2 != 0) - return false; - } - - if (!vendor.empty()) { - PathAppend(path, UTF8ToWide(vendor).c_str()); - } - PathAppend(path, UTF8ToWide(product).c_str()); - PathAppend(path, L"Crash Reports"); - settings_path = WideToUTF8(path); - return true; -} - -bool UIEnsurePathExists(const string& path) { - if (CreateDirectory(UTF8ToWide(path).c_str(), nullptr) == 0) { - if (GetLastError() != ERROR_ALREADY_EXISTS) return false; - } - - return true; -} - -bool UIFileExists(const string& path) { - DWORD attrs = GetFileAttributes(UTF8ToWide(path).c_str()); - return (attrs != INVALID_FILE_ATTRIBUTES); -} - -bool UIMoveFile(const string& oldfile, const string& newfile) { - if (oldfile == newfile) return true; - - return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str()) == - TRUE; -} - -bool UIDeleteFile(const string& oldfile) { - return DeleteFile(UTF8ToWide(oldfile).c_str()) == TRUE; -} - -ifstream* UIOpenRead(const string& filename, ios_base::openmode mode) { -#if defined(_MSC_VER) - ifstream* file = new ifstream(); - file->open(UTF8ToWide(filename).c_str(), mode); -#else // GCC - ifstream* file = - new ifstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(), mode); -#endif // _MSC_VER - - return file; -} - -ofstream* UIOpenWrite(const string& filename, ios_base::openmode mode) { -#if defined(_MSC_VER) - ofstream* file = new ofstream(); - file->open(UTF8ToWide(filename).c_str(), mode); -#else // GCC - ofstream* file = - new ofstream(WideToMBCP(UTF8ToWide(filename), CP_ACP).c_str(), mode); -#endif // _MSC_VER - - return file; -} - -struct FileData { - FILETIME timestamp; - wstring path; -}; - -static bool CompareFDTime(const FileData& fd1, const FileData& fd2) { - return CompareFileTime(&fd1.timestamp, &fd2.timestamp) > 0; -} - -void UIPruneSavedDumps(const std::string& directory) { - wstring wdirectory = UTF8ToWide(directory); - - WIN32_FIND_DATA fdata; - wstring findpath = wdirectory + L"\\*.dmp"; - HANDLE dirlist = FindFirstFile(findpath.c_str(), &fdata); - if (dirlist == INVALID_HANDLE_VALUE) return; - - vector dumpfiles; - - for (BOOL ok = true; ok; ok = FindNextFile(dirlist, &fdata)) { - FileData fd = {fdata.ftLastWriteTime, wdirectory + L"\\" + fdata.cFileName}; - dumpfiles.push_back(fd); - } - - sort(dumpfiles.begin(), dumpfiles.end(), CompareFDTime); - - while (dumpfiles.size() > kSaveCount) { - // get the path of the oldest file - wstring path = (--dumpfiles.end())->path; - DeleteFile(path.c_str()); - - // s/.dmp/.extra/ - path.replace(path.size() - 4, 4, L".extra"); - DeleteFile(path.c_str()); - - dumpfiles.pop_back(); - } - FindClose(dirlist); -} - -bool UIRunProgram(const string& exename, const std::vector& args, - bool wait) { - wstring cmdLine = L"\"" + UTF8ToWide(exename) + L"\" "; - - for (auto arg : args) { - cmdLine += L"\"" + UTF8ToWide(arg) + L"\" "; - } - - STARTUPINFO si = {}; - si.cb = sizeof(si); - PROCESS_INFORMATION pi = {}; - - if (!CreateProcess(/* lpApplicationName */ nullptr, (LPWSTR)cmdLine.c_str(), - /* lpProcessAttributes */ nullptr, - /* lpThreadAttributes */ nullptr, - /* bInheritHandles */ false, - NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, - /* lpEnvironment */ nullptr, - /* lpCurrentDirectory */ nullptr, &si, &pi)) { - return false; - } - - if (wait) { - WaitForSingleObject(pi.hProcess, INFINITE); - } - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - return true; -} - -string UIGetEnv(const string& name) { - const wchar_t* var = _wgetenv(UTF8ToWide(name).c_str()); - if (var && *var) { - return WideToUTF8(var); - } - - return ""; -} diff --git a/toolkit/crashreporter/client-rust/gtkbind/Cargo.toml b/toolkit/crashreporter/client/gtkbind/Cargo.toml similarity index 100% rename from toolkit/crashreporter/client-rust/gtkbind/Cargo.toml rename to toolkit/crashreporter/client/gtkbind/Cargo.toml diff --git a/toolkit/crashreporter/client-rust/gtkbind/build.rs b/toolkit/crashreporter/client/gtkbind/build.rs similarity index 100% rename from toolkit/crashreporter/client-rust/gtkbind/build.rs rename to toolkit/crashreporter/client/gtkbind/build.rs diff --git a/toolkit/crashreporter/client-rust/gtkbind/src/lib.rs b/toolkit/crashreporter/client/gtkbind/src/lib.rs similarity index 100% rename from toolkit/crashreporter/client-rust/gtkbind/src/lib.rs rename to toolkit/crashreporter/client/gtkbind/src/lib.rs diff --git a/toolkit/crashreporter/client/macbuild/Contents/PkgInfo b/toolkit/crashreporter/client/macbuild/Contents/PkgInfo deleted file mode 100644 index cae6d0a58f25..000000000000 --- a/toolkit/crashreporter/client/macbuild/Contents/PkgInfo +++ /dev/null @@ -1,2 +0,0 @@ -APPL???? - diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in deleted file mode 100644 index e08ce59eb660..000000000000 --- a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in +++ /dev/null @@ -1,8 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Localized versions of Info.plist keys */ - -CFBundleName = "Crash Reporter"; -CFBundleDisplayName = "@APP_NAME@ Crash Reporter"; diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib deleted file mode 100644 index 254131e43145..000000000000 --- a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/classes.nib +++ /dev/null @@ -1,100 +0,0 @@ - - - - - IBClasses - - - ACTIONS - - closeClicked - id - includeURLClicked - id - restartClicked - id - submitReportClicked - id - viewReportClicked - id - viewReportOkClicked - id - - CLASS - CrashReporterUI - LANGUAGE - ObjC - OUTLETS - - mCloseButton - NSButton - mCommentScrollView - NSScrollView - mCommentText - TextViewWithPlaceHolder - mDescriptionLabel - NSTextField - mEmailMeButton - NSButton - mEmailText - NSTextField - mErrorCloseButton - NSButton - mErrorHeaderLabel - NSTextField - mErrorLabel - NSTextField - mErrorView - NSView - mHeaderLabel - NSTextField - mIncludeURLButton - NSButton - mProgressIndicator - NSProgressIndicator - mProgressText - NSTextField - mRestartButton - NSButton - mSubmitReportButton - NSButton - mViewReportButton - NSButton - mViewReportOkButton - NSButton - mViewReportTextView - NSTextView - mViewReportWindow - NSWindow - mWindow - NSWindow - - SUPERCLASS - NSObject - - - ACTIONS - - insertTab - id - - CLASS - TextViewWithPlaceHolder - LANGUAGE - ObjC - SUPERCLASS - NSTextView - - - CLASS - FirstResponder - LANGUAGE - ObjC - SUPERCLASS - NSObject - - - IBVersion - 1 - - diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib deleted file mode 100644 index 517349ffceba..000000000000 --- a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/info.nib +++ /dev/null @@ -1,18 +0,0 @@ - - - - - IBFramework Version - 629 - IBOldestOS - 5 - IBOpenObjects - - 2 - - IBSystem Version - 9C7010 - targetFramework - IBCocoaFramework - - diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib deleted file mode 100644 index bfdcccb74c66..000000000000 Binary files a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib and /dev/null differ diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib deleted file mode 100644 index 254131e43145..000000000000 --- a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/classes.nib +++ /dev/null @@ -1,100 +0,0 @@ - - - - - IBClasses - - - ACTIONS - - closeClicked - id - includeURLClicked - id - restartClicked - id - submitReportClicked - id - viewReportClicked - id - viewReportOkClicked - id - - CLASS - CrashReporterUI - LANGUAGE - ObjC - OUTLETS - - mCloseButton - NSButton - mCommentScrollView - NSScrollView - mCommentText - TextViewWithPlaceHolder - mDescriptionLabel - NSTextField - mEmailMeButton - NSButton - mEmailText - NSTextField - mErrorCloseButton - NSButton - mErrorHeaderLabel - NSTextField - mErrorLabel - NSTextField - mErrorView - NSView - mHeaderLabel - NSTextField - mIncludeURLButton - NSButton - mProgressIndicator - NSProgressIndicator - mProgressText - NSTextField - mRestartButton - NSButton - mSubmitReportButton - NSButton - mViewReportButton - NSButton - mViewReportOkButton - NSButton - mViewReportTextView - NSTextView - mViewReportWindow - NSWindow - mWindow - NSWindow - - SUPERCLASS - NSObject - - - ACTIONS - - insertTab - id - - CLASS - TextViewWithPlaceHolder - LANGUAGE - ObjC - SUPERCLASS - NSTextView - - - CLASS - FirstResponder - LANGUAGE - ObjC - SUPERCLASS - NSObject - - - IBVersion - 1 - - diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/info.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/info.nib deleted file mode 100644 index 4a2251aaf502..000000000000 --- a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/info.nib +++ /dev/null @@ -1,18 +0,0 @@ - - - - - IBFramework Version - 629 - IBOldestOS - 5 - IBOpenObjects - - 2 - - IBSystem Version - 9D34 - targetFramework - IBCocoaFramework - - diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/keyedobjects.nib b/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/keyedobjects.nib deleted file mode 100644 index 6c93849b94ff..000000000000 Binary files a/toolkit/crashreporter/client/macbuild/Contents/Resources/English.lproj/MainMenuRTL.nib/keyedobjects.nib and /dev/null differ diff --git a/toolkit/crashreporter/client/macbuild/Contents/Resources/crashreporter.icns b/toolkit/crashreporter/client/macbuild/Contents/Resources/crashreporter.icns deleted file mode 100644 index 341cd05a4d00..000000000000 Binary files a/toolkit/crashreporter/client/macbuild/Contents/Resources/crashreporter.icns and /dev/null differ diff --git a/toolkit/crashreporter/client/moz.build b/toolkit/crashreporter/client/moz.build deleted file mode 100644 index 82e19b8637ea..000000000000 --- a/toolkit/crashreporter/client/moz.build +++ /dev/null @@ -1,97 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -if CONFIG["OS_TARGET"] != "Android": - Program("crashreporter") - - UNIFIED_SOURCES += [ - "../CrashAnnotations.cpp", - "crashreporter.cpp", - "ping.cpp", - ] - - LOCAL_INCLUDES += [ - "/toolkit/components/jsoncpp/include", - ] - - USE_LIBS += [ - "jsoncpp", - ] - -if CONFIG["OS_ARCH"] == "WINNT": - UNIFIED_SOURCES += [ - "crashreporter_win.cpp", - ] - include("/toolkit/crashreporter/breakpad-client/windows/sender/objs.mozbuild") - SOURCES += objs_sender - SOURCES += [ - "../google-breakpad/src/common/windows/http_upload.cc", - ] - DEFINES["UNICODE"] = True - DEFINES["_UNICODE"] = True - USE_LIBS += [ - "nss", - ] - OS_LIBS += [ - "advapi32", - "comctl32", - "gdi32", - "ole32", - "shell32", - "wininet", - "shlwapi", - "user32", - ] -elif CONFIG["OS_ARCH"] == "Darwin": - UNIFIED_SOURCES += [ - "../google-breakpad/src/common/mac/HTTPMultipartUpload.m", - "crashreporter_osx.mm", - "crashreporter_unix_common.cpp", - ] - LOCAL_INCLUDES += [ - "../google-breakpad/src/common/mac", - ] - OS_LIBS += ["-framework Cocoa"] - USE_LIBS += [ - "nss", - ] - LDFLAGS += ["-Wl,-rpath,@executable_path/../../../"] -elif CONFIG["OS_ARCH"] == "SunOS": - SOURCES += [ - "crashreporter_linux.cpp", - "crashreporter_unix.cpp", - ] - USE_LIBS += [ - "breakpad_solaris_common_s", - ] - -if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": - UNIFIED_SOURCES += [ - "../google-breakpad/src/common/linux/http_upload.cc", - "crashreporter_gtk_common.cpp", - "crashreporter_linux.cpp", - "crashreporter_unix_common.cpp", - ] - OS_LIBS += CONFIG["MOZ_GTK3_LIBS"] - OS_LIBS += CONFIG["MOZ_GTHREAD_LIBS"] - CXXFLAGS += CONFIG["MOZ_GTK3_CFLAGS"] - CXXFLAGS += CONFIG["MOZ_GTHREAD_CFLAGS"] - -if CONFIG["OS_ARCH"] == "Linux" or CONFIG["OS_ARCH"] == "SunOS": - FINAL_TARGET_FILES += [ - "Throbber-small.gif", - ] - -DEFINES["MOZ_APP_NAME"] = '"%s"' % CONFIG["MOZ_APP_NAME"] -DEFINES["BIN_SUFFIX"] = '"%s"' % CONFIG["BIN_SUFFIX"] - -RCINCLUDE = "crashreporter.rc" - -# Don't use the STL wrappers in the crashreporter clients; they don't -# link with -lmozalloc, and it really doesn't matter here anyway. -DisableStlWrapping() - -include("/toolkit/crashreporter/crashreporter.mozbuild") diff --git a/toolkit/crashreporter/client/ping.cpp b/toolkit/crashreporter/client/ping.cpp deleted file mode 100644 index b49211c9c158..000000000000 --- a/toolkit/crashreporter/client/ping.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "crashreporter.h" - -#include -#include -#include - -#if defined(XP_LINUX) -# include -# include -# include -#elif defined(XP_MACOSX) -# include -#elif defined(XP_WIN) -# include -#endif - -#include "json/json.h" - -#include "CrashAnnotations.h" - -using std::string; - -namespace CrashReporter { - -struct UUID { - uint32_t m0; - uint16_t m1; - uint16_t m2; - uint8_t m3[8]; -}; - -// Generates an UUID; the code here is mostly copied from nsUUIDGenerator.cpp -static string GenerateUUID() { - UUID id = {}; - -#if defined(XP_WIN) // Windows - HRESULT hr = CoCreateGuid((GUID*)&id); - if (FAILED(hr)) { - return ""; - } -#elif defined(XP_MACOSX) // MacOS X - CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); - if (!uuid) { - return ""; - } - - CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid); - memcpy(&id, &bytes, sizeof(UUID)); - - CFRelease(uuid); -#elif defined(HAVE_ARC4RANDOM_BUF) // Android, BSD, ... - arc4random_buf(&id, sizeof(UUID)); -#else // Linux - int fd = open("/dev/urandom", O_RDONLY); - - if (fd == -1) { - return ""; - } - - if (read(fd, &id, sizeof(UUID)) != sizeof(UUID)) { - close(fd); - return ""; - } - - close(fd); -#endif - - /* Put in the version */ - id.m2 &= 0x0fff; - id.m2 |= 0x4000; - - /* Put in the variant */ - id.m3[0] &= 0x3f; - id.m3[0] |= 0x80; - - const char* kUUIDFormatString = - "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"; - const size_t kUUIDFormatStringLength = 36; - char str[kUUIDFormatStringLength + 1] = {'\0'}; - - int num = snprintf(str, kUUIDFormatStringLength + 1, kUUIDFormatString, id.m0, - id.m1, id.m2, id.m3[0], id.m3[1], id.m3[2], id.m3[3], - id.m3[4], id.m3[5], id.m3[6], id.m3[7]); - - if (num != kUUIDFormatStringLength) { - return ""; - } - - return str; -} - -const char kISO8601Date[] = "%F"; -const char kISO8601DateHours[] = "%FT%H:00:00.000Z"; - -// Return the current date as a string in the specified format, the following -// constants are provided: -// - kISO8601Date, the ISO 8601 date format, YYYY-MM-DD -// - kISO8601DateHours, the ISO 8601 full date format, YYYY-MM-DDTHH:00:00.000Z -static string CurrentDate(string format) { - time_t now; - time(&now); - char buf[64]; // This should be plenty - strftime(buf, sizeof buf, format.c_str(), gmtime(&now)); - return buf; -} - -const char kTelemetryClientId[] = "TelemetryClientId"; -const char kTelemetryUrl[] = "TelemetryServerURL"; -const char kTelemetrySessionId[] = "TelemetrySessionId"; -const int kTelemetryVersion = 4; - -// Create the payload.metadata node of the crash ping using fields extracted -// from the .extra file -static Json::Value CreateMetadataNode(const Json::Value& aExtra) { - Json::Value node; - - for (Json::ValueConstIterator iter = aExtra.begin(); iter != aExtra.end(); - ++iter) { - Annotation annotation; - - if (AnnotationFromString(annotation, iter.memberName())) { - if (IsAnnotationAllowedForPing(annotation)) { - node[iter.memberName()] = *iter; - } - } - } - - return node; -} - -// Create the payload node of the crash ping -static Json::Value CreatePayloadNode(const Json::Value& aExtra, - const string& aHash, - const string& aSessionId) { - Json::Value payload; - - payload["sessionId"] = aSessionId; - payload["version"] = 1; - payload["crashDate"] = CurrentDate(kISO8601Date); - payload["crashTime"] = CurrentDate(kISO8601DateHours); - payload["hasCrashEnvironment"] = true; - payload["crashId"] = CrashReporter::GetDumpLocalID(); - payload["minidumpSha256Hash"] = aHash; - payload["processType"] = "main"; // This is always a main crash - if (aExtra.isMember("StackTraces")) { - payload["stackTraces"] = aExtra["StackTraces"]; - } - - // Assemble the payload metadata - payload["metadata"] = CreateMetadataNode(aExtra); - - return payload; -} - -// Create the application node of the crash ping -static Json::Value CreateApplicationNode( - const string& aVendor, const string& aName, const string& aVersion, - const string& aDisplayVersion, const string& aPlatformVersion, - const string& aChannel, const string& aBuildId, const string& aArchitecture, - const string& aXpcomAbi) { - Json::Value application; - - application["vendor"] = aVendor; - application["name"] = aName; - application["buildId"] = aBuildId; - application["displayVersion"] = aDisplayVersion; - application["platformVersion"] = aPlatformVersion; - application["version"] = aVersion; - application["channel"] = aChannel; - if (!aArchitecture.empty()) { - application["architecture"] = aArchitecture; - } - if (!aXpcomAbi.empty()) { - application["xpcomAbi"] = aXpcomAbi; - } - - return application; -} - -// Create the root node of the crash ping -static Json::Value CreateRootNode( - const Json::Value& aExtra, const string& aUuid, const string& aHash, - const string& aClientId, const string& aSessionId, const string& aName, - const string& aVersion, const string& aChannel, const string& aBuildId) { - Json::Value root; - root["type"] = "crash"; // This is a crash ping - root["id"] = aUuid; - root["version"] = kTelemetryVersion; - root["creationDate"] = CurrentDate(kISO8601DateHours); - root["clientId"] = aClientId; - - // Parse the telemetry environment - Json::Value environment; - Json::Reader reader; - string architecture; - string xpcomAbi; - string displayVersion; - string platformVersion; - - if (reader.parse(aExtra["TelemetryEnvironment"].asString(), environment, - /* collectComments */ false)) { - if (environment.isMember("build") && environment["build"].isObject()) { - Json::Value build = environment["build"]; - if (build.isMember("architecture") && build["architecture"].isString()) { - architecture = build["architecture"].asString(); - } - if (build.isMember("xpcomAbi") && build["xpcomAbi"].isString()) { - xpcomAbi = build["xpcomAbi"].asString(); - } - if (build.isMember("displayVersion") && - build["displayVersion"].isString()) { - displayVersion = build["displayVersion"].asString(); - } - if (build.isMember("platformVersion") && - build["platformVersion"].isString()) { - platformVersion = build["platformVersion"].asString(); - } - } - - root["environment"] = environment; - } - - root["payload"] = CreatePayloadNode(aExtra, aHash, aSessionId); - root["application"] = CreateApplicationNode( - aExtra["Vendor"].asString(), aName, aVersion, displayVersion, - platformVersion, aChannel, aBuildId, architecture, xpcomAbi); - - return root; -} - -// Generates the URL used to submit the crash ping, see TelemetrySend.sys.mjs -string GenerateSubmissionUrl(const string& aUrl, const string& aId, - const string& aName, const string& aVersion, - const string& aChannel, const string& aBuildId) { - return aUrl + "/submit/telemetry/" + aId + "/crash/" + aName + "/" + - aVersion + "/" + aChannel + "/" + aBuildId + - "?v=" + std::to_string(kTelemetryVersion); -} - -// Write out the ping into the specified file. -// -// Returns true if the ping was written out successfully, false otherwise. -static bool WritePing(const string& aPath, const string& aPing) { - std::ofstream* f = UIOpenWrite(aPath, std::ios::trunc); - bool success = false; - - if (f->is_open()) { - *f << aPing; - f->close(); - success = f->good(); - } - - delete f; - return success; -} - -// Assembles the crash ping using the JSON data extracted from the .extra file -// and sends it using the crash sender. All the telemetry specific data but the -// environment will be stripped from the annotations so that it won't be sent -// together with the crash report. -// -// Note that the crash ping sender is invoked in a fire-and-forget way so this -// won't block waiting for the ping to be delivered. -// -// Returns true if the ping was assembled and handed over to the pingsender -// correctly, also populates the aPingUuid parameter with the ping UUID. Returns -// false otherwise and leaves the aPingUuid parameter unmodified. -bool SendCrashPing(Json::Value& aExtra, const string& aHash, string& aPingUuid, - const string& pingDir) { - // Remove the telemetry-related data from the crash annotations - Json::Value value; - aExtra.removeMember(kTelemetryClientId, &value); - string clientId = value.asString(); - aExtra.removeMember(kTelemetryUrl, &value); - string serverUrl = value.asString(); - aExtra.removeMember(kTelemetrySessionId, &value); - string sessionId = value.asString(); - - if (clientId.empty() || serverUrl.empty() || sessionId.empty()) { - return false; - } - - string buildId = aExtra["BuildID"].asString(); - string channel = aExtra["ReleaseChannel"].asString(); - string name = aExtra["ProductName"].asString(); - string version = aExtra["Version"].asString(); - string uuid = GenerateUUID(); - string url = - GenerateSubmissionUrl(serverUrl, uuid, name, version, channel, buildId); - - if (serverUrl.empty() || uuid.empty()) { - return false; - } - - Json::Value root = CreateRootNode(aExtra, uuid, aHash, clientId, sessionId, - name, version, channel, buildId); - - // Write out the result to the pending pings directory - Json::StreamWriterBuilder builder; - builder["indentation"] = ""; - string ping = Json::writeString(builder, root); - string pingPath = pingDir + UI_DIR_SEPARATOR + uuid + ".json"; - - if (!WritePing(pingPath, ping)) { - return false; - } - - // Hand over the ping to the sender - std::vector args = {url, pingPath}; - if (UIRunProgram(CrashReporter::GetProgramPath(UI_PING_SENDER_FILENAME), - args)) { - aPingUuid = uuid; - return true; - } else { - return false; - } -} - -} // namespace CrashReporter diff --git a/toolkit/crashreporter/client/resource.h b/toolkit/crashreporter/client/resource.h deleted file mode 100644 index 2e7917daa46d..000000000000 --- a/toolkit/crashreporter/client/resource.h +++ /dev/null @@ -1,35 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by crashreporter.rc -// -#define IDD_SENDDIALOG 102 -#define IDR_THROBBER 103 -#define IDD_VIEWREPORTDIALOG 104 -#define IDI_MAINICON 105 -#define IDC_PROGRESS 1003 -#define IDC_DESCRIPTIONTEXT 1004 -#define IDC_CLOSEBUTTON 1005 -#define IDC_VIEWREPORTBUTTON 1006 -#define IDC_SUBMITREPORTCHECK 1007 -#define IDC_INCLUDEURLCHECK 1010 -#define IDC_COMMENTTEXT 1011 -#define IDC_RESTARTBUTTON 1012 -#define IDC_DESCRIPTIONLABEL 1013 -#define IDC_PROGRESSTEXT 1014 -#define IDC_THROBBER 1015 -#define IDC_VIEWREPORTTEXT 1016 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -# ifndef APSTUDIO_READONLY_SYMBOLS -# define _APS_NEXT_RESOURCE_VALUE 106 -# define _APS_NEXT_COMMAND_VALUE 40001 -# define _APS_NEXT_CONTROL_VALUE 1017 -# define _APS_NEXT_SYMED_VALUE 101 -# endif -#endif diff --git a/toolkit/crashreporter/moz.build b/toolkit/crashreporter/moz.build index 272ed99d1237..95c1ff94661d 100644 --- a/toolkit/crashreporter/moz.build +++ b/toolkit/crashreporter/moz.build @@ -68,7 +68,7 @@ if CONFIG["MOZ_CRASHREPORTER"]: if CONFIG["OS_TARGET"] != "Android": DIRS += [ - "client-rust/app", + "client/app", "minidump-analyzer", ]