예제 #1
0
    def _on_authorize_service(self, device, uuid, ok, err):
        def on_auth_action(action):
            logging.info(action)

            if action == "always":
                device = bluez.Device(n._device)
                device.set("Trusted", True)
            if action == "always" or action == "accept":
                ok()
            else:
                err(BluezErrorRejected("Rejected"))

            self.n = None

        logging.info("Agent.Authorize")
        dev_str = self.get_device_string(device)
        service = ServiceUUID(uuid).name
        notify_message = \
            (_("Authorization request for:") + "\n%s\n" + _("Service:") + " <b>%s</b>") % (dev_str, service)
        actions = [["always", _("Always accept")],
                   ["accept", _("Accept")],
                   ["deny", _("Deny")]]

        n = Notification(_("Bluetooth Authentication"), notify_message, 0, actions, on_auth_action, icon_name="blueman")
        n.show()
        n._device = device
예제 #2
0
    def _on_authorize_service(self, parameters, invocation):
        def on_auth_action(n, action):
            dprint(action)

            #self.applet.status_icon.set_blinking(False)
            if action == "always":
                device = Bluez.Device(n._device)
                device.set("Trusted", True)
            if action == "always" or action == "accept":
                invocation.return_value(GLib.Variant('()', ()))
            else:
                invocation.return_dbus_error('org.bluez.Error.Rejected', 'Rejected')

            self.n = None

        device, uuid = parameters.unpack()

        dprint("Agent.Authorize")
        alias = self.get_device_alias(device)
        uuid16 = uuid128_to_uuid16(uuid)
        service = uuid16_to_name(uuid16)
        notify_message = (_("Authorization request for:") + "\n%s\n" + _("Service:") + " <b>%s</b>") % (alias, service)
        actions = [["always", _("Always accept")],
                   ["accept", _("Accept")],
                   ["deny", _("Deny")]]

        n = Notification(_("Bluetooth Authentication"), notify_message, 0,
                         actions, on_auth_action,
                         pixbuf=get_icon("blueman", 48), status_icon=self.status_icon)
        n._device = device
예제 #3
0
    def _on_authorize_service(self, parameters, invocation):
        def on_auth_action(action):
            logging.info(action)

            if action == "always":
                device = Bluez.Device(n._device)
                device.set("Trusted", True)
            if action == "always" or action == "accept":
                invocation.return_value(GLib.Variant('()', ()))
            else:
                invocation.return_dbus_error('org.bluez.Error.Rejected', 'Rejected')

            self.n = None

        device, uuid = parameters.unpack()

        logging.info("Agent.Authorize")
        dev_str = self.get_device_string(device)
        service = ServiceUUID(uuid).name
        notify_message = (_("Authorization request for:") + "\n%s\n" + _("Service:") + " <b>%s</b>") % (dev_str, service)
        actions = [["always", _("Always accept")],
                   ["accept", _("Accept")],
                   ["deny", _("Deny")]]

        n = Notification(_("Bluetooth Authentication"), notify_message, 0, actions, on_auth_action,
                         icon_name="blueman", pos_hint=self.status_icon.geometry)
        n.show()
        n._device = device
예제 #4
0
    def Authorize(self, device, uuid, ok, err):

        def on_auth_action(n, action):
            dprint(action)

            #self.applet.status_icon.set_blinking(False)
            if action == "always":
                device = Bluez.Device(n._device)
                device.set("Trusted", True)
            if action == "always" or action == "accept":
                ok()
            else:
                err(AgentErrorRejected())

            self.n = None

        dprint("Agent.Authorize")
        alias = self.get_device_alias(device)
        uuid16 = uuid128_to_uuid16(uuid)
        service = uuid16_to_name(uuid16)
        notify_message = (_("Authorization request for:") + "\n%s\n" + _("Service:") + " <b>%s</b>") % (alias, service)
        actions = [["always", _("Always accept"), "blueman-trust"],
                   ["accept", _("Accept"), "help-about"],
                   ["deny", _("Deny"), "help-about"]]

        n = Notification(_("Bluetooth Authentication"), notify_message, 0,
                         actions, on_auth_action,
                         pixbuf=get_icon("blueman", 48), status_icon=self.status_icon)
        n._device = device
예제 #5
0
    def _on_display_passkey(self, device, passkey, _entered):
        logging.info('DisplayPasskey (%s, %d)' % (device, passkey))
        dev = Device(device)
        dev.connect_signal("property-changed",
                           self._on_device_property_changed)

        notify_message = _("Pairing passkey for") + " %s: %s" % (
            self.get_device_string(device), passkey)
        self.n = Notification("Bluetooth",
                              notify_message,
                              0,
                              icon_name="blueman")
        self.n.show()
예제 #6
0
    def _on_display_pin_code(self, device: str, pin_code: str) -> None:
        logging.info(f'DisplayPinCode ({device}, {pin_code})')
        dev = Device(obj_path=device)
        self._devhandlerids[device] = dev.connect_signal(
            "property-changed", self._on_device_property_changed)

        notify_message = _("Pairing PIN code for"
                           ) + f" {self.get_device_string(device)}: {pin_code}"
        self.n = Notification("Bluetooth",
                              notify_message,
                              0,
                              icon_name="blueman")
        self.n.show()
예제 #7
0
    def _on_display_passkey(self, device, passkey, _entered):
        logging.info(f"DisplayPasskey ({device}, {passkey:d})")
        dev = Device(obj_path=device)
        self._devhandlerids[device] = dev.connect_signal(
            "property-changed", self._on_device_property_changed)

        notify_message = _("Pairing passkey for"
                           ) + f" {self.get_device_string(device)}: {passkey}"
        self.n = Notification("Bluetooth",
                              notify_message,
                              0,
                              icon_name="blueman")
        self.n.show()
예제 #8
0
    def _on_authorize(self, _agent, transfer_path, address=None, filename=None, size=None):
        if address and filename and size:
            # stand-alone obexd
            # FIXME: /tmp is only the default. Can we get the actual root
            # directory from stand-alone obexd?
            root = '/tmp'
        else:
            # BlueZ 5 integrated obexd
            transfer = obex.Transfer(transfer_path)
            session = obex.Session(transfer.session)
            root = session.root
            address = session.address
            filename = transfer.name
            size = transfer.size

        try:
            device = Device(self._applet.Manager.get_adapter().find_device(address))
            name = device.Alias
            trusted = device.Trusted
        except Exception as e:
            dprint(e)
            name = address
            trusted = False

        self._pending_transfer = {'transfer_path': transfer_path, 'address': address, 'root': root,
                                  'filename': filename, 'size': size, 'name': name}

        try:
            status_icon = self._applet.Plugins.StatusIcon
        except:
            status_icon = None

        # This device was neither allowed nor is it trusted -> ask for confirmation
        if address not in self._allowed_devices and not (self._config['opp-accept'] and trusted):
            self._notification = Notification(_("Incoming file over Bluetooth"),
                _("Incoming file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>",
                                                       "1": "<b>" + name + "</b>"},
                30000, [["accept", _("Accept"), "help-about"], ["reject", _("Reject"), "help-about"]], self._on_action,
                pixbuf=get_icon("blueman", 48), status_icon=status_icon)
        # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept
        elif size > 350000:
            self._notification = Notification(_("Receiving file"),
                _("Receiving file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>",
                                                        "1": "<b>" + name + "</b>"},
                pixbuf=get_icon("blueman", 48), status_icon=status_icon)
            self._on_action(self._notification, 'accept')
        # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently
        else:
            self._notification = None
            self._on_action(self._notification, "accept")
예제 #9
0
    def _on_display_passkey(self, parameters, invocation):
        device, passkey, entered = parameters.unpack()
        logging.info('DisplayPasskey (%s, %d)' % (device, passkey))
        dev = bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed",
                                            self._on_device_property_changed)

        notify_message = _("Pairing passkey for") + " %s: %s" % (
            self.get_device_string(device), passkey)
        self.n = Notification("Bluetooth",
                              notify_message,
                              0,
                              icon_name="blueman")
        self.n.show()
