Beispiel #1
0
    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)
Beispiel #2
0
def send_note(device: Device, parent: Gtk.Window) -> None:
    builder = Builder("note.ui")
    dialog = builder.get_widget("dialog", Gtk.Dialog)
    dialog.set_transient_for(parent)
    dialog.props.icon_name = 'blueman'
    note = builder.get_widget("note", Gtk.Entry)
    dialog.connect('response', send_note_cb, device['Address'], note)
    dialog.present()
Beispiel #3
0
        def on_rename(_item: Gtk.MenuItem, device: Device) -> None:
            def on_response(dialog: Gtk.Dialog, response_id: int) -> None:
                if response_id == Gtk.ResponseType.ACCEPT:
                    assert isinstance(alias_entry, Gtk.Entry)  # https://github.com/python/mypy/issues/2608
                    device.set('Alias', alias_entry.get_text())
                elif response_id == 1:
                    device.set('Alias', '')
                dialog.destroy()

            builder = Builder("rename-device.ui")
            dialog = builder.get_widget("dialog", Gtk.Dialog)
            dialog.set_transient_for(self.Blueman.window)
            dialog.props.icon_name = "blueman"
            alias_entry = builder.get_widget("alias_entry", Gtk.Entry)
            alias_entry.set_text(device['Alias'])
            dialog.connect("response", on_response)
            dialog.present()
Beispiel #4
0
    def build_passkey_dialog(self, device_alias: str, dialog_msg: str,
                             is_numeric: bool) -> Tuple[Gtk.Dialog, Gtk.Entry]:
        def on_insert_text(editable: Gtk.Entry, new_text: str,
                           _new_text_length: int, _position: int) -> None:
            if not new_text.isdigit():
                editable.stop_emission("insert-text")

        builder = Builder("applet-passkey.ui")

        dialog = builder.get_widget("dialog", Gtk.Dialog)

        dialog.props.icon_name = "blueman"
        dev_name = builder.get_widget("device_name", Gtk.Label)
        dev_name.set_markup(device_alias)
        msg = builder.get_widget("message", Gtk.Label)
        msg.set_text(dialog_msg)
        pin_entry = builder.get_widget("pin_entry", Gtk.Entry)
        show_input = builder.get_widget("show_input_check", Gtk.CheckButton)
        if is_numeric:
            pin_entry.set_max_length(6)
            pin_entry.set_width_chars(6)
            pin_entry.connect("insert-text", on_insert_text)
            show_input.hide()
        else:
            pin_entry.set_max_length(16)
            pin_entry.set_width_chars(16)
            pin_entry.set_visibility(False)
        show_input.connect("toggled",
                           lambda x: pin_entry.set_visibility(x.props.active))
        accept_button = builder.get_widget("accept", Gtk.Button)
        pin_entry.connect(
            "changed",
            lambda x: accept_button.set_sensitive(x.get_text() != ''))

        return dialog, pin_entry
Beispiel #5
0
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)
Beispiel #6
0
    def __init__(self, applet: "BluemanApplet") -> None:
        super().__init__(title=_("Plugins"),
                         icon_name="blueman",
                         name="PluginDialog",
                         border_width=6,
                         default_width=490,
                         default_height=380,
                         resizable=False,
                         visible=False)

        self.applet = applet

        builder = Builder("applet-plugins-widget.ui")

        self.description = builder.get_widget("description", Gtk.Label)

        self.icon = builder.get_widget("icon", Gtk.Image)
        self.author_txt = builder.get_widget("author_txt", Gtk.Label)
        self.depends_hdr = builder.get_widget("depends_hdr", Gtk.Widget)
        self.depends_txt = builder.get_widget("depends_txt", Gtk.Label)
        self.conflicts_hdr = builder.get_widget("conflicts_hdr", Gtk.Widget)
        self.conflicts_txt = builder.get_widget("conflicts_txt", Gtk.Label)
        self.plugin_name = builder.get_widget("name", Gtk.Label)

        self.main_container = builder.get_widget("main_container", Gtk.Bin)
        self.content_grid = builder.get_widget("content", Gtk.Widget)

        self.b_prefs = builder.get_widget("b_prefs", Gtk.ToggleButton)
        self.b_prefs.connect("toggled", self.on_prefs_toggled)

        self.add(builder.get_widget("all", Gtk.Container))

        cr = Gtk.CellRendererToggle()
        cr.connect("toggled", self.on_toggled)

        data: List[ListDataDict] = [
            {
                "id": "active",
                "type": bool,
                "renderer": cr,
                "render_attrs": {
                    "active": 0,
                    "activatable": 1,
                    "visible": 1
                }
            },
            {
                "id": "activatable",
                "type": bool
            },
            {
                "id": "icon",
                "type": str,
                "renderer": Gtk.CellRendererPixbuf(),
                "render_attrs": {
                    "icon-name": 2
                }
            },
            # device caption
            {
                "id": "desc",
                "type": str,
                "renderer": Gtk.CellRendererText(),
                "render_attrs": {
                    "markup": 3
                },
                "view_props": {
                    "expand": True
                }
            },
            {
                "id": "name",
                "type": str
            },
        ]

        self.list = GenericList(data, headers_visible=False, visible=True)
        self.list.liststore.set_sort_column_id(3, Gtk.SortType.ASCENDING)
        self.list.liststore.set_sort_func(3, self.list_compare_func)

        self.list.selection.connect("changed", self.on_selection_changed)

        plugin_list = builder.get_widget("plugin_list", Gtk.ScrolledWindow)
        plugin_info = builder.get_widget("main_scrolled_window",
                                         Gtk.ScrolledWindow)
        plugin_list.add(self.list)

        # Disable overlay scrolling
        if Gtk.get_minor_version() >= 16:
            plugin_list.props.overlay_scrolling = False
            plugin_info.props.overlay_scrolling = False

        self.populate()

        self.sig_a: int = self.applet.Plugins.connect(
            "plugin-loaded", self.plugin_state_changed, True)
        self.sig_b: int = self.applet.Plugins.connect(
            "plugin-unloaded", self.plugin_state_changed, False)
        self.connect("delete-event", self._on_close)

        self.list.set_cursor(0)
