class GsmSettings(Gtk.Dialog): def __init__(self, bd_address: str) -> None: super().__init__() self.set_name("GsmSettings") self.device = bd_address builder = Builder("gsm-settings.ui") gsm_grid = builder.get_widget("gsm_grid", Gtk.Grid) self.config = Config("org.blueman.gsmsetting", f"/org/blueman/gsmsettings/{bd_address}/") self.props.icon_name = "network-wireless" self.props.title = _("GSM Settings") self.props.resizable = False a = self.get_content_area() a.pack_start(gsm_grid, True, True, 0) gsm_grid.show() self.e_apn = builder.get_widget("e_apn", Gtk.Entry) self.e_number = builder.get_widget("e_number", Gtk.Entry) self.config.bind_to_widget("apn", self.e_apn, "text") self.config.bind_to_widget("number", self.e_number, "text") self.add_button("_Close", Gtk.ResponseType.CLOSE)
class GsmSettings(Gtk.Dialog): def __init__(self, bd_address): GObject.GObject.__init__(self) self.device = bd_address self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") self.Builder.add_from_file(UI_PATH + "/gsm-settings.ui") vbox = self.Builder.get_object("vbox1") self.config = Config("org.blueman.gsmsetting", "/org/blueman/gsmsettings/%s/" % bd_address) self.props.icon_name = "network-wireless" self.props.title = _("GSM Settings") self.props.resizable = False a = self.get_content_area() a.pack_start(vbox, True, True, 0) vbox.show() self.e_apn = self.Builder.get_object("e_apn") self.e_number = self.Builder.get_object("e_number") self.config.bind_to_widget("apn", self.e_apn, "text") self.config.bind_to_widget("number", self.e_number, "text") self.add_button("_Close", Gtk.ResponseType.CLOSE)
class GsmSettings(Gtk.Dialog): def __init__(self, bd_address): super(GsmSettings, self).__init__() self.set_name("GsmSettings") self.device = bd_address self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/gsm-settings.ui") gsm_grid = self.Builder.get_object("gsm_grid") self.config = Config("org.blueman.gsmsetting", "/org/blueman/gsmsettings/%s/" % bd_address) self.props.icon_name = "network-wireless" self.props.title = _("GSM Settings") self.props.resizable = False a = self.get_content_area() a.pack_start(gsm_grid, True, True, 0) gsm_grid.show() self.e_apn = self.Builder.get_object("e_apn") self.e_number = self.Builder.get_object("e_number") self.config.bind_to_widget("apn", self.e_apn, "text") self.config.bind_to_widget("number", self.e_number, "text") self.add_button("_Close", Gtk.ResponseType.CLOSE)
class Blueman(Gtk.Window): def __init__(self): super().__init__(title=_("Bluetooth Devices")) self._applet_sig = None self.Config = Config("org.blueman.general") self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") # bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/manager-main.ui") grid = self.Builder.get_object("grid") self.add(grid) self.set_name("BluemanManager") self.Plugins = PluginManager(ManagerPlugin, blueman.plugins.manager, self) self.Plugins.load_plugin() area = MessageArea() grid.attach(area, 0, 3, 1, 1) # Add margin for resize grip or it will overlap if self.get_has_resize_grip(): statusbar = self.Builder.get_object("statusbar") margin_right = statusbar.get_margin_right() statusbar.set_margin_right(margin_right + 10) def do_present(time): if self.props.visible: self.present_with_time(time) check_single_instance("blueman-manager", do_present) def on_window_delete(window, event): w, h = self.get_size() x, y = self.get_position() self.Config["window-properties"] = [w, h, x, y] Gtk.main_quit() def bt_status_changed(status): if not status: self.hide() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), lambda: Gtk.main_quit()) else: self.show() def on_applet_signal(_proxy, _sender, signal_name, params): if signal_name == 'BluetoothStatusChanged': status = params.unpack() bt_status_changed(status) def on_dbus_name_vanished(_connection, name): logging.info(name) if self._applet_sig is not None: self.Applet.disconnect(self._applet_sig) self._applet_sig = None self.hide() d = ErrorDialog( _("Connection to BlueZ failed"), _("Bluez daemon is not running, blueman-manager cannot continue.\n" "This probably means that there were no Bluetooth adapters detected " "or Bluetooth daemon was not started."), icon_name="blueman") d.run() d.destroy() # FIXME ui can handle BlueZ start/stop but we should inform user Gtk.main_quit() def on_dbus_name_appeared(_connection, name, owner): logging.info("%s %s" % (name, owner)) setup_icon_path() try: self.Applet = AppletService() except DBusProxyFailed: print("Blueman applet needs to be running") exit() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), lambda: Gtk.main_quit()) manager = bluez.Manager() try: manager.get_adapter(self.Config['last-adapter']) except bluez.errors.DBusNoSuchAdapterError: logging.error( 'Default adapter not found, trying first available.') try: manager.get_adapter(None) except bluez.errors.DBusNoSuchAdapterError: logging.error('No adapter(s) found, exiting') exit(1) self._applet_sig = self.Applet.connect('g-signal', on_applet_signal) self.connect("delete-event", on_window_delete) self.props.icon_name = "blueman" w, h, x, y = self.Config["window-properties"] if w and h: self.resize(w, h) if x and y: self.move(x, y) sw = self.Builder.get_object("scrollview") # Disable overlay scrolling if Gtk.get_minor_version() >= 16: sw.props.overlay_scrolling = False self.List = ManagerDeviceList(adapter=self.Config["last-adapter"], inst=self) self.List.show() sw.add(self.List) self.Toolbar = ManagerToolbar(self) self.Menu = ManagerMenu(self) self.Stats = ManagerStats(self) if self.List.is_valid_adapter(): self.List.display_known_devices(autoselect=True) self.List.connect("adapter-changed", self.on_adapter_changed) toolbar = self.Builder.get_object("toolbar") statusbar = self.Builder.get_object("statusbar") self.Config.bind_to_widget("show-toolbar", toolbar, "visible") self.Config.bind_to_widget("show-statusbar", statusbar, "visible") self.show() bluez.Manager.watch_name_owner(on_dbus_name_appeared, on_dbus_name_vanished) def on_adapter_changed(self, lst, adapter): if adapter is not None: self.List.display_known_devices(autoselect=True) def inquiry(self): def prop_changed(lst, adapter, key_value): key, value = key_value if key == "Discovering" and not value: prog.finalize() self.List.disconnect(s1) self.List.disconnect(s2) def on_progress(lst, frac): if abs(1.0 - frac) <= 0.00001: if not prog.started(): prog.start() else: prog.fraction(frac) prog = ManagerProgressbar(self, text=_("Searching")) prog.connect("cancelled", lambda x: self.List.stop_discovery()) try: self.List.discover_devices() except Exception as e: prog.finalize() MessageArea.show_message(*e_(e)) s1 = self.List.connect("discovery-progress", on_progress) s2 = self.List.connect("adapter-property-changed", prop_changed) def setup(self, device): command = "blueman-assistant --device=%s" % device['Address'] launch(command, None, False, "blueman", _("Bluetooth Assistant")) def bond(self, device): def error_handler(e): logging.exception(e) message = 'Pairing failed for:\n%s (%s)' % (device['Alias'], device['Address']) Notification('Bluetooth', message, icon_name="blueman").show() device.pair(error_handler=error_handler) def adapter_properties(self): launch("blueman-adapters", None, False, "blueman", _("Adapter Preferences")) def toggle_trust(self, device): device['Trusted'] = not device['Trusted'] def send(self, device, f=None): adapter = self.List.Adapter command = "blueman-sendto --source=%s --device=%s" % ( adapter["Address"], device['Address']) launch(command, None, False, "blueman", _("File Sender")) def remove(self, device): self.List.Adapter.remove_device(device)
class Network(ServicePlugin): __plugin_info__ = (_("Network"), "network-workgroup") def on_load(self, container): self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/services-network.ui") self.widget = self.Builder.get_object("network_frame") container.pack_start(self.widget, True, True, 0) self.interfaces = [] for iface in get_net_interfaces(): if iface != "lo" and iface != "pan1": print(iface) ip = inet_aton(get_net_address(iface)) mask = inet_aton(get_net_netmask(iface)) self.interfaces.append((iface, ip, mask, mask_ip4_address(ip, mask))) self.setup_network() try: self.ip_check() except: pass return (_("Network"), "network-workgroup") def on_enter(self): self.widget.props.visible = True def on_leave(self): self.widget.props.visible = False def on_apply(self): if self.on_query_apply_state(): dprint("network apply") m = Mechanism() nap_enable = self.Builder.get_object("nap-enable") if nap_enable.props.active: if self.Builder.get_object("r_dhcpd").props.active: stype = "DhcpdHandler" elif self.Builder.get_object("r_dnsmasq").props.active: stype = "DnsMasqHandler" elif self.Builder.get_object("r_udhcpd").props.active: stype = "UdhcpdHandler" net_ip = self.Builder.get_object("net_ip") try: m.EnableNetwork('(ayays)', inet_aton(net_ip.props.text), inet_aton("255.255.255.0"), stype) if not self.Config["nap-enable"]: self.Config["nap-enable"] = True except Exception as e: d = NetworkErrorDialog(e, parent=self.widget.get_toplevel()) d.run() d.destroy() return else: self.Config["nap-enable"] = False m.DisableNetwork() self.clear_options() def ip_check(self): e = self.Builder.get_object("net_ip") address = e.props.text try: if address.count(".") != 3: raise Exception a = inet_aton(address) except: e.props.secondary_icon_name = "dialog-error" e.props.secondary_icon_tooltip_text = _("Invalid IP address") raise a_netmask = inet_aton("255.255.255.0") a_masked = mask_ip4_address(a, a_netmask) for iface, ip, netmask, masked in self.interfaces: # print mask_ip4_address(a, netmask).encode("hex_codec"), masked.encode("hex_codec") if a == ip: e.props.secondary_icon_name = "dialog-error" e.props.secondary_icon_tooltip_text = _("IP address conflicts with interface %s which has the same address" % iface) raise Exception elif mask_ip4_address(a, netmask) == masked: e.props.secondary_icon_name = "dialog-warning" e.props.secondary_icon_tooltip_text = _("IP address overlaps with subnet of interface" " %s, which has the following configuration %s/%s\nThis may cause incorrect network behavior" % (iface, inet_ntoa(ip), inet_ntoa(netmask))) return e.props.secondary_icon_name = None def on_query_apply_state(self): changed = False opts = self.get_options() if not opts: return False else: if "ip" in opts: try: self.ip_check() except Exception as e: print(e) return -1 return True def setup_network(self): self.Config = Config("org.blueman.network") nap_enable = self.Builder.get_object("nap-enable") r_dnsmasq = self.Builder.get_object("r_dnsmasq") r_dhcpd = self.Builder.get_object("r_dhcpd") r_udhcpd = self.Builder.get_object("r_udhcpd") net_ip = self.Builder.get_object("net_ip") rb_nm = self.Builder.get_object("rb_nm") rb_blueman = self.Builder.get_object("rb_blueman") rb_dun_nm = self.Builder.get_object("rb_dun_nm") rb_dun_blueman = self.Builder.get_object("rb_dun_blueman") nap_frame = self.Builder.get_object("nap_frame") warning = self.Builder.get_object("warning") rb_blueman.props.active = self.Config["dhcp-client"] if not self.Config["nap-enable"]: nap_frame.props.sensitive = False nc = NetConf.get_default() if nc.ip4_address is not None: net_ip.props.text = inet_ntoa(nc.ip4_address) nap_enable.props.active = True else: net_ip.props.text = "10.%d.%d.1" % (randint(0, 255), randint(0, 255)) if nc.get_dhcp_handler() is None: nap_frame.props.sensitive = False nap_enable.props.active = False r_dnsmasq.props.active = True self.Config["nap-enable"] = False if nc.get_dhcp_handler() == DnsMasqHandler: r_dnsmasq.props.active = True elif nc.get_dhcp_handler() == DhcpdHandler: r_dhcpd.props.active = True elif nc.get_dhcp_handler() == UdhcpdHandler: r_udhcpd.props.active = True if not have("dnsmasq") and not have("dhcpd3") and not have("dhcpd") and not have("udhcpd"): nap_frame.props.sensitive = False warning.props.visible = True warning.props.sensitive = True nap_enable.props.sensitive = False self.Config["nap-enable"] = False if not have("dnsmasq"): r_dnsmasq.props.sensitive = False r_dnsmasq.props.active = False if not have("dhcpd3") and not have("dhcpd"): r_dhcpd.props.sensitive = False r_dhcpd.props.active = False if not have("udhcpd"): r_udhcpd.props.sensitive = False r_udhcpd.props.active = False r_dnsmasq.connect("toggled", lambda x: self.option_changed_notify("dnsmasq")) r_udhcpd.connect("toggled", lambda x: self.option_changed_notify("udhcpd")) net_ip.connect("changed", lambda x: self.option_changed_notify("ip", False)) nap_enable.connect("toggled", lambda x: self.option_changed_notify("nap_enable")) self.Config.bind_to_widget("nap-enable", nap_enable, "active", Gio.SettingsBindFlags.GET) nap_enable.bind_property("active", nap_frame, "sensitive", 0) applet = AppletService() avail_plugins = applet.QueryAvailablePlugins() active_plugins = applet.QueryPlugins() def dun_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "PPPSupport", False) applet.SetPluginConfig('(sb)', "NMDUNSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMDUNSupport", False) applet.SetPluginConfig('(sb)', "PPPSupport", True) def pan_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "DhcpClient", False) applet.SetPluginConfig('(sb)', "NMPANSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMPANSupport", False) applet.SetPluginConfig('(sb)', "DhcpClient", True) if "PPPSupport" in active_plugins: rb_dun_blueman.props.active = True if "NMDUNSupport" in avail_plugins: rb_dun_nm.props.sensitive = True else: rb_dun_nm.props.sensitive = False rb_dun_nm.props.tooltip_text = _("Not currently supported with this setup") if "NMPANSupport" in avail_plugins: rb_nm.props.sensitive = True else: rb_nm.props.sensitive = False rb_nm.props.tooltip_text = _("Not currently supported with this setup") if "NMPANSupport" in active_plugins: rb_nm.props.active = True if "NMDUNSupport" in active_plugins: rb_dun_nm.props.active = True rb_nm.connect("toggled", pan_support_toggled, "nm") rb_blueman.connect("toggled", pan_support_toggled, "blueman") rb_dun_nm.connect("toggled", dun_support_toggled, "nm") rb_dun_blueman.connect("toggled", dun_support_toggled, "blueman")
class Network(ServicePlugin): __plugin_info__ = (_("Network"), "network-workgroup") def on_load(self, container): self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/services-network.ui") self.widget = self.Builder.get_object("network_frame") container.pack_start(self.widget, True, True, 0) self.interfaces = [] for iface in get_net_interfaces(): if iface != "lo" and iface != "pan1": logging.info(iface) ip = inet_aton(get_net_address(iface)) mask = inet_aton(get_net_netmask(iface)) self.interfaces.append((iface, ip, mask, mask_ip4_address(ip, mask))) self.setup_network() try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) return _("Network"), "network-workgroup" def on_enter(self): self.widget.props.visible = True def on_leave(self): self.widget.props.visible = False def on_apply(self): if self.on_query_apply_state(): logging.info("network apply") m = Mechanism() nap_enable = self.Builder.get_object("nap-enable") if nap_enable.props.active: if self.Builder.get_object("r_dhcpd").props.active: stype = "DhcpdHandler" elif self.Builder.get_object("r_dnsmasq").props.active: stype = "DnsMasqHandler" elif self.Builder.get_object("r_udhcpd").props.active: stype = "UdhcpdHandler" net_ip = self.Builder.get_object("net_ip") try: m.EnableNetwork('(ayays)', inet_aton(net_ip.props.text), inet_aton("255.255.255.0"), stype) if not self.Config["nap-enable"]: self.Config["nap-enable"] = True except Exception as e: d = ErrorDialog("<b>Failed to apply network settings</b>", excp=e, parent=self.widget.get_toplevel()) d.run() d.destroy() return else: self.Config["nap-enable"] = False m.DisableNetwork() self.clear_options() def ip_check(self): entry = self.Builder.get_object("net_ip") try: ipaddr = ipaddress.IPv4Address(entry.props.text) a = inet_aton(str(ipaddr)) except ipaddress.AddressValueError: entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = _("Invalid IP address") raise for iface, ip, netmask, masked in self.interfaces: if a == ip: error_message = _("IP address conflicts with interface %s which has the same address" % iface) tooltip_text = error_message entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = tooltip_text raise ValueError(error_message) elif mask_ip4_address(a, netmask) == masked: tooltip_text = _( "IP address overlaps with subnet of interface %s, which has the following configuration %s/%s\n" "This may cause incorrect network behavior" % (iface, inet_ntoa(ip), inet_ntoa(netmask))) entry.props.secondary_icon_name = "dialog-warning" entry.props.secondary_icon_tooltip_text = tooltip_text return entry.props.secondary_icon_name = None def on_query_apply_state(self): opts = self.get_options() if not opts: return False if "ip" in opts: try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) return -1 return True def setup_network(self): self.Config = Config("org.blueman.network") nap_enable = self.Builder.get_object("nap-enable") r_dnsmasq = self.Builder.get_object("r_dnsmasq") r_dhcpd = self.Builder.get_object("r_dhcpd") r_udhcpd = self.Builder.get_object("r_udhcpd") net_ip = self.Builder.get_object("net_ip") rb_nm = self.Builder.get_object("rb_nm") rb_blueman = self.Builder.get_object("rb_blueman") rb_dun_nm = self.Builder.get_object("rb_dun_nm") rb_dun_blueman = self.Builder.get_object("rb_dun_blueman") nap_frame = self.Builder.get_object("nap_frame") warning = self.Builder.get_object("warning") if not self.Config["nap-enable"]: nap_frame.props.sensitive = False nc = NetConf.get_default() if nc.ip4_address is not None: net_ip.props.text = inet_ntoa(nc.ip4_address) nap_enable.props.active = True else: net_ip.props.text = "10.%d.%d.1" % (randint(0, 255), randint(0, 255)) if nc.get_dhcp_handler() is None: nap_frame.props.sensitive = False nap_enable.props.active = False r_dnsmasq.props.active = True self.Config["nap-enable"] = False have_dhcpd = have("dhcpd3") or have("dhcpd") have_dnsmasq = have("dnsmasq") have_udhcpd = have("udhcpd") if nc.get_dhcp_handler() == DnsMasqHandler and have_dnsmasq: r_dnsmasq.props.active = True elif nc.get_dhcp_handler() == DhcpdHandler and have_dhcpd: r_dhcpd.props.active = True elif nc.get_dhcp_handler() == UdhcpdHandler and have_udhcpd: r_udhcpd.props.active = True else: r_dnsmasq.props.active = True if not have_dnsmasq and not have_dhcpd and not have_udhcpd: nap_frame.props.sensitive = False warning.props.visible = True warning.props.sensitive = True nap_enable.props.sensitive = False self.Config["nap-enable"] = False if not have_dnsmasq: r_dnsmasq.props.sensitive = False r_dnsmasq.props.active = False if not have_dhcpd: r_dhcpd.props.sensitive = False r_dhcpd.props.active = False if not have_udhcpd: r_udhcpd.props.sensitive = False r_udhcpd.props.active = False r_dnsmasq.connect("toggled", lambda x: self.option_changed_notify("dnsmasq")) r_dhcpd.connect("toggled", lambda x: self.option_changed_notify("dhcpd")) r_udhcpd.connect("toggled", lambda x: self.option_changed_notify("udhcpd")) net_ip.connect("changed", lambda x: self.option_changed_notify("ip", False)) nap_enable.connect("toggled", lambda x: self.option_changed_notify("nap_enable")) self.Config.bind_to_widget("nap-enable", nap_enable, "active", Gio.SettingsBindFlags.GET) nap_enable.bind_property("active", nap_frame, "sensitive", 0) applet = AppletService() avail_plugins = applet.QueryAvailablePlugins() active_plugins = applet.QueryPlugins() def dun_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "PPPSupport", False) applet.SetPluginConfig('(sb)', "NMDUNSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMDUNSupport", False) applet.SetPluginConfig('(sb)', "PPPSupport", True) def pan_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "DhcpClient", False) applet.SetPluginConfig('(sb)', "NMPANSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMPANSupport", False) applet.SetPluginConfig('(sb)', "DhcpClient", True) if "PPPSupport" in active_plugins: rb_dun_blueman.props.active = True if "NMDUNSupport" in avail_plugins: rb_dun_nm.props.sensitive = True else: rb_dun_nm.props.sensitive = False rb_dun_nm.props.tooltip_text = _("Not currently supported with this setup") if "DhcpClient" in active_plugins: rb_blueman.props.active = True if "NMPANSupport" in avail_plugins: rb_nm.props.sensitive = True else: rb_nm.props.sensitive = False rb_nm.props.tooltip_text = _("Not currently supported with this setup") if "NMPANSupport" in active_plugins: rb_nm.props.active = True if "NMDUNSupport" in active_plugins: rb_dun_nm.props.active = True rb_nm.connect("toggled", pan_support_toggled, "nm") rb_blueman.connect("toggled", pan_support_toggled, "blueman") rb_dun_nm.connect("toggled", dun_support_toggled, "nm") rb_dun_blueman.connect("toggled", dun_support_toggled, "blueman")
class Blueman(Gtk.Window): def __init__(self): super(Blueman, self).__init__(title=_("Bluetooth Devices")) self._applet_sig = None self.Config = Config("org.blueman.general") self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/manager-main.ui") grid = self.Builder.get_object("grid") self.add(grid) self.set_name("BluemanManager") self.Plugins = PluginManager(ManagerPlugin, blueman.plugins.manager, self) self.Plugins.load_plugin() area = MessageArea() grid.attach(area, 0, 3, 1, 1) # Add margin for resize grip or it will overlap if self.get_has_resize_grip(): statusbar = self.Builder.get_object("statusbar") margin_right = statusbar.get_margin_right() statusbar.set_margin_right(margin_right + 10) def do_present(time): if self.props.visible: self.present_with_time(time) check_single_instance("blueman-manager", do_present) def on_window_delete(window, event): w, h = self.get_size() x, y = self.get_position() self.Config["window-properties"] = [w, h, x, y] Gtk.main_quit() def bt_status_changed(status): if not status: self.hide() check_bluetooth_status(_("Bluetooth needs to be turned on for the device manager to function"), lambda: Gtk.main_quit()) else: self.show() def on_applet_signal(_proxy, _sender, signal_name, params): if signal_name == 'BluetoothStatusChanged': status = params.unpack() bt_status_changed(status) def on_dbus_name_vanished(_connection, name): logging.info(name) if self._applet_sig is not None: self.Applet.disconnect(self._applet_sig) self._applet_sig = None self.hide() d = ErrorDialog( _("Connection to BlueZ failed"), _("Bluez daemon is not running, blueman-manager cannot continue.\n" "This probably means that there were no Bluetooth adapters detected " "or Bluetooth daemon was not started."), icon_name="blueman") d.run() d.destroy() # FIXME ui can handle BlueZ start/stop but we should inform user Gtk.main_quit() def on_dbus_name_appeared(_connection, name, owner): logging.info("%s %s" % (name, owner)) setup_icon_path() try: self.Applet = AppletService() except DBusProxyFailed: print("Blueman applet needs to be running") exit() if 'PowerManager' in self.Applet.QueryPlugins(): if not self.Applet.get_bluetooth_status(): bt_status_changed(False) self._applet_sig = self.Applet.connect('g-signal', on_applet_signal) self.connect("delete-event", on_window_delete) self.props.icon_name = "blueman" w, h, x, y = self.Config["window-properties"] if w and h: self.resize(w, h) if x and y: self.move(x, y) sw = self.Builder.get_object("scrollview") # Disable overlay scrolling if Gtk.get_minor_version() >= 16: sw.props.overlay_scrolling = False self.List = ManagerDeviceList(adapter=self.Config["last-adapter"], inst=self) self.List.show() sw.add(self.List) self.Toolbar = ManagerToolbar(self) self.Menu = ManagerMenu(self) self.Stats = ManagerStats(self) if self.List.is_valid_adapter(): self.List.display_known_devices(autoselect=True) self.List.connect("adapter-changed", self.on_adapter_changed) toolbar = self.Builder.get_object("toolbar") statusbar = self.Builder.get_object("statusbar") self.Config.bind_to_widget("show-toolbar", toolbar, "visible") self.Config.bind_to_widget("show-statusbar", statusbar, "visible") self.show() bluez.Manager.watch_name_owner(on_dbus_name_appeared, on_dbus_name_vanished) def on_adapter_changed(self, lst, adapter): if adapter is not None: self.List.display_known_devices(autoselect=True) def inquiry(self): def prop_changed(lst, adapter, key_value): key, value = key_value if key == "Discovering" and not value: prog.finalize() self.List.disconnect(s1) self.List.disconnect(s2) def on_progress(lst, frac): if abs(1.0 - frac) <= 0.00001: if not prog.started(): prog.start() else: prog.fraction(frac) prog = ManagerProgressbar(self, text=_("Searching")) prog.connect("cancelled", lambda x: self.List.stop_discovery()) try: self.List.discover_devices() except Exception as e: prog.finalize() MessageArea.show_message(*e_(e)) s1 = self.List.connect("discovery-progress", on_progress) s2 = self.List.connect("adapter-property-changed", prop_changed) def setup(self, device): command = "blueman-assistant --device=%s" % device['Address'] launch(command, None, False, "blueman", _("Bluetooth Assistant")) def bond(self, device): def error_handler(e): logging.exception(e) message = 'Pairing failed for:\n%s (%s)' % (device['Alias'], device['Address']) Notification('Bluetooth', message, icon_name="blueman").show() device.pair(error_handler=error_handler) def adapter_properties(self): launch("blueman-adapters", None, False, "blueman", _("Adapter Preferences")) def toggle_trust(self, device): device['Trusted'] = not device['Trusted'] def send(self, device, f=None): adapter = self.List.Adapter command = "blueman-sendto --source=%s --device=%s" % (adapter["Address"], device['Address']) launch(command, None, False, "blueman", _("File Sender")) def remove(self, device): self.List.Adapter.remove_device(device)
class Blueman(Gtk.Application): def __init__(self) -> None: super().__init__(application_id="org.blueman.Manager") def do_quit(_: object) -> bool: self.quit() return False s = GLib.unix_signal_source_new(signal.SIGINT) s.set_callback(do_quit) s.attach() window: Optional[Gtk.ApplicationWindow] def do_startup(self) -> None: def doquit(_a: Gio.SimpleAction, _param: None) -> None: self.quit() Gtk.Application.do_startup(self) self.window = None self.Config = Config("org.blueman.general") quit_action = Gio.SimpleAction.new("Quit", None) quit_action.connect("activate", doquit) self.set_accels_for_action("app.Quit", ["<Ctrl>q", "<Ctrl>w"]) self.add_action(quit_action) def do_activate(self) -> None: if not self.window: self.window = Gtk.ApplicationWindow(application=self, name="BluemanManager", icon_name="blueman", title=_("Bluetooth Devices")) w, h, x, y = self.Config["window-properties"] if w and h: self.window.resize(w, h) if x and y: self.window.move(x, y) # Connect to configure event to store new window position and size self.window.connect("configure-event", self._on_configure) self.builder = Builder("manager-main.ui") box = self.builder.get_widget("box", Gtk.Box) self.window.add(box) grid = self.builder.get_widget("grid", Gtk.Grid) toolbar = self.builder.get_widget("toolbar", Gtk.Toolbar) statusbar = self.builder.get_widget("statusbar", Gtk.Box) self.Plugins = PluginManager(ManagerPlugin, blueman.plugins.manager, self) self.Plugins.load_plugin() area = MessageArea() grid.attach(area, 0, 1, 1, 1) self._applethandlerid: Optional[int] = None # Add margin for resize grip or it will overlap if self.window.get_has_resize_grip(): margin_right = statusbar.get_margin_right() statusbar.set_margin_right(margin_right + 10) def bt_status_changed(status: bool) -> None: assert self.window is not None if not status: self.window.hide() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), self.quit) else: self.window.show() def on_applet_signal(_proxy: AppletService, _sender: str, signal_name: str, params: GLib.Variant) -> None: if signal_name == 'BluetoothStatusChanged': status = params.unpack() bt_status_changed(status) def on_dbus_name_vanished(_connection: Gio.DBusConnection, name: str) -> None: logging.info(name) if self._applethandlerid: self.Applet.disconnect(self._applethandlerid) self._applethandlerid = None if self.window is not None: self.window.hide() d = ErrorDialog( _("Connection to BlueZ failed"), _("Bluez daemon is not running, blueman-manager cannot continue.\n" "This probably means that there were no Bluetooth adapters detected " "or Bluetooth daemon was not started."), icon_name="blueman") d.run() d.destroy() # FIXME ui can handle BlueZ start/stop but we should inform user self.quit() def on_dbus_name_appeared(_connection: Gio.DBusConnection, name: str, owner: str) -> None: logging.info(f"{name} {owner}") setup_icon_path() try: self.Applet = AppletService() except DBusProxyFailed: print("Blueman applet needs to be running") bmexit() check_bluetooth_status( _("Bluetooth needs to be turned on for the device manager to function" ), lambda: self.quit()) manager = Manager() try: manager.get_adapter(self.Config['last-adapter']) except DBusNoSuchAdapterError: logging.error( 'Default adapter not found, trying first available.') try: manager.get_adapter(None) except DBusNoSuchAdapterError: logging.error('No adapter(s) found, exiting') bmexit() self._applethandlerid = self.Applet.connect( 'g-signal', on_applet_signal) sw = self.builder.get_widget("scrollview", Gtk.ScrolledWindow) # Disable overlay scrolling if Gtk.get_minor_version() >= 16: sw.props.overlay_scrolling = False self.List = ManagerDeviceList( adapter=self.Config["last-adapter"], inst=self) self.List.show() sw.add(self.List) self.Toolbar = ManagerToolbar(self) self.Menu = ManagerMenu(self) self.Stats = ManagerStats(self) if self.List.is_valid_adapter(): self.List.populate_devices() self.List.connect("adapter-changed", self.on_adapter_changed) self.Config.bind_to_widget("show-toolbar", toolbar, "visible") self.Config.bind_to_widget("show-statusbar", statusbar, "visible") Manager.watch_name_owner(on_dbus_name_appeared, on_dbus_name_vanished) self.window.present_with_time(Gtk.get_current_event_time()) def _on_configure(self, _window: Gtk.ApplicationWindow, event: Gdk.EventConfigure) -> bool: width, height, x, y = self.Config["window-properties"] if event.x != x or event.y != y or event.width != width or event.height != height: self.Config["window-properties"] = [ event.width, event.height, event.x, event.y ] return False def on_adapter_changed(self, lst: ManagerDeviceList, adapter: str) -> None: if adapter is not None: self.List.populate_devices() def inquiry(self) -> None: def prop_changed(_lst: ManagerDeviceList, _adapter: Adapter, key_value: Tuple[str, Any]) -> None: key, value = key_value if key == "Discovering" and not value: prog.finalize() self.List.disconnect(s1) self.List.disconnect(s2) def on_progress(_lst: ManagerDeviceList, frac: float) -> None: if abs(1.0 - frac) <= 0.00001: if not prog.started(): prog.start() else: prog.fraction(frac) prog = ManagerProgressbar(self, text=_("Searching")) prog.connect("cancelled", lambda x: self.List.stop_discovery()) def on_error(e: Exception) -> None: prog.finalize() MessageArea.show_message(*e_(e)) self.List.discover_devices(error_handler=on_error) s1 = self.List.connect("discovery-progress", on_progress) s2 = self.List.connect("adapter-property-changed", prop_changed) @staticmethod def bond(device: Device) -> None: def error_handler(e: Exception) -> None: logging.exception(e) message = f"Pairing failed for:\n{device['Alias']} ({device['Address']})" Notification('Bluetooth', message, icon_name="blueman").show() device.pair(error_handler=error_handler) @staticmethod def adapter_properties() -> None: launch("blueman-adapters", name=_("Adapter Preferences")) @staticmethod def toggle_trust(device: Device) -> None: device['Trusted'] = not device['Trusted'] @staticmethod def toggle_blocked(device: Device) -> None: device['Blocked'] = not device['Blocked'] def send(self, device: Device) -> None: adapter = self.List.Adapter assert adapter command = f"blueman-sendto --source={adapter['Address']} --device={device['Address']}" launch(command, name=_("File Sender")) def remove(self, device: Device) -> None: assert self.List.Adapter self.List.Adapter.remove_device(device)
class Blueman(Gtk.Window): def __init__(self): super().__init__(title=_("Bluetooth Devices")) self.Config = Config("org.blueman.general") self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/manager-main.ui") grid = self.Builder.get_object("grid") self.add(grid) self.set_name("BluemanManager") self.Plugins = PluginManager(ManagerPlugin, blueman.plugins.manager, self) self.Plugins.load_plugin() area = MessageArea() grid.attach(area, 0, 3, 1, 1) self._applethandlerid: Optional[int] = None # Add margin for resize grip or it will overlap if self.get_has_resize_grip(): statusbar = self.Builder.get_object("statusbar") margin_right = statusbar.get_margin_right() statusbar.set_margin_right(margin_right + 10) def do_present(time): if self.props.visible: self.present_with_time(time) check_single_instance("blueman-manager", do_present) def on_window_delete(window, event): w, h = self.get_size() x, y = self.get_position() self.Config["window-properties"] = [w, h, x, y] Gtk.main_quit() setup_icon_path() try: self.Applet = AppletService() except DBusProxyFailed: print("Blueman applet needs to be running") exit() manager = Manager() try: manager.get_adapter(self.Config['last-adapter']) except DBusNoSuchAdapterError: logging.error('Default adapter not found, trying first available.') try: manager.get_adapter(None) except DBusNoSuchAdapterError: logging.error('No adapter(s) found') self.connect("delete-event", on_window_delete) self.props.icon_name = "blueman" w, h, x, y = self.Config["window-properties"] if w and h: self.resize(w, h) if x and y: self.move(x, y) sw = self.Builder.get_object("scrollview") # Disable overlay scrolling if Gtk.get_minor_version() >= 16: sw.props.overlay_scrolling = False self.List = ManagerDeviceList(adapter=self.Config["last-adapter"], inst=self) self.List.show() sw.add(self.List) self.Toolbar = ManagerToolbar(self) self.Menu = ManagerMenu(self) self.Stats = ManagerStats(self) if self.List.is_valid_adapter(): self.List.display_known_devices(autoselect=True) self.List.connect("adapter-changed", self.on_adapter_changed) toolbar = self.Builder.get_object("toolbar") statusbar = self.Builder.get_object("statusbar") self.Config.bind_to_widget("show-toolbar", toolbar, "visible") self.Config.bind_to_widget("show-statusbar", statusbar, "visible") self.show() def on_adapter_changed(self, lst, adapter): if adapter is not None: self.List.display_known_devices(autoselect=True) def inquiry(self): def prop_changed(lst, adapter, key_value): key, value = key_value if key == "Discovering" and not value: prog.finalize() # FIXME for some reason the signal handler is None if proghandler is not None: prog.disconnect(proghandler) self.List.disconnect(s1) self.List.disconnect(s2) def on_progress(lst, frac): if abs(1.0 - frac) <= 0.00001: if not prog.started(): prog.start() else: prog.fraction(frac) prog = ManagerProgressbar(self, text=_("Searching")) proghandler = prog.connect("cancelled", lambda x: self.List.stop_discovery()) try: self.List.discover_devices() except Exception as e: prog.finalize() MessageArea.show_message(*e_(e)) s1 = self.List.connect("discovery-progress", on_progress) s2 = self.List.connect("adapter-property-changed", prop_changed) @staticmethod def setup(device): command = "blueman-assistant --device=%s" % device['Address'] launch(command, None, False, "blueman", _("Bluetooth Assistant")) @staticmethod def bond(device): def error_handler(e): logging.exception(e) message = 'Pairing failed for:\n%s (%s)' % (device['Alias'], device['Address']) Notification('Bluetooth', message, icon_name="blueman").show() device.pair(error_handler=error_handler) @staticmethod def adapter_properties(): launch("blueman-adapters", None, False, "blueman", _("Adapter Preferences")) @staticmethod def toggle_trust(device): device['Trusted'] = not device['Trusted'] def send(self, device, f=None): adapter = self.List.Adapter assert adapter command = "blueman-sendto --source=%s --device=%s" % ( adapter["Address"], device['Address']) launch(command, None, False, "blueman", _("File Sender")) def remove(self, device): assert self.List.Adapter self.List.Adapter.remove_device(device)
class Network(ServicePlugin): __plugin_info__ = (_("Network"), "network-workgroup") def on_load(self, container): self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") self.Builder.add_from_file(UI_PATH + "/services-network.ui") self.widget = self.Builder.get_object("network") container.pack_start(self.widget, True, True, 0) self.interfaces = [] for iface in get_net_interfaces(): if iface != "lo" and iface != "pan1": print(iface) ip = inet_aton(get_net_address(iface)) mask = inet_aton(get_net_netmask(iface)) self.interfaces.append( (iface, ip, mask, mask_ip4_address(ip, mask))) self.setup_network() try: self.ip_check() except: pass return (_("Network"), "network-workgroup") def on_enter(self): self.widget.props.visible = True def on_leave(self): self.widget.props.visible = False def on_apply(self): if self.on_query_apply_state() == True: dprint("network apply") m = Mechanism() nap_enable = self.Builder.get_object("nap-enable") if nap_enable.props.active: r_dnsmasq = self.Builder.get_object("r_dnsmasq") if r_dnsmasq.props.active: stype = "DnsMasqHandler" else: stype = "DhcpdHandler" net_ip = self.Builder.get_object("net_ip") net_nat = self.Builder.get_object("net_nat") try: m.EnableNetwork(inet_aton(net_ip.props.text), inet_aton("255.255.255.0"), stype) except Exception as e: d = NetworkErrorDialog(e) d.run() d.destroy() return else: m.DisableNetwork() self.clear_options() def ip_check(self): e = self.Builder.get_object("net_ip") address = e.props.text try: if address.count(".") != 3: raise Exception a = inet_aton(address) except: e.props.secondary_icon_name = "dialog-error" e.props.secondary_icon_tooltip_text = _("Invalid IP address") raise a_netmask = inet_aton("255.255.255.0") a_masked = mask_ip4_address(a, a_netmask) for iface, ip, netmask, masked in self.interfaces: # print mask_ip4_address(a, netmask).encode("hex_codec"), masked.encode("hex_codec") if a == ip: e.props.secondary_icon_name = "dialog-error" e.props.secondary_icon_tooltip_text = _( "IP address conflicts with interface %s which has the same address" % iface) raise Exception elif mask_ip4_address(a, netmask) == masked: e.props.secondary_icon_name = "dialog-warning" e.props.secondary_icon_tooltip_text = _( "IP address overlaps with subnet of interface" " %s, which has the following configuration %s/%s\nThis may cause incorrect network behavior" % (iface, inet_ntoa(ip), inet_ntoa(netmask))) return e.props.secondary_icon_name = None def on_query_apply_state(self): changed = False opts = self.get_options() if opts == []: return False else: if "ip" in opts: try: self.ip_check() except Exception as e: print(e) return -1 return True def setup_network(self): self.Config = Config("org.blueman.network") gn_enable = self.Builder.get_object("gn-enable") # latest bluez does not support GN, apparently gn_enable.props.visible = False nap_enable = self.Builder.get_object("nap-enable") r_dnsmasq = self.Builder.get_object("r_dnsmasq") r_dhcpd = self.Builder.get_object("r_dhcpd") net_ip = self.Builder.get_object("net_ip") net_nat = self.Builder.get_object("net_nat") rb_nm = self.Builder.get_object("rb_nm") rb_blueman = self.Builder.get_object("rb_blueman") rb_dun_nm = self.Builder.get_object("rb_dun_nm") rb_dun_blueman = self.Builder.get_object("rb_dun_blueman") nap_frame = self.Builder.get_object("nap_frame") warning = self.Builder.get_object("warning") rb_blueman.props.active = self.Config["dhcp-client"] if not self.Config["nap-enable"]: nap_frame.props.sensitive = False nc = NetConf.get_default() if nc.ip4_address != None: net_ip.props.text = inet_ntoa(nc.ip4_address) else: net_ip.props.text = "10.%d.%d.1" % (randint(0, 255), randint( 0, 255)) #if ns["masq"] != 0: # net_nat.props.active = ns["masq"] if nc.get_dhcp_handler() == None: nap_frame.props.sensitive = False nap_enable.props.active = False else: if nc.get_dhcp_handler() == DnsMasqHandler: r_dnsmasq.props.active = True else: r_dhcpd.props.active = True if not have("dnsmasq") and not have("dhcpd3") and not have("dhcpd"): nap_frame.props.sensitive = False warning.props.visible = True warning.props.sensitive = True nap_enable.props.sensitive = False if not have("dnsmasq"): r_dnsmasq.props.sensitive = False r_dnsmasq.props.active = False r_dhcpd.props.active = True if not have("dhcpd3") and not have("dhcpd"): r_dhcpd.props.sensitive = False r_dhcpd.props.active = False r_dnsmasq.props.active = True r_dnsmasq.connect("toggled", lambda x: self.option_changed_notify("dnsmasq")) net_ip.connect("changed", lambda x: self.option_changed_notify("ip", False)) self.Config.bind_to_widget("nat", net_nat, "active") self.Config.bind_to_widget("gn-enable", gn_enable, "active") self.Config.bind_to_widget("nap-enable", nap_frame, "sensitive") self.Config.bind_to_widget("nap-enable", nap_enable, "active") applet = AppletService() avail_plugins = applet.QueryAvailablePlugins() active_plugins = applet.QueryPlugins() def dun_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig("PPPSupport", False) applet.SetPluginConfig("NMDUNSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig("NMDUNSupport", False) applet.SetPluginConfig("PPPSupport", True) def pan_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig("DhcpClient", False) applet.SetPluginConfig("NMPANSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig("NMPANSupport", False) applet.SetPluginConfig("DhcpClient", True) if "PPPSupport" in active_plugins: rb_dun_blueman.props.active = True if "NMDUNSupport" in avail_plugins: rb_dun_nm.props.sensitive = True else: rb_dun_nm.props.sensitive = False rb_dun_nm.props.tooltip_text = _( "Not currently supported with this setup") if "NMPANSupport" in avail_plugins: rb_nm.props.sensitive = True else: rb_nm.props.sensitive = False rb_nm.props.tooltip_text = _( "Not currently supported with this setup") if "NMPANSupport" in active_plugins: rb_nm.props.active = True if "NMDUNSupport" in active_plugins: rb_dun_nm.props.active = True rb_nm.connect("toggled", pan_support_toggled, "nm") rb_blueman.connect("toggled", pan_support_toggled, "blueman") rb_dun_nm.connect("toggled", dun_support_toggled, "nm") rb_dun_blueman.connect("toggled", dun_support_toggled, "blueman")
class Network(ServicePlugin): __plugin_info__ = (_("Network"), "network-workgroup") def on_load(self, container: Gtk.Box) -> None: self._builder = Builder("services-network.ui") self.widget = self._builder.get_widget("network_frame", Gtk.Widget) container.pack_start(self.widget, True, True, 0) self.interfaces: List[Tuple[str, Union[ipaddress.IPv4Interface, ipaddress.IPv6Interface]]] = [] netifs = get_local_interfaces() for iface in netifs: if iface != "lo" and iface != "pan1": logging.info(iface) ipiface = ipaddress.ip_interface('/'.join( cast(Tuple[str, str], netifs[iface]))) self.interfaces.append((iface, ipiface)) self.setup_network() try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) def on_enter(self) -> None: self.widget.props.visible = True def on_leave(self) -> None: self.widget.props.visible = False def on_apply(self) -> None: if self.on_query_apply_state(): logging.info("network apply") m = Mechanism() nap_enable = self._builder.get_widget("nap-enable", Gtk.CheckButton) if nap_enable.props.active: if self._builder.get_widget("r_dhcpd", Gtk.RadioButton).props.active: stype = "DhcpdHandler" elif self._builder.get_widget("r_dnsmasq", Gtk.RadioButton).props.active: stype = "DnsMasqHandler" elif self._builder.get_widget("r_udhcpd", Gtk.RadioButton).props.active: stype = "UdhcpdHandler" net_ip = self._builder.get_widget("net_ip", Gtk.Entry) try: m.EnableNetwork('(sss)', net_ip.props.text, "255.255.255.0", stype) if not self.Config["nap-enable"]: self.Config["nap-enable"] = True except Exception as e: parent = self.widget.get_toplevel() assert isinstance(parent, Gtk.Container) d = ErrorDialog("<b>Failed to apply network settings</b>", excp=e, parent=parent) d.run() d.destroy() return else: self.Config["nap-enable"] = False m.DisableNetwork() self.clear_options() def ip_check(self) -> None: entry = self._builder.get_widget("net_ip", Gtk.Entry) try: nap_ipiface = ipaddress.ip_interface('/'.join( (entry.props.text, '255.255.255.0'))) except (ValueError, ipaddress.AddressValueError): entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = _("Invalid IP address") raise for iface, ipiface in self.interfaces: if nap_ipiface.ip == ipiface.ip: error_message = _( "IP address conflicts with interface %s which has the same address" % iface) tooltip_text = error_message entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = tooltip_text raise ValueError(error_message) elif nap_ipiface.network == ipiface.network: tooltip_text = _( "IP address overlaps with subnet of interface %s, which has the following configuration %s/%s\n" "This may cause incorrect network behavior" % (iface, ipiface.ip, ipiface.netmask)) entry.props.secondary_icon_name = "dialog-warning" entry.props.secondary_icon_tooltip_text = tooltip_text return entry.props.secondary_icon_name = None def on_query_apply_state(self) -> Union[bool, "Literal[-1]"]: opts = self.get_options() if not opts: return False if "ip" in opts: try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) return -1 return True def setup_network(self) -> None: self.Config = Config("org.blueman.network") nap_enable = self._builder.get_widget("nap-enable", Gtk.CheckButton) r_dnsmasq = self._builder.get_widget("r_dnsmasq", Gtk.RadioButton) r_dhcpd = self._builder.get_widget("r_dhcpd", Gtk.RadioButton) r_udhcpd = self._builder.get_widget("r_udhcpd", Gtk.RadioButton) net_ip = self._builder.get_widget("net_ip", Gtk.Entry) rb_nm = self._builder.get_widget("rb_nm", Gtk.RadioButton) rb_blueman = self._builder.get_widget("rb_blueman", Gtk.RadioButton) rb_dun_nm = self._builder.get_widget("rb_dun_nm", Gtk.RadioButton) rb_dun_blueman = self._builder.get_widget("rb_dun_blueman", Gtk.RadioButton) nap_frame = self._builder.get_widget("nap_frame", Gtk.Frame) warning = self._builder.get_widget("warning", Gtk.Box) if not self.Config["nap-enable"]: nap_frame.props.sensitive = False nc = NetConf.get_default() if nc.ip4_address is not None: # previously we stored a bytearray, ipaddress module reads both net_ip.props.text = str(ipaddress.ip_address(nc.ip4_address)) nap_enable.props.active = True else: net_ip.props.text = "10.%d.%d.1" % (randint(0, 255), randint( 0, 255)) if nc.get_dhcp_handler() is None: nap_frame.props.sensitive = False nap_enable.props.active = False r_dnsmasq.props.active = True self.Config["nap-enable"] = False have_dhcpd = have("dhcpd3") or have("dhcpd") have_dnsmasq = have("dnsmasq") have_udhcpd = have("udhcpd") if nc.get_dhcp_handler() == DnsMasqHandler and have_dnsmasq: r_dnsmasq.props.active = True elif nc.get_dhcp_handler() == DhcpdHandler and have_dhcpd: r_dhcpd.props.active = True elif nc.get_dhcp_handler() == UdhcpdHandler and have_udhcpd: r_udhcpd.props.active = True else: r_dnsmasq.props.active = True if not have_dnsmasq and not have_dhcpd and not have_udhcpd: nap_frame.props.sensitive = False warning.props.visible = True warning.props.sensitive = True nap_enable.props.sensitive = False self.Config["nap-enable"] = False if not have_dnsmasq: r_dnsmasq.props.sensitive = False r_dnsmasq.props.active = False if not have_dhcpd: r_dhcpd.props.sensitive = False r_dhcpd.props.active = False if not have_udhcpd: r_udhcpd.props.sensitive = False r_udhcpd.props.active = False r_dnsmasq.connect("toggled", lambda x: self.option_changed_notify("dnsmasq")) r_dhcpd.connect("toggled", lambda x: self.option_changed_notify("dhcpd")) r_udhcpd.connect("toggled", lambda x: self.option_changed_notify("udhcpd")) net_ip.connect("changed", lambda x: self.option_changed_notify("ip", False)) nap_enable.connect("toggled", lambda x: self.option_changed_notify("nap_enable")) self.Config.bind_to_widget("nap-enable", nap_enable, "active", Gio.SettingsBindFlags.GET) nap_enable.bind_property("active", nap_frame, "sensitive", GObject.BindingFlags.DEFAULT) applet = AppletService() avail_plugins = applet.QueryAvailablePlugins() active_plugins = applet.QueryPlugins() def dun_support_toggled(rb: Gtk.RadioButton, x: str) -> None: if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "PPPSupport", False) applet.SetPluginConfig('(sb)', "NMDUNSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMDUNSupport", False) applet.SetPluginConfig('(sb)', "PPPSupport", True) def pan_support_toggled(rb: Gtk.RadioButton, x: str) -> None: if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "DhcpClient", False) applet.SetPluginConfig('(sb)', "NMPANSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMPANSupport", False) applet.SetPluginConfig('(sb)', "DhcpClient", True) if "PPPSupport" in active_plugins: rb_dun_blueman.props.active = True if "NMDUNSupport" in avail_plugins: rb_dun_nm.props.sensitive = True else: rb_dun_nm.props.sensitive = False rb_dun_nm.props.tooltip_text = _( "Not currently supported with this setup") if "DhcpClient" in active_plugins: rb_blueman.props.active = True if "NMPANSupport" in avail_plugins: rb_nm.props.sensitive = True else: rb_nm.props.sensitive = False rb_nm.props.tooltip_text = _( "Not currently supported with this setup") if "NMPANSupport" in active_plugins: rb_nm.props.active = True if "NMDUNSupport" in active_plugins: rb_dun_nm.props.active = True rb_nm.connect("toggled", pan_support_toggled, "nm") rb_blueman.connect("toggled", pan_support_toggled, "blueman") rb_dun_nm.connect("toggled", dun_support_toggled, "nm") rb_dun_blueman.connect("toggled", dun_support_toggled, "blueman")
class Network(ServicePlugin): __plugin_info__ = (_("Network"), "network-workgroup") def on_load(self, container): self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") bind_textdomain_codeset("blueman", "UTF-8") self.Builder.add_from_file(UI_PATH + "/services-network.ui") self.widget = self.Builder.get_object("network_frame") container.pack_start(self.widget, True, True, 0) self.interfaces = [] for iface in get_net_interfaces(): if iface != "lo" and iface != "pan1": logging.info(iface) ipiface = ipaddress.ip_interface('/'.join((get_net_address(iface), get_net_netmask(iface)))) self.interfaces.append((iface, ipiface)) self.setup_network() try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) return _("Network"), "network-workgroup" def on_enter(self): self.widget.props.visible = True def on_leave(self): self.widget.props.visible = False def on_apply(self): if self.on_query_apply_state(): logging.info("network apply") m = Mechanism() nap_enable = self.Builder.get_object("nap-enable") if nap_enable.props.active: if self.Builder.get_object("r_dhcpd").props.active: stype = "DhcpdHandler" elif self.Builder.get_object("r_dnsmasq").props.active: stype = "DnsMasqHandler" elif self.Builder.get_object("r_udhcpd").props.active: stype = "UdhcpdHandler" net_ip = self.Builder.get_object("net_ip") try: m.EnableNetwork('(sss)', net_ip.props.text, "255.255.255.0", stype) if not self.Config["nap-enable"]: self.Config["nap-enable"] = True except Exception as e: d = ErrorDialog("<b>Failed to apply network settings</b>", excp=e, parent=self.widget.get_toplevel()) d.run() d.destroy() return else: self.Config["nap-enable"] = False m.DisableNetwork() self.clear_options() def ip_check(self): entry = self.Builder.get_object("net_ip") try: nap_ipiface = ipaddress.ip_interface('/'.join((entry.props.text, '255.255.255.0'))) except (ValueError, ipaddress.AddressValueError): entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = _("Invalid IP address") raise for iface, ipiface in self.interfaces: if nap_ipiface.ip == ipiface.ip: error_message = _("IP address conflicts with interface %s which has the same address" % iface) tooltip_text = error_message entry.props.secondary_icon_name = "dialog-error" entry.props.secondary_icon_tooltip_text = tooltip_text raise ValueError(error_message) elif nap_ipiface.network == ipiface.network: tooltip_text = _( "IP address overlaps with subnet of interface %s, which has the following configuration %s/%s\n" "This may cause incorrect network behavior" % (iface, ipiface.ip, ipiface.netmask)) entry.props.secondary_icon_name = "dialog-warning" entry.props.secondary_icon_tooltip_text = tooltip_text return entry.props.secondary_icon_name = None def on_query_apply_state(self): opts = self.get_options() if not opts: return False if "ip" in opts: try: self.ip_check() except (ValueError, ipaddress.AddressValueError) as e: logging.exception(e) return -1 return True def setup_network(self): self.Config = Config("org.blueman.network") nap_enable = self.Builder.get_object("nap-enable") r_dnsmasq = self.Builder.get_object("r_dnsmasq") r_dhcpd = self.Builder.get_object("r_dhcpd") r_udhcpd = self.Builder.get_object("r_udhcpd") net_ip = self.Builder.get_object("net_ip") rb_nm = self.Builder.get_object("rb_nm") rb_blueman = self.Builder.get_object("rb_blueman") rb_dun_nm = self.Builder.get_object("rb_dun_nm") rb_dun_blueman = self.Builder.get_object("rb_dun_blueman") nap_frame = self.Builder.get_object("nap_frame") warning = self.Builder.get_object("warning") if not self.Config["nap-enable"]: nap_frame.props.sensitive = False nc = NetConf.get_default() if nc.ip4_address is not None: # previously we stored a bytearray, ipaddress module reads both net_ip.props.text = str(ipaddress.ip_address(nc.ip4_address)) nap_enable.props.active = True else: net_ip.props.text = "10.%d.%d.1" % (randint(0, 255), randint(0, 255)) if nc.get_dhcp_handler() is None: nap_frame.props.sensitive = False nap_enable.props.active = False r_dnsmasq.props.active = True self.Config["nap-enable"] = False have_dhcpd = have("dhcpd3") or have("dhcpd") have_dnsmasq = have("dnsmasq") have_udhcpd = have("udhcpd") if nc.get_dhcp_handler() == DnsMasqHandler and have_dnsmasq: r_dnsmasq.props.active = True elif nc.get_dhcp_handler() == DhcpdHandler and have_dhcpd: r_dhcpd.props.active = True elif nc.get_dhcp_handler() == UdhcpdHandler and have_udhcpd: r_udhcpd.props.active = True else: r_dnsmasq.props.active = True if not have_dnsmasq and not have_dhcpd and not have_udhcpd: nap_frame.props.sensitive = False warning.props.visible = True warning.props.sensitive = True nap_enable.props.sensitive = False self.Config["nap-enable"] = False if not have_dnsmasq: r_dnsmasq.props.sensitive = False r_dnsmasq.props.active = False if not have_dhcpd: r_dhcpd.props.sensitive = False r_dhcpd.props.active = False if not have_udhcpd: r_udhcpd.props.sensitive = False r_udhcpd.props.active = False r_dnsmasq.connect("toggled", lambda x: self.option_changed_notify("dnsmasq")) r_dhcpd.connect("toggled", lambda x: self.option_changed_notify("dhcpd")) r_udhcpd.connect("toggled", lambda x: self.option_changed_notify("udhcpd")) net_ip.connect("changed", lambda x: self.option_changed_notify("ip", False)) nap_enable.connect("toggled", lambda x: self.option_changed_notify("nap_enable")) self.Config.bind_to_widget("nap-enable", nap_enable, "active", Gio.SettingsBindFlags.GET) nap_enable.bind_property("active", nap_frame, "sensitive", 0) applet = AppletService() avail_plugins = applet.QueryAvailablePlugins() active_plugins = applet.QueryPlugins() def dun_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "PPPSupport", False) applet.SetPluginConfig('(sb)', "NMDUNSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMDUNSupport", False) applet.SetPluginConfig('(sb)', "PPPSupport", True) def pan_support_toggled(rb, x): if rb.props.active and x == "nm": applet.SetPluginConfig('(sb)', "DhcpClient", False) applet.SetPluginConfig('(sb)', "NMPANSupport", True) elif rb.props.active and x == "blueman": applet.SetPluginConfig('(sb)', "NMPANSupport", False) applet.SetPluginConfig('(sb)', "DhcpClient", True) if "PPPSupport" in active_plugins: rb_dun_blueman.props.active = True if "NMDUNSupport" in avail_plugins: rb_dun_nm.props.sensitive = True else: rb_dun_nm.props.sensitive = False rb_dun_nm.props.tooltip_text = _("Not currently supported with this setup") if "DhcpClient" in active_plugins: rb_blueman.props.active = True if "NMPANSupport" in avail_plugins: rb_nm.props.sensitive = True else: rb_nm.props.sensitive = False rb_nm.props.tooltip_text = _("Not currently supported with this setup") if "NMPANSupport" in active_plugins: rb_nm.props.active = True if "NMDUNSupport" in active_plugins: rb_dun_nm.props.active = True rb_nm.connect("toggled", pan_support_toggled, "nm") rb_blueman.connect("toggled", pan_support_toggled, "blueman") rb_dun_nm.connect("toggled", dun_support_toggled, "nm") rb_dun_blueman.connect("toggled", dun_support_toggled, "blueman")