예제 #10
0
    def _on_transfer_completed(self, _manager, transfer_path, success):
        try:
            attributes = self._agent.transfers[transfer_path]
        except KeyError:
            # This is probably not an incoming transfer we authorized
            return

        src = attributes['path']
        dest_dir = self._config["shared-path"]
        filename = os.path.basename(src)

        if os.path.exists(os.path.join(dest_dir, filename)):
            now = datetime.now()
            filename = "%s_%s" % (now.strftime("%Y%m%d%H%M%S"), filename)
            dprint("Destination file exists, renaming to: %s" % filename)

        dest = os.path.join(dest_dir, filename)
        shutil.move(src, dest)

        try:
            status_icon = self._applet.Plugins.StatusIcon
        except:
            status_icon = None

        if success:
            n = Notification(_("File received"),
                             _("File %(0)s from %(1)s successfully received") %
                             {
                                 "0": "<b>" + filename + "</b>",
                                 "1": "<b>" + attributes['name'] + "</b>"
                             },
                             pixbuf=get_icon("blueman", 48),
                             status_icon=status_icon)
            self._add_open(n, "Open", dest)
        elif not success:
            Notification(_("Transfer failed"),
                         _("Transfer of file %(0)s failed") % {
                             "0": "<b>" + filename + "</b>",
                             "1": "<b>" + attributes['name'] + "</b>"
                         },
                         pixbuf=get_icon("blueman", 48),
                         status_icon=status_icon)

            if attributes['size'] > 350000:
                self._normal_transfers -= 1
            else:
                self._silent_transfers -= 1

        del self._agent.transfers[transfer_path]
예제 #11
0
    def _on_request_confirmation(self, parameters, invocation):
        def on_confirm_action(n, action):
            if action == "confirm":
                invocation.return_value(GLib.Variant('()', ()))
            else:
                invocation.return_dbus_error('org.bluez.Error.Canceled',
                                             "User canceled pairing")

        params = parameters.unpack()
        if len(params) < 2:
            device_path = params[0]
            passkey = None
        else:
            device_path, passkey = params

        dprint("Agent.RequestConfirmation")
        alias = self.get_device_alias(device_path)
        notify_message = _("Pairing request for:") + "\n%s" % alias
        if passkey:
            notify_message += "\n" + _(
                "Confirm value for authentication:") + " <b>%s</b>" % passkey
        actions = [["confirm", _("Confirm")], ["deny", _("Deny")]]

        self.n = Notification("Bluetooth",
                              notify_message,
                              0,
                              actions,
                              on_confirm_action,
                              pixbuf=get_icon("blueman", 48),
                              status_icon=self.status_icon)
예제 #12
0
 def reply(*args):
     label_text = item["mitem"].get_child().get_children()[1].get_text()
     Notification(_("Connected"),
                  _("Connected to %s") % label_text,
                  pixbuf=get_icon(item["icon"], 48),
                  status_icon=self.Applet.Plugins.StatusIcon)
     item["mitem"].props.sensitive = True
예제 #13
0
파일: Battery.py 프로젝트: wtuemura/blueman
 def on_device_property_changed(self, path: str, key: str,
                                value: Any) -> None:
     if key == "ServicesResolved" and value:
         device = Device(obj_path=path)
         if self.applicable(device):
             text = "%d%%" % BluezBattery(obj_path=path)["Percentage"]
             Notification(device["Alias"], text, icon_name="battery").show()
예제 #14
0
            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", pos_hint=self.Applet.Plugins.StatusIcon.geometry).show()

                self.quering.remove(device)
예제 #15
0
    def _on_display_passkey(self, device: str, passkey: int,
                            entered: int) -> None:
        logging.info(f"DisplayPasskey ({device}, {passkey:d} {entered:d})")
        dev = Device(obj_path=device)
        self._devhandlerids[device] = dev.connect_signal(
            "property-changed", self._on_device_property_changed)

        key = f"{passkey:06}"
        notify_message = _("Pairing passkey for") + f" {self.get_device_string(device)}: " \
                                                    f"{key[:entered]}<b>{key[entered]}</b>{key[entered+1:]}"
        self._close()
        self._notification = Notification("Bluetooth",
                                          notify_message,
                                          0,
                                          icon_name="blueman")
        self._notification.show()
예제 #16
0
    def ask_passkey(
        self, dialog_msg: str, is_numeric: bool, device_path: str,
        ok: Callable[[Any], None],
        err: Callable[[Union[BluezErrorCanceled, BluezErrorRejected]], None]
    ) -> None:
        def passkey_dialog_cb(dialog: Gtk.Dialog, response_id: int) -> None:
            if response_id == Gtk.ResponseType.ACCEPT:
                ret = pin_entry.get_text()
                ok(int(ret) if is_numeric else ret)
            else:
                err(BluezErrorRejected("Rejected"))
            dialog.destroy()
            self.dialog = None

        dev_str = self.get_device_string(device_path)
        notify_message = _("Pairing request for %s") % dev_str

        if self.dialog:
            logging.info("Agent: Another dialog still active, cancelling")
            err(BluezErrorCanceled("Canceled"))

        self.dialog, pin_entry = self.build_passkey_dialog(
            dev_str, dialog_msg, is_numeric)
        if not self.dialog:
            logging.error("Agent: Failed to build dialog")
            err(BluezErrorCanceled("Canceled"))

        Notification(_("Bluetooth Authentication"),
                     notify_message,
                     icon_name="blueman").show()

        self.dialog.connect("response", passkey_dialog_cb)
        self.dialog.present()
예제 #17
0
    def dhcp_acquire(self, device: str) -> None:
        if device not in self.quering:
            self.quering.append(device)
        else:
            return

        if device != "":
            def reply(_obj: Mechanism, result: str, _user_data: None) -> None:
                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: Mechanism, result: GLib.Error, _user_data: None) -> None:
                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)
예제 #18
0
    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", pos_hint=self.Applet.Plugins.StatusIcon.geometry).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", pos_hint=self.Applet.Plugins.StatusIcon.geometry).show()

                self.quering.remove(device)

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

            m = Mechanism()
            m.DhcpClient(str('(s)'), device, result_handler=reply, error_handler=err, timeout=120)
예제 #19
0
            def reply(_obj: Mechanism, result: str, _user_data: None) -> None:
                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)
예제 #20
0
    def _on_request_confirmation(self, device_path, passkey, ok, err):
        def on_confirm_action(action):
            if action == "confirm":
                ok()
            else:
                err(BluezErrorCanceled("User canceled pairing"))

        logging.info("Agent.RequestConfirmation")
        notify_message = _("Pairing request for:") + "\n%s" % self.get_device_string(device_path)

        if passkey:
            notify_message += "\n" + _("Confirm value for authentication:") + " <b>%s</b>" % passkey
        actions = [["confirm", _("Confirm")], ["deny", _("Deny")]]

        self.n = Notification("Bluetooth", notify_message, 0, actions, on_confirm_action, icon_name="blueman")
        self.n.show()
예제 #21
0
 def err(reason):
     Notification(
         _("Failed to connect"),
         str(reason).split(": ")[-1],
         icon_name="dialog-error",
         pos_hint=self.Applet.Plugins.StatusIcon.geometry).show()
     menu_item.props.sensitive = True
예제 #22
0
    def ask_passkey(self, dialog_msg, notify_msg, is_numeric, notification,
                    device_path, ok, err):
        def passkey_dialog_cb(dialog, response_id):
            if response_id == Gtk.ResponseType.ACCEPT:
                ret = pin_entry.get_text()
                if is_numeric:
                    ret = GLib.Variant('(u)', int(ret))
                ok(ret)
            else:
                err(BluezErrorRejected("Rejected"))
            dialog.destroy()
            self.dialog = None

        dev_str = self.get_device_string(device_path)
        notify_message = _("Pairing request for %s") % dev_str

        if self.dialog:
            logging.info("Agent: Another dialog still active, cancelling")
            err(BluezErrorCanceled("Canceled"))

        self.dialog, pin_entry = self.build_passkey_dialog(
            dev_str, dialog_msg, is_numeric)
        if not self.dialog:
            logging.error("Agent: Failed to build dialog")
            err(BluezErrorCanceled("Canceled"))

        if notification:
            Notification(_("Bluetooth Authentication"),
                         notify_message,
                         icon_name="blueman").show()

        self.dialog.connect("response", passkey_dialog_cb)
        self.dialog.present()
