Beispiel #1
0
class NetUsage(AppletPlugin, GObject.GObject):
    __depends__ = ["Menu"]
    __icon__ = "network-wireless"
    __description__ = _("Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited "
                        "data access plans. This plugin tracks every device seperately.")
    __author__ = "Walmis"
    __autoload__ = False
    __gsignals__ = {
        'monitor-added': (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT,)),
        'monitor-removed': (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT,)),
        # monitor, tx, rx
        'stats': (GObject.SignalFlags.NO_HOOKS, None,
                  (GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT,)),
    }

    _any_network = None

    def on_load(self):
        GObject.GObject.__init__(self)
        self.monitors = []

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_property_changed)

        self.parent.Plugins.Menu.add(self, 84, text=_("Network _Usage"), icon_name="network-wireless",
                                     tooltip=_("Shows network traffic usage"), callback=self.activate_ui)

    def _on_network_property_changed(self, _network, key, value, path):
        if key == "Interface" and value != "":
            d = Device(path)
            self.monitor_interface(Monitor, d, value)

    def activate_ui(self):
        Dialog(self)

    def on_unload(self):
        del self._any_network
        self.parent.Plugins.Menu.unregister(self)

    def monitor_interface(self, montype, *args):
        m = montype(*args)
        self.monitors.append(m)
        m.connect("stats", self.on_stats)
        m.connect("disconnected", self.on_monitor_disconnected)
        self.emit("monitor-added", m)

    def on_ppp_connected(self, device, rfcomm, ppp_port):
        self.monitor_interface(Monitor, device, ppp_port)

    def on_monitor_disconnected(self, monitor):
        self.monitors.remove(monitor)
        self.emit("monitor-removed", monitor)

    def on_stats(self, monitor, tx, rx):
        self.emit("stats", monitor, tx, rx)
Beispiel #2
0
class DhcpClient(AppletPlugin):
    __description__ = _("Provides a basic dhcp client for Bluetooth PAN connections.")
    __icon__ = "network"
    __author__ = "Walmis"

    _any_network = None

    def on_load(self, applet):
        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_prop_changed)

        self.quering = []

    def on_unload(self):
        del self._any_network

    @dbus.service.method('org.blueman.Applet', in_signature="s")
    def DhcpClient(self, interface):
        self.dhcp_acquire(interface)

    def _on_network_prop_changed(self, _network, key, value, _path):
        if key == "Interface":
            if value != "":
                self.dhcp_acquire(value)

    def dhcp_acquire(self, device):
        if device not in self.quering:
            self.quering.append(device)
        else:
            return

        if device != "":
            def reply(ip_address):
                Notification(_("Bluetooth Network"),
                             _("Interface %(0)s bound to IP address %(1)s") % {"0": device, "1": ip_address},
                             pixbuf=get_icon("network-workgroup", 48),
                             status_icon=self.Applet.Plugins.StatusIcon)

                self.quering.remove(device)

            def err(msg):
                dprint(msg)
                Notification(_("Bluetooth Network"), _("Failed to obtain an IP address on %s") % (device),
                             pixbuf=get_icon("network-workgroup", 48),
                             status_icon=self.Applet.Plugins.StatusIcon)

                self.quering.remove(device)

            Notification(_("Bluetooth Network"), _("Trying to obtain an IP address on %s\nPlease wait..." % device),
                         pixbuf=get_icon("network-workgroup", 48),
                         status_icon=self.Applet.Plugins.StatusIcon)

            m = Mechanism()
            m.DhcpClient(device, reply_handler=reply, error_handler=err, timeout=120)
Beispiel #3
0
class DhcpClient(AppletPlugin):
    __description__ = _("Provides a basic dhcp client for Bluetooth PAN connections.")
    __icon__ = "network"
    __author__ = "Walmis"

    _any_network = None

    def on_load(self):
        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_prop_changed)

        self.quering = []

    def on_unload(self):
        del self._any_network

    @dbus.service.method('org.blueman.Applet', in_signature="s")
    def DhcpClient(self, interface):
        self.dhcp_acquire(interface)

    def _on_network_prop_changed(self, _network, key, value, _path):
        if key == "Interface":
            if value != "":
                self.dhcp_acquire(value)

    def dhcp_acquire(self, device):
        if device not in self.quering:
            self.quering.append(device)
        else:
            return

        if device != "":
            def reply(_obj, result, _user_data):
                logging.info(result)
                Notification(_("Bluetooth Network"),
                             _("Interface %(0)s bound to IP address %(1)s") % {"0": device, "1": result},
                             icon_name="network-workgroup").show()

                self.quering.remove(device)

            def err(_obj, result, _user_data):
                logging.warning(result)
                Notification(_("Bluetooth Network"), _("Failed to obtain an IP address on %s") % device,
                             icon_name="network-workgroup").show()

                self.quering.remove(device)

            Notification(_("Bluetooth Network"), _("Trying to obtain an IP address on %s\nPlease wait…" % device),
                         icon_name="network-workgroup").show()

            m = Mechanism()
            m.DhcpClient('(s)', device, result_handler=reply, error_handler=err, timeout=120)
Beispiel #4
0
    def on_load(self):
        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_prop_changed)

        self.quering = []

        self._add_dbus_method("DhcpClient", ("s",), "", self.dhcp_acquire)
Beispiel #5
0
    def __init__(self, blueman):
        super(ManagerDeviceMenu, self).__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman
        self.SelectedDevice = None

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed",
                                                                         self.on_device_property_changed)
        self._selection_done_signal = None

        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed', self._on_service_property_changed)

        try:
            self._appl = AppletService()
        except Exception:
            logging.error("** Failed to connect to applet", exc_info=True)
            self._appl = None

        self.Generate()
Beispiel #6
0
    def on_load(self):
        GObject.GObject.__init__(self)
        self.monitors = []

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_property_changed)

        self.parent.Plugins.Menu.add(self, 84, text=_("Network _Usage"), icon_name="network-wireless",
                                     tooltip=_("Shows network traffic usage"), callback=self.activate_ui)
Beispiel #7
0
    def on_load(self):
        GObject.GObject.__init__(self)
        self.monitors = []
        self.devices = weakref.WeakValueDictionary()

        self.bus = dbus.SystemBus()

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_property_changed)

        self.parent.Plugins.Menu.add(self, 84, text=_("Network _Usage"), icon_name="network-wireless",
                                     tooltip=_("Shows network traffic usage"), callback=self.activate_ui)

        self.bus.add_signal_receiver(self.on_nm_ppp_stats, "PppStats", "org.freedesktop.NetworkManager.Device.Serial",
                                     path_keyword="path")
        self.nm_paths = {}
Beispiel #8
0
    def on_load(self, applet):
        GObject.GObject.__init__(self)
        self.monitors = []
        self.devices = weakref.WeakValueDictionary()

        self.bus = dbus.SystemBus()

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_property_changed)

        item = create_menuitem(_("Network _Usage"), get_icon("network-wireless", 16))
        item.props.tooltip_text = _("Shows network traffic usage")
        item.connect("activate", self.activate_ui)
        self.Applet.Plugins.Menu.Register(self, item, 84, True)

        self.bus.add_signal_receiver(self.on_nm_ppp_stats, "PppStats", "org.freedesktop.NetworkManager.Device.Serial",
                                     path_keyword="path")
        self.nm_paths = {}
    def __init__(self, blueman):
        super(ManagerDeviceMenu, self).__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman
        self.SelectedDevice = None

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed",
                                                                         self.on_device_property_changed)
        self._selection_done_signal = None

        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed', self._on_service_property_changed)

        self.Generate()
Beispiel #10
0
    def on_load(self, applet):
        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_prop_changed)

        self.quering = []
Beispiel #11
0
class NetUsage(AppletPlugin, GObject.GObject):
    __depends__ = ["Menu"]
    __icon__ = "network-wireless"
    __description__ = _(
        "Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited data access plans. This plugin tracks every device seperately.")
    __author__ = "Walmis"
    __autoload__ = False
    __gsignals__ = {
    str('monitor-added'): (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT,)),
    str('monitor-removed'): (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT,)),
    #monitor, tx, rx
    str('stats'): (
    GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT, GObject.TYPE_PYOBJECT,)),
    }

    _any_network = None

    def on_load(self, applet):
        GObject.GObject.__init__(self)
        self.monitors = []
        self.devices = weakref.WeakValueDictionary()

        self.bus = dbus.SystemBus()

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_property_changed)

        item = create_menuitem(_("Network _Usage"), get_icon("network-wireless", 16))
        item.props.tooltip_text = _("Shows network traffic usage")
        item.connect("activate", self.activate_ui)
        self.Applet.Plugins.Menu.Register(self, item, 84, True)

        self.bus.add_signal_receiver(self.on_nm_ppp_stats, "PppStats", "org.freedesktop.NetworkManager.Device.Serial",
                                     path_keyword="path")
        self.nm_paths = {}

    def on_nm_ppp_stats(self, down, up, path):
        if path not in self.nm_paths:
            props = self.bus.call_blocking("org.freedesktop.NetworkManager",
                                           path,
                                           "org.freedesktop.DBus.Properties",
                                           "GetAll",
                                           "s",
                                           ["org.freedesktop.NetworkManager.Device"])

            if props["Driver"] == "bluetooth" and "rfcomm" in props["Interface"]:
                self.nm_paths[path] = True

                portid = int(props["Interface"].strip("rfcomm"))

                ls = rfcomm_list()
                for dev in ls:
                    if dev["id"] == portid:
                        adapter = self.Applet.Manager.get_adapter(dev["src"])
                        device = adapter.find_device(dev["dst"])

                        self.monitor_interface(NMMonitor, device, path)

                        return
            else:
                self.nm_paths[path] = False

    def _on_network_property_changed(self, _network, key, value, path):
        if key == "Interface" and value != "":
            d = Device(path)
            self.monitor_interface(Monitor, d, value)

    def activate_ui(self, item):
        Dialog(self)

    def on_unload(self):
        self.bus.remove_signal_receiver(self.on_nm_ppp_stats, "PppStats",
                                        "org.freedesktop.NetworkManager.Device.Serial", path_keyword="path")
        del self._any_network
        self.Applet.Plugins.Menu.Unregister(self)

    def monitor_interface(self, montype, *args):
        m = montype(*args)
        self.monitors.append(m)
        m.connect("stats", self.on_stats)
        m.connect("disconnected", self.on_monitor_disconnected)
        self.emit("monitor-added", m)

    def on_ppp_connected(self, device, rfcomm, ppp_port):
        self.monitor_interface(Monitor, device, ppp_port)

    def on_monitor_disconnected(self, monitor):
        self.monitors.remove(monitor)
        self.emit("monitor-removed", monitor)

    def on_stats(self, monitor, tx, rx):
        self.emit("stats", monitor, tx, rx)
