Blame SOURCES/firewalld-0.3.9-RHBZ#993782_d545084d.patch

36ae71
commit d545084d092fa049932e2ec1f9adc92c900eb0e7
36ae71
Author: Thomas Woerner <twoerner@redhat.com>
36ae71
Date:   Wed Feb 19 13:35:01 2014 +0100
36ae71
36ae71
    firewall-config: Use left button menu of -applet in Option menu
36ae71
    
36ae71
    nm-connection-editor is not used anymore to change zones of connections in the
36ae71
    Option menu "Change Zones of Connections...". The -applet left mouse menu is
36ae71
    attached as a submenu. Zone bindings of connections, interfaces and sources can
36ae71
    now be changes easily.
36ae71
36ae71
diff --git a/src/firewall-config b/src/firewall-config
36ae71
index a00a794..f963cbc 100755
36ae71
--- a/src/firewall-config
36ae71
+++ b/src/firewall-config
36ae71
@@ -58,14 +58,11 @@ if not datadir:
36ae71
     sys.path.insert(0, datadir)
36ae71
 from gtk3_chooserbutton import ChooserButton
36ae71
 
36ae71
-NM_CONNECTION_EDITOR = ""
36ae71
-for binary in [ "/usr/bin/nm-connection-editor",
36ae71
-                    "/bin/nm-connection-editor",
36ae71
-                "/usr/bin/kde-nm-connection-editor",
36ae71
-                    "/bin/kde-nm-connection-editor" ]:
36ae71
-    if os.path.exists(binary):
36ae71
-        NM_CONNECTION_EDITOR = binary
36ae71
-        break
36ae71
+def escape(text):
36ae71
+    text = text.replace('&', '&')
36ae71
+    text = text.replace('>', '>')
36ae71
+    text = text.replace('<', '<')
36ae71
+    return text
36ae71
 
36ae71
 FIREWALL_CONFIG_SCHEMA = "org.fedoraproject.FirewallConfig"
36ae71
 
36ae71
@@ -87,6 +84,10 @@ class FirewallConfig(object):
36ae71
         self.settings = Gio.Settings.new(FIREWALL_CONFIG_SCHEMA)
36ae71
         self.modified_timer = None
36ae71
 
36ae71
+        self.zone_connection_editors = { }
36ae71
+        self.zone_interface_editors = { }
36ae71
+        self.zone_source_editors = { }
36ae71
+
36ae71
         # get icon and logo
36ae71
         (foo, width, height) = Gtk.icon_size_lookup(Gtk.IconSize.BUTTON)
36ae71
         size = min(width, height)
36ae71
@@ -127,12 +128,13 @@ class FirewallConfig(object):
36ae71
 
36ae71
         self.changeZonesConnectionMenuitem = \
36ae71
             builder.get_object("changeZonesConnectionMenuitem")
36ae71
-        if NM_CONNECTION_EDITOR != "":
36ae71
-            self.changeZonesConnectionMenuitem.set_sensitive(True)
36ae71
-        else:
36ae71
-            self.changeZonesConnectionMenuitem.set_tooltip_markup(\
36ae71
-                _("NetworkManager connection editor is missing."))
36ae71
-            self.changeZonesConnectionMenuitem.set_sensitive(False)
36ae71
+
36ae71
+        self.left_menu = Gtk.Menu.new()
36ae71
+        self.left_menu.set_reserve_toggle_size(False)
36ae71
+        self.changeZonesConnectionMenuitem.set_submenu(self.left_menu)
36ae71
+        self.changeZonesConnectionMenuitem.connect(
36ae71
+            "activate", self.left_menu_cb, self.left_menu)
36ae71
+        self.active_zones = { }
36ae71
 
36ae71
         self.panicMenuitem = builder.get_object("panicMenuitem")
36ae71
         self.panic_check_id = \
36ae71
@@ -963,6 +965,61 @@ class FirewallConfig(object):
36ae71
         except KeyboardInterrupt:
36ae71
             self.onQuit()
36ae71
 