Beispiel #7
0
class Transfer(ServicePlugin):
    __plugin_info__ = (_("Transfer"), "document-open")

    def on_load(self, container: Gtk.Box) -> None:

        self._builder = Builder("services-transfer.ui")
        self.widget = self._builder.get_widget("transfer", Gtk.Widget)

        container.pack_start(self.widget, True, True, 0)
        a = AppletService()
        if "TransferService" in a.QueryPlugins():
            self._setup_transfer()
        else:
            self.widget.props.sensitive = False
            self.widget.props.tooltip_text = _(
                "Applet's transfer service plugin is disabled")

    def on_enter(self) -> None:
        self.widget.props.visible = True

    def on_leave(self) -> None:
        self.widget.props.visible = False

    def on_property_changed(self, config: Gio.Settings, key: str) -> None:
        value = config[key]

        if key == "shared-path":
            self._builder.get_widget(
                key, Gtk.FileChooserButton).set_current_folder(value)
            self.option_changed_notify(key, False)

    def on_apply(self) -> None:
        if self.on_query_apply_state():
            for opt in self.get_options():
                if opt == "shared-path":
                    shared_path = self._builder.get_widget(
                        "shared-path", Gtk.FileChooserButton)
                    self._config["shared-path"] = shared_path.get_filename()
                elif opt == "opp-accept":
                    opp_accept = self._builder.get_widget(
                        "opp-accept", Gtk.CheckButton)
                    self._config["opp-accept"] = opp_accept.get_active()
                else:
                    raise NotImplementedError("Unknow option: %s" % opt)

            self.clear_options()
            logging.info("transfer apply")

    def on_query_apply_state(self) -> bool:
        opts = self.get_options()
        if not opts:
            return False
        else:
            return True

    def _setup_transfer(self) -> None:
        self._config = Config("org.blueman.transfer")
        self._config.connect("changed", self.on_property_changed)

        opp_accept = self._builder.get_widget("opp-accept", Gtk.CheckButton)
        shared_path = self._builder.get_widget("shared-path",
                                               Gtk.FileChooserButton)

        opp_accept.props.active = self._config["opp-accept"]
        if self._config["shared-path"]:
            shared_path.set_current_folder(self._config["shared-path"])

        opp_accept.connect("toggled",
                           lambda x: self.option_changed_notify("opp-accept"))
        shared_path.connect(
            "file-set", lambda x: self.option_changed_notify("shared-path"))