예제 #23
0
    def _on_display_pin_code(self, parameters, invocation):
        device, pin_code = parameters.unpack()
        logging.info('DisplayPinCode (%s, %s)' % (device, pin_code))
        dev = bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed",
                                            self._on_device_property_changed)

        notify_message = _("Pairing PIN code for") + " %s: %s" % (
            self.get_device_string(device), pin_code)
        self.n = Notification("Bluetooth",
                              notify_message,
                              0,
                              icon_name="blueman")
        self.n.show()

        invocation.return_value(None)
예제 #24
0
    def on_mm_device_added(self, path):
        dprint(path)
        props = self.parent.bus.call_blocking(
            "org.freedesktop.ModemManager", path,
            "org.freedesktop.DBus.Properties", "GetAll", "s",
            ["org.freedesktop.ModemManager.Modem"])

        if self.rfcomm_dev and props["Driver"] == "bluetooth" and props[
                "Device"] in self.rfcomm_dev:
            dprint("It's our bluetooth modem!")

            modem = get_icon("modem", 24)
            blueman = get_icon("blueman", 48)

            icon = composite_icon(blueman, [(modem, 24, 24, 255)])

            Notification(
                _("Bluetooth Dialup"),
                _("DUN connection on %s will now be available in Network Manager"
                  ) % self.device.Alias,
                pixbuf=icon,
                status_icon=self.parent.Applet.Plugins.StatusIcon)

            self.reply(self.rfcomm_dev)
            self.cleanup()
예제 #25
0
 def err(reason):
     Notification(_("Failed to connect"),
                  str(reason).split(": ")[-1],
                  pixbuf=get_icon("dialog-error", 48),
                  status_icon=self.Applet.Plugins.StatusIcon)
     item["mitem"].props.sensitive = True
     sn.complete()
예제 #26
0
    def on_mm_device_added(self, path, name="org.freedesktop.ModemManager"):
        dprint(path)
        interface = "%s.Modem" % name
        props = self.parent.bus.call_blocking(
            name, path, "org.freedesktop.DBus.Properties", "GetAll", "s",
            [interface])

        try:
            drivers = props["Drivers"]
        except KeyError:
            drivers = [props["Driver"]]

        if self.rfcomm_dev and "bluetooth" in drivers and props[
                "Device"] in self.rfcomm_dev:
            dprint("It's our bluetooth modem!")

            modem = get_icon("modem", 24)
            blueman = get_icon("blueman", 48)

            icon = composite_icon(blueman, [(modem, 24, 24, 255)])

            Notification(
                _("Bluetooth Dialup"),
                _("DUN connection on %s will now be available in Network Manager"
                  ) % self.service.device['Alias'],
                pixbuf=icon,
                status_icon=self.parent.Applet.Plugins.StatusIcon)

            self.reply(self.rfcomm_dev)
            self.cleanup()
예제 #27
0
    def on_connected(self, _obj, result, _user_data):
        self.reply_handler(self.port)
        self.parent.Plugins.run("on_ppp_connected", self.service.device, self.port, result)

        msg = _("Successfully connected to <b>DUN</b> service on <b>%(0)s.</b>\n"
                "Network is now available through <b>%(1)s</b>") % {"0": self.service.device['Alias'], "1": result}

        Notification(_("Connected"), msg, icon_name="network-wireless").show()
예제 #28
0
    def _on_display_pin_code(self, device, pin_code):
        logging.info('DisplayPinCode (%s, %s)' % (device, pin_code))
        dev = bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed", self._on_device_property_changed)

        notify_message = _("Pairing PIN code for") + " %s: %s" % (self.get_device_string(device), pin_code)
        self.n = Notification("Bluetooth", notify_message, 0, icon_name="blueman")
        self.n.show()
예제 #29
0
    def _on_display_passkey(self, device, passkey, _entered):
        logging.info('DisplayPasskey (%s, %d)' % (device, passkey))
        dev = bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed", self._on_device_property_changed)

        notify_message = _("Pairing passkey for") + " %s: %s" % (self.get_device_string(device), passkey)
        self.n = Notification("Bluetooth", notify_message, 0, icon_name="blueman")
        self.n.show()
예제 #30
0
 def err(reason: Union[Exception, str]) -> None:
     Notification(_("Failed to connect"),
                  str(reason).split(": ")[-1],
                  icon_name="dialog-error").show()
     assert item[
         "mitem"] is not None  # https://github.com/python/mypy/issues/2608
     item["mitem"]["sensitive"] = True
     self.parent.Plugins.Menu.on_menu_changed()
예제 #31
0
 def reply() -> None:
     assert item[
         "mitem"] is not None  # https://github.com/python/mypy/issues/2608
     Notification(_("Connected"),
                  _("Connected to %s") % item["mitem"]["text"],
                  icon_name=item["icon"]).show()
     item["mitem"]["sensitive"] = True
     self.parent.Plugins.Menu.on_menu_changed()
예제 #32
0
 def reply(*args):
     label_text = menu_item.get_child().get_children()[1].get_text()
     Notification(
         _("Connected"),
         _("Connected to %s") % label_text,
         icon_name=item["icon"],
         pos_hint=self.Applet.Plugins.StatusIcon.geometry).show()
     menu_item.props.sensitive = True
예제 #33
0
    def on_device_property_changed(self, path: str, key: str, value: Any) -> None:
        if key == "Connected":
            device = Device(obj_path=path)
            if value and "Battery" in self.parent.Plugins.get_loaded() and Battery.applicable(device):
                return

            Notification(device["Alias"], _("Connected") if value else _("Disconnected"),
                         icon_name=device["Icon"]).show()
예제 #34
0
            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)
예제 #35
0
    def _on_transfer_completed(self, _manager, transfer_path, success):
        try:
            attributes = self._agent.transfers[transfer_path]
        except KeyError:
            logging.info("This is probably not an incoming transfer we authorized")
            return

        src = attributes['path']
        dest_dir, ignored = self._make_share_path()
        filename = os.path.basename(src)

        dest = os.path.join(dest_dir, filename)
        if os.path.exists(dest):
            now = datetime.now()
            filename = "%s_%s" % (now.strftime("%Y%m%d%H%M%S"), filename)
            logging.info("Destination file exists, renaming to: %s" % filename)

        try:
            shutil.move(src, dest)
        except (OSError, PermissionError):
            logging.error("Failed to move files", exc_info=True)
            success = False

        if success:
            self._notification = Notification(_("File received"),
                                              _("File %(0)s from %(1)s successfully received") % {
                                                  "0": "<b>" + escape(filename) + "</b>",
                                                  "1": "<b>" + escape(attributes['name']) + "</b>"},
                                              **self._notify_kwargs)
            self._add_open(self._notification, "Open", dest)
            self._notification.show()
        elif not success:
            n = Notification(
                _("Transfer failed"),
                _("Transfer of file %(0)s failed") % {
                    "0": "<b>" + escape(filename) + "</b>",
                    "1": "<b>" + escape(attributes['name']) + "</b>"},
                **self._notify_kwargs
            )
            n.show()
            if attributes['size'] > 350000:
                self._normal_transfers -= 1
            else:
                self._silent_transfers -= 1

        del self._agent.transfers[transfer_path]
예제 #36
0
 def reply(*args):
     Notification(_("Connected"),
                  _("Connected to %s") %
                  item["mitem"].get_child().props.label,
                  pixbuf=get_icon("network-transmit-recieve", 48),
                  status_icon=self.Applet.Plugins.StatusIcon)
     item["mitem"].props.sensitive = True
     sn.complete()
예제 #37
0
 def DisplayPinCode(self, device, pin_code):
     dprint('DisplayPinCode (%s, %s)' % (device, pin_code))
     notify_message = _("Pairing PIN code for") + " %s: %s" % (
         self.get_device_alias(device), pin_code)
     self.n = Notification("Bluetooth",
                           notify_message,
                           0,
                           pixbuf=get_icon("blueman", 48),
                           status_icon=self.status_icon)
예제 #38
0
	def add_open(self, n, name, path):
		if Notification.actions_supported():
			print "adding action"
			def on_open(*args):
				print "open"
				spawn(["xdg-open", path], True)

			n.add_action("open", name, on_open)
			n.show()	
예제 #39
0
    def _on_display_passkey(self, parameters, invocation):
        device, passkey, entered = parameters.unpack()
        logging.info('DisplayPasskey (%s, %d)' % (device, passkey))
        dev = Bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed", self._on_device_property_changed)

        notify_message = _("Pairing passkey for") + " %s: %s" % (self.get_device_string(device), passkey)
        self.n = Notification("Bluetooth", notify_message, 0, icon_name="blueman", pos_hint=self.status_icon.geometry)
        self.n.show()
