#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2011-2012 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

try:
    from gi.repository import Gtk, Gdk
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
sys.modules['gobject'] = GObject
import os
datadir = None
if os.getenv("FIREWALLD_DEVEL_ENV") != None:
    datadir = os.getenv("FIREWALLD_DEVEL_ENV")
    sys.path.insert(0, datadir)
import dbus

from firewall.config import *
from firewall.config.dbus import *
import firewall.client as client
from firewall.functions import *
from firewall.core.base import DEFAULT_ZONE_TARGET

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

NM_CONNECTION_EDITOR = "/usr/bin/nm-connection-editor"

#FIREWALL_CONFIG_SCHEMA = "org.fedoraproject.FirewallConfig"

# TODO:
#
# - add FirewallClient exception handling and error dialog for all uses
#

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

        self.connected = _("Connected.")
        self.no_connection = _("No connection.")
        self.waiting = _("Waiting ...")
        self.retrying = _("Retrying ...")

        # 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_NAME, size, 0)
            self.logo = self.icon_theme.load_icon(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.statusLabel = builder.get_object("statusLabel")
        self.modifiedLabel = builder.get_object("modifiedLabel")

        # make the toolbar the primary toolbar - odd that this is needed at all
        # glade-3 does not support this up to now.
        self.mainToolbar = builder.get_object("mainToolbar")
        sty = self.mainToolbar.get_style_context()
        sty.add_class("primary-toolbar")

        self.changeZonesConnectionMenuitem = \
            builder.get_object("changeZonesConnectionMenuitem")
        if os.path.isfile(NM_CONNECTION_EDITOR):
            self.changeZonesConnectionMenuitem.set_sensitive(True)
        else:
            self.changeZonesConnectionMenuitem.set_tooltip_markup(\
                _("%s is missing") % NM_CONNECTION_EDITOR)
            self.changeZonesConnectionMenuitem.set_sensitive(False)

        self.editServicesButton = \
            builder.get_object("editServicesButton")
        self.editServicesButton.hide()
        self.editIcmpTypesButton = \
            builder.get_object("editIcmpTypesButton")
        self.editIcmpTypesButton.hide()

        self.mainVBox = builder.get_object("mainVBox")
        self.optionMenuitem = builder.get_object("optionMenuitem")

        self.aboutDialog = builder.get_object("aboutDialog")
        self.aboutDialog.set_program_name(CONFIG_NAME)
        self.aboutDialog.set_version(VERSION)
        self.aboutDialog.set_authors(AUTHORS)
        self.aboutDialog.set_license(LICENSE)
        self.aboutDialog.set_wrap_license(True)
        self.aboutDialog.set_copyright(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(WEBSITE)

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

        self.zoneView = builder.get_object("zoneView")
        self.zoneStore = Gtk.ListStore(GObject.TYPE_STRING)
        self.zoneView.append_column(
            Gtk.TreeViewColumn("", Gtk.CellRendererText(), text=0))
        self.zoneView.set_model(self.zoneStore)
        self.zoneStore.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self.zoneView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.zoneView_selection_changed_handler_id = \
            self.zoneView.get_selection().connect("changed", self.onChangeZone)

        self.immutableNotebook = builder.get_object("immutableNotebook")
        self.mainNotebook = builder.get_object("mainNotebook")

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

        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.zoneBaseDialogImmutableCheck = \
            builder.get_object("zoneBaseDialogImmutableCheck")
        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.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")

        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.portProtoDialog = builder.get_object("portProtoDialog")
        self.portProtoDialogOkButton = \
            builder.get_object("portProtoDialogOkButton")
        self.portProtoDialogCancelButton = \
            builder.get_object("portProtoDialogCancelButton")
        self.portProtoDialogPortEntry = \
            builder.get_object("portProtoDialogPortEntry")
        self.portProtoDialogProtoCombobox = \
            builder.get_object("portProtoDialogProtoCombobox")
        self.portProtoDialogOtherProtoCheck = \
            builder.get_object("portProtoDialogOtherProtoCheck")
        self.portProtoDialogOtherProtoEntry = \
            builder.get_object("portProtoDialogOtherProtoEntry")

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

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

        self.serviceDialogServiceEditBox = \
            builder.get_object("serviceDialogServiceEditBox")
        self.serviceDialogEditServiceButton = \
            builder.get_object("serviceDialogEditServiceButton")
        self.serviceDialogRemoveServiceButton = \
            builder.get_object("serviceDialogRemoveServiceButton")
        self.serviceDialogLoadDefaultsServiceButton = \
            builder.get_object("serviceDialogLoadDefaultsServiceButton")

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

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

        self.serviceDialogEditPortButton = \
            builder.get_object("serviceDialogEditPortButton")
        self.serviceDialogRemovePortButton = \
            builder.get_object("serviceDialogRemovePortButton")

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

        self.serviceDialogEditModuleButton = \
            builder.get_object("serviceDialogEditModuleButton")
        self.serviceDialogRemoveModuleButton = \
            builder.get_object("serviceDialogRemoveModuleButton")

        self.serviceDialogDestIpv4Chooser = ChooserButton(
            builder.get_object("serviceDialogDestIpv4Chooser"), "")
        self.serviceDialogDestIpv6Chooser = ChooserButton(
            builder.get_object("serviceDialogDestIpv6Chooser"), "")

        self.moduleDialog = builder.get_object("moduleDialog")
        self.moduleDialogOkButton = \
            builder.get_object("moduleDialogOkButton")
        self.moduleDialogCancelButton = \
            builder.get_object("moduleDialogCancelButton")
        self.moduleDialogModuleEntry = \
            builder.get_object("moduleDialogModuleEntry")

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

        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.icmpDialog = builder.get_object("icmpDialog")

        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)

        # firewall client

        client.exception_handler = self._error
        self.fw = client.FirewallClient(wait=1)

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

        self.fw.connect("default-zone-changed", self.default_zone_changed_cb)
        self.fw.connect("reloaded", self.load)
        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("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("config:zone-updated", self.conf_zone_updated_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: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)

        # start with no connection

        self.connection_changed()

        # mainloop

        self.mainWindow.show()
        self.mainloop = GObject.MainLoop()
        try:
            self.mainloop.run()
        except KeyboardInterrupt as msg:
            self.onQuit()

    def _dialog(self, text, msg=None, title=None,
                message_type=Gtk.MessageType.INFO,
                buttons=("gtk-close", 1)):
        dialog = Gtk.MessageDialog(None, 0, 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(None, 0, 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=((_("Retry"), 0),("gtk-quit", 1))) == 1:
            self.onQuit()

    def connection_changed(self):
        if self.fw.connected:
            """
            # authorize
            while 1:
                try:
                    self.fw.config().listZones()
                except DBusException as e:
                    if "NotAuthorizedException" in str(e):
                        self._error(_("Authorization failed."))
                    else:
                        self._error(e)
                except Exception as e:
                    self._error(e)
                else:
                    # break the loop, continue with configuration
                    break
            """
            self.statusLabel.set_text(self.connected)
            self.modifiedLabel.set_text("")
            default_zone = self.fw.getDefaultZone()
            self.defaultZoneLabel.set_text(default_zone)
            self.currentViewCombobox.set_active(0)
        else:
            self.statusLabel.set_text(self.no_connection)
            self.modifiedLabel.set_text(self.waiting)

        self.mainToolbar.set_sensitive(self.fw.connected)
        self.mainVBox.set_sensitive(self.fw.connected)
        self.optionMenuitem.get_submenu().set_sensitive(self.fw.connected)

    def load(self):
        default_zone = self.fw.getDefaultZone()
        self.defaultZoneLabel.set_text(default_zone)
        self.load_zones()

    def load_zones(self):
        active_zone = self.get_active_zone()

        zones = [ ]
        if self.runtime_view:
            zones = sorted(self.fw.getZones())
        else:
            _zones = sorted(self.fw.config().listZones())
            for zone in _zones:
                z = self.fw.config().getZone(zone)
                zones.append(z.get_property("name"))

        # reset and fill notebook content according to view

        self.zoneView.get_selection().handler_block( \
            self.zoneView_selection_changed_handler_id)

        self.zoneStore.clear()
        self.serviceStore.clear()
        self.icmpStore.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:
            items = self.fw.config().listServices()
            for item in items:
                obj = self.fw.config().getService(item)
                self.serviceStore.append([False, obj.get_property("name")])
            items = self.fw.config().listIcmpTypes()
            for item in items:
                obj = self.fw.config().getIcmpType(item)
                self.icmpStore.append([False, obj.get_property("name")])

        # zones

        for zone in zones:
            self.zoneStore.append([zone])

        self.zoneView.get_selection().handler_unblock( \
            self.zoneView_selection_changed_handler_id)

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

        selection = self.zoneView.get_selection()
        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)

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

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

        services = [ ]
        _services = sorted(self.fw.config().listServices())
        for service in _services:
            z = self.fw.config().getService(service)
            settings = z.getSettings()
            services.append(z.get_property("name"))

        # reset and fill notebook content according to view

        self.serviceDialogServiceStore.clear()

        # services

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

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

    def service_added_cb(self, zone, service, timeout):
        if not self.runtime_view or zone != self.get_active_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_active_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]
        active_zone = self.get_active_zone()
        if self.runtime_view:
            if not old_val:
                self.fw.addService(active_zone, name)
            else:
                self.fw.removeService(active_zone, name)
        else:
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            if not old_val:
                settings.addService(name)
            else:
                settings.removeService(name)
            zone.update(settings)

    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_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):
        active_zone = self.get_active_zone()
        if self.runtime_view:
            if not self.masqueradeCheck.get_active():
                self.fw.addMasquerade(active_zone)
            else:
                self.fw.removeMasquerade(active_zone)
        else:
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            settings.setMasquerade(not self.masqueradeCheck.get_active())
            zone.update(settings)

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

    def masquerade_removed_cb(self, zone):
        if not self.runtime_view or zone != self.get_active_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]
        active_zone = self.get_active_zone()
        if self.runtime_view:
            if not old_val:
                self.fw.addIcmpBlock(active_zone, name)
            else:
                self.fw.removeIcmpBlock(active_zone, name)
        else:
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            if not old_val:
                settings.addIcmpBlock(name)
            else:
                settings.removeIcmpBlock(name)
            zone.update(settings)

    def icmp_added_cb(self, zone, icmp, timeout):
        if not self.runtime_view or zone != self.get_active_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_active_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 conf_zone_updated_cb(self, zone):
        self.onChangeZone()

    def _check_name_exception(self, exception, name):
        if "INVALID_NAME" in exception:
            self._warning(_("Invalid name: %s " % name))
        elif "NAME_CONFLICT" in exception:
            self._warning(_("Name '%s' already exists" % name))
        else:
            self._warning(exception)

    def combobox_select_text(self, combobox, value):
        model = combobox.get_model()
        iter = model.get_iter_first()
        while iter:
            if model.get_value(iter, 0) == value:
                combobox.set_active_iter(iter)
                return True
            iter = model.iter_next(iter)
        combobox.set_active(0)
        return False

    def get_active_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.runtime_view = (self.currentViewCombobox.get_active_text() == \
                                 _("Runtime Configuration"))

        self.editServicesButton.set_sensitive(not self.runtime_view)
        self.editIcmpTypesButton.set_sensitive(not self.runtime_view)
        self.zoneEditBox.set_sensitive(not self.runtime_view)
        if self.runtime_view:
            self.editServicesButton.hide()
            self.editIcmpTypesButton.hide()
            self.zoneEditBox.hide()
        else:
            self.editServicesButton.show()
            self.editIcmpTypesButton.show()
            self.zoneEditBox.show()

        self.load_zones()

    def onChangeConnectionsZone(self, *args):
        os.system("%s &" % NM_CONNECTION_EDITOR)

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

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

    def default_zone_changed_cb(self, zone):
        self.defaultZoneLabel.set_text(zone)

    def onChangeZone(self, *args):
        active_zone = self.get_active_zone()

        ### load zone settings

        self.portStore.clear()
        self.forwardStore.clear()

        self.serviceView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.portView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.forwardView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.icmpView.get_selection().set_mode(Gtk.SelectionMode.NONE)
        self.mainNotebook.set_tooltip_markup("")

        if not active_zone:
            self.zoneEditBox.set_sensitive(False)
            self.mainNotebook.set_sensitive(False)
            return

        self.zoneEditBox.set_sensitive(not self.runtime_view)
        self.mainNotebook.set_sensitive(True)

        services = [ ]
        ports = [ ]
        masquerade = False
        forward_ports = [ ]
        icmpblocks = [ ]

        if self.runtime_view:
            # load runtime configuration

            services = self.fw.getServices(active_zone)
            ports = self.fw.getPorts(active_zone)
            masquerade = self.fw.queryMasquerade(active_zone)
            forward_ports = self.fw.getForwardPorts(active_zone)
            icmpblocks = self.fw.getIcmpBlocks(active_zone)
            immutable = self.fw.isImmutable(active_zone)
            defaults = False
            builtin = False
        else:
            # load persistent configuration
            try:
                zone = self.fw.config().getZoneByName(active_zone)
            except:
                return
            settings = zone.getSettings()

            services = settings.getServices()
            ports = settings.getPorts()
            masquerade = settings.getMasquerade()
            forward_ports = settings.getForwardPorts()
            icmpblocks = settings.getIcmpBlocks()
            immutable = settings.getImmutable()
            defaults = zone.get_property("defaults")
            builtin = zone.get_property("builtin")

        self.mainNotebook.set_sensitive(not immutable)
        if immutable:
            self.mainNotebook.set_tooltip_markup(\
                "Immutable zones are not customizable.")
        self.zoneEditRemoveButton.set_sensitive(\
            not builtin and not immutable)
        self.zoneEditLoadDefaultsButton.set_sensitive(not defaults)

        # 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.") % \
                (active_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(active_zone, name)
                else:
                    settings.removeService(name)
                    zone.update(settings)

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

        # set masquerade
        self.masqueradeCheck.set_active(masquerade)

        # set forward ports
        for item in forward_ports:
            self.forwardStore.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)

        # handle unknown icmpblocks
        for name in _icmpblocks:
            text = _("Zone '%s': ICMP type '%s' is not available.") % \
                (active_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(active_zone, name)
                else:
                    settings.removeIcmpBlock(name)
                    zone.update(settings)

        self.serviceView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.portView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.forwardView.get_selection().set_mode(Gtk.SelectionMode.SINGLE)
        self.icmpView.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
        active_zone = self.get_active_zone()
        zone = self.fw.config().getZoneByName(active_zone)
        zone.remove()
        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
        active_zone = self.get_active_zone()
        zone = self.fw.config().getZoneByName(active_zone)
        try:
            zone.loadDefaults()
            self.onChangeZone()
        except DBusException:
            # no default settings
            pass

    def onZoneBaseDialogChanged(self, *args):
        self.zoneBaseDialogOkButton.set_sensitive(True)

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

    def add_edit_zone(self, add):
        if add:
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None
            old_immutable = None
            old_target = None

            self.zoneBaseDialogNameEntry.set_text("")
            self.zoneBaseDialogVersionEntry.set_text("")
            self.zoneBaseDialogShortEntry.set_text("")
            self.zoneBaseDialogDescText.get_buffer().set_text("")
            self.zoneBaseDialogImmutableCheck.set_active(False)
            self.zoneBaseDialogTargetCheck.set_active(True)
            self.zoneBaseDialogTargetCombobox.set_active(0)
        else:
            active_zone = self.get_active_zone()
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            builtin = zone.get_property("builtin")
    
            old_name = zone.get_property("name")
            old_version = settings.getVersion()
            old_short = settings.getShort()
            old_desc = settings.getDescription()
            old_immutable = settings.getImmutable()
            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)
            self.zoneBaseDialogImmutableCheck.set_active(old_immutable)
            if old_target == DEFAULT_ZONE_TARGET:
                self.zoneBaseDialogTargetCheck.set_active(True)
                self.zoneBaseDialogTargetCombobox.set_active(0)
            else:
                self.zoneBaseDialogTargetCheck.set_active(False)
                self.combobox_select_text(self.zoneBaseDialogTargetCombobox,
                                          old_target)

        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)

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

        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)
        immutable = self.zoneBaseDialogImmutableCheck.get_active()
        target = DEFAULT_ZONE_TARGET
        if not self.zoneBaseDialogTargetCheck.get_active():
            target = self.zoneBaseDialogTargetCombobox.get_active_text()

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

        if not add:
            active_zone = self.get_active_zone()
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
        else:
            settings = client.FirewallClientConfigZoneSettings()

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

        if not add:
            if old_name == name:
                return
            zone.rename(name)
        else:
            try:
                self.fw.config().addZone(name, settings)
            except DBusException as e:
                self._check_name_exception(str(e), name)
                return

        self.load_zones()
        #TODO: change active zone
        self.onChangeZone()

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

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

    def onRemovePort(self, *args):
        active_zone = self.get_active_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(active_zone, port, proto)
        else:
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            settings.removePort(port, proto)
            zone.update(settings)

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

    def add_edit_port(self, add):
        active_zone = self.get_active_zone()

        old_port = None
        old_proto = None
        iter = 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:
            self.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()
        result = self.portDialog.run()
        self.portDialog.hide()

        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(active_zone, port, proto):
                self.fw.addPort(active_zone, port, proto)
                if not add:
                    self.fw.removePort(active_zone, old_port, old_proto)
        else:
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            if not settings.queryPort(port, proto):
                if not add:
                    settings.removePort(old_port, old_proto)
                settings.addPort(port, proto)
                zone.update(settings)

    def onPortProtoChanged(self, *args):
        text = self.portProtoDialogPortEntry.get_text()
        ports = getPortRange(self.portProtoDialogPortEntry.get_text())
        if text != "" and not (isinstance(ports, types.ListType) or \
                                   isinstance(ports, types.TupleType)):
            self.portProtoDialogOkButton.set_sensitive(False)
        else:
            #TODO: check proto
            if self.portProtoDialogOtherProtoCheck.get_active() and \
                    self.portProtoDialogOtherProtoEntry.get_text() == "":
                self.portProtoDialogOkButton.set_sensitive(False)
            else:
                self.portProtoDialogOkButton.set_sensitive(True)

    def onPortProtoDialogOtherProtoCheckToggled(self, check, *args):
        self.portProtoDialogProtoCombobox.set_sensitive(not check.get_active())
        self.portProtoDialogOtherProtoEntry.set_sensitive(check.get_active())

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

        self.portProtoDialogPortEntry.set_text("")
        self.portProtoDialogProtoCombobox.set_active(0)
        self.portProtoDialogOtherProtoEntry.set_sensitive(True)
        self.portProtoDialogOtherProtoEntry.set_text("")
        self.portProtoDialogOtherProtoCheck.set_active(True)
        self.portProtoDialogOtherProtoCheck.set_active(False)
        self.portProtoDialogOtherProtoCheck.set_sensitive(True)

        old_port = None
        old_proto = None

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

        if old_port:
            self.portProtoDialogPortEntry.set_text(old_port)
        if old_proto:
            if not self.combobox_select_text(self.portProtoDialogProtoCombobox,
                                             old_proto):
                self.portProtoDialogOtherProtoEntry.set_text(old_proto)
                self.portProtoDialogOtherProtoCheck.set_active(True)

        self.portProtoDialogOkButton.set_sensitive(False)

        self.portProtoDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.portProtoDialog.set_transient_for(self.mainWindow)
        self.portProtoDialog.show_all()
        result = self.portProtoDialog.run()
        self.portProtoDialog.hide()

        if result != 1:
            return

        port = self.portProtoDialogPortEntry.get_text()
        if self.portProtoDialogOtherProtoCheck.get_active():
            proto = self.portProtoDialogOtherProtoEntry.get_text()
        else:
            proto = self.portProtoDialogProtoCombobox.get_active_text()
        
        if (old_port == port and old_proto == proto):
            # nothing to change
            return

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

    def port_added_cb(self, zone, port, protocol, timeout):
        if not self.runtime_view or zone != self.get_active_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_active_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 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 = getPortRange(ports)
        to_ports = getPortRange(to_ports)

        ports_ok = False
        if ports and (isinstance(ports, types.ListType) or \
                          isinstance(ports, types.TupleType)):
            ports_ok = True
        to_ports_ok = False
        if to_ports and (isinstance(to_ports, types.ListType) or \
                          isinstance(to_ports, types.TupleType)):
            to_ports_ok = True
        to_addr_ok = False
        if to_addr != "" and checkIP(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 add_edit_forward_port(self, add):
        active_zone = self.get_active_zone()

        self.forwardDialogOkButton.set_sensitive(False)
        self.forwardDialogLocalCheck.set_active(True)
        self.forwardDialogLocalCheck.set_active(False)
        self.forwardDialogToPortCheck.set_active(False)

        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)
            self.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()
        result = self.forwardDialog.run()
        self.forwardDialog.hide()

        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(active_zone, port, proto,
                                            to_port, to_addr):

                self.fw.addForwardPort(active_zone, port, proto,
                                       to_port, to_addr)
                if not add:
                    self.fw.removeForwardPort(active_zone, old_port, old_proto,
                                              old_to_port, old_to_addr)
        else:
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            if not settings.queryForwardPort(port, proto, to_port, to_addr):
                if not add:
                    settings.removeForwardPort(old_port, old_proto,
                                               old_to_port, old_to_addr)
                settings.addForwardPort(port, proto, to_port, to_addr)
                zone.update(settings)

    def forward_port_added_cb(self, zone, port, protocol, to_port, to_address,
                              timeout):
        if not self.runtime_view or zone != self.get_active_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_active_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):
        active_zone = self.get_active_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(active_zone, port, proto,
                                      to_port, to_addr)
        else:
            zone = self.fw.config().getZoneByName(active_zone)
            settings = zone.getSettings()
            settings.removeForwardPort(port, proto, to_port, to_addr)
            zone.update(settings)

        model.remove(iter)

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

        ### load service settings

        self.serviceDialogPortStore.clear()
        self.serviceDialogModuleStore.clear()
        self.serviceDialogDestIpv4Chooser.set_text("")
        self.serviceDialogDestIpv6Chooser.set_text("")

        self.serviceDialogPortView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)
        self.serviceDialogModuleView.get_selection().set_mode(
            Gtk.SelectionMode.NONE)

        if not active_service:
            self.serviceDialogServiceEditBox.set_sensitive(False)
            self.serviceDialogServiceNotebook.set_sensitive(False)
            return

        self.serviceDialogServiceEditBox.set_sensitive(True)
        self.serviceDialogServiceNotebook.set_sensitive(True)

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

        # load persistent configuration
        try:
            service = self.fw.config().getServiceByName(active_service)
        except:
            return
        settings = service.getSettings()

        ports = settings.getPorts()
        modules = settings.getModules()
        destination = settings.getDestinations()
        defaults = service.get_property("defaults")
        builtin = service.get_property("builtin")

        self.serviceDialogRemoveServiceButton.set_sensitive(not builtin)
        self.serviceDialogLoadDefaultsServiceButton.set_sensitive(not defaults)

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

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

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

        self.serviceDialogPortView.get_selection().set_mode(
            Gtk.SelectionMode.SINGLE)
        self.serviceDialogModuleView.get_selection().set_mode(
            Gtk.SelectionMode.SINGLE)

    def conf_service_added_cb(self, service):
        if self.runtime_view:
            return
        self.serviceStore.append([False, service])

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

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

    def onEditServices(self, *args):
        self.serviceDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.serviceDialog.set_transient_for(self.mainWindow)
        self.load_services()
        self.onChangeService()
        self.serviceDialog.show_all()
        self.serviceDialog.run()
        self.serviceDialog.hide()

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

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

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

    def onServiceBaseDialogChanged(self, *args):
        self.serviceBaseDialogOkButton.set_sensitive(True)

    def onServiceDialogAddPort(self, *args):
        self.add_edit_port_proto(True)

    def onServiceDialogEditPort(self, *args):
        self.add_edit_port_proto(False)

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

        service = self.fw.config().getServiceByName(active_service)
        settings = service.getSettings()
        settings.removePort(port, proto)
        service.update(settings)

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

    def add_edit_service(self, add):
        if add:
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None
            old_immutable = None
            old_target = 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()
            builtin = service.get_property("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)

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

        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.FirewallClientConfigServiceSettings()

        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:
            try:
                self.fw.config().addService(name, settings)
            except DBusException as e:
                self._check_name_exception(str(e), name)
                return


        self.load_services()
        #TODO: change active service
        self.onChangeService()

    def onServiceDialogLoadDefaultsService(self, *args):
        active_service = self.get_active_service()
        service = self.fw.config().getServiceByName(active_service)
        try:
            service.loadDefaults()
            self.onChangeService()
        except DBusException:
            # no default settings
            pass

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

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

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

        service = self.fw.config().getServiceByName(active_service)
        settings = service.getSettings()
        settings.removeModule(module)
        service.update(settings)

    def onModuleChanged(self, *args):
        self.moduleDialogOkButton.set_sensitive(True)

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

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

        self.moduleDialogModuleEntry.set_text("")

        old_module = None

        if not add:
            selection = self.serviceDialogModuleView.get_selection()
            (model, iter) = selection.get_selected()
            if iter is None:
                return
            old_module = self.serviceDialogModuleStore.get_value(iter, 0)

        if old_module:
            self.moduleDialogModuleEntry.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()
        result = self.moduleDialog.run()
        self.moduleDialog.hide()

        if result != 1:
            return

        module = self.moduleDialogModuleEntry.get_text()
        
        if (old_module == module and old_proto == proto):
            # nothing to change
            return

        service = self.fw.config().getServiceByName(active_service)
        settings = service.getSettings()
        if not settings.queryModule(module):
            if not add:
                settings.removeModule(old_module)
            settings.addModule(module)
            service.update(settings)

    def onChangeServiceDialogDestIpv4(self, *args):
        old_addr = self.serviceDialogDestIpv4Chooser.get_text()
        addr = self._address_dialog("ipv4", old_addr)
        if addr == None:
            return
        active_service = self.get_active_service()
        service = self.fw.config().getServiceByName(active_service)
        settings = service.getSettings()
        if not settings.queryDestination("ipv4", addr):
            settings.setDestination("ipv4", addr)
            service.update(settings)

    def onChangeServiceDialogDestIpv6(self, *args):
        old_addr = self.serviceDialogDestIpv6Chooser.get_text()
        addr = self._address_dialog("ipv6", old_addr)
        if addr == None:
            return
        active_service = self.get_active_service()
        service = self.fw.config().getServiceByName(active_service)
        settings = service.getSettings()
        if not settings.queryDestination("ipv6", addr):
            settings.setDestination("ipv6", addr)
            service.update(settings)

    def onAddressChanged(self, entry, addr_type):
        text = entry.get_text()
        self.addressDialogOkButton.set_sensitive(False)
        if addr_type == "ipv4":
            if checkIPnMask(text):
                self.addressDialogOkButton.set_sensitive(True)
        elif addr_type == "ipv6":
            if checkIP6nMask(text):
                self.addressDialogOkButton.set_sensitive(True)

    def _address_dialog(self, addr_type, old_address):
        active_service = self.get_active_service()
        if addr_type == "ipv4":
            self.addressDialogLabel.set_markup("Please enter an IPv4 address with the form address[/mask].\nThe mask can be a network mask or a number")
        elif addr_type == "ipv6":
            self.addressDialogLabel.set_markup("Please enter an IPv6 address with the form address[/mask].\nThe mask is a number.")

        self.addressDialogAddressEntry.set_text(old_address)
        handler_id = self.addressDialogAddressEntry.connect(\
            "changed", self.onAddressChanged, addr_type)
        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()
        result = self.addressDialog.run()
        self.addressDialog.hide()

        self.addressDialogAddressEntry.disconnect(handler_id)

        address = self.addressDialogAddressEntry.get_text()
        #TODO: addr check according to addr_type

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

    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):
        active_icmp = self.get_active_icmp()

        icmps = [ ]
        _icmps = sorted(self.fw.config().listIcmpTypes())
        for icmp in _icmps:
            z = self.fw.config().getIcmpType(icmp)
            settings = z.getSettings()
            icmps.append(z.get_property("name"))

        # reset and fill notebook content according to view

        self.icmpDialogIcmpStore.clear()

        # icmps

        for icmp in icmps:
            self.icmpDialogIcmpStore.append([icmp])

        selection = self.icmpDialogIcmpView.get_selection()
        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)

    def onChangeIcmp(self, *args):
        active_icmp = self.get_active_icmp()

        ### load service settings

        self.icmpDialogDestIpv4Check.set_active(False)
        self.icmpDialogDestIpv6Check.set_active(False)

        if not active_icmp:
            self.icmpDialogIcmpEditBox.set_sensitive(False)
            self.icmpDialogIcmpNotebook.set_sensitive(False)
            return

        self.icmpDialogIcmpEditBox.set_sensitive(True)
        self.icmpDialogIcmpNotebook.set_sensitive(True)

        destination = [ ]

        # load persistent configuration
        try:
            icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        except:
            return
        settings = icmp.getSettings()

        destination = settings.getDestinations()
        defaults = icmp.get_property("defaults")
        builtin = icmp.get_property("builtin")

        self.icmpDialogRemoveIcmpButton.set_sensitive(not builtin)
        self.icmpDialogLoadDefaultsIcmpButton.set_sensitive(not defaults)

        # set destination
        if "ipv4" in destination:
            self.icmpDialogDestIpv4Check.set_active(True)
        if "ipv6" in destination:
            self.icmpDialogDestIpv6Check.set_active(True)

    def onIcmpBaseDialogChanged(self, *args):
        self.icmpBaseDialogOkButton.set_sensitive(True)

    def onEditIcmps(self, *args):
        self.icmpDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.icmpDialog.set_transient_for(self.mainWindow)
        self.load_icmps()
        self.onChangeIcmp()
        self.icmpDialog.show_all()
        self.icmpDialog.run()
        self.icmpDialog.hide()

    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):
        self.icmpBaseDialogOkButton.set_sensitive(True)

    def change_icmp_dialog_port_selection_cb(self, selection):
        (model, iter) = selection.get_selected()
        if iter:
            self.icmpDialogEditPortButton.set_sensitive(True)
            self.icmpDialogRemovePortButton.set_sensitive(True)
        else:
            self.icmpDialogEditPortButton.set_sensitive(False)
            self.icmpDialogRemovePortButton.set_sensitive(False)

    def add_edit_icmp(self, add):
        if add:
            builtin = False
            old_name = None
            old_version = None
            old_short = None
            old_desc = None
            old_immutable = None
            old_target = 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()
            builtin = icmp.get_property("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)

        self.icmpBaseDialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
        self.icmpBaseDialog.set_transient_for(self.mainWindow)
        self.icmpBaseDialog.show_all()
        result = self.icmpBaseDialog.run()
        self.icmpBaseDialog.hide()

        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.FirewallClientConfigIcmpTypeSettings()

        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:
            try:
                self.fw.config().addIcmpType(name, settings)
            except DBusException as e:
                self._check_name_exception(str(e), name)
                return

        self.load_icmps()
        #TODO: change active icmp
        self.onChangeIcmp()

    def onIcmpDialogLoadDefaultsIcmp(self, *args):
        active_icmp = self.get_active_icmp()
        icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        try:
            icmp.loadDefaults()
            self.onChangeIcmp()
        except DBusException:
            # no default settings
            pass

    def icmp_dialog_dest_ipv4_check_cb(self, *args):
        active_icmp = self.get_active_icmp()
        icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        settings = icmp.getSettings()
        if self.icmpDialogDestIpv4Check.get_active():
            if settings.queryDestination("ipv4"):
                settings.removeDestination("ipv4")
                icmp.update(settings)
        elif not settings.queryDestination("ipv4"):
            settings.addDestination("ipv4")
            icmp.update(settings)

    def icmp_dialog_dest_ipv6_check_cb(self, *args):
        active_icmp = self.get_active_icmp()
        icmp = self.fw.config().getIcmpTypeByName(active_icmp)
        settings = icmp.getSettings()
        if self.icmpDialogDestIpv6Check.get_active():
            if settings.queryDestination("ipv6"):
                settings.removeDestination("ipv6")
                icmp.update(settings)
        elif not settings.queryDestination("ipv6"):
            settings.addDestination("ipv6")
            icmp.update(settings)

    def conf_icmp_added_cb(self, icmp):
        if self.runtime_view:
            return
        self.icmpStore.append([False, icmp])

    def conf_icmp_updated_cb(self, zone):
        self.onChangeIcmp()

    def conf_icmp_removed_cb(self, icmp):
        if self.runtime_view:
            return
        iter = self.icmpStore.get_iter_first()
        while iter:
            if self.icmpStore.get_value(iter, 1) == icmp:
                self.icmpStore.remove(iter)
                break
            iter = self.icmpStore.iter_next(iter)

# MAIN

app = FirewallConfig()
sys.exit(0)