36ae71
+    def left_menu_cb(self, widget, menu):
36ae71
+        menu.show_all()
36ae71
+
36ae71
+    def no_select(self, item):
36ae71
+        item.deselect()
36ae71
+
36ae71
+    def change_zone_interface_editor(self, item, interface, zone):
36ae71
+        if interface in self.zone_interface_editors:
36ae71
+            return self.zone_interface_editors[interface].present()
36ae71
+
36ae71
+        editor = ZoneInterfaceEditor(self.fw, interface, zone)
36ae71
+        editor.set_icon(self.icon)
36ae71
+        editor.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
36ae71
+        editor.set_transient_for(self.mainWindow)
36ae71
+        self.zone_interface_editors[interface] = editor
36ae71
+
36ae71
+        editor.show_all()
36ae71
+        result = editor.run()
36ae71
+        editor.hide()
36ae71
+        if result == 2:
36ae71
+            self.fw.changeZoneOfInterface(editor.get_zone(), interface)
36ae71
+        del self.zone_interface_editors[interface]
36ae71
+
36ae71
+    def change_zone_connection_editor(self, item, connection, zone):
36ae71
+        if connection in self.zone_connection_editors:
36ae71
+            return self.zone_connection_editors[connection].present()
36ae71
+
36ae71
+        editor = ZoneConnectionEditor(self.fw, connection, zone)
36ae71
+        editor.set_icon(self.icon)
36ae71
+        editor.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
36ae71
+        editor.set_transient_for(self.mainWindow)
36ae71
+        self.zone_connection_editors[connection] = editor
36ae71
+
36ae71
+        editor.show_all()
36ae71
+        editor.run()
36ae71
+        editor.hide()
36ae71
+        del self.zone_connection_editors[connection]
36ae71
+
36ae71
+    def change_zone_source_editor(self, item, source, zone):
36ae71
+        if source in self.zone_source_editors:
36ae71
+            return self.zone_source_editors[source].present()
36ae71
+
36ae71
+        editor = ZoneSourceEditor(self.fw, source, zone)
36ae71
+        editor.set_icon(self.icon)
36ae71
+        editor.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
36ae71
+        editor.set_transient_for(self.mainWindow)
36ae71
+        self.zone_source_editors[source] = editor
36ae71
+
36ae71
+        editor.show_all()
36ae71
+        result = editor.run()
36ae71
+        editor.hide()
36ae71
+        if result == 2:
36ae71
+            self.fw.changeZoneOfSource(editor.get_zone(), source)
36ae71
+        del self.zone_source_editors[source]
36ae71
+
36ae71
     def onViewICMPTypes_toggled(self, button):
36ae71
         self.settings.set_boolean("show-icmp-types", button.get_active())
36ae71
 
36ae71
@@ -1013,6 +1070,8 @@ class FirewallConfig(object):
36ae71
 
36ae71
     def nm_signal_receiver(self, *args, **kwargs):
36ae71
         #print("nm_signal_receiver", args, kwargs)
36ae71
+        self.update_active_zones()
36ae71
+
36ae71
         self.connections.clear()
36ae71
         self.connections_uuid.clear()
36ae71
 
36ae71
@@ -1134,6 +1193,7 @@ class FirewallConfig(object):
36ae71
             self.lockdownLabel.set_text("-")
36ae71
             self.panicLabel.set_text("-")
36ae71
 
36ae71
+        self.update_active_zones()
36ae71
         self.mainToolbar.set_sensitive(self.fw.connected)
36ae71
         self.mainVBox.set_sensitive(self.fw.connected)
36ae71
         self.optionMenuitem.get_submenu().set_sensitive(self.fw.connected)
36ae71
@@ -1507,6 +1567,7 @@ class FirewallConfig(object):
36ae71
         self.interfaceStore.append([interface, comment])
36ae71
 
36ae71
     def interface_added_cb(self, zone, interface):
36ae71
+        self.update_active_zones()
36ae71
         if not self.runtime_view or zone != self.get_active_zone():
36ae71
             return
36ae71
         iter = self.interfaceStore.get_iter_first()