예제 #40
0
            def err(msg):
                dprint(msg)
                Notification(_("Bluetooth Network"),
                             _("Failed to obtain an IP address on %s") %
                             (device),
                             pixbuf=get_icon("gtk-network", 48),
                             status_icon=self.Applet.Plugins.StatusIcon)

                self.quering.remove(device)
예제 #41
0
    def _add_open(n, name, path):
        if Notification.actions_supported():
            print("adding action")

            def on_open(*_args):
                print("open")
                launch("xdg-open", [path], True)

            n.add_action("open", name, on_open, None)
            n.show()
예제 #42
0
    def _on_display_pin_code(self, parameters, invocation):
        device, pin_code = parameters.unpack()
        logging.info('DisplayPinCode (%s, %s)' % (device, pin_code))
        dev = Bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed", self._on_device_property_changed)

        notify_message = _("Pairing PIN code for") + " %s: %s" % (self.get_device_string(device), pin_code)
        self.n = Notification("Bluetooth", notify_message, 0, icon_name="blueman", pos_hint=self.status_icon.geometry)
        self.n.show()

        invocation.return_value(None)
예제 #43
0
    def _on_session_removed(self, _manager, _session_path):
        if self._silent_transfers == 0:
            return

        share_path, ignored = self._make_share_path()
        if self._normal_transfers == 0:
            self._notification = Notification(_("Files received"),
                                              ngettext("Received %d file in the background",
                                                       "Received %d files in the background",
                                                       self._silent_transfers) % self._silent_transfers,
                                              **self._notify_kwargs)

            self._add_open(self._notification, "Open Location", share_path)
            self._notification.show()
        else:
            self._notification = Notification(_("Files received"),
                                              ngettext("Received %d more file in the background",
                                                       "Received %d more files in the background",
                                                       self._silent_transfers) % self._silent_transfers,
                                              **self._notify_kwargs)
            self._add_open(self._notification, "Open Location", share_path)
            self._notification.show()
예제 #44
0
    def on_load(self):
        def on_reset(*_args):
            self._notification = None
            self._config.reset('shared-path')
            logging.info('Reset share path')

        self._config = Config("org.blueman.transfer")

        share_path, invalid_share_path = self._make_share_path()

        if invalid_share_path:
            text = _('Configured directory for incoming files does not exist')
            secondary_text = _('Please make sure that directory "<b>%s</b>" exists or '
                               'configure it with blueman-services. Until then the default "%s" will be used')
            self._notification = Notification(text, secondary_text % (self._config["shared-path"], share_path),
                                              icon_name='blueman', timeout=30000,
                                              actions=[['reset', 'Reset to default', 'blueman']], actions_cb=on_reset)
            self._notification.show()

        self._watch = obex.Manager.watch_name_owner(self._on_dbus_name_appeared, self._on_dbus_name_vanished)
예제 #45
0
    def _on_request_confirmation(self, parameters, invocation):
        def on_confirm_action(action):
            if action == "confirm":
                invocation.return_value(GLib.Variant('()', ()))
            else:
                invocation.return_dbus_error('org.bluez.Error.Canceled', "User canceled pairing")

        params = parameters.unpack()
        if len(params) < 2:
            device_path = params[0]
            passkey = None
        else:
            device_path, passkey = params

        logging.info("Agent.RequestConfirmation")
        notify_message = _("Pairing request for:") + "\n%s" % self.get_device_string(device_path)

        if passkey:
            notify_message += "\n" + _("Confirm value for authentication:") + " <b>%s</b>" % passkey
        actions = [["confirm", _("Confirm")], ["deny", _("Deny")]]

        self.n = Notification("Bluetooth", notify_message, 0, actions, on_confirm_action, icon_name="blueman")
        self.n.show()
예제 #46
0
    def _on_session_removed(self, _manager, _session_path):
        if self._silent_transfers == 0:
            return

        if self._normal_transfers == 0:
            n = Notification(_("Files received"),
                             ngettext("Received %d file in the background", "Received %d files in the background",
                                      self._silent_transfers) % self._silent_transfers,
                             **self._notify_kwargs)

            self._add_open(n, "Open Location", self._config["shared-path"])
            n.show()
        else:
            n = Notification(_("Files received"),
                             ngettext("Received %d more file in the background",
                                      "Received %d more files in the background",
                                      self._silent_transfers) % self._silent_transfers,
                             **self._notify_kwargs)
            self._add_open(n, "Open Location", self._config["shared-path"])
            n.show()
예제 #47
0
    def transfer_finished(self, session, *args):
        type = args[-1]
        dprint(args)
        try:
            if not session.transfer["finished"]:

                if type != "cancelled" and type != "error":
                    session.transfer["finished"] = True

                    if session.transfer["total"] > 350000:
                        icon = get_icon("blueman", 48)
                        n = Notification(_("File received"),
                                         _("File %(0)s from %(1)s successfully received") % {
                                         "0": "<b>" + session.transfer["filename"] + "</b>",
                                         "1": "<b>" + session.transfer["name"] + "</b>"},
                                         pixbuf=icon, status_icon=self.status_icon)
                        self.add_open(n, "Open", session.transfer["filepath"])
                else:
                    session.transfer["failed"] = True
                    session.transfer["finished"] = True

                    n = session.transfer["notification"]
                    if n:
                        n.close()

                    icon = get_icon("blueman", 48)

                    session.transfer["notification"] = Notification(_("Transfer failed"),
                                                                    _("Transfer of file %(0)s failed") % {
                                                                    "0": "<b>" + session.transfer["filename"] + "</b>",
                                                                    "1": "<b>" + session.transfer["name"] + "</b>"},
                                                                    pixbuf=icon, status_icon=self.status_icon)
                    if session.transfer["total"] > 350000:
                        session.transfer["normal_transfers"] -= 1
                    else:
                        session.transfer["silent_transfers"] -= 1

            if type == "disconnected":
                icon = get_icon("blueman", 48)

                if session.transfer["normal_transfers"] == 0 and session.transfer["silent_transfers"] == 1:
                    n = Notification(_("File received"),
                                     _("File %(0)s from %(1)s successfully received") % {
                                     "0": "<b>" + session.transfer["filename"] + "</b>",
                                     "1": "<b>" + session.transfer["name"] + "</b>"},
                                     pixbuf=icon, status_icon=self.status_icon)

                    self.add_open(n, "Open", session.transfer["filepath"])

                elif session.transfer["normal_transfers"] == 0 and session.transfer["silent_transfers"] > 0:
                    n = Notification(_("Files received"),
                                     ngettext("Received %d file in the background",
                                              "Received %d files in the background",
                                              session.transfer["silent_transfers"]) % session.transfer[
                                         "silent_transfers"],
                                     pixbuf=icon, status_icon=self.status_icon)

                    self.add_open(n, "Open Location", self.Config.props.shared_path)

                elif session.transfer["normal_transfers"] > 0 and session.transfer["silent_transfers"] > 0:

                    n = Notification(_("Files received"),
                                     ngettext("Received %d more file in the background",
                                              "Received %d more files in the background",
                                              session.transfer["silent_transfers"]) % session.transfer[
                                         "silent_transfers"],
                                     pixbuf=icon, status_icon=self.status_icon)
                    self.add_open(n, "Open Location", self.Config.props.shared_path)

                del session.transfer
                del session.server

        except KeyError:
            pass
