Parowanie urządzeń bez nakładek z gnome lub kde

Ktoś Bardzo Mądry wymyślił, że nie ma już potrzeby parowania urządzeń bluetooth w prosty sposób, przez wpisywanie pinu do plików konfiguracyjnych, ani też żadne passkey-agenty nie są potrzebne.

Zainstaluj sobie bluez-gnome albo kbluetooth i paruj. Nie chcesz pół gnome w systemie? To spadaj!

Ale jakbym chciał gnome, to bym po prostu zainstalował. Spróbuję uruchomić transfer plików pomiędzy telefonem a laptopem we fluxboksie.

Zakładam, że mamy już zainstalowany bluez, wystartowany bluetooth, a polecenie:

hcitool scan

wykrywa telefon i podaje jego MAC (dla pewności lepiej na tę chwilę upublicznić telefon).

Jak już pisałem na wstępie, w bluez-utils+bluez-libs albo alternatywnym bluez nie da się dopisać PIN do pliku hcid.conf, bo go po prostu nie ma. Nie ma żadnych pin-helperów. Jest odesłanie do nakładek graficznych z gnome/kde. Ale da się inaczej.

Na forum archa znalazłem rozwiązanie (post #8)

http://bbs.archlinux.org/viewtopic.php?id=66085

Trzeba tylko ukraść skrypt simple-agent z innej paczki bluez :) Pan Bardzo Mądry musiał mieć w tym jakiś cel... Pobieramy paczkę ze strony http://www.kernel.org/pub/linux/bluetooth/bluez-4.32.tar.bz2 i szukamy simple-agenta (dla leniwych - jest w folderze "test")

Na wszelki wypadek zamieszczam skrypt poniżej:

 #!/usr/bin/python
    import gobject
    import sys
    import dbus
    import dbus.service
    import dbus.mainloop.glib

    class Rejected(dbus.DBusException):
        _dbus_error_name = "org.bluez.Error.Rejected"

    class Agent(dbus.service.Object):
        exit_on_release = True

        def set_exit_on_release(self, exit_on_release):
            self.exit_on_release = exit_on_release

        @dbus.service.method("org.bluez.Agent",
                        in_signature="", out_signature="")
        def Release(self):
            print "Release"
            if self.exit_on_release:
                mainloop.quit()

        @dbus.service.method("org.bluez.Agent",
                        in_signature="os", out_signature="")
        def Authorize(self, device, uuid):
            print "Authorize (%s, %s)" % (device, uuid)

        @dbus.service.method("org.bluez.Agent",
                        in_signature="o", out_signature="s")
        def RequestPinCode(self, device):
            print "RequestPinCode (%s)" % (device)
            return raw_input("Enter PIN Code: ")

        @dbus.service.method("org.bluez.Agent",
                        in_signature="o", out_signature="u")
        def RequestPasskey(self, device):
            print "RequestPasskey (%s)" % (device)
            passkey = raw_input("Enter passkey: ")
            return dbus.UInt32(passkey)

        @dbus.service.method("org.bluez.Agent",
                        in_signature="ou", out_signature="")
        def DisplayPasskey(self, device, passkey):
            print "DisplayPasskey (%s, %d)" % (device, passkey)

        @dbus.service.method("org.bluez.Agent",
                        in_signature="ou", out_signature="")
        def RequestConfirmation(self, device, passkey):
            print "RequestConfirmation (%s, %d)" % (device, passkey)
            confirm = raw_input("Confirm passkey (yes/no): ")
            if (confirm == "yes"):
                return
            raise Rejected("Passkey doesn't match")

        @dbus.service.method("org.bluez.Agent",
                        in_signature="s", out_signature="")
        def ConfirmModeChange(self, mode):
            print "ConfirmModeChange (%s)" % (mode)

        @dbus.service.method("org.bluez.Agent",
                        in_signature="", out_signature="")
        def Cancel(self):
            print "Cancel"

    def create_device_reply(device):
        print "New device (%s)" % (device)
        mainloop.quit()

    def create_device_error(error):
        print "Creating device failed: %s" % (error)
        mainloop.quit()

    if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

        bus = dbus.SystemBus()
        manager = dbus.Interface(bus.get_object("org.bluez", "/"),
                                "org.bluez.Manager")

        if len(sys.argv) > 1:
            path = manager.FindAdapter(sys.argv[1])
        else:
            path = manager.DefaultAdapter()

        adapter = dbus.Interface(bus.get_object("org.bluez", path),
                                "org.bluez.Adapter")

        path = "/test/agent"
        agent = Agent(bus, path)

        mainloop = gobject.MainLoop()

        if len(sys.argv) > 2:
            if len(sys.argv) > 3:
                device = adapter.FindDevice(sys.argv[2])
                adapter.RemoveDevice(device)

            agent.set_exit_on_release(False)
            adapter.CreatePairedDevice(sys.argv[2], path, "DisplayYesNo",
                        reply_handler=create_device_reply,
                        error_handler=create_device_error)
        else:
            adapter.RegisterAgent(path, "DisplayYesNo")
            print "Agent registered"

        mainloop.run()

        #adapter.UnregisterAgent(path)
        #print "Agent unregistered"

