From: Arjan van de Ven Date: Sat, 17 Jan 2009 18:34:22 +0000 (-0600) Subject: steal the applet from kerneloops.org X-Git-Tag: accepted/trunk/20130110.014835~198 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5be920670c7b87b633e229e96673d128c390a60e;p=platform%2Fupstream%2Fcorewatcher.git steal the applet from kerneloops.org --- diff --git a/Makefile b/Makefile index a7126d9..aac2759 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,18 @@ -all: corewatcher +all: corewatcher corewatcher-applet CFLAGS := -O2 -g -Wall -W -D_FORTIFY_SOURCE=2 -fstack-protector -CFLAGS += `pkg-config --cflags glib-2.0` `pkg-config --cflags dbus-glib-1` -fno-common -LINKFLAGS += `pkg-config --libs glib-2.0` `pkg-config --libs dbus-glib-1` `curl-config --libs` -fno-common +CFLAGS += `pkg-config --cflags glib-2.0 gtk+-2.0 dbus-glib-1` -fno-common + +LINKFLAGS += `pkg-config --libs glib-2.0 dbus-glib-1` `curl-config --libs` -fno-common LIBS = corewatcher.o find_file.o webinterface.o dbus.o configfile.o corewatcher: $(LIBS) coredumper.h Makefile gcc $(CFLAGS) $(LIBS) $(LINKFLAGS) -o corewatcher +corewatcher-applet: + gcc $(CFLAGS) $(LINKFLAGS) `pkg-config --libs gtk+-2.0` corewatcher-applet.c -o corewatcher-applet -lnotify + clean: rm -f *.o extract_core DEADJOE corewatcher *~ diff --git a/configfile.c b/configfile.c index 93f8ad1..4eb7b93 100644 --- a/configfile.c +++ b/configfile.c @@ -5,7 +5,7 @@ * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License. + * Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/core.c b/core.c index e27d1e3..4656962 100644 --- a/core.c +++ b/core.c @@ -5,7 +5,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the license. + * the Free Software Foundation; version 3 of the license. */ #include diff --git a/coredumper.h b/coredumper.h index bb98774..55641ba 100644 --- a/coredumper.h +++ b/coredumper.h @@ -5,7 +5,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; version 3 of the License. */ #ifndef __INCLUDE_GUARD_COREDUMPER_H__ diff --git a/corewatcher-applet.c b/corewatcher-applet.c new file mode 100644 index 0000000..7bf8edc --- /dev/null +++ b/corewatcher-applet.c @@ -0,0 +1,496 @@ +/* + * + * Kerneloops UI applet. + * + * Copyright (C) 2007 Intel Corporation + * + * Authors: + * Arjan van de Ven + * + * + * Based on the very useful example from bluez-gnome; many thanks: + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2005-2007 Marcel Holtmann + * Copyright (C) 2006-2007 Bastien Nocera + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +static DBusConnection *bus; + +static GtkStatusIcon *statusicon; + + +static NotifyNotification *notify; + +#define __unused __attribute__ ((__unused__)) + + +/* 0 = ask + positive = always + negative = never + */ + + +int user_preference; +static char *detail_file_name; + +static void write_config(char *permission) +{ + FILE *file; + char filename[2*PATH_MAX]; + + sprintf(filename, "%s/.corewatches", getenv("HOME")); + file = fopen(filename, "w"); + if (!file) { + printf("error is %s \n", strerror(errno)); + return; + } + fprintf(file, "allow-submit = %s\n", permission); + fclose(file); +} + +/* + * send a dbus message to signal the users answer to the permission + * question. + */ +static void send_permission(char *answer) +{ + DBusMessage *message; + message = dbus_message_new_signal("/org/moblin/coredump/permission", + "org.moblin.coredump.permission", answer); + dbus_connection_send(bus, message, NULL); + dbus_message_unref(message); + detail_file_name = NULL; +} + +/* + * remove an existing notification + */ +static void close_notification(void) +{ + if (notify) { + g_signal_handlers_destroy(notify); + notify_notification_close(notify, NULL); + notify = NULL; + } +} + + +/* + * the notify_action_* functions get called when the user clicks on + * the respective buttons we put in the notification window. + * user_data contains the string we pass, so "yes" "no" "always" or "never". + */ +static void notify_action(NotifyNotification __unused *notify, + gchar __unused *action, gpointer user_data) +{ + char *answer = (char *) user_data; + + send_permission(answer); + detail_file_name = NULL; + if (strcmp(answer, "always") == 0) + write_config("always"); + if (strcmp(answer, "never") == 0) + write_config("never"); + gtk_status_icon_set_visible(statusicon, FALSE); +} + +/* Called only from the detail window */ +static void send_action(GtkWidget __unused *button, GtkWidget *dialog) +{ + send_permission("yes"); + + gtk_widget_destroy(dialog); +} + + +/* Called only to display details */ +static void detail_action(NotifyNotification __unused *notify, + gchar __unused *action, gpointer __unused user_data) +{ + GtkWidget *dialog; + GtkWidget *scrollwindow; + GtkWidget *view; + GtkTextBuffer *buffer; + GtkWidget *button_cancel; + GtkWidget *button_send; + GtkTextTag *fixed; + GtkTextIter iter; + char *detail_data; + struct stat statb; + int detail_fd; + int ret; + + /* If anything goes wrong, return as early as possible... */ + + if (!detail_file_name) + return; + + memset(&statb, 0, sizeof(statb)); + ret = stat(detail_file_name, &statb); + if (statb.st_size < 1 || ret != 0) + return; + + detail_fd = open(detail_file_name, O_RDONLY); + if (detail_fd < 0) + return; + + detail_data = malloc(statb.st_size+1); + if (!detail_data) + return; + + if (read(detail_fd, detail_data, statb.st_size) != statb.st_size) { + free(detail_data); + return; + } + close(detail_fd); + detail_data[statb.st_size] = '\0'; + + dialog = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(dialog), _("Kernel failure details")); + gtk_widget_set_size_request(dialog, 600, 400); + scrollwindow = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrollwindow), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwindow, + TRUE, TRUE, 0); + view = gtk_text_view_new(); + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW (view)); + fixed = gtk_text_buffer_create_tag (buffer, "font", "font", "monospace", NULL); + gtk_text_buffer_get_iter_at_line_offset(buffer, &iter, 0, 0); + gtk_text_buffer_insert_with_tags(buffer, &iter, detail_data, -1, + fixed, NULL); + free(detail_data); + gtk_container_add (GTK_CONTAINER (scrollwindow), view); + + gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE); + button_send = gtk_button_new_with_label (_("Send")); + GTK_WIDGET_SET_FLAGS(button_send, GTK_CAN_DEFAULT); + button_cancel = gtk_button_new_with_label (_("Cancel")); + + g_signal_connect(G_OBJECT(dialog), "delete_event", + G_CALLBACK(gtk_widget_destroy), dialog); + g_signal_connect_swapped(G_OBJECT(button_cancel), "clicked", + G_CALLBACK(gtk_widget_destroy), + G_OBJECT(dialog)); + g_signal_connect(G_OBJECT(button_send), "clicked", + G_CALLBACK(send_action), dialog); + + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button_send, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), + button_cancel, TRUE, TRUE, 0); + gtk_widget_grab_default(button_send); + + gtk_widget_show(view); + gtk_widget_show(button_send); + gtk_widget_show(button_cancel); + gtk_widget_show(scrollwindow); + gtk_widget_show(dialog); +} + +static void got_a_message(void) +{ + char *summary = _("Your system had an application failure"); + char *message = + _("There is diagnostic information available for this failure." + " Do you want to submit this information to the www.moblin.org" + " website for use by the Moblin developers?\n"); + + NotifyActionCallback callback = notify_action; + + /* if there's a notification active already, close it first */ + close_notification(); + + notify = notify_notification_new(summary, message, + "/usr/share/corewatcher/icon.png", NULL); + + notify_notification_set_timeout(notify, 0); + notify_notification_set_urgency(notify, NOTIFY_URGENCY_CRITICAL); + + + /* + * add the buttons and default action + */ + + notify_notification_add_action(notify, "default", "action", + callback, "default", NULL); + + notify_notification_add_action(notify, "always", _("Always"), + callback, "always", NULL); + notify_notification_add_action(notify, "yes", _("Yes"), + callback, "yes", NULL); + notify_notification_add_action(notify, "no", _("No"), + callback, "no", NULL); + notify_notification_add_action(notify, "never", _("Never"), + callback, "never", NULL); + if (detail_file_name) { + notify_notification_add_action(notify, + "details", _("Show Details"), + detail_action, "details", NULL); + } + + notify_notification_show(notify, NULL); +} + +char url_to_oops[4095]; + +/* + * open a notification window (expires in 5 seconds) to say thank you + * to the user for his bug feedback. + */ +static void sent_an_oops(void) +{ + char *summary = _("Kernel bug diagnostic information sent"); + char *message = NULL; + char *message_1 = + _("Diagnostic information for your application has been " + "sent to www.moblin.org " + "for the Moblin developers to work on. \n" + "Thank you for contributing to improve the quality of the Moblin distribution.\n"); + + NotifyActionCallback callback = notify_action; + + close_notification(); + + + message = g_strdup_printf("%s", message_1); + + + url_to_oops[0] = 0; + + notify = notify_notification_new(summary, message, + "/usr/share/corewatcher/icon.png", NULL); + + notify_notification_set_timeout(notify, 5000); + notify_notification_set_urgency(notify, NOTIFY_URGENCY_LOW); + + + notify_notification_add_action(notify, "default", "action", + callback, "default", NULL); + + if (user_preference <= 0) + notify_notification_add_action(notify, "always", _("Always"), + callback, "always", NULL); + notify_notification_add_action(notify, "never", _("Never again"), + callback, "never", NULL); + + notify_notification_show(notify, NULL); + g_free(message); +} + +/* + * store the URL for the user + */ +static void got_an_url(DBusMessage *message) +{ + char *string = NULL; + dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &string, DBUS_TYPE_INVALID); + if (string) + strncpy(url_to_oops, string, 4095); + +} + + +/* + * When we start up, the daemon may already have collected some oopses + * so we send it a ping message to let it know someone is listening + * now. + */ +static void trigger_daemon(void) +{ + DBusMessage *message; + message = dbus_message_new_signal("/org/moblin/coredump/ping", + "org.moblin.coredump.ping", "ping"); + dbus_connection_send(bus, message, NULL); + dbus_message_unref(message); +} + +/* + * This function gets called if a dbus message arrives that we have + * subscribed to. + */ +static DBusHandlerResult dbus_gotmessage(DBusConnection __unused *connection, + DBusMessage *message, + void __unused *user_data) +{ + /* handle disconnect events first */ + if (dbus_message_is_signal(message, DBUS_ERROR_DISCONNECTED, + "Disconnected")) { + /* FIXME: need to exit the gtk main loop here */ + return DBUS_HANDLER_RESULT_HANDLED; + } + /* check if it's the daemon that asks for permission */ + if (dbus_message_is_signal(message, + "org.moblin.coredump.permission", "ask")) { + + if (user_preference > 0) { + /* the user / config file says "always" */ + send_permission("always"); + } else if (user_preference < 0) { + /* the user / config file says "never" */ + send_permission("never"); + } else { + /* ok time to ask the user */ + gtk_status_icon_set_visible(statusicon, TRUE); + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &detail_file_name, + DBUS_TYPE_INVALID); + got_a_message(); + gtk_status_icon_set_visible(statusicon, FALSE); + } + return DBUS_HANDLER_RESULT_HANDLED; + } + /* check if it's the daemon that asks for permission */ + if (dbus_message_is_signal(message, + "org.moblin.coredump.sent", "sent")) { + + gtk_status_icon_set_visible(statusicon, TRUE); + sent_an_oops(); + gtk_status_icon_set_visible(statusicon, FALSE); + return DBUS_HANDLER_RESULT_HANDLED; + } + /* check if it's the daemon that asks for permission */ + if (dbus_message_is_signal(message, + "org.moblin.coredump.url", "url")) { + + got_an_url(message); + return DBUS_HANDLER_RESULT_HANDLED; + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +/* + * read the ~/.corewatcher config file to see if the user pressed + * "always" or "never" before, and then honor that. + */ +static void read_config(void) +{ + char filename[2*PATH_MAX]; + size_t dummy; + FILE *file; + char *line = NULL; + sprintf(filename, "%s/.corewatcher", getenv("HOME")); + file = fopen(filename, "r"); + if (!file) + return; + if (getline(&line, &dummy, file) <= 0) { + free(line); + fclose(file); + return; + } + if (strstr(line, "always")) + user_preference = 1; + if (strstr(line, "never")) + user_preference = -1; + if (strstr(line, "ask")) + user_preference = 0; + free(line); + fclose(file); +} + + +int main(int argc, char *argv[]) +{ + DBusError error; + + /* Initialize translation stuff */ + setlocale(LC_ALL, ""); + bindtextdomain("corewatcher", "/usr/share/locale"); + textdomain("corewatcher"); + + + gtk_init(&argc, &argv); + + /* read the config file early; we may be able to bug out of stuff */ + read_config(); + + /* + * initialize the dbus connection; we want to listen to the system + * bus (which is where all daemons send their messages + */ + + dbus_error_init(&error); + bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error); + if (bus == NULL) { + g_printerr(_("Connecting to system bus failed: %s\n"), + error.message); + dbus_error_free(&error); + exit(EXIT_FAILURE); + } + + /* hook dbus into the main loop */ + dbus_connection_setup_with_g_main(bus, NULL); + + statusicon = gtk_status_icon_new_from_file("/usr/share/corewatcher/icon.png"); + + gtk_status_icon_set_tooltip(statusicon, _("corewatcher client")); + + notify_init("corewatcher-ui"); + + /* by default, don't show our icon */ + gtk_status_icon_set_visible(statusicon, FALSE); + + /* set the dbus message to listen for */ + dbus_bus_add_match(bus, "type='signal',interface='org.moblin.coredump.permission'", &error); + dbus_bus_add_match(bus, "type='signal',interface='org.moblin.coredump.sent'", &error); + dbus_bus_add_match(bus, "type='signal',interface='org.moblin.coredump.url'", &error); + dbus_connection_add_filter(bus, dbus_gotmessage, NULL, NULL); + + /* + * if the user said always/never in the config file, let the daemon + * know right away + */ + if (user_preference < 0) + send_permission("never"); + if (user_preference > 0) + send_permission("always"); + + /* send a ping to the userspace daemon to see if it has pending oopses */ + trigger_daemon(); + + + gtk_main(); + + close_notification(); + + return 0; +} diff --git a/corewatcher.c b/corewatcher.c index c361d2f..591ff68 100644 --- a/corewatcher.c +++ b/corewatcher.c @@ -8,7 +8,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; version 3 of the License. */ diff --git a/dbus.c b/dbus.c index 41ffc74..337a6e2 100644 --- a/dbus.c +++ b/dbus.c @@ -8,7 +8,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; version 3 of the License. */ #define _BSD_SOURCE diff --git a/find_file.c b/find_file.c index 8526ecd..dfb6360 100644 --- a/find_file.c +++ b/find_file.c @@ -5,7 +5,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; version 3 of the License. */ #define _GNU_SOURCE diff --git a/webinterface.c b/webinterface.c index b569045..5ea89fb 100644 --- a/webinterface.c +++ b/webinterface.c @@ -8,7 +8,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. + * the Free Software Foundation; version 3 of the License. */ #define _BSD_SOURCE