예제 #48
0
class TransferService(AppletPlugin):
    __author__ = "cschramm"
    __description__ = _("Provides OBEX file transfer capabilities")
    __icon__ = "blueman-send-file"

    _config = None

    _silent_transfers = 0
    _normal_transfers = 0

    _manager = None
    _signals = []
    _agent = None
    _watch = None
    _notification = None

    def on_load(self):
        def on_reset(*_args):
            self._notification = None
            self._config.reset('shared-path')
            logging.info('Reset share path')

        self._config = Config("org.blueman.transfer")

        share_path, invalid_share_path = self._make_share_path()

        if invalid_share_path:
            text = _('Configured directory for incoming files does not exist')
            secondary_text = _('Please make sure that directory "<b>%s</b>" exists or '
                               'configure it with blueman-services. Until then the default "%s" will be used')
            self._notification = Notification(text, secondary_text % (self._config["shared-path"], share_path),
                                              icon_name='blueman', timeout=30000,
                                              actions=[['reset', 'Reset to default', 'blueman']], actions_cb=on_reset)
            self._notification.show()

        self._watch = obex.Manager.watch_name_owner(self._on_dbus_name_appeared, self._on_dbus_name_vanished)

    def on_unload(self):
        if self._watch:
            Gio.bus_unwatch_name(self._watch)

        self._unregister_agent()

    def _make_share_path(self):
        config_path = self._config["shared-path"]
        default_path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD)
        path = None
        error = False

        if config_path == '':
            path = default_path
        elif not os.path.isdir(config_path):
            path = default_path
            error = True
            logging.warning('Invalid shared-path %s' % config_path)
        else:
            path = config_path

        if not path:
            path = os.path.expanduser("~")
            logging.warning('Failed to get Download dir from XDG')

        # We used to always store the full path which caused problems
        if config_path == default_path:
            logging.info('Reset stored path, identical to default path.')
            self._config["shared-path"] = ''

        return path, error

    def _register_agent(self):
        if not self._agent:
            self._agent = Agent(self.parent)
        self._agent.register_at_manager()

    def _unregister_agent(self):
        if self._agent:
            self._agent.unregister_from_manager()
            self._agent.unregister()
            self._agent = None

    def _on_dbus_name_appeared(self, _connection, name, owner):
        logging.info("%s %s" % (name, owner))

        self._manager = obex.Manager()
        self._signals.append(self._manager.connect("transfer-started", self._on_transfer_started))
        self._signals.append(self._manager.connect("transfer-completed", self._on_transfer_completed))
        self._signals.append(self._manager.connect('session-removed', self._on_session_removed))

        self._register_agent()

    def _on_dbus_name_vanished(self, _connection, name):
        logging.info("%s not running or was stopped" % name)

        for signal in self._signals:
            self._manager.disconnect(signal)
        self._manager = None
        if self._agent:
            self._agent.unregister()
            self._agent = None

    def _on_transfer_started(self, _manager, transfer_path):
        if transfer_path not in self._agent.transfers:
            # This is not an incoming transfer we authorized
            return

        if self._agent.transfers[transfer_path]['size'] > 350000:
            self._normal_transfers += 1
        else:
            self._silent_transfers += 1

    def _add_open(self, n, name, path):
        if n.actions_supported:
            logging.info("adding action")

            def on_open(*_args):
                self._notification = None
                logging.info("open")
                launch("xdg-open", [path], True)

            n.add_action("open", name, on_open)

    @property
    def _notify_kwargs(self):
        kwargs = {"icon_name": "blueman"}
        try:
            kwargs["pos_hint"] = self.parent.Plugins.StatusIcon.geometry
        except AttributeError:
            logging.error("No statusicon found")

        return kwargs

    def _on_transfer_completed(self, _manager, transfer_path, success):
        try:
            attributes = self._agent.transfers[transfer_path]
        except KeyError:
            logging.info("This is probably not an incoming transfer we authorized")
            return

        src = attributes['path']
        dest_dir, ignored = self._make_share_path()
        filename = os.path.basename(src)

        dest = os.path.join(dest_dir, filename)
        if os.path.exists(dest):
            now = datetime.now()
            filename = "%s_%s" % (now.strftime("%Y%m%d%H%M%S"), filename)
            logging.info("Destination file exists, renaming to: %s" % filename)

        try:
            shutil.move(src, dest)
        except (OSError, PermissionError):
            logging.error("Failed to move files", exc_info=True)
            success = False

        if success:
            self._notification = Notification(_("File received"),
                                              _("File %(0)s from %(1)s successfully received") % {
                                                  "0": "<b>" + escape(filename) + "</b>",
                                                  "1": "<b>" + escape(attributes['name']) + "</b>"},
                                              **self._notify_kwargs)
            self._add_open(self._notification, "Open", dest)
            self._notification.show()
        elif not success:
            n = Notification(
                _("Transfer failed"),
                _("Transfer of file %(0)s failed") % {
                    "0": "<b>" + escape(filename) + "</b>",
                    "1": "<b>" + escape(attributes['name']) + "</b>"},
                **self._notify_kwargs
            )
            n.show()
            if attributes['size'] > 350000:
                self._normal_transfers -= 1
            else:
                self._silent_transfers -= 1

        del self._agent.transfers[transfer_path]

    def _on_session_removed(self, _manager, _session_path):
        if self._silent_transfers == 0:
            return

        share_path, ignored = self._make_share_path()
        if self._normal_transfers == 0:
            self._notification = Notification(_("Files received"),
                                              ngettext("Received %d file in the background",
                                                       "Received %d files in the background",
                                                       self._silent_transfers) % self._silent_transfers,
                                              **self._notify_kwargs)

            self._add_open(self._notification, "Open Location", share_path)
            self._notification.show()
        else:
            self._notification = Notification(_("Files received"),
                                              ngettext("Received %d more file in the background",
                                                       "Received %d more files in the background",
                                                       self._silent_transfers) % self._silent_transfers,
                                              **self._notify_kwargs)
            self._add_open(self._notification, "Open Location", share_path)
            self._notification.show()
예제 #49
0
    def _on_authorize(self, parameters, invocation):
        def on_action(_notification, action):
            dprint(action)

            if action == "accept":
                self.transfers[self._pending_transfer['transfer_path']] = {
                    'path': self._pending_transfer['root'] + '/' + os.path.basename(self._pending_transfer['filename']),
                    'size': self._pending_transfer['size'],
                    'name': self._pending_transfer['name']
                }

                param = GLib.Variant('(s)', (self.transfers[self._pending_transfer['transfer_path']]['path'],))
                invocation.return_value(param)

                self._allowed_devices.append(self._pending_transfer['address'])
                GLib.timeout_add(60000, self._allowed_devices.remove, self._pending_transfer['address'])
            else:
                invocation.return_dbus_error('org.bluez.obex.Error.Rejected', 'Rejected')

        transfer_path = parameters.unpack()[0]

        transfer = obex.Transfer(transfer_path)
        session = obex.Session(transfer.session)
        root = session.root[0]
        address = session.address[0]
        filename = transfer.name
        size = transfer.size

        try:
            device = self._applet.Manager.get_adapter().find_device(address)
            name = device["Alias"]
            trusted = device["Trusted"]
        except Exception as e:
            dprint(e)
            name = address
            trusted = False

        self._pending_transfer = {'transfer_path': transfer_path, 'address': address, 'root': root,
                                  'filename': filename, 'size': size, 'name': name}

        try:
            status_icon = self._applet.Plugins.StatusIcon
        except:
            status_icon = None

        # This device was neither allowed nor is it trusted -> ask for confirmation
        if address not in self._allowed_devices and not (self._config['opp-accept'] and trusted):
            self._notification = Notification(_("Incoming file over Bluetooth"),
                _("Incoming file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>",
                                                       "1": "<b>" + name + "</b>"},
                30000, [["accept", _("Accept"), "help-about"], ["reject", _("Reject"), "help-about"]], on_action,
                pixbuf=get_icon("blueman", 48), status_icon=status_icon)
        # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept
        elif size > 350000:
            self._notification = Notification(_("Receiving file"),
                _("Receiving file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>",
                                                        "1": "<b>" + name + "</b>"},
                pixbuf=get_icon("blueman", 48), status_icon=status_icon)
            on_action(self._notification, 'accept')
        # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently
        else:
            self._notification = None
            on_action(self._notification, "accept")