Beispiel #8
0
    def build_adapter_tab(self, adapter: Adapter) -> "Tab":
        def on_hidden_toggle(radio: Gtk.RadioButton) -> None:
            if not radio.props.active:
                return
            adapter['DiscoverableTimeout'] = 0
            adapter['Discoverable'] = False
            hscale.set_sensitive(False)

        def on_always_toggle(radio: Gtk.RadioButton) -> None:
            if not radio.props.active:
                return
            adapter['DiscoverableTimeout'] = 0
            adapter['Discoverable'] = True
            hscale.set_sensitive(False)

        def on_temporary_toggle(radio: Gtk.RadioButton) -> None:
            if not radio.props.active:
                return
            adapter['Discoverable'] = True
            hscale.set_sensitive(True)
            hscale.set_value(3)

        def on_scale_format_value(_scale: Gtk.Scale, value: float) -> str:
            if value == 0:
                if adapter['Discoverable']:
                    return _("Always")
                else:
                    return _("Hidden")
            else:
                return gettext.ngettext("%(minutes)d Minute",
                                        "%(minutes)d Minutes", int(value)) % {
                                            "minutes": value
                                        }

        def on_scale_value_changed(scale: Gtk.Scale) -> None:
            val = scale.get_value()
            logging.info(f"value: {val}")
            if val == 0 and adapter['Discoverable']:
                always_radio.props.active = True
            timeout = int(val * 60)
            adapter['DiscoverableTimeout'] = timeout

        def on_name_changed(entry: Gtk.Entry) -> None:
            adapter['Alias'] = entry.get_text()

        builder = Builder("adapters-tab.ui")

        hscale = builder.get_widget("hscale", Gtk.Scale)
        hscale.connect("format-value", on_scale_format_value)
        hscale.connect("value-changed", on_scale_value_changed)
        hscale.set_range(0, 30)
        hscale.set_increments(1, 1)

        hidden_radio = builder.get_widget("hidden", Gtk.RadioButton)
        always_radio = builder.get_widget("always", Gtk.RadioButton)
        temporary_radio = builder.get_widget("temporary", Gtk.RadioButton)

        if adapter['Discoverable'] and adapter['DiscoverableTimeout'] > 0:
            temporary_radio.set_active(True)
            hscale.set_value(adapter['DiscoverableTimeout'])
            hscale.set_sensitive(True)
        elif adapter['Discoverable'] and adapter['DiscoverableTimeout'] == 0:
            always_radio.set_active(True)
        else:
            hidden_radio.set_active(True)

        name_entry = builder.get_widget("name_entry", Gtk.Entry)
        name_entry.set_text(adapter.get_name())

        hidden_radio.connect("toggled", on_hidden_toggle)
        always_radio.connect("toggled", on_always_toggle)
        temporary_radio.connect("toggled", on_temporary_toggle)
        name_entry.connect("changed", on_name_changed)

        return {
            "grid": builder.get_widget("grid", Gtk.Grid),
            "hidden_radio": hidden_radio,
            "always_radio": always_radio,
            "temparary_radio": temporary_radio,
            "visible": False,
            "label": Gtk.Label()
        }
Beispiel #9
0
    def __init__(self, device: Device, adapter_path: str,
                 files: Iterable[str]) -> None:
        super().__init__(title=_("Bluetooth File Transfer"),
                         name="BluemanSendTo",
                         icon_name="blueman",
                         border_width=5,
                         default_width=400,
                         window_position=Gtk.WindowPosition.CENTER,
                         type_hint=Gdk.WindowTypeHint.DIALOG)

        self.b_cancel = self.add_button(_("_Stop"), Gtk.ResponseType.CLOSE)
        self.b_cancel.props.receives_default = True
        self.b_cancel.props.use_underline = True
        self.b_cancel.connect("clicked", self.on_cancel)

        builder = Builder("send-dialog.ui")

        grid = builder.get_widget("sendto", Gtk.Grid)
        content_area = self.get_content_area()
        content_area.add(grid)

        self.l_dest = builder.get_widget("l_dest", Gtk.Label)
        self.l_file = builder.get_widget("l_file", Gtk.Label)

        self.pb = builder.get_widget("pb", Gtk.ProgressBar)
        self.pb.props.text = _("Connecting")

        self.device = device
        self.adapter = Adapter(obj_path=adapter_path)
        self.manager = Manager()
        self.files: List[Gio.File] = []
        self.num_files = 0
        self.object_push: Optional[ObjectPush] = None
        self.object_push_handlers: List[int] = []
        self.transfer: Optional[Transfer] = None

        self.total_bytes = 0
        self.total_transferred = 0

        self._last_bytes = 0
        self._last_update = 0.0

        self.error_dialog: Optional[ErrorDialog] = None
        self.cancelling = False

        # bytes transferred on a current transfer
        self.transferred = 0

        self.speed = SpeedCalc(6)

        for file_name in files:
            parsed_file = Gio.File.parse_name(file_name)

            if not parsed_file.query_exists():
                logging.info(
                    f"Skipping non existing file {parsed_file.get_path()}")
                continue

            file_info = parsed_file.query_info("standard::*",
                                               Gio.FileQueryInfoFlags.NONE)

            if file_info.get_file_type() == Gio.FileType.DIRECTORY:
                logging.info(f"Skipping directory {parsed_file.get_path()}")
                continue

            self.files.append(parsed_file)
            self.num_files += 1
            self.total_bytes += file_info.get_size()

        if len(self.files) == 0:
            self.emit("result", False)

        try:
            self.client = Client()
            self.manager.connect_signal('session-added', self.on_session_added)
            self.manager.connect_signal('session-removed',
                                        self.on_session_removed)
        except GLib.Error as e:
            if 'StartServiceByName' in e.message:
                logging.debug(e.message)
                parent = self.get_toplevel()
                assert isinstance(parent, Gtk.Container)
                d = ErrorDialog(
                    _("obexd not available"),
                    _("Failed to autostart obex service. Make sure the obex "
                      "daemon is running"),
                    parent=parent)
                d.run()
                d.destroy()
                self.emit("result", False)
            else:
                # Fail on anything else
                raise

        basename = self.files[-1].get_basename()
        assert basename is not None
        self.l_file.props.label = basename

        self.client.connect('session-failed', self.on_session_failed)

        logging.info(f"Sending to {device['Address']}")
        self.l_dest.props.label = device['Alias']

        # Stop discovery if discovering and let adapter settle for a second
        if self.adapter["Discovering"]:
            self.adapter.stop_discovery()
            time.sleep(1)

        self.create_session()

        self.show()