36ae71
@@ -1527,8 +1588,10 @@ class FirewallConfig(object):
36ae71
                 self.interfaceStore.remove(iter)
36ae71
                 break
36ae71
             iter = self.interfaceStore.iter_next(iter)
36ae71
+        self.update_active_zones()
36ae71
 
36ae71
     def zone_of_interface_changed_cb(self, zone, interface):
36ae71
+        self.update_active_zones()
36ae71
         if not self.runtime_view:
36ae71
             return
36ae71
         iter = self.interfaceStore.get_iter_first()
36ae71
@@ -1542,6 +1605,7 @@ class FirewallConfig(object):
36ae71
             self._add_interface(interface)
36ae71
 
36ae71
     def source_added_cb(self, zone, source):
36ae71
+        self.update_active_zones()
36ae71
         if not self.runtime_view or zone != self.get_active_zone():
36ae71
             return
36ae71
         iter = self.sourceStore.get_iter_first()
36ae71
@@ -1554,6 +1618,7 @@ class FirewallConfig(object):
36ae71
         self.sourceStore.append([source])
36ae71
 
36ae71
     def source_removed_cb(self, zone, source):
36ae71
+        self.update_active_zones()
36ae71
         if not self.runtime_view or zone != self.get_active_zone():
36ae71
             return
36ae71
         iter = self.sourceStore.get_iter_first()
36ae71
@@ -1564,6 +1629,7 @@ class FirewallConfig(object):
36ae71
             iter = self.sourceStore.iter_next(iter)
36ae71
 
36ae71
     def zone_of_source_changed_cb(self, zone, source):
36ae71
+        self.update_active_zones()
36ae71
         if not self.runtime_view:
36ae71
             return
36ae71
         iter = self.sourceStore.get_iter_first()
36ae71
@@ -1673,18 +1739,119 @@ class FirewallConfig(object):
36ae71
         self.load_direct()
36ae71
         self.load_lockdown_whitelist()
36ae71
 
36ae71
-    def nm_connection_editor(self, item, uuid=None):
36ae71
-        if NM_CONNECTION_EDITOR == "":
36ae71
-            self._warning("NetworkManager connection editor is missing.")
36ae71
+    def update_active_zones(self):
36ae71
+        self.active_zones.clear()
36ae71
+
36ae71
+        # remove all entries for the left menu
36ae71
+        left_menu_children = self.left_menu.get_children()
36ae71
+        for child in left_menu_children:
36ae71
+            self.left_menu.remove(child)
36ae71
+            child.destroy()
36ae71
+
36ae71
+        # add connecitons entry
36ae71
+        item = Gtk.MenuItem.new()
36ae71
+        label = Gtk.Label()
36ae71
+#        label.set_markup(""+escape(_("Connections"))+"")
36ae71
+        label.set_markup(escape(_("Connections")))
36ae71
+        label.set_alignment(0, 0.5)
36ae71
+        item.add(label)
36ae71
+        item.connect("select", self.no_select)
36ae71
+        self.left_menu.append(item)
36ae71
+
36ae71
+        if not self.fw.connected:
36ae71
             return
36ae71
 
