Blob Blame History Raw
#!/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2015 Red Hat, Inc.
#
# Authors:
# Thomas Woerner <twoerner@redhat.com>
#
# 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 <http://www.gnu.org/licenses/>.
#

import sys
import string
import gi

try:
    gi.require_version('Gtk', '3.0')
    from gi.repository import Gtk, Gdk, Pango, Gio
    Gtk.init(sys.argv)
except RuntimeError as e:
    print("firewall-config: %s" % e)
    print("This is a graphical application and requires DISPLAY to be set.")
    sys.exit(1)

from gi.repository import GObject, GLib
sys.modules['gobject'] = GObject
import os
datadir = None
if os.getenv("FIREWALLD_DEVEL_ENV") is not None:
    datadir = os.getenv("FIREWALLD_DEVEL_ENV")
    sys.path.insert(0, datadir)
from dbus.exceptions import DBusException

from firewall import config
from firewall import client
from firewall import functions
from firewall.core.base import DEFAULT_ZONE_TARGET, REJECT_TYPES, \
                               ZONE_SOURCE_IPSET_TYPES
from firewall.core.ipset import IPSET_MAXNAMELEN
from firewall.core.helper import HELPER_MAXNAMELEN
from firewall.core.io.zone import Zone
from firewall.core.io.service import Service
from firewall.core.io.icmptype import IcmpType
from firewall.core.io.ipset import IPSet
from firewall.core.io.helper import Helper
from firewall.core import rich
from firewall.core.fw_nm import nm_is_imported, nm_get_dbus_interface, \
                                nm_get_connections, nm_get_zone_of_connection, \
                                nm_set_zone_of_connection
from firewall import errors
from firewall.errors import FirewallError

import gettext
gettext.textdomain(config.DOMAIN)
_ = gettext.gettext

if not datadir:
    datadir = config.DATADIR
    sys.path.insert(0, datadir)
from gtk3_chooserbutton import ChooserButton
from gtk3_niceexpander import NiceExpander

def escape(text):
    text = text.replace('&', '&amp;')
    text = text.replace('>', '&gt;')
    text = text.replace('<', '&lt;')
    return text

FIREWALL_CONFIG_SCHEMA = "org.fedoraproject.FirewallConfig"

