pbap-client 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #!/usr/bin/python
  2. # SPDX-License-Identifier: LGPL-2.1-or-later
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. import os
  5. import sys
  6. import dbus
  7. import dbus.service
  8. import dbus.mainloop.glib
  9. try:
  10. from gi.repository import GObject
  11. except ImportError:
  12. import gobject as GObject
  13. BUS_NAME='org.bluez.obex'
  14. PATH = '/org/bluez/obex'
  15. CLIENT_INTERFACE = 'org.bluez.obex.Client1'
  16. SESSION_INTERFACE = 'org.bluez.obex.Session1'
  17. PHONEBOOK_ACCESS_INTERFACE = 'org.bluez.obex.PhonebookAccess1'
  18. TRANSFER_INTERFACE = 'org.bluez.obex.Transfer1'
  19. class Transfer:
  20. def __init__(self, callback_func):
  21. self.callback_func = callback_func
  22. self.path = None
  23. self.filename = None
  24. class PbapClient:
  25. def __init__(self, session_path):
  26. self.transfers = 0
  27. self.props = dict()
  28. self.flush_func = None
  29. bus = dbus.SessionBus()
  30. obj = bus.get_object(BUS_NAME, session_path)
  31. self.session = dbus.Interface(obj, SESSION_INTERFACE)
  32. self.pbap = dbus.Interface(obj, PHONEBOOK_ACCESS_INTERFACE)
  33. bus.add_signal_receiver(self.properties_changed,
  34. dbus_interface="org.freedesktop.DBus.Properties",
  35. signal_name="PropertiesChanged",
  36. path_keyword="path")
  37. def register(self, path, properties, transfer):
  38. transfer.path = path
  39. transfer.filename = properties["Filename"]
  40. self.props[path] = transfer
  41. print("Transfer created: %s (file %s)" % (path,
  42. transfer.filename))
  43. def error(self, err):
  44. print(err)
  45. mainloop.quit()
  46. def transfer_complete(self, path):
  47. req = self.props.get(path)
  48. if req == None:
  49. return
  50. self.transfers -= 1
  51. print("Transfer %s complete" % path)
  52. try:
  53. f = open(req.filename, "r")
  54. os.remove(req.filename)
  55. lines = f.readlines()
  56. del self.props[path]
  57. req.callback_func(lines)
  58. except:
  59. pass
  60. if (len(self.props) == 0) and (self.transfers == 0):
  61. if self.flush_func != None:
  62. f = self.flush_func
  63. self.flush_func = None
  64. f()
  65. def transfer_error(self, path):
  66. print("Transfer %s error" % path)
  67. mainloop.quit()
  68. def properties_changed(self, interface, properties, invalidated, path):
  69. req = self.props.get(path)
  70. if req == None:
  71. return
  72. if properties['Status'] == 'complete':
  73. self.transfer_complete(path)
  74. return
  75. if properties['Status'] == 'error':
  76. self.transfer_error(path)
  77. return
  78. def pull(self, vcard, params, func):
  79. req = Transfer(func)
  80. self.pbap.Pull(vcard, "", params,
  81. reply_handler=lambda o, p: self.register(o, p, req),
  82. error_handler=self.error)
  83. self.transfers += 1
  84. def pull_all(self, params, func):
  85. req = Transfer(func)
  86. self.pbap.PullAll("", params,
  87. reply_handler=lambda o, p: self.register(o, p, req),
  88. error_handler=self.error)
  89. self.transfers += 1
  90. def flush_transfers(self, func):
  91. if (len(self.props) == 0) and (self.transfers == 0):
  92. return
  93. self.flush_func = func
  94. def interface(self):
  95. return self.pbap
  96. if __name__ == '__main__':
  97. dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
  98. bus = dbus.SessionBus()
  99. mainloop = GObject.MainLoop()
  100. client = dbus.Interface(bus.get_object(BUS_NAME, PATH),
  101. CLIENT_INTERFACE)
  102. if (len(sys.argv) < 2):
  103. print("Usage: %s <device>" % (sys.argv[0]))
  104. sys.exit(1)
  105. print("Creating Session")
  106. session_path = client.CreateSession(sys.argv[1], { "Target": "PBAP" })
  107. pbap_client = PbapClient(session_path)
  108. def process_result(lines, header):
  109. if header != None:
  110. print(header)
  111. for line in lines:
  112. print(line),
  113. print
  114. def test_paths(paths):
  115. if len(paths) == 0:
  116. print
  117. print("FINISHED")
  118. mainloop.quit()
  119. return
  120. path = paths[0]
  121. print("\n--- Select Phonebook %s ---\n" % (path))
  122. pbap_client.interface().Select("int", path)
  123. print("\n--- GetSize ---\n")
  124. ret = pbap_client.interface().GetSize()
  125. print("Size = %d\n" % (ret))
  126. print("\n--- List vCard ---\n")
  127. try:
  128. ret = pbap_client.interface().List(dbus.Dictionary())
  129. except:
  130. ret = []
  131. params = dbus.Dictionary({ "Format" : "vcard30",
  132. "Fields" : ["PHOTO"] })
  133. for item in ret:
  134. print("%s : %s" % (item[0], item[1]))
  135. pbap_client.pull(item[0], params,
  136. lambda x: process_result(x, None))
  137. pbap_client.pull_all(params, lambda x: process_result(x,
  138. "\n--- PullAll ---\n"))
  139. pbap_client.flush_transfers(lambda: test_paths(paths[1:]))
  140. test_paths(["PB", "ICH", "OCH", "MCH", "CCH", "SPD", "FAV"])
  141. mainloop.run()