36ae71
-        if uuid:
36ae71
-            if "kde-" in NM_CONNECTION_EDITOR:
36ae71
-                os.system("%s %s &" % (NM_CONNECTION_EDITOR, uuid))
36ae71
-            else:
36ae71
-                os.system("%s --edit=%s &" % (NM_CONNECTION_EDITOR, uuid))
36ae71
-        else:
36ae71
-            os.system("%s &" % NM_CONNECTION_EDITOR)
36ae71
+        active_zones = self.fw.getActiveZones()
36ae71
+        if active_zones:
36ae71
+            self.active_zones = active_zones
36ae71
+
36ae71
+        # get all active connections (NM) and interfaces
36ae71
+        connections = { }
36ae71
+        interfaces = { }
36ae71
+        sources = { }
36ae71
+        for zone in sorted(self.active_zones):
36ae71
+            if "interfaces" in self.active_zones[zone]:
36ae71
+                for interface in sorted(self.active_zones[zone]["interfaces"]):
36ae71
+                    if interface not in self.connections:
36ae71
+                        interfaces[interface] = zone
36ae71
+                    else:
36ae71
+                        # NM controlled
36ae71
+                        connection = self.connections[interface]
36ae71
+                        if connection not in connections:
36ae71
+                            connections[connection] = [ zone, [ interface, ] ]
36ae71
+                        else:
36ae71
+                            connections[connection][1].append(interface)
36ae71
+            if "sources" in self.active_zones[zone]:
36ae71
+                for source in sorted(self.active_zones[zone]["sources"]):
36ae71
+                    sources[source] = zone
36ae71
+
36ae71
+        # add NM controlled entries
36ae71
+        for connection in sorted(connections):
36ae71
+            [ zone, _interfaces ] = connections[connection]
36ae71
+
36ae71
+            item = Gtk.MenuItem.new()
36ae71
+            hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
36ae71
+            label = Gtk.Label()
36ae71
+            label.set_markup("%s (%s)\n<small>%s: %s</small>" % \
36ae71
+                             (connection, ",".join(_interfaces), escape(_("Zone")), zone))
36ae71
+            label.set_alignment(0, 0.5)
36ae71
+            label.set_padding(12, 0)
36ae71
+            hbox.pack_start(label, True, True, 0)
36ae71
+            item.add(hbox)
36ae71
+            item.connect("activate", self.change_zone_connection_editor, connection, zone)
36ae71
+            self.left_menu.append(item)
36ae71
+
36ae71
+        if len(interfaces) > 0:
36ae71
+            item = Gtk.MenuItem.new()
36ae71
+            label = Gtk.Label()
36ae71
+#            label.set_markup(""+escape(_("Interfaces"))+"")
36ae71
+            label.set_markup(escape(_("Interfaces")))
36ae71
+            label.set_alignment(0, 0.5)
36ae71
+            item.add(label)
36ae71
+            item.connect("select", self.no_select)
36ae71
+            self.left_menu.append(item)
36ae71
+
36ae71
+            # add other interfaces
36ae71
+            for interface in sorted(interfaces):
36ae71
+                zone = interfaces[interface]
36ae71
+
36ae71
+                item = Gtk.MenuItem.new()
36ae71
+                hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
36ae71
+                label = Gtk.Label()
36ae71
+                label.set_markup("%s\n<small>%s: %s</small>" % \
36ae71
+                                     (interface, escape(_("Zone")), zone))
36ae71
+                label.set_alignment(0, 0.5)
36ae71
+                label.set_padding(12, 0)
36ae71
+                hbox.pack_start(label, True, True, 0)
36ae71
+                item.add(hbox)
36ae71
+                item.connect("activate", self.change_zone_interface_editor, interface, zone)
36ae71
+                self.left_menu.append(item)
36ae71
+
36ae71
+        if len(sources) > 0:
36ae71
+            item = Gtk.MenuItem.new()
36ae71
+            label = Gtk.Label()
36ae71
+#            label.set_markup(""+escape(_("Sources"))+"")
36ae71
+            label.set_markup(escape(_("Sources")))
36ae71
+            label.set_alignment(0, 0.5)
36ae71
+            item.add(label)
36ae71
+            item.connect("select", self.no_select)
36ae71
+            self.left_menu.append(item)
36ae71
+
36ae71
+            for source in sorted(sources):
36ae71
+                zone = sources[source]
36ae71
+
36ae71
+                item = Gtk.MenuItem.new()
36ae71
+                hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
36ae71
+                label = Gtk.Label()
36ae71
+                label.set_markup("%s\n<small>%s: %s</small>" % \
36ae71
+                                     (source, escape(_("Zone")),
36ae71
+                                      zone))
36ae71
+                label.set_alignment(0, 0.5)
36ae71
+                label.set_padding(12, 0)
36ae71
+                hbox.pack_start(label, True, True, 0)
36ae71
+                item.add(hbox)
36ae71
+                item.connect("activate", self.change_zone_source_editor, source, zone)
36ae71
+                self.left_menu.append(item)
36ae71
 