예제 #50
0
class Agent(DbusService):
    __agent_path = '/org/bluez/obex/agent/blueman'

    def __init__(self, applet):
        super().__init__(None, "org.bluez.obex.Agent1", self.__agent_path, Gio.BusType.SESSION)

        self.add_method("Release", (), "", self._release)
        self.add_method("Cancel", (), "", self._cancel)
        self.add_method("AuthorizePush", ("o",), "s", self._authorize_push, is_async=True)
        self.register()

        self._applet = applet
        self._config = Config("org.blueman.transfer")

        self._allowed_devices = []
        self._notification = None
        self._pending_transfer = None
        self.transfers = {}

    def register_at_manager(self):
        obex.AgentManager().register_agent(self.__agent_path)

    def unregister_from_manager(self):
        obex.AgentManager().unregister_agent(self.__agent_path)

    def _release(self):
        raise Exception(self.__agent_path + " was released unexpectedly")

    def _authorize_push(self, transfer_path, ok, err):
        def on_action(action):
            logging.info("Action %s" % action)

            if action == "accept":
                self.transfers[self._pending_transfer['transfer_path']] = {
                    'path': self._pending_transfer['root'] + '/' + os.path.basename(self._pending_transfer['filename']),
                    'size': self._pending_transfer['size'],
                    'name': self._pending_transfer['name']
                }

                ok(self.transfers[self._pending_transfer['transfer_path']]['path'])

                self._allowed_devices.append(self._pending_transfer['address'])
                GLib.timeout_add(60000, self._allowed_devices.remove, self._pending_transfer['address'])
            else:
                err(ObexErrorRejected("Rejected"))

        transfer = obex.Transfer(transfer_path)
        session = obex.Session(transfer.session)
        root = session.root
        address = session.address
        filename = transfer.name
        size = transfer.size

        try:
            adapter = self._applet.Manager.get_adapter()
            device = self._applet.Manager.find_device(address, adapter.get_object_path())
            name = device["Alias"]
            trusted = device["Trusted"]
        except Exception as e:
            logging.exception(e)
            name = address
            trusted = False

        self._pending_transfer = {'transfer_path': transfer_path, 'address': address, 'root': root,
                                  'filename': filename, 'size': size, 'name': name}

        notif_kwargs = {"icon_name": "blueman"}
        try:
            notif_kwargs["pos_hint"] = self._applet.Plugins.StatusIcon.geometry
        except AttributeError:
            logging.error("Failed to get StatusIcon")

        # This device was neither allowed nor is it trusted -> ask for confirmation
        if address not in self._allowed_devices and not (self._config['opp-accept'] and trusted):
            self._notification = Notification(
                _("Incoming file over Bluetooth"),
                _("Incoming file %(0)s from %(1)s") % {"0": "<b>" + escape(filename) + "</b>",
                                                       "1": "<b>" + escape(name) + "</b>"},
                30000, [["accept", _("Accept"), "help-about"], ["reject", _("Reject"), "help-about"]], on_action,
                **notif_kwargs
            )
            self._notification.show()
        # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept
        elif size > 350000:
            self._notification = Notification(
                _("Receiving file"),
                _("Receiving file %(0)s from %(1)s") % {"0": "<b>" + escape(filename) + "</b>",
                                                        "1": "<b>" + escape(name) + "</b>"},
                **notif_kwargs
            )
            on_action('accept')
            self._notification.show()
        # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently
        else:
            self._notification = None
            on_action("accept")

    def _cancel(self):
        self._notification.close()
        raise ObexErrorCanceled("Canceled")
예제 #51
0
class _Agent:
    def __init__(self, applet):
        self._applet = applet
        self._config = Config("org.blueman.transfer")

        self._agent_path = "/org/blueman/obex_agent"

        self._agent = obex.Agent(self._agent_path)
        self._agent.connect("release", self._on_release)
        self._agent.connect("authorize", self._on_authorize)
        self._agent.connect("cancel", self._on_cancel)

        self._allowed_devices = []
        self._notification = None
        self._pending_transfer = None
        self.transfers = {}

        obex.AgentManager().register_agent(self._agent_path)

    def __del__(self):
        obex.AgentManager().unregister_agent(self._agent_path)

    def _on_release(self, _agent):
        raise Exception(self._agent_path + " was released unexpectedly")

    def _on_action(self, _notification, action):
        dprint(action)

        if action == "accept":
            self.transfers[self._pending_transfer["transfer_path"]] = {
                "path": self._pending_transfer["root"] + "/" + os.path.basename(self._pending_transfer["filename"]),
                "size": self._pending_transfer["size"],
                "name": self._pending_transfer["name"],
            }
            self._agent.reply(self.transfers[self._pending_transfer["transfer_path"]]["path"])
            self._allowed_devices.append(self._pending_transfer["address"])
            GObject.timeout_add(60000, self._allowed_devices.remove, self._pending_transfer["address"])
        else:
            self._agent.reply(obex.Error.Rejected)

    def _on_authorize(self, _agent, transfer_path, address=None, filename=None, size=None):
        if address and filename and size:
            # stand-alone obexd
            # FIXME: /tmp is only the default. Can we get the actual root
            # directory from stand-alone obexd?
            root = "/tmp"
        else:
            # BlueZ 5 integrated obexd
            transfer = obex.Transfer(transfer_path)
            session = obex.Session(transfer.session)
            root = session.root
            address = session.address
            filename = transfer.name
            size = transfer.size

        try:
            device = Device(self._applet.Manager.get_adapter().find_device(address))
            name = device.Alias
            trusted = device.Trusted
        except Exception as e:
            dprint(e)
            name = address
            trusted = False

        self._pending_transfer = {
            "transfer_path": transfer_path,
            "address": address,
            "root": root,
            "filename": filename,
            "size": size,
            "name": name,
        }

        try:
            status_icon = self._applet.Plugins.StatusIcon
        except:
            status_icon = None

        # This device was neither allowed nor is it trusted -> ask for confirmation
        if address not in self._allowed_devices and not (self._config["opp-accept"] and trusted):
            self._notification = Notification(
                _("Incoming file over Bluetooth"),
                _("Incoming file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>", "1": "<b>" + name + "</b>"},
                30000,
                [["accept", _("Accept"), "help-about"], ["reject", _("Reject"), "help-about"]],
                self._on_action,
                pixbuf=get_icon("blueman", 48),
                status_icon=status_icon,
            )
        # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept
        elif size > 350000:
            self._notification = Notification(
                _("Receiving file"),
                _("Receiving file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>", "1": "<b>" + name + "</b>"},
                pixbuf=get_icon("blueman", 48),
                status_icon=status_icon,
            )
            self._on_action(self._notification, "accept")
        # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently
        else:
            self._notification = None
            self._on_action(self._notification, "accept")

    def _on_cancel(self, agent):
        self._notification.close()
        agent.reply(obex.Error.Canceled)
예제 #52
0
    def _on_authorize(self, parameters, invocation):
        def on_action(action):
            logging.info("Action %s" % action)

            if action == "accept":
                self.transfers[self._pending_transfer['transfer_path']] = {
                    'path': self._pending_transfer['root'] + '/' + os.path.basename(self._pending_transfer['filename']),
                    'size': self._pending_transfer['size'],
                    'name': self._pending_transfer['name']
                }

                param = GLib.Variant('(s)', (self.transfers[self._pending_transfer['transfer_path']]['path'],))
                invocation.return_value(param)

                self._allowed_devices.append(self._pending_transfer['address'])
                GLib.timeout_add(60000, self._allowed_devices.remove, self._pending_transfer['address'])
            else:
                invocation.return_dbus_error('org.bluez.obex.Error.Rejected', 'Rejected')

        transfer_path = parameters.unpack()[0]

        transfer = obex.Transfer(transfer_path)
        session = obex.Session(transfer.session)
        root = session.root
        address = session.address
        filename = transfer.name
        size = transfer.size

        try:
            adapter = self._applet.Manager.get_adapter()
            device = self._applet.Manager.find_device(address, adapter.get_object_path())
            name = device["Alias"]
            trusted = device["Trusted"]
        except Exception as e:
            logging.exception(e)
            name = address
            trusted = False

        self._pending_transfer = {'transfer_path': transfer_path, 'address': address, 'root': root,
                                  'filename': filename, 'size': size, 'name': name}

        notif_kwargs = {"icon_name": "blueman"}
        try:
            notif_kwargs["pos_hint"] = self._applet.Plugins.StatusIcon.geometry
        except AttributeError:
            logging.error("Failed to get StatusIcon")

        # This device was neither allowed nor is it trusted -> ask for confirmation
        if address not in self._allowed_devices and not (self._config['opp-accept'] and trusted):
            self._notification = Notification(_("Incoming file over Bluetooth"),
                _("Incoming file %(0)s from %(1)s") % {"0": "<b>" + escape(filename) + "</b>",
                                                       "1": "<b>" + escape(name) + "</b>"},
                30000, [["accept", _("Accept"), "help-about"], ["reject", _("Reject"), "help-about"]], on_action,
                **notif_kwargs)
            self._notification.show()
        # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept
        elif size > 350000:
            self._notification = Notification(_("Receiving file"),
                _("Receiving file %(0)s from %(1)s") % {"0": "<b>" + escape(filename) + "</b>",
                                                        "1": "<b>" + escape(name) + "</b>"},
                **notif_kwargs)
            on_action('accept')
            self._notification.show()
        # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently
        else:
            self._notification = None
            on_action("accept")