Uruchamiamy skrypt z poziomu roota i parujemy urządzenia. Telefon zawoła o PIN, wklepujemy, następnie powtarzamy w konsoli. I już.

Przenoszenie plików pomiędzy urządzeniami

Do przerzucania plików z komputera na telefon potrzebny jest obexftp:

Poleceniem:

sdptool browse 00:11:22:33:44:55

przeglądamy telefon i szukamy fragmentu, gdzie występuje "OBEX" w towarzystwie "Protocol Descriptor List", zczytujemy numer "Channel". Przyda się do przerzucania plików.

Np. tak:

    Service Name: OBEX File Transfer
    Service RecHandle: 0x1001a
    Service Class ID List:
      "OBEX File Transfer" (0x1106)
    Protocol Descriptor List:
      "L2CAP" (0x0100)
      "RFCOMM" (0x0003)
        Channel: 11
      "OBEX" (0x0008)
    Language Base Attr List:
      code_ISO639: 0x454e
      encoding:    0x6a
      base_offset: 0x100
    Profile Descriptor List:
      "OBEX File Transfer" (0x1106)
        Version: 0x0100

Jest! Channel: 11

Teraz wystarczy już tylko:

obexftp --nopath --noconn --uuid none --bluetooth 00:11:22:33:44:55 --channel 11 --put <plik>

np.:

    obexftp --nopath --noconn --uuid none --bluetooth 00:11:22:33:44:55 --channel 11 --put zajebiaszcza_tapeta.png

Mój komputer jest niewidzialny!

Na wiki archa znalazłem coś do wyszukiwania niewidzialnych urządzeń:

Twój komputer jest niewidzialny (dla telefonu)? Włącz PSCAN i ISCAN:

$ hciconfig hci0 piscan

sprawdź, czy działa:

$ hciconfig 
hci0:   Type: USB
        BD Address: 00:12:34:56:78:9A ACL MTU: 192:8 SCO MTU: 64:8
        UP RUNNING PSCAN ISCAN
        RX bytes:20425 acl:115 sco:0 events:526 errors:0
        TX bytes:5543 acl:84 sco:0 commands:340 errors:0

Uwaga: Sprawdź czasy widoczności (DiscoverableTimeout) i parowalności (PairableTimeout) w /etc/bluetooth/main.conf!

http://wiki.archlinux.org/index.php/Bluetooth#Using_Obex_for_sending_and_receiving_files

Przesyłanie plików

Do przesyłania plików przyda się moduł fuse Tworzymy folder do montowania telefonu, np.:

sudo mkdir /mnt/e50

Montujemy telefon:

mount -t fuse "obexfs#-b00:11:22:33:44:55 -B6" /katalog_docelowy

np.: mount -t fuse "obexfs#-b00:11:22:33:44:55 -B6" /mnt/e50

Dostęp do telefonu uzyskujemy z poziomu roota, zatem:

sudo mc

pozwala przeglądać telefon; nie próbujcie nic kopiować - działa ale długo trwa! (no i root jest właścicielem plików).

Oprócz forum i wiki archlinux korzystałem też ze strony projektu Obex: http://dev.zuckschwerdt.org/openobex/wiki/ObexFtpExamples

Aktualizacja:

Montowanie za pomocą fuse przestało u mnie działać. Nie wiem jak u Was :) Działa za to sposób:

obexfs -b <mac address telefonu> /katalog docelowy

Potem już normalnie, czyli mc z prawami roota. Odmontowujemy za pomocą komendy:

fusermount -u /punkt montowania

Automatyzacja

Aby zautomatyzować proces montowania i odmontowywania można posłużyć się prostymi skryptami:

montuj_fon

#!/bin/bash
sudo modprobe fuse
sudo sh /home/user/Skrypty/simple-agent
obexfs -b 00:11:22:33:44:55/punkt montowania

Skrypt ten odwołuje się do znanego już nam skryptu simple-agent, dzięki któremu telefon nie wymaga montowania z prawami roota. Pozwala to na dostęp do pamięci telefonu i/lub karty pamięci z poziomu użytkownika przez dowolny manager plików.

odmontuj_fon

#!/bin/bash
sudo fusermount -u /mnt/e50
sudo modprobe -r fuse

Aktywatory można podczepić do paska narzędzi lub do menu managera okien, np. we fluxboksie:

.fluxbox/menu

...
[submenu] (telefon)
      [exec]  (montuj) {sh /home/user/Skrypty/montuj_fon}
      [exec]  (odmontuj) {sh /home/user/Skrypty/odmontuj_fon}
[end]
...