Beispiel #10
0
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")
Beispiel #11
0
    def __init__(self, plugin: "NetUsage"):
        if not Dialog.running:
            Dialog.running = True
        else:
            return
        self.plugin = plugin
        builder = Builder("net-usage.ui")

        self.dialog = builder.get_widget("dialog", Gtk.Dialog)
        self.dialog.connect("response", self.on_response)
        cr1 = Gtk.CellRendererText()
        cr1.props.ellipsize = Pango.EllipsizeMode.END

        self._handlerids: List[int] = []
        self._handlerids.append(
            plugin.connect("monitor-added", self.monitor_added))
        self._handlerids.append(
            plugin.connect("monitor-removed", self.monitor_removed))
        self._handlerids.append(plugin.connect("stats", self.on_stats))

        cr2 = Gtk.CellRendererText()
        cr2.props.sensitive = False
        cr2.props.style = Pango.Style.ITALIC

        self.liststore = Gtk.ListStore(str, str, str, object)

        self.e_ul = builder.get_widget("e_ul", Gtk.Entry)
        self.e_dl = builder.get_widget("e_dl", Gtk.Entry)
        self.e_total = builder.get_widget("e_total", Gtk.Entry)

        self.l_started = builder.get_widget("l_started", Gtk.Label)
        self.l_duration = builder.get_widget("l_duration", Gtk.Label)

        self.b_reset = builder.get_widget("b_reset", Gtk.Button)
        self.b_reset.connect("clicked", self.on_reset)

        self.cb_device = builder.get_widget("cb_device", Gtk.ComboBox)
        self.cb_device.props.model = self.liststore
        self.cb_device.connect("changed", self.on_selection_changed)

        self.cb_device.pack_start(cr1, True)
        self.cb_device.add_attribute(cr1, 'markup', 1)

        self.cb_device.pack_start(cr2, False)
        self.cb_device.add_attribute(cr2, 'markup', 2)

        general_config = Config("org.blueman.general")

        added = False
        for d in general_config["netusage-dev-list"]:
            for m in plugin.monitors:
                if d == m.device["Address"]:
                    titer = self.liststore.append([
                        d,
                        self.get_caption(m.device["Alias"],
                                         m.device["Address"]),
                        _("Connected:") + " " + m.interface, m
                    ])
                    if self.cb_device.get_active() == -1:
                        self.cb_device.set_active_iter(titer)
                    added = True
                    break
            if not added:
                name = d
                if self.plugin.parent.Manager:
                    device = self.plugin.parent.Manager.find_device(d)
                    if device is None:
                        pass
                    else:
                        name = self.get_caption(device["Alias"],
                                                device["Address"])

                self.liststore.append([d, name, _("Not Connected"), None])
            added = False
        if len(self.liststore) > 0:
            if self.cb_device.get_active() == -1:
                self.cb_device.set_active(0)
        else:
            msg = _(
                "No usage statistics are available yet. Try establishing a connection first and "
                "then check this page.")
            d = Gtk.MessageDialog(parent=self.dialog,
                                  modal=True,
                                  type=Gtk.MessageType.INFO,
                                  buttons=Gtk.ButtonsType.CLOSE,
                                  text=msg)
            d.props.icon_name = "blueman"
            d.run()
            d.destroy()
            self.on_response(None, None)
            return

        self.dialog.show()