[ABRT PATCH 1/2] remove abrt-gui
by Jiri Moskovcak
---
configure.ac | 1 -
po/POTFILES.in | 1 -
src/Makefile.am | 2 +-
src/gui-gtk/Makefile.am | 38 --
src/gui-gtk/main.c | 1422 -----------------------------------------------
5 files changed, 1 insertion(+), 1463 deletions(-)
delete mode 100644 src/gui-gtk/Makefile.am
delete mode 100644 src/gui-gtk/main.c
diff --git a/configure.ac b/configure.ac
index 07d2f02..b04a5aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -187,7 +187,6 @@ AC_CONFIG_FILES([
src/daemon/Makefile
src/hooks/Makefile
src/applet/Makefile
- src/gui-gtk/Makefile
src/cli/Makefile
src/dbus/Makefile
src/plugins/abrt-action-install-debuginfo
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 4f070a6..c54004b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,7 +8,6 @@ src/daemon/abrt-server.c
src/dbus/abrt-dbus.c
src/daemon/abrtd.c
src/daemon/abrt-handle-event.c
-src/gui-gtk/main.c
src/lib/abrt_conf.c
src/lib/hooklib.c
src/lib/problem_api.c
diff --git a/src/Makefile.am b/src/Makefile.am
index ebf2a6f..b7da68f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1 +1 @@
-SUBDIRS = include lib hooks daemon applet gui-gtk plugins cli dbus python-problem
+SUBDIRS = include lib hooks daemon applet plugins cli dbus python-problem
diff --git a/src/gui-gtk/Makefile.am b/src/gui-gtk/Makefile.am
deleted file mode 100644
index 2274a41..0000000
--- a/src/gui-gtk/Makefile.am
+++ /dev/null
@@ -1,38 +0,0 @@
-bin_PROGRAMS = abrt-gui
-
-abrt_gui_SOURCES = \
- main.c
-abrt_gui_CFLAGS = \
- -I$(srcdir)/../include \
- -I$(srcdir)/../lib \
- -I$(srcdir)/../gtk-helpers \
- -DBIN_DIR=\"$(bindir)\" \
- -DLIBEXEC_DIR=\"$(libexecdir)\" \
- -DICON_DIR=\"${datadir}/abrt/icons/hicolor/48x48/status\" \
- $(GTK_CFLAGS) \
- $(LIBREPORT_GTK_CFLAGS) \
- -D_GNU_SOURCE \
- $(GIO_CFLAGS)
-# -I/usr/include/glib-2.0
-# -I/usr/lib/glib-2.0/include
-# $(LIBNOTIFY_CFLAGS)
-# $(DBUS_GLIB_CFLAGS)
-abrt_gui_LDADD = \
- -lglib-2.0 \
- -lgthread-2.0 \
- $(GIO_LIBS) \
- $(LIBREPORT_GTK_LIBS) \
- ../lib/libabrt.la \
- $(GTK_LIBS)
-# $(LIBNOTIFY_LIBS)
-
-#test_report_SOURCES = \
-# test_report.c
-#test_report_CPPFLAGS = \
-# -I$(srcdir)/../include/report -I$(srcdir)/../include \
-# $(GLIB_CFLAGS) \
-# -D_GNU_SOURCE
-#test_report_LDADD = \
-# ../lib/libreport.la
-
-DEFS = -DLOCALEDIR=\"$(localedir)\" @DEFS@
diff --git a/src/gui-gtk/main.c b/src/gui-gtk/main.c
deleted file mode 100644
index ea0c2fa..0000000
--- a/src/gui-gtk/main.c
+++ /dev/null
@@ -1,1422 +0,0 @@
-/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
-
- 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; either version 2 of the License, or
- (at your option) any later version.
-
- 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#include <gtk/gtk.h>
-#include <gdk/gdkkeysyms.h>
-#include <sys/inotify.h>
-#if HAVE_LOCALE_H
-# include <locale.h>
-#endif
-#include <libreport/internal_libreport_gtk.h>
-#include "libabrt.h"
-#include "abrt-dbus.h"
-
-#if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 22
-# define GDK_KEY_Delete GDK_Delete
-# define GDK_KEY_KP_Delete GDK_KP_Delete
-#endif
-
-/* We used to work with problem dirs directly.
- * Access via dbus was added in order to be able to see
- * (after authorization) problem dirs which are readable
- * only by root. These "root only" problems can also be deleted,
- * or chown'ed and then events can be run on them.
- * (IMO this feature added too much PITA for a rather limited gain.
- * Oh well...)
- */
-
-static void rescan_and_refresh(void);
-
-
-static const char help_uri[] =
-// For released versions, should be similar to:
-// "http://docs.fedoraproject.org/en-US/Fedora/14/html/Deployment_Guide/ch-ab...";
-//
-// This doc (hopefully) matches the most recent code.
-// It is supposed to be kept updated (see doc/deployment/*)
-// and uploaded to fedorahosted.org:
-"https://fedorahosted.org/releases/a/b/abrt/Deployment_Guide.html";
-
-enum {
- OPT_v = 1 << 0,
- OPT_p = 1 << 1,
- OPT_D = 1 << 2,
-};
-
-static unsigned g_opts;
-
-static int inotify_fd = -1;
-static GIOChannel *channel_inotify;
-static int channel_inotify_event_id = -1;
-static char **s_dirs;
-static int s_signal_pipe[2];
-
-static GtkListStore *s_dumps_list_store;
-static GtkListStore *s_reported_dumps_list_store;
-
-static GtkWidget *s_treeview;
-static GtkWidget *s_reported_treeview;
-static GtkWidget *s_active_treeview;
-static GtkTreePath *s_path_treeview;
-static GtkTreePath *s_path_reported_treeview;
-
-static GtkWidget *g_main_window;
-
-enum
-{
- COLUMN_SOURCE,
- COLUMN_REASON,
- COLUMN_LATEST_CRASH_STR,
- COLUMN_LATEST_CRASH,
- COLUMN_DUMP_DIR,
- COLUMN_DIR_OVER_DBUS,
- COLUMN_REPORTED_TO,
- NUM_COLUMNS
-};
-/* Must match the above enum! Used in gtk_list_store_new() call */
-# define COLUMN_TYPES \
- G_TYPE_STRING, \
- G_TYPE_STRING, \
- G_TYPE_STRING, \
- G_TYPE_INT, \
- G_TYPE_STRING, \
- G_TYPE_INT, \
- G_TYPE_STRING \
-
-/* Whether to try to authorize when getting list of problems */
-static gint g_authorize;
-
-/* Returns malloced copy */
-static char *get_last_line(const char *msg)
-{
- const char *last_eol = strrchr(msg, '\n');
-
- if (!last_eol) /* entire msg is one line? */
- return xstrdup(msg);
-
- if (last_eol[1] != '\0') /* last line is not \n terminated? */
- return xstrdup(last_eol + 1);
-
- /* It's "... \n line \n" and we point to last "\n" */
- const char *end = last_eol;
- /* Walk back */
- while (last_eol > msg)
- {
- if (last_eol[-1] == '\n') /* We found prev "\n" */
- return xstrndup(last_eol, end - last_eol);
- last_eol--;
- }
- /* There is no prev "\n" */
- return xstrndup(last_eol, end - last_eol);
-}
-
-static void show_warning_dialog(const char *message)
-{
- GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(g_main_window),
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_WARNING,
- GTK_BUTTONS_OK, /* wizard uses GTK_BUTTONS_CLOSE instead */
- "%s", message
- );
- gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
-}
-
-static void watch_this_dir(const char *dir_name)
-{
-//TODO: we probably need to remove old watches too...
- if (inotify_fd >= 0 && inotify_add_watch(inotify_fd, dir_name, 0
- // | IN_ATTRIB // Metadata changed
- // | IN_CLOSE_WRITE // File opened for writing was closed
- | IN_CREATE // File/directory created in watched directory
- | IN_DELETE // File/directory deleted from watched directory
- | IN_DELETE_SELF // Watched file/directory was itself deleted
- | IN_MODIFY // File was modified
- | IN_MOVE_SELF // Watched file/directory was itself moved
- | IN_MOVED_FROM // File moved out of watched directory
- | IN_MOVED_TO // File moved into watched directory
- ) < 0)
- {
- /* Missing .abrt/spool is ok, else complain */
- if (errno != ENOENT)
- perror_msg("inotify_add_watch failed on '%s'", dir_name);
- }
-}
-
-/* Returns non 0 if str is NULL or if str consists from white spaces */
-inline static int is_null_or_empty_string(const char *str)
-{
- return !str || skip_whitespace(str)[0] == '\0';
-}
-
-static void add_directory_to_dirlist(const char *problem_dir_path, gpointer data)
-{
- bool use_dbus = (bool)data;
- problem_data_t *pd;
- if (!use_dbus)
- {
- /* Silently ignore *any* errors, not only EACCES.
- * We saw "lock file is locked by process PID" error
- * when we raced with wizard.
- */
- int sv_logmode = logmode;
- logmode = 0;
- struct dump_dir *dd = dd_opendir(problem_dir_path, DD_OPEN_READONLY | DD_FAIL_QUIETLY_EACCES);
- logmode = sv_logmode;
- if (!dd)
- return;
-//FIXME: this is inefficient. We can instead read only selected elements, not all:
- pd = create_problem_data_from_dump_dir(dd);
- dd_close(dd);
- }
- else
- {
- pd = get_problem_data_dbus(problem_dir_path);
- if (!pd)
- return;
- }
-
- char time_buf[sizeof("YYYY-MM-DD hh:mm:ss")];
- time_buf[0] = '\0';
- const char *time_str = problem_data_get_content_or_NULL(pd, FILENAME_TIME);
- time_t t = 0;
- if (time_str && time_str[0])
- {
- t = strtol(time_str, NULL, 10); /* atoi won't work past 2038! */
- struct tm *ptm = localtime(&t);
- size_t time_len = strftime(time_buf, sizeof(time_buf)-1, "%Y-%m-%d %H:%M", ptm);
- time_buf[time_len] = '\0';
- }
-
- const char *reason = problem_data_get_content_or_NULL(pd, FILENAME_NOT_REPORTABLE);
- if (is_null_or_empty_string(reason)) /* if problem is NOT not reportable we use reason */
- {
- reason = problem_data_get_content_or_NULL(pd, FILENAME_REASON);
- if (is_null_or_empty_string(reason)) /* if we don't have reason we use 'N/A' */
- reason = "N/A";
- }
-
- /* the source of the problem:
- * - first we try to load component, as we use it on Fedora
- */
- const char *source = problem_data_get_content_or_NULL(pd, FILENAME_COMPONENT);
- if (is_null_or_empty_string(source)) /* if we don't have component, we fallback to executable */
- {
- source = problem_data_get_content_or_NULL(pd, FILENAME_EXECUTABLE);
- if (is_null_or_empty_string(source)) /* even if we don't have executable, we use 'N/A' */
- source = "N/A";
- }
-
- const char *msg = problem_data_get_content_or_NULL(pd, FILENAME_REPORTED_TO);
-
- GtkListStore *list_store = s_dumps_list_store;
- char *subm_status = NULL;
- if (msg)
- {
- list_store = s_reported_dumps_list_store;
- subm_status = get_last_line(msg);
- if (is_null_or_empty_string(subm_status))
- { /* the problem is reported but the submission status is not available */
- /* we have to use 'N/A' string instead of empty string */
- free(subm_status);
- subm_status = xstrdup("N/A");
- }
- }
-
- GtkTreeIter iter;
- gtk_list_store_append(list_store, &iter);
- gtk_list_store_set(list_store, &iter,
- COLUMN_SOURCE, source,
- COLUMN_REASON, reason,
- //OPTION: time format
- COLUMN_LATEST_CRASH_STR, time_buf,
- COLUMN_LATEST_CRASH, t,
- COLUMN_DUMP_DIR, problem_dir_path,
- COLUMN_DIR_OVER_DBUS, (int)use_dbus,
- COLUMN_REPORTED_TO, subm_status,
- -1);
-
- free(subm_status);
- problem_data_free(pd);
-
- VERB1 log("added: %s", problem_dir_path);
-}
-
-static void scan_directory_and_add_to_dirlist(const char *path)
-{
- DIR *dp = opendir(path);
- if (!dp)
- {
- /* We don't want to yell if, say, $HOME/.abrt/spool doesn't exist */
- //perror_msg("Can't open directory '%s'", path);
- return;
- }
-
- struct dirent *dent;
- while ((dent = readdir(dp)) != NULL)
- {
- if (dot_or_dotdot(dent->d_name))
- continue; /* skip "." and ".." */
-
- char *full_name = concat_path_file(path, dent->d_name);
- struct stat statbuf;
- if (stat(full_name, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
- add_directory_to_dirlist(full_name, /*use_dbus:*/ (void*)false);
- free(full_name);
- }
- closedir(dp);
-
- watch_this_dir(path);
-}
-
-static void query_dbus_and_add_to_dirlist(void)
-{
- GList *problem_dirs = get_problems_over_dbus(g_authorize);
-
- if (problem_dirs == ERR_PTR)
- {
- /* One way to trigger this is to temporarily rename
- * dbus socket (/var/run/dbus/system_bus_socket)
- */
- error_msg("Error in DBus communication, falling back to direct access to '%s'", g_settings_dump_location);
- scan_directory_and_add_to_dirlist(g_settings_dump_location);
- return;
- }
-
- if (problem_dirs)
- {
- g_list_foreach(problem_dirs, (GFunc)add_directory_to_dirlist, /*use_dbus:*/ (void*)true);
- list_free_with_free(problem_dirs);
- }
-
- /* HACK ALERT! We "magically know" that dbus-reported problem dirs
- * live in g_settings_dump_location.
- * Notifications on changes should be implemented to go over dbus too.
- */
- watch_this_dir(g_settings_dump_location);
-}
-
-static void scan_dirs_and_add_to_dirlist(void)
-{
- if (!(g_opts & OPT_D))
- query_dbus_and_add_to_dirlist();
-
- char **argv = s_dirs;
- while (*argv)
- scan_directory_and_add_to_dirlist(*argv++);
-}
-
-static void rescan_dirs_and_add_to_dirlist(void)
-{
- gtk_list_store_clear(s_dumps_list_store);
- gtk_list_store_clear(s_reported_dumps_list_store);
- scan_dirs_and_add_to_dirlist();
-}
-
-
-static GtkTreePath *get_cursor(void)
-{
- GtkTreeView *treeview = GTK_TREE_VIEW(s_treeview);
- GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
- if (selection)
- {
- GtkTreeIter iter;
- GtkTreeModel *store = gtk_tree_view_get_model(treeview);
- if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE)
- {
- return gtk_tree_model_get_path(store, &iter);
- }
- }
- return NULL;
-}
-
-static void sanitize_cursor(GtkTreePath *preferred_path)
-{
- GtkTreePath *path;
-
- gtk_tree_view_get_cursor(GTK_TREE_VIEW(s_treeview), &path, /* GtkTreeViewColumn** */ NULL);
- if (path)
- {
- /* Cursor exists already */
- goto ret;
- }
-
- if (preferred_path)
- {
- /* Try to position cursor on preferred_path */
- gtk_tree_view_set_cursor(GTK_TREE_VIEW(s_treeview), preferred_path,
- /* GtkTreeViewColumn *focus_column */ NULL, /* start_editing */ false);
-
- /* Did it work? */
- gtk_tree_view_get_cursor(GTK_TREE_VIEW(s_treeview), &path, /* GtkTreeViewColumn** */ NULL);
- if (path) /* yes */
- goto ret;
- }
-
- /* Try to position cursor on 1st element */
- GtkTreeIter iter;
- if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(s_dumps_list_store), &iter))
- {
- /* We have at least one element, put cursor on it */
-
- /* Get path from iter pointing to 1st element */
- path = gtk_tree_model_get_path(GTK_TREE_MODEL(s_dumps_list_store), &iter);
-
- /* Use it to set cursor */
- gtk_tree_view_set_cursor(GTK_TREE_VIEW(s_treeview), path,
- /* GtkTreeViewColumn *focus_column */ NULL, /* start_editing */ false);
- }
- /* else we have no elements */
-
- ret:
- gtk_tree_path_free(path);
-
- /* Without this, the *header* of the list gets the focus. Ugly. */
- gtk_widget_grab_focus(s_treeview);
-}
-
-
-/* create_main_window and helpers */
-
-static void deactivate_selection(GtkTreeView *tv)
-{
- if (!GTK_IS_TREE_VIEW(tv))
- return;
-
- GtkTreeSelection *selection = gtk_tree_view_get_selection(tv);
- if (selection)
- {
- /* Remember the selection */
- GList *list = gtk_tree_selection_get_selected_rows(selection, /*GtkTreeModel **model:*/ NULL);
- /* Note: returned list is a copy! We take ownership (IOW: must free it) */
- GtkTreePath **pp_path = NULL;
- if ((void*)tv == (void*)s_treeview)
- pp_path = &s_path_treeview;
- if ((void*)tv == (void*)s_reported_treeview)
- pp_path = &s_path_reported_treeview;
- if (pp_path && list)
- {
- if (*pp_path)
- gtk_tree_path_free(*pp_path);
- *pp_path = list->data;
- list = g_list_delete_link(list, list);
- }
- g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
- g_list_free(list);
- /* Deactivate */
- gtk_tree_selection_unselect_all(selection);
- }
-}
-
-/* Contrary to what I expected, this callback is NOT called
- * when I select a row with a mouse.
- * Maybe this callback can be removed.
- */
-static gboolean on_select_cursor_row_cb(
- GtkTreeView *treeview,
- gboolean arg1,
- gpointer user_data)
-{
- //log("SELECT_ROW:%p/%p", treeview, user_data);
- if (GTK_IS_TREE_VIEW(user_data))
- deactivate_selection(GTK_TREE_VIEW(user_data));
-
- return false; /* propagate the event further */
-}
-
-/* Called when I select a row with a mouse (among other cases).
- * Make sure other tv loses its selection.
- */
-static gboolean on_cursor_changed_cb(
- GtkTreeView *treeview,
- gpointer user_data)
-{
- //log("cursor-changed:%p/%p", treeview, user_data);
- if (GTK_IS_TREE_VIEW(user_data))
- deactivate_selection(GTK_TREE_VIEW(user_data));
-
- /* Without this, only <tab>ing to treeview sets s_active_treeview.
- * Thus, selecting a row with mouse and clicking [Open] with mouse
- * wouldn't work!
- */
- s_active_treeview = GTK_WIDGET(treeview);
-
- return false; /* propagate the event further */
-}
-
-/* Called when I <tab> to the treeview
- * Make sure other tv loses its selection.
- * Also, restore selection in current tv if it was desecleted
- * (for example, if we <tab>ed to the other seletion a few sec ago...).
- */
-static gboolean on_focus_cb(
- GtkWidget *widget,
- GtkDirectionType direction,
- gpointer user_data)
-{
- //log("FOCUS:%p/%p", widget, user_data);
- s_active_treeview = widget;
-
- /* Deactivate the other one */
- deactivate_selection(GTK_TREE_VIEW(user_data));
-
- /* Re-activate row in this one if it was deactivated */
- GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
- if (selection && gtk_tree_selection_count_selected_rows(selection) < 1)
- {
- GtkTreePath **pp_path = NULL;
- if (widget == s_treeview)
- pp_path = &s_path_treeview;
- if (widget == s_reported_treeview)
- pp_path = &s_path_reported_treeview;
- if (pp_path && *pp_path)
- {
- gtk_tree_selection_select_path(selection, *pp_path);
- gtk_tree_path_free(*pp_path);
- *pp_path = NULL;
- }
- }
-
- return false; /* propagate the event further */
-}
-
-static const char *current_dirname(int *is_dbus, GtkTreePath **path_p, GtkTreeView *treeview)
-{
- GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
- if (selection)
- {
- GtkTreeIter iter;
- GtkTreeModel *store = gtk_tree_view_get_model(treeview);
- if (gtk_tree_selection_get_selected(selection, &store, &iter) == TRUE)
- {
- if (path_p)
- *path_p = gtk_tree_model_get_path(store, &iter);
-
- GValue d_dir = { 0 };
- gtk_tree_model_get_value(store, &iter, COLUMN_DUMP_DIR, &d_dir);
- const char *dirname = g_value_get_string(&d_dir);
- if (is_dbus)
- {
- GValue d_int = { 0 };
- gtk_tree_model_get_value(store, &iter, COLUMN_DIR_OVER_DBUS, &d_int);
- *is_dbus = g_value_get_int(&d_int);
- }
- return dirname;
- }
- }
- return NULL;
-}
-
-static void on_row_activated_cb(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
-{
- int is_dbus;
- const char *dirname = current_dirname(&is_dbus, NULL, treeview);
- if (dirname)
- {
- if (!is_dbus || chown_dir_over_dbus(dirname) == 0)
- {
- fflush(NULL); /* paranoia */
- pid_t pid = fork();
- if (pid < 0) /* error */
- perror_msg_and_die("fork");
- if (pid == 0) /* child */
- {
- execl(LIBEXEC_DIR"/abrt-handle-event", "abrt-handle-event", "-e", "report-gui", "--", (char *)dirname, NULL);
- /* Child can't use GUI error reporting, we need to clear g_custom_logger */
- g_custom_logger = NULL;
- perror_msg_and_die("Can't execute '%s'", LIBEXEC_DIR"/abrt-handle-event");
- }
- }
- /* else: chown_dir_over_dbus already complained */
- }
-}
-
-static void open_problem_data_cb(GtkMenuItem *menuitem, gpointer user_data)
-{
- int is_dbus;
- const char *dirname = current_dirname(&is_dbus, NULL, GTK_TREE_VIEW(s_active_treeview));
- if (dirname)
- {
- if (is_dbus && chown_dir_over_dbus(dirname) != 0)
- {
- error_msg("Can't chown '%s'", dirname);
- return;
- }
-
- fflush(NULL); /* paranoia */
- pid_t pid = fork();
- if (pid < 0) /* error */
- perror_msg_and_die("fork");
- if (pid == 0) /* child */
- {
- execl(LIBEXEC_DIR"/abrt-handle-event", "abrt-handle-event", "-e", "open-gui", "--", (char *)dirname, NULL);
- /* Child can't use GUI error reporting, we need to clear g_custom_logger */
- g_custom_logger = NULL;
- perror_msg_and_die("Can't execute '%s'", LIBEXEC_DIR"/abrt-handle-event");
- }
- }
-}
-
-static void on_btn_report_cb(GtkButton *button, gpointer user_data)
-{
- if (s_active_treeview)
- on_row_activated_cb(GTK_TREE_VIEW(s_active_treeview), NULL, NULL, NULL);
-}
-
-static void on_column_change_cb(GtkTreeSortable *sortable, gpointer user_data)
-{
- const char *name;
- char *value;
- GtkSortType sort_type;
- int col_id;
-
- if (sortable == GTK_TREE_SORTABLE(s_dumps_list_store))
- name = "sort_column";
- else if (sortable == GTK_TREE_SORTABLE(s_reported_dumps_list_store))
- name = "sort_reported_column";
- else
- assert(0);
-
- gtk_tree_sortable_get_sort_column_id(sortable, &col_id, &sort_type);
- if (sort_type == GTK_SORT_ASCENDING)
- col_id = -col_id - 1; /* store ascending sort as negative id */
- value = xasprintf("%d", col_id);
- set_user_setting(name, value);
- free(value);
-}
-
-static void on_show_all_cb(GtkToggleButton *togglebutton, gpointer data)
-{
- g_authorize = gtk_toggle_button_get_active(togglebutton);
- rescan_and_refresh();
-}
-
-static void load_sort_setting(GtkTreeSortable *sortable)
-{
- const char *name, *value;
- GtkSortType sort_type;
- int col_id;
-
- if (sortable == GTK_TREE_SORTABLE(s_dumps_list_store))
- name = "sort_column";
- else if (sortable == GTK_TREE_SORTABLE(s_reported_dumps_list_store))
- name = "sort_reported_column";
- else
- return;
-
- /* defaults */
- col_id = COLUMN_LATEST_CRASH;
- sort_type = GTK_SORT_DESCENDING;
-
- value = get_user_setting(name);
- if (value)
- {
- col_id = xatoi(value);
- if (col_id < 0)
- {
- /* negative id means ascending order */
- col_id = -col_id - 1;
- sort_type = GTK_SORT_ASCENDING;
- }
- }
-
- if (col_id >= NUM_COLUMNS)
- col_id = COLUMN_LATEST_CRASH;
-
- gtk_tree_sortable_set_sort_column_id(sortable, col_id, sort_type);
-}
-
-static void delete_problem(GtkTreeView *treeview)
-{
- GtkTreePath *old_path = NULL;
- int is_dbus;
- const char *dirname = current_dirname(&is_dbus, &old_path, GTK_TREE_VIEW(s_active_treeview));
- if (dirname)
- {
- VERB1 log("Deleting '%s'", dirname);
-
- //TODO: I plan to implement deleting multiple items at once rhbz#541928
- GList *problem_dir_paths = NULL;
- problem_dir_paths = g_list_append(problem_dir_paths, xstrdup(dirname));
-
- int result;
- if (is_dbus)
- {
- result = delete_problem_dirs_over_dbus(problem_dir_paths);
- }
- else
- {
- result = delete_dump_dir_possibly_using_abrtd(dirname);
- }
- list_free_with_free(problem_dir_paths);
-
- if (result != 0)
- {
- /* Strange. Deletion did not succeed. Someone else deleted it?
- * Rescan the whole list */
- rescan_dirs_and_add_to_dirlist();
- }
-
- /* Try to retain the same cursor position */
- if (old_path)
- {
- sanitize_cursor(old_path);
- gtk_tree_path_free(old_path);
- }
- }
-}
-
-static gint on_key_press_event_cb(GtkTreeView *treeview, GdkEventKey *key, gpointer unused)
-{
- int k = key->keyval;
-
- if (k == GDK_KEY_Delete || k == GDK_KEY_KP_Delete)
- {
- delete_problem(treeview);
- return TRUE;
- }
- return FALSE;
-}
-
-static void on_btn_delete_cb(GtkButton *button, gpointer unused)
-{
- if (s_active_treeview)
- delete_problem(GTK_TREE_VIEW(s_active_treeview));
-}
-
-static void on_menu_help_cb(GtkMenuItem *menuitem, gpointer unused)
-{
- gtk_show_uri(NULL, help_uri, GDK_CURRENT_TIME, NULL);
-}
-
-static void show_error_dialog(GtkWindow *wnd, const char *summary, const char *description)
-{
- GtkWidget *dialog = gtk_message_dialog_new(wnd,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- summary);
-
- gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), description);
-
- gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy (dialog);
-}
-
-static void on_button_send_cb(GtkWidget *button, gpointer data)
-{
- GtkWidget *wnd_report = GTK_WIDGET(data);
-
- /* Excpecting that the first child is Vertical Box with all the widgets */
- GList *children = gtk_container_get_children(GTK_CONTAINER(wnd_report));
- GtkContainer *vbox = GTK_CONTAINER(children->data);
- g_list_free(children);
-
- /* Expected content of the children list:
- * Lable Summary
- * Entry Summary
- * TextView Description
- * Button Send
- */
- children = gtk_container_get_children(vbox);
-
- children = g_list_delete_link(children, children);
- GtkEntry *txe_summary = GTK_ENTRY(children->data);
-
- children = g_list_delete_link(children, children);
- GtkTextView *tev = GTK_TEXT_VIEW(children->data);
-
- g_list_free(children);
-
- GtkTextBuffer *buf = gtk_text_view_get_buffer(tev);
- GtkTextIter it_start;
- GtkTextIter it_end;
- gtk_text_buffer_get_start_iter(buf, &it_start);
- gtk_text_buffer_get_end_iter(buf, &it_end);
- gchar *description = gtk_text_buffer_get_text(buf,
- &it_start,
- &it_end,
- false);
-
- if (strlen(description) < 10)
- {
- show_error_dialog(GTK_WINDOW(wnd_report),
- _("The description of problem is too short"),
- _("In order to get more useful reports we "
- "do not accept reports with the description "
- "shorter than 10 letters."));
-
- gtk_widget_grab_focus(GTK_WIDGET(tev));
-
- free(description);
- return;
- }
-
- char *summary = xstrdup(gtk_entry_get_text(txe_summary));
- if (strlen(summary) < 10)
- {
- show_error_dialog(GTK_WINDOW(wnd_report),
- _("The summary of problem is too short"),
- _("In order to get more useful reports we "
- "do not accept reports with the summary "
- "shorter than 10 letters."));
-
- gtk_widget_grab_focus(GTK_WIDGET(txe_summary));
- gtk_editable_set_position(GTK_EDITABLE(txe_summary), strlen(summary));
-
- free(description);
- free(summary);
- return;
- }
-
-
- problem_data_t *pd = problem_data_new();
- problem_data_add_text_noteditable(pd, FILENAME_COMMENT, description);
- problem_data_add_text_noteditable(pd, FILENAME_REASON, summary);
- problem_data_add_text_noteditable(pd, FILENAME_COMPONENT, "abrt");
- char *version = xasprintf("abrt-%s", VERSION);
- problem_data_add_text_noteditable(pd, FILENAME_PACKAGE, version);
-
- /* Must be here because it computes FILENAME_DUPHASH from the content. */
- problem_data_add_basics(pd);
-
- /* why it doesn't want to hide before report ends? */
- gtk_widget_destroy(wnd_report);
-
- report_problem_in_memory(pd, LIBREPORT_NOWAIT | LIBREPORT_GETPID);
-
- free(version);
- free(summary);
- free(description);
- problem_data_free(pd);
-}
-
-static void on_menu_report_cb(GtkMenuItem *menuitem, gpointer unused)
-{
- GtkWidget *wnd_report = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_title(GTK_WINDOW(wnd_report), _("Problem description"));
- gtk_window_set_default_size(GTK_WINDOW(wnd_report), 400, 400);
-
- GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- gtk_widget_set_margin_top(vbox, 5);
- gtk_widget_set_margin_left(vbox, 5);
- gtk_widget_set_margin_right(vbox, 5);
-
- GtkWidget *lbl_summary = GTK_WIDGET(gtk_label_new(_("Summary:")));
- gtk_widget_set_halign(lbl_summary, GTK_ALIGN_START);
- gtk_widget_set_margin_left(lbl_summary, 3);
- gtk_widget_set_margin_right(lbl_summary, 3);
-
- GtkWidget *txe_reason = GTK_WIDGET(gtk_entry_new());
-
- GtkWidget *tev = gtk_text_view_new();
- gtk_widget_set_margin_left(tev, 3);
- gtk_widget_set_margin_right(tev, 3);
- gtk_widget_set_can_focus(tev, TRUE);
-
- GtkWidget *btn_send = gtk_button_new_with_label(_("_Send"));
- gtk_button_set_use_underline(GTK_BUTTON(btn_send), TRUE);
- g_signal_connect(btn_send, "clicked", G_CALLBACK(on_button_send_cb), wnd_report);
-
- /* gtk_box_pack_start(box, widget, expand, fill, padding) */
- gtk_box_pack_start(GTK_BOX(vbox), lbl_summary, FALSE, TRUE, 3);
- gtk_box_pack_start(GTK_BOX(vbox), txe_reason, FALSE, TRUE, 3);
- gtk_box_pack_start(GTK_BOX(vbox), tev, TRUE, TRUE, 5);
- gtk_box_pack_start(GTK_BOX(vbox), btn_send, FALSE, TRUE, 3);
-
- gtk_container_add(GTK_CONTAINER(wnd_report), vbox);
-
- gtk_widget_show_all(wnd_report);
-
- /* Sets text but text is selected :) */
- gtk_entry_set_text(GTK_ENTRY(txe_reason), _("A problem with ABRT"));
- /* Unselect text in txe_entry */
- gtk_editable_set_position(GTK_EDITABLE(txe_reason), 0);
-
- /* Move focus to text view with description of problem */
- gtk_widget_grab_focus(tev);
-}
-
-static void on_menu_about_cb(GtkMenuItem *menuitem, gpointer unused)
-{
- static const char copyright_str[] = "Copyright © 2009, 2010, 2011 Red Hat, Inc";
-
- static const char license_str[] = "This program is free software; you can redistribut"
- "e it and/or modify it under the terms of the GNU General Public License "
- "as published by the Free Software Foundation; either version 2 of the Li"
- "cense, or (at your option) any later version.\n\nThis program is distrib"
- "uted in the hope that it will be useful, but WITHOUT ANY WARRANTY; witho"
- "ut even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICU"
- "LAR PURPOSE. See the GNU General Public License for more details.\n\nYo"
- "u should have received a copy of the GNU General Public License along wi"
- "th this program. If not, see <http://www.gnu.org/licenses/>.";
-
- static const char website_url[] = "https://fedorahosted.org/abrt/";
-
- static const char *authors[] = {
- "Anton Arapov <aarapov(a)redhat.com>",
- "Karel Klic <kklic(a)redhat.com>",
- "Jiri Moskovcak <jmoskovc(a)redhat.com>",
- "Nikola Pajkovsky <npajkovs(a)redhat.com>",
- "Denys Vlasenko <dvlasenk(a)redhat.com>",
- "Michal Toman <mtoman(a)redhat.com>",
- "Zdenek Prikryl",
- NULL
- };
-
- static const char *artists[] = {
- "Patrick Connelly <pcon(a)fedoraproject.org>",
- "Máirín Duffy <duffy(a)fedoraproject.org>",
- "Lapo Calamandrei",
- "Jakub Steinar <jsteiner(a)redhat.com>",
- NULL
- };
-
- GtkWidget *about_d = gtk_about_dialog_new();
-
- gtk_window_set_icon_name(GTK_WINDOW(about_d), "abrt");
- gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_d), VERSION);
- gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(about_d), "abrt");
- gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about_d), "ABRT");
- gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_d), copyright_str);
- gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about_d), license_str);
- gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(about_d),true);
- gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about_d), website_url);
- gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about_d), authors);
- gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about_d), artists);
- gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about_d), _("translator-credits"));
-
- gtk_window_set_transient_for(GTK_WINDOW(about_d), GTK_WINDOW(g_main_window));
-
- gtk_dialog_run(GTK_DIALOG(about_d));
- gtk_widget_hide(GTK_WIDGET(about_d));
-}
-
-static void show_events_list_dialog_cb(GtkMenuItem *menuitem, gpointer user_data)
-{
- show_config_list_dialog(GTK_WINDOW(g_main_window));
-}
-
-static void add_columns(GtkTreeView *treeview)
-{
- GtkCellRenderer *renderer;
- GtkTreeViewColumn *column;
-
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Source"),
- renderer,
- "text",
- COLUMN_SOURCE,
- NULL);
- gtk_tree_view_column_set_resizable(column, TRUE);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_SOURCE);
- gtk_tree_view_append_column(treeview, column);
-
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Problem"),
- renderer,
- "text",
- COLUMN_REASON,
- NULL);
- gtk_tree_view_column_set_resizable(column, TRUE);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_REASON);
- gtk_tree_view_append_column(treeview, column);
-
- /*
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Stored in"),
- renderer,
- "text",
- COLUMN_DIRNAME,
- NULL);
- gtk_tree_view_column_set_resizable(column, TRUE);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_DIRNAME);
- gtk_tree_view_append_column(treeview, column);
- */
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Last Occurrence"),
- renderer,
- "text",
- COLUMN_LATEST_CRASH_STR,
- NULL);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_LATEST_CRASH);
- gtk_tree_view_append_column(treeview, column);
-}
-
-static void add_columns_reported(GtkTreeView *treeview)
-{
- GtkCellRenderer *renderer;
- GtkTreeViewColumn *column;
-
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Source"),
- renderer,
- "text",
- COLUMN_SOURCE,
- NULL);
- gtk_tree_view_column_set_resizable(column, TRUE);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_SOURCE);
- gtk_tree_view_append_column(treeview, column);
-
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Problem"),
- renderer,
- "text",
- COLUMN_REASON,
- NULL);
- gtk_tree_view_column_set_resizable(column, TRUE);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_REASON);
- gtk_tree_view_append_column(treeview, column);
-
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Date Submitted"),
- renderer,
- "text",
- COLUMN_LATEST_CRASH_STR,
- NULL);
- gtk_tree_view_column_set_sort_column_id(column, COLUMN_LATEST_CRASH);
- gtk_tree_view_append_column(treeview, column);
-
- renderer = gtk_cell_renderer_text_new();
- column = gtk_tree_view_column_new_with_attributes(_("Submission Result"),
- renderer,
- "text",
- COLUMN_REPORTED_TO,
- NULL);
- //gtk_tree_view_column_set_sort_column_id(column, COLUMN_LATEST_CRASH);
- gtk_tree_view_append_column(treeview, column);
-}
-
-void on_quit_cb(GtkWidget *widget, gpointer user_data)
-{
- GApplication *app = user_data;
-
- g_application_quit(app);
-}
-
-static GtkWidget *create_menu(GtkApplication *app)
-{
- /* main bar */
- GtkWidget *menu = gtk_menu_bar_new();
- GtkWidget *file_item = gtk_menu_item_new_with_mnemonic(_("_Problem"));
- GtkWidget *edit_item = gtk_menu_item_new_with_mnemonic(_("_Edit"));
- GtkWidget *help_item = gtk_menu_item_new_with_mnemonic(_("_Help"));
-
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), file_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), edit_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(menu), help_item);
-
- /* file submenu */
- GtkWidget *file_submenu = gtk_menu_new();
- GtkWidget *quit_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
- GtkWidget *report_item = gtk_image_menu_item_new_with_label(_("Report"));
- g_signal_connect(report_item, "activate", G_CALLBACK(on_btn_report_cb), NULL);
- GtkWidget *open_problem_item = gtk_menu_item_new_with_label(_("Open problem data"));
- g_signal_connect(open_problem_item, "activate", G_CALLBACK(open_problem_data_cb), NULL);
-
- gtk_menu_shell_append(GTK_MENU_SHELL(file_submenu), report_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(file_submenu), open_problem_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(file_submenu), quit_item);
-
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_submenu);
-
- g_signal_connect(quit_item, "activate", (GCallback)on_quit_cb, app);
-
- /* edit submenu */
- GtkWidget *edit_submenu = gtk_menu_new();
-
- GtkWidget *preferences_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_PREFERENCES, NULL);
- gtk_menu_shell_append(GTK_MENU_SHELL(edit_submenu), preferences_item);
- //gtk_menu_shell_append(GTK_MENU_SHELL(edit_submenu), preferences_item);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_item), edit_submenu);
-
- g_signal_connect(preferences_item, "activate", G_CALLBACK(show_events_list_dialog_cb), NULL);
-
- /* help submenu */
- GtkWidget *help_submenu = gtk_menu_new();
- GtkWidget *online_help_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_HELP, NULL);
- GtkWidget *report_problem_item = gtk_menu_item_new_with_label(_("Report problem with ABRT"));
- GtkWidget *about_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ABOUT, NULL);
- gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), online_help_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), report_problem_item);
- gtk_menu_shell_append(GTK_MENU_SHELL(help_submenu), about_item);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(help_item), help_submenu);
-
- g_signal_connect(online_help_item, "activate", G_CALLBACK(on_menu_help_cb), NULL);
- g_signal_connect(report_problem_item, "activate", G_CALLBACK(on_menu_report_cb), NULL);
- g_signal_connect(about_item, "activate", G_CALLBACK(on_menu_about_cb), NULL);
-
- return menu;
-}
-
-static GtkWidget *create_main_window(GtkApplication *app)
-{
- /* Main window */
- g_main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_default_size(GTK_WINDOW(g_main_window), 700, 700);
- gtk_window_set_title(GTK_WINDOW(g_main_window), _("Automatic Bug Reporting Tool"));
- gtk_window_set_default_icon_name("abrt");
-
- GtkWidget *main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- /* add menu */
- gtk_box_pack_start(GTK_BOX(main_vbox), create_menu(app), false, false, 0);
-
- GtkWidget *not_subm_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- gtk_container_set_border_width(GTK_CONTAINER(not_subm_vbox), 10);
- GtkWidget *subm_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
- gtk_container_set_border_width(GTK_CONTAINER(subm_vbox), 10);
-
- /* Scrolled region for not reported problems inside main window*/
- GtkWidget *new_problems_scroll_win = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(new_problems_scroll_win),
- GTK_SHADOW_ETCHED_IN);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(new_problems_scroll_win),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
-
- GtkWidget *not_subm_lbl = gtk_label_new(_("Not submitted reports"));
- gtk_misc_set_alignment(GTK_MISC(not_subm_lbl), 0, 0);
- gtk_label_set_markup(GTK_LABEL(not_subm_lbl), _("<b>Not submitted reports</b>"));
-
- GtkWidget *show_all_btn = gtk_check_button_new_with_label(_("Show all problems"));
- g_signal_connect(show_all_btn, "toggled", G_CALLBACK(on_show_all_cb), NULL);
-
- /* add label for not submitted tree view */
- gtk_box_pack_start(GTK_BOX(not_subm_vbox), not_subm_lbl, false, false, 0);
- gtk_box_pack_start(GTK_BOX(not_subm_vbox), new_problems_scroll_win, true, true, 0);
- gtk_box_pack_start(GTK_BOX(main_vbox), not_subm_vbox, true, true, 0);
- gtk_box_pack_start(GTK_BOX(main_vbox), show_all_btn, false, false, 0);
-
- /* Two tree views */
- s_treeview = gtk_tree_view_new();
- s_reported_treeview = gtk_tree_view_new();
-
- /* Tree view inside scrolled region */
- g_object_set(s_treeview, "rules-hint", 1, NULL); /* use alternating colors */
- add_columns(GTK_TREE_VIEW(s_treeview));
- gtk_container_add(GTK_CONTAINER(new_problems_scroll_win), s_treeview);
-
- /* Create data store for the list and attach it */
- s_dumps_list_store = gtk_list_store_new(NUM_COLUMNS, COLUMN_TYPES);
-
- load_sort_setting(GTK_TREE_SORTABLE(s_dumps_list_store));
-
- g_signal_connect(GTK_TREE_SORTABLE(s_dumps_list_store), "sort-column-changed", G_CALLBACK(on_column_change_cb), NULL);
-
- gtk_tree_view_set_model(GTK_TREE_VIEW(s_treeview), GTK_TREE_MODEL(s_dumps_list_store));
-
- /* Double click/Enter handler */
- g_signal_connect(s_treeview, "row-activated", G_CALLBACK(on_row_activated_cb), NULL);
- g_signal_connect(s_treeview, "focus", G_CALLBACK(on_focus_cb), s_reported_treeview);
- g_signal_connect(s_treeview, "select-cursor-row", G_CALLBACK(on_select_cursor_row_cb), s_reported_treeview);
- g_signal_connect(s_treeview, "cursor-changed", G_CALLBACK(on_cursor_changed_cb), s_reported_treeview);
- /* Delete handler */
- g_signal_connect(s_treeview, "key-press-event", G_CALLBACK(on_key_press_event_cb), NULL);
-
- /* scrolled region for reported problems */
- GtkWidget *reported_problems_scroll_win = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(reported_problems_scroll_win),
- GTK_SHADOW_ETCHED_IN);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(reported_problems_scroll_win),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
-
- GtkWidget *subm_lbl = gtk_label_new(_("Submitted reports"));
- /* align to left */
- gtk_misc_set_alignment(GTK_MISC(subm_lbl), 0, 0);
- gtk_label_set_markup(GTK_LABEL(subm_lbl), _("<b>Submitted reports</b>"));
-
- /* add label for submitted tree view */
- gtk_box_pack_start(GTK_BOX(subm_vbox), subm_lbl, false, false, 0);
- gtk_box_pack_start(GTK_BOX(subm_vbox), reported_problems_scroll_win, true, true, 0);
- gtk_box_pack_start(GTK_BOX(main_vbox), subm_vbox, true, true, 0);
-
- /* Tree view inside scrolled region */
- g_object_set(s_reported_treeview, "rules-hint", 1, NULL); /* use alternating colors */
- add_columns_reported(GTK_TREE_VIEW(s_reported_treeview));
- gtk_container_add(GTK_CONTAINER(reported_problems_scroll_win), s_reported_treeview);
-
- /* Create data store for the list and attach it */
- s_reported_dumps_list_store = gtk_list_store_new(NUM_COLUMNS, COLUMN_TYPES);
-
- load_sort_setting(GTK_TREE_SORTABLE(s_reported_dumps_list_store));
-
- g_signal_connect(GTK_TREE_SORTABLE(s_reported_dumps_list_store), "sort-column-changed", G_CALLBACK(on_column_change_cb), NULL);
-
- gtk_tree_view_set_model(GTK_TREE_VIEW(s_reported_treeview), GTK_TREE_MODEL(s_reported_dumps_list_store));
-
- /* buttons are homogenous so set size only for one button and it will
- * work for the rest buttons in same gtk_hbox_new() */
- GtkWidget *btn_report = gtk_button_new_with_label(_("Report"));
- gtk_widget_set_size_request(btn_report, 200, 30);
-
- GtkWidget *btn_delete = gtk_button_new_from_stock(GTK_STOCK_DELETE);
-
- GtkWidget *hbox_report_delete = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_set_homogeneous(GTK_BOX(hbox_report_delete), true);
- gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_delete, true, true, 0);
- gtk_box_pack_start(GTK_BOX(hbox_report_delete), btn_report, true, true, 10);
-
- GtkWidget *halign = gtk_alignment_new(1, 0, 0, 0);
- gtk_container_add(GTK_CONTAINER(halign), hbox_report_delete);
-
- gtk_box_pack_start(GTK_BOX(main_vbox), halign, false, false, 10);
-
- /* put the main_vbox to main window */
- gtk_container_add(GTK_CONTAINER(g_main_window), main_vbox);
-
- /* Double click/Enter handler */
- g_signal_connect(s_reported_treeview, "row-activated", G_CALLBACK(on_row_activated_cb), NULL);
- g_signal_connect(s_reported_treeview, "focus", G_CALLBACK(on_focus_cb), s_treeview);
- g_signal_connect(s_reported_treeview, "select-cursor-row", G_CALLBACK(on_select_cursor_row_cb), s_treeview);
- g_signal_connect(s_reported_treeview, "cursor-changed", G_CALLBACK(on_cursor_changed_cb), s_treeview);
- /* Delete handler */
- g_signal_connect(s_reported_treeview, "key-press-event", G_CALLBACK(on_key_press_event_cb), NULL);
-
- /* Open and delete button handlers */
- g_signal_connect(btn_report, "clicked", G_CALLBACK(on_btn_report_cb), NULL);
- g_signal_connect(btn_delete, "clicked", G_CALLBACK(on_btn_delete_cb), NULL);
-
- /* Quit when user closes the main window */
- g_signal_connect(g_main_window, "destroy", (GCallback)on_quit_cb, app);
-
- return g_main_window;
-}
-
-
-static void rescan_and_refresh(void)
-{
- GtkTreePath *old_path = get_cursor();
- //log("old_path1:'%s'", gtk_tree_path_to_string(old_path)); //leak
-
- rescan_dirs_and_add_to_dirlist();
-
- /* Try to restore cursor position */
- //log("old_path2:'%s'", gtk_tree_path_to_string(old_path)); //leak
- sanitize_cursor(old_path);
- if (old_path)
- gtk_tree_path_free(old_path);
-}
-
-
-static void handle_signal(int signo)
-{
- int save_errno = errno;
-
- // Enable for debugging only, malloc/printf are unsafe in signal handlers
- //VERB3 log("Got signal %d", signo);
-
- uint8_t sig_caught = signo;
- if (write(s_signal_pipe[1], &sig_caught, 1))
- /* we ignore result, if () shuts up stupid compiler */;
-
- errno = save_errno;
-}
-
-static gboolean handle_signal_pipe(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
-{
- /* It can only be SIGCHLD. Therefore we do not check the result,
- * and eat more than one byte at once: why refresh twice?
- */
- gchar buf[16];
- gsize bytes_read;
- g_io_channel_read_chars(gio, buf, sizeof(buf), &bytes_read, NULL);
-
- /* Destroy zombies */
- while (safe_waitpid(-1, NULL, WNOHANG) > 0)
- continue;
-
- rescan_and_refresh();
-
- return TRUE; /* "please don't remove this event" */
-}
-
-
-static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused);
-
-static void init_notify(void)
-{
- VERB1 log("Initializing inotify");
- errno = 0;
- inotify_fd = inotify_init();
- if (inotify_fd < 0)
- perror_msg("inotify_init failed");
- else
- {
- close_on_exec_on(inotify_fd);
- ndelay_on(inotify_fd);
- VERB1 log("Adding inotify watch to glib main loop");
- channel_inotify = g_io_channel_unix_new(inotify_fd);
- channel_inotify_event_id = g_io_add_watch(channel_inotify,
- G_IO_IN,
- handle_inotify_cb,
- NULL);
- }
-}
-
-#if 0 // UNUSED
-static void close_notify(void)
-{
- if (inotify_fd >= 0)
- {
- //VERB1 log("g_source_remove:");
- g_source_remove(channel_inotify_event_id);
- //VERB1 log("g_io_channel_unref:");
- g_io_channel_unref(channel_inotify);
- //VERB1 log("close(inotify_fd):");
- close(inotify_fd);
- inotify_fd = -1;
- //VERB1 log("Done");
- }
-}
-#endif
-
-/* Inotify handler */
-static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
-{
- /* Since dump dir creation usually involves directory rename as a last step,
- * we end up rescanning twice. A small wait after first inotify event
- * usually allows to avoid this.
- */
- usleep(10*1000);
-
- /* We read inotify events, but don't analyze them */
- gchar buf[sizeof(struct inotify_event) + PATH_MAX + 64];
- gsize bytes_read;
- while (g_io_channel_read_chars(gio, buf, sizeof(buf), &bytes_read, NULL) == G_IO_STATUS_NORMAL
- && bytes_read > 0
- ) {
- continue;
- }
-
- rescan_and_refresh();
-
- return TRUE; /* "please don't remove this event" */
-}
-
-static void activate(GtkApplication *app)
-{
-
- GList *windows = NULL;
-
- windows = gtk_application_get_windows(app);
-
- if (windows)
- {
- gtk_window_present(GTK_WINDOW(windows->data));
- return;
- }
-
- GtkWidget *main_window = create_main_window(app);
- load_abrt_conf();
- load_user_settings("abrt-gui");
-
- init_notify();
-
- scan_dirs_and_add_to_dirlist();
-
- gtk_window_set_application(GTK_WINDOW(main_window), app);
-
- gtk_widget_show_all(main_window);
-
- sanitize_cursor(NULL);
-
- /* Set up signal pipe */
- xpipe(s_signal_pipe);
- close_on_exec_on(s_signal_pipe[0]);
- close_on_exec_on(s_signal_pipe[1]);
- ndelay_on(s_signal_pipe[0]);
- ndelay_on(s_signal_pipe[1]);
- signal(SIGCHLD, handle_signal);
- g_io_add_watch(g_io_channel_unix_new(s_signal_pipe[0]),
- G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- handle_signal_pipe,
- NULL);
-
- g_custom_logger = &show_warning_dialog;
-
- return;
-}
-
-int main(int argc, char **argv)
-{
- /* I18n */
- setlocale(LC_ALL, "");
-#if ENABLE_NLS
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-#endif
-
- abrt_init(argv);
-
- /* without this the name is set to argv[0] which confuses
- * desktops which use the name to find the corresponding .desktop file
- * trac#180
- */
- g_set_prgname("abrt");
-
- gtk_init(&argc, &argv);
-
- /* Can't keep these strings/structs static: _() doesn't support that */
- const char *program_usage_string = _(
- "& [-vpD] [DIR]...\n"
- "\n"
- "Shows list of problem directories in specified DIR(s)\n"
- "and ones saved in system-wide problem directory spool."
- /* don't end last line with "\n"! */
- );
- /* Keep OPT_x enums and order of options below in sync! */
- struct options program_options[] = {
- OPT__VERBOSE(&g_verbose),
- OPT_BOOL( 'p', NULL, NULL , _("Add program names to log")),
- OPT_BOOL( 'D', NULL, NULL , _("Do not query problems over dbus (use only DIRs)")),
- OPT_END()
- };
- g_opts = parse_opts(argc, argv, program_options, program_usage_string);
-
- migrate_to_xdg_dirs();
-
- export_abrt_envvars(g_opts & OPT_p);
-
- const char *default_dirs[] = {
- NULL,
- NULL,
- };
- argv += optind;
- if (!argv[0])
- {
- default_dirs[0] = concat_path_file(g_get_user_cache_dir(), "abrt/spool");
- argv = (char**)default_dirs;
- }
- s_dirs = argv;
-
- GtkApplication *app = NULL;
-
-
- app = gtk_application_new("org.freedesktop.AbrtGui", 0);
- g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);
- gint status;
- status = g_application_run(G_APPLICATION(app), argc, argv);
-
- g_object_unref(app);
-
- save_user_settings();
- free_abrt_conf_data();
-
- return status;
-}
--
1.8.1.4
11 years, 1 month
[PATCH] improve is_text_file() to not treat valid Unicode as bad_chars
by Denys Vlasenko
In valid Unicode, first non-ASCII byte is always 11xxxxxx
and the following bytes are always 10xxxxxx.
Random binary data is likely to violate this rule *a lot*.
This patch makes bad_chars++ decision only if it sees a non-ASCII
byte which violates the rule described above.
Also, it makes immediate decision "it's binary"
not only on NULs, but on any non-whitespace control chars.
This hopefully improves handling of the problem
identified in rhbz#922433
Signed-off-by: Denys Vlasenko <dvlasenk(a)redhat.com>
---
src/lib/problem_data.c | 44 ++++++++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/src/lib/problem_data.c b/src/lib/problem_data.c
index 2e5e55f..77c46dd 100644
--- a/src/lib/problem_data.c
+++ b/src/lib/problem_data.c
@@ -288,7 +288,7 @@ static char* is_text_file(const char *name, ssize_t *sz)
}
lseek(fd, 0, SEEK_SET);
- char *buf = (char*)xmalloc(*sz);
+ unsigned char *buf = xmalloc(*sz);
ssize_t r = full_read(fd, buf, *sz);
close(fd);
if (r < 0)
@@ -306,7 +306,7 @@ static char* is_text_file(const char *name, ssize_t *sz)
{
base++;
if (is_in_string_list(base, (char**)always_text_files))
- return buf;
+ return (char*)buf;
}
/* Every once in a while, even a text file contains a few garbled
@@ -316,28 +316,44 @@ static char* is_text_file(const char *name, ssize_t *sz)
* os_release = "Schrödinger's Cat". Bumped to 10%.
* Alternatives: add os_release to always_text_files[]
* or add "if it is valid Unicode, then it's text" check here.
+ *
+ * Replaced crude "buf[r] > 0x7e is bad" logic with
+ * "if it is a broken Unicode, then it's bad".
*/
const unsigned RATIO = 10;
unsigned total_chars = r + RATIO;
unsigned bad_chars = 1; /* 1 prevents division by 0 later */
- while (--r >= 0)
+ bool prev_was_unicode = 0;
+ ssize_t i = -1;
+ while (++i < r)
{
- if (buf[r] >= 0x7f
- /* among control chars, only '\t','\n' etc are allowed */
- || (buf[r] < ' ' && !isspace(buf[r]))
- ) {
- if (buf[r] == '\0')
- {
- /* We don't like NULs very much. Not text for sure! */
- free(buf);
- return NULL;
- }
+ /* Among control chars, only '\t','\n' etc are allowed */
+ if (buf[i] < ' ' && !isspace(buf[i]))
+ {
+ /* We don't like NULs and other control chars very much.
+ * Not text for sure!
+ */
+ free(buf);
+ return NULL;
+ }
+ if (buf[i] == 0x7f)
bad_chars++;
+ else if (buf[i] > 0x7f)
+ {
+ /* We test two possible bad cases with one comparison:
+ * (1) prev byte was unicode AND cur byte is 11xxxxxx:
+ * BAD - unicode start byte can't be in the middle of unicode char
+ * (2) prev byte wasnt unicode AND cur byte is 10xxxxxx:
+ * BAD - unicode continuation byte can't start unicode char
+ */
+ if (prev_was_unicode == ((buf[i] & 0x40) == 0x40))
+ bad_chars++;
}
+ prev_was_unicode = (buf[i] > 0x7f);
}
if ((total_chars / bad_chars) >= RATIO)
- return buf; /* looks like text to me */
+ return (char*)buf; /* looks like text to me */
free(buf);
return NULL; /* it's binary */
--
1.8.1.4
11 years, 1 month
[PATCH] improve is_text_file() to not treat valid Unicode as bad_chars
by Denys Vlasenko
In valid Unicode, first non-ASCII byte is always 11xxxxxx
and the following bytes are always 10xxxxxx.
Random binary data is likely to violate this rule *a lot*.
This patch makes bad_chars++ decision only if it sees a non-ASCII
byte which violates the rule described above.
Also, it makes immediate decision "it's binary"
not only on NULs, but on any non-whitespace control chars.
This hopefully improves handling of the problem
identified in rhbz#922433
Please review.
--
vda
diff -x '*.po' -d -urpN libreport.8/src/lib/problem_data.c libreport.9/src/lib/problem_data.c
--- libreport.8/src/lib/problem_data.c 2013-03-20 13:51:15.000000000 +0100
+++ libreport.9/src/lib/problem_data.c 2013-03-25 09:59:19.510163001 +0100
@@ -288,7 +288,7 @@ static char* is_text_file(const char *na
}
lseek(fd, 0, SEEK_SET);
- char *buf = (char*)xmalloc(*sz);
+ unsigned char *buf = xmalloc(*sz);
ssize_t r = full_read(fd, buf, *sz);
close(fd);
if (r < 0)
@@ -306,7 +306,7 @@ static char* is_text_file(const char *na
{
base++;
if (is_in_string_list(base, (char**)always_text_files))
- return buf;
+ return (char*)buf;
}
/* Every once in a while, even a text file contains a few garbled
@@ -316,28 +316,43 @@ static char* is_text_file(const char *na
* os_release = "Schrödinger's Cat". Bumped to 10%.
* Alternatives: add os_release to always_text_files[]
* or add "if it is valid Unicode, then it's text" check here.
+ *
+ * Replaced crude "buf[r] > 0x7e is bad" logic with
+ * "if it is a broken Unicode, then it's bad".
*/
const unsigned RATIO = 10;
unsigned total_chars = r + RATIO;
unsigned bad_chars = 1; /* 1 prevents division by 0 later */
- while (--r >= 0)
+ bool prev_was_unicode = 0;
+ ssize_t i = -1;
+ while (++i < r)
{
- if (buf[r] >= 0x7f
- /* among control chars, only '\t','\n' etc are allowed */
- || (buf[r] < ' ' && !isspace(buf[r]))
- ) {
- if (buf[r] == '\0')
- {
- /* We don't like NULs very much. Not text for sure! */
- free(buf);
- return NULL;
- }
+ /* Among control chars, only '\t','\n' etc are allowed */
+ if (buf[i] < ' ' && !isspace(buf[i]))
+ {
+ /* We don't like NULs and other control chars very much.
+ * Not text for sure!
+ */
+ free(buf);
+ return NULL;
+ }
+ if (buf[i] == 0x7f)
bad_chars++;
+ else if (buf[i] > 0x7f)
+ {
+ /* Prev char was unicode AND cur char is 11xxxxxx:
+ * BAD - unicode start byte can't be in the middle of unicode char
+ * Prev char wasnt unicode AND cur char is 10xxxxxx:
+ * BAD - unicode continuation byte can't start unicode char
+ */
+ if (prev_was_unicode == ((buf[i] & 0x40) == 0x40))
+ bad_chars++;
}
+ prev_was_unicode = (buf[i] > 0x7f);
}
if ((total_chars / bad_chars) >= RATIO)
- return buf; /* looks like text to me */
+ return (char*)buf; /* looks like text to me */
free(buf);
return NULL; /* it's binary */
11 years, 1 month
[PATCH v2 2/2] reporter-rhtsupport: improve logging
by Denys Vlasenko
While testing previous patch, I got error messages
which were not very helpful.
Lets add URL to them.
--
vda
diff -x '*.po' -d -urpN libreport.7/src/plugins/abrt_rh_support.c libreport.8/src/plugins/abrt_rh_support.c
--- libreport.7/src/plugins/abrt_rh_support.c 2013-03-22 19:02:03.156493996 +0100
+++ libreport.8/src/plugins/abrt_rh_support.c 2013-03-22 18:57:03.581068163 +0100
@@ -357,7 +357,8 @@ post_case_to_url(const char* url,
errmsg = post_state->curl_error_msg;
if (errmsg && errmsg[0])
{
- result->msg = xasprintf(_("Error in case creation: %s"), errmsg);
+ result->msg = xasprintf(_("Error in case creation at '%s': %s"),
+ url, errmsg);
}
else
{
@@ -365,11 +366,13 @@ post_case_to_url(const char* url,
if (!errmsg)
errmsg = post_state->body;
if (errmsg && errmsg[0])
- result->msg = xasprintf(_("Error in case creation, HTTP code: %d, server says: '%s'"),
- post_state->http_resp_code, errmsg);
+ result->msg = xasprintf(_("Error in case creation at '%s',"
+ " HTTP code: %d, server says: '%s'"),
+ url, post_state->http_resp_code, errmsg);
else
- result->msg = xasprintf(_("Error in case creation, HTTP code: %d"),
- post_state->http_resp_code);
+ result->msg = xasprintf(_("Error in case creation at '%s',"
+ " HTTP code: %d"),
+ url, post_state->http_resp_code);
}
break;
@@ -410,17 +413,18 @@ create_new_case(const char* base_url,
description,
component
);
- free(url);
if (!result->error && !result->url)
{
/* Case Creation returned valid code, but no location */
result->error = -1;
free(result->msg);
- result->msg = xasprintf(_("Error in case creation: no Location URL, HTTP code: %d"),
- result->http_resp_code
+ result->msg = xasprintf(_("Error in case creation at '%s':"
+ " no Location URL, HTTP code: %d"),
+ url, result->http_resp_code
);
}
+ free(url);
return result;
}
@@ -519,7 +523,8 @@ post_comment_to_url(const char *url,
errmsg = post_state->curl_error_msg;
if (errmsg && errmsg[0])
{
- result->msg = xasprintf(_("Error in comment creation: %s"), errmsg);
+ result->msg = xasprintf(_("Error in comment creation at '%s': %s"),
+ url, errmsg);
}
else
{
@@ -527,11 +532,13 @@ post_comment_to_url(const char *url,
if (!errmsg)
errmsg = post_state->body;
if (errmsg && errmsg[0])
- result->msg = xasprintf(_("Error in comment creation, HTTP code: %d, server says: '%s'"),
- post_state->http_resp_code, errmsg);
+ result->msg = xasprintf(_("Error in comment creation at '%s',"
+ " HTTP code: %d, server says: '%s'"),
+ url, post_state->http_resp_code, errmsg);
else
- result->msg = xasprintf(_("Error in comment creation, HTTP code: %d"),
- post_state->http_resp_code);
+ result->msg = xasprintf(_("Error in comment creation at '%s',"
+ " HTTP code: %d"),
+ url, post_state->http_resp_code);
}
break;
@@ -569,17 +576,18 @@ add_comment_to_case(const char* base_url
(const char **) NULL, //text_plain_header,
comment_text
);
- free(url);
if (!result->error && !result->url)
{
/* Creation returned valid code, but no location */
result->error = -1;
free(result->msg);
- result->msg = xasprintf(_("Error in comment creation: no Location URL, HTTP code: %d"),
- result->http_resp_code
+ result->msg = xasprintf(_("Error in comment creation at '%s':"
+ " no Location URL, HTTP code: %d"),
+ url, result->http_resp_code
);
}
+ free(url);
return result;
}
@@ -655,17 +663,20 @@ post_file_to_url(const char* url,
errmsg = atch_state->curl_error_msg;
if (errmsg && errmsg[0])
{
- result->msg = xasprintf("Error in file upload: %s", errmsg);
+ result->msg = xasprintf("Error in file upload at '%s': %s",
+ url, errmsg);
}
else
{
errmsg = atch_state->body;
if (errmsg && errmsg[0])
- result->msg = xasprintf("Error in file upload, HTTP code: %d, server says: '%s'",
- atch_state->http_resp_code, errmsg);
+ result->msg = xasprintf("Error in file upload at '%s',"
+ " HTTP code: %d, server says: '%s'",
+ url, atch_state->http_resp_code, errmsg);
else
- result->msg = xasprintf("Error in file upload, HTTP code: %d",
- atch_state->http_resp_code);
+ result->msg = xasprintf("Error in file upload at '%s',"
+ " HTTP code: %d",
+ url, atch_state->http_resp_code);
}
break;
11 years, 2 months
[PATCH v2 1/2] reporter-rhtsupport: upload file to BigFileURL if it is large
by Denys Vlasenko
This patch adds BigFileURL and BigSizeMB parameters.
If uploaded DIR is bigger than BigSizeMB, then it is not attached
to the case, but uploaded to BigFileURL, then a comment is added
to the case with the URL of uploaded file.
Version 2: run-tested against actual server.
--
vda
diff -x '*.po' -d -urpN libreport.6/src/plugins/abrt_rh_support.c libreport.7/src/plugins/abrt_rh_support.c
--- libreport.6/src/plugins/abrt_rh_support.c 2013-03-22 15:26:05.695529936 +0100
+++ libreport.7/src/plugins/abrt_rh_support.c 2013-03-22 19:02:03.156493996 +0100
@@ -426,6 +426,165 @@ create_new_case(const char* base_url,
}
//
+// Add case comment
+//
+// $ curl -X POST -H 'Content-Type: application/xml' --data
+// '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+// <comment xmlns="http://www.redhat.com/gss/strata">
+// <text>Test comment! This can contain lots of information, etc.</text>
+// </comment>'
+// https://api.access.redhat.com/rs/cases/NNNNNNN/comments
+//
+static char*
+make_comment_data(const char *comment_text)
+{
+ char *retval;
+ xmlTextWriterPtr writer;
+ xmlBufferPtr buf;
+
+ buf = xxmlBufferCreate();
+ writer = xxmlNewTextWriterMemory(buf);
+
+ xxmlTextWriterStartDocument(writer, NULL, "UTF-8", "yes");
+ xxmlTextWriterStartElement(writer, "comment");
+ xxmlTextWriterWriteAttribute(writer, "xmlns",
+ "http://www.redhat.com/gss/strata");
+
+ xxmlTextWriterWriteElement(writer, "text", comment_text);
+
+ xxmlTextWriterEndDocument(writer);
+ retval = xstrdup((const char*)buf->content);
+ xmlFreeTextWriter(writer);
+ xmlBufferFree(buf);
+ return retval;
+}
+
+static rhts_result_t*
+post_comment_to_url(const char *url,
+ const char *username,
+ const char *password,
+ bool ssl_verify,
+ const char **additional_headers,
+ const char *comment_text)
+{
+ rhts_result_t *result = xzalloc(sizeof(*result));
+ char *url_copy = NULL;
+
+ char *xml = make_comment_data(comment_text);
+
+ int redirect_count = 0;
+ char *errmsg;
+ post_state_t *post_state;
+
+ redirect:
+ post_state = new_post_state(0
+ + POST_WANT_HEADERS
+ + POST_WANT_BODY
+ + POST_WANT_ERROR_MSG
+ + (ssl_verify ? POST_WANT_SSL_VERIFY : 0)
+ );
+ post_state->username = username;
+ post_state->password = password;
+
+ post_string(post_state, url, "application/xml", additional_headers, xml);
+
+ char *location = find_header_in_post_state(post_state, "Location:");
+
+ switch (post_state->http_resp_code)
+ {
+ case 404:
+ /* Not strictly necessary (default branch would deal with it too),
+ * but makes this typical error less cryptic:
+ * instead of returning html-encoded body, we show short concise message,
+ * and show offending URL (typos in which is a typical cause) */
+ result->error = -1;
+ result->msg = xasprintf("Error in HTTP POST, "
+ "HTTP code: 404 (Not found), URL:'%s'", url);
+ break;
+
+ case 301: /* "301 Moved Permanently" (for example, used to move http:// to https://) */
+ case 302: /* "302 Found" (just in case) */
+ case 305: /* "305 Use Proxy" */
+ if (++redirect_count < 10 && location)
+ {
+ free(url_copy);
+ url = url_copy = xstrdup(location);
+ free_post_state(post_state);
+ goto redirect;
+ }
+ /* fall through */
+
+ default:
+ result->error = -1;
+ errmsg = post_state->curl_error_msg;
+ if (errmsg && errmsg[0])
+ {
+ result->msg = xasprintf(_("Error in comment creation: %s"), errmsg);
+ }
+ else
+ {
+ errmsg = find_header_in_post_state(post_state, "Strata-Message:");
+ if (!errmsg)
+ errmsg = post_state->body;
+ if (errmsg && errmsg[0])
+ result->msg = xasprintf(_("Error in comment creation, HTTP code: %d, server says: '%s'"),
+ post_state->http_resp_code, errmsg);
+ else
+ result->msg = xasprintf(_("Error in comment creation, HTTP code: %d"),
+ post_state->http_resp_code);
+ }
+ break;
+
+ case 200:
+ case 201:
+ /* Created successfully */
+ result->url = xstrdup(location); /* note: xstrdup(NULL) returns NULL */
+ } /* switch (HTTP code) */
+
+ result->http_resp_code = post_state->http_resp_code;
+ result->body = post_state->body;
+ post_state->body = NULL;
+
+ free_post_state(post_state);
+ free(xml);
+ free(url_copy);
+ return result;
+}
+
+rhts_result_t*
+add_comment_to_case(const char* base_url,
+ const char* username,
+ const char* password,
+ bool ssl_verify,
+ const char* comment_text)
+{
+ char *url = concat_path_file(base_url, "comments");
+ rhts_result_t *result = post_comment_to_url(url,
+ username,
+ password,
+ ssl_verify,
+ // NB! text_plain_header here was causing error 404 instead of 201 (Created)!
+ // NULL makes curl use "Accept: */*" instead and creation works.
+ // Likely a bug on the server!
+ (const char **) NULL, //text_plain_header,
+ comment_text
+ );
+ free(url);
+
+ if (!result->error && !result->url)
+ {
+ /* Creation returned valid code, but no location */
+ result->error = -1;
+ free(result->msg);
+ result->msg = xasprintf(_("Error in comment creation: no Location URL, HTTP code: %d"),
+ result->http_resp_code
+ );
+ }
+
+ return result;
+}
+
+//
// Attach file to case
//
static rhts_result_t*
diff -x '*.po' -d -urpN libreport.6/src/plugins/abrt_rh_support.h libreport.7/src/plugins/abrt_rh_support.h
--- libreport.6/src/plugins/abrt_rh_support.h 2013-03-22 15:27:25.230430467 +0100
+++ libreport.7/src/plugins/abrt_rh_support.h 2013-03-22 19:00:57.484620125 +0100
@@ -70,6 +70,13 @@ create_new_case(const char* baseURL,
);
rhts_result_t*
+add_comment_to_case(const char* base_url,
+ const char* username,
+ const char* password,
+ bool ssl_verify,
+ const char* comment_text);
+
+rhts_result_t*
attach_file_to_case(const char* baseURL,
const char* username,
const char* password,
diff -x '*.po' -d -urpN libreport.6/src/plugins/reporter-rhtsupport.c libreport.7/src/plugins/reporter-rhtsupport.c
--- libreport.6/src/plugins/reporter-rhtsupport.c 2013-03-22 15:27:25.231430466 +0100
+++ libreport.7/src/plugins/reporter-rhtsupport.c 2013-03-22 19:02:41.401420478 +0100
@@ -163,6 +163,15 @@ int create_tarball(const char *tempfile,
return 1; /* failure */
}
+static
+char *get_param_string(const char *name, map_string_h *settings, const char *dflt)
+{
+ char *envname = xasprintf("RHTSupport_%s", name);
+ const char *envvar = getenv(envname);
+ free(envname);
+ return xstrdup(envvar ? envvar : (get_map_string_item_or_NULL(settings, name) ? : dflt));
+}
+
int main(int argc, char **argv)
{
abrt_init(argv);
@@ -189,7 +198,8 @@ int main(int argc, char **argv)
"\n"
"If not specified, CONFFILE defaults to "CONF_DIR"/plugins/rhtsupport.conf\n"
"Its lines should have 'PARAM = VALUE' format.\n"
- "Recognized string parameters: URL, Login, Password.\n"
+ "Recognized string parameters: URL, Login, Password, BigFileURL.\n"
+ "Recognized numeric parameter: BigSizeMB.\n"
"Recognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify.\n"
"Parameters can be overridden via $RHTSupport_PARAM environment variables.\n"
"\n"
@@ -233,21 +243,21 @@ int main(int argc, char **argv)
VERB3 log("Loaded '%s'", fn);
conf_file = g_list_remove(conf_file, fn);
}
- char* envvar;
- char *url;
- char *login;
- char *password;
- bool ssl_verify;
- envvar = getenv("RHTSupport_URL");
- url = xstrdup(envvar ? envvar : (get_map_string_item_or_NULL(settings, "URL") ? : "https://api.access.redhat.com/rs"));
- envvar = getenv("RHTSupport_Login");
- login = xstrdup(envvar ? envvar : get_map_string_item_or_empty(settings, "Login"));
- envvar = getenv("RHTSupport_Password");
- password = xstrdup(envvar ? envvar : get_map_string_item_or_empty(settings, "Password"));
- envvar = getenv("RHTSupport_SSLVerify");
- ssl_verify = string_to_bool(envvar ? envvar : get_map_string_item_or_empty(settings, "SSLVerify"));
+ char *url = get_param_string("URL" , settings, "https://api.access.redhat.com/rs");
+ char *login = get_param_string("Login" , settings, "");
+ char *password = get_param_string("Password" , settings, "");
+ char *bigurl = get_param_string("BigFileURL", settings, "ftp://dropbox.redhat.com/incoming/");
if (!login[0] || !password[0])
error_msg_and_die(_("Empty RHTS login or password"));
+ char* envvar;
+ envvar = getenv("RHTSupport_SSLVerify");
+ bool ssl_verify = string_to_bool(
+ envvar ? envvar : (get_map_string_item_or_NULL(settings, "SSLVerify") ? : "1")
+ );
+ envvar = getenv("RHTSupport_BigSizeMB");
+ unsigned bigsize = xatoi_positive(
+ envvar ? envvar : (get_map_string_item_or_NULL(settings, "BigSizeMB") ? : "1000")
+ );
free_map_string(settings);
if (opts & OPT_t)
@@ -374,6 +384,7 @@ int main(int argc, char **argv)
if (tempfile_size <= QUERY_HINTS_IF_SMALLER_THAN)
{
/* Check for hints and show them if we have something */
+ log(_("Checking for hints"));
result = get_rhts_hints(url,
login,
password,
@@ -471,16 +482,47 @@ int main(int argc, char **argv)
log("URL=%s", result->url);
}
/* else: error msg was already emitted by dd_opendir */
+
url = result->url;
}
- /* Attach the tarball of -d DIR */
- result_atch = attach_file_to_case(url,
- login,
- password,
- ssl_verify,
- tempfile
- );
+ char *remote_filename = NULL;
+ if (bigsize != 0 && tempfile_size / (1024*1024) >= bigsize)
+ {
+ /* Upload tarball of -d DIR to "big file" FTP */
+ /* log(_("Uploading problem data to '%s'"), bigurl); - upload_file does this */
+ remote_filename = upload_file(bigurl, tempfile);
+ }
+ if (remote_filename)
+ {
+ log(_("Adding comment to case '%s'"), url);
+ /*
+ * Do not translate message below - it goes
+ * to a server where *other people* will read it.
+ */
+ char *comment_text = xasprintf(
+ "Problem data was uploaded to %s",
+ remote_filename
+ );
+ free(remote_filename);
+ result_atch = add_comment_to_case(url,
+ login, password,
+ ssl_verify,
+ comment_text
+ );
+ free(comment_text);
+ }
+ else
+ {
+ /* Attach the tarball of -d DIR */
+ log(_("Attaching problem data to case '%s'"), url);
+ result_atch = attach_file_to_case(url,
+ login, password,
+ ssl_verify,
+ tempfile
+
+ );
+ }
if (result_atch->error)
{
if (!(opts & OPT_t))
diff -x '*.po' -d -urpN libreport.6/src/plugins/rhtsupport.conf libreport.7/src/plugins/rhtsupport.conf
--- libreport.6/src/plugins/rhtsupport.conf 2013-02-07 14:31:32.000000000 +0100
+++ libreport.7/src/plugins/rhtsupport.conf 2013-03-22 19:02:41.401420478 +0100
@@ -8,6 +8,10 @@
# URL=
# Login=
# Password=
+# BigFileURL=
+#
+# Integer parameter:
+# BigSizeMB=
#
# Boolean parameter:
# SSLVerify=
11 years, 2 months
[PATCH 3/3] reporter-rhtsupport: upload file to BigFileURL if it is large
by Denys Vlasenko
This patch adds BigFileURL and BigSizeMB parameters.
If uploaded DIR is bigger than BigSizeMB, then it is not attached
to the case, but uploaded to BigFileURL, then a comment is added
to the case with the URL of uploaded file.
--
vda
diff -x '*.po' -d -urpN libreport.5/src/plugins/abrt_rh_support.c libreport.6/src/plugins/abrt_rh_support.c
--- libreport.5/src/plugins/abrt_rh_support.c 2013-02-07 14:31:32.000000000 +0100
+++ libreport.6/src/plugins/abrt_rh_support.c 2013-03-22 13:53:33.069697211 +0100
@@ -108,9 +108,11 @@ xxmlTextWriterWriteString(xmlTextWriterP
#endif
//
+// Reportfile helpers
+//
+
// End the reportfile, and prepare it for delivery.
// No more bindings can be added after this.
-//
static void
close_writer(reportfile_t* file)
{
@@ -123,9 +125,7 @@ close_writer(reportfile_t* file)
file->writer = NULL;
}
-//
// This allocates a reportfile_t structure and initializes it.
-//
reportfile_t*
new_reportfile(void)
{
@@ -159,9 +159,7 @@ internal_reportfile_start_binding(report
xxmlTextWriterWriteAttribute(file->writer, "type", "text");
}
-//
// Add a new text binding
-//
void
reportfile_add_binding_from_string(reportfile_t* file, const char* name, const char* value)
{
@@ -171,9 +169,7 @@ reportfile_add_binding_from_string(repor
xxmlTextWriterEndElement(file->writer);
}
-//
// Add a new binding to a report whose value is represented as a file.
-//
void
reportfile_add_binding_from_namedfile(reportfile_t* file,
const char* on_disk_filename, /* unused so far */
@@ -189,9 +185,7 @@ reportfile_add_binding_from_namedfile(re
free(href_name);
}
-//
// Return the contents of the reportfile as a string.
-//
const char*
reportfile_as_string(reportfile_t* file)
{
@@ -222,9 +216,27 @@ void free_rhts_result(rhts_result_t *p)
}
//
-// create_new_case()
+// Common
//
+static const char *const text_plain_header[] = {
+ "Accept: text/plain",
+ NULL
+};
+//
+// Creating new case
+// See
+// https://access.redhat.com/knowledge/docs/Red_Hat_Customer_Portal/integrat...
+//
+// $ curl -X POST -H 'Content-Type: application/xml' --data
+// '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+// <case xmlns="http://www.redhat.com/gss/strata">
+// <summary>Example Case</summary>
+// <description>Example created with cURL</description>
+// <product>Red Hat Enterprise Linux</product><version>6.0</version>
+// </case>'
+// https://api.access.redhat.com/rs/cases
+//
static char*
make_case_data(const char* summary, const char* description,
const char* product, const char* version,
@@ -261,52 +273,6 @@ make_case_data(const char* summary, cons
return retval;
}
-#if 0 //unused
-static char*
-make_response(const char* title, const char* body,
- const char* actualURL, const char* displayURL)
-{
- char* retval;
- xmlTextWriterPtr writer;
- xmlBufferPtr buf;
-
- buf = xxmlBufferCreate();
- writer = xxmlNewTextWriterMemory(buf);
-
- xxmlTextWriterStartDocument(writer, NULL, "UTF-8", "yes");
- xxmlTextWriterStartElement(writer, "response");
- if (title) {
- xxmlTextWriterWriteElement(writer, "title", title);
- }
- if (body) {
- xxmlTextWriterWriteElement(writer, "body", body);
- }
- if (actualURL || displayURL) {
- xxmlTextWriterStartElement(writer, "URL");
- if (actualURL) {
- xxmlTextWriterWriteAttribute(writer, "href", actualURL);
- }
- if (displayURL) {
- xxmlTextWriterWriteString(writer, displayURL);
- }
- }
-
- xxmlTextWriterEndDocument(writer);
- retval = xstrdup((const char*)buf->content);
- xmlFreeTextWriter(writer);
- xmlBufferFree(buf);
- return retval;
-}
-//Example:
-//<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-//<response><title>Case Created and Report Attached</title><body></body><URL href="http://support-services-devel.gss.redhat.com:8080/Strata/cases/00005129/a...">New Case URL</URL></response>
-#endif
-
-static const char *const text_plain_header[] = {
- "Accept: text/plain",
- NULL
-};
-
static rhts_result_t*
post_case_to_url(const char* url,
const char* username,
@@ -332,23 +298,23 @@ post_case_to_url(const char* url,
int redirect_count = 0;
char *errmsg;
- post_state_t *case_state;
+ post_state_t *post_state;
- redirect_case:
- case_state = new_post_state(0
+ redirect:
+ post_state = new_post_state(0
+ POST_WANT_HEADERS
+ POST_WANT_BODY
+ POST_WANT_ERROR_MSG
+ (ssl_verify ? POST_WANT_SSL_VERIFY : 0)
);
- case_state->username = username;
- case_state->password = password;
+ post_state->username = username;
+ post_state->password = password;
- post_string(case_state, url, "application/xml", additional_headers, case_data);
+ post_string(post_state, url, "application/xml", additional_headers, case_data);
- char *case_location = find_header_in_post_state(case_state, "Location:");
+ char *location = find_header_in_post_state(post_state, "Location:");
- switch (case_state->http_resp_code)
+ switch (post_state->http_resp_code)
{
case 404:
/* Not strictly necessary (default branch would deal with it too),
@@ -363,12 +329,12 @@ post_case_to_url(const char* url,
case 301: /* "301 Moved Permanently" (for example, used to move http:// to https://) */
case 302: /* "302 Found" (just in case) */
case 305: /* "305 Use Proxy" */
- if (++redirect_count < 10 && case_location)
+ if (++redirect_count < 10 && location)
{
free(url_copy);
- url = url_copy = xstrdup(case_location);
- free_post_state(case_state);
- goto redirect_case;
+ url = url_copy = xstrdup(location);
+ free_post_state(post_state);
+ goto redirect;
}
/* fall through */
@@ -388,42 +354,236 @@ post_case_to_url(const char* url,
// '^M'
// ' ' <------ body is useless
result->error = -1;
- errmsg = case_state->curl_error_msg;
+ errmsg = post_state->curl_error_msg;
if (errmsg && errmsg[0])
{
result->msg = xasprintf(_("Error in case creation: %s"), errmsg);
}
else
{
- errmsg = find_header_in_post_state(case_state, "Strata-Message:");
+ errmsg = find_header_in_post_state(post_state, "Strata-Message:");
if (!errmsg)
- errmsg = case_state->body;
+ errmsg = post_state->body;
if (errmsg && errmsg[0])
result->msg = xasprintf(_("Error in case creation, HTTP code: %d, server says: '%s'"),
- case_state->http_resp_code, errmsg);
+ post_state->http_resp_code, errmsg);
else
result->msg = xasprintf(_("Error in case creation, HTTP code: %d"),
- case_state->http_resp_code);
+ post_state->http_resp_code);
}
break;
case 200:
case 201:
- /* Cose created successfully */
- result->url = xstrdup(case_location); /* note: xstrdup(NULL) returns NULL */
- //result->msg = xstrdup("Case created");
+ /* Created successfully */
+ result->url = xstrdup(location); /* note: xstrdup(NULL) returns NULL */
} /* switch (HTTP code) */
- result->http_resp_code = case_state->http_resp_code;
- result->body = case_state->body;
- case_state->body = NULL;
+ result->http_resp_code = post_state->http_resp_code;
+ result->body = post_state->body;
+ post_state->body = NULL;
- free_post_state(case_state);
+ free_post_state(post_state);
free(case_data);
free(url_copy);
return result;
}
+rhts_result_t*
+create_new_case(const char* base_url,
+ const char* username,
+ const char* password,
+ bool ssl_verify,
+ const char* release,
+ const char* summary,
+ const char* description,
+ const char* component)
+{
+ char *url = concat_path_file(base_url, "cases");
+ rhts_result_t *result = post_case_to_url(url,
+ username,
+ password,
+ ssl_verify,
+ (const char **)text_plain_header,
+ release,
+ summary,
+ description,
+ component
+ );
+ free(url);
+
+ if (!result->error && !result->url)
+ {
+ /* Case Creation returned valid code, but no location */
+ result->error = -1;
+ free(result->msg);
+ result->msg = xasprintf(_("Error in case creation: no Location URL, HTTP code: %d"),
+ result->http_resp_code
+ );
+ }
+
+ return result;
+}
+
+//
+// Add case comment
+//
+// $ curl -X POST -H 'Content-Type: application/xml' --data
+// '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+// <comment xmlns="http://www.redhat.com/gss/strata">
+// <text>Test comment! This can contain lots of information, etc.</text>
+// </comment>'
+// https://api.access.redhat.com/rs/cases/NNNNNNN/comments
+//
+static char*
+make_comment_data(const char *comment_text)
+{
+ char *retval;
+ xmlTextWriterPtr writer;
+ xmlBufferPtr buf;
+
+ buf = xxmlBufferCreate();
+ writer = xxmlNewTextWriterMemory(buf);
+
+ xxmlTextWriterStartDocument(writer, NULL, "UTF-8", "yes");
+ xxmlTextWriterStartElement(writer, "comment");
+ xxmlTextWriterWriteAttribute(writer, "xmlns",
+ "http://www.redhat.com/gss/strata");
+
+ xxmlTextWriterWriteElement(writer, "text", comment_text);
+
+ xxmlTextWriterEndDocument(writer);
+ retval = xstrdup((const char*)buf->content);
+ xmlFreeTextWriter(writer);
+ xmlBufferFree(buf);
+ return retval;
+}
+
+static rhts_result_t*
+post_comment_to_url(const char *url,
+ const char *username,
+ const char *password,
+ bool ssl_verify,
+ const char **additional_headers,
+ const char *comment_text)
+{
+ rhts_result_t *result = xzalloc(sizeof(*result));
+ char *url_copy = NULL;
+
+ char *xml = make_comment_data(comment_text);
+
+ int redirect_count = 0;
+ char *errmsg;
+ post_state_t *post_state;
+
+ redirect:
+ post_state = new_post_state(0
+ + POST_WANT_HEADERS
+ + POST_WANT_BODY
+ + POST_WANT_ERROR_MSG
+ + (ssl_verify ? POST_WANT_SSL_VERIFY : 0)
+ );
+ post_state->username = username;
+ post_state->password = password;
+
+ post_string(post_state, url, "application/xml", additional_headers, xml);
+
+ char *location = find_header_in_post_state(post_state, "Location:");
+
+ switch (post_state->http_resp_code)
+ {
+ case 404:
+ /* Not strictly necessary (default branch would deal with it too),
+ * but makes this typical error less cryptic:
+ * instead of returning html-encoded body, we show short concise message,
+ * and show offending URL (typos in which is a typical cause) */
+ result->error = -1;
+ result->msg = xasprintf("Error in HTTP POST, "
+ "HTTP code: 404 (Not found), URL:'%s'", url);
+ break;
+
+ case 301: /* "301 Moved Permanently" (for example, used to move http:// to https://) */
+ case 302: /* "302 Found" (just in case) */
+ case 305: /* "305 Use Proxy" */
+ if (++redirect_count < 10 && location)
+ {
+ free(url_copy);
+ url = url_copy = xstrdup(location);
+ free_post_state(post_state);
+ goto redirect;
+ }
+ /* fall through */
+
+ default:
+ result->error = -1;
+ errmsg = post_state->curl_error_msg;
+ if (errmsg && errmsg[0])
+ {
+ result->msg = xasprintf(_("Error in comment creation: %s"), errmsg);
+ }
+ else
+ {
+ errmsg = find_header_in_post_state(post_state, "Strata-Message:");
+ if (!errmsg)
+ errmsg = post_state->body;
+ if (errmsg && errmsg[0])
+ result->msg = xasprintf(_("Error in comment creation, HTTP code: %d, server says: '%s'"),
+ post_state->http_resp_code, errmsg);
+ else
+ result->msg = xasprintf(_("Error in comment creation, HTTP code: %d"),
+ post_state->http_resp_code);
+ }
+ break;
+
+ case 200:
+ case 201:
+ /* Created successfully */
+ result->url = xstrdup(location); /* note: xstrdup(NULL) returns NULL */
+ } /* switch (HTTP code) */
+
+ result->http_resp_code = post_state->http_resp_code;
+ result->body = post_state->body;
+ post_state->body = NULL;
+
+ free_post_state(post_state);
+ free(xml);
+ free(url_copy);
+ return result;
+}
+
+rhts_result_t*
+add_comment_to_case(const char* base_url,
+ const char* username,
+ const char* password,
+ bool ssl_verify,
+ const char* comment_text)
+{
+ char *url = concat_path_file(base_url, "comments");
+ rhts_result_t *result = post_comment_to_url(url,
+ username,
+ password,
+ ssl_verify,
+ (const char **)text_plain_header,
+ comment_text
+ );
+ free(url);
+
+ if (!result->error && !result->url)
+ {
+ /* Creation returned valid code, but no location */
+ result->error = -1;
+ free(result->msg);
+ result->msg = xasprintf(_("Error in comment creation: no Location URL, HTTP code: %d"),
+ result->http_resp_code
+ );
+ }
+
+ return result;
+}
+
+//
+// Attach file to case
+//
static rhts_result_t*
post_file_to_url(const char* url,
const char* username,
@@ -522,41 +682,28 @@ post_file_to_url(const char* url,
}
rhts_result_t*
-create_new_case(const char* base_url,
+attach_file_to_case(const char* base_url,
const char* username,
const char* password,
bool ssl_verify,
- const char* release,
- const char* summary,
- const char* description,
- const char* component)
+ const char *file_name)
{
- char *url = concat_path_file(base_url, "cases");
- rhts_result_t *result = post_case_to_url(url,
+ char *url = concat_path_file(base_url, "attachments");
+ rhts_result_t *result = post_file_to_url(url,
username,
password,
ssl_verify,
- (const char **)text_plain_header,
- release,
- summary,
- description,
- component
+ /*post_as_form:*/ true,
+ (const char **) text_plain_header,
+ file_name
);
free(url);
-
- if (!result->error && !result->url)
- {
- /* Case Creation returned valid code, but no location */
- result->error = -1;
- free(result->msg);
- result->msg = xasprintf(_("Error in case creation: no Location URL, HTTP code: %d"),
- result->http_resp_code
- );
- }
-
return result;
}
+//
+// Get hint
+//
rhts_result_t*
get_rhts_hints(const char* base_url,
const char* username,
@@ -584,25 +731,5 @@ get_rhts_hints(const char* base_url,
file_name
);
free(url);
- return result;
-}
-
-rhts_result_t*
-attach_file_to_case(const char* base_url,
- const char* username,
- const char* password,
- bool ssl_verify,
- const char *file_name)
-{
- char *url = concat_path_file(base_url, "attachments");
- rhts_result_t *result = post_file_to_url(url,
- username,
- password,
- ssl_verify,
- /*post_as_form:*/ true,
- (const char **) text_plain_header,
- file_name
- );
- free(url);
return result;
}
diff -x '*.po' -d -urpN libreport.5/src/plugins/abrt_rh_support.h libreport.6/src/plugins/abrt_rh_support.h
--- libreport.5/src/plugins/abrt_rh_support.h 2013-02-07 14:31:32.000000000 +0100
+++ libreport.6/src/plugins/abrt_rh_support.h 2013-03-22 11:57:17.860089776 +0100
@@ -70,6 +70,13 @@ create_new_case(const char* baseURL,
);
rhts_result_t*
+add_comment_to_case(const char* base_url,
+ const char* username,
+ const char* password,
+ bool ssl_verify,
+ const char* comment_text);
+
+rhts_result_t*
attach_file_to_case(const char* baseURL,
const char* username,
const char* password,
diff -x '*.po' -d -urpN libreport.5/src/plugins/reporter-rhtsupport.c libreport.6/src/plugins/reporter-rhtsupport.c
--- libreport.5/src/plugins/reporter-rhtsupport.c 2013-03-22 14:56:23.241918966 +0100
+++ libreport.6/src/plugins/reporter-rhtsupport.c 2013-03-22 12:03:39.283404448 +0100
@@ -163,6 +163,15 @@ int create_tarball(const char *tempfile,
return 1; /* failure */
}
+static
+char *get_param_string(const char *name, map_string_h *settings, const char *dflt)
+{
+ char *envname = xasprintf("RHTSupport_%s", name);
+ const char *envvar = getenv(envname);
+ free(envname);
+ return xstrdup(envvar ? envvar : (get_map_string_item_or_NULL(settings, name) ? : dflt));
+}
+
int main(int argc, char **argv)
{
abrt_init(argv);
@@ -189,7 +198,8 @@ int main(int argc, char **argv)
"\n"
"If not specified, CONFFILE defaults to "CONF_DIR"/plugins/rhtsupport.conf\n"
"Its lines should have 'PARAM = VALUE' format.\n"
- "Recognized string parameters: URL, Login, Password.\n"
+ "Recognized string parameters: URL, Login, Password, BigFileURL.\n"
+ "Recognized numeric parameter: BigSizeMB.\n"
"Recognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify.\n"
"Parameters can be overridden via $RHTSupport_PARAM environment variables.\n"
"\n"
@@ -233,21 +243,21 @@ int main(int argc, char **argv)
VERB3 log("Loaded '%s'", fn);
conf_file = g_list_remove(conf_file, fn);
}
- char* envvar;
- char *url;
- char *login;
- char *password;
- bool ssl_verify;
- envvar = getenv("RHTSupport_URL");
- url = xstrdup(envvar ? envvar : (get_map_string_item_or_NULL(settings, "URL") ? : "https://api.access.redhat.com/rs"));
- envvar = getenv("RHTSupport_Login");
- login = xstrdup(envvar ? envvar : get_map_string_item_or_empty(settings, "Login"));
- envvar = getenv("RHTSupport_Password");
- password = xstrdup(envvar ? envvar : get_map_string_item_or_empty(settings, "Password"));
- envvar = getenv("RHTSupport_SSLVerify");
- ssl_verify = string_to_bool(envvar ? envvar : get_map_string_item_or_empty(settings, "SSLVerify"));
+ char *url = get_param_string("URL" , settings, "https://api.access.redhat.com/rs");
+ char *login = get_param_string("Login" , settings, "");
+ char *password = get_param_string("Password" , settings, "");
+ char *bigurl = get_param_string("BigFileURL", settings, "ftp://dropbox.redhat.com/incoming/");
if (!login[0] || !password[0])
error_msg_and_die(_("Empty RHTS login or password"));
+ char* envvar;
+ envvar = getenv("RHTSupport_SSLVerify");
+ bool ssl_verify = string_to_bool(
+ envvar ? envvar : (get_map_string_item_or_NULL(settings, "SSLVerify") ? : "1")
+ );
+ envvar = getenv("RHTSupport_BigSizeMB");
+ unsigned bigsize = xatoi_positive(
+ envvar ? envvar : (get_map_string_item_or_NULL(settings, "BigSizeMB") ? : "1000")
+ );
free_map_string(settings);
if (opts & OPT_t)
@@ -471,16 +481,44 @@ int main(int argc, char **argv)
log("URL=%s", result->url);
}
/* else: error msg was already emitted by dd_opendir */
+
url = result->url;
}
- /* Attach the tarball of -d DIR */
- result_atch = attach_file_to_case(url,
- login,
- password,
- ssl_verify,
- tempfile
- );
+ char *remote_filename = NULL;
+ if (bigsize != 0 && tempfile_size / (1024*1024) >= bigsize)
+ {
+ /* Upload tarball of -d DIR to "big file" FTP */
+ remote_filename = upload_file(bigurl, tempfile);
+ }
+ if (remote_filename)
+ {
+ /* Attach a comment where to find uploaded tarball.
+ * Do not translate this message - it goes to a server
+ * where *other people* will read it
+ */
+ char *comment_text = xasprintf(
+ "Problem data was uploaded to %s",
+ remote_filename
+ );
+ free(remote_filename);
+ result_atch = add_comment_to_case(url,
+ login, password,
+ ssl_verify,
+ comment_text
+ );
+ free(comment_text);
+ }
+ else
+ {
+ /* Attach the tarball of -d DIR */
+ result_atch = attach_file_to_case(url,
+ login, password,
+ ssl_verify,
+ tempfile
+
+ );
+ }
if (result_atch->error)
{
if (!(opts & OPT_t))
11 years, 2 months
[PATCH 2/3] reporter-upload: move file upload function to lib/
by Denys Vlasenko
This patch moves send_file() out of reporter-upload
into lib/curl.c
--
vda
diff -x '*.po' -d -urpN libreport.4/src/include/libreport_curl.h libreport.5/src/include/libreport_curl.h
--- libreport.4/src/include/libreport_curl.h 2013-03-21 15:58:13.855064590 +0100
+++ libreport.5/src/include/libreport_curl.h 2013-03-22 14:30:32.890220652 +0100
@@ -117,6 +117,9 @@ post_file_as_form(post_state_t *state,
filename, POST_DATA_FROMFILE_AS_FORM_DATA);
}
+#define upload_file libreport_upload_file
+char *upload_file(const char *url, const char *filename);
+
#ifdef __cplusplus
}
#endif
diff -x '*.po' -d -urpN libreport.4/src/lib/curl.c libreport.5/src/lib/curl.c
--- libreport.4/src/lib/curl.c 2013-03-21 17:05:42.730493856 +0100
+++ libreport.5/src/lib/curl.c 2013-03-22 14:30:32.891220651 +0100
@@ -571,3 +571,59 @@ post(post_state_t *state,
return response_code;
}
+
+/* Unlike post_file(),
+ * this function will use PUT, not POST if url is "http(s)://..."
+ */
+char *upload_file(const char *url, const char *filename)
+{
+ /* we don't want to print the whole url as it may contain password
+ * rhbz#856960
+ * there can be '@' in the login or password so let's try to find the
+ * first '@' from the end
+ */
+ const char *clean_url = strrchr(url, '@');
+ if (clean_url)
+ clean_url++;
+ else
+ clean_url = url;
+
+ log(_("Sending %s to %s"), filename, clean_url);
+
+ char *whole_url;
+ unsigned len = strlen(url);
+ if (len > 0 && url[len-1] == '/')
+ whole_url = concat_path_file(url, strrchr(filename, '/') ? : filename);
+ else
+ whole_url = xstrdup(url);
+
+ post_state_t *state = new_post_state(POST_WANT_ERROR_MSG);
+ post(state,
+ whole_url,
+ /*content_type:*/ "???",
+ /*additional_headers:*/ NULL,
+ /*data:*/ filename,
+ POST_DATA_FROMFILE_PUT
+ );
+
+ int error = (state->curl_result != 0);
+ if (error)
+ {
+ if (state->curl_error_msg)
+ error_msg("Error while uploading: '%s'", state->curl_error_msg);
+ else
+ /* for example, when source file can't be opened */
+ error_msg("Error while uploading");
+ free(whole_url);
+ whole_url = NULL;
+ }
+ else
+ {
+ /* This ends up a "reporting status message" in abrtd */
+ log(_("Successfully sent %s to %s"), filename, clean_url);
+ }
+
+ free_post_state(state);
+
+ return whole_url;
+}
diff -x '*.po' -d -urpN libreport.4/src/plugins/reporter-upload.c libreport.5/src/plugins/reporter-upload.c
--- libreport.4/src/plugins/reporter-upload.c 2013-03-21 17:29:31.246399895 +0100
+++ libreport.5/src/plugins/reporter-upload.c 2013-03-22 14:32:07.721848903 +0100
@@ -20,58 +20,6 @@
#include "libreport_curl.h"
#include "internal_libreport.h"
-static int send_file(const char *url, const char *filename)
-{
- /* we don't want to print the whole url as it may contain password
- * rhbz#856960
- * there can be '@' in the login or password so let's try to find the
- * first '@' from the end
- */
- const char *clean_url = strrchr(url, '@');
- if (clean_url)
- clean_url++;
- else
- clean_url = url;
-
- log(_("Sending %s to %s"), filename, clean_url);
-
- char *whole_url;
- unsigned len = strlen(url);
- if (len > 0 && url[len-1] == '/')
- whole_url = concat_path_file(url, strrchr(filename, '/') ? : filename);
- else
- whole_url = xstrdup(url);
-
- post_state_t *state = new_post_state(POST_WANT_ERROR_MSG);
- post(state,
- whole_url,
- /*content_type:*/ "???",
- /*additional_headers:*/ NULL,
- /*data:*/ filename,
- POST_DATA_FROMFILE_PUT
- );
- free(whole_url);
-
- int error = (state->curl_result != 0);
- if (error)
- {
- if (state->curl_error_msg)
- error_msg("Error while uploading: '%s'", state->curl_error_msg);
- else
- /* for example, when source file can't be opened */
- error_msg("Error while uploading");
- }
- else
- {
- /* This ends up a "reporting status message" in abrtd */
- log(_("Successfully sent %s to %s"), filename, clean_url);
- }
-
- free_post_state(state);
-
- return error;
-}
-
static int create_and_upload_archive(
const char *dump_dir_name,
map_string_h *settings)
@@ -183,7 +131,9 @@ static int create_and_upload_archive(
/* Upload from /tmp to /tmp + deletion -> BAD, exclude this possibility */
if (url && url[0] && strcmp(url, "file:///tmp/") != 0)
{
- result = send_file(url, tempfile);
+ char *remote_name = upload_file(url, tempfile);
+ result = (remote_name == NULL); /* error if NULL */
+ free(remote_name);
/* cleanup code will delete tempfile */
}
else
11 years, 2 months
[PATCH 1/3] reporter-upload: factor out HTTP PUT upload
by Denys Vlasenko
This patch adds HTTP PUT upload support to post()
helper function. This simplifies send_file()
in reporter-upload.
--
vda
diff -x '*.po' -d -urpN libreport.3/src/include/libreport_curl.h libreport.4/src/include/libreport_curl.h
--- libreport.3/src/include/libreport_curl.h 2013-02-07 14:31:32.000000000 +0100
+++ libreport.4/src/include/libreport_curl.h 2013-03-21 15:58:13.855064590 +0100
@@ -37,6 +37,12 @@ typedef struct post_state {
const char *password;
/* Results of POST transaction: */
int http_resp_code;
+ /* cast from CURLcode enum.
+ * 0 = success.
+ * -1 = curl_easy_perform wasn't even reached (file open error, etc).
+ * Else curl_easy_perform's error (which is positive, see curl/curl.h).
+ */
+ int curl_result;
unsigned header_cnt;
char **headers;
char *curl_error_msg;
@@ -59,8 +65,9 @@ enum {
/* Must be -1! CURLOPT_POSTFIELDSIZE interprets -1 as "use strlen" */
POST_DATA_STRING = -1,
POST_DATA_FROMFILE = -2,
- POST_DATA_FROMFILE_AS_FORM_DATA = -3,
- POST_DATA_STRING_AS_FORM_DATA = -4,
+ POST_DATA_FROMFILE_PUT = -3,
+ POST_DATA_FROMFILE_AS_FORM_DATA = -4,
+ POST_DATA_STRING_AS_FORM_DATA = -5,
};
int
post(post_state_t *state,
diff -x '*.po' -d -urpN libreport.3/src/lib/curl.c libreport.4/src/lib/curl.c
--- libreport.3/src/lib/curl.c 2013-03-22 14:35:16.119617253 +0100
+++ libreport.4/src/lib/curl.c 2013-03-21 17:05:42.730493856 +0100
@@ -313,7 +313,7 @@ post(post_state_t *state,
state = &localstate;
}
- state->http_resp_code = response_code = -1;
+ state->curl_result = state->http_resp_code = response_code = -1;
CURL *handle = xcurl_easy_init();
@@ -325,7 +325,8 @@ post(post_state_t *state,
// Shut off the built-in progress meter completely
xcurl_easy_setopt_long(handle, CURLOPT_NOPROGRESS, 1);
- if (g_verbose >= 2) {
+ if (g_verbose >= 2)
+ {
// "Display a lot of verbose information about its operations.
// Very useful for libcurl and/or protocol debugging and understanding.
// The verbose information will be sent to stderr, or the stream set
@@ -339,37 +340,61 @@ post(post_state_t *state,
xcurl_easy_setopt_ptr(handle, CURLOPT_URL, url);
// Auth if configured
- if (state->username) {
+ if (state->username)
+ {
// bitmask of allowed auth methods
xcurl_easy_setopt_long(handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
xcurl_easy_setopt_ptr(handle, CURLOPT_USERNAME, state->username);
xcurl_easy_setopt_ptr(handle, CURLOPT_PASSWORD, (state->password ? state->password : ""));
}
- // Do a regular HTTP post. This also makes curl use
- // a "Content-Type: application/x-www-form-urlencoded" header.
- // (This is by far the most commonly used POST method).
- xcurl_easy_setopt_long(handle, CURLOPT_POST, 1);
- // Supply POST data...
- struct curl_httppost* post = NULL;
- struct curl_httppost* last = NULL;
- FILE* data_file = NULL;
- if (data_size == POST_DATA_FROMFILE) {
+ if (data_size != POST_DATA_FROMFILE_PUT)
+ {
+ // Do a HTTP POST. This also makes curl use
+ // a "Content-Type: application/x-www-form-urlencoded" header.
+ // (This is by far the most commonly used POST method).
+ xcurl_easy_setopt_long(handle, CURLOPT_POST, 1);
+ }
+ // else (only POST_DATA_FROMFILE_PUT): do HTTP PUT.
+
+ struct curl_httppost *post = NULL;
+ struct curl_httppost *last = NULL;
+ FILE *data_file = NULL;
+ FILE *body_stream = NULL;
+ struct curl_slist *httpheader_list = NULL;
+
+ // Supply data...
+ if (data_size == POST_DATA_FROMFILE
+ || data_size == POST_DATA_FROMFILE_PUT
+ ) {
// ...from a file
data_file = fopen(data, "r");
if (!data_file)
-//FIXME:
- perror_msg_and_die("Can't open '%s'", data);
+ {
+ perror_msg("Can't open '%s'", data);
+ goto ret; // return -1
+ }
+
xcurl_easy_setopt_ptr(handle, CURLOPT_READDATA, data_file);
// Want to use custom read function
xcurl_easy_setopt_ptr(handle, CURLOPT_READFUNCTION, (const void*)fread_with_reporting);
- // Without this, curl would send "Content-Length: -1"
- // servers don't like that: "413 Request Entity Too Large"
fseeko(data_file, 0, SEEK_END);
off_t sz = ftello(data_file);
fseeko(data_file, 0, SEEK_SET);
- xcurl_easy_setopt_off_t(handle, CURLOPT_POSTFIELDSIZE_LARGE, sz);
- } else if (data_size == POST_DATA_FROMFILE_AS_FORM_DATA) {
+ if (data_size == POST_DATA_FROMFILE)
+ {
+ // Without this, curl would send "Content-Length: -1"
+ // servers don't like that: "413 Request Entity Too Large"
+ xcurl_easy_setopt_off_t(handle, CURLOPT_POSTFIELDSIZE_LARGE, sz);
+ }
+ else
+ {
+ xcurl_easy_setopt_long(handle, CURLOPT_UPLOAD, 1);
+ xcurl_easy_setopt_off_t(handle, CURLOPT_INFILESIZE_LARGE, sz);
+ }
+ }
+ else if (data_size == POST_DATA_FROMFILE_AS_FORM_DATA)
+ {
// ...from a file, in multipart/formdata format
const char *basename = strrchr(data, '/');
if (basename) basename++;
@@ -385,8 +410,10 @@ post(post_state_t *state,
#else
data_file = fopen(data, "r");
if (!data_file)
-//FIXME:
- perror_msg_and_die("Can't open '%s'", data);
+ {
+ perror_msg("Can't open '%s'", data);
+ goto ret; // return -1
+ }
// Want to use custom read function
xcurl_easy_setopt_ptr(handle, CURLOPT_READFUNCTION, (const void*)fread_with_reporting);
// Need to know file size
@@ -408,10 +435,12 @@ post(post_state_t *state,
//FIXME:
error_msg_and_die("out of memory or read error (curl_formadd error code: %d)", (int)curlform_err);
xcurl_easy_setopt_ptr(handle, CURLOPT_HTTPPOST, post);
- } else if (data_size == POST_DATA_STRING_AS_FORM_DATA) {
+ }
+ else if (data_size == POST_DATA_STRING_AS_FORM_DATA)
+ {
CURLFORMcode curlform_err = curl_formadd(&post, &last,
CURLFORM_PTRNAME, "file", // element name
- // curl bug - missing filename
+ // curl bug - missing filename
// http://curl.haxx.se/mail/lib-2011-07/0176.html
// https://github.com/bagder/curl/commit/45d883d
// fixed in curl-7.22.0~144
@@ -426,8 +455,10 @@ post(post_state_t *state,
if (curlform_err != 0)
error_msg_and_die("out of memory or read error (curl_formadd error code: %d)", (int)curlform_err);
xcurl_easy_setopt_ptr(handle, CURLOPT_HTTPPOST, post);
- } else {
- // .. from a blob in memory
+ }
+ else
+ {
+ // ...from a blob in memory
xcurl_easy_setopt_ptr(handle, CURLOPT_POSTFIELDS, data);
// note1: if data_size == POST_DATA_STRING == -1, curl will use strlen(data)
xcurl_easy_setopt_long(handle, CURLOPT_POSTFIELDSIZE, data_size);
@@ -436,8 +467,6 @@ post(post_state_t *state,
// Not a big problem: memory blobs >4GB are very unlikely.
}
- struct curl_slist *httpheader_list = NULL;
-
// Override "Content-Type:"
if (data_size != POST_DATA_FROMFILE_AS_FORM_DATA
&& data_size != POST_DATA_STRING_AS_FORM_DATA)
@@ -491,7 +520,6 @@ post(post_state_t *state,
xcurl_easy_setopt_ptr(handle, CURLOPT_HEADERFUNCTION, (void*)save_headers);
xcurl_easy_setopt_ptr(handle, CURLOPT_WRITEHEADER, state);
}
- FILE* body_stream = NULL;
if (state->flags & POST_WANT_BODY)
{
body_stream = open_memstream(&state->body, &state->body_size);
@@ -507,7 +535,7 @@ post(post_state_t *state,
// This is the place where everything happens.
// Here errors are not limited to "out of memory", can't just die.
- curl_err = curl_easy_perform_with_proxy(handle, url);
+ state->curl_result = curl_err = curl_easy_perform_with_proxy(handle, url);
if (curl_err)
{
VERB2 log("curl_easy_perform: error %d", (int)curl_err);
@@ -528,7 +556,7 @@ post(post_state_t *state,
curl_err = curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code);
die_if_curl_error(curl_err);
state->http_resp_code = response_code;
- VERB3 log("after curl_easy_perform: http code %ld body:'%s'", response_code, state->body);
+ VERB3 log("after curl_easy_perform: response_code:%ld body:'%s'", response_code, state->body);
ret:
curl_easy_cleanup(handle);
diff -x '*.po' -d -urpN libreport.3/src/plugins/reporter-upload.c libreport.4/src/plugins/reporter-upload.c
--- libreport.3/src/plugins/reporter-upload.c 2013-02-07 14:31:32.000000000 +0100
+++ libreport.4/src/plugins/reporter-upload.c 2013-03-21 17:29:31.246399895 +0100
@@ -20,57 +20,21 @@
#include "libreport_curl.h"
#include "internal_libreport.h"
-//TODO: use this for better logging
-#if 0
-/* "read local data from a file" callback */
-static size_t fread_with_reporting(void *ptr, size_t size, size_t nmemb, void *userdata)
-{
- static time_t last_t; // hack
-
- FILE *fp = (FILE*)userdata;
- time_t t = time(NULL);
-
- // Report current file position every 16 seconds
- if (!(t & 0xf) && last_t != t)
- {
- last_t = t;
- off_t cur_pos = ftello(fp);
- fseeko(fp, 0, SEEK_END);
- off_t sz = ftello(fp);
- fseeko(fp, cur_pos, SEEK_SET);
- log(_("Uploaded: %llu of %llu kbytes"),
- (unsigned long long)cur_pos / 1024,
- (unsigned long long)sz / 1024);
- }
-
- return fread(ptr, size, nmemb, fp);
-}
-#endif
-
static int send_file(const char *url, const char *filename)
{
- FILE *fp = fopen(filename, "r");
- if (!fp)
- {
- perror_msg("Can't open '%s'", filename);
- return 1;
- }
-
/* we don't want to print the whole url as it may contain password
* rhbz#856960
* there can be '@' in the login or password so let's try to find the
* first '@' from the end
*/
const char *clean_url = strrchr(url, '@');
- if (clean_url != NULL)
+ if (clean_url)
clean_url++;
else
clean_url = url;
log(_("Sending %s to %s"), filename, clean_url);
- off_t st_size = fstat_st_size_or_die(fileno(fp));
-
char *whole_url;
unsigned len = strlen(url);
if (len > 0 && url[len-1] == '/')
@@ -78,45 +42,41 @@ static int send_file(const char *url, co
else
whole_url = xstrdup(url);
- CURL *curl = curl_easy_init();
- if (!curl)
+ post_state_t *state = new_post_state(POST_WANT_ERROR_MSG);
+ post(state,
+ whole_url,
+ /*content_type:*/ "???",
+ /*additional_headers:*/ NULL,
+ /*data:*/ filename,
+ POST_DATA_FROMFILE_PUT
+ );
+ free(whole_url);
+
+ int error = (state->curl_result != 0);
+ if (error)
{
- error_msg_and_die("Can't create curl handle");
+ if (state->curl_error_msg)
+ error_msg("Error while uploading: '%s'", state->curl_error_msg);
+ else
+ /* for example, when source file can't be opened */
+ error_msg("Error while uploading");
}
- /* Buffer[CURL_ERROR_SIZE] curl stores human readable error messages in.
- * This may be more helpful than just return code from curl_easy_perform.
- * curl will need it until curl_easy_cleanup. */
- char curl_err_msg[CURL_ERROR_SIZE];
- curl_err_msg[0] = '\0';
- curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_msg);
- /* enable uploading */
- curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
- /* specify target */
- curl_easy_setopt(curl, CURLOPT_URL, whole_url);
- /* FILE handle: passed to the default callback, it will fread() it */
- curl_easy_setopt(curl, CURLOPT_READDATA, fp);
- curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)st_size);
-
- /* everything is done here; result 0 means success */
- CURLcode result = curl_easy_perform_with_proxy(curl, whole_url);
- free(whole_url);
- fclose(fp);
- if (result != 0)
- error_msg("Error while uploading: '%s'", curl_easy_strerror(result));
else
+ {
/* This ends up a "reporting status message" in abrtd */
log(_("Successfully sent %s to %s"), filename, clean_url);
+ }
- curl_easy_cleanup(curl);
+ free_post_state(state);
- return result;
+ return error;
}
static int create_and_upload_archive(
const char *dump_dir_name,
map_string_h *settings)
{
- int result = 0;
+ int result = 1; /* error */
pid_t child;
TAR* tar = NULL;
@@ -125,7 +85,7 @@ static int create_and_upload_archive(
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
- exit(1); /* error msg is already logged by dd_opendir */
+ xfunc_die(); /* error msg is already logged by dd_opendir */
/* Gzipping e.g. 0.5gig coredump takes a while. Let client know what we are doing */
log(_("Compressing data"));
@@ -228,6 +188,7 @@ static int create_and_upload_archive(
}
else
{
+ result = 0; /* success */
log(_("Archive is created: '%s'"), tempfile);
free(tempfile);
tempfile = NULL;
11 years, 2 months
[ABRT PATCH] abrtd: recreate Dump Location directory if it is delete
by Jakub Filak
- add inotify watch IN_DELETE_SELF and IN_MOVE_SELF and as a rection on
these events create the dump location and restore inotify watch.
- closes #624
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/daemon/abrtd.c | 82 +++++++++++++++++++++++++++++++++---------------------
1 file changed, 50 insertions(+), 32 deletions(-)
diff --git a/src/daemon/abrtd.c b/src/daemon/abrtd.c
index f6d3965..7bc93ef 100644
--- a/src/daemon/abrtd.c
+++ b/src/daemon/abrtd.c
@@ -41,6 +41,7 @@
/* Maximum number of simultaneously opened client connections. */
#define MAX_CLIENT_COUNT 10
+#define IN_DUMP_LOCATION_FLAGS (IN_CREATE | IN_MOVED_TO | IN_DELETE_SELF | IN_MOVE_SELF)
/* Daemon initializes, then sits in glib main loop, waiting for events.
* Events can be:
@@ -490,6 +491,36 @@ static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition condition,
/* Removing will also drop the last ref to this gio, closing/freeing it */
}
+static void ensure_writable_dir(const char *dir, mode_t mode, const char *user)
+{
+ struct stat sb;
+
+ if (mkdir(dir, mode) != 0 && errno != EEXIST)
+ perror_msg_and_die("Can't create '%s'", dir);
+ if (stat(dir, &sb) != 0 || !S_ISDIR(sb.st_mode))
+ error_msg_and_die("'%s' is not a directory", dir);
+
+ struct passwd *pw = getpwnam(user);
+ if (!pw)
+ perror_msg_and_die("Can't find user '%s'", user);
+
+ if ((sb.st_uid != pw->pw_uid || sb.st_gid != pw->pw_gid) && lchown(dir, pw->pw_uid, pw->pw_gid) != 0)
+ perror_msg_and_die("Can't set owner %u:%u on '%s'", (unsigned int)pw->pw_uid, (unsigned int)pw->pw_gid, dir);
+ if ((sb.st_mode & 07777) != mode && chmod(dir, mode) != 0)
+ perror_msg_and_die("Can't set mode %o on '%s'", mode, dir);
+}
+
+static void sanitize_dump_dir_rights()
+{
+ /* We can't allow everyone to create dumps: otherwise users can flood
+ * us with thousands of bogus or malicious dumps */
+ /* 07000 bits are setuid, setgit, and sticky, and they must be unset */
+ /* 00777 bits are usual "rwxrwxrwx" access rights */
+ ensure_writable_dir(g_settings_dump_location, 0755, "abrt");
+ /* temp dir */
+ ensure_writable_dir(VAR_RUN"/abrt", 0755, "root");
+}
+
/* Inotify handler */
static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
@@ -594,6 +625,22 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin
continue;
}
+ if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF)
+ {
+ /* HACK: we expect that we watch deletion only of 'g_settings_dump_location'
+ * but this handler is used for 'g_settings_sWatchCrashdumpArchiveDir' too
+ */
+ log("Recreating deleted dump location '%s'", g_settings_dump_location);
+ inotify_rm_watch(g_io_channel_unix_get_fd(gio), event->wd);
+ sanitize_dump_dir_rights();
+ if (inotify_add_watch(g_io_channel_unix_get_fd(gio), g_settings_dump_location, IN_DUMP_LOCATION_FLAGS) < 0)
+ {
+ perror_msg_and_die("inotify_add_watch failed on recreated '%s'", g_settings_dump_location);
+ }
+
+ continue;
+ }
+
if (!(event->mask & IN_ISDIR) || !name)
{
/* ignore lock files and such */
@@ -810,36 +857,6 @@ static void start_syslog_logging()
putenv((char*)"ABRT_SYSLOG=1");
}
-static void ensure_writable_dir(const char *dir, mode_t mode, const char *user)
-{
- struct stat sb;
-
- if (mkdir(dir, mode) != 0 && errno != EEXIST)
- perror_msg_and_die("Can't create '%s'", dir);
- if (stat(dir, &sb) != 0 || !S_ISDIR(sb.st_mode))
- error_msg_and_die("'%s' is not a directory", dir);
-
- struct passwd *pw = getpwnam(user);
- if (!pw)
- perror_msg_and_die("Can't find user '%s'", user);
-
- if ((sb.st_uid != pw->pw_uid || sb.st_gid != pw->pw_gid) && lchown(dir, pw->pw_uid, pw->pw_gid) != 0)
- perror_msg_and_die("Can't set owner %u:%u on '%s'", (unsigned int)pw->pw_uid, (unsigned int)pw->pw_gid, dir);
- if ((sb.st_mode & 07777) != mode && chmod(dir, mode) != 0)
- perror_msg_and_die("Can't set mode %o on '%s'", mode, dir);
-}
-
-static void sanitize_dump_dir_rights()
-{
- /* We can't allow everyone to create dumps: otherwise users can flood
- * us with thousands of bogus or malicious dumps */
- /* 07000 bits are setuid, setgit, and sticky, and they must be unset */
- /* 00777 bits are usual "rwxrwxrwx" access rights */
- ensure_writable_dir(g_settings_dump_location, 0755, "abrt");
- /* temp dir */
- ensure_writable_dir(VAR_RUN"/abrt", 0755, "root");
-}
-
int main(int argc, char** argv)
{
/* I18n */
@@ -966,8 +983,9 @@ int main(int argc, char** argv)
perror_msg_and_die("inotify_init failed");
close_on_exec_on(inotify_fd);
- /* Watching 'g_settings_dump_location' for new files... */
- if (inotify_add_watch(inotify_fd, g_settings_dump_location, IN_CREATE | IN_MOVED_TO) < 0)
+ /* Watching 'g_settings_dump_location' for new files and delete self
+ * because hooks expects that the dump location exists if abrtd is runnig*/
+ if (inotify_add_watch(inotify_fd, g_settings_dump_location, IN_DUMP_LOCATION_FLAGS) < 0)
{
perror_msg("inotify_add_watch failed on '%s'", g_settings_dump_location);
goto init_error;
--
1.8.1.4
11 years, 2 months
[LIBREPORT PATCH] report-gtk: update excluded elements check boxes before emergency analysis event
by Jakub Filak
- closes #141
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/gui-wizard-gtk/wizard.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index 5f4db93..7c00d3c 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -1204,9 +1204,9 @@ static void append_item_to_ls_details(gpointer name, gpointer value, gpointer da
}
/* Based on selected reporter, update item checkboxes */
-static void update_ls_details_checkboxes(void)
+static void update_ls_details_checkboxes(const char *event_name)
{
- event_config_t *cfg = get_event_config(g_event_selected);
+ event_config_t *cfg = get_event_config(event_name);
//log("%s: event:'%s', cfg:'%p'", __func__, g_event_selected, cfg);
GHashTableIter iter;
char *name;
@@ -1684,6 +1684,7 @@ static void on_btn_failed_cb(GtkButton *button)
gtk_expander_set_expanded(g_exp_report_log, TRUE);
clear_warnings();
+ update_ls_details_checkboxes(EMERGENCY_ANALYSIS_EVENT_NAME);
setup_and_start_event_run(EMERGENCY_ANALYSIS_EVENT_NAME);
/* single shot button -> hide after click */
@@ -2446,7 +2447,7 @@ static void on_page_prepare(GtkNotebook *assistant, GtkWidget *page, gpointer us
if (pages[PAGENO_REVIEW_DATA].page_widget == page)
{
gtk_widget_set_sensitive(g_btn_next, gtk_toggle_button_get_active(g_tb_approve_bt));
- update_ls_details_checkboxes();
+ update_ls_details_checkboxes(g_event_selected);
}
}
@@ -2888,7 +2889,7 @@ static void on_btn_add_file(GtkButton *button)
problem_data_reload_from_dump_dir();
update_gui_state_from_problem_data(/* don't update selected event */ 0);
/* Set flags for the new item */
- update_ls_details_checkboxes();
+ update_ls_details_checkboxes(g_event_selected);
}
}
free(new_name);
--
1.8.1.4
11 years, 2 months