Beispiel #12
0
class ManagerDeviceMenu(Gtk.Menu):
    __ops__: Dict[str, str] = {}
    __instances__: List["ManagerDeviceMenu"] = []

    SelectedDevice: Device

    def __init__(self, blueman: "Blueman") -> None:
        super().__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect(
            "device-property-changed", self.on_device_property_changed)
        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed',
                                        self._on_service_property_changed)

        try:
            self._appl: Optional[AppletService] = AppletService()
        except DBusProxyFailed:
            logging.error("** Failed to connect to applet", exc_info=True)
            self._appl = None

        self.generate()

    def __del__(self) -> None:
        logging.debug("deleting devicemenu")

    def popup_at_pointer(self, event: Optional[Gdk.Event]) -> None:
        self.is_popup = True
        self.generate()

        super().popup_at_pointer(event)

    def clear(self) -> None:
        def remove_and_destroy(child: Gtk.Widget) -> None:
            self.remove(child)
            child.destroy()

        self.foreach(remove_and_destroy)

    def set_op(self, device: Device, message: str) -> None:
        ManagerDeviceMenu.__ops__[device.get_object_path()] = message
        for inst in ManagerDeviceMenu.__instances__:
            logging.info(f"op: regenerating instance {inst}")
            if inst.SelectedDevice == self.SelectedDevice and not (
                    inst.is_popup and not inst.props.visible):
                inst.generate()

    def get_op(self, device: Device) -> Optional[str]:
        try:
            return ManagerDeviceMenu.__ops__[device.get_object_path()]
        except KeyError:
            return None

    def unset_op(self, device: Device) -> None:
        del ManagerDeviceMenu.__ops__[device.get_object_path()]
        for inst in ManagerDeviceMenu.__instances__:
            logging.info(f"op: regenerating instance {inst}")
            if inst.SelectedDevice == self.SelectedDevice and not (
                    inst.is_popup and not inst.props.visible):
                inst.generate()

    def _on_service_property_changed(self, _service: Union[AnyNetwork,
                                                           AnyDevice],
                                     key: str, _value: object,
                                     _path: str) -> None:
        if key == "Connected":
            self.generate()

    def on_connect(self, _item: Gtk.MenuItem, service: Service) -> None:
        device = service.device

        def success(_obj: AppletService, _result: None,
                    _user_data: None) -> None:
            logging.info("success")
            prog.message(_("Success!"))

            MessageArea.close()

            self.unset_op(device)

        def fail(_obj: Optional[AppletService], result: GLib.Error,
                 _user_data: None) -> None:
            prog.message(_("Failed"))

            self.unset_op(device)
            logging.warning(f"fail {result}")
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Connection Failed: ") + msg, tb)

        self.set_op(device, _("Connecting…"))
        prog = ManagerProgressbar(self.Blueman, False)

        if self._appl is None:
            fail(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.ConnectService('(os)',
                                  device.get_object_path(),
                                  service.uuid,
                                  result_handler=success,
                                  error_handler=fail,
                                  timeout=GLib.MAXINT)

        prog.start()

    def on_disconnect(self,
                      _item: Gtk.MenuItem,
                      service: Service,
                      port: int = 0) -> None:
        def ok(_obj: AppletService, _result: None, _user_date: None) -> None:
            logging.info("disconnect success")
            self.generate()

        def err(_obj: Optional[AppletService], result: GLib.Error,
                _user_date: None) -> None:
            logging.warning(f"disconnect failed {result}")
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Disconnection Failed: ") + msg, tb)
            self.generate()

        if self._appl is None:
            err(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.DisconnectService('(osd)',
                                     service.device.get_object_path(),
                                     service.uuid,
                                     port,
                                     result_handler=ok,
                                     error_handler=err)

    def on_device_property_changed(self, lst: "ManagerDeviceList",
                                   _device: Device, tree_iter: Gtk.TreeIter,
                                   key_value: Tuple[str, object]) -> None:
        key, value = key_value
        # print "menu:", key, value
        if lst.compare(tree_iter, lst.selected()):
            if key in ("Connected", "UUIDs", "Trusted", "Paired"):
                self.generate()

    def _handle_error_message(self, msg: str) -> None:
        msg = msg.split(":", 3)[-1].strip()

        # https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/gnu/errlist.h
        # https://git.musl-libc.org/cgit/musl/tree/src/errno/__strerror.h
        # https://git.uclibc.org/uClibc/tree/libc/string/_string_syserrmsgs.c
        if msg == "Protocol not available":
            # ENOPROTOOPT
            logging.warning(
                "No audio endpoints registered to bluetoothd. "
                "Pulseaudio Bluetooth module, bluez-alsa, PipeWire or other audio support missing."
            )
            msg = _("No audio endpoints registered")
        elif msg in ("Input/output error", "I/O error"):
            # EIO
            logging.warning(
                "bluetoothd reported input/output error. Check its logs for context."
            )
            msg = _("Input/output error")
        elif msg == "Host is down":
            # EHOSTDOWN (Bluetooth errors 0x04 (Page Timeout) or 0x3c (Advertising Timeout))
            msg = _("Device did not respond")
        elif msg == "Resource temporarily unavailable":
            # EAGAIN
            logging.warning(
                "bluetoothd reported resource temporarily unavailable. "
                "Retry or check its logs for context.")
            msg = _("Resource temporarily unavailable")

        if msg != "Cancelled":
            MessageArea.show_message(_("Connection Failed: ") + msg)

    def generic_connect(self, _item: Optional[Gtk.MenuItem], device: Device,
                        connect: bool) -> None:
        def fail(_obj: AppletService, result: GLib.Error,
                 _user_data: None) -> None:
            logging.info(f"fail: {result}")
            prog.message(_("Failed"))
            self.unset_op(device)
            self._handle_error_message(result.message)

        def success(_obj: AppletService, _result: None,
                    _user_data: None) -> None:
            logging.info("success")
            prog.message(_("Success!"))
            MessageArea.close()
            self.unset_op(device)

        assert self._appl

        if connect:
            self.set_op(self.SelectedDevice, _("Connecting…"))
            self._appl.ConnectService("(os)",
                                      device.get_object_path(),
                                      '00000000-0000-0000-0000-000000000000',
                                      result_handler=success,
                                      error_handler=fail,
                                      timeout=GLib.MAXINT)
        else:
            self.set_op(self.SelectedDevice, _("Disconnecting…"))
            self._appl.DisconnectService(
                "(osd)",
                device.get_object_path(),
                '00000000-0000-0000-0000-000000000000',
                0,
                result_handler=success,
                error_handler=fail,
                timeout=GLib.MAXINT)

        prog = ManagerProgressbar(self.Blueman)

        def abort() -> None:
            assert self._appl is not None  # https://github.com/python/mypy/issues/2608
            self._appl.DisconnectService(
                "(osd)", device.get_object_path(),
                '00000000-0000-0000-0000-000000000000', 0)

        prog.connect("cancelled", lambda x: abort())
        prog.start()

    def show_generic_connect_calc(self, device_uuids: Iterable[str]) -> bool:
        # Generic (dis)connect
        for uuid in device_uuids:
            service_uuid = ServiceUUID(uuid)
            if service_uuid.short_uuid in (AUDIO_SOURCE_SVCLASS_ID,
                                           AUDIO_SINK_SVCLASS_ID,
                                           HANDSFREE_AGW_SVCLASS_ID,
                                           HANDSFREE_SVCLASS_ID,
                                           HEADSET_SVCLASS_ID, HID_SVCLASS_ID,
                                           0x1812):
                return True
            elif not service_uuid.reserved:
                if uuid == '03b80e5a-ede8-4b33-a751-6ce34ec4c700':
                    return True
        # LE devices do not appear to expose certain properties like uuids until connect to at least once.
        return not device_uuids

    def generate(self) -> None:
        self.clear()

        items: List[Tuple[int, Gtk.MenuItem]] = []

        if not self.is_popup or self.props.visible:
            selected = self.Blueman.List.selected()
            if not selected:
                return
            row = self.Blueman.List.get(selected, "alias", "paired",
                                        "connected", "trusted", "objpush",
                                        "device")
        else:
            (x, y) = self.Blueman.List.get_pointer()
            path = self.Blueman.List.get_path_at_pos(x, y)
            if path is not None:
                assert path[0] is not None
                row = self.Blueman.List.get(path[0], "alias", "paired",
                                            "connected", "trusted", "objpush",
                                            "device")
            else:
                return

        self.SelectedDevice = row["device"]

        op = self.get_op(self.SelectedDevice)

        if op is not None:
            item: Gtk.MenuItem = create_menuitem(op,
                                                 "network-transmit-receive")
            item.props.sensitive = False
            item.show()
            self.append(item)
            return

        show_generic_connect = self.show_generic_connect_calc(
            self.SelectedDevice['UUIDs'])

        if not row["connected"] and show_generic_connect:
            connect_item = create_menuitem(_("_<b>_Connect</b>"), "blueman")
            connect_item.connect("activate", self.generic_connect,
                                 self.SelectedDevice, True)
            connect_item.props.tooltip_text = _(
                "Connects auto connect profiles A2DP source, A2DP sink, and HID"
            )
            connect_item.show()
            self.append(connect_item)
        elif show_generic_connect:
            connect_item = create_menuitem(_("_<b>Disconnect</b>"),
                                           "network-offline")
            connect_item.props.tooltip_text = _(
                "Forcefully disconnect the device")
            connect_item.connect("activate", self.generic_connect,
                                 self.SelectedDevice, False)
            connect_item.show()
            self.append(connect_item)

        for plugin in self.Blueman.Plugins.get_loaded_plugins(
                MenuItemsProvider):
            for item, pos in plugin.on_request_menu_items(
                    self, self.SelectedDevice):
                items.append((pos, item))

        logging.debug(row["alias"])

        have_disconnectables = False
        have_connectables = False

        if True in map(lambda x: 100 <= x[0] < 200, items):
            have_disconnectables = True

        if True in map(lambda x: x[0] < 100, items):
            have_connectables = True

        if True in map(lambda x: x[0] >= 200,
                       items) and (have_connectables or have_disconnectables):
            item = Gtk.SeparatorMenuItem()
            item.show()
            items.append((199, item))

        if have_connectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Connect To:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((0, item))

        if have_disconnectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Disconnect:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((99, item))

        items.sort(key=itemgetter(0))
        for priority, item in items:
            self.append(item)

        if items:
            item = Gtk.SeparatorMenuItem()
            item.show()
            self.append(item)

        del items

        send_item = create_menuitem(_("Send a _File…"), "edit-copy")
        send_item.props.sensitive = False
        self.append(send_item)
        send_item.show()

        if row["objpush"]:
            send_item.connect("activate",
                              lambda x: self.Blueman.send(self.SelectedDevice))
            send_item.props.sensitive = True

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Pair"), "dialog-password")
        item.props.tooltip_text = _("Create pairing with the device")
        self.append(item)
        item.show()
        if not row["paired"]:
            item.connect("activate",
                         lambda x: self.Blueman.bond(self.SelectedDevice))
        else:
            item.props.sensitive = False

        if not row["trusted"]:
            item = create_menuitem(_("_Trust"), "blueman-trust")
            item.connect(
                "activate",
                lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            self.append(item)
            item.show()
        else:
            item = create_menuitem(_("_Untrust"), "blueman-untrust")
            self.append(item)
            item.connect(
                "activate",
                lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            item.show()
        item.props.tooltip_text = _("Mark/Unmark this device as trusted")

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

        item = Gtk.MenuItem.new_with_mnemonic(_("R_ename device…"))
        item.connect('activate', on_rename, self.SelectedDevice)
        self.append(item)
        item.show()

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Remove…"), "edit-delete")
        item.connect("activate",
                     lambda x: self.Blueman.remove(self.SelectedDevice))
        self.append(item)
        item.show()
        item.props.tooltip_text = _(
            "Remove this device from the known devices list")
class ManagerDeviceMenu(Gtk.Menu):
    __ops__ = {}
    __instances__ = []

    def __init__(self, blueman):
        super(ManagerDeviceMenu, self).__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman
        self.SelectedDevice = None

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed",
                                                                         self.on_device_property_changed)
        self._selection_done_signal = None

        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed', self._on_service_property_changed)

        self.Generate()

    def __del__(self):
        dprint("deleting devicemenu")

    def popup(self, *args):
        self.is_popup = True

        if not self._device_property_changed_signal:
            self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed",
                                                                             self.on_device_property_changed)

        if not self._selection_done_signal:
            def disconnectall(x):
                self.disconnect(self._device_property_changed_signal)
                self.disconnect(self._selection_done_signal)

            self._selection_done_signal = self.connect("selection-done", disconnectall)

        self.Generate()

        Gtk.Menu.popup(self, *args)

    def clear(self):
        def each(child, data):
            self.remove(child)
            child.destroy()

        self.foreach(each, None)

    def set_op(self, device, message):
        ManagerDeviceMenu.__ops__[device.get_object_path()] = message
        for inst in ManagerDeviceMenu.__instances__:
            dprint("op: regenerating instance", inst)
            if inst.SelectedDevice == self.SelectedDevice and not (inst.is_popup and not inst.props.visible):
                inst.Generate()

    def get_op(self, device):
        try:
            return ManagerDeviceMenu.__ops__[device.get_object_path()]
        except:
            return None

    def unset_op(self, device):
        del ManagerDeviceMenu.__ops__[device.get_object_path()]
        for inst in ManagerDeviceMenu.__instances__:
            dprint("op: regenerating instance", inst)
            if inst.SelectedDevice == self.SelectedDevice and not (inst.is_popup and not inst.props.visible):
                inst.Generate()

    def _on_service_property_changed(self, _service, key, _value, _path):
        if key == "Connected":
            self.Generate()

    def on_connect(self, _item, service):
        device = service.device

        def success(*args2):
            dprint("success", " ".join(args2))
            prog.message(_("Success!"))

            if isinstance(service, SerialPort) and SERIAL_PORT_SVCLASS_ID == uuid128_to_uuid16(service.uuid):
                MessageArea.show_message(_("Serial port connected to %s") % args2[0], "dialog-information")
            else:
                MessageArea.close()

            self.unset_op(device)

        def fail(*args):
            prog.message(_("Failed"))

            self.unset_op(device)
            dprint("fail", args)
            MessageArea.show_message(_("Connection Failed: ") + e_(str(args[0])))

        self.set_op(device, _("Connecting..."))
        prog = ManagerProgressbar(self.Blueman, False)

        try:
            appl = AppletService()
        except:
            dprint("** Failed to connect to applet")
            fail()
            return
        try:
            appl.SetTimeHint(Gtk.get_current_event_time())
        except:
            pass

        appl.connect_service(device.get_object_path(), service.uuid,
                             reply_handler=success, error_handler=fail,
                             timeout=200)

        prog.start()

    def on_disconnect(self, item, service, port=0):
        try:
            appl = AppletService()
        except:
            dprint("** Failed to connect to applet")
            return

        appl.disconnect_service(service.device.get_object_path(), service.uuid, port)
        self.Generate()

    def on_device_property_changed(self, List, device, tree_iter, key_value):
        key, value = key_value
        # print "menu:", key, value
        if List.compare(tree_iter, List.selected()):
            if key == "Connected" \
                or key == "UUIDs" \
                or key == "Trusted" \
                or key == "Paired":
                self.Generate()

    def Generate(self):
        self.clear()

        appl = AppletService()

        items = []

        if not self.is_popup or self.props.visible:
            selected = self.Blueman.List.selected()
            if not selected:
                return
            row = self.Blueman.List.get(selected, "alias", "bonded", "connected", "trusted", "objpush", "device")
        else:
            (x, y) = self.Blueman.List.get_pointer()
            path = self.Blueman.List.get_path_at_pos(x, y)
            if path is not None:
                row = self.Blueman.List.get(path[0], "alias", "bonded", "connected", "trusted", "objpush", "device")
            else:
                return

        self.SelectedDevice = row["device"]

        op = self.get_op(self.SelectedDevice)

        if op is not None:
            item = create_menuitem(op, get_icon("network-transmit-recieve", 16))
            item.props.sensitive = False
            item.show()
            self.append(item)
            return

        rets = self.Blueman.Plugins.Run("on_request_menu_items", self, self.SelectedDevice)

        for ret in rets:
            if ret:
                for (item, pos) in ret:
                    items.append((pos, item))

        dprint(row["alias"])

        have_disconnectables = False
        have_connectables = False

        if True in map(lambda x: 100 <= x[0] < 200, items):
            have_disconnectables = True

        if True in map(lambda x: x[0] < 100, items):
            have_connectables = True

        if True in map(lambda x: x[0] >= 200, items) and (have_connectables or have_disconnectables):
            item = Gtk.SeparatorMenuItem()
            item.show()
            items.append((199, item))

        if have_connectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Connect To:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((0, item))

        if have_disconnectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Disconnect:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((99, item))

        items.sort(key=itemgetter(0))
        for priority, item in items:
            self.append(item)

        if items:
            item = Gtk.SeparatorMenuItem()
            item.show()
            self.append(item)

        del items

        send_item = create_menuitem(_("Send a _File..."), get_icon("edit-copy", 16))
        send_item.props.sensitive = False
        self.append(send_item)
        send_item.show()

        if row["objpush"]:
            send_item.connect("activate", lambda x: self.Blueman.send(self.SelectedDevice))
            send_item.props.sensitive = True

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Pair"), get_icon("dialog-password", 16))
        item.props.tooltip_text = _("Create pairing with the device")
        self.append(item)
        item.show()
        if not row["bonded"]:
            item.connect("activate", lambda x: self.Blueman.bond(self.SelectedDevice))
        else:
            item.props.sensitive = False

        if not row["trusted"]:
            item = create_menuitem(_("_Trust"), get_icon("blueman-trust", 16))
            item.connect("activate", lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            self.append(item)
            item.show()
        else:
            item = create_menuitem(_("_Untrust"), get_icon("blueman-untrust", 16))
            self.append(item)
            item.connect("activate", lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            item.show()
        item.props.tooltip_text = _("Mark/Unmark this device as trusted")

        item = create_menuitem(_("_Setup..."), get_icon("document-properties", 16))
        self.append(item)
        item.connect("activate", lambda x: self.Blueman.setup(self.SelectedDevice))
        item.show()
        item.props.tooltip_text = _("Run the setup assistant for this device")

        def on_rename(_item, device):
            def on_response(dialog, response_id):
                if response_id == Gtk.ResponseType.ACCEPT:
                    device.set('Alias', alias_entry.get_text())
                elif response_id == 1:
                    device.set('Alias', '')
                dialog.destroy()

            builder = Gtk.Builder()
            builder.set_translation_domain("blueman")
            bind_textdomain_codeset("blueman", "UTF-8")
            builder.add_from_file(UI_PATH + "/rename-device.ui")
            dialog = builder.get_object("dialog")
            dialog.set_transient_for(self.Blueman)
            dialog.props.icon_name = "blueman"
            alias_entry = builder.get_object("alias_entry")
            alias_entry.set_text(device['Alias'])
            dialog.connect("response", on_response)
            dialog.present()

        item = Gtk.MenuItem.new_with_label("Rename device...")
        item.connect('activate', on_rename, self.SelectedDevice)
        self.append(item)
        item.show()

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Remove..."), get_icon("edit-delete", 16))
        item.connect("activate", lambda x: self.Blueman.remove(self.SelectedDevice))
        self.append(item)
        item.show()
        item.props.tooltip_text = _("Remove this device from the known devices list")

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Disconnect"), get_icon("network-offline", 16))
        item.props.tooltip_text = _("Forcefully disconnect the device")

        self.append(item)
        item.show()

        def on_disconnect(item):
            def finished(*args):
                self.unset_op(self.SelectedDevice)
                
            self.set_op(self.SelectedDevice, _("Disconnecting..."))
            self.Blueman.disconnect(self.SelectedDevice,
                                    reply_handler=finished,
                                    error_handler=finished)

        if row['connected']:
            item.connect("activate", on_disconnect)

        else:
            item.props.sensitive = False
Beispiel #14
0
class DhcpClient(AppletPlugin):
    __description__ = _(
        "Provides a basic dhcp client for Bluetooth PAN connections.")
    __icon__ = "network-workgroup"
    __author__ = "Walmis"

    _any_network = None

    def on_load(self):
        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_network_prop_changed)

        self.quering = []

        self._add_dbus_method("DhcpClient", ("s", ), "", self.dhcp_acquire)

    def on_unload(self):
        del self._any_network

    def _on_network_prop_changed(self, _network, key, value, _path):
        if key == "Interface":
            if value != "":
                self.dhcp_acquire(value)

    def dhcp_acquire(self, device):
        if device not in self.quering:
            self.quering.append(device)
        else:
            return

        if device != "":

            def reply(_obj, result, _user_data):
                logging.info(result)
                Notification(_("Bluetooth Network"),
                             _("Interface %(0)s bound to IP address %(1)s") % {
                                 "0": device,
                                 "1": result
                             },
                             icon_name="network-workgroup").show()

                self.quering.remove(device)

            def err(_obj, result, _user_data):
                logging.warning(result)
                Notification(_("Bluetooth Network"),
                             _("Failed to obtain an IP address on %s") %
                             device,
                             icon_name="network-workgroup").show()

                self.quering.remove(device)

            Notification(
                _("Bluetooth Network"),
                _("Trying to obtain an IP address on %s\nPlease wait…" %
                  device),
                icon_name="network-workgroup").show()

            m = Mechanism()
            m.DhcpClient('(s)',
                         device,
                         result_handler=reply,
                         error_handler=err,
                         timeout=120 * 1000)
Beispiel #15
0
class ManagerDeviceMenu(Gtk.Menu):
    __ops__: Dict[str, str] = {}
    __instances__: List["ManagerDeviceMenu"] = []

    SelectedDevice: Device

    def __init__(self, blueman):
        super().__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect(
            "device-property-changed", self.on_device_property_changed)
        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed',
                                        self._on_service_property_changed)

        try:
            self._appl: Optional[AppletService] = AppletService()
        except DBusProxyFailed:
            logging.error("** Failed to connect to applet", exc_info=True)
            self._appl = None

        self.generate()

    def __del__(self):
        logging.debug("deleting devicemenu")

    def popup(self, *args):
        self.is_popup = True
        self.generate()

        super().popup(*args)

    def clear(self):
        def remove_and_destroy(child):
            self.remove(child)
            child.destroy()

        self.foreach(remove_and_destroy)

    def set_op(self, device, message):
        ManagerDeviceMenu.__ops__[device.get_object_path()] = message
        for inst in ManagerDeviceMenu.__instances__:
            logging.info("op: regenerating instance %s" % inst)
            if inst.SelectedDevice == self.SelectedDevice and not (
                    inst.is_popup and not inst.props.visible):
                inst.generate()

    def get_op(self, device):
        try:
            return ManagerDeviceMenu.__ops__[device.get_object_path()]
        except KeyError:
            return None

    def unset_op(self, device):
        del ManagerDeviceMenu.__ops__[device.get_object_path()]
        for inst in ManagerDeviceMenu.__instances__:
            logging.info("op: regenerating instance %s" % inst)
            if inst.SelectedDevice == self.SelectedDevice and not (
                    inst.is_popup and not inst.props.visible):
                inst.generate()

    def _on_service_property_changed(self, _service, key, _value, _path):
        if key == "Connected":
            self.generate()

    def on_connect(self, _item, service):
        device = service.device

        def success(obj, result, _user_data):
            logging.info("success")
            prog.message(_("Success!"))

            if isinstance(service, SerialPort
                          ) and SERIAL_PORT_SVCLASS_ID == service.short_uuid:
                MessageArea.show_message(
                    _("Serial port connected to %s") % result, None,
                    "dialog-information")
            else:
                MessageArea.close()

            self.unset_op(device)

        def fail(obj, result, _user_data):
            prog.message(_("Failed"))

            self.unset_op(device)
            logging.warning("fail %s" % result)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Connection Failed: ") + msg, tb)

        self.set_op(device, _("Connecting..."))
        prog = ManagerProgressbar(self.Blueman, False)

        if self._appl is None:
            fail(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.ConnectService('(os)',
                                  device.get_object_path(),
                                  service.uuid,
                                  result_handler=success,
                                  error_handler=fail,
                                  timeout=GLib.MAXINT)

        prog.start()

    def on_disconnect(self, item, service, port=0):
        def ok(obj, result, user_date):
            logging.info("disconnect success")
            self.generate()

        def err(obj, result, user_date):
            logging.warning("disconnect failed %s" % result)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Disconnection Failed: ") + msg, tb)
            self.generate()

        if self._appl is None:
            err(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.DisconnectService('(osd)',
                                     service.device.get_object_path(),
                                     service.uuid,
                                     port,
                                     result_handler=ok,
                                     error_handler=err)

    def on_device_property_changed(self, lst, device, tree_iter, key_value):
        key, value = key_value
        # print "menu:", key, value
        if lst.compare(tree_iter, lst.selected()):
            if key in ("Connected", "UUIDs", "Trusted", "Paired"):
                self.generate()

    def generic_connect(self, item, device, connect):
        def fail(obj, result, user_date):
            logging.info("fail: %s", result)
            prog.message(_("Failed"))
            self.unset_op(device)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Connection Failed: ") + msg)

        def success(obj, result, user_data):
            logging.info("success")
            prog.message(_("Success!"))
            MessageArea.close()
            self.unset_op(device)

        assert self._appl

        if connect:
            self.set_op(self.SelectedDevice, _("Connecting..."))
            self._appl.ConnectService("(os)",
                                      device.get_object_path(),
                                      '00000000-0000-0000-0000-000000000000',
                                      result_handler=success,
                                      error_handler=fail,
                                      timeout=GLib.MAXINT)
        else:
            self.set_op(self.SelectedDevice, _("Disconnecting..."))
            self._appl.DisconnectService(
                "(osd)",
                device.get_object_path(),
                '00000000-0000-0000-0000-000000000000',
                0,
                result_handler=success,
                error_handler=fail,
                timeout=GLib.MAXINT)

        prog = ManagerProgressbar(self.Blueman, False)
        prog.start()

    def show_generic_connect_calc(self, device_uuids):
        # Generic (dis)connect
        for uuid in device_uuids:
            service_uuid = ServiceUUID(uuid)
            if service_uuid.short_uuid in (AUDIO_SOURCE_SVCLASS_ID,
                                           AUDIO_SINK_SVCLASS_ID,
                                           HANDSFREE_AGW_SVCLASS_ID,
                                           HANDSFREE_SVCLASS_ID,
                                           HEADSET_SVCLASS_ID, HID_SVCLASS_ID,
                                           0x1812):
                return True
            elif not service_uuid.reserved:
                if uuid == '03b80e5a-ede8-4b33-a751-6ce34ec4c700':
                    return True
        # LE devices do not appear to expose certain properties like uuids until connect to at least once.
        return not device_uuids

    def generate(self):
        self.clear()

        items: List[Tuple[int, Gtk.MenuItem]] = []

        if not self.is_popup or self.props.visible:
            selected = self.Blueman.List.selected()
            if not selected:
                return
            row = self.Blueman.List.get(selected, "alias", "paired",
                                        "connected", "trusted", "objpush",
                                        "device")
        else:
            (x, y) = self.Blueman.List.get_pointer()
            path = self.Blueman.List.get_path_at_pos(x, y)
            if path is not None:
                row = self.Blueman.List.get(path[0], "alias", "paired",
                                            "connected", "trusted", "objpush",
                                            "device")
            else:
                return

        self.SelectedDevice = row["device"]

        op = self.get_op(self.SelectedDevice)

        if op is not None:
            item = create_menuitem(op, "network-transmit-receive")
            item.props.sensitive = False
            item.show()
            self.append(item)
            return

        show_generic_connect = self.show_generic_connect_calc(
            self.SelectedDevice['UUIDs'])

        if not row["connected"] and show_generic_connect:
            connect_item = create_menuitem(_("_<b>Connect</b>"), "blueman")
            connect_item.connect("activate", self.generic_connect,
                                 self.SelectedDevice, True)
            connect_item.props.tooltip_text = _(
                "Connects auto connect profiles A2DP source, A2DP sink, and HID"
            )
            connect_item.show()
            self.append(connect_item)
        elif show_generic_connect:
            connect_item = create_menuitem(_("_<b>Disconnect</b>"),
                                           "network-offline")
            connect_item.props.tooltip_text = _(
                "Forcefully disconnect the device")
            connect_item.connect("activate", self.generic_connect,
                                 self.SelectedDevice, False)
            connect_item.show()
            self.append(connect_item)

        rets = self.Blueman.Plugins.run("on_request_menu_items", self,
                                        self.SelectedDevice)

        for ret in rets:
            if ret:
                for (item, pos) in ret:
                    items.append((pos, item))

        logging.debug(row["alias"])

        have_disconnectables = False
        have_connectables = False

        if True in map(lambda x: 100 <= x[0] < 200, items):
            have_disconnectables = True

        if True in map(lambda x: x[0] < 100, items):
            have_connectables = True

        if True in map(lambda x: x[0] >= 200,
                       items) and (have_connectables or have_disconnectables):
            item = Gtk.SeparatorMenuItem()
            item.show()
            items.append((199, item))

        if have_connectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Connect To:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((0, item))

        if have_disconnectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Disconnect:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((99, item))

        items.sort(key=itemgetter(0))
        for priority, item in items:
            self.append(item)

        if items:
            item = Gtk.SeparatorMenuItem()
            item.show()
            self.append(item)

        del items

        send_item = create_menuitem(_("Send a _File..."), "edit-copy")
        send_item.props.sensitive = False
        self.append(send_item)
        send_item.show()

        if row["objpush"]:
            send_item.connect("activate",
                              lambda x: self.Blueman.send(self.SelectedDevice))
            send_item.props.sensitive = True

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Pair"), "dialog-password")
        item.props.tooltip_text = _("Create pairing with the device")
        self.append(item)
        item.show()
        if not row["paired"]:
            item.connect("activate",
                         lambda x: self.Blueman.bond(self.SelectedDevice))
        else:
            item.props.sensitive = False

        if not row["trusted"]:
            item = create_menuitem(_("_Trust"), "blueman-trust")
            item.connect(
                "activate",
                lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            self.append(item)
            item.show()
        else:
            item = create_menuitem(_("_Untrust"), "blueman-untrust")
            self.append(item)
            item.connect(
                "activate",
                lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            item.show()
        item.props.tooltip_text = _("Mark/Unmark this device as trusted")

        item = create_menuitem(_("_Setup..."), "document-properties")
        self.append(item)
        item.connect("activate",
                     lambda x: self.Blueman.setup(self.SelectedDevice))
        item.show()
        item.props.tooltip_text = _("Run the setup assistant for this device")

        def on_rename(_item, device):
            def on_response(dialog, response_id):
                if response_id == Gtk.ResponseType.ACCEPT:
                    device.set('Alias', alias_entry.get_text())
                elif response_id == 1:
                    device.set('Alias', '')
                dialog.destroy()

            builder = Gtk.Builder()
            builder.set_translation_domain("blueman")
            bind_textdomain_codeset("blueman", "UTF-8")
            builder.add_from_file(UI_PATH + "/rename-device.ui")
            dialog = builder.get_object("dialog")
            dialog.set_transient_for(self.Blueman)
            dialog.props.icon_name = "blueman"
            alias_entry = builder.get_object("alias_entry")
            alias_entry.set_text(device['Alias'])
            dialog.connect("response", on_response)
            dialog.present()

        item = Gtk.MenuItem.new_with_mnemonic("R_ename device...")
        item.connect('activate', on_rename, self.SelectedDevice)
        self.append(item)
        item.show()

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Remove..."), "edit-delete")
        item.connect("activate",
                     lambda x: self.Blueman.remove(self.SelectedDevice))
        self.append(item)
        item.show()
        item.props.tooltip_text = _(
            "Remove this device from the known devices list")
Beispiel #16
0
class ManagerDeviceMenu(Gtk.Menu):
    __ops__ = {}
    __instances__ = []

    def __init__(self, blueman):
        super(ManagerDeviceMenu, self).__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman
        self.SelectedDevice = None

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed",
                                                                         self.on_device_property_changed)
        self._selection_done_signal = None

        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed', self._on_service_property_changed)

        try:
            self._appl = AppletService()
        except Exception:
            logging.error("** Failed to connect to applet", exc_info=True)
            self._appl = None

        self.Generate()

    def __del__(self):
        logging.debug("deleting devicemenu")

    def popup(self, *args):
        self.is_popup = True

        if not self._device_property_changed_signal:
            self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed",
                                                                             self.on_device_property_changed)

        if not self._selection_done_signal:
            def disconnectall(x):
                self.disconnect(self._device_property_changed_signal)
                self.disconnect(self._selection_done_signal)

            self._selection_done_signal = self.connect("selection-done", disconnectall)

        self.Generate()

        super().popup(*args)

    def clear(self):
        def each(child, data):
            self.remove(child)
            child.destroy()

        self.foreach(each, None)

    def set_op(self, device, message):
        ManagerDeviceMenu.__ops__[device.get_object_path()] = message
        for inst in ManagerDeviceMenu.__instances__:
            logging.info("op: regenerating instance %s" % inst)
            if inst.SelectedDevice == self.SelectedDevice and not (inst.is_popup and not inst.props.visible):
                inst.Generate()

    def get_op(self, device):
        try:
            return ManagerDeviceMenu.__ops__[device.get_object_path()]
        except KeyError:
            return None

    def unset_op(self, device):
        del ManagerDeviceMenu.__ops__[device.get_object_path()]
        for inst in ManagerDeviceMenu.__instances__:
            logging.info("op: regenerating instance %s" % inst)
            if inst.SelectedDevice == self.SelectedDevice and not (inst.is_popup and not inst.props.visible):
                inst.Generate()

    def _on_service_property_changed(self, _service, key, _value, _path):
        if key == "Connected":
            self.Generate()

    def on_connect(self, _item, service):
        device = service.device

        def success(obj, result, _user_data):
            logging.info("success")
            prog.message(_("Success!"))

            if isinstance(service, SerialPort) and SERIAL_PORT_SVCLASS_ID == service.short_uuid:
                MessageArea.show_message(_("Serial port connected to %s") % result, None, "dialog-information")
            else:
                MessageArea.close()

            self.unset_op(device)

        def fail(obj, result, _user_data):
            prog.message(_("Failed"))

            self.unset_op(device)
            logging.warning("fail %s" % result)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Connection Failed: ") + msg, tb)

        self.set_op(device, _("Connecting..."))
        prog = ManagerProgressbar(self.Blueman, False)

        if self._appl is None:
            fail(None, GLib.Error('Applet DBus Service not available'), None)
            return

        try:
            self._appl.SetTimeHint('(u)', Gtk.get_current_event_time())
        except Exception as e:
            logging.exception(e)

        self._appl.connect_service('(os)', device.get_object_path(), service.uuid,
                                   result_handler=success, error_handler=fail,
                                   timeout=GLib.MAXINT)

        prog.start()

    def on_disconnect(self, item, service, port=0):
        def ok(obj, result, user_date):
            logging.info("disconnect success")
            self.Generate()

        def err(obj, result, user_date):
            logging.warning("disconnect failed %s" % result)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Disconnection Failed: ") + msg, tb)
            self.Generate()

        if self._appl is None:
            err(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.disconnect_service('(osd)', service.device.get_object_path(), service.uuid, port,
                                      result_handler=ok, error_handler=err)

    def on_device_property_changed(self, List, device, tree_iter, key_value):
        key, value = key_value
        # print "menu:", key, value
        if List.compare(tree_iter, List.selected()):
            if key in ("Connected", "UUIDs", "Trusted", "Paired"):
                self.Generate()

    def _generic_connect(self, item, device, connect):
        def fail(obj, result, user_date):
            logging.info("fail", result)
            prog.message(_("Failed"))
            self.unset_op(device)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Connection Failed: ") + msg)

        def success(obj, result, user_data):
            logging.info("success")
            prog.message(_("Success!"))
            MessageArea.close()
            self.unset_op(device)

        if connect:
            self.set_op(self.SelectedDevice, _("Connecting..."))
            self._appl.connect_service("(os)",
                                       device.get_object_path(),
                                       '00000000-0000-0000-0000-000000000000',
                                       result_handler=success, error_handler=fail,
                                       timeout=GLib.MAXINT)
        else:
            self.set_op(self.SelectedDevice, _("Disconnecting..."))
            self._appl.disconnect_service("(osd)",
                                          device.get_object_path(),
                                          '00000000-0000-0000-0000-000000000000',
                                          0,
                                          result_handler=success, error_handler=fail,
                                          timeout=GLib.MAXINT)

        prog = ManagerProgressbar(self.Blueman, False)
        prog.start()

    def Generate(self):
        self.clear()

        items = []

        if not self.is_popup or self.props.visible:
            selected = self.Blueman.List.selected()
            if not selected:
                return
            row = self.Blueman.List.get(selected, "alias", "paired", "connected", "trusted", "objpush", "device")
        else:
            (x, y) = self.Blueman.List.get_pointer()
            path = self.Blueman.List.get_path_at_pos(x, y)
            if path is not None:
                row = self.Blueman.List.get(path[0], "alias", "paired", "connected", "trusted", "objpush", "device")
            else:
                return

        self.SelectedDevice = row["device"]

        op = self.get_op(self.SelectedDevice)

        if op is not None:
            item = create_menuitem(op, "network-transmit-recieve")
            item.props.sensitive = False
            item.show()
            self.append(item)
            return

        # Generic (dis)connect
        # LE devices do not appear to expose certain properties like uuids until connect to at least once.
        # show generic connect for these as we will not show any way to connect otherwise.
        device_uuids = self.SelectedDevice['UUIDs']
        show_generic_connect = not device_uuids
        for uuid in device_uuids:
            service_uuid = ServiceUUID(uuid)
            if service_uuid.short_uuid in (
                    AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID, HANDSFREE_AGW_SVCLASS_ID, HANDSFREE_SVCLASS_ID,
                    HEADSET_SVCLASS_ID, HID_SVCLASS_ID, 0x1812
            ):
                show_generic_connect = True
                break
            elif not service_uuid.reserved:
                show_generic_connect = uuid == '03b80e5a-ede8-4b33-a751-6ce34ec4c700'
                break

        if not row["connected"] and show_generic_connect:
            connect_item = create_menuitem(_("_Connect"), "blueman")
            connect_item.connect("activate", self._generic_connect, self.SelectedDevice, True)
            connect_item.props.tooltip_text = _("Connects auto connect profiles A2DP source, A2DP sink, and HID")
            connect_item.show()
            self.append(connect_item)
        elif show_generic_connect:
            connect_item = create_menuitem(_("_Disconnect"), "network-offline")
            connect_item.props.tooltip_text = _("Forcefully disconnect the device")
            connect_item.connect("activate", self._generic_connect, self.SelectedDevice, False)
            connect_item.show()
            self.append(connect_item)

        rets = self.Blueman.Plugins.Run("on_request_menu_items", self, self.SelectedDevice)

        for ret in rets:
            if ret:
                for (item, pos) in ret:
                    items.append((pos, item))

        logging.debug(row["alias"])

        have_disconnectables = False
        have_connectables = False

        if True in map(lambda x: 100 <= x[0] < 200, items):
            have_disconnectables = True

        if True in map(lambda x: x[0] < 100, items):
            have_connectables = True

        if True in map(lambda x: x[0] >= 200, items) and (have_connectables or have_disconnectables):
            item = Gtk.SeparatorMenuItem()
            item.show()
            items.append((199, item))

        if have_connectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Connect To:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((0, item))

        if have_disconnectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Disconnect:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((99, item))

        items.sort(key=itemgetter(0))
        for priority, item in items:
            self.append(item)

        if items:
            item = Gtk.SeparatorMenuItem()
            item.show()
            self.append(item)

        del items

        send_item = create_menuitem(_("Send a _File..."), "edit-copy")
        send_item.props.sensitive = False
        self.append(send_item)
        send_item.show()

        if row["objpush"]:
            send_item.connect("activate", lambda x: self.Blueman.send(self.SelectedDevice))
            send_item.props.sensitive = True

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Pair"), "dialog-password")
        item.props.tooltip_text = _("Create pairing with the device")
        self.append(item)
        item.show()
        if not row["paired"]:
            item.connect("activate", lambda x: self.Blueman.bond(self.SelectedDevice))
        else:
            item.props.sensitive = False

        if not row["trusted"]:
            item = create_menuitem(_("_Trust"), "blueman-trust")
            item.connect("activate", lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            self.append(item)
            item.show()
        else:
            item = create_menuitem(_("_Untrust"), "blueman-untrust")
            self.append(item)
            item.connect("activate", lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            item.show()
        item.props.tooltip_text = _("Mark/Unmark this device as trusted")

        item = create_menuitem(_("_Setup..."), "document-properties")
        self.append(item)
        item.connect("activate", lambda x: self.Blueman.setup(self.SelectedDevice))
        item.show()
        item.props.tooltip_text = _("Run the setup assistant for this device")

        def on_rename(_item, device):
            def on_response(dialog, response_id):
                if response_id == Gtk.ResponseType.ACCEPT:
                    device.set('Alias', alias_entry.get_text())
                elif response_id == 1:
                    device.set('Alias', '')
                dialog.destroy()

            builder = Gtk.Builder()
            builder.set_translation_domain("blueman")
            bind_textdomain_codeset("blueman", "UTF-8")
            builder.add_from_file(UI_PATH + "/rename-device.ui")
            dialog = builder.get_object("dialog")
            dialog.set_transient_for(self.Blueman)
            dialog.props.icon_name = "blueman"
            alias_entry = builder.get_object("alias_entry")
            alias_entry.set_text(device['Alias'])
            dialog.connect("response", on_response)
            dialog.present()

        item = Gtk.MenuItem.new_with_mnemonic("R_ename device...")
        item.connect('activate', on_rename, self.SelectedDevice)
        self.append(item)
        item.show()

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Remove..."), "edit-delete")
        item.connect("activate", lambda x: self.Blueman.remove(self.SelectedDevice))
        self.append(item)
        item.show()
        item.props.tooltip_text = _("Remove this device from the known devices list")
Beispiel #17
0
class ManagerDeviceMenu(Gtk.Menu):
    __ops__: Dict[str, str] = {}
    __instances__: List["ManagerDeviceMenu"] = []

    SelectedDevice: Device

    def __init__(self, blueman: "Blueman") -> None:
        super().__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect("device-property-changed",
                                                                         self.on_device_property_changed)
        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed', self._on_service_property_changed)

        try:
            self._appl: Optional[AppletService] = AppletService()
        except DBusProxyFailed:
            logging.error("** Failed to connect to applet", exc_info=True)
            self._appl = None

        self.generate()

    def __del__(self) -> None:
        logging.debug("deleting devicemenu")

    def popup_at_pointer(self, event: Optional[Gdk.Event]) -> None:
        self.is_popup = True
        self.generate()

        super().popup_at_pointer(event)

    def clear(self) -> None:
        def remove_and_destroy(child: Gtk.Widget) -> None:
            self.remove(child)
            child.destroy()

        self.foreach(remove_and_destroy)

    def set_op(self, device: Device, message: str) -> None:
        ManagerDeviceMenu.__ops__[device.get_object_path()] = message
        for inst in ManagerDeviceMenu.__instances__:
            logging.info(f"op: regenerating instance {inst}")
            if inst.SelectedDevice == self.SelectedDevice and not (inst.is_popup and not inst.props.visible):
                inst.generate()

    def get_op(self, device: Device) -> Optional[str]:
        try:
            return ManagerDeviceMenu.__ops__[device.get_object_path()]
        except KeyError:
            return None

    def unset_op(self, device: Device) -> None:
        del ManagerDeviceMenu.__ops__[device.get_object_path()]
        for inst in ManagerDeviceMenu.__instances__:
            logging.info(f"op: regenerating instance {inst}")
            if inst.SelectedDevice == self.SelectedDevice and not (inst.is_popup and not inst.props.visible):
                inst.generate()

    def _on_service_property_changed(self, _service: Union[AnyNetwork, AnyDevice], key: str, _value: object,
                                     _path: str) -> None:
        if key == "Connected":
            self.generate()

    GENERIC_CONNECT = "00000000-0000-0000-0000-000000000000"

    def connect_service(self, device: Device, uuid: str = GENERIC_CONNECT) -> None:
        def success(_obj: AppletService, _result: None, _user_data: None) -> None:
            logging.info("success")
            prog.message(_("Success!"))

            MessageArea.close()

            self.unset_op(device)

        def fail(_obj: Optional[AppletService], result: GLib.Error, _user_data: None) -> None:
            prog.message(_("Failed"))

            self.unset_op(device)
            logging.warning(f"fail {result}")
            self._handle_error_message(result)

        self.set_op(device, _("Connecting…"))
        prog = ManagerProgressbar(self.Blueman, cancellable=uuid == self.GENERIC_CONNECT)
        if uuid == self.GENERIC_CONNECT:
            prog.connect("cancelled", lambda x: self.disconnect_service(device))

        if self._appl is None:
            fail(None, GLib.Error('Applet DBus Service not available'), None)
            return

        def connect(error_handler: Callable[[AppletService, GLib.Error, None], None]) -> None:
            assert self._appl is not None  # https://github.com/python/mypy/issues/2608
            self._appl.ConnectService('(os)', device.get_object_path(), uuid,
                                      result_handler=success, error_handler=error_handler,
                                      timeout=GLib.MAXINT)

        def initial_error_handler(obj: AppletService, result: GLib.Error, user_date: None) -> None:
            # There are (Intel) drivers that fail to connect while a discovery is running
            if self._get_errno(result) == errno.EAGAIN:
                assert self.Blueman.List.Adapter is not None
                self.Blueman.List.Adapter.stop_discovery()
                connect(fail)
            else:
                fail(obj, result, user_date)

        connect(initial_error_handler)

        prog.start()

    def disconnect_service(self, device: Device, uuid: str = GENERIC_CONNECT, port: int = 0) -> None:
        def ok(_obj: AppletService, _result: None, _user_date: None) -> None:
            logging.info("disconnect success")
            self.generate()

        def err(_obj: Optional[AppletService], result: GLib.Error, _user_date: None) -> None:
            logging.warning(f"disconnect failed {result}")
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Disconnection Failed: ") + msg, tb)
            self.generate()

        if self._appl is None:
            err(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.DisconnectService('(osd)', device.get_object_path(), uuid, port,
                                     result_handler=ok, error_handler=err, timeout=GLib.MAXINT)

    def on_device_property_changed(self, lst: "ManagerDeviceList", _device: Device, tree_iter: Gtk.TreeIter,
                                   key_value: Tuple[str, object]) -> None:
        key, value = key_value
        # print "menu:", key, value
        if lst.compare(tree_iter, lst.selected()):
            if key in ("Connected", "UUIDs", "Trusted", "Paired", "Blocked"):
                self.generate()

    def _handle_error_message(self, error: GLib.Error) -> None:
        err = self._get_errno(error)

        if err == errno.ENOPROTOOPT:
            logging.warning("No audio endpoints registered to bluetoothd. "
                            "Pulseaudio Bluetooth module, bluez-alsa, PipeWire or other audio support missing.")
            msg = _("No audio endpoints registered")
        elif err == errno.EIO:
            logging.warning("bluetoothd reported input/output error. Check its logs for context.")
            msg = _("Input/output error")
        elif err == errno.EHOSTDOWN:
            msg = _("Device did not respond")
        elif err == errno.EAGAIN:
            logging.warning("bluetoothd reported resource temporarily unavailable. "
                            "Retry or check its logs for context.")
            msg = _("Resource temporarily unavailable")
        else:
            msg = error.message.split(":", 3)[-1].strip()

        if msg != "Cancelled":
            MessageArea.show_message(_("Connection Failed: ") + msg)

    @staticmethod
    def _get_errno(error: GLib.Error) -> Optional[int]:
        msg = error.message.split(":", 3)[-1].strip()

        # https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/gnu/errlist.h
        # https://git.musl-libc.org/cgit/musl/tree/src/errno/__strerror.h
        # https://git.uclibc.org/uClibc/tree/libc/string/_string_syserrmsgs.c
        if msg == "Protocol not available":
            return errno.ENOPROTOOPT
        if msg in ("Input/output error", "I/O error"):
            return errno.EIO
        if msg == "Host is down":
            # Bluetooth errors 0x04 (Page Timeout) or 0x3c (Advertising Timeout)
            return errno.EHOSTDOWN
        if msg == "Resource temporarily unavailable":
            return errno.EAGAIN

        return None

    def show_generic_connect_calc(self, device_uuids: Iterable[str]) -> bool:
        # Generic (dis)connect
        for uuid in device_uuids:
            service_uuid = ServiceUUID(uuid)
            if service_uuid.short_uuid in (
                    AUDIO_SOURCE_SVCLASS_ID, AUDIO_SINK_SVCLASS_ID, HANDSFREE_AGW_SVCLASS_ID, HANDSFREE_SVCLASS_ID,
                    HEADSET_SVCLASS_ID, HID_SVCLASS_ID, 0x1812
            ):
                return True
            elif not service_uuid.reserved:
                if uuid == '03b80e5a-ede8-4b33-a751-6ce34ec4c700':
                    return True
        # LE devices do not appear to expose certain properties like uuids until connect to at least once.
        return not device_uuids

    def generate(self) -> None:
        self.clear()

        if not self.is_popup or self.props.visible:
            selected = self.Blueman.List.selected()
            if not selected:
                return
            row = self.Blueman.List.get(selected, "alias", "paired", "connected", "trusted", "objpush", "device",
                                        "blocked")
        else:
            (x, y) = self.Blueman.List.get_pointer()
            path = self.Blueman.List.get_path_at_pos(x, y)
            if path is not None:
                assert path[0] is not None
                row = self.Blueman.List.get(path[0], "alias", "paired", "connected", "trusted", "objpush", "device",
                                            "blocked")
            else:
                return

        self.SelectedDevice = row["device"]

        op = self.get_op(self.SelectedDevice)

        if op is not None:
            item: Gtk.MenuItem = create_menuitem(op, "network-transmit-receive-symbolic")
            item.props.sensitive = False
            item.show()
            self.append(item)
            return

        show_generic_connect = self.show_generic_connect_calc(self.SelectedDevice['UUIDs'])

        if not row["connected"] and show_generic_connect:
            connect_item = create_menuitem(_("<b>_Connect</b>"), "bluetooth-symbolic")
            connect_item.connect("activate", lambda _item: self.connect_service(self.SelectedDevice))
            connect_item.props.tooltip_text = _("Connects auto connect profiles A2DP source, A2DP sink, and HID")
            connect_item.show()
            self.append(connect_item)
        elif show_generic_connect:
            connect_item = create_menuitem(_("<b>_Disconnect</b>"), "bluetooth-disabled-symbolic")
            connect_item.props.tooltip_text = _("Forcefully disconnect the device")
            connect_item.connect("activate", lambda _item: self.disconnect_service(self.SelectedDevice))
            connect_item.show()
            self.append(connect_item)

        logging.debug(row["alias"])

        items = [item for plugin in self.Blueman.Plugins.get_loaded_plugins(MenuItemsProvider)
                 for item in plugin.on_request_menu_items(self, self.SelectedDevice)]

        connect_items = [i for i in items if i.group == DeviceMenuItem.Group.CONNECT]
        disconnect_items = [i for i in items if i.group == DeviceMenuItem.Group.DISCONNECT]
        autoconnect_items = [item for item in items if item.group == DeviceMenuItem.Group.AUTOCONNECT]
        action_items = [i for i in items if i.group == DeviceMenuItem.Group.ACTIONS]

        if connect_items:
            self.append(self._create_header(_("<b>Connect To:</b>")))
            for it in sorted(connect_items, key=lambda i: i.position):
                self.append(it.item)

        if disconnect_items:
            self.append(self._create_header(_("<b>Disconnect:</b>")))
            for it in sorted(disconnect_items, key=lambda i: i.position):
                self.append(it.item)

        config = AutoConnectConfig()
        generic_service = ServiceUUID("00000000-0000-0000-0000-000000000000")
        generic_autoconnect = (self.SelectedDevice.get_object_path(), str(generic_service)) in set(config["services"])

        if row["connected"] or generic_autoconnect or autoconnect_items:
            self.append(self._create_header(_("<b>Auto-connect:</b>")))

            if row["connected"] or generic_autoconnect:
                item = Gtk.CheckMenuItem(label=generic_service.name)
                config.bind_to_menuitem(item, self.SelectedDevice, str(generic_service))
                item.show()
                self.append(item)

            for it in sorted(autoconnect_items, key=lambda i: i.position):
                self.append(it.item)

        if show_generic_connect or connect_items or disconnect_items or autoconnect_items:
            item = Gtk.SeparatorMenuItem()
            item.show()
            self.append(item)

        for it in sorted(action_items, key=lambda i: i.position):
            self.append(it.item)

        send_item = create_menuitem(_("Send a _File…"), "blueman-send-symbolic")
        send_item.props.sensitive = False
        self.append(send_item)
        send_item.show()

        if row["objpush"]:
            send_item.connect("activate", lambda x: self.Blueman.send(self.SelectedDevice))
            send_item.props.sensitive = True

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Pair"), "blueman-pair-symbolic")
        item.props.tooltip_text = _("Create pairing with the device")
        self.append(item)
        item.show()
        if not row["paired"]:
            item.connect("activate", lambda x: self.Blueman.bond(self.SelectedDevice))
        else:
            item.props.sensitive = False

        if not row["trusted"]:
            item = create_menuitem(_("_Trust"), "blueman-trust-symbolic")
            item.connect("activate", lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            self.append(item)
            item.show()
        else:
            item = create_menuitem(_("_Untrust"), "blueman-untrust-symbolic")
            self.append(item)
            item.connect("activate", lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            item.show()
        item.props.tooltip_text = _("Mark/Unmark this device as trusted")

        if not row["blocked"]:
            item = create_menuitem(_("_Block"), "blueman-block-symbolic")
            item.connect("activate", lambda x: self.Blueman.toggle_blocked(self.SelectedDevice))
            self.append(item)
            item.show()
        else:
            item = create_menuitem(_("_Unblock"), "blueman-block-symbolic")
            self.append(item)
            item.connect("activate", lambda x: self.Blueman.toggle_blocked(self.SelectedDevice))
            item.show()
        item.props.tooltip_text = _("Block/Unblock this device")

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

        item = Gtk.MenuItem.new_with_mnemonic(_("R_ename device…"))
        item.connect('activate', on_rename, self.SelectedDevice)
        self.append(item)
        item.show()

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Remove…"), "list-remove-symbolic")
        item.connect("activate", lambda x: self.Blueman.remove(self.SelectedDevice))
        self.append(item)
        item.show()
        item.props.tooltip_text = _("Remove this device from the known devices list")

    @staticmethod
    def _create_header(text: str) -> Gtk.MenuItem:
        item = Gtk.MenuItem()
        label = Gtk.Label()
        label.set_markup(text)
        label.props.xalign = 0.0

        label.show()
        item.add(label)
        item.props.sensitive = False
        item.show()
        return item
Beispiel #18
0
class NetUsage(AppletPlugin, GObject.GObject):
    __depends__ = ["Menu"]
    __icon__ = "network-wireless"
    __description__ = _(
        "Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited "
        "data access plans. This plugin tracks every device seperately.")
    __author__ = "Walmis"
    __autoload__ = False
    __gsignals__ = {
        'monitor-added':
        (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, )),
        'monitor-removed':
        (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, )),
        # monitor, tx, rx
        'stats': (GObject.SignalFlags.NO_HOOKS, None, (
            GObject.TYPE_PYOBJECT,
            GObject.TYPE_PYOBJECT,
            GObject.TYPE_PYOBJECT,
        )),
    }

    _any_network = None

    def on_load(self):
        GObject.GObject.__init__(self)
        self.monitors = []
        self.devices = weakref.WeakValueDictionary()

        self.bus = dbus.SystemBus()

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_network_property_changed)

        self.parent.Plugins.Menu.add(self,
                                     84,
                                     text=_("Network _Usage"),
                                     icon_name="network-wireless",
                                     tooltip=_("Shows network traffic usage"),
                                     callback=self.activate_ui)

        self.bus.add_signal_receiver(
            self.on_nm_ppp_stats,
            "PppStats",
            "org.freedesktop.NetworkManager.Device.Serial",
            path_keyword="path")
        self.nm_paths = {}

    def on_nm_ppp_stats(self, down, up, path):
        if path not in self.nm_paths:
            props = self.bus.call_blocking(
                "org.freedesktop.NetworkManager", path,
                "org.freedesktop.DBus.Properties", "GetAll", "s",
                ["org.freedesktop.NetworkManager.Device"])

            if props["Driver"] == "bluetooth" and "rfcomm" in props[
                    "Interface"]:
                self.nm_paths[path] = True

                portid = int(props["Interface"].strip("rfcomm"))

                ls = rfcomm_list()
                for dev in ls:
                    if dev["id"] == portid:
                        adapter = self.parent.Manager.get_adapter(dev["src"])
                        device = self.parent.Manager.find_device(
                            dev["dst"], adapter.get_object_path())

                        self.monitor_interface(NMMonitor, device, path)

                        return
            else:
                self.nm_paths[path] = False

    def _on_network_property_changed(self, _network, key, value, path):
        if key == "Interface" and value != "":
            d = Device(path)
            self.monitor_interface(Monitor, d, value)

    def activate_ui(self):
        Dialog(self)

    def on_unload(self):
        self.bus.remove_signal_receiver(
            self.on_nm_ppp_stats,
            "PppStats",
            "org.freedesktop.NetworkManager.Device.Serial",
            path_keyword="path")
        del self._any_network
        self.parent.Plugins.Menu.unregister(self)

    def monitor_interface(self, montype, *args):
        m = montype(*args)
        self.monitors.append(m)
        m.connect("stats", self.on_stats)
        m.connect("disconnected", self.on_monitor_disconnected)
        self.emit("monitor-added", m)

    def on_ppp_connected(self, device, rfcomm, ppp_port):
        self.monitor_interface(Monitor, device, ppp_port)

    def on_monitor_disconnected(self, monitor):
        self.monitors.remove(monitor)
        self.emit("monitor-removed", monitor)

    def on_stats(self, monitor, tx, rx):
        self.emit("stats", monitor, tx, rx)
Beispiel #19
0
class NetUsage(AppletPlugin, GObject.GObject):
    __depends__ = ["Menu"]
    __icon__ = "network-wireless"
    __description__ = _(
        "Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited "
        "data access plans. This plugin tracks every device seperately.")
    __author__ = "Walmis"
    __autoload__ = False
    __gsignals__ = {
        'monitor-added':
        (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, )),
        'monitor-removed':
        (GObject.SignalFlags.NO_HOOKS, None, (GObject.TYPE_PYOBJECT, )),
        # monitor, tx, rx
        'stats': (GObject.SignalFlags.NO_HOOKS, None, (
            GObject.TYPE_PYOBJECT,
            GObject.TYPE_PYOBJECT,
            GObject.TYPE_PYOBJECT,
        )),
    }

    _any_network = None

    def on_load(self):
        GObject.GObject.__init__(self)
        self.monitors = []

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_network_property_changed)

        self.parent.Plugins.Menu.add(self,
                                     84,
                                     text=_("Network _Usage"),
                                     icon_name="network-wireless",
                                     tooltip=_("Shows network traffic usage"),
                                     callback=self.activate_ui)

    def _on_network_property_changed(self, _network, key, value, path):
        if key == "Interface" and value != "":
            d = Device(path)
            self.monitor_interface(Monitor, d, value)

    def activate_ui(self):
        Dialog(self)

    def on_unload(self):
        del self._any_network
        self.parent.Plugins.Menu.unregister(self)

    def monitor_interface(self, montype, *args):
        m = montype(*args)
        self.monitors.append(m)
        m.connect("stats", self.on_stats)
        m.connect("disconnected", self.on_monitor_disconnected)
        self.emit("monitor-added", m)

    def on_ppp_connected(self, device, rfcomm, ppp_port):
        self.monitor_interface(Monitor, device, ppp_port)

    def on_monitor_disconnected(self, monitor):
        self.monitors.remove(monitor)
        self.emit("monitor-removed", monitor)

    def on_stats(self, monitor, tx, rx):
        self.emit("stats", monitor, tx, rx)
Beispiel #20
0
class ManagerDeviceMenu(Gtk.Menu):
    __ops__ = {}
    __instances__ = []

    def __init__(self, blueman):
        super(ManagerDeviceMenu, self).__init__()
        self.set_name("ManagerDeviceMenu")
        self.Blueman = blueman
        self.SelectedDevice = None

        self.is_popup = False

        self._device_property_changed_signal = self.Blueman.List.connect(
            "device-property-changed", self.on_device_property_changed)
        self._selection_done_signal = None

        ManagerDeviceMenu.__instances__.append(self)

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_service_property_changed)

        self._any_device = AnyDevice()
        self._any_device.connect_signal('property-changed',
                                        self._on_service_property_changed)

        try:
            self._appl = AppletService()
        except Exception:
            logging.error("** Failed to connect to applet", exc_info=True)
            self._appl = None

        self.Generate()

    def __del__(self):
        logging.debug("deleting devicemenu")

    def popup(self, *args):
        self.is_popup = True

        if not self._device_property_changed_signal:
            self._device_property_changed_signal = self.Blueman.List.connect(
                "device-property-changed", self.on_device_property_changed)

        if not self._selection_done_signal:

            def disconnectall(x):
                self.disconnect(self._device_property_changed_signal)
                self.disconnect(self._selection_done_signal)

            self._selection_done_signal = self.connect("selection-done",
                                                       disconnectall)

        self.Generate()

        Gtk.Menu.popup(self, *args)

    def clear(self):
        def each(child, data):
            self.remove(child)
            child.destroy()

        self.foreach(each, None)

    def set_op(self, device, message):
        ManagerDeviceMenu.__ops__[device.get_object_path()] = message
        for inst in ManagerDeviceMenu.__instances__:
            logging.info("op: regenerating instance %s" % inst)
            if inst.SelectedDevice == self.SelectedDevice and not (
                    inst.is_popup and not inst.props.visible):
                inst.Generate()

    def get_op(self, device):
        try:
            return ManagerDeviceMenu.__ops__[device.get_object_path()]
        except KeyError:
            return None

    def unset_op(self, device):
        del ManagerDeviceMenu.__ops__[device.get_object_path()]
        for inst in ManagerDeviceMenu.__instances__:
            logging.info("op: regenerating instance %s" % inst)
            if inst.SelectedDevice == self.SelectedDevice and not (
                    inst.is_popup and not inst.props.visible):
                inst.Generate()

    def _on_service_property_changed(self, _service, key, _value, _path):
        if key == "Connected":
            self.Generate()

    def on_connect(self, _item, service):
        device = service.device

        def success(obj, result, _user_data):
            logging.info("success")
            prog.message(_("Success!"))

            if isinstance(service, SerialPort
                          ) and SERIAL_PORT_SVCLASS_ID == uuid128_to_uuid16(
                              service.uuid):
                MessageArea.show_message(
                    _("Serial port connected to %s") % result, None,
                    "dialog-information")
            else:
                MessageArea.close()

            self.unset_op(device)

        def fail(obj, result, _user_data):
            prog.message(_("Failed"))

            self.unset_op(device)
            logging.warning("fail %s" % result)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Connection Failed: ") + msg, tb)

        self.set_op(device, _("Connecting..."))
        prog = ManagerProgressbar(self.Blueman, False)

        if self._appl is None:
            fail(None, GLib.Error('Applet DBus Service not available'), None)
            return

        try:
            self._appl.SetTimeHint(str('(u)'), Gtk.get_current_event_time())
        except Exception as e:
            logging.exception(e)

        self._appl.connect_service(str('(os)'),
                                   device.get_object_path(),
                                   service.uuid,
                                   result_handler=success,
                                   error_handler=fail,
                                   timeout=GLib.MAXINT)

        prog.start()

    def on_disconnect(self, item, service, port=0):
        def ok(obj, result, user_date):
            logging.info("disconnect success")
            self.Generate()

        def err(obj, result, user_date):
            logging.warning("disconnect failed %s" % result)
            msg, tb = e_(result.message)
            MessageArea.show_message(_("Disconnection Failed: ") + msg, tb)
            self.Generate()

        if self._appl is None:
            err(None, GLib.Error('Applet DBus Service not available'), None)
            return

        self._appl.disconnect_service(str('(osd)'),
                                      service.device.get_object_path(),
                                      service.uuid,
                                      port,
                                      result_handler=ok,
                                      error_handler=err)

    def on_device_property_changed(self, List, device, tree_iter, key_value):
        key, value = key_value
        # print "menu:", key, value
        if List.compare(tree_iter, List.selected()):
            if key == "Connected" \
                or key == "UUIDs" \
                or key == "Trusted" \
                or key == "Paired":
                self.Generate()

    def Generate(self):
        self.clear()

        items = []

        if not self.is_popup or self.props.visible:
            selected = self.Blueman.List.selected()
            if not selected:
                return
            row = self.Blueman.List.get(selected, "alias", "bonded",
                                        "connected", "trusted", "objpush",
                                        "device")
        else:
            (x, y) = self.Blueman.List.get_pointer()
            path = self.Blueman.List.get_path_at_pos(x, y)
            if path is not None:
                row = self.Blueman.List.get(path[0], "alias", "bonded",
                                            "connected", "trusted", "objpush",
                                            "device")
            else:
                return

        self.SelectedDevice = row["device"]

        op = self.get_op(self.SelectedDevice)

        if op is not None:
            item = create_menuitem(op, get_icon("network-transmit-recieve",
                                                16))
            item.props.sensitive = False
            item.show()
            self.append(item)
            return

        rets = self.Blueman.Plugins.Run("on_request_menu_items", self,
                                        self.SelectedDevice)

        for ret in rets:
            if ret:
                for (item, pos) in ret:
                    items.append((pos, item))

        logging.debug(row["alias"])

        have_disconnectables = False
        have_connectables = False

        if True in map(lambda x: 100 <= x[0] < 200, items):
            have_disconnectables = True

        if True in map(lambda x: x[0] < 100, items):
            have_connectables = True

        if True in map(lambda x: x[0] >= 200,
                       items) and (have_connectables or have_disconnectables):
            item = Gtk.SeparatorMenuItem()
            item.show()
            items.append((199, item))

        if have_connectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Connect To:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((0, item))

        if have_disconnectables:
            item = Gtk.MenuItem()
            label = Gtk.Label()
            label.set_markup(_("<b>Disconnect:</b>"))
            label.props.xalign = 0.0

            label.show()
            item.add(label)
            item.props.sensitive = False
            item.show()
            items.append((99, item))

        items.sort(key=itemgetter(0))
        for priority, item in items:
            self.append(item)

        if items:
            item = Gtk.SeparatorMenuItem()
            item.show()
            self.append(item)

        del items

        send_item = create_menuitem(_("Send a _File..."),
                                    get_icon("edit-copy", 16))
        send_item.props.sensitive = False
        self.append(send_item)
        send_item.show()

        if row["objpush"]:
            send_item.connect("activate",
                              lambda x: self.Blueman.send(self.SelectedDevice))
            send_item.props.sensitive = True

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Pair"), get_icon("dialog-password", 16))
        item.props.tooltip_text = _("Create pairing with the device")
        self.append(item)
        item.show()
        if not row["bonded"]:
            item.connect("activate",
                         lambda x: self.Blueman.bond(self.SelectedDevice))
        else:
            item.props.sensitive = False

        if not row["trusted"]:
            item = create_menuitem(_("_Trust"), get_icon("blueman-trust", 16))
            item.connect(
                "activate",
                lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            self.append(item)
            item.show()
        else:
            item = create_menuitem(_("_Untrust"),
                                   get_icon("blueman-untrust", 16))
            self.append(item)
            item.connect(
                "activate",
                lambda x: self.Blueman.toggle_trust(self.SelectedDevice))
            item.show()
        item.props.tooltip_text = _("Mark/Unmark this device as trusted")

        item = create_menuitem(_("_Setup..."),
                               get_icon("document-properties", 16))
        self.append(item)
        item.connect("activate",
                     lambda x: self.Blueman.setup(self.SelectedDevice))
        item.show()
        item.props.tooltip_text = _("Run the setup assistant for this device")

        def on_rename(_item, device):
            def on_response(dialog, response_id):
                if response_id == Gtk.ResponseType.ACCEPT:
                    device.set('Alias', alias_entry.get_text())
                elif response_id == 1:
                    device.set('Alias', '')
                dialog.destroy()

            builder = Gtk.Builder()
            builder.set_translation_domain("blueman")
            bind_textdomain_codeset("blueman", "UTF-8")
            builder.add_from_file(UI_PATH + "/rename-device.ui")
            dialog = builder.get_object("dialog")
            dialog.set_transient_for(self.Blueman)
            dialog.props.icon_name = "blueman"
            alias_entry = builder.get_object("alias_entry")
            alias_entry.set_text(device['Alias'])
            dialog.connect("response", on_response)
            dialog.present()

        item = Gtk.MenuItem.new_with_mnemonic("R_ename device...")
        item.connect('activate', on_rename, self.SelectedDevice)
        self.append(item)
        item.show()

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Remove..."), get_icon("edit-delete", 16))
        item.connect("activate",
                     lambda x: self.Blueman.remove(self.SelectedDevice))
        self.append(item)
        item.show()
        item.props.tooltip_text = _(
            "Remove this device from the known devices list")

        item = Gtk.SeparatorMenuItem()
        item.show()
        self.append(item)

        item = create_menuitem(_("_Disconnect"),
                               get_icon("network-offline", 16))
        item.props.tooltip_text = _("Forcefully disconnect the device")

        self.append(item)
        item.show()

        def on_disconnect(item):
            def finished(*args):
                self.unset_op(self.SelectedDevice)

            self.set_op(self.SelectedDevice, _("Disconnecting..."))
            self.Blueman.disconnect(self.SelectedDevice,
                                    result_handler=finished,
                                    error_handler=finished)

        if row['connected']:
            item.connect("activate", on_disconnect)

        else:
            item.props.sensitive = False
Beispiel #21
0
class NetUsage(AppletPlugin, GObject.GObject, PPPConnectedListener):
    __depends__ = ["Menu"]
    __icon__ = "network-wireless"
    __description__ = _(
        "Allows you to monitor your (mobile broadband) network traffic usage. Useful for limited "
        "data access plans. This plugin tracks every device seperately.")
    __author__ = "Walmis"
    __autoload__ = False
    __gsignals__: GSignals = {
        'monitor-added': (GObject.SignalFlags.NO_HOOKS, None, (Monitor, )),
        'monitor-removed': (GObject.SignalFlags.NO_HOOKS, None, (Monitor, )),
        # monitor, tx, rx
        'stats': (GObject.SignalFlags.NO_HOOKS, None, (Monitor, int, int)),
    }

    _any_network = None

    def on_load(self) -> None:
        GObject.GObject.__init__(self)
        self.monitors: List[Monitor] = []

        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_network_property_changed)

        self.parent.Plugins.Menu.add(self,
                                     84,
                                     text=_("Network _Usage"),
                                     icon_name="network-wireless",
                                     tooltip=_("Shows network traffic usage"),
                                     callback=self.activate_ui)

    def _on_network_property_changed(self, _network: AnyNetwork, key: str,
                                     value: Any, path: str) -> None:
        if key == "Interface" and value != "":
            d = Device(obj_path=path)
            self.monitor_interface(d, value)

    def activate_ui(self) -> None:
        Dialog(self)

    def on_unload(self) -> None:
        del self._any_network
        self.parent.Plugins.Menu.unregister(self)

    def monitor_interface(self, device: Device, interface: str) -> None:
        m = Monitor(device, interface)
        self.monitors.append(m)
        m.connect("stats", self.on_stats)
        m.connect("disconnected", self.on_monitor_disconnected)
        self.emit("monitor-added", m)

    def on_ppp_connected(self, device: Device, _rfcomm: str,
                         ppp_port: str) -> None:
        self.monitor_interface(device, ppp_port)

    def on_monitor_disconnected(self, monitor: Monitor) -> None:
        self.monitors.remove(monitor)
        self.emit("monitor-removed", monitor)

    def on_stats(self, monitor: Monitor, tx: int, rx: int) -> None:
        self.emit("stats", monitor, tx, rx)
Beispiel #22
0
class DhcpClient(AppletPlugin):
    __description__ = _(
        "Provides a basic dhcp client for Bluetooth PAN connections.")
    __icon__ = "network"
    __author__ = "Walmis"

    _any_network = None

    def on_load(self, applet):
        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed',
                                         self._on_network_prop_changed)

        self.quering = []

    def on_unload(self):
        del self._any_network

    @dbus.service.method('org.blueman.Applet', in_signature="s")
    def DhcpClient(self, interface):
        self.dhcp_acquire(interface)

    def _on_network_prop_changed(self, _network, key, value, _path):
        if key == "Interface":
            if value != "":
                self.dhcp_acquire(value)

    def dhcp_acquire(self, device):
        if device not in self.quering:
            self.quering.append(device)
        else:
            return

        if device != "":

            def reply(ip_address):
                Notification(_("Bluetooth Network"),
                             _("Interface %(0)s bound to IP address %(1)s") % {
                                 "0": device,
                                 "1": ip_address
                             },
                             pixbuf=get_icon("network-workgroup", 48),
                             status_icon=self.Applet.Plugins.StatusIcon)

                self.quering.remove(device)

            def err(msg):
                dprint(msg)
                Notification(_("Bluetooth Network"),
                             _("Failed to obtain an IP address on %s") %
                             (device),
                             pixbuf=get_icon("network-workgroup", 48),
                             status_icon=self.Applet.Plugins.StatusIcon)

                self.quering.remove(device)

            Notification(
                _("Bluetooth Network"),
                _("Trying to obtain an IP address on %s\nPlease wait..." %
                  device),
                pixbuf=get_icon("network-workgroup", 48),
                status_icon=self.Applet.Plugins.StatusIcon)

            m = Mechanism()
            m.DhcpClient(device,
                         reply_handler=reply,
                         error_handler=err,
                         timeout=120)
Beispiel #23
0
    def on_load(self, applet):
        self._any_network = AnyNetwork()
        self._any_network.connect_signal('property-changed', self._on_network_prop_changed)

        self.quering = []