#!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1-or-later from __future__ import absolute_import, print_function, unicode_literals import os import sys import dbus import dbus.service import dbus.mainloop.glib try: from gi.repository import GObject except ImportError: import gobject as GObject BUS_NAME='org.bluez.obex' PATH = '/org/bluez/obex' CLIENT_INTERFACE = 'org.bluez.obex.Client1' SESSION_INTERFACE = 'org.bluez.obex.Session1' PHONEBOOK_ACCESS_INTERFACE = 'org.bluez.obex.PhonebookAccess1' TRANSFER_INTERFACE = 'org.bluez.obex.Transfer1' class Transfer: def __init__(self, callback_func): self.callback_func = callback_func self.path = None self.filename = None class PbapClient: def __init__(self, session_path): self.transfers = 0 self.props = dict() self.flush_func = None bus = dbus.SessionBus() obj = bus.get_object(BUS_NAME, session_path) self.session = dbus.Interface(obj, SESSION_INTERFACE) self.pbap = dbus.Interface(obj, PHONEBOOK_ACCESS_INTERFACE) bus.add_signal_receiver(self.properties_changed, dbus_interface="org.freedesktop.DBus.Properties", signal_name="PropertiesChanged", path_keyword="path") def register(self, path, properties, transfer): transfer.path = path transfer.filename = properties["Filename"] self.props[path] = transfer print("Transfer created: %s (file %s)" % (path, transfer.filename)) def error(self, err): print(err) mainloop.quit() def transfer_complete(self, path): req = self.props.get(path) if req == None: return self.transfers -= 1 print("Transfer %s complete" % path) try: f = open(req.filename, "r") os.remove(req.filename) lines = f.readlines() del self.props[path] req.callback_func(lines) except: pass if (len(self.props) == 0) and (self.transfers == 0): if self.flush_func != None: f = self.flush_func self.flush_func = None f() def transfer_error(self, path): print("Transfer %s error" % path) mainloop.quit() def properties_changed(self, interface, properties, invalidated, path): req = self.props.get(path) if req == None: return if properties['Status'] == 'complete': self.transfer_complete(path) return if properties['Status'] == 'error': self.transfer_error(path) return def pull(self, vcard, params, func): req = Transfer(func) self.pbap.Pull(vcard, "", params, reply_handler=lambda o, p: self.register(o, p, req), error_handler=self.error) self.transfers += 1 def pull_all(self, params, func): req = Transfer(func) self.pbap.PullAll("", params, reply_handler=lambda o, p: self.register(o, p, req), error_handler=self.error) self.transfers += 1 def flush_transfers(self, func): if (len(self.props) == 0) and (self.transfers == 0): return self.flush_func = func def interface(self): return self.pbap if __name__ == '__main__': dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) bus = dbus.SessionBus() mainloop = GObject.MainLoop() client = dbus.Interface(bus.get_object(BUS_NAME, PATH), CLIENT_INTERFACE) if (len(sys.argv) < 2): print("Usage: %s " % (sys.argv[0])) sys.exit(1) print("Creating Session") session_path = client.CreateSession(sys.argv[1], { "Target": "PBAP" }) pbap_client = PbapClient(session_path) def process_result(lines, header): if header != None: print(header) for line in lines: print(line), print def test_paths(paths): if len(paths) == 0: print print("FINISHED") mainloop.quit() return path = paths[0] print("\n--- Select Phonebook %s ---\n" % (path)) pbap_client.interface().Select("int", path) print("\n--- GetSize ---\n") ret = pbap_client.interface().GetSize() print("Size = %d\n" % (ret)) print("\n--- List vCard ---\n") try: ret = pbap_client.interface().List(dbus.Dictionary()) except: ret = [] params = dbus.Dictionary({ "Format" : "vcard30", "Fields" : ["PHOTO"] }) for item in ret: print("%s : %s" % (item[0], item[1])) pbap_client.pull(item[0], params, lambda x: process_result(x, None)) pbap_client.pull_all(params, lambda x: process_result(x, "\n--- PullAll ---\n")) pbap_client.flush_transfers(lambda: test_paths(paths[1:])) test_paths(["PB", "ICH", "OCH", "MCH", "CCH", "SPD", "FAV"]) mainloop.run()