36ae71
     def onChangeDefaultZone(self, *args):
36ae71
         self.defaultZoneStore.clear()
36ae71
@@ -5020,6 +5187,7 @@ class ZoneConnectionEditor(Gtk.Dialog):
36ae71
 
36ae71
         self.combo = Gtk.ComboBoxText()
36ae71
         zones = self.fw.getZones()
36ae71
+        self.combo.append_text(_("Default Zone"))
36ae71
         for zone in zones:
36ae71
             self.combo.append_text(zone)
36ae71
         vbox.pack_start(self.combo, True, True, 0)
36ae71
@@ -5044,7 +5212,10 @@ class ZoneConnectionEditor(Gtk.Dialog):
36ae71
             self.combo_changed(None)
36ae71
 
36ae71
     def get_zone(self):
36ae71
-        return self.combo.get_active_text()
36ae71
+        text = self.combo.get_active_text()
36ae71
+        if text == _("Default Zone"):
36ae71
+            text = ""
36ae71
+        return text
36ae71
 
36ae71
     def run(self):
36ae71
         result = super(ZoneConnectionEditor, self).run()
36ae71
@@ -5068,6 +5239,119 @@ class ZoneConnectionEditor(Gtk.Dialog):
36ae71
         if settings and connection_obj:
36ae71
             settings["connection"]["zone"] = self.get_zone()
36ae71
             connection_obj.Update(settings)