class FirewallConfig(object):
    def __init__(self):
        builder = Gtk.Builder()
        builder.set_translation_domain("firewalld")
        builder.add_from_file("%s/%s" % (datadir, config.CONFIG_GLADE_NAME))
        builder.connect_signals(self)

        self.connected_label = _("Connection to firewalld established.")
        self.trying_to_connect_label = \
            _("Trying to connect to firewalld, waiting...")
        self.failed_to_connect_label = \
            _("Failed to connect to firewalld. Please make sure that the "
              "service has been started correctly and try again.")
        self.changes_applied_label = _("Changes applied.")
        self.used_by_label = _("Used by network connection '%s'")
        self.default_zone_used_by_label = _("Default zone used by network "
                                            "connection '%s'")
        self.enabled = _("enabled")
        self.disabled = _("disabled")

        self.settings = Gio.Settings.new(FIREWALL_CONFIG_SCHEMA)
        self.modified_timer = None
        self.connection_timer = None

        self.zone_connection_editors = { }
        self.zone_interface_editors = { }
        self.zone_source_editors = { }

        self.default_zone = ""
        self.nf_conntrack_helpers = { }

        # point to the visible dialogs
        self.visible_dialogs = [ ]
        self.connection_lost = False

        # get icon and logo
        (foo, width, height) = Gtk.icon_size_lookup(Gtk.IconSize.BUTTON)
        size = min(width, height)
        self.icon_theme = Gtk.IconTheme.get_default()
        try:
            self.icon = self.icon_theme.load_icon(config.CONFIG_NAME, size, 0)
            self.logo = self.icon_theme.load_icon(config.CONFIG_NAME, 48, 0)
        except:
            print(_("Failed to load icons."))
            self.icon = self.logo = None

        # get widgets

        self.mainWindow = builder.get_object("mainWindow")
        self.mainWindow.set_icon(self.icon)

        self.mainOverlay = builder.get_object("mainOverlay")

        self.mainPaned = builder.get_object("mainPaned")

        self.statusLabel = builder.get_object("statusLabel")
        self.modifiedLabel = builder.get_object("modifiedLabel")
        self.lockdownLabel = builder.get_object("lockdownLabel")
        self.panicLabel = builder.get_object("panicLabel")

        self.waitingWindow = builder.get_object("waitingWindow")
        self.waitingWindowLabel = builder.get_object("waitingWindowLabel")
        self.waitingWindowSpinner = builder.get_object("waitingWindowSpinner")
        self.waitingWindowQuitButton = \
            builder.get_object("waitingWindowQuitButton")
        self.mainOverlay.add_overlay(self.waitingWindow)
        self.waitingWindow.set_valign(Gtk.Align.CENTER)
        self.waitingWindow.set_halign(Gtk.Align.CENTER)

        self.mainNotebook = builder.get_object("mainNotebook")
        self.ipsetsBox = builder.get_object("ipsetsBox")
        self.ipsetsMenuitem = builder.get_object("ipsetsMenuitem")
        self.icmpTypesBox = builder.get_object("icmpTypesBox")
        self.icmpTypesMenuitem = builder.get_object("icmpTypesMenuitem")
        self.helpersBox = builder.get_object("helpersBox")
        self.helpersMenuitem = builder.get_object("helpersMenuitem")
        self.directBox = builder.get_object("directBox")
        self.directMenuitem = builder.get_object("directMenuitem")
        self.lockdownWhitelistBox = builder.get_object("lockdownWhitelistBox")
        self.lockdownWhitelistMenuitem = \
            builder.get_object("lockdownWhitelistMenuitem")
        self.activeBindingsMenuitem = \
            builder.get_object("activeBindingsMenuitem")

        self.changeZonesConnectionMenuitem = \
            builder.get_object("changeZonesConnectionMenuitem")

        self.left_menu = Gtk.Menu.new()
        self.left_menu.set_reserve_toggle_size(False)
        self.changeZonesConnectionMenuitem.set_submenu(self.left_menu)
        self.changeZonesConnectionMenuitem.connect(
            "activate", self.left_menu_cb, self.left_menu)
        self.active_zones = { }

        self.panicMenuitem = builder.get_object("panicMenuitem")
        self.panic_check_id = \
            self.panicMenuitem.connect_after("toggled", self.panic_check_cb)
        self.lockdownMenuitem = builder.get_object("lockdownMenuitem")
        self.lockdown_check_id = \
            self.lockdownMenuitem.connect_after("toggled",
                                                self.lockdown_check_cb)

        self.lockdownContextView = builder.get_object("lockdownContextView")
        self.lockdownContextStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.lockdownContextView.append_column(
            Gtk.TreeViewColumn(_("Context"), Gtk.CellRendererText(), text=0))
        self.lockdownContextView.set_model(self.lockdownContextStore)
        self.lockdownContextView.get_selection().connect( \
            "changed", self.change_lockdown_context_selection_cb)
        self.editLockdownContextButton = \
            builder.get_object("editLockdownContextButton")
        self.removeLockdownContextButton = \
            builder.get_object("removeLockdownContextButton")

        self.contextDialog = builder.get_object("contextDialog")
        self.contextDialogOkButton = builder.get_object("contextDialogOkButton")
        self.contextDialogCancelButton = \
            builder.get_object("contextDialogCancelButton")
        self.contextDialogContextEntry = \
            builder.get_object("contextDialogContextEntry")

        self.lockdownCommandView = builder.get_object("lockdownCommandView")
        self.lockdownCommandStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.lockdownCommandView.append_column(
            Gtk.TreeViewColumn(_("Command line"), Gtk.CellRendererText(), text=0))
        self.lockdownCommandView.set_model(self.lockdownCommandStore)
        self.lockdownCommandView.get_selection().connect( \
            "changed", self.change_lockdown_command_selection_cb)
        self.editLockdownCommandButton = \
            builder.get_object("editLockdownCommandButton")
        self.removeLockdownCommandButton = \
            builder.get_object("removeLockdownCommandButton")

        self.commandDialog = builder.get_object("commandDialog")
        self.commandDialogOkButton = builder.get_object("commandDialogOkButton")
        self.commandDialogCancelButton = \
            builder.get_object("commandDialogCancelButton")
        self.commandDialogCommandEntry = \
            builder.get_object("commandDialogCommandEntry")

        self.lockdownUserView = builder.get_object("lockdownUserView")
        self.lockdownUserStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.lockdownUserView.append_column(
            Gtk.TreeViewColumn(_("User name"), Gtk.CellRendererText(), text=0))
        self.lockdownUserView.set_model(self.lockdownUserStore)
        self.lockdownUserView.get_selection().connect( \
            "changed", self.change_lockdown_user_selection_cb)
        self.editLockdownUserButton = \
            builder.get_object("editLockdownUserButton")
        self.removeLockdownUserButton = \
            builder.get_object("removeLockdownUserButton")

        self.userDialog = builder.get_object("userDialog")
        self.userDialogOkButton = builder.get_object("userDialogOkButton")
        self.userDialogCancelButton = \
            builder.get_object("userDialogCancelButton")
        self.userDialogUserEntry = \
            builder.get_object("userDialogUserEntry")

        self.lockdownUidView = builder.get_object("lockdownUidView")
        self.lockdownUidStore = Gtk.ListStore(GObject.TYPE_INT)
        self.lockdownUidView.append_column(
            Gtk.TreeViewColumn(_("User id"), Gtk.CellRendererText(), text=0))
        self.lockdownUidView.set_model(self.lockdownUidStore)
        self.lockdownUidView.get_selection().connect( \
            "changed", self.change_lockdown_uid_selection_cb)
        self.editLockdownUidButton = \
            builder.get_object("editLockdownUidButton")
        self.removeLockdownUidButton = \
            builder.get_object("removeLockdownUidButton")

        self.uidDialog = builder.get_object("uidDialog")
        self.uidDialogOkButton = builder.get_object("uidDialogOkButton")
        self.uidDialogCancelButton = \
            builder.get_object("uidDialogCancelButton")
        self.uidDialogUidEntry = \
            builder.get_object("uidDialogUidEntry")

        self.serviceConfServicesEditBox = \
            builder.get_object("serviceConfServicesEditBox")
        self.serviceConfPortBox = \
            builder.get_object("serviceConfPortBox")
        self.serviceConfProtocolBox = \
            builder.get_object("serviceConfProtocolBox")
        self.serviceConfSourcePortBox = \
            builder.get_object("serviceConfSourcePortBox")
        self.serviceConfModuleBox = \
            builder.get_object("serviceConfModuleBox")
        self.serviceConfDestinationGrid = \
            builder.get_object("serviceConfDestinationGrid")

        self.icmpDialogIcmpEditBox = \
            builder.get_object("icmpDialogIcmpEditBox")

        self.directChainView = builder.get_object("directChainView")

        self.directChainStore = Gtk.ListStore(GObject.TYPE_STRING, # ipv
                                              GObject.TYPE_STRING, # table
                                              GObject.TYPE_STRING) # chain
        self.directChainView.append_column(
            Gtk.TreeViewColumn("ipv", Gtk.CellRendererText(), text=0))
        self.directChainView.append_column(
            Gtk.TreeViewColumn(_("Table"), Gtk.CellRendererText(), text=1))
        self.directChainView.append_column(
            Gtk.TreeViewColumn(_("Chain"), Gtk.CellRendererText(), text=2))
        self.directChainView.set_model(self.directChainStore)

        self.directChainView.get_selection().connect( \
            "changed", self.change_chain_selection_cb)
        self.editDirectChainButton = \
            builder.get_object("editDirectChainButton")
        self.removeDirectChainButton = \
            builder.get_object("removeDirectChainButton")

        self.directChainDialog = builder.get_object("directChainDialog")
        self.directChainDialogOkButton = \
            builder.get_object("directChainDialogOkButton")
        self.directChainDialogCancelButton = \
            builder.get_object("directChainDialogCancelButton")
        self.directChainDialogIPVCombobox = \
            builder.get_object("directChainDialogIPVCombobox")
        self.directChainDialogTableCombobox = \
            builder.get_object("directChainDialogTableCombobox")
        self.directChainDialogChainEntry = \
            builder.get_object("directChainDialogChainEntry")

        self.directRuleView = builder.get_object("directRuleView")

        self.directRuleStore = Gtk.ListStore(GObject.TYPE_STRING, # ipv
                                             GObject.TYPE_STRING, # table
                                             GObject.TYPE_STRING, # chain
                                             GObject.TYPE_INT, # priority
                                             GObject.TYPE_STRING) # args
        self.directRuleView.append_column(
            Gtk.TreeViewColumn("ipv", Gtk.CellRendererText(), text=0))
        self.directRuleView.append_column(
            Gtk.TreeViewColumn(_("Table"), Gtk.CellRendererText(), text=1))
        self.directRuleView.append_column(
            Gtk.TreeViewColumn(_("Chain"), Gtk.CellRendererText(), text=2))
        self.directRuleView.append_column(
            Gtk.TreeViewColumn(_("Priority"), Gtk.CellRendererText(), text=3))
        self.directRuleView.append_column(
            Gtk.TreeViewColumn(_("Args"), Gtk.CellRendererText(), text=4))
        self.directRuleView.set_model(self.directRuleStore)

        self.directRuleView.get_selection().connect( \
            "changed", self.change_rule_selection_cb)
        self.editDirectRuleButton = \
            builder.get_object("editDirectRuleButton")
        self.removeDirectRuleButton = \
            builder.get_object("removeDirectRuleButton")

        self.directRuleDialog = builder.get_object("directRuleDialog")
        self.directRuleDialogOkButton = \
            builder.get_object("directRuleDialogOkButton")
        self.directRuleDialogCancelButton = \
            builder.get_object("directRuleDialogCancelButton")

        self.directRuleDialogIPVCombobox = \
            builder.get_object("directRuleDialogIPVCombobox")
        self.directRuleDialogTableCombobox = \
            builder.get_object("directRuleDialogTableCombobox")
        self.directRuleDialogChainEntry = \
            builder.get_object("directRuleDialogChainEntry")
        self.directRuleDialogPrioritySpinbutton = \
            builder.get_object("directRuleDialogPrioritySpinbutton")
        self.directRuleDialogArgsEntry = \
            builder.get_object("directRuleDialogArgsEntry")

        self.directPassthroughBox = builder.get_object("directPassthroughBox")

        self.directPassthroughView = builder.get_object("directPassthroughView")

        self.directPassthroughStore = Gtk.ListStore(
            GObject.TYPE_STRING, # ipv
            GObject.TYPE_STRING) # passthrough
        self.directPassthroughView.append_column(
            Gtk.TreeViewColumn("ipv", Gtk.CellRendererText(), text=0))
        self.directPassthroughView.append_column(
            Gtk.TreeViewColumn(_("Args"), Gtk.CellRendererText(), text=1))
        self.directPassthroughView.set_model(self.directPassthroughStore)

        self.directPassthroughView.get_selection().connect( \
            "changed", self.change_passthrough_selection_cb)
        self.editDirectPassthroughButton = \
            builder.get_object("editDirectPassthroughButton")
        self.removeDirectPassthroughButton = \
            builder.get_object("removeDirectPassthroughButton")

        self.directPassthroughDialog = \
            builder.get_object("directPassthroughDialog")
        self.directPassthroughDialogOkButton = \
            builder.get_object("directPassthroughDialogOkButton")
        self.directPassthroughDialogCancelButton = \
            builder.get_object("directPassthroughDialogCancelButton")
        self.directPassthroughDialogIPVCombobox = \
            builder.get_object("directPassthroughDialogIPVCombobox")
        self.directPassthroughDialogArgsEntry = \
            builder.get_object("directPassthroughDialogArgsEntry")

        self.mainVBox = builder.get_object("mainVBox")
        self.optionsMenuitem = builder.get_object("optionsMenuitem")
        self.viewMenuitem = builder.get_object("viewMenuitem")

        self.aboutDialog = builder.get_object("aboutDialog")
        self.aboutDialog.set_program_name(config.CONFIG_NAME)
        self.aboutDialog.set_version(config.VERSION)
        self.aboutDialog.set_authors(config.AUTHORS)
        self.aboutDialog.set_license(config.LICENSE)
        self.aboutDialog.set_wrap_license(True)
        self.aboutDialog.set_copyright(config.COPYRIGHT)
        self.aboutDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.aboutDialog.set_transient_for(self.mainWindow)
        self.aboutDialog.set_modal(True)
        self.aboutDialog.set_icon(self.icon)
        self.aboutDialog.set_logo(self.logo)
        self.aboutDialog.set_website(config.WEBSITE)

        self.currentViewCombobox = builder.get_object("currentViewCombobox")
        self.currentViewCombobox.append_text(_("Runtime"))
        self.currentViewCombobox.append_text(_("Permanent"))
        self.runtime_view = True

        self.zoneView = builder.get_object("zoneView")
        self.zoneStore = Gtk.ListStore(GObject.TYPE_STRING, # name
                                       GObject.TYPE_INT) # weight
        self.zoneView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0, weight=1))
        self.zoneView.set_model(self.zoneStore)
        self.zoneStore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self.zoneView.get_selection().connect("changed", self.onChangeZone)

        self.zoneNotebook = builder.get_object("zoneNotebook")

        self.defaultZoneLabel = builder.get_object("defaultZoneLabel")
        self.defaultZoneDialog = builder.get_object("defaultZoneDialog")
        self.defaultZoneDialogOkButton = \
            builder.get_object("defaultZoneDialogOkButton")
        self.defaultZoneView = builder.get_object("defaultZoneView")
        self.defaultZoneStore = Gtk.ListStore(GObject.TYPE_STRING,
                                              GObject.TYPE_INT)
        self.defaultZoneView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0, weight=1))
        self.defaultZoneView.set_model(self.defaultZoneStore)

        self.defaultZoneView.get_selection().connect(\
            "changed", self.on_defaultZoneViewSelection_changed)

        self.logDeniedLabel = builder.get_object("logDeniedLabel")
        self.logDeniedDialog = builder.get_object("logDeniedDialog")
        self.logDeniedDialogOkButton = \
            builder.get_object("logDeniedDialogOkButton")
        self.logDeniedDialogValueCombobox = \
            builder.get_object("logDeniedDialogValueCombobox")
        for value in config.LOG_DENIED_VALUES:
            self.logDeniedDialogValueCombobox.append_text(value)

        self.automaticHelpersLabel = builder.get_object("automaticHelpersLabel")
        self.automaticHelpersDialog = builder.get_object("automaticHelpersDialog")
        self.automaticHelpersDialogOkButton = \
            builder.get_object("automaticHelpersDialogOkButton")
        self.automaticHelpersDialogValueCombobox = \
            builder.get_object("automaticHelpersDialogValueCombobox")
        for value in config.AUTOMATIC_HELPERS_VALUES:
            self.automaticHelpersDialogValueCombobox.append_text(value)

        self.zoneEditBox = builder.get_object("zoneEditBox")
        self.zoneEditBox.hide()
        self.zoneEditLoadDefaultsButton = \
            builder.get_object("zoneEditLoadDefaultsButton")
        self.zoneEditEditButton = builder.get_object("zoneEditEditButton")
        self.zoneEditRemoveButton = builder.get_object("zoneEditRemoveButton")

        self.zoneBaseDialog = builder.get_object("zoneBaseDialog")
        self.zoneBaseDialogOkButton = \
            builder.get_object("zoneBaseDialogOkButton")

        self.zoneBaseDialogNameEntry = \
            builder.get_object("zoneBaseDialogNameEntry")
        self.zoneBaseDialogVersionEntry = \
            builder.get_object("zoneBaseDialogVersionEntry")
        self.zoneBaseDialogShortEntry = \
            builder.get_object("zoneBaseDialogShortEntry")
        self.zoneBaseDialogDescText = \
            builder.get_object("zoneBaseDialogDescText")
        self.zoneBaseDialogDescText.get_buffer().connect(\
            "changed", self.onZoneBaseDialogChanged)
        self.zoneBaseDialogTargetCheck = \
            builder.get_object("zoneBaseDialogTargetCheck")
        self.zoneBaseDialogTargetCombobox = \
            builder.get_object("zoneBaseDialogTargetCombobox")

        self.serviceView = builder.get_object("serviceView")
        self.serviceStore = Gtk.ListStore(GObject.TYPE_BOOLEAN, # checked
                                          GObject.TYPE_STRING)  # name
        toggle = Gtk.CellRendererToggle()
        toggle.connect("toggled", self.service_toggle_cb, self.serviceStore, 0)
        self.serviceView.append_column(Gtk.TreeViewColumn("", toggle, active=0))
        self.serviceView.append_column(
            Gtk.TreeViewColumn(_("Service"), Gtk.CellRendererText(), text=1))
        self.serviceView.set_model(self.serviceStore)
        self.serviceStore.set_sort_column_id(1, Gtk.SortType.ASCENDING)

        self.portView = builder.get_object("portView")
        self.portStore = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING)
        self.portView.append_column(
            Gtk.TreeViewColumn(_("Port"), Gtk.CellRendererText(), text=0))
        self.portView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=1))
        self.portView.set_model(self.portStore)
        self.portStore.set_sort_column_id(1, Gtk.SortType.ASCENDING)
        self.portView.get_selection().connect("changed",
                                              self.change_port_selection_cb)

        self.editPortButton = builder.get_object("editPortButton")
        self.removePortButton = builder.get_object("removePortButton")

        self.portDialog = builder.get_object("portDialog")
        self.portDialogOkButton = builder.get_object("portDialogOkButton")
        self.portDialogCancelButton = \
            builder.get_object("portDialogCancelButton")
        self.portDialogPortEntry = builder.get_object("portDialogPortEntry")
        self.portDialogProtoCombobox = \
            builder.get_object("portDialogProtoCombobox")

        self.protocolView = builder.get_object("protocolView")
        self.protocolStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.protocolView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=0))
        self.protocolView.set_model(self.protocolStore)
        self.protocolStore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self.protocolView.get_selection().connect(
            "changed", self.change_protocol_selection_cb)

        self.editProtocolButton = builder.get_object("editProtocolButton")
        self.removeProtocolButton = builder.get_object("removeProtocolButton")

        self.protoDialog = builder.get_object("protoDialog")
        self.protoDialogOkButton = builder.get_object("protoDialogOkButton")
        self.protoDialogCancelButton = \
            builder.get_object("protoDialogCancelButton")
        self.protoDialogProtoLabel = builder.get_object("protoDialogProtoLabel")
        self.protoDialogProtoCombobox = \
            builder.get_object("protoDialogProtoCombobox")
        self.protoDialogOtherProtoCheck = \
            builder.get_object("protoDialogOtherProtoCheck")
        self.protoDialogOtherProtoEntry = \
            builder.get_object("protoDialogOtherProtoEntry")

        self.sourcePortView = builder.get_object("sourcePortView")
        self.sourcePortStore = Gtk.ListStore(GObject.TYPE_STRING,
                                             GObject.TYPE_STRING)
        self.sourcePortView.append_column(
            Gtk.TreeViewColumn(_("Port"), Gtk.CellRendererText(), text=0))
        self.sourcePortView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=1))
        self.sourcePortView.set_model(self.sourcePortStore)
        self.sourcePortStore.set_sort_column_id(1, Gtk.SortType.ASCENDING)
        self.sourcePortView.get_selection().connect(
            "changed", self.change_source_port_selection_cb)

        self.editSourcePortButton = builder.get_object("editSourcePortButton")
        self.removeSourcePortButton = \
            builder.get_object("removeSourcePortButton")



        self.masqueradeCheck = builder.get_object("masqueradeCheck")
        self.masqueradeEventbox = builder.get_object("masqueradeEventbox")
        self.masqueradeEventbox.connect("button-press-event",
                                        self.masquerade_check_cb)

        self.forwardView = builder.get_object("forwardView")
        self.forwardStore = Gtk.ListStore(GObject.TYPE_STRING,
                                          GObject.TYPE_STRING,
                                          GObject.TYPE_STRING,
                                          GObject.TYPE_STRING)
        self.forwardView.append_column(
            Gtk.TreeViewColumn(_("Port"), Gtk.CellRendererText(), text=0))
        self.forwardView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=1))
        self.forwardView.append_column(
            Gtk.TreeViewColumn(_("To Port"), Gtk.CellRendererText(), text=2))
        self.forwardView.append_column(
            Gtk.TreeViewColumn(_("To Address"), Gtk.CellRendererText(), text=3))
        self.forwardView.set_model(self.forwardStore)
        self.forwardStore.set_sort_column_id(1, Gtk.SortType.ASCENDING)
        self.forwardView.get_selection().connect(\
            "changed", self.change_forward_selection_cb)

        self.editForwardButton = builder.get_object("editForwardButton")
        self.removeForwardButton = builder.get_object("removeForwardButton")

        self.forwardDialog = builder.get_object("forwardDialog")
        self.forwardDialogOkButton = builder.get_object("forwardDialogOkButton")
        self.forwardDialogCancelButton = \
            builder.get_object("forwardDialogCancelButton")
        self.forwardDialogPortEntry = \
            builder.get_object("forwardDialogPortEntry")
        self.forwardDialogProtoCombobox = \
            builder.get_object("forwardDialogProtoCombobox")
        self.forwardDialogLocalCheck = \
            builder.get_object("forwardDialogLocalCheck")
        self.forwardDialogToPortCheck = \
            builder.get_object("forwardDialogToPortCheck")
        self.forwardDialogToPortLabel = \
            builder.get_object("forwardDialogToPortLabel")
        self.forwardDialogToPortEntry = \
            builder.get_object("forwardDialogToPortEntry")
        self.forwardDialogToAddrLabel = \
            builder.get_object("forwardDialogToAddrLabel")
        self.forwardDialogToAddrEntry = \
            builder.get_object("forwardDialogToAddrEntry")

        # bindings Expander
        self.bindingsBox = builder.get_object("bindingsBox")
        self.bindingsExpanderButton = \
            builder.get_object("bindingsExpanderButton")
        self.bindingsUnexpanderButton = \
            builder.get_object("bindingsUnexpanderButton")

        self.bindingsExpander = NiceExpander(
            self.bindingsExpanderButton, self.bindingsUnexpanderButton,
            self.mainPaned, self.bindingsBox)
        self.bindingsExpander.connect("notify::expanded",
                                      self.bindings_expander_changed)

        # bindings View
        self.bindingsView = builder.get_object("bindingsView")
        self.bindingsStore = Gtk.TreeStore(GObject.TYPE_STRING, # label
                                           GObject.TYPE_STRING, # connection/interface/source
                                           GObject.TYPE_STRING) # real zone
        self.bindingsView.set_model(self.bindingsStore)
        self.bindingsView.append_column(
            Gtk.TreeViewColumn(_("Bindings"), Gtk.CellRendererText(), markup=0))
        self.connectionsIter = self.bindingsStore.append(
            None, [ _("Connections"), "", "" ])
        self.interfacesIter = self.bindingsStore.append(
            None, [ _("Interfaces"), "", "" ])
        self.sourcesIter = self.bindingsStore.append(
            None, [ _("Sources"), "", "" ])
        self.bindingsView.get_selection().connect("changed",
                                                  self.onSelectBinding)
        self.bindingsView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.bindingsView.set_show_expanders(False)
        self.bindingsView.set_level_indentation(10)

        self.changeBindingsButton = builder.get_object("changeBindingsButton")
        self.changeBindingsButton.connect("clicked", self.onChangeBinding)
        #self.editBindingsButton = builder.get_object("editBindingsButton")
        #self.editBindingsButton.connect("clicked", self.onEditBinding)

        self.ipsetConfIPSetView = builder.get_object("ipsetConfIPSetView")
        self.ipsetConfIPSetStore = Gtk.ListStore(GObject.TYPE_STRING)  # name
        self.ipsetConfIPSetView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0))
        self.ipsetConfIPSetView.set_model(self.ipsetConfIPSetStore)
        self.ipsetConfIPSetStore.set_sort_column_id(
            0, Gtk.SortType.ASCENDING)
        self.ipsetConfIPSetView.get_selection().connect("changed",
                                                        self.onChangeIPSet)

        self.ipsetConfNotebook = builder.get_object("ipsetConfNotebook")
        self.ipsetConfEntryLabel = builder.get_object("ipsetConfEntryLabel")
        self.ipsetConfTimeoutLabel = builder.get_object("ipsetConfTimeoutLabel")
        self.ipsetConfEntrySW = builder.get_object("ipsetConfEntrySW")
        self.ipsetConfEntryView = builder.get_object("ipsetConfEntryView")
        self.ipsetConfEntryStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.ipsetConfEntryView.append_column(
            Gtk.TreeViewColumn(_("Entry"), Gtk.CellRendererText(), text=0))
        self.ipsetConfEntryView.set_model(self.ipsetConfEntryStore)
        self.ipsetConfEntryStore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self.ipsetConfEntryView.get_selection().connect(\
            "changed", self.change_ipset_conf_entry_selection_cb)

        self.ipsetConfIPSetEditBox = \
            builder.get_object("ipsetConfIPSetEditBox")
        self.ipsetConfEntryBox = \
            builder.get_object("ipsetConfEntryBox")

        self.ipsetConfEditIPSetButton = \
            builder.get_object("ipsetConfEditIPSetButton")
        self.ipsetConfRemoveIPSetButton = \
            builder.get_object("ipsetConfRemoveIPSetButton")
        self.ipsetConfLoadDefaultsIPSetButton = \
            builder.get_object("ipsetConfLoadDefaultsIPSetButton")

        self.ipsetConfAddEntryBox = \
            builder.get_object("ipsetConfAddEntryBox")
        self.ipsetConfAddEntryMenu = \
            builder.get_object("ipsetConfAddEntryMenu")
        self.ipsetConfAddEntryMenubutton = \
            builder.get_object("ipsetConfAddEntryMenubutton")
        self.ipsetConfEditEntryButton = \
            builder.get_object("ipsetConfEditEntryButton")
        self.ipsetConfRemoveEntryBox = \
            builder.get_object("ipsetConfRemoveEntryBox")
        self.ipsetConfRemoveEntryMenu = \
            builder.get_object("ipsetConfRemoveEntryMenu")
        self.ipsetConfRemoveEntryMenubutton = \
            builder.get_object("ipsetConfRemoveEntryMenubutton")
        self.ipsetConfRemoveEntryMenuitem = \
            builder.get_object("ipsetConfRemoveEntryMenuitem")
        self.ipsetConfRemoveEntryMenuitem.set_sensitive(False)

        self.ipsetEntryDialog = \
            builder.get_object("ipsetEntryDialog")

        self.ipsetEntryDialogCancelButton = \
            builder.get_object("ipsetEntryDialogCancelButton")
        self.ipsetEntryDialogOkButton = \
            builder.get_object("ipsetEntryDialogOkButton")
        self.ipsetEntryDialogEntryEntry = \
            builder.get_object("ipsetEntryDialogEntryEntry")
        self.ipsetEntryDialogTypeLabel = \
            builder.get_object("ipsetEntryDialogTypeLabel")

        self.ipsetBaseDialog = builder.get_object("ipsetBaseDialog")
        self.ipsetBaseDialogOkButton = \
            builder.get_object("ipsetBaseDialogOkButton")

        self.ipsetBaseDialogNameEntry = \
            builder.get_object("ipsetBaseDialogNameEntry")
        self.ipsetBaseDialogVersionEntry = \
            builder.get_object("ipsetBaseDialogVersionEntry")
        self.ipsetBaseDialogShortEntry = \
            builder.get_object("ipsetBaseDialogShortEntry")
        self.ipsetBaseDialogDescText = \
            builder.get_object("ipsetBaseDialogDescText")
        self.ipsetBaseDialogDescText.get_buffer().connect(\
            "changed", self.onIPSetBaseDialogChanged)
        self.ipsetBaseDialogTypeCombobox = \
            builder.get_object("ipsetBaseDialogTypeCombobox")
        self.ipsetBaseDialogBadTypeLabel = \
            builder.get_object("ipsetBaseDialogBadTypeLabel")

        self.ipsetBaseDialogFamilyLabel = \
            builder.get_object("ipsetBaseDialogFamilyLabel")
        self.ipsetBaseDialogFamilyCombobox = \
            builder.get_object("ipsetBaseDialogFamilyCombobox")
        self.ipsetBaseDialogTimeoutEntry = \
            builder.get_object("ipsetBaseDialogTimeoutEntry")
        self.ipsetBaseDialogHashsizeEntry = \
            builder.get_object("ipsetBaseDialogHashsizeEntry")
        self.ipsetBaseDialogMaxelemEntry = \
            builder.get_object("ipsetBaseDialogMaxelemEntry")

        self.helperConfHelperNotebook = \
            builder.get_object("helperConfHelperNotebook")

        self.helperConfHelperEditBox = \
            builder.get_object("helperConfHelperEditBox")
        self.helperConfPortBox = \
            builder.get_object("helperConfPortBox")

        self.helperConfEditHelperButton = \
            builder.get_object("helperConfEditHelperButton")
        self.helperConfRemoveHelperButton = \
            builder.get_object("helperConfRemoveHelperButton")
        self.helperConfLoadDefaultsHelperButton = \
            builder.get_object("helperConfLoadDefaultsHelperButton")

        self.helperConfAddPortButton = \
            builder.get_object("helperConfAddPortButton")
        self.helperConfEditPortButton = \
            builder.get_object("helperConfEditPortButton")
        self.helperConfRemovePortButton = \
            builder.get_object("helperConfRemovePortButton")

        self.helperBaseDialog = builder.get_object("helperBaseDialog")
        self.helperBaseDialogOkButton = \
            builder.get_object("helperBaseDialogOkButton")

        self.helperBaseDialogNameEntry = \
            builder.get_object("helperBaseDialogNameEntry")
        self.helperBaseDialogVersionEntry = \
            builder.get_object("helperBaseDialogVersionEntry")
        self.helperBaseDialogShortEntry = \
            builder.get_object("helperBaseDialogShortEntry")
        self.helperBaseDialogDescText = \
            builder.get_object("helperBaseDialogDescText")
        self.helperBaseDialogDescText.get_buffer().connect(\
            "changed", self.onHelperBaseDialogChanged)
        self.helperBaseDialogModuleChooser = \
            ChooserButton(builder.get_object("helperBaseDialogModuleChooser"))
        self.helperBaseDialogFamilyCombobox = \
            builder.get_object("helperBaseDialogFamilyCombobox")

        self.icmpView = builder.get_object("icmpView")
        self.icmpStore = Gtk.ListStore(GObject.TYPE_BOOLEAN, # checked
                                       GObject.TYPE_STRING)  # name
        toggle = Gtk.CellRendererToggle()
        toggle.connect("toggled", self.icmp_toggle_cb, self.icmpStore, 0)
        self.icmpView.append_column(Gtk.TreeViewColumn("", toggle, active=0))
        self.icmpView.append_column(
            Gtk.TreeViewColumn(_("Icmp Type"), Gtk.CellRendererText(), text=1))
        self.icmpView.set_model(self.icmpStore)
        self.icmpStore.set_sort_column_id(1, Gtk.SortType.ASCENDING)

        self.icmpBlockInversionCheck = \
            builder.get_object("icmpBlockInversionCheck")
        self.icmpBlockInversionEventbox = \
            builder.get_object("icmpBlockInversionEventbox")
        self.icmpBlockInversionEventbox.connect(
            "button-press-event", self.icmp_block_inversion_check_cb)

        self.helperConfHelperView = builder.get_object("helperConfHelperView")
        self.helperConfHelperStore = Gtk.ListStore(GObject.TYPE_STRING)  # name
        self.helperConfHelperView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0))
        self.helperConfHelperView.set_model(self.helperConfHelperStore)
        self.helperConfHelperStore.set_sort_column_id(
            0, Gtk.SortType.ASCENDING)
        self.helperConfHelperView.get_selection().connect("changed",
                                                          self.onChangeHelper)

        self.helperConfPortView = builder.get_object("helperConfPortView")
        self.helperConfPortStore = Gtk.ListStore(GObject.TYPE_STRING,
                                                 GObject.TYPE_STRING)
        self.helperConfPortView.append_column(
            Gtk.TreeViewColumn(_("Port"), Gtk.CellRendererText(), text=0))
        self.helperConfPortView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=1))
        self.helperConfPortView.set_model(self.helperConfPortStore)
        self.helperConfPortStore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self.helperConfPortView.get_selection().connect(\
            "changed", self.change_helper_conf_port_selection_cb)

        self.richRuleView = builder.get_object("richRuleView")
        self.richRuleStore = Gtk.ListStore(GObject.TYPE_PYOBJECT, # the rule obj
                                           GObject.TYPE_STRING, # ipv4/ipv6
                                           GObject.TYPE_INT,    # priority
                                           GObject.TYPE_STRING, # action
                                           GObject.TYPE_STRING, # element
                                           GObject.TYPE_STRING, # source
                                           GObject.TYPE_STRING, # destination
                                           GObject.TYPE_STRING, # log
                                           GObject.TYPE_STRING) # audit

        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("Family"), Gtk.CellRendererText(), text=1))
        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("Priority"), Gtk.CellRendererText(), text=2))
        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("Action"), Gtk.CellRendererText(), text=3))
        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("Element"), Gtk.CellRendererText(), text=4))
        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("Src"), Gtk.CellRendererText(), text=5))
        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("Dest"), Gtk.CellRendererText(), text=6))
        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("log"), Gtk.CellRendererText(), text=7))
        self.richRuleView.append_column(
            Gtk.TreeViewColumn(_("Audit"), Gtk.CellRendererText(), text=8))
        self.richRuleView.set_model(self.richRuleStore)
        self.richRuleStore.set_sort_column_id(2, Gtk.SortType.ASCENDING)

        self.richRuleView.get_selection().connect( \
            "changed", self.change_rich_rule_selection_cb)

        self.addRichRuleButton = builder.get_object("addRichRuleButton")
        self.editRichRuleButton = builder.get_object("editRichRuleButton")
        self.removeRichRuleButton = builder.get_object("removeRichRuleButton")

        self.richRuleDialog = builder.get_object("richRuleDialog")
        self.richRuleDialogOkButton = builder.get_object( \
            "richRuleDialogOkButton")
        self.richRuleDialogCancelButton = builder.get_object( \
            "richRuleDialogCancelButton")

        self.richRuleDialogFamilyCombobox = builder.get_object( \
            "richRuleDialogFamilyCombobox")
        self.richRuleDialogPriorityEntry = builder.get_object( \
            "richRuleDialogPriorityEntry")
        self.richRuleDialogElementCheck = builder.get_object( \
            "richRuleDialogElementCheck")
        self.richRuleDialogElementBox = builder.get_object( \
            "richRuleDialogElementBox")
        self.richRuleDialogElementCombobox = builder.get_object( \
            "richRuleDialogElementCombobox")

        self.richRuleDialogElementChooser = ChooserButton(builder.get_object( \
            "richRuleDialogElementChooser"))
        self.richRuleDialogActionCheck = builder.get_object( \
            "richRuleDialogActionCheck")
        self.richRuleDialogActionBox = builder.get_object( \
            "richRuleDialogActionBox")
        self.richRuleDialogActionCombobox = builder.get_object( \
            "richRuleDialogActionCombobox")
        self.richRuleDialogActionRejectBox = builder.get_object( \
            "richRuleDialogActionRejectBox")
        self.richRuleDialogActionRejectTypeCheck = builder.get_object( \
            "richRuleDialogActionRejectTypeCheck")
        self.richRuleDialogActionRejectTypeCombobox = builder.get_object( \
            "richRuleDialogActionRejectTypeCombobox")
        self.richRuleDialogActionMarkBox = builder.get_object( \
            "richRuleDialogActionMarkBox")
        self.richRuleDialogActionMarkChooser = ChooserButton(builder.get_object( \
            "richRuleDialogActionMarkChooser"))
        self.richRuleDialogActionLimitCheck = builder.get_object( \
            "richRuleDialogActionLimitCheck")
        self.richRuleDialogActionLimitBox = builder.get_object( \
            "richRuleDialogActionLimitBox")
        self.richRuleDialogActionLimitRateEntry = builder.get_object( \
            "richRuleDialogActionLimitRateEntry")
        self.richRuleDialogActionLimitDurationCombobox = builder.get_object( \
            "richRuleDialogActionLimitDurationCombobox")
        self.richRuleDialogSourceLabel = builder.get_object( \
            "richRuleDialogSourceLabel")
        self.richRuleDialogSourceInvertCheck = builder.get_object( \
            "richRuleDialogSourceInvertCheck")
        self.richRuleDialogSourceTypeCombobox = builder.get_object( \
            "richRuleDialogSourceTypeCombobox")
        self.richRuleDialogSourceChooser = ChooserButton(builder.get_object( \
                "richRuleDialogSourceChooser"))
        self.richRuleDialogDestinationLabel = builder.get_object( \
            "richRuleDialogDestinationLabel")
        self.richRuleDialogDestinationBox = builder.get_object( \
            "richRuleDialogDestinationBox")
        self.richRuleDialogDestinationInvertCheck = builder.get_object( \
            "richRuleDialogDestinationInvertCheck")
        self.richRuleDialogDestinationChooser = \
            ChooserButton(builder.get_object( \
                "richRuleDialogDestinationChooser"))
        self.richRuleDialogLogCheck = builder.get_object( \
            "richRuleDialogLogCheck")
        self.richRuleDialogLogGrid = builder.get_object( \
            "richRuleDialogLogGrid")
        self.richRuleDialogLogPrefixEntry = builder.get_object( \
            "richRuleDialogLogPrefixEntry")
        self.richRuleDialogLogLevelCombobox = builder.get_object( \
            "richRuleDialogLogLevelCombobox")
        self.richRuleDialogLogLimitCheck = builder.get_object( \
            "richRuleDialogLogLimitCheck")
        self.richRuleDialogLogLimitBox = builder.get_object( \
            "richRuleDialogLogLimitBox")
        self.richRuleDialogLogLimitRateEntry = builder.get_object( \
            "richRuleDialogLogLimitRateEntry")
        self.richRuleDialogLogLimitDurationCombobox = builder.get_object( \
            "richRuleDialogLogLimitDurationCombobox")
        self.richRuleDialogAuditCheck = builder.get_object( \
            "richRuleDialogAuditCheck")
        self.richRuleDialogAuditBox = builder.get_object( \
            "richRuleDialogAuditBox")
        self.richRuleDialogAuditLimitBox = builder.get_object( \
            "richRuleDialogAuditLimitBox")
        self.richRuleDialogAuditLimitCheck = builder.get_object( \
            "richRuleDialogAuditLimitCheck")
        self.richRuleDialogAuditLimitRateEntry = builder.get_object( \
            "richRuleDialogAuditLimitRateEntry")
        self.richRuleDialogAuditLimitDurationCombobox = builder.get_object( \
            "richRuleDialogAuditLimitDurationCombobox")

        self.interfaceView = builder.get_object("interfaceView")
        self.interfaceStore = Gtk.ListStore(GObject.TYPE_STRING, # interface
                                            GObject.TYPE_STRING) # comment
        self.interfaceView.append_column(
            Gtk.TreeViewColumn(_("Interface"), Gtk.CellRendererText(), text=0))
        self.interfaceView.append_column(
            Gtk.TreeViewColumn(_("Comment"), Gtk.CellRendererText(), text=1))
        self.interfaceView.set_model(self.interfaceStore)
        self.interfaceView.get_selection().connect(
            "changed", self.change_interface_selection_cb)

        self.interfaceDialog = builder.get_object("interfaceDialog")
        self.interfaceDialogOkButton = builder.get_object(
            "interfaceDialogOkButton")
        self.interfaceDialogCancelButton = builder.get_object(
            "interfaceDialogCancelButton")
        self.interfaceDialogInterfaceEntry = builder.get_object(
            "interfaceDialogInterfaceEntry")

        self.editInterfaceButton = builder.get_object("editInterfaceButton")
        self.removeInterfaceButton = builder.get_object("removeInterfaceButton")

        self.sourceView = builder.get_object("sourceView")
        self.sourceStore = Gtk.ListStore(GObject.TYPE_STRING) # source
        self.sourceView.append_column(
            Gtk.TreeViewColumn(_("Source"), Gtk.CellRendererText(), text=0))
        self.sourceView.set_model(self.sourceStore)
        self.sourceView.get_selection().connect(
            "changed", self.change_source_selection_cb)

        self.editSourceButton = builder.get_object("editSourceButton")
        self.removeSourceButton = builder.get_object("removeSourceButton")

        self.serviceConfServiceNotebook = \
            builder.get_object("serviceConfServiceNotebook")

        self.serviceConfServiceEditBox = \
            builder.get_object("serviceConfServiceEditBox")
        self.serviceConfEditServiceButton = \
            builder.get_object("serviceConfEditServiceButton")
        self.serviceConfRemoveServiceButton = \
            builder.get_object("serviceConfRemoveServiceButton")
        self.serviceConfLoadDefaultsServiceButton = \
            builder.get_object("serviceConfLoadDefaultsServiceButton")

        self.serviceConfServiceView = \
            builder.get_object("serviceConfServiceView")
        self.serviceConfServiceStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.serviceConfServiceView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0))
        self.serviceConfServiceView.set_model(self.serviceConfServiceStore)
        self.serviceConfServiceStore.set_sort_column_id(
            0, Gtk.SortType.ASCENDING)
        self.serviceConfServiceView.get_selection().connect(\
            "changed", self.onChangeService)

        self.serviceConfPortView = builder.get_object("serviceConfPortView")
        self.serviceConfPortStore = Gtk.ListStore(GObject.TYPE_STRING,
                                                  GObject.TYPE_STRING)
        self.serviceConfPortView.append_column(
            Gtk.TreeViewColumn(_("Port"), Gtk.CellRendererText(), text=0))
        self.serviceConfPortView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=1))
        self.serviceConfPortView.set_model(self.serviceConfPortStore)
        self.serviceConfPortStore.set_sort_column_id(1, Gtk.SortType.ASCENDING)
        self.serviceConfPortView.get_selection().connect(\
            "changed", self.change_service_dialog_port_selection_cb)

        self.serviceConfEditPortButton = \
            builder.get_object("serviceConfEditPortButton")
        self.serviceConfRemovePortButton = \
            builder.get_object("serviceConfRemovePortButton")

        self.serviceConfProtocolView = \
            builder.get_object("serviceConfProtocolView")
        self.serviceConfProtocolStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.serviceConfProtocolView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=0))
        self.serviceConfProtocolView.set_model(self.serviceConfProtocolStore)
        self.serviceConfProtocolStore.set_sort_column_id(0,
                                                         Gtk.SortType.ASCENDING)
        self.serviceConfProtocolView.get_selection().connect(\
            "changed", self.change_service_dialog_protocol_selection_cb)

        self.serviceConfEditProtocolButton = \
            builder.get_object("serviceConfEditProtocolButton")
        self.serviceConfRemoveProtocolButton = \
            builder.get_object("serviceConfRemoveProtocolButton")

        self.serviceConfSourcePortView = \
            builder.get_object("serviceConfSourcePortView")
        self.serviceConfSourcePortStore = Gtk.ListStore(GObject.TYPE_STRING,
                                                        GObject.TYPE_STRING)
        self.serviceConfSourcePortView.append_column(
            Gtk.TreeViewColumn(_("Port"), Gtk.CellRendererText(), text=0))
        self.serviceConfSourcePortView.append_column(
            Gtk.TreeViewColumn(_("Protocol"), Gtk.CellRendererText(), text=1))
        self.serviceConfSourcePortView.set_model(self.serviceConfSourcePortStore)
        self.serviceConfSourcePortStore.set_sort_column_id(
            1, Gtk.SortType.ASCENDING)
        self.serviceConfSourcePortView.get_selection().connect(\
            "changed", self.change_service_dialog_source_port_selection_cb)

        self.serviceConfEditSourcePortButton = \
            builder.get_object("serviceConfEditSourcePortButton")
        self.serviceConfRemoveSourcePortButton = \
            builder.get_object("serviceConfRemoveSourcePortButton")

        self.serviceConfModuleView = \
            builder.get_object("serviceConfModuleView")
        self.serviceConfModuleStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.serviceConfModuleView.append_column(
            Gtk.TreeViewColumn("Module", Gtk.CellRendererText(), text=0))
        self.serviceConfModuleView.set_model(self.serviceConfModuleStore)
        self.serviceConfModuleStore.set_sort_column_id(
            0, Gtk.SortType.ASCENDING)
        self.serviceConfModuleView.get_selection().connect(\
            "changed", self.change_service_dialog_module_selection_cb)

        self.serviceConfEditModuleButton = \
            builder.get_object("serviceConfEditModuleButton")
        self.serviceConfRemoveModuleButton = \
            builder.get_object("serviceConfRemoveModuleButton")

        self.serviceConfDestIpv4Chooser = ChooserButton(
            builder.get_object("serviceConfDestIpv4Chooser"), "")
        self.serviceConfDestIpv6Chooser = ChooserButton(
            builder.get_object("serviceConfDestIpv6Chooser"), "")

        self.addressDialog = builder.get_object("addressDialog")
        self.addressDialogLabel = builder.get_object("addressDialogLabel")
        self.addressDialogLabel2 = builder.get_object("addressDialogLabel2")
        self.addressDialogOkButton = \
            builder.get_object("addressDialogOkButton")
        self.addressDialogCancelButton = \
            builder.get_object("addressDialogCancelButton")
        self.addressDialogAddressEntry = \
            builder.get_object("addressDialogAddressEntry")

        self.macDialog = builder.get_object("macDialog")
        self.macDialogOkButton = \
            builder.get_object("macDialogOkButton")
        self.macDialogCancelButton = \
            builder.get_object("macDialogCancelButton")
        self.macDialogMacEntry = \
            builder.get_object("macDialogMacEntry")

        self.ipsetDialog = builder.get_object("ipsetDialog")
        self.ipsetDialogOkButton = \
            builder.get_object("ipsetDialogOkButton")
        self.ipsetDialogCancelButton = \
            builder.get_object("ipsetDialogCancelButton")
        self.ipsetDialogIPSetView = \
            builder.get_object("ipsetDialogIPSetView")

        self.ipsetDialogIPSetStore = Gtk.ListStore(GObject.TYPE_STRING,
                                                   GObject.TYPE_STRING)
        self.ipsetDialogIPSetView.append_column(
            Gtk.TreeViewColumn("IPSet", Gtk.CellRendererText(), text=0))
        self.ipsetDialogIPSetView.append_column(
            Gtk.TreeViewColumn("Type", Gtk.CellRendererText(), text=1))
        self.ipsetDialogIPSetView.set_model(self.ipsetDialogIPSetStore)
        self.ipsetDialogIPSetView.get_selection().connect( \
            "changed", self.change_ipset_selection_cb)

        self.helperDialog = builder.get_object("helperDialog")
        self.helperDialogOkButton = \
            builder.get_object("helperDialogOkButton")
        self.helperDialogCancelButton = \
            builder.get_object("helperDialogCancelButton")
        self.helperDialogHelperView = \
            builder.get_object("helperDialogHelperView")

        self.helperDialogHelperStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.helperDialogHelperView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0))
        self.helperDialogHelperView.set_model(self.helperDialogHelperStore)
        self.helperDialogHelperView.get_selection().connect( \
            "changed", self.change_helper_selection_cb)

        self.moduleDialog = builder.get_object("moduleDialog")
        self.moduleDialogOkButton = builder.get_object("moduleDialogOkButton")
        self.moduleDialogCancelButton = \
            builder.get_object("moduleDialogCancelButton")
        self.moduleDialogModuleLabel = builder.get_object("moduleDialogModuleLabel")
        self.moduleDialogModuleCombobox = \
            builder.get_object("moduleDialogModuleCombobox")
        self.moduleDialogOtherModuleCheck = \
            builder.get_object("moduleDialogOtherModuleCheck")
        self.moduleDialogOtherModuleEntry = \
            builder.get_object("moduleDialogOtherModuleEntry")

        self.sourceDialog = builder.get_object("sourceDialog")
        self.sourceDialogOkButton = \
            builder.get_object("sourceDialogOkButton")
        self.sourceDialogCancelButton = \
            builder.get_object("sourceDialogCancelButton")
        self.sourceDialogSourceTypeCombobox = \
            builder.get_object("sourceDialogSourceTypeCombobox")
        self.sourceDialogSourceChooser = ChooserButton(builder.get_object( \
                "sourceDialogSourceChooser"))

        self.markDialog = builder.get_object("markDialog")
        self.markDialogOkButton = \
            builder.get_object("markDialogOkButton")
        self.markDialogCancelButton = \
            builder.get_object("markDialogCancelButton")
        self.markDialogMarkEntry = \
            builder.get_object("markDialogMarkEntry")
        self.markDialogMaskEntry = \
            builder.get_object("markDialogMaskEntry")

        self.serviceBaseDialog = builder.get_object("serviceBaseDialog")
        self.serviceBaseDialogOkButton = \
            builder.get_object("serviceBaseDialogOkButton")

        self.serviceBaseDialogNameEntry = \
            builder.get_object("serviceBaseDialogNameEntry")
        self.serviceBaseDialogVersionEntry = \
            builder.get_object("serviceBaseDialogVersionEntry")
        self.serviceBaseDialogShortEntry = \
            builder.get_object("serviceBaseDialogShortEntry")
        self.serviceBaseDialogDescText = \
            builder.get_object("serviceBaseDialogDescText")
        self.serviceBaseDialogDescText.get_buffer().connect(\
            "changed", self.onServiceBaseDialogChanged)

        self.icmpDialogIcmpNotebook = \
            builder.get_object("icmpDialogIcmpNotebook")

        self.icmpDialogIcmpEditBox = \
            builder.get_object("icmpDialogIcmpEditBox")
        self.icmpDialogEditIcmpButton = \
            builder.get_object("icmpDialogEditIcmpButton")
        self.icmpDialogRemoveIcmpButton = \
            builder.get_object("icmpDialogRemoveIcmpButton")
        self.icmpDialogLoadDefaultsIcmpButton = \
            builder.get_object("icmpDialogLoadDefaultsIcmpButton")

        self.icmpDialogIcmpView = \
            builder.get_object("icmpDialogIcmpView")
        self.icmpDialogIcmpStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.icmpDialogIcmpView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0))
        self.icmpDialogIcmpView.set_model(self.icmpDialogIcmpStore)
        self.icmpDialogIcmpStore.set_sort_column_id(
            0, Gtk.SortType.ASCENDING)
        self.icmpDialogIcmpView.get_selection().connect(\
            "changed", self.onChangeIcmp)

        self.icmpDialogDestIpv4Check = \
            builder.get_object("icmpDialogDestIpv4Check")
        self.icmpDialogDestIpv6Check = \
            builder.get_object("icmpDialogDestIpv6Check")

        self.icmpDialogDestIpv4Eventbox = \
            builder.get_object("icmpDialogDestIpv4Eventbox")
        self.icmpDialogDestIpv4Eventbox.connect(\
            "button-press-event", self.icmp_dialog_dest_ipv4_check_cb)
        self.icmpDialogDestIpv6Eventbox = \
            builder.get_object("icmpDialogDestIpv6Eventbox")
        self.icmpDialogDestIpv6Eventbox.connect(\
            "button-press-event", self.icmp_dialog_dest_ipv6_check_cb)

        self.icmpBaseDialog = builder.get_object("icmpBaseDialog")
        self.icmpBaseDialogOkButton = \
            builder.get_object("icmpBaseDialogOkButton")

        self.icmpBaseDialogNameEntry = \
            builder.get_object("icmpBaseDialogNameEntry")
        self.icmpBaseDialogVersionEntry = \
            builder.get_object("icmpBaseDialogVersionEntry")
        self.icmpBaseDialogShortEntry = \
            builder.get_object("icmpBaseDialogShortEntry")
        self.icmpBaseDialogDescText = \
            builder.get_object("icmpBaseDialogDescText")
        self.icmpBaseDialogDescText.get_buffer().connect(\
            "changed", self.onIcmpBaseDialogChanged)

        # service dialog

        self.serviceDialog = builder.get_object("serviceDialog")
        self.serviceDialogOkButton = builder.get_object("serviceDialogOkButton")
        self.serviceDialogCancelButton = \
            builder.get_object("serviceDialogCancelButton")
        self.serviceDialogServiceView = \
            builder.get_object("serviceDialogServiceView")
        self.serviceDialogServiceStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.serviceDialogServiceView.append_column(
            Gtk.TreeViewColumn("Service", Gtk.CellRendererText(), text=0))
        self.serviceDialogServiceView.set_model(self.serviceDialogServiceStore)
        self.serviceDialogServiceView.get_selection().connect( \
            "changed", self.change_service_selection_cb)

        # icmptype dialog

        self.icmptypeDialog = builder.get_object("icmptypeDialog")
        self.icmptypeDialogOkButton = \
            builder.get_object("icmptypeDialogOkButton")
        self.icmptypeDialogCancelButton = \
            builder.get_object("icmptypeDialogCancelButton")
        self.icmptypeDialogIcmptypeView = \
            builder.get_object("icmptypeDialogIcmptypeView")

        self.icmptypeDialogIcmptypeStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.icmptypeDialogIcmptypeView.append_column(
            Gtk.TreeViewColumn("ICMP Type", Gtk.CellRendererText(), text=0))
        self.icmptypeDialogIcmptypeView.set_model(
            self.icmptypeDialogIcmptypeStore)
        self.icmptypeDialogIcmptypeView.get_selection().connect( \
            "changed", self.change_icmptype_selection_cb)

        # firewall client

        self.fw = client.FirewallClient(wait=1)
        self.__use_exception_handler = True
        self.fw.setExceptionHandler(self._exception_handler)
        self.fw.setNotAuthorizedLoop(True)

        self.fw.connect("panic-mode-enabled", self.panic_mode_enabled_cb)
        self.fw.connect("panic-mode-disabled", self.panic_mode_disabled_cb)

        self.fw.connect("connection-changed", self.connection_changed)

        self.fw.connect("default-zone-changed", self.default_zone_changed_cb)
        self.fw.connect("reloaded", self.reload_cb)
        self.fw.connect("lockdown-enabled", self.lockdown_enabled_cb)
        self.fw.connect("lockdown-disabled", self.lockdown_disabled_cb)

        self.fw.connect("log-denied-changed", self.log_denied_changed_cb)

        self.fw.connect("service-added", self.service_added_cb)
        self.fw.connect("service-removed", self.service_removed_cb)
        self.fw.connect("port-added", self.port_added_cb)
        self.fw.connect("port-removed", self.port_removed_cb)
        self.fw.connect("protocol-added", self.protocol_added_cb)
        self.fw.connect("protocol-removed", self.protocol_removed_cb)
        self.fw.connect("source-port-added", self.source_port_added_cb)
        self.fw.connect("source-port-removed", self.source_port_removed_cb)
        self.fw.connect("masquerade-added", self.masquerade_added_cb)
        self.fw.connect("masquerade-removed", self.masquerade_removed_cb)
        self.fw.connect("forward-port-added", self.forward_port_added_cb)
        self.fw.connect("forward-port-removed", self.forward_port_removed_cb)
        self.fw.connect("icmp-block-added", self.icmp_added_cb)
        self.fw.connect("icmp-block-removed", self.icmp_removed_cb)
        self.fw.connect("icmp-block-inversion-added",
                        self.icmp_inversion_added_cb)
        self.fw.connect("icmp-block-inversion-removed",
                        self.icmp_inversion_removed_cb)
        self.fw.connect("richrule-added", self.richrule_added_cb)
        self.fw.connect("richrule-removed", self.richrule_removed_cb)
        self.fw.connect("interface-added", self.interface_added_cb)
        self.fw.connect("interface-removed", self.interface_removed_cb)
        self.fw.connect("zone-of-interface-changed",
                        self.zone_of_interface_changed_cb)
        self.fw.connect("source-added", self.source_added_cb)
        self.fw.connect("source-removed", self.source_removed_cb)
        self.fw.connect("zone-of-source-changed",
                        self.zone_of_source_changed_cb)

        self.fw.connect("ipset-entry-added", self.ipset_entry_added_cb)
        self.fw.connect("ipset-entry-removed", self.ipset_entry_removed_cb)

        self.fw.connect("lockdown-whitelist-command-added",
                        self.lockdown_whitelist_command_added_cb)
        self.fw.connect("lockdown-whitelist-command-removed",
                        self.lockdown_whitelist_command_removed_cb)
        self.fw.connect("lockdown-whitelist-context-added",
                        self.lockdown_whitelist_context_added_cb)
        self.fw.connect("lockdown-whitelist-context-removed",
                        self.lockdown_whitelist_context_removed_cb)
        self.fw.connect("lockdown-whitelist-uid-added",
                        self.lockdown_whitelist_uid_added_cb)
        self.fw.connect("lockdown-whitelist-uid-removed",
                        self.lockdown_whitelist_uid_removed_cb)
        self.fw.connect("lockdown-whitelist-user-added",
                        self.lockdown_whitelist_user_added_cb)
        self.fw.connect("lockdown-whitelist-user-removed",
                        self.lockdown_whitelist_user_removed_cb)

        self.fw.connect("direct:chain-added", self.direct_chain_added_cb)
        self.fw.connect("direct:chain-removed", self.direct_chain_removed_cb)
        self.fw.connect("direct:rule-added", self.direct_rule_added_cb)
        self.fw.connect("direct:rule-removed", self.direct_rule_removed_cb)
        self.fw.connect("direct:passthrough-added", self.direct_passthrough_added_cb)
        self.fw.connect("direct:passthrough-removed", self.direct_passthrough_removed_cb)
        self.fw.connect("config:direct:updated", self.direct_updated_cb)

        self.fw.connect("config:zone-added", self.conf_zone_added_cb)
        self.fw.connect("config:zone-updated", self.conf_zone_updated_cb)
        self.fw.connect("config:zone-removed", self.conf_zone_removed_cb)
        self.fw.connect("config:zone-renamed", self.conf_zone_renamed_cb)
        self.fw.connect("config:ipset-added", self.conf_ipset_added_cb)
        self.fw.connect("config:ipset-updated", self.conf_ipset_updated_cb)
        self.fw.connect("config:ipset-removed", self.conf_ipset_removed_cb)
        self.fw.connect("config:ipset-renamed", self.conf_ipset_renamed_cb)
        self.fw.connect("config:service-added", self.conf_service_added_cb)
        self.fw.connect("config:service-updated", self.conf_service_updated_cb)
        self.fw.connect("config:service-removed", self.conf_service_removed_cb)
        self.fw.connect("config:service-renamed", self.conf_service_renamed_cb)
        self.fw.connect("config:icmptype-added", self.conf_icmp_added_cb)
        self.fw.connect("config:icmptype-updated", self.conf_icmp_updated_cb)
        self.fw.connect("config:icmptype-removed", self.conf_icmp_removed_cb)
        self.fw.connect("config:icmptype-renamed", self.conf_icmp_renamed_cb)
        self.fw.connect("config:helper-added", self.conf_helper_added_cb)
        self.fw.connect("config:helper-updated", self.conf_helper_updated_cb)
        self.fw.connect("config:helper-removed", self.conf_helper_removed_cb)
        self.fw.connect("config:helper-renamed", self.conf_helper_renamed_cb)
        self.fw.connect("config:policies:lockdown-whitelist-updated",
                        self.lockdown_whitelist_updated_cb)

        # settings

        self.settings.connect("changed::show-ipsets",
                              self.settings_show_ipsets_changed)
        self.settings_show_ipsets_changed(self.settings, "show-ipsets")

        self.settings.connect("changed::show-icmp-types",
                              self.settings_show_icmp_types_changed)
        self.settings_show_icmp_types_changed(self.settings, "show-icmp-types")

        self.settings.connect("changed::show-direct",
                              self.settings_show_direct_changed)
        self.settings_show_direct_changed(self.settings, "show-direct")

        self.settings.connect("changed::show-helpers",
                              self.settings_show_helpers_changed)
        self.settings_show_helpers_changed(self.settings, "show-helpers")

        self.settings.connect("changed::show-lockdown-whitelist",
                              self.settings_show_lockdown_whitelist_changed)
        self.settings_show_lockdown_whitelist_changed(self.settings,
                                                      "show-lockdown-whitelist")
        self.settings.connect("changed::show-active-bindings",
                              self.settings_show_active_bindings_changed)
        self.settings_show_active_bindings_changed(self.settings,
                                                   "show-active-bindings")

        # connect

        self.connections = { }
        self.connections_name = { }

        if nm_is_imported():
            self.fw.bus.add_signal_receiver(
                self.nm_signal_receiver,
                dbus_interface=nm_get_dbus_interface(),
                signal_name='PropertiesChanged',
                member_keyword='member')
        else:
            text = _("No NetworkManager imports available")
            self._warning(text)
        self.nm_signal_receiver()

        # start with no connection

        self.connection_changed()

        # mainloop

        self.mainWindow.show()
        self.mainloop = GLib.MainLoop()
        try:
            self.mainloop.run()
        except KeyboardInterrupt:
            self.onQuit()

    def add_visible_dialog(self, dialog):
        self.visible_dialogs.append(dialog)

    def remove_visible_dialog(self, dialog):
        self.visible_dialogs.append(dialog)

    def hide_and_remove_visible_dialogs(self):
        while len(self.visible_dialogs) > 0:
            dialog = self.visible_dialogs.pop()
            dialog.hide()

    def left_menu_cb(self, widget, menu):
        menu.show_all()

    def no_select(self, item):
        item.deselect()

    def change_zone_interface_editor(self, item, interface, zone):
        if interface in self.zone_interface_editors:
            return self.zone_interface_editors[interface].present()

        editor = ZoneInterfaceEditor(self.fw, interface, zone)
        editor.set_icon(self.icon)
        editor.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        editor.set_transient_for(self.mainWindow)
        self.zone_interface_editors[interface] = editor

        editor.show_all()
        result = editor.run()
        editor.hide()
        if result == 2:
            self.fw.changeZoneOfInterface(editor.get_zone(), interface)
        del self.zone_interface_editors[interface]

    def change_zone_connection_editor(self, item, connection, connection_name, zone):
        if connection in self.zone_connection_editors:
            return self.zone_connection_editors[connection].present()

        editor = ZoneConnectionEditor(self.fw, connection, connection_name, zone)
        editor.set_icon(self.icon)
        editor.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        editor.set_transient_for(self.mainWindow)
        self.zone_connection_editors[connection] = editor

        editor.show_all()
        editor.run()
        editor.hide()
        del self.zone_connection_editors[connection]

    def change_zone_source_editor(self, item, source, zone):
        if source in self.zone_source_editors:
            return self.zone_source_editors[source].present()

        editor = ZoneSourceEditor(self.fw, source, zone)
        editor.set_icon(self.icon)
        editor.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        editor.set_transient_for(self.mainWindow)
        self.zone_source_editors[source] = editor

        editor.show_all()
        result = editor.run()
        editor.hide()
        if result == 2:
            self.fw.changeZoneOfSource(editor.get_zone(), source)
        del self.zone_source_editors[source]

    def onViewIPSet_toggled(self, button):
        self.settings.set_boolean("show-ipsets", button.get_active())

    def settings_show_ipsets_changed(self, settings, key):
        self.show_ipsets = settings.get_boolean(key)
        self.ipsetsBox.set_visible(self.show_ipsets)
        self.ipsetsMenuitem.set_active(self.show_ipsets)

        if self.show_ipsets:
            if self.fw.connected:
                self.load_ipsets()
        else:
            self.ipsetConfIPSetStore.clear()

    def onViewICMPTypes_toggled(self, button):
        self.settings.set_boolean("show-icmp-types", button.get_active())

    def settings_show_icmp_types_changed(self, settings, key):
        self.show_icmp_types = settings.get_boolean(key)
        self.icmpTypesBox.set_visible(self.show_icmp_types)
        self.icmpTypesMenuitem.set_active(self.show_icmp_types)

        if self.show_icmp_types:
            if self.fw.connected:
                self.load_icmps()
        else:
            self.icmpDialogIcmpStore.clear()

    def onViewHelpers_toggled(self, button):
        self.settings.set_boolean("show-helpers", button.get_active())

    def settings_show_helpers_changed(self, settings, key):
        self.show_helpers = settings.get_boolean(key)
        self.helpersBox.set_visible(self.show_helpers)
        self.helpersMenuitem.set_active(self.show_helpers)

        if self.show_helpers:
            if self.fw.connected:
                self.load_helpers()
        else:
            self.helperConfHelperStore.clear()

    def onViewDirect_toggled(self, button):
        self.settings.set_boolean("show-direct", button.get_active())

    def settings_show_direct_changed(self, settings, key):
        self.show_direct = settings.get_boolean(key)
        self.directBox.set_visible(self.show_direct)
        self.directMenuitem.set_active(self.show_direct)

        if self.show_direct:
            if self.fw.connected:
                self.load_direct()
        else:
            self.directChainStore.clear()
            self.directRuleStore.clear()
            self.directPassthroughStore.clear()

    def onViewLockdownWhitelist_toggled(self, button):
        self.settings.set_boolean("show-lockdown-whitelist",
                                  button.get_active())

    def settings_show_lockdown_whitelist_changed(self, settings, key):
        self.show_lockdown_whitelist = settings.get_boolean(key)
        self.lockdownWhitelistBox.set_visible(self.show_lockdown_whitelist)
        self.lockdownWhitelistMenuitem.set_active(self.show_lockdown_whitelist)

        if self.show_lockdown_whitelist:
            if self.fw.connected:
                self.load_lockdown_whitelist()
        else:
            self.lockdownContextStore.clear()
            self.lockdownCommandStore.clear()
            self.lockdownUserStore.clear()
            self.lockdownUidStore.clear()

    def settings_show_active_bindings_changed(self, settings, key):
        self.show_active_bindings = settings.get_boolean(key)
        self.activeBindingsMenuitem.set_active(self.show_active_bindings)
        if self.show_active_bindings != self.bindingsExpander.get_expanded():
            self.bindingsExpander.set_expanded(self.show_active_bindings)

    def onViewActiveBindings_toggled(self, button):
        self.settings.set_boolean("show-active-bindings",
                                  button.get_active())

    def bindings_expander_changed(self, *args):
        self.show_active_bindings = self.bindingsExpander.get_expanded()
        self.settings.set_boolean("show-active-bindings",
                                  self.show_active_bindings)
        self.activeBindingsMenuitem.set_active(self.show_active_bindings)

    def nm_signal_receiver(self, *args, **kwargs):
        #print("nm_signal_receiver", args, kwargs)
        self.update_active_zones()

        self.connections.clear()
        self.connections_name.clear()

        # do not use NMClient could result in python core dump

        if nm_is_imported():
            try:
                nm_get_connections(self.connections, self.connections_name)
            except Exception:
                text = _("Failed to get connections from NetworkManager")
                self._warning(text)

        iter = self.interfaceStore.get_iter_first()
        while iter:
            interface = self.interfaceStore.get_value(iter, 0)
            if interface in self.connections:
                connection = self.connections[interface]
                connection_name = self.connections_name[connection]
                zone = nm_get_zone_of_connection(connection)
                if zone == "":
                    comment = self.default_zone_used_by_label % \
                              connection_name
                else:
                    comment = self.used_by_label % connection_name
                self.interfaceStore.set_value(iter, 1, comment)
            iter = self.interfaceStore.iter_next(iter)
        self.change_interface_selection_cb(self.interfaceView.get_selection())

    def _dialog(self, text, msg=None, title=None,
                message_type=Gtk.MessageType.INFO,
                buttons=[("gtk-close", 1)]):
        dialog = Gtk.MessageDialog(parent=None, flags=0,
                                   message_type=message_type)
        dialog.set_markup(text)
        if title:
            dialog.set_title(title)
        if msg:
            dialog.format_secondary_markup(msg)
        if len(buttons) > 0:
            for button,id in buttons:
                dialog.add_button(button, id)
        dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        dialog.set_transient_for(self.mainWindow)
        result = dialog.run()
        dialog.hide()
        return result

    def _warning(self, msg):
        dialog = Gtk.MessageDialog(parent=None, flags=0,
                                   message_type=Gtk.MessageType.WARNING)
        dialog.set_markup("<b>" + _("Warning") + "</b>")
        dialog.format_secondary_markup(msg)
        dialog.add_button("gtk-close", 1)
        dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        dialog.set_transient_for(self.mainWindow)
        dialog.run()
        dialog.hide()

    def _error(self, msg):
        if self._dialog("<b>"+_("Error")+"</b>",
                        message_type=Gtk.MessageType.ERROR, msg=msg,
                        buttons=(("gtk-ok", 0),("gtk-quit", 1))) == 1:
            self.onQuit()

    def connection_failed(self, msg):
        if self._dialog("<b>"+_("Error")+"</b>",
                        message_type=Gtk.MessageType.ERROR, msg=msg,
                        buttons=[("gtk-quit", 1)]) == 1:
            self.onQuit()

    def connection_changed(self):
        if self.connection_timer:
            GLib.source_remove(self.connection_timer)
            self.connection_timer = None
        if self.fw.connected:
            self.fw.authorizeAll()
            self.statusLabel.set_text(self.connected_label)
            self.default_zone = self.fw.getDefaultZone()
            self.defaultZoneLabel.set_text(self.default_zone)
            self.log_denied = self.fw.getLogDenied()
            self.logDeniedLabel.set_text(self.log_denied)
            self.automatic_helpers = self.fw.getAutomaticHelpers()
            self.set_automaticHelpersLabel(self.automatic_helpers)
            lockdown = self.fw.queryLockdown()
            if lockdown:
                self.lockdownLabel.set_text(self.enabled)
            else:
                self.lockdownLabel.set_text(self.disabled)
            panic = self.fw.queryPanicMode()
            if panic:
                self.panicLabel.set_text(self.enabled)
            else:
                self.panicLabel.set_text(self.disabled)
            self.modifiedLabel.set_text("")
            self.lockdownMenuitem.handler_block(self.lockdown_check_id)
            self.lockdownMenuitem.set_active(lockdown)
            self.lockdownMenuitem.handler_unblock(self.lockdown_check_id)
            self.panicMenuitem.handler_block(self.panic_check_id)
            self.panicMenuitem.set_active(panic)
            self.panicMenuitem.handler_unblock(self.panic_check_id)

            self.nf_conntrack_helpers = \
                self.fw.get_property("nf_conntrack_helpers")
            for x in self.nf_conntrack_helpers.keys():
                self.moduleDialogModuleCombobox.append_text(x)

            if self.connection_lost:
                self.onChangeView()
            else:
                self.currentViewCombobox.set_active(0)

            self.waitingWindow.hide()
            self.waitingWindowSpinner.stop()

        else:
            if self.statusLabel.get_text() == self.connected_label:
                self.connection_lost = True
            self.statusLabel.set_text(self.trying_to_connect_label)
            self.defaultZoneLabel.set_text("-")
            self.lockdownLabel.set_text("-")
            self.panicLabel.set_text("-")

            self.moduleDialogModuleCombobox.remove_all()
            self.nf_conntrack_helpers.clear()

            self.hide_and_remove_visible_dialogs()
            self.waitingWindow.show()
            self.waitingWindowLabel.set_text(self.trying_to_connect_label)
            self.waitingWindowSpinner.start()

            self.connection_timer = GLib.timeout_add_seconds(
                15, self.connection_failed, self.failed_to_connect_label)

        self.update_active_zones()
        self.mainPaned.set_sensitive(self.fw.connected)
        # make all entries in options menu (in)sensitive
        for child in self.optionsMenuitem.get_submenu().get_children():
            child.set_sensitive(self.fw.connected)
        # make all entries in view menu (in)sensitive
        for child in self.viewMenuitem.get_submenu().get_children():
            child.set_sensitive(self.fw.connected)

    def changes_applied(self):
        self.modifiedLabel.set_text(self.changes_applied_label)
        if self.modified_timer:
            GLib.source_remove(self.modified_timer)
        self.modified_timer = GLib.timeout_add_seconds(
            5, self.clear_changes_applied, None)

    def clear_changes_applied(self, *args):
        self.modifiedLabel.set_text("")
        self.modified_timer = None

    def panic_mode_enabled_cb(self):
        self.panicLabel.set_text(self.enabled)
        self.panicMenuitem.handler_block(self.panic_check_id)
        self.panicMenuitem.set_active(True)
        self.panicMenuitem.handler_unblock(self.panic_check_id)

    def panic_mode_disabled_cb(self):
        self.panicLabel.set_text(self.disabled)
        self.panicMenuitem.handler_block(self.panic_check_id)
        self.panicMenuitem.set_active(False)
        self.panicMenuitem.handler_unblock(self.panic_check_id)

    def reload_cb(self):
        self.default_zone = self.fw.getDefaultZone()
        self.defaultZoneLabel.set_text(self.default_zone)
        self.log_denied = self.fw.getLogDenied()
        self.logDeniedLabel.set_text(self.log_denied)
        self.automatic_helpers = self.fw.getAutomaticHelpers()
        self.set_automaticHelpersLabel(self.automatic_helpers)
        self.load_ipsets()
        self.load_zones()
        self.load_services()
        self.load_icmps()
        self.load_helpers()
        self.load_direct()
        self.load_lockdown_whitelist()
        self.update_active_zones()

    def load_zones(self):
        selected_zone = self.get_selected_zone()

        if self.runtime_view:
            zones = self.fw.getZones()
        else:
            zones = self.fw.config().getZoneNames()

        # reset and fill notebook content according to view

        selection = self.zoneView.get_selection()
        selection.set_mode(Gtk.SelectionMode.NONE)

        self.zoneStore.clear()
        self.serviceStore.clear()
        self.portStore.clear()
        self.protocolStore.clear()
        self.forwardStore.clear()
        self.icmpStore.clear()
        self.richRuleStore.clear()
        self.interfaceStore.clear()
        self.sourceStore.clear()

        if self.runtime_view:
            for item in self.fw.listServices():
                self.serviceStore.append([False, item])
            for item in self.fw.listIcmpTypes():
                self.icmpStore.append([False, item])
        else:
            for item in self.fw.config().getServiceNames():
                self.serviceStore.append([False, item])
            for item in self.fw.config().getIcmpTypeNames():
                self.icmpStore.append([False, item])

        # zones
        active_zones = self.active_zones.keys()
        for zone in zones:
            if zone in active_zones:
                self.zoneStore.append([zone, Pango.Weight.BOLD])
            else:
                self.zoneStore.append([zone, Pango.Weight.NORMAL])

        if selected_zone in zones:
            _zone = selected_zone
        else:
            _zone = self.defaultZoneLabel.get_text()

        selection.set_mode(Gtk.SelectionMode.SINGLE)

        iter = self.zoneStore.get_iter_first()
        while iter:
            if self.zoneStore.get_value(iter, 0) == _zone:
                selection.select_iter(iter)
                return
            iter = self.zoneStore.iter_next(iter)
        # fallback
        selection.select_path(0)

        if not self.get_selected_zone():
            self.zoneEditEditButton.set_sensitive(False)
            self.zoneEditRemoveButton.set_sensitive(False)
            self.zoneEditLoadDefaultsButton.set_sensitive(False)
            self.zoneNotebook.set_sensitive(False)

    def get_active_service(self):
        selection = self.serviceConfServiceView.get_selection()
        (model, iter) = selection.get_selected()
        if iter:
            return self.serviceConfServiceStore.get_value(iter, 0)
        return None

    def load_services(self):
        active_service = self.get_active_service()

        if self.runtime_view:
            services = self.fw.listServices()
        else:
            services = self.fw.config().getServiceNames()

        selection = self.serviceConfServiceView.get_selection()
        selection.set_mode(Gtk.SelectionMode.NONE)

        # reset and fill notebook content according to view

        self.serviceConfServiceStore.clear()

        # services

        for service in services:
            self.serviceConfServiceStore.append([service])

        selection.set_mode(Gtk.SelectionMode.SINGLE)

        iter = self.serviceConfServiceStore.get_iter_first()
        while iter:
            if self.serviceConfServiceStore.get_value(iter, 0) == \
                    active_service:
                selection.select_iter(iter)
                return
            iter = self.serviceConfServiceStore.iter_next(iter)
        selection.select_path(0)

        if not self.get_active_service():
            self.serviceConfEditServiceButton.set_sensitive(False)
            self.serviceConfRemoveServiceButton.set_sensitive(False)
            self.serviceConfLoadDefaultsServiceButton.set_sensitive(False)
            self.serviceConfServiceNotebook.set_sensitive(False)

    def change_rich_rule_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editRichRuleButton.set_sensitive(True)
            self.removeRichRuleButton.set_sensitive(True)
        else:
            self.editRichRuleButton.set_sensitive(False)
            self.removeRichRuleButton.set_sensitive(False)

    def service_added_cb(self, zone, service, timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.serviceStore.get_iter_first()
        while iter:
            if self.serviceStore.get_value(iter, 1) == service:
                self.serviceStore.set_value(iter, 0, True)
                break
            iter = self.serviceStore.iter_next(iter)

    def service_removed_cb(self, zone, service):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.serviceStore.get_iter_first()
        while iter:
            if self.serviceStore.get_value(iter, 1) == service:
                self.serviceStore.set_value(iter, 0, False)
                break
            iter = self.serviceStore.iter_next(iter)

    def service_toggle_cb(self, toggle, row, model, col):
        iter = model.get_iter(row)
        old_val = model.get(iter, col)[0]
        name = model.get(iter, 1)[0]
        selected_zone = self.get_selected_zone()
        if self.runtime_view:
            if not old_val:
                self.fw.addService(selected_zone, name)
            else:
                self.fw.removeService(selected_zone, name)
            self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not old_val:
                zone.addService(name)
            else:
                zone.removeService(name)
            self.changes_applied()

    def change_port_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editPortButton.set_sensitive(True)
            self.removePortButton.set_sensitive(True)
        else:
            self.editPortButton.set_sensitive(False)
            self.removePortButton.set_sensitive(False)

    def change_source_port_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editSourcePortButton.set_sensitive(True)
            self.removeSourcePortButton.set_sensitive(True)
        else:
            self.editSourcePortButton.set_sensitive(False)
            self.removeSourcePortButton.set_sensitive(False)

    def change_protocol_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editProtocolButton.set_sensitive(True)
            self.removeProtocolButton.set_sensitive(True)
        else:
            self.editProtocolButton.set_sensitive(False)
            self.removeProtocolButton.set_sensitive(False)

    def change_forward_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editForwardButton.set_sensitive(True)
            self.removeForwardButton.set_sensitive(True)
        else:
            self.editForwardButton.set_sensitive(False)
            self.removeForwardButton.set_sensitive(False)

    def masquerade_check_cb(self, *args):
        selected_zone = self.get_selected_zone()
        if self.runtime_view:
            if not self.masqueradeCheck.get_active():
                if not self.fw.queryMasquerade(selected_zone):
                    self.fw.addMasquerade(selected_zone)
                    self.changes_applied()
            else:
                if self.fw.queryMasquerade(selected_zone):
                    self.fw.removeMasquerade(selected_zone)
                    self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.setMasquerade(not self.masqueradeCheck.get_active())
            self.changes_applied()

    def masquerade_added_cb(self, zone, timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        self.masqueradeCheck.set_active(True)

    def masquerade_removed_cb(self, zone):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        self.masqueradeCheck.set_active(False)

    def icmp_toggle_cb(self, toggle, row, model, col):
        iter = model.get_iter(row)
        old_val = model.get(iter, col)[0]
        name = model.get(iter, 1)[0]
        selected_zone = self.get_selected_zone()
        if self.runtime_view:
            if not old_val:
                self.fw.addIcmpBlock(selected_zone, name)
            else:
                self.fw.removeIcmpBlock(selected_zone, name)
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not old_val:
                zone.addIcmpBlock(name)
            else:
                zone.removeIcmpBlock(name)
        self.changes_applied()

    def icmp_added_cb(self, zone, icmp, timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.icmpStore.get_iter_first()
        while iter:
            if self.icmpStore.get_value(iter, 1) == icmp:
                self.icmpStore.set_value(iter, 0, True)
                break
            iter = self.icmpStore.iter_next(iter)

    def icmp_removed_cb(self, zone, icmp):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.icmpStore.get_iter_first()
        while iter:
            if self.icmpStore.get_value(iter, 1) == icmp:
                self.icmpStore.set_value(iter, 0, False)
                break
            iter = self.icmpStore.iter_next(iter)

    def icmp_block_inversion_check_cb(self, *args):
        selected_zone = self.get_selected_zone()
        if self.runtime_view:
            if not self.icmpBlockInversionCheck.get_active():
                if not self.fw.queryIcmpBlockInversion(selected_zone):
                    self.fw.addIcmpBlockInversion(selected_zone)
                    self.changes_applied()
            else:
                if self.fw.queryIcmpBlockInversion(selected_zone):
                    self.fw.removeIcmpBlockInversion(selected_zone)
                    self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.setIcmpBlockInversion(not self.icmpBlockInversionCheck.get_active())
            self.changes_applied()

    def icmp_inversion_added_cb(self, zone):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        self.icmpBlockInversionCheck.set_active(True)

    def icmp_inversion_removed_cb(self, zone):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        self.icmpBlockInversionCheck.set_active(False)

    def _add_rich_rule(self, obj):
        family = "all"
        priority = 0
        src = ""
        dest = ""
        elem = ""
        log = ""
        audit = ""
        action = ""

        if obj.family:
            family = obj.family
        if obj.priority:
            priority = obj.priority
        if obj.action:
            if type(obj.action) == rich.Rich_Accept:
                action = _("accept")
            elif type(obj.action) == rich.Rich_Reject:
                action = _("reject")
                if obj.action.type is not None:
                    action += "\n" + obj.action.type
            elif type(obj.action) == rich.Rich_Drop:
                action = _("drop")
            elif type(obj.action) == rich.Rich_Mark:
                action = _("mark")
                action += "\nset " + obj.action.set
            if obj.action.limit:
                action += "\n" + _("limit") + " " + obj.action.limit.value
        if obj.source:
            if obj.source.invert:
                src = "! "
            if obj.source.addr:
                src += "IP: %s" % obj.source.addr
            elif obj.source.mac:
                src += "MAC: %s" % obj.source.mac
            elif obj.source.ipset:
                src += "ipset:%s" % obj.source.ipset
        if obj.destination:
            dest = obj.destination.addr
            if obj.destination.invert:
                dest = "! %s" % dest
        if obj.element:
            if type(obj.element) == rich.Rich_Service:
                elem = _("service") + "\n" + obj.element.name
            elif type(obj.element) == rich.Rich_Port:
                elem = _("port") + "\n%s/%s" % (obj.element.port,
                                                obj.element.protocol)
            elif type(obj.element) == rich.Rich_Protocol:
                elem = _("protocol") + "\n" + obj.element.value
            elif type(obj.element) == rich.Rich_Masquerade:
                elem = _("masquerade")
            elif type(obj.element) == rich.Rich_IcmpBlock:
                elem = _("icmp-block") + "\n%s" % obj.element.name
            elif type(obj.element) == rich.Rich_IcmpType:
                elem = _("icmp-type") + "\n%s" % obj.element.name
            elif type(obj.element) == rich.Rich_ForwardPort:
                elem = _("forward-port") + "\n%s" % self.create_fwp_string(
                    obj.element.port, obj.element.protocol,
                    obj.element.to_port, obj.element.to_address)
            elif type(obj.element) == rich.Rich_SourcePort:
                elem = _("source-port") + "\n%s/%s" % (obj.element.port,
                                                       obj.element.protocol)
            else:
                elem = str(obj.element)

        if obj.log:
            if obj.log.prefix:
                log = '"%s"' % obj.log.prefix
            if obj.log.level:
                log += "\n" + _("level") + " " + obj.log.level
            if obj.log.limit:
                log += "\n" + _("limit") + " " + obj.log.limit.value
            if log == "":
                log = _("yes")
        if obj.audit:
            if obj.audit.limit:
                audit += "\n" + _("limit") + " " + obj.audit.limit.value
            if audit == "":
                audit = _("yes")

        self.richRuleStore.append([obj, family, priority, action, elem, src,
                                   dest, log, audit])

    def richrule_added_cb(self, zone, rule, timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        obj = rich.Rich_Rule(rule_str=rule)
        iter = self.richRuleStore.get_iter_first()
        while iter:
            if str(self.richRuleStore.get_value(iter, 0)) == str(obj):
                # already there
                return
            iter = self.richRuleStore.iter_next(iter)
        # nothing found, so add it
        self._add_rich_rule(obj)

    def richrule_removed_cb(self, zone, rule):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        obj = rich.Rich_Rule(rule_str=rule)
        iter = self.richRuleStore.get_iter_first()
        while iter:
            if str(self.richRuleStore.get_value(iter, 0)) == str(obj):
                self.richRuleStore.remove(iter)
                break
            iter = self.richRuleStore.iter_next(iter)

    def _add_interface(self, interface):
        comment = ""
        if interface in self.connections:
            zone = nm_get_zone_of_connection(self.connections[interface])
            if zone == "":
                comment = self.default_zone_used_by_label % \
                          self.connections[interface]
            else:
                comment = self.used_by_label % self.connections[interface]
        self.interfaceStore.append([interface, comment])

    def interface_added_cb(self, zone, interface):
        self.update_active_zones()
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.interfaceStore.get_iter_first()
        while iter:
            if self.interfaceStore.get_value(iter, 0) == interface:
                # already there
                return
            iter = self.interfaceStore.iter_next(iter)
        # nothing found, so add it
        self._add_interface(interface)

    def interface_removed_cb(self, zone, interface):
        self.update_active_zones()
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.interfaceStore.get_iter_first()
        while iter:
            if self.interfaceStore.get_value(iter, 0) == interface:
                self.interfaceStore.remove(iter)
                break
            iter = self.interfaceStore.iter_next(iter)

    def zone_of_interface_changed_cb(self, zone, interface):
        self.update_active_zones()
        if not self.runtime_view:
            return
        iter = self.interfaceStore.get_iter_first()
        while iter:
            if self.interfaceStore.get_value(iter, 0) == interface:
                # it is here, remove it
                self.interfaceStore.remove(iter)
            iter = self.interfaceStore.iter_next(iter)
        # add if zone is active_zone
        if zone == self.get_selected_zone():
            self._add_interface(interface)

    def source_added_cb(self, zone, source):
        self.update_active_zones()
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.sourceStore.get_iter_first()
        while iter:
            if self.sourceStore.get_value(iter, 0) == source:
                # already there
                return
            iter = self.sourceStore.iter_next(iter)
        # nothing found, so add it
        self.sourceStore.append([source])

    def source_removed_cb(self, zone, source):
        self.update_active_zones()
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.sourceStore.get_iter_first()
        while iter:
            if self.sourceStore.get_value(iter, 0) == source:
                self.sourceStore.remove(iter)
                break
            iter = self.sourceStore.iter_next(iter)

    def zone_of_source_changed_cb(self, zone, source):
        self.update_active_zones()
        if not self.runtime_view:
            return
        iter = self.sourceStore.get_iter_first()
        while iter:
            if self.sourceStore.get_value(iter, 0) == source:
                # it is here, remove it
                self.sourceStore.remove(iter)
            iter = self.sourceStore.iter_next(iter)
        # add if zone is active_zone
        if zone == self.get_selected_zone():
            self.sourceStore.append([source])

    def conf_zone_added_cb(self, zone):
        if self.runtime_view:
            return
        # check if zone is in store
        iter = self.zoneStore.get_iter_first()
        while iter:
            if self.zoneStore.get_value(iter, 0) == zone:
                return
            iter = self.zoneStore.iter_next(iter)
        # not in list, append
        if zone in self.active_zones:
            self.zoneStore.append([zone, Pango.Weight.BOLD])
        else:
            self.zoneStore.append([zone, Pango.Weight.NORMAL])
        selection = self.zoneView.get_selection()
        if selection.count_selected_rows() == 0:
            selection.select_path(0)

    def conf_zone_updated_cb(self, zone):
        if self.runtime_view or zone != self.get_selected_zone():
            return
        self.onChangeZone()

    def conf_zone_removed_cb(self, zone):
        if self.runtime_view:
            return
        iter = self.zoneStore.get_iter_first()
        while iter:
            if self.zoneStore.get_value(iter, 0) == zone:
                self.zoneStore.remove(iter)
                break
            iter = self.zoneStore.iter_next(iter)

    def conf_zone_renamed_cb(self, zone):
        if self.runtime_view:
            return

        # Get all zones, renamed the one that is missing.
        # If more or less than one is missing, update zone store.

        zones = self.fw.config().getZoneNames()

        use_iter = None
        iter = self.zoneStore.get_iter_first()
        while iter:
            if self.zoneStore.get_value(iter, 0) not in zones:
                if use_iter is not None:
                    return self.load_zones()
                use_iter = iter
            iter = self.zoneStore.iter_next(iter)

        if use_iter is None:
            return self.load_zones()

        self.zoneStore.set_value(use_iter, 0, zone)

    def deactivate_exception_handler(self):
        self.__use_exception_handler = False

    def activate_exception_handler(self):
        self.__use_exception_handler = True

    def _exception_handler(self, exception_message):
        if not self.__use_exception_handler:
            raise
        if "NotAuthorizedException" in exception_message:
            self._error(_("Authorization failed."))
        elif "INVALID_NAME" in exception_message:
            msg = exception_message.replace("INVALID_NAME",
                                            functions.b2u(_("Invalid name")))
            self._warning(msg)
        elif "NAME_CONFLICT" in exception_message:
            msg = exception_message.replace(
                "NAME_CONFLICT", functions.b2u(_("Name already exists")))
            self._warning(msg)
        elif "NO_DEFAULTS" in exception_message:
            pass
        else:
            self._error(exception_message)

    def get_selected_zone(self):
        selection = self.zoneView.get_selection()
        (model, iter) = selection.get_selected()
        if iter:
            return self.zoneStore.get_value(iter, 0)
        return None

    def onQuit(self, *args):
        self.mainloop.quit()
        sys.exit()

    def onAbout(self, *args):
        self.aboutDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.aboutDialog.set_transient_for(self.mainWindow)
        self.aboutDialog.show_all()
        self.aboutDialog.run()
        self.aboutDialog.hide()

    def onReloadFirewalld(self, *args):
        self.fw.reload()

    def onChangeView(self, *args):
        # Fix interaction problem of changed event of gtk combobox with
        # polkit-kde by processing all remaining events.
        #
        # The changed callback is signaled before the popup window has been
        # destroyed and before the focus (keyboard and mouse) has been reset.
        # This results in a deadlock in KDE and Qt, because the polkit KDE
        # agent can not get the focus and the user has no chance to enter the
        # desired password into the agent and is also not able to close the
        # agent with the mouse. The focus is still on the combobox popup.
        Gdk.DisplayManager.get().get_default_display().flush()

        self.fw.authorizeAll()

        self.runtime_view = (self.currentViewCombobox.get_active_text() == \
                                 _("Runtime"))

        self.zoneEditBox.set_sensitive(not self.runtime_view)
        self.serviceConfDestinationGrid.set_sensitive(not self.runtime_view)
        self.icmpDialogDestIpv4Check.set_sensitive(not self.runtime_view)
        self.icmpDialogDestIpv6Check.set_sensitive(not self.runtime_view)
        self.ipsetConfEntryBox.set_sensitive(False)

        if self.runtime_view:
            self.zoneEditBox.hide()
            self.ipsetConfIPSetEditBox.hide()
            self.serviceConfServiceEditBox.hide()
            self.serviceConfPortBox.hide()
            self.serviceConfProtocolBox.hide()
            self.serviceConfSourcePortBox.hide()
            self.serviceConfModuleBox.hide()
            self.icmpDialogIcmpEditBox.hide()
            self.helperConfHelperEditBox.hide()
            self.helperConfPortBox.hide()
        else:
            self.zoneEditBox.show()
            self.ipsetConfIPSetEditBox.show()
            self.serviceConfServiceEditBox.show()
            self.serviceConfPortBox.show()
            self.serviceConfProtocolBox.show()
            self.serviceConfSourcePortBox.show()
            self.serviceConfModuleBox.show()
            self.icmpDialogIcmpEditBox.show()
            self.helperConfHelperEditBox.show()
            self.helperConfPortBox.show()

        self.load_ipsets()
        self.load_zones()
        self.load_services()
        self.load_icmps()
        self.load_helpers()
        self.load_direct()
        self.load_lockdown_whitelist()

    def update_active_zones(self):
        self.active_zones.clear()

        # remove all entries for the left menu
        left_menu_children = self.left_menu.get_children()
        for child in left_menu_children:
            self.left_menu.remove(child)
            child.destroy()

        # add connecitons entry
        item = Gtk.MenuItem.new()
        label = Gtk.Label()
        label.set_markup(escape(_("Connections")))
        label.set_alignment(0, 0.5)
        item.add(label)
        item.connect("select", self.no_select)
        self.left_menu.append(item)

        if self.fw.connected:
            self.active_zones = self.fw.getActiveZones()
        else:
            self.active_zones = { }

        # clean bindingsView, leave connections, interfaces and sources entries
        self.bindingsView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        iter = self.bindingsStore.iter_children(self.connectionsIter)
        while iter:
            self.bindingsStore.remove(iter)
            iter = self.bindingsStore.iter_children(self.connectionsIter)
        iter = self.bindingsStore.iter_children(self.interfacesIter)
        while iter:
            self.bindingsStore.remove(iter)
            iter = self.bindingsStore.iter_children(self.interfacesIter)
        iter = self.bindingsStore.iter_children(self.sourcesIter)
        while iter:
            self.bindingsStore.remove(iter)
            iter = self.bindingsStore.iter_children(self.sourcesIter)
        self.changeBindingsButton.set_sensitive(False)

        # get all active connections (NM) and interfaces
        connections = { }
        interfaces = { }
        sources = { }
        for zone in sorted(self.active_zones):
            if "interfaces" in self.active_zones[zone]:
                for interface in sorted(self.active_zones[zone]["interfaces"]):
                    if interface not in self.connections:
                        interfaces[interface] = zone
            if "sources" in self.active_zones[zone]:
                for source in sorted(self.active_zones[zone]["sources"]):
                    sources[source] = zone
        # NM controlled connections
        for interface in self.connections:
            connection = self.connections[interface]
            if connection not in connections:
                zone = nm_get_zone_of_connection(connection)
                connections[connection] = [ zone, [ interface, ] ]
            else:
                connections[connection][1].append(interface)

        # add NM controlled entries
        for connection in sorted(connections):
            [ zone, _interfaces ] = connections[connection]
            connection_name = self.connections_name[connection]

            item = Gtk.MenuItem.new()
            hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
            label = Gtk.Label()
            if zone == "":
                label.set_markup("%s (%s)\n<small>%s: %s</small>" % \
                                 (connection_name, ",".join(_interfaces),
                                  escape(_("Default Zone")), self.default_zone))
            else:
                label.set_markup("%s (%s)\n<small>%s: %s</small>" % \
                                 (connection_name, ",".join(_interfaces),
                                  escape(_("Zone")), zone))
            label.set_alignment(0, 0.5)
            label.set_padding(12, 0)
            hbox.pack_start(label, True, True, 0)
            item.add(hbox)
            item.connect("activate", self.change_zone_connection_editor, connection, connection_name, zone)
            self.left_menu.append(item)

            if zone == "":
                self.bindingsStore.append(
                    self.connectionsIter,
                    [ "%s (%s)\n<small>%s</small>" % (
                        connection_name, ",".join(_interfaces),
                        _("Default Zone: %s") % self.default_zone),
                      connection, zone ])
            else:
                self.bindingsStore.append(
                    self.connectionsIter,
                    [ "%s (%s)\n<small>%s</small>" % (
                        connection_name, ",".join(_interfaces),
                        _("Zone: %s") % zone),
                      connection, zone ])

        item = Gtk.MenuItem.new()
        label = Gtk.Label()
        label.set_markup(escape(_("Interfaces")))
        label.set_alignment(0, 0.5)
        item.add(label)
        item.connect("select", self.no_select)
        self.left_menu.append(item)

        if len(interfaces) > 0:
            # add other interfaces
            for interface in sorted(interfaces):
                zone = interfaces[interface]

                item = Gtk.MenuItem.new()
                hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
                label = Gtk.Label()
                label.set_markup("%s\n<small>%s: %s</small>" % \
                                     (interface, escape(_("Zone")), zone))
                label.set_alignment(0, 0.5)
                label.set_padding(12, 0)
                hbox.pack_start(label, True, True, 0)
                item.add(hbox)
                item.connect("activate", self.change_zone_interface_editor, interface, zone)
                self.left_menu.append(item)

                self.bindingsStore.append(
                    self.interfacesIter,
                    [ "%s\n<small>%s</small>" % (interface,
                                                 _("Zone: %s") % zone),
                      interface, zone ])

        item = Gtk.MenuItem.new()
        label = Gtk.Label()
        label.set_markup(escape(_("Sources")))
        label.set_alignment(0, 0.5)
        item.add(label)
        item.connect("select", self.no_select)
        self.left_menu.append(item)

        if len(sources) > 0:
            for source in sorted(sources):
                zone = sources[source]

                item = Gtk.MenuItem.new()
                hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
                label = Gtk.Label()
                label.set_markup("%s\n<small>%s: %s</small>" % \
                                     (source, escape(_("Zone")),
                                      zone))
                label.set_alignment(0, 0.5)
                label.set_padding(12, 0)
                hbox.pack_start(label, True, True, 0)
                item.add(hbox)
                item.connect("activate", self.change_zone_source_editor, source, zone)
                self.left_menu.append(item)

                self.bindingsStore.append(
                    self.sourcesIter,
                    [ "%s\n<small>%s</small>" % (source, _("Zone: %s") % zone),
                      source, zone ])

        self.bindingsView.expand_all()
        self.bindingsView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)

        iter = self.zoneStore.get_iter_first()
        while iter:
            if self.zoneStore.get_value(iter, 0) in self.active_zones.keys():
                self.zoneStore.set_value(iter, 1, Pango.Weight.BOLD)
            else:
                self.zoneStore.set_value(iter, 1, Pango.Weight.NORMAL)
            iter = self.zoneStore.iter_next(iter)

    def onChangeDefaultZone(self, *args):
        self.defaultZoneStore.clear()
        zones = self.fw.getZones()
#        self.default_zone = self.fw.getDefaultZone()
        for zone in zones:
            if zone == self.default_zone:
                self.defaultZoneStore.append([zone, Pango.Weight.BOLD])
            else:
                self.defaultZoneStore.append([zone, Pango.Weight.NORMAL])
        selection = self.defaultZoneView.get_selection()
        if self.default_zone in zones:
            selection.select_path(zones.index(self.default_zone))
        else:
            selection.set_mode(Gtk.SelectionMode.NONE)

        self.defaultZoneDialogOkButton.set_sensitive(False)
        self.defaultZoneDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.defaultZoneDialog.set_transient_for(self.mainWindow)
        self.defaultZoneDialog.show_all()
        self.add_visible_dialog(self.defaultZoneDialog)
        result = self.defaultZoneDialog.run()
        self.defaultZoneDialog.hide()
        self.remove_visible_dialog(self.defaultZoneDialog)
        if result == 1:
            (model, iter) = selection.get_selected()
            if not iter:
                return
            new_default_zone = model.get(iter, 0)[0]
            if new_default_zone != self.default_zone:
                self.fw.setDefaultZone(new_default_zone)
                self.default_zone = new_default_zone
                self.changes_applied()

    def on_logDeniedDialogValueCombobox_changed(self, combo):
        self.logDeniedDialogOkButton.set_sensitive(
            combo.get_active_text() != self.log_denied)

    def onChangeLogDenied(self, *args):
        combobox_select_text(self.logDeniedDialogValueCombobox,
                             self.fw.getLogDenied())
        self.logDeniedDialogOkButton.set_sensitive(False)
        self.logDeniedDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.logDeniedDialog.set_transient_for(self.mainWindow)
        self.logDeniedDialog.show_all()
        self.add_visible_dialog(self.logDeniedDialog)
        result = self.logDeniedDialog.run()
        self.logDeniedDialog.hide()
        self.remove_visible_dialog(self.logDeniedDialog)
        if result == 1:
            value = self.logDeniedDialogValueCombobox.get_active_text()
            if value != self.log_denied:
                self.fw.setLogDenied(value)
                self.log_denied = value
                self.changes_applied()

    def log_denied_changed_cb(self, value):
        self.logDeniedLabel.set_text(value)
        combobox_select_text(self.logDeniedDialogValueCombobox, value)

    def set_automaticHelpersLabel(self, value):
        if value == "system":
            self.automaticHelpersLabel.set_text(
                "%s (%s)" % (value,
                             { 0:"off", 1:"on" }[
                                 self.fw.get_property("nf_conntrack_helper_setting")]))
        else:
            self.automaticHelpersLabel.set_text(value)

    def on_automaticHelpersDialogValueCombobox_changed(self, combo):
        self.automaticHelpersDialogOkButton.set_sensitive(
            combo.get_active_text() != self.automatic_helpers)

    def onChangeAutomaticHelpers(self, *args):
        combobox_select_text(self.automaticHelpersDialogValueCombobox,
                             self.fw.getAutomaticHelpers())
        self.automaticHelpersDialogOkButton.set_sensitive(False)
        self.automaticHelpersDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.automaticHelpersDialog.set_transient_for(self.mainWindow)
        self.automaticHelpersDialog.show_all()
        self.add_visible_dialog(self.automaticHelpersDialog)
        result = self.automaticHelpersDialog.run()
        self.automaticHelpersDialog.hide()
        self.remove_visible_dialog(self.automaticHelpersDialog)
        if result == 1:
            value = self.automaticHelpersDialogValueCombobox.get_active_text()
            if value != self.automatic_helpers:
                self.fw.setAutomaticHelpers(value)
                self.automatic_helpers = value
                self.changes_applied()

    def automatic_helpers_changed_cb(self, value):
        self.set_automaticHelpersLabel(value)
        combobox_select_text(self.automaticHelpersDialogValueCombobox, value)

    def onRuntimeToPermanent(self, *args):
        self.fw.runtimeToPermanent()

    def on_defaultZoneViewSelection_changed(self, selection):
        (model, iter) = selection.get_selected()
        if not iter:
            return
        new_default_zone = model.get(iter, 0)[0]
        self.defaultZoneDialogOkButton.set_sensitive( \
            new_default_zone != self.default_zone)

    def default_zone_changed_cb(self, zone):
        self.default_zone = zone
        self.defaultZoneLabel.set_text(zone)
        self.update_active_zones()

    def onSelectBinding(self, *args):
        selection = self.bindingsView.get_selection()
        (model, iter) = selection.get_selected()
        if not iter:
            self.changeBindingsButton.set_sensitive(False)
            return

        parent_iter = self.bindingsStore.iter_parent(iter)
        if parent_iter is None:
            selection.unselect_all()
            self.changeBindingsButton.set_sensitive(False)
            #self.editBindingsButton.set_sensitive(False)
            return
        if self.bindingsStore.get_value(parent_iter, 0) == _("Connections"):
            self.changeBindingsButton.set_sensitive(True)
            #self.editBindingsButton.set_sensitive(False)
        elif self.bindingsStore.get_value(parent_iter, 0) == _("Interfaces"):
            self.changeBindingsButton.set_sensitive(True)
            #self.editBindingsButton.set_sensitive(True)
        elif self.bindingsStore.get_value(parent_iter, 0) == _("Sources"):
            self.changeBindingsButton.set_sensitive(True)
            #self.editBindingsButton.set_sensitive(True)

    def onBindingClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.onChangeBinding()

    def onChangeBinding(self, *args):
        selection = self.bindingsView.get_selection()
        (model, iter) = selection.get_selected()
        if not iter:
            return
        parent_iter = self.bindingsStore.iter_parent(iter)
        if parent_iter is None:
            return

        item = self.bindingsStore.get_value(iter, 1)
        zone = self.bindingsStore.get_value(iter, 2)

        if self.bindingsStore.get_value(parent_iter, 0) == _("Connections"):
            self.change_zone_connection_editor(None, item, self.connections_name[item], zone)
        elif self.bindingsStore.get_value(parent_iter, 0) == _("Interfaces"):
            self.change_zone_interface_editor(None, item, zone)
        elif self.bindingsStore.get_value(parent_iter, 0) == _("Sources"):
            self.change_zone_source_editor(None, item, zone)

    #def onEditBindingClicked(self, widget, event):
    #    if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
    #        self.onEditBinding()

    #def onEditBinding(self, *args):
    #    return

    def onChangeZone(self, *args):
        selected_zone = self.get_selected_zone()

        ### load zone settings

        self.portStore.clear()
        self.protocolStore.clear()
        self.forwardStore.clear()
        self.sourcePortStore.clear()
        self.richRuleStore.clear()
        self.interfaceStore.clear()
        self.sourceStore.clear()

        self.serviceView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.portView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.protocolView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.forwardView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.sourcePortView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.icmpView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.richRuleView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.zoneNotebook.set_tooltip_markup("")

        if not selected_zone:
            self.zoneEditEditButton.set_sensitive(False)
            self.zoneEditRemoveButton.set_sensitive(False)
            self.zoneEditLoadDefaultsButton.set_sensitive(False)
            self.zoneNotebook.set_sensitive(False)

            iter = self.serviceStore.get_iter_first()
            while iter:
                self.serviceStore.set_value(iter, 0, False)
                iter = self.serviceStore.iter_next(iter)

            self.masqueradeCheck.set_active(False)

            iter = self.icmpStore.get_iter_first()
            while iter:
                self.icmpStore.set_value(iter, 0, False)
                iter = self.icmpStore.iter_next(iter)

            self.icmpBlockInversionCheck.set_active(False)

            return

        self.zoneEditEditButton.set_sensitive(True)
        self.zoneNotebook.set_sensitive(True)

        if self.runtime_view:
            # load runtime configuration
            try:
                settings = self.fw.getZoneSettings(selected_zone)
            except:
                return

            default = False
            builtin = False
        else:
            # load permanent configuration
            try:
                zone = self.fw.config().getZoneByName(selected_zone)
            except:
                return

            settings = zone.getSettings()
            props = zone.get_properties()
            default = props["default"]
            builtin = props["builtin"]

        services = settings.getServices()
        ports = settings.getPorts()
        protocols = settings.getProtocols()
        masquerade = settings.getMasquerade()
        forward_ports = settings.getForwardPorts()
        source_ports = settings.getSourcePorts()
        icmpblocks = settings.getIcmpBlocks()
        rules = settings.getRichRules()
        interfaces = settings.getInterfaces()
        sources = settings.getSources()
        icmp_block_inversion = settings.getIcmpBlockInversion()

        self.zoneNotebook.set_sensitive(True)
        self.zoneEditRemoveButton.set_sensitive(not builtin and default)
        self.zoneEditLoadDefaultsButton.set_sensitive(not default)

        # set services
        _services = services[:]
        iter = self.serviceStore.get_iter_first()
        while iter:
            name = self.serviceStore.get_value(iter, 1)
            if name in _services:
                self.serviceStore.set_value(iter, 0, True)
                _services.remove(name)
            else:
                self.serviceStore.set_value(iter, 0, False)
            iter = self.serviceStore.iter_next(iter)

        # handle unknown services
        for name in _services:
            text = _("Zone '%s': Service '%s' is not available.") % \
                (selected_zone, name)
            result = self._dialog(text, message_type=Gtk.MessageType.WARNING,
                                  title=_("Warning"),
                                  buttons=((_("Remove"), 1), (_("Ignore"), 2)))
            if result == 1:
                if self.runtime_view:
                    self.fw.removeService(selected_zone, name)
                else:
                    settings.removeService(name)
                    zone.update(settings)
                self.changes_applied()

        # set ports
        for item in ports:
            self.portStore.append(item)

        # set protocols
        for item in protocols:
            self.protocolStore.append([item])

        # set masquerade
        self.masqueradeCheck.set_active(masquerade)

        # set forward ports
        for item in forward_ports:
            self.forwardStore.append(item)

        # set source ports
        for item in source_ports:
            self.sourcePortStore.append(item)

        # set icmpblocks
        _icmpblocks = icmpblocks[:]
        iter = self.icmpStore.get_iter_first()
        while iter:
            name = self.icmpStore.get_value(iter, 1)
            if name in _icmpblocks:
                self.icmpStore.set_value(iter, 0, True)
                _icmpblocks.remove(name)
            else:
                self.icmpStore.set_value(iter, 0, False)
            iter = self.icmpStore.iter_next(iter)

        self.icmpBlockInversionCheck.set_active(icmp_block_inversion)

        # handle unknown icmpblocks
        for name in _icmpblocks:
            text = _("Zone '%s': ICMP type '%s' is not available.") % \
                (selected_zone, name)
            result = self._dialog(text, message_type=Gtk.MessageType.WARNING,
                                  title=_("Warning"),
                                  buttons=((_("Remove"), 1),(_("Ignore"), 2)))
            if result == 1:
                if self.runtime_view:
                    self.fw.removeIcmpBlock(selected_zone, name)
                else:
                    settings.removeIcmpBlock(name)
                    zone.update(settings)
                self.changes_applied()

        # set rich rules
        for item in rules:
            rule = rich.Rich_Rule(rule_str=item)
            self._add_rich_rule(rule)

        # set interfaces
        for item in interfaces:
            self._add_interface(item)

        # set sources
        for item in sources:
            self.sourceStore.append([item])

        self.serviceView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.portView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.protocolView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.forwardView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.sourcePortView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.icmpView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.richRuleView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.interfaceView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.sourceView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)

    def onAddZone(self, *args):
        if self.runtime_view:
            return
        self.add_edit_zone(True)

    def onRemoveZone(self, *args):
        if self.runtime_view:
            return
        selected_zone = self.get_selected_zone()
        zone = self.fw.config().getZoneByName(selected_zone)
        zone.remove()
        self.changes_applied()
        self.load_zones()
        self.onChangeZone()

    def onEditZone(self, *args):
        if self.runtime_view:
            return
        self.add_edit_zone(False)

    def onLoadDefaultsZone(self, *args):
        if self.runtime_view:
            return
        selected_zone = self.get_selected_zone()
        zone = self.fw.config().getZoneByName(selected_zone)
        zone.loadDefaults()
        self.changes_applied()
        self.onChangeZone()

    def entry_changed(self, entry, allowed_chars, modify=None):
        "Remove all disallowed characters and truncate length."
        origtext = entry.get_text()
        newtext = origtext
        for char in origtext:
            if char not in allowed_chars:
                newtext = newtext.replace(char, "")
        OK = len(newtext) > 0
        if modify:
            OK, newtext = modify(newtext)

        if newtext != origtext:
            entry.set_text(newtext)
        return OK

    def onZoneBaseDialogChanged(self, *args):
        def check_zone_name(zone):
            max_len = functions.max_zone_name_len()
            parts = zone.split('/')
            if len(parts) < 2:
                return (True, zone)
            if len(parts[0]) > max_len:
                parts[0] = parts[0][:max_len]
            zone = '/'.join(parts[:2])
            OK = len(zone) > 1 and zone[0] != '/' and zone[-1] != '/'
            return (OK, zone)

        OK=True
        if args and (args[0] == self.zoneBaseDialogNameEntry):
            additional_chars = "".join(Zone.ADDITIONAL_ALNUM_CHARS)
            allowed_chars = string.ascii_letters+string.digits+additional_chars
            OK = self.entry_changed(args[0], allowed_chars, check_zone_name)
        self.zoneBaseDialogOkButton.set_sensitive(OK)

    def onZoneBaseDialogTargetCheckToggled(self, check):
        val = check.get_active()
        self.zoneBaseDialogTargetCombobox.set_sensitive(not val)

    def add_edit_zone(self, add):
        l = functions.max_zone_name_len()
        self.zoneBaseDialogNameEntry.set_max_length(l)
        self.zoneBaseDialogNameEntry.set_width_chars(l)
        self.zoneBaseDialogNameEntry.set_max_width_chars(l)

        if add:
            default = True
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None
            old_target = None

            self.zoneBaseDialogNameEntry.set_text("")
            self.zoneBaseDialogVersionEntry.set_text("")
            self.zoneBaseDialogShortEntry.set_text("")
            self.zoneBaseDialogDescText.get_buffer().set_text("")
            self.zoneBaseDialogTargetCheck.set_active(True)
            self.zoneBaseDialogTargetCombobox.set_active(0)
        else:
            selected_zone = self.get_selected_zone()
            zone = self.fw.config().getZoneByName(selected_zone)
            settings = zone.getSettings()
            props = zone.get_properties()
            default = props["default"]
            builtin = props["builtin"]

            old_name = zone.get_property("name")
            old_version = settings.getVersion()
            old_short = settings.getShort()
            old_desc = settings.getDescription()
            old_target = settings.getTarget()

            self.zoneBaseDialogNameEntry.set_text(old_name)
            self.zoneBaseDialogVersionEntry.set_text(old_version)
            self.zoneBaseDialogShortEntry.set_text(old_short)
            self.zoneBaseDialogDescText.get_buffer().set_text(old_desc)
            if old_target == "default" or \
               old_target == DEFAULT_ZONE_TARGET:
                self.zoneBaseDialogTargetCheck.set_active(True)
                self.zoneBaseDialogTargetCombobox.set_active(0)
            else:
                self.zoneBaseDialogTargetCheck.set_active(False)
                combobox_select_text(self.zoneBaseDialogTargetCombobox,
                                     old_target if old_target != "%%REJECT%%"
                                     else "REJECT")

        self.zoneBaseDialogOkButton.set_sensitive(False)
        if builtin:
            self.zoneBaseDialogNameEntry.set_tooltip_markup(\
                _("Built-in zone, rename not supported."))
        else:
            self.zoneBaseDialogNameEntry.set_tooltip_markup("")
        self.zoneBaseDialogNameEntry.set_sensitive(not builtin and default)

        self.zoneBaseDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.zoneBaseDialog.set_transient_for(self.mainWindow)
        self.zoneBaseDialog.show_all()
        self.add_visible_dialog(self.zoneBaseDialog)
        result = self.zoneBaseDialog.run()
        self.zoneBaseDialog.hide()
        self.remove_visible_dialog(self.zoneBaseDialog)

        if result != 1:
            return

        name = self.zoneBaseDialogNameEntry.get_text()
        version = self.zoneBaseDialogVersionEntry.get_text()
        short = self.zoneBaseDialogShortEntry.get_text()
        buffer = self.zoneBaseDialogDescText.get_buffer()
        desc = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(),
                               False)
        target = "default" # this has been DEFAULT_ZONE_TARGET before
        if not self.zoneBaseDialogTargetCheck.get_active():
            target = self.zoneBaseDialogTargetCombobox.get_active_text()
            if target == "REJECT":
                target = "%%REJECT%%"

        if old_name == name and \
                old_version == version and old_short == short and \
                old_desc == desc and old_target == target:
            # no changes
            return

        if not add:
            selected_zone = self.get_selected_zone()
            zone = self.fw.config().getZoneByName(selected_zone)
            settings = zone.getSettings()
        else:
            settings = client.FirewallClientZoneSettings()

        if old_version != version or old_short != short or \
                old_desc != desc or old_target != target:
            # settings
            settings.setVersion(version)
            settings.setShort(short)
            settings.setDescription(desc)
            settings.setTarget(target)
            if not add:
                zone.update(settings)

        if not add:
            if old_name == name:
                return
            zone.rename(name)
        else:
            self.fw.config().addZone(name, settings)
        self.changes_applied()

    def onAddRichRule(self, *args):
        self.add_edit_rich_rule(True)

    def onEditRichRule(self, *args):
        self.add_edit_rich_rule(False)

    def onRichRuleClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_rich_rule(False)

    def onRemoveRichRule(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.richRuleView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        obj = self.richRuleStore.get_value(iter, 0)

        if self.runtime_view:
            self.fw.removeRichRule(selected_zone, str(obj))
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.removeRichRule(str(obj))
        self.changes_applied()

    def add_edit_rich_rule(self, add):
        self.richRuleDialogFamilyCombobox.set_active(0)
        self.richRuleDialogPriorityEntry.set_value(0)
        self.richRuleDialogElementCheck.set_active(False)
        self.richRuleDialogElementCombobox.set_active(0)
        self.richRuleDialogElementChooser.set_text("")
        self.richRuleDialogActionCheck.set_active(False)
        self.richRuleDialogActionCombobox.set_active(0)
        self.richRuleDialogActionRejectTypeCheck.set_active(False)
        self.richRuleDialogActionRejectTypeCombobox.set_active(0)
        self.richRuleDialogActionMarkChooser.set_text("")
        self.richRuleDialogActionLimitCheck.set_active(False)
        self.richRuleDialogActionLimitRateEntry.set_text("")
        self.richRuleDialogActionLimitDurationCombobox.set_active(0)
        self.richRuleDialogSourceInvertCheck.set_active(False)
        self.richRuleDialogSourceTypeCombobox.set_active(0)

        self.richRuleDialogSourceChooser.set_text("")
        self.richRuleDialogDestinationInvertCheck.set_active(False)
        self.richRuleDialogDestinationChooser.set_text("")
        self.richRuleDialogLogCheck.set_active(False)
        self.richRuleDialogLogPrefixEntry.set_text("")
        self.richRuleDialogLogLevelCombobox.set_active(4)
        self.richRuleDialogLogLimitCheck.set_active(False)
        self.richRuleDialogLogLimitRateEntry.set_text("")
        self.richRuleDialogLogLimitDurationCombobox.set_active(0)
        self.richRuleDialogAuditCheck.set_active(False)
        self.richRuleDialogAuditLimitCheck.set_active(False)
        self.richRuleDialogAuditLimitRateEntry.set_text("")
        self.richRuleDialogAuditLimitDurationCombobox.set_active(0)

        smhd = { "s": _("second"),
                 "m": _("minute"),
                 "h": _("hour"),
                 "d": _("day") }
        loglevel = { "emerg": _("emergency"),
                     "alert": _("alert"),
                     "crit": _("critical"),
                     "error": _("error"),
                     "warning": _("warning"),
                     "notice": _("notice"),
                     "info": _("info"),
                     "debug": _("debug"), }

        selected_zone = self.get_selected_zone()

        old_obj = None
        iter = None
        if not add:
            selection = self.richRuleView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_obj = self.richRuleStore.get_value(iter, 0)

        self.richRuleDialog.old_obj = old_obj

        if old_obj:
            if old_obj.family in [ "ipv4", "ipv6" ]:
                combobox_select_text(self.richRuleDialogFamilyCombobox,
                                     old_obj.family, insensitive=True)
            if old_obj.priority != 0:
                self.richRuleDialogPriorityEntry.set_value(old_obj.priority)

            if old_obj.element:
                self.richRuleDialogElementCheck.set_active(True)

            # element
            if type(old_obj.element) == rich.Rich_Service:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("service"))
                self.richRuleDialogElementChooser.set_text( \
                    old_obj.element.name)

            elif type(old_obj.element) == rich.Rich_Port:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("port"))
                self.richRuleDialogElementChooser.set_text( \
                    "%s/%s" % (old_obj.element.port, old_obj.element.protocol))
            elif type(old_obj.element) == rich.Rich_Protocol:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("protocol"))
                self.richRuleDialogElementChooser.set_text( \
                    old_obj.element.value)
            elif type(old_obj.element) == rich.Rich_Masquerade:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("masquerade"))
            elif type(old_obj.element) == rich.Rich_IcmpBlock:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("icmp-block"))
                self.richRuleDialogElementChooser.set_text( \
                    old_obj.element.name)
            elif type(old_obj.element) == rich.Rich_IcmpType:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("icmp-type"))
                self.richRuleDialogElementChooser.set_text( \
                    old_obj.element.name)
            elif type(old_obj.element) == rich.Rich_ForwardPort:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("forward-port"))
                s = "%s/%s" % (old_obj.element.port, old_obj.element.protocol)
                if old_obj.element.to_port != "":
                    s += " >%s" % old_obj.element.to_port
                if old_obj.element.to_address != "":
                    s += " @%s" % old_obj.element.to_address
                self.richRuleDialogElementChooser.set_text(s)
            elif type(old_obj.element) == rich.Rich_SourcePort:
                combobox_select_text(self.richRuleDialogElementCombobox,
                                     _("source-port"))
                self.richRuleDialogElementChooser.set_text( \
                    "%s/%s" % (old_obj.element.port, old_obj.element.protocol))
            # action
            if old_obj.action:
                self.richRuleDialogActionCheck.set_active(True)
                action = None
                if type(old_obj.action) == rich.Rich_Accept:
                    action = _("accept")
                elif type(old_obj.action) == rich.Rich_Reject:
                    action = _("reject")
                    self.richRuleDialogActionRejectTypeCombobox.remove_all()
                    if old_obj.family is not None:
                        for icmp in REJECT_TYPES[old_obj.family]:
                            self.richRuleDialogActionRejectTypeCombobox. \
                                                        append(icmp, icmp)
                        if old_obj.action.type:
                            self.richRuleDialogActionRejectTypeCheck. \
                                set_active(True)
                            self.richRuleDialogActionRejectTypeCombobox. \
                                            set_active_id(old_obj.action.type)
                        else:
                            self.richRuleDialogActionRejectTypeCombobox. \
                                set_active_id(REJECT_TYPES[old_obj.family][0])
                elif type(old_obj.action) == rich.Rich_Drop:
                    action = _("drop")
                elif type(old_obj.action) == rich.Rich_Mark:
                    action = _("mark")
                    self.richRuleDialogActionMarkChooser.set_text(old_obj.action.set)

                combobox_select_text(self.richRuleDialogActionCombobox, action)

                if old_obj.action.limit:
                    self.richRuleDialogActionLimitCheck.set_active(True)
                    (rate, duration) = old_obj.action.limit.value.split("/")
                    self.richRuleDialogActionLimitRateEntry.set_text(rate)
                    combobox_select_text( \
                        self.richRuleDialogActionLimitDurationCombobox,
                        smhd[duration], insensitive=True)

            # source
            if old_obj.source:
                if old_obj.source.addr:
                    combobox_select_text(self.richRuleDialogSourceTypeCombobox,
                                         "IP")
                    self.richRuleDialogSourceChooser.set_text(old_obj.source.addr)
                elif old_obj.source.mac:
                    combobox_select_text(self.richRuleDialogSourceTypeCombobox,
                                         "MAC")
                    self.richRuleDialogSourceChooser.set_text(old_obj.source.mac)
                elif old_obj.source.ipset:
                    combobox_select_text(self.richRuleDialogSourceTypeCombobox,
                                         "ipset")
                    self.richRuleDialogSourceChooser.set_text(old_obj.source.ipset)
                self.richRuleDialogSourceInvertCheck.set_active( \
                    old_obj.source.invert)

            # destination
            if old_obj.destination:
                self.richRuleDialogDestinationChooser.set_text( \
                    old_obj.destination.addr)
                self.richRuleDialogDestinationInvertCheck.set_active( \
                    old_obj.destination.invert)

            # log
            if old_obj.log:
                self.richRuleDialogLogCheck.set_active(True)
                if old_obj.log.prefix:
                    self.richRuleDialogLogPrefixEntry.set_text( \
                                                        old_obj.log.prefix)
                log_level = "warning"
                if old_obj.log.level and old_obj.log.level != log_level:
                    log_level = old_obj.log.level
                combobox_select_text(self.richRuleDialogLogLevelCombobox,
                                     loglevel[log_level])
                if old_obj.log.limit:
                    self.richRuleDialogLogLimitCheck.set_active(True)
                    (rate, duration) = old_obj.log.limit.value.split("/")
                    self.richRuleDialogLogLimitRateEntry.set_text(rate)
                    combobox_select_text( \
                        self.richRuleDialogLogLimitDurationCombobox,
                        smhd[duration], insensitive=True)

            # audit
            if old_obj.audit:
                self.richRuleDialogAuditCheck.set_active(True)
                if old_obj.audit.limit:
                    self.richRuleDialogAuditLimitCheck.set_active(True)
                    (rate, duration) = old_obj.audit.limit.value.split("/")
                    self.richRuleDialogAuditLimitRateEntry.set_text(rate)
                    combobox_select_text( \
                        self.richRuleDialogAuditLimitDurationCombobox,
                        smhd[duration], insensitive=True)

        self.richRuleDialogOkButton.set_sensitive(False)
        self.on_richRuleDialog_changed()

        self.richRuleDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.richRuleDialog.set_transient_for(self.mainWindow)
        self.richRuleDialog.show_all()
        self.add_visible_dialog(self.richRuleDialog)
        result = self.richRuleDialog.run()
        self.richRuleDialog.hide()
        self.remove_visible_dialog(self.richRuleDialog)

        if result != 1:
            return

        obj = self.richRuleDialog_getRule()
        old_rule = str(old_obj)
        rule = str(obj)
        if old_rule == rule:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryRichRule(selected_zone, rule):
                self.fw.addRichRule(selected_zone, rule)
                if not add:
                    self.fw.removeRichRule(selected_zone, old_rule)
                self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not zone.queryRichRule(rule):
                if not add:
                    zone.removeRichRule(old_rule)
                zone.addRichRule(rule)
                self.changes_applied()

    def on_richRuleDialogElementChooser_clicked(self, *args):
        combolabel = self.richRuleDialogElementCombobox.get_active_text()
        old_value = self.richRuleDialogElementChooser.get_text()

        familylabel = self.richRuleDialogFamilyCombobox.get_active_text()
        if familylabel == _("ipv4"):
            family = "ipv4"
        elif familylabel == _("ipv6"):
            family = "ipv6"
        else:
            family = None

        value = None
        if combolabel == _("service"):
            value = self.service_select_dialog(old_value)
        elif combolabel == _("port"):
            old_port = None
            old_proto = None
            if old_value != "":
                try:
                    (old_port,old_proto) = old_value.split("/")
                except:
                    pass
            value = self.port_select_dialog(old_port, old_proto)
        elif combolabel == _("protocol"):
            value = self.protocol_select_dialog(old_value)
        elif combolabel == _("icmp-block"):
            value = self.icmptype_select_dialog(old_value)
        elif combolabel == _("icmp-type"):
            value = self.icmptype_select_dialog(old_value)
        elif combolabel == _("forward-port"):
            value = self.forwardport_select_dialog(family, old_value)
        elif combolabel == _("source-port"):
            old_port = None
            old_proto = None
            if old_value != "":
                try:
                    (old_port,old_proto) = old_value.split("/")
                except:
                    pass
            value = self.port_select_dialog(old_port, old_proto)

        if value is None:
            return
        self.richRuleDialogElementChooser.set_text(value)

    def port_select_dialog(self, old_port, old_proto):
        self.portDialogPortEntry.set_text("")
        self.portDialogProtoCombobox.set_active(0)

        if old_port:
            self.portDialogPortEntry.set_text(old_port)
        if old_proto:
            combobox_select_text(self.portDialogProtoCombobox, old_proto)

        self.portDialogOkButton.set_sensitive(False)

        self.portDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.portDialog.set_transient_for(self.mainWindow)
        self.portDialog.show_all()
        self.add_visible_dialog(self.portDialog)
        result = self.portDialog.run()
        self.portDialog.hide()
        self.remove_visible_dialog(self.portDialog)

        if result != 1:
            return None

        port = self.portDialogPortEntry.get_text()
        proto = self.portDialogProtoCombobox.get_active_text()

        if old_port == port and old_proto == proto:
            # nothing to change
            return None

        return "%s/%s" % (port, proto)

    def onProtoChanged(self, *args):
        if self.protoDialogOtherProtoCheck.get_active():
            self.protoDialogProtoLabel.set_sensitive(False)
            self.protoDialogProtoCombobox.set_sensitive(False)
            self.protoDialogOtherProtoEntry.set_sensitive(True)
            proto = self.protoDialogOtherProtoEntry.get_text()
        else:
            self.protoDialogProtoLabel.set_sensitive(True)
            self.protoDialogProtoCombobox.set_sensitive(True)
            self.protoDialogOtherProtoEntry.set_sensitive(False)
            proto = self.protoDialogProtoCombobox.get_active_text()
        if functions.checkProtocol(proto):
            self.protoDialogOkButton.set_sensitive(True)
        else:
            self.protoDialogOkButton.set_sensitive(False)

    def protocol_select_dialog(self, old_proto):
        self.protoDialogProtoCombobox.set_active(0)
        self.protoDialogOtherProtoCheck.set_active(False)
        self.protoDialogOtherProtoEntry.set_text("")

        if old_proto:
            if not combobox_select_text(self.protoDialogProtoCombobox,
                                        old_proto):
                self.protoDialogOtherProtoCheck.set_active(True)
                self.protoDialogOtherProtoEntry.set_text(old_proto)

        self.protoDialogOkButton.set_sensitive(False)

        self.protoDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.protoDialog.set_transient_for(self.mainWindow)
        self.protoDialog.show_all()
        self.add_visible_dialog(self.protoDialog)
        result = self.protoDialog.run()
        self.protoDialog.hide()
        self.remove_visible_dialog(self.protoDialog)

        if result != 1:
            return None

        if self.protoDialogOtherProtoCheck.get_active():
            proto = self.protoDialogOtherProtoEntry.get_text()
        else:
            proto = self.protoDialogProtoCombobox.get_active_text()

        if old_proto == proto:
            # nothing to change
            return None

        return proto

    def change_service_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.serviceDialogOkButton.set_sensitive(True)
        else:
            self.serviceDialogOkButton.set_sensitive(False)

    def service_select_dialog(self, old_service=""):
        self.serviceDialogServiceStore.clear()
        if self.runtime_view:
            services = self.fw.listServices()
        else:
            services = self.fw.config().getServiceNames()

        for service in services:
            self.serviceDialogServiceStore.append([service])

        selection = self.serviceDialogServiceView.get_selection()
        selection.set_mode(Gtk.SelectionMode.SINGLE)
        selection.select_path(0)
        iter = self.serviceDialogServiceStore.get_iter_first()
        while iter:
            if self.serviceDialogServiceStore.get_value(iter, 0) == \
                    old_service:
                selection.select_iter(iter)
            iter = self.serviceDialogServiceStore.iter_next(iter)

        self.serviceDialogOkButton.set_sensitive(False)
        self.serviceDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.serviceDialog.set_transient_for(self.mainWindow)
        self.serviceDialog.show_all()
        self.add_visible_dialog(self.serviceDialog)

        result = self.serviceDialog.run()
        self.serviceDialog.hide()
        self.remove_visible_dialog(self.serviceDialog)

        if result != 1:
            return None

        (model, iter) = selection.get_selected()
        if not iter:
            return None
        service = self.serviceDialogServiceStore.get_value(iter, 0)
        if old_service == service:
            return None
        return service

    def change_icmptype_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.icmptypeDialogOkButton.set_sensitive(True)
        else:
            self.icmptypeDialogOkButton.set_sensitive(False)

    def icmptype_select_dialog(self, old_icmptype=""):
        self.icmptypeDialogIcmptypeStore.clear()
        if self.runtime_view:
            icmptypes = self.fw.listIcmpTypes()
        else:
            icmptypes = self.fw.config().getIcmpTypeNames()

        for icmptype in icmptypes:
            self.icmptypeDialogIcmptypeStore.append([icmptype])

        selection = self.icmptypeDialogIcmptypeView.get_selection()
        selection.set_mode(Gtk.SelectionMode.SINGLE)
        selection.select_path(0)
        iter = self.icmptypeDialogIcmptypeStore.get_iter_first()
        while iter:
            if self.icmptypeDialogIcmptypeStore.get_value(iter, 0) == \
                    old_icmptype:
                selection.select_iter(iter)
            iter = self.icmptypeDialogIcmptypeStore.iter_next(iter)

        self.icmptypeDialogOkButton.set_sensitive(False)
        self.icmptypeDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.icmptypeDialog.set_transient_for(self.mainWindow)
        self.icmptypeDialog.show_all()
        self.add_visible_dialog(self.icmptypeDialog)

        result = self.icmptypeDialog.run()
        self.icmptypeDialog.hide()
        self.remove_visible_dialog(self.icmptypeDialog)

        if result != 1:
            return None

        (model, iter) = selection.get_selected()
        if not iter:
            return None
        icmptype = self.icmptypeDialogIcmptypeStore.get_value(iter, 0)
        if old_icmptype == icmptype:
            return None
        return icmptype

    def on_richRuleDialogSourceChooser_clicked(self, *args):
        old_address =  self.richRuleDialogSourceChooser.get_text()

        _type = self.richRuleDialogSourceTypeCombobox.get_active_text()

        combolabel = self.richRuleDialogFamilyCombobox.get_active_text()
        if combolabel == _("ipv4"):
            family = "ipv4"
        elif combolabel == _("ipv6"):
            family = "ipv6"
        else:
            family = None

        if _type == "IP":
            address = self.address_select_dialog(family, old_address)
            if address is not None:
                self.richRuleDialogSourceChooser.set_text(address)

        elif _type == "MAC":
            address = self.mac_select_dialog(old_address)
            if address is not None:
                self.richRuleDialogSourceChooser.set_text(address.upper())

        elif _type == "ipset":
            address = self.ipset_select_dialog(old_address, family)
            if address is not None:
                self.richRuleDialogSourceChooser.set_text(address)

    def on_richRuleDialogDestinationChooser_clicked(self, *args):
        combolabel = self.richRuleDialogFamilyCombobox.get_active_text()
        if combolabel == _("ipv4"):
            family = "ipv4"
        elif combolabel == _("ipv6"):
            family = "ipv6"
        else:
            family = None
        old_address =  self.richRuleDialogDestinationChooser.get_text()

        address = self.address_select_dialog(family, old_address)
        if address is not None:
            self.richRuleDialogDestinationChooser.set_text(address)

    def create_fwp_string(self, port, proto, to_port, to_addr):
        _to_port = ""
        if to_port != "":
            _to_port = " >%s" % to_port
        _to_addr = ""
        if to_addr != "":
            _to_addr = " @%s" % to_addr
        return "%s/%s%s%s" % (port, proto, _to_port, _to_addr)

    def split_fwp_string(self, text):
        port = ""
        proto = ""
        to_port = ""
        to_addr = ""
        if ">" in text: # to_port
            splits = text.split(">")
            (port,proto) = splits[0].split("/")
            if "@" in splits[1]:
                (to_port,to_addr) = splits[1].split("@")
            else:
                to_port = splits[1]
        elif "@" in text:
            splits = text.split("@")
            (port,proto) = splits[0].split("/")
            to_addr = splits[1]
        return (port.strip(), proto.strip(), to_port.strip(), to_addr.strip())

    def richRuleDialog_getRule(self):
        smhd = { _("second"): "s",
                 _("minute"): "m",
                 _("hour"): "h",
                 _("day"): "d" }
        loglevel = { _("emergency"): "emerg", # 0, system is unusable
                     _("alert"): "alert",     # 1, action must be taken immediately
                     _("critical"): "crit",   # 2, critical conditions
                     _("error"): "error",     # 3, error conditions
                     _("warning"): "warning", # 4, warning conditions
                     _("notice"): "notice",   # 5, normal but significant condition
                     _("info"): "info",       # 6, informational
                     _("debug"): "debug", }   # 7, debug-level messages

        # family
        combolabel = self.richRuleDialogFamilyCombobox.get_active_text()
        if combolabel == _("ipv4"):
            rule = rich.Rich_Rule("ipv4") # ipv4 rule
        elif combolabel == _("ipv6"):
            rule = rich.Rich_Rule("ipv6") # ipv6 rule
        else:
            rule = rich.Rich_Rule() # ipv4+ipv6 rule

        # priority
        priority = self.richRuleDialogPriorityEntry.get_value_as_int()
        if priority != 0:
            rule.priority = priority

        # element
        if self.richRuleDialogElementCheck.get_active():
            combolabel = self.richRuleDialogElementCombobox.get_active_text()
            if combolabel == _("service"):
                rule.element = rich.Rich_Service(
                    self.richRuleDialogElementChooser.get_text())
            elif combolabel == _("port"):
                text = self.richRuleDialogElementChooser.get_text()
                port = ""
                proto = ""
                try:
                    if '/' in text:
                        (port, proto) = text.split("/")
                except:
                    return None
                rule.element = rich.Rich_Port(port, proto)
            elif combolabel == _("protocol"):
                rule.element = rich.Rich_Protocol(
                    self.richRuleDialogElementChooser.get_text())
            elif combolabel == _("icmp-block"):
                rule.element = rich.Rich_IcmpBlock(
                    self.richRuleDialogElementChooser.get_text())
            elif combolabel == _("icmp-type"):
                rule.element = rich.Rich_IcmpType(
                    self.richRuleDialogElementChooser.get_text())
            elif combolabel == _("forward-port"):
                text = self.richRuleDialogElementChooser.get_text()
                try:
                    (port, proto, to_port, to_addr) = \
                        self.split_fwp_string(text)
                except:
                    return None
                rule.element = rich.Rich_ForwardPort(port, proto, to_port, to_addr)
            elif combolabel == _("masquerade"):
                rule.element = rich.Rich_Masquerade()
            elif combolabel == _("source-port"):
                text = self.richRuleDialogElementChooser.get_text()
                port = ""
                proto = ""
                try:
                    if '/' in text:
                        (port, proto) = text.split("/")
                except:
                    return None
                rule.element = rich.Rich_SourcePort(port, proto)

        # action
        if self.richRuleDialogActionCheck.is_sensitive() and \
           self.richRuleDialogActionCheck.get_active():
            limit = None
            if self.richRuleDialogActionLimitCheck.get_active():
                value = self.richRuleDialogActionLimitRateEntry.get_text()
                value += "/"
                value += smhd[self.richRuleDialogActionLimitDurationCombobox.get_active_text()]
                limit = rich.Rich_Limit(value)
            combolabel = self.richRuleDialogActionCombobox.get_active_text()
            if combolabel == _("accept"):
                rule.action = rich.Rich_Accept(limit)
            elif combolabel == _("reject"):
                _type = None
                if self.richRuleDialogActionRejectTypeCheck.get_active():
                    _type = self.richRuleDialogActionRejectTypeCombobox.get_active_text()
                rule.action = rich.Rich_Reject(_type, limit)
            elif combolabel == _("drop"):
                rule.action = rich.Rich_Drop(limit)
            elif combolabel == _("mark"):
                _set = self.richRuleDialogActionMarkChooser.get_text()
                rule.action = rich.Rich_Mark(_set, limit)

        # source
        if self.richRuleDialogSourceChooser.is_sensitive() \
           and (self.richRuleDialogSourceChooser.get_text() != "" \
                or self.richRuleDialogSourceInvertCheck.get_active()):
            txt = self.richRuleDialogSourceTypeCombobox.get_active_text()
            addr = mac = ipset = None
            if txt == "IP":
                addr = self.richRuleDialogSourceChooser.get_text()
            if txt == "MAC":
                mac = self.richRuleDialogSourceChooser.get_text()
            if txt == "ipset":
                ipset = self.richRuleDialogSourceChooser.get_text()
            rule.source = rich.Rich_Source(
                addr, mac, ipset,
                self.richRuleDialogSourceInvertCheck.get_active())

        # destination
        if self.richRuleDialogDestinationBox.is_sensitive() \
           and (self.richRuleDialogDestinationChooser.get_text() != "" \
                or self.richRuleDialogDestinationInvertCheck.get_active()):
            rule.destination = rich.Rich_Destination(
                self.richRuleDialogDestinationChooser.get_text(),
                self.richRuleDialogDestinationInvertCheck.get_active())

        # log
        if self.richRuleDialogLogCheck.is_sensitive() and \
           self.richRuleDialogLogCheck.get_active():
            limit = None
            if self.richRuleDialogLogLimitCheck.get_active():
                value = self.richRuleDialogLogLimitRateEntry.get_text()
                value += "/"
                value += smhd[self.richRuleDialogLogLimitDurationCombobox.get_active_text()]
                limit = rich.Rich_Limit(value)

            level = self.richRuleDialogLogLevelCombobox.get_active_text()
            rule.log = rich.Rich_Log(
                self.richRuleDialogLogPrefixEntry.get_text(),
                loglevel[level], limit)

        # audit
        if self.richRuleDialogAuditCheck.is_sensitive() and \
           self.richRuleDialogAuditCheck.get_active():
            limit = None
            if self.richRuleDialogAuditLimitCheck.get_active():
                value = self.richRuleDialogAuditLimitRateEntry.get_text()
                value += "/"
                value += smhd[self.richRuleDialogAuditLimitDurationCombobox.get_active_text()]
                limit = rich.Rich_Limit(value)
            rule.audit = rich.Rich_Audit(limit)

        return rule

    def on_richRuleDialogFamilyCombobox_changed(self, *args):
        combolabel = self.richRuleDialogFamilyCombobox.get_active_text()
        if combolabel == _("ipv4"):
            family = "ipv4"
        elif combolabel == _("ipv6"):
            family = "ipv6"
        else:
            family = None

        self.richRuleDialogActionRejectTypeCombobox.remove_all()
        if family is not None:
            for icmp in REJECT_TYPES[family]:
                self.richRuleDialogActionRejectTypeCombobox.append(icmp, icmp)
            old_obj = self.richRuleDialog.old_obj
            if old_obj and old_obj.family == family and \
               hasattr(old_obj.action, 'type') and old_obj.action.type:
                self.richRuleDialogActionRejectTypeCombobox. \
                                     set_active_id(old_obj.action.type)
            else:
                self.richRuleDialogActionRejectTypeCombobox. \
                                     set_active_id(REJECT_TYPES[family][0])

    def on_richRuleDialogElementCombobox_changed(self, *args):
        self.richRuleDialogElementChooser.set_text("")

    def on_richRuleDialogActionMarkChooser_clicked(self, *args):
        old_value = self.richRuleDialogActionMarkChooser.get_text()
        if "/" in old_value:
            try:
                (old_mark, old_mask) = old_value.split("/")
            except:
                return
        else:
            old_mark = old_value
            old_mask = ""

        _value = self.mark_select_dialog(old_mark, old_mask)
        if _value is None:
            return

        (mark, mask) = _value
        if mask != "":
            value = "%s/%s" % (mark, mask)
        else:
            value = mark
        self.richRuleDialogActionMarkChooser.set_text(value)

    def on_richRuleDialog_changed(self, *args):
        combolabel = self.richRuleDialogFamilyCombobox.get_active_text()
        if combolabel == _("ipv4"):
            family = "ipv4"
        elif combolabel == _("ipv6"):
            family = "ipv6"
        else:
            family = None
        v4v6_source = (self.richRuleDialogSourceTypeCombobox.get_active_text()
                       == "MAC" or \
                       self.richRuleDialogSourceTypeCombobox.get_active_text()
                       == "ipset")

        if family is None:
            self.richRuleDialogSourceChooser.set_sensitive(v4v6_source)
            self.richRuleDialogSourceInvertCheck.set_sensitive(v4v6_source)
            self.richRuleDialogDestinationLabel.set_sensitive(False)
            self.richRuleDialogDestinationBox.set_sensitive(False)
        else:
            self.richRuleDialogSourceChooser.set_sensitive(True)
            self.richRuleDialogSourceInvertCheck.set_sensitive(True)
            self.richRuleDialogDestinationLabel.set_sensitive(True)
            self.richRuleDialogDestinationBox.set_sensitive(True)

        self.richRuleDialogActionCheck.set_sensitive(True)
        self.richRuleDialogActionBox.set_sensitive(
            self.richRuleDialogActionCheck.get_active())
        self.richRuleDialogElementChooser.set_sensitive(True)
        self.richRuleDialogElementBox.set_sensitive(
            self.richRuleDialogElementCheck.get_active())
        self.richRuleDialogLogCheck.set_sensitive(True)
        self.richRuleDialogAuditCheck.set_sensitive(True)

        self.richRuleDialogActionLimitBox.set_sensitive(
            self.richRuleDialogActionLimitCheck.get_active())
        self.richRuleDialogActionRejectTypeCombobox.set_sensitive(
            self.richRuleDialogActionRejectTypeCheck.get_active())
        self.richRuleDialogActionRejectBox.set_sensitive(family is not None and \
            self.richRuleDialogActionCombobox.get_active_text() == _("reject"))
        self.richRuleDialogActionMarkBox.set_sensitive(self.richRuleDialogActionCombobox.get_active_text() == _("mark"))
        self.richRuleDialogLogGrid.set_sensitive(
            self.richRuleDialogLogCheck.get_active())
        self.richRuleDialogLogLimitBox.set_sensitive(
            self.richRuleDialogLogLimitCheck.get_active())
        self.richRuleDialogAuditBox.set_sensitive(
            self.richRuleDialogAuditCheck.get_active())
        self.richRuleDialogAuditLimitBox.set_sensitive(
            self.richRuleDialogAuditLimitCheck.get_active())

        if self.richRuleDialogElementCheck.get_active():
            combolabel = self.richRuleDialogElementCombobox.get_active_text()
            if combolabel == _("masquerade"):
                self.richRuleDialogElementChooser.set_sensitive(False)
                self.richRuleDialogActionCheck.set_sensitive(False)
                self.richRuleDialogActionBox.set_sensitive(False)
                self.richRuleDialogLogCheck.set_sensitive(False)
                self.richRuleDialogLogGrid.set_sensitive(False)
                self.richRuleDialogAuditCheck.set_sensitive(False)
                self.richRuleDialogAuditBox.set_sensitive(False)
            elif combolabel == _("forward-port"):
                self.richRuleDialogActionCheck.set_sensitive(False)
                self.richRuleDialogActionBox.set_sensitive(False)
                self.richRuleDialogLogCheck.set_sensitive(False)
                self.richRuleDialogLogGrid.set_sensitive(False)
                self.richRuleDialogAuditCheck.set_sensitive(False)
                self.richRuleDialogAuditBox.set_sensitive(False)
            elif combolabel == _("icmp-block"):
                self.richRuleDialogActionCheck.set_sensitive(False)
                self.richRuleDialogActionBox.set_sensitive(False)

        rule = self.richRuleDialog_getRule()
        try:
            rule.check()
        except Exception as msg:
            self.richRuleDialogOkButton.set_sensitive(False)
            self.richRuleDialogOkButton.set_tooltip_text(str(msg))
        else:
            if str(self.richRuleDialog.old_obj) != str(rule):
                self.richRuleDialogOkButton.set_sensitive(True)
            else:
                self.richRuleDialogOkButton.set_sensitive(False)
            self.richRuleDialogOkButton.set_tooltip_text("")

    def onAddInterface(self, *args):
        self.add_edit_interface(True)

    def onEditInterface(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.interfaceView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        interface = self.interfaceStore.get_value(iter, 0)
        if interface in self.connections:
            connection = self.connections[interface]
            connection_name = self.connections_name[connection]
            if selected_zone == self.default_zone:
                selected_zone = nm_get_zone_of_connection(connection)
            editor = ZoneConnectionEditor(self.fw, connection, connection_name, selected_zone)
            editor.set_icon(self.icon)
            editor.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
            editor.set_transient_for(self.mainWindow)
            editor.show_all()
            try:
                editor.run()
            except Exception:
                text = _("Failed to set zone {zone} "
                         "for connection {connection_name}")
                self._warning(text.format(zone=editor.get_zone(),
                                          connection_name=editor.connection_name))
            editor.hide()
        else:
            self.add_edit_interface(False)
        self.changes_applied()

    def onInterfaceClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.onEditInterface()

    def onRemoveInterface(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.interfaceView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        interface = self.interfaceStore.get_value(iter, 0)
        if self.runtime_view:
            self.fw.removeInterface(selected_zone, interface)
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.removeInterface(interface)
        self.changes_applied()

    def change_interface_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editInterfaceButton.set_sensitive(True)
            interface = self.interfaceStore.get_value(iter, 0)
            if interface in self.connections:
                self.removeInterfaceButton.set_sensitive(False)
            else:
                self.removeInterfaceButton.set_sensitive(True)
        else:
            self.editInterfaceButton.set_sensitive(False)
            self.removeInterfaceButton.set_sensitive(False)

    def add_edit_interface(self, add):
        selected_zone = self.get_selected_zone()
        old_interface = None

        if add:
            self.interfaceDialogInterfaceEntry.set_text("")
        else:
            selection = self.interfaceView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_interface = self.interfaceStore.get_value(iter, 0)
            self.interfaceDialogInterfaceEntry.set_text(old_interface)

        self.interfaceDialogOkButton.set_sensitive(False)

        self.interfaceDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.interfaceDialog.set_transient_for(self.mainWindow)
        self.interfaceDialog.show_all()
        self.add_visible_dialog(self.interfaceDialog)
        result = self.interfaceDialog.run()
        self.interfaceDialog.hide()
        self.remove_visible_dialog(self.interfaceDialog)

        if result != 1:
            return

        interface = self.interfaceDialogInterfaceEntry.get_text()
        if old_interface == interface:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryInterface(selected_zone, interface):
                self.fw.addInterface(selected_zone, interface)
                if not add:
                    self.fw.removeInterface(selected_zone, old_interface)
                self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not zone.queryInterface(interface):
                if not add:
                    zone.removeInterface(old_interface)
                zone.addInterface(interface)
                self.changes_applied()

    def onInterfaceChanged(self, *args):
        text = self.interfaceDialogInterfaceEntry.get_text()
        if text != "" and functions.checkInterface(text):
            self.interfaceDialogOkButton.set_sensitive(True)
        else:
            self.interfaceDialogOkButton.set_sensitive(False)

    def onAddSource(self, *args):
        self.add_edit_source(True)

    def onEditSource(self, *args):
        self.add_edit_source(False)

    def onSourceClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_source(False)

    def onRemoveSource(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.sourceView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        source = self.sourceStore.get_value(iter, 0)
        if self.runtime_view:
            self.fw.removeSource(selected_zone, source)
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.removeSource(source)
        self.changes_applied()

    def change_source_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editSourceButton.set_sensitive(True)
            self.removeSourceButton.set_sensitive(True)
        else:
            self.editSourceButton.set_sensitive(False)
            self.removeSourceButton.set_sensitive(False)

    def add_edit_source(self, add):
        selected_zone = self.get_selected_zone()

        old_source = ""
        if not add:
            selection = self.sourceView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_source = self.sourceStore.get_value(iter, 0)

        #source = self.address_select_dialog(None, old_source, True, True)
        source = self.source_select_dialog(old_source)
        if not source:
            return

        if self.runtime_view:
            if not self.fw.querySource(selected_zone, source):
                self.fw.addSource(selected_zone, source)
                if not add:
                    self.fw.removeSource(selected_zone, old_source)
                self.changes_applied()
            else:
                self._warning("Source '%s' already bound to zone '%s'" % \
                              (old_source, selected_zone))
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not zone.querySource(source):
                if not add:
                    zone.removeSource(old_source)
                zone.addSource(source)
                self.changes_applied()
            else:
                self._warning("Source '%s' already bound to zone '%s'" % \
                              (old_source, selected_zone))

    def on_markDialog_changed(self, entry, old_mark, old_mask):
        mark = self.markDialogMarkEntry.get_text()
        mask = self.markDialogMaskEntry.get_text()

        if not functions.checkUINT32(mark):
            self.markDialogOkButton.set_sensitive(False)
        else:
            if mask != "" and not functions.checkUINT32(mask):
                self.markDialogOkButton.set_sensitive(False)
            else:
                if old_mark != mark or old_mask != mask:
                    self.markDialogOkButton.set_sensitive(True)

    def mark_select_dialog(self, old_mark, old_mask):
        self.markDialogMarkEntry.set_text(old_mark)
        self.markDialogMaskEntry.set_text(old_mask)

        handler_id1 = self.markDialogMarkEntry.connect(
            "changed", self.on_markDialog_changed, old_mark, old_mask)
        handler_id2 = self.markDialogMaskEntry.connect(
            "changed", self.on_markDialog_changed, old_mark, old_mask)

        self.markDialogOkButton.set_sensitive(False)

        self.markDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.markDialog.set_transient_for(self.mainWindow)
        self.markDialog.show_all()
        self.add_visible_dialog(self.markDialog)
        result = self.markDialog.run()
        self.markDialog.hide()
        self.remove_visible_dialog(self.markDialog)

        self.markDialogMarkEntry.disconnect(handler_id1)
        self.markDialogMaskEntry.disconnect(handler_id2)

        mark = self.markDialogMarkEntry.get_text()
        mask = self.markDialogMaskEntry.get_text()

        if result != 1 or (old_mark == mark and old_mask == mask):
            return None
        return (mark, mask)

    def on_macDialog_changed(self, entry, old_mac):
        text = entry.get_text()
        if text == "":
            self.macDialogOkButton.set_sensitive(True)
            return

        self.macDialogOkButton.set_sensitive(False)
        if functions.check_mac(text) and text != old_mac:
            self.macDialogOkButton.set_sensitive(True)

    def mac_select_dialog(self, old_mac):
        self.macDialogMacEntry.set_text(old_mac)
        handler_id = self.macDialogMacEntry.connect("changed",
                                                    self.on_macDialog_changed,
                                                    old_mac)
        self.macDialogOkButton.set_sensitive(False)

        self.macDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.macDialog.set_transient_for(self.mainWindow)
        self.macDialog.show_all()
        self.add_visible_dialog(self.macDialog)
        result = self.macDialog.run()
        self.macDialog.hide()
        self.remove_visible_dialog(self.macDialog)

        self.macDialogMacEntry.disconnect(handler_id)

        mac = self.macDialogMacEntry.get_text()

        if result != 1 or old_mac == mac:
            return None
        return mac.upper()

    def change_ipset_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.ipsetDialogOkButton.set_sensitive(True)
        else:
            self.ipsetDialogOkButton.set_sensitive(False)

    def ipset_select_dialog(self, old_ipset="", ipv=None):
        self.ipsetDialogIPSetStore.clear()

        ipsets = { }
        if self.runtime_view:
            for x in self.fw.getIPSets():
                self.deactivate_exception_handler()
                try:
                    settings = self.fw.getIPSetSettings(x)
                except (DBusException, Exception) as msg:
                    self.activate_exception_handler()
                    if isinstance(msg, DBusException):
                        msg = msg.get_dbus_message()
                    else:
                        msg = str(msg)
                    code = FirewallError.get_code(msg)
                    if code == errors.NOT_APPLIED:
                        continue
                    raise
                self.activate_exception_handler()
                if settings.getType() not in ZONE_SOURCE_IPSET_TYPES:
                    continue
                ipsets[x] = settings
        else:
            for i in self.fw.config().listIPSets():
                obj = self.fw.config().getIPSet(i)
                ipsets[obj.get_property("name")] = obj.getSettings()

        for i in sorted(ipsets.keys()):
            # for all hash:ip and hash:net types, ipv has to match the family
            # of the set
            ipset_type = ipsets[i].getType()
            if ipset_type.startswith("hash:ip") or \
               ipset_type.startswith("hash:net"):
                opts = ipsets[i].getOptions()
                if "family" in opts:
                    if opts["family"] == "inet6" and \
                       (ipv != "ipv6" and ipv != "all"):
                        continue
                else:
                    if ipv == "ipv6" or ipv is None:
                        continue
            self.ipsetDialogIPSetStore.append([i, ipset_type])

        selection = self.ipsetDialogIPSetView.get_selection()
        selection.set_mode(Gtk.SelectionMode.SINGLE)
        #selection.select_path(0)
        iter = self.ipsetDialogIPSetStore.get_iter_first()
        while iter:
            if self.ipsetDialogIPSetStore.get_value(iter, 0) == old_ipset:
                selection.select_iter(iter)
            iter = self.ipsetDialogIPSetStore.iter_next(iter)

        self.ipsetDialogOkButton.set_sensitive(False)
        self.ipsetDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.ipsetDialog.set_transient_for(self.mainWindow)
        self.ipsetDialog.show_all()
        self.add_visible_dialog(self.ipsetDialog)

        result = self.ipsetDialog.run()
        self.ipsetDialog.hide()
        self.remove_visible_dialog(self.ipsetDialog)

        #self.ipsetDialogIPSetEntry.disconnect(handler_id)

        #ipset = self.ipsetDialogIPSetEntry.get_text()

        if result != 1:
            return None

        (model, iter) = selection.get_selected()
        if not iter:
            return None
        ipset = self.ipsetDialogIPSetStore.get_value(iter, 0)
        if old_ipset == ipset:
            return None
        return ipset

    def change_helper_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.helperDialogOkButton.set_sensitive(True)
        else:
            self.helperDialogOkButton.set_sensitive(False)

    def on_sourceDialog_changed(self, arg, old_type, old_source):
        _type = self.sourceDialogSourceTypeCombobox.get_active_text()
        _source = self.sourceDialogSourceChooser.get_text()

        self.sourceDialogOkButton.set_sensitive(False)

        if old_source != _source:
            if _type == "MAC" and functions.check_mac(_source):
                self.sourceDialogOkButton.set_sensitive(True)
            elif _type == "IP" and (functions.checkIPnMask(_source) or \
                                    functions.checkIP6nMask(_source)):
                self.sourceDialogOkButton.set_sensitive(True)
            elif _type == "ipset":
                self.sourceDialogOkButton.set_sensitive(True)

    def on_sourceDialogSourceChooser_clicked(self, *args):
        old_address =  self.sourceDialogSourceChooser.get_text()

        _type = self.sourceDialogSourceTypeCombobox.get_active_text()

        if _type == "IP":
            address = self.address_select_dialog(None, old_address)
            if address is not None:
                self.sourceDialogSourceChooser.set_text(address)

        elif _type == "MAC":
            address = self.mac_select_dialog(old_address)
            if address is not None:
                self.sourceDialogSourceChooser.set_text(address.upper())

        elif _type == "ipset":
            address = self.ipset_select_dialog(old_address, "all")
            if address is not None:
                self.sourceDialogSourceChooser.set_text(address)

    def source_select_dialog(self, old_source):
        if old_source:
            if old_source.startswith("ipset:"):
                old_type = "ipset"
                old_source = old_source[6:]
            elif functions.check_mac(old_source):
                old_type = "MAC"
            else:
                old_type = "IP"
            combobox_select_text(self.sourceDialogSourceTypeCombobox, old_type)
        else:
            old_type = None
            self.sourceDialogSourceTypeCombobox.set_active(0)

        self.sourceDialogSourceChooser.set_text(old_source)

        h_type_id = self.sourceDialogSourceTypeCombobox.connect(
            "changed", self.on_sourceDialog_changed, old_type, old_source)
        h_addr_id = self.sourceDialogSourceChooser.connect(
            "clicked", self.on_sourceDialog_changed, old_type, old_source)

        self.sourceDialogOkButton.set_sensitive(False)

        self.sourceDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.sourceDialog.set_transient_for(self.mainWindow)
        self.sourceDialog.show_all()
        self.add_visible_dialog(self.sourceDialog)

        result = self.sourceDialog.run()
        self.sourceDialog.hide()
        self.remove_visible_dialog(self.sourceDialog)

        self.sourceDialogSourceTypeCombobox.disconnect(h_type_id)
        self.sourceDialogSourceChooser.disconnect(h_addr_id)

        source = self.sourceDialogSourceChooser.get_text()
        if self.sourceDialogSourceTypeCombobox.get_active_text() == "ipset":
            source = "ipset:%s" % source

        if result != 1 or old_source == source:
            return None
        return source

    def onAddPort(self, *args):
        self.add_edit_port(True)

    def onEditPort(self, *args):
        self.add_edit_port(False)

    def onPortClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_port(False)

    def onRemovePort(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.portView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        port = self.portStore.get_value(iter, 0)
        proto = self.portStore.get_value(iter, 1)

        if self.runtime_view:
            self.fw.removePort(selected_zone, port, proto)
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.removePort(port, proto)
        self.changes_applied()

    def onPortChanged(self, *args):
        ports = functions.getPortRange(self.portDialogPortEntry.get_text())
        if not ports or not (isinstance(ports, list) or \
                             isinstance(ports, tuple)):
            self.portDialogOkButton.set_sensitive(False)
        else:
            self.portDialogOkButton.set_sensitive(True)

    def add_edit_port(self, add):
        selected_zone = self.get_selected_zone()

        old_port = None
        old_proto = None
        if not add:
            selection = self.portView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_port = self.portStore.get_value(iter, 0)
            old_proto = self.portStore.get_value(iter, 1)

        self.portDialogPortEntry.set_text("")
        self.portDialogProtoCombobox.set_active(0)

        if old_port:
            self.portDialogPortEntry.set_text(old_port)
        if old_proto:
            combobox_select_text(self.portDialogProtoCombobox, old_proto)

        self.portDialogOkButton.set_sensitive(False)

        self.portDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.portDialog.set_transient_for(self.mainWindow)
        self.portDialog.show_all()
        self.add_visible_dialog(self.portDialog)
        result = self.portDialog.run()
        self.portDialog.hide()
        self.remove_visible_dialog(self.portDialog)

        if result != 1:
            return

        port = self.portDialogPortEntry.get_text()
        proto = self.portDialogProtoCombobox.get_active_text()
        if old_port == port and old_proto == proto:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryPort(selected_zone, port, proto):
                self.fw.addPort(selected_zone, port, proto)
                if not add:
                    self.fw.removePort(selected_zone, old_port, old_proto)
                self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not zone.queryPort(port, proto):
                if not add:
                    zone.removePort(old_port, old_proto)
                zone.addPort(port, proto)
                self.changes_applied()

    def onPortProtoChanged(self, *args):
        ports = functions.getPortRange(self.portDialogPortEntry.get_text())
        if not ports or not (isinstance(ports, list) or \
                             isinstance(ports, tuple)):
            self.portDialogOkButton.set_sensitive(False)
        else:
            self.portDialogOkButton.set_sensitive(True)

    def onPortProtoDialogOtherProtoCheckToggled(self, check, *args):
        self.portDialogPortEntry.set_sensitive(not check.get_active())
        self.portDialogProtoCombobox.set_sensitive(not check.get_active())

    def service_conf_add_edit_port(self, add):
        active_service = self.get_active_service()

        self.portDialogPortEntry.set_text("")
        self.portDialogProtoCombobox.set_active(0)

        old_port = None
        old_proto = None

        if not add:
            selection = self.serviceConfPortView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_port = self.serviceConfPortStore.get_value(iter, 0)
            old_proto = self.serviceConfPortStore.get_value(iter, 1)

        if old_port:
            self.portDialogPortEntry.set_text(old_port)
        if old_proto:
            combobox_select_text(self.portDialogProtoCombobox, old_proto)

        self.portDialogOkButton.set_sensitive(False)

        self.portDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.portDialog.set_transient_for(self.mainWindow)
        self.portDialog.show_all()
        self.add_visible_dialog(self.portDialog)
        result = self.portDialog.run()
        self.portDialog.hide()
        self.remove_visible_dialog(self.portDialog)

        if result != 1:
            return

        port = self.portDialogPortEntry.get_text()
        proto = self.portDialogProtoCombobox.get_active_text()

        if old_port == port and old_proto == proto:
            # nothing to change
            return

        service = self.fw.config().getServiceByName(active_service)
        if not service.queryPort(port, proto):
            if not add:
                service.removePort(old_port, old_proto)
            service.addPort(port, proto)
            self.changes_applied()

    def port_added_cb(self, zone, port, protocol, timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.portStore.get_iter_first()
        while iter:
            if self.portStore.get_value(iter, 0) == port and \
                    self.portStore.get_value(iter, 1) == protocol:
                # already there
                return
            iter = self.portStore.iter_next(iter)
        # nothing found, so add it
        self.portStore.append([port, protocol])

    def port_removed_cb(self, zone, port, protocol):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.portStore.get_iter_first()
        while iter:
            if self.portStore.get_value(iter, 0) == port and \
                    self.portStore.get_value(iter, 1) == protocol:
                self.portStore.remove(iter)
                break
            iter = self.portStore.iter_next(iter)

    def onAddSourcePort(self, *args):
        self.add_edit_source_port(True)

    def onEditSourcePort(self, *args):
        self.add_edit_source_port(False)

    def onSourcePortClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_source_port(False)

    def onRemoveSourcePort(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.sourcePortView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        port = self.sourcePortStore.get_value(iter, 0)
        proto = self.sourcePortStore.get_value(iter, 1)

        if self.runtime_view:
            self.fw.removeSourcePort(selected_zone, port, proto)
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.removeSourcePort(port, proto)
        self.changes_applied()

    def add_edit_source_port(self, add):
        selected_zone = self.get_selected_zone()

        old_port = None
        old_proto = None
        if not add:
            selection = self.sourcePortView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_port = self.sourcePortStore.get_value(iter, 0)
            old_proto = self.sourcePortStore.get_value(iter, 1)

        self.portDialogPortEntry.set_text("")
        self.portDialogProtoCombobox.set_active(0)

        if old_port:
            self.portDialogPortEntry.set_text(old_port)
        if old_proto:
            combobox_select_text(self.portDialogProtoCombobox, old_proto)

        self.portDialogOkButton.set_sensitive(False)

        self.portDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.portDialog.set_transient_for(self.mainWindow)
        self.portDialog.show_all()
        self.add_visible_dialog(self.portDialog)
        result = self.portDialog.run()
        self.portDialog.hide()
        self.remove_visible_dialog(self.portDialog)

        if result != 1:
            return

        port = self.portDialogPortEntry.get_text()
        proto = self.portDialogProtoCombobox.get_active_text()
        if old_port == port and old_proto == proto:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.querySourcePort(selected_zone, port, proto):
                self.fw.addSourcePort(selected_zone, port, proto)
                if not add:
                    self.fw.removeSourcePort(selected_zone, old_port, old_proto)
                self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not zone.querySourcePort(port, proto):
                if not add:
                    zone.removeSourcePort(old_port, old_proto)
                zone.addSourcePort(port, proto)
                self.changes_applied()

    def service_conf_add_edit_source_port(self, add):
        active_service = self.get_active_service()

        self.portDialogPortEntry.set_text("")
        self.portDialogProtoCombobox.set_active(0)

        old_port = None
        old_proto = None

        if not add:
            selection = self.serviceConfSourcePortView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_port = self.serviceConfSourcePortStore.get_value(iter, 0)
            old_proto = self.serviceConfSourcePortStore.get_value(iter, 1)

        if old_port:
            self.portDialogPortEntry.set_text(old_port)
        if old_proto:
            combobox_select_text(self.portDialogProtoCombobox, old_proto)

        self.portDialogOkButton.set_sensitive(False)

        self.portDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.portDialog.set_transient_for(self.mainWindow)
        self.portDialog.show_all()
        self.add_visible_dialog(self.portDialog)
        result = self.portDialog.run()
        self.portDialog.hide()
        self.remove_visible_dialog(self.portDialog)

        if result != 1:
            return

        port = self.portDialogPortEntry.get_text()
        proto = self.portDialogProtoCombobox.get_active_text()

        if old_port == port and old_proto == proto:
            # nothing to change
            return

        service = self.fw.config().getServiceByName(active_service)
        if not service.querySourcePort(port, proto):
            if not add:
                service.removeSourcePort(old_port, old_proto)
            service.addSourcePort(port, proto)
            self.changes_applied()

    def source_port_added_cb(self, zone, port, protocol, timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.sourcePortStore.get_iter_first()
        while iter:
            if self.sourcePortStore.get_value(iter, 0) == port and \
                    self.sourcePortStore.get_value(iter, 1) == protocol:
                # already there
                return
            iter = self.sourcePortStore.iter_next(iter)
        # nothing found, so add it
        self.sourcePortStore.append([port, protocol])

    def source_port_removed_cb(self, zone, port, protocol):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.sourcePortStore.get_iter_first()
        while iter:
            if self.sourcePortStore.get_value(iter, 0) == port and \
                    self.sourcePortStore.get_value(iter, 1) == protocol:
                self.sourcePortStore.remove(iter)
                break
            iter = self.sourcePortStore.iter_next(iter)

    def onAddProtocol(self, *args):
        self.add_edit_protocol(True)

    def onEditProtocol(self, *args):
        self.add_edit_protocol(False)

    def onProtocolClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_protocol(False)

    def onRemoveProtocol(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.protocolView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        proto = self.protocolStore.get_value(iter, 0)

        if self.runtime_view:
            self.fw.removeProtocol(selected_zone, proto)
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.removeProtocol(proto)
        self.changes_applied()

    def add_edit_protocol(self, add):
        selected_zone = self.get_selected_zone()

        old_proto = None
        if not add:
            selection = self.protocolView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_proto = self.protocolStore.get_value(iter, 0)

        self.protoDialogProtoCombobox.set_active(0)
        self.protoDialogOtherProtoCheck.set_active(False)

        if old_proto:
            combobox_select_text(self.protoDialogProtoCombobox, old_proto)

        self.protoDialogOkButton.set_sensitive(False)

        self.protoDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.protoDialog.set_transient_for(self.mainWindow)
        self.protoDialog.show_all()
        self.add_visible_dialog(self.protoDialog)
        result = self.protoDialog.run()
        self.protoDialog.hide()
        self.remove_visible_dialog(self.protoDialog)

        if result != 1:
            return

        if self.protoDialogOtherProtoCheck.get_active():
            proto = self.protoDialogOtherProtoEntry.get_text()
        else:
            proto = self.protoDialogProtoCombobox.get_active_text()

        if old_proto == proto:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryProtocol(selected_zone, proto):
                self.fw.addProtocol(selected_zone, proto)
                if not add:
                    self.fw.removeProtocol(selected_zone, old_proto)
                self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not zone.queryProtocol(proto):
                if not add:
                    zone.removeProtocol(old_proto)
                zone.addProtocol(proto)
                self.changes_applied()

    def service_conf_add_edit_protocol(self, add):
        active_service = self.get_active_service()

        old_proto = None
        if not add:
            selection = self.serviceConfProtocolView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_proto = self.serviceConfProtocolStore.get_value(iter, 0)

        self.protoDialogProtoCombobox.set_active(0)
        self.protoDialogOtherProtoCheck.set_active(False)

        if old_proto:
            combobox_select_text(self.protoDialogProtoCombobox, old_proto)

        self.protoDialogOkButton.set_sensitive(False)

        self.protoDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.protoDialog.set_transient_for(self.mainWindow)
        self.protoDialog.show_all()
        self.add_visible_dialog(self.protoDialog)
        result = self.protoDialog.run()
        self.protoDialog.hide()
        self.remove_visible_dialog(self.protoDialog)

        if result != 1:
            return

        if self.protoDialogOtherProtoCheck.get_active():
            proto = self.protoDialogOtherProtoEntry.get_text()
        else:
            proto = self.protoDialogProtoCombobox.get_active_text()

        if old_proto == proto:
            # nothing to change
            return

        service = self.fw.config().getServiceByName(active_service)
        if not service.queryProtocol(proto):
            if not add:
                service.removeProtocol(old_proto)
            service.addProtocol(proto)
            self.changes_applied()

    def protocol_added_cb(self, zone, protocol, timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.protocolStore.get_iter_first()
        while iter:
            if self.protocolStore.get_value(iter, 0) == protocol:
                # already there
                return
            iter = self.protocolStore.iter_next(iter)
        # nothing found, so add it
        self.protocolStore.append([protocol])

    def protocol_removed_cb(self, zone, protocol):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        iter = self.protocolStore.get_iter_first()
        while iter:
            if self.protocolStore.get_value(iter, 0) == protocol:
                self.protocolStore.remove(iter)
                break
            iter = self.protocolStore.iter_next(iter)

    def onForwardDialogChecksToggled(self, check, *args):
        val1 = self.forwardDialogLocalCheck.get_active()
        val2 = self.forwardDialogToPortCheck.get_active()

        self.forwardDialogToAddrLabel.set_sensitive(not val1)
        self.forwardDialogToAddrEntry.set_sensitive(not val1)
        self.forwardDialogToPortCheck.set_sensitive(not val1)
        self.forwardDialogToPortLabel.set_sensitive(val1 or val2)
        self.forwardDialogToPortEntry.set_sensitive(val1 or val2)

        self.onForwardChanged(None)

    def onForwardDialogToPortCheckToggled(self, check, *args):
        toport = check.get_active()
        self.forwardDialogToPortLabel.set_sensitive(toport)
        self.forwardDialogToPortEntry.set_sensitive(toport)
        self.onForwardChanged(None)

    def _check_forward(self):
        ports = self.forwardDialogPortEntry.get_text()
        to_ports = self.forwardDialogToPortEntry.get_text()
        to_addr = self.forwardDialogToAddrEntry.get_text()

        local_check = self.forwardDialogLocalCheck.get_active()
        to_port_check = self.forwardDialogToPortCheck.get_active()

        ports = functions.getPortRange(ports)
        to_ports = functions.getPortRange(to_ports)

        ports_ok = False
        if ports and (isinstance(ports, list) or \
                      isinstance(ports, tuple)):
            ports_ok = True
        to_ports_ok = False
        if to_ports and (isinstance(to_ports, list) or \
                         isinstance(to_ports, tuple)):
            to_ports_ok = True
        to_addr_ok = False
        if to_addr != "":
            if self.forwardDialog.family == "ipv4" and \
               functions.checkIP(to_addr):
                to_addr_ok = True
            if self.forwardDialog.family == "ipv6" and \
               functions.checkIP6(to_addr):
                to_addr_ok = True
            if self.forwardDialog.family is None and \
               (functions.checkIP(to_addr) or functions.checkIP6(to_addr)):
                to_addr_ok = True
        ok = False
        if ports_ok:
            if local_check:
                if to_ports_ok and ports != to_ports:
                    ok = True
            elif to_addr_ok:
                if to_port_check:
                    if to_ports_ok:
                        ok = True
                else:
                    ok = True
        return ok

    def onForwardChanged(self, arg):
        ok = False
        if arg == self.forwardDialogProtoCombobox:
            if self._check_forward():
                ok = True
        else:
            ok = self._check_forward()

        self.forwardDialogOkButton.set_sensitive(ok)

    def onAddForwardPort(self, *args):
        self.add_edit_forward_port(True)

    def onEditForwardPort(self, *args):
        self.add_edit_forward_port(False)

    def onForwardPortClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_forward_port(False)

    def forwardport_select_dialog(self, family, old_value=None):
        self.forwardDialogOkButton.set_sensitive(False)
        self.forwardDialogLocalCheck.set_active(True)
        self.forwardDialogLocalCheck.set_active(False)
        self.forwardDialogToPortCheck.set_active(False)
        self.forwardDialog.family = family

        (old_port, old_proto, old_to_port, old_to_addr) = \
            self.split_fwp_string(old_value)

        self.forwardDialogPortEntry.set_text("")
        if old_port is not None:
            self.forwardDialogPortEntry.set_text(old_port)
        combobox_select_text(self.forwardDialogProtoCombobox, old_proto)
        self.forwardDialogToPortEntry.set_text("")
        if old_to_port is not None:
            self.forwardDialogToPortEntry.set_text(old_to_port)
        if old_to_addr:
            if old_to_port:
                self.forwardDialogToPortCheck.set_active(True)
        else:
            self.forwardDialogLocalCheck.set_active(True)
        self.forwardDialogToAddrEntry.set_text("")
        if old_to_addr is not None:
            self.forwardDialogToAddrEntry.set_text(old_to_addr)

        self.forwardDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.forwardDialog.set_transient_for(self.mainWindow)
        self.forwardDialog.show_all()
        self.add_visible_dialog(self.forwardDialog)
        result = self.forwardDialog.run()
        self.forwardDialog.hide()
        self.remove_visible_dialog(self.forwardDialog)

        if result != 1:
            return None

        port = self.forwardDialogPortEntry.get_text()
        proto = self.forwardDialogProtoCombobox.get_active_text()
        to_addr = self.forwardDialogToAddrEntry.get_text()
        to_port = self.forwardDialogToPortEntry.get_text()
        if not self.forwardDialogLocalCheck.get_active():
            if not self.forwardDialogToPortCheck.get_active():
                to_port = ""
        else:
            to_addr = ""

        value = self.create_fwp_string(port, proto, to_port, to_addr)
        if old_value == value:
            return None

        return value

    def add_edit_forward_port(self, add):
        selected_zone = self.get_selected_zone()

        self.forwardDialogOkButton.set_sensitive(False)
        self.forwardDialogLocalCheck.set_active(True)
        self.forwardDialogLocalCheck.set_active(False)
        self.forwardDialogToPortCheck.set_active(False)
        self.forwardDialog.family = None

        old_port = None
        old_proto = None
        old_to_port = None
        old_to_addr = None
        iter = None
        if add:
            self.forwardDialogPortEntry.set_text("")
            self.forwardDialogProtoCombobox.set_active(0)
            self.forwardDialogToPortEntry.set_text("")
            self.forwardDialogToAddrEntry.set_text("")
        else:
            selection = self.forwardView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_port = self.forwardStore.get_value(iter, 0)
            old_proto = self.forwardStore.get_value(iter, 1)
            old_to_port = self.forwardStore.get_value(iter, 2)
            old_to_addr = self.forwardStore.get_value(iter, 3)

            self.forwardDialogPortEntry.set_text(old_port)
            combobox_select_text(self.forwardDialogProtoCombobox, old_proto)
            self.forwardDialogToPortEntry.set_text(old_to_port)
            if old_to_addr:
                if old_to_port:
                    self.forwardDialogToPortCheck.set_active(True)
            else:
                self.forwardDialogLocalCheck.set_active(True)
            self.forwardDialogToAddrEntry.set_text(old_to_addr)

        self.forwardDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.forwardDialog.set_transient_for(self.mainWindow)
        self.forwardDialog.show_all()
        self.add_visible_dialog(self.forwardDialog)
        result = self.forwardDialog.run()
        self.forwardDialog.hide()
        self.remove_visible_dialog(self.forwardDialog)

        if result != 1:
            return

        port = self.forwardDialogPortEntry.get_text()
        proto = self.forwardDialogProtoCombobox.get_active_text()
        to_addr = self.forwardDialogToAddrEntry.get_text()
        to_port = self.forwardDialogToPortEntry.get_text()
        if not self.forwardDialogLocalCheck.get_active():
            if not self.forwardDialogToPortCheck.get_active():
                to_port = ""
        else:
            to_addr = ""

        if not add and (old_port == port and old_proto == proto and \
                            old_to_port == to_port and old_to_addr == to_addr):
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryForwardPort(selected_zone, port, proto,
                                            to_port, to_addr):

                self.fw.addForwardPort(selected_zone, port, proto,
                                       to_port, to_addr)
                if not add:
                    self.fw.removeForwardPort(selected_zone, old_port, old_proto,
                                              old_to_port, old_to_addr)
                if add and to_addr and not self.fw.queryMasquerade(selected_zone):
                    if self.masqueradeQueryDialog() == Gtk.ResponseType.YES:
                        self.fw.addMasquerade(selected_zone)
                self.changes_applied()
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            if not zone.queryForwardPort(port, proto, to_port, to_addr):
                if not add:
                    zone.removeForwardPort(old_port, old_proto,
                                           old_to_port, old_to_addr)
                zone.addForwardPort(port, proto, to_port, to_addr)
                if add and to_addr and not zone.getMasquerade():
                    if self.masqueradeQueryDialog() == Gtk.ResponseType.YES:
                        zone.setMasquerade(True)
                self.changes_applied()

    def masqueradeQueryDialog(self):
        text = _("Forwarding to another system is only useful if the interface is masqueraded.\nDo you want to masquerade this zone ?")
        return self._dialog(text=text,
                            buttons=((Gtk.STOCK_YES, Gtk.ResponseType.YES),
                                     (Gtk.STOCK_NO, Gtk.ResponseType.NO)))

    def forward_port_added_cb(self, zone, port, protocol, to_port, to_address,
                              timeout):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        self._forward_port_added_cb(zone, port, protocol, to_port, to_address)

    def forward_port_removed_cb(self, zone, port, protocol, to_port,
                                to_address):
        if not self.runtime_view or zone != self.get_selected_zone():
            return
        self._forward_port_removed_cb(zone, port, protocol, to_port, to_address)

    def _forward_port_added_cb(self, zone, port, protocol, to_port, to_address):
        iter = self.forwardStore.get_iter_first()
        while iter:
            if self.forwardStore.get_value(iter, 0) == port and \
                    self.forwardStore.get_value(iter, 1) == protocol and \
                    self.forwardStore.get_value(iter, 2) == to_port and \
                    self.forwardStore.get_value(iter, 3) == to_address:
                # already there
                return
            iter = self.forwardStore.iter_next(iter)
        # nothing found, so add it
        self.forwardStore.append([port, protocol, to_port, to_address])

    def _forward_port_removed_cb(self, zone, port, protocol, to_port,
                                 to_address):
        iter = self.forwardStore.get_iter_first()
        while iter:
            if self.forwardStore.get_value(iter, 0) == port and \
                    self.forwardStore.get_value(iter, 1) == protocol and \
                    self.forwardStore.get_value(iter, 2) == to_port and \
                    self.forwardStore.get_value(iter, 3) == to_address:
                self.forwardStore.remove(iter)
                break
            iter = self.forwardStore.iter_next(iter)

    def onRemoveForwardPort(self, *args):
        selected_zone = self.get_selected_zone()
        selection = self.forwardView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        port = self.forwardStore.get_value(iter, 0)
        proto = self.forwardStore.get_value(iter, 1)
        to_port = self.forwardStore.get_value(iter, 2)
        to_addr = self.forwardStore.get_value(iter, 3)

        if self.runtime_view:
            self.fw.removeForwardPort(selected_zone, port, proto,
                                      to_port, to_addr)
        else:
            zone = self.fw.config().getZoneByName(selected_zone)
            zone.removeForwardPort(port, proto, to_port, to_addr)
        self.changes_applied()

    def onChangeService(self, *args):
        active_service = self.get_active_service()

        ### load service settings

        self.serviceConfPortStore.clear()
        self.serviceConfProtocolStore.clear()
        self.serviceConfSourcePortStore.clear()
        self.serviceConfModuleStore.clear()
        self.serviceConfDestIpv4Chooser.set_text("")
        self.serviceConfDestIpv6Chooser.set_text("")

        self.serviceConfPortView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)
        self.serviceConfProtocolView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)
        self.serviceConfSourcePortView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)
        self.serviceConfModuleView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)

        if not active_service:
            self.serviceConfEditServiceButton.set_sensitive(False)
            self.serviceConfRemoveServiceButton.set_sensitive(False)
            self.serviceConfLoadDefaultsServiceButton.set_sensitive(False)
            self.serviceConfServiceNotebook.set_sensitive(False)
            return

        self.serviceConfEditServiceButton.set_sensitive(True)
        self.serviceConfServiceNotebook.set_sensitive(True)

        ports = [ ]
        protocols = [ ]
        source_ports = [ ]
        modules = [ ]
        destination = { }

        if self.runtime_view:
            # load runtime configuration

            settings = self.fw.getServiceSettings(active_service)
            ports = settings.getPorts()
            protocols = settings.getProtocols()
            source_ports = settings.getSourcePorts()
            modules = settings.getModules()
            destination = settings.getDestinations()
            default = False
            builtin = False
        else:
            try:
                service = self.fw.config().getServiceByName(active_service)
            except:
                return

            # load permanent configuration
            settings = service.getSettings()
            ports = settings.getPorts()
            protocols = settings.getProtocols()
            source_ports = settings.getSourcePorts()
            modules = settings.getModules()
            destination = settings.getDestinations()
            props = service.get_properties()
            default = props["default"]
            builtin = props["builtin"]

        self.serviceConfRemoveServiceButton.set_sensitive(not builtin and default)
        self.serviceConfLoadDefaultsServiceButton.set_sensitive(not default)

        # set ports
        for item in ports:
            self.serviceConfPortStore.append(item)

        # set protocols
        for item in protocols:
            self.serviceConfProtocolStore.append([item])

        # set ports
        for item in source_ports:
            self.serviceConfSourcePortStore.append(item)

        # set modules
        for item in modules:
            self.serviceConfModuleStore.append([item])

        # set destination
        if "ipv4" in destination:
            self.serviceConfDestIpv4Chooser.set_text(destination["ipv4"])
        if "ipv6" in destination:
            self.serviceConfDestIpv6Chooser.set_text(destination["ipv6"])

        self.serviceConfPortView.get_selection().set_mode(
            Gtk.SelectionMode.SINGLE)
        self.serviceConfProtocolView.get_selection().set_mode(
            Gtk.SelectionMode.SINGLE)
        self.serviceConfSourcePortView.get_selection().set_mode(
            Gtk.SelectionMode.SINGLE)
        self.serviceConfModuleView.get_selection().set_mode(
            Gtk.SelectionMode.SINGLE)

    def conf_service_added_cb(self, service):
        if self.runtime_view:
            return
        # check if service is in store
        iter = self.serviceConfServiceStore.get_iter_first()
        while iter:
            if self.serviceConfServiceStore.get_value(iter, 0) == service:
                return
            iter = self.serviceConfServiceStore.iter_next(iter)
        # not in list, append
        self.serviceConfServiceStore.append([service])

    def conf_service_updated_cb(self, service):
        self.onChangeService()

    def conf_service_removed_cb(self, service):
        if self.runtime_view:
            return
        iter = self.serviceConfServiceStore.get_iter_first()
        while iter:
            if self.serviceConfServiceStore.get_value(iter, 0) == service:
                self.serviceConfServiceStore.remove(iter)
                break
            iter = self.serviceConfServiceStore.iter_next(iter)

    def conf_service_renamed_cb(self, service):
        if self.runtime_view:
            return

        # Get all services, renamed the one that is missing.
        # If more or less than one is missing, update service store.

        services = self.fw.config().getServiceNames()

        use_iter = None
        iter = self.serviceConfServiceStore.get_iter_first()
        while iter:
            if self.serviceConfServiceStore.get_value(iter, 0) not in services:
                if use_iter is not None:
                    return self.load_services()
                use_iter = iter
            iter = self.serviceConfServiceStore.iter_next(iter)

        if use_iter is None:
            return self.load_services()

        self.serviceConfServiceStore.set_value(use_iter, 0, service)

    def onServiceConfAddService(self, *args):
        self.add_edit_service(True)

    def onServiceConfRemoveService(self, *args):
        active_service = self.get_active_service()
        service = self.fw.config().getServiceByName(active_service)
        service.remove()
        self.changes_applied()
        self.load_services()
        self.onChangeService()

    def onServiceConfEditService(self, *args):
        self.add_edit_service(False)

    def onServiceBaseDialogChanged(self, *args):
        if args and (args[0] == self.serviceBaseDialogNameEntry):
            additional_chars = "".join(Service.ADDITIONAL_ALNUM_CHARS)
            allowed_chars = string.ascii_letters+string.digits+additional_chars
            self.entry_changed(args[0], allowed_chars)

        self.serviceBaseDialogOkButton.set_sensitive(True)

    def onServiceConfAddPort(self, *args):
        self.service_conf_add_edit_port(True)

    def onServiceConfEditPort(self, *args):
        self.service_conf_add_edit_port(False)

    def onServiceConfPortClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and \
           not self.runtime_view:
            self.service_conf_add_edit_port(False)

    def onServiceConfRemovePort(self, *args):
        active_service = self.get_active_service()
        selection = self.serviceConfPortView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        port = self.serviceConfPortStore.get_value(iter, 0)
        proto = self.serviceConfPortStore.get_value(iter, 1)

        service = self.fw.config().getServiceByName(active_service)
        service.removePort(port, proto)
        self.changes_applied()

    def change_service_dialog_port_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.serviceConfEditPortButton.set_sensitive(True)
            self.serviceConfRemovePortButton.set_sensitive(True)
        else:
            self.serviceConfEditPortButton.set_sensitive(False)
            self.serviceConfRemovePortButton.set_sensitive(False)

    def onServiceConfAddProtocol(self, *args):
        self.service_conf_add_edit_protocol(True)

    def onServiceConfEditProtocol(self, *args):
        self.service_conf_add_edit_protocol(False)

    def onServiceConfProtocolClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and \
           not self.runtime_view:
            self.service_conf_add_edit_protocol(False)

    def onServiceConfRemoveProtocol(self, *args):
        active_service = self.get_active_service()
        selection = self.serviceConfProtocolView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        proto = self.serviceConfProtocolStore.get_value(iter, 0)

        service = self.fw.config().getServiceByName(active_service)
        service.removeProtocol(proto)
        self.changes_applied()

    def change_service_dialog_protocol_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.serviceConfEditProtocolButton.set_sensitive(True)
            self.serviceConfRemoveProtocolButton.set_sensitive(True)
        else:
            self.serviceConfEditProtocolButton.set_sensitive(False)
            self.serviceConfRemoveProtocolButton.set_sensitive(False)

    def onServiceConfAddSourcePort(self, *args):
        self.service_conf_add_edit_source_port(True)

    def onServiceConfEditSourcePort(self, *args):
        self.service_conf_add_edit_source_port(False)

    def onServiceConfSourcePortClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and \
           not self.runtime_view:
            self.service_conf_add_edit_source_port(False)

    def onServiceConfRemoveSourcePort(self, *args):
        active_service = self.get_active_service()
        selection = self.serviceConfSourcePortView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        port = self.serviceConfSourcePortStore.get_value(iter, 0)
        proto = self.serviceConfSourcePortStore.get_value(iter, 1)

        service = self.fw.config().getServiceByName(active_service)
        service.removeSourcePort(port, proto)
        self.changes_applied()

    def change_service_dialog_source_port_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.serviceConfEditSourcePortButton.set_sensitive(True)
            self.serviceConfRemoveSourcePortButton.set_sensitive(True)
        else:
            self.serviceConfEditSourcePortButton.set_sensitive(False)
            self.serviceConfRemoveSourcePortButton.set_sensitive(False)

    def add_edit_service(self, add):
        if add:
            default = True
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None

            self.serviceBaseDialogNameEntry.set_text("")
            self.serviceBaseDialogVersionEntry.set_text("")
            self.serviceBaseDialogShortEntry.set_text("")
            self.serviceBaseDialogDescText.get_buffer().set_text("")
        else:
            active_service = self.get_active_service()
            service = self.fw.config().getServiceByName(active_service)
            settings = service.getSettings()
            props = service.get_properties()
            default = props["default"]
            builtin = props["builtin"]

            old_name = service.get_property("name")
            old_version = settings.getVersion()
            old_short = settings.getShort()
            old_desc = settings.getDescription()

            self.serviceBaseDialogNameEntry.set_text(old_name)
            self.serviceBaseDialogVersionEntry.set_text(old_version)
            self.serviceBaseDialogShortEntry.set_text(old_short)
            self.serviceBaseDialogDescText.get_buffer().set_text(old_desc)

        self.serviceBaseDialogOkButton.set_sensitive(False)
        if builtin:
            self.serviceBaseDialogNameEntry.set_tooltip_markup(\
                _("Built-in service, rename not supported."))
        else:
            self.serviceBaseDialogNameEntry.set_tooltip_markup("")
        self.serviceBaseDialogNameEntry.set_sensitive(not builtin and default)

        self.serviceBaseDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.serviceBaseDialog.set_transient_for(self.mainWindow)
        self.serviceBaseDialog.show_all()
        self.add_visible_dialog(self.serviceBaseDialog)
        result = self.serviceBaseDialog.run()
        self.serviceBaseDialog.hide()
        self.remove_visible_dialog(self.serviceBaseDialog)

        if result != 1:
            return

        name = self.serviceBaseDialogNameEntry.get_text()
        version = self.serviceBaseDialogVersionEntry.get_text()
        short = self.serviceBaseDialogShortEntry.get_text()
        buffer = self.serviceBaseDialogDescText.get_buffer()
        desc = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(),
                               False)

        if old_name == name and \
                old_version == version and old_short == short and \
                old_desc == desc:
            # no changes
            return

        if not add:
            active_service = self.get_active_service()
            service = self.fw.config().getServiceByName(active_service)
            settings = service.getSettings()
        else:
            settings = client.FirewallClientServiceSettings()

        if old_version != version or old_short != short or \
                old_desc != desc:
            # settings
            settings.setVersion(version)
            settings.setShort(short)
            settings.setDescription(desc)
            if not add:
                service.update(settings)

        if not add:
            if old_name == name:
                return
            service.rename(name)
        else:
            self.fw.config().addService(name, settings)
        self.changes_applied()

    def onServiceConfLoadDefaultsService(self, *args):
        active_service = self.get_active_service()
        service = self.fw.config().getServiceByName(active_service)
        service.loadDefaults()
        self.changes_applied()
        self.onChangeService()

    def onServiceConfAddModule(self, *args):
        self.add_edit_module(True)

    def onServiceConfEditModule(self, *args):
        self.add_edit_module(False)

    def onServiceConfModuleClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and \
           not self.runtime_view:
            self.add_edit_module(False)

    def onServiceConfRemoveModule(self, *args):
        active_service = self.get_active_service()
        selection = self.serviceConfModuleView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        module = self.serviceConfModuleStore.get_value(iter, 0)

        service = self.fw.config().getServiceByName(active_service)
        service.removeModule(module)
        self.changes_applied()

    def change_service_dialog_module_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.serviceConfEditModuleButton.set_sensitive(True)
            self.serviceConfRemoveModuleButton.set_sensitive(True)
        else:
            self.serviceConfEditModuleButton.set_sensitive(False)
            self.serviceConfRemoveModuleButton.set_sensitive(False)

    def helper_select_dialog(self, old_helper=""):
        self.helperDialogHelperStore.clear()

        helpers = [ ]
        if self.runtime_view:
            helpers = self.fw.getHelpers()
        else:
            helpers = self.fw.config().getHelperNames()

        for helper in sorted(helpers):
            self.helperDialogHelperStore.append([helper])

        selection = self.helperDialogHelperView.get_selection()
        selection.set_mode(Gtk.SelectionMode.SINGLE)

        iter = self.helperDialogHelperStore.get_iter_first()
        while iter:
            if self.helperDialogHelperStore.get_value(iter, 0) == old_helper:
                selection.select_iter(iter)
            iter = self.helperDialogHelperStore.iter_next(iter)

        self.helperDialogOkButton.set_sensitive(False)
        self.helperDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.helperDialog.set_transient_for(self.mainWindow)
        self.helperDialog.show_all()
        self.add_visible_dialog(self.helperDialog)

        result = self.helperDialog.run()
        self.helperDialog.hide()
        self.remove_visible_dialog(self.helperDialog)

        if result != 1:
            return None

        (model, iter) = selection.get_selected()
        if not iter:
            return None
        helper = self.helperDialogHelperStore.get_value(iter, 0)
        if old_helper == helper:
            return None
        return helper

    def add_edit_module(self, add):
        active_service = self.get_active_service()

        old_helper = None

        if not add:
            selection = self.serviceConfModuleView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_helper = self.serviceConfModuleStore.get_value(iter, 0)

        helper = self.helper_select_dialog(old_helper)
        if helper is None:
            return

        if old_helper == helper:
            # nothing to change
            return

        service = self.fw.config().getServiceByName(active_service)
        if not service.queryModule(helper):
            if not add:
                service.removeModule(old_helper)
            service.addModule(helper)
            self.changes_applied()

    def onChangeServiceConfDestIpv4(self, *args):
        old_addr = self.serviceConfDestIpv4Chooser.get_text()
        addr = self.address_select_dialog("ipv4", old_addr)
        if addr is None:
            return
        active_service = self.get_active_service()
        service = self.fw.config().getServiceByName(active_service)
        if not service.queryDestination("ipv4", addr):
            if addr != "":
                service.setDestination("ipv4", addr)
            else:
                service.removeDestination("ipv4")
            self.changes_applied()

    def onChangeServiceConfDestIpv6(self, *args):
        old_addr = self.serviceConfDestIpv6Chooser.get_text()
        addr = self.address_select_dialog("ipv6", old_addr)
        if addr is None:
            return
        active_service = self.get_active_service()
        service = self.fw.config().getServiceByName(active_service)
        if not service.queryDestination("ipv6", addr):
            if addr != "":
                service.setDestination("ipv6", addr)
            else:
                service.removeDestination("ipv6")
            self.changes_applied()

    def onAddressChanged(self, entry, addr_type, old_address):
        text = entry.get_text()
        if text == "":
            self.addressDialogOkButton.set_sensitive(True)
            return

        self.addressDialogOkButton.set_sensitive(False)
        if addr_type == "ipv4":
            if functions.checkIPnMask(text) and text != old_address:
                self.addressDialogOkButton.set_sensitive(True)
        elif addr_type == "ipv6":
            if functions.checkIP6nMask(text) and text != old_address:
                self.addressDialogOkButton.set_sensitive(True)
        else:
            if (functions.checkIPnMask(text) or functions.checkIP6nMask(text)) \
               and text != old_address:
                self.addressDialogOkButton.set_sensitive(True)

    def address_select_dialog(self, addr_type, old_address):
        if addr_type == "ipv4":
            label1 = _("Please enter an ipv4 address with the form address[/mask].")
            label2 = _("The mask can be a network mask or a number.")
        elif addr_type == "ipv6":
            label1 = _("Please enter an ipv6 address with the form address[/mask].")
            label2 = _("The mask is a number.")
        else:
            label1 = _("Please enter an ipv4 or ipv6 address with the form address[/mask].")
            label2 = _("The mask can be a network mask or a number for ipv4.\nThe mask is a number for ipv6.")
        self.addressDialogLabel.set_markup(label1)
        self.addressDialogLabel2.set_markup(label2)

        self.addressDialogAddressEntry.set_text(old_address)
        handler_id = self.addressDialogAddressEntry.connect(
            "changed", self.onAddressChanged, addr_type, old_address)
        self.addressDialogOkButton.set_sensitive(False)

        self.addressDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.addressDialog.set_transient_for(self.mainWindow)
        self.addressDialog.show_all()
        self.add_visible_dialog(self.addressDialog)
        result = self.addressDialog.run()
        self.addressDialog.hide()
        self.remove_visible_dialog(self.addressDialog)

        self.addressDialogAddressEntry.disconnect(handler_id)

        address = self.addressDialogAddressEntry.get_text()

        if functions.check_mac(address):
            address = address.upper()

        if result != 1 or old_address == address:
            return None
        return address

    def get_active_ipset(self):
        selection = self.ipsetConfIPSetView.get_selection()
        (model, iter) = selection.get_selected()
        if iter:
            return self.ipsetConfIPSetStore.get_value(iter, 0)
        return None

    def load_ipsets(self):
        if not self.show_ipsets:
            return
        active_ipset = self.get_active_ipset()

        if self.runtime_view:
            ipsets = self.fw.getIPSets()
        else:
            ipsets = self.fw.config().getIPSetNames()

        selection = self.ipsetConfIPSetView.get_selection()
        selection.set_mode(Gtk.SelectionMode.NONE)

        # reset and fill notebook content according to view

        self.ipsetConfIPSetStore.clear()

        # ipsets

        for ipset in ipsets:
            self.ipsetConfIPSetStore.append([ipset])

        selection.set_mode(Gtk.SelectionMode.SINGLE)

        iter = self.ipsetConfIPSetStore.get_iter_first()
        while iter:
            if self.ipsetConfIPSetStore.get_value(iter, 0) == \
                    active_ipset:
                selection.select_iter(iter)
                return
            iter = self.ipsetConfIPSetStore.iter_next(iter)
        selection.select_path(0)

        self.ipsetConfRemoveEntryMenubutton.set_sensitive(
            len(self.ipsetConfEntryStore) > 0)

        if not self.get_active_ipset():
            self.ipsetConfEditIPSetButton.set_sensitive(False)
            self.ipsetConfRemoveIPSetButton.set_sensitive(False)
            self.ipsetConfLoadDefaultsIPSetButton.set_sensitive(False)
            self.ipsetConfEntryBox.set_sensitive(False)

    def onIPSetConfAddIPSet(self, *args):
        self.add_edit_ipset(True)

    def onIPSetConfRemoveIPSet(self, *args):
        active_ipset = self.get_active_ipset()
        ipset = self.fw.config().getIPSetByName(active_ipset)
        ipset.remove()
        self.changes_applied()
        self.load_ipsets()
        self.onChangeIPSet()

    def onIPSetConfEditIPSet(self, *args):
        self.add_edit_ipset(False)

    def onIPSetConfLoadDefaultsIPSet(self, *args):
        active_ipset = self.get_active_ipset()
        ipset = self.fw.config().getIPSetByName(active_ipset)
        ipset.loadDefaults()
        self.changes_applied()
        self.onChangeIPSet()

    def onIPSetBaseDialogChanged(self, *args):
        def check_ipset_name(ipset):
            return (len(ipset) <= IPSET_MAXNAMELEN, ipset)

        OK=True
        if args and (args[0] == self.ipsetBaseDialogNameEntry):
            additional_chars = "".join(IPSet.ADDITIONAL_ALNUM_CHARS)
            allowed_chars = string.ascii_letters+string.digits+additional_chars
            OK = self.entry_changed(args[0], allowed_chars, check_ipset_name)
        self.ipsetBaseDialogOkButton.set_sensitive(OK)

    def add_edit_ipset(self, add):
        self.ipsetBaseDialogTypeCombobox.remove_all()
        ipset_types = self.fw.get_property("IPSetTypes")
        for x in ipset_types:
            self.ipsetBaseDialogTypeCombobox.append_text(x)
        self.ipsetBaseDialogBadTypeLabel.set_text("")

        if add:
            default = True
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None
            old_ipset_type = None
            old_options = { }

            self.ipsetBaseDialogNameEntry.set_text("")
            self.ipsetBaseDialogVersionEntry.set_text("")
            self.ipsetBaseDialogShortEntry.set_text("")
            self.ipsetBaseDialogDescText.get_buffer().set_text("")
            combobox_select_text(self.ipsetBaseDialogTypeCombobox, "hash:ip")
            self.ipsetBaseDialogFamilyCombobox.set_active(0)
            self.ipsetBaseDialogTimeoutEntry.set_text("")
            self.ipsetBaseDialogHashsizeEntry.set_text("")
            self.ipsetBaseDialogMaxelemEntry.set_text("")
        else:
            active_ipset = self.get_active_ipset()
            ipset = self.fw.config().getIPSetByName(active_ipset)
            settings = ipset.getSettings()
            props = ipset.get_properties()
            default = props["default"]
            builtin = props["builtin"]

            old_name = ipset.get_property("name")
            old_version = settings.getVersion()
            old_short = settings.getShort()
            old_desc = settings.getDescription()
            old_ipset_type = settings.getType()
            old_options = settings.getOptions()

            self.ipsetBaseDialogNameEntry.set_text(old_name)
            self.ipsetBaseDialogVersionEntry.set_text(old_version)
            self.ipsetBaseDialogShortEntry.set_text(old_short)
            self.ipsetBaseDialogDescText.get_buffer().set_text(old_desc)
            if old_ipset_type not in ipset_types:
                self.ipsetBaseDialogBadTypeLabel.set_text(old_ipset_type)
            else:
                combobox_select_text(self.ipsetBaseDialogTypeCombobox,
                                     old_ipset_type)
            if "family" in old_options and \
               old_options["family"] in [ "inet", "inet6" ]:
                combobox_select_text(self.ipsetBaseDialogFamilyCombobox,
                                     old_options["family"])
            else:
                self.ipsetBaseDialogFamilyCombobox.set_active(0)
            if "timeout" in old_options:
                self.ipsetBaseDialogTimeoutEntry.set_text(
                    old_options["timeout"])
            else:
                self.ipsetBaseDialogTimeoutEntry.set_text("")
            if "hashsize" in old_options:
                self.ipsetBaseDialogHashsizeEntry.set_text(
                    old_options["hashsize"])
            else:
                self.ipsetBaseDialogHashsizeEntry.set_text("")
            if "maxelem" in old_options:
                self.ipsetBaseDialogMaxelemEntry.set_text(
                    old_options["maxelem"])
            else:
                self.ipsetBaseDialogMaxelemEntry.set_text("")

        self.ipsetBaseDialogOkButton.set_sensitive(False)
        if builtin:
            self.ipsetBaseDialogNameEntry.set_tooltip_markup(\
                _("Built-in ipset, rename not supported."))
        else:
            self.ipsetBaseDialogNameEntry.set_tooltip_markup("")
        self.ipsetBaseDialogNameEntry.set_sensitive(not builtin and default)

        self.ipsetBaseDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.ipsetBaseDialog.set_transient_for(self.mainWindow)
        self.ipsetBaseDialog.show_all()
        self.add_visible_dialog(self.ipsetBaseDialog)
        result = self.ipsetBaseDialog.run()
        self.ipsetBaseDialog.hide()
        self.remove_visible_dialog(self.ipsetBaseDialog)

        if result != 1:
            return

        name = self.ipsetBaseDialogNameEntry.get_text()
        version = self.ipsetBaseDialogVersionEntry.get_text()
        short = self.ipsetBaseDialogShortEntry.get_text()
        buffer = self.ipsetBaseDialogDescText.get_buffer()
        desc = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(),
                               False)
        ipset_type = self.ipsetBaseDialogBadTypeLabel.get_text()
        ipset_type = self.ipsetBaseDialogTypeCombobox.get_active_text()
        options = { }
        if self.ipsetBaseDialogFamilyCombobox.is_sensitive():
            x = self.ipsetBaseDialogFamilyCombobox.get_active_text()
            if x != "inet":
                options["family"] = x
        if self.ipsetBaseDialogTimeoutEntry.is_sensitive():
            x = self.ipsetBaseDialogTimeoutEntry.get_text()
            if x != "":
                options["timeout"] = x
        x = self.ipsetBaseDialogHashsizeEntry.get_text()
        if x != "":
            options["hashsize"] = x
        x = self.ipsetBaseDialogMaxelemEntry.get_text()
        if x != "":
            options["maxelem"] = x

        if old_name == name and \
                old_version == version and old_short == short and \
                old_desc == desc and old_ipset_type == ipset_type and \
                old_options == options:
            # no changes
            return

        if not add:
            active_ipset = self.get_active_ipset()
            ipset = self.fw.config().getIPSetByName(active_ipset)
            settings = ipset.getSettings()
        else:
            settings = client.FirewallClientIPSetSettings()

        if old_version != version or old_short != short or \
                old_desc != desc or old_ipset_type != ipset_type or \
                old_options != options:
            # settings
            settings.setVersion(version)
            settings.setShort(short)
            settings.setDescription(desc)
            settings.setType(ipset_type)
            settings.setOptions(options)
            if not add:
                ipset.update(settings)

        if not add:
            if old_name == name:
                return
            ipset.rename(name)
        else:
            self.fw.config().addIPSet(name, settings)
        self.changes_applied()

    def onIPSetChanged(self, *args):
        if self.ipsetBaseDialogTypeCombobox.get_active_text() is None:
            # unsupported ipset type
            return
        if self.ipsetBaseDialogTypeCombobox.get_active_text() == "hash:mac":
            self.ipsetBaseDialogFamilyLabel.set_sensitive(False)
            self.ipsetBaseDialogFamilyCombobox.set_sensitive(False)
        else:
            self.ipsetBaseDialogFamilyLabel.set_sensitive(True)
            self.ipsetBaseDialogFamilyCombobox.set_sensitive(True)

        self.ipsetBaseDialogOkButton.set_sensitive(True)

    def onIPSetConfAddEntry(self, *args):
        self.add_edit_ipset_entry(True)

    def onIPSetConfAddEntriesFromFile(self, *args):
        dialog = Gtk.FileChooserDialog(
            _("Please select a file"), None, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
        dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        dialog.set_transient_for(self.mainWindow)

        filefilter = Gtk.FileFilter()
        filefilter.set_name(_("Text Files"))
        filefilter.add_mime_type("text/plain")
        dialog.add_filter(filefilter)

        filefilter = Gtk.FileFilter()
        filefilter.set_name(_("All Files"))
        filefilter.add_pattern("*")
        dialog.add_filter(filefilter)

        result = dialog.run()
        dialog.hide()

        if result == Gtk.ResponseType.OK:
            filename = dialog.get_filename()
        else:
            return

        dialog.destroy()

        entries = self.get_ipset_entries_from_file(filename)

        active_ipset = self.get_active_ipset()

        if self.runtime_view:
            old_entries = self.fw.getEntries(active_ipset)

            changed = False
            for entry in entries:
                if entry not in old_entries:
                    old_entries.append(entry)
                    changed = True
            if changed:
                self.fw.setEntries(active_ipset, old_entries)
        else:
            ipset = self.fw.config().getIPSetByName(active_ipset)
            settings = ipset.getSettings()

            changed = False
            for entry in entries:
                if not settings.queryEntry(entry):
                    settings.addEntry(entry)
                    changed = True
            if changed:
                ipset.update(settings)

    def onIPSetConfEditEntry(self, *args):
        self.add_edit_ipset_entry(False)

    def onIPSetConfEntryClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and \
           not self.runtime_view:
            self.add_edit_ipset_entry(False)

    def onIPSetConfRemoveEntry(self, *args):
        active_ipset = self.get_active_ipset()
        selection = self.ipsetConfEntryView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        entry = self.ipsetConfEntryStore.get_value(iter, 0)

        if self.runtime_view:
            if self.fw.queryEntry(active_ipset, entry):
                self.fw.removeEntry(active_ipset, entry)
                self.changes_applied()
        else:
            ipset = self.fw.config().getIPSetByName(active_ipset)
            ipset.removeEntry(entry)
            self.changes_applied()

        self.ipsetConfRemoveEntryMenubutton.set_sensitive(
            len(self.ipsetConfEntryStore) > 0)

    def onIPSetConfRemoveEntriesFromFile(self, *args):
        dialog = Gtk.FileChooserDialog(
            _("Please select a file"), None, Gtk.FileChooserAction.OPEN,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
        dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        dialog.set_transient_for(self.mainWindow)

        filefilter = Gtk.FileFilter()
        filefilter.set_name(_("Text Files"))
        filefilter.add_mime_type("text/plain")
        dialog.add_filter(filefilter)

        filefilter = Gtk.FileFilter()
        filefilter.set_name(_("All Files"))
        filefilter.add_pattern("*")
        dialog.add_filter(filefilter)

        result = dialog.run()
        dialog.hide()

        if result == Gtk.ResponseType.OK:
            filename = dialog.get_filename()
        else:
            return

        dialog.destroy()

        entries = self.get_ipset_entries_from_file(filename)

        active_ipset = self.get_active_ipset()

        if self.runtime_view:
            old_entries = self.fw.getEntries(active_ipset)

            changed = False
            for entry in entries:
                if entry in old_entries:
                    old_entries.remove(entry)
                    changed = True
            if changed:
                self.fw.setEntries(active_ipset, old_entries)
        else:
            ipset = self.fw.config().getIPSetByName(active_ipset)
            settings = ipset.getSettings()

            changed = False
            for entry in entries:
                if settings.queryEntry(entry):
                    settings.removeEntry(entry)
                    changed = True
            if changed:
                ipset.update(settings)

    def onIPSetConfRemoveAllEntries(self, *args):
        active_ipset = self.get_active_ipset()
        if self.runtime_view:
            self.fw.setEntries(active_ipset, [ ])
            self.changes_applied()
        else:
            ipset = self.fw.config().getIPSetByName(active_ipset)
            ipset.setEntries([ ])
            self.changes_applied()

        self.ipsetConfRemoveEntryMenubutton.set_sensitive(
            len(self.ipsetConfEntryStore) > 0)

    def onIPSetEntryChanged(self, *args):
        settings = self.active_ipset_settings
        entry = self.ipsetEntryDialogEntryEntry.get_text()

        try:
            IPSet.check_entry(entry, settings.getOptions(), settings.getType())
        except Exception:
            self.ipsetEntryDialogOkButton.set_sensitive(False)
        else:
            self.ipsetEntryDialogOkButton.set_sensitive(True)

    def change_ipset_conf_entry_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.ipsetConfEditEntryButton.set_sensitive(True)
            self.ipsetConfRemoveEntryMenuitem.set_sensitive(True)
        else:
            self.ipsetConfEditEntryButton.set_sensitive(False)
            self.ipsetConfRemoveEntryMenuitem.set_sensitive(False)

    def add_edit_ipset_entry(self, add):
        active_ipset = self.get_active_ipset()
        if self.runtime_view:
            settings = self.fw.getIPSetSettings(active_ipset)
        else:
            settings = self.fw.config().getIPSetByName(active_ipset).getSettings()
        self.active_ipset_settings = settings

        self.ipsetEntryDialogTypeLabel.set_text(settings.getType())
        self.ipsetEntryDialogEntryEntry.set_text("")

        old_entry = None

        if not add:
            selection = self.ipsetConfEntryView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_entry = self.ipsetConfEntryStore.get_value(iter, 0)

        if old_entry:
            self.ipsetEntryDialogEntryEntry.set_text(old_entry)

        self.ipsetEntryDialogOkButton.set_sensitive(False)

        self.ipsetEntryDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.ipsetEntryDialog.set_transient_for(self.mainWindow)
        self.ipsetEntryDialog.show_all()
        self.add_visible_dialog(self.ipsetEntryDialog)
        result = self.ipsetEntryDialog.run()
        self.ipsetEntryDialog.hide()
        self.active_ipset_settings = None
        self.remove_visible_dialog(self.ipsetEntryDialog)

        if result != 1:
            return

        entry = self.ipsetEntryDialogEntryEntry.get_text()

        if old_entry == entry:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryEntry(active_ipset, entry):
                self.fw.addEntry(active_ipset, entry)
                if not add:
                    self.fw.removeEntry(active_ipset, old_entry)
                self.changes_applied()
        else:
            ipset = self.fw.config().getIPSetByName(active_ipset)
            if not ipset.queryEntry(entry):
                if not add:
                    ipset.removeEntry(old_entry)
                ipset.addEntry(entry)
                self.changes_applied()

    def ipset_entry_added_cb(self, ipset, entry):
        if not self.runtime_view or ipset != self.get_active_ipset():
            return
        iter = self.ipsetConfEntryStore.get_iter_first()
        while iter:
            if self.ipsetConfEntryStore.get_value(iter, 0) == entry:
                # already there
                return
            iter = self.ipsetConfEntryStore.iter_next(iter)
        # nothing found, so add it
        self.ipsetConfEntryStore.append([entry])

        self.ipsetConfRemoveEntryMenubutton.set_sensitive(
            len(self.ipsetConfEntryStore) > 0)

    def ipset_entry_removed_cb(self, ipset, entry):
        if not self.runtime_view or ipset != self.get_active_ipset():
            return
        iter = self.ipsetConfEntryStore.get_iter_first()
        while iter:
            if self.ipsetConfEntryStore.get_value(iter, 0) == entry:
                self.ipsetConfEntryStore.remove(iter)
                break
            iter = self.ipsetConfEntryStore.iter_next(iter)

        self.ipsetConfRemoveEntryMenubutton.set_sensitive(
            len(self.ipsetConfEntryStore) > 0)

    def conf_ipset_added_cb(self, ipset):
        if self.runtime_view:
            return
        # check if ipset is in store
        iter = self.ipsetConfIPSetStore.get_iter_first()
        while iter:
            if self.ipsetConfIPSetStore.get_value(iter, 0) == ipset:
                return
            iter = self.ipsetConfIPSetStore.iter_next(iter)
        # not in list, append
        self.ipsetConfIPSetStore.append([ipset])
        selection = self.ipsetConfIPSetView.get_selection()
        if selection.count_selected_rows() == 0:
            selection.select_path(0)

    def conf_ipset_updated_cb(self, ipset):
        if self.runtime_view or ipset != self.get_active_ipset():
            return
        self.onChangeIPSet()

    def conf_ipset_removed_cb(self, ipset):
        if self.runtime_view:
            return
        iter = self.ipsetConfIPSetStore.get_iter_first()
        while iter:
            if self.ipsetConfIPSetStore.get_value(iter, 0) == ipset:
                self.ipsetConfIPSetStore.remove(iter)
                break
            iter = self.ipsetConfIPSetStore.iter_next(iter)

    def conf_ipset_renamed_cb(self, ipset):
        if self.runtime_view:
            return

        # Get all ipsets, renamed the one that is missing.
        # If more or less than one is missing, update ipset store.

        ipsets = self.fw.config().getIPSetNames()

        use_iter = None
        iter = self.ipsetConfIPSetStore.get_iter_first()
        while iter:
            if self.ipsetConfIPSetStore.get_value(iter, 0) not in ipsets:
                if use_iter is not None:
                    return self.load_ipsets()
                use_iter = iter
            iter = self.ipsetConfIPSetStore.iter_next(iter)

        if use_iter is None:
            return self.load_ipsets()

        self.ipsetConfIPSetStore.set_value(use_iter, 0, ipset)

    def onChangeIPSet(self, *args):
        active_ipset = self.get_active_ipset()

        self.ipsetConfEntryStore.clear()

        self.ipsetConfEntryView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)

        if not active_ipset:
            self.ipsetConfEditIPSetButton.set_sensitive(False)
            self.ipsetConfRemoveIPSetButton.set_sensitive(False)
            self.ipsetConfLoadDefaultsIPSetButton.set_sensitive(False)
            self.ipsetConfEntryBox.set_sensitive(False)
            return

        self.ipsetConfEditIPSetButton.set_sensitive(True)
        self.ipsetConfEntryBox.set_sensitive(True)

        entries = [ ]

        if self.runtime_view:
            # load runtime configuration
            self.deactivate_exception_handler()
            try:
                settings = self.fw.getIPSetSettings(active_ipset)
            except (DBusException, Exception) as msg:
                self.activate_exception_handler()
                if isinstance(msg, DBusException):
                    msg = msg.get_dbus_message()
                else:
                    msg = str(msg)
                code = FirewallError.get_code(msg)
                if code == errors.NOT_APPLIED:
                    self.ipsetConfNotebook.set_sensitive(False)
                    return
                raise
            else:
                self.ipsetConfNotebook.set_sensitive(True)
            self.activate_exception_handler()
            entries = settings.getEntries()
            options = settings.getOptions()
            default = False
            builtin = False
        else:
            try:
                ipset = self.fw.config().getIPSetByName(active_ipset)
            except:
                return

            # load permanent configuration
            settings = ipset.getSettings()
            entries = settings.getEntries()
            options = settings.getOptions()
            props = ipset.get_properties()
            default = props["default"]
            builtin = props["builtin"]

        if "timeout" in options:
            self.ipsetConfEntrySW.hide()
            self.ipsetConfEntryBox.hide()
            self.ipsetConfEntryLabel.hide()
            self.ipsetConfTimeoutLabel.show()
        else:
            self.ipsetConfEntrySW.show()
            self.ipsetConfEntryBox.show()
            self.ipsetConfEntryLabel.show()
            self.ipsetConfTimeoutLabel.hide()

            # set entries
            for item in entries:
                self.ipsetConfEntryStore.append([item])

            self.ipsetConfEntryView.get_selection().set_mode(
                Gtk.SelectionMode.SINGLE)

        self.ipsetConfRemoveIPSetButton.set_sensitive(not builtin and default)
        self.ipsetConfLoadDefaultsIPSetButton.set_sensitive(not default)

        self.ipsetConfRemoveEntryMenubutton.set_sensitive(
            len(self.ipsetConfEntryStore) > 0)

    def get_active_helper(self):
        selection = self.helperConfHelperView.get_selection()
        (model, iter) = selection.get_selected()
        if iter:
            return self.helperConfHelperStore.get_value(iter, 0)
        return None

    def load_helpers(self):
        if not self.show_helpers:
            return
        active_helper = self.get_active_helper()

        if self.runtime_view:
            helpers = self.fw.getHelpers()
        else:
            helpers = self.fw.config().getHelperNames()

        selection = self.helperConfHelperView.get_selection()
        selection.set_mode(Gtk.SelectionMode.NONE)

        # reset and fill notebook content according to view

        self.helperConfHelperStore.clear()

        # helpers

        for helper in helpers:
            self.helperConfHelperStore.append([helper])

        selection.set_mode(Gtk.SelectionMode.SINGLE)

        iter = self.helperConfHelperStore.get_iter_first()
        while iter:
            if self.helperConfHelperStore.get_value(iter, 0) == \
                    active_helper:
                selection.select_iter(iter)
                return
            iter = self.helperConfHelperStore.iter_next(iter)
        selection.select_path(0)

        if not self.get_active_helper():
            self.helperConfEditHelperButton.set_sensitive(False)
            self.helperConfRemoveHelperButton.set_sensitive(False)
            self.helperConfLoadDefaultsHelperButton.set_sensitive(False)
            self.helperConfHelperNotebook.set_sensitive(False)

    def onHelperConfAddHelper(self, *args):
        self.add_edit_helper(True)

    def onHelperConfRemoveHelper(self, *args):
        active_helper = self.get_active_helper()
        helper = self.fw.config().getHelperByName(active_helper)
        helper.remove()
        self.changes_applied()
        self.load_helpers()
        self.onChangeHelper()

    def onHelperConfEditHelper(self, *args):
        self.add_edit_helper(False)

    def onHelperConfLoadDefaultsHelper(self, *args):
        active_helper = self.get_active_helper()
        helper = self.fw.config().getHelperByName(active_helper)
        helper.loadDefaults()
        self.changes_applied()
        self.onChangeHelper()

    def onHelperBaseDialogModuleChooserClicked(self, *args):
        old_module = self.helperBaseDialogModuleChooser.get_text()

        module = self.module_select_dialog(old_module)
        if module is not None:
            self.helperBaseDialogModuleChooser.set_text(module)

    def onHelperBaseDialogChanged(self, *args):
        def check_helper_name(helper):
            return (len(helper) <= HELPER_MAXNAMELEN, helper)

        OK=True
        if args and (args[0] == self.helperBaseDialogNameEntry):
            additional_chars = "".join(Helper.ADDITIONAL_ALNUM_CHARS)
            allowed_chars = string.ascii_letters+string.digits+additional_chars
            OK = self.entry_changed(args[0], allowed_chars, check_helper_name)
        module = self.helperBaseDialogModuleChooser.get_text()
        if module is None or not module.startswith("nf_conntrack_") or \
           len(module.replace("nf_conntrack_", "")) < 1:
            OK = False
        self.helperBaseDialogOkButton.set_sensitive(OK)

    def add_edit_helper(self, add):
        if add:
            default = True
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None
            old_module = None
            old_family = None

            self.helperBaseDialogNameEntry.set_text("")
            self.helperBaseDialogVersionEntry.set_text("")
            self.helperBaseDialogShortEntry.set_text("")
            self.helperBaseDialogDescText.get_buffer().set_text("")
            self.helperBaseDialogModuleChooser.set_text("")
            self.helperBaseDialogFamilyCombobox.set_active(0)

        else:
            active_helper = self.get_active_helper()
            helper = self.fw.config().getHelperByName(active_helper)
            settings = helper.getSettings()
            props = helper.get_properties()
            default = props["default"]
            builtin = props["builtin"]

            old_name = helper.get_property("name")
            old_version = settings.getVersion()
            old_short = settings.getShort()
            old_desc = settings.getDescription()
            old_module = settings.getModule()
            old_family = settings.getFamily()

            self.helperBaseDialogNameEntry.set_text(old_name)
            self.helperBaseDialogVersionEntry.set_text(old_version)
            self.helperBaseDialogShortEntry.set_text(old_short)
            self.helperBaseDialogDescText.get_buffer().set_text(old_desc)
            self.helperBaseDialogModuleChooser.set_text(old_module)
            self.helperBaseDialogFamilyCombobox.set_active(0)
            combobox_select_text(self.helperBaseDialogFamilyCombobox,
                                 { "": _("All") , "ipv4": _("IPv4"),
                                   "ipv6" : _("IPv6") }[old_family])

        self.helperBaseDialogOkButton.set_sensitive(False)
        if builtin:
            self.helperBaseDialogNameEntry.set_tooltip_markup(\
                _("Built-in helper, rename not supported."))
        else:
            self.helperBaseDialogNameEntry.set_tooltip_markup("")
        self.helperBaseDialogNameEntry.set_sensitive(not builtin and default)

        self.helperBaseDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.helperBaseDialog.set_transient_for(self.mainWindow)
        self.helperBaseDialog.show_all()
        self.add_visible_dialog(self.helperBaseDialog)
        result = self.helperBaseDialog.run()
        self.helperBaseDialog.hide()
        self.remove_visible_dialog(self.helperBaseDialog)

        if result != 1:
            return

        name = self.helperBaseDialogNameEntry.get_text()
        version = self.helperBaseDialogVersionEntry.get_text()
        short = self.helperBaseDialogShortEntry.get_text()
        buffer = self.helperBaseDialogDescText.get_buffer()
        desc = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(),
                               False)
        module = self.helperBaseDialogModuleChooser.get_text()
        family = { _("All") : "", _("IPv4") : "ipv4", _("IPv6") : "ipv6" } \
                 [self.helperBaseDialogFamilyCombobox.get_active_text()]
        if old_name == name and \
                old_version == version and old_short == short and \
                old_desc == desc and old_module == module and \
                old_family == family:
            # no changes
            return

        if not add:
            active_helper = self.get_active_helper()
            helper = self.fw.config().getHelperByName(active_helper)
            settings = helper.getSettings()
        else:
            settings = client.FirewallClientHelperSettings()

        if old_version != version or old_short != short or \
           old_desc != desc or old_family != family:
            # settings
            settings.setVersion(version)
            settings.setShort(short)
            settings.setDescription(desc)
            settings.setModule(module)
            settings.setFamily(family)
            if not add:
                helper.update(settings)

        if not add:
            if old_name == name:
                return
            helper.rename(name)
        else:
            self.fw.config().addHelper(name, settings)
        self.changes_applied()

    def onHelperChanged(self, *args):
        self.helperBaseDialogOkButton.set_sensitive(True)

    def onHelperConfAddPort(self, *args):
        self.add_edit_helper_port(True)

    def onHelperConfEditPort(self, *args):
        self.add_edit_helper_port(False)

    def onHelperConfPortClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS and \
           not self.runtime_view:
            self.add_edit_helper_port(False)

    def onHelperConfRemovePort(self, *args):
        active_helper = self.get_active_helper()
        selection = self.helperConfPortView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        port = self.helperConfPortStore.get_value(iter, 0)
        proto = self.helperConfPortStore.get_value(iter, 1)

        if self.runtime_view:
            if self.fw.queryPort(active_helper, port, proto):
                self.fw.removePort(active_helper, port, proto)
                self.changes_applied()
        else:
            helper = self.fw.config().getHelperByName(active_helper)
            helper.removePort(port, proto)
            self.changes_applied()

    def change_helper_conf_port_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.helperConfEditPortButton.set_sensitive(True)
            self.helperConfRemovePortButton.set_sensitive(True)
        else:
            self.helperConfEditPortButton.set_sensitive(False)
            self.helperConfRemovePortButton.set_sensitive(False)

    def add_edit_helper_port(self, add):
        active_helper = self.get_active_helper()

        self.portDialogPortEntry.set_text("")
        self.portDialogProtoCombobox.set_active(0)

        old_port = None
        old_proto = None

        if not add:
            selection = self.helperConfPortView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_port = self.helperConfPortStore.get_value(iter, 0)
            old_proto = self.helperConfPortStore.get_value(iter, 1)

        if old_port:
            self.portDialogPortEntry.set_text(old_port)
        if old_proto:
            combobox_select_text(self.portDialogProtoCombobox, old_proto)

        self.portDialogOkButton.set_sensitive(False)

        self.portDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.portDialog.set_transient_for(self.mainWindow)
        self.portDialog.show_all()
        self.add_visible_dialog(self.portDialog)
        result = self.portDialog.run()
        self.portDialog.hide()
        self.remove_visible_dialog(self.portDialog)

        if result != 1:
            return

        port = self.portDialogPortEntry.get_text()
        proto = self.portDialogProtoCombobox.get_active_text()

        if old_port == port and old_proto == proto:
            # nothing to change
            return

        helper = self.fw.config().getHelperByName(active_helper)
        if not helper.queryPort(port, proto):
            if not add:
                helper.removePort(old_port, old_proto)
            helper.addPort(port, proto)
            self.changes_applied()

    def helper_port_added_cb(self, helper, entry):
        if not self.runtime_view or helper != self.get_active_helper():
            return
        iter = self.helperConfPortStore.get_iter_first()
        while iter:
            if self.helperConfPortStore.get_value(iter, 0) == entry:
                # already there
                return
            iter = self.helperConfPortStore.iter_next(iter)
        # nothing found, so add it
        self.helperConfPortStore.append([entry])

    def helper_port_removed_cb(self, helper, entry):
        if not self.runtime_view or helper != self.get_active_helper():
            return
        iter = self.helperConfPortStore.get_iter_first()
        while iter:
            if self.helperConfPortStore.get_value(iter, 0) == entry:
                self.helperConfPortStore.remove(iter)
                break
            iter = self.helperConfPortStore.iter_next(iter)

    def conf_helper_added_cb(self, helper):
        if self.runtime_view:
            return
        # check if helper is in store
        iter = self.helperConfHelperStore.get_iter_first()
        while iter:
            if self.helperConfHelperStore.get_value(iter, 0) == helper:
                return
            iter = self.helperConfHelperStore.iter_next(iter)
        # not in list, append
        self.helperConfHelperStore.append([helper])
        selection = self.helperConfHelperView.get_selection()
        if selection.count_selected_rows() == 0:
            selection.select_path(0)

    def conf_helper_updated_cb(self, helper):
        if self.runtime_view or helper != self.get_active_helper():
            return
        self.onChangeHelper()

    def conf_helper_removed_cb(self, helper):
        if self.runtime_view:
            return
        iter = self.helperConfHelperStore.get_iter_first()
        while iter:
            if self.helperConfHelperStore.get_value(iter, 0) == helper:
                self.helperConfHelperStore.remove(iter)
                break
            iter = self.helperConfHelperStore.iter_next(iter)

    def conf_helper_renamed_cb(self, helper):
        if self.runtime_view:
            return

        # Get all helpers, renamed the one that is missing.
        # If more or less than one is missing, update helper store.

        helpers = self.fw.config().getHelperNames()

        use_iter = None
        iter = self.helperConfHelperStore.get_iter_first()
        while iter:
            if self.helperConfHelperStore.get_value(iter, 0) not in helpers:
                if use_iter is not None:
                    return self.load_helpers()
                use_iter = iter
            iter = self.helperConfHelperStore.iter_next(iter)

        if use_iter is None:
            return self.load_helpers()

        self.helperConfHelperStore.set_value(use_iter, 0, helper)

    def onChangeHelper(self, *args):
        active_helper = self.get_active_helper()

        self.helperConfPortStore.clear()

        self.helperConfPortView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)

        if not active_helper:
            self.helperConfEditHelperButton.set_sensitive(False)
            self.helperConfRemoveHelperButton.set_sensitive(False)
            self.helperConfLoadDefaultsHelperButton.set_sensitive(False)
            self.helperConfHelperNotebook.set_sensitive(False)
            return

        self.helperConfEditHelperButton.set_sensitive(True)
        self.helperConfHelperNotebook.set_sensitive(True)

        ports = [ ]

        if self.runtime_view:
            # load runtime configuration

            settings = self.fw.getHelperSettings(active_helper)
            ports = settings.getPorts()
            default = False
            builtin = False
        else:
            try:
                helper = self.fw.config().getHelperByName(active_helper)
            except:
                return

            # load permanent configuration
            settings = helper.getSettings()
            ports = settings.getPorts()
            props = helper.get_properties()
            default = props["default"]
            builtin = props["builtin"]

        # set entries
        for item in ports:
            self.helperConfPortStore.append(item)

        self.helperConfPortView.get_selection().set_mode(
            Gtk.SelectionMode.SINGLE)

        self.helperConfRemoveHelperButton.set_sensitive(not builtin and default)
        self.helperConfLoadDefaultsHelperButton.set_sensitive(not default)

    def onModuleChanged(self, *args):
        if self.moduleDialogOtherModuleCheck.get_active():
            self.moduleDialogModuleLabel.set_sensitive(False)
            self.moduleDialogModuleCombobox.set_sensitive(False)
            self.moduleDialogOtherModuleEntry.set_sensitive(True)
            module = self.moduleDialogOtherModuleEntry.get_text()
        else:
            self.moduleDialogModuleLabel.set_sensitive(True)
            self.moduleDialogModuleCombobox.set_sensitive(True)
            self.moduleDialogOtherModuleEntry.set_sensitive(False)
            module = self.moduleDialogModuleCombobox.get_active_text()
        if module is not None and module.startswith("nf_conntrack_") and \
           len(module.replace("nf_conntrack_", "")) > 1:
            self.moduleDialogOkButton.set_sensitive(True)
        else:
            self.moduleDialogOkButton.set_sensitive(False)

    def module_select_dialog(self, old_module):
        self.moduleDialogModuleCombobox.set_active(0)
        self.moduleDialogOtherModuleCheck.set_active(False)
        self.moduleDialogOtherModuleEntry.set_text("")

        if old_module:
            if not combobox_select_text(self.moduleDialogModuleCombobox,
                                        old_module):
                self.moduleDialogOtherModuleCheck.set_active(True)
                self.moduleDialogOtherModuleEntry.set_text(old_module)

        self.moduleDialogOkButton.set_sensitive(False)

        self.moduleDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.moduleDialog.set_transient_for(self.mainWindow)
        self.moduleDialog.show_all()
        self.add_visible_dialog(self.moduleDialog)
        result = self.moduleDialog.run()
        self.moduleDialog.hide()
        self.remove_visible_dialog(self.moduleDialog)

        if result != 1:
            return None

        if self.moduleDialogOtherModuleCheck.get_active():
            module = self.moduleDialogOtherModuleEntry.get_text()
        else:
            module = self.moduleDialogModuleCombobox.get_active_text()

        if old_module == module:
            # nothing to change
            return None

        return module

    def get_active_icmp(self):
        selection = self.icmpDialogIcmpView.get_selection()
        (model, iter) = selection.get_selected()
        if iter:
            return self.icmpDialogIcmpStore.get_value(iter, 0)
        return None

    def load_icmps(self):
        if not self.show_icmp_types:
            return
        active_icmp = self.get_active_icmp()

        if self.runtime_view:
            icmps = self.fw.listIcmpTypes()
        else:
            icmps = self.fw.config().getIcmpTypeNames()

        selection = self.icmpDialogIcmpView.get_selection()
        selection.set_mode(Gtk.SelectionMode.NONE)

        # reset and fill notebook content according to view

        self.icmpDialogIcmpStore.clear()

        # icmps

        for icmp in icmps:
            self.icmpDialogIcmpStore.append([icmp])

        selection.set_mode(Gtk.SelectionMode.SINGLE)

        iter = self.icmpDialogIcmpStore.get_iter_first()
        while iter:
            if self.icmpDialogIcmpStore.get_value(iter, 0) == \
                    active_icmp:
                selection.select_iter(iter)
                return
            iter = self.icmpDialogIcmpStore.iter_next(iter)
        selection.select_path(0)

        if not self.get_active_icmp():
            self.icmpDialogEditIcmpButton.set_sensitive(False)
            self.icmpDialogRemoveIcmpButton.set_sensitive(False)
            self.icmpDialogLoadDefaultsIcmpButton.set_sensitive(False)
            self.icmpDialogIcmpNotebook.set_sensitive(False)

    def onChangeIcmp(self, *args):
        active_icmp = self.get_active_icmp()

        ### load service settings

        self.icmpDialogDestIpv4Check.set_active(True)
        self.icmpDialogDestIpv6Check.set_active(True)

        if not active_icmp:
            self.icmpDialogEditIcmpButton.set_sensitive(False)
            self.icmpDialogRemoveIcmpButton.set_sensitive(False)
            self.icmpDialogLoadDefaultsIcmpButton.set_sensitive(False)
            self.icmpDialogIcmpNotebook.set_sensitive(False)
            return

        self.icmpDialogEditIcmpButton.set_sensitive(True)
        self.icmpDialogIcmpNotebook.set_sensitive(True)

        destination = [ ]

        if self.runtime_view:
            # load runtime configuration

            settings = self.fw.getIcmpTypeSettings(active_icmp)
            destination = settings.getDestinations()
            default = False
            builtin = False
        else:
            try:
                icmp = self.fw.config().getIcmpTypeByName(active_icmp)
            except:
                return

            # load permanent configuration
            settings = icmp.getSettings()
            destination = settings.getDestinations()
            props = icmp.get_properties()
            default = props["default"]
            builtin = props["builtin"]

        self.icmpDialogRemoveIcmpButton.set_sensitive(not builtin and default)
        self.icmpDialogLoadDefaultsIcmpButton.set_sensitive(not default)

        ipv4 = "ipv4" in destination
        ipv6 = "ipv6" in destination
        # set destination
        if ipv4 != ipv6:
            if not ipv4:
                self.icmpDialogDestIpv4Check.set_active(False)
            if not ipv6:
                self.icmpDialogDestIpv6Check.set_active(False)

    def onIcmpDialogAddIcmp(self, *args):
        self.add_edit_icmp(True)

    def onIcmpDialogRemoveIcmp(self, *args):
        active_icmp = self.get_active_icmp()
        icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        icmp.remove()
        self.load_icmps()
        self.onChangeIcmp()

    def onIcmpDialogEditIcmp(self, *args):
        self.add_edit_icmp(False)

    def onIcmpBaseDialogChanged(self, *args):
        if args and (args[0] == self.icmpBaseDialogNameEntry):
            additional_chars = "".join(IcmpType.ADDITIONAL_ALNUM_CHARS)
            allowed_chars = string.ascii_letters+string.digits+additional_chars
            self.entry_changed(args[0], allowed_chars)

        self.icmpBaseDialogOkButton.set_sensitive(True)

    def add_edit_icmp(self, add):
        if add:
            default = True
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None

            self.icmpBaseDialogNameEntry.set_text("")
            self.icmpBaseDialogVersionEntry.set_text("")
            self.icmpBaseDialogShortEntry.set_text("")
            self.icmpBaseDialogDescText.get_buffer().set_text("")
        else:
            active_icmp = self.get_active_icmp()
            icmp = self.fw.config().getIcmpTypeByName(active_icmp)
            settings = icmp.getSettings()
            props = icmp.get_properties()
            default = props["default"]
            builtin = props["builtin"]

            old_name = icmp.get_property("name")
            old_version = settings.getVersion()
            old_short = settings.getShort()
            old_desc = settings.getDescription()

            self.icmpBaseDialogNameEntry.set_text(old_name)
            self.icmpBaseDialogVersionEntry.set_text(old_version)
            self.icmpBaseDialogShortEntry.set_text(old_short)
            self.icmpBaseDialogDescText.get_buffer().set_text(old_desc)

        self.icmpBaseDialogOkButton.set_sensitive(False)
        if builtin:
            self.icmpBaseDialogNameEntry.set_tooltip_markup(\
                _("Built-in icmp, rename not supported."))
        else:
            self.icmpBaseDialogNameEntry.set_tooltip_markup("")
        self.icmpBaseDialogNameEntry.set_sensitive(not builtin and default)

        self.icmpBaseDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.icmpBaseDialog.set_transient_for(self.mainWindow)
        self.icmpBaseDialog.show_all()
        self.add_visible_dialog(self.icmpBaseDialog)
        result = self.icmpBaseDialog.run()
        self.icmpBaseDialog.hide()
        self.remove_visible_dialog(self.icmpBaseDialog)

        if result != 1:
            return

        name = self.icmpBaseDialogNameEntry.get_text()
        version = self.icmpBaseDialogVersionEntry.get_text()
        short = self.icmpBaseDialogShortEntry.get_text()
        buffer = self.icmpBaseDialogDescText.get_buffer()
        desc = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(),
                               False)

        if old_name == name and \
                old_version == version and old_short == short and \
                old_desc == desc:
            # no changes
            return

        if not add:
            active_icmp = self.get_active_icmp()
            icmp = self.fw.config().getIcmpTypeByName(active_icmp)
            settings = icmp.getSettings()
        else:
            settings = client.FirewallClientIcmpTypeSettings()

        if old_version != version or old_short != short or \
                old_desc != desc:
            # settings
            settings.setVersion(version)
            settings.setShort(short)
            settings.setDescription(desc)
            if not add:
                icmp.update(settings)

        if not add:
            if old_name == name:
                return
            icmp.rename(name)
        else:
            self.fw.config().addIcmpType(name, settings)
        self.changes_applied()

    def onIcmpDialogLoadDefaultsIcmp(self, *args):
        active_icmp = self.get_active_icmp()
        icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        icmp.loadDefaults()
        self.changes_applied()
        self.onChangeIcmp()

    def icmp_dialog_dest_ipv4_check_cb(self, *args):
        active_icmp = self.get_active_icmp()
        icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        if self.icmpDialogDestIpv4Check.get_active():
            if icmp.queryDestination("ipv4"):
                icmp.removeDestination("ipv4")
                self.changes_applied()
        elif not icmp.queryDestination("ipv4"):
            icmp.addDestination("ipv4")
            self.changes_applied()

    def icmp_dialog_dest_ipv6_check_cb(self, *args):
        active_icmp = self.get_active_icmp()
        icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        if self.icmpDialogDestIpv6Check.get_active():
            if icmp.queryDestination("ipv6"):
                icmp.removeDestination("ipv6")
                self.changes_applied()
        elif not icmp.queryDestination("ipv6"):
            icmp.addDestination("ipv6")
            self.changes_applied()

    def conf_icmp_added_cb(self, icmp):
        if self.runtime_view:
            return
        if not self.show_icmp_types:
            return
        # check if icmp is in store
        iter = self.icmpDialogIcmpStore.get_iter_first()
        while iter:
            if self.icmpDialogIcmpStore.get_value(iter, 0) == icmp:
                return
            iter = self.icmpDialogIcmpStore.iter_next(iter)
        # not in list, append
        self.icmpDialogIcmpStore.append([icmp])
        selection = self.icmpDialogIcmpView.get_selection()
        if selection.count_selected_rows() == 0:
            selection.select_path(0)

    def conf_icmp_updated_cb(self, zone):
        if self.runtime_view:
            return
        if not self.show_icmp_types:
            return
        self.onChangeIcmp()

    def conf_icmp_removed_cb(self, icmp):
        if self.runtime_view:
            return
        if not self.show_icmp_types:
            return
        iter = self.icmpDialogIcmpStore.get_iter_first()
        while iter:
            if self.icmpDialogIcmpStore.get_value(iter, 0) == icmp:
                self.icmpDialogIcmpStore.remove(iter)
                break
            iter = self.icmpDialogIcmpStore.iter_next(iter)

    def conf_icmp_renamed_cb(self, icmp):
        if self.runtime_view:
            return

        # Get all icmps, renamed the one that is missing.
        # If more or less than one is missing, update icmp store.

        icmps = self.fw.config().getIcmpTypeNames()

        use_iter = None
        iter = self.icmpDialogIcmpStore.get_iter_first()
        while iter:
            if self.icmpDialogIcmpStore.get_value(iter, 0) not in icmps:
                if use_iter is not None:
                    return self.load_icmps()
                use_iter = iter
            iter = self.icmpDialogIcmpStore.iter_next(iter)

        if use_iter is None:
            return self.load_icmps()

        self.icmpDialogIcmpStore.set_value(use_iter, 0, icmp)

    def lockdown_check_cb(self, *args):
        if self.fw.queryLockdown():
            self.fw.config().set_property("Lockdown", "no")    # permanent
            self.fw.disableLockdown()                          # runtime
        else:
            self.fw.config().set_property("Lockdown", "yes")   # permanent
            self.fw.enableLockdown()                           # runtime
        self.changes_applied()

    def panic_check_cb(self, *args):
        if self.fw.queryPanicMode():
            self.fw.disablePanicMode()
        else:
            self.fw.enablePanicMode()
        self.changes_applied()

    def load_direct(self):
        if not self.show_direct:
            return
        if self.runtime_view:
            chains = self.fw.getAllChains()
            rules = self.fw.getAllRules()
            passthroughs = self.fw.getAllPassthroughs()
        else:
            direct = self.fw.config().direct()
            settings = direct.getSettings()

            chains = settings.getAllChains()
            rules = settings.getAllRules()
            passthroughs = settings.getAllPassthroughs()

        self.directChainStore.clear()
        self.directRuleStore.clear()
        self.directPassthroughStore.clear()

        for x in chains:
            self.directChainStore.append(x)
        for (ipv, table, chain, priority, args) in rules:
            self.directRuleStore.append((ipv, table, chain, priority,
                                         functions.joinArgs(args)))
        for (ipv, args) in passthroughs:
            self.directPassthroughStore.append((ipv, functions.joinArgs(args)))

    def load_lockdown_whitelist(self):
        if not self.show_lockdown_whitelist:
            return
        if self.runtime_view:
            contexts = self.fw.getLockdownWhitelistContexts()
            commands = self.fw.getLockdownWhitelistCommands()
            users = self.fw.getLockdownWhitelistUsers()
            uids = self.fw.getLockdownWhitelistUids()
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            contexts = whitelist.getContexts()
            commands = whitelist.getCommands()
            users = whitelist.getUsers()
            uids = whitelist.getUids()

        self.lockdownContextStore.clear()
        self.lockdownCommandStore.clear()
        self.lockdownUserStore.clear()
        self.lockdownUidStore.clear()

        for context in contexts:
            self.lockdownContextStore.append([context])
        self.lockdownContextView.get_selection().select_path(0)
        for command in commands:
            self.lockdownCommandStore.append([command])
        self.lockdownCommandView.get_selection().select_path(0)
        for user in users:
            self.lockdownUserStore.append([user])
        self.lockdownUserView.get_selection().select_path(0)
        for uid in uids:
            self.lockdownUidStore.append([uid])
        self.lockdownUidView.get_selection().select_path(0)

    def lockdown_enabled_cb(self):
        self.lockdownLabel.set_text(self.enabled)
        self.lockdownMenuitem.handler_block(self.lockdown_check_id)
        self.lockdownMenuitem.set_active(True)
        self.lockdownMenuitem.handler_unblock(self.lockdown_check_id)

    def lockdown_disabled_cb(self):
        self.lockdownLabel.set_text(self.disabled)
        self.lockdownMenuitem.handler_block(self.lockdown_check_id)
        self.lockdownMenuitem.set_active(False)
        self.lockdownMenuitem.handler_unblock(self.lockdown_check_id)

    def change_lockdown_context_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editLockdownContextButton.set_sensitive(True)
            self.removeLockdownContextButton.set_sensitive(True)
        else:
            self.editLockdownContextButton.set_sensitive(False)
            self.removeLockdownContextButton.set_sensitive(False)

    def change_lockdown_command_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editLockdownCommandButton.set_sensitive(True)
            self.removeLockdownCommandButton.set_sensitive(True)
        else:
            self.editLockdownCommandButton.set_sensitive(False)
            self.removeLockdownCommandButton.set_sensitive(False)

    def change_lockdown_user_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editLockdownUserButton.set_sensitive(True)
            self.removeLockdownUserButton.set_sensitive(True)
        else:
            self.editLockdownUserButton.set_sensitive(False)
            self.removeLockdownUserButton.set_sensitive(False)

    def change_lockdown_uid_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editLockdownUidButton.set_sensitive(True)
            self.removeLockdownUidButton.set_sensitive(True)
        else:
            self.editLockdownUidButton.set_sensitive(False)
            self.removeLockdownUidButton.set_sensitive(False)

    def onAddContext(self, button):
        self.add_edit_context(True)

    def onEditContext(self, button):
        self.add_edit_context(False)

    def onContextClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_context(False)

    def onRemoveContext(self, button):
        selection = self.lockdownContextView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        context = self.lockdownContextStore.get_value(iter, 0)

        if self.runtime_view:
            self.fw.removeLockdownWhitelistContext(context)
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            whitelist.removeContext(context)
            self.fw.config().policies().setLockdownWhitelist(whitelist)
        self.changes_applied()

    def lockdown_whitelist_context_added_cb(self, context):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownContextStore.get_iter_first()
        while iter:
            if self.lockdownContextStore.get_value(iter, 0) == context:
                return
            iter = self.lockdownContextStore.iter_next(iter)
        self.lockdownContextStore.append([context])

    def lockdown_whitelist_context_removed_cb(self, context):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownContextStore.get_iter_first()
        while iter:
            if self.lockdownContextStore.get_value(iter, 0) == context:
                self.lockdownContextStore.remove(iter)
                break
            iter = self.lockdownContextStore.iter_next(iter)

    def add_edit_context(self, add):
        if add:
            old_context = ""
        else:
            selection = self.lockdownContextView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_context = self.lockdownContextStore.get_value(iter, 0)

        self.contextDialogContextEntry.set_text(old_context)
        self.contextDialogOkButton.set_sensitive(False)

        self.contextDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.contextDialog.set_transient_for(self.mainWindow)
        self.contextDialog.show_all()
        self.add_visible_dialog(self.contextDialog)
        result = self.contextDialog.run()
        self.contextDialog.hide()
        self.remove_visible_dialog(self.contextDialog)

        if result != 1:
            return

        context = self.contextDialogContextEntry.get_text()
        if old_context == context:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryLockdownWhitelistContext(context):
                self.fw.addLockdownWhitelistContext(context)
                if not add:
                    self.fw.removeLockdownWhitelistContext(old_context)
                self.changes_applied()
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            if not whitelist.queryContext(context):
                if not add:
                    whitelist.removeContext(old_context)
                whitelist.addContext(context)
                self.fw.config().policies().setLockdownWhitelist(whitelist)
                self.changes_applied()

    def onContextChanged(self, *args):
        text = self.contextDialogContextEntry.get_text()
        if text != "" and functions.checkContext(text):
            self.contextDialogOkButton.set_sensitive(True)
        else:
            self.contextDialogOkButton.set_sensitive(False)


    def onAddCommand(self, button):
        self.add_edit_command(True)

    def onEditCommand(self, button):
        self.add_edit_command(False)

    def onCommandClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_command(False)

    def onRemoveCommand(self, button):
        selection = self.lockdownCommandView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        command = self.lockdownCommandStore.get_value(iter, 0)

        if self.runtime_view:
            self.fw.removeLockdownWhitelistCommand(command)
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            whitelist.removeCommand(command)
            self.fw.config().policies().setLockdownWhitelist(whitelist)
        self.changes_applied()

    def lockdown_whitelist_command_added_cb(self, command):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownCommandStore.get_iter_first()
        while iter:
            if self.lockdownCommandStore.get_value(iter, 0) == command:
                return
            iter = self.lockdownCommandStore.iter_next(iter)
        self.lockdownCommandStore.append([command])

    def lockdown_whitelist_command_removed_cb(self, command):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownCommandStore.get_iter_first()
        while iter:
            if self.lockdownCommandStore.get_value(iter, 0) == command:
                self.lockdownCommandStore.remove(iter)
                break
            iter = self.lockdownCommandStore.iter_next(iter)

    def add_edit_command(self, add):
        if add:
            old_command = ""
        else:
            selection = self.lockdownCommandView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_command = self.lockdownCommandStore.get_value(iter, 0)

        self.commandDialogCommandEntry.set_text(old_command)
        self.commandDialogOkButton.set_sensitive(False)

        self.commandDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.commandDialog.set_transient_for(self.mainWindow)
        self.commandDialog.show_all()
        self.add_visible_dialog(self.commandDialog)
        result = self.commandDialog.run()
        self.commandDialog.hide()
        self.remove_visible_dialog(self.commandDialog)

        if result != 1:
            return

        command = self.commandDialogCommandEntry.get_text()
        if old_command == command:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryLockdownWhitelistCommand(command):
                self.fw.addLockdownWhitelistCommand(command)
                if not add:
                    self.fw.removeLockdownWhitelistCommand(old_command)
                self.changes_applied()
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            if not whitelist.queryCommand(command):
                if not add:
                    whitelist.removeCommand(old_command)
                whitelist.addCommand(command)
                self.fw.config().policies().setLockdownWhitelist(whitelist)
                self.changes_applied()

    def onCommandChanged(self, *args):
        text = self.commandDialogCommandEntry.get_text()
        if functions.checkCommand(text):
            self.commandDialogOkButton.set_sensitive(True)
        else:
            self.commandDialogOkButton.set_sensitive(False)

    def onAddUser(self, button):
        self.add_edit_user(True)

    def onEditUser(self, button):
        self.add_edit_user(False)

    def onUserClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_user(False)

    def onRemoveUser(self, button):
        selection = self.lockdownUserView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        user = self.lockdownUserStore.get_value(iter, 0)

        if self.runtime_view:
            self.fw.removeLockdownWhitelistUser(user)
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            whitelist.removeUser(user)
            self.fw.config().policies().setLockdownWhitelist(whitelist)
        self.changes_applied()

    def lockdown_whitelist_user_added_cb(self, user):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownUserStore.get_iter_first()
        while iter:
            if self.lockdownUserStore.get_value(iter, 0) == user:
                return
            iter = self.lockdownUserStore.iter_next(iter)
        self.lockdownUserStore.append([user])

    def lockdown_whitelist_user_removed_cb(self, user):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownUserStore.get_iter_first()
        while iter:
            if self.lockdownUserStore.get_value(iter, 0) == user:
                self.lockdownUserStore.remove(iter)
                break
            iter = self.lockdownUserStore.iter_next(iter)

    def add_edit_user(self, add):
        if add:
            old_user = ""
        else:
            selection = self.lockdownUserView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_user = self.lockdownUserStore.get_value(iter, 0)

        self.userDialogUserEntry.set_text(old_user)
        self.userDialogOkButton.set_sensitive(False)

        self.userDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.userDialog.set_transient_for(self.mainWindow)
        self.userDialog.show_all()
        self.add_visible_dialog(self.userDialog)
        result = self.userDialog.run()
        self.userDialog.hide()
        self.remove_visible_dialog(self.userDialog)

        if result != 1:
            return

        user = self.userDialogUserEntry.get_text()
        if old_user == user:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryLockdownWhitelistUser(user):
                self.fw.addLockdownWhitelistUser(user)
                if not add:
                    self.fw.removeLockdownWhitelistUser(old_user)
                self.changes_applied()
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            if not whitelist.queryUser(user):
                if not add:
                    whitelist.removeUser(old_user)
                whitelist.addUser(user)
                self.fw.config().policies().setLockdownWhitelist(whitelist)
                self.changes_applied()

    def onUserChanged(self, *args):
        text = self.userDialogUserEntry.get_text()
        if text != "" and functions.checkUser(text):
            self.userDialogOkButton.set_sensitive(True)
        else:
            self.userDialogOkButton.set_sensitive(False)


    def onAddUid(self, button):
        self.add_edit_uid(True)

    def onEditUid(self, button):
        self.add_edit_uid(False)

    def onUidClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_uid(False)

    def onRemoveUid(self, button):
        selection = self.lockdownUidView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        uid = self.lockdownUidStore.get_value(iter, 0)

        if self.runtime_view:
            self.fw.removeLockdownWhitelistUid(uid)
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            whitelist.removeUid(uid)
            self.fw.config().policies().setLockdownWhitelist(whitelist)
        self.changes_applied()

    def lockdown_whitelist_uid_added_cb(self, uid):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownUidStore.get_iter_first()
        while iter:
            if self.lockdownUidStore.get_value(iter, 0) == uid:
                return
            iter = self.lockdownUidStore.iter_next(iter)
        self.lockdownUidStore.append([uid])

    def lockdown_whitelist_uid_removed_cb(self, uid):
        if not self.show_lockdown_whitelist:
            return
        iter = self.lockdownUidStore.get_iter_first()
        while iter:
            if self.lockdownUidStore.get_value(iter, 0) == uid:
                self.lockdownUidStore.remove(iter)
                break
            iter = self.lockdownUidStore.iter_next(iter)

    def add_edit_uid(self, add):
        if add:
            old_uid = ""
        else:
            selection = self.lockdownUidView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_uid = self.lockdownUidStore.get_value(iter, 0)

        self.uidDialogUidEntry.set_text("%s" % old_uid)
        self.uidDialogOkButton.set_sensitive(False)

        self.uidDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.uidDialog.set_transient_for(self.mainWindow)
        self.uidDialog.show_all()
        self.add_visible_dialog(self.uidDialog)
        result = self.uidDialog.run()
        self.uidDialog.hide()
        self.remove_visible_dialog(self.uidDialog)

        if result != 1:
            return

        uid = int(self.uidDialogUidEntry.get_text())
        if old_uid == uid:
            # nothing to change
            return

        if self.runtime_view:
            if not self.fw.queryLockdownWhitelistUid(uid):
                self.fw.addLockdownWhitelistUid(uid)
                if not add:
                    self.fw.removeLockdownWhitelistUid(old_uid)
                self.changes_applied()
        else:
            whitelist = self.fw.config().policies().getLockdownWhitelist()
            if not whitelist.queryUid(uid):
                if not add:
                    whitelist.removeUid(old_uid)
                whitelist.addUid(uid)
                self.fw.config().policies().setLockdownWhitelist(whitelist)
                self.changes_applied()

    def onUidChanged(self, *args):
        text = self.uidDialogUidEntry.get_text()
        if text != "" and functions.checkUid(text):
            self.uidDialogOkButton.set_sensitive(True)
        else:
            self.uidDialogOkButton.set_sensitive(False)

    def lockdown_whitelist_updated_cb(self):
        self.load_lockdown_whitelist()

    def change_chain_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editDirectChainButton.set_sensitive(True)
            self.removeDirectChainButton.set_sensitive(True)
        else:
            self.editDirectChainButton.set_sensitive(False)
            self.removeDirectChainButton.set_sensitive(False)

    def onAddChain(self, button):
        self.add_edit_direct_chain(True)

    def onEditChain(self, button):
        self.add_edit_direct_chain(False)

    def onChainClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_direct_chain(False)

    def onRemoveChain(self, button):
        selection = self.directChainView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        ipv = self.directChainStore.get_value(iter, 0)
        table = self.directChainStore.get_value(iter, 1)
        chain = self.directChainStore.get_value(iter, 2)

        if self.runtime_view:
            self.fw.removeChain(ipv, table, chain)
            self.changes_applied()
        else:
            direct = self.fw.config().direct()
            if direct.queryChain(ipv, table, chain):
                direct.removeChain(ipv, table, chain)
                self.changes_applied()

    def direct_updated_cb(self):
        if not self.show_direct:
            return
        if self.runtime_view:
            return
        self.load_direct()

    def direct_chain_added_cb(self, ipv, table, chain):
        if not self.show_direct:
            return
        if not self.runtime_view:
            return
        iter = self.directChainStore.get_iter_first()
        while iter:
            if self.directChainStore.get_value(iter, 0) == ipv and \
               self.directChainStore.get_value(iter, 1) == table and \
               self.directChainStore.get_value(iter, 2) == chain:
                return
            iter = self.directChainStore.iter_next(iter)
        self.directChainStore.append([ipv, table, chain])

    def direct_chain_removed_cb(self, ipv, table, chain):
        if not self.show_direct:
            return
        if not self.runtime_view:
            return
        iter = self.directChainStore.get_iter_first()
        while iter:
            if self.directChainStore.get_value(iter, 0) == ipv and \
               self.directChainStore.get_value(iter, 1) == table and \
               self.directChainStore.get_value(iter, 2) == chain:
                self.directChainStore.remove(iter)
                break
            iter = self.directChainStore.iter_next(iter)

    def add_edit_direct_chain(self, add):
        if add:
            old_ipv = ""
            old_table = ""
            old_chain = ""
        else:
            selection = self.directChainView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_ipv = self.directChainStore.get_value(iter, 0)
            old_table = self.directChainStore.get_value(iter, 1)
            old_chain = self.directChainStore.get_value(iter, 2)

        self.directChainDialogIPVCombobox.set_active(0)
        combobox_select_text(self.directChainDialogIPVCombobox, old_ipv)
        combobox_select_text(self.directChainDialogTableCombobox, old_table)
        self.directChainDialogChainEntry.set_text("%s" % old_chain)
        self.directChainDialogOkButton.set_sensitive(False)

        self.directChainDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.directChainDialog.set_transient_for(self.mainWindow)
        self.directChainDialog.show_all()
        self.add_visible_dialog(self.directChainDialog)
        result = self.directChainDialog.run()
        self.directChainDialog.hide()
        self.remove_visible_dialog(self.directChainDialog)

        if result != 1:
            return

        ipv = self.directChainDialogIPVCombobox.get_active_text()
        table = self.directChainDialogTableCombobox.get_active_text()
        chain = self.directChainDialogChainEntry.get_text()

        if self.runtime_view:
            if not self.fw.queryChain(ipv, table, chain):
                self.fw.addChain(ipv, table, chain)
                if not add:
                    self.fw.removeChain(old_ipv, old_table, old_chain)
                self.changes_applied()
        else:
            direct = self.fw.config().direct()
            if not direct.queryChain(ipv, table, chain):
                if not add:
                    direct.removeChain(old_ipv, old_table, old_chain)
                direct.addChain(ipv, table, chain)
                self.changes_applied()

    def onDirectChainDialogChanged(self, *args):
        self.directChainDialogOkButton.set_sensitive(True)

    def onDirectChainDialogIPVChanged(self, *args):
        old_table = self.directChainDialogTableCombobox.get_active_text()

        ipv = self.directChainDialogIPVCombobox.get_active_text()
        self.directChainDialogTableCombobox.remove_all()
        self.directChainDialogTableCombobox.append_text("filter")
        if ipv in [ "ipv4", "ipv6" ]:
            self.directChainDialogTableCombobox.append_text("nat")
            self.directChainDialogTableCombobox.append_text("mangle")
            self.directChainDialogTableCombobox.append_text("raw")
            self.directChainDialogTableCombobox.append_text("security")
        else:
            self.directChainDialogTableCombobox.append_text("broute")

        combobox_select_text(self.directChainDialogTableCombobox, old_table)

    def change_rule_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editDirectRuleButton.set_sensitive(True)
            self.removeDirectRuleButton.set_sensitive(True)
        else:
            self.editDirectRuleButton.set_sensitive(False)
            self.removeDirectRuleButton.set_sensitive(False)

    def onAddRule(self, button):
        self.add_edit_direct_rule(True)

    def onEditRule(self, button):
        self.add_edit_direct_rule(False)

    def onRuleClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_direct_rule(False)

    def onRemoveRule(self, button):
        selection = self.directRuleView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        ipv = self.directRuleStore.get_value(iter, 0)
        table = self.directRuleStore.get_value(iter, 1)
        chain = self.directRuleStore.get_value(iter, 2)
        priority = self.directRuleStore.get_value(iter, 3)
        args = self.directRuleStore.get_value(iter, 4)

        split_args = functions.splitArgs(args)

        if self.runtime_view:
            self.fw.removeRule(ipv, table, chain, priority, split_args)
            self.changes_applied()
        else:
            direct = self.fw.config().direct()
            if direct.queryRule(ipv, table, chain, priority, split_args):
                direct.removeRule(ipv, table, chain, priority, split_args)
                self.changes_applied()

    def direct_rule_added_cb(self, ipv, table, chain, priority, args):
        if not self.show_direct:
            return
        if not self.runtime_view:
            return
        joined_args = functions.joinArgs(args)
        iter = self.directRuleStore.get_iter_first()
        while iter:
            if self.directRuleStore.get_value(iter, 0) == ipv and \
               self.directRuleStore.get_value(iter, 1) == table and \
               self.directRuleStore.get_value(iter, 2) == chain and \
               self.directRuleStore.get_value(iter, 3) == priority and \
               self.directRuleStore.get_value(iter, 4) == joined_args:
                return
            iter = self.directRuleStore.iter_next(iter)
        self.directRuleStore.append([ipv, table, chain, priority, joined_args])

    def direct_rule_removed_cb(self, ipv, table, chain, priority, args):
        if not self.show_direct:
            return
        if not self.runtime_view:
            return
        joined_args = functions.joinArgs(args)
        iter = self.directRuleStore.get_iter_first()
        while iter:
            if self.directRuleStore.get_value(iter, 0) == ipv and \
               self.directRuleStore.get_value(iter, 1) == table and \
               self.directRuleStore.get_value(iter, 2) == chain and \
               self.directRuleStore.get_value(iter, 3) == priority and \
               self.directRuleStore.get_value(iter, 4) == joined_args:
                self.directRuleStore.remove(iter)
                break
            iter = self.directRuleStore.iter_next(iter)

    def add_edit_direct_rule(self, add):
        if add:
            old_ipv = ""
            old_table = ""
            old_chain = ""
            old_priority = 0
            old_args = ""
        else:
            selection = self.directRuleView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_ipv = self.directRuleStore.get_value(iter, 0)
            old_table = self.directRuleStore.get_value(iter, 1)
            old_chain = self.directRuleStore.get_value(iter, 2)
            old_priority = self.directRuleStore.get_value(iter, 3)
            old_args = self.directRuleStore.get_value(iter, 4)

        self.directRuleDialogIPVCombobox.set_active(0)
        combobox_select_text(self.directRuleDialogIPVCombobox, old_ipv)
        combobox_select_text(self.directRuleDialogTableCombobox, old_table)
        self.directRuleDialogChainEntry.set_text("%s" % old_chain)
        self.directRuleDialogPrioritySpinbutton.set_value(old_priority)
        self.directRuleDialogArgsEntry.set_text("%s" % old_args)
        self.directRuleDialogOkButton.set_sensitive(False)

        self.directRuleDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.directRuleDialog.set_transient_for(self.mainWindow)
        self.directRuleDialog.show_all()
        self.add_visible_dialog(self.directRuleDialog)
        result = self.directRuleDialog.run()
        self.directRuleDialog.hide()
        self.remove_visible_dialog(self.directRuleDialog)

        if result != 1:
            return

        ipv = self.directRuleDialogIPVCombobox.get_active_text()
        table = self.directRuleDialogTableCombobox.get_active_text()
        chain = self.directRuleDialogChainEntry.get_text()
        priority = self.directRuleDialogPrioritySpinbutton.get_value_as_int()
        args = self.directRuleDialogArgsEntry.get_text()

        split_args = functions.splitArgs(args)
        split_old_args = functions.splitArgs(old_args)

        if self.runtime_view:
            if not self.fw.queryRule(ipv, table, chain, priority, split_args):
                self.fw.addRule(ipv, table, chain, priority, split_args)
                if not add:
                    self.fw.removeRule(old_ipv, old_table, old_chain,
                                       old_priority, split_old_args)
                self.changes_applied()
        else:
            direct = self.fw.config().direct()
            if not direct.queryRule(ipv, table, chain, priority, split_args):
                if not add:
                    direct.removeRule(old_ipv, old_table, old_chain,
                                      old_priority, split_old_args)
                direct.addRule(ipv, table, chain, priority, split_args)
                self.changes_applied()

    def onDirectRuleDialogChanged(self, *args):
        self.directRuleDialogOkButton.set_sensitive(True)

    def onDirectRuleDialogIPVChanged(self, *args):
        old_table = self.directRuleDialogTableCombobox.get_active_text()

        ipv = self.directRuleDialogIPVCombobox.get_active_text()
        self.directRuleDialogTableCombobox.remove_all()
        self.directRuleDialogTableCombobox.append_text("filter")
        if ipv in [ "ipv4", "ipv6" ]:
            self.directRuleDialogTableCombobox.append_text("nat")
            self.directRuleDialogTableCombobox.append_text("mangle")
            self.directRuleDialogTableCombobox.append_text("raw")
            self.directRuleDialogTableCombobox.append_text("security")
        else:
            self.directRuleDialogTableCombobox.append_text("broute")

        combobox_select_text(self.directRuleDialogTableCombobox, old_table)

    def change_passthrough_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.editDirectPassthroughButton.set_sensitive(True)
            self.removeDirectPassthroughButton.set_sensitive(True)
        else:
            self.editDirectPassthroughButton.set_sensitive(False)
            self.removeDirectPassthroughButton.set_sensitive(False)

    def onAddPassthrough(self, button):
        self.add_edit_direct_passthrough(True)

    def onEditPassthrough(self, button):
        self.add_edit_direct_passthrough(False)

    def onPassthroughClicked(self, widget, event):
        if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
            self.add_edit_direct_passthrough(False)

    def onRemovePassthrough(self, button):
        selection = self.directPassthroughView.get_selection()
        (model, iter) = selection.get_selected()
        if iter is None:
            return
        ipv = self.directPassthroughStore.get_value(iter, 0)
        args = self.directPassthroughStore.get_value(iter, 1)

        split_args = functions.splitArgs(args)

        if self.runtime_view:
            self.fw.removePassthrough(ipv, split_args)
            self.changes_applied()
        else:
            direct = self.fw.config().direct()
            if direct.queryPassthrough(ipv, split_args):
                direct.removePassthrough(ipv, split_args)
                self.changes_applied()

    def direct_passthrough_added_cb(self, ipv, args):
        if not self.show_direct:
            return
        if not self.runtime_view:
            return
        joined_args = functions.joinArgs(args)
        iter = self.directPassthroughStore.get_iter_first()
        while iter:
            if self.directPassthroughStore.get_value(iter, 0) == ipv and \
               self.directPassthroughStore.get_value(iter, 1) == joined_args:
                return
            iter = self.directPassthroughStore.iter_next(iter)
        self.directPassthroughStore.append([ipv, joined_args])

    def direct_passthrough_removed_cb(self, ipv, args):
        if not self.show_direct:
            return
        if not self.runtime_view:
            return
        joined_args = functions.joinArgs(args)
        iter = self.directPassthroughStore.get_iter_first()
        while iter:
            if self.directPassthroughStore.get_value(iter, 0) == ipv and \
               self.directPassthroughStore.get_value(iter, 1) == joined_args:
                self.directPassthroughStore.remove(iter)
                break
            iter = self.directPassthroughStore.iter_next(iter)

    def add_edit_direct_passthrough(self, add):
        if add:
            old_ipv = ""
            old_args = ""
        else:
            selection = self.directPassthroughView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_ipv = self.directPassthroughStore.get_value(iter, 0)
            old_args = self.directPassthroughStore.get_value(iter, 1)

        self.directPassthroughDialogIPVCombobox.set_active(0)
        combobox_select_text(self.directPassthroughDialogIPVCombobox, old_ipv)
        self.directPassthroughDialogArgsEntry.set_text("%s" % old_args)
        self.directPassthroughDialogOkButton.set_sensitive(False)

        self.directPassthroughDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.directPassthroughDialog.set_transient_for(self.mainWindow)
        self.directPassthroughDialog.show_all()
        self.add_visible_dialog(self.directPassthroughDialog)
        result = self.directPassthroughDialog.run()
        self.directPassthroughDialog.hide()
        self.remove_visible_dialog(self.directPassthroughDialog)

        if result != 1:
            return

        ipv = self.directPassthroughDialogIPVCombobox.get_active_text()
        args = self.directPassthroughDialogArgsEntry.get_text()

        split_args = functions.splitArgs(args)
        split_old_args = functions.splitArgs(old_args)

        if self.runtime_view:
            if not self.fw.queryPassthrough(ipv, split_args):
                self.fw.addPassthrough(ipv, split_args)
                if not add:
                    self.fw.removePassthrough(old_ipv, split_old_args)
                self.changes_applied()
        else:
            direct = self.fw.config().direct()
            if not direct.queryPassthrough(ipv, split_args):
                if not add:
                    direct.removePassthrough(old_ipv, split_old_args)
                direct.addPassthrough(ipv, split_args)
                self.changes_applied()

    def onDirectPassthroughDialogChanged(self, *args):
        self.directPassthroughDialogOkButton.set_sensitive(True)

    def get_ipset_entries_from_file(self, filename):
        entries = [ ]
        try:
            f = open(filename)
        except Exception as ex:
            self._error(_("Failed to read file '%s': %s") % (filename, ex))
        else:
            for line in f:
                if not line:
                    break
                line = line.strip()
                if len(line) < 1 or line[0] in ['#', ';']:
                    continue
                if line not in entries:
                    entries.append(line)
            f.close()
        return entries


def combobox_select_text(combobox, value, insensitive=False):
    model = combobox.get_model()
    iter = model.get_iter_first()
    while iter:
        if (not insensitive and model.get_value(iter, 0) == value) or \
                (insensitive and \
                     model.get_value(iter, 0).lower() == value.lower()):
            combobox.set_active_iter(iter)
            return True
        iter = model.iter_next(iter)
    combobox.set_active(0)
    return False

class ZoneInterfaceEditor(Gtk.Dialog):
    def __init__(self, fw, interface, zone):
        self.fw = fw
        self.interface = interface
        self.zone = None
        self.title = _("Select zone for interface '%s'") % self.interface

        Gtk.Dialog.__init__(self, self.title)
        self.create_ui(zone)

    def create_ui(self, zone):
        self.set_property("width-request", 100)
        self.resize_to_geometry(100, 50)
        self.set_resizable(True)

        self.add_button("gtk-close", 1)
        self.ok_button = self.add_button("gtk-ok", 2)
        self.ok_button.set_sensitive(False)

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
        vbox.set_border_width(12)
        vbox.set_homogeneous(False)

        label = Gtk.Label()
        label.set_text(self.title)
        label.set_line_wrap(True)
        label.set_justify(Gtk.Justification.LEFT)
        label.set_alignment(0, 0.5)
        vbox.pack_start(label, True, True, 0)

        self.combo = Gtk.ComboBoxText()
        self.fill_zone_combo()
        vbox.pack_start(self.combo, True, True, 0)

        box = self.get_content_area()
        box.set_border_width(6)
        box.set_homogeneous(False)
        box.pack_start(vbox, False, True, 0)

        self.combo.connect("changed", self.combo_changed)
        self.set_zone(zone)

    def combo_changed(self, combo):
        self.ok_button.set_sensitive(self.get_zone() != self.zone)

    def set_zone(self, zone):
        old_zone = self.zone
        self.zone = zone
        if self.get_zone() == old_zone:
            if zone == "":
                combobox_select_text(self.combo, _("Default Zone"))
            else:
                combobox_select_text(self.combo, self.zone)
        else:
            self.combo_changed(None)

    def get_zone(self):
        text = self.combo.get_active_text()
        if text == _("Default Zone"):
            text = ""
        return text

    def fill_zone_combo(self):
        self.combo.remove_all()
        for zone in self.fw.getZones():
            self.combo.append_text(zone)

    def zones_changed(self):
        zone = self.get_zone()
        self.fill_zone_combo()
        self.set_zone(zone)

    def run(self):
        if Gtk.Dialog.run(self) != 2:
            return

        self.fw.changeZoneOfInterface(self.get_zone(), self.interface)

class ZoneConnectionEditor(ZoneInterfaceEditor):
    def __init__(self, fw, connection, connection_name, zone):
        self.fw = fw
        self.connection = connection
        self.connection_name = connection_name
        self.zone = None
        self.title = _("Select zone for connection '%s'") % self.connection_name

        Gtk.Dialog.__init__(self, self.title)
        self.create_ui(zone)

    def fill_zone_combo(self):
        self.combo.remove_all()
        self.combo.append_text(_("Default Zone"))
        for zone in self.fw.getZones():
            self.combo.append_text(zone)

    def run(self):
        if Gtk.Dialog.run(self) != 2:
            return

        nm_set_zone_of_connection(self.get_zone(), self.connection)

class ZoneSourceEditor(ZoneInterfaceEditor):
    def __init__(self, fw, source, zone):
        self.fw = fw
        self.source = source
        self.zone = None
        self.title = _("Select zone for source %s") % self.source

        Gtk.Dialog.__init__(self, self.title)
        self.create_ui(zone)

    def run(self):
        if Gtk.Dialog.run(self) != 2:
            return

        self.fw.changeZoneOfSource(self.get_zone(), self.source)

# MAIN

if len(sys.argv) > 1:
    print("""Usage: %s [options]

Options:
  -h, --help     show this help message and exit
"""  % sys.argv[0])
    sys.exit(1)

app = FirewallConfig()
sys.exit(0)