fune/toolkit/crashreporter/client/crashreporter_gtk_common.cpp
Stanca Serban cefd926755 Backed out 9 changesets (bug 1826760, bug 1826758, bug 1826752, bug 1826756, bug 1826759, bug 1826761, bug 1826757, bug 1826753, bug 1826754) for causing bp-hybrid bustages in ClearKeyDecryptionManager.cpp.
CLOSED TREE

Backed out changeset 210012222277 (bug 1826761)
Backed out changeset e364bb149efa (bug 1826760)
Backed out changeset e456e2f9966c (bug 1826759)
Backed out changeset 2b6ff545f4a3 (bug 1826758)
Backed out changeset 95fe1de8ba00 (bug 1826757)
Backed out changeset f8af52d7f2a1 (bug 1826756)
Backed out changeset 2646e773f098 (bug 1826754)
Backed out changeset 58d5d74b1835 (bug 1826753)
Backed out changeset 8567e6595acc (bug 1826752)
2023-04-17 13:52:39 +03:00

361 lines
9.4 KiB
C++

/* -*- 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 <unistd.h>
#include <dlfcn.h>
#include <errno.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <gdk/gdkkeysyms.h>
#include <algorithm>
#include <string>
#include <vector>
#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<string> gRestartArgs;
GThread* gSendThreadID;
// From crashreporter_linux.cpp
void SendReport();
void DisableGUIAndSendReport();
void TryInitGnome();
void UpdateSubmit();
static bool RestartApplication() {
char** argv = reinterpret_cast<char**>(
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;
} else if (pid == 0) {
(void)execv(argv[0], argv);
_exit(1);
}
free(argv);
return true;
}
// Quit the app, used as a timeout callback
static 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<char*>("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);
}