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