예제 #53
0
class Agent(obex.Agent):
    __agent_path = '/org/bluez/obex/agent/blueman'

    def __init__(self, applet):
        super(Agent, self).__init__(self.__agent_path, self._handle_method_call)

        self._applet = applet
        self._config = Config("org.blueman.transfer")

        self._allowed_devices = []
        self._notification = None
        self._pending_transfer = None
        self.transfers = {}

    def _handle_method_call(self, connection, sender, agent_path, interface_name, method_name, parameters, invocation):
        log_msg = "%s %s" % (method_name, agent_path)
        if method_name == 'Release':
            logging.info(log_msg)
            self._on_release()
        elif method_name == 'AuthorizePush':
            logging.info(log_msg)
            self._on_authorize(parameters, invocation)
        elif method_name == 'Cancel':
            logging.info(log_msg)
            self._on_cancel(parameters, invocation)

    def register(self):
        obex.AgentManager().register_agent(self.__agent_path)

    def unregister(self):
        obex.AgentManager().unregister_agent(self.__agent_path)

    def _on_release(self):
        raise Exception(self.__agent_path + " was released unexpectedly")

    def _on_authorize(self, parameters, invocation):
        def on_action(action):
            logging.info("Action %s" % action)

            if action == "accept":
                self.transfers[self._pending_transfer['transfer_path']] = {
                    'path': self._pending_transfer['root'] + '/' + os.path.basename(self._pending_transfer['filename']),
                    'size': self._pending_transfer['size'],
                    'name': self._pending_transfer['name']
                }

                param = GLib.Variant('(s)', (self.transfers[self._pending_transfer['transfer_path']]['path'],))
                invocation.return_value(param)

                self._allowed_devices.append(self._pending_transfer['address'])
                GLib.timeout_add(60000, self._allowed_devices.remove, self._pending_transfer['address'])
            else:
                invocation.return_dbus_error('org.bluez.obex.Error.Rejected', 'Rejected')

        transfer_path = parameters.unpack()[0]

        transfer = obex.Transfer(transfer_path)
        session = obex.Session(transfer.session)
        root = session.root
        address = session.address
        filename = transfer.name
        size = transfer.size

        try:
            adapter = self._applet.Manager.get_adapter()
            device = self._applet.Manager.find_device(address, adapter.get_object_path())
            name = device["Alias"]
            trusted = device["Trusted"]
        except Exception as e:
            logging.exception(e)
            name = address
            trusted = False

        self._pending_transfer = {'transfer_path': transfer_path, 'address': address, 'root': root,
                                  'filename': filename, 'size': size, 'name': name}

        notif_kwargs = {"icon_name": "blueman"}
        try:
            notif_kwargs["pos_hint"] = self._applet.Plugins.StatusIcon.geometry
        except AttributeError:
            logging.error("Failed to get StatusIcon")

        # This device was neither allowed nor is it trusted -> ask for confirmation
        if address not in self._allowed_devices and not (self._config['opp-accept'] and trusted):
            self._notification = Notification(_("Incoming file over Bluetooth"),
                _("Incoming file %(0)s from %(1)s") % {"0": "<b>" + escape(filename) + "</b>",
                                                       "1": "<b>" + escape(name) + "</b>"},
                30000, [["accept", _("Accept"), "help-about"], ["reject", _("Reject"), "help-about"]], on_action,
                **notif_kwargs)
            self._notification.show()
        # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept
        elif size > 350000:
            self._notification = Notification(_("Receiving file"),
                _("Receiving file %(0)s from %(1)s") % {"0": "<b>" + escape(filename) + "</b>",
                                                        "1": "<b>" + escape(name) + "</b>"},
                **notif_kwargs)
            on_action('accept')
            self._notification.show()
        # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently
        else:
            self._notification = None
            on_action("accept")

    def _on_cancel(self, parameters, invocation):
        self._notification.close()
        invocation.return_dbus_error('org.bluez.obex.Error.Canceled', 'Canceled')
