312 lines
12 KiB
Python
Executable File
312 lines
12 KiB
Python
Executable File
#! /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(_("<b>Adding Device...</b>"))
|
|
self.assistant.set_page_title(pages[PAGE_PAIRING], _("Adding"))
|
|
else:
|
|
pages[PAGE_PAIRING].set_markup(_("<b>Pairing in progress...</b>"))
|
|
|
|
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(_("<b>Failed to add device</b>"))
|
|
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(_("<b>Failed to add device</b>"))
|
|
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(_("<b>Device added and connected successfuly</b>"))
|
|
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(_("<b>Device added successfuly, but failed to connect</b>"))
|
|
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()
|