summaryrefslogtreecommitdiffstats
path: root/seaudit
diff options
context:
space:
mode:
Diffstat (limited to 'seaudit')
-rw-r--r--seaudit/Makefile.am90
-rw-r--r--seaudit/dot_seaudit.in12
-rw-r--r--seaudit/filter_view.c1127
-rw-r--r--seaudit/filter_view.h42
-rw-r--r--seaudit/message_view.c1341
-rw-r--r--seaudit/message_view.h178
-rw-r--r--seaudit/modify_view.c327
-rw-r--r--seaudit/modify_view.h41
-rw-r--r--seaudit/open_policy_window.c469
-rw-r--r--seaudit/open_policy_window.h46
-rw-r--r--seaudit/policy_components_view.c373
-rw-r--r--seaudit/policy_components_view.h56
-rw-r--r--seaudit/policy_view.c573
-rw-r--r--seaudit/policy_view.h77
-rw-r--r--seaudit/preferences.c585
-rw-r--r--seaudit/preferences.h274
-rw-r--r--seaudit/preferences_view.c310
-rw-r--r--seaudit/preferences_view.h44
-rw-r--r--seaudit/progress.c200
-rw-r--r--seaudit/progress.h139
-rw-r--r--seaudit/report_window.c261
-rw-r--r--seaudit/report_window.h41
-rw-r--r--seaudit/seaudit-report-group.conf3
-rw-r--r--seaudit/seaudit-report-service.conf5
-rw-r--r--seaudit/seaudit-report-service.in24
-rw-r--r--seaudit/seaudit-report.c246
-rw-r--r--seaudit/seaudit-report.conf62
-rw-r--r--seaudit/seaudit-report.css178
-rw-r--r--seaudit/seaudit-small.pngbin0 -> 336 bytes
-rw-r--r--seaudit/seaudit.c418
-rw-r--r--seaudit/seaudit.glade7713
-rw-r--r--seaudit/seaudit.gladep7
-rw-r--r--seaudit/seaudit.h231
-rw-r--r--seaudit/seaudit.pngbin0 -> 992 bytes
-rw-r--r--seaudit/seaudit.xcfbin0 -> 7462 bytes
-rw-r--r--seaudit/seaudit_help.txt293
-rw-r--r--seaudit/toplevel.c1179
-rw-r--r--seaudit/toplevel.h263
-rw-r--r--seaudit/utilgui.c134
-rw-r--r--seaudit/utilgui.h106
40 files changed, 17468 insertions, 0 deletions
diff --git a/seaudit/Makefile.am b/seaudit/Makefile.am
new file mode 100644
index 0000000..1987c99
--- /dev/null
+++ b/seaudit/Makefile.am
@@ -0,0 +1,90 @@
+setoolsdir = @setoolsdir@
+bin_PROGRAMS = seaudit-report
+sbin_PROGRAMS = seaudit
+
+AM_CFLAGS = @DEBUGCFLAGS@ @WARNCFLAGS@ @PROFILECFLAGS@ @SELINUX_CFLAGS@ \
+ @QPOL_CFLAGS@ @APOL_CFLAGS@ @SEAUDIT_CFLAGS@
+
+seaudit_CFLAGS = $(AM_CFLAGS) \
+ @GTK_CFLAGS@ @PIXBUF_CFLAGS@ @GLADE_CFLAGS@ @GTHREAD_CFLAGS@
+seaudit_report_CFLAGS = $(AM_CFLAGS) -DAPOL_INSTALL_DIR='"${setoolsdir}"'
+
+AM_LDFLAGS = @DEBUGLDFLAGS@ @WARNLDFLAGS@ @PROFILELDFLAGS@
+
+# need the -rdynamic flag below - glade uses dlopen() upon seaudit callbacks
+seaudit_LDFLAGS = $(AM_LDFLAGS) \
+ @GTK_LIBS@ @PIXBUF_LIBS@ @GLADE_LIBS@ @GTHREAD_LIBS@ -rdynamic
+
+LDADD = @SELINUX_LIB_FLAG@ @SEAUDIT_LIB_FLAG@ @APOL_LIB_FLAG@ @QPOL_LIB_FLAG@
+
+dist_setools_DATA = \
+ seaudit.glade \
+ seaudit_help.txt \
+ seaudit-report.conf \
+ seaudit-report.css \
+ seaudit.png seaudit-small.png
+
+nodist_setools_DATA = \
+ dot_seaudit \
+ seaudit-report-service
+
+seaudit_SOURCES = \
+ filter_view.c filter_view.h \
+ message_view.c message_view.h \
+ modify_view.c modify_view.h \
+ open_policy_window.c open_policy_window.h \
+ policy_components_view.c policy_components_view.h \
+ policy_view.c policy_view.h \
+ preferences.c preferences.h \
+ preferences_view.c preferences_view.h \
+ progress.c progress.h \
+ report_window.c report_window.h \
+ seaudit.c seaudit.h \
+ toplevel.c toplevel.h \
+ utilgui.c utilgui.h
+
+seaudit_DEPENDENCIES = $(top_builddir)/libseaudit/src/libseaudit.so \
+ $(top_builddir)/libapol/src/libapol.so \
+ $(top_builddir)/libqpol/src/libqpol.so
+
+dot_seaudit: dot_seaudit.in Makefile
+ sed -e 's|\@setoolsdir\@|$(setoolsdir)|g' $< > $@
+
+seaudit_report_SOURCES = seaudit-report.c
+seaudit_report_DEPENDENCIES = $(top_builddir)/libseaudit/src/libseaudit.so \
+ $(top_builddir)/libapol/src/libapol.so \
+ $(top_builddir)/libqpol/src/libqpol.so
+
+logwatch = $(DESTDIR)/etc/logwatch
+LOGWATCH_GROUP = $(logwatch)/conf/logfiles
+LOGWATCH_SERVICE = $(logwatch)/conf/services
+LOGWATCH_FILTER = $(logwatch)/scripts/services
+
+dist_noinst_DATA = dot_seaudit.in \
+ seaudit-report-group.conf \
+ seaudit-report-service.conf \
+ seaudit-report-service.in
+
+seaudit-report-service: seaudit-report-service.in Makefile
+ sed -e 's|\@bindir\@|$(bindir)|g' $< > $@
+
+install-logwatch: $(dist_noinst_DATA) seaudit-report-service
+ mkdir -p -- $(LOGWATCH_GROUP)
+ install -m 644 seaudit-report-group.conf $(LOGWATCH_GROUP)
+ mkdir -p -- $(LOGWATCH_SERVICE)
+ install -m 644 seaudit-report-service.conf $(LOGWATCH_SERVICE)
+ mkdir -p -- $(LOGWATCH_FILTER)
+ install -m 755 seaudit-report-service $(LOGWATCH_FILTER)
+
+$(top_builddir)/libapol/src/libapol.so:
+ $(MAKE) -C $(top_builddir)/libapol/src $(notdir $@)
+
+$(top_builddir)/libqpol/src/libqpol.so:
+ $(MAKE) -C $(top_builddir)/libqpol/src $(notdir $@)
+
+$(top_builddir)/libsefs/src/libsefs.so:
+ $(MAKE) -C $(top_builddir)/libsefs/src $(notdir $@)
+
+.PHONY: install-logwatch
+
+CLEANFILES = dot_seaudit seaudit-report-service
diff --git a/seaudit/dot_seaudit.in b/seaudit/dot_seaudit.in
new file mode 100644
index 0000000..2852819
--- /dev/null
+++ b/seaudit/dot_seaudit.in
@@ -0,0 +1,12 @@
+# Configuration file for seaudit - an audit log tool for Security
+# Enhanced Linux. This file is auto-generated by the build system.
+
+DEFAULT_LOG_FILE /var/log/audit/audit.log
+DEFAULT_POLICY_FILE
+DEFAULT_REPORT_CONFIG_FILE @setoolsdir@/seaudit-report.conf
+DEFAULT_REPORT_CSS_FILE @setoolsdir@/seaudit-report.css
+RECENT_LOG_FILES
+RECENT_POLICY_FILES
+LOG_COLUMNS_HIDDEN path_field:src_usr_field:src_role_field:tgt_usr_field:tgt_role_field:inode_field:pid_field:
+REAL_TIME_LOG_MONITORING 0
+REAL_TIME_UPDATE_INTERVAL 1000
diff --git a/seaudit/filter_view.c b/seaudit/filter_view.c
new file mode 100644
index 0000000..e0d8745
--- /dev/null
+++ b/seaudit/filter_view.c
@@ -0,0 +1,1127 @@
+/**
+ * @file
+ * Run the dialog to modify a particular filter.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "filter_view.h"
+#include "policy_components_view.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <apol/policy-query.h>
+#include <apol/mls-query.h>
+#include <apol/util.h>
+#include <glade/glade.h>
+
+struct context_item
+{
+ GtkButton *button;
+ GtkEntry *entry;
+ apol_vector_t *items;
+};
+
+struct date_item
+{
+ GtkComboBox *month;
+ GtkSpinButton *day, *hour, *minute, *second;
+ GtkFrame *frame;
+};
+
+struct filter_view
+{
+ toplevel_t *top;
+ seaudit_filter_t *filter;
+ GladeXML *xml;
+
+ GtkDialog *dialog;
+
+ GtkEntry *name_entry;
+ GtkComboBox *match_combo;
+
+ struct context_item suser, srole, stype, smls_lvl, smls_clr, tuser, trole, ttype, tmls_lvl, tmls_clr, obj_class;
+ GtkButton *context_clear_button;
+
+ GtkEntry *ipaddr_entry, *port_entry, *netif_entry, *exe_entry, *path_entry, *host_entry, *comm_entry;
+ GtkComboBox *message_combo;
+ GtkButton *other_clear_button;
+
+ GtkRadioButton *date_none_radio, *date_before_radio, *date_after_radio, *date_between_radio;
+ struct date_item dates[2];
+ GtkTextBuffer *description_buffer;
+};
+
+/**
+ * Initialize pointers to widgets on the context tab.
+ */
+static void filter_view_init_widgets_context(struct filter_view *fv)
+{
+ fv->suser.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSUserButton"));
+ fv->srole.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSRoleButton"));
+ fv->stype.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSTypeButton"));
+ fv->smls_lvl.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSMLSLVLButton"));
+ fv->smls_clr.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewSMLSCLRButton"));
+ fv->tuser.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTUserButton"));
+ fv->trole.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTRoleButton"));
+ fv->ttype.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTTypeButton"));
+ fv->tmls_lvl.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTMLSLVLButton"));
+ fv->tmls_clr.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewTMLSCLRButton"));
+ fv->obj_class.button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewClassButton"));
+ assert(fv->suser.button != NULL && fv->srole.button != NULL && fv->stype.button != NULL && fv->smls_lvl.button != NULL && fv->smls_clr.button != NULL &&
+ fv->tuser.button != NULL && fv->trole.button != NULL && fv->ttype.button != NULL && fv->tmls_lvl.button != NULL && fv->tmls_clr.button != NULL && fv->obj_class.button != NULL);
+
+ fv->suser.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSUserEntry"));
+ fv->srole.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSRoleEntry"));
+ fv->stype.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSTypeEntry"));
+ fv->smls_lvl.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSMLSLVLEntry"));
+ fv->smls_clr.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewSMLSCLREntry"));
+ fv->tuser.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTUserEntry"));
+ fv->trole.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTRoleEntry"));
+ fv->ttype.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTTypeEntry"));
+ fv->tmls_lvl.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTMLSLVLEntry"));
+ fv->tmls_clr.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewTMLSCLREntry"));
+ fv->obj_class.entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewClassEntry"));
+ assert(fv->suser.entry != NULL && fv->srole.entry != NULL && fv->stype.entry != NULL && fv->smls_lvl.entry != NULL && fv->smls_clr.entry != NULL &&
+ fv->tuser.entry != NULL && fv->trole.entry != NULL && fv->ttype.entry != NULL && fv->tmls_lvl.entry != NULL && fv->tmls_clr.entry != NULL && fv->obj_class.entry != NULL);
+ g_object_set_data(G_OBJECT(fv->suser.entry), "data", &fv->suser);
+ g_object_set_data(G_OBJECT(fv->srole.entry), "data", &fv->srole);
+ g_object_set_data(G_OBJECT(fv->stype.entry), "data", &fv->stype);
+ g_object_set_data(G_OBJECT(fv->smls_lvl.entry), "data", &fv->smls_lvl);
+ g_object_set_data(G_OBJECT(fv->smls_clr.entry), "data", &fv->smls_clr);
+ g_object_set_data(G_OBJECT(fv->tuser.entry), "data", &fv->tuser);
+ g_object_set_data(G_OBJECT(fv->trole.entry), "data", &fv->trole);
+ g_object_set_data(G_OBJECT(fv->ttype.entry), "data", &fv->ttype);
+ g_object_set_data(G_OBJECT(fv->tmls_lvl.entry), "data", &fv->tmls_lvl);
+ g_object_set_data(G_OBJECT(fv->tmls_clr.entry), "data", &fv->tmls_clr);
+ g_object_set_data(G_OBJECT(fv->obj_class.entry), "data", &fv->obj_class);
+
+ fv->context_clear_button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewContextClearButton"));
+ assert(fv->context_clear_button != NULL);
+}
+
+/**
+ * Initialize pointers to widgets on the other tab.
+ */
+static void filter_view_init_widgets_other(struct filter_view *fv)
+{
+ fv->ipaddr_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewIPAddrEntry"));
+ fv->port_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewPortEntry"));
+ fv->netif_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewNetIfEntry"));
+ assert(fv->ipaddr_entry != NULL && fv->port_entry != NULL && fv->netif_entry != NULL);
+
+ fv->exe_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewExeEntry"));
+ fv->path_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewPathEntry"));
+ fv->host_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewHostEntry"));
+ fv->comm_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewCommEntry"));
+ assert(fv->exe_entry != NULL && fv->path_entry != NULL && fv->host_entry != NULL && fv->comm_entry != NULL);
+
+ fv->message_combo = GTK_COMBO_BOX(glade_xml_get_widget(fv->xml, "FilterViewMessageCombo"));
+ assert(fv->message_combo != NULL);
+
+ fv->other_clear_button = GTK_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewOtherClearButton"));
+ assert(fv->other_clear_button != NULL);
+}
+
+/**
+ * Initialize pointers to widgets on the date tab.
+ */
+static void filter_view_init_widgets_date(struct filter_view *fv)
+{
+ static const char *widgets[2][6] = {
+ {"FilterViewDateStartFrame", "FilterViewDateStartMonthCombo", "FilterViewDateStartDaySpin",
+ "FilterViewDateStartHourSpin", "FilterViewDateStartMinuteSpin", "FilterViewDateStartSecondSpin"},
+ {"FilterViewDateEndFrame", "FilterViewDateEndMonthCombo", "FilterViewDateEndDaySpin",
+ "FilterViewDateEndHourSpin", "FilterViewDateEndMinuteSpin", "FilterViewDateEndSecondSpin"}
+ };
+ size_t i;
+ fv->date_none_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateNoneRadio"));
+ fv->date_before_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateBeforeRadio"));
+ fv->date_after_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateAfterRadio"));
+ fv->date_between_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(fv->xml, "FilterViewDateBetweenRadio"));
+ assert(fv->date_none_radio != NULL && fv->date_before_radio != NULL && fv->date_after_radio != NULL
+ && fv->date_between_radio != NULL);
+
+ for (i = 0; i < 2; i++) {
+ fv->dates[i].frame = GTK_FRAME(glade_xml_get_widget(fv->xml, widgets[i][0]));
+ fv->dates[i].month = GTK_COMBO_BOX(glade_xml_get_widget(fv->xml, widgets[i][1]));
+ fv->dates[i].day = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][2]));
+ fv->dates[i].hour = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][3]));
+ fv->dates[i].minute = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][4]));
+ fv->dates[i].second = GTK_SPIN_BUTTON(glade_xml_get_widget(fv->xml, widgets[i][5]));
+ assert(fv->dates[i].frame != NULL && fv->dates[i].month != NULL && fv->dates[i].day != NULL &&
+ fv->dates[i].hour != NULL && fv->dates[i].minute != NULL && fv->dates[i].second != NULL);
+ }
+}
+
+static void filter_view_init_widgets(struct filter_view *fv, GtkWindow * parent)
+{
+ GtkTextView *description_view;
+
+ fv->dialog = GTK_DIALOG(glade_xml_get_widget(fv->xml, "FilterWindow"));
+ assert(fv->dialog != NULL);
+ gtk_window_set_transient_for(GTK_WINDOW(fv->dialog), parent);
+
+ fv->name_entry = GTK_ENTRY(glade_xml_get_widget(fv->xml, "FilterViewNameEntry"));
+ fv->match_combo = GTK_COMBO_BOX(glade_xml_get_widget(fv->xml, "FilterViewMatchCombo"));
+ assert(fv->name_entry != NULL && fv->match_combo);
+
+ filter_view_init_widgets_context(fv);
+ filter_view_init_widgets_other(fv);
+ filter_view_init_widgets_date(fv);
+
+ fv->description_buffer = gtk_text_buffer_new(NULL);
+#ifdef GTK_2_8
+ g_object_ref_sink(fv->description_buffer);
+#endif
+ description_view = GTK_TEXT_VIEW(glade_xml_get_widget(fv->xml, "FilterViewDescView"));
+ assert(description_view != NULL);
+ gtk_text_view_set_buffer(description_view, fv->description_buffer);
+}
+
+/********** functions that copies filter object values to widget **********/
+
+/**
+ * Get the vector of strings from the accessor function. If the
+ * vector is NULL then clear the entry's contents; otherwies set the
+ * entry to the vector of strings, comma delimited.
+ */
+static void filter_view_context_item_to_entry(struct filter_view *fv, struct context_item *item)
+{
+ if (item->items == NULL) {
+ gtk_entry_set_text(item->entry, "");
+ } else {
+ GString *s = g_string_new("");
+ size_t i;
+ for (i = 0; i < apol_vector_get_size(item->items); i++) {
+ char *t = apol_vector_get_element(item->items, i);
+ if (i > 0) {
+ g_string_append(s, ", ");
+ }
+ g_string_append(s, t);
+ }
+ gtk_entry_set_text(item->entry, s->str);
+ g_string_free(s, TRUE);
+ }
+}
+
+static void filter_view_context_items_to_entries(struct filter_view *fv)
+{
+ filter_view_context_item_to_entry(fv, &fv->suser);
+ filter_view_context_item_to_entry(fv, &fv->srole);
+ filter_view_context_item_to_entry(fv, &fv->stype);
+ filter_view_context_item_to_entry(fv, &fv->smls_lvl);
+ filter_view_context_item_to_entry(fv, &fv->smls_clr);
+ filter_view_context_item_to_entry(fv, &fv->tuser);
+ filter_view_context_item_to_entry(fv, &fv->trole);
+ filter_view_context_item_to_entry(fv, &fv->ttype);
+ filter_view_context_item_to_entry(fv, &fv->tmls_lvl);
+ filter_view_context_item_to_entry(fv, &fv->tmls_clr);
+ filter_view_context_item_to_entry(fv, &fv->obj_class);
+}
+
+static void filter_view_init_context(struct filter_view *fv)
+{
+ const apol_vector_t *v;
+ v = seaudit_filter_get_source_user(fv->filter);
+ if (v != NULL && (fv->suser.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_source_role(fv->filter);
+ if (v != NULL && (fv->srole.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_source_type(fv->filter);
+ if (v != NULL && (fv->stype.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_source_mls_lvl(fv->filter);
+ if (v != NULL && (fv->smls_lvl.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_source_mls_clr(fv->filter);
+ if (v != NULL && (fv->smls_clr.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+
+ v = seaudit_filter_get_target_user(fv->filter);
+ if (v != NULL && (fv->tuser.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_target_role(fv->filter);
+ if (v != NULL && (fv->trole.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_target_type(fv->filter);
+ if (v != NULL && (fv->ttype.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_target_mls_lvl(fv->filter);
+ if (v != NULL && (fv->tmls_lvl.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ v = seaudit_filter_get_target_mls_clr(fv->filter);
+ if (v != NULL && (fv->tmls_clr.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+
+ v = seaudit_filter_get_target_class(fv->filter);
+ if (v != NULL && (fv->obj_class.items = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
+ toplevel_ERR(fv->top, "Error initializing context tab: %s", strerror(errno));
+ return;
+ }
+ filter_view_context_items_to_entries(fv);
+}
+
+/**
+ * Get the string from the accessor function. If the returned string
+ * is NULL then clear the entry's contents; otherwise set the entry to
+ * the returned string.
+ */
+static void filter_view_init_entry(struct filter_view *fv, const char *(*accessor) (const seaudit_filter_t *), GtkEntry * entry)
+{
+ const char *s = accessor(fv->filter);
+ if (s == NULL) {
+ s = "";
+ }
+ gtk_entry_set_text(entry, s);
+}
+
+static void filter_view_init_other(struct filter_view *fv)
+{
+ char s[32];
+ filter_view_init_entry(fv, seaudit_filter_get_anyaddr, fv->ipaddr_entry);
+ if (seaudit_filter_get_anyport(fv->filter) <= 0) {
+ s[0] = '\0';
+ } else {
+ snprintf(s, 32, "%d", seaudit_filter_get_anyport(fv->filter));
+ }
+ gtk_entry_set_text(fv->port_entry, s);
+ filter_view_init_entry(fv, seaudit_filter_get_netif, fv->netif_entry);
+ filter_view_init_entry(fv, seaudit_filter_get_executable, fv->exe_entry);
+ filter_view_init_entry(fv, seaudit_filter_get_path, fv->path_entry);
+ filter_view_init_entry(fv, seaudit_filter_get_host, fv->host_entry);
+ filter_view_init_entry(fv, seaudit_filter_get_command, fv->comm_entry);
+ switch (seaudit_filter_get_message_type(fv->filter)) {
+ case SEAUDIT_AVC_DENIED:
+ gtk_combo_box_set_active(fv->message_combo, 1);
+ break;
+ case SEAUDIT_AVC_GRANTED:
+ gtk_combo_box_set_active(fv->message_combo, 2);
+ break;
+ default:
+ gtk_combo_box_set_active(fv->message_combo, 0);
+ }
+}
+
+static void filter_view_init_date(struct filter_view *fv)
+{
+ const struct tm *start, *end;
+ struct tm values[2];
+ int has_value[2] = { 0, 0 };
+ seaudit_filter_date_match_e match;
+ size_t i;
+
+ seaudit_filter_get_date(fv->filter, &start, &end, &match);
+ if (start == NULL && end == NULL) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_none_radio), TRUE);
+ } else {
+ if (match == SEAUDIT_FILTER_DATE_MATCH_BEFORE) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_before_radio), TRUE);
+ } else if (match == SEAUDIT_FILTER_DATE_MATCH_AFTER) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_after_radio), TRUE);
+ }
+ memcpy(values + 0, start, sizeof(values[0]));
+ has_value[0] = 1;
+ }
+ if (match == SEAUDIT_FILTER_DATE_MATCH_BETWEEN) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fv->date_between_radio), TRUE);
+ memcpy(values + 1, end, sizeof(values[1]));
+ has_value[1] = 1;
+ }
+ for (i = 0; i < 2; i++) {
+ if (has_value[i]) {
+ gtk_combo_box_set_active(fv->dates[i].month, values[i].tm_mon);
+ gtk_spin_button_set_value(fv->dates[i].day, values[i].tm_mday);
+ gtk_spin_button_set_value(fv->dates[i].hour, values[i].tm_hour);
+ gtk_spin_button_set_value(fv->dates[i].minute, values[i].tm_min);
+ gtk_spin_button_set_value(fv->dates[i].second, values[i].tm_sec);
+ } else {
+ gtk_combo_box_set_active(fv->dates[i].month, 0);
+ }
+ }
+}
+
+/**
+ * Copy values from seaudit filter object to GTK+ widgets.
+ */
+static void filter_view_init_dialog(struct filter_view *fv)
+{
+ const char *name = seaudit_filter_get_name(fv->filter);
+ const char *desc = seaudit_filter_get_description(fv->filter);;
+ if (name == NULL) {
+ name = "Untitled";
+ }
+ gtk_entry_set_text(fv->name_entry, name);
+ gtk_combo_box_set_active(fv->match_combo, seaudit_filter_get_match(fv->filter));
+
+ filter_view_init_context(fv);
+ filter_view_init_other(fv);
+ filter_view_init_date(fv);
+
+ if (desc == NULL) {
+ desc = "";
+ }
+ gtk_text_buffer_set_text(fv->description_buffer, desc, -1);
+}
+
+/********** functions that copies widget values to filter object **********/
+
+static void filter_view_apply_context(struct filter_view *fv)
+{
+ if (seaudit_filter_set_source_user(fv->filter, fv->suser.items) < 0 ||
+ seaudit_filter_set_source_role(fv->filter, fv->srole.items) < 0 ||
+ seaudit_filter_set_source_type(fv->filter, fv->stype.items) < 0 ||
+ seaudit_filter_set_source_mls_lvl(fv->filter, fv->smls_lvl.items) < 0 ||
+ seaudit_filter_set_source_mls_clr(fv->filter, fv->smls_clr.items) < 0 ||
+ seaudit_filter_set_target_user(fv->filter, fv->tuser.items) < 0 ||
+ seaudit_filter_set_target_role(fv->filter, fv->trole.items) < 0 ||
+ seaudit_filter_set_target_type(fv->filter, fv->ttype.items) < 0 ||
+ seaudit_filter_set_target_mls_lvl(fv->filter, fv->tmls_lvl.items) < 0 ||
+ seaudit_filter_set_target_mls_clr(fv->filter, fv->tmls_clr.items) < 0 ||
+ seaudit_filter_set_target_class(fv->filter, fv->obj_class.items) < 0) {
+ toplevel_ERR(fv->top, "Error applying context: %s", strerror(errno));
+ }
+}
+
+/**
+ * If the entry is empty, then call the modifier function passing NULL
+ * as the second parameter. Else call the function with the entry's
+ * contents.
+ */
+static void filter_view_apply_entry(struct filter_view *fv, GtkEntry * entry, int (*modifier) (seaudit_filter_t *, const char *))
+{
+ const char *s = gtk_entry_get_text(entry);
+ if (strcmp(s, "") == 0) {
+ s = NULL;
+ }
+ if (modifier(fv->filter, s) < 0) {
+ toplevel_ERR(fv->top, "Error apply settings: %s", strerror(errno));
+ }
+}
+
+/**
+ * Copy values from the other tab to filter object.
+ */
+static void filter_view_apply_other(struct filter_view *fv)
+{
+ const char *s;
+ int port = 0;
+ seaudit_avc_message_type_e message_type;
+
+ filter_view_apply_entry(fv, fv->ipaddr_entry, seaudit_filter_set_anyaddr);
+ s = gtk_entry_get_text(fv->port_entry);
+ if (strcmp(s, "") != 0) {
+ port = atoi(s);
+ }
+ if (seaudit_filter_set_anyport(fv->filter, port) < 0) {
+ toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno));
+ return;
+ }
+ filter_view_apply_entry(fv, fv->netif_entry, seaudit_filter_set_netif);
+ filter_view_apply_entry(fv, fv->exe_entry, seaudit_filter_set_executable);
+ filter_view_apply_entry(fv, fv->path_entry, seaudit_filter_set_path);
+ filter_view_apply_entry(fv, fv->host_entry, seaudit_filter_set_host);
+ filter_view_apply_entry(fv, fv->comm_entry, seaudit_filter_set_command);
+ switch (gtk_combo_box_get_active(fv->message_combo)) {
+ case 1:
+ message_type = SEAUDIT_AVC_DENIED;
+ break;
+ case 2:
+ message_type = SEAUDIT_AVC_GRANTED;
+ break;
+ default:
+ message_type = SEAUDIT_AVC_UNKNOWN;
+ }
+ if (seaudit_filter_set_message_type(fv->filter, message_type) < 0) {
+ toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno));
+ return;
+ }
+}
+
+/**
+ * Returns which date radio button is active:
+ *
+ * -1 if date_none_radio,
+ * else something that can be casted to seaudit_filter_date_match
+ */
+static int filter_view_get_date_match(struct filter_view *fv)
+{
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fv->date_before_radio))) {
+ return SEAUDIT_FILTER_DATE_MATCH_BEFORE;
+ }
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fv->date_after_radio))) {
+ return SEAUDIT_FILTER_DATE_MATCH_AFTER;
+ }
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fv->date_between_radio))) {
+ return SEAUDIT_FILTER_DATE_MATCH_BETWEEN;
+ }
+ return -1;
+}
+
+/**
+ * Copy values from date tab to the seaudit filter object.
+ */
+static void filter_view_apply_date(struct filter_view *fv)
+{
+ struct tm tm[2];
+ size_t i;
+ int date_match = filter_view_get_date_match(fv);
+ memset(&tm, 0, sizeof(tm));
+ for (i = 0; i < 2; i++) {
+ tm[i].tm_mon = gtk_combo_box_get_active(fv->dates[i].month);
+ tm[i].tm_mday = gtk_spin_button_get_value_as_int(fv->dates[i].day);
+ tm[i].tm_year = 0;
+ tm[i].tm_hour = gtk_spin_button_get_value_as_int(fv->dates[i].hour);
+ tm[i].tm_min = gtk_spin_button_get_value_as_int(fv->dates[i].minute);
+ tm[i].tm_sec = gtk_spin_button_get_value_as_int(fv->dates[i].second);
+ }
+ if (date_match < 0) {
+ seaudit_filter_set_date(fv->filter, NULL, NULL, 0);
+ } else {
+ seaudit_filter_set_date(fv->filter, tm + 0, tm + 1, (seaudit_filter_date_match_e) date_match);
+ }
+}
+
+/**
+ * Copy values from GTK+ widgets to the seaudit filter object.
+ */
+static void filter_view_apply(struct filter_view *fv)
+{
+ GtkTextIter start, end;
+ char *s;
+ seaudit_filter_match_e match = SEAUDIT_FILTER_MATCH_ALL;
+
+ filter_view_apply_entry(fv, fv->name_entry, seaudit_filter_set_name);
+ if (gtk_combo_box_get_active(fv->match_combo) == 1) {
+ match = SEAUDIT_FILTER_MATCH_ANY;
+ }
+ if (seaudit_filter_set_match(fv->filter, match) < 0) {
+ toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno));
+ }
+
+ filter_view_apply_context(fv);
+ filter_view_apply_other(fv);
+ filter_view_apply_date(fv);
+
+ gtk_text_buffer_get_bounds(fv->description_buffer, &start, &end);
+ s = gtk_text_buffer_get_text(fv->description_buffer, &start, &end, FALSE);
+ if (strcmp(s, "") == 0) {
+ free(s);
+ s = NULL;
+ }
+ if (seaudit_filter_set_description(fv->filter, s) < 0) {
+ toplevel_ERR(fv->top, "Error setting filter: %s", strerror(errno));
+ }
+ free(s);
+}
+
+/******************** signal handlers for dialog ********************/
+
+/**
+ * Return a list of users within the currently loaded policy, sorted
+ * alphabetically. If there is no policy loaded then return NULL.
+ */
+static apol_vector_t *filter_view_get_policy_users(struct filter_view *fv)
+{
+ apol_vector_t *policy_items = NULL, *v = NULL;
+ apol_policy_t *p = toplevel_get_policy(fv->top);
+ size_t i;
+ if (p == NULL) {
+ return NULL;
+ }
+ if (apol_user_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) {
+ toplevel_ERR(fv->top, "Error getting a list of policy users: %s", strerror(errno));
+ apol_vector_destroy(&policy_items);
+ return NULL;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ const qpol_user_t *e = apol_vector_get_element(v, i);
+ const char *name;
+ qpol_user_get_name(apol_policy_get_qpol(p), e, &name);
+ if (apol_vector_append(policy_items, (void *)name) < 0) {
+ toplevel_ERR(fv->top, "Error getting a list of policy users: %s", strerror(errno));
+ apol_vector_destroy(&v);
+ apol_vector_destroy(&policy_items);
+ }
+ }
+ apol_vector_destroy(&v);
+ apol_vector_sort(policy_items, apol_str_strcmp, NULL);
+ return policy_items;
+}
+
+/**
+ * Return a list of roles within the currently loaded policy, sorted
+ * alphabetically. If there is no policy loaded then return NULL.
+ */
+static apol_vector_t *filter_view_get_policy_roles(struct filter_view *fv)
+{
+ apol_vector_t *policy_items = NULL, *v = NULL;
+ apol_policy_t *p = toplevel_get_policy(fv->top);
+ size_t i;
+ if (p == NULL) {
+ return NULL;
+ }
+ if (apol_role_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) {
+ toplevel_ERR(fv->top, "Error getting a list of policy roles: %s", strerror(errno));
+ apol_vector_destroy(&policy_items);
+ return NULL;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ const qpol_role_t *e = apol_vector_get_element(v, i);
+ const char *name;
+ qpol_role_get_name(apol_policy_get_qpol(p), e, &name);
+ if (apol_vector_append(policy_items, (void *)name) < 0) {
+ toplevel_ERR(fv->top, "Error getting a list of policy roles: %s", strerror(errno));
+ apol_vector_destroy(&v);
+ apol_vector_destroy(&policy_items);
+ }
+ }
+ apol_vector_destroy(&v);
+ apol_vector_sort(policy_items, apol_str_strcmp, NULL);
+ return policy_items;
+}
+
+/**
+ * Return a list of types (not attributes nor aliases) within the
+ * currently loaded policy, sorted alphabetically. If there is no
+ * policy loaded then return NULL.
+ */
+static apol_vector_t *filter_view_get_policy_types(struct filter_view *fv)
+{
+ apol_vector_t *policy_items = NULL, *v = NULL;
+ apol_policy_t *p = toplevel_get_policy(fv->top);
+ size_t i;
+ if (p == NULL) {
+ return NULL;
+ }
+ if (apol_type_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) {
+ toplevel_ERR(fv->top, "Error getting a list of policy types: %s", strerror(errno));
+ apol_vector_destroy(&policy_items);
+ return NULL;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ const qpol_type_t *e = apol_vector_get_element(v, i);
+ const char *name;
+ qpol_type_get_name(apol_policy_get_qpol(p), e, &name);
+ if (apol_vector_append(policy_items, (void *)name) < 0) {
+ toplevel_ERR(fv->top, "Error getting a list of policy types: %s", strerror(errno));
+ apol_vector_destroy(&v);
+ apol_vector_destroy(&policy_items);
+ }
+ }
+ apol_vector_destroy(&v);
+ apol_vector_sort(policy_items, apol_str_strcmp, NULL);
+ return policy_items;
+}
+
+/**
+ * Return a list of mls levels/clearance (not aliases) within the
+ * currently loaded policy, sorted alphabetically. If there is no
+ * policy loaded then return NULL.
+ */
+static apol_vector_t *filter_view_get_policy_mls_lvl(struct filter_view *fv)
+{
+ apol_vector_t *policy_items = NULL, *v = NULL;
+ apol_policy_t *p = toplevel_get_policy(fv->top);
+ const qpol_iterator_t **cats = NULL;
+
+ size_t i;
+
+ if (p == NULL) {
+ return NULL;
+ }
+
+ if (apol_level_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(&free)) == NULL) {
+ toplevel_ERR(fv->top, "Error getting a list of policy mls levels: %s", strerror(errno));
+ apol_vector_destroy(&policy_items);
+ return NULL;
+ }
+
+ for (i = 0; i < apol_vector_get_size(v); i++)
+ {
+ const char *name = NULL;
+ const char *mls = malloc(100*sizeof(mls));
+
+ const char *cat_name1 = NULL, *cat_name2 = NULL;
+ uint32_t *cat_val1, *cat_val2;
+ const char *cat_low = NULL;
+ const char *cat_high = NULL;
+ bool isrange = false, isrange_end = false, isempty = true;
+ size_t k;
+ qpol_cat_t *c = NULL;
+ const qpol_level_t *e = apol_vector_get_element(v, i);
+
+ qpol_level_get_name(apol_policy_get_qpol(p), e, &name);
+ strcpy(mls, name);
+ if (qpol_level_get_cat_iter(apol_policy_get_qpol(p), e, &cats) < 0){
+ toplevel_ERR(fv->top, "Error getting categories for level: %s", strerror(errno));
+ qpol_iterator_destroy(&cats);
+ }
+ qpol_iterator_get_size(cats, &k);
+
+ if (k > 0){
+ strcat(mls, ":");
+ isempty = true;
+ }
+ if (qpol_iterator_get_item(cats, &c) < 0){
+ toplevel_ERR(fv->top, "Error getting category: %s", strerror(errno));
+ qpol_iterator_destroy(&cats);
+ }
+ qpol_cat_get_value(apol_policy_get_qpol(p), c, &cat_val1);
+ qpol_cat_get_name(apol_policy_get_qpol(p), c, &cat_name1);
+ isrange = false;
+ isrange_end = false;
+
+ for (; !qpol_iterator_end(cats); qpol_iterator_next(cats))
+ {
+ if (qpol_iterator_get_item(cats, &c) < 0){
+ toplevel_ERR(fv->top, "Error getting category: %s", strerror(errno));
+ qpol_iterator_destroy(&cats);
+ }
+ qpol_cat_get_value(apol_policy_get_qpol(p), c, &cat_val2);
+ qpol_cat_get_name(apol_policy_get_qpol(p), c, &cat_name2);
+ if (((int)cat_val2 == ((int)cat_val1 + 1)) && (isrange == false))
+ {
+ cat_low = cat_name1;
+ strcat(mls, cat_low);
+ strcat(mls, ".");
+ isrange = true;
+ isempty = false;
+ }
+ if ((isrange == true) && ((int)cat_val2 == ((int)cat_val1 + 1)))
+ {
+ cat_high = cat_name2;
+ }
+ else if ((isrange == true) && ((int)cat_val2 != ((int)cat_val1 + 1)))
+ {
+ cat_high = cat_name1;
+ isrange_end = true;
+ strcat(mls, cat_high);
+ isempty=false;
+ }
+ if ((isrange == false) && (isempty == false) && ((int)cat_val2 != ((int)cat_val1 + 1)))
+ {
+ strcat(mls, ",");
+ strcat(mls, cat_name2);
+ }
+ cat_val1 = cat_val2;
+ cat_name1 = cat_name2;
+
+ }
+ if ((isrange == true) && (isrange_end == false))
+ {
+ strcat(mls, cat_high);
+ }
+ if (apol_vector_append(policy_items, (void *)mls) < 0) {
+ toplevel_ERR(fv->top, "Error getting a list of policy mls levels: %s", strerror(errno));
+ apol_vector_destroy(&v);
+ apol_vector_destroy(&policy_items);
+ }
+ }
+
+ apol_vector_destroy(&v);
+ qpol_iterator_destroy(&cats);
+ apol_vector_sort(policy_items, apol_str_strcmp, NULL);
+ return policy_items;
+}
+
+/**
+ * Return a list of object classeswithin the currently loaded policy,
+ * sorted alphabetically. If there is no policy loaded then return
+ * NULL.
+ */
+static apol_vector_t *filter_view_get_policy_classes(struct filter_view *fv)
+{
+ apol_vector_t *policy_items = NULL, *v = NULL;
+ apol_policy_t *p = toplevel_get_policy(fv->top);
+ size_t i;
+ if (p == NULL) {
+ return NULL;
+ }
+ if (apol_class_get_by_query(p, NULL, &v) < 0 || (policy_items = apol_vector_create(NULL)) == NULL) {
+ toplevel_ERR(fv->top, "Error getting a list of policy classes: %s", strerror(errno));
+ apol_vector_destroy(&policy_items);
+ return NULL;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ const qpol_class_t *e = apol_vector_get_element(v, i);
+ const char *name;
+ qpol_class_get_name(apol_policy_get_qpol(p), e, &name);
+ if (apol_vector_append(policy_items, (void *)name) < 0) {
+ toplevel_ERR(fv->top, "Error getting a list of policy classes: %s", strerror(errno));
+ apol_vector_destroy(&v);
+ apol_vector_destroy(&policy_items);
+ }
+ }
+ apol_vector_destroy(&v);
+ apol_vector_sort(policy_items, apol_str_strcmp, NULL);
+ return policy_items;
+}
+
+static void filter_view_on_suser_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_users(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_users(fv);
+ fv->suser.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source User Items", log_items, policy_items,
+ fv->suser.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->suser);
+}
+
+static void filter_view_on_srole_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_roles(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_roles(fv);
+ fv->srole.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source Role Items", log_items, policy_items,
+ fv->srole.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->srole);
+}
+
+static void filter_view_on_stype_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_types(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_types(fv);
+ fv->stype.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source Type Items", log_items, policy_items,
+ fv->stype.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->stype);
+}
+
+static void filter_view_on_smls_lvl_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+
+ apol_vector_t *log_items = toplevel_get_log_mls_lvl(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv);
+ fv->smls_lvl.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source MLS Level Items", log_items, policy_items,
+ fv->smls_lvl.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->smls_lvl);
+}
+
+static void filter_view_on_smls_clr_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_mls_clr(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv);
+ fv->smls_clr.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Source MLS Clearance Items", log_items, policy_items,
+ fv->smls_clr.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->smls_clr);
+}
+
+static void filter_view_on_tuser_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_users(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_users(fv);
+ fv->tuser.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target User Items", log_items, policy_items,
+ fv->tuser.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->tuser);
+}
+
+static void filter_view_on_trole_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_roles(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_roles(fv);
+ fv->trole.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target Role Items", log_items, policy_items,
+ fv->trole.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->trole);
+}
+
+static void filter_view_on_ttype_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_types(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_types(fv);
+ fv->ttype.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target Type Items", log_items, policy_items,
+ fv->ttype.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->ttype);
+}
+
+static void filter_view_on_tmls_lvl_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_mls_lvl(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv);
+ fv->tmls_lvl.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target MLS Level Items", log_items, policy_items,
+ fv->tmls_lvl.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->tmls_lvl);
+}
+
+static void filter_view_on_tmls_clr_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_mls_clr(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_mls_lvl(fv);
+ fv->tmls_clr.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Target MLS Clearance Items", log_items, policy_items,
+ fv->tmls_clr.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->tmls_clr);
+}
+
+static void filter_view_on_class_context_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ apol_vector_t *log_items = toplevel_get_log_classes(fv->top);
+ apol_vector_t *policy_items = filter_view_get_policy_classes(fv);
+ fv->obj_class.items =
+ policy_components_view_run(fv->top, GTK_WINDOW(fv->dialog), "Object Class Items", log_items, policy_items,
+ fv->obj_class.items);
+ apol_vector_destroy(&log_items);
+ apol_vector_destroy(&policy_items);
+ filter_view_context_item_to_entry(fv, &fv->obj_class);
+}
+
+/**
+ * Whenever the user finished manually editing a context entry,
+ * convert the entry's string into the underlying vector.
+ */
+static gboolean filter_view_on_entry_focus_out(GtkWidget * widget, GdkEventFocus * event
+ __attribute__ ((unused)), gpointer user_data)
+{
+ struct context_item *item = g_object_get_data(G_OBJECT(widget), "data");
+ struct filter_view *fv = (struct filter_view *)user_data;
+ gchar **strs = g_strsplit(gtk_entry_get_text(GTK_ENTRY(widget)), ",", -1);
+ gchar *s;
+ size_t i = 0;
+ char *t;
+ apol_vector_t *new_v = NULL;
+ while (1) {
+ s = strs[i++];
+ if (s == NULL) {
+ break;
+ }
+ if (new_v == NULL && (new_v = apol_vector_create(free)) == NULL) {
+ toplevel_ERR(fv->top, "Could not interpret entry contents: %s", strerror(errno));
+ break;
+ }
+ if ((t = strdup(s)) == NULL) {
+ toplevel_ERR(fv->top, "Could not interpret entry contents: %s", strerror(errno));
+ free(t);
+ break;
+ }
+ apol_str_trim(t);
+ if (apol_vector_append(new_v, t) < 0) {
+ toplevel_ERR(fv->top, "Could not interpret entry contents: %s", strerror(errno));
+ free(t);
+ break;
+ }
+ }
+ g_strfreev(strs);
+ apol_vector_destroy(&item->items);
+ item->items = new_v;
+ filter_view_context_item_to_entry(fv, item);
+ return FALSE;
+}
+
+static void filter_view_destroy_context_vectors(struct filter_view *fv)
+{
+ apol_vector_destroy(&fv->suser.items);
+ apol_vector_destroy(&fv->srole.items);
+ apol_vector_destroy(&fv->stype.items);
+ apol_vector_destroy(&fv->smls_lvl.items);
+ apol_vector_destroy(&fv->smls_clr.items);
+ apol_vector_destroy(&fv->tuser.items);
+ apol_vector_destroy(&fv->trole.items);
+ apol_vector_destroy(&fv->ttype.items);
+ apol_vector_destroy(&fv->tmls_lvl.items);
+ apol_vector_destroy(&fv->tmls_clr.items);
+ apol_vector_destroy(&fv->obj_class.items);
+}
+
+static void filter_view_on_context_clear_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ filter_view_destroy_context_vectors(fv);
+ filter_view_context_items_to_entries(fv);
+}
+
+static void filter_view_init_context_signals(struct filter_view *fv)
+{
+ g_signal_connect(fv->suser.button, "clicked", G_CALLBACK(filter_view_on_suser_context_click), fv);
+ g_signal_connect(fv->suser.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->srole.button, "clicked", G_CALLBACK(filter_view_on_srole_context_click), fv);
+ g_signal_connect(fv->srole.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->stype.button, "clicked", G_CALLBACK(filter_view_on_stype_context_click), fv);
+ g_signal_connect(fv->stype.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->smls_lvl.button, "clicked", G_CALLBACK(filter_view_on_smls_lvl_context_click), fv);
+ g_signal_connect(fv->smls_lvl.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->smls_clr.button, "clicked", G_CALLBACK(filter_view_on_smls_clr_context_click), fv);
+ g_signal_connect(fv->smls_clr.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->tuser.button, "clicked", G_CALLBACK(filter_view_on_tuser_context_click), fv);
+ g_signal_connect(fv->tuser.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->trole.button, "clicked", G_CALLBACK(filter_view_on_trole_context_click), fv);
+ g_signal_connect(fv->trole.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->ttype.button, "clicked", G_CALLBACK(filter_view_on_ttype_context_click), fv);
+ g_signal_connect(fv->ttype.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->tmls_lvl.button, "clicked", G_CALLBACK(filter_view_on_tmls_lvl_context_click), fv);
+ g_signal_connect(fv->tmls_lvl.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->tmls_clr.button, "clicked", G_CALLBACK(filter_view_on_tmls_clr_context_click), fv);
+ g_signal_connect(fv->tmls_clr.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->obj_class.button, "clicked", G_CALLBACK(filter_view_on_class_context_click), fv);
+ g_signal_connect(fv->obj_class.entry, "focus_out_event", G_CALLBACK(filter_view_on_entry_focus_out), fv);
+ g_signal_connect(fv->context_clear_button, "clicked", G_CALLBACK(filter_view_on_context_clear_click), fv);
+}
+
+static void filter_view_on_other_clear_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ gtk_entry_set_text(fv->ipaddr_entry, "");
+ gtk_entry_set_text(fv->port_entry, "");
+ gtk_entry_set_text(fv->netif_entry, "");
+ gtk_entry_set_text(fv->exe_entry, "");
+ gtk_entry_set_text(fv->path_entry, "");
+ gtk_entry_set_text(fv->host_entry, "");
+ gtk_entry_set_text(fv->comm_entry, "");
+ gtk_combo_box_set_active(fv->message_combo, 0);
+}
+
+static void filter_view_on_date_toggle(GtkToggleButton * widget, gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ int match;
+ /* clicking on the radio buttons emit two toggle signals, one for
+ * the original button and one for the new one. thus only need to
+ * handle half of all signals */
+ if (!gtk_toggle_button_get_active(widget)) {
+ return;
+ }
+ match = filter_view_get_date_match(fv);
+ gtk_widget_set_sensitive(GTK_WIDGET(fv->dates[0].frame), (match != -1));
+ gtk_widget_set_sensitive(GTK_WIDGET(fv->dates[1].frame), (match == SEAUDIT_FILTER_DATE_MATCH_BETWEEN));
+}
+
+/* Given the year and the month set the spin button to have the
+ correct number of days for that month */
+static void filter_view_date_set_number_days(int month, GtkSpinButton * button)
+{
+ static const int days[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ int cur_day;
+ /* get the current day because set_range moves the current day
+ * by the difference minus 1 day. e.g., going from jan 20 to
+ * february the day would automatically become 18 */
+ cur_day = gtk_spin_button_get_value_as_int(button);
+ gtk_spin_button_set_range(button, 1, days[month]);
+ /* return to current day, or to the max value allowed in range */
+ gtk_spin_button_set_value(button, cur_day);
+}
+
+static void filter_view_on_month0_change(GtkComboBox * widget, gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ filter_view_date_set_number_days(gtk_combo_box_get_active(widget), fv->dates[0].day);
+}
+
+static void filter_view_on_month1_change(GtkComboBox * widget, gpointer user_data)
+{
+ struct filter_view *fv = (struct filter_view *)user_data;
+ filter_view_date_set_number_days(gtk_combo_box_get_active(widget), fv->dates[1].day);
+}
+
+static void filter_view_init_signals(struct filter_view *fv)
+{
+ filter_view_init_context_signals(fv);
+ g_signal_connect(fv->other_clear_button, "clicked", G_CALLBACK(filter_view_on_other_clear_click), fv);
+ g_signal_connect(fv->date_none_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv);
+ g_signal_connect(fv->date_before_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv);
+ g_signal_connect(fv->date_after_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv);
+ g_signal_connect(fv->date_between_radio, "toggled", G_CALLBACK(filter_view_on_date_toggle), fv);
+ g_signal_connect(fv->dates[0].month, "changed", G_CALLBACK(filter_view_on_month0_change), fv);
+ g_signal_connect(fv->dates[1].month, "changed", G_CALLBACK(filter_view_on_month1_change), fv);
+}
+
+/******************** public function below ********************/
+
+void filter_view_run(seaudit_filter_t * filter, toplevel_t * top, GtkWindow * parent)
+{
+ struct filter_view fv;
+ gint response;
+
+ memset(&fv, 0, sizeof(fv));
+ fv.top = top;
+ fv.filter = filter;
+ fv.xml = glade_xml_new(toplevel_get_glade_xml(top), "FilterWindow", NULL);
+ filter_view_init_widgets(&fv, parent);
+ filter_view_init_signals(&fv);
+ filter_view_init_dialog(&fv);
+ do {
+ response = gtk_dialog_run(fv.dialog);
+ } while (response != GTK_RESPONSE_CLOSE);
+
+ filter_view_apply(&fv);
+ g_object_unref(fv.description_buffer);
+ gtk_widget_destroy(GTK_WIDGET(fv.dialog));
+ filter_view_destroy_context_vectors(&fv);
+}
diff --git a/seaudit/filter_view.h b/seaudit/filter_view.h
new file mode 100644
index 0000000..d94ece3
--- /dev/null
+++ b/seaudit/filter_view.h
@@ -0,0 +1,42 @@
+/**
+ * @file
+ * Dialog that allows the user to modify a particular filter.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FILTER_VIEW_H
+#define FILTER_VIEW_H
+
+#include "toplevel.h"
+#include <seaudit/filter.h>
+#include <gtk/gtk.h>
+
+/**
+ * Display and run a dialog that allows the user to modify a single
+ * filter.
+ *
+ * @param top Toplevel containing message view.
+ * @param view Message view to modify.
+ * @param parent Parent window upon which to center this dialog.
+ */
+void filter_view_run(seaudit_filter_t * filter, toplevel_t * top, GtkWindow * parent);
+
+#endif
diff --git a/seaudit/message_view.c b/seaudit/message_view.c
new file mode 100644
index 0000000..64d625f
--- /dev/null
+++ b/seaudit/message_view.c
@@ -0,0 +1,1341 @@
+/**
+ * @file
+ * Implementation of the view for a libseaudit model.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "message_view.h"
+#include "modify_view.h"
+#include "utilgui.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <apol/util.h>
+
+/**
+ * A custom model that implements the interfaces GtkTreeModel and
+ * GtkTreeSortable.
+ */
+typedef struct message_view_store
+{
+ /** this must be the first field, to satisfy glib */
+ GObject parent;
+ /** pointer to the store's controller */
+ message_view_t *view;
+ /** vector of seaudit_message_t, as returned by
+ * seaudit_model_get_messages() */
+ apol_vector_t *messages;
+ /** column that is currently being sorted; use OTHER_FIELD to
+ * indicate no sorting */
+ gint sort_field;
+ /** current sort direction, either 1 or ascending or -1 for
+ * descending */
+ int sort_dir;
+ /** unique integer for each instance of a model */
+ gint stamp;
+} message_view_store_t;
+
+typedef struct message_view_store_class
+{
+ GObjectClass parent_class;
+} message_view_store_class_t;
+
+static GType message_view_store_get_type(void);
+#define SEAUDIT_TYPE_MESSAGE_VIEW_STORE (message_view_store_get_type())
+#define SEAUDIT_IS_MESSAGE_VIEW_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SEAUDIT_TYPE_MESSAGE_VIEW_STORE))
+
+struct message_view
+{
+ seaudit_model_t *model;
+ toplevel_t *top;
+ /** toplevel of the view, currently a scrolled_window */
+ GtkWidget *w;
+ /** actual GTK+ tree view widget that displays the rows and
+ * columns of message data */
+ GtkTreeView *view;
+ /** GTK+ store that models messages within the tree */
+ message_view_store_t *store;
+ /** filename for when this view was saved (could be NULL) */
+ char *filename;
+ /** most recent filename for exported messages (could be NULL) */
+ char *export_filename;
+};
+
+typedef seaudit_sort_t *(*sort_generator_fn_t) (int direction);
+
+struct view_column_record
+{
+ preference_field_e id;
+ const char *name;
+ const char *sample_text;
+ sort_generator_fn_t sort;
+};
+
+static const struct view_column_record column_data[] = {
+ {HOST_FIELD, "Hostname", "Hostname", seaudit_sort_by_host},
+ {MESSAGE_FIELD, "Message", "Message", seaudit_sort_by_message_type},
+ {DATE_FIELD, "Date", "Jan 01 00:00:00", seaudit_sort_by_date},
+ {SUSER_FIELD, "Source\nUser", "Source", seaudit_sort_by_source_user},
+ {SROLE_FIELD, "Source\nRole", "Source", seaudit_sort_by_source_role},
+ {STYPE_FIELD, "Source\nType", "unlabeled_t", seaudit_sort_by_source_type},
+ {SMLS_LVL_FIELD, "Source\nMLS Level", "MLS Level", seaudit_sort_by_source_mls_lvl},
+ {SMLS_CLR_FIELD, "Source\nMLS Clearance", "MLS Clearance", seaudit_sort_by_source_mls_clr},
+ {TUSER_FIELD, "Target\nUser", "Target", seaudit_sort_by_target_user},
+ {TROLE_FIELD, "Target\nRole", "Target", seaudit_sort_by_target_role},
+ {TTYPE_FIELD, "Target\nType", "unlabeled_t", seaudit_sort_by_target_type},
+ {TMLS_LVL_FIELD, "Target\nMLS Level", "MLS Level", seaudit_sort_by_target_mls_lvl},
+ {TMLS_CLR_FIELD, "Target\nMLS Clearance", "MLS Clearance", seaudit_sort_by_target_mls_clr},
+ {OBJCLASS_FIELD, "Object\nClass", "Object", seaudit_sort_by_object_class},
+ {PERM_FIELD, "Permission", "Permission", seaudit_sort_by_permission},
+ {EXECUTABLE_FIELD, "Executable", "/usr/bin/cat", seaudit_sort_by_executable},
+ {COMMAND_FIELD, "Command", "/usr/bin/cat", seaudit_sort_by_command},
+ {NAME_FIELD, "Name", "iceweasel", seaudit_sort_by_name},
+ {PID_FIELD, "PID", "12345", seaudit_sort_by_pid},
+ {INODE_FIELD, "Inode", "123456", seaudit_sort_by_inode},
+ {PATH_FIELD, "Path", "/home/gburdell/foo", seaudit_sort_by_path},
+ {OTHER_FIELD, "Other", "Lorem ipsum dolor sit amet, consectetur", NULL}
+};
+
+static const size_t num_columns = sizeof(column_data) / sizeof(column_data[0]);
+
+/**
+ * (Re)sort the view based upon which column is clicked. If already
+ * sorting on this column, then reverse the sort direction. Also
+ * update the sort indicator for this column.
+ */
+static gboolean message_view_on_column_click(GtkTreeViewColumn * column, gpointer user_data)
+{
+ gint column_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column id"));
+ message_view_t *view = (message_view_t *) user_data;
+ int dir = 0;
+ seaudit_sort_t *sort;
+ GtkTreeViewColumn *prev_column;
+ if (column_id == view->store->sort_field) {
+ dir = view->store->sort_dir * -1;
+ } else {
+ dir = 1;
+ }
+
+ if ((sort = column_data[(preference_field_e) column_id].sort(dir)) == NULL) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ return TRUE;
+ }
+ seaudit_model_clear_sorts(view->model);
+ if (seaudit_model_append_sort(view->model, sort) < 0) {
+ seaudit_sort_destroy(&sort);
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ }
+ prev_column = gtk_tree_view_get_column(view->view, view->store->sort_field);
+ if (prev_column != NULL) {
+ gtk_tree_view_column_set_sort_indicator(prev_column, FALSE);
+ }
+ gtk_tree_view_column_set_sort_indicator(column, TRUE);
+ if (dir > 0) {
+ gtk_tree_view_column_set_sort_order(column, GTK_SORT_ASCENDING);
+ } else {
+ gtk_tree_view_column_set_sort_order(column, GTK_SORT_DESCENDING);
+ }
+
+ view->store->sort_field = column_id;
+ view->store->sort_dir = dir;
+ message_view_update_rows(view);
+ return TRUE;
+}
+
+/*************** implementation of a custom GtkTreeModel ***************/
+
+static GObjectClass *parent_class = NULL;
+
+static void message_view_store_init(message_view_store_t * m);
+static void message_view_store_class_init(message_view_store_class_t * c);
+static void message_view_store_tree_init(GtkTreeModelIface * iface);
+static void message_view_store_finalize(GObject * object);
+static GtkTreeModelFlags message_view_store_get_flags(GtkTreeModel * tree_model);
+static gint message_view_store_get_n_columns(GtkTreeModel * tree_model);
+static GType message_view_store_get_column_type(GtkTreeModel * tree_model, gint index);
+static gboolean message_view_store_get_iter(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreePath * path);
+static GtkTreePath *message_view_store_get_path(GtkTreeModel * tree_model, GtkTreeIter * iter);
+static void message_view_store_get_value(GtkTreeModel * tree_model, GtkTreeIter * iter, gint column, GValue * value);
+static gboolean message_view_store_iter_next(GtkTreeModel * tree_model, GtkTreeIter * iter);
+static gboolean message_view_store_iter_children(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent);
+static gboolean message_view_store_iter_has_child(GtkTreeModel * tree_model, GtkTreeIter * iter);
+static gint message_view_store_iter_n_children(GtkTreeModel * tree_model, GtkTreeIter * iter);
+static gboolean message_view_store_iter_nth_child(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent, gint n);
+static gboolean message_view_store_iter_parent(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * child);
+
+static GType message_view_store_get_type(void)
+{
+ static GType store_type = 0;
+ static const GTypeInfo store_info = {
+ sizeof(message_view_store_class_t),
+ NULL,
+ NULL,
+ (GClassInitFunc) message_view_store_class_init,
+ NULL,
+ NULL,
+ sizeof(message_view_store_t),
+ 0,
+ (GInstanceInitFunc) message_view_store_init
+ };
+ static const GInterfaceInfo tree_model_info = {
+ (GInterfaceInitFunc) message_view_store_tree_init,
+ NULL,
+ NULL
+ };
+
+ if (store_type)
+ return store_type;
+
+ store_type = g_type_register_static(G_TYPE_OBJECT, "message_view_store", &store_info, (GTypeFlags) 0);
+ g_type_add_interface_static(store_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
+ return store_type;
+}
+
+static void message_view_store_init(message_view_store_t * m)
+{
+ static int next_stamp = 0;
+ m->messages = NULL;
+ m->sort_field = OTHER_FIELD;
+ m->sort_dir = 1;
+ m->stamp = next_stamp++;
+}
+
+static void message_view_store_class_init(message_view_store_class_t * c)
+{
+ GObjectClass *object_class;
+ parent_class = g_type_class_peek_parent(c);
+ object_class = (GObjectClass *) c;
+ object_class->finalize = message_view_store_finalize;
+}
+
+static void message_view_store_tree_init(GtkTreeModelIface * iface)
+{
+ iface->get_flags = message_view_store_get_flags;
+ iface->get_n_columns = message_view_store_get_n_columns;
+ iface->get_column_type = message_view_store_get_column_type;
+ iface->get_iter = message_view_store_get_iter;
+ iface->get_path = message_view_store_get_path;
+ iface->get_value = message_view_store_get_value;
+ iface->iter_next = message_view_store_iter_next;
+ iface->iter_children = message_view_store_iter_children;
+ iface->iter_has_child = message_view_store_iter_has_child;
+ iface->iter_n_children = message_view_store_iter_n_children;
+ iface->iter_nth_child = message_view_store_iter_nth_child;
+ iface->iter_parent = message_view_store_iter_parent;
+}
+
+static void message_view_store_finalize(GObject * object)
+{
+ (*parent_class->finalize) (object);
+}
+
+static GtkTreeModelFlags message_view_store_get_flags(GtkTreeModel * tree_model)
+{
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), 0);
+ return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint message_view_store_get_n_columns(GtkTreeModel * tree_model __attribute__ ((unused)))
+{
+ return OTHER_FIELD + 1;
+}
+
+static GType message_view_store_get_column_type(GtkTreeModel * tree_model, gint idx __attribute__ ((unused)))
+{
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), G_TYPE_INVALID);
+ /* everything is a string for now */
+ return G_TYPE_STRING;
+}
+
+static gboolean message_view_store_get_iter(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreePath * path)
+{
+ gint i;
+ message_view_store_t *store = (message_view_store_t *) tree_model;
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE);
+ g_return_val_if_fail(gtk_tree_path_get_depth(path) > 0, FALSE);
+ i = gtk_tree_path_get_indices(path)[0];
+ if (i >= apol_vector_get_size(store->messages))
+ return FALSE;
+
+ iter->stamp = store->stamp;
+ iter->user_data = apol_vector_get_element(store->messages, i);
+ iter->user_data2 = GINT_TO_POINTER(i);
+ iter->user_data3 = store->view;
+ return TRUE;
+}
+
+static GtkTreePath *message_view_store_get_path(GtkTreeModel * tree_model, GtkTreeIter * iter)
+{
+ GtkTreePath *retval;
+ message_view_store_t *store = (message_view_store_t *) tree_model;
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), NULL);
+ g_return_val_if_fail(iter->stamp == store->stamp, NULL);
+ retval = gtk_tree_path_new();
+ gtk_tree_path_append_index(retval, GPOINTER_TO_INT(iter->user_data2));
+ return retval;
+}
+
+/**
+ * Given a string, check that it is UTF8 legal. If not, or if the
+ * string is NULL, then return an empty string. Otherwise return the
+ * original string.
+ */
+static void message_view_to_utf8(GValue * value, const char *s)
+{
+ if (s == NULL || !g_utf8_validate(s, -1, NULL)) {
+ g_value_set_string(value, "");
+ }
+ g_value_set_string(value, s);
+}
+
+static void message_view_store_get_value(GtkTreeModel * tree_model, GtkTreeIter * iter, gint column, GValue * value)
+{
+ message_view_store_t *store;
+ message_view_t *view;
+ seaudit_message_t *m;
+ seaudit_message_type_e type;
+ void *data;
+ seaudit_avc_message_t *avc;
+ g_return_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model));
+ g_return_if_fail(iter != NULL);
+ g_return_if_fail(column <= OTHER_FIELD);
+ g_value_init(value, G_TYPE_STRING);
+ store = (message_view_store_t *) tree_model;
+ view = store->view;
+ m = (seaudit_message_t *) iter->user_data;
+ data = seaudit_message_get_data(m, &type);
+ preference_field_e field = column;
+
+ switch (field) {
+ case HOST_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_message_get_host(m));
+ return;
+ }
+ case MESSAGE_FIELD:
+ {
+ char *message = "Invalid";
+ switch (type) {
+ case SEAUDIT_MESSAGE_TYPE_BOOL:
+ {
+ message = "Boolean";
+ break;
+ }
+ case SEAUDIT_MESSAGE_TYPE_LOAD:
+ {
+ message = "Load";
+ break;
+ }
+ case SEAUDIT_MESSAGE_TYPE_AVC:
+ {
+ avc = (seaudit_avc_message_t *) data;
+ seaudit_avc_message_type_e avc_type;
+ avc_type = seaudit_avc_message_get_message_type(avc);
+ switch (avc_type) {
+ case SEAUDIT_AVC_DENIED:
+ {
+ message = "Denied";
+ break;
+ }
+ case SEAUDIT_AVC_GRANTED:
+ {
+ message = "Granted";
+ break;
+ }
+ default:
+ {
+ /* should never get here */
+ toplevel_ERR(view->top, "Got an invalid AVC message type %d!", avc_type);
+ assert(0);
+ return;
+ }
+ }
+ break;
+ }
+ default:
+ {
+ /* should never get here */
+ toplevel_ERR(view->top, "Got an invalid message type %d!", type);
+ assert(0);
+ return;
+ }
+ }
+ message_view_to_utf8(value, message);
+ return;
+ }
+ case DATE_FIELD:
+ {
+ const struct tm *tm = seaudit_message_get_time(m);
+ char date[256];
+ /* check to see if we have been given a valid year, if
+ * so display, otherwise no year displayed */
+ if (tm->tm_year == 0) {
+ strftime(date, 256, "%b %d %H:%M:%S", tm);
+ } else {
+ strftime(date, 256, "%b %d %H:%M:%S %Y", tm);
+ }
+ message_view_to_utf8(value, date);
+ return;
+ }
+ case OTHER_FIELD:
+ {
+ char *other = seaudit_message_to_misc_string(m);;
+ if (other == NULL) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ return;
+ }
+ message_view_to_utf8(value, other);
+ free(other);
+ return;
+ }
+ default: /* FALLTHROUGH */
+ break;
+ }
+
+ if (type != SEAUDIT_MESSAGE_TYPE_AVC) {
+ /* the rest of the columns are blank for non-AVC
+ * messages */
+ message_view_to_utf8(value, "");
+ return;
+ }
+ avc = (seaudit_avc_message_t *) data;
+
+ switch (field) {
+ case SUSER_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_source_user(avc));
+ return;
+ }
+ case SROLE_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_source_role(avc));
+ return;
+ }
+ case STYPE_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_source_type(avc));
+ return;
+ }
+ case SMLS_LVL_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_source_mls_lvl(avc));
+ return;
+ }
+ case SMLS_CLR_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_source_mls_clr(avc));
+ return;
+ }
+ case TUSER_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_target_user(avc));
+ return;
+ }
+ case TROLE_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_target_role(avc));
+ return;
+ }
+ case TTYPE_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_target_type(avc));
+ return;
+ }
+ case TMLS_LVL_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_target_mls_lvl(avc));
+ return;
+ }
+ case TMLS_CLR_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_target_mls_clr(avc));
+ return;
+ }
+ case OBJCLASS_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_object_class(avc));
+ return;
+ }
+ case PERM_FIELD:
+ {
+ const apol_vector_t *perms = seaudit_avc_message_get_perm(avc);
+ char *perm = NULL;
+ size_t i, len = 0;
+ for (i = 0; perms != NULL && i < apol_vector_get_size(perms); i++) {
+ char *p = apol_vector_get_element(perms, i);
+ if (apol_str_appendf(&perm, &len, "%s%s", (i > 0 ? "," : ""), p) < 0) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ return;
+ }
+ }
+ message_view_to_utf8(value, perm);
+ free(perm);
+ return;
+ }
+ case EXECUTABLE_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_exe(avc));
+ return;
+ }
+ case COMMAND_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_comm(avc));
+ return;
+ }
+ case NAME_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_name(avc));
+ return;
+ }
+ case PID_FIELD:
+ {
+ char *s;
+ if (asprintf(&s, "%u", seaudit_avc_message_get_pid(avc)) < 0) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ return;
+ }
+ message_view_to_utf8(value, s);
+ free(s);
+ return;
+ }
+ case INODE_FIELD:
+ {
+ char *s;
+ if (asprintf(&s, "%lu", seaudit_avc_message_get_inode(avc)) < 0) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ return;
+ }
+ message_view_to_utf8(value, s);
+ free(s);
+ return;
+ }
+ case PATH_FIELD:
+ {
+ message_view_to_utf8(value, seaudit_avc_message_get_path(avc));
+ return;
+ }
+ default: /* FALLTHROUGH */
+ break;
+ }
+ /* should never get here */
+ toplevel_ERR(view->top, "Got an invalid column %d!", field);
+ assert(0);
+}
+
+static gboolean message_view_store_iter_next(GtkTreeModel * tree_model, GtkTreeIter * iter)
+{
+ gint i;
+ message_view_store_t *store = (message_view_store_t *) tree_model;
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE);
+ g_return_val_if_fail(iter->stamp == store->stamp, FALSE);
+ if (iter == NULL || iter->user_data == NULL)
+ return FALSE;
+ i = GPOINTER_TO_INT(iter->user_data2) + 1;
+ if (i >= apol_vector_get_size(store->messages)) {
+ return FALSE;
+ }
+ iter->user_data = apol_vector_get_element(store->messages, i);
+ iter->user_data2 = GINT_TO_POINTER(i);
+ iter->user_data3 = store->view;
+ return TRUE;
+}
+
+static gboolean message_view_store_iter_children(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent)
+{
+ message_view_store_t *store;
+ g_return_val_if_fail(parent == NULL || parent->user_data != NULL, FALSE);
+ if (parent)
+ return FALSE;
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE);
+
+ /* set iterator to first row, if possible */
+ store = (message_view_store_t *) tree_model;
+ if (store->messages == NULL || apol_vector_get_size(store->messages) == 0)
+ return FALSE;
+
+ iter->stamp = store->stamp;
+ iter->user_data = apol_vector_get_element(store->messages, 0);
+ iter->user_data2 = GINT_TO_POINTER(0);
+ iter->user_data3 = store->view;
+ return TRUE;
+}
+
+static gboolean message_view_store_iter_has_child(GtkTreeModel * tree_model __attribute__ ((unused)), GtkTreeIter * iter
+ __attribute__ ((unused)))
+{
+ return FALSE;
+}
+
+static gint message_view_store_iter_n_children(GtkTreeModel * tree_model, GtkTreeIter * iter)
+{
+ message_view_store_t *store;
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), -1);
+ g_return_val_if_fail(iter == NULL || iter->user_data != NULL, 0);
+ store = (message_view_store_t *) tree_model;
+ /* return the number of rows, if iterator is at the top;
+ * otherwise return 0 because this store is just a list */
+ if (iter != NULL || store->messages == NULL) {
+ return 0;
+ }
+ return apol_vector_get_size(store->messages);
+}
+
+static gboolean message_view_store_iter_nth_child(GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent, gint n)
+{
+ message_view_store_t *store;
+ g_return_val_if_fail(SEAUDIT_IS_MESSAGE_VIEW_STORE(tree_model), FALSE);
+ store = (message_view_store_t *) tree_model;
+ if (store->messages == NULL || parent != NULL) {
+ return FALSE;
+ }
+ if (n >= apol_vector_get_size(store->messages)) {
+ return FALSE;
+ }
+ iter->stamp = store->stamp;
+ iter->user_data = apol_vector_get_element(store->messages, n);
+ iter->user_data2 = GINT_TO_POINTER(n);
+ iter->user_data3 = store->view;
+ return TRUE;
+}
+
+static gboolean message_view_store_iter_parent(GtkTreeModel * tree_model __attribute__ ((unused)), GtkTreeIter * iter
+ __attribute__ ((unused)), GtkTreeIter * child __attribute__ ((unused)))
+{
+ return FALSE;
+}
+
+/*************** end of custom GtkTreeModel implementation ***************/
+
+/*************** message_view_messages_vector() callbacks ******************/
+#define LBACK 1
+#define LFORWARD 2
+#define LNOOP 255
+
+typedef struct _msg_user_data
+{
+ message_view_t *view;
+ apol_vector_t *messages;
+ GtkDialog *dialog;
+ GtkTextBuffer *buffer;
+ gint handle_id;
+} _msg_user_data_t;
+
+static void message_view_dialog_change(GtkTreeModel * tree_model,
+ GtkTreePath * path __attribute__ ((unused)),
+ GtkTreeIter * iter __attribute__ ((unused)), gpointer user_data)
+{
+ _msg_user_data_t *d = (_msg_user_data_t *) user_data;
+ /* Disconnect this signal handler after it fires. It's one
+ * shot, nothing should be able to bring the next and previous
+ * buttons back from the dead if the view ever changes.
+ */
+ g_signal_handler_disconnect(tree_model, d->handle_id);
+ d->view = NULL;
+ gtk_dialog_set_response_sensitive(d->dialog, LBACK, FALSE);
+ gtk_dialog_set_response_sensitive(d->dialog, LFORWARD, FALSE);
+}
+
+static void message_view_dialog_response(GtkDialog * dialog, gint response, gpointer user_data)
+{
+ _msg_user_data_t *d = (_msg_user_data_t *) user_data;
+ GtkTreePath *p;
+ GtkTreeIter tree_iter;
+ GtkTextIter text_iter;
+ size_t i;
+ gboolean go_back = FALSE;
+ gboolean go_forward = FALSE;
+
+ gtk_text_buffer_set_text(d->buffer, "", -1);
+ p = apol_vector_get_element(d->messages, 0);
+ assert(p != NULL);
+ switch (response) {
+ case LNOOP:
+ break; /* no-op response, display and test only */
+ case LBACK:
+ gtk_tree_path_prev(p);
+ break;
+ case LFORWARD:
+ gtk_tree_path_next(p);
+ break;
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CLOSE:
+ apol_vector_destroy(&d->messages);
+ if (d->view != NULL) {
+ g_signal_handler_disconnect(d->view->store, d->handle_id);
+ }
+ free(d);
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+ return;
+ default:
+ /* should never get here */
+ toplevel_ERR(d->view->top, "Unhandled response type (%d).\n", response);
+ assert(0);
+ return;
+ }
+ assert(d->view != NULL);
+
+ /* determine if the forward and backward buttons should be
+ enabled or not */
+ if (apol_vector_get_size(d->messages) == 1) {
+ GtkTreePath *dupe_p = gtk_tree_path_copy(p);
+ if (dupe_p == NULL) {
+ toplevel_ERR(d->view->top, "%s", strerror(errno));
+ return;
+ }
+ go_back = gtk_tree_path_prev(dupe_p);
+ gtk_tree_path_free(dupe_p);
+
+ message_view_store_get_iter(GTK_TREE_MODEL(d->view->store), &tree_iter, p);
+ go_forward = gtk_tree_model_iter_next(GTK_TREE_MODEL(d->view->store), &tree_iter);
+ }
+ gtk_dialog_set_response_sensitive(dialog, LBACK, go_back);
+ gtk_dialog_set_response_sensitive(dialog, LFORWARD, go_forward);
+
+ gtk_text_buffer_get_start_iter(d->buffer, &text_iter);
+ for (i = 0; i < apol_vector_get_size(d->messages); i++) {
+ char *s;
+ p = apol_vector_get_element(d->messages, i);
+ message_view_store_get_iter(GTK_TREE_MODEL(d->view->store), &tree_iter, p);
+ if ((s = seaudit_message_to_string(tree_iter.user_data)) == NULL) {
+ toplevel_ERR(d->view->top, "%s", strerror(errno));
+ continue;
+ }
+
+ gtk_text_buffer_insert(d->buffer, &text_iter, s, -1);
+ gtk_text_buffer_insert(d->buffer, &text_iter, "\n", -1);
+ free(s);
+ }
+}
+
+/**
+ * Show all messages within the messages vector (vector of
+ * GtkTreePaths into the view's store).
+ *
+ * Callback function cb_view_message takes ownership of messages
+ * vector and state.
+ */
+static void message_view_messages_vector(message_view_t * view, apol_vector_t * messages)
+{
+ GtkWidget *window = NULL;
+ GtkWidget *scroll;
+ GtkWidget *text_view;
+ GtkTextBuffer *buffer;
+ _msg_user_data_t *state;
+
+ state = malloc(sizeof(_msg_user_data_t));
+ if (state == NULL) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ apol_vector_destroy(&messages);
+ return;
+ }
+
+ window = gtk_dialog_new_with_buttons("View Messages",
+ toplevel_get_window(view->top),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_GO_BACK, LBACK,
+ GTK_STOCK_GO_FORWARD, LFORWARD, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(window), GTK_RESPONSE_CLOSE);
+ gtk_window_set_modal(GTK_WINDOW(window), FALSE);
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ text_view = gtk_text_view_new();
+ gtk_window_set_default_size(GTK_WINDOW(window), 480, 300);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), scroll);
+ gtk_container_add(GTK_CONTAINER(scroll), text_view);
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_WORD);
+ gtk_widget_show(text_view);
+ gtk_widget_show(scroll);
+
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
+
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
+ state->view = view;
+ state->messages = messages;
+ state->dialog = GTK_DIALOG(window);
+ state->buffer = buffer;
+ g_signal_connect(window, "response", G_CALLBACK(message_view_dialog_response), state);
+ state->handle_id = g_signal_connect(view->store, "row-changed", G_CALLBACK(message_view_dialog_change), state);
+ message_view_dialog_response(GTK_DIALOG(window), LNOOP, state);
+
+ gtk_widget_show_all(GTK_WIDGET(window));
+}
+
+/******************** handlers for right click menu ********************/
+
+static void message_view_popup_on_view_message_activate(GtkMenuItem * menuitem, gpointer user_data __attribute__ ((unused)))
+{
+ message_view_t *v = g_object_get_data(G_OBJECT(menuitem), "view-object");
+ message_view_entire_message(v);
+}
+
+static void message_view_popup_on_find_terules_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ message_view_t *v = g_object_get_data(G_OBJECT(menuitem), "view-object");
+ toplevel_find_terules(v->top, (seaudit_message_t *) user_data);
+}
+
+static void message_view_popup_on_export_selected_messages_activate(GtkMenuItem * menuitem, gpointer user_data
+ __attribute__ ((unused)))
+{
+ message_view_t *v = g_object_get_data(G_OBJECT(menuitem), "view-object");
+ message_view_export_selected_messages(v);
+}
+
+static void message_view_popup_menu(GtkWidget * treeview, GdkEventButton * event, message_view_t * view,
+ seaudit_message_t * message)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+ gint num_selected_rows = gtk_tree_selection_count_selected_rows(selection);
+ GtkWidget *menu, *menuitem, *menuitem2, *menuitem3;
+ int button, event_time;
+
+ menu = gtk_menu_new();
+ if (num_selected_rows == 1) {
+ menuitem = gtk_menu_item_new_with_label("View Selected Message");
+ menuitem3 = gtk_menu_item_new_with_label("Export Selected Message...");
+ } else {
+ menuitem = gtk_menu_item_new_with_label("View Selected Messages");
+ menuitem3 = gtk_menu_item_new_with_label("Export Selected Messages...");
+ }
+ menuitem2 = gtk_menu_item_new_with_label("Find TERules using Message...");
+ g_signal_connect(menuitem, "activate", (GCallback) message_view_popup_on_view_message_activate, message);
+ g_signal_connect(menuitem2, "activate", (GCallback) message_view_popup_on_find_terules_activate, message);
+ g_signal_connect(menuitem3, "activate", (GCallback) message_view_popup_on_export_selected_messages_activate, NULL);
+ g_object_set_data(G_OBJECT(menuitem), "view-object", view);
+ g_object_set_data(G_OBJECT(menuitem2), "view-object", view);
+ g_object_set_data(G_OBJECT(menuitem3), "view-object", view);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem2);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem3);
+ gtk_widget_show_all(menu);
+ if (toplevel_get_policy(view->top) == NULL) {
+ gtk_widget_set_sensitive(menuitem2, FALSE);
+ }
+
+ if (event) {
+ button = event->button;
+ event_time = event->time;
+ } else {
+ button = 0;
+ event_time = gtk_get_current_event_time();
+ }
+ gtk_menu_attach_to_widget(GTK_MENU(menu), treeview, NULL);
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, event_time);
+}
+
+static gboolean message_view_delayed_selection_menu_item(gpointer data)
+{
+ message_view_t *view = (message_view_t *) data;
+ toplevel_update_selection_menu_item(view->top);
+ return FALSE;
+}
+
+static gboolean message_view_on_button_press(GtkWidget * treeview, GdkEventButton * event, gpointer user_data)
+{
+ message_view_t *view = (message_view_t *) user_data;
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+ if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), event->x, event->y, &path, NULL, NULL, NULL)) {
+ return FALSE;
+ }
+ /* if the right click occurred on an unselected row, remove
+ * all selections and select the item under the pointer */
+ if (!gtk_tree_selection_path_is_selected(selection, path)) {
+ gtk_tree_selection_unselect_all(selection);
+ gtk_tree_selection_select_path(selection, path);
+ }
+ message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, path);
+ /* popup a menu for the row that was clicked */
+ message_view_popup_menu(treeview, event, view, (seaudit_message_t *) iter.user_data);
+ return TRUE;
+ } else if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
+ /* n.b.: rows can be selected but never deselected.
+ * delay updating the menu, for upon the first click
+ * there is not a selection yet */
+ g_idle_add(&message_view_delayed_selection_menu_item, view);
+ return FALSE;
+ } else if (event->type == GDK_2BUTTON_PRESS && event->button == 1){
+ /* Show message on double click */
+ message_view_entire_message(view);
+ }
+ return FALSE;
+}
+
+static void message_view_gtk_tree_path_free(gpointer data, gpointer user_data __attribute__ ((unused)))
+{
+ gtk_tree_path_free((GtkTreePath *) data);
+}
+
+static gboolean message_view_on_popup_menu(GtkWidget * treeview, gpointer user_data)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
+ GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL);
+ message_view_t *view = (message_view_t *) user_data;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ if (glist == NULL) {
+ return FALSE;
+ }
+ path = g_list_nth_data(glist, 0);
+ message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, path);
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+ message_view_popup_menu(treeview, NULL, view, (seaudit_message_t *) iter.user_data);
+ return TRUE;
+}
+
+static void message_view_on_row_activate(GtkTreeView * tree_view __attribute__ ((unused)), GtkTreePath * path
+ __attribute__ ((unused)), GtkTreeViewColumn * column
+ __attribute__ ((unused)), gpointer user_data)
+{
+ message_view_t *view = (message_view_t *) user_data;
+ toplevel_update_selection_menu_item(view->top);
+}
+
+/******************** other public functions below ********************/
+
+message_view_t *message_view_create(toplevel_t * top, seaudit_model_t * model, const char *filename)
+{
+ message_view_t *view;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+ size_t i;
+
+ if ((view = calloc(1, sizeof(*view))) == NULL || (filename != NULL && (view->filename = strdup(filename)) == NULL)) {
+ int error = errno;
+ toplevel_ERR(top, "%s", strerror(error));
+ message_view_destroy(&view);
+ errno = error;
+ return NULL;
+ }
+ view->top = top;
+ view->model = model;
+ view->store = (message_view_store_t *) g_object_new(SEAUDIT_TYPE_MESSAGE_VIEW_STORE, NULL);
+ view->store->view = view;
+ view->store->sort_field = OTHER_FIELD;
+ view->store->sort_dir = 1;
+ view->w = gtk_scrolled_window_new(NULL, NULL);
+ view->view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(view->store)));
+ selection = gtk_tree_view_get_selection(view->view);
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+ gtk_container_add(GTK_CONTAINER(view->w), GTK_WIDGET(view->view));
+ gtk_widget_show(GTK_WIDGET(view->view));
+ gtk_widget_show(view->w);
+
+ renderer = gtk_cell_renderer_text_new();
+ for (i = 0; i < num_columns; i++) {
+ struct view_column_record r = column_data[i];
+ PangoLayout *layout = gtk_widget_create_pango_layout(GTK_WIDGET(view->view), r.sample_text);
+ gint width;
+ GtkTreeViewColumn *column;
+ pango_layout_get_pixel_size(layout, &width, NULL);
+ g_object_unref(G_OBJECT(layout));
+ width += 12;
+ column = gtk_tree_view_column_new_with_attributes(r.name, renderer, "text", r.id, NULL);
+ gtk_tree_view_column_set_clickable(column, TRUE);
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ if (r.sort != NULL) {
+ g_object_set_data(G_OBJECT(column), "column id", GINT_TO_POINTER(r.id));
+ g_signal_connect_after(G_OBJECT(column), "clicked", G_CALLBACK(message_view_on_column_click), view);
+ }
+ gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
+ gtk_tree_view_column_set_fixed_width(column, width);
+ gtk_tree_view_append_column(view->view, column);
+ }
+
+ g_signal_connect(G_OBJECT(view->view), "button-press-event", G_CALLBACK(message_view_on_button_press), view);
+ g_signal_connect(G_OBJECT(view->view), "popup-menu", G_CALLBACK(message_view_on_popup_menu), view);
+ g_signal_connect(G_OBJECT(view->view), "row-activated", G_CALLBACK(message_view_on_row_activate), view);
+ message_view_update_visible_columns(view);
+ message_view_update_rows(view);
+ return view;
+}
+
+void message_view_destroy(message_view_t ** view)
+{
+ if (view != NULL && *view != NULL) {
+ /* emit a signal to force all message view dialogs to
+ disable their scroll buttons. need to pass a
+ non-NULL path in the signal handler to make GTK
+ shut up */
+ GtkTreePath *path = gtk_tree_path_new_first();
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter(GTK_TREE_MODEL((*view)->store), &iter, path);
+ g_signal_emit_by_name((*view)->store, "row-changed", path, &iter);
+ gtk_tree_path_free(path);
+ seaudit_model_destroy(&(*view)->model);
+ apol_vector_destroy(&((*view)->store->messages));
+ g_free((*view)->filename);
+ g_free((*view)->export_filename);
+ /* let glib handle destruction of object */
+ g_object_unref((*view)->store);
+ free(*view);
+ *view = NULL;
+ }
+}
+
+seaudit_model_t *message_view_get_model(message_view_t * view)
+{
+ return view->model;
+}
+
+void message_view_set_model(message_view_t * view, seaudit_model_t * model)
+{
+ seaudit_model_destroy(&view->model);
+ view->model = model;
+ toplevel_update_tabs(view->top);
+ message_view_update_rows(view);
+}
+
+GtkWidget *message_view_get_view(message_view_t * view)
+{
+ return view->w;
+}
+
+size_t message_view_get_num_log_messages(message_view_t * view)
+{
+ if (view->store->messages == NULL) {
+ return 0;
+ }
+ return apol_vector_get_size(view->store->messages);
+}
+
+gboolean message_view_is_message_selected(message_view_t * view)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(view->view);
+ GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL);
+ if (glist == NULL) {
+ return FALSE;
+ }
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+ return TRUE;
+}
+
+void message_view_vector_gtk_tree_path_free(void *elem)
+{
+ GtkTreePath *path = (GtkTreePath *) elem;
+ gtk_tree_path_free(path);
+}
+
+void message_view_entire_message(message_view_t * view)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(view->view);
+ GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL);
+ GList *l;
+ apol_vector_t *messages;
+ if (glist == NULL) {
+ return;
+ }
+ if ((messages = apol_vector_create(message_view_vector_gtk_tree_path_free)) == NULL) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+ return;
+ }
+ for (l = glist; l != NULL; l = l->next) {
+ GtkTreePath *path = gtk_tree_path_copy((GtkTreePath *) l->data);
+ if (path == NULL || apol_vector_append(messages, path) < 0) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ gtk_tree_path_free(path);
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+ apol_vector_destroy(&messages);
+ return;
+ }
+ }
+ /* the following function takes ownership of messages vector */
+ message_view_messages_vector(view, messages);
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+}
+
+void message_view_save(message_view_t * view)
+{
+ if (view->filename == NULL) {
+ GtkWindow *parent = toplevel_get_window(view->top);
+ char *path = util_save_file(parent, "Save View", NULL);
+ if (path == NULL) {
+ return;
+ }
+ view->filename = path;
+ }
+ if (seaudit_model_save_to_file(view->model, view->filename) < 0) {
+ toplevel_ERR(view->top, "Error saving view: %s", strerror(errno));
+ }
+}
+
+void message_view_saveas(message_view_t * view)
+{
+ GtkWindow *parent = toplevel_get_window(view->top);
+ char *path = util_save_file(parent, "Save View As", view->filename);
+ if (path == NULL) {
+ return;
+ }
+ g_free(view->filename);
+ view->filename = path;
+ if (seaudit_model_save_to_file(view->model, view->filename) < 0) {
+ toplevel_ERR(view->top, "Error saving view: %s", strerror(errno));
+ }
+}
+
+void message_view_modify(message_view_t * view)
+{
+ if (modify_view_run(view->top, view)) {
+ toplevel_update_status_bar(view->top);
+ }
+}
+
+void message_view_clear(message_view_t * view)
+{
+ size_t i;
+ for (i = 0; i < apol_vector_get_size(view->store->messages); i++) {
+ seaudit_message_t *m = apol_vector_get_element(view->store->messages, i);
+ seaudit_model_hide_message(view->model, m);
+ }
+ message_view_update_rows(view);
+}
+
+/**
+ * Write to a file all messages in the given vector. Upon success,
+ * update the view object's export filename.
+ *
+ * @param view View containing messages to write.
+ * @param path Destination to write file, overwriting existing files
+ * as necessary.
+ * @param messages Vector of seaudit_message_t.
+ */
+static void message_view_export_messages_vector(message_view_t * view, char *path, apol_vector_t * messages)
+{
+ FILE *f = NULL;
+ size_t i;
+ g_free(view->export_filename);
+ view->export_filename = path;
+ if ((f = fopen(path, "w")) == NULL) {
+ toplevel_ERR(view->top, "Could not open %s for writing.", path);
+ goto cleanup;
+ }
+ for (i = 0; i < apol_vector_get_size(messages); i++) {
+ seaudit_message_t *m = apol_vector_get_element(messages, i);
+ char *s = seaudit_message_to_string(m);
+ if (s == NULL || fprintf(f, "%s\n", s) < 0) {
+ toplevel_ERR(view->top, "Error writing string: %s", strerror(errno));
+ goto cleanup;
+ }
+ free(s);
+ }
+ cleanup:
+ if (f != NULL) {
+ fclose(f);
+ }
+}
+
+void message_view_export_all_messages(message_view_t * view)
+{
+ GtkWindow *parent = toplevel_get_window(view->top);
+ char *path = util_save_file(parent, "Export Messages", view->export_filename);
+ apol_vector_t *messages = view->store->messages;
+ if (path == NULL) {
+ return;
+ }
+ message_view_export_messages_vector(view, path, messages);
+}
+
+void message_view_export_selected_messages(message_view_t * view)
+{
+ GtkWindow *parent = toplevel_get_window(view->top);
+ char *path;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(view->view);
+ GList *glist = gtk_tree_selection_get_selected_rows(selection, NULL);
+ GList *l;
+ apol_vector_t *messages;
+ if (glist == NULL) {
+ return;
+ }
+ path = util_save_file(parent, "Export Selected Messages", view->export_filename);
+ if (path == NULL) {
+ return;
+ }
+ if ((messages = apol_vector_create(NULL)) == NULL) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+ return;
+ }
+ for (l = glist; l != NULL; l = l->next) {
+ GtkTreePath *tree_path = (GtkTreePath *) l->data;
+ GtkTreeIter iter;
+ message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, tree_path);
+ if (apol_vector_append(messages, iter.user_data) < 0) {
+ toplevel_ERR(view->top, "%s", strerror(errno));
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+ apol_vector_destroy(&messages);
+ return;
+ }
+ }
+ message_view_export_messages_vector(view, path, messages);
+ g_list_foreach(glist, message_view_gtk_tree_path_free, NULL);
+ g_list_free(glist);
+ apol_vector_destroy(&messages);
+}
+
+/**
+ * Given the name of a column, return its column record data.
+ */
+static const struct view_column_record *get_record(const char *name)
+{
+ size_t i;
+ for (i = 0; i < num_columns; i++) {
+ const struct view_column_record *r = column_data + i;
+ if (strcmp(r->name, name) == 0) {
+ return r;
+ }
+ }
+ return NULL;
+}
+
+void message_view_update_visible_columns(message_view_t * view)
+{
+ GList *columns, *c;
+ preferences_t *prefs = toplevel_get_prefs(view->top);
+ columns = gtk_tree_view_get_columns(view->view);
+ c = columns;
+ while (c != NULL) {
+ GtkTreeViewColumn *vc = GTK_TREE_VIEW_COLUMN(c->data);
+ const gchar *title = gtk_tree_view_column_get_title(vc);
+ const struct view_column_record *r = get_record(title);
+ if (preferences_is_column_visible(prefs, r->id)) {
+ gtk_tree_view_column_set_visible(vc, TRUE);
+ } else {
+ gtk_tree_view_column_set_visible(vc, FALSE);
+ }
+ c = g_list_next(c);
+ }
+ g_list_free(columns);
+}
+
+void message_view_update_rows(message_view_t * view)
+{
+ /* remove all existing rows, then insert them back into the
+ * view according to the model. automatically scroll to the
+ * same seleceted row(s). */
+ GtkTreeSelection *selection;
+ GList *rows, *r, *selected = NULL;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ seaudit_log_t *log;
+ size_t i, num_old_messages = 0, num_new_messages = 0, num_changed;
+ int first_scroll = 0;
+
+ if (!seaudit_model_is_changed(view->model)) {
+ return;
+ }
+
+ /* convert the current selection into a GList of message
+ * pointers */
+ selection = gtk_tree_view_get_selection(view->view);
+ rows = gtk_tree_selection_get_selected_rows(selection, NULL);
+ for (r = rows; r != NULL; r = r->next) {
+ path = (GtkTreePath *) r->data;
+ message_view_store_get_iter(GTK_TREE_MODEL(view->store), &iter, path);
+ selected = g_list_prepend(selected, iter.user_data);
+ }
+ g_list_foreach(rows, message_view_gtk_tree_path_free, NULL);
+ g_list_free(rows);
+
+ log = toplevel_get_log(view->top);
+ if (view->store->messages != NULL) {
+ num_old_messages = apol_vector_get_size(view->store->messages);
+ }
+ apol_vector_destroy(&view->store->messages);
+ if (log != NULL) {
+ view->store->messages = seaudit_model_get_messages(log, view->model);
+ num_new_messages = apol_vector_get_size(view->store->messages);
+ }
+ gtk_tree_selection_unselect_all(selection);
+
+ /* mark which rows have been changed/removed/inserted. do
+ * this as a single pass, rather than a two pass
+ * mark-and-sweep, for GTK+ tree views can be somewhat slow */
+ num_changed = num_old_messages;
+ if (num_new_messages < num_changed) {
+ num_changed = num_new_messages;
+ }
+ for (i = 0; i < num_changed; i++) {
+ path = gtk_tree_path_new();
+ gtk_tree_path_append_index(path, i);
+ iter.user_data = apol_vector_get_element(view->store->messages, i);
+ iter.user_data2 = GINT_TO_POINTER(i);
+ iter.user_data3 = view;
+ gtk_tree_model_row_changed(GTK_TREE_MODEL(view->store), path, &iter);
+ for (r = selected; r != NULL; r = r->next) {
+ if (r->data == iter.user_data) {
+ gtk_tree_selection_select_iter(selection, &iter);
+ if (!first_scroll) {
+ gtk_tree_view_scroll_to_cell(view->view, path, NULL, FALSE, 0.0, 0.0);
+ first_scroll = 1;
+ }
+ break;
+ }
+ }
+ gtk_tree_path_free(path);
+ }
+ if (num_old_messages > num_changed) {
+ /* delete in reverse order, else indices get renumbered */
+ for (i = num_old_messages; i > num_changed; i--) {
+ path = gtk_tree_path_new();
+ gtk_tree_path_append_index(path, i - 1);
+ gtk_tree_model_row_deleted(GTK_TREE_MODEL(view->store), path);
+ gtk_tree_path_free(path);
+ }
+ } else {
+ for (; i < num_new_messages; i++) {
+ path = gtk_tree_path_new();
+ gtk_tree_path_append_index(path, i);
+ iter.user_data = apol_vector_get_element(view->store->messages, i);
+ iter.user_data2 = GINT_TO_POINTER(i);
+ iter.user_data3 = view;
+ gtk_tree_model_row_inserted(GTK_TREE_MODEL(view->store), path, &iter);
+ for (r = selected; r != NULL; r = r->next) {
+ if (r->data == iter.user_data) {
+ gtk_tree_selection_select_iter(selection, &iter);
+ if (!first_scroll) {
+ gtk_tree_view_scroll_to_cell(view->view, path, NULL, FALSE, 0.0, 0.0);
+ first_scroll = 1;
+ }
+ break;
+ }
+ }
+ gtk_tree_path_free(path);
+ }
+ }
+ g_list_free(selected);
+}
diff --git a/seaudit/message_view.h b/seaudit/message_view.h
new file mode 100644
index 0000000..5b9bdd6
--- /dev/null
+++ b/seaudit/message_view.h
@@ -0,0 +1,178 @@
+/**
+ * @file
+ * Declaration of a single tab within the main notebook, showing
+ * all messages within a libseaudit model.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MESSAGE_VIEW_H
+#define MESSAGE_VIEW_H
+
+#include "toplevel.h"
+
+#include <gtk/gtk.h>
+#include <seaudit/model.h>
+
+typedef struct message_view message_view_t;
+
+/**
+ * Allocate a new view for a particular model.
+ *
+ * @param top Handle to the controlling toplevel widget.
+ * @param model libseaudit model to display. The view takes ownership
+ * of the model afterwards.
+ * @param filename Initial filename for the view, or NULL if none.
+ * This function will duplicate the string.
+ *
+ * @return A newly allocated view, or NULL upon error. The caller is
+ * responsible for calling message_view_destroy() afterwards.
+ */
+message_view_t *message_view_create(toplevel_t * top, seaudit_model_t * model, const char *filename);
+
+/**
+ * Destroy a view and free its memory. This does nothing if the
+ * pointer is set to NULL.
+ *
+ * @param view Reference to a toplevel object. Afterwards the pointer
+ * will be set to NULL.
+ */
+void message_view_destroy(message_view_t ** view);
+
+/**
+ * Get the message view's model. If the caller changes the model then
+ * he is responsible for calling message_view_update_rows() to update
+ * the view.
+ *
+ * @param view View whose model to obtain.
+ *
+ * @return View's model.
+ */
+seaudit_model_t *message_view_get_model(message_view_t * view);
+
+/**
+ * Replace a message view's model with a different model. The
+ * previous model will be destroyed. Afterwards the view will update
+ * its rows.
+ *
+ * @param view View to modify.
+ * @param libseaudit model to display. The view takes ownership
+ * of the model afterwards.
+ */
+void message_view_set_model(message_view_t * view, seaudit_model_t * model);
+
+/**
+ * Get the message view's widget display. This widget will be placed
+ * in a container for the user to see.
+ *
+ * @param view View whose widget to obtain.
+ *
+ * @return View's widget.
+ */
+GtkWidget *message_view_get_view(message_view_t * view);
+
+/**
+ * Return the number of messages currently in this view.
+ *
+ * @param view View object to query.
+ *
+ * @return Number of log messages, or 0 if no model is associated with
+ * the view.
+ */
+size_t message_view_get_num_log_messages(message_view_t * view);
+
+/**
+ * Return TRUE if the message view has one or more messages selected,
+ * FALSE if not.
+ *
+ * @param view View object to query.
+ *
+ * @return TRUE if any messages are selected.
+ */
+gboolean message_view_is_message_selected(message_view_t * view);
+
+/**
+ * Save the current view to disk.
+ *
+ * @param view View to save.
+ */
+void message_view_save(message_view_t * view);
+
+/**
+ * Save the current view to disk under a new filename.
+ *
+ * @param view View to save.
+ */
+void message_view_saveas(message_view_t * view);
+
+/**
+ * Modify the settings for this view.
+ *
+ * @param view View to modify.
+ */
+void message_view_modify(message_view_t * view);
+
+/**
+ * Clear all messages from this view.
+ *
+ * @param view View to clear.
+ */
+void message_view_clear(message_view_t * view);
+
+/**
+ * Export to file all messages in a particular view.
+ *
+ * @param view View whose messages to export.
+ */
+void message_view_export_all_messages(message_view_t * view);
+
+/**
+ * Export to file all messages selected in a particular view.
+ *
+ * @param view View whose messages to export.
+ */
+void message_view_export_selected_messages(message_view_t * view);
+
+/**
+ * Open a dialog that shows an approximation of the message(s)
+ * currently selected.
+ *
+ * @param view View whose messages to show.
+ */
+void message_view_entire_message(message_view_t * view);
+
+/**
+ * Show/hide columns in a view based upon the user's current
+ * preferences.
+ *
+ * @param view View's columns to update.
+ */
+void message_view_update_visible_columns(message_view_t * view);
+
+/**
+ * (Re)synchronize the messages displayed in a view with its
+ * underlying model. This needs to be called when a model's filter
+ * changes or if new messages are found within the model's log.
+ *
+ * @param view View's rows to update.
+ */
+void message_view_update_rows(message_view_t * view);
+
+#endif
diff --git a/seaudit/modify_view.c b/seaudit/modify_view.c
new file mode 100644
index 0000000..abfbcc4
--- /dev/null
+++ b/seaudit/modify_view.c
@@ -0,0 +1,327 @@
+/**
+ * @file
+ * Run the dialog to modify a view.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "filter_view.h"
+#include "modify_view.h"
+#include "utilgui.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <glade/glade.h>
+
+struct modify_view
+{
+ toplevel_t *top;
+ message_view_t *view;
+ GladeXML *xml;
+ /** the model currently being modified -- note that this is a
+ * deep copy of the message_view's model */
+ seaudit_model_t *model;
+
+ /** model containing a list of filter names, needs to be
+ * destroyed afterwords */
+ GtkListStore *filter_store;
+ GtkDialog *dialog;
+ GtkEntry *name_entry;
+ GtkComboBox *visible_combo, *match_combo;
+ GtkTreeView *filter_view;
+ GtkButton *add_button, *edit_button, *remove_button, *import_button, *export_button;
+
+ /** keep track of most recent filter filename */
+ char *filter_filename;
+};
+
+/**
+ * Return the currently selected filter, or NULL if no filter is
+ * selected.
+ */
+static seaudit_filter_t *modify_view_get_current_filter(struct modify_view *mv)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view);
+ GtkTreeIter iter;
+ seaudit_filter_t *filter;
+ if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
+ return NULL;
+ }
+ gtk_tree_model_get(GTK_TREE_MODEL(mv->filter_store), &iter, 0, &filter, -1);
+ return filter;
+}
+
+/**
+ * Rebuild the filter store, preserving the current selection if
+ * possible.
+ */
+static void modify_view_update_filter_store(struct modify_view *mv)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view);
+ GtkTreeIter old_iter, iter;
+ gboolean selection_existed = gtk_tree_selection_get_selected(selection, NULL, &old_iter);
+ const apol_vector_t *filters = seaudit_model_get_filters(mv->model);
+ size_t i;
+ gtk_list_store_clear(mv->filter_store);
+ for (i = 0; i < apol_vector_get_size(filters); i++) {
+ seaudit_filter_t *filter = apol_vector_get_element(filters, i);
+ gtk_list_store_append(mv->filter_store, &iter);
+ gtk_list_store_set(mv->filter_store, &iter, 0, filter, 1, seaudit_filter_get_name(filter), -1);
+ }
+ /* initially select the last thing, then reset selection */
+ if (i > 0) {
+ gtk_tree_selection_select_iter(selection, &iter);
+ }
+ if (selection_existed && gtk_list_store_iter_is_valid(mv->filter_store, &old_iter)) {
+ gtk_tree_selection_select_iter(selection, &old_iter);
+ }
+}
+
+static void modify_view_on_selection_change(GtkTreeSelection * selection, gpointer user_data)
+{
+ struct modify_view *mv = (struct modify_view *)user_data;
+ gboolean sens = gtk_tree_selection_get_selected(selection, NULL, NULL);
+ gtk_widget_set_sensitive(GTK_WIDGET(mv->edit_button), sens);
+ gtk_widget_set_sensitive(GTK_WIDGET(mv->remove_button), sens);
+ gtk_widget_set_sensitive(GTK_WIDGET(mv->export_button), sens);
+}
+
+static void modify_view_on_add_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct modify_view *mv = (struct modify_view *)user_data;
+ seaudit_filter_t *filter = NULL;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view);
+
+ if ((filter = seaudit_filter_create("Untitled")) == NULL || (seaudit_model_append_filter(mv->model, filter) < 0)) {
+ toplevel_ERR(mv->top, "Error adding new filter: %s", strerror(errno));
+ seaudit_filter_destroy(&filter);
+ return;
+ }
+ /* select the filter that was just created, by removing the
+ * selection and letting the following function select it */
+ gtk_tree_selection_unselect_all(selection);
+ modify_view_update_filter_store(mv);
+ filter_view_run(filter, mv->top, GTK_WINDOW(mv->dialog));
+ modify_view_update_filter_store(mv);
+}
+
+static void modify_view_on_edit_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct modify_view *mv = (struct modify_view *)user_data;
+ seaudit_filter_t *filter = modify_view_get_current_filter(mv);
+ assert(filter != NULL);
+ filter_view_run(filter, mv->top, GTK_WINDOW(mv->dialog));
+ modify_view_update_filter_store(mv);
+}
+
+static void modify_view_on_remove_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct modify_view *mv = (struct modify_view *)user_data;
+ seaudit_filter_t *filter = modify_view_get_current_filter(mv);
+ assert(filter != NULL);
+ seaudit_model_remove_filter(mv->model, filter);
+ modify_view_update_filter_store(mv);
+}
+
+static void modify_view_on_import_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct modify_view *mv = (struct modify_view *)user_data;
+ apol_vector_t *paths = util_open_file(GTK_WINDOW(mv->dialog), "Import Filter", mv->filter_filename, 0);
+ apol_vector_t *filters;
+ size_t i;
+ if (paths == NULL) {
+ return;
+ }
+ free(mv->filter_filename);
+ if ((mv->filter_filename = strdup(apol_vector_get_element(paths, 0))) == NULL) {
+ toplevel_ERR(mv->top, "Error importing filter: %s", strerror(errno));
+ apol_vector_destroy(&paths);
+ return;
+ }
+ apol_vector_destroy(&paths);
+ if ((filters = seaudit_filter_create_from_file(mv->filter_filename)) == NULL) {
+ toplevel_ERR(mv->top, "Error importing filter: %s", strerror(errno));
+ apol_vector_destroy(&paths);
+ return;
+ }
+ for (i = 0; i < apol_vector_get_size(filters); i++) {
+ seaudit_filter_t *filter = apol_vector_get_element(filters, i);
+ seaudit_filter_t *new_f = NULL;
+ if ((new_f = seaudit_filter_create_from_filter(filter)) == NULL ||
+ seaudit_model_append_filter(mv->model, new_f) < 0) {
+ toplevel_ERR(mv->top, "Error importing filter: %s", strerror(errno));
+ seaudit_filter_destroy(&new_f);
+ apol_vector_destroy(&filters);
+ return;
+ }
+ modify_view_update_filter_store(mv);
+ }
+ apol_vector_destroy(&filters);
+}
+
+static void modify_view_on_export_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct modify_view *mv = (struct modify_view *)user_data;
+ char *path = util_save_file(GTK_WINDOW(mv->dialog), "Export Filter", mv->filter_filename);
+ seaudit_filter_t *filter = modify_view_get_current_filter(mv);
+ assert(filter != NULL);
+ if (path == NULL) {
+ return;
+ }
+ g_free(mv->filter_filename);
+ mv->filter_filename = path;
+ if (seaudit_filter_save_to_file(filter, mv->filter_filename) < 0) {
+ toplevel_ERR(mv->top, "Error exporting filter: %s", strerror(errno));
+ }
+}
+
+/**
+ * Make libglade calls to fill in struct modify_view widget
+ * references.
+ */
+static void modify_view_init_widgets(struct modify_view *mv)
+{
+ mv->dialog = GTK_DIALOG(glade_xml_get_widget(mv->xml, "ModifyViewWindow"));
+ assert(mv->dialog != NULL);
+ gtk_window_set_transient_for(GTK_WINDOW(mv->dialog), toplevel_get_window(mv->top));
+
+ mv->name_entry = GTK_ENTRY(glade_xml_get_widget(mv->xml, "ModifyViewNameEntry"));
+ assert(mv->name_entry != NULL);
+
+ mv->visible_combo = GTK_COMBO_BOX(glade_xml_get_widget(mv->xml, "ModifyViewVisibleCombo"));
+ mv->match_combo = GTK_COMBO_BOX(glade_xml_get_widget(mv->xml, "ModifyViewMatchCombo"));
+ assert(mv->visible_combo != NULL && mv->match_combo != NULL);
+
+ mv->filter_view = GTK_TREE_VIEW(glade_xml_get_widget(mv->xml, "ModifyViewFilterView"));
+ assert(mv->filter_view != NULL);
+ mv->filter_store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
+ gtk_tree_view_set_model(mv->filter_view, GTK_TREE_MODEL(mv->filter_store));
+
+ mv->add_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewAddButton"));
+ mv->edit_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewEditButton"));
+ mv->remove_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewRemoveButton"));
+ mv->import_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewImportButton"));
+ mv->export_button = GTK_BUTTON(glade_xml_get_widget(mv->xml, "ModifyViewExportButton"));
+ assert(mv->add_button != NULL && mv->edit_button != NULL && mv->remove_button != NULL &&
+ mv->import_button != NULL && mv->export_button != NULL);
+}
+
+static void modify_view_init_signals(struct modify_view *mv)
+{
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("Filter names", renderer, "text", 1, NULL);
+ gtk_tree_view_column_set_clickable(column, FALSE);
+ gtk_tree_view_column_set_resizable(column, FALSE);
+ gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_visible(column, TRUE);
+ gtk_tree_view_append_column(mv->filter_view, column);
+
+ selection = gtk_tree_view_get_selection(mv->filter_view);
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
+ g_signal_connect(selection, "changed", G_CALLBACK(modify_view_on_selection_change), mv);
+
+ g_signal_connect(mv->add_button, "clicked", G_CALLBACK(modify_view_on_add_click), mv);
+ g_signal_connect(mv->edit_button, "clicked", G_CALLBACK(modify_view_on_edit_click), mv);
+ g_signal_connect(mv->remove_button, "clicked", G_CALLBACK(modify_view_on_remove_click), mv);
+ g_signal_connect(mv->import_button, "clicked", G_CALLBACK(modify_view_on_import_click), mv);
+ g_signal_connect(mv->export_button, "clicked", G_CALLBACK(modify_view_on_export_click), mv);
+}
+
+/**
+ * Set up the window to reflect the current view's values.
+ */
+static void modify_view_init_dialog(struct modify_view *mv)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(mv->filter_view);
+ GtkTreeIter iter;
+
+ gtk_entry_set_text(mv->name_entry, seaudit_model_get_name(mv->model));
+
+ gtk_combo_box_set_active(mv->visible_combo, seaudit_model_get_filter_visible(mv->model));
+ gtk_combo_box_set_active(mv->match_combo, seaudit_model_get_filter_match(mv->model));
+
+ gtk_tree_selection_unselect_all(selection);
+ modify_view_update_filter_store(mv);
+ /* automatically select the first filter upon dialog
+ * startup */
+
+ if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(mv->filter_store), &iter)) {
+ gtk_tree_selection_select_iter(selection, &iter);
+ }
+}
+
+int modify_view_run(toplevel_t * top, message_view_t * view)
+{
+ struct modify_view mv;
+ seaudit_model_t *orig_model = message_view_get_model(view);
+ gint response;
+ int retval;
+
+ memset(&mv, 0, sizeof(mv));
+ mv.top = top;
+ mv.view = view;
+ mv.xml = glade_xml_new(toplevel_get_glade_xml(top), "ModifyViewWindow", NULL);
+ mv.filter_filename = NULL;
+ if ((mv.model = seaudit_model_create_from_model(orig_model)) == NULL) {
+ toplevel_ERR(mv.top, "Error duplicating model: %s", strerror(errno));
+ return 0;
+ }
+ modify_view_init_widgets(&mv);
+ modify_view_init_signals(&mv);
+ modify_view_init_dialog(&mv);
+
+ do {
+ response = gtk_dialog_run(mv.dialog);
+ const gchar *text = gtk_entry_get_text(mv.name_entry);
+
+ if (seaudit_model_set_name(mv.model, text) < 0) {
+ toplevel_ERR(mv.top, "Could not set name: %s", strerror(errno));
+ }
+ seaudit_model_set_filter_visible(mv.model, gtk_combo_box_get_active(mv.visible_combo));
+ seaudit_model_set_filter_match(mv.model, gtk_combo_box_get_active(mv.match_combo));
+ if (response == GTK_RESPONSE_APPLY) {
+ seaudit_model_t *new_model;
+ if ((new_model = seaudit_model_create_from_model(mv.model)) == NULL) {
+ toplevel_ERR(mv.top, "Error applying model: %s", strerror(errno));
+ break;
+ }
+ message_view_set_model(mv.view, new_model);
+ toplevel_update_status_bar(mv.top);
+ }
+ } while (response == GTK_RESPONSE_APPLY);
+
+ if (response == GTK_RESPONSE_OK) {
+ message_view_set_model(mv.view, mv.model);
+ retval = 1;
+ } else {
+ seaudit_model_destroy(&mv.model);
+ retval = 0;
+ }
+ gtk_widget_destroy(GTK_WIDGET(mv.dialog));
+ g_object_unref(mv.filter_store);
+ return retval;
+}
diff --git a/seaudit/modify_view.h b/seaudit/modify_view.h
new file mode 100644
index 0000000..06993f3
--- /dev/null
+++ b/seaudit/modify_view.h
@@ -0,0 +1,41 @@
+/**
+ * @file
+ * Dialog that allows the user to modify the current view.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef MODIFY_VIEW_H
+#define MODIFY_VIEW_H
+
+#include "toplevel.h"
+#include "message_view.h"
+
+/**
+ * Display and run a dialog that allows the user to modify a view.
+ *
+ * @param top Toplevel containing message view.
+ * @param view Message view to modify.
+ *
+ * @return Non-zero if the view changed, zero if not.
+ */
+int modify_view_run(toplevel_t * top, message_view_t * view);
+
+#endif
diff --git a/seaudit/open_policy_window.c b/seaudit/open_policy_window.c
new file mode 100644
index 0000000..ca8a511
--- /dev/null
+++ b/seaudit/open_policy_window.c
@@ -0,0 +1,469 @@
+/**
+ * @file
+ * Run the dialog to allow the user to open a policy.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "open_policy_window.h"
+#include "utilgui.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <apol/util.h>
+#include <apol/vector.h>
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+
+struct open_policy
+{
+ GladeXML *xml;
+ toplevel_t *top;
+ char *last_module_path;
+ GtkDialog *dialog;
+
+ GtkRadioButton *monolithic_radio, *modular_radio;
+ GtkLabel *main_label;
+
+ GtkHBox *bottom_hbox;
+ GtkListStore *module_store;
+
+ GtkEntry *base_entry;
+ GtkButton *base_browse_button;
+
+ GtkTreeView *module_view;
+ GtkButton *add_button, *remove_button, *import_button, *export_button;
+ GtkButton *ok_button;
+};
+
+enum module_columns
+{
+ PATH_COLUMN = 0, NAME_COLUMN, VERSION_COLUMN, NUM_COLUMNS
+};
+
+/**
+ * Sort columns in alphabetical order.
+ */
+static gint open_policy_sort(GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data)
+{
+ GValue value_a = { 0 }, value_b = {
+ 0};
+ const char *name_a, *name_b;
+ int retval, column_id = GPOINTER_TO_INT(user_data);
+
+ gtk_tree_model_get_value(model, a, column_id, &value_a);
+ gtk_tree_model_get_value(model, b, column_id, &value_b);
+ name_a = g_value_get_string(&value_a);
+ name_b = g_value_get_string(&value_b);
+ retval = strcmp(name_a, name_b);
+ g_value_unset(&value_a);
+ g_value_unset(&value_b);
+ return retval;
+}
+
+static void open_policy_init_widgets(struct open_policy *op)
+{
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ op->dialog = GTK_DIALOG(glade_xml_get_widget(op->xml, "PolicyOpenWindow"));
+ assert(op->dialog != NULL);
+ gtk_window_set_transient_for(GTK_WINDOW(op->dialog), toplevel_get_window(op->top));
+
+ op->monolithic_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(op->xml, "monolithic radio"));
+ op->modular_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(op->xml, "modular radio"));
+ op->main_label = GTK_LABEL(glade_xml_get_widget(op->xml, "main filename label"));
+ assert(op->monolithic_radio != NULL && op->modular_radio != NULL && op->main_label != NULL);
+
+ op->base_entry = GTK_ENTRY(glade_xml_get_widget(op->xml, "base entry"));
+ op->base_browse_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "base browse"));
+ assert(op->base_entry != NULL && op->base_browse_button != NULL);
+
+ op->bottom_hbox = GTK_HBOX(glade_xml_get_widget(op->xml, "hbox.3"));
+ assert(op->bottom_hbox != NULL);
+
+ op->module_view = GTK_TREE_VIEW(glade_xml_get_widget(op->xml, "module view"));
+ assert(op->module_view != NULL);
+ op->module_store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_tree_view_set_model(op->module_view, GTK_TREE_MODEL(op->module_store));
+
+ op->add_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module add button"));
+ op->remove_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module remove button"));
+ op->import_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module list import button"));
+ op->export_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "module list export button"));
+ op->ok_button = GTK_BUTTON(glade_xml_get_widget(op->xml, "ok button"));
+ assert(op->add_button != NULL && op->remove_button != NULL &&
+ op->import_button != NULL && op->export_button != NULL && op->ok_button != NULL);
+
+ selection = gtk_tree_view_get_selection(op->module_view);
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
+
+ column = gtk_tree_view_column_new_with_attributes("Module", renderer, "text", NAME_COLUMN, NULL);
+ gtk_tree_view_column_set_sort_column_id(column, NAME_COLUMN);
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ gtk_tree_view_append_column(op->module_view, column);
+ gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(op->module_store), NAME_COLUMN, open_policy_sort, (gpointer) NAME_COLUMN,
+ NULL);
+
+ column = gtk_tree_view_column_new_with_attributes("Version", renderer, "text", VERSION_COLUMN, NULL);
+ gtk_tree_view_column_set_sort_column_id(column, VERSION_COLUMN);
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ gtk_tree_view_append_column(op->module_view, column);
+ gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(op->module_store), VERSION_COLUMN, open_policy_sort,
+ (gpointer) VERSION_COLUMN, NULL);
+
+ column = gtk_tree_view_column_new_with_attributes("Path", renderer, "text", PATH_COLUMN, NULL);
+ gtk_tree_view_column_set_sort_column_id(column, PATH_COLUMN);
+ gtk_tree_view_column_set_resizable(column, TRUE);
+ gtk_tree_view_append_column(op->module_view, column);
+ gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(op->module_store), PATH_COLUMN, open_policy_sort, (gpointer) PATH_COLUMN,
+ NULL);
+
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(op->module_store), NAME_COLUMN, GTK_SORT_ASCENDING);
+}
+
+static void open_policy_on_policy_type_toggle(GtkToggleButton * widget, gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ /* clicking on the radio buttons emit two toggle signals, one for
+ * the original button and one for the new one. thus only need to
+ * handle half of all signals */
+ if (!gtk_toggle_button_get_active(widget)) {
+ return;
+ }
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(op->monolithic_radio))) {
+ gtk_widget_set_sensitive(GTK_WIDGET(op->bottom_hbox), FALSE);
+ gtk_label_set_markup(op->main_label, "<b>Policy Filename:</b>");
+ } else {
+ gtk_widget_set_sensitive(GTK_WIDGET(op->bottom_hbox), TRUE);
+ gtk_label_set_markup(op->main_label, "<b>Base Filename:</b>");
+ }
+}
+
+static void open_policy_on_entry_event_after(GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
+ __attribute__ ((unused)), gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ gboolean sens = FALSE;
+ if (strcmp(gtk_entry_get_text(op->base_entry), "") != 0) {
+ sens = TRUE;
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(op->export_button), sens);
+ gtk_widget_set_sensitive(GTK_WIDGET(op->ok_button), sens);
+}
+
+static void open_policy_on_base_browse_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ const char *current_path = gtk_entry_get_text(op->base_entry);
+ char *title;
+ apol_vector_t *paths;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(op->monolithic_radio))) {
+ title = "Open Monolithic Policy";
+ } else {
+ title = "Open Modular Policy";
+ }
+ if (strcmp(current_path, "") == 0) {
+ current_path = NULL;
+ }
+ if ((paths = util_open_file(GTK_WINDOW(op->dialog), title, current_path, 0)) == NULL) {
+ return;
+ }
+ gtk_entry_set_text(op->base_entry, apol_vector_get_element(paths, 0));
+ apol_vector_destroy(&paths);
+}
+
+/**
+ * Attempt to load a module and retrieve its name and version. Upon
+ * success add an entry to the list store.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int open_policy_load_module(struct open_policy *op, const char *path)
+{
+ const char *module_name, *version_string;
+ int module_type;
+ qpol_module_t *module = NULL;
+ GtkTreeIter iter;
+
+ /* check if modulue was already loaded */
+ gboolean iter_valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(op->module_store), &iter);
+ while (iter_valid) {
+ char *s;
+ gtk_tree_model_get(GTK_TREE_MODEL(op->module_store), &iter, PATH_COLUMN, &s, -1);
+ if (strcmp(s, path) == 0) {
+ toplevel_ERR(op->top, "Module %s was already added.", path);
+ return -1;
+ }
+ iter_valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(op->module_store), &iter);
+ }
+ if ((qpol_module_create_from_file(path, &module)) < 0) {
+ toplevel_ERR(op->top, "Error opening module %s: %s", path, strerror(errno));
+ return -1;
+ }
+ if (qpol_module_get_name(module, &module_name) < 0 ||
+ qpol_module_get_version(module, &version_string) < 0 || qpol_module_get_type(module, &module_type) < 0) {
+ toplevel_ERR(op->top, "Error reading module %s: %s", path, strerror(errno));
+ qpol_module_destroy(&module);
+ return -1;
+ }
+ if (module_type != QPOL_MODULE_OTHER) {
+ toplevel_ERR(op->top, "%s is not a loadable module.", path);
+ qpol_module_destroy(&module);
+ return -1;
+ }
+ gtk_list_store_append(op->module_store, &iter);
+ gtk_list_store_set(op->module_store, &iter, PATH_COLUMN, path, NAME_COLUMN, module_name, VERSION_COLUMN, version_string,
+ -1);
+ qpol_module_destroy(&module);
+ return 0;
+}
+
+static void open_policy_on_add_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ apol_vector_t *paths;
+ const char *path = NULL, *prev_path;
+ size_t i;
+ if ((prev_path = op->last_module_path) == NULL) {
+ prev_path = gtk_entry_get_text(op->base_entry);
+ if (strcmp(prev_path, "") == 0) {
+ prev_path = NULL;
+ }
+ }
+ paths = util_open_file(GTK_WINDOW(op->dialog), "Open Module", prev_path, 1);
+ if (paths == NULL) {
+ return;
+ }
+ int all_succeed = 1;
+ for (i = 0; i < apol_vector_get_size(paths); i++) {
+ path = apol_vector_get_element(paths, i);
+ if (open_policy_load_module(op, path) < 0) {
+ all_succeed = 0;
+ }
+ }
+ if (all_succeed) {
+ assert(path != NULL);
+ free(op->last_module_path);
+ op->last_module_path = strdup(path);
+ }
+ apol_vector_destroy(&paths);
+}
+
+static void open_policy_on_remove_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(op->module_view);
+ GtkTreeIter iter;
+ char *path;
+ if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
+ return;
+ }
+ gtk_tree_model_get(GTK_TREE_MODEL(op->module_store), &iter, 0, &path, -1);
+ gtk_list_store_remove(op->module_store, &iter);
+}
+
+static void open_policy_on_import_click(GtkButton * button __attribute__ ((unused)), gpointer user_data);
+static void open_policy_on_export_click(GtkButton * button __attribute__ ((unused)), gpointer user_data);
+
+static void open_policy_on_selection_change(GtkTreeSelection * selection, gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ gboolean sens = gtk_tree_selection_get_selected(selection, NULL, NULL);
+ gtk_widget_set_sensitive(GTK_WIDGET(op->remove_button), sens);
+}
+
+static void open_policy_init_signals(struct open_policy *op)
+{
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(op->module_view);
+ g_signal_connect(op->monolithic_radio, "toggled", G_CALLBACK(open_policy_on_policy_type_toggle), op);
+ g_signal_connect(op->modular_radio, "toggled", G_CALLBACK(open_policy_on_policy_type_toggle), op);
+ g_signal_connect(op->base_entry, "event-after", G_CALLBACK(open_policy_on_entry_event_after), op);
+ g_signal_connect(op->base_browse_button, "clicked", G_CALLBACK(open_policy_on_base_browse_click), op);
+ g_signal_connect(selection, "changed", G_CALLBACK(open_policy_on_selection_change), op);
+ g_signal_connect(op->add_button, "clicked", G_CALLBACK(open_policy_on_add_click), op);
+ g_signal_connect(op->remove_button, "clicked", G_CALLBACK(open_policy_on_remove_click), op);
+ g_signal_connect(op->import_button, "clicked", G_CALLBACK(open_policy_on_import_click), op);
+ g_signal_connect(op->export_button, "clicked", G_CALLBACK(open_policy_on_export_click), op);
+}
+
+static void open_policy_init_values(struct open_policy *op, const apol_policy_path_t * path)
+{
+ if (path != NULL) {
+ apol_policy_path_type_e path_type = apol_policy_path_get_type(path);
+ const char *primary_path = apol_policy_path_get_primary(path);
+ gtk_entry_set_text(op->base_entry, primary_path);
+ gtk_list_store_clear(op->module_store);
+ if (path_type == APOL_POLICY_PATH_TYPE_MONOLITHIC) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(op->monolithic_radio), TRUE);
+ } else if (path_type == APOL_POLICY_PATH_TYPE_MODULAR) {
+ const apol_vector_t *modules = apol_policy_path_get_modules(path);
+ size_t i;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(op->modular_radio), TRUE);
+ for (i = 0; i < apol_vector_get_size(modules); i++) {
+ char *module_path = apol_vector_get_element(modules, i);
+ if (open_policy_load_module(op, module_path) < 0) {
+ break;
+ }
+ }
+ } else {
+ /* should never get here */
+ toplevel_ERR(op->top, "Unknown policy path type %d.", path_type);
+ }
+ }
+}
+
+/**
+ * Build the policy path corresponding to the user's inputs on this
+ * dialog.
+ *
+ * @return path for the dialog, or NULL upon error. The caller must
+ * call apol_policy_path_destroy() afterwards.
+ */
+static apol_policy_path_t *open_policy_build_path(struct open_policy *op)
+{
+ const char *primary_path = gtk_entry_get_text(op->base_entry);
+ apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ apol_vector_t *modules = NULL;
+ apol_policy_path_t *path = NULL;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(op->modular_radio))) {
+ path_type = APOL_POLICY_PATH_TYPE_MODULAR;
+ GtkTreeIter iter;
+ if ((modules = apol_vector_create(free)) == NULL) {
+ toplevel_ERR(op->top, "%s", strerror(errno));
+ return NULL;
+ }
+ if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(op->module_store), &iter)) {
+ do {
+ GValue value = { 0 };
+ char *module_path;
+ gtk_tree_model_get_value(GTK_TREE_MODEL(op->module_store), &iter, PATH_COLUMN, &value);
+ module_path = g_value_dup_string(&value);
+ g_value_unset(&value);
+ if (apol_vector_append(modules, module_path) < 0) {
+ toplevel_ERR(op->top, "%s", strerror(errno));
+ free(module_path);
+ apol_vector_destroy(&modules);
+ return NULL;
+ }
+ } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(op->module_store), &iter));
+ }
+ }
+ path = apol_policy_path_create(path_type, primary_path, modules);
+ apol_vector_destroy(&modules);
+ if (path == NULL) {
+ toplevel_ERR(op->top, "%s", strerror(errno));
+ return NULL;
+ }
+ return path;
+}
+
+static void open_policy_on_import_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ apol_vector_t *paths = NULL;
+ apol_policy_path_t *ppath = NULL;
+ const char *path = NULL, *prev_path;
+ if ((prev_path = op->last_module_path) == NULL) {
+ prev_path = gtk_entry_get_text(op->base_entry);
+ if (strcmp(prev_path, "") == 0) {
+ prev_path = NULL;
+ }
+ }
+ paths = util_open_file(GTK_WINDOW(op->dialog), "Import Policy List", prev_path, 1);
+ if (paths == NULL) {
+ return;
+ }
+ path = apol_vector_get_element(paths, 0);
+ ppath = apol_policy_path_create_from_file(path);
+ if (ppath == NULL) {
+ toplevel_ERR(op->top, "Error importing policy list %s: %s", path, strerror(errno));
+ goto cleanup;
+ }
+ open_policy_init_values(op, ppath);
+ free(op->last_module_path);
+ op->last_module_path = strdup(path);
+ cleanup:
+ apol_vector_destroy(&paths);
+ apol_policy_path_destroy(&ppath);
+}
+
+static void open_policy_on_export_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ struct open_policy *op = (struct open_policy *)user_data;
+ char *path = util_save_file(GTK_WINDOW(op->dialog), "Export Policy List", NULL);
+ apol_policy_path_t *ppath = NULL;
+ if (path == NULL) {
+ return;
+ }
+ ppath = open_policy_build_path(op);
+ if (ppath == NULL) {
+ goto cleanup;
+ }
+ if (apol_policy_path_to_file(ppath, path) < 0) {
+ toplevel_ERR(op->top, "Error exporting policy list %s: %s", path, strerror(errno));
+ }
+ cleanup:
+ g_free(path);
+ apol_policy_path_destroy(&ppath);
+}
+
+void open_policy_window_run(toplevel_t * top, const apol_policy_path_t * path, apol_policy_path_t ** selection)
+{
+ struct open_policy op;
+ gint response;
+ apol_policy_path_t *input;
+
+ memset(&op, 0, sizeof(op));
+ op.top = top;
+ op.xml = glade_xml_new(toplevel_get_glade_xml(top), "PolicyOpenWindow", NULL);
+
+ open_policy_init_widgets(&op);
+ open_policy_init_signals(&op);
+ open_policy_init_values(&op, path);
+ if (selection != NULL) {
+ *selection = NULL;
+ }
+
+ while (1) {
+ response = gtk_dialog_run(op.dialog);
+ if (response == GTK_RESPONSE_CANCEL || response == GTK_RESPONSE_DELETE_EVENT) {
+ break;
+ }
+ if ((input = open_policy_build_path(&op)) == NULL) {
+ continue;
+ }
+ if (selection == NULL) {
+ if (toplevel_open_policy(op.top, input) == 0) {
+ break;
+ }
+ } else {
+ *selection = input;
+ break;
+ }
+ }
+ gtk_widget_destroy(GTK_WIDGET(op.dialog));
+ free(op.last_module_path);
+ g_object_unref(op.module_store);
+}
diff --git a/seaudit/open_policy_window.h b/seaudit/open_policy_window.h
new file mode 100644
index 0000000..2b57e9d
--- /dev/null
+++ b/seaudit/open_policy_window.h
@@ -0,0 +1,46 @@
+/**
+ * @file
+ * Dialog that allows the user to select either a monolithic policy
+ * or a base policy + list of modules. The dialog may also actually
+ * open the policy or it may be used simply as a file chooser.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef OPEN_POLICY_WINDOW_H
+#define OPEN_POLICY_WINDOW_H
+
+#include "toplevel.h"
+#include <apol/policy-path.h>
+
+/**
+ * Display and run a dialog that allows the user open a policy, either
+ * a monolithic or a modular policy.
+ *
+ * @param top Toplevel for the application.
+ * @param path If not NULL, the default path for the policy.
+ * @param selection If non-NULL, then allocate and set this reference
+ * pointer to the path selected; caller must call
+ * apol_policy_path_destroy() afterwards. Otherwise if NULL then
+ * actually load the policy and set the path tloplvel_open_policy().
+ */
+void open_policy_window_run(toplevel_t * top, const apol_policy_path_t * path, apol_policy_path_t ** selection);
+
+#endif
diff --git a/seaudit/policy_components_view.c b/seaudit/policy_components_view.c
new file mode 100644
index 0000000..c2f1d02
--- /dev/null
+++ b/seaudit/policy_components_view.c
@@ -0,0 +1,373 @@
+/**
+ * @file
+ * Run the dialog to select from lists of strings.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "policy_components_view.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <apol/util.h>
+#include <glade/glade.h>
+
+struct polcomp_view
+{
+ GladeXML *xml;
+ toplevel_t *top;
+ apol_vector_t *log_items, *policy_items, *both_items, *included_items;
+ GtkDialog *dialog;
+
+ GtkRadioButton *log_radio, *policy_radio, *both_radio;
+
+ GtkListStore *master_store;
+ GtkTreeModel *inc_store, *exc_store;
+ GtkTreeView *inc_view, *exc_view;
+ GtkButton *inc_select_button, *inc_unselect_button, *exc_select_button, *exc_unselect_button;
+
+ GtkButton *to_exc_button, *to_inc_button;
+};
+
+enum polcom_columns
+{
+ POINTER_COLUMN = 0, NAME_COLUMN, ISLOG_COLUMN, ISPOLICY_COLUMN, ISINC_COLUMN
+};
+
+static void policy_components_view_init_widgets(struct polcomp_view *pv)
+{
+ pv->dialog = GTK_DIALOG(glade_xml_get_widget(pv->xml, "PolicyComponentListsWindow"));
+ assert(pv->dialog != NULL);
+ gtk_window_set_transient_for(GTK_WINDOW(pv->dialog), toplevel_get_window(pv->top));
+
+ pv->log_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompLogRadio"));
+ pv->policy_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompPolicyRadio"));
+ pv->both_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompBothRadio"));
+ assert(pv->log_radio != NULL && pv->policy_radio != NULL && pv->both_radio != NULL);
+
+ pv->inc_view = GTK_TREE_VIEW(glade_xml_get_widget(pv->xml, "PolicyCompIncView"));
+ pv->exc_view = GTK_TREE_VIEW(glade_xml_get_widget(pv->xml, "PolicyCompExcView"));
+ assert(pv->inc_view != NULL && pv->exc_view != NULL);
+
+ pv->inc_select_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompIncSelectButton"));
+ pv->inc_unselect_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompIncUnselectButton"));
+ pv->exc_select_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompExcSelectButton"));
+ pv->exc_unselect_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompExcUnselectButton"));
+ assert(pv->inc_select_button != NULL && pv->inc_unselect_button &&
+ pv->exc_select_button != NULL && pv->exc_unselect_button);
+
+ pv->to_exc_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompToExcButton"));
+ pv->to_inc_button = GTK_BUTTON(glade_xml_get_widget(pv->xml, "PolicyCompToIncButton"));
+ assert(pv->to_exc_button != NULL && pv->to_inc_button);
+}
+
+/******************** functions to build the lists ********************/
+
+/**
+ * Determine if a particular row should be visible based upon the
+ * current radio button selection. If the current item source is
+ * 'Log' then return TRUE if the islog attribute is enabled. If the
+ * source is 'Policy' then return TRUE if ispolicy is enabled.
+ * Otherwise the item is visible by default.
+ */
+static gboolean policy_components_view_is_visible_radio(struct polcomp_view *pv, gboolean islog, gboolean ispolicy)
+{
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->log_radio))) {
+ return islog;
+ } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->policy_radio))) {
+ return ispolicy;
+ }
+ return TRUE;
+}
+
+/**
+ * Callback invoked to determine if a row should be visible to the
+ * included view.
+ */
+static gboolean policy_components_view_is_visible_included(GtkTreeModel * model, GtkTreeIter * iter, gpointer data)
+{
+ struct polcomp_view *pv = (struct polcomp_view *)data;
+ gboolean islog, ispolicy, isinc;
+ gtk_tree_model_get(model, iter, ISLOG_COLUMN, &islog, ISPOLICY_COLUMN, &ispolicy, ISINC_COLUMN, &isinc, -1);
+ if (!isinc) {
+ return FALSE;
+ }
+ return policy_components_view_is_visible_radio(pv, islog, ispolicy);
+}
+
+/**
+ * Callback invoked to determine if a row should be visible in the
+ * included view.
+ */
+static gboolean policy_components_view_is_visible_excluded(GtkTreeModel * model, GtkTreeIter * iter, gpointer data)
+{
+ struct polcomp_view *pv = (struct polcomp_view *)data;
+ gboolean islog, ispolicy, isinc;
+ gtk_tree_model_get(model, iter, ISLOG_COLUMN, &islog, ISPOLICY_COLUMN, &ispolicy, ISINC_COLUMN, &isinc, -1);
+ if (isinc) {
+ return FALSE;
+ }
+ return policy_components_view_is_visible_radio(pv, islog, ispolicy);
+}
+
+static void policy_components_view_init_lists(struct polcomp_view *pv)
+{
+ GtkTreeIter iter;
+ size_t i, j;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+
+ if ((pv->both_items = apol_vector_create_from_vector(pv->log_items, NULL, NULL, NULL)) == NULL) {
+ toplevel_ERR(pv->top, "Error generating union list: %s", strerror(errno));
+ return;
+ }
+ if (pv->policy_items == NULL) {
+ gtk_widget_set_sensitive(GTK_WIDGET(pv->policy_radio), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(pv->both_radio), FALSE);
+ } else {
+ if (apol_vector_cat(pv->both_items, pv->policy_items) < 0) {
+ toplevel_ERR(pv->top, "Error generating union list: %s", strerror(errno));
+ return;
+ }
+ apol_vector_sort_uniquify(pv->both_items, apol_str_strcmp, NULL);
+ }
+ pv->master_store =
+ gtk_list_store_new(ISINC_COLUMN + 1, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+ for (i = 0; i < apol_vector_get_size(pv->both_items); i++) {
+ char *s = apol_vector_get_element(pv->both_items, i);
+ gboolean is_log = FALSE, is_policy = FALSE, is_included = FALSE;
+ if (apol_vector_get_index(pv->log_items, s, NULL, NULL, &j) == 0) {
+ is_log = TRUE;
+ }
+ if (pv->policy_items != NULL && apol_vector_get_index(pv->policy_items, s, NULL, NULL, &j) == 0) {
+ is_policy = TRUE;
+ }
+ if (apol_vector_get_index(pv->included_items, s, apol_str_strcmp, NULL, &j) == 0) {
+ is_included = TRUE;
+ }
+ gtk_list_store_append(pv->master_store, &iter);
+ gtk_list_store_set(pv->master_store, &iter,
+ POINTER_COLUMN, s,
+ NAME_COLUMN, s, ISLOG_COLUMN, is_log, ISPOLICY_COLUMN, is_policy, ISINC_COLUMN, is_included, -1);
+ }
+
+ pv->inc_store = gtk_tree_model_filter_new(GTK_TREE_MODEL(pv->master_store), NULL);
+ gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(pv->inc_store), policy_components_view_is_visible_included, pv,
+ NULL);
+ pv->exc_store = gtk_tree_model_filter_new(GTK_TREE_MODEL(pv->master_store), NULL);
+ gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(pv->exc_store), policy_components_view_is_visible_excluded, pv,
+ NULL);
+ gtk_tree_view_set_model(pv->inc_view, pv->inc_store);
+ gtk_tree_view_set_model(pv->exc_view, pv->exc_store);
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("Item names", renderer, "text", NAME_COLUMN, NULL);
+ gtk_tree_view_column_set_clickable(column, FALSE);
+ gtk_tree_view_column_set_resizable(column, FALSE);
+ gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_visible(column, TRUE);
+ gtk_tree_view_append_column(pv->inc_view, column);
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes("Item names", renderer, "text", NAME_COLUMN, NULL);
+ gtk_tree_view_column_set_clickable(column, FALSE);
+ gtk_tree_view_column_set_resizable(column, FALSE);
+ gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
+ gtk_tree_view_column_set_visible(column, TRUE);
+ gtk_tree_view_append_column(pv->exc_view, column);
+
+ selection = gtk_tree_view_get_selection(pv->inc_view);
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+ selection = gtk_tree_view_get_selection(pv->exc_view);
+ gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+}
+
+/******************** signal handlers ********************/
+
+static void policy_components_view_on_source_toggle(GtkToggleButton * widget, gpointer user_data)
+{
+ struct polcomp_view *pv = (struct polcomp_view *)user_data;
+ /* clicking on the radio buttons emit two toggle signals, one for
+ * the original button and one for the new one. thus only need to
+ * handle half of all signals */
+ if (!gtk_toggle_button_get_active(widget)) {
+ return;
+ }
+ gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->inc_store));
+ gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->exc_store));
+}
+
+static void policy_components_gtk_tree_path_free(gpointer data, gpointer user_data __attribute__ ((unused)))
+{
+ gtk_tree_path_free((GtkTreePath *) data);
+}
+
+static void policy_components_gtk_tree_row_reference_free(gpointer data, gpointer user_data __attribute__ ((unused)))
+{
+ gtk_tree_row_reference_free((GtkTreeRowReference *) data);
+}
+
+static void policy_components_view_on_to_exc_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct polcomp_view *pv = (struct polcomp_view *)user_data;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(pv->inc_view);
+ GList *r, *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
+ GList *refs = NULL;
+
+ /* use references because the filtered store will be changing
+ * as master_store's ISINC_COLUMN value changes */
+ for (r = rows; r != NULL; r = r->next) {
+ GtkTreePath *path = (GtkTreePath *) r->data;
+ GtkTreeRowReference *ref = gtk_tree_row_reference_new(pv->inc_store, path);
+ refs = g_list_prepend(refs, ref);
+ }
+
+ for (r = refs; r != NULL; r = r->next) {
+ GtkTreeRowReference *ref = (GtkTreeRowReference *) r->data;
+ GtkTreePath *path = gtk_tree_row_reference_get_path(ref);
+ GtkTreeIter iter, child_iter;
+ char *name;
+ size_t i = 0;
+ int retval;
+ gtk_tree_model_get_iter(pv->inc_store, &iter, path);
+ gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(pv->inc_store), &child_iter, &iter);
+ gtk_tree_model_get(GTK_TREE_MODEL(pv->master_store), &child_iter, NAME_COLUMN, &name, -1);
+ gtk_list_store_set(pv->master_store, &child_iter, ISINC_COLUMN, FALSE, -1);
+ retval = apol_vector_get_index(pv->included_items, name, apol_str_strcmp, NULL, &i);
+ assert(retval == 0);
+ name = apol_vector_get_element(pv->included_items, i);
+ free(name);
+ apol_vector_remove(pv->included_items, i);
+ }
+
+ g_list_foreach(refs, policy_components_gtk_tree_row_reference_free, NULL);
+ g_list_free(refs);
+ g_list_foreach(rows, policy_components_gtk_tree_path_free, NULL);
+ g_list_free(rows);
+ gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->inc_store));
+ gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->exc_store));
+}
+
+static void policy_components_view_on_to_inc_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct polcomp_view *pv = (struct polcomp_view *)user_data;
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(pv->exc_view);
+ GList *r, *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
+
+ /* use references because the filtered store will be changing
+ * as master_store's ISINC_COLUMN value changes */
+ GList *refs = NULL;
+ for (r = rows; r != NULL; r = r->next) {
+ GtkTreePath *path = (GtkTreePath *) r->data;
+ GtkTreeRowReference *ref = gtk_tree_row_reference_new(pv->exc_store, path);
+ refs = g_list_prepend(refs, ref);
+ }
+
+ for (r = refs; r != NULL; r = r->next) {
+ GtkTreeRowReference *ref = (GtkTreeRowReference *) r->data;
+ GtkTreePath *path = gtk_tree_row_reference_get_path(ref);
+ GtkTreeIter iter, child_iter;
+ char *name;
+ gtk_tree_model_get_iter(pv->exc_store, &iter, path);
+ gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(pv->exc_store), &child_iter, &iter);
+ gtk_tree_model_get(GTK_TREE_MODEL(pv->master_store), &child_iter, NAME_COLUMN, &name, -1);
+ gtk_list_store_set(pv->master_store, &child_iter, ISINC_COLUMN, TRUE, -1);
+ apol_vector_append(pv->included_items, strdup(name));
+ }
+ apol_vector_sort_uniquify(pv->included_items, apol_str_strcmp, NULL);
+ g_list_foreach(refs, policy_components_gtk_tree_row_reference_free, NULL);
+ g_list_free(refs);
+ g_list_foreach(rows, policy_components_gtk_tree_path_free, NULL);
+ g_list_free(rows);
+ gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->inc_store));
+ gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(pv->exc_store));
+}
+
+static void policy_components_view_on_select_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ GtkTreeView *tv = GTK_TREE_VIEW(user_data);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(tv);
+ gtk_tree_selection_select_all(selection);
+}
+
+static void policy_components_view_on_unselect_click(GtkButton * widget __attribute__ ((unused)), gpointer user_data)
+{
+ GtkTreeView *tv = GTK_TREE_VIEW(user_data);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(tv);
+ gtk_tree_selection_unselect_all(selection);
+}
+
+static void policy_components_view_init_signals(struct polcomp_view *pv)
+{
+ g_signal_connect(pv->log_radio, "toggled", G_CALLBACK(policy_components_view_on_source_toggle), pv);
+ g_signal_connect(pv->policy_radio, "toggled", G_CALLBACK(policy_components_view_on_source_toggle), pv);
+ g_signal_connect(pv->both_radio, "toggled", G_CALLBACK(policy_components_view_on_source_toggle), pv);
+ g_signal_connect(pv->to_exc_button, "clicked", G_CALLBACK(policy_components_view_on_to_exc_click), pv);
+ g_signal_connect(pv->to_inc_button, "clicked", G_CALLBACK(policy_components_view_on_to_inc_click), pv);
+ g_signal_connect(pv->inc_select_button, "clicked", G_CALLBACK(policy_components_view_on_select_click), pv->inc_view);
+ g_signal_connect(pv->inc_unselect_button, "clicked", G_CALLBACK(policy_components_view_on_unselect_click), pv->inc_view);
+ g_signal_connect(pv->exc_select_button, "clicked", G_CALLBACK(policy_components_view_on_select_click), pv->exc_view);
+ g_signal_connect(pv->exc_unselect_button, "clicked", G_CALLBACK(policy_components_view_on_unselect_click), pv->exc_view);
+}
+
+apol_vector_t *policy_components_view_run(toplevel_t * top, GtkWindow * parent __attribute__ ((unused)), const char *title,
+ apol_vector_t * log_items, apol_vector_t * policy_items, apol_vector_t * included)
+{
+ struct polcomp_view pv;
+ gint response;
+
+ memset(&pv, 0, sizeof(pv));
+ pv.top = top;
+ pv.xml = glade_xml_new(toplevel_get_glade_xml(top), "PolicyComponentListsWindow", NULL);
+ pv.log_items = log_items;
+ pv.policy_items = policy_items;
+ if (included == NULL) {
+ pv.included_items = apol_vector_create(free);
+ } else {
+ pv.included_items = apol_vector_create_from_vector(included, apol_str_strdup, NULL, free);
+ }
+ apol_vector_destroy(&included);
+ if (pv.included_items == NULL) {
+ toplevel_ERR(pv.top, "Error creating dialog: %s", strerror(errno));
+ return NULL;
+ }
+
+ policy_components_view_init_widgets(&pv);
+ policy_components_view_init_lists(&pv);
+ policy_components_view_init_signals(&pv);
+ gtk_window_set_title(GTK_WINDOW(pv.dialog), title);
+ do {
+ response = gtk_dialog_run(pv.dialog);
+ } while (response != GTK_RESPONSE_CLOSE);
+
+ gtk_widget_destroy(GTK_WIDGET(pv.dialog));
+ g_object_unref(pv.master_store);
+ g_object_unref(pv.inc_store);
+ g_object_unref(pv.exc_store);
+ apol_vector_destroy(&pv.both_items);
+ if (apol_vector_get_size(pv.included_items) == 0) {
+ apol_vector_destroy(&pv.included_items);
+ return NULL;
+ }
+ return pv.included_items;
+}
diff --git a/seaudit/policy_components_view.h b/seaudit/policy_components_view.h
new file mode 100644
index 0000000..eece365
--- /dev/null
+++ b/seaudit/policy_components_view.h
@@ -0,0 +1,56 @@
+/**
+ * @file
+ * Dialog that shows two columns of strings, an included list and an
+ * excluded list. The user then moves items between the two lists.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef POLICY_COMPONENTS_VIEW_H
+#define POLICY_COMPONENTS_VIEW_H
+
+#include "toplevel.h"
+#include <apol/vector.h>
+#include <gtk/gtk.h>
+
+/**
+ * Display and run a dialog that allows the user to select items from
+ * arrays of strings.
+ *
+ * @param top Toplevel containing message view.
+ * @param parent Parent window upon which to center this dialog.
+ * @param title Title for the dialog window.
+ * @param log_items Vector of strings that the log has. The function
+ * will not modify this vector.
+ * @param policy_items Vector of strings that the policy has. If
+ * NULL, then no policy is loaded. The function will not modify this
+ * vector.
+ * @param included List of strings to be included. The strings are
+ * assumed to have been strdup()ped from some other source. This
+ * function takes ownership of the vector and its contents.
+ *
+ * @return A vector newly allocated strings corresponding to the items
+ * to be included, or NULL upon error. The caller must call
+ * apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *policy_components_view_run(toplevel_t * top, GtkWindow * parent, const char *title,
+ apol_vector_t * log_items, apol_vector_t * policy_items, apol_vector_t * included);
+
+#endif
diff --git a/seaudit/policy_view.c b/seaudit/policy_view.c
new file mode 100644
index 0000000..5fdc9c0
--- /dev/null
+++ b/seaudit/policy_view.c
@@ -0,0 +1,573 @@
+/**
+ * @file
+ * Implementation of policy viewer.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "policy_view.h"
+#include "utilgui.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <apol/policy-query.h>
+#include <apol/util.h>
+#include <glade/glade.h>
+#include <qpol/policy.h>
+#include <qpol/policy_extend.h>
+#include <seaudit/avc_message.h>
+
+/* these are for mmaping the policy file */
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+struct policy_view
+{
+ toplevel_t *top;
+ GladeXML *xml;
+ GtkWindow *window;
+ GtkNotebook *notebook;
+ GtkToggleButton *stype_check, *ttype_check, *class_check;
+ GtkComboBoxEntry *stype_combo, *ttype_combo, *class_combo;
+ GtkToggleButton *stype_direct, *ttype_direct;
+ GtkListStore *type_model, *class_model;
+ apol_vector_t *type_list, *class_list;
+ GtkTextBuffer *rules_text, *policy_text;
+ char *policy_text_mmap;
+ size_t policy_text_len;
+};
+
+/**
+ * Display a vector of rules (either qpol_avrule_t or
+ * qpol_syn_avrule_t) in the rules text buffer.
+ */
+static void policy_view_display_avrule_results(policy_view_t * pv, apol_vector_t * results, int is_syn_rules)
+{
+ apol_policy_t *policy = toplevel_get_policy(pv->top);
+ qpol_policy_t *qp = apol_policy_get_qpol(policy);
+ GtkTextIter start, end;
+ char *string, buf[64];
+ size_t i;
+
+ gtk_text_buffer_get_start_iter(pv->rules_text, &start);
+ gtk_text_buffer_get_end_iter(pv->rules_text, &end);
+ gtk_text_buffer_delete(pv->rules_text, &start, &end);
+
+ snprintf(buf, 64, "%zd rule(s) match the search criteria.\n\n", apol_vector_get_size(results));
+ gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, buf, -1, "summary", NULL);
+ for (i = 0; i < apol_vector_get_size(results); i++) {
+ if (!is_syn_rules) {
+ qpol_avrule_t *rule = apol_vector_get_element(results, i);
+ string = apol_avrule_render(policy, rule);
+ } else {
+ qpol_syn_avrule_t *rule = apol_vector_get_element(results, i);
+ string = apol_syn_avrule_render(policy, rule);
+ unsigned long lineno;
+ if (qpol_policy_has_capability(qp, QPOL_CAP_LINE_NUMBERS)) {
+ qpol_syn_avrule_get_lineno(qp, rule, &lineno);
+ sprintf(buf, "%ld", lineno);
+ gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, "[", -1, "rule", NULL);
+ gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, buf, -1, "line-number", NULL);
+ gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, "] ", -1, "rule", NULL);
+ }
+ }
+ if (string == NULL) {
+ toplevel_ERR(pv->top, "Error displaying rule: %s", strerror(errno));
+ return;
+ }
+ gtk_text_buffer_insert_with_tags_by_name(pv->rules_text, &end, string, -1, "rule", NULL);
+ free(string);
+ gtk_text_buffer_insert(pv->rules_text, &end, "\n", -1);
+ }
+}
+
+struct find_terules_datum
+{
+ apol_policy_t *policy;
+ apol_avrule_query_t *query;
+ apol_vector_t *results;
+ int is_syn_rules, retval;
+ progress_t *progress;
+};
+
+/**
+ * Perform the rule query within a thread.
+ */
+static gpointer policy_view_find_terules_runner(gpointer data)
+{
+ struct find_terules_datum *run = (struct find_terules_datum *)data;
+ run->results = NULL;
+ qpol_policy_t *q = apol_policy_get_qpol(run->policy);
+ if (!qpol_policy_has_capability(q, QPOL_CAP_SYN_RULES)) {
+ progress_update(run->progress, "Searching AV rules");
+ run->retval = apol_avrule_get_by_query(run->policy, run->query, &run->results);
+ run->is_syn_rules = 0;
+ } else {
+ qpol_policy_build_syn_rule_table(q);
+ progress_update(run->progress, "Searching syntactic AV rules");
+ run->retval = apol_syn_avrule_get_by_query(run->policy, run->query, &run->results);
+ run->is_syn_rules = 1;
+ }
+ if (run->retval == 0) {
+ progress_done(run->progress);
+ } else {
+ progress_abort(run->progress, NULL);
+ }
+ return NULL;
+}
+
+/**
+ * Collect the rule search criteria into an avrule_query_t object.
+ * Actually execute the query in a progress thread.
+ */
+static void policy_view_on_find_terules_click(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ policy_view_t *pv = (policy_view_t *) user_data;
+ apol_policy_t *policy = toplevel_get_policy(pv->top);
+ apol_avrule_query_t *query = apol_avrule_query_create();
+ apol_avrule_query_set_regex(policy, query, 1);
+ struct find_terules_datum run;
+ const char *s;
+ gboolean only_direct;
+ apol_avrule_query_set_rules(policy, query, QPOL_RULE_ALLOW);
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->stype_check))) {
+ s = util_combo_box_get_active_text(GTK_COMBO_BOX(pv->stype_combo));
+ only_direct = gtk_toggle_button_get_active(pv->stype_direct);
+ if (strcmp(s, "") == 0) {
+ toplevel_ERR(pv->top, "No source type was selected.");
+ return;
+ }
+ apol_avrule_query_set_source(policy, query, s, only_direct == FALSE);
+ apol_avrule_query_set_source_component(policy, query, APOL_QUERY_SYMBOL_IS_TYPE);
+ }
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->ttype_check))) {
+ s = util_combo_box_get_active_text(GTK_COMBO_BOX(pv->ttype_combo));
+ only_direct = gtk_toggle_button_get_active(pv->ttype_direct);
+ if (strcmp(s, "") == 0) {
+ toplevel_ERR(pv->top, "No target type was selected.");
+ return;
+ }
+ apol_avrule_query_set_target(policy, query, s, only_direct == FALSE);
+ apol_avrule_query_set_source_component(policy, query, APOL_QUERY_SYMBOL_IS_TYPE);
+ }
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pv->class_check))) {
+ s = util_combo_box_get_active_text(GTK_COMBO_BOX(pv->class_combo));
+ if (strcmp(s, "") == 0) {
+ toplevel_ERR(pv->top, "No object class was selected.");
+ return;
+ }
+ apol_avrule_query_append_class(policy, query, s);
+ }
+
+ util_cursor_wait(GTK_WIDGET(pv->window));
+ run.policy = policy;
+ run.query = query;
+ run.progress = toplevel_get_progress(pv->top);
+ progress_show(run.progress, "Finding TE Rules");
+ g_thread_create(policy_view_find_terules_runner, &run, FALSE, NULL);
+ progress_wait(run.progress);
+ progress_hide(run.progress);
+ util_cursor_clear(GTK_WIDGET(pv->window));
+ apol_avrule_query_destroy(&query);
+ if (run.retval == 0) {
+ policy_view_display_avrule_results(pv, run.results, run.is_syn_rules);
+ }
+ apol_vector_destroy(&run.results);
+}
+
+static void policy_view_close(GtkButton * button __attribute__ ((unused)), gpointer user_data)
+{
+ policy_view_t *pv = (policy_view_t *) user_data;
+ gtk_widget_hide(GTK_WIDGET(pv->window));
+}
+
+static gboolean policy_view_on_delete_event(GtkWidget * widget, GdkEvent * event __attribute__ ((unused)), gpointer user_data
+ __attribute__ ((unused)))
+{
+ gtk_widget_hide(widget);
+ return TRUE;
+}
+
+static void policy_view_on_stype_toggle(GtkToggleButton * toggle, gpointer user_data)
+{
+ gboolean sens = gtk_toggle_button_get_active(toggle);
+ policy_view_t *pv = (policy_view_t *) user_data;
+ gtk_widget_set_sensitive(GTK_WIDGET(pv->stype_combo), sens);
+ gtk_widget_set_sensitive(GTK_WIDGET(pv->stype_direct), sens);
+}
+
+static void policy_view_on_ttype_toggle(GtkToggleButton * toggle, gpointer user_data)
+{
+ gboolean sens = gtk_toggle_button_get_active(toggle);
+ policy_view_t *pv = (policy_view_t *) user_data;
+ gtk_widget_set_sensitive(GTK_WIDGET(pv->ttype_combo), sens);
+ gtk_widget_set_sensitive(GTK_WIDGET(pv->ttype_direct), sens);
+}
+
+static void policy_view_on_class_toggle(GtkToggleButton * toggle, gpointer user_data)
+{
+ gboolean sens = gtk_toggle_button_get_active(toggle);
+ policy_view_t *pv = (policy_view_t *) user_data;
+ gtk_widget_set_sensitive(GTK_WIDGET(pv->class_combo), sens);
+
+}
+
+static gboolean policy_view_on_line_event(GtkTextTag * tag
+ __attribute__ ((unused)), GObject * event_object
+ __attribute__ ((unused)), GdkEvent * event, const GtkTextIter * iter, gpointer user_data)
+{
+ policy_view_t *pv = (policy_view_t *) user_data;
+ GtkTextIter start, end;
+ int line;
+ GtkTextView *view;
+ if (event->type != GDK_BUTTON_PRESS) {
+ return FALSE;
+ }
+ start = *iter;
+ while (!gtk_text_iter_starts_word(&start))
+ gtk_text_iter_backward_char(&start);
+ end = start;
+ while (!gtk_text_iter_ends_word(&end))
+ gtk_text_iter_forward_char(&end);
+ /* subtract 1 because text buffers are indexed from 0 */
+ line = atoi(gtk_text_iter_get_slice(&start, &end)) - 1;
+ view = GTK_TEXT_VIEW(glade_xml_get_widget(pv->xml, "PolicyWindowPolicyText"));
+ assert(view != NULL);
+ gtk_notebook_set_current_page(pv->notebook, 1);
+ gtk_text_buffer_get_start_iter(pv->policy_text, &start);
+ gtk_text_iter_set_line(&start, line);
+ gtk_text_view_scroll_to_iter(view, &start, 0.0001, TRUE, 0.0, 0.5);
+ gtk_text_buffer_place_cursor(pv->policy_text, &start);
+ gtk_text_view_set_cursor_visible(view, TRUE);
+ return TRUE;
+}
+
+static gboolean policy_view_on_rules_motion(GtkWidget * widget, GdkEventMotion * event, gpointer user_data __attribute__ ((unused)))
+{
+ GtkTextView *textview = GTK_TEXT_VIEW(widget);
+ gint x, ex, y, ey;
+ GtkTextIter iter;
+ GSList *tags, *tagp;
+ int hovering = 0;
+ if (event->is_hint) {
+ gdk_window_get_pointer(event->window, &ex, &ey, NULL);
+ } else {
+ ex = event->x;
+ ey = event->y;
+ }
+ gtk_text_view_window_to_buffer_coords(textview, GTK_TEXT_WINDOW_WIDGET, ex, ey, &x, &y);
+ gtk_text_view_get_iter_at_location(textview, &iter, x, y);
+ tags = gtk_text_iter_get_tags(&iter);
+ for (tagp = tags; tagp != NULL; tagp = tagp->next) {
+ if (strcmp(GTK_TEXT_TAG(tagp->data)->name, "line-number") == 0) {
+ hovering = TRUE;
+ break;
+ }
+ }
+ if (hovering) {
+ GdkCursor *cursor = gdk_cursor_new(GDK_HAND2);
+ gdk_window_set_cursor(event->window, cursor);
+ gdk_cursor_unref(cursor);
+ gdk_flush();
+ } else {
+ gdk_window_set_cursor(event->window, NULL);
+ }
+ g_slist_free(tags);
+ return FALSE;
+}
+
+/**
+ * Create a text buffer to hold the results of running the TE rules
+ * search. Initialize its tags and add event handlers to the
+ * "line-number" tag, such that clicking on the tag jumps to the
+ * policy's line and hovering over the tag changes the cursor.
+ */
+static void policy_view_create_rules_buffer(policy_view_t * pv)
+{
+ GtkTextView *rules_textview;
+ GtkTextTagTable *table;
+ GtkTextTag *tag;
+ rules_textview = GTK_TEXT_VIEW(glade_xml_get_widget(pv->xml, "PolicyWindowTERulesResults"));
+ assert(rules_textview != NULL);
+ pv->rules_text = gtk_text_buffer_new(NULL);
+ gtk_text_view_set_buffer(rules_textview, pv->rules_text);
+ table = gtk_text_buffer_get_tag_table(pv->rules_text);
+ gtk_text_buffer_create_tag(pv->rules_text, "summary", "family", "monospace", "weight", "bold", NULL);
+ tag = gtk_text_buffer_create_tag(pv->rules_text, "line-number",
+ "family", "monospace", "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL);
+ g_signal_connect(G_OBJECT(tag), "event", G_CALLBACK(policy_view_on_line_event), pv);
+ g_signal_connect(rules_textview, "motion-notify-event", G_CALLBACK(policy_view_on_rules_motion), NULL);
+ gtk_text_buffer_create_tag(pv->rules_text, "rule", "family", "monospace", NULL);
+}
+
+policy_view_t *policy_view_create(toplevel_t * top)
+{
+ GtkWidget *w;
+ GtkTextView *policy_textview;
+ policy_view_t *pv;
+ if ((pv = calloc(1, sizeof(*pv))) == NULL) {
+ return NULL;
+ }
+ pv->top = top;
+ pv->xml = glade_xml_new(toplevel_get_glade_xml(top), "PolicyWindow", NULL);
+ pv->window = GTK_WINDOW(glade_xml_get_widget(pv->xml, "PolicyWindow"));
+ assert(pv->window != NULL);
+ gtk_window_set_transient_for(pv->window, toplevel_get_window(top));
+ pv->notebook = GTK_NOTEBOOK(glade_xml_get_widget(pv->xml, "PolicyWindowNotebook"));
+ assert(pv->notebook != NULL);
+
+ pv->stype_check = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowSTypeCheck"));
+ pv->ttype_check = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowTTypeCheck"));
+ pv->class_check = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowClassCheck"));
+ assert(pv->stype_check != NULL && pv->ttype_check != NULL && pv->class_check != NULL);
+ g_signal_connect(pv->stype_check, "toggled", G_CALLBACK(policy_view_on_stype_toggle), pv);
+ g_signal_connect(pv->ttype_check, "toggled", G_CALLBACK(policy_view_on_ttype_toggle), pv);
+ g_signal_connect(pv->class_check, "toggled", G_CALLBACK(policy_view_on_class_toggle), pv);
+
+ pv->stype_combo = GTK_COMBO_BOX_ENTRY(glade_xml_get_widget(pv->xml, "PolicyWindowSTypeCombo"));
+ pv->ttype_combo = GTK_COMBO_BOX_ENTRY(glade_xml_get_widget(pv->xml, "PolicyWindowTTypeCombo"));
+ pv->class_combo = GTK_COMBO_BOX_ENTRY(glade_xml_get_widget(pv->xml, "PolicyWindowClassCombo"));
+ assert(pv->stype_combo != NULL && pv->ttype_combo != NULL && pv->class_combo != NULL);
+ pv->type_model = gtk_list_store_new(1, G_TYPE_STRING);
+ pv->class_model = gtk_list_store_new(1, G_TYPE_STRING);
+ gtk_combo_box_set_model(GTK_COMBO_BOX(pv->stype_combo), GTK_TREE_MODEL(pv->type_model));
+ gtk_combo_box_set_model(GTK_COMBO_BOX(pv->ttype_combo), GTK_TREE_MODEL(pv->type_model));
+ gtk_combo_box_set_model(GTK_COMBO_BOX(pv->class_combo), GTK_TREE_MODEL(pv->class_model));
+ gtk_combo_box_entry_set_text_column(pv->stype_combo, 0);
+ gtk_combo_box_entry_set_text_column(pv->ttype_combo, 0);
+ gtk_combo_box_entry_set_text_column(pv->class_combo, 0);
+
+ pv->stype_direct = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowSTypeDirectCheck"));
+ pv->ttype_direct = GTK_TOGGLE_BUTTON(glade_xml_get_widget(pv->xml, "PolicyWindowTTypeDirectCheck"));
+ assert(pv->stype_direct != NULL && pv->ttype_direct != NULL);
+
+ policy_view_create_rules_buffer(pv);
+
+ policy_textview = GTK_TEXT_VIEW(glade_xml_get_widget(pv->xml, "PolicyWindowPolicyText"));
+ assert(policy_textview != NULL);
+ pv->policy_text = gtk_text_buffer_new(NULL);
+ gtk_text_view_set_buffer(policy_textview, pv->policy_text);
+
+ /* set up signal handlers for the widgets */
+
+ w = glade_xml_get_widget(pv->xml, "PolicyWindowFindTERulesButton");
+ assert(w != NULL);
+ g_signal_connect(w, "clicked", G_CALLBACK(policy_view_on_find_terules_click), pv);
+
+ w = glade_xml_get_widget(pv->xml, "PolicyWindowCloseButton");
+ assert(w != NULL);
+ g_signal_connect(w, "clicked", G_CALLBACK(policy_view_close), pv);
+ g_signal_connect(pv->window, "delete_event", G_CALLBACK(policy_view_on_delete_event), NULL);
+
+ policy_view_update(pv, NULL);
+ return pv;
+}
+
+void policy_view_destroy(policy_view_t ** pv)
+{
+ if (pv != NULL && *pv != NULL) {
+ apol_vector_destroy(&(*pv)->type_list);
+ apol_vector_destroy(&(*pv)->class_list);
+ free(*pv);
+ *pv = NULL;
+ }
+}
+
+/**
+ * If the currently loaded policy is a source policy, then load its
+ * contents into the policy text buffer. Otherwise let the user know
+ * that the policy is binary.
+ *
+ * @param pv Policy view's policy source tab to update.
+ * @param path Path to the currently loaded policy, or NULL if no
+ * policy is loaded.
+ */
+static void policy_view_load_policy_source(policy_view_t * pv, apol_policy_path_t * path)
+{
+ apol_policy_t *policy = toplevel_get_policy(pv->top);
+ const char *primary_path;
+ if (path == NULL) {
+ gtk_text_buffer_set_text(pv->policy_text, "No policy has been loaded.", -1);
+ return;
+ }
+ primary_path = apol_policy_path_get_primary(path);
+ if (!qpol_policy_has_capability(apol_policy_get_qpol(policy), QPOL_CAP_SOURCE)) {
+ GString *string = g_string_new("");
+ g_string_printf(string, "Policy file %s is not a source policy.", primary_path);
+ gtk_text_buffer_set_text(pv->policy_text, string->str, -1);
+ g_string_free(string, TRUE);
+ } else {
+ /* load the policy by mmap()ing the file */
+ struct stat statbuf;
+ int fd;
+ if (pv->policy_text_mmap != NULL) {
+ munmap(pv->policy_text_mmap, pv->policy_text_len);
+ }
+
+ pv->policy_text_mmap = NULL;
+ pv->policy_text_len = 0;
+
+ if ((fd = open(primary_path, O_RDONLY)) < 0) {
+ toplevel_ERR(pv->top, "Could not open %s for reading.", primary_path);
+ return;
+ }
+ if (fstat(fd, &statbuf) < 0) {
+ close(fd);
+ toplevel_ERR(pv->top, "Could not stat %s.", primary_path);
+ return;
+ }
+
+ pv->policy_text_len = statbuf.st_size;
+ if ((pv->policy_text_mmap = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+ close(fd);
+ pv->policy_text_mmap = NULL;
+ toplevel_ERR(pv->top, "Could not mmap %s.", primary_path);
+ return;
+ }
+ close(fd);
+ gtk_text_buffer_set_text(pv->policy_text, pv->policy_text_mmap, pv->policy_text_len);
+ }
+}
+
+/**
+ * If a policy is currently loaded then set the rule search combo box
+ * menus to that policy's components. Otherwies clear the combo box
+ * menus.
+ *
+ * @param pv Policy view's rule search boxes to modify.
+ */
+static void policy_view_populate_combo_boxes(policy_view_t * pv)
+{
+ apol_policy_t *policy = toplevel_get_policy(pv->top);
+ gtk_list_store_clear(pv->type_model);
+ gtk_list_store_clear(pv->class_model);
+ apol_vector_destroy(&pv->type_list);
+ apol_vector_destroy(&pv->class_list);
+ pv->type_list = apol_vector_create(NULL);
+ pv->class_list = apol_vector_create(NULL);
+ if (policy != NULL) {
+ qpol_policy_t *qp = apol_policy_get_qpol(policy);
+ size_t i;
+ const qpol_type_t *type;
+ const qpol_class_t *obj_class;
+ const char *s;
+ GtkTreeIter iter;
+ apol_vector_t *v;
+ apol_type_get_by_query(policy, NULL, &v);
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ type = apol_vector_get_element(v, i);
+ qpol_type_get_name(qp, type, &s);
+ apol_vector_append(pv->type_list, (void *)s);
+ }
+ apol_vector_destroy(&v);
+ apol_vector_sort(pv->type_list, apol_str_strcmp, NULL);
+ for (i = 0; i < apol_vector_get_size(pv->type_list); i++) {
+ s = apol_vector_get_element(pv->type_list, i);
+#ifdef GTK_2_8
+ gtk_list_store_insert_with_values(pv->type_model, &iter, i, 0, s, -1);
+#else
+ gtk_list_store_insert(pv->type_model, &iter, i);
+ gtk_list_store_set(pv->type_model, &iter, 0, s, -1);
+#endif
+ }
+ apol_class_get_by_query(policy, NULL, &v);
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ obj_class = apol_vector_get_element(v, i);
+ qpol_class_get_name(qp, obj_class, &s);
+ apol_vector_append(pv->class_list, (void *)s);
+ }
+ apol_vector_destroy(&v);
+ apol_vector_sort(pv->class_list, apol_str_strcmp, NULL);
+ for (i = 0; i < apol_vector_get_size(pv->class_list); i++) {
+ s = apol_vector_get_element(pv->class_list, i);
+#ifdef GTK_2_8
+ gtk_list_store_insert_with_values(pv->class_model, &iter, i, 0, s, -1);
+#else
+ gtk_list_store_insert(pv->class_model, &iter, i);
+ gtk_list_store_set(pv->class_model, &iter, 0, s, -1);
+#endif
+ }
+ }
+}
+
+void policy_view_update(policy_view_t * pv, apol_policy_path_t * path)
+{
+ GtkTextIter start, end;
+ policy_view_load_policy_source(pv, path);
+ policy_view_populate_combo_boxes(pv);
+ gtk_text_buffer_get_start_iter(pv->rules_text, &start);
+ gtk_text_buffer_get_end_iter(pv->rules_text, &end);
+ gtk_text_buffer_delete(pv->rules_text, &start, &end);
+
+}
+
+void policy_view_find_terules(policy_view_t * pv, seaudit_message_t * message)
+{
+ seaudit_message_type_e type = SEAUDIT_MESSAGE_TYPE_INVALID;
+ void *data = NULL;
+ const char *stype = "", *ttype = "", *obj_class = "";
+ size_t i;
+ assert(pv->type_list != NULL);
+ assert(pv->class_list != NULL);
+ if (message != NULL) {
+ data = seaudit_message_get_data(message, &type);
+ }
+ if (type == SEAUDIT_MESSAGE_TYPE_AVC) {
+ seaudit_avc_message_t *avc = data;
+ if ((stype = seaudit_avc_message_get_source_type(avc)) == NULL) {
+ stype = "";
+ }
+ if ((ttype = seaudit_avc_message_get_target_type(avc)) == NULL) {
+ ttype = "";
+ }
+ if ((obj_class = seaudit_avc_message_get_object_class(avc)) == NULL) {
+ obj_class = "";
+ }
+ }
+ if (strcmp(stype, "") == 0 || apol_vector_get_index(pv->type_list, stype, apol_str_strcmp, NULL, &i) < 0) {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(pv->stype_combo), -1);
+ gtk_toggle_button_set_active(pv->stype_check, FALSE);
+ } else {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(pv->stype_combo), i);
+ gtk_toggle_button_set_active(pv->stype_check, TRUE);
+ }
+ if (strcmp(ttype, "") == 0 || apol_vector_get_index(pv->type_list, ttype, apol_str_strcmp, NULL, &i) < 0) {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(pv->ttype_combo), -1);
+ gtk_toggle_button_set_active(pv->ttype_check, FALSE);
+ } else {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(pv->ttype_combo), i);
+ gtk_toggle_button_set_active(pv->ttype_check, TRUE);
+ }
+ if (strcmp(obj_class, "") == 0 || apol_vector_get_index(pv->class_list, obj_class, apol_str_strcmp, NULL, &i) < 0) {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(pv->class_combo), -1);
+ gtk_toggle_button_set_active(pv->class_check, FALSE);
+ } else {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(pv->class_combo), i);
+ gtk_toggle_button_set_active(pv->class_check, TRUE);
+ }
+ gtk_notebook_set_current_page(pv->notebook, 0);
+ gtk_widget_show(GTK_WIDGET(pv->window));
+}
diff --git a/seaudit/policy_view.h b/seaudit/policy_view.h
new file mode 100644
index 0000000..17b23ed
--- /dev/null
+++ b/seaudit/policy_view.h
@@ -0,0 +1,77 @@
+/**
+ * @file
+ * Declaration of viewer for the currently loaded policy.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef POLICY_VIEW_H
+#define POLICY_VIEW_H
+
+#include "toplevel.h"
+
+#include <seaudit/message.h>
+
+typedef struct policy_view policy_view_t;
+
+/**
+ * Create a new policy view object. This is used to display the
+ * policy's content and to search for TE rules.
+ *
+ * @param top Toplevel object that will control the newly opened
+ * policy view.
+ *
+ * @return An initialized policy view object, or NULL upon error. The
+ * caller must call policy_view_destroy() upon the returned value.
+ */
+policy_view_t *policy_view_create(toplevel_t * top);
+
+/**
+ * Destroy the policy view object. This does nothing if the pointer
+ * is set to NULL.
+ *
+ * @param pv Reference to a policy view object. Afterwards the
+ * pointer will be set to NULL.
+ */
+void policy_view_destroy(policy_view_t ** pv);
+
+/**
+ * (Re)synchronize the policy displayed in the viewer with the one
+ * actually loaded. If there is no policy loaded then clear the
+ * viewer's contents.
+ *
+ * @param pv Policy view to update.
+ * @param path Path to the policy, or NULL if no policy is loaded.
+ */
+void policy_view_update(policy_view_t * pv, apol_policy_path_t * path);
+
+/**
+ * (Re)open the policy view window to allow the user to search for TE
+ * rules in the currently opened policy. If message is not NULL then
+ * set the query's initial parameters to the message's source type,
+ * target type, and object class.
+ *
+ * @param pv Policy view object. Note that a policy must already
+ * exist and policy_view_update() must be first called.
+ * @param message If non-NULL, the initial parameters for query.
+ */
+void policy_view_find_terules(policy_view_t * pv, seaudit_message_t * message);
+
+#endif
diff --git a/seaudit/preferences.c b/seaudit/preferences.c
new file mode 100644
index 0000000..5e65385
--- /dev/null
+++ b/seaudit/preferences.c
@@ -0,0 +1,585 @@
+/**
+ * @file
+ * Implementation of the storage class preferences_t.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "preferences.h"
+
+#include <apol/util.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** default frequency, in milliseconds, to poll log file for changes */
+#define DEFAULT_LOG_UPDATE_INTERVAL 1000
+
+/** maximum number of recent log files and recent policy files to remember */
+#define MAX_RECENT_ENTRIES 5
+
+/** name of the user's seaudit personal preferences file */
+#define USER_SEAUDIT_CONF ".seaudit"
+
+/** name of the system seaudit preference file */
+#define SYSTEM_SEAUDIT_CONF "dot_seaudit"
+
+struct visible_field
+{
+ preference_field_e id;
+ const char *field;
+ int visible;
+};
+
+static const struct visible_field default_visible_fields[] = {
+ {HOST_FIELD, "host_field", 1},
+ {MESSAGE_FIELD, "msg_field", 1},
+ {DATE_FIELD, "date_field", 1},
+ {SUSER_FIELD, "src_usr_field", 0},
+ {SROLE_FIELD, "src_role_field", 0},
+ {STYPE_FIELD, "src_type_field", 1},
+ {SMLS_LVL_FIELD, "src_mls_lvl_field", 0},
+ {SMLS_CLR_FIELD, "src_mls_clr_field", 0},
+ {TUSER_FIELD, "tgt_usr_field", 0},
+ {TROLE_FIELD, "tgt_role_field", 0},
+ {TTYPE_FIELD, "tgt_type_field", 1},
+ {TMLS_LVL_FIELD, "tgt_mls_lvl_field", 0},
+ {TMLS_CLR_FIELD, "tgt_mls_clr_field", 0},
+ {OBJCLASS_FIELD, "obj_class_field", 1},
+ {PERM_FIELD, "perm_field", 1},
+ {EXECUTABLE_FIELD, "exe_field", 1},
+ {COMMAND_FIELD, "comm_field", 1},
+ {NAME_FIELD, "name_field", 0},
+ {PID_FIELD, "pid_field", 0},
+ {INODE_FIELD, "inode_field", 0},
+ {PATH_FIELD, "path_field", 0},
+ {OTHER_FIELD, "other_field", 1}
+};
+
+static const size_t num_visible_fields = sizeof(default_visible_fields) / sizeof(default_visible_fields[0]);
+
+struct preferences
+{
+ /** path to default system log file */
+ char *log;
+ /** path to default policy */
+ apol_policy_path_t *policy;
+ /** default path when writing reports */
+ char *report;
+ /** default path to the stylesheet, used during report writing */
+ char *stylesheet;
+ /** vector of paths (strings) to recently opened log files */
+ apol_vector_t *recent_log_files;
+ /** vector of apol_policy_path_t objects to recently opened
+ policies */
+ apol_vector_t *recent_policy_files;
+ /** non-zero if seaudit should poll the log file for changes */
+ int real_time_log;
+ /** frequency, in milliesconds, to poll log file */
+ int real_time_interval;
+ struct visible_field *fields;
+};
+
+void preferences_apol_policy_path_free(void *elem)
+{
+ apol_policy_path_t *path = elem;
+ apol_policy_path_destroy(&path);
+}
+
+/**
+ * Parse the old-style recent policies list (a ':' separated list of
+ * paths) into the recent_policy_files field.
+ */
+static int preferences_parse_old_recent_files(preferences_t * prefs, const char *s)
+{
+ apol_vector_t *v = NULL;
+ size_t i;
+ char *base;
+ apol_policy_path_t *path;
+ int error = 0;
+
+ if ((v = apol_str_split(s, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ base = apol_vector_get_element(v, i);
+ if ((path = apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, base, NULL)) == NULL ||
+ apol_vector_append(prefs->recent_policy_files, path) < 0) {
+ error = errno;
+ apol_policy_path_destroy(&path);
+ goto cleanup;
+ }
+ }
+
+ cleanup:
+ apol_vector_destroy(&v);
+ if (error != 0) {
+ errno = error;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Parse the new recent policy files, which now spans across multiple
+ * lines.
+ */
+static int preferences_parse_new_recent_files(preferences_t * prefs, FILE * f, int num_files)
+{
+ int count;
+ for (count = 0; count < num_files; count++) {
+ char *var_name, *value = NULL;
+ apol_policy_path_t *p = NULL;
+ if (asprintf(&var_name, "RECENT_POLICY_PATH_%d", count) < 0) {
+ return -1;
+ }
+ value = apol_config_get_var(var_name, f);
+ free(var_name);
+ if (value == NULL ||
+ (p = apol_policy_path_create_from_string(value)) == NULL ||
+ apol_vector_append(prefs->recent_policy_files, p) < 0) {
+ free(value);
+ apol_policy_path_destroy(&p);
+ return -1;
+ }
+ free(value);
+ }
+ return 0;
+}
+
+preferences_t *preferences_create(void)
+{
+ preferences_t *prefs = NULL;
+ FILE *file = NULL;
+ char *path = NULL, *value;
+ apol_vector_t *v = NULL;
+ size_t i, j;
+ int error = 0;
+
+ if ((prefs = calloc(1, sizeof(*prefs))) == NULL ||
+ (prefs->log = strdup("")) == NULL ||
+ (prefs->report = strdup("")) == NULL ||
+ (prefs->stylesheet = strdup("")) == NULL ||
+ (prefs->recent_log_files = apol_vector_create(free)) == NULL ||
+ (prefs->recent_policy_files = apol_vector_create(preferences_apol_policy_path_free)) == NULL ||
+ (prefs->fields = calloc(num_visible_fields, sizeof(struct visible_field))) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ prefs->real_time_interval = DEFAULT_LOG_UPDATE_INTERVAL;
+ memcpy(prefs->fields, default_visible_fields, num_visible_fields * sizeof(struct visible_field));
+ path = apol_file_find_user_config(USER_SEAUDIT_CONF);
+ if (!path) {
+ if ((path = apol_file_find_path(SYSTEM_SEAUDIT_CONF)) == NULL) {
+ return prefs;
+ }
+ }
+ if ((file = fopen(path, "r")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((value = apol_config_get_var("DEFAULT_LOG_FILE", file)) != NULL) {
+ free(prefs->log);
+ prefs->log = value;
+ }
+ if ((value = apol_config_get_var("DEFAULT_POLICY_FILE", file)) != NULL) {
+ apol_policy_path_destroy(&prefs->policy);
+ if (apol_policy_path_create(APOL_POLICY_PATH_TYPE_MONOLITHIC, value, NULL) == NULL) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ free(value);
+ }
+ if ((value = apol_config_get_var("DEFAULT_POLICY_PATH", file)) != NULL) {
+ apol_policy_path_destroy(&prefs->policy);
+ if ((prefs->policy = apol_policy_path_create_from_string(value)) == NULL) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ free(value);
+ }
+ if ((value = apol_config_get_var("DEFAULT_REPORT_CONFIG_FILE", file)) != NULL) {
+ free(prefs->report);
+ prefs->report = value;
+ }
+ if ((value = apol_config_get_var("DEFAULT_REPORT_CSS_FILE", file)) != NULL) {
+ free(prefs->stylesheet);
+ prefs->stylesheet = value;
+ }
+ if ((value = apol_config_get_var("RECENT_LOG_FILES", file)) == NULL || (v = apol_str_split(value, ":")) == NULL) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ free(value);
+ apol_vector_destroy(&prefs->recent_log_files);
+ prefs->recent_log_files = v;
+
+ /* test if there exists the new recent list that contains
+ * module filenames */
+ if ((value = apol_config_get_var("RECENT_POLICY_PATH_FILES", file)) != NULL) {
+ if (preferences_parse_new_recent_files(prefs, file, atoi(value)) < 0) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ } else {
+ /* use older style that could only handle monolithic policies */
+ if ((value = apol_config_get_var("RECENT_POLICY_FILES", file)) == NULL
+ || preferences_parse_old_recent_files(prefs, value) < 0) {
+ error = errno;
+ free(value);
+ goto cleanup;
+ }
+ }
+ free(value);
+
+ if ((value = apol_config_get_var("LOG_COLUMNS_HIDDEN", file)) == NULL || (v = apol_str_split(value, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ for (j = 0; j < num_visible_fields; j++) {
+ prefs->fields[j].visible = 1;
+ }
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ char *s = apol_vector_get_element(v, i);
+ for (j = 0; j < num_visible_fields; j++) {
+ if (strcmp(s, prefs->fields[j].field) == 0) {
+ prefs->fields[j].visible = 0;
+ break;
+ }
+ }
+ }
+ free(value);
+ apol_vector_destroy(&v);
+ value = apol_config_get_var("REAL_TIME_LOG_MONITORING", file);
+ if (value != NULL && value[0] != '0') {
+ prefs->real_time_log = 1;
+ }
+ free(value);
+ value = apol_config_get_var("REAL_TIME_LOG_UPDATE_INTERVAL", file);
+ if (value != NULL) {
+ prefs->real_time_interval = atoi(value);
+ }
+ free(value);
+ cleanup:
+ free(path);
+ if (file != NULL) {
+ fclose(file);
+ }
+ if (error != 0) {
+ preferences_destroy(&prefs);
+ errno = error;
+ return NULL;
+ }
+ return prefs;
+}
+
+void preferences_destroy(preferences_t ** prefs)
+{
+ if (prefs != NULL && *prefs != NULL) {
+ free((*prefs)->log);
+ apol_policy_path_destroy(&(*prefs)->policy);
+ free((*prefs)->report);
+ free((*prefs)->stylesheet);
+ apol_vector_destroy(&(*prefs)->recent_log_files);
+ apol_vector_destroy(&(*prefs)->recent_policy_files);
+ free((*prefs)->fields);
+ free(*prefs);
+ *prefs = NULL;
+ }
+}
+
+int preferences_write_to_conf_file(preferences_t * prefs)
+{
+ FILE *file = NULL;
+ char *home, *conf_file = NULL, *value;
+ apol_vector_t *hidden_fields = NULL;
+ size_t i;
+ int retval = 0, error = 0;
+
+ /* we need to open ~/.seaudit */
+ home = getenv("HOME");
+ if (!home) {
+ error = EBADRQC;
+ goto cleanup;
+ }
+ if (asprintf(&conf_file, "%s/%s", home, USER_SEAUDIT_CONF) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+
+ if ((file = fopen(conf_file, "w")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+
+ fprintf(file, "# configuration file for seaudit - an audit log tool for Security Enhanced Linux.\n");
+ fprintf(file, "# this file is auto-generated\n\n");
+
+ if (strcmp(prefs->log, "") != 0) {
+ fprintf(file, "DEFAULT_LOG_FILE %s\n", prefs->log);
+ }
+ if (prefs->policy != NULL) {
+ value = apol_policy_path_to_string(prefs->policy);
+ if (value == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "DEFAULT_POLICY_PATH %s\n", value);
+ free(value);
+ }
+ if (strcmp(prefs->report, "") != 0) {
+ fprintf(file, "DEFAULT_REPORT_CONFIG_FILE %s\n", prefs->report);
+ }
+ if (strcmp(prefs->stylesheet, "") != 0) {
+ fprintf(file, "DEFAULT_REPORT_CSS_FILE %s\n", prefs->stylesheet);
+ }
+ if ((value = apol_str_join(prefs->recent_log_files, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "RECENT_LOG_FILES %s\n", value);
+ free(value);
+
+ fprintf(file, "RECENT_POLICY_PATH_FILES %zd\n", apol_vector_get_size(prefs->recent_policy_files));
+ for (i = 0; i < apol_vector_get_size(prefs->recent_policy_files); i++) {
+ apol_policy_path_t *p = apol_vector_get_element(prefs->recent_policy_files, i);
+ if ((value = apol_policy_path_to_string(p)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "RECENT_POLICY_PATH_%zd %s\n", i, value);
+ free(value);
+ }
+
+ if ((hidden_fields = apol_vector_create(NULL)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ for (i = 0; i < num_visible_fields; i++) {
+ if (!prefs->fields[i].visible && apol_vector_append(hidden_fields, (char *)prefs->fields[i].field) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ }
+ if ((value = apol_str_join(hidden_fields, ":")) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ fprintf(file, "LOG_COLUMNS_HIDDEN %s\n", value);
+ free(value);
+ fprintf(file, "REAL_TIME_LOG_MONITORING %d\n", prefs->real_time_log);
+ fprintf(file, "REAL_TIME_LOG_UPDATE_INTERVAL %d\n", prefs->real_time_interval);
+ retval = 0;
+ cleanup:
+ free(conf_file);
+ apol_vector_destroy(&hidden_fields);
+ if (file != NULL) {
+ fclose(file);
+ }
+ errno = error;
+ return retval;
+}
+
+int preferences_is_column_visible(preferences_t * prefs, preference_field_e id)
+{
+ size_t i;
+ for (i = 0; i < num_visible_fields; i++) {
+ if (prefs->fields[i].id == id) {
+ return prefs->fields[i].visible;
+ }
+ }
+ assert(0);
+ return -1;
+}
+
+void preferences_set_column_visible(preferences_t * prefs, preference_field_e id, int visible)
+{
+ size_t i;
+ for (i = 0; i < num_visible_fields; i++) {
+ if (prefs->fields[i].id == id) {
+ prefs->fields[i].visible = visible;
+ return;
+ }
+ }
+ assert(0);
+}
+
+int preferences_set_log(preferences_t * prefs, const char *log)
+{
+ char *s;
+ if ((s = strdup(log)) == NULL) {
+ return -1;
+ }
+ free(prefs->log);
+ prefs->log = s;
+ return 0;
+}
+
+const char *preferences_get_log(preferences_t * prefs)
+{
+ return prefs->log;
+}
+
+int preferences_set_policy(preferences_t * prefs, const apol_policy_path_t * policy)
+{
+ apol_policy_path_t *new_policy;
+ if ((new_policy = apol_policy_path_create_from_policy_path(policy)) == NULL) {
+ return -1;
+ }
+ apol_policy_path_destroy(&prefs->policy);
+ prefs->policy = new_policy;
+ return 0;
+}
+
+const apol_policy_path_t *preferences_get_policy(preferences_t * prefs)
+{
+ return prefs->policy;
+}
+
+int preferences_set_report(preferences_t * prefs, const char *report)
+{
+ char *s;
+ if ((s = strdup(report)) == NULL) {
+ return -1;
+ }
+ free(prefs->report);
+ prefs->report = s;
+ return 0;
+}
+
+const char *preferences_get_report(preferences_t * prefs)
+{
+ return prefs->report;
+}
+
+int preferences_set_stylesheet(preferences_t * prefs, const char *stylesheet)
+{
+ char *s;
+ if ((s = strdup(stylesheet)) == NULL) {
+ return -1;
+ }
+ free(prefs->stylesheet);
+ prefs->stylesheet = s;
+ return 0;
+}
+
+const char *preferences_get_stylesheet(preferences_t * prefs)
+{
+ return prefs->stylesheet;
+}
+
+void preferences_set_real_time_at_startup(preferences_t * prefs, int startup)
+{
+ prefs->real_time_log = startup;
+}
+
+int preferences_get_real_time_at_startup(preferences_t * prefs)
+{
+ return prefs->real_time_log;
+}
+
+void preferences_set_real_time_interval(preferences_t * prefs, int interval)
+{
+ if (interval <= 0) {
+ prefs->real_time_interval = 0;
+ } else {
+ prefs->real_time_interval = interval;
+ }
+}
+
+int preferences_get_real_time_interval(preferences_t * prefs)
+{
+ return prefs->real_time_interval;
+}
+
+/**
+ * Add an entry to a vector, discarding the oldest entry if the vector
+ * size is too large.
+ */
+static int prefs_add_recent_vector(apol_vector_t * v, const char *entry)
+{
+ size_t i;
+ char *s;
+ if (apol_vector_get_index(v, (void *)entry, apol_str_strcmp, NULL, &i) == 0) {
+ return 0;
+ }
+ if ((s = strdup(entry)) == NULL || apol_vector_append(v, s) < 0) {
+ int error = errno;
+ free(s);
+ errno = error;
+ return -1;
+ }
+ if (apol_vector_get_size(v) >= MAX_RECENT_ENTRIES) {
+ s = apol_vector_get_element(v, 0);
+ free(s);
+ return apol_vector_remove(v, 0);
+ }
+ return 0;
+}
+
+int preferences_add_recent_log(preferences_t * prefs, const char *log)
+{
+ return prefs_add_recent_vector(prefs->recent_log_files, log);
+}
+
+apol_vector_t *preferences_get_recent_logs(preferences_t * prefs)
+{
+ return prefs->recent_log_files;
+}
+
+static int preferences_policy_path_compare(const void *a, const void *b, void *data __attribute__ ((unused)))
+{
+ return apol_policy_path_compare((const apol_policy_path_t *)a, (const apol_policy_path_t *)b);
+}
+
+int preferences_add_recent_policy(preferences_t * prefs, const apol_policy_path_t * policy)
+{
+ size_t i;
+ apol_policy_path_t *p = NULL;
+ if (apol_vector_get_index(prefs->recent_policy_files, policy, preferences_policy_path_compare, NULL, &i) == 0) {
+ return 0;
+ }
+ if ((p = apol_policy_path_create_from_policy_path(policy)) == NULL || apol_vector_append(prefs->recent_policy_files, p) < 0) {
+ int error = errno;
+ apol_policy_path_destroy(&p);
+ errno = error;
+ return -1;
+ }
+ if (apol_vector_get_size(prefs->recent_policy_files) >= MAX_RECENT_ENTRIES) {
+ p = apol_vector_get_element(prefs->recent_policy_files, 0);
+ apol_policy_path_destroy(&p);
+ return apol_vector_remove(prefs->recent_policy_files, 0);
+ }
+ return 0;
+}
+
+apol_vector_t *preferences_get_recent_policies(preferences_t * prefs)
+{
+ return prefs->recent_policy_files;
+}
diff --git a/seaudit/preferences.h b/seaudit/preferences.h
new file mode 100644
index 0000000..8891943
--- /dev/null
+++ b/seaudit/preferences.h
@@ -0,0 +1,274 @@
+/**
+ * @file
+ * Declaration of the current user's preferences for the seaudit
+ * application.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PREFERENCES_H
+#define PREFERENCES_H
+
+#include <apol/policy-path.h>
+#include <apol/vector.h>
+
+typedef struct preferences preferences_t;
+
+/* n.b.: OTHER_FIELD must be the last entry in this enumeration, for
+ message_view stops processing after that token */
+typedef enum preference_field
+{
+ HOST_FIELD, MESSAGE_FIELD, DATE_FIELD,
+ SUSER_FIELD, SROLE_FIELD, STYPE_FIELD, SMLS_LVL_FIELD, SMLS_CLR_FIELD,
+ TUSER_FIELD, TROLE_FIELD, TTYPE_FIELD, TMLS_LVL_FIELD, TMLS_CLR_FIELD,
+ OBJCLASS_FIELD, PERM_FIELD,
+ EXECUTABLE_FIELD, COMMAND_FIELD, NAME_FIELD,
+ PID_FIELD, INODE_FIELD, PATH_FIELD, OTHER_FIELD
+} preference_field_e;
+
+/**
+ * Allocate and return a preferences object. This function will first
+ * initialize the object using the user's configuration file. If that
+ * is not readable then the system-wide configuration is attempted.
+ * It is not an error if both files are not available.
+ *
+ * @return An initialized preferences object, or NULL upon error. The
+ * caller must call preferences_destroy() afterwards.
+ */
+preferences_t *preferences_create(void);
+
+/**
+ * Destroy a preferences object, and all memory associated with it.
+ * Does nothing if the pointer is already NULL.
+ *
+ * @param prefs Reference to a preferences object to destroy. This
+ * will be set to NULL afterwards.
+ */
+void preferences_destroy(preferences_t ** prefs);
+
+/**
+ * Write the preferences object to the user's configuration file,
+ * overwriting any existing file.
+ *
+ * @param prefs Preference object to write.
+ *
+ * @return 0 if successfully written, < 0 upon error.
+ */
+int preferences_write_to_conf_file(preferences_t * prefs);
+
+/**
+ * Return the visibility of the column with the given preference id.
+ *
+ * @param prefs Preference object to query.
+ * @param id Preferences column identifier.
+ *
+ * @return Non-zero if the column is set to be visible, zero if not.
+ */
+int preferences_is_column_visible(preferences_t * prefs, preference_field_e id);
+
+/**
+ * Set the visibility of a column with the given preference id. Note
+ * that this will <b>not</b> update any message_view_t.
+ *
+ * @param prefs Preference object to query.
+ * @param id Preferences column identifier.
+ * @param visible If non-zero then set column visible, zero to hide.
+ *
+ * @see message_view_update_visible_columns needs to be called if
+ * column visibilities are changed.
+ */
+void preferences_set_column_visible(preferences_t * prefs, preference_field_e id, int visible);
+
+/**
+ * Set the filename for the preferred audit log file. Unless
+ * overridden by the command line, this log file will be opened when
+ * seaudit is launched.
+ *
+ * @param prefs Preference object to modify.
+ * @param log Path to the log file. The string will be duplicated.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int preferences_set_log(preferences_t * prefs, const char *log);
+
+/**
+ * Get the filename for the preferred log file from the preferences
+ * object.
+ *
+ * @param prefs Preference object to query.
+ *
+ * @return Filename for the log file, or an empty string if none set.
+ * Do not modify this string.
+ */
+const char *preferences_get_log(preferences_t * prefs);
+
+/**
+ * Set the path for the preferred policy. Unless overridden by the
+ * command line, this policy will be opened when seaudit is launched.
+ *
+ * @param prefs Preference object to modify.
+ * @param policy Path to the policy file. The policy path object will
+ * be duplicated.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int preferences_set_policy(preferences_t * prefs, const apol_policy_path_t * policy);
+
+/**
+ * Get the policy path object for the preferred policy from the
+ * preferences object.
+ *
+ * @param prefs Preference object to query.
+ *
+ * @return Policy path object for the policy, or NULL if none set. Do
+ * not modify this object.
+ */
+const apol_policy_path_t *preferences_get_policy(preferences_t * prefs);
+
+/**
+ * Set the default report filename.
+ *
+ * @param prefs Preference object to modify.
+ * @param report Path to the report. The string will be duplicated.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int preferences_set_report(preferences_t * prefs, const char *report);
+
+/**
+ * Get the default report filename.
+ *
+ * @param prefs Preference object to query.
+ *
+ * @return Filename for the report, or an empty string if none set.
+ * Do not modify this string.
+ */
+const char *preferences_get_report(preferences_t * prefs);
+
+/**
+ * Set the default stylesheet filename.
+ *
+ * @param prefs Preference object to modify.
+ * @param stylesheet Path to the stylesheet. The string will be
+ * duplicated.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int preferences_set_stylesheet(preferences_t * prefs, const char *stylesheet);
+
+/**
+ * Get the default stylesheet filename.
+ *
+ * @param prefs Preference object to query.
+ *
+ * @return Filename for the stylesheet, or an empty string if none
+ * set. Do not modify this string.
+ */
+const char *preferences_get_stylesheet(preferences_t * prefs);
+
+/**
+ * Set the default real-time setting for opened log files. If startup
+ * is non-zero, then the real-time monitor will be enabled for new log
+ * files.
+ *
+ * @param prefs Preferences object to modify.
+ * @param startup If non-zero, then enable real-time by default.
+ */
+void preferences_set_real_time_at_startup(preferences_t * prefs, int startup);
+
+/**
+ * Get the default value for real-time monitoring.
+ *
+ * @param prefs Preference object to query.
+ *
+ * @return Non-zero if opened logs should be monitored.
+ */
+int preferences_get_real_time_at_startup(preferences_t * prefs);
+
+/**
+ * Set the time interval (in milliseconds) for polling the log file
+ * during real-time monitoring.
+ *
+ * @param prefs Preferences object to modify.
+ * @param interval Polling interval in milliseconds.
+ */
+void preferences_set_real_time_interval(preferences_t * prefs, int interval);
+
+/**
+ * Get the time interval (in milliseconds) when performing real-time
+ * monitoring.
+ *
+ * @param prefs Preference object to query.
+ *
+ * @return Time interval in milliseconds.
+ */
+int preferences_get_real_time_interval(preferences_t * prefs);
+
+/**
+ * Add a filename to the recently opened log files list. If the name
+ * is already in the list then do nothing. Otherwise append the name
+ * to the end of the list. If the list grows too large then remove
+ * the oldest entry.
+ *
+ * @param prefs Preference object to modify.
+ * @param log Path to the most recently opened log. The string will
+ * be duplicated.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int preferences_add_recent_log(preferences_t * prefs, const char *log);
+
+/**
+ * Return a vector of recently loaded log files (type char *), with
+ * the oldest file first. Note that the vector may be empty.
+ *
+ * @param prefs Preferences object to query.
+ *
+ * @return Vector of paths. Treat this vector as const.
+ */
+apol_vector_t *preferences_get_recent_logs(preferences_t * prefs);
+
+/**
+ * Add a policy path to the recently opened policy files list. If the
+ * name is already in the list then do nothing. Otherwise append the
+ * name to the end of the list. If the list grows too large then
+ * remove the oldest entry.
+ *
+ * @param prefs Preference object to modify.
+ * @param policy Path to the most recently opened policy. The path
+ * will be duplicated.
+ *
+ * @return 0 on success, < 0 on error.
+ */
+int preferences_add_recent_policy(preferences_t * prefs, const apol_policy_path_t * policy);
+
+/**
+ * Return a vector of recently loaded policy files (type
+ * apol_policy_path_t *), with the oldest file first. Note that the
+ * vector may be empty.
+ *
+ * @param prefs Preferences object to query.
+ *
+ * @return Vector of paths. Treat this vector as const.
+ */
+apol_vector_t *preferences_get_recent_policies(preferences_t * prefs);
+
+#endif
diff --git a/seaudit/preferences_view.c b/seaudit/preferences_view.c
new file mode 100644
index 0000000..7ac5ed3
--- /dev/null
+++ b/seaudit/preferences_view.c
@@ -0,0 +1,310 @@
+/**
+ * @file
+ * Implementation of preferences editor.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "open_policy_window.h"
+#include "preferences_view.h"
+#include "utilgui.h"
+#include <assert.h>
+#include <string.h>
+#include <glade/glade.h>
+
+struct pref_view
+{
+ GladeXML *xml;
+ toplevel_t *top;
+ preferences_t *prefs;
+ GtkDialog *dialog;
+ const char *current_log;
+ const apol_policy_path_t *current_policy;
+ apol_policy_path_t *policy_path;
+};
+
+struct pref_entry
+{
+ const char *entry_name, *browse_name;
+ const char *(*accessor) (preferences_t *);
+ int (*modifier) (preferences_t *, const char *);
+ const char *title;
+ /* next field is for callbacks to the browse button */
+ struct pref_view *pv;
+};
+
+static struct pref_entry pref_entry_data[] = {
+ {"PrefsViewLogEntry", "PrefsViewLogBrowseButton", preferences_get_log, preferences_set_log, "Select Default Log"},
+ {"PrefsViewConfigEntry", "PrefsViewConfigBrowseButton", preferences_get_report, preferences_set_report,
+ "Select Report Configuration File"},
+ {"PrefsViewStylesheetEntry", "PrefsViewStylesheetBrowseButton", preferences_get_stylesheet, preferences_set_stylesheet,
+ "Select HTML Report Style File"}
+};
+static const size_t num_entries = sizeof(pref_entry_data) / sizeof(pref_entry_data[0]);
+
+struct pref_toggle
+{
+ const char *widget_name;
+ preference_field_e preference_field;
+};
+
+static const struct pref_toggle pref_toggle_map[] = {
+ {"HostCheck", HOST_FIELD},
+ {"MessageCheck", MESSAGE_FIELD},
+ {"DateCheck", DATE_FIELD},
+ {"SourceUserCheck", SUSER_FIELD},
+ {"SourceRoleCheck", SROLE_FIELD},
+ {"SourceTypeCheck", STYPE_FIELD},
+ {"SourceMLSLVLCheck", SMLS_LVL_FIELD},
+ {"SourceMLSCLRCheck", SMLS_CLR_FIELD},
+ {"TargetUserCheck", TUSER_FIELD},
+ {"TargetRoleCheck", TROLE_FIELD},
+ {"TargetTypeCheck", TTYPE_FIELD},
+ {"TargetMLSLVLCheck", TMLS_LVL_FIELD},
+ {"TargetMLSCLRCheck", TMLS_CLR_FIELD},
+ {"ObjectClassCheck", OBJCLASS_FIELD},
+ {"PermissionCheck", PERM_FIELD},
+ {"ExecutableCheck", EXECUTABLE_FIELD},
+ {"CommandCheck", COMMAND_FIELD},
+ {"NameCheck", NAME_FIELD},
+ {"PIDCheck", PID_FIELD},
+ {"InodeCheck", INODE_FIELD},
+ {"PathCheck", PATH_FIELD},
+ {"OtherCheck", OTHER_FIELD}
+};
+static const size_t num_toggles = sizeof(pref_toggle_map) / sizeof(pref_toggle_map[0]);
+
+static void preferences_view_on_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data)
+{
+ const struct pref_entry *pe = (const struct pref_entry *)user_data;
+ struct pref_view *pv = pe->pv;
+ GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, pe->entry_name));
+ const char *current_path = gtk_entry_get_text(entry);
+ GtkWindow *parent = GTK_WINDOW(pv->dialog);
+ const char *title = pe->title;
+ apol_vector_t *new_paths = util_open_file(parent, title, current_path, 0);
+ if (new_paths != NULL) {
+ gtk_entry_set_text(entry, apol_vector_get_element(new_paths, 0));
+ apol_vector_destroy(&new_paths);
+ }
+}
+
+static void preferences_view_on_log_current_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct pref_view *pv = (struct pref_view *)user_data;
+ GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, "PrefsViewLogEntry"));
+ assert(entry != NULL);
+ if (pv->current_log == NULL) {
+ gtk_entry_set_text(entry, "");
+ } else {
+ gtk_entry_set_text(entry, pv->current_log);
+ }
+}
+
+static void preferences_view_on_policy_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct pref_view *pv = (struct pref_view *)user_data;
+ GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, "PrefsViewPolicyEntry"));
+ assert(entry != NULL);
+ apol_policy_path_t *new_path;
+
+ open_policy_window_run(pv->top, pv->policy_path, &new_path);
+ if (new_path != NULL) {
+ apol_policy_path_destroy(&pv->policy_path);
+ pv->policy_path = new_path;
+ char *path_string = util_policy_path_to_string(pv->policy_path);
+ gtk_entry_set_text(entry, path_string);
+ free(path_string);
+ }
+}
+
+static void preferences_view_on_policy_current_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct pref_view *pv = (struct pref_view *)user_data;
+ GtkEntry *entry = GTK_ENTRY(glade_xml_get_widget(pv->xml, "PrefsViewPolicyEntry"));
+ assert(entry != NULL);
+ apol_policy_path_destroy(&pv->policy_path);
+ if (pv->current_policy != NULL) {
+ pv->policy_path = apol_policy_path_create_from_policy_path(pv->current_policy);
+ char *path_string = util_policy_path_to_string(pv->policy_path);
+ gtk_entry_set_text(entry, path_string);
+ free(path_string);
+ } else {
+ gtk_entry_set_text(entry, "");
+ }
+}
+
+static void preferences_view_init_widgets(struct pref_view *pv)
+{
+ GtkWidget *w;
+ size_t i;
+
+ w = glade_xml_get_widget(pv->xml, "PreferencesWindow");
+ assert(w != NULL);
+ pv->dialog = GTK_DIALOG(w);
+ gtk_window_set_transient_for(GTK_WINDOW(pv->dialog), toplevel_get_window(pv->top));
+
+ for (i = 0; i < num_entries; i++) {
+ struct pref_entry *pe = pref_entry_data + i;
+ w = glade_xml_get_widget(pv->xml, pe->browse_name);
+ assert(w != NULL);
+ pe->pv = pv;
+ g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_browse_click), pe);
+ }
+
+ w = glade_xml_get_widget(pv->xml, "PrefsViewLogCurrentButton");
+ assert(w != NULL);
+ if (pv->current_log == NULL) {
+ gtk_widget_set_sensitive(w, FALSE);
+ }
+ g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_log_current_click), pv);
+
+ w = glade_xml_get_widget(pv->xml, "PrefsViewPolicyModifyButton");
+ assert(w != NULL);
+ g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_policy_browse_click), pv);
+ w = glade_xml_get_widget(pv->xml, "PrefsViewPolicyCurrentButton");
+ assert(w != NULL);
+ if (pv->current_policy == NULL) {
+ gtk_widget_set_sensitive(w, FALSE);
+ }
+ g_signal_connect(w, "clicked", G_CALLBACK(preferences_view_on_policy_current_click), pv);
+}
+
+/**
+ * Copy values from preferences object to dialog widgets.
+ */
+static void preferences_view_init_values(struct pref_view *pv)
+{
+ GtkWidget *w;
+ const char *current_value;
+ const apol_policy_path_t *current_path;
+ char *s;
+ size_t i;
+
+ for (i = 0; i < num_entries; i++) {
+ const struct pref_entry *pe = pref_entry_data + i;
+ w = glade_xml_get_widget(pv->xml, pe->entry_name);
+ assert(w != NULL);
+ current_value = pe->accessor(pv->prefs);
+ gtk_entry_set_text(GTK_ENTRY(w), current_value);
+ }
+ if ((current_path = preferences_get_policy(pv->prefs)) != NULL) {
+ pv->policy_path = apol_policy_path_create_from_policy_path(current_path);
+ w = glade_xml_get_widget(pv->xml, "PrefsViewPolicyEntry");
+ char *path_string = util_policy_path_to_string(pv->policy_path);
+ assert(w != NULL);
+ gtk_entry_set_text(GTK_ENTRY(w), path_string);
+ free(path_string);
+ }
+ for (i = 0; i < num_toggles; i++) {
+ int visible;
+ w = glade_xml_get_widget(pv->xml, pref_toggle_map[i].widget_name);
+ assert(w != NULL);
+ visible = preferences_is_column_visible(pv->prefs, pref_toggle_map[i].preference_field);
+ if (visible) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), TRUE);
+ } else {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), FALSE);
+ }
+ }
+ w = glade_xml_get_widget(pv->xml, "PrefsViewIntervalEntry");
+ assert(w != NULL);
+ if (asprintf(&s, "%d", preferences_get_real_time_interval(pv->prefs)) >= 0) {
+ gtk_entry_set_text(GTK_ENTRY(w), s);
+ free(s);
+ } else {
+ gtk_entry_set_text(GTK_ENTRY(w), "");
+ }
+ w = glade_xml_get_widget(pv->xml, "RealTimeCheck");
+ assert(w != NULL);
+ if (preferences_get_real_time_at_startup(pv->prefs)) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), TRUE);
+ } else {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), FALSE);
+ }
+}
+
+/**
+ * Copy values from dialog widget to the preferences object.
+ */
+static void preferences_view_get_from_dialog(struct pref_view *pv)
+{
+ GtkWidget *w;
+ const gchar *entry;
+ size_t i;
+
+ for (i = 0; i < num_entries; i++) {
+ const struct pref_entry *pe = pref_entry_data + i;
+ w = glade_xml_get_widget(pv->xml, pe->entry_name);
+ entry = gtk_entry_get_text(GTK_ENTRY(w));
+ pe->modifier(pv->prefs, entry);
+ }
+ preferences_set_policy(pv->prefs, pv->policy_path);
+ for (i = 0; i < num_toggles; i++) {
+ gboolean active;
+ w = glade_xml_get_widget(pv->xml, pref_toggle_map[i].widget_name);
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
+ if (active) {
+ preferences_set_column_visible(pv->prefs, pref_toggle_map[i].preference_field, 1);
+ } else {
+ preferences_set_column_visible(pv->prefs, pref_toggle_map[i].preference_field, 0);
+ }
+ }
+ w = glade_xml_get_widget(pv->xml, "PrefsViewIntervalEntry");
+ entry = gtk_entry_get_text(GTK_ENTRY(w));
+ if (strcmp(entry, "") == 0) {
+ entry = "0";
+ }
+ preferences_set_real_time_interval(pv->prefs, atoi(entry));
+ w = glade_xml_get_widget(pv->xml, "RealTimeCheck");
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) {
+ preferences_set_real_time_at_startup(pv->prefs, 1);
+ } else {
+ preferences_set_real_time_at_startup(pv->prefs, 0);
+ }
+}
+
+int preferences_view_run(toplevel_t * top, const char *current_log, const apol_policy_path_t * current_policy)
+{
+ struct pref_view pv;
+ gint response;
+
+ memset(&pv, 0, sizeof(pv));
+ pv.top = top;
+ pv.xml = glade_xml_new(toplevel_get_glade_xml(top), "PreferencesWindow", NULL);
+ pv.prefs = toplevel_get_prefs(top);
+ pv.current_log = current_log;
+ pv.current_policy = current_policy;
+
+ preferences_view_init_widgets(&pv);
+ preferences_view_init_values(&pv);
+
+ response = gtk_dialog_run(pv.dialog);
+ if (response != GTK_RESPONSE_OK) {
+ gtk_widget_destroy(GTK_WIDGET(pv.dialog));
+ return 0;
+ }
+ preferences_view_get_from_dialog(&pv);
+ gtk_widget_destroy(GTK_WIDGET(pv.dialog));
+ return 1;
+}
diff --git a/seaudit/preferences_view.h b/seaudit/preferences_view.h
new file mode 100644
index 0000000..d36aa3c
--- /dev/null
+++ b/seaudit/preferences_view.h
@@ -0,0 +1,44 @@
+/**
+ * @file
+ * Declaration of preferences editor.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PREFERENCES_VIEW_H
+#define PREFERENCES_VIEW_H
+
+#include "toplevel.h"
+#include <gtk/gtk.h>
+
+/**
+ * Display a dialog from which the user may edit his preferences.
+ *
+ * @param top Toplevel object containing preferences to modify
+ * @param current_log Path to the currently loaded log file, or NULL
+ * if none loaded.
+ * @param current_policy Path to the currently loaded policy, or NULL
+ * if none loaded.
+ *
+ * @return Non-zero if preferences changed, zero if not.
+ */
+int preferences_view_run(toplevel_t * top, const char *current_log, const apol_policy_path_t * current_policy);
+
+#endif
diff --git a/seaudit/progress.c b/seaudit/progress.c
new file mode 100644
index 0000000..01b01fb
--- /dev/null
+++ b/seaudit/progress.c
@@ -0,0 +1,200 @@
+/**
+ * @file
+ * Routines to show a progress dialog, indicating that the
+ * application is doing something.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "progress.h"
+#include "utilgui.h"
+
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <glib/gprintf.h>
+
+struct progress
+{
+ toplevel_t *top;
+ GtkWidget *progress;
+ GtkWidget *label1, *label2;
+ char *s;
+ int done;
+ GCond *cond;
+ GMutex *mutex;
+};
+
+progress_t *progress_create(toplevel_t * top)
+{
+ progress_t *p;
+ GtkWidget *vbox;
+
+ if ((p = calloc(1, sizeof(*p))) == NULL) {
+ return NULL;
+ }
+ p->top = top;
+ p->progress = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_modal(GTK_WINDOW(p->progress), TRUE);
+ gtk_window_set_transient_for(GTK_WINDOW(p->progress), toplevel_get_window(top));
+ gtk_window_set_default_size(GTK_WINDOW(p->progress), 300, 100);
+ vbox = gtk_vbox_new(FALSE, 2);
+ gtk_container_add(GTK_CONTAINER(p->progress), vbox);
+ p->label1 = gtk_label_new(NULL);
+ gtk_container_add(GTK_CONTAINER(vbox), p->label1);
+ p->label2 = gtk_label_new(NULL);
+ gtk_container_add(GTK_CONTAINER(vbox), p->label2);
+ gtk_widget_show(p->label1);
+ gtk_widget_show(p->label2);
+ gtk_widget_show(vbox);
+ util_cursor_wait(p->progress);
+ p->cond = g_cond_new();
+ p->mutex = g_mutex_new();
+ return p;
+}
+
+void progress_destroy(progress_t ** progress)
+{
+ if (progress != NULL && *progress != NULL) {
+ free((*progress)->s);
+ g_cond_free((*progress)->cond);
+ g_mutex_free((*progress)->mutex);
+ free(*progress);
+ *progress = NULL;
+ }
+}
+
+void progress_show(progress_t * progress, const char *title)
+{
+ gtk_label_set_text(GTK_LABEL(progress->label1), title);
+ gtk_label_set_text(GTK_LABEL(progress->label2), "");
+ gtk_widget_show(progress->progress);
+ gtk_window_deiconify(GTK_WINDOW(progress->progress));
+ gtk_window_set_title(GTK_WINDOW(progress->progress), title);
+ progress->done = 0;
+}
+
+void progress_hide(progress_t * progress)
+{
+ gtk_widget_hide(progress->progress);
+}
+
+int progress_wait(progress_t * progress)
+{
+ GTimeVal wait_time = { 0, 50000 };
+ g_mutex_lock(progress->mutex);
+ while (!progress->done) {
+ g_cond_timed_wait(progress->cond, progress->mutex, &wait_time);
+ if (progress->s != NULL) {
+ gtk_label_set_text(GTK_LABEL(progress->label2), progress->s);
+ free(progress->s);
+ progress->s = NULL;
+ }
+ while (gtk_events_pending())
+ gtk_main_iteration();
+ }
+ g_mutex_unlock(progress->mutex);
+ if (progress->done < 0) {
+ toplevel_ERR(progress->top, GTK_LABEL(progress->label2)->label);
+ return progress->done;
+ } else if (progress->done > 1) {
+ toplevel_WARN(progress->top, GTK_LABEL(progress->label2)->label);
+ return progress->done - 1;
+ } else {
+ progress->done = 0;
+ return 0;
+ }
+}
+
+void progress_done(progress_t * progress)
+{
+ g_mutex_lock(progress->mutex);
+ progress->done = 1;
+ g_cond_signal(progress->cond);
+ g_mutex_unlock(progress->mutex);
+}
+
+void progress_warn(progress_t * progress, char *reason, ...)
+{
+ gchar *s;
+ va_list ap;
+ g_mutex_lock(progress->mutex);
+ if (reason != NULL) {
+ va_start(ap, reason);
+ g_vasprintf(&s, reason, ap);
+ free(progress->s);
+ progress->s = s;
+ va_end(ap);
+ }
+ progress->done = 2;
+ g_cond_signal(progress->cond);
+ g_mutex_unlock(progress->mutex);
+}
+
+void progress_abort(progress_t * progress, char *reason, ...)
+{
+ gchar *s;
+ va_list ap;
+ g_mutex_lock(progress->mutex);
+ if (reason != NULL) {
+ va_start(ap, reason);
+ g_vasprintf(&s, reason, ap);
+ free(progress->s);
+ progress->s = s;
+ va_end(ap);
+ }
+ progress->done = -1;
+ g_cond_signal(progress->cond);
+ g_mutex_unlock(progress->mutex);
+}
+
+static void progress_update_label(progress_t * progress, const char *fmt, va_list va_args)
+{
+ gchar *s = NULL;
+ g_vasprintf(&s, fmt, va_args);
+ g_mutex_lock(progress->mutex);
+ free(progress->s);
+ progress->s = s;
+ g_cond_signal(progress->cond);
+ g_mutex_unlock(progress->mutex);
+}
+
+void progress_update(progress_t * progress, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ progress_update_label(progress, fmt, ap);
+ va_end(ap);
+}
+
+void progress_seaudit_handle_func(void *arg, const seaudit_log_t * log __attribute__ ((unused)), int level
+ __attribute__ ((unused)), const char *fmt, va_list va_args)
+{
+ progress_t *progress = arg;
+ progress_update_label(progress, fmt, va_args);
+}
+
+void progress_apol_handle_func(void *varg, const apol_policy_t * p __attribute__ ((unused)), int level
+ __attribute__ ((unused)), const char *fmt, va_list argp)
+{
+ progress_t *progress = varg;
+ progress_update_label(progress, fmt, argp);
+}
diff --git a/seaudit/progress.h b/seaudit/progress.h
new file mode 100644
index 0000000..5c6646f
--- /dev/null
+++ b/seaudit/progress.h
@@ -0,0 +1,139 @@
+/**
+ * @file
+ * Header for showing progress dialogs.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef PROGRESS_H
+#define PROGRESS_H
+
+typedef struct progress progress_t;
+
+#include "toplevel.h"
+
+#include <apol/policy.h>
+#include <seaudit/log.h>
+
+/**
+ * Allocate and return a new progress dialog object.
+ *
+ * @param top Toplevel object that will control the progress object.
+ *
+ * @return An initialized progress object, or NULL upon error. The
+ * caller is responsible for calling progress_destroy() afterwards.
+ */
+progress_t *progress_create(toplevel_t * top);
+
+/**
+ * Destroy a progress dialog. Does nothing if the pointer is already
+ * NULL.
+ *
+ * @param prefs Reference to a progress object to destroy. This will
+ * be set to NULL afterwards.
+ */
+void progress_destroy(progress_t ** progress);
+
+/**
+ * Display a progress dialog.
+ *
+ * @param progress Progress dialog to show.
+ * @param title Title for the progress window.
+ */
+void progress_show(progress_t * progress, const char *title);
+
+/**
+ * Hide the progress dialog. Note that this does not actually destroy
+ * the object.
+ *
+ * @param progress Progress dialog to hide.
+ */
+void progress_hide(progress_t * progress);
+
+/* the rest of these are for multi-threaded progress dialog */
+
+/**
+ * Block the current thread until the progress dialog receives a done
+ * signal via progress_done() or progress_abort(). The dialog will
+ * periodically awake and update the user interface, based upon
+ * message received by its handle implementations.
+ *
+ * @param progress Progress object to wait against.
+ *
+ * @return 0 if the progress object got a progress_done(), < 0 if
+ * progress_abort().
+ */
+int progress_wait(progress_t * progress);
+
+/**
+ * Signal to a progress object that this thread is ending
+ * successfully. This will cause all threads waiting upon the
+ * progress object to resume.
+ *
+ * @param progress Progress object to signal completion.
+ */
+void progress_done(progress_t * progress);
+
+/**
+ * Signal to a progress object that this thread completed with
+ * warnings. This will cause all threads waiting upon the progress
+ * object to resume.
+ *
+ * @param progress Progress object to signal completion.
+ * @param reason Explanation for warning, or NULL to use most recently
+ * written message as the reason.
+ */
+void progress_warn(progress_t * progress, char *reason, ...) __attribute__ ((format(printf, 2, 3)));
+
+/**
+ * Signal to a progress object that this thread is aborting. This
+ * will cause all threads waiting upon the progress object to resume.
+ *
+ * @param progress Progress object to signal completion.
+ * @param reason Explanation for abort, or NULL to abort for no
+ * reason. The most recently written message will be used as the
+ * reason.
+ */
+void progress_abort(progress_t * progress, char *reason, ...) __attribute__ ((format(printf, 2, 3)));
+
+/**
+ * Have the progress dialog show a message upon its next refresh.
+ *
+ * @param progress Progress object to update.
+ * @param fmt Format for string to display.
+ */
+void progress_update(progress_t * progress, char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
+
+/**
+ * Implementation of libseaudit's message callback function. This
+ * will route messages generated by libseaudit to the progress
+ * dialog's display. To use this, pass the progress_t object as
+ * seaudit_log_create()'s callback_arg parameter.
+ */
+void progress_seaudit_handle_func(void *arg, const seaudit_log_t * log, int level, const char *fmt, va_list va_args);
+
+/**
+ * Implementation of a libapol message callback function. This will
+ * route messages generated by libapol to the progress dialog's
+ * display. To use this, pass the progress_t object as
+ * apol_policy_open()'s varg parameter.
+ */
+void progress_apol_handle_func(void *varg, const apol_policy_t * p, int level, const char *fmt, va_list argp);
+
+#endif
diff --git a/seaudit/report_window.c b/seaudit/report_window.c
new file mode 100644
index 0000000..d7213b5
--- /dev/null
+++ b/seaudit/report_window.c
@@ -0,0 +1,261 @@
+/**
+ * @file
+ * Run the dialog that generates reports.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "report_window.h"
+#include "utilgui.h"
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <glade/glade.h>
+#include <seaudit/report.h>
+
+struct report_window
+{
+ GladeXML *xml;
+ GtkDialog *dialog;
+ GtkRadioButton *all_messages_radio, *text_radio;
+ GtkToggleButton *malformed_toggle, *use_stylesheet_toggle;
+ GtkWidget *stylesheet_label, *stylesheet_browse, *config_browse;
+ GtkEntry *stylesheet_entry, *config_entry;
+ char *filename;
+ message_view_t *current_view;
+ seaudit_log_t *log;
+ int result;
+ progress_t *progress;
+};
+
+static void report_window_on_all_messages_toggle(GtkToggleButton * toggle, gpointer user_data)
+{
+ gboolean sens = gtk_toggle_button_get_active(toggle);
+ struct report_window *rw = (struct report_window *)user_data;
+ gtk_widget_set_sensitive(GTK_WIDGET(rw->malformed_toggle), sens);
+}
+
+static void report_window_on_use_stylesheet_toggle(GtkToggleButton * toggle, gpointer user_data)
+{
+ gboolean sens = gtk_toggle_button_get_active(toggle);
+ struct report_window *rw = (struct report_window *)user_data;
+ gtk_widget_set_sensitive(rw->stylesheet_label, sens);
+ gtk_widget_set_sensitive(GTK_WIDGET(rw->stylesheet_entry), sens);
+ gtk_widget_set_sensitive(rw->stylesheet_browse, sens);
+}
+
+static void report_window_on_output_format_toggle(GtkToggleButton * toggle, gpointer user_data)
+{
+ gboolean sens = gtk_toggle_button_get_active(toggle);
+ struct report_window *rw = (struct report_window *)user_data;
+ gtk_widget_set_sensitive(GTK_WIDGET(rw->use_stylesheet_toggle), !sens);
+ if (sens == TRUE) {
+ gtk_widget_set_sensitive(rw->stylesheet_label, FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(rw->stylesheet_entry), FALSE);
+ gtk_widget_set_sensitive(rw->stylesheet_browse, FALSE);
+ } else {
+ report_window_on_use_stylesheet_toggle(rw->use_stylesheet_toggle, rw);
+ }
+}
+
+static void report_window_browse(GtkEntry * entry, GtkWindow * parent, const char *title)
+{
+ const char *current_path = gtk_entry_get_text(entry);
+ apol_vector_t *new_paths = util_open_file(parent, title, current_path, 0);
+ if (new_paths != NULL) {
+ gtk_entry_set_text(entry, apol_vector_get_element(new_paths, 0));
+ apol_vector_destroy(&new_paths);
+ }
+}
+
+static void report_window_on_stylesheet_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct report_window *rw = (struct report_window *)user_data;
+ report_window_browse(rw->stylesheet_entry, GTK_WINDOW(rw->dialog), "Select Style Sheet");
+}
+
+static void report_window_on_config_browse_click(GtkWidget * widget __attribute__ ((unused)), gpointer user_data)
+{
+ struct report_window *rw = (struct report_window *)user_data;
+ report_window_browse(rw->config_entry, GTK_WINDOW(rw->dialog), "Select Report Configuration");
+}
+
+/**
+ * Set up report window struct's widget pointers.
+ */
+static void report_window_init_dialog(struct report_window *rw, toplevel_t * top)
+{
+ rw->dialog = GTK_DIALOG(glade_xml_get_widget(rw->xml, "ReportWindow"));
+ assert(rw->dialog != NULL);
+ gtk_window_set_transient_for(GTK_WINDOW(rw->dialog), toplevel_get_window(top));
+
+ rw->all_messages_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowAllMessagesRadio"));
+ rw->malformed_toggle = GTK_TOGGLE_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowMalformedCheck"));
+ assert(rw->all_messages_radio != NULL && rw->malformed_toggle != NULL);
+
+ rw->text_radio = GTK_RADIO_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowTextRadio"));
+ rw->use_stylesheet_toggle = GTK_TOGGLE_BUTTON(glade_xml_get_widget(rw->xml, "ReportWindowUseStylesheetCheck"));
+ assert(rw->text_radio != NULL && rw->use_stylesheet_toggle != NULL);
+
+ rw->stylesheet_label = glade_xml_get_widget(rw->xml, "ReportWindowStylesheetLabel");
+ rw->stylesheet_entry = GTK_ENTRY(glade_xml_get_widget(rw->xml, "ReportWindowStylesheetEntry"));
+ rw->stylesheet_browse = glade_xml_get_widget(rw->xml, "ReportWindowStylesheetBrowse");
+ assert(rw->stylesheet_label != NULL && rw->stylesheet_entry && rw->stylesheet_browse);
+
+ rw->config_entry = GTK_ENTRY(glade_xml_get_widget(rw->xml, "ReportWindowConfigEntry"));
+ rw->config_browse = glade_xml_get_widget(rw->xml, "ReportWindowConfigBrowse");
+ assert(rw->config_entry != NULL && rw->config_browse != NULL);
+
+ /* set up signal handlers */
+ g_signal_connect(rw->all_messages_radio, "toggled", G_CALLBACK(report_window_on_all_messages_toggle), rw);
+ g_signal_connect(rw->text_radio, "toggled", G_CALLBACK(report_window_on_output_format_toggle), rw);
+ g_signal_connect(rw->use_stylesheet_toggle, "toggled", G_CALLBACK(report_window_on_use_stylesheet_toggle), rw);
+ g_signal_connect(rw->stylesheet_browse, "clicked", G_CALLBACK(report_window_on_stylesheet_browse_click), rw);
+ g_signal_connect(rw->config_browse, "clicked", G_CALLBACK(report_window_on_config_browse_click), rw);
+
+}
+
+/**
+ * The first time the report window is shown, populate its entry boxes
+ * with values from the user's preferences. On subsequent times
+ * remember the user's entries.
+ */
+static void report_window_copy_prefs(struct report_window *rw, toplevel_t * top)
+{
+ static int report_window_initialized = 0;
+ if (!report_window_initialized) {
+ preferences_t *prefs = toplevel_get_prefs(top);
+ gtk_entry_set_text(rw->stylesheet_entry, preferences_get_stylesheet(prefs));
+ gtk_entry_set_text(rw->config_entry, preferences_get_report(prefs));
+ }
+ report_window_initialized = 1;
+}
+
+static gpointer report_window_create_report_runner(gpointer data)
+{
+ struct report_window *rw = (struct report_window *)data;
+ seaudit_model_t *model = NULL;
+ seaudit_report_t *report = NULL;
+ seaudit_report_format_e format = SEAUDIT_REPORT_FORMAT_TEXT;
+ int do_malformed = 0, do_stylesheet = 0;
+ const char *config_name = NULL, *stylesheet_name = NULL;
+
+ rw->result = -1;
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rw->all_messages_radio))) {
+ model = seaudit_model_create("All Messages", rw->log);
+ if (gtk_toggle_button_get_active(rw->malformed_toggle)) {
+ do_malformed = 1;
+ }
+ } else {
+ seaudit_model_t *view_model = message_view_get_model(rw->current_view);
+ model = seaudit_model_create_from_model(view_model);
+ }
+ if (model == NULL) {
+ progress_abort(rw->progress, "%s", strerror(errno));
+ goto cleanup;
+ }
+ if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rw->text_radio))) {
+ format = SEAUDIT_REPORT_FORMAT_HTML;
+ }
+ if (gtk_toggle_button_get_active(rw->use_stylesheet_toggle)) {
+ do_stylesheet = 1;
+ }
+ stylesheet_name = gtk_entry_get_text(rw->stylesheet_entry);
+ if (strcmp(stylesheet_name, "") == 0) {
+ stylesheet_name = NULL;
+ }
+ config_name = gtk_entry_get_text(rw->config_entry);
+ if (strcmp(config_name, "") == 0) {
+ config_name = NULL;
+ }
+
+ if ((report = seaudit_report_create(model)) == NULL) {
+ progress_abort(rw->progress, "%s", strerror(errno));
+ goto cleanup;
+ }
+ if (seaudit_report_set_format(rw->log, report, format) < 0 ||
+ seaudit_report_set_configuration(rw->log, report, config_name) < 0 ||
+ seaudit_report_set_stylesheet(rw->log, report, stylesheet_name, do_stylesheet) < 0 ||
+ seaudit_report_set_malformed(rw->log, report, do_malformed) < 0) {
+ goto cleanup;
+ }
+ progress_update(rw->progress, "Writing");
+ if (seaudit_report_write(rw->log, report, rw->filename) < 0) {
+ goto cleanup;
+ }
+ rw->result = 0;
+ cleanup:
+ seaudit_report_destroy(&report);
+ seaudit_model_destroy(&model);
+ if (rw->result == 0) {
+ progress_done(rw->progress);
+ } else {
+ progress_abort(rw->progress, NULL);
+ }
+ return NULL;
+}
+
+void report_window_run(toplevel_t * top, message_view_t * view)
+{
+ struct report_window rw;
+ /** keey track of most recently used report filename */
+ static char *filename = NULL;
+
+ memset(&rw, 0, sizeof(rw));
+ rw.xml = glade_xml_new(toplevel_get_glade_xml(top), "ReportWindow", NULL);
+ report_window_init_dialog(&rw, top);
+ report_window_copy_prefs(&rw, top);
+
+ rw.current_view = view;
+ rw.log = toplevel_get_log(top);
+ rw.progress = toplevel_get_progress(top);
+ rw.filename = filename;
+ do {
+ gint response = gtk_dialog_run(rw.dialog);
+ if (response != GTK_RESPONSE_OK) {
+ break;
+ }
+ if ((filename = util_save_file(GTK_WINDOW(rw.dialog), "Save Report to File", rw.filename)) == NULL) {
+ continue;
+ }
+ g_free(rw.filename);
+ rw.filename = filename;
+ util_cursor_wait(GTK_WIDGET(rw.dialog));
+ progress_show(rw.progress, "Creating Report");
+ g_thread_create(report_window_create_report_runner, &rw, FALSE, NULL);
+ progress_wait(rw.progress);
+ progress_hide(rw.progress);
+ /* Reset the cursor if the save failed. upon success,
+ * the window will be destroyed anyways, so don't
+ * bother resetting the cursor.
+ *
+ * (Real reason: util_cursor_clear() resets the cursor
+ * as an idle callback -- but by the time it triggers,
+ * the window will be destroyed by then.)
+ */
+ if (rw.result == 0) {
+ break;
+ }
+ util_cursor_clear(GTK_WIDGET(rw.dialog));
+ } while (1);
+ gtk_widget_destroy(GTK_WIDGET(rw.dialog));
+}
diff --git a/seaudit/report_window.h b/seaudit/report_window.h
new file mode 100644
index 0000000..ff9fcb7
--- /dev/null
+++ b/seaudit/report_window.h
@@ -0,0 +1,41 @@
+/**
+ * @file
+ * Dialog that generates reports from all messages or only those in
+ * the current view.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef REPORT_WINDOW_H
+#define REPORT_WINDOW_H
+
+#include "toplevel.h"
+#include "message_view.h"
+
+/**
+ * Display and run a dialog that allows the user to generate a report.
+ *
+ * @param top Toplevel containing preferences and log file for report
+ * writer.
+ * @param view Current message view.
+ */
+void report_window_run(toplevel_t * top, message_view_t * view);
+
+#endif
diff --git a/seaudit/seaudit-report-group.conf b/seaudit/seaudit-report-group.conf
new file mode 100644
index 0000000..3b0664c
--- /dev/null
+++ b/seaudit/seaudit-report-group.conf
@@ -0,0 +1,3 @@
+# This is the logfile group configuration file for Logwatch
+LogFile = messages
+
diff --git a/seaudit/seaudit-report-service.conf b/seaudit/seaudit-report-service.conf
new file mode 100644
index 0000000..30efcde
--- /dev/null
+++ b/seaudit/seaudit-report-service.conf
@@ -0,0 +1,5 @@
+# This is the service filter configuration file for Logwatch
+Title = "seaudit-report"
+
+# Which logfile group...
+LogFile = seaudit-report-group
diff --git a/seaudit/seaudit-report-service.in b/seaudit/seaudit-report-service.in
new file mode 100644
index 0000000..d923589
--- /dev/null
+++ b/seaudit/seaudit-report-service.in
@@ -0,0 +1,24 @@
+#!/bin/sh
+# shell script to run seaudit-report on STDIN
+#
+
+SEAUDITREPORT=@bindir@
+OPTS="--stdin --malformed"
+
+echo "Date Range: $LOGWATCH_DATE_RANGE"
+echo "Detail Level: $LOGWATCH_DETAIL_LEVEL"
+echo "Temp Dir: $LOGWATCH_TEMP_DIR"
+echo "Debug Level: $LOGWATCH_DEBUG"
+
+# execute the program with the specified options
+${SEAUDITREPORT} ${OPTS}
+
+# program failed
+if [ $? -ne 0 ]; then
+ RC=$?
+ echo >&2 "Failed while executing seaudit-report.\n"
+ exit $RC
+fi
+
+# All done, exit ok
+exit 0
diff --git a/seaudit/seaudit-report.c b/seaudit/seaudit-report.c
new file mode 100644
index 0000000..af3c6fb
--- /dev/null
+++ b/seaudit/seaudit-report.c
@@ -0,0 +1,246 @@
+/**
+ * @file
+ * Command line tool for processing SELinux audit logs and generating
+ * a concise report containing standard information as well as
+ * customized information using seaudit views. Reports are rendered
+ * in either HTML or plain text. Future support will provide
+ * rendering into XML. The HTML report can be formatted by providing
+ * an alternate stylesheet file or by configuring the default
+ * stylesheet. This tool also provides the option for including
+ * malformed strings within the report.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2004-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <seaudit/log.h>
+#include <seaudit/parse.h>
+#include <seaudit/report.h>
+
+#include <apol/vector.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define COPYRIGHT_INFO "Copyright (C) 2004-2007 Tresys Technology, LLC"
+
+enum opts
+{
+ OPT_HTML = 256, OPT_STYLESHEET
+};
+
+static struct option const longopts[] = {
+ {"html", no_argument, NULL, OPT_HTML},
+ {"malformed", no_argument, NULL, 'm'},
+ {"output", required_argument, NULL, 'o'},
+ {"stylesheet", required_argument, NULL, OPT_STYLESHEET},
+ {"stdin", no_argument, NULL, 's'},
+ {"config", required_argument, NULL, 'c'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+/**
+ * Vector of seaudit_log_t, corresponding to each of the log files to
+ * process.
+ */
+static apol_vector_t *logs = NULL;
+
+/**
+ * Error reporting log handler.
+ */
+static seaudit_log_t *first_log = NULL;
+
+/**
+ * Model that incorporates all of the logs within the logs vector.
+ */
+static seaudit_model_t *model = NULL;
+
+/**
+ * Report object for the above model.
+ */
+static seaudit_report_t *report = NULL;
+
+/**
+ * Destination file for the seaudit report, or NULL to write to
+ * standard output.
+ */
+static char *outfile = NULL;
+
+static void seaudit_report_info_usage(const char *program_name, int brief)
+{
+ printf("Usage: %s [OPTIONS] LOGFILE ...\n\n", program_name);
+ if (brief) {
+ printf("\tTry %s --help for more help.\n\n", program_name);
+ return;
+ }
+ printf("Generate a customized SELinux log report.\n\n");
+ printf(" -s, --stdin read log data from standard input\n");
+ printf(" -m, --malformed include malformed log messages\n");
+ printf(" -o FILE, --output=FILE output to FILE\n");
+ printf(" --config=FILE read configuration from FILE\n");
+ printf(" --html set output format to HTML\n");
+ printf(" --stylesheet=FILE HTML style sheet for formatting HTML report\n");
+ printf(" (ignored if --html is not given)\n");
+ printf(" -h, --help print this help text and exit\n");
+ printf(" -V, --version print version information and exit\n");
+ printf("\n");
+ printf("Default style sheet is at %s.\n", APOL_INSTALL_DIR);
+}
+
+static void parse_command_line_args(int argc, char **argv)
+{
+ int optc, i;
+ int do_malformed = 0, do_style = 0, read_stdin = 0;
+ seaudit_report_format_e format = SEAUDIT_REPORT_FORMAT_TEXT;
+ char *configfile = NULL, *stylesheet = NULL;
+
+ /* get option arguments */
+ while ((optc = getopt_long(argc, argv, "smo:c:hV", longopts, NULL)) != -1) {
+ switch (optc) {
+ case 's': /* read LOGFILES from standard input */
+ read_stdin = 1;
+ break;
+ case 'm': /* include malformed messages */
+ do_malformed = 1;
+ break;
+ case 'o': /* output file name */
+ outfile = optarg;
+ break;
+ case 'c': /* Alternate config file path */
+ configfile = optarg;
+ break;
+ case OPT_HTML: /* Set the output to format to html */
+ format = SEAUDIT_REPORT_FORMAT_HTML;
+ do_style = 1;
+ break;
+ case OPT_STYLESHEET: /* HTML stylesheet file path */
+ stylesheet = optarg;
+ do_style = 1;
+ break;
+ case 'h':
+ /* display help */
+ seaudit_report_info_usage(argv[0], 0);
+ exit(0);
+ case 'V':
+ /* display version */
+ printf("seaudit-report %s\n%s\n", VERSION, COPYRIGHT_INFO);
+ exit(0);
+ default:
+ /* display usage and handle error */
+ seaudit_report_info_usage(argv[0], 1);
+ exit(-1);
+ }
+ }
+
+ /* Throw warning if a stylesheet was specified, but the --html
+ * option was not. */
+ if (stylesheet != NULL && format != SEAUDIT_REPORT_FORMAT_HTML) {
+ fprintf(stderr, "Warning: The --html option was not specified.\n");
+ exit(-1);
+ }
+
+ if (!read_stdin && optind >= argc) {
+ /* display usage and handle error */
+ seaudit_report_info_usage(argv[0], 1);
+ exit(-1);
+ }
+
+ if ((model = seaudit_model_create("seaudit-report", NULL)) == NULL) {
+ exit(-1);
+ }
+ if ((first_log = seaudit_log_create(NULL, NULL)) == NULL || seaudit_model_append_log(model, first_log) < 0) {
+ fprintf(stderr, "ERROR: %s\n", strerror(errno));
+ exit(-1);
+ }
+ if ((logs = apol_vector_create(NULL)) == NULL || apol_vector_append(logs, first_log) < 0) {
+ fprintf(stderr, "ERROR: %s\n", strerror(errno));
+ exit(-1);
+ }
+ if (read_stdin) {
+ /* Ensure that logfiles were not specified in addition
+ * to the standard-in option */
+ if (optind < argc) {
+ fprintf(stderr, "WARNING: %s\n", "Command line filename(s) will be ignored. Reading from stdin.");
+ }
+ if (seaudit_log_parse(first_log, stdin) < 0) {
+ exit(-1);
+ }
+ } else {
+ /* Parse given filenames */
+ FILE *f;
+ seaudit_log_t *l;
+ if ((f = fopen(argv[optind], "r")) == NULL) {
+ fprintf(stderr, "ERROR: %s\n", strerror(errno));
+ exit(-1);
+ }
+ if (seaudit_log_parse(first_log, f) < 0) {
+ exit(-1);
+ }
+ fclose(f);
+ for (i = optind + 1; i < argc; i++) {
+ if ((l = seaudit_log_create(NULL, NULL)) == NULL || seaudit_model_append_log(model, l) < 0) {
+ exit(-1);
+ }
+ if (apol_vector_append(logs, l) < 0) {
+ fprintf(stderr, "ERROR: %s\n", strerror(errno));
+ exit(-1);
+ }
+ if ((f = fopen(argv[i], "r")) == NULL) {
+ fprintf(stderr, "ERROR: %s\n", strerror(errno));
+ exit(-1);
+ }
+ if (seaudit_log_parse(l, f) < 0) {
+ exit(-1);
+ }
+ fclose(f);
+ }
+ }
+
+ if ((report = seaudit_report_create(model)) == NULL ||
+ seaudit_report_set_format(first_log, report, format) < 0 ||
+ seaudit_report_set_configuration(first_log, report, configfile) < 0 ||
+ seaudit_report_set_stylesheet(first_log, report, stylesheet, do_style) < 0 ||
+ seaudit_report_set_malformed(first_log, report, do_malformed) < 0) {
+ exit(-1);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ size_t i;
+ parse_command_line_args(argc, argv);
+ if (seaudit_report_write(first_log, report, outfile) < 0) {
+ return -1;
+ }
+ seaudit_report_destroy(&report);
+ seaudit_model_destroy(&model);
+ for (i = 0; i < apol_vector_get_size(logs); i++) {
+ seaudit_log_t *l = apol_vector_get_element(logs, i);
+ seaudit_log_destroy(&l);
+ }
+ apol_vector_destroy(&logs);
+ return 0;
+}
diff --git a/seaudit/seaudit-report.conf b/seaudit/seaudit-report.conf
new file mode 100644
index 0000000..fb36c24
--- /dev/null
+++ b/seaudit/seaudit-report.conf
@@ -0,0 +1,62 @@
+<?xml version="1.0" ?>
+<!-- comment
+ seaudit-report.conf
+
+ This conf file is used to configure information presented in
+ reports generated by the seaudit-report tool.
+
+ The XML-based configuration file is laid out as follows:
+ Report Configuration
+ Standard Section Definitions
+ Custom Section Definitions
+ SEAudit View Definitions
+
+ The STANDARD SECTION definitions define a set of predefined tags
+ that the tool will look for when creating the report. The tool
+ will consider each of these tags as a standard section for the
+ report. To exclude a standard section within the report, simply
+ remove the appropriate standard-section tag. The predefined
+ standard-section tags may use any of the following identifiers:
+
+ 'Statistics': displays general statistics for the log.
+ 'PolicyLoads': displays all load policy messages.
+ 'EnforcementToggles': displays all enforcement toggle messages.
+ 'PolicyBooleans': displays all policy boolean messages.
+ 'AllowListing': displays all allow messages.
+ 'DenyListing': displays all denied messages.
+
+ All of the above predefined tags require the attribute 'id' to
+ be specified or an error will be returned. The 'title' attribute
+ is optional.
+
+ The CUSTOM SECTION definitions are used to create customized
+ sections within the report through the use of saved seaudit
+ view files. SEAudit views files can be created using the seaudit
+ GUI tool or by manually creating the file(s) with the correct
+ format. View tags should be provided as children within the
+ custom-section tag and a valid pathname is required for the
+ tags' 'file' attribute. An example of a custom-section tag can
+ be:
+ <custom-section title="Critical Errors">
+ <view file="/home/sec_admin/seaudit-report/views/critical.vw">
+ </view>
+ </custom-section>
+
+ The 'title' attribute is optional for the custom-section tag.
+
+ NOTE: The tool will display the reports' sections in the order
+ in which the tags are defined within the config file. So for
+ instance, inserting the custom-section tag to be the first defined
+ tag within the config file, will display the custom-section results
+ before all other results in the report. See the default settings
+ below for further information.
+-->
+
+<seaudit-report title="SEAudit Log Report">
+ <standard-section id ="Statistics" title="Log Statistics"></standard-section>
+ <standard-section id ="PolicyLoads" title="Policy Loads"></standard-section>
+ <standard-section id ="EnforcementToggles" title="Enforcement mode toggles"></standard-section>
+ <standard-section id ="PolicyBooleans" title="Policy boolean changes"></standard-section>
+ <standard-section id ="AllowListing" title="Allow Listing"></standard-section>
+ <standard-section id ="DenyListing" title="Deny Listing"></standard-section>
+</seaudit-report>
diff --git a/seaudit/seaudit-report.css b/seaudit/seaudit-report.css
new file mode 100644
index 0000000..4780a2d
--- /dev/null
+++ b/seaudit/seaudit-report.css
@@ -0,0 +1,178 @@
+# seaudit-report.css
+#
+# This is a default stylesheet template used to format an HTML report
+# generated by the seaudit-report tool.
+#
+# There are two ways of configuring this style sheet:
+#
+# 1. External Style Sheet:
+# Specify an external stylesheet to link to the HTML report using a
+# <link> tag, as follows:
+# <link rel="stylesheet" type="text/css" href="mystyle.css">
+# The seaudit-report tool will insert the <link> tag you define
+# within the <head> section of the generated HTML report.
+#
+# 2. Internal Style Sheet:
+# Specify internal style tags for the HTML report using the <style>
+# tag. An example can be:
+# <style type="text/css">
+# body {background-color: red}
+# p {margin-left: 20px}
+# </style>
+# The seaudit-report tool will insert the <style> tag you define
+# within the head section of the generated HTML report.
+#
+# The following is a list of defined HTML tags and their class selectors
+# that can be used:
+#
+# HTML Tag Class Selector(s)
+# -------- -----------------
+# <h1> report_title
+#
+# <h2> standard_section_title, custom_section_title
+#
+# <font> message_count_label, stats_label, message_date,
+# host_name, syscall_timestamp, avc_type,
+# src_context, tgt_context, obj_class
+#
+# <b> report_date, message_count, stats_count
+#
+# See the default (internal) style sheet format below for an example.s
+
+body
+{
+ font-size: 82%;
+ color:#000000;
+ background-color:white;
+ margin:0px;
+}
+
+h1.report_title
+{
+ margin-top:0px;
+ margin-bottom:5px;
+ font-size:110%;
+ padding-top:0px;
+ padding-bottom:1px;
+ padding-left:4px;
+ color:#ffffff;
+ text-align:left;
+ background-color:#808080;
+}
+
+h2.standard_section_title
+{
+ margin-top:0px;
+ margin-bottom:5px;
+ font-size:100%;
+ padding-top:0px;
+ padding-bottom:1px;
+ padding-left:0px;
+ color:black;
+ background-color:transparent;
+}
+
+h2.custom_section_title
+{
+ margin-top:0px;
+ margin-bottom:5px;
+ font-size:100%;
+ padding-top:0px;
+ padding-bottom:1px;
+ padding-left:0px;
+ color:black;
+ background-color:transparent;
+}
+
+font.message_count_label
+{
+color: #000000;
+background-color:transparent;
+}
+
+b.message_count
+{
+color: #000000;
+background-color:transparent;
+}
+
+font.stats_label
+{
+color: #000000;
+background-color:transparent;
+}
+
+b.stats_count
+{
+color: #000000;
+background-color:transparent;
+}
+
+b.report_date
+{
+color: #000000;
+background-color:transparent;
+}
+
+font.message_date
+{
+color: black;
+background-color:transparent;
+position:relative
+}
+
+font.host_name
+{
+color: #000000;
+background-color:transparent;
+}
+
+font.syscall_timestamp
+{
+color: #000000;
+background-color:transparent;
+}
+
+font.avc_deny
+{
+color:red;
+background-color:transparent;
+}
+
+font.avc_grant
+{
+color:green;
+background-color:transparent;
+}
+
+font.exe
+{
+color: #000000;
+background-color:transparent;
+}
+
+font.path
+{
+color: blue;
+background-color:transparent;
+}
+
+font.src_context
+{
+color:black;
+background-color:transparent;
+font-weight: bold
+}
+
+font.tgt_context
+{
+color:black;
+background-color:transparent;
+font-weight: bold
+}
+
+font.obj_class
+{
+color: #000000;
+background-color:transparent;
+} \ No newline at end of file
diff --git a/seaudit/seaudit-small.png b/seaudit/seaudit-small.png
new file mode 100644
index 0000000..4cced9b
--- /dev/null
+++ b/seaudit/seaudit-small.png
Binary files differ
diff --git a/seaudit/seaudit.c b/seaudit/seaudit.c
new file mode 100644
index 0000000..ff542a9
--- /dev/null
+++ b/seaudit/seaudit.c
@@ -0,0 +1,418 @@
+/**
+ * @file
+ * Main driver for the seaudit application. This file also
+ * implements the main class seaudit_t.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "seaudit.h"
+#include "toplevel.h"
+
+#include <apol/util.h>
+#include <seaudit/model.h>
+#include <seaudit/parse.h>
+#include <seaudit/util.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glade/glade.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+struct seaudit
+{
+ preferences_t *prefs;
+ apol_policy_t *policy;
+ apol_policy_path_t *policy_path;
+ seaudit_log_t *log;
+ FILE *file;
+ char *log_path;
+ size_t num_log_messages;
+ const struct tm *first, *last;
+ toplevel_t *top;
+};
+
+static struct option const opts[] = {
+ {"log", required_argument, NULL, 'l'},
+ {"help", no_argument, NULL, 'h'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0}
+};
+
+preferences_t *seaudit_get_prefs(seaudit_t * s)
+{
+ return s->prefs;
+}
+
+void seaudit_set_policy(seaudit_t * s, apol_policy_t * policy, apol_policy_path_t * path)
+{
+ if (policy != NULL) {
+ if (preferences_add_recent_policy(s->prefs, path) < 0) {
+ toplevel_ERR(s->top, "%s", strerror(errno));
+ apol_policy_destroy(&policy);
+ return;
+ }
+ apol_policy_destroy(&s->policy);
+ s->policy = policy;
+ if (path != s->policy_path) {
+ apol_policy_path_destroy(&s->policy_path);
+ }
+ s->policy_path = path;
+ } else {
+ apol_policy_destroy(&s->policy);
+ apol_policy_path_destroy(&s->policy_path);
+ }
+}
+
+apol_policy_t *seaudit_get_policy(seaudit_t * s)
+{
+ return s->policy;
+}
+
+apol_policy_path_t *seaudit_get_policy_path(seaudit_t * s)
+{
+ return s->policy_path;
+}
+
+void seaudit_set_log(seaudit_t * s, seaudit_log_t * log, FILE * f, const char *filename)
+{
+ if (s->file != NULL) {
+ fclose(s->file);
+ s->file = NULL;
+ }
+ if (log != NULL) {
+ seaudit_model_t *model = NULL;
+ apol_vector_t *messages = NULL;
+ char *t = NULL;
+ if ((model = seaudit_model_create(NULL, log)) == NULL ||
+ (messages = seaudit_model_get_messages(log, model)) == NULL ||
+ (t = strdup(filename)) == NULL || preferences_add_recent_log(s->prefs, filename) < 0) {
+ toplevel_ERR(s->top, "%s", strerror(errno));
+ seaudit_log_destroy(&log);
+ seaudit_model_destroy(&model);
+ apol_vector_destroy(&messages);
+ free(t);
+ return;
+ }
+ /* do it in this order, for filename could be pointing to
+ * s->log_path */
+ seaudit_log_destroy(&s->log);
+ s->log = log;
+ s->file = f;
+ free(s->log_path);
+ s->log_path = t;
+ s->num_log_messages = apol_vector_get_size(messages);
+ if (s->num_log_messages == 0) {
+ s->first = s->last = NULL;
+ } else {
+ seaudit_message_t *message = apol_vector_get_element(messages, 0);
+ s->first = seaudit_message_get_time(message);
+ message = apol_vector_get_element(messages, s->num_log_messages - 1);
+ s->last = seaudit_message_get_time(message);
+ }
+ seaudit_model_destroy(&model);
+ apol_vector_destroy(&messages);
+ } else {
+ seaudit_log_destroy(&s->log);
+ free(s->log_path);
+ s->log_path = NULL;
+ s->num_log_messages = 0;
+ s->first = s->last = NULL;
+ }
+}
+
+int seaudit_parse_log(seaudit_t * s)
+{
+ return seaudit_log_parse(s->log, s->file);
+}
+
+seaudit_log_t *seaudit_get_log(seaudit_t * s)
+{
+ return s->log;
+}
+
+char *seaudit_get_log_path(seaudit_t * s)
+{
+ return s->log_path;
+}
+
+apol_vector_t *seaudit_get_log_users(seaudit_t * s)
+{
+ if (s->log == NULL) {
+ return NULL;
+ } else {
+ return seaudit_log_get_users(s->log);
+ }
+}
+
+apol_vector_t *seaudit_get_log_roles(seaudit_t * s)
+{
+ if (s->log == NULL) {
+ return NULL;
+ } else {
+ return seaudit_log_get_roles(s->log);
+ }
+}
+
+apol_vector_t *seaudit_get_log_types(seaudit_t * s)
+{
+ if (s->log == NULL) {
+ return NULL;
+ } else {
+ return seaudit_log_get_types(s->log);
+ }
+}
+
+apol_vector_t *seaudit_get_log_mls_lvl(seaudit_t * s)
+{
+ if (s->log == NULL) {
+ return NULL;
+ } else {
+ return seaudit_log_get_mls_lvl(s->log);
+ }
+}
+
+apol_vector_t *seaudit_get_log_mls_clr(seaudit_t * s)
+{
+ if (s->log == NULL) {
+ return NULL;
+ } else {
+ return seaudit_log_get_mls_clr(s->log);
+ }
+}
+
+apol_vector_t *seaudit_get_log_classes(seaudit_t * s)
+{
+ if (s->log == NULL) {
+ return NULL;
+ } else {
+ return seaudit_log_get_classes(s->log);
+ }
+}
+
+size_t seaudit_get_num_log_messages(seaudit_t * s)
+{
+ return s->num_log_messages;
+}
+
+const struct tm *seaudit_get_log_first(seaudit_t * s)
+{
+ return s->first;
+}
+
+const struct tm *seaudit_get_log_last(seaudit_t * s)
+{
+ return s->last;
+}
+
+static seaudit_t *seaudit_create(preferences_t * prefs)
+{
+ seaudit_t *s = calloc(1, sizeof(*s));
+ if (s != NULL) {
+ s->prefs = prefs;
+ }
+ return s;
+}
+
+static void seaudit_destroy(seaudit_t ** s)
+{
+ if (s != NULL && *s != NULL) {
+ apol_policy_destroy(&(*s)->policy);
+ seaudit_log_destroy(&(*s)->log);
+ if ((*s)->file != NULL) {
+ fclose((*s)->file);
+ }
+ preferences_destroy(&(*s)->prefs);
+ toplevel_destroy(&(*s)->top);
+ free((*s)->policy_path);
+ free((*s)->log_path);
+ free(*s);
+ *s = NULL;
+ }
+}
+
+static void print_version_info(void)
+{
+ printf("seaudit %s\n%s\n", VERSION, COPYRIGHT_INFO);
+}
+
+static void print_usage_info(const char *program_name, int brief)
+{
+ printf("Usage: %s [OPTIONS] [POLICY ...]\n\n", program_name);
+ if (brief) {
+ printf("\tTry %s --help for more help.\n\n", program_name);
+ return;
+ }
+ printf("Audit Log analysis tool for Security Enhanced Linux.\n\n");
+ printf(" -l FILE, --log=FILE open the log FILE\n");
+ printf(" -h, --help print this help text and exit\n");
+ printf(" -V, --version print version information and exit\n\n");
+}
+
+static void seaudit_parse_command_line(seaudit_t * seaudit, int argc, char **argv, const char **log, apol_policy_path_t ** policy)
+{
+ int optc;
+ *log = NULL;
+ *policy = NULL;
+ apol_policy_path_type_e path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ char *primary_path = NULL;
+ apol_vector_t *modules = NULL;
+ while ((optc = getopt_long(argc, argv, "l:hV", opts, NULL)) != -1) {
+ switch (optc) {
+ case 'l':
+ {
+ *log = optarg;
+ break;
+ }
+ case 'h':
+ {
+ print_usage_info(argv[0], 0);
+ seaudit_destroy(&seaudit);
+ exit(EXIT_SUCCESS);
+ }
+ case 'V':
+ {
+ print_version_info();
+ seaudit_destroy(&seaudit);
+ exit(EXIT_SUCCESS);
+ }
+ default:
+ {
+ /* unrecognized argument give full usage */
+ print_usage_info(argv[0], 1);
+ seaudit_destroy(&seaudit);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ if (optind < argc) { /* modules */
+ if ((modules = apol_vector_create(NULL)) == NULL) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ seaudit_destroy(&seaudit);
+ exit(EXIT_FAILURE);
+ }
+ path_type = APOL_POLICY_PATH_TYPE_MONOLITHIC;
+ primary_path = argv[optind++];
+ while (argc - optind) {
+ if (apol_vector_append(modules, argv[optind])) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ seaudit_destroy(&seaudit);
+ exit(EXIT_FAILURE);
+ }
+ path_type = APOL_POLICY_PATH_TYPE_MODULAR;
+ optind++;
+ }
+ }
+ if (*log == NULL) {
+ *log = preferences_get_log(seaudit->prefs);
+ }
+ if (primary_path != NULL && strcmp(primary_path, "") != 0) {
+ if (apol_file_is_policy_path_list(primary_path)) {
+ if ((*policy = apol_policy_path_create_from_file(primary_path)) == NULL) {
+ ERR(NULL, "%s", "invalid policy list");
+ seaudit_destroy(&seaudit);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ if ((*policy = apol_policy_path_create(path_type, primary_path, modules)) == NULL) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ seaudit_destroy(&seaudit);
+ exit(EXIT_FAILURE);
+ }
+ }
+ } else {
+ const apol_policy_path_t *path = preferences_get_policy(seaudit->prefs);
+ if (path != NULL && (*policy = apol_policy_path_create_from_policy_path(path)) == NULL) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ seaudit_destroy(&seaudit);
+ exit(EXIT_FAILURE);
+ }
+ }
+ apol_vector_destroy(&modules);
+}
+
+/*
+ * We don't want to do the heavy work of loading and displaying the
+ * log and policy before the main loop has started because it will
+ * freeze the gui for too long. To solve this, the function is called
+ * from an idle callback set-up in main.
+ */
+struct delay_file_data
+{
+ toplevel_t *top;
+ const char *log_filename;
+ apol_policy_path_t *policy_path;
+};
+
+static gboolean delayed_main(gpointer data)
+{
+ struct delay_file_data *dfd = (struct delay_file_data *)data;
+ if (dfd->log_filename != NULL && strcmp(dfd->log_filename, "") != 0) {
+ toplevel_open_log(dfd->top, dfd->log_filename);
+ }
+ if (dfd->policy_path != NULL) {
+ toplevel_open_policy(dfd->top, dfd->policy_path);
+ }
+ return FALSE;
+}
+
+int main(int argc, char **argv)
+{
+ preferences_t *prefs;
+ seaudit_t *app;
+ const char *log;
+ apol_policy_path_t *policy;
+ struct delay_file_data file_data;
+
+ gtk_init(&argc, &argv);
+ glade_init();
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+ if ((prefs = preferences_create()) == NULL) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ exit(EXIT_FAILURE);
+ }
+ if ((app = seaudit_create(prefs)) == NULL) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ exit(EXIT_FAILURE);
+ }
+ seaudit_parse_command_line(app, argc, argv, &log, &policy);
+ if ((app->top = toplevel_create(app)) == NULL) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ seaudit_destroy(&app);
+ exit(EXIT_FAILURE);
+ }
+ file_data.top = app->top;
+ file_data.log_filename = log;
+ file_data.policy_path = policy;
+ g_idle_add(&delayed_main, &file_data);
+ gtk_main();
+ if (preferences_write_to_conf_file(app->prefs) < 0) {
+ ERR(NULL, "%s", strerror(ENOMEM));
+ }
+ seaudit_destroy(&app);
+ exit(EXIT_SUCCESS);
+}
diff --git a/seaudit/seaudit.glade b/seaudit/seaudit.glade
new file mode 100644
index 0000000..95da87e
--- /dev/null
+++ b/seaudit/seaudit.glade
@@ -0,0 +1,7713 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="gnome"/>
+
+<widget class="GtkDialog" id="PreferencesWindow">
+ <property name="title" translatable="yes">seaudit Preferences</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewCancelButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ <accessibility>
+ <atkproperty name="AtkObject::accessible_name" translatable="yes">Close</atkproperty>
+ </accessibility>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewOKButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame1">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox39">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table2">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">4</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">10</property>
+
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Policy:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewLogBrowseButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Browse</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="PrefsViewLogEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewLogCurrentButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use Current</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Log:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewPolicyModifyButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="stock">gtk-edit</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Choose...</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="PrefsViewPolicyEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewPolicyCurrentButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use Current</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table31">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">10</property>
+
+ <child>
+ <widget class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Report Config File:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Report Style Sheet:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="PrefsViewStylesheetEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewConfigBrowseButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Browse</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PrefsViewStylesheetBrowseButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Browse</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="PrefsViewConfigEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Default Files&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame2">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkTable" id="table3">
+ <property name="border_width">10</property>
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">5</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">2</property>
+ <property name="column_spacing">18</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="SourceTypeCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Source Type</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="SourceRoleCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Source Role</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="SourceUserCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Source User</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="SourceMLSLVLCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Source MLS Level</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="SourceMLSCLRCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Source MLS Clearance</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="DateCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Date</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="MessageCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Message</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="HostCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Hostname</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="TargetUserCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Target User</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="TargetRoleCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Target Role</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="TargetTypeCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Target Type</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="TargetMLSLVLCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Target MLS Level</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="TargetMLSCLRCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Target MLS Clearance</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="ObjectClassCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Object Class</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="PermissionCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Permission</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="ExecutableCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Executable</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="PIDCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">PID</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="InodeCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Inode</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="PathCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Path</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="OtherCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Other</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="NameCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Name</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="CommandCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Command</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Columns to Display&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame3">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkTable" id="table4">
+ <property name="border_width">10</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">1</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">2</property>
+ <property name="column_spacing">18</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Log update interval (in milliseconds):</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="PrefsViewIntervalEntry">
+ <property name="width_request">53</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Time interval for updating the log in real-time mode</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="RealTimeCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Enable real-time monitoring of newly opened log files</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Real-time Monitoring&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="PolicyWindow">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK</property>
+ <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
+ <property name="title" translatable="yes">Find TE Rules</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">False</property>
+ <property name="default_width">800</property>
+ <property name="default_height">600</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkNotebook" id="PolicyWindowNotebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="border_width">10</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">41</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="PolicyWindowSTypeCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Source type regular expression</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="PolicyWindowSTypeCombo">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="PolicyWindowSTypeDirectCheck">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Only show direct matches</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="PolicyWindowTTypeCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Target type regular expression</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="PolicyWindowTTypeCombo">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="PolicyWindowTTypeDirectCheck">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Only show direct matches</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="PolicyWindowClassCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Object class</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="PolicyWindowClassCombo">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkButton" id="PolicyWindowFindTERulesButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <accelerator key="Return" modifiers="0" signal="clicked"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-find</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Find TE Rules</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PolicyWindowCloseButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTextView" id="PolicyWindowTERulesResults">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK</property>
+ <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
+ <property name="editable">False</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_NONE</property>
+ <property name="cursor_visible">True</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
+ <property name="text" translatable="yes"></property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="PolicyWindowFindTERulesTab">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Find TE Rules</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTextView" id="PolicyWindowPolicyText">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_NONE</property>
+ <property name="cursor_visible">True</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
+ <property name="text" translatable="yes"></property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="PolicyWindowPolicyTextTab">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Policy Source</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkStatusbar" id="statusbar1">
+ <property name="visible">True</property>
+ <property name="has_resize_grip">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkWindow" id="TopLevel">
+ <property name="title" translatable="yes">seaudit</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">950</property>
+ <property name="default_height">650</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <signal name="destroy" handler="toplevel_on_destroy" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 16:53:05 GMT"/>
+
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property>
+ <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property>
+
+ <child>
+ <widget class="GtkMenuItem" id="FileMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="FileMenu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="OpenLog">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Open a log file</property>
+ <property name="label" translatable="yes">Open _Log</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_open_log_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:23:31 GMT"/>
+ <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1458">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="OpenRecentLog">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Open a log from the recent files list</property>
+ <property name="label" translatable="yes">Open Recent Log</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator3">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="OpenPolicy">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Open a policy</property>
+ <property name="label" translatable="yes">Open _Policy</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_open_policy_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:23:18 GMT"/>
+ <accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1459">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="OpenRecentPolicy">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Open a policy from the recent files list</property>
+ <property name="label" translatable="yes">Open Recent Policy</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="Preferences">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Edit startup and display preferences</property>
+ <property name="label" translatable="yes">Preferences</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_preferences_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:22:57 GMT"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1460">
+ <property name="visible">True</property>
+ <property name="stock">gtk-preferences</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator4">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="Quit">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Quit seaudit</property>
+ <property name="label" translatable="yes">_Quit</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_quit_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:24:49 GMT"/>
+ <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1461">
+ <property name="visible">True</property>
+ <property name="stock">gtk-quit</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="ViewMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="ViewMenu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="NewView">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Create a new default view</property>
+ <property name="label" translatable="yes">_New View</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_new_view_activate" object="TopLevel" last_modification_time="Tue, 05 Dec 2006 20:38:59 GMT"/>
+ <accelerator key="N" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1462">
+ <property name="visible">True</property>
+ <property name="stock">gtk-new</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="OpenView">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Open an existing view</property>
+ <property name="label" translatable="yes">_Open View...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_open_view_activate" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:22 GMT"/>
+ <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1463">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="SaveView">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Save the current view</property>
+ <property name="label" translatable="yes">_Save View</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_save_view_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:34:20 GMT"/>
+ <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1464">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="SaveViewAs">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Save the current view as a new file</property>
+ <property name="label" translatable="yes">S_ave View As...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_save_viewas_activate" object="TopLevel" last_modification_time="Tue, 05 Dec 2006 20:40:24 GMT"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1465">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save-as</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator5">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="ModifyView">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Modify the current view</property>
+ <property name="label" translatable="yes">_Modify View</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_modify_view_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:35:27 GMT"/>
+ <accelerator key="M" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1466">
+ <property name="visible">True</property>
+ <property name="stock">gtk-convert</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator7">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="ExportAll">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Export to a file all messages in the current view</property>
+ <property name="label" translatable="yes">_Export Messages...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_export_all_messages_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:37:54 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="ExportSelected">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Export to a file selected messages</property>
+ <property name="label" translatable="yes">E_xport Selected Messages...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_export_selected_messages_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:37:16 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator8">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="ViewMessage">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">View all fields of the selected message</property>
+ <property name="label" translatable="yes">_View Selected Message</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_view_entire_message_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 15:39:51 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="SearchMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Search</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="SearchMenu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="FindTERules">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Find TE rules in the loaded policy</property>
+ <property name="label" translatable="yes">_Find TE Rules...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_find_terules_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:30:21 GMT"/>
+ <accelerator key="F" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1467">
+ <property name="visible">True</property>
+ <property name="stock">gtk-find</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="ToolsMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Tools</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="ToolsMenu_menu">
+
+ <child>
+ <widget class="GtkMenuItem" id="CreateReport">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Create a report from audit messages</property>
+ <property name="label" translatable="yes">_Create Report...</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_create_report_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:30:21 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator10">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkCheckMenuItem" id="MonitorLog">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Enable or disable real-time monitoring of log file</property>
+ <property name="label" translatable="yes">_Monitor Log</property>
+ <property name="use_underline">True</property>
+ <property name="active">False</property>
+ <signal name="activate" handler="toplevel_on_monitor_log_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:35:09 GMT"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="ClearView">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Clear all messages from the current view</property>
+ <property name="label" translatable="yes">C_lear View</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_clear_view_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:30:21 GMT"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkMenuItem" id="HelpMenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+
+ <child>
+ <widget class="GtkMenu" id="HelpMenu_menu">
+
+ <child>
+ <widget class="GtkImageMenuItem" id="Help">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_help_activate" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:44:08 GMT"/>
+ <accelerator key="H" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1468">
+ <property name="visible">True</property>
+ <property name="stock">gtk-help</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separator9">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkImageMenuItem" id="About">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_About seaudit</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="toplevel_on_about_seaudit_activate" object="TopLevel" last_modification_time="Wed, 22 Nov 2006 16:02:03 GMT"/>
+
+ <child internal-child="image">
+ <widget class="GtkImage" id="image1469">
+ <property name="visible">True</property>
+ <property name="stock">gtk-about</property>
+ <property name="icon_size">1</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkButton" id="FindTERulesButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Find TE rules in the loaded policy</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="toplevel_on_find_terules_click" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:56 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment54">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox69">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1488">
+ <property name="visible">True</property>
+ <property name="stock">gtk-find</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label207">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Find TE Rules</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ModifyViewButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Modify the current view</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="toplevel_on_modify_view_click" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:51 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment55">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox70">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1489">
+ <property name="visible">True</property>
+ <property name="stock">gtk-convert</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label208">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Modify View</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="MonitorLogButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Toggle the monitor log feature</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="toplevel_on_monitor_log_click" object="TopLevel" last_modification_time="Mon, 27 Nov 2006 15:48:44 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment56">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox71">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1490">
+ <property name="visible">True</property>
+ <property name="stock">gtk-refresh</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label209">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Monitor Log</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ClearViewButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="tooltip" translatable="yes">Clear messages in the current view</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <signal name="clicked" handler="toplevel_on_clear_view_click" object="TopLevel" last_modification_time="Thu, 05 Jul 2007 21:07:02 GMT"/>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment57">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox72">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1491">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label210">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Clear View</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="NotebookVBox">
+ <property name="border_width">1</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="PolicyVersionLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Policy: No Policy</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="width_chars">28</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">20</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="LogNumLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Log Messages: No log</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.519999980927</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="width_chars">24</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="LogDateLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Dates: No log</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="MonitorLogLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Monitor Status: &lt;span foreground=&quot;red&quot;&gt;OFF&lt;/span&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">18</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">20</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="ReportWindow">
+ <property name="title" translatable="yes">Create Report</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="default_width">760</property>
+ <property name="default_height">240</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="ReportWindowClose">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ReportWindowCreate">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment26">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox44">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1474">
+ <property name="visible">True</property>
+ <property name="stock">gtk-new</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label129">
+ <property name="visible">True</property>
+ <property name="label">Create Report</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox36">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame27">
+ <property name="border_width">8</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment21">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">4</property>
+ <property name="right_padding">4</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox14">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox18">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="ReportWindowAllMessagesRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Messages from entire audit log</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="ReportWindowViewMessagesRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Messages from current view
+(Does not preserve sort order.)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">ReportWindowAllMessagesRadio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="ReportWindowMalformedCheck">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Include malformed messages</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label122">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Input&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame28">
+ <property name="border_width">8</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment22">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">4</property>
+ <property name="right_padding">4</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox15">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox16">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="ReportWindowTextRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Plain Text</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="ReportWindowHTMLRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">HTML</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">ReportWindowTextRadio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox17">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="ReportWindowUseStylesheetCheck">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use HTML style sheet</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox42">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">7</property>
+
+ <child>
+ <widget class="GtkLabel" id="ReportWindowStylesheetLabel">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes"> Style sheet file:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="ReportWindowStylesheetEntry">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ReportWindowStylesheetBrowse">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment25">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox43">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1473">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label128">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Browse</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox39">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">7</property>
+
+ <child>
+ <widget class="GtkLabel" id="label123">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Report config file:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="ReportWindowConfigEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ReportWindowConfigBrowse">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment24">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox41">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1472">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label126">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Browse</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label124">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Output&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="ModifyViewWindow">
+ <property name="title" translatable="yes">Modify View</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button48">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button49">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-apply</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-10</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button56">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox19">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox46">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label131">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">View name:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="ModifyViewNameEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame29">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox47">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkComboBox" id="ModifyViewVisibleCombo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Show
+Hide</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label132">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">messages that match</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="ModifyViewMatchCombo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">all filters
+any filter</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label133">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Match&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame30">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox48">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="ModifyViewFilterView">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox2">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkButton" id="ModifyViewAddButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ModifyViewEditButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-edit</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ModifyViewRemoveButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ModifyViewImportButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment28">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox49">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1476">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label134">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Import</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ModifyViewExportButton">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment29">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox50">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1477">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label135">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">E_xport</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label136">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Filters&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="FilterWindow">
+ <property name="title" translatable="yes">Edit Filter</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="closebutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox20">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame31">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox21">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox51">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label138">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Filter name:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewNameEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"> </property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox52">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label139">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Filter match:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="FilterViewMatchCombo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">All Criteria
+Any Criterion</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkNotebook" id="notebook1">
+ <property name="border_width">4</property>
+ <property name="width_request">349</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox22">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame32">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkTable" id="table17">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewSUserEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Source user(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewSRoleEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Source role(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewSTypeEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Source type(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewSMLSLVLEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Source MLS Level(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewSMLSCLREntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Source MLS Clearance(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewSRoleButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select source role(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> Role: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewSUserButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select source user(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> User: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewSTypeButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select source type(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> Type: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewSMLSLVLButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select source MLS Level(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> MLS Level: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewSMLSCLRButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select source MLS Clearance(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> MLS Clearance: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label140">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Source Context&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame33">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkTable" id="table18">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewTTypeButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select target type(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> Type: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewTUserButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select target user(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> User: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewTRoleButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select target role(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> Role: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewTMLSLVLButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select target MLS Level(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> MLS Level: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewTMLSCLRButton">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select target MLS Clearance(s)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> MLS Clearance: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewTTypeEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Target type(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewTUserEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Target user(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewTRoleEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Target role(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewTMLSLVLEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Target MLS Level(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewTMLSCLREntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Target MLS Clearance(s) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label141">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Target Context&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame34">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox53">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewClassButton">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Select object class(es)</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes"> Class: </property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewClassEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Object class(es) to filter, comma separated</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label142">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Object Class&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox6">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewContextClearButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment38">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox58">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1480">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label175">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Clear Tab</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label144">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Context</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox23">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame35">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkTable" id="table19">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label145">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">IP Address:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label146">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Port:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label147">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Interface:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewIPAddrEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">IP Address to filter (match as a glob expression)</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewPortEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Port number to match (any of port, source, dest, fport or lport)</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewNetIfEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Network interface to match (exact string match)</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label148">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Networking&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame36">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkTable" id="table20">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">4</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label149">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Executable:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewExeEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Name of executable (match as a glob expression)</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewPathEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Path of target file (match as a glob expression)</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label150">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Path:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label151">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Hostname:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewHostEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Host system that generated audit message (match as a glob expression)</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label152">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Command:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="FilterViewCommEntry">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Name of command (match as a glob expression)</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label153">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Message Type:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="FilterViewMessageCombo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">All Messages
+Only AVC Denied
+Only AVC Granted</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label154">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Other&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox7">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">5</property>
+
+ <child>
+ <widget class="GtkButton" id="FilterViewOtherClearButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment31">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox55">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1479">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label155">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Clear Tab</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label156">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Other</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox24">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="FilterViewDateNoneRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Do not match date and time</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="FilterViewDateBeforeRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Match messages before Start</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">FilterViewDateNoneRadio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="FilterViewDateAfterRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Match messages after Start</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">FilterViewDateNoneRadio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment41">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">20</property>
+ <property name="right_padding">20</property>
+
+ <child>
+ <widget class="GtkFrame" id="FilterViewDateStartFrame">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment42">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">4</property>
+ <property name="right_padding">4</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox29">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table26">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">True</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label183">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Month:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label184">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Day:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateStartDaySpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 1 31 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="FilterViewDateStartMonthCombo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Jan
+Feb
+Mar
+Apr
+May
+Jun
+Jul
+Aug
+Sep
+Oct
+Nov
+Dec</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table27">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label186">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Hour:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label187">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Minute:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label188">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Second:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateStartHourSpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 23 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateStartMinuteSpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 59 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateStartSecondSpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 59 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label190">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Start&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="FilterViewDateBetweenRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Match messages between Start and End</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">FilterViewDateNoneRadio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment44">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">20</property>
+ <property name="right_padding">20</property>
+
+ <child>
+ <widget class="GtkFrame" id="FilterViewDateEndFrame">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment45">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">4</property>
+ <property name="right_padding">4</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox30">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table28">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">True</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label191">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Month:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label192">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Day:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateEndDaySpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 1 31 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="FilterViewDateEndMonthCombo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Jan
+Feb
+Mar
+Apr
+May
+Jun
+Jul
+Aug
+Sep
+Oct
+Nov
+Dec</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table29">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">4</property>
+
+ <child>
+ <widget class="GtkLabel" id="label193">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Hour:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label194">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Minute:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label195">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Second:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateEndHourSpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 23 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateEndMinuteSpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 59 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSpinButton" id="FilterViewDateEndSecondSpin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">0 0 59 1 10 10</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label196">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;End&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label173">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Date</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox27">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTextView" id="FilterViewDescView">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="overwrite">False</property>
+ <property name="accepts_tab">True</property>
+ <property name="justification">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap_mode">GTK_WRAP_WORD</property>
+ <property name="cursor_visible">True</property>
+ <property name="pixels_above_lines">0</property>
+ <property name="pixels_below_lines">0</property>
+ <property name="pixels_inside_wrap">0</property>
+ <property name="left_margin">0</property>
+ <property name="right_margin">0</property>
+ <property name="indent">0</property>
+ <property name="text" translatable="yes"></property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label174">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Notes</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="PolicyComponentListsWindow">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Policy Components</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="default_width">600</property>
+ <property name="default_height">450</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area5">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="closebutton2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox31">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">10</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox37">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label200">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Select items from:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment49">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">10</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox38">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="PolicyCompLogRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Log</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="PolicyCompPolicyRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Policy</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">PolicyCompLogRadio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="PolicyCompBothRadio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Log and Policy</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">PolicyCompLogRadio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox59">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkFrame" id="frame50">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox35">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow7">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="PolicyCompIncView">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Unselected Items</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_ENTER_NOTIFY_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox9">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="PolicyCompIncSelectButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Select All</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PolicyCompIncUnselectButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Unselect All</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label199">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Included Items&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment47">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">0.20000000298</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">50</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox3">
+ <property name="width_request">85</property>
+ <property name="height_request">56</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="PolicyCompToExcButton">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Add to selected items list</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment48">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox64">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1482">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-forward</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label202">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PolicyCompToIncButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image1483">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-back</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFrame" id="frame52">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="label_yalign">0.5</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox36">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow8">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="PolicyCompExcView">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Unselected Items</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_ENTER_NOTIFY_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox10">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_SPREAD</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="PolicyCompExcSelectButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Select All</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="PolicyCompExcUnselectButton">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Unselect All</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label201">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Excluded Items&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+<widget class="GtkDialog" id="PolicyOpenWindow">
+ <property name="title" translatable="yes">Open Policy</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="modal">True</property>
+ <property name="default_width">340</property>
+ <property name="default_height">360</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">True</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area6">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancel button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="ok button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">10</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox.1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Policy Type:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment.1.2">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">10</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox.1.2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="monolithic radio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Monolithic policy</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="modular radio">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Modular policy</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">monolithic radio</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox.2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="main filename label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Policy Filename:&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox.2.2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkEntry" id="base entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="base browse">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment.2.2.1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox.2.2.1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image.2.2.1.1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label.2.2.1.1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Browse</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox.3">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">4</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow.3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="module view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">False</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox.3">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">8</property>
+
+ <child>
+ <widget class="GtkButton" id="module add button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-add</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="module remove button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-remove</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="module list import button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment50">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox65">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1484">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label203">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Import</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="module list export button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment51">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox66">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image1485">
+ <property name="visible">True</property>
+ <property name="stock">gtk-save</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label204">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">E_xport</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/seaudit/seaudit.gladep b/seaudit/seaudit.gladep
new file mode 100644
index 0000000..5b8f438
--- /dev/null
+++ b/seaudit/seaudit.gladep
@@ -0,0 +1,7 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">
+
+<glade-project>
+ <name>seaudit</name>
+ <program_name>seaudit</program_name>
+</glade-project>
diff --git a/seaudit/seaudit.h b/seaudit/seaudit.h
new file mode 100644
index 0000000..34be02b
--- /dev/null
+++ b/seaudit/seaudit.h
@@ -0,0 +1,231 @@
+/**
+ * @file
+ * Declaration of the main driver class for seaudit.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SEAUDIT_H
+#define SEAUDIT_H
+
+#include "preferences.h"
+#include <apol/policy.h>
+#include <apol/policy-path.h>
+#include <seaudit/log.h>
+#include <stdio.h>
+#include <time.h>
+
+typedef struct seaudit seaudit_t;
+
+#define COPYRIGHT_INFO "Copyright (c) 2003-2007 Tresys Technology, LLC"
+
+/**
+ * Retrieve the preferences object associated with the seaudit object.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Pointer to a preferences object. Do not free() this pointer.
+ */
+preferences_t *seaudit_get_prefs(seaudit_t * s);
+
+/**
+ * Set the currently loaded policy for seaudit. This will also update
+ * the preferences object's recently loaded policies.
+ *
+ * @param s seaudit object to modify.
+ * @param policy New policy file for seaudit. If NULL then seaudit
+ * has no policy opened. Afterwards seaudit takes ownership of the
+ * policy.
+ * @param path If policy is not NULL, then add this path to the most
+ * recently used policy files. This function takes ownership of the
+ * path.
+ */
+void seaudit_set_policy(seaudit_t * s, apol_policy_t * policy, apol_policy_path_t * path);
+
+/**
+ * Retrieve the currently loaded policy.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Pointer to an apol policy, or NULL if none loaded. Treat
+ * this as a const pointer.
+ */
+apol_policy_t *seaudit_get_policy(seaudit_t * s);
+
+/**
+ * Return the path to the currently loaded policy. If the current
+ * policy is modular then this returns the base policy's path.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Path of policy, or NULL if none loaded. Treat this as a
+ * const pointer.
+ */
+apol_policy_path_t *seaudit_get_policy_path(seaudit_t * s);
+
+/**
+ * Set the currently loaded log for seaudit. This will also update
+ * the preferences object's recently loaded files.
+ *
+ * @param s seaudit object to modify.
+ * @param log New log file for seaudit. If NULL then seaudit has no
+ * log files opened. Afterwards seaudit takes ownership of the log.
+ * @param f File handler that was used to open the log. Afterwards
+ * seaudit takes ownership of this handler.
+ * @param filename If log is not NULL, then add this filename to the
+ * most recently used files.
+ */
+void seaudit_set_log(seaudit_t * s, seaudit_log_t * log, FILE * f, const char *filename);
+
+/**
+ * Command seaudit to (re)parse its log file.
+ *
+ * @param s seaudit object containing the log.
+ *
+ * @return 0 if log parsed cleanly, < 0 upon errors, or > 0 if there
+ * were warnings.
+ */
+int seaudit_parse_log(seaudit_t * s);
+
+/**
+ * Retrieve the currently loaded log file.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Pointer to a libseaudit log, or NULL if none loaded. Treat
+ * this as a const pointer.
+ */
+seaudit_log_t *seaudit_get_log(seaudit_t * s);
+
+/**
+ * Return the path to the currently loaded log file.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Path of log file, or NULL if none loaded. Treat this as a
+ * const pointer.
+ */
+char *seaudit_get_log_path(seaudit_t * s);
+
+/**
+ * Return a vector of strings corresponding to all users found within
+ * currently opened log files. The vector will be sorted
+ * alphabetically.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Vector of sorted users, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *seaudit_get_log_users(seaudit_t * s);
+
+/**
+ * Return a vector of strings corresponding to all roles found within
+ * currently opened log files. The vector will be sorted
+ * alphabetically.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Vector of sorted roles, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *seaudit_get_log_roles(seaudit_t * s);
+
+/**
+ * Return a vector of strings corresponding to all types found within
+ * currently opened log files. The vector will be sorted
+ * alphabetically.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Vector of sorted types, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *seaudit_get_log_types(seaudit_t * s);
+
+/**
+ * Return a vector of strings corresponding to all mls levels
+ * found within currently opened log files. The vector will be sorted
+ * alphabetically.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Vector of sorted types, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *seaudit_get_log_mls_lvl(seaudit_t * s);
+
+/**
+ * Return a vector of strings corresponding to all mls clearance
+ * found within currently opened log files. The vector will be sorted
+ * alphabetically.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Vector of sorted types, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *seaudit_get_log_mls_clr(seaudit_t * s);
+
+/**
+ * Return a vector of strings corresponding to all object classes
+ * found within currently opened log file. The vector will be sorted
+ * alphabetically.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Vector of sorted classes, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *seaudit_get_log_classes(seaudit_t * s);
+
+/**
+ * Return the number of messages in the current log.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Number of log messages, or 0 if no log is opened.
+ */
+size_t seaudit_get_num_log_messages(seaudit_t * s);
+
+/**
+ * Return the time stamp for the first message in the currently opened
+ * log.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Time of the first log message, or NULL if no log is opened.
+ * Treat this as a const pointer.
+ */
+const struct tm *seaudit_get_log_first(seaudit_t * s);
+
+/**
+ * Return the time stamp for the last message in the currently opened
+ * log.
+ *
+ * @param s seaudit object to query.
+ *
+ * @return Time of the last log message, or NULL if no log is opened.
+ * Treat this as a const pointer.
+ */
+const struct tm *seaudit_get_log_last(seaudit_t * s);
+
+#endif
diff --git a/seaudit/seaudit.png b/seaudit/seaudit.png
new file mode 100644
index 0000000..8ed09e2
--- /dev/null
+++ b/seaudit/seaudit.png
Binary files differ
diff --git a/seaudit/seaudit.xcf b/seaudit/seaudit.xcf
new file mode 100644
index 0000000..ada98bb
--- /dev/null
+++ b/seaudit/seaudit.xcf
Binary files differ
diff --git a/seaudit/seaudit_help.txt b/seaudit/seaudit_help.txt
new file mode 100644
index 0000000..3959f02
--- /dev/null
+++ b/seaudit/seaudit_help.txt
@@ -0,0 +1,293 @@
+Audit Log Analysis Tool for Security Enhanced Linux
+
+
+Overview:
+---------
+This file contains basic help information for using seaudit, an audit
+log analysis tool for Security Enhanced Linux (SELinux) audit
+messages.
+
+The tool does not need to be installed on an SELinux system; it will
+work on any Linux machine. The tool parses a given syslog and
+extracts all load policy messages, AVC messages, and change of Boolean
+messages from conditional policies.
+
+The tool has the following main functions:
+ 1) Browse and sort SELinux audit messages.
+ 2) Filter an audit log based on fields in the messages.
+ 3) Search the policy based on data from a given audit message.
+ 4) Export SELinux audit messages to a file.
+ 5) Generate reports in HTML or plain text format from an entire log
+ or an seaudit view.
+
+
+Log and Policy Files:
+---------------------
+The program provides you with the option of opening either a source,
+monolithic binary, or modular policy file. If a policy is not
+specified at the command line, seaudit will attempt to use the default
+policy location, as specified during configuration time (e.g.,
+./configure --with-default-policy).
+
+Note that seaudit does not require an opened policy; in this case the
+user will not be able to use the search policy features of the tool.
+Only one policy and one audit log can be open at a time, so if another
+one is opened the current one will be closed.
+
+When opening a log file the user may get the warning "Warning! One or
+more invalid messages found in audit log." This means that one or
+more of the SELinux audit messages either was missing a standard
+message field (e.g., time, hostname, or access type) or:
+
+ 1) A message had an unrecognized time stamp,
+ 2) An AVC message did not contain permissions,
+ 3) An AVC message was not labeled as "denied" or "granted",
+ 4) A load policy message was not in the correct form, such as
+ missing a line or a data field, or
+ 5) A Boolean message did not contain a list of Booleans.
+
+The seaudit program will still attempt to display the remaining data
+from the SELinux audit message in question along with all the other
+SELinux messages in the log, but only if one of the following
+sub-strings is found within the message:
+
+ "avc:" - an access denied or granted message,
+ "security:" - a load policy message, or
+ "committed booleans" - a change in one or more Boolean states.
+
+All other messages will be ignored.
+
+
+Menus:
+------
+Use the FILE menu to load a different audit log or a policy. The file
+menu also allows the user to change preferences including default log,
+default policy, which columns to present when viewing audit logs, and
+whether seaudit should enable real-time log monitoring upon start-up.
+All of these settings will be saved and reloaded each time seaudit is
+started.
+
+The VIEW menu allows the user to display multiple views of a log. A
+default view is created automatically when an audit log is first
+opened. Additional views can be created by selecting View->New View.
+A view has its own set of filters that limits which messages are
+shown. Use 'Save View' and 'Save View As...' menu items to save to
+file the current view's settings. 'Export Messages' writes to a file
+the messages within the current view; 'Export Selected Messages'
+writes only those that are currently selected. 'View Selected
+Message' will open a new window that shows all of the fields for the
+selected log message or messages.
+
+Use the SEARCH menu to find type enforcement rules within the policy.
+
+The TOOLS menu presents seaudit's advanced features. The first
+option, 'Create Report...', is used to create report files in HTML or
+plain text format using an entire audit log or an seaudit view.
+'Monitor Log' enables and disables seaudit's real-time monitoring
+feature.
+
+Right-click on an audit message within a view to display a pop-up menu
+that allows the user to:
+ - View the entire message within a separate text box,
+ - Find TE Rules within the policy using the message, or
+ - Export selected messages to a file.
+
+
+Sorting:
+--------
+By default the messages within a view are sorted in the order they
+appear within the log file, typically chronologically. To sort by a
+particular field click on the column heading. The only column that
+cannot be used for sorting is the 'Other' column. Only one level of
+sorting can be performed. The file KNOWN-BUGS describes a particular
+instance where the sort order may be misleading.
+
+
+Log Monitoring:
+---------------
+Selecting 'Monitor Log' from the Tools Menu or clicking on the 'Toggle
+Monitor' button turns on and off the real-time log monitoring feature.
+When this feature is on, seaudit checks for new messages at a regular
+interval, per second by default. This interval can be configured from
+the Preferences dialog. As new messages are added to the currently
+loaded log file, each view will be updated according to its filters
+and sorting criterion.
+
+
+Finding TE Rules:
+-----------------
+The 'Find TE Rules' button opens a new dialog box that contains two
+tabs. In the first tab, the user enters search criteria similar to
+those in apol's TE Rules query. If the user had right-clicked an
+audit message and selected the second option, the search criteria will
+be filled in automatically based on that message. For each entry, the
+user may enter a regular expression; he may also choose a entry from
+the drop-down box.
+
+The 'Only show direct matches' checkbox alters the meaning of the
+search. By default the search returns rules that have either the
+provided type or any of the type's attributes in the appropriate
+field. If this checkbox is enabled then the search will only find
+that type; it ignores the type's attributes.
+
+Click on 'Find TE Rules' button to perform the search and return a
+list of matching rules. If the currently opened policy file is
+capable of showing line numbers, the displayed rules will contain
+hyperlinks to the appropriate line in the Policy Source tab.
+
+The second tab, 'Policy Source', provides a convenient display of the
+text of the policy source file and is only available when opening a
+source policy. If a modular policy was opened, then this tab only
+shows the base policy's source.
+
+The seaudit program provides limited searching. More thorough policy
+searches and analyses may be conducted through the companion tool,
+apol.
+
+
+Log Views:
+----------
+The 'Modify View' button opens a dialog box that lets the user modify
+the list of filters for the current view. Filters are used to select
+either messages to show or to hide; in addition messages can match
+either any filter or all filters.
+
+
+Modifying Filters Within A View:
+--------------------------------
+To add a new filter, first select the view for which the filter is
+needed by clicking on the corresponding tab, then click on the 'Modify
+View' button, and then 'Add'. Within this new dialog, edit the
+various properties of a filter such as its name, description, source
+context, target context, object type, etc.
+
+Use the 'Context' tab to enter values for part or all of the source
+and target context, as well as the object class. Either enter the
+values manually with a comma between entries or click on the button
+(e.g., Types) and to open another dialog that has a list of all valid
+entries. This list can be populated by values from the log, the
+policy, or both the log and policy, by selecting the appropriate radio
+button.
+
+Use the 'Other' tab to filter by networking criteria (i.e., IP
+address, port and/or interface) and other miscellaneous fields. Many
+of these fields accept either an exact match or a glob expression (see
+Globbing Expressions below); the text entries' tool tips specify how
+matching is performed.
+
+The filter criteria are saved automatically when this dialog is
+closed.
+
+
+Globbing Expressions:
+---------------------
+Use glob expressions to construct more flexible search filters by
+allowing for pattern expansion instead of just static strings. There
+are several different methods of glob syntax that are supported by
+seaudit.
+
+(1) Wildcard Matching
+
+String containing the characters '?' and '*' are said to contain
+wildcard characters. While, both are considered wildcards they allow
+for different functionality.
+
+ (a) The '?' character matches any character.
+
+ example: ?at matches the strings aat, bat, cat, etc.
+
+ (b) The '*' matches any string.
+
+ example: sys* matches the strings system, sysadmin, etc.
+
+(2) Character Classes
+
+Character classes are used when one desires to find certain
+characters, at a certain position within a string. The '[' character
+is used to begin a character class and the ']' character is used to
+end the class. The characters in the string contained between the two
+brackets comprise the character class, which can NOT be empty.
+
+ example: e[abz]x matches the strings eax, ebx, ezx
+
+(3) Ranges
+
+Ranges are an extension of character classes which allow one to allow
+for finding a certain sequential set of characters at any point in the
+string. The '-' character is used to indicate a range of characters,
+where the character to the left of the '-' is the beginning and the
+character to the right of the '-' is the end. Multiple ranges can be
+used within the same character class.
+
+ example: a[b-e]f matches the strings abf, acf, adf, aef
+ example: 1[2-36-8]9 matches the strings 129, 139, 169, 179, 189
+
+(4) Complementation
+
+Complementation allows for searching using the complement of any given
+character class or range. The character '!' must be the first
+character after '[' when one desires to use a complementation. When
+using complementations the complement of the string enclosed in the
+brackets after the '!' character is used.
+
+ example: a[!b-y]z matches all three-character strings starting
+ with a followed by any character not occurring between b
+ and y (inclusive), and ending in z
+
+ example: a[!c-ik-y]z matches all three-character string starting
+ with a followed by any character not occurring between c
+ and i (inclusive) or between k and y (inclusive), and
+ ending in z
+
+
+*** CAUTION ***
+
+The seaudit program intersperses the use of regular expressions versus
+glob expressions. For example, 'Edit Filter' uses tool tips to
+specify what type of matching is permitted. The 'Find TE Rules'
+dialog allows regular expressions, not glob expressions.
+Additionally, note that all characters used in glob expressions are
+case sensitive.
+
+
+Status Bar:
+-----------
+At the bottom of seaudit is a status bar. In the left corner it
+displays the approximate version of the policy loaded along with the
+policy type. In the middle it displays the number of log messages in
+the current view and the total number of SELinux messages in the audit
+log. The next label shows the span of the dates in the audit log and
+the right-most label shows the status of the real-time log monitor.
+
+
+Creating Reports:
+-----------------
+From the Tools menu the user can create report files in HTML or plain
+text format using an entire audit log or only those messages present
+in the current view. Select the 'Create Report' menu item to display
+a dialog for making configurations to the report and then save the
+report to a file.
+
+Choose which messages to report using the input frame. Messages may
+come from the entire audit log file or only those in the current view.
+If choosing the entire log, one may also include malformed messages
+within the report. See the previous 'Log and Policy Files' heading
+for what makes up a malformed message in seaudit.
+
+Choose the type to report, either plain text or HTML, in the output
+frame. If selecting an HTML file, an HTML style sheet may also be
+included into the report. A report configuration file specifies the
+type and order of messages to report. If the style sheet or the
+configuration file is not specified, seaudit will use the appropriate
+system default files; the default files may be changed from the
+Preferences dialog.
+
+The seaudit report configuration file may be configured to affect
+information presented in reports; it is required for report
+generation. From this file, one can configure various sections for
+the report, as well as create custom sections in the report through
+the use of saved seaudit view files. Review the default
+seaudit-report.conf file that comes packaged with the SETools
+distribution for more information. This file can be located in the
+shared data directory where seaudit was installed, typically
+/usr/local/share/setools-<version>.
diff --git a/seaudit/toplevel.c b/seaudit/toplevel.c
new file mode 100644
index 0000000..d901a99
--- /dev/null
+++ b/seaudit/toplevel.c
@@ -0,0 +1,1179 @@
+/**
+ * @file
+ * Implementation for the main toplevel window.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "message_view.h"
+#include "open_policy_window.h"
+#include "policy_view.h"
+#include "preferences_view.h"
+#include "report_window.h"
+#include "toplevel.h"
+#include "utilgui.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <apol/util.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <seaudit/parse.h>
+
+struct toplevel
+{
+ seaudit_t *s;
+ policy_view_t *pv;
+ progress_t *progress;
+ /** vector of message_view_t that are in the toplevel's notebook */
+ apol_vector_t *views;
+ GladeXML *xml;
+ /** filename for glade file */
+ char *xml_filename;
+ /** toplevel window widget */
+ GtkWindow *w;
+ GtkNotebook *notebook;
+ /** non-zero if the log file should be polled for changes */
+ int do_monitor_log;
+ /** event id for the monitor callback */
+ guint monitor_id;
+ /** serial number for models created, such that new models
+ * will be named Untitled <number> */
+ int next_model_number;
+ /** filename for most recently opened view */
+ char *view_filename;
+};
+
+/**
+ * Given a view, return its index within the toplevel notebook pages.
+ *
+ * @param top Toplevel containing the notebook.
+ * @param view View to look up.
+ *
+ * @return Index of the view (zero-indexed), or -1 if not found.
+ */
+static gint toplevel_notebook_find_view(toplevel_t * top, message_view_t * view)
+{
+ gint num_pages = gtk_notebook_get_n_pages(top->notebook);
+ while (num_pages >= 1) {
+ GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, num_pages - 1);
+ GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
+ message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object");
+ if (v == view) {
+ return num_pages - 1;
+ }
+ num_pages--;
+ }
+ return -1;
+}
+
+/**
+ * Return the view on the page that is currently raised, or NULL if
+ * there are no views.
+ */
+static message_view_t *toplevel_get_current_view(toplevel_t * top)
+{
+ gint current = gtk_notebook_get_current_page(top->notebook);
+ if (current >= 0) {
+ GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, current);
+ GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
+ return g_object_get_data(G_OBJECT(tab), "view-object");
+ }
+ return NULL;
+}
+
+static void toplevel_on_notebook_switch_page(GtkNotebook * notebook __attribute__ ((unused)), GtkNotebookPage * page
+ __attribute__ ((unused)), guint pagenum __attribute__ ((unused)), toplevel_t * top)
+{
+ toplevel_update_selection_menu_item(top);
+ toplevel_update_status_bar(top);
+}
+
+/**
+ * Callback invoked when a tab close button is clicked.
+ */
+static void toplevel_on_tab_close(GtkButton * button, toplevel_t * top)
+{
+ /* disallow the close if this is the last tab */
+ if (top->views == NULL || apol_vector_get_size(top->views) <= 1) {
+ return;
+ } else {
+ message_view_t *view = g_object_get_data(G_OBJECT(button), "view-object");
+ gint idx = toplevel_notebook_find_view(top, view);
+ size_t i;
+ assert(idx >= 0);
+ gtk_notebook_remove_page(top->notebook, idx);
+ apol_vector_get_index(top->views, view, NULL, NULL, &i);
+ message_view_destroy(&view);
+ apol_vector_remove(top->views, i);
+ }
+}
+
+/**
+ * Create a new view associated with the given model, then create a
+ * tab to place that view. The newly created tab will then be raised.
+ *
+ * @param top Toplevel containing notebook to which add the view and tab.
+ * @param model Model from which to create a view.
+ * @param filename Initial filename for the view.
+ */
+static void toplevel_add_new_view(toplevel_t * top, seaudit_model_t * model, const char *filename)
+{
+ message_view_t *view;
+ GtkWidget *tab, *button, *label, *image;
+ gint idx;
+ if ((view = message_view_create(top, model, filename)) == NULL) {
+ return;
+ }
+ if (apol_vector_append(top->views, view) < 0) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ message_view_destroy(&view);
+ return;
+ }
+ tab = gtk_hbox_new(FALSE, 5);
+ g_object_set_data(G_OBJECT(tab), "view-object", view);
+ button = gtk_button_new();
+ g_object_set_data(G_OBJECT(button), "view-object", view);
+ image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+ gtk_container_add(GTK_CONTAINER(button), image);
+ gtk_widget_set_size_request(image, 8, 8);
+ g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(toplevel_on_tab_close), top);
+ label = gtk_label_new(seaudit_model_get_name(model));
+ g_object_set_data(G_OBJECT(tab), "label", label);
+ gtk_box_pack_start(GTK_BOX(tab), label, TRUE, TRUE, 5);
+ gtk_box_pack_end(GTK_BOX(tab), button, FALSE, FALSE, 5);
+ gtk_widget_show(label);
+ gtk_widget_show(button);
+ gtk_widget_show(image);
+ idx = gtk_notebook_append_page(top->notebook, message_view_get_view(view), tab);
+ gtk_notebook_set_current_page(top->notebook, idx);
+}
+
+/**
+ * Create a new model for the currently loaded log file (which could
+ * be NULL), then create a view that watches that model.
+ */
+static void toplevel_add_new_model(toplevel_t * top)
+{
+ seaudit_log_t *log = seaudit_get_log(top->s);
+ char *model_name = NULL;
+ seaudit_model_t *model = NULL;
+ if (asprintf(&model_name, "Untitled %d", top->next_model_number) < 0) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ return;
+ }
+ model = seaudit_model_create(model_name, log);
+ free(model_name);
+ if (model == NULL) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ return;
+ } else {
+ top->next_model_number++;
+ toplevel_add_new_view(top, model, NULL);
+ }
+}
+
+/**
+ * Callback whenever an item from the recent logs submenu is activated.
+ */
+static void toplevel_on_open_recent_log_activate(GtkWidget * widget, gpointer user_data)
+{
+ GtkWidget *label = gtk_bin_get_child(GTK_BIN(widget));
+ const char *path = gtk_label_get_text(GTK_LABEL(label));
+ toplevel_t *top = (toplevel_t *) user_data;
+ toplevel_open_log(top, path);
+}
+
+/**
+ * Update the entries within recent logs submenu to match those in the
+ * preferences object.
+ */
+static void toplevel_set_recent_logs_submenu(toplevel_t * top)
+{
+ GtkMenuItem *recent = GTK_MENU_ITEM(glade_xml_get_widget(top->xml, "OpenRecentLog"));
+ apol_vector_t *paths = preferences_get_recent_logs(toplevel_get_prefs(top));
+ GtkWidget *submenu, *submenu_item;
+ size_t i;
+
+ gtk_menu_item_remove_submenu(recent);
+ submenu = gtk_menu_new();
+ for (i = 0; i < apol_vector_get_size(paths); i++) {
+ char *path = (char *)apol_vector_get_element(paths, i);
+ submenu_item = gtk_menu_item_new_with_label(path);
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(submenu), submenu_item);
+ gtk_widget_show(submenu_item);
+ g_signal_connect(G_OBJECT(submenu_item), "activate", G_CALLBACK(toplevel_on_open_recent_log_activate), top);
+ }
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), submenu);
+}
+
+/**
+ * Callback whenever an item from the recent policies submenu is
+ * activated.
+ */
+static void toplevel_on_open_recent_policy_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+ apol_policy_path_t *path = g_object_get_data(G_OBJECT(menuitem), "path");
+ toplevel_t *top = (toplevel_t *) user_data;
+ apol_policy_path_t *dup_path = apol_policy_path_create_from_policy_path(path);
+ if (dup_path == NULL) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ return;
+ }
+ toplevel_open_policy(top, dup_path);
+}
+
+/**
+ * Update the entries within recent policies submenu to match those in
+ * the preferences object.
+ */
+static void toplevel_set_recent_policies_submenu(toplevel_t * top)
+{
+ GtkMenuItem *recent = GTK_MENU_ITEM(glade_xml_get_widget(top->xml, "OpenRecentPolicy"));
+ apol_vector_t *paths = preferences_get_recent_policies(toplevel_get_prefs(top));
+ GtkWidget *submenu, *submenu_item;
+ size_t i;
+
+ GtkTooltipsData *tips_data = gtk_tooltips_data_get(GTK_WIDGET(recent));
+ assert(tips_data != NULL);
+ GtkTooltips *tooltips = tips_data->tooltips;
+
+ gtk_menu_item_remove_submenu(recent);
+ submenu = gtk_menu_new();
+ for (i = 0; i < apol_vector_get_size(paths); i++) {
+ apol_policy_path_t *path = apol_vector_get_element(paths, i);
+ char *menu_label = NULL;
+ const char *primary_path = apol_policy_path_get_primary(path);
+ GString *tip = g_string_new(NULL);
+ if ((menu_label = util_policy_path_to_string(path)) == NULL) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ g_string_free(tip, TRUE);
+ break;
+ }
+ submenu_item = gtk_menu_item_new_with_label(menu_label);
+ free(menu_label);
+ if (apol_policy_path_get_type(path) == APOL_POLICY_PATH_TYPE_MONOLITHIC) {
+ g_string_append_printf(tip, "monolithic policy: %s", primary_path);
+ } else {
+ char *s = NULL;
+ const apol_vector_t *modules = apol_policy_path_get_modules(path);
+ size_t num_modules = apol_vector_get_size(modules);
+ g_string_append_printf(tip, "base policy: %s", primary_path);
+ if (num_modules > 0) {
+ if ((s = apol_str_join(modules, "\n ")) == NULL) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ break;
+ }
+ g_string_append_printf(tip, "\n %s", s);
+ free(s);
+ }
+ }
+ gtk_tooltips_set_tip(tooltips, GTK_WIDGET(submenu_item), tip->str, "");
+ g_string_free(tip, TRUE);
+ g_object_set_data(G_OBJECT(submenu_item), "path", path);
+ gtk_menu_shell_prepend(GTK_MENU_SHELL(submenu), submenu_item);
+ gtk_widget_show(submenu_item);
+ g_signal_connect(G_OBJECT(submenu_item), "activate", G_CALLBACK(toplevel_on_open_recent_policy_activate), top);
+ }
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(recent), submenu);
+}
+
+/**
+ * Enable/disable all items (menus and buttons) that depend upon if a
+ * log is loaded.
+ *
+ * @param top Toplevel object containing menu items.
+ * @param TRUE to enable items, FALSE to disable.
+ */
+static void toplevel_enable_log_items(toplevel_t * top, gboolean sens)
+{
+ static const char *items[] = {
+ "NewView", "OpenView", "SaveView", "SaveViewAs", "ModifyView",
+ "ExportAll", "ExportSelected", "ViewMessage",
+ "CreateReport", "MonitorLog", "ClearView",
+ "ModifyViewButton", "MonitorLogButton", "ClearViewButton",
+ NULL
+ };
+ size_t i;
+ const char *s;
+ for (i = 0, s = items[0]; s != NULL; s = items[++i]) {
+ GtkWidget *w = glade_xml_get_widget(top->xml, s);
+ assert(w != NULL);
+ gtk_widget_set_sensitive(w, sens);
+ }
+}
+
+/**
+ * Enable/disable all items (menus and buttons) that depend upon if a
+ * policy is loaded.
+ *
+ * @param top Toplevel object containing widgets.
+ * @param TRUE to enable items, FALSE to disable.
+ */
+static void toplevel_enable_policy_items(toplevel_t * top, gboolean sens)
+{
+ static const char *items[] = {
+ "FindTERules", "FindTERulesButton",
+ NULL
+ };
+ size_t i;
+ const char *s;
+ for (i = 0, s = items[0]; s != NULL; s = items[++i]) {
+ GtkWidget *w = glade_xml_get_widget(top->xml, s);
+ assert(w != NULL);
+ gtk_widget_set_sensitive(w, sens);
+ }
+}
+
+/**
+ * Update the toplevel's title bar to list the log and policy files
+ * opened.
+ *
+ * @param top Toplevel to modify.
+ */
+static void toplevel_update_title_bar(toplevel_t * top)
+{
+ char *log_path = seaudit_get_log_path(top->s);
+ apol_policy_path_t *policy_path = seaudit_get_policy_path(top->s);
+ char *policy_type_str = "Policy";
+ const char *primary_path;
+ char *s;
+
+ if (log_path == NULL) {
+ log_path = "No Log";
+ }
+ if (policy_path == NULL) {
+ primary_path = "No Policy";
+ } else {
+ if (apol_policy_path_get_type(policy_path) == APOL_POLICY_PATH_TYPE_MODULAR) {
+ policy_type_str = "Base";
+ }
+ primary_path = apol_policy_path_get_primary(policy_path);
+ }
+ if (asprintf(&s, "seaudit - [Log file: %s] [%s file: %s]", log_path, policy_type_str, primary_path) < 0) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ return;
+ }
+ gtk_window_set_title(top->w, s);
+ free(s);
+}
+
+/**
+ * Initialize the application icons for the program. These icons are
+ * the ones shown by the window manager within title bars and pagers.
+ * The last icon listed in the array will be displayed in the About
+ * dialog.
+ *
+ * @param top Toplevel whose icon to set. All child windows will
+ * inherit these icons.
+ */
+static void init_icons(toplevel_t * top)
+{
+ static const char *icon_names[] = { "seaudit-small.png", "seaudit.png" };
+ GdkPixbuf *icon;
+ char *path;
+ GList *icon_list = NULL;
+ size_t i;
+ for (i = 0; i < sizeof(icon_names) / sizeof(icon_names[0]); i++) {
+ if ((path = apol_file_find_path(icon_names[i])) == NULL) {
+ continue;
+ }
+ icon = gdk_pixbuf_new_from_file(path, NULL);
+ free(path);
+ if (icon == NULL) {
+ continue;
+ }
+ icon_list = g_list_append(icon_list, icon);
+ }
+ gtk_window_set_default_icon_list(icon_list);
+ gtk_window_set_icon_list(top->w, icon_list);
+}
+
+static void message_view_free(void *elem)
+{
+ message_view_t *view = elem;
+ message_view_destroy(&view);
+}
+
+toplevel_t *toplevel_create(seaudit_t * s)
+{
+ toplevel_t *top;
+ GtkWidget *vbox;
+ int error = 0;
+
+ if ((top = calloc(1, sizeof(*top))) == NULL || (top->views = apol_vector_create(message_view_free)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ top->s = s;
+ top->next_model_number = 1;
+
+ if ((top->xml_filename = apol_file_find_path("seaudit.glade")) == NULL ||
+ (top->xml = glade_xml_new(top->xml_filename, "TopLevel", NULL)) == NULL) {
+ fprintf(stderr, "Could not open seaudit.glade.\n");
+ error = EIO;
+ goto cleanup;
+ }
+ top->w = GTK_WINDOW(glade_xml_get_widget(top->xml, "TopLevel"));
+ g_object_set_data(G_OBJECT(top->w), "toplevel", top);
+ init_icons(top);
+ top->notebook = GTK_NOTEBOOK(gtk_notebook_new());
+ g_signal_connect_after(G_OBJECT(top->notebook), "switch-page", G_CALLBACK(toplevel_on_notebook_switch_page), top);
+ vbox = glade_xml_get_widget(top->xml, "NotebookVBox");
+ gtk_container_add(GTK_CONTAINER(vbox), GTK_WIDGET(top->notebook));
+ gtk_widget_show(GTK_WIDGET(top->notebook));
+ gtk_widget_show(GTK_WIDGET(top->w));
+ toplevel_set_recent_logs_submenu(top);
+ toplevel_set_recent_policies_submenu(top);
+
+ glade_xml_signal_autoconnect(top->xml);
+
+ /* create initial blank tab for the notebook */
+ toplevel_add_new_model(top);
+
+ /* initialize sub-windows, now that glade XML file has been
+ * read */
+ if ((top->pv = policy_view_create(top)) == NULL || (top->progress = progress_create(top)) == NULL) {
+ error = errno;
+ goto cleanup;
+ }
+ cleanup:
+ if (error != 0) {
+ toplevel_destroy(&top);
+ errno = error;
+ return NULL;
+ }
+ return top;
+}
+
+void toplevel_destroy(toplevel_t ** top)
+{
+ if (top != NULL && *top != NULL) {
+ if ((*top)->monitor_id > 0) {
+ g_source_remove((*top)->monitor_id);
+ }
+ policy_view_destroy(&(*top)->pv);
+ apol_vector_destroy(&(*top)->views);
+ free((*top)->xml_filename);
+ g_free((*top)->view_filename);
+ progress_destroy(&(*top)->progress);
+ if ((*top)->w != NULL) {
+ gtk_widget_destroy(GTK_WIDGET((*top)->w));
+ }
+ free(*top);
+ *top = NULL;
+ }
+}
+
+struct log_run_datum
+{
+ toplevel_t *top;
+ FILE *file;
+ const char *filename;
+ seaudit_log_t *log;
+ int result;
+};
+
+/**
+ * Update the seaudit log, then refresh all views as necessary. Note
+ * that this only works in a single-threaded environment; otherwise
+ * there are two possible race conditions:
+ * - monitor is disabled while this function is being executed
+ * - a new log file is loaded while the function is being executed
+ *
+ * But what happens if this function is scheduled and then a new log
+ * is opened? In toplevel_open_log(), do_monitor_log is temporarily
+ * disabled because that function is threaded. It is then re-enabled
+ * afterwards.
+ *
+ * To make this function fully thread-safe requires making this entire
+ * function synchronized, and then employ locking every time
+ * do_monitor_log and monitor_id are set.
+ */
+static gboolean toplevel_monitor_log_timer(gpointer data)
+{
+ toplevel_t *top = (toplevel_t *) data;
+ if (top->do_monitor_log) {
+ int retval;
+ gint i = gtk_notebook_get_n_pages(top->notebook) - 1;
+ uint delay;
+ retval = seaudit_parse_log(top->s);
+ if (retval < 0) {
+ GtkCheckMenuItem *w;
+ toplevel_ERR(top, "Error while monitoring log: %s", strerror(errno));
+ w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog"));
+ top->monitor_id = 0;
+ gtk_check_menu_item_set_active(w, 0);
+ return FALSE;
+ }
+ while (i >= 0) {
+ GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, i);
+ GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
+ message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object");
+ message_view_update_rows(v);
+ i--;
+ }
+
+ /* reschedule another timer callback */
+ delay = preferences_get_real_time_interval(toplevel_get_prefs(top));
+ top->monitor_id = g_timeout_add(delay, toplevel_monitor_log_timer, top);
+ } else {
+ top->monitor_id = 0;
+ }
+ return FALSE;
+}
+
+/**
+ * Enable or disable the log monitoring feature. While enabled, the
+ * log file will be periodically polled; new lines will be parsed and
+ * inserted into the seaudit log object. All models and their views
+ * will then be notified of the changes.
+ *
+ * @param top Toplevel object whose widgets to update.
+ */
+static void toplevel_monitor_log(toplevel_t * top)
+{
+ GtkLabel *label = GTK_LABEL(glade_xml_get_widget(top->xml, "MonitorLogLabel"));
+ assert(label != NULL);
+ if (top->do_monitor_log) {
+ gtk_label_set_markup(label, "Monitor Status: <span foreground=\"green\">ON</span>");
+ if (top->monitor_id == 0) {
+ uint delay = preferences_get_real_time_interval(toplevel_get_prefs(top));
+ top->monitor_id = g_timeout_add(delay, toplevel_monitor_log_timer, top);
+ }
+ } else {
+ if (top->monitor_id > 0) {
+ g_source_remove(top->monitor_id);
+ top->monitor_id = 0;
+ }
+ gtk_label_set_markup(label, "Monitor Status: <span foreground=\"red\">OFF</span>");
+ }
+}
+
+/**
+ * Thread that loads and parses a log file. It will write to
+ * progress_seaudit_handle_func() its status during the load. Note
+ * that the file handle is not closed upon completion; it is left open
+ * so that subsequent calls to seaudit_log_parse(), such as
+ * forreal-time monitoring.
+ *
+ * @param data Pointer to a struct log_run_datum, for control
+ * information.
+ */
+static gpointer toplevel_open_log_runner(gpointer data)
+{
+ struct log_run_datum *run = (struct log_run_datum *)data;
+ progress_update(run->top->progress, "Parsing %s", run->filename);
+ if ((run->file = fopen(run->filename, "r")) == NULL) {
+ progress_update(run->top->progress, "Could not open %s for reading.", run->filename);
+ run->result = -1;
+ goto cleanup;
+ }
+ if ((run->log = seaudit_log_create(progress_seaudit_handle_func, run->top->progress)) == NULL) {
+ progress_update(run->top->progress, "%s", strerror(errno));
+ run->result = -1;
+ goto cleanup;
+ }
+ run->result = seaudit_log_parse(run->log, run->file);
+ cleanup:
+ if (run->result < 0) {
+ if (run->file != NULL) {
+ fclose(run->file);
+ }
+ run->file = NULL;
+ seaudit_log_destroy(&run->log);
+ progress_abort(run->top->progress, NULL);
+ } else if (run->result > 0) {
+ progress_warn(run->top->progress, NULL);
+ } else {
+ progress_done(run->top->progress);
+ }
+ return NULL;
+}
+
+/**
+ * Destroy all views and their notebook tabs.
+ */
+static void toplevel_destroy_views(toplevel_t * top)
+{
+ gint num_pages = gtk_notebook_get_n_pages(top->notebook);
+ while (num_pages >= 1) {
+ message_view_t *view = apol_vector_get_element(top->views, num_pages - 1);
+ gtk_notebook_remove_page(top->notebook, num_pages - 1);
+ message_view_destroy(&view);
+ apol_vector_remove(top->views, num_pages - 1);
+ num_pages--;
+ }
+}
+
+void toplevel_open_log(toplevel_t * top, const char *filename)
+{
+ struct log_run_datum run = { top, NULL, filename, NULL, 0 };
+ int was_monitor_running;
+ GtkCheckMenuItem *w;
+
+ /* disable monitoring during the threaded part of this code */
+ was_monitor_running = top->do_monitor_log;
+ top->do_monitor_log = 0;
+ toplevel_monitor_log(top);
+
+ util_cursor_wait(GTK_WIDGET(top->w));
+ progress_show(top->progress, "Opening Log");
+ g_thread_create(toplevel_open_log_runner, &run, FALSE, NULL);
+ progress_wait(top->progress);
+ progress_hide(top->progress);
+ util_cursor_clear(GTK_WIDGET(top->w));
+
+ if (run.result < 0) {
+ top->do_monitor_log = was_monitor_running;
+ toplevel_monitor_log(top);
+ return;
+ }
+
+ toplevel_destroy_views(top);
+ top->next_model_number = 1;
+ seaudit_set_log(top->s, run.log, run.file, filename);
+ toplevel_set_recent_logs_submenu(top);
+ toplevel_enable_log_items(top, TRUE);
+ toplevel_add_new_model(top);
+ toplevel_update_title_bar(top);
+ toplevel_update_status_bar(top);
+ toplevel_update_selection_menu_item(top);
+ top->do_monitor_log = preferences_get_real_time_at_startup(toplevel_get_prefs(top));
+
+ w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog"));
+
+ gtk_check_menu_item_set_active(w, top->do_monitor_log);
+ /* call this again because the check item could have already
+ * been active, thus its handler would not run */
+ toplevel_monitor_log(top);
+}
+
+struct policy_run_datum
+{
+ toplevel_t *top;
+ apol_policy_path_t *path;
+ apol_policy_t *policy;
+ int result;
+};
+
+/**
+ * Thread that loads and parses a policy file. It will write to
+ * progress_seaudit_handle_func() its status during the load.
+ *
+ * @param data Pointer to a struct policy_run_datum, for control
+ * information.
+ */
+static gpointer toplevel_open_policy_runner(gpointer data)
+{
+ struct policy_run_datum *run = (struct policy_run_datum *)data;
+ progress_update(run->top->progress, "Opening policy.");
+ run->policy =
+ apol_policy_create_from_policy_path(run->path, QPOL_POLICY_OPTION_NO_NEVERALLOWS, progress_apol_handle_func,
+ run->top->progress);
+ if (run->policy == NULL) {
+ run->result = -1;
+ progress_abort(run->top->progress, NULL);
+ return NULL;
+ }
+ run->result = 0;
+ progress_done(run->top->progress);
+ return NULL;
+}
+
+int toplevel_open_policy(toplevel_t * top, apol_policy_path_t * path)
+{
+ struct policy_run_datum run = { top, path, NULL, 0 };
+
+ util_cursor_wait(GTK_WIDGET(top->w));
+ progress_show(top->progress, apol_policy_path_get_primary(path));
+ g_thread_create(toplevel_open_policy_runner, &run, FALSE, NULL);
+ progress_wait(top->progress);
+ progress_hide(top->progress);
+ util_cursor_clear(GTK_WIDGET(top->w));
+ if (run.result < 0) {
+ apol_policy_path_destroy(&path);
+ return run.result;
+ }
+ seaudit_set_policy(top->s, run.policy, path);
+ toplevel_set_recent_policies_submenu(top);
+ toplevel_enable_policy_items(top, TRUE);
+ toplevel_update_title_bar(top);
+ toplevel_update_status_bar(top);
+ policy_view_update(top->pv, path);
+ return 0;
+}
+
+void toplevel_update_status_bar(toplevel_t * top)
+{
+ apol_policy_t *policy = seaudit_get_policy(top->s);
+ GtkLabel *policy_version = (GtkLabel *) glade_xml_get_widget(top->xml, "PolicyVersionLabel");
+ GtkLabel *log_num = (GtkLabel *) glade_xml_get_widget(top->xml, "LogNumLabel");
+ GtkLabel *log_dates = (GtkLabel *) glade_xml_get_widget(top->xml, "LogDateLabel");
+ seaudit_log_t *log = toplevel_get_log(top);
+
+ if (policy == NULL) {
+ gtk_label_set_text(policy_version, "Policy: No policy");
+ } else {
+ char *policy_str = apol_policy_get_version_type_mls_str(policy);
+ if (policy_str == NULL) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ } else {
+ char *s;
+ if (asprintf(&s, "Policy: %s", policy_str) < 0) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ } else {
+ gtk_label_set_text(policy_version, s);
+ free(s);
+ }
+ free(policy_str);
+ }
+ }
+
+ if (log == NULL) {
+ gtk_label_set_text(log_num, "Log Messages: No log");
+ gtk_label_set_text(log_dates, "Dates: No log");
+ } else {
+ message_view_t *view = toplevel_get_current_view(top);
+ size_t num_messages = seaudit_get_num_log_messages(top->s);
+ size_t num_view_messages;
+ const struct tm *first = seaudit_get_log_first(top->s);
+ const struct tm *last = seaudit_get_log_last(top->s);
+ assert(view != NULL);
+ num_view_messages = message_view_get_num_log_messages(view);
+ char *s, t1[256], t2[256];
+ if (asprintf(&s, "Log Messages: %zd/%zd", num_view_messages, num_messages) < 0) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ } else {
+ gtk_label_set_text(log_num, s);
+ free(s);
+ }
+ if (first == NULL || last == NULL) {
+ gtk_label_set_text(log_dates, "Dates: No messages");
+ } else {
+ strftime(t1, 256, "%b %d %H:%M:%S", first);
+ strftime(t2, 256, "%b %d %H:%M:%S", last);
+ if (asprintf(&s, "Dates: %s - %s", t1, t2) < 0) {
+ toplevel_ERR(top, "%s", strerror(errno));
+ } else {
+ gtk_label_set_text(log_dates, s);
+ free(s);
+ }
+ }
+ }
+}
+
+void toplevel_update_tabs(toplevel_t * top)
+{
+ gint i = gtk_notebook_get_n_pages(top->notebook) - 1;
+ while (i >= 0) {
+ GtkWidget *child = gtk_notebook_get_nth_page(top->notebook, i);
+ GtkWidget *tab = gtk_notebook_get_tab_label(top->notebook, child);
+ GtkWidget *label = g_object_get_data(G_OBJECT(tab), "label");
+ message_view_t *v = g_object_get_data(G_OBJECT(tab), "view-object");
+ seaudit_model_t *model = message_view_get_model(v);
+ const char *name = seaudit_model_get_name(model);
+ gtk_label_set_text(GTK_LABEL(label), name);
+ i--;
+ }
+}
+
+void toplevel_update_selection_menu_item(toplevel_t * top)
+{
+ static const char *items[] = {
+ "ExportSelected", "ViewMessage",
+ NULL
+ };
+ message_view_t *view = toplevel_get_current_view(top);
+ gboolean sens = FALSE;
+ size_t i;
+ const char *s;
+ if (view != NULL) {
+ sens = message_view_is_message_selected(view);
+ }
+ for (i = 0, s = items[0]; s != NULL; s = items[++i]) {
+ GtkWidget *w = glade_xml_get_widget(top->xml, s);
+ assert(s != NULL);
+ gtk_widget_set_sensitive(w, sens);
+ }
+}
+
+preferences_t *toplevel_get_prefs(toplevel_t * top)
+{
+ return seaudit_get_prefs(top->s);
+}
+
+seaudit_log_t *toplevel_get_log(toplevel_t * top)
+{
+ return seaudit_get_log(top->s);
+}
+
+apol_vector_t *toplevel_get_log_users(toplevel_t * top)
+{
+ return seaudit_get_log_users(top->s);
+}
+
+apol_vector_t *toplevel_get_log_roles(toplevel_t * top)
+{
+ return seaudit_get_log_roles(top->s);
+}
+
+apol_vector_t *toplevel_get_log_types(toplevel_t * top)
+{
+ return seaudit_get_log_types(top->s);
+}
+
+apol_vector_t *toplevel_get_log_mls_lvl(toplevel_t * top)
+{
+ return seaudit_get_log_mls_lvl(top->s);
+}
+
+apol_vector_t *toplevel_get_log_mls_clr(toplevel_t * top)
+{
+ return seaudit_get_log_mls_clr(top->s);
+}
+
+apol_vector_t *toplevel_get_log_classes(toplevel_t * top)
+{
+ return seaudit_get_log_classes(top->s);
+}
+
+apol_policy_t *toplevel_get_policy(toplevel_t * top)
+{
+ return seaudit_get_policy(top->s);
+}
+
+char *toplevel_get_glade_xml(toplevel_t * top)
+{
+ return top->xml_filename;
+}
+
+progress_t *toplevel_get_progress(toplevel_t * top)
+{
+ return top->progress;
+}
+
+GtkWindow *toplevel_get_window(toplevel_t * top)
+{
+ return top->w;
+}
+
+void toplevel_find_terules(toplevel_t * top, seaudit_message_t * message)
+{
+ policy_view_find_terules(top->pv, message);
+}
+
+/**
+ * Pop-up a dialog with a line of text and wait for the user to
+ * dismiss the dialog.
+ *
+ * @param top Toplevel window; this message dialog will be centered
+ * upon it.
+ * @param msg_type Type of message being displayed.
+ * @param fmt Format string to print, using syntax of printf(3).
+ */
+static void toplevel_message(toplevel_t * top, GtkMessageType msg_type, const char *fmt, va_list ap)
+{
+ GtkWidget *dialog;
+ char *msg;
+ if (vasprintf(&msg, fmt, ap) < 0) {
+ ERR(NULL, "%s", strerror(errno));
+ return;
+ }
+ dialog = gtk_message_dialog_new(top->w, GTK_DIALOG_DESTROY_WITH_PARENT, msg_type, GTK_BUTTONS_CLOSE, msg);
+ free(msg);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+}
+
+void toplevel_ERR(toplevel_t * top, const char *format, ...)
+{
+ va_list(ap);
+ va_start(ap, format);
+ toplevel_message(top, GTK_MESSAGE_ERROR, format, ap);
+ va_end(ap);
+}
+
+void toplevel_WARN(toplevel_t * top, const char *format, ...)
+{
+ va_list(ap);
+ va_start(ap, format);
+ toplevel_message(top, GTK_MESSAGE_WARNING, format, ap);
+ va_end(ap);
+}
+
+/************* below are callbacks for the toplevel menu items *************/
+
+void toplevel_on_destroy(gpointer user_data, GtkObject * object __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ top->w = NULL;
+ gtk_main_quit();
+}
+
+void toplevel_on_open_log_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ apol_vector_t *paths = util_open_file(top->w, "Open Log", seaudit_get_log_path(top->s), 0);
+ if (paths != NULL) {
+ toplevel_open_log(top, apol_vector_get_element(paths, 0));
+ apol_vector_destroy(&paths);
+ }
+}
+
+void toplevel_on_open_policy_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ open_policy_window_run(top, seaudit_get_policy_path(top->s), NULL);
+}
+
+void toplevel_on_preferences_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ if (preferences_view_run(top, seaudit_get_log_path(top->s), seaudit_get_policy_path(top->s))) {
+ size_t i;
+ for (i = 0; i < apol_vector_get_size(top->views); i++) {
+ message_view_t *v = apol_vector_get_element(top->views, i);
+ message_view_update_visible_columns(v);
+ }
+ }
+}
+
+void toplevel_on_quit_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ top->w = NULL;
+ gtk_main_quit();
+}
+
+void toplevel_on_new_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ toplevel_add_new_model(top);
+}
+
+void toplevel_on_open_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ apol_vector_t *paths = util_open_file(top->w, "Open View", top->view_filename, 0);
+ seaudit_model_t *model = NULL;
+ if (paths == NULL) {
+ return;
+ }
+ free(top->view_filename);
+ top->view_filename = strdup(apol_vector_get_element(paths, 0));
+ apol_vector_destroy(&paths);
+ if (top->view_filename == NULL ||
+ (model = seaudit_model_create_from_file(top->view_filename)) == NULL ||
+ seaudit_model_append_log(model, seaudit_get_log(top->s)) < 0) {
+ toplevel_ERR(top, "Error opening view: %s", strerror(errno));
+ seaudit_model_destroy(&model);
+ } else {
+ toplevel_add_new_view(top, model, top->view_filename);
+ }
+}
+
+void toplevel_on_save_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_save(view);
+}
+
+void toplevel_on_save_viewas_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_saveas(view);
+}
+
+void toplevel_on_modify_view_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_modify(view);
+}
+
+void toplevel_on_export_all_messages_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_export_all_messages(view);
+}
+
+void toplevel_on_export_selected_messages_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_export_selected_messages(view);
+}
+
+void toplevel_on_view_entire_message_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_entire_message(view);
+}
+
+void toplevel_on_find_terules_activate(gpointer user_data, GtkWidget * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ toplevel_find_terules(top, NULL);
+}
+
+void toplevel_on_create_report_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ report_window_run(top, view);
+}
+
+void toplevel_on_monitor_log_activate(gpointer user_data, GtkMenuItem * widget)
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
+ top->do_monitor_log = 1;
+ } else {
+ top->do_monitor_log = 0;
+ }
+ toplevel_monitor_log(top);
+}
+
+void toplevel_on_clear_view_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_clear(view);
+}
+
+void toplevel_on_help_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ GtkWidget *window;
+ GtkWidget *scroll;
+ GtkWidget *text_view;
+ GtkTextBuffer *buffer;
+ char *help_text = NULL;
+ size_t len;
+ int rt;
+ char *dir;
+
+ window = gtk_dialog_new_with_buttons("seaudit Help",
+ GTK_WINDOW(top->w),
+ GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
+ gtk_dialog_set_default_response(GTK_DIALOG(window), GTK_RESPONSE_CLOSE);
+ g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window);
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ text_view = gtk_text_view_new();
+ gtk_window_set_default_size(GTK_WINDOW(window), 520, 300);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), scroll);
+ gtk_container_add(GTK_CONTAINER(scroll), text_view);
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text_view), GTK_WRAP_NONE);
+ buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_view));
+ dir = apol_file_find_path("seaudit_help.txt");
+ if (!dir) {
+ toplevel_ERR(top, "Cannot find help file.");
+ return;
+ }
+ rt = apol_file_read_to_buffer(dir, &help_text, &len);
+ free(dir);
+ if (rt != 0) {
+ free(help_text);
+ return;
+ }
+ gtk_text_buffer_set_text(buffer, help_text, len);
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE);
+ gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER_ON_PARENT);
+ gtk_widget_show(text_view);
+ gtk_widget_show(scroll);
+ gtk_widget_show(window);
+}
+
+void toplevel_on_about_seaudit_activate(gpointer user_data, GtkMenuItem * widget __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+#ifdef GTK_2_8
+ gtk_show_about_dialog(top->w,
+ "comments", "Audit Log Analysis Tool for Security Enhanced Linux",
+ "copyright", COPYRIGHT_INFO,
+ "name", "seaudit", "version", VERSION, "website", "http://oss.tresys.com/projects/setools", NULL);
+#else
+ GtkWidget *w = gtk_message_dialog_new(top->w,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_CLOSE,
+ "%s %s\n%s\n%s\n%s",
+ "seaudit", VERSION,
+ "Audit Log Analysis Tool for Security Enhanced Linux",
+ COPYRIGHT_INFO,
+ "http://oss.tresys.com/projects/setools");
+ gtk_dialog_run(GTK_DIALOG(w));
+ gtk_widget_destroy(w);
+#endif
+}
+
+void toplevel_on_find_terules_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
+ __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ toplevel_find_terules(top, NULL);
+}
+
+void toplevel_on_modify_view_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
+ __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_modify(view);
+}
+
+void toplevel_on_monitor_log_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
+ __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ GtkCheckMenuItem *w = GTK_CHECK_MENU_ITEM(glade_xml_get_widget(top->xml, "MonitorLog"));
+ gboolean old_state;
+ assert(w != NULL);
+ old_state = gtk_check_menu_item_get_active(w);
+ gtk_check_menu_item_set_active(w, !old_state);
+}
+
+void toplevel_on_clear_view_click(gpointer user_data, GtkWidget * widget __attribute__ ((unused)), GdkEvent * event
+ __attribute__ ((unused)))
+{
+ toplevel_t *top = g_object_get_data(G_OBJECT(user_data), "toplevel");
+ message_view_t *view = toplevel_get_current_view(top);
+ assert(view != NULL);
+ message_view_clear(view);
+}
diff --git a/seaudit/toplevel.h b/seaudit/toplevel.h
new file mode 100644
index 0000000..448c8ad
--- /dev/null
+++ b/seaudit/toplevel.h
@@ -0,0 +1,263 @@
+/**
+ * @file
+ * Declaration of the main toplevel window for seaudit.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ * @author Jeremy Solt jsolt@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TOPLEVEL_H
+#define TOPLEVEL_H
+
+typedef struct toplevel toplevel_t;
+
+#include "progress.h"
+#include "seaudit.h"
+#include <apol/policy-path.h>
+#include <gtk/gtk.h>
+#include <seaudit/message.h>
+
+/**
+ * Allocate and return an instance of the toplevel window object.
+ * This will create the window, set up the menus and icons, create an
+ * empty notebook, then display the window.
+ *
+ * @param s Main seaudit object that will control the toplevel.
+ *
+ * @return An initialized toplevel object, or NULL upon error. The
+ * caller must call toplevel_destroy() afterwards.
+ */
+toplevel_t *toplevel_create(seaudit_t * s);
+
+/**
+ * Destroy the toplevel window. This function will recursively
+ * destroy all other windows. This does nothing if the pointer is set
+ * to NULL.
+ *
+ * @param top Reference to a toplevel object. Afterwards the pointer
+ * will be set to NULL.
+ */
+void toplevel_destroy(toplevel_t ** top);
+
+/**
+ * Open a log file, destroying any existing logs and views first.
+ * Afterwards, create a new view for the log.
+ *
+ * @param top Toplevel object, used for UI control.
+ * @param filename Name of the log to open.
+ */
+void toplevel_open_log(toplevel_t * top, const char *filename);
+
+/**
+ * Open a policy file, destroying any existing policies upon success.
+ *
+ * @param top Toplevel object, used for UI control.
+ * @param path Path to the policy to open. This function takes
+ * ownership of this object.
+ *
+ * @return 0 on successful open, < 0 on error.
+ */
+int toplevel_open_policy(toplevel_t * top, apol_policy_path_t * path);
+
+/**
+ * Update the status bar to show the current policy, number of log
+ * messages in the current view, range of messages in current view,
+ * and monitor status.
+ *
+ * @param top Toplevel whose status bar to update.
+ */
+void toplevel_update_status_bar(toplevel_t * top);
+
+/**
+ * Update the menu items whenever a message is selected/deselected.
+ * Certain commands are legal only when one or more messages are
+ * selected.
+ *
+ * @param top Toplevel whose menu to update.
+ */
+void toplevel_update_selection_menu_item(toplevel_t * top);
+
+/**
+ * Update the tab names for all views.
+ *
+ * @param top Toplevel whose notebook tabs to update.
+ */
+void toplevel_update_tabs(toplevel_t * top);
+
+/**
+ * Return the current preferences object for the toplevel object.
+ *
+ * @param top Toplevel containing preferences.
+ *
+ * @return Pointer to a preferences object. Do not free() this pointer.
+ */
+preferences_t *toplevel_get_prefs(toplevel_t * top);
+
+/**
+ * Return a seaudit_log_t object used for error reporting by
+ * libseaudit.
+ *
+ * @param top Toplevel containing seaudit log object.
+ *
+ * @return libseaudit reporting object, or NULL if no log exists yet.
+ * Treat this as a const pointer.
+ */
+seaudit_log_t *toplevel_get_log(toplevel_t * top);
+
+/**
+ * Return a vector of strings corresponding to all users found within
+ * the current log file. The vector will be sorted alphabetically.
+ *
+ * @param top Toplevel containing seaudit log object.
+ *
+ * @return Vector of sorted users, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *toplevel_get_log_users(toplevel_t * top);
+
+/**
+ * Return a vector of strings corresponding to all roles found within
+ * the current log file. The vector will be sorted alphabetically.
+ *
+ * @param top Toplevel containing seaudit log object.
+ *
+ * @return Vector of sorted roles, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *toplevel_get_log_roles(toplevel_t * top);
+
+/**
+ * Return a vector of strings corresponding to all types found within
+ * the current log file. The vector will be sorted alphabetically.
+ *
+ * @param top Toplevel containing seaudit log object.
+ *
+ * @return Vector of sorted types, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *toplevel_get_log_types(toplevel_t * top);
+
+/**
+ * Return a vector of strings corresponding to all mls
+ * levels found within the current log file.
+ * The vector will be sorted alphabetically.
+ *
+ * @param top Toplevel containing seaudit log object.
+ *
+ * @return Vector of sorted types, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *toplevel_get_log_mls_lvl(toplevel_t * top);
+
+/**
+ * Return a vector of strings corresponding to all mls
+ * clearance found within the current log file.
+ * The vector will be sorted alphabetically.
+ *
+ * @param top Toplevel containing seaudit log object.
+ *
+ * @return Vector of sorted types, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *toplevel_get_log_mls_clr(toplevel_t * top);
+
+/**
+ * Return a vector of strings corresponding to all object classes
+ * found within the current log file. The vector will be sorted
+ * alphabetically.
+ *
+ * @param top Toplevel containing seaudit log object.
+ *
+ * @return Vector of sorted classes, or NULL if no log is loaded. The
+ * caller must call apol_vector_destroy() upon the return value.
+ */
+apol_vector_t *toplevel_get_log_classes(toplevel_t * top);
+
+/**
+ * Return the currently loaded policy.
+ *
+ * @param top Toplevel containing policy.
+ *
+ * @return Current policy, or NULL if no policy is loaded yet. Treat
+ * this as a const pointer.
+ */
+apol_policy_t *toplevel_get_policy(toplevel_t * top);
+
+/**
+ * Return the filename containing seaudit's glade file.
+ *
+ * @param top Toplevel containing glade XML declarations.
+ *
+ * @return Name of the glade file. Do not modify this string.
+ */
+char *toplevel_get_glade_xml(toplevel_t * top);
+
+/**
+ * Return the progress object, so that sub-windows may also show the
+ * threaded progress object.
+ *
+ * @param top Toplevel containing progress object.
+ *
+ * @return Progress object. Do not free() this pointer.
+ */
+progress_t *toplevel_get_progress(toplevel_t * top);
+
+/**
+ * Return the main application window. Sub-windows should be set
+ * transient to this window.
+ *
+ * @param top Toplevel containing main window.
+ *
+ * @return Main window.
+ */
+GtkWindow *toplevel_get_window(toplevel_t * top);
+
+/**
+ * (Re)open a dialog that allows the user to search for TE rules in
+ * the currently opened policy. If message is not NULL then set the
+ * query's initial parameters to the message's source type, target
+ * type, and object class.
+ *
+ * @param top Toplevel containing policy.
+ * @param message If non-NULL, the initial parameters for query.
+ */
+void toplevel_find_terules(toplevel_t * top, seaudit_message_t * message);
+
+/**
+ * Pop-up an error dialog with a line of text and wait for the user to
+ * dismiss the dialog.
+ *
+ * @param top Toplevel window; this message dialog will be centered
+ * upon it.
+ * @param format Format string to print, using syntax of printf(3).
+ */
+void toplevel_ERR(toplevel_t * top, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
+
+/**
+ * Pop-up a warning dialog with a line of text and wait for the user
+ * to dismiss the dialog.
+ *
+ * @param top Toplevel window; this message dialog will be centered
+ * upon it.
+ * @param format Format string to print, using syntax of printf(3).
+ */
+void toplevel_WARN(toplevel_t * top, const char *format, ...) __attribute__ ((format(printf, 2, 3)));
+
+#endif
diff --git a/seaudit/utilgui.c b/seaudit/utilgui.c
new file mode 100644
index 0000000..22028e1
--- /dev/null
+++ b/seaudit/utilgui.c
@@ -0,0 +1,134 @@
+/**
+ * @file
+ * Miscellaneous helper functions for GTK+ applications.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "utilgui.h"
+#include <string.h>
+
+void util_message(GtkWindow * parent, GtkMessageType msg_type, const char *msg)
+{
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, msg_type, GTK_BUTTONS_CLOSE, msg);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+}
+
+void util_cursor_wait(GtkWidget * widget)
+{
+ GdkCursor *cursor;
+ if (widget->window != NULL) {
+ cursor = gdk_cursor_new(GDK_WATCH);
+ gdk_window_set_cursor(widget->window, cursor);
+ gdk_cursor_unref(cursor);
+ }
+}
+
+/**
+ * WARNING: this is sort of a hack
+ *
+ * If we reset the pointer at the end of a callback, it gets reset too
+ * soon (i.e. before all of the pending events have been processed. To
+ * avoid this, this function is put in an idle handler by
+ * util_clear_cursor().
+ */
+static gboolean pointer_reset(gpointer data)
+{
+ gdk_window_set_cursor(GTK_WIDGET(data)->window, NULL);
+ return FALSE;
+}
+
+void util_cursor_clear(GtkWidget * widget)
+{
+ g_idle_add(&pointer_reset, widget);
+}
+
+apol_vector_t *util_open_file(GtkWindow * parent, const char *title, const char *init_path, gboolean multiple)
+{
+ GtkWidget *dialog = gtk_file_chooser_dialog_new(title, parent, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+ apol_vector_t *paths = NULL;
+ if (init_path != NULL) {
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), init_path);
+ }
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), multiple);
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ GSList *files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+ GSList *f;
+ paths = apol_vector_create(g_free);
+ for (f = files; f != NULL; f = f->next) {
+ apol_vector_append(paths, f->data);
+ }
+ g_slist_free(files);
+ }
+ gtk_widget_destroy(dialog);
+ return paths;
+}
+
+char *util_save_file(GtkWindow * parent, const char *title, const char *init_path)
+{
+ GtkWidget *dialog = gtk_file_chooser_dialog_new(title, parent, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+ char *path = NULL;
+#ifdef GTK_2_8
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
+#endif
+ if (init_path != NULL) {
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), init_path);
+ } else {
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled");
+ }
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ }
+ gtk_widget_destroy(dialog);
+ return path;
+}
+
+char *util_policy_path_to_string(const apol_policy_path_t * path)
+{
+ char *s;
+ const char *primary_path = apol_policy_path_get_primary(path);
+ if (apol_policy_path_get_type(path) == APOL_POLICY_PATH_TYPE_MONOLITHIC) {
+ return strdup(primary_path);
+ } else {
+ const apol_vector_t *modules = apol_policy_path_get_modules(path);
+ size_t num_modules = apol_vector_get_size(modules);
+ if (asprintf(&s, "%s + %zd module%s", primary_path, num_modules, num_modules == 1 ? "" : "s") < 0) {
+ return NULL;
+ }
+ return s;
+ }
+}
+
+const gchar *util_combo_box_get_active_text(GtkComboBox * w)
+{
+#ifdef GTK_2_8
+ return gtk_combo_box_get_active_text(w);
+#else
+ return gtk_entry_get_text(GTK_ENTRY(GTK_BIN(w)->child));
+#endif
+}
diff --git a/seaudit/utilgui.h b/seaudit/utilgui.h
new file mode 100644
index 0000000..52365f4
--- /dev/null
+++ b/seaudit/utilgui.h
@@ -0,0 +1,106 @@
+/**
+ * @file
+ * Miscellaneous helper functions for GTK+ applications.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2003-2007 Tresys Technology, LLC
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef UTILGUI_H
+#define UTILGUI_H
+
+#include <apol/policy-path.h>
+#include <gtk/gtk.h>
+
+/**
+ * Pop-up a dialog with a line of text and wait for the user to
+ * dismiss the dialog.
+ *
+ * @param parent Parent window; this message dialog will be centered
+ * upon the parent.
+ * @param msg_type Type of message being displayed.
+ * @param msg Text of message to display.
+ */
+void util_message(GtkWindow * parent, GtkMessageType msg_type, const char *msg);
+/**
+ * Set the cursor over a widget to the watch cursor.
+ *
+ * @param widget Widget whose cursor to set.
+ */
+void util_cursor_wait(GtkWidget * widget);
+
+/**
+ * Clear the cursor over a widget, setting it to the default arrow.
+ *
+ * @param widget Widget whose cursor to set.
+ */
+void util_cursor_clear(GtkWidget * widget);
+
+/**
+ * Allow the user select one or more existing files. Run the dialog
+ * and return a vector of selected filenames.
+ *
+ * @param parent Parent window; this dialog will be centered upon the
+ * parent.
+ * @param title Name of the dialog.
+ * @param init_path If not NULL, the default filename.
+ * @param multiple If true, allow the user to select multiple files.
+ * Otherwise only one file at a time may be chosen.
+ *
+ * @return Vector of filenames selected, or NULL if none were
+ * selected. The caller must call apol_vector_destroy() upon the
+ * returned value.
+ */
+apol_vector_t *util_open_file(GtkWindow * parent, const char *title, const char *init_path, gboolean multiple);
+
+/**
+ * Allow the user select an existing file or enter a new file for
+ * writing. Run the dialog and return the selected filename.
+ *
+ * @param parent Parent window; this dialog will be centered upon the
+ * parent.
+ * @param title Name of the dialog.
+ * @param init_path If not NULL, the default filename.
+ *
+ * @return Name of the file selected, or NULL if no file was selected.
+ * The caller must free the returned value with g_free().
+ */
+char *util_save_file(GtkWindow * parent, const char *title, const char *init_path);
+
+/**
+ * Given a policy path, return a newly allocated string that briefly
+ * describes the path. This string is suitable for showing to the
+ * user.
+ *
+ * @param path Policy path to describe.
+ *
+ * @return String describing the path, or NULL upon error. The caller
+ * must free the string afterwards.
+ */
+char *util_policy_path_to_string(const apol_policy_path_t * path);
+
+/**
+ * Get the active text from a GtkComboBox.
+ *
+ * Whereas GTK 2.6 has gtk_combo_box_get_active_text(), GTK 2.4
+ * (another supported platform) does not.
+ */
+const gchar *util_combo_box_get_active_text(GtkComboBox * w);
+
+#endif