예제 #54
0
class BluezAgent(Agent):
    __agent_path = '/org/bluez/agent/blueman'

    def __init__(self, status_icon, time_func):
        super(BluezAgent, self).__init__(self.__agent_path, self._handle_method_call)

        self.status_icon = status_icon
        self.dialog = None
        self.n = None
        self.signal_id = None
        self.time_func = time_func
        self._db = None

    def register_agent(self):
        logging.info("Register Agent")
        self._register_object()
        Bluez.AgentManager().register_agent(self.__agent_path, "KeyboardDisplay", default=True)

    def unregister_agent(self):
        logging.info("Unregister Agent")
        self._unregister_object()
        Bluez.AgentManager().unregister_agent(self.__agent_path)

    def _handle_method_call(self, connection, sender, agent_path, interface_name, method_name, parameters, invocation):

        if method_name == 'Release':
            self._on_release()
        elif method_name == 'RequestPinCode':
            self._on_request_pin_code(parameters, invocation)
        elif method_name == 'DisplayPinCode':
            self._on_display_pin_code(parameters, invocation)
        elif method_name == 'RequestPasskey':
            self._on_request_passkey(parameters, invocation)
        elif method_name == 'DisplayPasskey':
            self._on_display_passkey(parameters, invocation)
        elif method_name == 'RequestConfirmation':
            self._on_request_confirmation(parameters, invocation)
        elif method_name == 'RequestAuthorization':
            self._on_request_authorization(parameters, invocation)
        elif method_name == 'AuthorizeService':
            self._on_authorize_service(parameters, invocation)
        elif method_name == 'Cancel':
            self._on_cancel()
        else:
            logging.warning('Unhandled method: %s' % method_name)

    def build_passkey_dialog(self, device_alias, dialog_msg, is_numeric):
        def on_insert_text(editable, new_text, new_text_length, position):
            if not new_text.isdigit():
                editable.stop_emission("insert-text")

        builder = Gtk.Builder()
        builder.add_from_file(UI_PATH + "/applet-passkey.ui")
        builder.set_translation_domain("blueman")
        bind_textdomain_codeset("blueman", "UTF-8")
        dialog = builder.get_object("dialog")

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

        return (dialog, pin_entry)

    def get_device_string(self, device_path):
        device = Bluez.Device(device_path)
        return "<b>%s</b> (%s)" % (escape(device["Alias"]), device["Address"])

    def _lookup_default_pin(self, device_path):
        if not self._db:
            self._db = ElementTree.parse(os.path.join(PKGDATA_DIR, 'pin-code-database.xml'))

        device = Bluez.Device(device_path)
        lookup_dict = {
            'name': device['Name'],
            'type': bt_class_to_string(device['Class']),
            'oui': device['Address'][:9]
        }

        pin = None
        for s in PIN_SEARCHES:
            search = s.format(**lookup_dict)
            entry = self._db.find(search)
            if entry is not None:
                pin = entry.get('pin')
                break

        if pin is not None:
            if 'max:' in pin:
                pin = "".join(random.sample('123456789', int(pin[-1])))
        return pin

    def ask_passkey(self, dialog_msg, notify_msg, is_numeric, notification, parameters, invocation):
        device_path = parameters.unpack()[0]

        def passkey_dialog_cb(dialog, response_id):
            if response_id == Gtk.ResponseType.ACCEPT:
                ret = pin_entry.get_text()
                if is_numeric:
                    ret = GLib.Variant('(u)', int(ret))
                invocation.return_value(GLib.Variant('(s)', (ret,)))
            else:
                invocation.return_dbus_error('org.bluez.Error.Rejected', 'Rejected')
            dialog.destroy()
            self.dialog = None

        dev_str = self.get_device_string(device_path)
        notify_message = _("Pairing request for %s") % dev_str

        if self.dialog:
            logging.info("Agent: Another dialog still active, cancelling")
            invocation.return_dbus_error('org.bluez.Error.Canceled', 'Canceled')

        self.dialog, pin_entry = self.build_passkey_dialog(dev_str, dialog_msg, is_numeric)
        if not self.dialog:
            logging.error("Agent: Failed to build dialog")
            invocation.return_dbus_error('org.bluez.Error.Canceled', 'Canceled')

        if notification:
            Notification(_("Bluetooth Authentication"), notify_message, icon_name="blueman",
                         pos_hint=self.status_icon.geometry)

        self.dialog.connect("response", passkey_dialog_cb)
        self.dialog.present()

    # Workaround BlueZ not calling the Cancel method, see #164
    def _on_device_property_changed(self, device, key, value, path):
        if (key == "Paired" and value) or (key == "Connected" and not value):
            device.disconnect_signal(self.signal_id)
            self._on_cancel()

    def _on_release(self):
        logging.info("Agent.Release")
        self._on_cancel()
        self._unregister_object()

    def _on_cancel(self):
        logging.info("Agent.Cancel")
        if self.dialog:
            self.dialog.response(Gtk.ResponseType.REJECT)
        try:
            self.n.close()
        except AttributeError:
            pass


    def _on_request_pin_code(self, parameters, invocation):
        logging.info("Agent.RequestPinCode")
        dialog_msg = _("Enter PIN code for authentication:")
        notify_msg = _("Enter PIN code")

        object_path = parameters.unpack()[0]
        default_pin = self._lookup_default_pin(object_path)
        if default_pin is not None:
            logging.info('Sending default pin: %s' % default_pin)
            invocation.return_value(GLib.Variant('(s)', (default_pin,)))
            return

        self.ask_passkey(dialog_msg, notify_msg, False, True, parameters, invocation)
        if self.dialog:
            self.dialog.present_with_time(self.time_func())

    def _on_request_passkey(self, parameters, invocation):
        logging.info("Agent.RequestPasskey")
        dialog_msg = _("Enter passkey for authentication:")
        notify_msg = _("Enter passkey")
        self.ask_passkey(dialog_msg, notify_msg, True, True, parameters, invocation)
        if self.dialog:
            self.dialog.present_with_time(self.time_func())

    def _on_display_passkey(self, parameters, invocation):
        device, passkey, entered = parameters.unpack()
        logging.info('DisplayPasskey (%s, %d)' % (device, passkey))
        dev = Bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed", self._on_device_property_changed)

        notify_message = _("Pairing passkey for") + " %s: %s" % (self.get_device_string(device), passkey)
        self.n = Notification("Bluetooth", notify_message, 0, icon_name="blueman", pos_hint=self.status_icon.geometry)
        self.n.show()

    def _on_display_pin_code(self, parameters, invocation):
        device, pin_code = parameters.unpack()
        logging.info('DisplayPinCode (%s, %s)' % (device, pin_code))
        dev = Bluez.Device(device)
        self.signal_id = dev.connect_signal("property-changed", self._on_device_property_changed)

        notify_message = _("Pairing PIN code for") + " %s: %s" % (self.get_device_string(device), pin_code)
        self.n = Notification("Bluetooth", notify_message, 0, icon_name="blueman", pos_hint=self.status_icon.geometry)
        self.n.show()

        invocation.return_value(None)

    def _on_request_confirmation(self, parameters, invocation):
        def on_confirm_action(action):
            if action == "confirm":
                invocation.return_value(GLib.Variant('()', ()))
            else:
                invocation.return_dbus_error('org.bluez.Error.Canceled', "User canceled pairing")

        params = parameters.unpack()
        if len(params) < 2:
            device_path = params[0]
            passkey = None
        else:
            device_path, passkey = params

        logging.info("Agent.RequestConfirmation")
        notify_message = _("Pairing request for:") + "\n%s" % self.get_device_string(device_path)

        if passkey:
            notify_message += "\n" + _("Confirm value for authentication:") + " <b>%s</b>" % passkey
        actions = [["confirm", _("Confirm")], ["deny", _("Deny")]]

        self.n = Notification("Bluetooth", notify_message, 0, actions, on_confirm_action, icon_name="blueman",
                              pos_hint=self.status_icon.geometry)
        self.n.show()

    def _on_request_authorization(self, parameters, invocation):
        self._on_request_confirmation(parameters, invocation)

    def _on_authorize_service(self, parameters, invocation):
        def on_auth_action(action):
            logging.info(action)

            if action == "always":
                device = Bluez.Device(n._device)
                device.set("Trusted", True)
            if action == "always" or action == "accept":
                invocation.return_value(GLib.Variant('()', ()))
            else:
                invocation.return_dbus_error('org.bluez.Error.Rejected', 'Rejected')

            self.n = None

        device, uuid = parameters.unpack()

        logging.info("Agent.Authorize")
        dev_str = self.get_device_string(device)
        service = ServiceUUID(uuid).name
        notify_message = (_("Authorization request for:") + "\n%s\n" + _("Service:") + " <b>%s</b>") % (dev_str, service)
        actions = [["always", _("Always accept")],
                   ["accept", _("Accept")],
                   ["deny", _("Deny")]]

        n = Notification(_("Bluetooth Authentication"), notify_message, 0, actions, on_auth_action,
                         icon_name="blueman", pos_hint=self.status_icon.geometry)
        n.show()
        n._device = device
예제 #55
0
class _Agent:
    def __init__(self, applet):
        self._applet = applet
        self._config = Config("org.blueman.transfer")

        self._agent_path = '/org/blueman/obex_agent'

        self._agent = obex.Agent(self._agent_path)
        self._agent.connect('release', self._on_release)
        self._agent.connect('authorize', self._on_authorize)
        self._agent.connect('cancel', self._on_cancel)

        self._allowed_devices = []
        self._notification = None
        self._pending_transfer = None
        self.transfers = {}

    def register(self):
        obex.AgentManager().register_agent(self._agent_path)

    def unregister(self):
        obex.AgentManager().unregister_agent(self._agent_path)

    def _on_release(self, _agent):
        raise Exception(self._agent_path + " was released unexpectedly")

    def _on_action(self, _notification, action):
        dprint(action)

        if action == "accept":
            self.transfers[self._pending_transfer['transfer_path']] = {
                'path': self._pending_transfer['root'] + '/' + os.path.basename(self._pending_transfer['filename']),
                'size': self._pending_transfer['size'],
                'name': self._pending_transfer['name']
            }
            self._agent.reply(self.transfers[self._pending_transfer['transfer_path']]['path'])
            self._allowed_devices.append(self._pending_transfer['address'])
            GLib.timeout_add(60000, self._allowed_devices.remove, self._pending_transfer['address'])
        else:
            self._agent.reply(obex.Error.Rejected)

    def _on_authorize(self, _agent, transfer_path):
        transfer = obex.Transfer(transfer_path)
        session = obex.Session(transfer.session)
        root = session.root
        address = session.address
        filename = transfer.name
        size = transfer.size

        try:
            device = self._applet.Manager.get_adapter().find_device(address)
            name = device["Alias"]
            trusted = device["Trusted"]
        except Exception as e:
            dprint(e)
            name = address
            trusted = False

        self._pending_transfer = {'transfer_path': transfer_path, 'address': address, 'root': root,
                                  'filename': filename, 'size': size, 'name': name}

        try:
            status_icon = self._applet.Plugins.StatusIcon
        except:
            status_icon = None

        # This device was neither allowed nor is it trusted -> ask for confirmation
        if address not in self._allowed_devices and not (self._config['opp-accept'] and trusted):
            self._notification = Notification(_("Incoming file over Bluetooth"),
                _("Incoming file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>",
                                                       "1": "<b>" + name + "</b>"},
                30000, [["accept", _("Accept"), "help-about"], ["reject", _("Reject"), "help-about"]], self._on_action,
                pixbuf=get_icon("blueman", 48), status_icon=status_icon)
        # Device is trusted or was already allowed, larger file -> display a notification, but auto-accept
        elif size > 350000:
            self._notification = Notification(_("Receiving file"),
                _("Receiving file %(0)s from %(1)s") % {"0": "<b>" + filename + "</b>",
                                                        "1": "<b>" + name + "</b>"},
                pixbuf=get_icon("blueman", 48), status_icon=status_icon)
            self._on_action(self._notification, 'accept')
        # Device is trusted or was already allowed. very small file -> auto-accept and transfer silently
        else:
            self._notification = None
            self._on_action(self._notification, "accept")

    def _on_cancel(self, agent):
        self._notification.close()
        agent.reply(obex.Error.Canceled)