36ae71
+
36ae71
+class ZoneInterfaceEditor(Gtk.Dialog):
36ae71
+    def __init__(self, fw, interface, zone):
36ae71
+        self.fw = fw
36ae71
+        self.interface = interface
36ae71
+        self.zone = zone
36ae71
+        self.title = _("Select zone for interface '%s'") % self.interface
36ae71
+
36ae71
+        super(ZoneInterfaceEditor, self).__init__(self.title)
36ae71
+
36ae71
+        self.set_property("width-request", 100)
36ae71
+        self.resize_to_geometry(100, 50)
36ae71
+        self.set_resizable(True)
36ae71
+
36ae71
+        self.add_button("gtk-close", 1)
36ae71
+        self.ok_button = self.add_button("gtk-ok", 2)
36ae71
+        self.ok_button.set_sensitive(False)
36ae71
+
36ae71
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
36ae71
+        vbox.set_border_width(12)
36ae71
+        vbox.set_homogeneous(False)
36ae71
+
36ae71
+        label = Gtk.Label()
36ae71
+        label.set_text(self.title)
36ae71
+        label.set_line_wrap(True)
36ae71
+        label.set_justify(Gtk.Justification.LEFT)
36ae71
+        label.set_alignment(0, 0.5)
36ae71
+        vbox.pack_start(label, True, True, 0)
36ae71
+
36ae71
+        self.combo = Gtk.ComboBoxText()
36ae71
+        zones = self.fw.getZones()
36ae71
+        for zone in zones:
36ae71
+            self.combo.append_text(zone)
36ae71
+        vbox.pack_start(self.combo, True, True, 0)
36ae71
+
36ae71
+        box = self.get_content_area()
36ae71
+        box.set_border_width(6)
36ae71
+        box.set_homogeneous(False)
36ae71
+        box.pack_start(vbox, False, True, 0)
36ae71
+
36ae71
+        combobox_select_text(self.combo, self.zone)
36ae71
+        self.combo.connect("changed", self.combo_changed)
36ae71
+
36ae71
+    def combo_changed(self, combo):
36ae71
+        self.ok_button.set_sensitive(self.combo.get_active_text() != self.zone)
36ae71
+
36ae71
+    def set_zone(self, zone):
36ae71
+        old_zone = self.zone
36ae71
+        self.zone = zone
36ae71
+        if self.combo.get_active_text() == old_zone:
36ae71
+            combobox_select_text(self.combo, self.zone)
36ae71
+        else:
36ae71
+            self.combo_changed(None)
36ae71
+
36ae71
+    def get_zone(self):
36ae71
+        return self.combo.get_active_text()
36ae71
+
36ae71
+class ZoneSourceEditor(Gtk.Dialog):
36ae71
+    def __init__(self, fw, source, zone):
36ae71
+        self.fw = fw
36ae71
+        self.source = source
36ae71
+        self.zone = zone
36ae71
+        self.title = _("Select zone for source %s") % self.source
36ae71
+
36ae71
+        super(ZoneSourceEditor, self).__init__(self.title)
36ae71
+
36ae71
+        self.set_property("width-request", 100)
36ae71
+        self.resize_to_geometry(100, 50)
36ae71
+        self.set_resizable(True)
36ae71
+
36ae71
+        self.add_button("gtk-close", 1)
36ae71
+        self.ok_button = self.add_button("gtk-ok", 2)
36ae71
+        self.ok_button.set_sensitive(False)
36ae71
+
36ae71
+        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
36ae71
+        vbox.set_border_width(12)
36ae71
+        vbox.set_homogeneous(False)
36ae71
+
36ae71
+        label = Gtk.Label()
36ae71
+        label.set_text(self.title)
36ae71
+        label.set_line_wrap(True)
36ae71
+        label.set_justify(Gtk.Justification.LEFT)
36ae71
+        label.set_alignment(0, 0.5)
36ae71
+        vbox.pack_start(label, True, True, 0)
36ae71
+
36ae71
+        self.combo = Gtk.ComboBoxText()
36ae71
+        zones = self.fw.getZones()
36ae71
+        for zone in zones:
36ae71
+            self.combo.append_text(zone)
36ae71
+        vbox.pack_start(self.combo, True, True, 0)
36ae71
+
36ae71
+        box = self.get_content_area()
36ae71
+        box.set_border_width(6)
36ae71
+        box.set_homogeneous(False)
36ae71
+        box.pack_start(vbox, False, True, 0)
36ae71
+
36ae71
+        combobox_select_text(self.combo, self.zone)
36ae71
+        self.combo.connect("changed", self.combo_changed)
36ae71
+
36ae71
+    def combo_changed(self, combo):
36ae71
+        self.ok_button.set_sensitive(self.combo.get_active_text() != self.zone)
36ae71
+
36ae71
+    def set_zone(self, zone):
36ae71
+        old_zone = self.zone
36ae71
+        self.zone = zone
36ae71
+        if self.combo.get_active_text() == old_zone:
36ae71
+            combobox_select_text(self.combo, self.zone)
36ae71
+        else:
36ae71
+            self.combo_changed(None)
36ae71
+
36ae71
+    def get_zone(self):
36ae71
+        return self.combo.get_active_text()
36ae71
+
36ae71
 # MAIN
36ae71
 
36ae71
 if len(sys.argv) > 1:
36ae71
diff --git a/src/firewall-config.glade b/src/firewall-config.glade
36ae71
index 2cc33d2..872748e 100755
36ae71
--- a/src/firewall-config.glade
36ae71
+++ b/src/firewall-config.glade
36ae71
@@ -2073,14 +2073,11 @@
36ae71
                       </object>
36ae71
                     </child>
36ae71
                     <child>
36ae71
-                      <object class="GtkImageMenuItem" id="changeZonesConnectionMenuitem">
36ae71
+                      <object class="GtkMenuItem" id="changeZonesConnectionMenuitem">
36ae71
                         <property name="label" translatable="yes">Change Zones of Connections...</property>
36ae71
                         <property name="visible">True</property>
36ae71
                         <property name="can_focus">False</property>
36ae71
                         <property name="tooltip_text" translatable="yes">Change which zone a network connection belongs to.</property>
36ae71
-                        <property name="image">image2</property>
36ae71
-                        <property name="use_stock">False</property>
36ae71
-                        <signal name="activate" handler="nm_connection_editor" swapped="no"/>
36ae71
                       </object>
36ae71
                     </child>
36ae71
                     <child>