diff -up setroubleshoot-2.1.12/gui/browser.glade.guiredesign setroubleshoot-2.1.12/gui/browser.glade
--- setroubleshoot-2.1.12/gui/browser.glade.guiredesign 2009-06-10 09:50:58.605308760 -0400
+++ setroubleshoot-2.1.12/gui/browser.glade 2009-06-10 10:42:52.488312815 -0400
@@ -0,0 +1,454 @@
+
+
+
+
+
+ True
+ 15
+ SELinux Security Alerts
+ False
+ center
+ north
+
+
+ True
+
+
+ True
+
+
+ True
+ 58
+ gtk-dialog-warning
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ 0
+ <span face="Helvetica" size='xx-large' weight='bold'>SELinux has detected suspicious behavior on your system</span>
+ True
+
+
+ 1
+
+
+
+
+ False
+ False
+ 0
+
+
+
+
+ 710
+ 290
+ True
+ 0
+
+
+ True
+
+
+ True
+ 0
+ 15
+ 10
+ <span size='large' weight='bold' face='verdana'>A program has requested access it has not been granted</span>
+ True
+
+
+ False
+ 0
+
+
+
+
+ True
+ 0
+ 15
+ <span foreground='grey'>date</span>
+ True
+
+
+ False
+ False
+ 1
+
+
+
+
+ 650
+ True
+ 0
+ 25
+ 5
+ No alerts available.
+ True
+ True
+
+
+ False
+ False
+ 15
+ 2
+
+
+
+
+ True
+ True
+ 1
+
+
+
+ True
+ True
+ automatic
+ etched-out
+
+
+
+
+
+
+
+ True
+ Show full error output
+ True
+
+
+ label_item
+
+
+
+
+ 3
+
+
+
+
+ True
+ end
+
+
+ True
+ True
+ True
+ False
+ Reports a bug to bugzilla.redhat.com.
+
+
+
+ True
+ 0
+ 0
+
+
+ True
+ 2
+
+
+ True
+ gtk-about
+ 4
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ Report this Bug
+ True
+
+
+ False
+ False
+ 1
+
+
+
+
+
+
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ False
+ True
+ True
+ False
+ Certain signatures allow administrators to correct your system with setroubleshoot.
+
+
+
+ True
+ 0
+ 0
+
+
+ True
+ 2
+
+
+ True
+ gtk-apply
+ 4
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ Fix it
+ True
+
+
+ False
+ False
+ 1
+
+
+
+
+
+
+
+
+ False
+ False
+ 1
+
+
+
+
+ False
+ False
+ 5
+ 4
+
+
+
+
+
+
+ 1
+
+
+
+
+ True
+
+
+ Don't notify me if this happens again.
+ True
+ True
+ False
+ True
+ True
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ 1
+ <span weight='bold' size='large' face='verdana'>Alert - of -</span>
+ True
+ right
+
+
+ False
+ False
+ 1
+
+
+
+
+ False
+ False
+ 6
+ 2
+
+
+
+
+ True
+
+
+ True
+ start
+
+
+ 180
+ 40
+ True
+ True
+ True
+ False
+
+
+
+ True
+ 0
+ 0
+
+
+ True
+ 2
+
+
+ True
+ gtk-undo
+ 4
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ Previous
+ True
+
+
+ False
+ False
+ 1
+
+
+
+
+
+
+
+
+ False
+ False
+ 0
+
+
+
+
+ 180
+ 40
+ True
+ True
+ True
+ False
+
+
+
+ True
+ 0
+ 0
+
+
+ True
+ 2
+
+
+ True
+ gtk-redo
+ 4
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ Next
+ True
+
+
+ False
+ False
+ 1
+
+
+
+
+
+
+
+
+ False
+ False
+ 1
+
+
+
+
+ 0
+
+
+
+
+ True
+ end
+
+
+ gtk-close
+ 125
+ 40
+ True
+ True
+ True
+ False
+ True
+
+
+
+ False
+ False
+ 0
+
+
+
+
+ 1
+
+
+
+
+ False
+ False
+ 3
+
+
+
+
+
+
diff -up setroubleshoot-2.1.12/gui/bug_report.glade.guiredesign setroubleshoot-2.1.12/gui/bug_report.glade
--- setroubleshoot-2.1.12/gui/bug_report.glade.guiredesign 2009-06-10 09:50:58.605308760 -0400
+++ setroubleshoot-2.1.12/gui/bug_report.glade 2009-06-10 10:42:52.996310976 -0400
@@ -0,0 +1,281 @@
+
+
+
+
+
+ True
+ 15
+ Review and Submit Bug Report
+ False
+ center
+
+
+ True
+
+
+ True
+ 0
+ <span size='large' weight='bold'>Review and Submit Bug Report</span>
+ True
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ 0
+ You may wish to review the error output that will be included in this bug report and modify it to exclude any sensitive data. You may do that below.
+ True
+ True
+
+
+ False
+ False
+ 5
+ 1
+
+
+
+
+ 144
+ 16
+ True
+ 0
+ Included error output:
+
+
+ False
+ False
+ 2
+
+
+
+
+ 300
+ True
+ True
+ 1
+ automatic
+ out
+
+
+ True
+ True
+ word
+
+
+
+
+ 3
+
+
+
+
+ True
+
+
+ True
+ Please enter your
+
+
+ 0
+
+
+
+
+ bugzilla.redhat.com
+ True
+ True
+ True
+ True
+ none
+ False
+ https://bugzilla.redhat.com/createaccount.cgi
+
+
+ 1
+
+
+
+
+ True
+ credentials below.
+
+
+ 2
+
+
+
+
+ 4
+
+
+
+
+ True
+
+
+ 101
+ 26
+ True
+ Bugzilla Login:
+
+
+ False
+ False
+ 0
+
+
+
+
+ 303
+ 27
+ True
+ True
+ ●
+
+
+ 1
+
+
+
+
+ False
+ False
+ 5
+
+
+
+
+ True
+
+
+ 100
+ 24
+ True
+ Password:
+
+
+ False
+ False
+ 0
+
+
+
+
+ 303
+ 27
+ True
+ True
+ False
+ ●
+
+
+ 1
+
+
+
+
+ False
+ False
+ 6
+
+
+
+
+ True
+
+
+ Save password.
+ True
+ True
+ False
+ True
+ True
+
+
+ False
+ False
+ 0
+
+
+
+
+ gtk-cancel
+ True
+ True
+ False
+ True
+
+
+
+ False
+ False
+ 1
+
+
+
+
+ True
+ True
+ False
+
+
+
+ True
+ 0
+ 0
+
+
+ True
+ 2
+
+
+ True
+ gtk-yes
+ 4
+
+
+ False
+ False
+ 0
+
+
+
+
+ True
+ Submit Report
+ True
+
+
+ False
+ False
+ 1
+
+
+
+
+
+
+
+
+ False
+ False
+ 2
+
+
+
+
+ False
+ False
+ 7
+
+
+
+
+
+
diff -up setroubleshoot-2.1.12/gui/fail_dialog.glade.guiredesign setroubleshoot-2.1.12/gui/fail_dialog.glade
--- setroubleshoot-2.1.12/gui/fail_dialog.glade.guiredesign 2009-06-10 09:50:58.606308606 -0400
+++ setroubleshoot-2.1.12/gui/fail_dialog.glade 2009-06-10 10:42:53.478312557 -0400
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+ True
+ Error
+ GTK_WINDOW_TOPLEVEL
+ GTK_WIN_POS_CENTER_ON_PARENT
+ True
+ True
+ False
+ True
+ False
+ False
+ GDK_WINDOW_TYPE_HINT_DIALOG
+ GDK_GRAVITY_NORTH_WEST
+ True
+ False
+
+
+
+ True
+ False
+ 0
+
+
+
+ True
+ False
+ 0
+
+
+
+ 76
+ 52
+ True
+ dialog-error
+ 50
+ 0.5
+ 0
+ 0
+ 15
+
+
+ 0
+ True
+ True
+
+
+
+
+
+ 280
+ 138
+ True
+ This operation was completed. The quick brown fox jumped over the lazy dog.
+ False
+ True
+ GTK_JUSTIFY_LEFT
+ True
+ False
+ 0.5
+ 0
+ 0
+ 15
+ PANGO_ELLIPSIZE_NONE
+ -1
+ False
+ 0
+
+
+ 0
+ False
+ False
+
+
+
+
+ 0
+ True
+ True
+
+
+
+
+
+ True
+ GTK_BUTTONBOX_DEFAULT_STYLE
+ 0
+
+
+
+ 80
+ 40
+ True
+ True
+ gtk-ok
+ True
+ GTK_RELIEF_NORMAL
+ True
+
+
+
+
+
+ 15
+ True
+ True
+
+
+
+
+
+
+
diff -up setroubleshoot-2.1.12/gui/Makefile.am.guiredesign setroubleshoot-2.1.12/gui/Makefile.am
--- setroubleshoot-2.1.12/gui/Makefile.am.guiredesign 2009-04-03 15:57:24.000000000 -0400
+++ setroubleshoot-2.1.12/gui/Makefile.am 2009-06-10 09:50:58.606308606 -0400
@@ -1,6 +1,10 @@
GUI_FILES = \
setroubleshoot_icon.png \
setroubleshoot_red_icon.png \
+ browser.glade \
+ bug_report.glade \
+ fail_dialog.glade \
+ success_dialog.glade \
$(NULL)
icondir = /usr/share/icons/hicolor/96x96/apps
diff -up setroubleshoot-2.1.12/gui/Makefile.in.guiredesign setroubleshoot-2.1.12/gui/Makefile.in
--- setroubleshoot-2.1.12/gui/Makefile.in.guiredesign 2009-06-02 11:07:27.000000000 -0400
+++ setroubleshoot-2.1.12/gui/Makefile.in 2009-06-10 09:50:58.607308732 -0400
@@ -195,6 +195,10 @@ top_srcdir = @top_srcdir@
GUI_FILES = \
setroubleshoot_icon.png \
setroubleshoot_red_icon.png \
+ browser.glade \
+ bug_report.glade \
+ fail_dialog.glade \
+ success_dialog.glade \
$(NULL)
icondir = /usr/share/icons/hicolor/96x96/apps
diff -up setroubleshoot-2.1.12/gui/success_dialog.glade.guiredesign setroubleshoot-2.1.12/gui/success_dialog.glade
--- setroubleshoot-2.1.12/gui/success_dialog.glade.guiredesign 2009-06-10 09:50:58.607308732 -0400
+++ setroubleshoot-2.1.12/gui/success_dialog.glade 2009-06-10 10:42:54.017312627 -0400
@@ -0,0 +1,97 @@
+
+
+
+
+
+ True
+ Success!
+
+
+ True
+
+
+ True
+
+
+ 76
+ 52
+ True
+ 0
+ 15
+ 50
+ emblem-default
+
+
+ 0
+
+
+
+
+ True
+ 0
+ 15
+ This operation was completed. The quick brown fox jumped over the lazy dog.
+ True
+ True
+
+
+ False
+ False
+ 10
+ 1
+
+
+
+
+ 0
+
+
+
+
+ button
+ True
+ False
+ True
+ True
+ none
+ False
+ http://glade.gnome.org
+
+
+ False
+ False
+ 10
+ 1
+
+
+
+
+ True
+
+
+ gtk-ok
+ True
+ True
+ True
+ False
+ True
+
+
+
+ False
+ False
+ 0
+
+
+
+
+ False
+ False
+ 5
+ 2
+
+
+
+
+
+
diff -up setroubleshoot-2.1.12/src/browser.py.guiredesign setroubleshoot-2.1.12/src/browser.py
--- setroubleshoot-2.1.12/src/browser.py.guiredesign 2009-04-03 15:57:24.000000000 -0400
+++ setroubleshoot-2.1.12/src/browser.py 2009-06-10 10:42:39.286312339 -0400
@@ -1,44 +1,20 @@
-# Authors: John Dennis
-# Authors: Dan Walsh
-#
-# Copyright (C) 2006,2007,2008 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
+#!/usr/bin/env python
-__all__ = ['BrowserApplet',
- ]
+# Author: Thomas Liu
-# This import must come before importing gtk to silence warnings
-from setroubleshoot.gui_utils import *
-import os
-import sys
-import pygtk
-pygtk.require("2.0")
-import gtk
-import pango
-import re
+import sys, os
+from xml.dom import minidom
+import datetime
import time
-import traceback
-from types import *
-
-import gobject
-import gnome.ui
import gtkhtml2
-
+import bugzilla, xmlrpclib, hashlib
+from filer import *
+import pygtk
+import gobject
+import gnomekeyring
+import gtk
+import gtk.glade
from setroubleshoot.log import *
from setroubleshoot.analyze import *
from setroubleshoot.config import get_config
@@ -50,2458 +26,583 @@ from setroubleshoot.html_util import *
from setroubleshoot.rpc import *
from setroubleshoot.rpc_interfaces import *
from setroubleshoot.run_cmd import *
+import re
-#------------------------------------------------------------------------------
-
-NUM_COLUMNS = 7
-(PYOBJECT_COLUMN, FILTER_TYPE_COLUMN, DATE_COLUMN, HOST_COLUMN, COUNT_COLUMN, CATEGORY_COLUMN,
- SUMMARY_COLUMN) = range(NUM_COLUMNS)
-
-tv_column_info = {
- FILTER_TYPE_COLUMN: {'name' : 'Filter', 'title' : _('Quiet'),},
- DATE_COLUMN: {'name' : 'Date', 'title' : _('Date'),},
- HOST_COLUMN: {'name' : 'Host', 'title' : _('Host'),},
- COUNT_COLUMN: {'name' : 'Count', 'title' : _('Count'),},
- CATEGORY_COLUMN: {'name' : 'Category', 'title' : _('Category'),},
- SUMMARY_COLUMN: {'name' : 'Summary', 'title' : _('Summary'),},
-}
-
-#------------------------------------------------------------------------------
-
-def get_siginfo_from_model_path(model, path):
- if type(path) is StringType:
- iter = model.get_iter_from_string(path)
- else:
- iter = model.get_iter(path)
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- return siginfo
-
-def get_model_path_from_local_id(model, local_id):
- iter = model.get_iter_first()
- while iter:
- row_siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- if row_siginfo.local_id == local_id:
- return model.get_path(iter)
- iter = model.iter_next(iter)
- return None
-
-def get_local_id_from_model_path(model, path):
- iter = model.get_iter(path)
- if iter is None:
- return None
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- return siginfo.local_id
-
-
-def validate_siginfo(siginfo):
- timestamp = None
- if siginfo.first_seen_date is None:
- if timestamp is None:
- timestamp = TimeStamp()
- siginfo.first_seen_date = timestamp
- if siginfo.last_seen_date is None:
- if timestamp is None:
- timestamp = TimeStamp()
- siginfo.last_seen_date = timestamp
-
-def convert_paths_to_local_ids(model, paths):
- local_ids = []
- if model is None:
- return local_ids
-
- for path in paths:
- local_id = get_local_id_from_model_path(model, path)
- if local_id is None:
- log_gui_data.error("unable to lookup local_id of row %s in model", path)
- continue
- local_ids.append(local_id)
- return local_ids
-
-def convert_local_ids_to_paths(model, local_ids):
- paths = []
- if model is None:
- return paths
- for local_id in local_ids:
- path = get_model_path_from_local_id(model, local_id)
- if path is None:
- log_gui_data.error("unable to lookup path for local_id %s in model", local_id)
- continue
- paths.append(path)
- return paths
-
-def dump_tv_columns(treeview):
- column_infos = []
- i = 0
- for tv_column in treeview.get_columns():
- title = tv_column.get_title()
- sort_column_id = tv_column.get_sort_column_id()
- sort_order = tv_column.get_sort_order()
- sort_indicator = tv_column.get_sort_indicator()
+GLADE_DIRECTORY = "/usr/share/setroubleshoot/gui/"
+PREF_DIRECTORY = os.environ['HOME'] + "/"
+PREF_FILENAME = ".setroubleshoot"
+PREF_PATH = PREF_DIRECTORY + PREF_FILENAME
+SYSTEM_VERSION_PATH = "/etc/system-release"
+DUMP_PATH = "/tmp/setroubleshootdump.txt"
+
+# BugReport is the window that pops up when you press the Report Bug button
+class BugReport:
+ def __init__(self, parent, siginfo, bugzilla_username):
+
+ self.parent = parent
+ self.gladefile = GLADE_DIRECTORY + "bug_report.glade"
+ self.widget_tree = gtk.glade.XML(self.gladefile)
+
+ self.siginfo = siginfo
+ self.siginfo.host = "(removed)"
+ self.siginfo.environment.hostname = "(removed)"
+ self.siginfo.sig.host = "(removed)"
+
+ self.summary = self.siginfo.solution.summary
+ # Get the widgets we need
+ self.main_window = self.widget("bug_report_window")
+ self.error_submit_text = self.widget("error_submit_text")
+ self.username_entry = self.widget("username_entry")
+ self.password_entry = self.widget("password_entry")
+ self.submit_button = self.widget("submit_button")
+ self.cancel_button = self.widget("cancel_button")
+ self.error_submit_text = self.widget("error_submit_text")
+ self.remember_check = self.widget("remember_check")
+ self.password_entry.connect("activate", self.submit_button_clicked)
+ self.username_entry.connect("activate", self.submit_button_clicked)
+ self.username_entry.set_text(bugzilla_username)
- order = {None:'None', gtk.SORT_DESCENDING:'DESCENDING', gtk.SORT_ASCENDING:'ASCENDING'}[sort_order]
-
- column_info = "%d:%s, order=%s indicator=%s" % (i, title, order, sort_indicator)
- column_infos.append(column_info)
- i += 1
+ if bugzilla_username != "":
+ try:
+ items = gnomekeyring.find_items_sync(gnomekeyring.ITEM_GENERIC_SECRET, {"user": bugzilla_username, "server": "bugzilla.redhat.com"})
+ self.password_entry.set_text(items[0].secret)
+ self.remember_check.set_active(True)
+ except:
+ pass
+
+
+ # Construct and connect the dictionary
+ dic = { "on_cancel_button_clicked" : self.cancel_button_clicked,
+ "on_submit_button_clicked" : self.submit_button_clicked}
+
+ self.main_window.connect("destroy", self.destroy)
+ self.widget_tree.signal_autoconnect(dic)
+
+ text_buf = gtk.TextBuffer()
+ text_buf.set_text(self.siginfo.format_text())
+ self.error_submit_text.set_buffer(text_buf)
+
+ def destroy(self, widget):
+ # When we close the window let the parent know that it no longer exists
+ self.parent.bug_report_window = None
+ self.main_window.destroy()
- print '\n'.join(column_infos)
- print
- return True
+ def cancel_button_clicked(self, widget):
+ self.destroy(self.main_window)
-def get_iconset_from_name(icon_name):
- icon_source = gtk.IconSource()
- icon_source.set_icon_name(icon_name)
- iconset = gtk.IconSet()
- iconset.add_source(icon_source)
- return iconset
-
-def load_stock_icons(icon_name_list):
- factory = gtk.IconFactory()
- for icon_name in icon_name_list:
- iconset = get_iconset_from_name(icon_name)
- factory.add(icon_name, iconset)
- factory.add_default()
-
-#------------------------------------------------------------------------------
-
-class AlertListView(gobject.GObject):
- __gsignals__ = {
- 'row-changed':
- (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)),
- 'load-data':
- (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)),
- 'properties-changed':
- (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
- 'async-error': # callback(method, errno, strerror)
- (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)),
- }
-
- column_types = (gobject.TYPE_PYOBJECT,# siginfo
- gobject.TYPE_BOOLEAN, # filter
- gobject.TYPE_PYOBJECT,# date
- gobject.TYPE_STRING, # host
- gobject.TYPE_INT, # count
- gobject.TYPE_STRING, # category
- gobject.TYPE_STRING) # summary
-
- def __init__(self, username, browser):
- gobject.GObject.__init__(self)
- self.username = username
- self.browser = browser
-
- self.scrolled_window = gtk.ScrolledWindow()
- self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.view = gtk.TreeView()
- self.scrolled_window.add(self.view)
-
- self.tv_columns = [None] * NUM_COLUMNS
-
- self.selection = None
-
- self.sort_column_id = DATE_COLUMN
- self.sort_order = gtk.SORT_DESCENDING
- self.hide_deleted = False
- self.hide_quiet = False
- self.last_selected_row = 0
-
- self.base_model = None
- self.filter_model = None
- self.sort_model = None
- self.view_model = None
-
- self.row_inserted_signal = SignalConnection('row-inserted')
- self.row_deleted_signal = SignalConnection('row-deleted')
- self.row_changed_signal = SignalConnection('row-changed')
-
- self.properties_changed_signal = SignalConnection('properties-changed')
- self.load_data_signal = SignalConnection('load-data')
- self.async_error_signal = SignalConnection('async-error')
-
- self.button_press_event = SignalConnection('button_press_event')
- self.button_press_event.connect(self.view, self.browser.on_button_press_event)
-
- #
- # Create each column and intitialize it's cell renderers, etc.
- #
-
- # --- siginfo ---
- self.tv_columns[PYOBJECT_COLUMN] = tv_column = gtk.TreeViewColumn()
- tv_column.set_visible(False)
- self.view.append_column(tv_column)
-
- # --- filter ---
- self.tv_columns[FILTER_TYPE_COLUMN] = tv_column = gtk.TreeViewColumn(tv_column_info[FILTER_TYPE_COLUMN]['title'])
- cell = gtk.CellRendererToggle()
- cell.set_property('activatable', True)
- cell.connect( 'toggled', self.on_filter_toggle)
- tv_column.pack_start(cell)
- tv_column.set_cell_data_func(cell, self.filter_type_cell_data, FILTER_TYPE_COLUMN)
- tv_column.set_sort_column_id(FILTER_TYPE_COLUMN)
- self.view.append_column(tv_column)
-
- # --- date ----
- self.tv_columns[DATE_COLUMN] = tv_column = gtk.TreeViewColumn(tv_column_info[DATE_COLUMN]['title'])
- cell = gtk.CellRendererText()
- tv_column.pack_start(cell)
- tv_column.set_cell_data_func(cell, self.date_cell_data, DATE_COLUMN)
- tv_column.set_sort_column_id(DATE_COLUMN)
- self.view.append_column(tv_column)
-
- # --- host ---
- self.tv_columns[HOST_COLUMN] = tv_column = gtk.TreeViewColumn(tv_column_info[HOST_COLUMN]['title'])
- cell = gtk.CellRendererText()
- tv_column.pack_start(cell)
- tv_column.set_cell_data_func(cell, self.text_cell_data, HOST_COLUMN)
- tv_column.set_sort_column_id(HOST_COLUMN)
- #tv_column.set_visible(False)
- self.view.append_column(tv_column)
-
- # --- count ---
- self.tv_columns[COUNT_COLUMN] = tv_column = gtk.TreeViewColumn(tv_column_info[COUNT_COLUMN]['title'])
- cell = gtk.CellRendererText()
- tv_column.pack_start(cell)
- tv_column.set_cell_data_func(cell, self.count_cell_data, COUNT_COLUMN)
- tv_column.set_sort_column_id(COUNT_COLUMN)
- self.view.append_column(tv_column)
-
- # --- category ---
- self.tv_columns[CATEGORY_COLUMN] = tv_column = gtk.TreeViewColumn(tv_column_info[CATEGORY_COLUMN]['title'])
- cell = gtk.CellRendererText()
- tv_column.pack_start(cell)
- tv_column.set_cell_data_func(cell, self.text_cell_data, CATEGORY_COLUMN)
- tv_column.set_sort_column_id(CATEGORY_COLUMN)
- self.view.append_column(tv_column)
-
- # --- summary ---
- self.tv_columns[SUMMARY_COLUMN] = tv_column = gtk.TreeViewColumn(tv_column_info[SUMMARY_COLUMN]['title'])
- cell = gtk.CellRendererText()
- tv_column.pack_start(cell)
- tv_column.set_cell_data_func(cell, self.text_cell_data, SUMMARY_COLUMN)
- tv_column.set_sort_column_id(SUMMARY_COLUMN)
- self.view.append_column(tv_column)
-
- #
- # Some final properties
- #
-
- # alternate row color for easy reading
- self.view.set_rules_hint(True)
-
- # Set up the selection objects
- self.selection = self.view.get_selection()
- self.selection.set_mode(gtk.SELECTION_MULTIPLE)
-
- self.scrolled_window.show_all()
-
- def on_sort_column_changed(self, treesortable, treeview):
- sort_column_id, sort_order = treesortable.get_sort_column_id()
- if debug:
- if sort_column_id is None:
- title = None
- else:
- tv_column = treeview.get_column(sort_column_id)
- title = tv_column.get_title()
- order = {None:'None', gtk.SORT_DESCENDING:'DESCENDING', gtk.SORT_ASCENDING:'ASCENDING'}[sort_order]
- log_gui.debug('on_sort_column_changed: %s %s', title, order)
-
- self.sort_column_id = sort_column_id
- self.sort_order = sort_order
-
- def set_model(self, base_model):
- if debug:
- log_gui.debug('set_model:')
-
- if base_model is None:
- self.base_model = None
- self.filter_model = None
- self.sort_model = None
- self.view_model = None
- else:
- self.base_model = base_model
-
- # create an intermediate model to filter rows with
- self.filter_model = self.base_model.filter_new()
- self.filter_model.set_visible_func(self.visible_row_filter)
- self.filter_model.set_modify_func(self.column_types, self.get_row_col_model_data)
-
- # create an intermediate model to sort the filtered rows with
- self.sort_model = gtk.TreeModelSort(self.filter_model)
- self.sort_model.connect('sort-column-changed', self.on_sort_column_changed, self.view)
- self.sort_model.set_sort_func(DATE_COLUMN, self.sort_date_column, DATE_COLUMN)
-
- self.view.set_model(self.sort_model)
- self.view_model = self.sort_model
-
-
- self.sort_model.set_sort_column_id(self.sort_column_id, self.sort_order)
-
- self.row_inserted_signal.connect(self.view_model, self.on_model_row_inserted)
- self.row_deleted_signal.connect (self.view_model, self.on_model_row_deleted)
- self.row_changed_signal.connect (self.view_model, self.on_model_row_changed)
-
- def bind_data(self, alert_data):
- if debug:
- if alert_data is None:
- name = None
- else:
- name = alert_data.name
- log_gui.debug("view.bind_data: %s", name)
-
- self.alert_data = alert_data
- self.set_model(alert_data.model)
-
- self.properties_changed_signal.connect(self.alert_data, self.on_data_properties_changed)
- self.load_data_signal.connect(self.alert_data, self.on_load_data)
-
- # --- Row Handling ---
-
- def get_row_col_model_data(self, model, iter, column):
- value = None
- # Convert the filter iter to the corresponding child model iter.
- child_model_iter = model.convert_iter_to_child_iter(iter)
- if child_model_iter is None:
- return None
- child_model = model.get_model()
- siginfo = child_model.get_value(child_model_iter, 0)
- if siginfo is None:
+ def idle_func(self):
+ while gtk.events_pending():
+ gtk.main_iteration()
+
+ def submit_button_clicked(self, widget):
+ main_window = self.main_window.get_root_window()
+ busy_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ ready_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
+ main_window.set_cursor(busy_cursor)
+ self.idle_func()
+
+ self.submit()
+
+ main_window.set_cursor(ready_cursor)
+ self.idle_func()
+
+ def submit(self):
+ import rpmUtils.arch
+ bugzillaUrl = "https://bugzilla.redhat.com/show_bug.cgi?id="
+ password = self.password_entry.get_text()
+ username = self.username_entry.get_text()
+
+ # if they wanted this remembered, let the parent know to keep the username, write the file and then write to the keyring.
+
+ text_buf = self.error_submit_text.get_buffer()
+ content = text_buf.get_text(text_buf.get_start_iter(), text_buf.get_end_iter())
+ file = open(DUMP_PATH, "w")
+ file.write(content)
+ file.close()
+ content += "audit2allow suggests:" + run_audit2allow(DUMP_PATH)
+ def withBugzillaDo(bz, fn):
+ try:
+ retval = fn(bz)
+ return retval
+ except CommunicationError, e:
+ msg = _("Your bug could not be filed due to the following error when communicating with bugzilla:\n\n%s" % str(e))
+
+ FailDialog(msg)
return None
-
- if column == PYOBJECT_COLUMN:
- value = siginfo
- elif column == COUNT_COLUMN:
- value = siginfo.report_count
- elif column == DATE_COLUMN:
- value = siginfo.last_seen_date
- elif column == HOST_COLUMN:
- value = siginfo.host
- elif column == CATEGORY_COLUMN:
- value = default_text(siginfo.category)
- elif column == SUMMARY_COLUMN:
- value = html_to_text(siginfo.solution.summary, 1024)
-
- return value
-
-
- def visible_row_filter(self, model, iter):
- visible = True
-
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- if siginfo is not None:
- user_data = siginfo.get_user_data(self.username)
-
- if user_data.delete_flag and self.hide_deleted:
- visible = False
-
- if user_data.filter.filter_type == FILTER_ALWAYS and self.hide_quiet:
- visible = False
-
- return visible
-
- def on_filter_toggle(self, cell, path):
- if self.view_model is None:
- return
- model = self.view_model
-
- iter = model.get_iter_from_string(path)
- siginfo = get_siginfo_from_model_path(model, path)
- user_data = siginfo.get_user_data(self.username)
-
- if user_data.filter.filter_type == FILTER_NEVER:
- filter_type = FILTER_ALWAYS
- else:
- filter_type = FILTER_NEVER
- database = self.alert_data.database
- database.set_filter(siginfo.sig, self.username, filter_type, '')
- return True # return True ==> handled, False ==> propagate
-
- def on_model_row_inserted(self, model, path, iter):
- if debug:
- pass
- #log_gui_data.debug("model_row_inserted: %s", path)
- self.emit('row-changed', self.view_model, 'add', iter)
-
- def on_model_row_changed(self, model, path, iter):
- if debug:
- pass
- #log_gui_data.debug("model_row_changed: %s", path)
- self.emit('row-changed', self.view_model, 'modify', iter)
-
- def on_model_row_deleted(self, model, path):
- if debug:
- pass
- #log_gui_data.debug("model_row_deleted: %s", path)
- self.emit('row-changed', self.view_model, 'delete', None)
-
- # --- Column Handling ---
-
- def sort_date_column(self, model, iter1, iter2, column_index):
- if debug:
- log_gui.debug('sort_date_column:')
- timestamp1 = model.get_value(iter1, column_index)
- timestamp2 = model.get_value(iter2, column_index)
- if timestamp1 is None or timestamp2 is None:
- return 0
- return cmp(timestamp1, timestamp2)
-
- def count_cell_data(self, column, cell, model, iter, column_index):
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- text_attributes = self.get_text_attributes(siginfo)
- cell.set_property("attributes", text_attributes)
-
- # FIXME: this should be a global property, not set each time
- cell.set_property("xalign", 1.0)
-
- text = model.get_value(iter, column_index)
- cell.set_property('text', text)
- return
-
- def date_cell_data(self, column, cell, model, iter, column_index):
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- text_attributes = self.get_text_attributes(siginfo)
- cell.set_property("attributes", text_attributes)
- timestamp = model.get_value(iter, column_index)
- if timestamp is None:
- return
- cell.set_property('text', timestamp.format())
- return
-
- def text_cell_data(self, column, cell, model, iter, column_index):
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- text_attributes = self.get_text_attributes(siginfo)
- cell.set_property("attributes", text_attributes)
- text = model.get_value(iter, column_index)
- cell.set_property('text', text)
- return
-
- def filter_type_cell_data(self, column, cell, model, iter, column_index):
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- user_data = siginfo.get_user_data(self.username)
-
- if user_data.filter.filter_type == FILTER_NEVER:
- cell.set_property('active', False)
- else:
- cell.set_property('active', True)
- return
-
- def restore_selection(self):
- if debug:
- log_gui.debug('restore_selection:')
- if self.selection is None or self.view_model is None:
- return
-
- self.selection.unselect_all()
- n_paths = len(self.view_model)
- if n_paths == 0:
- new_row = 0
- else:
- new_row = min(self.last_selected_row, n_paths-1)
- if debug:
- log_gui.debug('restore_selection: new_row=%s', new_row)
- self.selection.select_path((new_row,))
- self.view.scroll_to_cell((new_row,))
-
- def get_selected_siginfos(self):
- model, selected_paths = self.selection.get_selected_rows()
-
- siginfos = []
- for path in selected_paths:
- siginfo = get_siginfo_from_model_path(model, path)
- siginfos.append(siginfo)
- return siginfos
-
- # --- Signals ---
-
- def on_data_properties_changed(self, alert_data, properties):
- self.emit('properties-changed', alert_data, properties)
-
- def on_load_data(self, alert_data, state, errno, strerror):
- self.emit('load-data', alert_data, state, errno, strerror)
-
- def on_async_error(self, alert_data, method, errno, strerror):
- if debug:
- log_program.debug("%s.on_async_error(%s, %d, %s)", self.__class__.__name__, method, errno, strerror)
- self.emit('async-error', alert_data, method, errno, strerror)
-
- # --- Utilities ---
-
- def get_text_attributes(self, siginfo):
- user_data = siginfo.get_user_data(self.username)
- text_attributes = pango.AttrList()
-
- if not user_data.seen_flag:
- text_attributes.insert(pango.AttrWeight(pango.WEIGHT_HEAVY, 0, -1))
-
- if user_data.delete_flag:
- text_attributes.insert(pango.AttrStrikethrough(True, 0, 1000))
-
- return text_attributes
-
+ filer = BugzillaFiler(bugUrl="https://bugzilla.redhat.com/xmlrpc.cgi",develVersion="rawhide", defaultProduct="Fedora")
+ if not filer.supportsFiling() or not filer.bugUrl:
-#------------------------------------------------------------------------------
-
-class AlertData(gobject.GObject):
-
- __gsignals__ = {
- 'load-data':
- (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)),
- 'properties-changed':
- (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)),
- 'async-error': # callback(method, errno, strerror)
- (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)),
- }
-
-
- def __init__(self, name, database):
- gobject.GObject.__init__(self)
-
- self.name = name
- self.database = database
- self.database_properties = SEDatabaseProperties()
- # create the base model, it holds a siginfo
- self.model = gtk.ListStore(gobject.TYPE_PYOBJECT)
-
- self.clear()
- self.get_properties()
- database.connect('signatures_updated', self.signatures_updated)
-
- def clear(self):
- if debug:
- log_gui.debug("AlertData (%s) clear: cur row count = %d", self.name, len(self.model))
- self.model.clear()
-
- def set_properties(self, properties):
- if debug:
- log_gui.debug("set_properties: properties=%s", properties)
- if properties is None:
- self.database_properties = SEDatabaseProperties()
- else:
- self.database_properties = properties
- self.emit('properties-changed', self.database_properties)
-
- def get_properties(self):
- if self.database is None: return
- async_rpc = self.database.get_properties()
- async_rpc.add_callback(self.get_properties_callback)
- async_rpc.add_errback(self.get_properties_errback)
-
- def get_properties_callback(self, properties):
- if debug:
- log_gui.debug("get_properties_callback: properties=%s", properties)
- self.set_properties(properties)
-
- def get_properties_errback(self, method, errno, strerror):
- log_rpc.error('database bind: %s', strerror)
- self.set_properties(None)
-
- def signatures_updated(self, database, type, item):
- if debug:
- log_gui_data.debug("signatures_updated() %s: type=%s, item=%s alert_list size=%s",
- self.name, type, item, len(self.model))
-
- def new_siginfo_callback(sigs):
- if debug:
- log_gui_data.debug("new_siginfo_callback(), type=%s %s", type, str(sigs))
-
- for siginfo in sigs.signature_list:
- self.insert_siginfo_into_model(siginfo)
-
- if type == 'add' or type == 'modify':
- async_rpc = self.database.query_alerts(item)
- async_rpc.add_callback(new_siginfo_callback)
- elif type == 'delete':
- iter = self.get_iter_from_local_id(item)
- if iter is not None:
- self.model.remove(iter)
- else:
- raise ProgramError(ERR_UNKNOWN_VALUE, "signatures_updated: type = %s not recognized" % type)
+ FailDialog(_("Bug filing not supported. Your distribution does not provide a supported bug filing system."))
+ return
+ if username == "" or password == "":
- def get_iter_from_local_id(self, local_id, model=None):
- if model is None:
- model = self.model
- iter = model.get_iter_first()
- while iter:
- row_siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- if row_siginfo.local_id == local_id:
- return iter
- iter = model.iter_next(iter)
-
- return None
-
- def insert_siginfo_into_model(self, siginfo):
- iter = self.get_iter_from_local_id(siginfo.local_id)
- if iter is None:
- if debug:
- log_gui_data.debug("insert_siginfo_into_model(): new")
- iter = self.new_model_row(siginfo)
- else:
- if debug:
- log_gui_data.debug("insert_siginfo_into_model(): replace")
- self.update_model_row(iter, siginfo)
-
- def update_model_row(self, iter, siginfo):
- validate_siginfo(siginfo)
- self.model.set(iter, PYOBJECT_COLUMN, siginfo)
+ FailDialog(_("Please provide a valid username and password."))
+ return
+ hash = hashlib.sha256(str(self.siginfo.sig)).hexdigest()
-
- def new_model_row(self, siginfo):
- validate_siginfo(siginfo)
- iter = self.model.append((siginfo,))
- return iter
-
- def load_model_data_from_sigs(self, sigs):
- self.model.clear()
- for siginfo in sigs.signature_list:
- self.new_model_row(siginfo)
-
- def load_data(self):
- self.clear()
-
- if debug:
- log_gui.debug("load_data(): database=%s", self.name)
-
- self.get_properties()
-
- if self.database is not None:
- criteria = '*'
- self.emit('load-data', 'start', 0, '')
- async_rpc = self.database.query_alerts(criteria)
- async_rpc.add_callback(self.query_alerts_callback)
- async_rpc.add_errback(self.query_alerts_error)
-
-
- def query_alerts_callback(self, sigs):
- if debug:
- log_gui.debug("query_alerts_callback():")
- self.sigs = sigs
- self.load_model_data_from_sigs(sigs)
- self.emit('load-data', 'end', 0, '')
-
-
- def query_alerts_error(self, method, errno, strerror):
- log_gui.error("query_alerts: [%d] %s", errno, strerror)
- self.emit('load-data', 'end', errno, strerror)
-
- def get_siginfos(self, criteria=None):
- siginfos = []
- iter = self.model.get_iter_first()
- while iter:
- siginfo = self.model.get_value(iter, PYOBJECT_COLUMN)
- siginfos.append(siginfo)
- iter = self.model.iter_next(iter)
- return siginfos
+ try:
+ cred = withBugzillaDo(filer, lambda b: b.login(username, password))
+ except LoginError:
-gobject.type_register(AlertData)
-
-#------------------------------------------------------------------------------
-
-class AlertViewData(object):
- def __init__(self, name, username, browser):
- self.name = name
- self.username = username
- self.list_view = AlertListView(username, browser)
- self.alert_data = None
-
- def bind_data(self, alert_data):
- self.alert_data = alert_data
- self.list_view.bind_data(alert_data)
-
-#-----------------------------------------------------
-
-class ScanLogfileDialog(gtk.Dialog):
- def __init__(self):
- gtk.Dialog.__init__(self, title=_('Scan Log File'))
- #buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
-
- self.analyzer = LogfileAnalyzer()
- self.analyzer.connect('progress', self.on_progress)
- self.analyzer.connect('state-changed', self.on_analyzer_state_change)
-
- icon_name = get_config('general','icon_name')
- self.set_icon_name(icon_name)
- self.set_default_size(400, 100)
-
- self.cancel_response_button = self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
- self.cancel_response_button.connect('clicked', self.run_analysis, False)
-
- self.ok_response_button = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
- self.ok_response_button.set_sensitive(False)
-
- self.file_hbox = gtk.HBox()
- self.action_hbox = gtk.HBox()
- self.progress_bar = gtk.ProgressBar()
- self.vbox.pack_start(self.file_hbox, False)
- self.vbox.pack_start(self.action_hbox, False)
- self.vbox.pack_start(self.progress_bar, False)
-
- self.file_entry = gtk.Entry()
- self.file_entry.connect('activate', self.on_filepath_activate)
- self.file_entry.connect('changed', self.on_filepath_changed)
-
- self.file_chooser_button = gtk.Button(stock=gtk.STOCK_OPEN)
- self.file_chooser_button.connect('clicked', self.run_file_chooser)
-
- self.file_hbox.pack_start(self.file_entry, True)
- self.file_hbox.pack_start(self.file_chooser_button, False)
-
- self.run_analysis_button = gtk.Button(stock=gtk.STOCK_EXECUTE)
- self.run_analysis_button.connect('clicked', self.run_analysis, True)
- self.run_analysis_button.set_sensitive(False)
-
- self.cancel_analysis_button = gtk.Button(stock=gtk.STOCK_STOP)
- self.cancel_analysis_button.connect('clicked', self.run_analysis, False)
- self.cancel_analysis_button.set_sensitive(False)
-
- self.action_hbox.pack_start(self.run_analysis_button, True)
- self.action_hbox.pack_start(self.cancel_analysis_button, True)
-
- self.set_position(gtk.WIN_POS_CENTER)
- self.set_keep_above(True)
- self.show_all()
- self.set_widget_state('pending')
-
- filepath = property(lambda self: self.file_entry.get_text())
-
- def on_progress(self, analyzer, progress):
- self.progress_bar.set_fraction(progress)
- if progress == 1.0:
- self.cancel_analysis_button.set_sensitive(False)
-
-
- def on_analyzer_state_change(self, analyzer, state):
- self.set_widget_state(state)
- if state == 'stopped':
- if analyzer.strerror:
- display_error(analyzer.strerror)
-
- def scan_file(self, filepath):
- if debug:
- log_avc.debug('%s.scan_file(%s)', self.__class__.__name__, filepath)
- self.analyzer.cancelled = False
- self.analyzer.open(self.filepath)
- self.progress_bar.set_text(self.analyzer.friendly_name)
- self.analyzer.run()
-
- def set_widget_state(self, state):
- if state == 'pending':
- self.ok_response_button.set_sensitive(False)
- self.cancel_response_button.set_sensitive(True)
- self.file_chooser_button.set_sensitive(True)
- self.file_entry.set_sensitive(True)
- self.run_analysis_button.set_sensitive(True)
- self.cancel_analysis_button.set_sensitive(False)
- elif state == 'stopped':
- if not self.analyzer.errno:
- self.ok_response_button.set_sensitive(True)
- else:
- self.ok_response_button.set_sensitive(False)
- self.cancel_response_button.set_sensitive(True)
- self.file_chooser_button.set_sensitive(False)
- self.file_entry.set_sensitive(False)
- self.run_analysis_button.set_sensitive(False)
- self.cancel_analysis_button.set_sensitive(False)
- elif state == 'running':
- self.ok_response_button.set_sensitive(False)
- self.cancel_response_button.set_sensitive(True)
- self.file_chooser_button.set_sensitive(False)
- self.file_entry.set_sensitive(False)
- self.run_analysis_button.set_sensitive(False)
- self.cancel_analysis_button.set_sensitive(True)
- else:
- raise ValueError("unknown state (%s)" % state)
-
- def run_analysis(self, widget, start):
- if debug:
- log_avc.debug('%s.run_analysis() start=%s', self.__class__.__name__, start)
- if start:
- self.scan_file(self.filepath)
- else:
- self.analyzer.cancelled = True
-
- def on_filepath_changed(self, widget):
- if self.filepath:
- self.run_analysis_button.set_sensitive(True)
- else:
- self.run_analysis_button.set_sensitive(False)
-
- def on_filepath_activate(self, widget):
- self.run_analysis(widget, True)
-
- def run_file_chooser(self, widget):
- result = None
- file_open = gtk.FileChooserDialog(self.get_title(), action=gtk.FILE_CHOOSER_ACTION_OPEN,
- buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
-
- if file_open.run() == gtk.RESPONSE_OK:
- self.file_entry.set_text(file_open.get_filename())
- file_open.destroy()
-
- def get_database(self):
- if not self.analyzer.errno:
- return self.analyzer.database
- else:
- return None
-
-
-#------------------------------------------------------------------------------
+ FailDialog(_("Unable to login. There was an error logging in with the provided username and password."))
+ return
-class StatusMessage(object):
- LOW_PRIORITY = 0
- MEDIUM_PRIORITY = 1
- HIGH_PRIORITY = 2
-
- message_priorities = [LOW_PRIORITY, MEDIUM_PRIORITY, HIGH_PRIORITY]
-
- map_priority_to_string = {
- LOW_PRIORITY : 'LOW',
- MEDIUM_PRIORITY : 'MEDIUM',
- HIGH_PRIORITY : 'HIGH',
- }
+ # Check for existing bugs.
+ wb = "setroubleshoot_trace_hash:%s" % hash
- INFO_TYPE = 0
- ERROR_TYPE = 1
-
- message_types = [INFO_TYPE, ERROR_TYPE]
+ buglist = withBugzillaDo(filer, lambda b: b.query({"status_whiteboard": wb,
+ "status_whiteboard_type": "allwordssubstr",
+ "bug_status": []}))
+ if buglist is None:
+ return
- map_type_to_string = {
- INFO_TYPE : 'INFO',
- ERROR_TYPE : 'ERROR',
- }
-
- time_fmt = '%I:%M.%S %p'
-
- def __init__(self, owner, type, priority, text, time_to_live=None, message_name=None):
- self.owner = owner
- self.type = type
- self.priority = priority
- self.text = text
- self.start_time = time.time()
- self.time_to_live = time_to_live
- self.message_name = message_name
-
- def __str__(self):
- time_str = time.strftime(self.time_fmt, time.localtime(self.start_time))
- if self.time_to_live is not None:
- expiration_time = self.start_time + self.time_to_live
- time_str += ' - %s' % (time.strftime(self.time_fmt, time.localtime(expiration_time)))
-
- text = "[%s,%s,%s, %s] %s" % (self.map_type_to_string[self.type],
- self.map_priority_to_string[self.priority],
- time_str, self.message_name,
- self.text)
- return text
-
-
- def update_text(self, text, time_to_live=None):
- self.text = text
-
- if time_to_live is not None:
- self.start_time = time.time()
- self.time_to_live = time_to_live
+ if len(buglist) == 0:
+ bug = withBugzillaDo(filer, lambda b: b.createbug(product=filer.getproduct("setroubleshoot"),
+ component="selinux-policy",
+ platform=rpmUtils.arch.getBaseArch(),
+ version=get_version(),
+ bug_severity="medium",
+ priority="medium",
+ op_sys="Linux",
+ summary="setroubleshoot: %s" % self.summary,
+ comment="The following was filed automatically by setroubleshoot:\n%s" % content,
+ status_whiteboard=wb))
- self.owner.update_message_text(self)
-
-
-#------------------------------------------------------------------------------
-
-class StatusMessageManager(object):
-
- '''Messages are inserted into a priority list, the message
- with the highest priority is the one currently displayed.
-
- Messages may be either expiring (timeout) or non-expiring.
-
- There is at most one non-expiring message of any given
- type. The next non-expiring message written replaces the
- previous non-expiring message of the same type.
-
- Expiring messages persist in the message list until they
- expire or are manually removed.
-
- Any message may be removed at any time by calling
- remove_message(). It is not an error to remove a message not
- present in the message list.
-
- The currently displayed message is updated whenever the
- message list is updated which occures when a message is added,
- removed, modified, or times out.
-
- Setting a message does not guarantee it will be displayed, a
- higher priority message may obscure it. In such a case it
- might be displayed later if the obscuring message times out or
- is manually removed.
-
- '''
-
- def __init__(self, name, set_message_func):
- self.name = name
- self.set_message = set_message_func
- self.expire_timeout_id = None
- self.messages = []
-
- def _expire_timeout_callback(self):
- if debug:
- log_gui.debug("_expire_timeout_callback (%s)", self.name)
- self.expire_timeout_id = None
- self._prune_expiring_messages()
- self._display_current_message()
- return False
-
- def _prune_non_expiring_messages(self):
- if debug:
- self.dump_message_list("_prune_non_expiring_messages start (%s)" % (self.name))
- message_at_priority_level = {}
-
- # Note iterate over copy of message list (e.g. [:]) to avoid problems with modification during iteration
- for message in self.messages[:]:
- if message.time_to_live is None:
- if message_at_priority_level.get(message.priority):
- self.messages.remove(message)
- else:
- message_at_priority_level[message.priority] = message
-
- if debug:
- self.dump_message_list("_prune_non_expiring_messages end (%s)" % (self.name))
-
- def _prune_expiring_messages(self):
- now = time.time()
-
- if debug:
- self.dump_message_list("_prune_expiring_messages start (%s) now=%s" % (self.name, time.strftime(StatusMessage.time_fmt, time.localtime(now))))
-
- if self.expire_timeout_id is not None:
- gobject.source_remove(self.expire_timeout_id)
- self.expire_timeout_id = None
-
- maximum_expiration_time = 0.0
- soonest_message_to_expire = None
- # Note iterate over copy of message list (e.g. [:]) to avoid problems with modification during iteration
- for message in self.messages[:]:
- if message.time_to_live is not None:
- message_expiration_time = message.start_time + message.time_to_live
- if message_expiration_time <= now:
- self.messages.remove(message)
- else:
- if message_expiration_time > maximum_expiration_time:
- maximum_expiration_time = message_expiration_time
- soonest_message_to_expire = message
- if soonest_message_to_expire is not None:
- seconds_to_next_expire = (soonest_message_to_expire.start_time + soonest_message_to_expire.time_to_live) - now
- if debug:
- log_gui.debug("expire next (%s) in %.1f: %s", self.name, seconds_to_next_expire, soonest_message_to_expire)
- self.expire_timeout_id = gobject.timeout_add(int(seconds_to_next_expire*1000), self._expire_timeout_callback)
+ SuccessDialog(_("Bug Created"), _("A new bug has been created with your audit messages. Please add additional information such as what you were doing when you encountered the bug, screenshots, and whatever else is appropriate to the following bug:\n\n%s%s") % (bugzillaUrl, bug.id()), bugzillaUrl + str(bug.id()))
+ if bug is None:
+ return
else:
- if debug:
- log_gui.debug("NO expiring messages")
-
- if debug:
- self.dump_message_list("_prune_expiring_messages end (%s)" % (self.name))
-
-
- def get_message_by_name(self, message_name):
- for message in self.messages:
- if message.message_name == message_name:
- return message
- return None
-
- def dump_message_list(self, header=None):
- if header is not None:
- log_gui.debug(header)
- for message in self.messages:
- log_gui.debug(message)
+ bug = buglist[0]
+ withBugzillaDo(bug, lambda b: b.addCC(username))
- def _message_sort_func(self, msg2, msg1):
- # sort descending by swapping input parameters
- relation = cmp(msg1.priority, msg2.priority)
- if relation: return relation
- relation = cmp(msg1.start_time, msg2.start_time)
- return relation
-
- def _add_message(self, message):
- if message.message_name is not None:
- existing_named_message = self.get_message_by_name(message.message_name)
- if existing_named_message != message:
- self.remove_message(existing_named_message)
-
- if not message in self.messages:
- self.messages.append(message)
- self.messages.sort(self._message_sort_func)
-
- if debug:
- self.dump_message_list("_add_message (%s): %s" % (self.name, message))
- self._prune_non_expiring_messages()
- self._prune_expiring_messages()
- self._display_current_message()
-
- def _display_current_message(self):
- if debug:
- self.dump_message_list("_display_current_message (%s)" % (self.name))
- if len(self.messages) > 0:
- message = self.messages[0]
- self.set_message(message.text)
- else:
- self.set_message(None)
-
- def update_message_text(self, message):
- self._add_message(message)
-
- def remove_message(self, message):
- if message in self.messages:
- self.messages.remove(message)
- self._display_current_message()
- if debug:
- self.dump_message_list("remove_message (%s): %s" % (self.name, message))
-
- def remove_message_by_name(self, message_name):
- message = self.get_message_by_name(message_name)
- if message is not None:
- self.remove_message(message)
-
- def remove_all_messages(self):
- if debug:
- self.dump_message_list("remove_all_messages (%s)" % (self.name))
- # Note iterate over copy of message list (e.g. [:]) to avoid problems with modification during iteration
- for message in self.messages[:]:
- self.remove_message(message)
-
- def new_message(self, type, priority, text, time_to_live=None, message_name=None):
- message = StatusMessage(self, type, priority, text, time_to_live, message_name)
- self._add_message(message)
- return message
-
-#------------------------------------------------------------------------------
-
-class BrowserStatusBar(gtk.VBox):
- # These should sum to 1.0
- visit_msg_proportion = 0.20
- alert_count_proportion = 0.10
- status_msg_proportion = 0.55
- progress_proportion = 0.15
-
- def __init__(self):
- gtk.VBox.__init__(self)
-
- self.status_hbox = gtk.HBox()
-
-
- # Error bar
- self.error_frame = gtk.Frame()
- self.error_hbox = gtk.HBox()
- error_icon = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_MENU)
- self.error_hbox.pack_start(error_icon, expand=False)
- self.error_msg = gtk.Label("error")
- self.error_msg.set_ellipsize(pango.ELLIPSIZE_END)
- self.error_msg.set_alignment(0.0, 0.5)
- self.error_hbox.pack_start(self.error_msg, expand=True)
- self.error_frame.add(self.error_hbox)
-
- self.connect_icon = gtk.Image()
- self.connect_icon.set_from_stock(gtk.STOCK_DISCONNECT, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- self.connect_icon_frame = gtk.Frame()
- self.connect_icon_frame.add(self.connect_icon)
- self.status_hbox.add(self.connect_icon_frame)
-
- self.visit_msg = gtk.Label("visiting")
- self.visit_msg.set_ellipsize(pango.ELLIPSIZE_END)
- self.visit_msg.set_alignment(0.0, 0.5)
- self.visit_msg_frame = gtk.Frame()
- self.visit_msg_frame.add(self.visit_msg)
- self.status_hbox.add(self.visit_msg_frame)
-
- self.alert_count = gtk.Label("count")
- self.alert_count.set_ellipsize(pango.ELLIPSIZE_END)
- self.alert_count.set_alignment(0.0, 0.5)
- self.alert_count_frame = gtk.Frame()
- self.alert_count_frame.add(self.alert_count)
- self.status_hbox.add(self.alert_count_frame)
-
- self.status_msg = gtk.Label("status")
- self.status_msg.set_ellipsize(pango.ELLIPSIZE_END)
- self.status_msg.set_alignment(0.0, 0.5)
- self.status_msg_frame = gtk.Frame()
- self.status_msg_frame.add(self.status_msg)
- self.status_hbox.add(self.status_msg_frame)
-
- self.progress = gtk.ProgressBar()
- self.progress.set_ellipsize(pango.ELLIPSIZE_END)
- self.progress_frame = gtk.Frame()
- self.progress_frame.add(self.progress)
- self.status_hbox.add(self.progress_frame)
-
- self.pack_start(self.error_frame, expand=False)
- self.pack_start(self.status_hbox, expand=False)
-
- self.show_all()
- self.error_frame.hide() # error is initially hidden
-
- self.status = StatusMessageManager('statusbar status', self.set_status_message)
- self.error = StatusMessageManager('statusbar error', self.set_error_message)
-
- def do_size_allocate(self, allocation):
- if debug:
- log_gui.debug("%s.do_size_allocate: (%d,%d)(%dx%d)",
- self.__class__.__name__, allocation.x, allocation.y, allocation.width, allocation.height)
-
- max_x = allocation.x + allocation.width
-
- # If the error bar is visible, allocate space for it
- if self.error_frame.flags() & gtk.VISIBLE:
- child_rect = gtk.gdk.Rectangle(allocation.x, allocation.y, allocation.width, allocation.height/2)
- self.error_frame.size_allocate(child_rect)
- child_rect.y += child_rect.height
+ SuccessDialog(_("Bug Updated"), _("A bug with your information already exists. Your account has been added to the CC list. Please add additional information such as what you were doing when you encountered the bug, screenshots, and whatever else is appropriate to the following bug:\n\n%s%s") % (bugzillaUrl, bug.id()), bugzillaUrl + str(bug.id()))
+ # keyring stuff
+ if self.remember_check.get_active() == True:
+ self.parent.bugzilla_username = username
+ gnomekeyring.item_create_sync(gnomekeyring.get_default_keyring_sync(), gnomekeyring.ITEM_GENERIC_SECRET, "setroubleshoot-bugzilla", {"user" : username, "server": "bugzilla.redhat.com"}, password, True)
+ self.parent.remember_me = True
else:
- child_rect = gtk.gdk.Rectangle(allocation.x, allocation.y, allocation.width, allocation.height)
+ self.parent.remember_me = False
+ self.parent.bugzilla_username = ""
- # Compute size for connection icon
- icon_width, icon_height = self.connect_icon_frame.size_request()
-
- # Total space available for fixed sized items
- fixed_width_total = icon_width
- fixed_width_total = min(allocation.width, fixed_width_total)
- fixed_width_remaining = fixed_width_total
-
- # Total space available remaining for scaled items
- scaled_width_total = allocation.width - fixed_width_total
- scaled_width_remaining = scaled_width_total
-
- # Move left to right laying out items:
- # [connection icon][visit msg][status msg][progress bar]
-
- # Connection Icon
- child_rect.width = min(fixed_width_total, icon_width)
- self.connect_icon_frame.size_allocate(child_rect)
- child_rect.x += child_rect.width
- fixed_width_remaining = fixed_width_remaining - child_rect.width
-
- # Visit Message
- child_rect.width = int(scaled_width_total * self.visit_msg_proportion)
- if (child_rect.x + child_rect.width) > max_x:
- child_rect.width = max_x - child_rect.x
- self.visit_msg_frame.size_allocate(child_rect)
- scaled_width_remaining = scaled_width_remaining - child_rect.width
- child_rect.x += child_rect.width
-
- # Alert Count
- child_rect.width = int(scaled_width_total * self.alert_count_proportion)
- if (child_rect.x + child_rect.width) > max_x:
- child_rect.width = max_x - child_rect.x
- self.alert_count_frame.size_allocate(child_rect)
- scaled_width_remaining = scaled_width_remaining - child_rect.width
- child_rect.x += child_rect.width
-
- # Status Message
- child_rect.width = int(scaled_width_total * self.status_msg_proportion)
- if (child_rect.x + child_rect.width) > max_x:
- child_rect.width = max_x - child_rect.x
- self.status_msg_frame.size_allocate(child_rect)
- scaled_width_remaining = scaled_width_remaining - child_rect.width
- child_rect.x += child_rect.width
-
- # Progress Bar
- # Note, we don't compute the proportionate space for the last scaled item
- # because of potential rounding errors, we just use whats left
- child_rect.width = scaled_width_remaining
- if child_rect.x + child_rect.width > max_x:
- child_rect.width = max(0, max_x - child_rect.x)
- self.progress_frame.size_allocate(child_rect)
-
- def set_status_message(self, text):
- if debug:
- log_gui.debug("set_status_message: %s", text)
- if text is None:
- self.status_msg.set_text('')
- else:
- self.status_msg.set_text(text)
- def set_error_message(self, text):
- if debug:
- log_gui.debug("set_error_message: %s", text)
- if text is None:
- self.error_frame.hide()
- else:
- text = '%s' % text
- self.error_msg.set_markup(text)
- self.error_frame.show()
-
- def set_connected_state(self, is_connected):
- if is_connected:
- self.connect_icon.set_from_stock(gtk.STOCK_CONNECT, gtk.ICON_SIZE_SMALL_TOOLBAR)
- else:
- self.connect_icon.set_from_stock(gtk.STOCK_DISCONNECT, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- def set_visit_message(self, msg):
- if msg is None:
- self.visit_message = ''
- else:
- self.visit_message = msg
- self.visit_msg.set_text(self.visit_message)
+ self.destroy(self.main_window)
-gobject.type_register(BrowserStatusBar)
-#------------------------------------------------------------------------------
+ def widget(self, name):
+ return self.widget_tree.get_widget(name)
-class SignalConnection(object):
- def __init__(self, signal, emitter=None, id=None):
- self.signal = signal
- self.emitter = emitter
- self.id = id
-
- def connect(self, emitter, handler):
- self.disconnect()
- self.emitter = emitter
- if self.emitter is not None:
- self.id = self.emitter.connect(self.signal, handler)
-
+def timeout_callback(bar):
+ bar.pulse()
+ return True
+class LoadingDialog():
+ def __init__(self, parent):
+ self.gladefile = GLADE_DIRECTORY + "loading.glade"
+ self.widget_tree = gtk.glade.XML(self.gladefile)
+ self.window = self.widget("loading_window")
+ self.bar = self.widget("progressbar1")
+ self.window.show_all()
+ self.window.connect("destroy", self.destroy)
+ self.timeout = gobject.timeout_add(100, timeout_callback, self.bar)
+ #parent.submit()
+ def destroy(self, widget):
+ gobject.source_remove(self.timeout)
+ self.window.destroy()
+
+
+ def widget(self, name):
+ return self.widget_tree.get_widget(name)
+
+
+class FailDialog():
+ def __init__(self, message):
+ self.gladefile = GLADE_DIRECTORY + "fail_dialog.glade"
+ self.widget_tree = gtk.glade.XML(self.gladefile)
+
+ # Get the widgets we need
+ self.window = self.widget("window")
+ self.text_label = self.widget("text_label")
+ self.ok_button = self.widget("ok_button")
+
+ self.text_label.set_text(message)
+ # Construct and connect the dictionary
+ dic = { "on_ok_button_pressed" : self.destroy}
+
+ self.window.connect("destroy", self.destroy)
+ self.widget_tree.signal_autoconnect(dic)
+
+ self.window.show()
+ def destroy(self, widget):
+ self.window.destroy()
+
+ def widget(self, name):
+ return self.widget_tree.get_widget(name)
+
+class SuccessDialog():
+ def __init__(self, title, message, uri):
+ self.gladefile = GLADE_DIRECTORY + "success_dialog.glade"
+ self.widget_tree = gtk.glade.XML(self.gladefile)
+
+ # Get the widgets we need
+ self.window = self.widget("window")
+ self.window.set_title(title)
+ self.text_label = self.widget("text_label")
+ self.ok_button = self.widget("ok_button")
+ self.linkbutton = self.widget("linkbutton")
+ self.linkbutton.set_uri(uri)
+ self.text_label.set_text(message)
+ # Construct and connect the dictionary
+ dic = { "on_ok_button_clicked" : self.destroy}
+
+ self.window.connect("destroy", self.destroy)
+ self.widget_tree.signal_autoconnect(dic)
+
+ self.window.show()
+ def destroy(self, widget):
+ self.window.destroy()
- def disconnect(self):
- if self.emitter is not None and self.id is not None:
- self.emitter.disconnect(self.id)
- self.emitter = None
- self.id = None
-
-#------------------------------------------------------------------------------
-
-class BrowserApplet(object):
- VISIT_AUDIT = 0
- VISIT_LOGFILE = 1
- map_visit_num_to_name = {VISIT_AUDIT : 'audit', VISIT_LOGFILE : 'logfile'}
+ def widget(self, name):
+ return self.widget_tree.get_widget(name)
+
+def run_audit2allow(file):
+ import commands
+ command = "audit2allow -i " + file
+ rc, output = commands.getstatusoutput(command)
+ if rc==0:
+ return output
+ return "\naudit2allow is not installed."
+
+def get_version():
+
+ if os.path.exists(SYSTEM_VERSION_PATH):
+ file = open(SYSTEM_VERSION_PATH, "r")
+ content = file.read()
+ return content.split(" ")[2]
+ else:
+ # default to rawhide
+ return "rawhide"
- # --- Initialization ---
+# The main security alert window
+class BrowserApplet:
+ """Security Alert Browser"""
def __init__(self, username=None, server=None):
self.username = username
+ self.database = server
self.server = server
- self.displayed_siginfo = None
- self.mark_seen_timeout_event_id = None
- self.update_alert_view_idle_event_id = None
- self.restore_selection_idle_event_id = None
- self.alert_display = None
- self.window_delete_hides = True
-# New status app
-# self.window_delete_hides = False
- self.load_in_progress = False
- self.list_view = None
- self.toolbar_visible = False
- self.window_state = gtk.gdk.WINDOW_STATE_WITHDRAWN
- self.visibility_state = gtk.gdk.VISIBILITY_FULLY_OBSCURED
-
- self.view_data_collection = {}
- self.audit_data = AlertData('audit', self.server)
-
- self.audit_view_data = AlertViewData('audit', username, self)
- self.audit_view_data.bind_data(self.audit_data)
- self.set_visit_data('audit', self.audit_view_data)
-
- self.logfile_view_data = AlertViewData('logfile', username, self)
- self.set_visit_data('logfile', self.logfile_view_data)
-
- self.default_save_folder = get_user_home_dir()
- self.default_save_filename = 'selinux_alert.txt'
- self.clipboard = gtk.Clipboard()
- self.print_settings = None
-
- # How long an alert must be displayed before it's marked as having been seen
- self.seen_after_displayed_seconds = 3
-
- program_name = _('setroubleshoot browser')
- program_version = '1.0'
- gnome.init(program_name, program_version)
- self.window_name = _("SETroubleshoot Browser")
-
- self.connection_state_change_signal = SignalConnection('connection_state_changed')
- self.connection_pending_retry_signal = SignalConnection('pending_retry')
- self.properties_changed_signal = SignalConnection('properties-changed')
- self.load_data_signal = SignalConnection('load-data')
- self.async_error_signal = SignalConnection('async-error')
-
- self.alert_list_changed_signal = SignalConnection('row-changed')
- self.selection_changed_signal = SignalConnection('changed')
-
- self.init_widgets()
-
- window_state = os.getenv('SEALERT_WINDOW_STATE')
- if debug:
- log_gui.debug("read SEALERT_WINDOW_STATE from environment (%s)", window_state)
- if window_state is None:
- window_state = 'hidden'
- self.window_state = parse_window_state(window_state)
- self.update_window_state(self.window_state)
-
- window_geometry = os.getenv('SEALERT_WINDOW_GEOMETRY')
- if debug:
- log_gui.debug("read SEALERT_WINDOW_GEOMETRY from environment (%s)", window_geometry)
- if window_geometry is not None:
- self.set_geometry(window_geometry)
-
- self.update_connection_state(server, server.connection_state)
-
- self.connection_state_change_signal.connect(self.server, self.on_connection_state_change)
- self.connection_pending_retry_signal.connect(self.server.connection_retry, self.on_connection_pending_retry)
- self.async_error_signal.connect(self.server, self.on_async_error)
-
- self.do_visit('audit')
- if (self.server.connection_state.flags & ConnectionState.OPEN) and len(self.audit_data.model) == 0:
- self.audit_data.load_data()
-
- def create_ui(self):
- load_stock_icons(['stock_mail-send', 'connect_creating'])
-
- toggle_column_visibility = "\n".join([" " % \
- tv_column_info[column]['name'] for column in range(1, NUM_COLUMNS)])
-
-
- ui_string = """
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- """ % toggle_column_visibility
-
- self.action_group = gtk.ActionGroup('WindowActions')
-
- # File Menu
- action = gtk.Action('FileMenu', _('_File'), None, None)
- self.action_group.add_action(action)
-
- # View Menu
- action = gtk.Action('ViewMenu', _('_View'), None, None)
- self.action_group.add_action(action)
-
-
- # Edit Menu
- action = gtk.Action('EditMenu', _('_Edit'), None, None)
- self.action_group.add_action(action)
-
- # Help Menu
- action = gtk.Action('HelpMenu', _('_Help'), None, None)
- self.action_group.add_action(action)
+ self.server.connect('signatures_updated', self.update_alerts)
-
- # Column Visibility Menu
- action = gtk.Action('ColumnVisibilityMenu', _('_Column Visibility'), None, None)
- self.action_group.add_action(action)
-
- action = gtk.Action('ConnectTo', _('Connect To...'), _('Connect to setroubleshoot server, browse alert results'), 'connect_creating')
- action.connect('activate', self.on_connect_to)
- self.action_group.add_action_with_accel(action, None)
-
- action = gtk.Action('ScanLogfile', _('Scan Logfile...'), _('Scan a log file, browse alert results'), gtk.STOCK_OPEN)
- action.connect('activate', self.on_open_logfile)
- self.action_group.add_action_with_accel(action, None)
-
- action = gtk.Action('SaveAs', _('Save _As...'), _('Save selected alerts in file'), gtk.STOCK_SAVE_AS)
- action.connect('activate', self.on_save_as)
- self.action_group.add_action_with_accel(action, 'S')
-
- action = gtk.Action('Print', _('Print...'), _('Print selected alerts'), gtk.STOCK_PRINT)
- action.connect('activate', self.on_print)
- self.action_group.add_action_with_accel(action, 'P')
-
- action = gtk.Action('EditEmailList', _('Edit Email Alert List...'), _('Edit list of email addresses which receive alerts'), 'stock_mail-send')
- action.connect('activate', self.on_edit_email_alert_list)
- self.action_group.add_action_with_accel(action, None)
-
- if self.window_delete_hides:
- action = gtk.Action('Close', _('_Close'), _('Close the window'), gtk.STOCK_CLOSE)
-
- else:
- action = gtk.Action('Close', _('_Quit'), _('Exit the window'), gtk.STOCK_QUIT)
- action.connect('activate', self.on_close)
- self.action_group.add_action_with_accel(action, 'W')
-
- action = gtk.Action('SelectAll', _('Select _All'), _('Select all alerts'), gtk.STOCK_SELECT_ALL)
- action.connect('activate', self.on_select_all)
- self.action_group.add_action_with_accel(action, 'A')
-
- action = gtk.Action('SelectNone', _('Select _None'), _('Remove all selections'), None)
- action.connect('activate', self.on_select_none)
- self.action_group.add_action_with_accel(action, None)
-
- action = gtk.Action('Copy', _('Copy'), _('Copy selected text in detail pane'), gtk.STOCK_COPY)
- action.connect('activate', self.on_copy)
- self.action_group.add_action_with_accel(action, 'C')
-
- action = gtk.Action('CopyAlert', _('Copy Alert'), _('Copy selected alerts in entirety to clipboard'), gtk.STOCK_COPY)
- action.connect('activate', self.on_copy_alert)
- self.action_group.add_action_with_accel(action, 'C')
-
- action = gtk.Action('MarkDelete', _('Mark _Delete'), _('Mark for deletion'), gtk.STOCK_DELETE)
- action.connect('activate', self.on_delete)
- self.action_group.add_action_with_accel(action, 'Delete')
-
- action = gtk.Action('Undelete', _('_Undelete'), _('Clear deletion flag'), gtk.STOCK_UNDELETE)
- action.connect('activate', self.on_undelete)
- self.action_group.add_action_with_accel(action, 'D')
-
- action = gtk.Action('Expunge', _('Remove Marked Deleted'), _('Permanently delete alerts marked for deletion'), gtk.STOCK_REMOVE)
- action.connect('activate', self.on_expunge)
- self.action_group.add_action_with_accel(action, 'E')
-
- action = gtk.Action('RunFixCmd', _('Run Fix Command'), _('Run the alert\'s fix command'), gtk.STOCK_EXECUTE)
- action.connect('activate', self.on_run_fix_cmd)
- self.action_group.add_action_with_accel(action, None)
-
- action = gtk.Action('Help', _('Help'), _('Show help information'), gtk.STOCK_HELP)
- action.connect('activate', self.on_user_help)
- self.action_group.add_action_with_accel(action, 'F1')
-
- action = gtk.Action('About', _('About'), _('About'), gtk.STOCK_ABOUT)
- action.connect('activate', self.on_about)
- self.action_group.add_action_with_accel(action, None)
-
-
- action = gtk.RadioAction('ViewAudit', _('View Audit Alerts'), _('View alerts from audit system'), None, self.VISIT_AUDIT)
- self.visit_radio_action = action
- self.action_group.add_action_with_accel(action, None)
-
- action = gtk.RadioAction('ViewLogfile', _('View Logfile Scan'), _('View alerts from last log file scan'), None, self.VISIT_LOGFILE)
- action.set_group(self.visit_radio_action)
- action.set_sensitive(False)
- self.action_group.add_action_with_accel(action, None)
-
- self.visit_radio_action.connect('changed', self.on_visit_change)
-
- action = gtk.ToggleAction('HideDeleted', _('Hide deleted'), _('Toggle hide deleted alerts'), None)
- action.connect('activate', self.on_hide_deleted)
- action.set_active(False)
- self.action_group.add_action_with_accel(action, None)
-
- action = gtk.ToggleAction('HideQuiet', _('Hide quiet'), _('Toggle hide quiet alerts'), None)
- action.connect('activate', self.on_hide_quiet)
- action.set_active(False)
- self.action_group.add_action_with_accel(action, None)
-
- action = gtk.ToggleAction('ToggleToolbar', _('Show Toolbar'), _('Toggle the toolbar on/off'), None)
- action.connect('activate', self.on_toggle_toolbar)
- self.action_group.add_action_with_accel(action, None)
-
- # Column Visibility
- for column in range(1, NUM_COLUMNS):
- column_name = tv_column_info[column]['name']
- column_title = tv_column_info[column]['title']
- action = gtk.ToggleAction('Toggle%sColumn' % column_name, _('Show %s Column') % column_title, _('Show/Hide %s Column') % column_title, None)
- action.connect('activate', self.on_toggle_column_visibility, column)
- action.set_active(True)
- self.action_group.add_action_with_accel(action, None)
-
- self.ui = gtk.UIManager()
- self.ui.insert_action_group(self.action_group, 0)
- self.ui.add_ui_from_string(ui_string)
- self.browser_win.add_accel_group(self.ui.get_accel_group())
-
- self.menubar = self.ui.get_widget('/Menubar')
- self.toolbar = self.ui.get_widget('/Toolbar')
-
- def on_realize(self, widget):
- # position the divider between the top and bottom pane
- vpane_rect = self.browser_vpane.get_allocation()
- self.browser_vpane.set_position(vpane_rect.height/4)
-
- def get_geometry(self):
- width, height = self.browser_win.get_size()
- xoffset, yoffset = self.browser_win.get_position()
- geometry = '%dx%d+%d+%d' % (width, height, xoffset, yoffset)
- if debug:
- log_gui.debug("get_geometry() %s", geometry)
- return geometry
-
- def set_geometry(self, geometry):
- screen_width = gtk.gdk.screen_width()
- screen_height = gtk.gdk.screen_height()
- match = re.search("(\d+)x(\d+)", geometry)
- if match:
- width = int(match.group(1))
- height = int(match.group(2))
- #print "width=%d height=%d" % (width, height)
- self.browser_win.resize(width, height)
-
- match = re.search("([+-]\d+)([+-]\d+)", geometry)
- if match:
- xoffset = int(match.group(1))
- yoffset = int(match.group(2))
- #print "xoffset=%d yoffset=%d" % (xoffset, yoffset)
- if xoffset >= 0:
- x = xoffset
- else:
- x = screen_width() + xoffset
-
- if yoffset >= 0:
- y = yoffset
- else:
- y = screen_height()+ yoffset
-
- x = max(x, 0)
- y = max(y, 0)
- # force window to be visible
- if x >= screen_width - 20:
- x = 0
- if y >= screen_height - 20:
- y = 0
- self.browser_win.move(x, y)
-
- def visibility_state_event_cb(self, window, event):
- if debug:
- log_gui.debug("window visibility event: %s", visibility_state_to_string(event.state))
- self.visibility_state = event.state
-
- def window_state_event_cb(self, window, event):
- if debug:
- log_gui.debug("window state event: %s", window_state_to_string(event.new_window_state))
- self.window_state = event.new_window_state
- if event.new_window_state & (gtk.gdk.WINDOW_STATE_WITHDRAWN | gtk.gdk.WINDOW_STATE_ICONIFIED):
- # If the window is iconified or removed a visibility-notify event is not emitted
- # so synthesize one to make it easier to just examine the vis
- event = gtk.gdk.Event(gtk.gdk.VISIBILITY_NOTIFY)
- event.state = gtk.gdk.VISIBILITY_FULLY_OBSCURED
- self.browser_win.emit('visibility-notify-event', event)
-
-
- def on_style_set(self, widget, previous_style):
- if debug:
- log_gui.debug("on_style_set:")
- self.update_alert_view()
-
- def configure_event_cb(self, window, event):
- if debug:
- log_gui.debug("configure event: x=%d y=%d width=%d height=%d",
- event.x, event.y, event.width, event.height)
-
- def init_widgets(self):
- self.browser_win = gtk.Window()
- self.browser_win.set_position(gtk.WIN_POS_CENTER)
- self.browser_win.set_title(_("setroubleshoot browser"))
- self.browser_win.set_default_size(800, 700)
- icon_name = get_config('general','icon_name')
- self.browser_win.set_icon_name(icon_name)
-
- self.browser_win.connect('delete-event', self.on_close)
-
- self.browser_win.connect_after("realize", self.on_realize)
- self.browser_win.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK)
- self.browser_win.connect('visibility-notify-event', self.visibility_state_event_cb)
- self.browser_win.connect('window-state-event', self.window_state_event_cb)
- self.browser_win.connect('configure-event', self.configure_event_cb)
- self.browser_win.connect('style-set', self.on_style_set)
-
- self.create_ui()
-
- self.browser_vbox = gtk.VBox()
- self.browser_win.add(self.browser_vbox)
- self.browser_vbox.show()
- self.browser_vbox.pack_start(self.menubar, expand=False)
- self.browser_vbox.pack_start(self.toolbar, expand=False)
- if self.toolbar_visible:
- self.toolbar.show()
- else:
- self.toolbar.hide()
- self.action_group.get_action('ToggleToolbar').set_active(self.toolbar_visible)
-
- self.browser_vpane = gtk.VPaned()
- self.browser_vpane.show()
- self.browser_vbox.pack_start(self.browser_vpane)
-
- self.statusbar = BrowserStatusBar()
-# self.statusbar.show_all()
- self.browser_vbox.pack_start(self.statusbar, expand=False)
-
- # alert detail
- self.alert_detail_scrolled_window = gtk.ScrolledWindow()
- self.alert_detail_scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.browser_vpane.add2(self.alert_detail_scrolled_window)
-
- view, doc = self.create_htmlview(self.alert_detail_scrolled_window)
- doc.connect("link-clicked", self.link_clicked)
- self.detail_doc = doc
- self.detail_view = view
- self.alert_detail_scrolled_window.show_all()
+ # TODO Does this need anything?
+ self.window_delete_hides = True
-
- self.popup_menu = self.ui.get_widget('/PopupMenu')
- self.button_press_event = SignalConnection('button_press_event')
- self.button_press_event.connect(self.detail_view, self.on_button_press_event)
-
- self.visit_radio_action.set_current_value(self.VISIT_AUDIT)
-
- def on_report_bug(self, action):
- bug_report_url = get_config('help', 'bug_report_url')
- # FIXME - Should be specific to the alert
- launch_web_browser_on_url(bug_report_url)
-
+ # This is to be filled with siginfos.
+ self.alert_list = []
+ self.do_not_notify_list = []
+
+ #set the glade filg
+ self.gladefile = GLADE_DIRECTORY + "browser.glade"
+ self.widget_tree = gtk.glade.XML(self.gladefile)
+
+ # Get widgets so we can work with them
+ self.main_window = self.widget("main_window")
+ self.close_button = self.widget("close_button")
+ self.next_button = self.widget("next_button")
+ self.previous_button = self.widget("previous_button")
+ self.alert_num_label = self.widget("alert_num_label")
+ self.expander = self.widget("expander1")
+ self.access_label = self.widget("access_label")
+ self.main_container = self.widget("main_container")
+ self.notify_check = self.widget("notify_check")
+ self.inner_frame = self.widget("inner_frame")
+ self.text_label = self.widget("text_label")
+ self.image = self.widget("image")
+ self.warning_label = self.widget("warning_label")
+ self.date_label = self.widget("date_label")
+ self.error_text = self.widget("error_text")
+ self.scrolledwindow1 = self.widget("scrolledwindow1")
+ self.main_window.connect("destroy", self.quit)
+ self.grant_button = self.widget("grant_button")
+ self.image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
+ # Make a gtkhtml view and doc and stick it in the scrolled window
+ self.detail_view, self.detail_doc = self.create_htmlview(self.scrolledwindow1)
+ self.detail_doc.connect("link-clicked", self.link_clicked)
+ self.scrolledwindow1.show_all()
+ self.bug_report_window = None
+ self.main_window.move(self.main_window.get_position()[0], 75)
+ self.bugzilla_username = ""
+ self.remember_me = False
+ # construct and connect the dictionary
+ dic = {"on_main_window_destroy" : self.quit,
+ "on_expander1_activate" : self.expander_activate,
+ "on_previous_button_clicked" : self.previous_button_clicked,
+ "on_next_button_clicked" : self.next_button_clicked,
+ "on_report_button_clicked" : self.report_button_clicked,
+ "on_grant_button_clicked" : self.grant_button_clicked,
+ "on_close_button_clicked" : self.quit}
+ self.widget_tree.signal_autoconnect(dic)
+ self.update_button_visibility()
+ self.load_data()
+ # gtk.main()
+
def link_clicked(self, doc, link):
launch_web_browser_on_url(link)
-
- # --- Utilities ---
-
- def mark_delete(self, database, siginfo, value=True):
- user_data = siginfo.get_user_data(self.username)
- user_data.delete_flag = value
- database.set_user_data(siginfo.sig, self.username, 'delete_flag', value)
-
-
- # --- View Management ---
-
- def show(self):
- self.browser_win.present()
-
- def hide(self):
- self.browser_win.hide()
-
- def update_window_state(self, state):
- if debug:
- log_gui.debug("set_window_state() %s:%s",
- state, window_state_to_string(state))
-
- if state & gtk.gdk.WINDOW_STATE_ICONIFIED:
- self.browser_win.iconify()
- else:
- self.browser_win.deiconify()
-
- if state & gtk.gdk.WINDOW_STATE_MAXIMIZED:
- self.browser_win.maximize()
- else:
- self.browser_win.unmaximize()
-
- if state & gtk.gdk.WINDOW_STATE_STICKY:
- self.browser_win.stick()
-
- if state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
- self.browser_win.fullscreen()
- else:
- self.browser_win.unfullscreen()
-
- if state & gtk.gdk.WINDOW_STATE_ABOVE:
- self.browser_win.set_keep_above(True)
- else:
- self.browser_win.set_keep_above(False)
-
- if state & gtk.gdk.WINDOW_STATE_BELOW:
- self.browser_win.set_keep_below(True)
- else:
- self.browser_win.set_keep_below(False)
-
- if state & gtk.gdk.WINDOW_STATE_WITHDRAWN:
- self.browser_win.hide()
- else:
- self.browser_win.show()
-
- def get_window_state(self):
- return window_state_to_string(self.window_state), visibility_state_to_string(self.visibility_state)
- def get_foreground_background_colors(self):
- style = self.browser_win.get_style()
- c = style.fg[gtk.STATE_NORMAL]
- foreground_color = "#%.2X%.2X%.2X" % (c.red / 256, c.green / 256, c.blue / 256)
-
- c = style.bg[gtk.STATE_NORMAL]
- background_color = "#%.2X%.2X%.2X" % (c.red / 256, c.green / 256, c.blue / 256)
-
- return foreground_color, background_color
-
def create_htmlview(self, container):
- view = gtkhtml2.View()
- doc = gtkhtml2.Document()
- container.set_hadjustment(view.get_hadjustment())
- container.set_vadjustment(view.get_vadjustment())
- view.set_document(doc)
- container.add(view)
-
- return (view, doc)
-
- def mark_seen(self, database, siginfo):
- if self.displayed_siginfo == siginfo:
- user_data = siginfo.get_user_data(self.username)
- user_data.seen_flag = True
- database.set_user_data(siginfo.sig, self.username, 'seen_flag', True)
-
- self.mark_seen_timeout_event_id = None
- return False # False ==> do not call again, True ==> call again
-
- def idle_update_alert_view(self):
- if debug:
- log_gui.debug("idle_update_alert_view")
- self.update_alert_view()
- self.update_alert_view_idle_event_id = None
-
- def update_alert_view(self):
- if self.list_view is None: return
- n_selected_paths = self.list_view.selection.count_selected_rows()
-
- if n_selected_paths != 1:
- if debug:
- log_gui.debug("update_alert_view: %d selected paths, not single selection, clearing alert view",
- n_selected_paths)
- self.clear_alert_view()
- return
+ view = gtkhtml2.View()
+ doc = gtkhtml2.Document()
+ view.set_document(doc)
+ container.add(view)
+ return (view, doc)
+
+ def set_prefs(self):
+ self.current_alert = 0
+ filename = PREF_PATH
+ if os.path.exists(filename):
+ file = open(filename, "r")
+ id = None
+ content = file.read()
+ pairs = content.split("\n")
+ for pair in pairs:
+ if pair.find("pos") >= 0:
+ id = pair.split("=")[1]
+ if pair.find("dontnotify") >= 0:
+ if len(pair.split("=")) == 2:
+ self.do_not_notify_list = pair.split("=")[1].split(",")
+ if pair.find("bugzilla_user") >= 0:
+ if len(pair.split("=")) == 2:
+ self.bugzilla_username = pair.split("=")[1]
+ else:
+ self.bugzilla_username = ""
+ file.close()
+ for sig in self.alert_list:
+ if sig.local_id == id:
+ self.current_alert = self.alert_list.index(sig)
+
+ def quit(self, widget):
+ if len(self.alert_list) != 0:
+ self.update_do_not_notify_list()
+ path = os.environ['HOME']
+ filename = PREF_PATH
+ file = open(filename, "w")
+ file.write("dontnotify=")
+ for id in self.do_not_notify_list:
+ file.write(id)
+ if self.do_not_notify_list.index(id) != len(self.do_not_notify_list) - 1:
+ file.write(",")
+ saved_id = ""
+ if len(self.alert_list) != 0:
+ saved_id = str(self.alert_list[self.current_alert].local_id)
+ file.write("\npos=" + saved_id)
+
+ if self.remember_me == True:
+ file.write("\nbugzilla_user=" + self.bugzilla_username)
+ file.close()
+ gtk.main_quit()
- siginfo = self.list_view.get_selected_siginfos()[0]
+ def update_alerts(self, database, type, item):
+ def new_siginfo_callback(sigs):
+ for siginfo in sigs.signature_list:
+ self.add_siginfo(siginfo)
+ self.update_num_label()
+ self.prune_alert_list()
+ self.show_current_alert()
+ if type == "add" or type == "modify":
+ async_rpc = self.database.query_alerts(item)
+ async_rpc.add_callback(new_siginfo_callback)
+
+ def check_do_not_notify(self, siginfo):
+ for id in self.do_not_notify_list:
+ if id == siginfo.local_id:
+ return False
+ return True
+
+ def prune_alert_list(self):
+ self.alert_list = filter(self.check_do_not_notify, self.alert_list)
+
+ def get_siginfo_from_localid(self, local_id):
+ for siginfo in self.alert_list:
+ if siginfo.local_id == local_id:
+ return siginfo
+ return None
+
+ def add_siginfo(self, new_sig):
+ curr_siginfo = self.get_siginfo_from_localid(new_sig.local_id)
+ if curr_siginfo is None:
+ self.alert_list.append(new_sig)
+ else:
+ self.alert_list.remove(curr_siginfo)
+ self.alert_list.append(new_sig)
+ self.alert_list.sort(compare_alert)
+
+
+ def report_button_clicked(self, widget):
+ # If we don't have a bug_report_window yet, make a new one
+ if self.bug_report_window is None:
+ br = BugReport(self, self.alert_list[self.current_alert], self.bugzilla_username)
+ self.bug_report_window = br
+ self.bug_report_window.main_window.show()
+
+ def grant_button_clicked(self, widget):
+ # Grant access here
+ # TODO
+ # Stop showing the current alert that we've just granted access to
+ self.delete_current_alert()
+
+ def delete_current_alert(self):
+ del self.alert_list[self.current_alert]
+ self.update_button_visibility()
+
+ # If there are no alerts left to review, exit
+ if len(self.alert_list) == 0:
+ gtk.main_quit()
+ else:
+ if self.current_alert > len(self.alert_list)-1:
+ self.current_alert = len(self.alert_list)-1
+ self.show_current_alert()
+
+
+ def show_current_alert(self):
+ self.update_button_visibility()
+ alert = self.alert_list[self.current_alert]
+ self.show_alert(alert)
+ if alert.fixable is True:
+ self.grant_button.set_sensitive(True)
+ else:
+ self.grant_button.set_sensitive(False)
+ if alert.level == "red":
+ self.warning_label.set_markup(_("Your system could be seriously compromised!"))
+ self.image.set_from_stock(gtk.STOCK_STOP, gtk.ICON_SIZE_DIALOG)
+ else:
+ self.warning_label.set_markup(_("SELinux has detected suspicious behavior on your system"))
+ self.image.set_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG)
+ def previous_button_clicked(self, widget):
+ if self.current_alert > 0:
+ self.update_do_not_notify_list()
+ self.current_alert -= 1
+ self.show_current_alert()
+ self.update_dnn_checkbox()
+
+ def update_do_not_notify_list(self):
+ curr_id = self.alert_list[self.current_alert].local_id
+ if self.notify_check.get_active() == True and self.do_not_notify_list.count(curr_id) == 0:
+ self.do_not_notify_list.append(curr_id)
+ elif self.notify_check.get_active() == False:
+ if self.do_not_notify_list.count(curr_id) > 0:
+ self.do_not_notify_list.remove(curr_id)
+
+ def update_dnn_checkbox(self):
+ self.notify_check.set_active(False)
+ curr_id = self.alert_list[self.current_alert].local_id
+ if self.do_not_notify_list.count(curr_id) > 0:
+ self.notify_check.set_active(True)
+
+ def next_button_clicked(self, widget):
+ if self.current_alert < len(self.alert_list)-1:
+ self.update_do_not_notify_list()
+ self.current_alert += 1
+ self.show_current_alert()
+ self.update_dnn_checkbox()
+
+ # Check and update the visibility of the next and previous buttons
+ # They should be hidden if there is only a single alert
+ def update_button_visibility(self):
+ if len(self.alert_list) == 1:
+ self.next_button.hide()
+ self.previous_button.hide()
+ if len(self.alert_list) > 1:
+ self.next_button.show()
+ self.previous_button.show()
+
+ def time_since_days(self, before, after):
+ time = after - before
+ if time.days == 0:
+ return "Today"
+ if time.days == 1:
+ return "Yesterday"
+ return "%d days ago" % time.days
+
+ def show(self):
+ self.main_window.present()
- if debug:
- log_gui.debug("update_alert_view: siginfo=%s", siginfo.local_id)
+ def hide(self):
+ self.main_window.hide()
+ # pass this a siginfo.
+ def show_alert(self, alert):
+ # Format the data that we get and display it in the appropriate places
+ date_format = "%a %b %e, %Y at %r %Z"
+ alert_date = alert.last_seen_date
+ start_date = alert.first_seen_date
+ self.time_since_days(start_date, alert_date)
+ num_of_times = _("s")
+ if alert.report_count == 1:
+ num_of_times = ""
+ date_text = _("%s on %s - %d time%s since %s") % (self.time_since_days(start_date, alert_date), alert_date.format(date_format), alert.report_count, num_of_times, start_date.format(date_format))
+ self.date_label.set_markup(date_text)
+ msg_text = _("SELinux denied access requested by %s. It is not expected that this access is required by %s and this access may signal an intrusion attempt. It is also possible that the specific version of configuration of the application is causing it to requre additional access.") % (alert.source, alert.source)
+
+ parts = alert.description_adjusted_for_permissive().split("\n")
+ parts = filter(lambda x:x!="", parts)
+ parts = map(lambda x: x.strip(), parts)
+ desc = ""
+ for x in parts:
+ desc += x
+ desc += " "
+ self.text_label.set_markup(desc)
+
+ parts = alert.solution.summary.split("\n")
+ parts = filter(lambda x:x!="", parts)
+ parts = map(lambda x: x.strip(), parts)
+ desc = ""
+ for x in parts:
+ desc += x
+ desc += " "
+ self.access_label.set_markup("%s" % desc)
self.detail_doc.clear()
self.detail_doc.open_stream("text/html")
- foreground_color, background_color = self.get_foreground_background_colors()
- html_body = siginfo.format_html(foreground_color, background_color)
+ html_body = alert.format_html()
html_doc = html_document(html_body)
-
- if debug:
- #log_gui.debug(html_doc)
- pass
-
self.detail_doc.write_stream(html_doc)
- self.detail_doc.close_stream()
-
- if self.displayed_siginfo != siginfo:
- # Displaying different alert than previously.
-
- # If we had a timeout pending from the previous alert then cancel it.
- if self.mark_seen_timeout_event_id is not None:
- gobject.source_remove(self.mark_seen_timeout_event_id)
- self.mark_seen_timeout_event_id = None
-
- # If this alert has not been seen start a timer to mark it seen
- user_data = siginfo.get_user_data(self.username)
- if not user_data.seen_flag:
- self.mark_seen_timeout_event_id = \
- gobject.timeout_add(1000*self.seen_after_displayed_seconds,
- self.mark_seen, self.list_view.alert_data.database, siginfo)
-
- self.displayed_siginfo = siginfo
-
- # --- Data/View Management ---
-
- def set_visit_data(self, name, view_data):
- self.view_data_collection[name] = view_data
-
- def get_visit_data(self, name):
- return self.view_data_collection.get(name)
-
- def clear_alert_view(self):
- self.detail_doc.clear()
- self.alert_detail_scrolled_window.queue_draw()
-
- def do_visit(self, name):
- if debug:
- log_gui.debug("do_visit: %s", name)
- visit_data = self.get_visit_data(name)
- self.set_view_data(visit_data)
-
- def set_view_data(self, view_data):
- if debug:
- log_gui.debug("set_view_data: %s", view_data.name)
-
- self.selection_changed_signal.disconnect()
-
- previous = self.browser_vpane.get_child1()
- if previous is not None:
- self.browser_vpane.remove(previous)
- self.list_view = view_data.list_view
- self.browser_vpane.add1(self.list_view.scrolled_window)
-
- self.properties_changed_signal.connect(self.list_view, self.on_view_data_properties_changed)
- self.load_data_signal.connect (self.list_view, self.on_load_data)
-
- self.alert_list_changed_signal.connect(self.list_view, self.on_alert_list_changed)
-
- self.action_group.get_action('HideDeleted').set_active(self.list_view.hide_deleted)
- self.action_group.get_action('HideQuiet').set_active(self.list_view.hide_quiet)
-
- # Column Visibility
- for column in range(1, NUM_COLUMNS):
- column_name = tv_column_info[column]['name']
- tv_column = self.list_view.tv_columns[column]
- self.action_group.get_action('Toggle%sColumn' % column_name).set_active(tv_column.get_visible())
-
- self.selection_changed_signal.connect(self.list_view.selection, self.on_selection_changed)
- self.update_alert_view()
- self.update_alert_count()
- self.update_visit_message(view_data.alert_data.database_properties.friendly_name)
-
- def update_visit_message(self, name):
- if name is None:
- self.statusbar.set_visit_message(_('None'))
- else:
- self.statusbar.set_visit_message(name)
-
- def update_alert_count(self):
- if self.list_view is None or self.list_view.view_model is None:
- text = '--/--'
- else:
- text = '%d/%d' % (len(self.list_view.base_model), len(self.list_view.view_model))
- self.statusbar.alert_count.set_text(text)
-
- # --- Selections ---
-
- def idle_restore_selection(self):
- if self.list_view is None: return
- self.list_view.restore_selection()
- self.restore_selection_idle_event_id = None
-
- def on_selection_changed(self, selection):
- if self.list_view is None: return
- model, selected_paths = selection.get_selected_rows()
- if debug:
- log_gui.debug("on_selection_changed(): paths=%s", ','.join([str(row) for row in selected_paths]))
-
- if len(selected_paths) > 0:
- self.list_view.last_selected_row = selected_paths[0]
- else:
- self.list_view.last_selected_row = 0
-
- if get_config('fix_cmd','run_fix_cmd_enable', bool):
- if len(selected_paths) != 1:
- self.action_group.get_action('RunFixCmd').set_sensitive(False)
- else:
- siginfo = self.list_view.get_selected_siginfos()[0]
- if siginfo.solution.fix_cmd:
- self.action_group.get_action('RunFixCmd').set_sensitive(True)
- else:
- self.action_group.get_action('RunFixCmd').set_sensitive(False)
- else:
- self.action_group.get_action('RunFixCmd').set_sensitive(False)
-
-
- if self.update_alert_view_idle_event_id is None:
- self.update_alert_view_idle_event_id = gobject.idle_add(self.idle_update_alert_view)
-
- # --- Data Handling ---
-
- def on_alert_list_changed(self, alert_list, model, type, iter):
- if debug:
- log_gui_data.debug("on_alert_list_changed: %s", type)
- if type == 'add':
- self.update_alert_count()
- elif type == 'delete':
- self.update_alert_count()
- elif type == 'modify':
- # If the row which changed is what is currently being displayed
- # in the alert detail window then update the alert view.
-
- siginfo = model.get_value(iter, PYOBJECT_COLUMN)
- if self.displayed_siginfo is None or self.displayed_siginfo.local_id == siginfo.local_id:
- self.update_alert_view()
- else:
- raise ProgramError(ERR_UNKNOWN_VALUE, "on_alert_list_changed: type = %s not recognized" % type)
-
-
- def on_view_data_properties_changed(self, list_view, alert_data, properties):
- if debug:
- log_gui.debug("on_view_data_properties_changed: %s %s", alert_data.name, properties)
- self.update_visit_message(properties.friendly_name)
-
-
- def progress_pulse(self):
- if self.load_in_progress:
- self.statusbar.progress.pulse()
- return True # call again
- else:
- return False # do not call again
-
- def on_load_data(self, list_view, alert_data, state, errno, strerror):
- if debug:
- log_gui.debug('on_load_data: alert_data=%s state=%s errno=%d strerror=%s',
- alert_data.name, state, errno, strerror)
- if state == 'start':
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('loading data ...'), message_name='load_data')
- self.load_in_progress = True
- self.statusbar.progress.pulse()
- gobject.timeout_add(100, self.progress_pulse)
- self.statusbar.progress.set_text(_("Load %s" % alert_data.name))
- elif state == 'end':
- self.load_in_progress = False
- if self.list_view is not None: self.list_view.restore_selection()
- self.statusbar.progress.set_text("")
- self.statusbar.progress.set_fraction(0)
- if errno == 0:
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('loading data done'), 15, message_name='load_data')
- else:
- self.statusbar.status.remove_message_by_name('load_data')
- self.statusbar.error.new_message(StatusMessage.ERROR_TYPE, StatusMessage.MEDIUM_PRIORITY, _("load data failed: %s") % (strerror), 15, message_name='load_data')
-
- self.update_alert_count()
-
- def save_siginfos(self, file, siginfos):
- text = ''
- try:
- fd=open(file, "w")
- except IOError, e:
- raise ProgramError(ERR_FILE_OPEN, detail="%s, %s" % (filepath, e.strerror))
-
- i = 0
- for siginfo in siginfos:
- text += siginfo.format_text()
- i += 1
- if i < len(siginfos):
- text += "\f\n" # break between multiple siginfo's
-
- fd.write(text)
- fd.close()
-
- # --- Event Handlers ---
-
- def on_button_press_event(self, treeview, event):
- if debug:
- log_gui.debug("on_button_press_event(): button=%s", event.button)
- if event.button == 3:
- self.popup_menu.popup( None, None, None, event.button, event.time)
- return True
-
- def on_copy(self, action):
- text = gtkhtml2.html_selection_get_text(self.detail_view)
-
- if debug:
- log_gui.debug("on_copy(): text=%s", text)
-
- if text is not None:
- self.clipboard.set_text(text)
- return True # return True ==> handled, False ==> propagate
-
- def on_copy_alert(self, action):
- if self.list_view is None: return
- text = ''
- siginfos = self.list_view.get_selected_siginfos()
- i = 0
- for siginfo in siginfos:
- text += siginfo.format_text()
- i += 1
- if i < len(siginfos):
- text += "\n" # break between multiple siginfo's
- self.clipboard.set_text(text)
- return True # return True ==> handled, False ==> propagate
-
-
- def on_close(self, *args):
- if self.window_delete_hides:
- self.hide()
- return True
- else:
- gtk.main_quit()
- return True # return True ==> handled, False ==> propagate
-
- def on_connection_pending_retry(self, retry, seconds_pending, alert_client):
- if seconds_pending <= 0.005:
- self.statusbar.set_connected_state(False)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('retrying connection'), message_name='pending_retry')
- else:
- minutes = int(seconds_pending) / 60
- seconds = seconds_pending % 60
- if minutes:
- pending = _("%d minutes %.1f seconds") % (minutes, seconds)
- else:
- pending = _("%.0f seconds") % (seconds)
- self.statusbar.set_connected_state(False)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('retrying connection in %s' % pending), message_name='pending_retry')
-
-
- def on_user_help(self, action):
- help_url = get_config('help','help_url')
- launch_web_browser_on_url(help_url)
-
- def on_about(self, action):
- pkg_name = get_config('general', 'pkg_name')
- pkg_version = get_config('general', 'pkg_version')
- project_url = get_config('general', 'project_url')
-
- def email_clicked(dialog, addr, user_data=None):
- launch_web_browser_on_url('mailto:' + addr)
-
- def link_clicked(dialog, url, user_data=None):
- launch_web_browser_on_url(url)
-
- gtk.about_dialog_set_email_hook(email_clicked)
- gtk.about_dialog_set_url_hook(link_clicked)
-
- dlg = gtk.AboutDialog()
- dlg.set_name(pkg_name)
- dlg.set_version(pkg_version)
- dlg.set_copyright(_("Copyright 2006-2008 Red Hat, Inc."))
- dlg.set_comments(_("A user friendly tool to diagnose and monitor SELinux AVC denials"))
- dlg.set_license("GPL v2")
- dlg.set_website(project_url)
- dlg.set_authors(["John Dennis ",
- "Daniel Walsh ",
- "Karl MacMillon "])
-
- icon_name = get_config('general','icon_name')
- dlg.set_logo_icon_name(icon_name)
-
-
- dlg.run()
- dlg.destroy()
-
- def on_save_as(self, action):
- dialog = gtk.FileChooserDialog(_("Save.."),
- None,
- gtk.FILE_CHOOSER_ACTION_SAVE,
- (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_SAVE, gtk.RESPONSE_OK))
- dialog.set_default_response(gtk.RESPONSE_OK)
-
- if self.default_save_folder is not None:
- dialog.set_current_folder(self.default_save_folder)
- if self.default_save_filename is not None:
- dialog.set_current_name(self.default_save_filename)
-
- filter = gtk.FileFilter()
- filter.set_name("All files")
- filter.add_pattern("*")
- dialog.add_filter(filter)
-
- response = dialog.run()
- if response == gtk.RESPONSE_OK:
- self.default_save_folder = dialog.get_current_folder()
- self.default_save_filename = os.path.basename(dialog.get_filename())
- try:
- if self.list_view is not None:
- self.save_siginfos(dialog.get_filename(),
- self.list_view.get_selected_siginfos())
- except ProgramError, e:
- self.display_error(e.strerror)
-
- dialog.destroy()
-
- def on_connect_to(self, action):
- connection = None
- dlg = OpenConnectionDialog()
- response = dlg.run()
- if response == gtk.RESPONSE_OK:
- connection = dlg.get_connection()
- dlg.destroy()
- if debug:
- log_communication.debug("on_connect_to: %s", connection)
-
- # FIXME: we need a more centralized way to handle retry's
-
- self.statusbar.status.remove_message_by_name('pending_retry')
- self.server.retry_connection_if_closed = False
- if self.server.connection_state.flags & ConnectionState.RETRY:
- self.server.connection_retry.stop()
- self.server.connection_state.update(0, ConnectionState.RETRY)
- self.server.close_connection()
- if connection is None:
- self.statusbar.error.remove_all_messages()
- else:
- self.server.retry_connection_if_closed = False
- self.server.open(connection)
- else:
- dlg.destroy()
-
-
- def on_open_logfile(self, action):
- dlg = ScanLogfileDialog()
- response = dlg.run()
- if response == gtk.RESPONSE_OK:
- database = dlg.get_database()
- database_rpc = SETroubleshootDatabaseLocal(database)
- alert_data = AlertData('logfile', database_rpc)
-
- # FIXME: Is there a better way to populate the model?
- for siginfo in database.sigs.signature_list:
- alert_data.signatures_updated(database_rpc, 'add', siginfo.local_id)
-
- self.logfile_view_data.bind_data(alert_data)
-
- self.action_group.get_action('ViewLogfile').set_sensitive(True)
- self.visit_radio_action.set_current_value(self.VISIT_LOGFILE)
- if self.restore_selection_idle_event_id is None:
- self.restore_selection_idle_event_id = gobject.idle_add(self.idle_restore_selection)
-
- dlg.destroy()
-
- def on_edit_email_alert_list(self, action):
- def query_email_recipients_callback(recipients):
- if debug:
- log_gui.debug("query_email_recipients_callback: %s", recipients)
-
- dlg = EmailDialog(recipients, parent=self.browser_win)
- new_recipients = dlg.run()
- if debug:
- log_gui.debug("EmailDialog returned: %s", str(new_recipients))
-
- if new_recipients is not None:
- self.server.set_email_recipients(new_recipients)
-
- async_rpc = self.server.query_email_recipients()
- async_rpc.add_callback(query_email_recipients_callback)
-
- def on_print(self, action):
-
- def draw_page(operation, context, page_number, siginfos):
- try:
- siginfo = siginfos[page_number]
- except IndexError:
- return
- text = siginfo.format_text()
-
- cr = context.get_cairo_context()
- layout = context.create_pango_layout()
- layout.set_font_description(pango.FontDescription('monospace 10'))
- layout.set_text(text)
- cr.show_layout(layout)
-
- if self.list_view is not None:
- siginfos = self.list_view.get_selected_siginfos()
- else:
- siginfos = []
-
- dialog = gtk.PrintOperation()
- if self.print_settings != None:
- dialog.set_print_settings(self.print_settings)
- dialog.connect("draw_page", draw_page, siginfos)
- dialog.set_n_pages(len(siginfos))
-
- res = dialog.run(gtk.PRINT_OPERATION_ACTION_PRINT_DIALOG)
- if res == gtk.PRINT_OPERATION_RESULT_ERROR:
- error_dialog = gtk.MessageDialog(self.browser_win, gtk.DIALOG_DESTROY_WITH_PARENT,
- gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE,
- "Error printing file:\n")
- error_dialog.connect("response", lambda w,id: w.destroy())
- error_dialog.show()
- elif res == gtk.PRINT_OPERATION_RESULT_APPLY:
- self.print_settings = dialog.get_print_settings()
- return True # return True ==> handled, False ==> propagate
-
- def on_hide_deleted(self, action):
- if self.list_view is None: return
- self.list_view.hide_deleted = action.get_active()
- if debug:
- log_gui.debug("on_hide_deleted() hide_deleted=%s", self.list_view.hide_deleted)
- if self.list_view.filter_model is not None:
- self.list_view.filter_model.refilter()
-
- def on_hide_quiet(self, action):
- if self.list_view is None: return
- self.list_view.hide_quiet = action.get_active()
- if debug:
- log_gui.debug("on_hide_quiet() hide_quiet=%s", self.list_view.hide_quiet)
- if self.list_view.filter_model is not None:
- self.list_view.filter_model.refilter()
-
- def on_visit_change(self, action, current):
- visit_name = self.map_visit_num_to_name[action.get_current_value()]
- if debug:
- log_gui.debug("on_visit_change: %s", visit_name)
- self.do_visit(visit_name)
-
- def on_delete(self, action):
- if self.list_view is None: return
- database = self.list_view.alert_data.database
- for siginfo in self.list_view.get_selected_siginfos():
- self.mark_delete(database, siginfo, True)
- return True # return True ==> handled, False ==> propagate
-
- def on_expunge(self, action):
- if self.list_view is None: return
- if self.list_view.alert_data is None: return
-
- database = self.list_view.alert_data.database
- for siginfo in self.list_view.alert_data.get_siginfos():
- user_data = siginfo.get_user_data(self.username)
- if user_data.delete_flag:
- database.delete_signature(siginfo.sig)
-
- def on_undelete(self, action):
- if self.list_view is None: return
- database = self.list_view.alert_data.database
- for siginfo in self.list_view.get_selected_siginfos():
- self.mark_delete(database, siginfo, False)
- return True # return True ==> handled, False ==> propagate
-
- def on_select_all(self, action):
- if self.list_view is None: return
- self.list_view.selection.select_all()
- return True # return True ==> handled, False ==> propagate
-
- def on_select_none(self, action):
- if self.list_view is None: return
- self.list_view.selection.unselect_all()
- return True # return True ==> handled, False ==> propagate
-
- def on_run_fix_cmd(self, action):
- if debug:
- log_gui.debug("on_run_fix_cmd()")
- siginfos = self.list_view.get_selected_siginfos()
- if len(siginfos) == 1:
- siginfo = siginfos[0]
- fix_cmd = siginfo.solution.fix_cmd
- siginfo_host = siginfo.host
- this_host = get_hostname()
- if this_host == siginfo_host:
- cmd = 'sudo %s' % (fix_cmd)
- else:
- cmd = 'ssh root@%s %s' % (siginfo_host, fix_cmd)
- if debug:
- log_gui.debug("cmd=%s siginfo_host=%s this_host=%s", cmd, siginfo_host, this_host)
-
- dlg = RunCmdGUI(cmd)
- rc = dlg.dlg.run()
- dlg.dlg.destroy()
-
- def on_toggle_toolbar(self, action):
- self.toolbar_visible = action.get_active()
- if debug:
- log_gui.debug("toggle_toolbar: %s", ('hide', 'show')[self.toolbar_visible])
- if self.toolbar_visible:
- self.toolbar.show()
- else:
- self.toolbar.hide()
-
- def on_toggle_column_visibility(self, action, column):
- if self.list_view is None: return
- tv_column = self.list_view.tv_columns[column]
- is_active = action.get_active()
- is_visible = tv_column.get_visible()
- if debug:
- log_gui.debug("toggle_column_visibility(%s): should be active=%s, currently is visible=%s",
- tv_column.get_title(), is_active, is_visible)
- tv_column.set_visible(is_active)
-
- # --- Interaction Dialogs ---
-
- def display_error(self, message):
- self.statusbar.error.new_message(StatusMessage.ERROR_TYPE, StatusMessage.MEDIUM_PRIORITY, message, 15)
- return display_error(message)
+ self.detail_doc.close_stream()
+ self.update_num_label()
- # --- Status Notification ---
-
- def on_async_error(self, alert_data, method, errno, strerror):
- message_name = None
- time_to_live = 15
- if errno in [ERR_USER_PROHIBITED, ERR_NOT_AUTHENTICATED]:
- message_name ='not_authenticated'
- time_to_live = None
- self.statusbar.error.new_message(StatusMessage.ERROR_TYPE, StatusMessage.MEDIUM_PRIORITY, strerror, time_to_live, message_name)
-
-
- def update_connection_state(self, connection, connection_state):
- if debug:
- log_gui.debug("update_connection_state: state=%s", connection_state)
-
- if connection_state.flags & ConnectionState.OPEN:
- self.statusbar.set_connected_state(True)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('connected'), 15, message_name='connection_state')
- self.statusbar.error.remove_all_messages()
-
- if not (connection_state.flags & ConnectionState.AUTHENTICATED):
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('open but not logged on'), 15, message_name='connection_state')
- else:
- self.statusbar.set_connected_state(False)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('connection closed'), 15, message_name='connection_state')
-
- if connection_state.flags & ConnectionState.ERROR:
- self.statusbar.set_connected_state(False)
- errno, strerror = connection_state.get_result()
- self.statusbar.error.new_message(StatusMessage.ERROR_TYPE, StatusMessage.HIGH_PRIORITY, _('connection failed at %s, %s') % (connection.socket_address.get_friendly_name(), strerror), message_name='connection_state')
-
- if connection_state.flags & ConnectionState.HUP:
- self.statusbar.set_connected_state(False)
- self.statusbar.error.new_message(StatusMessage.ERROR_TYPE, StatusMessage.HIGH_PRIORITY, _('connection lost to %s') % (connection.socket_address.get_friendly_name()), message_name='connection_state')
-
- if connection_state.flags & ConnectionState.TIMEOUT:
- self.statusbar.set_connected_state(False)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('connection timed out'), 15, message_name='connection_state')
-
- if not (connection_state.flags & ConnectionState.RETRY):
- self.statusbar.status.remove_message_by_name('pending_retry')
-
- def on_connection_state_change(self, connection, connection_state, flags, flags_added, flags_removed):
- if debug:
- log_program.debug("%s.on_connection_state_change: connection_state=%s flags_added=%s flags_removed=%s address=%s",
- self.__class__.__name__, connection_state,
- connection_state.flags_to_string(flags_added), connection_state.flags_to_string(flags_removed),
- connection.socket_address)
-
- if flags_removed & ConnectionState.OPEN:
- self.audit_data.clear()
- self.audit_data.set_properties(None)
- self.statusbar.set_connected_state(False)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('connection closed'), 15, message_name='connection_state')
-
- if flags_added & ConnectionState.OPEN:
- self.statusbar.set_connected_state(True)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('connected'), 15, message_name='connection_state')
- self.statusbar.error.remove_all_messages()
-
- if flags_added & ConnectionState.AUTHENTICATED:
- self.audit_data.clear()
- self.audit_data.load_data()
- self.statusbar.set_connected_state(True)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('authenticated'), 15, message_name='connection_state')
-
- if flags_added & ConnectionState.TIMEOUT:
- self.statusbar.set_connected_state(True)
- self.statusbar.status.new_message(StatusMessage.INFO_TYPE, StatusMessage.MEDIUM_PRIORITY, _('connection timed out'), 15, message_name='connection_state')
-
- if flags_added & ConnectionState.HUP:
- self.statusbar.set_connected_state(False)
- self.statusbar.error.new_message(StatusMessage.ERROR_TYPE, StatusMessage.HIGH_PRIORITY, _('connection lost to %s)') % (connection.socket_address.get_friendly_name()), message_name='connection_state')
-
- if flags_added & (ConnectionState.ERROR):
- errno, strerror = connection_state.get_result()
- self.statusbar.set_connected_state(False)
- self.statusbar.error.new_message(StatusMessage.ERROR_TYPE, StatusMessage.HIGH_PRIORITY, _('connection failed at %s, %s') % (connection.socket_address.get_friendly_name(), strerror), message_name='connection_state')
-
-
- if flags_removed & ConnectionState.RETRY:
- self.statusbar.status.remove_message_by_name('pending_retry')
-
-#------------------------------------------------------------------------------
-
-class OpenConnectionDialog(gtk.Dialog):
- def __init__(self):
- gtk.Dialog.__init__(self, title=_('Open Connection'),
- buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_OK, gtk.RESPONSE_OK))
-
- self.connection_choice = None
-
- table = gtk.Table(3, 2)
-
- self.vbox.pack_start(table)
-
- self.disconnect_radiobutton = gtk.RadioButton(None, _('No Connection'))
- self.disconnect_radiobutton.connect('toggled', self.on_connection_choice_changed, 'disconnect')
- table.attach(self.disconnect_radiobutton, left_attach=0, right_attach=1, top_attach=0, bottom_attach=1)
- radiobutton_group = self.disconnect_radiobutton
-
- self.local_radiobutton = gtk.RadioButton(radiobutton_group, _('Local Server'))
- self.local_radiobutton.connect('toggled', self.on_connection_choice_changed, 'local')
- table.attach(self.local_radiobutton, left_attach=0, right_attach=1, top_attach=1, bottom_attach=2)
-
- self.remote_radiobutton = gtk.RadioButton(radiobutton_group, _('Remote Server'))
- self.remote_radiobutton.connect('toggled', self.on_connection_choice_changed, 'remote')
- table.attach(self.remote_radiobutton, left_attach=0, right_attach=1, top_attach=2, bottom_attach=3)
-
- self.remote_addr_entry = gtk.Entry()
- self.remote_addr_entry.connect('activate', self.on_remote_addr_activate)
- self.remote_addr_entry.set_sensitive(False)
- table.attach(self.remote_addr_entry, left_attach=1, right_attach=2, top_attach=2, bottom_attach=3)
-
- self.on_connection_choice_changed(radiobutton_group, 'local')
-
- self.vbox.show_all()
- self.local_radiobutton.set_active(True)
-
- def on_connection_choice_changed(self, radiobutton, choice):
- if radiobutton.get_active():
- self.connection_choice = choice
- log_gui.debug("on_connection_choice_changed: %s", self.connection_choice)
-
- if self.connection_choice == 'remote':
- self.remote_addr_entry.set_sensitive(True)
- else:
- self.remote_addr_entry.set_sensitive(False)
-
-
- def on_remote_addr_activate(self, widget):
- self.emit('response', gtk.RESPONSE_OK)
-
- def get_connection_choice(self):
- group = self.local_radiobutton.get_group()
- for radiobutton in group:
- if radiobutton.get_active():
- return radiobutton
- return None
-
- def get_connection(self):
- server_address = None
- cfg_section = 'client_connect_to'
-
- if self.connection_choice == 'local':
- server_address = get_local_server_socket_address()
- elif self.connection_choice == 'remote':
- remote_addr = self.remote_addr_entry.get_text().strip()
- server_address = SocketAddress('inet', remote_addr)
- elif self.connection_choice == 'disconnect':
- return None
+ def update_num_label(self):
+ self.alert_num_label.set_markup(_("Alert %d of %d") % (self.current_alert+1, len(self.alert_list)))
- return server_address
+ # When you activate the expander, we need to resize the frame that displays data
+ # and also the size of the window. We also need to move some widgets.
+ def expander_activate(self, widget):
+ if self.expander.get_expanded() == True:
+ self.main_window.set_size_request(self.main_window.get_size()[0], 460)
+ self.scrolledwindow1.hide()
+ elif self.expander.get_expanded() == False:
+ self.main_window.set_size_request(self.main_window.get_size()[0], 685)
+ self.scrolledwindow1.show()
+ def widget(self, name):
+ return self.widget_tree.get_widget(name)
+
+ def load_data(self):
+ if self.database is not None:
+ criteria = "*"
+ async_rpc = self.database.query_alerts(criteria)
+ async_rpc.add_callback(self.first_load)
+ async_rpc.add_errback(self.database_error)
-#-----------------------------------------------------------------------------
-
-# -- Main --
-
-if __name__ == "__main__":
- import getopt
-
- def usage():
- print '''
- -h help
-'''
-
- try:
- opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
- except getopt.GetoptError:
- # print help information and exit:
- usage()
- sys.exit(2)
+ def first_load(self, sigs):
+ for sig in sigs.siginfos():
+ self.alert_list.append(sig)
+ self.set_prefs()
+ self.prune_alert_list()
+ self.set_prefs()
+ self.show_current_alert()
+
+ # TODO
+ def database_error(self, method, errno, strerror):
+ pass
- for o, a in opts:
- if o in ("-h", "--help"):
- usage()
- sys.exit()
+def compare_alert(a, b):
+ return cmp(a.last_seen_date, b.last_seen_date)
- browser_applet = BrowserApplet()
- browser_applet.show()
- gtk.main()
diff -up setroubleshoot-2.1.12/src/filer.py.guiredesign setroubleshoot-2.1.12/src/filer.py
--- setroubleshoot-2.1.12/src/filer.py.guiredesign 2009-06-10 09:50:58.616309307 -0400
+++ setroubleshoot-2.1.12/src/filer.py 2009-06-10 09:50:58.616309307 -0400
@@ -0,0 +1,452 @@
+# Copyright (C) 2008 Red Hat, Inc.
+# All rights reserved.
+#
+# 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, see .
+#
+# Author(s): Chris Lumens
+#
+import xmlrpclib
+import socket
+
+class LoginError(Exception):
+ """An error occurred while logging into the bug reporting system."""
+ def __init__(self, bugUrl, username):
+ self.bugUrl = bugUrl
+ self.username = username
+
+ def __str__(self):
+ return "Could not login to %s with username %s" % (self.bugUrl, self.username)
+
+class CommunicationError(Exception):
+ """Some miscellaneous error occurred while communicating with the
+ bug reporting system. This could include XML-RPC errors, passing
+ bad data, or network problems."""
+ def __init__(self, msg):
+ self.msg = msg
+
+ def __str__(self):
+ return "Error communicating with bug system: %s" % self.msg
+
+
+# These classes don't do anything except say that automated bug filing are not
+# supported. They also define the interface that concrete classes should use,
+# as this is what will be expected by exception.py.
+class AbstractFiler(object):
+ """The base class for Filer objects. This is an abstract class.
+
+ Within this class's help, Bug refers to a concrete AbstractBug subclass
+ and Filer refers to a concrete AbstractFiler subclass.
+
+ A Filer object communicates with a bug filing system - like bugzilla -
+ that a distribution uses to track defects. Install classes specify
+ what bug filing system they use by instantiating a subclass of
+ AbstractFiler. The intention is that each subclass of AbstractFiler
+ will make use of some system library to handle the actual communication
+ with the bug filing system. For now, all systems will be assumed to act
+ like bugzilla.
+
+ Methods in this class should raise the following exceptions:
+
+ CommunicationError -- For all problems communicating with the remote
+ bug filing system.
+ LoginError -- For invalid login information.
+ ValueError -- For all other operations where the client
+ supplied values are not correct.
+ """
+ def __init__(self, bugUrl=None, develVersion=None, defaultProduct=None):
+ """Create a new AbstractFiler instance. This method need not be
+ overridden by subclasses.
+
+ bugUrl -- The URL of the bug filing system.
+ develVersion -- What version of the product should be treated as
+ the development version. This is used in case
+ anaconda attempts to file bugs against invalid
+ versions. It need not be set.
+ defaultProduct -- The product bugs should be filed against, should
+ anaconda get an invalid product name from the
+ boot media. This must be set.
+ """
+ self.bugUrl = bugUrl
+ self.develVersion = develVersion
+ self.defaultProduct = defaultProduct
+
+ def login(self, username, password):
+ """Using the given username and password, attempt to login to the
+ bug filing system. This method must be provided by all subclasses,
+ and should raise LoginError if login is unsuccessful.
+ """
+ raise NotImplementedError
+
+ def createbug(self, *args, **kwargs):
+ """Create a new bug. The kwargs dictionary is all the arguments that
+ should be used when creating the new bug and is entirely up to the
+ subclass to handle. This method must be provided by all subclasses.
+ On success, it should return a Bug instance.
+ """
+ raise NotImplementedError
+
+ def getbug(self, id):
+ """Search for a bug given by id and return it. This method must be
+ provided by all subclasses. On success, it should return a Bug
+ instance. On error, it should return an instance that is empty.
+ """
+ raise NotImplementedError
+
+ def getbugs(self, idlist):
+ """Search for all the bugs given by the IDs in idlist and return.
+ This method must be provided by all subclasses. On success, it
+ should return a list of Bug instances, or an empty instance for
+ invalid IDs.
+ """
+ raise NotImplementedError
+
+ def getproduct(self, prod):
+ """Verify that prod is a valid product name. If it is, return that
+ same product name. If not, return self.defaultProduct. This method
+ queries the bug filing system for a list of valid products. It must
+ be provided by all subclasses.
+ """
+ raise NotImplementedError
+
+ def getversion(self, ver, prod):
+ """Verify that ver is a valid version number for the product name prod.
+ If it is, return that same version number. If not, return
+ self.develVersion if it exists or the latest version number
+ otherwise. This method queries the bug filing system for a list of
+ valid versions numbers. It must be provided by all subclasses.
+ """
+ raise NotImplementedError
+
+ def query(self, query):
+ """Perform the provided query and return a list of Bug instances that
+ meet the query. What the query is depends on the exact bug filing
+ system, though anaconda will treat it as a dictionary of bug
+ attibutes since this is what bugzilla expects. Other filing systems
+ will need to take extra work to munge this data into the expected
+ format. This method must be provided by all subclasses.
+ """
+ raise NotImplementedError
+
+ def supportsFiling(self):
+ """Does this class support filing bugs? All subclasses should override
+ this method and return True, or automatic filing will not work. The
+ base install class will use this method, so automatic filing will
+ not be attempted by anaconda on unknown products.
+ """
+ return False
+
+class AbstractBug(object):
+ """The base class for Bug objects. This is an abstract class.
+
+ Within this class's help, Bug refers to a concrete AbstractBug subclass
+ and Filer refers to a concrete AbstractFiler subclass.
+
+ A Bug object represents one single bug within a Filer. This is where
+ most of the interesting stuff happens - attaching files, adding comments
+ and email addresses, and modifying whiteboards. Subclasses of this
+ class are returned by most operations within a Filer subclass. For now,
+ all bugs will be assumed to act like bugzilla's bugs.
+
+ Bug objects wrap objects in the underlying module that communicates with
+ the bug filing system. For example, the bugzilla filer uses the
+ python-bugzilla module to communicate. This module has its own Bug
+ object. So, BugzillaBug wraps that object. Therefore, Bugs may be
+ created out of existing BugzillaBugs or may create their own if
+ necessary.
+
+ Methods in this class should raise the following exceptions:
+
+ CommunicationError -- For all problems communicating with the remote
+ bug filing system.
+ ValueError -- For all other operations where the client
+ supplied values are not correct (invalid
+ resolution, status, whiteboard, etc.).
+ """
+ def __init__(self, filer, bug=None, *args, **kwargs):
+ """Create a new Bug instance. It is recommended that subclasses
+ override this method to add extra attributes.
+
+ filer -- A reference to a Filer object used when performing
+ certain operations. This may be None if it is not
+ required by the Filer or Bug objects.
+ bug -- If None, the filer-specific code should create a new
+ bug object. Otherwise, the filer-specific code
+ should use the provided object as needed.
+ args, kwargs -- If provided, these arguments should be passed as-is
+ when creating a new underlying bug object. This
+ only makes sense if bug is not None.
+ """
+ self.filer = filer
+
+ def __str__(self):
+ raise NotImplementedError
+
+ def __repr__(self):
+ raise NotImplementedError
+
+ def addCC(self, address):
+ """Add the provided email address to this bug. This method must be
+ provided by all subclasses, and return some non-None value on
+ success.
+ """
+ raise NotImplementedError
+
+ def addcomment(self, comment):
+ """Add the provided comment to this bug. This method must be provided
+ by all subclasses, and return some non-None value on success.
+ """
+ raise NotImplementedError
+
+ def attachfile(self, file, description, **kwargs):
+ """Attach the filename given by file, with the given description, to
+ this bug. If provided, the given kwargs will be passed along to
+ the Filer when attaching the file. These args may be useful for
+ doing things like setting the MIME type of the file. This method
+ must be provided by all subclasses and return some non-None value
+ on success.
+ """
+ raise NotImplementedError
+
+ def close(self, resolution, dupeid=0, comment=''):
+ """Close this bug with the given resolution, optionally closing it
+ as a duplicate of the provided dupeid and with the optional comment.
+ resolution must be a value accepted by the Filer. This method must
+ be provided by all subclasses and return some non-None value on
+ success.
+ """
+ raise NotImplementedError
+
+ def id(self):
+ """Return this bug's ID number. This method must be provided by all
+ subclasses.
+ """
+ raise NotImplementedError
+
+ def setstatus(self, status, comment=''):
+ """Set this bug's status and optionally add a comment. status must be
+ a value accepted by the Filer. This method must be provided by all
+ subclasses and return some non-None value on success.
+ """
+ raise NotImplementedError
+
+ def setassignee(self, assigned_to='', reporter='', comment=''):
+ """Assign this bug to the person given by assigned_to, optionally
+ changing the reporter and attaching a comment. assigned_to must be
+ a valid account in the Filer. This method must be provided by all
+ subclasses and return some non-None value on success.
+ """
+ raise NotImplementedError
+
+ def getwhiteboard(self, which=''):
+ """Get the given whiteboard from this bug and return it. Not all bug
+ filing systems support the concept of whiteboards, so this method
+ is optional. Currently, anaconda does not call it.
+ """
+ return ""
+
+ def appendwhiteboard(self, text, which=''):
+ """Append the given text to the given whiteboard. Not all bug filing
+ systems support the concept of whiteboards, so this method is
+ optional. If provided, it should return some non-None value on
+ success. Currently, anaconda does not call this method.
+ """
+ return True
+
+ def prependwhiteboard(self, text, which=''):
+ """Put the given text at the front of the given whiteboard. Not all
+ bug filing systems support the concept of whiteboards, so this
+ method is optional. If provided, it should return some non-None
+ value on success. Currently, anaconda does not call this method.
+ """
+ return True
+
+ def setwhiteboard(self, text, which=''):
+ """Set the given whiteboard to be the given text. Not all bug filing
+ systems support the concept of whiteboards, so this method is
+ optional. If provided, it should return some non-None value on
+ success. Currently, anaconda does not call this method.
+ """
+ return True
+
+
+# Concrete classes for automatically filing bugs against Bugzilla instances.
+# This requires the python-bugzilla module to do almost all of the real work.
+# We basically just make some really thin wrappers around it here since we
+# expect all bug filing systems to act similar to bugzilla.
+class BugzillaFiler(AbstractFiler):
+ def __withBugzillaDo(self, fn):
+ try:
+ retval = fn(self._bz)
+ return retval
+ except xmlrpclib.ProtocolError, e:
+ raise CommunicationError(str(e))
+ except xmlrpclib.Fault, e:
+ raise ValueError(str(e))
+ except socket.error, e:
+ raise CommunicationError(str(e))
+
+ def __init__(self, bugUrl=None, develVersion=None, defaultProduct=None):
+ AbstractFiler.__init__(self, bugUrl=bugUrl, develVersion=develVersion,
+ defaultProduct=defaultProduct)
+ self._bz = None
+
+ def login(self, username, password):
+ import bugzilla
+
+ try:
+ self._bz = bugzilla.Bugzilla(url=self.bugUrl)
+ retval = self._bz.login(username, password)
+ except socket.error, e:
+ raise CommunicationError(str(e))
+
+ if not retval:
+ raise LoginError(self.bugUrl, username)
+
+ return retval
+
+ def createbug(self, *args, **kwargs):
+ whiteboards = []
+
+ for (key, val) in kwargs.items():
+ if key.endswith("_whiteboard"):
+ wb = key.split("_")[0]
+ whiteboards.append((wb, val))
+ kwargs.pop(key)
+
+ if key == "platform":
+ platformLst = self.__withBugzillaDo(lambda b: b._proxy.Bug.legal_values({'field': 'platform'}))
+ if not val in platformLst['values']:
+ kwargs[key] = platformLst['values'][0]
+
+ bug = self.__withBugzillaDo(lambda b: b.createbug(**kwargs))
+ for (wb, val) in whiteboards:
+ bug.setwhiteboard(val, which=wb)
+
+ return BugzillaBug(self, bug=bug)
+
+ def getbug(self, id):
+ return BugzillaBug(self, bug=self.__withBugzillaDo(lambda b: b.getbug(id)))
+
+ def getbugs(self, idlist):
+ lst = self.__withBugzillaDo(lambda b: b.getbugs(idlist))
+ return map(lambda b: BugzillaBug(self, bug=b), lst)
+
+ def getproduct(self, prod):
+ details = self.__withBugzillaDo(lambda b: b.getproducts())
+ for d in details:
+ if d['name'] == prod:
+ return prod
+
+ if self.defaultProduct:
+ return self.defaultProduct
+ else:
+ raise ValueError, "The product %s is not valid and no defaultProduct is set." % prod
+
+ def getversion(self, ver, prod):
+ details = self.__withBugzillaDo(lambda b: b._proxy.bugzilla.getProductDetails(prod))
+ bugzillaVers = details[1]
+ bugzillaVers.sort()
+
+ if ver not in bugzillaVers:
+ if self.develVersion:
+ return self.develVersion
+ else:
+ return bugzillaVers[-1]
+ else:
+ return ver
+
+ def query(self, query):
+ lst = self.__withBugzillaDo(lambda b: b.query(query))
+ return map(lambda b: BugzillaBug(self, bug=b), lst)
+
+ def supportsFiling(self):
+ return True
+
+class BugzillaBug(AbstractBug):
+ def __withBugDo(self, fn):
+ try:
+ retval = fn(self._bug)
+ return retval
+ except xmlrpclib.ProtocolError, e:
+ raise CommunicationError(str(e))
+ except xmlrpclib.Fault, e:
+ raise ValueError(str(e))
+ except socket.error, e:
+ raise CommunicationError(str(e))
+
+ def __init__(self, filer, bug=None, *args, **kwargs):
+ import bugzilla
+
+ self.filer = filer
+
+ if not bug:
+ self._bug = bugzilla.Bug(self.filer, *args, **kwargs)
+ else:
+ self._bug = bug
+
+ def __str__(self):
+ return self._bug.__str__()
+
+ def __repr__(self):
+ return self._bug.__repr__()
+
+ def addCC(self, address):
+ try:
+ return self.filer._bz._updatecc(self._bug.bug_id, [address], 'add')
+ except xmlrpclib.ProtocolError, e:
+ raise CommunicationError(str(e))
+ except xmlrpclib.Fault, e:
+ raise ValueError(str(e))
+ except socket.error, e:
+ raise CommunicationError(str(e))
+
+ def addcomment(self, comment):
+ return self.__withBugDo(lambda b: b.addcomment(comment))
+
+ def attachfile(self, file, description, **kwargs):
+ try:
+ return self.filer._bz.attachfile(self._bug.bug_id, file, description, **kwargs)
+ except xmlrpclib.ProtocolError, e:
+ raise CommunicationError(str(e))
+ except xmlrpclib.Fault, e:
+ raise ValueError(str(e))
+ except socket.error, e:
+ raise CommunicationError(str(e))
+
+ def id(self):
+ return self._bug.bug_id
+
+ def close(self, resolution, dupeid=0, comment=''):
+ return self.__withBugDo(lambda b: b.close(resolution, dupeid=dupeid,
+ comment=comment))
+
+ def setstatus(self, status, comment=''):
+ return self.__withBugDo(lambda b: b.setstatus(status, comment=comment))
+
+ def setassignee(self, assigned_to='', reporter='', comment=''):
+ return self.__withBugDo(lambda b: b.setassignee(assigned_to=assigned_to,
+ reporter=reporter,
+ comment=comment))
+
+ def getwhiteboard(self, which='status'):
+ return self.__withBugDo(lambda b: b.getwhiteboard(which=which))
+
+ def appendwhiteboard(self, text, which='status'):
+ return self.__withBugDo(lambda b: b.appendwhiteboard(text, which=which))
+
+ def prependwhiteboard(self, text, which='status'):
+ return self.__withBugDo(lambda b: b.prependwhiteboard(text, which=which))
+
+ def setwhiteboard(self, text, which='status'):
+ return self.__withBugDo(lambda b: b.setwhiteboard(text, which=which))
diff -up setroubleshoot-2.1.12/src/Makefile.am.guiredesign setroubleshoot-2.1.12/src/Makefile.am
--- setroubleshoot-2.1.12/src/Makefile.am.guiredesign 2009-04-03 16:07:55.000000000 -0400
+++ setroubleshoot-2.1.12/src/Makefile.am 2009-06-10 09:50:58.616309307 -0400
@@ -11,6 +11,7 @@ PYTHON_FILES = \
email_alert.py \
email_dialog.py \
errcode.py \
+ filer.py \
gui_utils.py \
html_util.py \
log.py \
diff -up setroubleshoot-2.1.12/src/Makefile.in.guiredesign setroubleshoot-2.1.12/src/Makefile.in
--- setroubleshoot-2.1.12/src/Makefile.in.guiredesign 2009-06-02 11:07:27.000000000 -0400
+++ setroubleshoot-2.1.12/src/Makefile.in 2009-06-10 09:50:58.617308874 -0400
@@ -247,6 +247,7 @@ PYTHON_FILES = \
email_alert.py \
email_dialog.py \
errcode.py \
+ filer.py \
gui_utils.py \
html_util.py \
log.py \
diff -up setroubleshoot-2.1.12/src/signature.py.guiredesign setroubleshoot-2.1.12/src/signature.py
--- setroubleshoot-2.1.12/src/signature.py.guiredesign 2009-06-10 10:42:15.146313357 -0400
+++ setroubleshoot-2.1.12/src/signature.py 2009-06-10 10:42:28.336311489 -0400
@@ -1,4 +1,5 @@
# Authors: John Dennis
+# Thomas Liu
#
# Copyright (C) 2006,2007,2008 Red Hat, Inc.
#
@@ -256,6 +257,7 @@ class SEFaultSignatureInfo(XmlSerialize)
'local_id' : {'XMLForm':'element' },
'users' : {'XMLForm':'element', 'list':'user', 'import_typecast':SEFaultSignatureUser, },
'level' : {'XMLForm':'element' },
+ 'fixable' : {'XMLForm':'element' },
}
merge_include = ['audit_event', 'tpath', 'src_rpm_list', 'tgt_rpm_list',