#! /usr/bin/python3 from __future__ import print_function from __future__ import division from __future__ import absolute_import from __future__ import unicode_literals PAGE_INTRO = 0 PAGE_DEVLIST = 1 PAGE_PASSKEY = 2 PAGE_PAIRING = 3 PAGE_CONNECT = 4 PAGE_CONNECTING = 5 PAGE_FINISH = 6 pages = {} import os import sys import random import signal import dbus.glib from optparse import OptionParser #support running uninstalled _dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) if os.path.exists(os.path.join(_dirname, "CHANGELOG.md")): sys.path.insert(0, _dirname) from blueman.Constants import * from blueman.Functions import * from blueman.gui.DeviceSelectorWidget import DeviceSelectorWidget from blueman.main.applet.BluezAgent import TempAgent from blueman.bluez.Manager import Manager from blueman.bluez.BlueZInterface import BlueZInterface from blueman.main.FakeDevice import FakeDevice from blueman.main.Device import Device from blueman.main.AppletService import AppletService import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # Workaround introspection bug, gnome bug 622084 signal.signal(signal.SIGINT, signal.SIG_DFL) class Assistant: def __init__(self): setup_icon_path() usage = "Usage: %prog [options]" parser = OptionParser(usage) parser.add_option("-d", "--device", dest="device", action="store", help=_("Start configuration assistant for this device"), metavar="ADDRESS") (options, args) = parser.parse_args() check_bluetooth_status(_("Bluetooth needs to be turned on for the Bluetooth assistant to work"), lambda: exit()) self.options = options self.Device = None self.Adapter = None self.pair = True self.service = None self.Builder = Gtk.Builder() self.Builder.set_translation_domain("blueman") self.Builder.add_from_file(UI_PATH + "/assistant.ui") self.assistant = self.Builder.get_object("assistant") self.assistant.set_title(_("Bluetooth Assistant")) self.applet = AppletService() self.assistant.connect("prepare", self.on_prepare) self.assistant.connect("close", self.on_close) self.assistant.connect("cancel", self.on_close) pages[PAGE_INTRO] = self.Builder.get_object("l_page0") self.assistant.set_page_header_image(pages[PAGE_INTRO], get_icon("blueman", 32)) self.assistant.set_page_complete(pages[PAGE_INTRO], True) pages[PAGE_DEVLIST] = self.Builder.get_object("a_page1") self.assistant.set_page_header_image(pages[PAGE_DEVLIST], get_icon("blueman", 32)) pages[PAGE_PASSKEY] = self.Builder.get_object("a_page2") self.assistant.set_page_header_image(pages[PAGE_PASSKEY], get_icon("dialog-password", 32)) pages[PAGE_PAIRING] = self.Builder.get_object("l_page3") self.assistant.set_page_header_image(pages[PAGE_PAIRING], get_icon("dialog-password", 32)) pages[PAGE_CONNECT] = self.Builder.get_object("a_page4") self.assistant.set_page_header_image(pages[PAGE_CONNECT], get_icon("network-transmit-recieve", 32)) pages[PAGE_CONNECTING] = self.Builder.get_object("l_page5") self.assistant.set_page_header_image(pages[PAGE_CONNECTING], get_icon("network-transmit-recieve", 32)) pages[PAGE_FINISH] = self.Builder.get_object("l_page6") self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32)) self.svc_vbox = self.Builder.get_object("svcs") self.Builder.get_object("r_dontp").connect("toggled", self.on_pairing_method_changed, False) self.Builder.get_object("r_pair").connect("toggled", self.on_pairing_method_changed, True) self.dev_widget = DeviceSelectorWidget() self.dev_widget.List.connect("device-selected", self.on_device_selected) self.dev_widget.List.connect("row-activated", self.on_row_activated) self.assistant.set_forward_page_func(self.next_page_fn, None) pages[PAGE_DEVLIST].add(self.dev_widget) self.dev_widget.show() if not self.dev_widget.List.IsValidAdapter(): d = Gtk.MessageDialog(type=Gtk.MessageType.ERROR, ) d.props.text = _("No adapters found") d.props.icon_name = "blueman" d.props.title = "Blueman Assistant" d.add_button("window-close", Gtk.ResponseType.CANCEL) d.run() exit(1) self.assistant.show() if options.device != None: m = Manager() try: adapter = m.get_adapter() except: print("Error: No Adapters present") exit(1) try: d = adapter.find_device(options.device) self.Device = Device(d) self.Adapter = adapter if self.Device.Paired: self.assistant.set_current_page(PAGE_CONNECT) else: self.assistant.set_current_page(PAGE_PASSKEY) except: info = {} info["Address"] = options.device info["Name"] = info["Address"].replace(":", "-") info["Alias"] = info["Name"] info["Fake"] = True self.Device = FakeDevice(info) self.Adapter = adapter self.assistant.set_current_page(PAGE_PASSKEY) else: self.dev_widget.List.DiscoverDevices() Gtk.main() def on_row_activated(self, treeview, path, view_column, *args): self.assistant.set_current_page(self.next_page_fn(self.assistant.get_current_page(), None)) def next_page_fn(self, page, data): if page == PAGE_INTRO: return PAGE_DEVLIST elif page == PAGE_DEVLIST: if self.Device: if self.Device.Fake or not self.Device.Paired: return PAGE_PASSKEY else: return PAGE_CONNECT else: return PAGE_PASSKEY elif page == PAGE_PASSKEY: if self.Device and not self.Device.Fake and not self.Device.Paired and not self.pair: return PAGE_CONNECT #self.assistant.set_page_complete(pages[PAGE_PASSKEY], True) return PAGE_PAIRING elif page == PAGE_PAIRING: if len(self.Device.get_services()) == 0: return PAGE_FINISH return PAGE_CONNECT elif page == PAGE_CONNECT: if self.service: return PAGE_CONNECTING else: return PAGE_FINISH elif page == PAGE_CONNECTING: return PAGE_FINISH elif page == PAGE_FINISH: return PAGE_FINISH + 1 return page def on_pairing_method_changed(self, radio_button, pair): if radio_button.props.active: self.assistant.set_page_complete(pages[PAGE_PASSKEY], True) self.pair = pair def on_device_selected(self, list, device, iter): if not device: self.assistant.set_page_complete(pages[PAGE_DEVLIST], False) self.Device = None self.Adapter = list.Adapter else: self.assistant.set_page_complete(pages[PAGE_DEVLIST], True) self.Device = device self.Adapter = list.Adapter def on_close(self, assistant): Gtk.main_quit() def on_service_toggled(self, rb, service): if rb.props.active: self.service = service self.assistant.set_page_complete(pages[PAGE_CONNECT], True) def on_prepare(self, assistant, page): num = assistant.get_current_page() if num == PAGE_PASSKEY: self.assistant.set_page_complete(pages[PAGE_PASSKEY], True) elif num == PAGE_PAIRING: if self.Device.Fake and not self.pair: pages[PAGE_PAIRING].set_markup(_("Adding Device...")) self.assistant.set_page_title(pages[PAGE_PAIRING], _("Adding")) else: pages[PAGE_PAIRING].set_markup(_("Pairing in progress...")) if BlueZInterface.get_interface_version()[0] < 5: def ok(dev): self.Device = Device(dev) self.assistant.set_current_page(PAGE_CONNECT) def err(err): print(err) pages[PAGE_FINISH].set_markup(_("Failed to add device")) self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32)) self.assistant.set_current_page(PAGE_FINISH) if self.pair: agent_path = "/org/blueman/agent/temp/" + self.Device.Address.replace(":", "") agent = TempAgent(self.applet.Plugins.StatusIcon, agent_path, Gtk.get_current_event_time()) self.Adapter.create_paired_device(self.Device.Address, agent_path, "", reply_handler=ok, error_handler=err) else: self.Adapter.create_device(self.Device.Address, reply_handler=ok, error_handler=err) else: if self.pair: def ok(): self.Device = Device(device) self.assistant.set_current_page(PAGE_CONNECT) def err(err): print(err) pages[PAGE_FINISH].set_markup(_("Failed to add device")) self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32)) self.assistant.set_current_page(PAGE_FINISH) device = self.Adapter.find_device(self.Device.Address) device.pair(reply_handler=ok, error_handler=err) elif num == PAGE_CONNECT: self.svc_vbox.foreach(lambda x, y: self.svc_vbox.remove(x), None) print(self.Device.get_services()) rbs = [] for service in self.Device.get_services(): rbs.append(Gtk.RadioButton(service.name)) rbs[-1].connect("toggled", self.on_service_toggled, service) self.svc_vbox.pack_start(rbs[-1], False, False, 0) if len(rbs) > 1: rbs[-1].join_group(rbs[0]) rbs.append(Gtk.RadioButton(_("Don't connect"))) rbs[-1].join_group(rbs[0]) rbs[-1].connect("toggled", self.on_service_toggled, None) self.svc_vbox.pack_start(rbs[-1], False, False, 8) self.svc_vbox.show_all() rbs[0].emit("toggled") if len(self.svc_vbox.get_children()) == 1: self.assistant.set_current_page(self.next_page_fn(self.assistant.get_current_page(), None)) elif num == PAGE_CONNECTING: print("connect") def success(*args): pages[PAGE_FINISH].set_markup(_("Device added and connected successfuly")) self.assistant.set_page_complete(pages[PAGE_CONNECTING], True) self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("help-about", 32)) self.assistant.set_current_page(PAGE_FINISH) def fail(*args): pages[PAGE_FINISH].set_markup(_("Device added successfuly, but failed to connect")) self.assistant.set_page_complete(pages[PAGE_CONNECTING], True) self.assistant.set_page_header_image(pages[PAGE_FINISH], get_icon("dialog-warning", 32)) self.assistant.set_current_page(PAGE_FINISH) self.applet.connect_service(self.service.device.get_object_path(), self.service.uuid, reply_handler=success, error_handler=fail) set_proc_title() Assistant()