From 034a07d678ede7415b6942437a56d9804585e8c7 Mon Sep 17 00:00:00 2001 From: Wu zheng Date: Mon, 21 Oct 2013 15:46:54 +0800 Subject: Upgrade to bluez-5.10 for testing --- ChangeLog | 11 + Makefile.am | 2 +- Makefile.android | 2 + Makefile.in | 196 ++- Makefile.tools | 7 +- android/Android.mk | 20 + android/hal-ipc-api.txt | 1247 +++++++++++++++++++ bluez.pc.in | 10 - configure | 42 +- configure.ac | 2 +- doc/input-api.txt | 32 - doc/mgmt-api.txt | 50 +- doc/settings-storage.txt | 225 ---- emulator/btdev.c | 23 + gdbus/client.c | 5 - gdbus/object.c | 11 +- monitor/bt.h | 9 + monitor/packet.c | 31 +- obexd/client/session.c | 12 + obexd/plugins/messages-tracker.c | 345 ------ obexd/plugins/phonebook-ebook.c | 707 ----------- obexd/plugins/phonebook-tracker.c | 1718 -------------------------- obexd/plugins/syncevolution.c | 482 -------- packaging/bluetooth.sh | 0 packaging/bluez.spec | 2 +- packaging/create-symlinks | 0 packaging/obex-root-setup | 0 profiles/audio/1.patch | 108 -- profiles/audio/avctp.c | 21 + profiles/audio/avdtp.c | 44 +- profiles/audio/media.c | 40 +- test/exchange-business-cards | 19 - test/ftp-client | 176 --- test/get-managed-objects | 29 - test/get-obex-capabilities | 19 - test/list-folders | 39 - test/map-client | 231 ---- test/opp-client | 116 -- test/pbap-client | 173 --- test/simple-obex-agent | 85 -- test/test-alert | 0 test/test-cyclingspeed | 0 test/test-heartrate | 0 test/test-hfp | 0 test/test-profile | 0 tools/bdaddr.1 | 68 -- tools/btmgmt.c | 4 +- tools/example.psr | 12 - tools/mgmt-tester.c | 37 + tools/mpris-player.c | 27 +- tools/obexctl.c | 2400 +++++++++++++++++++++++++++++++++++++ tools/sdptool.1 | 6 + tools/update_compids.sh | 57 - ylwrap | 226 ---- 54 files changed, 4133 insertions(+), 4995 deletions(-) create mode 100644 android/hal-ipc-api.txt delete mode 100644 bluez.pc.in delete mode 100644 doc/input-api.txt delete mode 100644 doc/settings-storage.txt delete mode 100644 obexd/plugins/messages-tracker.c delete mode 100644 obexd/plugins/phonebook-ebook.c delete mode 100644 obexd/plugins/phonebook-tracker.c delete mode 100644 obexd/plugins/syncevolution.c mode change 100644 => 100755 packaging/bluetooth.sh mode change 100644 => 100755 packaging/create-symlinks mode change 100644 => 100755 packaging/obex-root-setup delete mode 100644 profiles/audio/1.patch delete mode 100755 test/exchange-business-cards delete mode 100755 test/ftp-client delete mode 100755 test/get-managed-objects delete mode 100755 test/get-obex-capabilities delete mode 100755 test/list-folders delete mode 100755 test/map-client delete mode 100755 test/opp-client delete mode 100755 test/pbap-client delete mode 100755 test/simple-obex-agent mode change 100755 => 100644 test/test-alert mode change 100755 => 100644 test/test-cyclingspeed mode change 100755 => 100644 test/test-heartrate mode change 100755 => 100644 test/test-hfp mode change 100755 => 100644 test/test-profile delete mode 100644 tools/bdaddr.1 delete mode 100644 tools/example.psr create mode 100644 tools/obexctl.c delete mode 100755 tools/update_compids.sh delete mode 100755 ylwrap diff --git a/ChangeLog b/ChangeLog index d8296402..fc9b3d7f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +ver 5.10: + Fix issue with discoverable timeout handling. + Fix issue with MAP messages and record version. + Fix issue with MAP messages and status events. + Fix issue with MAP messages and relative folders. + Fix issue with MAP messages and type property signals. + Fix issue with transfer size for OBEX GET operations. + Fix issue with AVRCP service class identifier. + Fix issue with AVRCP tracking seeked signal. + Add support for OBEX command line client. + ver 5.9: Fix issue with network service and adapter removal. Fix issue with misleading OBEX error messages. diff --git a/Makefile.am b/Makefile.am index 51204f47..8aed6f7e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -80,7 +80,7 @@ include_HEADERS += $(lib_headers) lib_LTLIBRARIES += lib/libbluetooth.la lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources) -lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:0:17 +lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:1:17 lib_libbluetooth_la_DEPENDENCIES = $(local_headers) endif diff --git a/Makefile.android b/Makefile.android index e161e6dc..3ceefd8f 100644 --- a/Makefile.android +++ b/Makefile.android @@ -6,3 +6,5 @@ android_bluetoothd_LDADD = @GLIB_LIBS@ endif EXTRA_DIST += android/Android.mk android/log.c + +EXTRA_DIST += android/hal-ipc-api.txt diff --git a/Makefile.in b/Makefile.in index 68410241..677ad3e9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -58,12 +58,13 @@ build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) noinst_PROGRAMS = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ - $(am__EXEEXT_7) + $(am__EXEEXT_7) $(am__EXEEXT_8) libexec_PROGRAMS = src/bluetoothd$(EXEEXT) obexd/src/obexd$(EXEEXT) @LIBRARY_TRUE@am__append_1 = $(lib_headers) @LIBRARY_TRUE@am__append_2 = lib/libbluetooth.la DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \ - $(dist_man_MANS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(dist_man_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.android $(srcdir)/Makefile.in \ $(srcdir)/Makefile.obexd $(srcdir)/Makefile.plugins \ $(srcdir)/Makefile.tools $(srcdir)/config.h.in \ $(top_srcdir)/configure $(top_srcdir)/lib/bluez.pc.in \ @@ -114,10 +115,11 @@ DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \ @EXPERIMENTAL_TRUE@ tools/mgmt-tester tools/gap-tester \ @EXPERIMENTAL_TRUE@ tools/l2cap-tester tools/sco-tester \ @EXPERIMENTAL_TRUE@ tools/bdaddr tools/avinfo tools/avtest \ -@EXPERIMENTAL_TRUE@ tools/scotest tools/hcieventmask \ -@EXPERIMENTAL_TRUE@ tools/hcisecfilter tools/hwdb tools/btmgmt \ -@EXPERIMENTAL_TRUE@ tools/btinfo tools/btattach tools/btsnoop \ -@EXPERIMENTAL_TRUE@ tools/btiotest tools/mpris-player +@EXPERIMENTAL_TRUE@ tools/scotest tools/amptest tools/hwdb \ +@EXPERIMENTAL_TRUE@ tools/hcieventmask tools/hcisecfilter \ +@EXPERIMENTAL_TRUE@ tools/btmgmt tools/btinfo tools/btattach \ +@EXPERIMENTAL_TRUE@ tools/btsnoop tools/btiotest tools/cltest \ +@EXPERIMENTAL_TRUE@ tools/mpris-player @TOOLS_TRUE@am__append_16 = tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \ @TOOLS_TRUE@ tools/rfcomm tools/rctest tools/l2test tools/l2ping \ @TOOLS_TRUE@ tools/sdptool tools/ciptool tools/bccmd @@ -138,7 +140,7 @@ DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \ @EXPERIMENTAL_TRUE@am__append_21 = tools/bdaddr.1 @READLINE_TRUE@am__append_22 = attrib/gatttool \ @READLINE_TRUE@ tools/obex-client-tool tools/obex-server-tool \ -@READLINE_TRUE@ tools/bluetooth-player +@READLINE_TRUE@ tools/bluetooth-player tools/obexctl @EXPERIMENTAL_TRUE@am__append_23 = profiles/iap/iapd @CUPS_TRUE@cups_PROGRAMS = profiles/cups/bluetooth$(EXEEXT) @@ -149,8 +151,9 @@ DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \ @OBEX_TRUE@ obexd/plugins/vcard.h obexd/plugins/vcard.c \ @OBEX_TRUE@ obexd/plugins/phonebook.h \ @OBEX_TRUE@ obexd/plugins/phonebook-dummy.c -@HID2HCI_TRUE@am__append_28 = $(rules_DATA) -TESTS = $(am__EXEEXT_7) +@ANDROID_TRUE@am__append_28 = android/bluetoothd +@HID2HCI_TRUE@am__append_29 = $(rules_DATA) +TESTS = $(am__EXEEXT_8) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ @@ -275,20 +278,23 @@ plugins_external_dummy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @EXPERIMENTAL_TRUE@ tools/bdaddr$(EXEEXT) tools/avinfo$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/avtest$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/scotest$(EXEEXT) \ +@EXPERIMENTAL_TRUE@ tools/amptest$(EXEEXT) tools/hwdb$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/hcieventmask$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/hcisecfilter$(EXEEXT) \ -@EXPERIMENTAL_TRUE@ tools/hwdb$(EXEEXT) tools/btmgmt$(EXEEXT) \ -@EXPERIMENTAL_TRUE@ tools/btinfo$(EXEEXT) \ +@EXPERIMENTAL_TRUE@ tools/btmgmt$(EXEEXT) tools/btinfo$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/btattach$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/btsnoop$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/btiotest$(EXEEXT) \ +@EXPERIMENTAL_TRUE@ tools/cltest$(EXEEXT) \ @EXPERIMENTAL_TRUE@ tools/mpris-player$(EXEEXT) @READLINE_TRUE@am__EXEEXT_5 = attrib/gatttool$(EXEEXT) \ @READLINE_TRUE@ tools/obex-client-tool$(EXEEXT) \ @READLINE_TRUE@ tools/obex-server-tool$(EXEEXT) \ -@READLINE_TRUE@ tools/bluetooth-player$(EXEEXT) +@READLINE_TRUE@ tools/bluetooth-player$(EXEEXT) \ +@READLINE_TRUE@ tools/obexctl$(EXEEXT) @EXPERIMENTAL_TRUE@am__EXEEXT_6 = profiles/iap/iapd$(EXEEXT) -am__EXEEXT_7 = unit/test-eir$(EXEEXT) unit/test-uuid$(EXEEXT) \ +@ANDROID_TRUE@am__EXEEXT_7 = android/bluetoothd$(EXEEXT) +am__EXEEXT_8 = unit/test-eir$(EXEEXT) unit/test-uuid$(EXEEXT) \ unit/test-textfile$(EXEEXT) unit/test-crc$(EXEEXT) \ unit/test-mgmt$(EXEEXT) unit/test-sdp$(EXEEXT) \ unit/test-gdbus-client$(EXEEXT) \ @@ -298,6 +304,11 @@ am__EXEEXT_7 = unit/test-eir$(EXEEXT) unit/test-uuid$(EXEEXT) \ unit/test-gobex-apparam$(EXEEXT) unit/test-lib$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(cups_PROGRAMS) $(libexec_PROGRAMS) \ $(noinst_PROGRAMS) $(udev_PROGRAMS) +am__android_bluetoothd_SOURCES_DIST = android/main.c src/log.c +@ANDROID_TRUE@am_android_bluetoothd_OBJECTS = android/main.$(OBJEXT) \ +@ANDROID_TRUE@ src/log.$(OBJEXT) +android_bluetoothd_OBJECTS = $(am_android_bluetoothd_OBJECTS) +android_bluetoothd_DEPENDENCIES = am__attrib_gatttool_SOURCES_DIST = attrib/gatttool.c attrib/att.c \ attrib/gatt.c attrib/gattrib.c btio/btio.c attrib/gatttool.h \ attrib/interactive.c attrib/utils.c src/log.c client/display.c \ @@ -330,14 +341,15 @@ am__emulator_btvirt_SOURCES_DIST = emulator/main.c monitor/bt.h \ monitor/mainloop.h monitor/mainloop.c emulator/server.h \ emulator/server.c emulator/vhci.h emulator/vhci.c \ emulator/btdev.h emulator/btdev.c emulator/bthost.h \ - emulator/bthost.c + emulator/bthost.c emulator/amp.h emulator/amp.c @EXPERIMENTAL_TRUE@am_emulator_btvirt_OBJECTS = \ @EXPERIMENTAL_TRUE@ emulator/main.$(OBJEXT) \ @EXPERIMENTAL_TRUE@ monitor/mainloop.$(OBJEXT) \ @EXPERIMENTAL_TRUE@ emulator/server.$(OBJEXT) \ @EXPERIMENTAL_TRUE@ emulator/vhci.$(OBJEXT) \ @EXPERIMENTAL_TRUE@ emulator/btdev.$(OBJEXT) \ -@EXPERIMENTAL_TRUE@ emulator/bthost.$(OBJEXT) +@EXPERIMENTAL_TRUE@ emulator/bthost.$(OBJEXT) \ +@EXPERIMENTAL_TRUE@ emulator/amp.$(OBJEXT) emulator_btvirt_OBJECTS = $(am_emulator_btvirt_OBJECTS) emulator_btvirt_LDADD = $(LDADD) am__monitor_btmon_SOURCES_DIST = monitor/main.c monitor/bt.h \ @@ -614,6 +626,10 @@ src_bluetoothd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(src_bluetoothd_CFLAGS) $(CFLAGS) $(src_bluetoothd_LDFLAGS) \ $(LDFLAGS) -o $@ +tools_amptest_SOURCES = tools/amptest.c +tools_amptest_OBJECTS = tools/amptest.$(OBJEXT) +@EXPERIMENTAL_TRUE@tools_amptest_DEPENDENCIES = \ +@EXPERIMENTAL_TRUE@ lib/libbluetooth-internal.la tools_avinfo_SOURCES = tools/avinfo.c tools_avinfo_OBJECTS = tools/avinfo.$(OBJEXT) @EXPERIMENTAL_TRUE@tools_avinfo_DEPENDENCIES = \ @@ -681,6 +697,13 @@ tools_btsnoop_LDADD = $(LDADD) tools_ciptool_SOURCES = tools/ciptool.c tools_ciptool_OBJECTS = tools/ciptool.$(OBJEXT) @TOOLS_TRUE@tools_ciptool_DEPENDENCIES = lib/libbluetooth-internal.la +am__tools_cltest_SOURCES_DIST = tools/cltest.c monitor/mainloop.h \ + monitor/mainloop.c +@EXPERIMENTAL_TRUE@am_tools_cltest_OBJECTS = tools/cltest.$(OBJEXT) \ +@EXPERIMENTAL_TRUE@ monitor/mainloop.$(OBJEXT) +tools_cltest_OBJECTS = $(am_tools_cltest_OBJECTS) +@EXPERIMENTAL_TRUE@tools_cltest_DEPENDENCIES = \ +@EXPERIMENTAL_TRUE@ lib/libbluetooth-internal.la am__tools_gap_tester_SOURCES_DIST = tools/gap-tester.c monitor/bt.h \ emulator/btdev.h emulator/btdev.c emulator/bthost.h \ emulator/bthost.c src/shared/hciemu.h src/shared/hciemu.c \ @@ -844,6 +867,13 @@ am__tools_obex_server_tool_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \ tools_obex_server_tool_OBJECTS = $(am_tools_obex_server_tool_OBJECTS) @READLINE_TRUE@tools_obex_server_tool_DEPENDENCIES = \ @READLINE_TRUE@ lib/libbluetooth-internal.la +am__tools_obexctl_SOURCES_DIST = tools/obexctl.c client/display.h \ + client/display.c +@READLINE_TRUE@am_tools_obexctl_OBJECTS = tools/obexctl.$(OBJEXT) \ +@READLINE_TRUE@ client/display.$(OBJEXT) +tools_obexctl_OBJECTS = $(am_tools_obexctl_OBJECTS) +@READLINE_TRUE@tools_obexctl_DEPENDENCIES = \ +@READLINE_TRUE@ gdbus/libgdbus-internal.la tools_rctest_SOURCES = tools/rctest.c tools_rctest_OBJECTS = tools/rctest.$(OBJEXT) @TOOLS_TRUE@tools_rctest_DEPENDENCIES = lib/libbluetooth-internal.la @@ -957,18 +987,19 @@ SOURCES = $(profiles_sap_libsap_a_SOURCES) \ $(lib_libbluetooth_internal_la_SOURCES) \ $(lib_libbluetooth_la_SOURCES) \ $(plugins_external_dummy_la_SOURCES) \ - $(attrib_gatttool_SOURCES) $(client_bluetoothctl_SOURCES) \ - $(emulator_b1ee_SOURCES) $(emulator_btvirt_SOURCES) \ - $(monitor_btmon_SOURCES) $(obexd_src_obexd_SOURCES) \ - $(nodist_obexd_src_obexd_SOURCES) \ + $(android_bluetoothd_SOURCES) $(attrib_gatttool_SOURCES) \ + $(client_bluetoothctl_SOURCES) $(emulator_b1ee_SOURCES) \ + $(emulator_btvirt_SOURCES) $(monitor_btmon_SOURCES) \ + $(obexd_src_obexd_SOURCES) $(nodist_obexd_src_obexd_SOURCES) \ $(profiles_cups_bluetooth_SOURCES) \ $(profiles_iap_iapd_SOURCES) $(src_bluetoothd_SOURCES) \ - $(nodist_src_bluetoothd_SOURCES) tools/avinfo.c tools/avtest.c \ - $(tools_bccmd_SOURCES) $(tools_bdaddr_SOURCES) \ - $(tools_bluetooth_player_SOURCES) tools/btattach.c \ - $(tools_btinfo_SOURCES) $(tools_btiotest_SOURCES) \ - $(tools_btmgmt_SOURCES) $(tools_btsnoop_SOURCES) \ - tools/ciptool.c $(tools_gap_tester_SOURCES) \ + $(nodist_src_bluetoothd_SOURCES) tools/amptest.c \ + tools/avinfo.c tools/avtest.c $(tools_bccmd_SOURCES) \ + $(tools_bdaddr_SOURCES) $(tools_bluetooth_player_SOURCES) \ + tools/btattach.c $(tools_btinfo_SOURCES) \ + $(tools_btiotest_SOURCES) $(tools_btmgmt_SOURCES) \ + $(tools_btsnoop_SOURCES) tools/ciptool.c \ + $(tools_cltest_SOURCES) $(tools_gap_tester_SOURCES) \ $(tools_hciattach_SOURCES) $(tools_hciconfig_SOURCES) \ $(tools_hcidump_SOURCES) tools/hcieventmask.c \ tools/hcisecfilter.c $(tools_hcitool_SOURCES) tools/hid2hci.c \ @@ -976,11 +1007,12 @@ SOURCES = $(profiles_sap_libsap_a_SOURCES) \ tools/l2test.c $(tools_mgmt_tester_SOURCES) \ $(tools_mpris_player_SOURCES) \ $(tools_obex_client_tool_SOURCES) \ - $(tools_obex_server_tool_SOURCES) tools/rctest.c \ - tools/rfcomm.c $(tools_sco_tester_SOURCES) tools/scotest.c \ - $(tools_sdptool_SOURCES) $(unit_test_crc_SOURCES) \ - $(unit_test_eir_SOURCES) $(unit_test_gdbus_client_SOURCES) \ - $(unit_test_gobex_SOURCES) $(unit_test_gobex_apparam_SOURCES) \ + $(tools_obex_server_tool_SOURCES) $(tools_obexctl_SOURCES) \ + tools/rctest.c tools/rfcomm.c $(tools_sco_tester_SOURCES) \ + tools/scotest.c $(tools_sdptool_SOURCES) \ + $(unit_test_crc_SOURCES) $(unit_test_eir_SOURCES) \ + $(unit_test_gdbus_client_SOURCES) $(unit_test_gobex_SOURCES) \ + $(unit_test_gobex_apparam_SOURCES) \ $(unit_test_gobex_header_SOURCES) \ $(unit_test_gobex_packet_SOURCES) \ $(unit_test_gobex_transfer_SOURCES) $(unit_test_lib_SOURCES) \ @@ -991,6 +1023,7 @@ DIST_SOURCES = $(am__profiles_sap_libsap_a_SOURCES_DIST) \ $(lib_libbluetooth_internal_la_SOURCES) \ $(am__lib_libbluetooth_la_SOURCES_DIST) \ $(am__plugins_external_dummy_la_SOURCES_DIST) \ + $(am__android_bluetoothd_SOURCES_DIST) \ $(am__attrib_gatttool_SOURCES_DIST) \ $(am__client_bluetoothctl_SOURCES_DIST) \ $(am__emulator_b1ee_SOURCES_DIST) \ @@ -999,14 +1032,15 @@ DIST_SOURCES = $(am__profiles_sap_libsap_a_SOURCES_DIST) \ $(am__obexd_src_obexd_SOURCES_DIST) \ $(am__profiles_cups_bluetooth_SOURCES_DIST) \ $(am__profiles_iap_iapd_SOURCES_DIST) \ - $(am__src_bluetoothd_SOURCES_DIST) tools/avinfo.c \ - tools/avtest.c $(am__tools_bccmd_SOURCES_DIST) \ + $(am__src_bluetoothd_SOURCES_DIST) tools/amptest.c \ + tools/avinfo.c tools/avtest.c $(am__tools_bccmd_SOURCES_DIST) \ $(am__tools_bdaddr_SOURCES_DIST) \ $(am__tools_bluetooth_player_SOURCES_DIST) tools/btattach.c \ $(am__tools_btinfo_SOURCES_DIST) \ $(am__tools_btiotest_SOURCES_DIST) \ $(am__tools_btmgmt_SOURCES_DIST) \ $(am__tools_btsnoop_SOURCES_DIST) tools/ciptool.c \ + $(am__tools_cltest_SOURCES_DIST) \ $(am__tools_gap_tester_SOURCES_DIST) \ $(am__tools_hciattach_SOURCES_DIST) \ $(am__tools_hciconfig_SOURCES_DIST) \ @@ -1017,7 +1051,8 @@ DIST_SOURCES = $(am__profiles_sap_libsap_a_SOURCES_DIST) \ tools/l2test.c $(am__tools_mgmt_tester_SOURCES_DIST) \ $(am__tools_mpris_player_SOURCES_DIST) \ $(am__tools_obex_client_tool_SOURCES_DIST) \ - $(am__tools_obex_server_tool_SOURCES_DIST) tools/rctest.c \ + $(am__tools_obex_server_tool_SOURCES_DIST) \ + $(am__tools_obexctl_SOURCES_DIST) tools/rctest.c \ tools/rfcomm.c $(am__tools_sco_tester_SOURCES_DIST) \ tools/scotest.c $(am__tools_sdptool_SOURCES_DIST) \ $(unit_test_crc_SOURCES) $(unit_test_eir_SOURCES) \ @@ -1224,13 +1259,14 @@ dist_man_MANS = $(am__append_17) $(am__append_19) dist_noinst_MANS = CLEANFILES = $(builtin_files) src/bluetooth.service \ obexd/src/builtin.h $(builtin_files) obexd/src/obex.service \ - $(am__append_28) + $(am__append_29) EXTRA_DIST = src/bluetooth.service.in src/org.bluez.service \ src/genbuiltin src/bluetooth.conf src/main.conf \ profiles/network/network.conf profiles/input/input.conf \ profiles/proximity/proximity.conf $(am__append_18) \ $(am__append_20) $(am__append_21) obexd/src/obex.service.in \ obexd/src/org.bluez.obex.service obexd/src/genbuiltin \ + android/Android.mk android/log.c android/hal-ipc-api.txt \ tools/hid2hci.rules $(test_scripts) doc/assigned-numbers.txt \ doc/supported-features.txt doc/mgmt-api.txt \ doc/adapter-api.txt doc/device-api.txt doc/agent-api.txt \ @@ -1267,7 +1303,7 @@ extra_sources = lib/uuid.c local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file))) BUILT_SOURCES = $(local_headers) src/builtin.h obexd/src/builtin.h @LIBRARY_TRUE@lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources) -@LIBRARY_TRUE@lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:0:17 +@LIBRARY_TRUE@lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:1:17 @LIBRARY_TRUE@lib_libbluetooth_la_DEPENDENCIES = $(local_headers) lib_libbluetooth_internal_la_SOURCES = $(lib_headers) $(lib_sources) \ $(extra_headers) $(extra_sources) @@ -1405,7 +1441,8 @@ test_scripts = test/sap_client.py test/bluezutils.py test/dbusdef.py \ @EXPERIMENTAL_TRUE@ emulator/server.h emulator/server.c \ @EXPERIMENTAL_TRUE@ emulator/vhci.h emulator/vhci.c \ @EXPERIMENTAL_TRUE@ emulator/btdev.h emulator/btdev.c \ -@EXPERIMENTAL_TRUE@ emulator/bthost.h emulator/bthost.c +@EXPERIMENTAL_TRUE@ emulator/bthost.h emulator/bthost.c \ +@EXPERIMENTAL_TRUE@ emulator/amp.h emulator/amp.c @EXPERIMENTAL_TRUE@emulator_b1ee_SOURCES = emulator/b1ee.c monitor/mainloop.h monitor/mainloop.c @EXPERIMENTAL_TRUE@tools_mgmt_tester_SOURCES = tools/mgmt-tester.c monitor/bt.h \ @@ -1502,8 +1539,9 @@ test_scripts = test/sap_client.py test/bluezutils.py test/dbusdef.py \ @EXPERIMENTAL_TRUE@tools_avinfo_LDADD = lib/libbluetooth-internal.la @EXPERIMENTAL_TRUE@tools_avtest_LDADD = lib/libbluetooth-internal.la @EXPERIMENTAL_TRUE@tools_scotest_LDADD = lib/libbluetooth-internal.la -@EXPERIMENTAL_TRUE@tools_hcieventmask_LDADD = lib/libbluetooth-internal.la +@EXPERIMENTAL_TRUE@tools_amptest_LDADD = lib/libbluetooth-internal.la @EXPERIMENTAL_TRUE@tools_hwdb_LDADD = lib/libbluetooth-internal.la +@EXPERIMENTAL_TRUE@tools_hcieventmask_LDADD = lib/libbluetooth-internal.la @EXPERIMENTAL_TRUE@tools_btmgmt_SOURCES = tools/btmgmt.c src/glib-helper.c src/eir.c \ @EXPERIMENTAL_TRUE@ src/shared/util.h src/shared/util.c \ @EXPERIMENTAL_TRUE@ src/shared/mgmt.h src/shared/mgmt.c @@ -1518,6 +1556,8 @@ test_scripts = test/sap_client.py test/bluezutils.py test/dbusdef.py \ @EXPERIMENTAL_TRUE@tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ @EXPERIMENTAL_TRUE@tools_mpris_player_SOURCES = tools/mpris-player.c @EXPERIMENTAL_TRUE@tools_mpris_player_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ +@EXPERIMENTAL_TRUE@tools_cltest_SOURCES = tools/cltest.c monitor/mainloop.h monitor/mainloop.c +@EXPERIMENTAL_TRUE@tools_cltest_LDADD = lib/libbluetooth-internal.la @READLINE_TRUE@attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \ @READLINE_TRUE@ attrib/gattrib.c btio/btio.c \ @READLINE_TRUE@ attrib/gatttool.h attrib/interactive.c \ @@ -1541,6 +1581,12 @@ test_scripts = test/sap_client.py test/bluezutils.py test/dbusdef.py \ @READLINE_TRUE@tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \ @READLINE_TRUE@ @GLIB_LIBS@ @DBUS_LIBS@ -lreadline +@READLINE_TRUE@tools_obexctl_SOURCES = tools/obexctl.c \ +@READLINE_TRUE@ client/display.h client/display.c + +@READLINE_TRUE@tools_obexctl_LDADD = gdbus/libgdbus-internal.la \ +@READLINE_TRUE@ @GLIB_LIBS@ @DBUS_LIBS@ -lreadline + @EXPERIMENTAL_TRUE@profiles_iap_iapd_SOURCES = profiles/iap/main.c @EXPERIMENTAL_TRUE@profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ @CUPS_TRUE@cupsdir = $(libdir)/cups/backend @@ -1600,10 +1646,10 @@ obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \ @ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic -obexd_src_obexd_CFLAGS = @GLIB_CFLAGS@ @DBUS_CFLAGS@ @ICAL_CFLAGS@ \ - -DOBEX_PLUGIN_BUILTIN \ - -DPLUGINDIR=\""$(obex_plugindir)"\" \ - -fPIC -D_FILE_OFFSET_BITS=64 +obexd_src_obexd_CFLAGS = $(AM_CFLAGS) @GLIB_CFLAGS@ @DBUS_CFLAGS@ \ + @ICAL_CFLAGS@ -DOBEX_PLUGIN_BUILTIN \ + -DPLUGINDIR=\""$(obex_plugindir)"\" \ + -fPIC -D_FILE_OFFSET_BITS=64 obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src \ -I$(srcdir)/obexd/src -I$(srcdir)/btio \ @@ -1612,6 +1658,8 @@ obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src \ obexd_src_obexd_SHORTNAME = obexd obexd_builtin_files = obexd/src/builtin.h $(obexd_builtin_nodist) nodist_obexd_src_obexd_SOURCES = $(obexd_builtin_files) +@ANDROID_TRUE@android_bluetoothd_SOURCES = android/main.c src/log.c +@ANDROID_TRUE@android_bluetoothd_LDADD = @GLIB_LIBS@ @HID2HCI_TRUE@rulesdir = @UDEV_DIR@/rules.d @HID2HCI_TRUE@rules_DATA = tools/97-hid2hci.rules @TEST_TRUE@testdir = $(pkglibdir)/test @@ -1672,7 +1720,8 @@ unit_test_lib_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ pkgconfigdir = $(libdir)/pkgconfig @LIBRARY_TRUE@pkgconfig_DATA = lib/bluez.pc DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles --enable-library \ - --disable-systemd --disable-udev + --disable-systemd --disable-udev \ + --enable-android DISTCLEANFILES = $(pkgconfig_DATA) MAINTAINERCLEANFILES = Makefile.in \ @@ -1690,7 +1739,7 @@ all: $(BUILT_SOURCES) config.h .SUFFIXES: .c .lo .o .obj am--refresh: Makefile @: -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(am__configure_deps) +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/Makefile.android $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -1713,7 +1762,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; -$(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd: +$(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/Makefile.android: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck @@ -2061,6 +2110,24 @@ clean-udevPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list +android/$(am__dirstamp): + @$(MKDIR_P) android + @: > android/$(am__dirstamp) +android/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) android/$(DEPDIR) + @: > android/$(DEPDIR)/$(am__dirstamp) +android/main.$(OBJEXT): android/$(am__dirstamp) \ + android/$(DEPDIR)/$(am__dirstamp) +src/$(am__dirstamp): + @$(MKDIR_P) src + @: > src/$(am__dirstamp) +src/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) src/$(DEPDIR) + @: > src/$(DEPDIR)/$(am__dirstamp) +src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) +android/bluetoothd$(EXEEXT): $(android_bluetoothd_OBJECTS) $(android_bluetoothd_DEPENDENCIES) $(EXTRA_android_bluetoothd_DEPENDENCIES) android/$(am__dirstamp) + @rm -f android/bluetoothd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(android_bluetoothd_OBJECTS) $(android_bluetoothd_LDADD) $(LIBS) attrib/$(am__dirstamp): @$(MKDIR_P) attrib @: > attrib/$(am__dirstamp) @@ -2087,13 +2154,6 @@ attrib/interactive.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/utils.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) -src/$(am__dirstamp): - @$(MKDIR_P) src - @: > src/$(am__dirstamp) -src/$(DEPDIR)/$(am__dirstamp): - @$(MKDIR_P) src/$(DEPDIR) - @: > src/$(DEPDIR)/$(am__dirstamp) -src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) client/$(am__dirstamp): @$(MKDIR_P) client @: > client/$(am__dirstamp) @@ -2143,6 +2203,8 @@ emulator/btdev.$(OBJEXT): emulator/$(am__dirstamp) \ emulator/$(DEPDIR)/$(am__dirstamp) emulator/bthost.$(OBJEXT): emulator/$(am__dirstamp) \ emulator/$(DEPDIR)/$(am__dirstamp) +emulator/amp.$(OBJEXT): emulator/$(am__dirstamp) \ + emulator/$(DEPDIR)/$(am__dirstamp) emulator/btvirt$(EXEEXT): $(emulator_btvirt_OBJECTS) $(emulator_btvirt_DEPENDENCIES) $(EXTRA_emulator_btvirt_DEPENDENCIES) emulator/$(am__dirstamp) @rm -f emulator/btvirt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(emulator_btvirt_OBJECTS) $(emulator_btvirt_LDADD) $(LIBS) @@ -2606,6 +2668,11 @@ tools/$(am__dirstamp): tools/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) tools/$(DEPDIR) @: > tools/$(DEPDIR)/$(am__dirstamp) +tools/amptest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/amptest$(EXEEXT): $(tools_amptest_OBJECTS) $(tools_amptest_DEPENDENCIES) $(EXTRA_tools_amptest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/amptest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_amptest_OBJECTS) $(tools_amptest_LDADD) $(LIBS) tools/avinfo.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/avinfo$(EXEEXT): $(tools_avinfo_OBJECTS) $(tools_avinfo_DEPENDENCIES) $(EXTRA_tools_avinfo_DEPENDENCIES) tools/$(am__dirstamp) @@ -2687,6 +2754,11 @@ tools/ciptool.$(OBJEXT): tools/$(am__dirstamp) \ tools/ciptool$(EXEEXT): $(tools_ciptool_OBJECTS) $(tools_ciptool_DEPENDENCIES) $(EXTRA_tools_ciptool_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/ciptool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_ciptool_OBJECTS) $(tools_ciptool_LDADD) $(LIBS) +tools/cltest.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/cltest$(EXEEXT): $(tools_cltest_OBJECTS) $(tools_cltest_DEPENDENCIES) $(EXTRA_tools_cltest_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/cltest$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_cltest_OBJECTS) $(tools_cltest_LDADD) $(LIBS) tools/gap-tester.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) src/shared/hciemu.$(OBJEXT): src/shared/$(am__dirstamp) \ @@ -2849,6 +2921,11 @@ tools/obex-server-tool.$(OBJEXT): tools/$(am__dirstamp) \ tools/obex-server-tool$(EXEEXT): $(tools_obex_server_tool_OBJECTS) $(tools_obex_server_tool_DEPENDENCIES) $(EXTRA_tools_obex_server_tool_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/obex-server-tool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_obex_server_tool_OBJECTS) $(tools_obex_server_tool_LDADD) $(LIBS) +tools/obexctl.$(OBJEXT): tools/$(am__dirstamp) \ + tools/$(DEPDIR)/$(am__dirstamp) +tools/obexctl$(EXEEXT): $(tools_obexctl_OBJECTS) $(tools_obexctl_DEPENDENCIES) $(EXTRA_tools_obexctl_DEPENDENCIES) tools/$(am__dirstamp) + @rm -f tools/obexctl$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(tools_obexctl_OBJECTS) $(tools_obexctl_LDADD) $(LIBS) tools/rctest.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/rctest$(EXEEXT): $(tools_rctest_OBJECTS) $(tools_rctest_DEPENDENCIES) $(EXTRA_tools_rctest_DEPENDENCIES) tools/$(am__dirstamp) @@ -2995,6 +3072,7 @@ uninstall-testSCRIPTS: mostlyclean-compile: -rm -f *.$(OBJEXT) + -rm -f android/main.$(OBJEXT) -rm -f attrib/att.$(OBJEXT) -rm -f attrib/bluetoothd-att.$(OBJEXT) -rm -f attrib/bluetoothd-gatt-service.$(OBJEXT) @@ -3011,6 +3089,7 @@ mostlyclean-compile: -rm -f client/agent.$(OBJEXT) -rm -f client/display.$(OBJEXT) -rm -f client/main.$(OBJEXT) + -rm -f emulator/amp.$(OBJEXT) -rm -f emulator/b1ee.$(OBJEXT) -rm -f emulator/btdev.$(OBJEXT) -rm -f emulator/bthost.$(OBJEXT) @@ -3192,6 +3271,7 @@ mostlyclean-compile: -rm -f src/shared/tester.$(OBJEXT) -rm -f src/shared/util.$(OBJEXT) -rm -f src/textfile.$(OBJEXT) + -rm -f tools/amptest.$(OBJEXT) -rm -f tools/avinfo.$(OBJEXT) -rm -f tools/avtest.$(OBJEXT) -rm -f tools/bccmd.$(OBJEXT) @@ -3203,6 +3283,7 @@ mostlyclean-compile: -rm -f tools/btmgmt.$(OBJEXT) -rm -f tools/btsnoop.$(OBJEXT) -rm -f tools/ciptool.$(OBJEXT) + -rm -f tools/cltest.$(OBJEXT) -rm -f tools/csr.$(OBJEXT) -rm -f tools/csr_3wire.$(OBJEXT) -rm -f tools/csr_bcsp.$(OBJEXT) @@ -3231,6 +3312,7 @@ mostlyclean-compile: -rm -f tools/mpris-player.$(OBJEXT) -rm -f tools/obex-client-tool.$(OBJEXT) -rm -f tools/obex-server-tool.$(OBJEXT) + -rm -f tools/obexctl.$(OBJEXT) -rm -f tools/parser/amp.$(OBJEXT) -rm -f tools/parser/att.$(OBJEXT) -rm -f tools/parser/avctp.$(OBJEXT) @@ -3279,6 +3361,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/att.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-att.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt-service.Po@am__quote@ @@ -3295,6 +3378,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/agent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/display.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/amp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/b1ee.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/btdev.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/bthost.Po@am__quote@ @@ -3466,6 +3550,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/pcap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/tester.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/util.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/amptest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avtest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bccmd.Po@am__quote@ @@ -3477,6 +3562,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btmgmt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btsnoop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ciptool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/cltest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_3wire.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_bcsp.Po@am__quote@ @@ -3505,6 +3591,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mpris-player.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obex-client-tool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obex-server-tool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obexctl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rctest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rfcomm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sco-tester.Po@am__quote@ @@ -5266,6 +5353,7 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs + -rm -rf android/.libs android/_libs -rm -rf attrib/.libs attrib/_libs -rm -rf client/.libs client/_libs -rm -rf emulator/.libs emulator/_libs @@ -5938,6 +6026,8 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f android/$(DEPDIR)/$(am__dirstamp) + -rm -f android/$(am__dirstamp) -rm -f attrib/$(DEPDIR)/$(am__dirstamp) -rm -f attrib/$(am__dirstamp) -rm -f btio/$(DEPDIR)/$(am__dirstamp) @@ -6021,7 +6111,7 @@ clean-am: clean-binPROGRAMS clean-cupsPROGRAMS clean-generic \ distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR) + -rm -rf android/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags @@ -6076,7 +6166,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR) + -rm -rf android/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/Makefile.tools b/Makefile.tools index 87bb62e8..840b95cb 100644 --- a/Makefile.tools +++ b/Makefile.tools @@ -218,7 +218,7 @@ endif if READLINE noinst_PROGRAMS += attrib/gatttool \ tools/obex-client-tool tools/obex-server-tool \ - tools/bluetooth-player + tools/bluetooth-player tools/obexctl attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \ attrib/gattrib.c btio/btio.c \ @@ -240,6 +240,11 @@ tools_bluetooth_player_SOURCES = tools/bluetooth-player.c \ client/display.h client/display.c tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \ @GLIB_LIBS@ @DBUS_LIBS@ -lreadline + +tools_obexctl_SOURCES = tools/obexctl.c \ + client/display.h client/display.c +tools_obexctl_LDADD = gdbus/libgdbus-internal.la \ + @GLIB_LIBS@ @DBUS_LIBS@ -lreadline endif if EXPERIMENTAL diff --git a/android/Android.mk b/android/Android.mk index ec820aca..0e025acd 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -29,3 +29,23 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_MODULE := bluetoothd include $(BUILD_EXECUTABLE) + +# +# bluetooth.default.so HAL +# + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + hal_bluetooth.c \ + hal_bt_sock.c \ + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + +LOCAL_MODULE := bluetooth.default +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := SHARED_LIBRARIES + +include $(BUILD_SHARED_LIBRARY) diff --git a/android/hal-ipc-api.txt b/android/hal-ipc-api.txt new file mode 100644 index 00000000..9a8b770f --- /dev/null +++ b/android/hal-ipc-api.txt @@ -0,0 +1,1247 @@ +Android HAL protocol for Bluetooth +================================== + +The Android HAL daemon for Bluetooth functionality implements the Unix socket +server protocol around /run/bluetooth/daemon (tentative location) or Linux +abstract sockets (tentative name). + +The daemon is single threaded and uses a mainloop for scheduling and general +operation. + +The protocol is SOCK_SEQPACKET based and follows a strict PDU specification +with a generic header and initial registration exchange. The communication +is driven from the HAL with command/response exchanges. The daemon will use +notification to signal events. The protocol is single PDU exchanged based, +meaning every command requires a response. Notification does not require +any confirmation. Not handling this PDU exchange leads to a disconnection of +the socket. + +Command/response and notification use separate sockets. First connected socket +is used for command/response, second for notification. All services are +multi-plexed over same pair of sockets. Separation is done to ease +implementation of simple HAL library with dedicated thread for handling +notification. + +This strict protocol requirement is done to match C based callbacks and +callout functions that are running in a thread inside the HAL and might +block. + + .--Android--. .--Android--. + | daemon | | HAL | + | | Command | | + | | <-------------------------- | | + | | | | + | | --------------------------> | | + | | Response | | + | | | | + | | | | + | | Notification | | + | | --------------------------> | | + | | | | + '-----------' '-----------' + +Every packet will follow the basic header to support simple multi-plexing +over the same socket. It will also support a basic control channel with service +id 0. + + 0 8 16 24 31 + +--------------+--------------+--------------+--------------+ + | Service ID | Opcode | Data Length | + +--------------+--------------+-----------------------------+ + | | + +The unique service ID is assigned by this specification for each HAL. + +As general rule of thumb, the opcode for command matches the opcode for a +response. Or the opcode 0x00 for an error is returned. + +Notification opcodes start from 0x80. + +All command/response opcodes have the least significant bit not set. And all +notifications have the least significant bit set. + +The HAL modules only have the job to map the callback and event functions +to the protocol. They do not need to do anything else. Below is an example +of a sample transaction for the Bluetooth Core HAL and enabling of an +adapter. + + HAL Daemon + ---------------------------------------------------- + + call enable() --> command 0x01 + return enable() <-- response 0x01 + + call adapter_state_changed() <-- notification 0x81 + return adapter_state_changed() + +When the Android hardware framework calls into the Bluetooth Core HAL +and executes the enable() callback, the HAL module sends the enable +command with opcode 0x01 to the daemon. As soon as the daemon responds, +the callback will return with the appropriate result. + +After the daemon switched on the adapter, it will send a notification +with opcode 0x81 to the HAL module. + +The Bluetooth Core HAL and Bluetooth Socket HAL are guaranteed to be +available from the daemon. All other HAL modules are optional. + +When the Bluetooth Core HAL init() function is called, it should open +the socket and register both "bluetooth" and "socket" service modules. It is +required to register "socket" service at the same time since the HAL module +does not have its own init() function. + +When new profiles are initiated, the get_profile_interface() callback +will load the profile and during init() of the profile, it should register the +specific service. + + Bluetooth main thread Daemon + ------------------------------------------------------- + + init() --> open command socket + --> open notification socket + --> register module "bluetooth" + --> register module "socket" + + get_profile_interface() --> return profile struct + --> continue on Handsfree thread + + + Handsfree thread Daemon + -------------------------------------------------------- + + init() --> register module handsfree + + +Core Service (ID 0) +=================== + + Opcode 0x00 - Error response + + Response parameters: Error (1 octet) + + Opcode 0x01 - Register module command/response + + Command parameters: Service id (1 octet) + Response parameters: + + In case a command is sent for an undeclared service ID, it will + be rejected. Also there will be no notifications for undeclared + service ID. + + In case of an error, the error response will be returned. + + Opcode 0x02 - Unregister module command/response + + Command parameters: Service id (1 octet) + Response parameters: + + In case of an error, the error response will be returned. + + +Bluetooth Core HAL (ID 1) +========================= + +Android HAL name: "bluetooth" (BT_HARDWARE_MODULE_ID) + +Commands and responses: + + Opcode 0x00 - Error response + + Response parameters: Status (1 octet) + + Opcode 0x01 - Enable command/response + + Command parameters: + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x02 - Disable command/response + + Command parameters: + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x03 - Get Adapter Properties command/response + + Command parameters: + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x04 - Get Adapter Property command/response + + Command parameters: Property type (1 octet) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x05 - Set Adapter Property command/response + + Command parameters: Property type (1 octet) + Property length (2 octets) + Property value (variable) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x06 - Get Remote Device Properties command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x07 - Get Remote Device Property command/response + + Command parameters: Remote address (6 octets) + Property type (1 octet) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x08 - Set Remote Device Property command/response + + Command parameters: Remote address (6 octets) + Property type (1 octet) + Property length (2 octets) + Property value (variable) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x09 - Get Remote Service Record command/response + + Command parameters: Remote address (6 octets) + UUID (16 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0a - Get Remote Services command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0b - Start Discovery command/response + + Command parameters: + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0c - Cancel Discovery command/response + + Command parameters: + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0d - Create Bond command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0e - Remove Bond command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0f - Cancel Bond command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x10 - PIN Reply command/response + + Command parameters: Remote address (6 octets) + Accept (1 octet) + PIN length (1 octet) + PIN code (16 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x11 - SSP Reply command/response + + Command parameters: Remote address (6 octets) + SSP variant (1 octet) + Accept (1 octet) + Passkey (4 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x12 - DUT Mode Configure command/response + + Command parameters: Enable (1 octet) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x13 - DUT Mode Send command/response + + Command parameters: Opcode (2 octets) + Length (1 octet) + Data (variable) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x14 - LE Test Mode command/response + + Command parameters: Opcode (2 octets) + Length (1 octet) + Data (variable) + Response parameters: + + In case of an error, the error response will be returned. + +Notifications: + + Opcode 0x81 - Adapter State Changed notification + + Notifications parameters: State (1 octect) + + Opcode 0x82 - Adapter Properties Changed notification + + Notification parameters: Status (1 octect) + Num properties (1 octet) + Type[i] (1 octect) + Length[i] (2 octets) + Value[i] (variable) + + Opcode 0x83 - Remote Device Properties notification + + Notification parameters: Status (1 octect) + Remote address (6 octets) + Num properties (1 octet) + Type[i] (1 octect) + Length[i] (2 octets) + Value[i] (variable) + + Opcode 0x84 - Device Found notification + + Notification parameters: Num properties (1 octet) + Type[i] (1 octect) + Length[i] (2 octets) + Value[i] (variable) + + Opcode 0x85 - Discovery State Changed notification + + Notifications parameters: State (1 octect) + + Opcode 0x86 - PIN Request notification + + Notification parameters: Remote address (6 octets) + Remote name (249 octets) + Class of device (3 octets) + + Opcode 0x87 - SSP Request notification + + Notification parameters: Remote address (6 octets) + Remote name (249 octets) + Class of device (3 octets) + Pairing variant (1 octet) + Passkey (4 octets) + + Opcode 0x88 - Bond State Changed notification + + Notification parameters: Status (1 octect) + Remote address (6 octets) + Bond state (1 octet) + + Opcode 0x89 - ACL State Changed notification + + Notification parameters: Status (1 octect) + Remote address (6 octets) + ACL state (1 octet) + + Opcode 0x8a - DUT Mode Receive notification + + Notification parameters: Opcode (2 octects) + Length (1 octet) + Data (variable) + + Opcode 0x8b - LE Test Mode notification + + Notification parameters: Status (1 octect) + Num packets (2 octets) + + +Bluetooth Socket HAL (ID 2) +=========================== + +Android HAL name:: "socket" (BT_PROFILE_SOCKETS_ID) + +Commands and responses: + + Opcode 0x00 - Error response + + Response parameters: Status (1 octet) + + Valid status values: 0x01 = Fail + 0x02 = Not ready + 0x03 = No memory + 0x04 = Busy + 0x05 = Done (already completed) + 0x06 = Unsupported + 0x07 = Parameter invalid + 0x08 = Unhandled + 0x09 = Authentication failure + 0x0a = Remote device down + + Opcode 0x01 - Listen command/response + + Command parameters: Socket type (1 octet) + Service name (256 octets) + Service UUID (16 octets) + Channel (2 octets) + Socket flags (1 octet) + Response parameters: File descriptor (inline) + + Valid socket types: 0x01 = RFCOMM + 0x02 = SCO + 0x03 = L2CAP + + Valid socket flags: 0x01 = Encrypt + 0x02 = Auth + + In case of an error, the error response will be returned. + + Opcode 0x02 - Connect command/response + + Command parameters: Remote address (6 octets) + Socket type (1 octet) + Service UUID (16 octets) + Channel (2 octets) + Socket flags (1 octet) + Response parameters: File descriptor (inline) + + Valid socket types: 0x01 = RFCOMM + 0x02 = SCO + 0x03 = L2CAP + + Valid socket flags: 0x01 = Encrypt + 0x02 = Auth + + In case of an error, the error response will be returned. + + +Bluetooth HID Host HAL (ID 3) +============================ + +Android HAL name: "hidhost" (BT_PROFILE_HIDHOST_ID) + +Commands and responses: + + Opcode 0x00 - Error response + + Response parameters: Status (1 octet) + + Valid status values: 0x01 = Fail + 0x02 = Not ready + 0x03 = No memory + 0x04 = Busy + 0x05 = Done (already completed) + 0x06 = Unsupported + 0x07 = Parameter invalid + 0x08 = Unhandled + 0x09 = Authentication failure + 0x0a = Remote device down + + Opcode 0x01 - Connect command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x02 - Disconnect command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x03 - Virtual Unplug command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x04 - Set Info command/response + + Command parameters: Remote address (6 octets) + Attribute mask (2 octets) + Subclass (1 octet) + Application ID (1 octet) + Vendor ID (2 octets) + Product ID (2 octets) + Version (2 octets) + Country code (1 octet) + Descriptor length (2 octet) + Descriptor value (884 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x05 - Get Protocol command/response + + Command parameters: Remote address (6 octets) + Protocol mode (1 octet) + Response parameters: + + Valid protocol modes: 0x00 = Report + 0x01 = Boot + 0xff = Unsupported + + In case of an error, the error response will be returned. + + Opcode 0x06 - Set Protocol command/response + + Command parameters: Remote address (6 octets) + Protocol mode (1 octet) + Response parameters: + + Valid protocol modes: 0x00 = Report + 0x01 = Boot + 0xff = Unsupported + + In case of an error, the error response will be returned. + + Opcode 0x07 - Get Report command/response + + Command parameters: Remote address (6 octets) + Report type (1 octet) + Report ID (1 octet) + Buffer size (2 octet) + Response parameters: + + Valid report types: 0x01 = Input + 0x02 = Output + 0x03 = Feature + + In case of an error, the error response will be returned. + + Opcode 0x08 - Set Report command/response + + Command parameters: Remote address (6 octets) + Report type (1 octet) + ... + Response parameters: + + Valid report types: 0x01 = Input + 0x02 = Output + 0x03 = Feature + + In case of an error, the error response will be returned. + + Opcode 0x09 - Send Data command/response + + Command parameters: Remote address (6 octets) + ... + Response parameters: + + In case of an error, the error response will be returned. + +Notifications: + + Opcode 0x81 - Connection State notification + + Notification parameters: Remote address (6 octets) + + Valid connection states: 0x00 = Connected + 0x01 = Connecting + 0x02 = Disconnected + 0x03 = Disconnecting + 0x04 = Failed - Mouse from host + 0x05 = Failed - Keyboard from host + 0x06 = Failed - Too many devices + 0x07 = Failed - No HID driver + 0x08 = Failed - generic + 0x09 = Unknown + + Opcode 0x82 - HID Info notification + + Notification parameters: Remote address (6 octets) + Attribute mask (2 octets) + Subclass (1 octet) + Application ID (1 octet) + Vendor ID (2 octets) + Product ID (2 octets) + Version (2 octets) + Country code (1 octet) + Descriptor length (2 octet) + Descriptor value (884 octets) + + Opcode 0x83 - Protocol Mode notification + + Notification parameters: Remote address (6 octets) + Status (1 octet) + Protocol mode (1 octet) + + Valid protocol modes: 0x00 = Report + 0x01 = Boot + 0xff = Unsupported + + Opcode 0x84 - Idle Time notification + + Notification parameters: Remote address (6 octets) + Status (1 octet) + Idle time (2 octets) + + Opcode 0x85 - Get Report notification + + Notification parameters: Remote address (6 octets) + Status (1 octet) + Report length (2 octets) + Report data (variable) + + Opcode 0x86 - Virtual Unplug notification + + Notification parameters: Remote address (6 octets) + Status (1 octet) + + Valid status values: 0x00 = Ok + 0x01 = Handshake - Device not ready + 0x02 = Handshake - Invalid report ID + 0x03 = Handshake - Transaction not SPT + 0x04 = Handshake - Invalid parameter + 0x05 = Handshake - Generic error + 0x06 = General error + 0x07 = SDP error + 0x08 = Set protocol error + 0x09 = Device database full + 0x0a = Device type not supported + 0x0b = No resources + 0x0c = Authentication failed + 0x0d = HDL + + +Bluetooth PAN HAL (ID 4) +======================== + +Android HAL name: "pan" (BT_PROFILE_PAN_ID) + +Commands and responses: + + Opcode 0x00 - Error response + + Response parameters: Status (1 octet) + + Valid status values: 0x01 = Fail + 0x02 = Not ready + 0x03 = No memory + 0x04 = Busy + 0x05 = Done (already completed) + 0x06 = Unsupported + 0x07 = Parameter invalid + 0x08 = Unhandled + 0x09 = Authentication failure + 0x0a = Remote device down + + Opcode 0x01 - Enable command/response + + Command parameters: Local role (1 octet) + Response parameters: + + Valid role values: 0x00 = None + 0x01 = NAP + 0x02 = PANU + + In case of an error, the error response will be returned. + + Opcode 0x02 - Get Local Role command/response + + Command parameters: + Response parameters: Local role (1 octet) + + Valid role values: 0x00 = None + 0x01 = NAP + 0x02 = PANU + + In case of an error, the error response will be returned. + + Opcode 0x03 - Connect command/response + + Command parameters: Remote address (6 octets) + Local role (1 octet) + Remote role (1 octet) + Response parameters: + + Valid role values: 0x01 = NAP + 0x02 = PANU + + In case of an error, the error response will be returned. + + Opcode 0x04 - Disconnect command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + +Notifications: + + Opcode 0x81 - Control State notification + + Notification parameters: Control state (1 octect) + Status (1 octet) + Local role (1 octet) + Interface name (17 octet) + + Valid control states: 0x00 = Enabled + 0x01 = Disabled + + Valid role values: 0x00 = None + 0x01 = NAP + 0x02 = PANU + + Opcode 0x82 - Connection State notification + + Notification parameters: Connection state (1 octect) + Status (1 octet) + Remote address (6 octets) + Local role (1 octet) + Remote role (1 octet) + + Valid connection states: 0x00 = Connected + 0x01 = Connecting + 0x02 = Disconnected + 0x03 = Disconnecting + + Valid role values: 0x01 = NAP + 0x02 = PANU + + +Bluetooth Handsfree HAL (ID 5) +============================== + +Android HAL name: "handsfree" (BT_PROFILE_HANDSFREE_ID) + + Opcode 0x00 - Error response + + Response parameters: Status (1 octet) + + Valid status values: 0x01 = Fail + 0x02 = Not ready + 0x03 = No memory + 0x04 = Busy + 0x05 = Done (already completed) + 0x06 = Unsupported + 0x07 = Parameter invalid + 0x08 = Unhandled + 0x09 = Authentication failure + 0x0a = Remote device down + + Opcode 0x01 - Connect command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x02 - Disconnect command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x03 - Connect Audio command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x04 - Disconnect Audio command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x05 - Start Voice Recognition command/response + + Command parameters: + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x06 - Stop Voice Recognition command/response + + Command parameters: + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x07 - Volume Control command/response + + Command parameters: Volume type (1 octet) + Volume (1 octet) + Response parameters: + + Valid volume types: 0x00 = Speaker + 0x01 = Microphone + + In case of an error, the error response will be returned. + + Opcode 0x08 - Device Status Notification command/response + + Command parameters: Network state (1 octet) + Service type (1 octet) + Signal strength (1 octet) + Battery level (1 octet) + Response parameters: + + Valid network states: 0x00 = Not available + 0x01 = Available + + Valid service types: 0x00 = Home network + 0x01 = Roaming network + + In case of an error, the error response will be returned. + + Opcode 0x09 - COPS Response command/response + + Command parameters: COPS command response (string) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0a - CIND Response command/response + + Command parameters: Service (1 octet) + Number of active calls (1 octet) + Number of held calls (1 octet) + Call setup state (1 octet) + Signal strength (1 octet) + Roaming indicator (1 octet) + Battery level (1 octet) + Response parameters: + + Valid call setup states: 0x00 = Active + 0x01 = Held + 0x02 = Dialing + 0x03 = Alerting + 0x04 = Incoming + 0x05 = Waiting + 0x06 = Idle + + In case of an error, the error response will be returned. + + Opcode 0x0b - Formatted AT Response command/response + + Command parameters: Pre-formatted AT response (string) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x0c - AT Response command/response + + Command parameters: Response code (1 octet) + Error code (1 octet) + Response parameters: + + Valid response codes: 0x00 = ERROR + 0x01 = OK + + In case of an error, the error response will be returned. + + Opcode 0x0d - CLCC Response command/response + + Command parameters: Call index (1 octet) + Call direction (1 octet) + Call state (1 octet) + Call mode (1 octet) + Call multiparty type (1 octet) + Call number type (1 octet) + Call number (variable) + Response parameters: + + Valid call directions: 0x00 = Outgoing + 0x01 = Incoming + + Valid call states: 0x00 = Active + 0x01 = Held + 0x02 = Dialing + 0x03 = Alerting + 0x04 = Incoming + 0x05 = Waiting + 0x06 = Idle + + Valid call modes: 0x00 = Voice + 0x01 = Data + 0x02 = Fax + + Valid multiparty types: 0x00 = Single call + 0x01 = Multiparty call + + Valid number types: 0x81 = Unknown + 0x91 = International + + In case of an error, the error response will be returned. + + Opcode 0x0e - Phone Status Change command/response + + Command parameters: Number of active calls (1 octet) + Number of held calls (1 octet) + Call setup state (1 octet) + Call number type (1 octet) + Call number (variable) + Response parameters: + + Valid call setup states: 0x00 = Active + 0x01 = Held + 0x02 = Dialing + 0x03 = Alerting + 0x04 = Incoming + 0x05 = Waiting + 0x06 = Idle + + Valid number types: 0x81 = Unknown + 0x91 = International + + In case of an error, the error response will be returned. + +Notifications: + + Opcode 0x81 - Connection State notification + + Notification parameters: Connection state (1 octect) + Remote address (6 octets) + + Valid connection states: 0x00 = Disconnected + 0x01 = Connecting + 0x02 = Connected + 0x03 = SLC connected + 0x04 = Disconnecting + + Opcode 0x82 - Audio State notification + + Notification parameters: Audio state (1 octect) + Remote address (6 octets) + + Valid audio states: 0x00 = Disconnected + 0x01 = Connecting + 0x02 = Connected + 0x03 = Disconnecting + + Opcode 0x83 - Voice Recognition Command notification + + Notification parameters: Voice recognition state (1 octet) + + Valid voice recognition states: 0x00 = Stopped + 0x01 = Started + + Opcode 0x84 - Answer Call Command notification + + Notification parameters: + + Opcode 0x85 - Hangup Call Command notification + + Notification parameters: + + Opcode 0x86 - Volume Command notification + + Notification parameters: Volume type (1 octet) + + Valid volume types: 0x00 = Speaker + 0x01 = Microphone + + Opcode 0x87 - Dial Call Command notification + + Notification parameters: Number (string) + + Opcode 0x88 - DTMF Command notification + + Notification parameters: Tone (1 octet) + + Opcode 0x89 - NREC Command notification + + Notification parameters: NREC types (1 octet) + + Valid NREC types: 0x00 = Stop + 0x01 = Start + + Opcode 0x8a - CHLD Command notification + + Notification parameters: NREC types (1 octet) + + Valid CHLD types: 0x00 = Release and hold + 0x01 = Release active and accept held + 0x02 = Hold active and accept held + 0x03 = Add held call to conference + + Opcode 0x8b - CNUM Command notification + + Notification parameters: + + Opcode 0x8c - CIND Command notification + + Notification parameters: + + Opcode 0x8d - COPS Command notification + + Notification parameters: + + Opcode 0x8e - CLCC Command notification + + Notification parameters: + + Opcode 0x8f - Unknown AT Command notification + + Notification parameters: AT command (string) + + Opcode 0x90 - Key Pressed Command notification + + Notification parameters: + + +Bluetooth Advanced Audio HAL (ID 6) +=================================== + +Android HAL name: "ad2p" (BT_PROFILE_ADVANCED_AUDIO_ID) + +Commands and responses: + + Opcode 0x00 - Error response + + Response parameters: Status (1 octet) + + Valid status values: 0x01 = Fail + 0x02 = Not ready + 0x03 = No memory + 0x04 = Busy + 0x05 = Done (already completed) + 0x06 = Unsupported + 0x07 = Parameter invalid + 0x08 = Unhandled + 0x09 = Authentication failure + 0x0a = Remote device down + + Opcode 0x01 - Connect command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x02 - Disconnect command/response + + Command parameters: Remote address (6 octets) + Response parameters: + + In case of an error, the error response will be returned. + +Notifications: + + Opcode 0x81 - Connection State notification + + Notification parameters: Connection state (1 octect) + Remote address (6 octets) + + Valid connection states: 0x00 = Disconnected + 0x01 = Connecting + 0x02 = Connected + 0x03 = Disconnecting + + Opcode 0x82 - Audio State notification + + Notification parameters: Audio state (1 octect) + Remote address (6 octets) + + Valid connection states: 0x00 = Remote suspend + 0x01 = Stopped + 0x02 = Started + + +Bluetooth Health HAL (ID 7) +=========================== + +Android HAL name: "health" (BT_PROFILE_HEALTH_ID) + + Opcode 0x00 - Error response + + Response parameters: Status (1 octet) + + Valid status values: 0x01 = Fail + 0x02 = Not ready + 0x03 = No memory + 0x04 = Busy + 0x05 = Done (already completed) + 0x06 = Unsupported + 0x07 = Parameter invalid + 0x08 = Unhandled + 0x09 = Authentication failure + 0x0a = Remote device down + + Opcode 0x01 - Register Application command/response + + Command parameters: Application name (string) + Provider name (string) + Service name (string) + Service description (string) + Number of MDEP (1 octet) + MDEP Role[i] (1 octet) + Data type[i] (1 octet) + Channel type[i] (1 octet) + MDEP description (string) + Response parameters: Application ID (2 octets) + + In case of an error, the error response will be returned. + + Opcode 0x02 - Unregister Application command/response + + Command parameters: Application ID (2 octets) + Response parameters: + + In case of an error, the error response will be returned. + + Opcode 0x03 - Connect Channel command/response + + Command parameters: Application ID (2 octets) + Remote address (6 octets) + MDEP index (1 octet) + Response parameters: Channel ID (2 octets) + + In case of an error, the error response will be returned. + + Opcode 0x04 - Destroy Channel command/response + + Command parameters: Channel ID (2 octets) + Response parameters: + + In case of an error, the error response will be returned. + +Notifications: + + Opcode 0x81 - Application Registration State notification + + Notification parameters: Application ID (2 octects) + Application state (1 octet) + + Valid application states: 0x00 = Registration success + 0x01 = Registration failed + 0x02 = Deregistration success + 0x03 = Deregistration failed + + Opcode 0x82 - Channel State notification + + Notification parameters: Application ID (2 octects) + Remote address (6 octets) + MDEP index (1 octet) + Channel ID (2 octets) + Channel state (1 octet) + File descriptor (inline) + + Valid channel states: 0x00 = Connecting + 0x01 = Connected + 0x02 = Disconnecting + 0x03 = Disconnected + 0x04 = Destroyed + + +Bluetooth Remote Control HAL (ID 8) +=================================== + +Android HAL name: "avrcp" (BT_PROFILE_AV_RC_ID) + + Opcode 0x00 - Error response + Opcode 0x01 - Get Play Status command/response + Opcode 0x02 - List Player Application Attributes command/response + Opcode 0x03 - List Player Application Values command/response + Opcode 0x04 - Get Player Application Values command/response + Opcode 0x05 - Get Player Application Attributes Text command/response + Opcode 0x06 - Get Player Application Values Text command/response + Opcode 0x07 - Get Element Attributes Text command/response + Opcode 0x08 - Set Player Attributes Value command/response + Opcode 0x09 - Register Notification command/response + + Opcode 0x81 - Get Play Status notification + Opcode 0x82 - List Player Application Attributes notification + ... + + +Bluetooth GATT HAL (ID 9) +========================= + +Android HAL name: "gatt" (BT_PROFILE_GATT_ID) + + Opcode 0x00 - Error response + Opcode 0x01 - Register Client command/response + Opcode 0x02 - Unregister Client command/response + Opcode 0x03 - Scan command/response + Opcode 0x04 - Connect Device command/response + Opcode 0x05 - Disconnect Device command/response + Opcode 0x06 - Refresh command/response + Opcode 0x07 - Search Service command/response + Opcode 0x08 - Get Included Service command/response + Opcode 0x09 - Get Characteristic command/response + Opcode 0x0a - Get Descriptor command/response + Opcode 0x0b - Read Characteristic command/response + Opcode 0x0c - Write Characteristic command/response + Opcode 0x0d - Read Descriptor command/response + Opcode 0x0e - Write Descriptor command/response + Opcode 0x0f - Execute Write command/response + Opcode 0x10 - Register For Notification command/response + Opcode 0x11 - Deregister For Notification command/response + Opcode 0x12 - Read Remote RSSI command/response + Opcode 0x13 - Get Device Type command/response + Opcode 0x14 - Test Command command/response + Opcode 0x15 - Register Server command/response + Opcode 0x16 - Unregister Server command/response + Opcode 0x17 - Connect Peripheral command/response + Opcode 0x18 - Disconnect Peripheral command/response + Opcode 0x19 - Add Service command/response + Opcode 0x1a - Add Included Service command/response + Opcode 0x1b - Add Characteristic command/response + Opcode 0x1c - Add Descriptor command/response + Opcode 0x1d - Start Service command/response + Opcode 0x1e - Stop Service command/response + Opcode 0x1f - Delete Service command/response + Opcode 0x20 - Send Indication command/response + Opcode 0x21 - Send Response command/response + + Opcode 0x81 - Register Client notification + Opcode 0x82 - Scan Result notification + Opcode 0x83 - Connect Device notification + Opcode 0x84 - Disconnect Device notification + Opcode 0x85 - Search Complete notification + Opcode 0x86 - Search Result notification + Opcode 0x87 - Get Characteristic notification + Opcode 0x88 - Get Descriptor notification + Opcode 0x89 - Get Included Service notification + Opcode 0x8a - Register For Notification notification + Opcode 0x8b - Notify notification + Opcode 0x8c - Read Characteristic notification + Opcode 0x8d - Write Characteristic notification + Opcode 0x8e - Execute Write notification + Opcode 0x8f - Read Descriptor notification + Opcode 0x90 - Write Descriptor notification + Opcode 0x91 - Read Remote RSSI notification + Opcode 0x92 - Register Server notification + Opcode 0x93 - Connection notification + Opcode 0x94 - Service Added notification + Opcode 0x95 - Included Service Added notification + Opcode 0x96 - Characteristic Added notification + Opcode 0x97 - Descriptor Added notification + Opcode 0x98 - Service Started notification + Opcode 0x99 - Service Stopped notification + Opcode 0x9a - Service Deleted notification + Opcode 0x9b - Request Read notification + Opcode 0x9c - Request Write notification + Opcode 0x9d - Request Execute Write notification + Opcode 0x9e - Response Confirmation notification diff --git a/bluez.pc.in b/bluez.pc.in deleted file mode 100644 index 3d6e5961..00000000 --- a/bluez.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: BlueZ -Description: Bluetooth protocol stack for Linux -Version: @VERSION@ -Libs: -L${libdir} -lbluetooth -Cflags: -I${includedir} diff --git a/configure b/configure index 26a2e354..2bb5b0f5 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for bluez 5.9. +# Generated by GNU Autoconf 2.69 for bluez 5.10. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -587,8 +587,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='bluez' PACKAGE_TARNAME='bluez' -PACKAGE_VERSION='5.9' -PACKAGE_STRING='bluez 5.9' +PACKAGE_VERSION='5.10' +PACKAGE_STRING='bluez 5.10' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -633,6 +633,8 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +ANDROID_FALSE +ANDROID_TRUE CONFIGDIR EXPERIMENTAL_FALSE EXPERIMENTAL_TRUE @@ -831,6 +833,7 @@ with_systemdsystemunitdir with_systemduserunitdir enable_datafiles enable_experimental +enable_android ' ac_precious_vars='build_alias host_alias @@ -1394,7 +1397,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures bluez 5.9 to adapt to many kinds of systems. +\`configure' configures bluez 5.10 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1464,7 +1467,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of bluez 5.9:";; + short | recursive ) echo "Configuration of bluez 5.10:";; esac cat <<\_ACEOF @@ -1498,6 +1501,7 @@ Optional Features: --disable-systemd disable systemd integration --disable-datafiles do not install configuration and data files --enable-experimental enable experimental plugins (SAP, NFC, ...) + --enable-android enable BlueZ for Android Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1611,7 +1615,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -bluez configure 5.9 +bluez configure 5.10 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1976,7 +1980,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by bluez $as_me 5.9, which was +It was created by bluez $as_me 5.10, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2831,7 +2835,7 @@ fi # Define the identity of the package. PACKAGE='bluez' - VERSION='5.9' + VERSION='5.10' cat >>confdefs.h <<_ACEOF @@ -13589,6 +13593,20 @@ _ACEOF CONFIGDIR="${configdir}" +# Check whether --enable-android was given. +if test "${enable_android+set}" = set; then : + enableval=$enable_android; enable_android=${enableval} +fi + + if test "${enable_android}" = "yes"; then + ANDROID_TRUE= + ANDROID_FALSE='#' +else + ANDROID_TRUE='#' + ANDROID_FALSE= +fi + + ac_config_files="$ac_config_files Makefile src/bluetoothd.8 lib/bluez.pc" cat >confcache <<\_ACEOF @@ -13776,6 +13794,10 @@ if test -z "${EXPERIMENTAL_TRUE}" && test -z "${EXPERIMENTAL_FALSE}"; then as_fn_error $? "conditional \"EXPERIMENTAL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${ANDROID_TRUE}" && test -z "${ANDROID_FALSE}"; then + as_fn_error $? "conditional \"ANDROID\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -14173,7 +14195,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by bluez $as_me 5.9, which was +This file was extended by bluez $as_me 5.10, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14239,7 +14261,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -bluez config.status 5.9 +bluez config.status 5.10 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 7b1f64aa..b4d3998d 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ(2.60) -AC_INIT(bluez, 5.9) +AC_INIT(bluez, 5.10) AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules tar-pax no-dist-gzip dist-xz]) diff --git a/doc/input-api.txt b/doc/input-api.txt deleted file mode 100644 index 67da08b1..00000000 --- a/doc/input-api.txt +++ /dev/null @@ -1,32 +0,0 @@ -BlueZ D-Bus Input API description -********************************* - -Input hierarchy -=============== - -Service org.bluez -Interface org.bluez.Input1 -Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX - -Properties string ReconnectMode [readonly] - - Determines the Connectability mode of the HID device as - defined by the HID Profile specification, Section 5.4.2. - - This mode is based in the two properties - HIDReconnectInitiate (see Section 5.3.4.6) and - HIDNormallyConnectable (see Section 5.3.4.14) which - define the following four possible values: - - "none" Device and host are not required to - automatically restore the connection. - - "host" Bluetooth HID host restores connection. - - "device" Bluetooth HID device restores - connection. - - "any" Bluetooth HID device shall attempt to - restore the lost connection, but - Bluetooth HID Host may also restore the - connection. diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt index c1590494..371f2529 100644 --- a/doc/mgmt-api.txt +++ b/doc/mgmt-api.txt @@ -237,11 +237,17 @@ Set Discoverable Command This command is used to set the discoverable property of a controller. The allowed Discoverable command parameter values - are 0x00 and 0x01. All other values will return Invalid Parameters. + are 0x00, 0x01 and 0x02. All other values will return Invalid + Parameters. Timeout is the time in seconds and is only meaningful when - Discoverable is set to 0x01. Providing a timeout with 0x00 will - return Invalid Parameters. + Discoverable is set to 0x01 or 0x02. Providing a timeout + with 0x00 return Invalid Parameters. For 0x02, the timeout + value is required. + + The value 0x00 disables discoverable, the value 0x01 enables + general discoverable and the value 0x02 enables limited + discoverable. This command is only available for BR/EDR capable controllers (e.g. not for single-mode LE ones). It will return Not Supported @@ -279,9 +285,13 @@ Set Connectable Command controller. The allowed Connectable command parameter values are 0x00 and 0x01. All other values will return Invalid Parameters. - This command is only available for BR/EDR capable controllers - (e.g. not for single-mode LE ones). It will return Not Supported - otherwise. + This command is available for BR/EDR, LE-only and also dual + mode controllers. For BR/EDR is changes the page scan setting + and for LE controllers it changes the advertising type. For + dual mode controllers it affects both settings. + + For LE capable controllers the connectable setting only takes + affect when advertising is enabled. This command can be used when the controller is not powered and all settings will be programmed once powered. @@ -1238,7 +1248,7 @@ Set Advertising Command Command Code: 0x0029 Controller Index: - Command Parameters Advertising (1 Octet) + Command Parameters: Advertising (1 Octet) Return Parameters: Current_Settings (4 Octets) This command is used to enable LE advertising on a controller @@ -1264,7 +1274,7 @@ Set BR/EDR Command Command Code: 0x002A Controller Index: - Command Parameters BR/EDR (1 Octet) + Command Parameters: BR/EDR (1 Octet) Return Parameters: Current_Settings (4 Octets) This command is used to enable or disable BR/EDR support @@ -1294,7 +1304,7 @@ Set Static Address Command Command Code: 0x002B Controller Index: - Command Parameters Address (6 Octets) + Command Parameters: Address (6 Octets) Return Parameters: This command allows for setting the static random address. It is @@ -1316,6 +1326,28 @@ Set Static Address Command Invalid Index +Set Scan Parameters Command +=========================== + + Command Code: 0x002C + Controller Index: + Command Parameters: Interval (2 Octets) + Window (2 Octets) + Return Parameters: + + This command allows for setting the Low Energy scan parameters + used for connection establishment and passive scanning. It is + only supported on controllers with LE support. + + This command generates a Command Complete event on success or a + Command Status event on failure. + + Possible errors: Rejected + Not Supported + Invalid Parameters + Invalid Index + + Command Complete Event ====================== diff --git a/doc/settings-storage.txt b/doc/settings-storage.txt deleted file mode 100644 index a3b58e63..00000000 --- a/doc/settings-storage.txt +++ /dev/null @@ -1,225 +0,0 @@ -BlueZ settings storage -********************** - -Purpose -======= - -The purpose of this document is to describe the directory structure of -BlueZ settings storage. In effect, this document will serve as the primary, -up to date source of BlueZ storage information. - -It is intended as reference for developers. Direct access to the storage -outside from bluetoothd is highly discouraged. - -Adapter and remote device info are read form the storage during object -initialization. Write to storage is performed immediately on every value -change. - -Default storage directory is /var/lib/bluetooth. This can be adjusted -by the --localstatedir configure switch. Default is --localstatedir=/var. - -All files are in ini-file format. - - -Storage directory structure -=========================== - -There is one directory per adapter, named by its Bluetooth address, which -contains: - - a settings file for the local adapter - - an attributes file containing attributes of supported LE services - - a cache directory containing: - - one file per device, named by remote device address, which contains - device name - - one directory per remote device, named by remote device address, which - contains: - - an info file - - an attributes file containing attributes of remote LE services - - a ccc file containing persistent Client Characteristic Configuration - (CCC) descriptor information for GATT characteristics - -So the directory structure is: - /var/lib/bluetooth// - ./settings - ./attributes - ./cache/ - ./ - ./ - ... - .// - ./info - ./attributes - ./ccc - .// - ./info - ./attributes - ... - - -Settings file format -==================== - -Settings file contains one [General] group with adapter info like: - - Alias String Friendly user provided name advertised - for this adapter - - This value overwrites the system - name (pretty hostname) - - Discoverable Boolean Discoverability of the adapter - - PairableTimeout Integer How long to stay in pairable mode - before going back to non-pairable. - The value is in seconds. - 0 = disable timer, i.e. stay - pairable forever - - DiscoverableTimeout Integer How long to stay in discoverable mode - before going back to non-discoverable. - The value is in seconds. - 0 = disable timer, i.e. stay - discoverable forever - -Sample: - [General] - Name=My PC - Discoverable=false - Pairable=true - DiscoverableTimeout=0 - - -Attributes file format -====================== - -The attributes file lists all attributes supported by the local adapter or -remote device. - -Attributes are stored using their handle as group name (decimal format). - -Each group contains: - - UUID String 128-bit UUID of the attribute - - Value String Value of the attribute as hexadecimal encoded - string - - EndGroupHandle Integer End group handle in decimal format - -Sample: - [1] - UUID=00002800-0000-1000-8000-00805f9b34fb - Value=0018 - - [4] - UUID=00002803-0000-1000-8000-00805f9b34fb - Value=020600002A - - [6] - UUID=00002a00-0000-1000-8000-00805f9b34fb - Value=4578616D706C6520446576696365 - - -CCC file format -====================== - -The ccc file stores the current CCC descriptor values for GATT characteristics -which have notification/indication enabled by the remote device. - -Information is stored using CCC attribute handle as group name (in decimal -format). - -Each group contains: - - Value String CCC descriptor value encoded in - hexadecimal - - -Cache directory file format -============================ - -Each file, named by remote device address, may includes multiple groups -(General and ServiceRecords). - -In ServiceRecords, SDP records are stored using their handle as key -(hexadecimal format). - -[General] group contains: - - Name String Remote device friendly name - - ShortName String Remote device shortened name - -[ServiceRecords] group contains - - <0x...> String SDP record as hexadecimal encoded - string - - -Info file format -================ - -Info file may includes multiple groups (General, Device ID, Link key and -Long term key) related to a remote device. - -[General] group contains: - - Name String Remote device friendly name - - Alias String Alias name - - Class String Device class in hexadecimal, - i.e. 0x000000 - - Appearance String Device appearance in hexadecimal, - i.e. 0x0000 - - SupportedTechnologies List of List of technologies supported by - strings device, separated by ";" - Technologies can be BR/EDR or LE - - AddressType String An address can be "static" or "public" - - Trusted Boolean True if the remote device is trusted - - Blocked Boolean True if the remote device is blocked - - Services List of List of service UUIDs advertised by - strings remote in 128-bits UUID format, - separated by ";" - - -[DeviceID] group contains: - - Source Integer Assigner of Device ID - - Vendor Integer Device vendor - - Product Integer Device product - - Version Integer Device version - - -[LinkKey] group contains: - - Key String Key in hexadecimal format - - Type Integer Type of link key - - PINLength Integer Length of PIN - - -[LongTermKey] group contains: - - Key String Long term key in hexadecimal format - - Authenticated Boolean True if remote device has been - authenticated - - Master Boolean True for master key - - EncSize Integer Encrypted size - - EDiv Integer Encrypted diversifier - - Rand Integer Randomizer diff --git a/emulator/btdev.c b/emulator/btdev.c index f98b5239..5f04bd17 100644 --- a/emulator/btdev.c +++ b/emulator/btdev.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "monitor/bt.h" #include "btdev.h" @@ -1072,6 +1073,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, struct bt_hci_rsp_read_auth_enable rae; struct bt_hci_rsp_read_class_of_dev rcod; struct bt_hci_rsp_read_voice_setting rvs; + struct bt_hci_rsp_read_num_supported_iac rnsi; + struct bt_hci_rsp_read_current_iac_lap *rcil; struct bt_hci_rsp_read_inquiry_mode rim; struct bt_hci_rsp_read_afh_assessment_mode raam; struct bt_hci_rsp_read_ext_inquiry_response reir; @@ -1415,6 +1418,26 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &status, sizeof(status)); break; + case BT_HCI_CMD_READ_NUM_SUPPORTED_IAC: + if (btdev->type == BTDEV_TYPE_LE) + goto unsupported; + rnsi.status = BT_HCI_ERR_SUCCESS; + rnsi.num_iac = 0x01; + cmd_complete(btdev, opcode, &rnsi, sizeof(rnsi)); + break; + + case BT_HCI_CMD_READ_CURRENT_IAC_LAP: + if (btdev->type == BTDEV_TYPE_LE) + goto unsupported; + rcil = alloca(sizeof(*rcil) + 3); + rcil->status = BT_HCI_ERR_SUCCESS; + rcil->num_iac = 0x01; + rcil->iac_lap[0] = 0x33; + rcil->iac_lap[1] = 0x8b; + rcil->iac_lap[2] = 0x9e; + cmd_complete(btdev, opcode, rcil, sizeof(*rcil) + 3); + break; + case BT_HCI_CMD_WRITE_CURRENT_IAC_LAP: if (btdev->type == BTDEV_TYPE_LE) goto unsupported; diff --git a/gdbus/client.c b/gdbus/client.c index 7bffdad1..be8cc296 100644 --- a/gdbus/client.c +++ b/gdbus/client.c @@ -112,11 +112,6 @@ static gboolean modify_match(DBusConnection *conn, const char *member, return FALSE; } - if (call == NULL) { - dbus_message_unref(msg); - return FALSE; - } - dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL); dbus_pending_call_unref(call); diff --git a/gdbus/object.c b/gdbus/object.c index 0822fe88..268fed55 100644 --- a/gdbus/object.c +++ b/gdbus/object.c @@ -1510,11 +1510,20 @@ gboolean g_dbus_send_message_with_reply(DBusConnection *connection, DBusMessage *message, DBusPendingCall **call, int timeout) { + dbus_bool_t ret; + /* Flush pending signal to guarantee message order */ g_dbus_flush(connection); - return dbus_connection_send_with_reply(connection, message, call, + ret = dbus_connection_send_with_reply(connection, message, call, timeout); + + if (ret == TRUE && call != NULL && *call == NULL) { + error("Unable to send message (passing fd blocked?)"); + return FALSE; + } + + return ret; } gboolean g_dbus_send_error_valist(DBusConnection *connection, diff --git a/monitor/bt.h b/monitor/bt.h index d82fddaf..2245ab31 100644 --- a/monitor/bt.h +++ b/monitor/bt.h @@ -741,8 +741,17 @@ struct bt_hci_rsp_read_num_supported_iac { } __attribute__ ((packed)); #define BT_HCI_CMD_READ_CURRENT_IAC_LAP 0x0c39 +struct bt_hci_rsp_read_current_iac_lap { + uint8_t status; + uint8_t num_iac; + uint8_t iac_lap[0]; +} __attribute__ ((packed)); #define BT_HCI_CMD_WRITE_CURRENT_IAC_LAP 0x0c3a +struct bt_hci_cmd_write_current_iac_lap { + uint8_t num_iac; + uint8_t iac_lap[0]; +} __attribute__ ((packed)); #define BT_HCI_CMD_READ_PAGE_SCAN_PERIOD_MODE 0x0c3b struct bt_hci_rsp_read_page_scan_period_mode { diff --git a/monitor/packet.c b/monitor/packet.c index b7f83145..55c9f0f0 100644 --- a/monitor/packet.c +++ b/monitor/packet.c @@ -3651,6 +3651,29 @@ static void read_num_supported_iac_rsp(const void *data, uint8_t size) print_field("Number of IAC: %d", rsp->num_iac); } +static void read_current_iac_lap_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_current_iac_lap *rsp = data; + uint8_t i; + + print_status(rsp->status); + print_field("Number of IAC: %d", rsp->num_iac); + + for (i = 0; i < rsp->num_iac; i++) + print_iac(rsp->iac_lap + (i * 3)); +} + +static void write_current_iac_lap_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_current_iac_lap *cmd = data; + uint8_t i; + + print_field("Number of IAC: %d", cmd->num_iac); + + for (i = 0; i < cmd->num_iac; i++) + print_iac(cmd->iac_lap + (i * 3)); +} + static void read_page_scan_period_mode_rsp(const void *data, uint8_t size) { const struct bt_hci_rsp_read_page_scan_period_mode *rsp = data; @@ -4922,8 +4945,12 @@ static const struct opcode_data opcode_table[] = { { 0x0c38, 90, "Read Number of Supported IAC", null_cmd, 0, true, read_num_supported_iac_rsp, 2, true }, - { 0x0c39, 91, "Read Current IAC LAP" }, - { 0x0c3a, 92, "Write Current IAC LAP" }, + { 0x0c39, 91, "Read Current IAC LAP", + null_cmd, 0, true, + read_current_iac_lap_rsp, 2, false }, + { 0x0c3a, 92, "Write Current IAC LAP", + write_current_iac_lap_cmd, 1, false, + status_rsp, 1, true }, { 0x0c3b, 93, "Read Page Scan Period Mode", null_cmd, 0, true, read_page_scan_period_mode_rsp, 2, true }, diff --git a/obexd/client/session.c b/obexd/client/session.c index 63692a12..7a56acdb 100644 --- a/obexd/client/session.c +++ b/obexd/client/session.c @@ -296,6 +296,16 @@ done: g_free(callback); } +static void session_disconnected(GObex *obex, GError *err, gpointer user_data) +{ + struct obc_session *session = user_data; + + if (err) + error("%s", err->message); + + obc_session_shutdown(session); +} + static void transport_func(GIOChannel *io, GError *err, gpointer user_data) { struct callback_data *callback = user_data; @@ -345,6 +355,8 @@ static void transport_func(GIOChannel *io, GError *err, gpointer user_data) session->obex = obex; sessions = g_slist_prepend(sessions, session); + g_obex_set_disconnect_function(obex, session_disconnected, session); + return; done: callback->func(callback->session, NULL, err, callback->data); diff --git a/obexd/plugins/messages-tracker.c b/obexd/plugins/messages-tracker.c deleted file mode 100644 index 60f3a807..00000000 --- a/obexd/plugins/messages-tracker.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * - * OBEX Server - * - * Copyright (C) 2010-2011 Nokia Corporation - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "messages.h" - -struct message_folder { - char *name; - GSList *subfolders; - char *query; -}; - -struct session { - char *cwd; - struct message_folder *folder; - char *name; - uint16_t max; - uint16_t offset; - void *user_data; - void (*folder_list_cb)(void *session, int err, uint16_t size, - const char *name, void *user_data); -}; - -static struct message_folder *folder_tree = NULL; - -static struct message_folder *get_folder(const char *folder) -{ - GSList *folders = folder_tree->subfolders; - struct message_folder *last = NULL; - char **path; - int i; - - if (g_strcmp0(folder, "/") == 0) - return folder_tree; - - path = g_strsplit(folder, "/", 0); - - for (i = 1; path[i] != NULL; i++) { - gboolean match_found = FALSE; - GSList *l; - - for (l = folders; l != NULL; l = g_slist_next(l)) { - struct message_folder *folder = l->data; - - if (g_strcmp0(folder->name, path[i]) == 0) { - match_found = TRUE; - last = l->data; - folders = folder->subfolders; - break; - } - } - - if (!match_found) { - g_strfreev(path); - return NULL; - } - } - - g_strfreev(path); - - return last; -} - -static struct message_folder *create_folder(const char *name, const char *query) -{ - struct message_folder *folder = g_new0(struct message_folder, 1); - - folder->name = g_strdup(name); - folder->query = g_strdup(query); - - return folder; -} - -static void destroy_folder_tree(void *root) -{ - struct message_folder *folder = root; - GSList *tmp, *next; - - if (folder == NULL) - return; - - g_free(folder->name); - g_free(folder->query); - - tmp = folder->subfolders; - while (tmp != NULL) { - next = g_slist_next(tmp); - destroy_folder_tree(tmp->data); - tmp = next; - } - - g_slist_free(folder->subfolders); - g_free(folder); -} - -static void create_folder_tree(void) -{ - struct message_folder *parent, *child; - - folder_tree = create_folder("/", "FILTER (!BOUND(?msg))"); - - parent = create_folder("telecom", "FILTER (!BOUND(?msg))"); - folder_tree->subfolders = g_slist_append(folder_tree->subfolders, - parent); - - child = create_folder("msg", "FILTER (!BOUND(?msg))"); - parent->subfolders = g_slist_append(parent->subfolders, child); - - parent = child; - - child = create_folder("inbox", "?msg nmo:isSent \"false\" ; " - "nmo:isDeleted \"false\" ; " - "nmo:isDraft \"false\". "); - parent->subfolders = g_slist_append(parent->subfolders, child); - - child = create_folder("sent", "?msg nmo:isDeleted \"false\" ; " - "nmo:isSent \"true\" . "); - parent->subfolders = g_slist_append(parent->subfolders, child); - - child = create_folder("deleted", "?msg nmo:isDeleted \"true\" . "); - parent->subfolders = g_slist_append(parent->subfolders, child); -} - -int messages_init(void) -{ - create_folder_tree(); - - return 0; -} - -void messages_exit(void) -{ - destroy_folder_tree(folder_tree); -} - -int messages_connect(void **s) -{ - struct session *session = g_new0(struct session, 1); - - session->cwd = g_strdup("/"); - session->folder = folder_tree; - - *s = session; - - return 0; -} - -void messages_disconnect(void *s) -{ - struct session *session = s; - - g_free(session->cwd); - g_free(session); -} - -int messages_set_notification_registration(void *session, - void (*send_event)(void *session, - const struct messages_event *event, void *user_data), - void *user_data) -{ - return -ENOSYS; -} - -int messages_set_folder(void *s, const char *name, gboolean cdup) -{ - struct session *session = s; - char *newrel = NULL; - char *newabs; - char *tmp; - - if (name && (strchr(name, '/') || strcmp(name, "..") == 0)) - return -EBADR; - - if (cdup) { - if (session->cwd[0] == 0) - return -ENOENT; - - newrel = g_path_get_dirname(session->cwd); - - /* We use empty string for indication of the root directory */ - if (newrel[0] == '.' && newrel[1] == 0) - newrel[0] = 0; - } - - tmp = newrel; - if (!cdup && (!name || name[0] == 0)) - newrel = g_strdup(""); - else - newrel = g_build_filename(newrel ? newrel : session->cwd, name, - NULL); - g_free(tmp); - - if (newrel[0] != '/') - newabs = g_build_filename("/", newrel, NULL); - else - newabs = g_strdup(newrel); - - session->folder = get_folder(newabs); - if (session->folder == NULL) { - g_free(newrel); - g_free(newabs); - - return -ENOENT; - } - - g_free(newrel); - g_free(session->cwd); - session->cwd = newabs; - - return 0; -} - -static gboolean async_get_folder_listing(void *s) -{ - struct session *session = s; - gboolean count = FALSE; - int folder_count = 0; - char *path = NULL; - struct message_folder *folder; - GSList *dir; - - if (session->name && strchr(session->name, '/') != NULL) - goto done; - - path = g_build_filename(session->cwd, session->name, NULL); - - if (path == NULL || strlen(path) == 0) - goto done; - - folder = get_folder(path); - - if (folder == NULL) - goto done; - - if (session->max == 0) { - session->max = 0xffff; - session->offset = 0; - count = TRUE; - } - - for (dir = folder->subfolders; dir && - (folder_count - session->offset) < session->max; - folder_count++, dir = g_slist_next(dir)) { - struct message_folder *dir_data = dir->data; - - if (count == FALSE && session->offset <= folder_count) - session->folder_list_cb(session, -EAGAIN, 0, - dir_data->name, session->user_data); - } - - done: - session->folder_list_cb(session, 0, folder_count, NULL, - session->user_data); - - g_free(path); - g_free(session->name); - - return FALSE; -} - -int messages_get_folder_listing(void *s, const char *name, - uint16_t max, uint16_t offset, - messages_folder_listing_cb callback, - void *user_data) -{ - struct session *session = s; - session->name = g_strdup(name); - session->max = max; - session->offset = offset; - session->folder_list_cb = callback; - session->user_data = user_data; - - g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing, - session, NULL); - - return 0; -} - -int messages_get_messages_listing(void *session, const char *name, - uint16_t max, uint16_t offset, - uint8_t subject_len, - const struct messages_filter *filter, - messages_get_messages_listing_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -int messages_get_message(void *session, const char *handle, - unsigned long flags, - messages_get_message_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -int messages_update_inbox(void *session, messages_status_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -int messages_set_read(void *session, const char *handle, uint8_t value, - messages_status_cb callback, void *user_data) -{ - return -ENOSYS; -} - -int messages_set_delete(void *session, const char *handle, uint8_t value, - messages_status_cb callback, - void *user_data) -{ - return -ENOSYS; -} - -void messages_abort(void *session) -{ -} diff --git a/obexd/plugins/phonebook-ebook.c b/obexd/plugins/phonebook-ebook.c deleted file mode 100644 index 2e495767..00000000 --- a/obexd/plugins/phonebook-ebook.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * - * OBEX Server - * - * Copyright (C) 2009-2010 Intel Corporation - * Copyright (C) 2007-2010 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include - -#include "log.h" -#include "obex.h" -#include "service.h" -#include "phonebook.h" - -#define QUERY_FN "(contains \"family_name\" \"%s\")" -#define QUERY_NAME "(contains \"given_name\" \"%s\")" -#define QUERY_PHONE "(contains \"phone\" \"%s\")" - -struct query_context { - const struct apparam_field *params; - phonebook_cb contacts_cb; - phonebook_entry_cb entry_cb; - phonebook_cache_ready_cb ready_cb; - EBookQuery *query; - unsigned int count; - GString *buf; - char *id; - unsigned queued_calls; - void *user_data; - GSList *ebooks; - gboolean canceled; -}; - -static char *attribute_mask[] = { -/* 0 */ "VERSION", - "FN", - "N", - "PHOTO", - "BDAY", - "ADR", - "LABEL", - "TEL", -/* 8 */ "EMAIL", - "MAILER", - "TZ", - "GEO", - "TITLE", - "ROLE", - "LOGO", - "AGENT", -/* 16 */ "ORG", - "NOTE", - "REV", - "SOUND", - "URL", - "UID", - "KEY", - "NICKNAME", -/* 24 */ "CATEGORIES", - "PROID", - "CLASS", - "SORT-STRING", -/* 28 */ "X-IRMC-CALL-DATETIME", - NULL - -}; - -static void close_ebooks(GSList *ebooks) -{ - g_slist_free_full(ebooks, g_object_unref); -} - -static void free_query_context(struct query_context *data) -{ - g_free(data->id); - - if (data->buf != NULL) - g_string_free(data->buf, TRUE); - - if (data->query != NULL) - e_book_query_unref(data->query); - - close_ebooks(data->ebooks); - - g_free(data); -} - -static char *evcard_to_string(EVCard *evcard, unsigned int format, - uint64_t filter) -{ - EVCard *evcard2; - GList *l; - char *vcard; - - if (!filter) - return e_vcard_to_string(evcard, EVC_FORMAT_VCARD_30); - /* XXX There is no support for VCARD 2.1 at this time */ - - /* - * Mandatory attributes for vCard 2.1 are VERSION ,N and TEL. - * Mandatory attributes for vCard 3.0 are VERSION, N, FN and TEL - */ - filter = format == EVC_FORMAT_VCARD_30 ? filter | 0x87: filter | 0x85; - - l = e_vcard_get_attributes(evcard); - evcard2 = e_vcard_new(); - for (; l; l = g_list_next(l)) { - EVCardAttribute *attrib = l->data; - const char *name; - int i; - - if (!attrib) - continue; - - name = e_vcard_attribute_get_name(attrib); - - for (i = 0; attribute_mask[i] != NULL; i++) { - if (!(filter & (1 << i))) - continue; - if (g_strcmp0(name, attribute_mask[i]) != 0) - continue; - - e_vcard_add_attribute(evcard2, - e_vcard_attribute_copy(attrib)); - } - } - - vcard = e_vcard_to_string(evcard2, format); - g_object_unref(evcard2); - - return vcard; -} - -static void ebookpull_cb(EBook *book, const GError *gerr, GList *contacts, - void *user_data) -{ - struct query_context *data = user_data; - GList *l; - unsigned int count, maxcount; - - data->queued_calls--; - - if (data->canceled) - goto canceled; - - if (gerr != NULL) { - error("E-Book query failed: %s", gerr->message); - goto done; - } - - DBG(""); - - /* - * When MaxListCount is zero, PCE wants to know the number of used - * indexes in the phonebook of interest. All other parameters that - * may be present in the request shall be ignored. - */ - maxcount = data->params->maxlistcount; - if (maxcount == 0) { - data->count += g_list_length(contacts); - goto done; - } - - l = g_list_nth(contacts, data->params->liststartoffset); - - for (count = 0; l && count + data->count < maxcount; l = g_list_next(l), - count++) { - EContact *contact = E_CONTACT(l->data); - EVCard *evcard = E_VCARD(contact); - char *vcard; - - vcard = evcard_to_string(evcard, EVC_FORMAT_VCARD_30, - data->params->filter); - - data->buf = g_string_append(data->buf, vcard); - data->buf = g_string_append(data->buf, "\r\n"); - g_free(vcard); - } - - DBG("collected %d vcards", count); - - data->count += count; - - g_list_free_full(contacts, g_object_unref); - -done: - if (data->queued_calls == 0) { - GString *buf = data->buf; - data->buf = NULL; - - data->contacts_cb(buf->str, buf->len, data->count, - 0, TRUE, data->user_data); - - g_string_free(buf, TRUE); - - } - - return; - -canceled: - if (data->queued_calls == 0) - free_query_context(data); -} - -static void ebook_entry_cb(EBook *book, const GError *gerr, - EContact *contact, void *user_data) -{ - struct query_context *data = user_data; - EVCard *evcard; - char *vcard; - size_t len; - - data->queued_calls--; - - if (data->canceled) - goto done; - - if (gerr != NULL) { - error("E-Book query failed: %s", gerr->message); - goto done; - } - - DBG(""); - - evcard = E_VCARD(contact); - - vcard = evcard_to_string(evcard, EVC_FORMAT_VCARD_30, - data->params->filter); - - len = vcard ? strlen(vcard) : 0; - - data->count++; - data->contacts_cb(vcard, len, 1, 0, TRUE, data->user_data); - - g_free(vcard); - g_object_unref(contact); - - return; - -done: - if (data->queued_calls == 0) { - if (data->count == 0) - data->contacts_cb(NULL, 0, 1, 0, TRUE, - data->user_data); - else if (data->canceled) - free_query_context(data); - } -} - -static char *evcard_name_attribute_to_string(EVCard *evcard) -{ - EVCardAttribute *attrib; - GList *l; - GString *name = NULL; - - attrib = e_vcard_get_attribute(evcard, EVC_N); - if (!attrib) - return NULL; - - for (l = e_vcard_attribute_get_values(attrib); l; l = l->next) { - const char *value = l->data; - - if (!strlen(value)) - continue; - - if (!name) - name = g_string_new(value); - else { - name = g_string_append(name, ";"); - name = g_string_append(name, l->data); - } - } - - if (!name) - return NULL; - - return g_string_free(name, FALSE); -} - -static void cache_cb(EBook *book, const GError *gerr, GList *contacts, - void *user_data) -{ - struct query_context *data = user_data; - GList *l; - - data->queued_calls--; - - if (data->canceled) - goto canceled; - - if (gerr != NULL) { - error("E-Book operation failed: %s", gerr->message); - goto done; - } - - DBG(""); - - for (l = contacts; l; l = g_list_next(l)) { - EContact *contact = E_CONTACT(l->data); - EVCard *evcard = E_VCARD(contact); - EVCardAttribute *attrib; - char *uid, *tel, *name; - - name = evcard_name_attribute_to_string(evcard); - if (!name) - continue; - - attrib = e_vcard_get_attribute(evcard, EVC_UID); - if (!attrib) - continue; - - uid = e_vcard_attribute_get_value(attrib); - if (!uid) - continue; - - attrib = e_vcard_get_attribute(evcard, EVC_TEL); - if (attrib) - tel = e_vcard_attribute_get_value(attrib); - else - tel = g_strdup(""); - - data->entry_cb(uid, PHONEBOOK_INVALID_HANDLE, name, NULL, - tel, data->user_data); - - g_free(name); - g_free(uid); - g_free(tel); - } - - g_list_free_full(contacts, g_object_unref); - -done: - if (data->queued_calls == 0) - data->ready_cb(data->user_data); - - return; - -canceled: - if (data->queued_calls == 0) - free_query_context(data); -} - -static GSList *traverse_sources(GSList *ebooks, GSList *sources, - char **default_src) { - GError *gerr = NULL; - - for (; sources != NULL; sources = g_slist_next(sources)) { - char *uri; - ESource *source = E_SOURCE(sources->data); - EBook *ebook = e_book_new(source, &gerr); - - if (ebook == NULL) { - error("Can't create user's address book: %s", - gerr->message); - g_clear_error(&gerr); - continue; - } - - uri = e_source_get_uri(source); - if (g_strcmp0(*default_src, uri) == 0) { - g_free(uri); - continue; - } - g_free(uri); - - if (e_book_open(ebook, FALSE, &gerr) == FALSE) { - error("Can't open e-book address book: %s", - gerr->message); - g_object_unref(ebook); - g_clear_error(&gerr); - continue; - } - - if (*default_src == NULL) - *default_src = e_source_get_uri(source); - - DBG("%s address book opened", e_source_peek_name(source)); - - ebooks = g_slist_append(ebooks, ebook); - } - - return ebooks; -} - -int phonebook_init(void) -{ - g_type_init(); - - return 0; -} - -static GSList *open_ebooks(void) -{ - GError *gerr = NULL; - ESourceList *src_list; - GSList *list; - char *default_src = NULL; - GSList *ebooks = NULL; - - if (e_book_get_addressbooks(&src_list, &gerr) == FALSE) { - error("Can't list user's address books: %s", gerr->message); - g_error_free(gerr); - return NULL; - } - - list = e_source_list_peek_groups(src_list); - while (list != NULL) { - ESourceGroup *group = E_SOURCE_GROUP(list->data); - GSList *sources = e_source_group_peek_sources(group); - - ebooks = traverse_sources(ebooks, sources, &default_src); - - list = list->next; - } - - g_free(default_src); - g_object_unref(src_list); - - return ebooks; -} - -void phonebook_exit(void) -{ -} - -char *phonebook_set_folder(const char *current_folder, - const char *new_folder, uint8_t flags, int *err) -{ - gboolean root, child; - char *fullname = NULL, *tmp1, *tmp2, *base; - int ret = 0, len; - - root = (g_strcmp0("/", current_folder) == 0); - child = (new_folder && strlen(new_folder) != 0); - - /* Evolution back-end will support /telecom/pb folder only */ - - switch (flags) { - case 0x02: - /* Go back to root */ - if (!child) { - fullname = g_strdup("/"); - goto done; - } - - /* Go down 1 level */ - fullname = g_build_filename(current_folder, new_folder, NULL); - if (strcmp(PB_TELECOM_FOLDER, fullname) != 0 && - strcmp(PB_CONTACTS_FOLDER, fullname) != 0) { - g_free(fullname); - fullname = NULL; - ret = -ENOENT; - } - - break; - case 0x03: - /* Go up 1 level */ - if (root) { - /* Already root */ - ret = -EBADR; - goto done; - } - - /* - * Removing one level of the current folder. Current folder - * contains AT LEAST one level since it is not at root folder. - * Use glib utility functions to handle invalid chars in the - * folder path properly. - */ - tmp1 = g_path_get_basename(current_folder); - tmp2 = g_strrstr(current_folder, tmp1); - len = tmp2 - (current_folder + 1); - - g_free(tmp1); - - if (len == 0) - base = g_strdup("/"); - else - base = g_strndup(current_folder, len); - - /* Return one level only */ - if (!child) { - fullname = base; - goto done; - } - - fullname = g_build_filename(base, new_folder, NULL); - if (strcmp(fullname, PB_TELECOM_FOLDER) != 0 && - strcmp(fullname, PB_CONTACTS_FOLDER) != 0) { - g_free(fullname); - fullname = NULL; - ret = -ENOENT; - } - - g_free(base); - - break; - default: - ret = -EBADR; - break; - } - -done: - if (err) - *err = ret; - - return fullname; -} - -void phonebook_req_finalize(void *request) -{ - struct query_context *data = request; - - if (data->queued_calls == 0) - free_query_context(data); - else - data->canceled = TRUE; -} - -void *phonebook_pull(const char *name, const struct apparam_field *params, - phonebook_cb cb, void *user_data, int *err) -{ - struct query_context *data; - - if (g_strcmp0(PB_CONTACTS, name) != 0) { - if (err) - *err = -ENOENT; - - return NULL; - } - - data = g_new0(struct query_context, 1); - data->contacts_cb = cb; - data->params = params; - data->user_data = user_data; - data->buf = g_string_new(""); - data->query = e_book_query_any_field_contains(""); - data->ebooks = open_ebooks(); - - if (err) - *err = data->ebooks == NULL ? -EIO : 0; - - return data; -} - -int phonebook_pull_read(void *request) -{ - struct query_context *data = request; - GSList *l; - - if (!data) - return -ENOENT; - - for (l = data->ebooks; l != NULL; l = g_slist_next(l)) { - EBook *ebook = l->data; - - if (e_book_is_opened(ebook) == FALSE) - continue; - - if (e_book_get_contacts_async(ebook, data->query, - ebookpull_cb, data) == TRUE) - data->queued_calls++; - } - - if (data->queued_calls == 0) - return -ENOENT; - - return 0; -} - -void *phonebook_get_entry(const char *folder, const char *id, - const struct apparam_field *params, - phonebook_cb cb, void *user_data, int *err) -{ - struct query_context *data; - GSList *l; - - data = g_new0(struct query_context, 1); - data->contacts_cb = cb; - data->params = params; - data->user_data = user_data; - data->id = g_strdup(id); - data->ebooks = open_ebooks(); - - for (l = data->ebooks; l != NULL; l = g_slist_next(l)) { - EBook *ebook = l->data; - - if (e_book_is_opened(ebook) == FALSE) - continue; - - if (e_book_get_contact_async(ebook, data->id, - ebook_entry_cb, data) == TRUE) - data->queued_calls++; - } - - if (err) - *err = (data->queued_calls == 0 ? -ENOENT : 0); - - return data; -} - -void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb, - phonebook_cache_ready_cb ready_cb, void *user_data, int *err) -{ - struct query_context *data; - EBookQuery *query; - GSList *l; - EContact *me; - EVCard *evcard; - GError *gerr = NULL; - EBook *eb; - EVCardAttribute *attrib; - char *uid, *tel, *cname; - - if (g_strcmp0(PB_CONTACTS_FOLDER, name) != 0) { - if (err) - *err = -ENOENT; - - return NULL; - } - - DBG(""); - - query = e_book_query_any_field_contains(""); - - data = g_new0(struct query_context, 1); - data->entry_cb = entry_cb; - data->ready_cb = ready_cb; - data->user_data = user_data; - data->query = query; - data->ebooks = open_ebooks(); - - /* Add 0.vcf */ - if (e_book_get_self(&me, &eb, &gerr) == FALSE) { - g_error_free(gerr); - goto next; - } - - evcard = E_VCARD(me); - - cname = evcard_name_attribute_to_string(evcard); - if (!cname) - cname = g_strdup(""); - - attrib = e_vcard_get_attribute(evcard, EVC_UID); - uid = e_vcard_attribute_get_value(attrib); - if (!uid) - uid = g_strdup(""); - - attrib = e_vcard_get_attribute(evcard, EVC_TEL); - if (attrib) - tel = e_vcard_attribute_get_value(attrib); - else - tel = g_strdup(""); - - data->entry_cb(uid, 0, cname, NULL, tel, data->user_data); - - data->count++; - - g_free(cname); - g_free(uid); - g_free(tel); - g_object_unref(eb); - -next: - for (l = data->ebooks; l != NULL; l = g_slist_next(l)) { - EBook *ebook = l->data; - - if (e_book_is_opened(ebook) == FALSE) - continue; - - if (e_book_get_contacts_async(ebook, query, - cache_cb, data) == TRUE) - data->queued_calls++; - } - - if (err) - *err = (data->queued_calls == 0 ? -ENOENT : 0); - - return data; -} diff --git a/obexd/plugins/phonebook-tracker.c b/obexd/plugins/phonebook-tracker.c deleted file mode 100644 index 433f95a7..00000000 --- a/obexd/plugins/phonebook-tracker.c +++ /dev/null @@ -1,1718 +0,0 @@ -/* - * Phonebook access through D-Bus vCard and call history service - * - * Copyright (C) 2010 Nokia Corporation - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "log.h" -#include "obex.h" -#include "service.h" -#include "mimetype.h" -#include "phonebook.h" -#include "vcard.h" - -#define TRACKER_SERVICE "org.freedesktop.Tracker1" -#define TRACKER_RESOURCES_PATH "/org/freedesktop/Tracker1/Resources" -#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources" - -#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me" -#define AFFILATION_HOME "Home" -#define AFFILATION_WORK "Work" -#define ADDR_FIELD_AMOUNT 7 -#define PULL_QUERY_COL_AMOUNT 23 -#define COUNT_QUERY_COL_AMOUNT 1 - -#define COL_PHONE_AFF 0 /* work/home phone numbers */ -#define COL_FULL_NAME 1 -#define COL_FAMILY_NAME 2 -#define COL_GIVEN_NAME 3 -#define COL_ADDITIONAL_NAME 4 -#define COL_NAME_PREFIX 5 -#define COL_NAME_SUFFIX 6 -#define COL_ADDR_AFF 7 /* addresses from affilation */ -#define COL_BIRTH_DATE 8 -#define COL_NICKNAME 9 -#define COL_URL 10 -#define COL_PHOTO 11 -#define COL_ORG_ROLE 12 -#define COL_UID 13 -#define COL_TITLE 14 -#define COL_AFF_TYPE 15 -#define COL_ORG_NAME 16 -#define COL_ORG_DEPARTMENT 17 -#define COL_EMAIL_AFF 18 /* email's from affilation (work/home) */ -#define COL_DATE 19 -#define COL_SENT 20 -#define COL_ANSWERED 21 -#define CONTACTS_ID_COL 22 -#define CONTACT_ID_PREFIX "urn:uuid:" -#define CALL_ID_PREFIX "message:" - -#define FAX_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#FaxNumber" -#define MOBILE_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#CellPhoneNumber" - -#define MAIN_DELIM "\30" /* Main delimiter between phones, addresses, emails*/ -#define SUB_DELIM "\31" /* Delimiter used in telephone number strings*/ -#define ADDR_DELIM "\37" /* Delimiter used for address data fields */ -#define MAX_FIELDS 100 /* Max amount of fields to be concatenated at once*/ -#define VCARDS_PART_COUNT 50 /* amount of vcards sent at once to PBAP core */ -#define QUERY_OFFSET_FORMAT "%s OFFSET %d" - -#define CONTACTS_QUERY_ALL \ -"SELECT " \ -"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?aff_number)," \ -"\"\31\", nco:phoneNumber(?aff_number)), \"\30\")" \ -"WHERE {" \ -" ?_role nco:hasPhoneNumber ?aff_number" \ -"}) " \ -"nco:fullname(?_contact) " \ -"nco:nameFamily(?_contact) " \ -"nco:nameGiven(?_contact) " \ -"nco:nameAdditional(?_contact) " \ -"nco:nameHonorificPrefix(?_contact) " \ -"nco:nameHonorificSuffix(?_contact) " \ -"(SELECT GROUP_CONCAT(fn:concat(" \ -"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:locality(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:region(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:country(?aff_addr), \"\"), " \ -"\"\31\", rdfs:label(?_role) ), " \ -"\"\30\") " \ -"WHERE {" \ -"?_role nco:hasPostalAddress ?aff_addr" \ -"}) " \ -"nco:birthDate(?_contact) " \ -"(SELECT " \ -" ?nick " \ -" WHERE { " \ -" { " \ -" ?_contact nco:nickname ?nick " \ -" } UNION { " \ -" ?_contact nco:hasAffiliation ?role . " \ -" ?role nco:hasIMAddress ?im . " \ -" ?im nco:imNickname ?nick " \ -" } " \ -" } " \ -") " \ -"(SELECT GROUP_CONCAT(fn:concat( " \ - "?url_val, \"\31\", tracker:coalesce(rdfs:label(?_role), \"\") "\ - "), \"\30\") " \ - "WHERE {" \ - "?_role nco:url ?url_val . " \ -"})" \ -"nie:url(nco:photo(?_contact)) " \ -"nco:role(?_role) " \ -"nco:contactUID(?_contact) " \ -"nco:title(?_role) " \ -"rdfs:label(?_role) " \ -"nco:fullname(nco:org(?_role))" \ -"nco:department(?_role) " \ -"(SELECT GROUP_CONCAT(fn:concat(?emailaddress,\"\31\"," \ - "tracker:coalesce(rdfs:label(?_role), \"\"))," \ - "\"\30\") " \ - "WHERE { " \ - "?_role nco:hasEmailAddress " \ - " [ nco:emailAddress ?emailaddress ] " \ - "}) " \ -"\"NOTACALL\" \"false\" \"false\" " \ -"?_contact " \ -"WHERE {" \ -" ?_contact a nco:PersonContact ." \ -" OPTIONAL {?_contact nco:hasAffiliation ?_role .}" \ -"}" \ -"ORDER BY tracker:id(?_contact)" - -#define CONTACTS_QUERY_ALL_LIST \ - "SELECT ?c nco:nameFamily(?c) " \ - "nco:nameGiven(?c) nco:nameAdditional(?c) " \ - "nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c) " \ - "(SELECT " \ - "?nick " \ - "WHERE { " \ - "{ " \ - "?c nco:nickname ?nick " \ - "} UNION { " \ - "?c nco:hasAffiliation ?role . " \ - "?role nco:hasIMAddress ?im . " \ - "?im nco:imNickname ?nick " \ - "} " \ - "} " \ - ") " \ - "nco:phoneNumber(?h) " \ - "WHERE { " \ - "?c a nco:PersonContact . " \ - "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \ - "OPTIONAL { " \ - "?c nco:hasAffiliation ?a . " \ - "?a nco:hasPhoneNumber ?h . " \ - "} " \ - "} GROUP BY ?c" - -#define CALLS_CONSTRAINTS(CONSTRAINT) \ -" WHERE { " \ - "?_call a nmo:Call . " \ - "?_unb_contact a nco:Contact . " \ - "?_unb_contact nco:hasPhoneNumber ?_cpn . " \ -CONSTRAINT \ - "OPTIONAL { " \ - "{ SELECT ?_contact ?_no ?_role ?_number " \ - "count(?_contact) as ?cnt " \ - "WHERE { " \ - "?_contact a nco:PersonContact . " \ - "{ " \ - "?_contact nco:hasAffiliation ?_role . "\ - "?_role nco:hasPhoneNumber ?_number . " \ - "} UNION { " \ - "?_contact nco:hasPhoneNumber ?_number" \ - "} " \ - "?_number maemo:localPhoneNumber ?_no . " \ - "} GROUP BY ?_no } " \ - "FILTER(?cnt = 1) " \ - "?_cpn maemo:localPhoneNumber ?_no . " \ - "} " \ -"} " - -#define CALLS_LIST(CONSTRAINT) \ -"SELECT ?_call nco:nameFamily(?_contact) " \ - "nco:nameGiven(?_contact) nco:nameAdditional(?_contact) " \ - "nco:nameHonorificPrefix(?_contact) " \ - "nco:nameHonorificSuffix(?_contact) " \ - "(SELECT " \ - "?nick " \ - "WHERE { " \ - "{ " \ - "?_contact nco:nickname ?nick " \ - "} UNION { " \ - "?_contact nco:hasAffiliation ?role . " \ - "?role nco:hasIMAddress ?im . " \ - "?im nco:imNickname ?nick " \ - "} " \ - "} " \ - ") " \ - "nco:phoneNumber(?_cpn) " \ -CALLS_CONSTRAINTS(CONSTRAINT) \ -"ORDER BY DESC(nmo:sentDate(?_call)) " - -#define CALLS_QUERY(CONSTRAINT) \ -"SELECT " \ -"(SELECT fn:concat(rdf:type(?role_number)," \ - "\"\31\", nco:phoneNumber(?role_number))" \ - "WHERE {" \ - "{" \ - " ?_role nco:hasPhoneNumber ?role_number " \ - " FILTER (?role_number = ?_number)" \ - "} UNION { " \ - "?_unb_contact nco:hasPhoneNumber ?role_number . " \ - " FILTER (!bound(?_role)) " \ - "}" \ -"} GROUP BY nco:phoneNumber(?role_number) ) " \ - "nco:fullname(?_contact) " \ - "nco:nameFamily(?_contact) " \ - "nco:nameGiven(?_contact) " \ - "nco:nameAdditional(?_contact) " \ - "nco:nameHonorificPrefix(?_contact) " \ - "nco:nameHonorificSuffix(?_contact) " \ -"(SELECT GROUP_CONCAT(fn:concat(" \ - "tracker:coalesce(nco:pobox(?aff_addr), \"\"), \"\37\"," \ - "tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \"\37\","\ - "tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \"\37\","\ - "tracker:coalesce(nco:locality(?aff_addr), \"\"), \"\37\"," \ - "tracker:coalesce(nco:region(?aff_addr), \"\"), \"\37\"," \ - "tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \"\37\"," \ - "tracker:coalesce(nco:country(?aff_addr), \"\"), " \ - "\"\31\", rdfs:label(?c_role) ), " \ - "\"\30\") " \ - "WHERE {" \ - "?_contact nco:hasAffiliation ?c_role . " \ - "?c_role nco:hasPostalAddress ?aff_addr" \ - "}) " \ - "nco:birthDate(?_contact) " \ -"(SELECT " \ - "?nick " \ - "WHERE { " \ - " { " \ - " ?_contact nco:nickname ?nick " \ - " } UNION { " \ - " ?_contact nco:hasAffiliation ?role . " \ - " ?role nco:hasIMAddress ?im . " \ - " ?im nco:imNickname ?nick " \ - " } " \ - " } " \ - ") " \ -"(SELECT GROUP_CONCAT(fn:concat(?url_value, \"\31\", " \ - "tracker:coalesce(rdfs:label(?c_role), \"\")), \"\30\") " \ - "WHERE {" \ - "?_contact nco:hasAffiliation ?c_role . " \ - "?c_role nco:url ?url_value . " \ -"})" \ - "nie:url(nco:photo(?_contact)) " \ - "nco:role(?_role) " \ - "nco:contactUID(?_contact) " \ - "nco:title(?_role) " \ - "rdfs:label(?_role) " \ - "nco:fullname(nco:org(?_role)) " \ - "nco:department(?_role) " \ -"(SELECT GROUP_CONCAT(fn:concat(?emailaddress,\"\31\"," \ - "tracker:coalesce(rdfs:label(?c_role), \"\"))," \ - "\"\30\") " \ - "WHERE { " \ - "?_contact nco:hasAffiliation ?c_role . " \ - "?c_role nco:hasEmailAddress " \ - " [ nco:emailAddress ?emailaddress ] " \ - "}) " \ - "nmo:receivedDate(?_call) " \ - "nmo:isSent(?_call) " \ - "nmo:isAnswered(?_call) " \ - "?_call " \ -CALLS_CONSTRAINTS(CONSTRAINT) \ -"ORDER BY DESC(nmo:sentDate(?_call)) " - -#define MISSED_CONSTRAINT \ -"?_call nmo:from ?_unb_contact . " \ -"?_call nmo:isSent false . " \ -"?_call nmo:isAnswered false . " - -#define INCOMING_CONSTRAINT \ -"?_call nmo:from ?_unb_contact . " \ -"?_call nmo:isSent false . " \ -"?_call nmo:isAnswered true . " - -#define OUTGOING_CONSTRAINT \ -"?_call nmo:to ?_unb_contact . " \ -"?_call nmo:isSent true . " - -#define COMBINED_CONSTRAINT \ -"{ " \ -" ?_call nmo:from ?_unb_contact . " \ -" ?_call nmo:isSent false " \ -"} UNION { " \ -" ?_call nmo:to ?_unb_contact . " \ -" ?_call nmo:isSent true " \ -"} " - -#define CALL_URI_CONSTRAINT \ -COMBINED_CONSTRAINT \ -"FILTER (?_call = <%s>) " - -#define MISSED_CALLS_QUERY CALLS_QUERY(MISSED_CONSTRAINT) -#define MISSED_CALLS_LIST CALLS_LIST(MISSED_CONSTRAINT) -#define INCOMING_CALLS_QUERY CALLS_QUERY(INCOMING_CONSTRAINT) -#define INCOMING_CALLS_LIST CALLS_LIST(INCOMING_CONSTRAINT) -#define OUTGOING_CALLS_QUERY CALLS_QUERY(OUTGOING_CONSTRAINT) -#define OUTGOING_CALLS_LIST CALLS_LIST(OUTGOING_CONSTRAINT) -#define COMBINED_CALLS_QUERY CALLS_QUERY(COMBINED_CONSTRAINT) -#define COMBINED_CALLS_LIST CALLS_LIST(COMBINED_CONSTRAINT) -#define CONTACT_FROM_CALL_QUERY CALLS_QUERY(CALL_URI_CONSTRAINT) - -#define CONTACTS_QUERY_FROM_URI \ -"SELECT " \ -"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?aff_number)," \ -"\"\31\", nco:phoneNumber(?aff_number)), \"\30\")" \ -"WHERE {" \ -" ?_role nco:hasPhoneNumber ?aff_number" \ -"}) " \ -"nco:fullname(<%s>) " \ -"nco:nameFamily(<%s>) " \ -"nco:nameGiven(<%s>) " \ -"nco:nameAdditional(<%s>) " \ -"nco:nameHonorificPrefix(<%s>) " \ -"nco:nameHonorificSuffix(<%s>) " \ -"(SELECT GROUP_CONCAT(fn:concat(" \ -"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:locality(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:region(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \"\37\"," \ -"tracker:coalesce(nco:country(?aff_addr), \"\"), " \ -"\"\31\", rdfs:label(?_role) ), " \ -"\"\30\") " \ -"WHERE {" \ -"?_role nco:hasPostalAddress ?aff_addr" \ -"}) " \ -"nco:birthDate(<%s>) " \ -"(SELECT " \ -" ?nick " \ -" WHERE { " \ -" { " \ -" ?_contact nco:nickname ?nick " \ -" } UNION { " \ -" ?_contact nco:hasAffiliation ?role . " \ -" ?role nco:hasIMAddress ?im . " \ -" ?im nco:imNickname ?nick " \ -" } " \ -" FILTER (?_contact = <%s>)" \ -" } " \ -") " \ -"(SELECT GROUP_CONCAT(fn:concat( " \ - "?url_val, \"\31\", tracker:coalesce(rdfs:label(?_role), \"\") "\ - "), \"\30\") " \ - "WHERE {" \ - "?_role nco:url ?url_val . " \ -"})" \ -"nie:url(nco:photo(<%s>)) " \ -"nco:role(?_role) " \ -"nco:contactUID(<%s>) " \ -"nco:title(?_role) " \ -"rdfs:label(?_role) " \ -"nco:fullname(nco:org(?_role))" \ -"nco:department(?_role) " \ -"(SELECT GROUP_CONCAT(fn:concat(?emailaddress,\"\31\"," \ - "tracker:coalesce(rdfs:label(?_role), \"\"))," \ - "\"\30\") " \ - "WHERE { " \ - "?_role nco:hasEmailAddress " \ - " [ nco:emailAddress ?emailaddress ] " \ - "}) " \ -"\"NOTACALL\" \"false\" \"false\" " \ -"<%s> " \ -"WHERE {" \ -" <%s> a nco:PersonContact ." \ -" OPTIONAL {<%s> nco:hasAffiliation ?_role .}" \ -"}" - -#define CONTACTS_OTHER_QUERY_FROM_URI \ - "SELECT fn:concat(\"TYPE_OTHER\", \"\31\", nco:phoneNumber(?t))"\ - "\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" " \ - "\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" " \ - " \"NOTACALL\" \"false\" \"false\" <%s> " \ - "WHERE { " \ - "<%s> a nco:Contact . " \ - "OPTIONAL { <%s> nco:hasPhoneNumber ?t . } " \ - "} " - -#define CONTACTS_COUNT_QUERY \ - "SELECT COUNT(?c) " \ - "WHERE {" \ - "?c a nco:PersonContact ." \ - "}" - -#define MISSED_CALLS_COUNT_QUERY \ - "SELECT COUNT(?call) WHERE {" \ - "?c a nco:Contact ;" \ - "nco:hasPhoneNumber ?h ." \ - "?call a nmo:Call ;" \ - "nmo:isSent false ;" \ - "nmo:from ?c ;" \ - "nmo:isAnswered false ." \ - "}" - -#define INCOMING_CALLS_COUNT_QUERY \ - "SELECT COUNT(?call) WHERE {" \ - "?c a nco:Contact ;" \ - "nco:hasPhoneNumber ?h ." \ - "?call a nmo:Call ;" \ - "nmo:isSent false ;" \ - "nmo:from ?c ;" \ - "nmo:isAnswered true ." \ - "}" - -#define OUTGOING_CALLS_COUNT_QUERY \ - "SELECT COUNT(?call) WHERE {" \ - "?c a nco:Contact ;" \ - "nco:hasPhoneNumber ?h ." \ - "?call a nmo:Call ;" \ - "nmo:isSent true ;" \ - "nmo:to ?c ." \ - "}" - -#define COMBINED_CALLS_COUNT_QUERY \ - "SELECT COUNT(?call) WHERE {" \ - "{" \ - "?c a nco:Contact ;" \ - "nco:hasPhoneNumber ?h ." \ - "?call a nmo:Call ;" \ - "nmo:isSent true ;" \ - "nmo:to ?c ." \ - "}UNION {" \ - "?c a nco:Contact ;" \ - "nco:hasPhoneNumber ?h ." \ - "?call a nmo:Call ;" \ - "nmo:from ?c ." \ - "}" \ - "}" - -#define NEW_MISSED_CALLS_COUNT_QUERY \ - "SELECT COUNT(?call) WHERE {" \ - "?c a nco:Contact ;" \ - "nco:hasPhoneNumber ?h ." \ - "?call a nmo:Call ;" \ - "nmo:isSent false ;" \ - "nmo:from ?c ;" \ - "nmo:isAnswered false ;" \ - "nmo:isRead false ." \ - "}" - -typedef int (*reply_list_foreach_t) (const char **reply, int num_fields, - void *user_data); - -typedef void (*add_field_t) (struct phonebook_contact *contact, - const char *value, int type); - -struct pending_reply { - reply_list_foreach_t callback; - void *user_data; - int num_fields; -}; - -struct contact_data { - char *id; - struct phonebook_contact *contact; -}; - -struct phonebook_data { - phonebook_cb cb; - void *user_data; - int index; - gboolean vcardentry; - const struct apparam_field *params; - GSList *contacts; - phonebook_cache_ready_cb ready_cb; - phonebook_entry_cb entry_cb; - int newmissedcalls; - GCancellable *query_canc; - char *req_name; - int vcard_part_count; - int tracker_index; -}; - -struct phonebook_index { - GArray *phonebook; - int index; -}; - -static TrackerSparqlConnection *connection = NULL; - -static const char *name2query(const char *name) -{ - if (g_str_equal(name, PB_CONTACTS)) - return CONTACTS_QUERY_ALL; - else if (g_str_equal(name, PB_CALLS_INCOMING)) - return INCOMING_CALLS_QUERY; - else if (g_str_equal(name, PB_CALLS_OUTGOING)) - return OUTGOING_CALLS_QUERY; - else if (g_str_equal(name, PB_CALLS_MISSED)) - return MISSED_CALLS_QUERY; - else if (g_str_equal(name, PB_CALLS_COMBINED)) - return COMBINED_CALLS_QUERY; - - return NULL; -} - -static const char *name2count_query(const char *name) -{ - if (g_str_equal(name, PB_CONTACTS)) - return CONTACTS_COUNT_QUERY; - else if (g_str_equal(name, PB_CALLS_INCOMING)) - return INCOMING_CALLS_COUNT_QUERY; - else if (g_str_equal(name, PB_CALLS_OUTGOING)) - return OUTGOING_CALLS_COUNT_QUERY; - else if (g_str_equal(name, PB_CALLS_MISSED)) - return MISSED_CALLS_COUNT_QUERY; - else if (g_str_equal(name, PB_CALLS_COMBINED)) - return COMBINED_CALLS_COUNT_QUERY; - - return NULL; -} - -static gboolean folder_is_valid(const char *folder) -{ - if (folder == NULL) - return FALSE; - - if (g_str_equal(folder, "/")) - return TRUE; - else if (g_str_equal(folder, PB_TELECOM_FOLDER)) - return TRUE; - else if (g_str_equal(folder, PB_CONTACTS_FOLDER)) - return TRUE; - else if (g_str_equal(folder, PB_CALLS_INCOMING_FOLDER)) - return TRUE; - else if (g_str_equal(folder, PB_CALLS_OUTGOING_FOLDER)) - return TRUE; - else if (g_str_equal(folder, PB_CALLS_MISSED_FOLDER)) - return TRUE; - else if (g_str_equal(folder, PB_CALLS_COMBINED_FOLDER)) - return TRUE; - - return FALSE; -} - -static const char *folder2query(const char *folder) -{ - if (g_str_equal(folder, PB_CONTACTS_FOLDER)) - return CONTACTS_QUERY_ALL_LIST; - else if (g_str_equal(folder, PB_CALLS_INCOMING_FOLDER)) - return INCOMING_CALLS_LIST; - else if (g_str_equal(folder, PB_CALLS_OUTGOING_FOLDER)) - return OUTGOING_CALLS_LIST; - else if (g_str_equal(folder, PB_CALLS_MISSED_FOLDER)) - return MISSED_CALLS_LIST; - else if (g_str_equal(folder, PB_CALLS_COMBINED_FOLDER)) - return COMBINED_CALLS_LIST; - - return NULL; -} - -static const char **string_array_from_cursor(TrackerSparqlCursor *cursor, - int array_len) -{ - const char **result; - int i; - - result = g_new0(const char *, array_len); - - for (i = 0; i < array_len; ++i) { - TrackerSparqlValueType type; - - type = tracker_sparql_cursor_get_value_type(cursor, i); - - if (type == TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE || - type == TRACKER_SPARQL_VALUE_TYPE_UNBOUND) - /* For null/unbound type filling result part with ""*/ - result[i] = ""; - else - /* Filling with string representation of content*/ - result[i] = tracker_sparql_cursor_get_string(cursor, i, - NULL); - } - - return result; -} - -static void update_cancellable(struct phonebook_data *pdata, - GCancellable *canc) -{ - if (pdata->query_canc) - g_object_unref(pdata->query_canc); - - pdata->query_canc = canc; -} - -static void async_query_cursor_next_cb(GObject *source, GAsyncResult *result, - gpointer user_data) -{ - struct pending_reply *pending = user_data; - TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR(source); - GCancellable *cancellable; - GError *error = NULL; - gboolean success; - const char **node; - int err; - - success = tracker_sparql_cursor_next_finish( - TRACKER_SPARQL_CURSOR(source), - result, &error); - - if (!success) { - if (error) { - DBG("cursor_next error: %s", error->message); - g_error_free(error); - } else - /* When tracker_sparql_cursor_next_finish ends with - * failure and no error is set, that means end of - * results returned by query */ - pending->callback(NULL, 0, pending->user_data); - - goto failed; - } - - node = string_array_from_cursor(cursor, pending->num_fields); - err = pending->callback(node, pending->num_fields, pending->user_data); - g_free(node); - - /* Fetch next result only if processing current chunk ended with - * success. Sometimes during processing data, we are able to determine - * if there is no need to get more data from tracker - by example - * stored amount of data parts is big enough for sending and we might - * want to suspend processing or just some error occurred. */ - if (!err) { - cancellable = g_cancellable_new(); - update_cancellable(pending->user_data, cancellable); - tracker_sparql_cursor_next_async(cursor, cancellable, - async_query_cursor_next_cb, - pending); - return; - } - -failed: - g_object_unref(cursor); - g_free(pending); -} - -static int query_tracker(const char *query, int num_fields, - reply_list_foreach_t callback, void *user_data) -{ - struct pending_reply *pending; - GCancellable *cancellable; - TrackerSparqlCursor *cursor; - GError *error = NULL; - - DBG(""); - - if (connection == NULL) - connection = tracker_sparql_connection_get_direct( - NULL, &error); - - if (!connection) { - if (error) { - DBG("direct-connection error: %s", error->message); - g_error_free(error); - } - - return -EINTR; - } - - cancellable = g_cancellable_new(); - update_cancellable(user_data, cancellable); - cursor = tracker_sparql_connection_query(connection, query, - cancellable, &error); - - if (cursor == NULL) { - if (error) { - DBG("connection_query error: %s", error->message); - g_error_free(error); - } - - g_object_unref(cancellable); - - return -EINTR; - } - - pending = g_new0(struct pending_reply, 1); - pending->callback = callback; - pending->user_data = user_data; - pending->num_fields = num_fields; - - /* Now asynchronously going through each row of results - callback - * async_query_cursor_next_cb will be called ALWAYS, even if async - * request was canceled */ - tracker_sparql_cursor_next_async(cursor, cancellable, - async_query_cursor_next_cb, - pending); - - return 0; -} - -static char *iso8601_utc_to_localtime(const char *datetime) -{ - time_t time; - struct tm tm, *local; - char localdate[32]; - int nr; - - memset(&tm, 0, sizeof(tm)); - - nr = sscanf(datetime, "%04u-%02u-%02uT%02u:%02u:%02u", - &tm.tm_year, &tm.tm_mon, &tm.tm_mday, - &tm.tm_hour, &tm.tm_min, &tm.tm_sec); - if (nr < 6) { - /* Invalid time format */ - error("sscanf(): %s (%d)", strerror(errno), errno); - return g_strdup(""); - } - - /* Time already in localtime */ - if (!g_str_has_suffix(datetime, "Z")) { - strftime(localdate, sizeof(localdate), "%Y%m%dT%H%M%S", &tm); - return g_strdup(localdate); - } - - tm.tm_year -= 1900; /* Year since 1900 */ - tm.tm_mon--; /* Months since January, values 0-11 */ - - time = mktime(&tm); - time -= timezone; - - local = localtime(&time); - - strftime(localdate, sizeof(localdate), "%Y%m%dT%H%M%S", local); - - return g_strdup(localdate); -} - -static void set_call_type(struct phonebook_contact *contact, - const char *datetime, const char *is_sent, - const char *is_answered) -{ - gboolean sent, answered; - - if (g_strcmp0(datetime, "NOTACALL") == 0) { - contact->calltype = CALL_TYPE_NOT_A_CALL; - return; - } - - sent = g_str_equal(is_sent, "true"); - answered = g_str_equal(is_answered, "true"); - - if (sent == FALSE) { - if (answered == FALSE) - contact->calltype = CALL_TYPE_MISSED; - else - contact->calltype = CALL_TYPE_INCOMING; - } else - contact->calltype = CALL_TYPE_OUTGOING; - - /* Tracker gives time in the ISO 8601 format, UTC time */ - contact->datetime = iso8601_utc_to_localtime(datetime); -} - -static gboolean contact_matches(struct contact_data *c_data, const char *id, - const char *datetime) -{ - char *localtime; - int cmp_ret; - - if (g_strcmp0(c_data->id, id) != 0) - return FALSE; - - /* id is equal and not call history entry => contact matches */ - if (c_data->contact->calltype == CALL_TYPE_NOT_A_CALL) - return TRUE; - - /* for call history entries have to compare also timestamps of calls */ - localtime = iso8601_utc_to_localtime(datetime); - cmp_ret = g_strcmp0(c_data->contact->datetime, localtime); - g_free(localtime); - - return (cmp_ret == 0) ? TRUE : FALSE; -} - -static struct phonebook_contact *find_contact(GSList *contacts, const char *id, - const char *datetime) -{ - GSList *l; - - for (l = contacts; l; l = l->next) { - struct contact_data *c_data = l->data; - - if (contact_matches(c_data, id, datetime)) - return c_data->contact; - } - - return NULL; -} - -static struct phonebook_field *find_field(GSList *fields, const char *value, - int type) -{ - GSList *l; - - for (l = fields; l; l = l->next) { - struct phonebook_field *field = l->data; - /* Returning phonebook number if phone values and type values - * are equal */ - if (g_strcmp0(field->text, value) == 0 && field->type == type) - return field; - } - - return NULL; -} - -static void add_phone_number(struct phonebook_contact *contact, - const char *phone, int type) -{ - struct phonebook_field *number; - - if (phone == NULL || strlen(phone) == 0) - return; - - /* Not adding number if there is already added with the same value */ - if (find_field(contact->numbers, phone, type)) - return; - - number = g_new0(struct phonebook_field, 1); - number->text = g_strdup(phone); - number->type = type; - - contact->numbers = g_slist_append(contact->numbers, number); -} - -static void add_email(struct phonebook_contact *contact, const char *address, - int type) -{ - struct phonebook_field *email; - - if (address == NULL || strlen(address) == 0) - return; - - /* Not adding email if there is already added with the same value */ - if (find_field(contact->emails, address, type)) - return; - - email = g_new0(struct phonebook_field, 1); - email->text = g_strdup(address); - email->type = type; - - contact->emails = g_slist_append(contact->emails, email); -} - -static gboolean addr_matches(struct phonebook_addr *a, struct phonebook_addr *b) -{ - GSList *la, *lb; - - if (a->type != b->type) - return FALSE; - - for (la = a->fields, lb = b->fields; la && lb; - la = la->next, lb = lb->next) { - char *field_a = la->data; - char *field_b = lb->data; - - if (g_strcmp0(field_a, field_b) != 0) - return FALSE; - } - - return TRUE; -} - -/* generates phonebook_addr struct from tracker address data string. */ -static struct phonebook_addr *gen_addr(const char *address, int type) -{ - struct phonebook_addr *addr; - GSList *fields = NULL; - char **addr_parts; - int i; - - /* This test handles cases when address points to empty string - * (or address is NULL pointer) or string containing only six - * separators. It indicates that none of address fields is present - * and there is no sense to create dummy phonebook_addr struct */ - if (address == NULL || strlen(address) < ADDR_FIELD_AMOUNT) - return NULL; - - addr_parts = g_strsplit(address, ADDR_DELIM, ADDR_FIELD_AMOUNT); - - for (i = 0; i < ADDR_FIELD_AMOUNT; ++i) - fields = g_slist_append(fields, g_strdup(addr_parts[i])); - - g_strfreev(addr_parts); - - addr = g_new0(struct phonebook_addr, 1); - addr->fields = fields; - addr->type = type; - - return addr; -} - -static void add_address(struct phonebook_contact *contact, - const char *address, int type) -{ - struct phonebook_addr *addr; - GSList *l; - - addr = gen_addr(address, type); - if (addr == NULL) - return; - - /* Not adding address if there is already added with the same value. - * These type of checks have to be done because sometimes tracker - * returns results for contact data in more than 1 row - then the same - * address may be returned more than once in query results */ - for (l = contact->addresses; l; l = l->next) { - struct phonebook_addr *tmp = l->data; - - if (addr_matches(tmp, addr)) { - phonebook_addr_free(addr); - return; - } - } - - contact->addresses = g_slist_append(contact->addresses, addr); -} - -static void add_url(struct phonebook_contact *contact, const char *url_val, - int type) -{ - struct phonebook_field *url; - - if (url_val == NULL || strlen(url_val) == 0) - return; - - /* Not adding url if there is already added with the same value */ - if (find_field(contact->urls, url_val, type)) - return; - - url = g_new0(struct phonebook_field, 1); - - url->text = g_strdup(url_val); - url->type = type; - - contact->urls = g_slist_append(contact->urls, url); -} - -static GString *gen_vcards(GSList *contacts, - const struct apparam_field *params) -{ - GSList *l; - GString *vcards; - - vcards = g_string_new(NULL); - - /* Generating VCARD string from contacts and freeing used contacts */ - for (l = contacts; l; l = l->next) { - struct contact_data *c_data = l->data; - phonebook_add_contact(vcards, c_data->contact, - params->filter, params->format); - } - - return vcards; -} - -static int pull_contacts_size(const char **reply, int num_fields, - void *user_data) -{ - struct phonebook_data *data = user_data; - - if (num_fields < 0) { - data->cb(NULL, 0, num_fields, 0, TRUE, data->user_data); - return -EINTR; - } - - if (reply != NULL) { - data->index = atoi(reply[0]); - return 0; - } - - data->cb(NULL, 0, data->index, data->newmissedcalls, TRUE, - data->user_data); - - return 0; - /* - * phonebook_data is freed in phonebook_req_finalize. Useful in - * cases when call is terminated. - */ -} - -static void add_affiliation(char **field, const char *value) -{ - if (strlen(*field) > 0 || value == NULL || strlen(value) == 0) - return; - - g_free(*field); - - *field = g_strdup(value); -} - -static void contact_init(struct phonebook_contact *contact, - const char **reply) -{ - if (reply[COL_FAMILY_NAME][0] == '\0' && - reply[COL_GIVEN_NAME][0] == '\0' && - reply[COL_ADDITIONAL_NAME][0] == '\0' && - reply[COL_NAME_PREFIX][0] == '\0' && - reply[COL_NAME_SUFFIX][0] == '\0') { - if (reply[COL_FULL_NAME][0] != '\0') - contact->family = g_strdup(reply[COL_FULL_NAME]); - else - contact->family = g_strdup(reply[COL_NICKNAME]); - } else { - contact->family = g_strdup(reply[COL_FAMILY_NAME]); - contact->given = g_strdup(reply[COL_GIVEN_NAME]); - contact->additional = g_strdup(reply[COL_ADDITIONAL_NAME]); - contact->prefix = g_strdup(reply[COL_NAME_PREFIX]); - contact->suffix = g_strdup(reply[COL_NAME_SUFFIX]); - } - contact->fullname = g_strdup(reply[COL_FULL_NAME]); - contact->birthday = g_strdup(reply[COL_BIRTH_DATE]); - contact->nickname = g_strdup(reply[COL_NICKNAME]); - contact->photo = g_strdup(reply[COL_PHOTO]); - contact->company = g_strdup(reply[COL_ORG_NAME]); - contact->department = g_strdup(reply[COL_ORG_DEPARTMENT]); - contact->role = g_strdup(reply[COL_ORG_ROLE]); - contact->uid = g_strdup(reply[COL_UID]); - contact->title = g_strdup(reply[COL_TITLE]); - - set_call_type(contact, reply[COL_DATE], reply[COL_SENT], - reply[COL_ANSWERED]); -} - -static enum phonebook_number_type get_phone_type(const char *affilation) -{ - if (g_strcmp0(AFFILATION_HOME, affilation) == 0) - return TEL_TYPE_HOME; - else if (g_strcmp0(AFFILATION_WORK, affilation) == 0) - return TEL_TYPE_WORK; - - return TEL_TYPE_OTHER; -} - -static void add_aff_number(struct phonebook_contact *contact, - const char *pnumber, const char *aff_type) -{ - char **num_parts; - char *type, *number; - - /* For phone taken directly from contacts data, phone number string - * is represented as number type and number string - those strings are - * separated by SUB_DELIM string */ - num_parts = g_strsplit(pnumber, SUB_DELIM, 2); - - if (!num_parts) - return; - - if (num_parts[0]) - type = num_parts[0]; - else - goto failed; - - if (num_parts[1]) - number = num_parts[1]; - else - goto failed; - - if (g_strrstr(type, FAX_NUM_TYPE)) - add_phone_number(contact, number, TEL_TYPE_FAX); - else if (g_strrstr(type, MOBILE_NUM_TYPE)) - add_phone_number(contact, number, TEL_TYPE_MOBILE); - else - /* if this is no fax/mobile phone, then adding phone number - * type based on type of the affilation field */ - add_phone_number(contact, number, get_phone_type(aff_type)); - -failed: - g_strfreev(num_parts); -} - -static void contact_add_numbers(struct phonebook_contact *contact, - const char **reply) -{ - char **aff_numbers; - int i; - - /* Filling phone numbers from contact's affilation */ - aff_numbers = g_strsplit(reply[COL_PHONE_AFF], MAIN_DELIM, MAX_FIELDS); - - if (aff_numbers) - for (i = 0; aff_numbers[i]; ++i) - add_aff_number(contact, aff_numbers[i], - reply[COL_AFF_TYPE]); - - g_strfreev(aff_numbers); -} - -static enum phonebook_field_type get_field_type(const char *affilation) -{ - if (g_strcmp0(AFFILATION_HOME, affilation) == 0) - return FIELD_TYPE_HOME; - else if (g_strcmp0(AFFILATION_WORK, affilation) == 0) - return FIELD_TYPE_WORK; - - return FIELD_TYPE_OTHER; -} - -static void add_aff_field(struct phonebook_contact *contact, - const char *aff_email, add_field_t add_field_cb) -{ - char **email_parts; - char *type, *email; - - /* Emails from affilation data, are represented as real email - * string and affilation type - those strings are separated by - * SUB_DELIM string */ - email_parts = g_strsplit(aff_email, SUB_DELIM, 2); - - if (!email_parts) - return; - - if (email_parts[0]) - email = email_parts[0]; - else - goto failed; - - if (email_parts[1]) - type = email_parts[1]; - else - goto failed; - - add_field_cb(contact, email, get_field_type(type)); - -failed: - g_strfreev(email_parts); -} - -static void contact_add_emails(struct phonebook_contact *contact, - const char **reply) -{ - char **aff_emails; - int i; - - /* Emails from affilation */ - aff_emails = g_strsplit(reply[COL_EMAIL_AFF], MAIN_DELIM, MAX_FIELDS); - - if (aff_emails) - for (i = 0; aff_emails[i] != NULL; ++i) - add_aff_field(contact, aff_emails[i], add_email); - - g_strfreev(aff_emails); -} - -static void contact_add_addresses(struct phonebook_contact *contact, - const char **reply) -{ - char **aff_addr; - int i; - - /* Addresses from affilation */ - aff_addr = g_strsplit(reply[COL_ADDR_AFF], MAIN_DELIM, MAX_FIELDS); - - if (aff_addr) - for (i = 0; aff_addr[i] != NULL; ++i) - add_aff_field(contact, aff_addr[i], add_address); - - g_strfreev(aff_addr); -} - -static void contact_add_urls(struct phonebook_contact *contact, - const char **reply) -{ - char **aff_url; - int i; - - /* Addresses from affilation */ - aff_url = g_strsplit(reply[COL_URL], MAIN_DELIM, MAX_FIELDS); - - if (aff_url) - for (i = 0; aff_url[i] != NULL; ++i) - add_aff_field(contact, aff_url[i], add_url); - - g_strfreev(aff_url); -} - -static void contact_add_organization(struct phonebook_contact *contact, - const char **reply) -{ - /* Adding fields connected by nco:hasAffiliation - they may be in - * separate replies */ - add_affiliation(&contact->title, reply[COL_TITLE]); - add_affiliation(&contact->company, reply[COL_ORG_NAME]); - add_affiliation(&contact->department, reply[COL_ORG_DEPARTMENT]); - add_affiliation(&contact->role, reply[COL_ORG_ROLE]); -} - -static void free_data_contacts(struct phonebook_data *data) -{ - GSList *l; - - /* freeing contacts */ - for (l = data->contacts; l; l = l->next) { - struct contact_data *c_data = l->data; - - g_free(c_data->id); - phonebook_contact_free(c_data->contact); - g_free(c_data); - } - - g_slist_free(data->contacts); - data->contacts = NULL; -} - -static void send_pull_part(struct phonebook_data *data, - const struct apparam_field *params, gboolean lastpart) -{ - GString *vcards; - - DBG(""); - vcards = gen_vcards(data->contacts, params); - data->cb(vcards->str, vcards->len, g_slist_length(data->contacts), - data->newmissedcalls, lastpart, data->user_data); - - if (!lastpart) - free_data_contacts(data); - g_string_free(vcards, TRUE); -} - -static int pull_contacts(const char **reply, int num_fields, void *user_data) -{ - struct phonebook_data *data = user_data; - const struct apparam_field *params = data->params; - struct phonebook_contact *contact; - struct contact_data *contact_data; - int last_index, i; - gboolean cdata_present = FALSE, part_sent = FALSE; - static char *temp_id = NULL; - - if (num_fields < 0) { - data->cb(NULL, 0, num_fields, 0, TRUE, data->user_data); - goto fail; - } - - DBG("reply %p", reply); - data->tracker_index++; - - if (reply == NULL) - goto done; - - /* Trying to find contact in recently added contacts. It is needed for - * contacts that have more than one telephone number filled */ - contact = find_contact(data->contacts, reply[CONTACTS_ID_COL], - reply[COL_DATE]); - - /* If contact is already created then adding only new phone numbers */ - if (contact) { - cdata_present = TRUE; - goto add_numbers; - } - - /* We are doing a PullvCardEntry, no need for those checks */ - if (data->vcardentry) - goto add_entry; - - /* Last four fields are always present, ignoring them */ - for (i = 0; i < num_fields - 4; i++) { - if (reply[i][0] != '\0') - break; - } - - if (i == num_fields - 4 && !g_str_equal(reply[CONTACTS_ID_COL], - TRACKER_DEFAULT_CONTACT_ME)) - return 0; - - if (g_strcmp0(temp_id, reply[CONTACTS_ID_COL])) { - data->index++; - g_free(temp_id); - temp_id = g_strdup(reply[CONTACTS_ID_COL]); - - /* Incrementing counter for vcards in current part of data, - * but only if liststartoffset has been already reached */ - if (data->index > params->liststartoffset) - data->vcard_part_count++; - } - - if (data->vcard_part_count > VCARDS_PART_COUNT) { - DBG("Part of vcard data ready for sending..."); - data->vcard_part_count = 0; - /* Sending part of data to PBAP core - more data can be still - * fetched, so marking lastpart as FALSE */ - send_pull_part(data, params, FALSE); - - /* Later, after adding contact data, need to return -EINTR to - * stop fetching more data for this request. Data will be - * downloaded again from this point, when phonebook_pull_read - * will be called again with current request as a parameter*/ - part_sent = TRUE; - } - - last_index = params->liststartoffset + params->maxlistcount; - - if (data->index <= params->liststartoffset) - return 0; - - /* max number of results achieved - need send vcards data that was - * already collected and stop further data processing (these operations - * will be invoked in "done" section) */ - if (data->index > last_index && params->maxlistcount > 0) { - DBG("Maxlistcount achieved"); - goto done; - } - -add_entry: - contact = g_new0(struct phonebook_contact, 1); - contact_init(contact, reply); - -add_numbers: - contact_add_numbers(contact, reply); - contact_add_emails(contact, reply); - contact_add_addresses(contact, reply); - contact_add_urls(contact, reply); - contact_add_organization(contact, reply); - - DBG("contact %p", contact); - - /* Adding contacts data to wrapper struct - this data will be used to - * generate vcard list */ - if (!cdata_present) { - contact_data = g_new0(struct contact_data, 1); - contact_data->contact = contact; - contact_data->id = g_strdup(reply[CONTACTS_ID_COL]); - data->contacts = g_slist_append(data->contacts, contact_data); - } - - if (part_sent) - return -EINTR; - - return 0; - -done: - /* Processing is end, this is definitely last part of transmission - * (marking lastpart as TRUE) */ - send_pull_part(data, params, TRUE); - -fail: - g_free(temp_id); - temp_id = NULL; - - return -EINTR; - /* - * phonebook_data is freed in phonebook_req_finalize. Useful in - * cases when call is terminated. - */ -} - -static int add_to_cache(const char **reply, int num_fields, void *user_data) -{ - struct phonebook_data *data = user_data; - char *formatted; - int i; - - if (reply == NULL || num_fields < 0) - goto done; - - /* the first element is the URI, always not empty */ - for (i = 1; i < num_fields; i++) { - if (reply[i][0] != '\0') - break; - } - - if (i == num_fields && - !g_str_equal(reply[0], TRACKER_DEFAULT_CONTACT_ME)) - return 0; - - if (i == 7) - formatted = g_strdup(reply[7]); - else if (i == 6) - formatted = g_strdup(reply[6]); - else - formatted = g_strdup_printf("%s;%s;%s;%s;%s", - reply[1], reply[2], reply[3], reply[4], - reply[5]); - - /* The owner vCard must have the 0 handle */ - if (strcmp(reply[0], TRACKER_DEFAULT_CONTACT_ME) == 0) - data->entry_cb(reply[0], 0, formatted, "", - reply[6], data->user_data); - else - data->entry_cb(reply[0], PHONEBOOK_INVALID_HANDLE, formatted, - "", reply[6], data->user_data); - - g_free(formatted); - - return 0; - -done: - if (num_fields <= 0) - data->ready_cb(data->user_data); - - return -EINTR; - /* - * phonebook_data is freed in phonebook_req_finalize. Useful in - * cases when call is terminated. - */ -} - -int phonebook_init(void) -{ - g_thread_init(NULL); - g_type_init(); - - return 0; -} - -void phonebook_exit(void) -{ -} - -char *phonebook_set_folder(const char *current_folder, const char *new_folder, - uint8_t flags, int *err) -{ - char *tmp1, *tmp2, *base, *path = NULL; - gboolean root, child; - int ret = 0; - int len; - - root = (g_strcmp0("/", current_folder) == 0); - child = (new_folder && strlen(new_folder) != 0); - - switch (flags) { - case 0x02: - /* Go back to root */ - if (!child) { - path = g_strdup("/"); - goto done; - } - - path = g_build_filename(current_folder, new_folder, NULL); - break; - case 0x03: - /* Go up 1 level */ - if (root) { - /* Already root */ - path = g_strdup("/"); - goto done; - } - - /* - * Removing one level of the current folder. Current folder - * contains AT LEAST one level since it is not at root folder. - * Use glib utility functions to handle invalid chars in the - * folder path properly. - */ - tmp1 = g_path_get_basename(current_folder); - tmp2 = g_strrstr(current_folder, tmp1); - len = tmp2 - (current_folder + 1); - - g_free(tmp1); - - if (len == 0) - base = g_strdup("/"); - else - base = g_strndup(current_folder, len); - - /* Return: one level only */ - if (!child) { - path = base; - goto done; - } - - path = g_build_filename(base, new_folder, NULL); - g_free(base); - - break; - default: - ret = -EBADR; - break; - } - -done: - if (path && !folder_is_valid(path)) - ret = -ENOENT; - - if (ret < 0) { - g_free(path); - path = NULL; - } - - if (err) - *err = ret; - - return path; -} - -static int pull_newmissedcalls(const char **reply, int num_fields, - void *user_data) -{ - struct phonebook_data *data = user_data; - reply_list_foreach_t pull_cb; - int col_amount, err; - const char *query; - int nmissed; - - if (num_fields < 0) { - data->cb(NULL, 0, num_fields, 0, TRUE, data->user_data); - - return -EINTR; - } - - if (reply != NULL) { - nmissed = atoi(reply[0]); - data->newmissedcalls = - nmissed <= UINT8_MAX ? nmissed : UINT8_MAX; - DBG("newmissedcalls %d", data->newmissedcalls); - - return 0; - } - - if (data->params->maxlistcount == 0) { - query = name2count_query(PB_CALLS_MISSED); - col_amount = COUNT_QUERY_COL_AMOUNT; - pull_cb = pull_contacts_size; - } else { - query = name2query(PB_CALLS_MISSED); - col_amount = PULL_QUERY_COL_AMOUNT; - pull_cb = pull_contacts; - } - - err = query_tracker(query, col_amount, pull_cb, data); - if (err < 0) { - data->cb(NULL, 0, err, 0, TRUE, data->user_data); - - return -EINTR; - } - - return 0; -} - -void phonebook_req_finalize(void *request) -{ - struct phonebook_data *data = request; - - DBG(""); - - if (!data) - return; - - /* canceling asynchronous operation on tracker if any is active */ - if (data->query_canc) { - g_cancellable_cancel(data->query_canc); - g_object_unref(data->query_canc); - } - - free_data_contacts(data); - g_free(data->req_name); - g_free(data); -} - -void *phonebook_pull(const char *name, const struct apparam_field *params, - phonebook_cb cb, void *user_data, int *err) -{ - struct phonebook_data *data; - - DBG("name %s", name); - - data = g_new0(struct phonebook_data, 1); - data->params = params; - data->user_data = user_data; - data->cb = cb; - data->req_name = g_strdup(name); - - if (err) - *err = 0; - - return data; -} - -int phonebook_pull_read(void *request) -{ - struct phonebook_data *data = request; - reply_list_foreach_t pull_cb; - const char *query; - char *offset_query; - int col_amount; - int ret; - - if (!data) - return -ENOENT; - - data->newmissedcalls = 0; - - if (g_strcmp0(data->req_name, PB_CALLS_MISSED) == 0 && - data->tracker_index == 0) { - /* new missed calls amount should be counted only once - it - * will be done during generating first part of results of - * missed calls history */ - query = NEW_MISSED_CALLS_COUNT_QUERY; - col_amount = COUNT_QUERY_COL_AMOUNT; - pull_cb = pull_newmissedcalls; - } else if (data->params->maxlistcount == 0) { - query = name2count_query(data->req_name); - col_amount = COUNT_QUERY_COL_AMOUNT; - pull_cb = pull_contacts_size; - } else { - query = name2query(data->req_name); - col_amount = PULL_QUERY_COL_AMOUNT; - pull_cb = pull_contacts; - } - - if (query == NULL) - return -ENOENT; - - if (pull_cb == pull_contacts && data->tracker_index > 0) { - /* Adding offset to pull query to download next parts of data - * from tracker (phonebook_pull_read may be called many times - * from PBAP core to fetch data partially) */ - offset_query = g_strdup_printf(QUERY_OFFSET_FORMAT, query, - data->tracker_index); - ret = query_tracker(offset_query, col_amount, pull_cb, data); - - g_free(offset_query); - - return ret; - } - - return query_tracker(query, col_amount, pull_cb, data); -} - -void *phonebook_get_entry(const char *folder, const char *id, - const struct apparam_field *params, - phonebook_cb cb, void *user_data, int *err) -{ - struct phonebook_data *data; - char *query; - int ret; - - DBG("folder %s id %s", folder, id); - - data = g_new0(struct phonebook_data, 1); - data->user_data = user_data; - data->params = params; - data->cb = cb; - data->vcardentry = TRUE; - - if (g_str_has_prefix(id, CONTACT_ID_PREFIX) == TRUE || - g_strcmp0(id, TRACKER_DEFAULT_CONTACT_ME) == 0) - query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id, - id, id, id, id, id, id, id, id, id); - else if (g_str_has_prefix(id, CALL_ID_PREFIX) == TRUE) - query = g_strdup_printf(CONTACT_FROM_CALL_QUERY, id); - else - query = g_strdup_printf(CONTACTS_OTHER_QUERY_FROM_URI, - id, id, id); - - ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data); - if (err) - *err = ret; - - g_free(query); - - return data; -} - -void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb, - phonebook_cache_ready_cb ready_cb, void *user_data, int *err) -{ - struct phonebook_data *data; - const char *query; - int ret; - - DBG("name %s", name); - - query = folder2query(name); - if (query == NULL) { - if (err) - *err = -ENOENT; - return NULL; - } - - data = g_new0(struct phonebook_data, 1); - data->entry_cb = entry_cb; - data->ready_cb = ready_cb; - data->user_data = user_data; - - ret = query_tracker(query, 8, add_to_cache, data); - if (err) - *err = ret; - - return data; -} diff --git a/obexd/plugins/syncevolution.c b/obexd/plugins/syncevolution.c deleted file mode 100644 index edc00c84..00000000 --- a/obexd/plugins/syncevolution.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * - * OBEX Server - * - * Copyright (C) 2007-2010 Intel Corporation - * Copyright (C) 2007-2010 Marcel Holtmann - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include "plugin.h" -#include "obex.h" -#include "service.h" -#include "mimetype.h" -#include "log.h" -#include "manager.h" -#include "obexd.h" -#include "filesystem.h" - -#define SYNCML_TARGET_SIZE 11 - -static const uint8_t SYNCML_TARGET[SYNCML_TARGET_SIZE] = { - 0x53, 0x59, 0x4E, 0x43, 0x4D, 0x4C, 0x2D, 0x53, - 0x59, 0x4E, 0x43 }; - -#define SYNCEVOLUTION_CHANNEL 19 - -#define SYNCEVOLUTION_RECORD "\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -" - -#define SYNCE_BUS_NAME "org.syncevolution" -#define SYNCE_PATH "/org/syncevolution/Server" -#define SYNCE_SERVER_INTERFACE "org.syncevolution.Server" -#define SYNCE_CONN_INTERFACE "org.syncevolution.Connection" - -struct synce_context { - struct obex_session *os; - DBusConnection *dbus_conn; - char *conn_obj; - unsigned int reply_watch; - unsigned int abort_watch; - GString *buffer; - int lasterr; - char *id; -}; - -static void append_dict_entry(DBusMessageIter *dict, const char *key, - int type, void *val) -{ - DBusMessageIter entry; - - dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, - NULL, &entry); - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val); - dbus_message_iter_close_container(dict, &entry); -} - -static gboolean reply_signal(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct synce_context *context = data; - const char *path = dbus_message_get_path(msg); - DBusMessageIter iter, array_iter; - char *value; - int length; - - if (strcmp(context->conn_obj, path) != 0) { - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; - return FALSE; - } - - dbus_message_iter_init(msg, &iter); - - dbus_message_iter_recurse(&iter, &array_iter); - dbus_message_iter_get_fixed_array(&array_iter, &value, &length); - - context->buffer = g_string_new_len(value, length); - obex_object_set_io_flags(context, G_IO_IN, 0); - context->lasterr = 0; - - return TRUE; -} - -static gboolean abort_signal(DBusConnection *conn, DBusMessage *msg, - void *data) -{ - struct synce_context *context = data; - - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; - - return TRUE; -} - -static void connect_cb(DBusPendingCall *call, void *user_data) -{ - struct synce_context *context = user_data; - DBusConnection *conn; - DBusMessage *reply; - DBusError err; - char *path; - - conn = context->dbus_conn; - - reply = dbus_pending_call_steal_reply(call); - - dbus_error_init(&err); - if (dbus_message_get_args(reply, &err, DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_INVALID) == FALSE) { - error("%s", err.message); - dbus_error_free(&err); - goto failed; - } - - DBG("Got conn object %s from syncevolution", path); - context->conn_obj = g_strdup(path); - - context->reply_watch = g_dbus_add_signal_watch(conn, NULL, path, - SYNCE_CONN_INTERFACE, "Reply", - reply_signal, context, NULL); - - context->abort_watch = g_dbus_add_signal_watch(conn, NULL, path, - SYNCE_CONN_INTERFACE, "Abort", - abort_signal, context, NULL); - - dbus_message_unref(reply); - - return; - -failed: - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; -} - -static void process_cb(DBusPendingCall *call, void *user_data) -{ - struct synce_context *context = user_data; - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("process_cb(): syncevolution replied with an error:" - " %s, %s", derr.name, derr.message); - dbus_error_free(&derr); - - obex_object_set_io_flags(context, G_IO_ERR, -EPERM); - context->lasterr = -EPERM; - goto done; - } - - obex_object_set_io_flags(context, G_IO_OUT, 0); - context->lasterr = 0; - -done: - dbus_message_unref(reply); -} - -static void *synce_connect(struct obex_session *os, int *err) -{ - DBusConnection *conn; - struct synce_context *context; - char *address; - - manager_register_session(os); - - conn = manager_dbus_get_connection(); - if (!conn) - goto failed; - - context = g_new0(struct synce_context, 1); - context->dbus_conn = conn; - context->lasterr = -EAGAIN; - context->os = os; - - if (obex_getpeername(os, &address) == 0) { - context->id = g_strdup_printf("%s+%d", address, - SYNCEVOLUTION_CHANNEL); - g_free(address); - } - - if (err) - *err = 0; - - return context; - -failed: - if (err) - *err = -EPERM; - - return NULL; -} - -static int synce_put(struct obex_session *os, void *user_data) -{ - return 0; -} - -static int synce_get(struct obex_session *os, void *user_data) -{ - return obex_get_stream_start(os, NULL); -} - -static void close_cb(DBusPendingCall *call, void *user_data) -{ - DBusMessage *reply; - DBusError derr; - - reply = dbus_pending_call_steal_reply(call); - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - error("close_cb(): syncevolution replied with an error:" - " %s, %s", derr.name, derr.message); - dbus_error_free(&derr); - } - - dbus_message_unref(reply); -} - -static void synce_disconnect(struct obex_session *os, void *user_data) -{ - struct synce_context *context = user_data; - - g_free(context); -} - -static void *synce_open(const char *name, int oflag, mode_t mode, - void *user_data, size_t *size, int *err) -{ - struct synce_context *context = user_data; - - if (err) - *err = context ? 0 : -EFAULT; - - return user_data; -} - -static int synce_close(void *object) -{ - struct synce_context *context = object; - DBusMessage *msg; - const char *error; - gboolean normal; - DBusPendingCall *call; - - if (!context->conn_obj) - goto done; - - msg = dbus_message_new_method_call(SYNCE_BUS_NAME, context->conn_obj, - SYNCE_CONN_INTERFACE, "Close"); - if (!msg) - goto failed; - - normal = TRUE; - error = "none"; - dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &normal, - DBUS_TYPE_STRING, &error, DBUS_TYPE_INVALID); - - g_dbus_send_message_with_reply(context->dbus_conn, msg, &call, -1); - dbus_pending_call_set_notify(call, close_cb, NULL, NULL); - dbus_message_unref(msg); - dbus_pending_call_unref(call); - -failed: - g_dbus_remove_watch(context->dbus_conn, context->reply_watch); - context->reply_watch = 0; - g_dbus_remove_watch(context->dbus_conn, context->abort_watch); - context->abort_watch = 0; - - g_free(context->conn_obj); - context->conn_obj = NULL; - -done: - dbus_connection_unref(context->dbus_conn); - g_free(context); - return 0; -} - -static ssize_t synce_read(void *object, void *buf, size_t count) -{ - struct synce_context *context = object; - DBusConnection *conn; - char transport[36], transport_description[24]; - const char *session; - DBusMessage *msg; - DBusMessageIter iter, dict; - gboolean authenticate; - DBusPendingCall *call; - - if (context->buffer) - return string_read(context->buffer, buf, count); - - conn = manager_dbus_get_connection(); - if (conn == NULL) - return -EPERM; - - msg = dbus_message_new_method_call(SYNCE_BUS_NAME, SYNCE_PATH, - SYNCE_SERVER_INTERFACE, "Connect"); - if (!msg) - return -EPERM; - - dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING - DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING - DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); - - append_dict_entry(&dict, "id", DBUS_TYPE_STRING, context->id); - - snprintf(transport, sizeof(transport), "%s.obexd", OBEXD_SERVICE); - append_dict_entry(&dict, "transport", DBUS_TYPE_STRING, transport); - - snprintf(transport_description, sizeof(transport_description), - "version %s", VERSION); - append_dict_entry(&dict, "transport_description", DBUS_TYPE_STRING, - transport_description); - - dbus_message_iter_close_container(&iter, &dict); - - authenticate = FALSE; - session = ""; - dbus_message_append_args(msg, DBUS_TYPE_BOOLEAN, &authenticate, - DBUS_TYPE_STRING, &session, DBUS_TYPE_INVALID); - - if (!g_dbus_send_message_with_reply(conn, msg, &call, -1)) { - error("D-Bus call to %s failed.", SYNCE_SERVER_INTERFACE); - dbus_message_unref(msg); - return -EPERM; - } - - dbus_pending_call_set_notify(call, connect_cb, context, NULL); - - dbus_pending_call_unref(call); - dbus_message_unref(msg); - - return -EAGAIN; -} - -static ssize_t synce_write(void *object, const void *buf, size_t count) -{ - struct synce_context *context = object; - DBusMessage *msg; - DBusMessageIter iter, array_iter; - DBusPendingCall *call; - const char *type = obex_get_type(context->os); - - if (context->lasterr == 0) - return count; - - if (!context->conn_obj) - return -EFAULT; - - msg = dbus_message_new_method_call(SYNCE_BUS_NAME, context->conn_obj, - SYNCE_CONN_INTERFACE, "Process"); - if (!msg) - return -EFAULT; - - dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_BYTE_AS_STRING, &array_iter); - - dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, - &buf, count); - dbus_message_iter_close_container(&iter, &array_iter); - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &type, - DBUS_TYPE_INVALID); - - if (!g_dbus_send_message_with_reply(context->dbus_conn, msg, - &call, -1)) { - error("D-Bus call to %s failed.", SYNCE_CONN_INTERFACE); - dbus_message_unref(msg); - return -EPERM; - } - - dbus_pending_call_set_notify(call, process_cb, context, NULL); - - dbus_message_unref(msg); - dbus_pending_call_unref(call); - - return -EAGAIN; -} - -static struct obex_mime_type_driver synce_driver = { - .target = SYNCML_TARGET, - .target_size = SYNCML_TARGET_SIZE, - .open = synce_open, - .close = synce_close, - .read = synce_read, - .write = synce_write, -}; - -static struct obex_service_driver synce = { - .name = "OBEX server for SyncML, using SyncEvolution", - .service = OBEX_SYNCEVOLUTION, - .channel = SYNCEVOLUTION_CHANNEL, - .secure = TRUE, - .record = SYNCEVOLUTION_RECORD, - .target = SYNCML_TARGET, - .target_size = SYNCML_TARGET_SIZE, - .get = synce_get, - .put = synce_put, - .connect = synce_connect, - .disconnect = synce_disconnect, -}; - -static int synce_init(void) -{ - int err; - - err = obex_mime_type_driver_register(&synce_driver); - if (err < 0) - return err; - - return obex_service_driver_register(&synce); -} - -static void synce_exit(void) -{ - obex_service_driver_unregister(&synce); - obex_mime_type_driver_unregister(&synce_driver); -} - -OBEX_PLUGIN_DEFINE(syncevolution, synce_init, synce_exit) diff --git a/packaging/bluetooth.sh b/packaging/bluetooth.sh old mode 100644 new mode 100755 diff --git a/packaging/bluez.spec b/packaging/bluez.spec index e5592f35..0395ca5f 100644 --- a/packaging/bluez.spec +++ b/packaging/bluez.spec @@ -20,7 +20,7 @@ BuildRequires: udev BuildRequires: pkgconfig(libnl-1) BuildRequires: libical-devel Url: http://www.bluez.org -Version: 5.9 +Version: 5.10 Release: 0 Summary: Bluetooth Stack for Linux License: GPL-2.0+ diff --git a/packaging/create-symlinks b/packaging/create-symlinks old mode 100644 new mode 100755 diff --git a/packaging/obex-root-setup b/packaging/obex-root-setup old mode 100644 new mode 100755 diff --git a/profiles/audio/1.patch b/profiles/audio/1.patch deleted file mode 100644 index fa44d323..00000000 --- a/profiles/audio/1.patch +++ /dev/null @@ -1,108 +0,0 @@ -commit e6e654d70e07b9cb2bf0237787725a294aa791cb -Author: Luiz Augusto von Dentz -Date: Thu Mar 7 11:41:22 2013 +0200 - - audio: Remove profile enabling/disabling logic - - This should be handle by the core for all profiles - -diff --git a/profiles/audio/audio.conf b/profiles/audio/audio.conf -index f556610..067b3fc 100644 ---- a/profiles/audio/audio.conf -+++ b/profiles/audio/audio.conf -@@ -6,7 +6,3 @@ - - # Switch to master role for incoming connections (defaults to true) - #Master=true -- --# If we want to disable support for specific services --# Defaults to supporting the services: Sink, Control --#Disable=Source -diff --git a/profiles/audio/manager.c b/profiles/audio/manager.c -index 934227e..42a2b58 100644 ---- a/profiles/audio/manager.c -+++ b/profiles/audio/manager.c -@@ -70,12 +70,6 @@ - static GKeyFile *config = NULL; - static GSList *devices = NULL; - --static struct enabled_interfaces enabled = { -- .sink = TRUE, -- .source = FALSE, -- .control = TRUE, --}; -- - static struct audio_device *get_audio_dev(struct btd_device *device) - { - return manager_get_audio_device(device, TRUE); -@@ -410,47 +404,12 @@ void audio_control_disconnected(struct btd_device *dev, int err) - - int audio_manager_init(GKeyFile *conf) - { -- char **list; -- int i; -- -- if (!conf) -- goto proceed; -- -- config = conf; -- -- list = g_key_file_get_string_list(config, "General", "Enable", -- NULL, NULL); -- for (i = 0; list && list[i] != NULL; i++) { -- if (g_str_equal(list[i], "Sink")) -- enabled.sink = TRUE; -- else if (g_str_equal(list[i], "Source")) -- enabled.source = TRUE; -- else if (g_str_equal(list[i], "Control")) -- enabled.control = TRUE; -- } -- g_strfreev(list); -+ if (conf) -+ config = conf; - -- list = g_key_file_get_string_list(config, "General", "Disable", -- NULL, NULL); -- for (i = 0; list && list[i] != NULL; i++) { -- if (g_str_equal(list[i], "Sink")) -- enabled.sink = FALSE; -- else if (g_str_equal(list[i], "Source")) -- enabled.source = FALSE; -- else if (g_str_equal(list[i], "Control")) -- enabled.control = FALSE; -- } -- g_strfreev(list); -- --proceed: -- if (enabled.source) -- btd_profile_register(&a2dp_source_profile); -- -- if (enabled.sink) -- btd_profile_register(&a2dp_sink_profile); -- -- if (enabled.control) -- btd_profile_register(&avrcp_profile); -+ btd_profile_register(&a2dp_source_profile); -+ btd_profile_register(&a2dp_sink_profile); -+ btd_profile_register(&avrcp_profile); - - btd_register_adapter_driver(&media_driver); - -@@ -464,14 +423,9 @@ void audio_manager_exit(void) - config = NULL; - } - -- if (enabled.source) -- btd_profile_unregister(&a2dp_source_profile); -- -- if (enabled.sink) -- btd_profile_unregister(&a2dp_sink_profile); -- -- if (enabled.control) -- btd_profile_unregister(&avrcp_profile); -+ btd_profile_unregister(&a2dp_source_profile); -+ btd_profile_unregister(&a2dp_sink_profile); -+ btd_profile_unregister(&avrcp_profile); - - btd_unregister_adapter_driver(&media_driver); - } diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c index 845027f9..dac7a66c 100644 --- a/profiles/audio/avctp.c +++ b/profiles/audio/avctp.c @@ -1480,7 +1480,28 @@ static struct avctp_pending_req *pending_create(struct avctp_channel *chan, GDestroyNotify destroy) { struct avctp_pending_req *p; + GSList *l, *tmp; + if (!chan->processed) + goto done; + + tmp = g_slist_copy(chan->processed); + + /* Find first unused transaction id */ + for (l = tmp; l; l = l->next) { + struct avctp_pending_req *req = l->data; + + if (req->transaction == chan->transaction) { + chan->transaction++; + chan->transaction %= 16; + tmp = g_slist_delete_link(tmp, l); + l = tmp; + } + } + + g_slist_free(tmp); + +done: p = g_new0(struct avctp_pending_req, 1); p->chan = chan; p->transaction = chan->transaction; diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index 622dff81..dab8f1c8 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -354,6 +354,12 @@ struct avdtp_state_callback { void *user_data; }; +struct discover_callback { + unsigned int id; + avdtp_discover_cb_t cb; + void *user_data; +}; + struct avdtp_stream { GIOChannel *io; uint16_t imtu; @@ -412,9 +418,7 @@ struct avdtp { char *buf; - avdtp_discover_cb_t discov_cb; - void *user_data; - + struct discover_callback *discover; struct pending_req *req; guint dc_timer; @@ -1041,19 +1045,21 @@ static void avdtp_sep_set_state(struct avdtp *session, static void finalize_discovery(struct avdtp *session, int err) { + struct discover_callback *discover = session->discover; struct avdtp_error avdtp_err; - avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err); - - if (!session->discov_cb) + if (!discover) return; - session->discov_cb(session, session->seps, - err ? &avdtp_err : NULL, - session->user_data); + avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err); + + if (discover->id > 0) + g_source_remove(discover->id); - session->discov_cb = NULL; - session->user_data = NULL; + discover->cb(session, session->seps, err ? &avdtp_err : NULL, + discover->user_data); + g_free(discover); + session->discover = NULL; } static void release_stream(struct avdtp_stream *stream, struct avdtp *session) @@ -3322,6 +3328,8 @@ static gboolean process_discover(gpointer data) { struct avdtp *session = data; + session->discover->id = 0; + finalize_discovery(session, 0); return FALSE; @@ -3332,20 +3340,22 @@ int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb, { int err; - if (session->discov_cb) + if (session->discover) return -EBUSY; + session->discover = g_new0(struct discover_callback, 1); + if (session->seps) { - session->discov_cb = cb; - session->user_data = user_data; - g_idle_add(process_discover, session); + session->discover->cb = cb; + session->discover->user_data = user_data; + session->discover->id = g_idle_add(process_discover, session); return 0; } err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0); if (err == 0) { - session->discov_cb = cb; - session->user_data = user_data; + session->discover->cb = cb; + session->discover->user_data = user_data; } return err; diff --git a/profiles/audio/media.c b/profiles/audio/media.c index 9c72b8dc..5edd3dee 100644 --- a/profiles/audio/media.c +++ b/profiles/audio/media.c @@ -95,7 +95,7 @@ struct media_player { GHashTable *track; /* Player current track */ guint watch; guint properties_watch; - guint track_watch; + guint seek_watch; char *status; uint32_t position; uint32_t duration; @@ -948,7 +948,7 @@ static void media_player_free(gpointer data) g_dbus_remove_watch(conn, mp->watch); g_dbus_remove_watch(conn, mp->properties_watch); - g_dbus_remove_watch(conn, mp->track_watch); + g_dbus_remove_watch(conn, mp->seek_watch); if (mp->track) g_hash_table_unref(mp->track); @@ -1304,13 +1304,21 @@ static gboolean set_status(struct media_player *mp, DBusMessageIter *iter) static gboolean set_position(struct media_player *mp, DBusMessageIter *iter) { uint64_t value; + const char *status; if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INT64) return FALSE; dbus_message_iter_get_basic(iter, &value); - mp->position = value / 1000; + value /= 1000; + + if (value > get_position(mp)) + status = "forward-seek"; + else + status = "reverse-seek"; + + mp->position = value; g_timer_start(mp->timer); DBG("Position=%u", mp->position); @@ -1325,9 +1333,14 @@ static gboolean set_position(struct media_player *mp, DBusMessageIter *iter) * If position is the maximum value allowed or greater than track's * duration, we send a track-reached-end event. */ - if (mp->position == UINT32_MAX || mp->position >= mp->duration) + if (mp->position == UINT32_MAX || mp->position >= mp->duration) { avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_END, NULL); + return TRUE; + } + + /* Send a status change to force resync the position */ + avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, status); return TRUE; } @@ -1681,6 +1694,21 @@ static gboolean properties_changed(DBusConnection *connection, DBusMessage *msg, return TRUE; } +static gboolean position_changed(DBusConnection *connection, DBusMessage *msg, + void *user_data) +{ + struct media_player *mp = user_data; + DBusMessageIter iter; + + DBG("sender=%s path=%s", mp->sender, mp->path); + + dbus_message_iter_init(msg, &iter); + + set_position(mp, &iter); + + return TRUE; +} + static struct media_player *media_player_create(struct media_adapter *adapter, const char *sender, const char *path, @@ -1702,6 +1730,10 @@ static struct media_player *media_player_create(struct media_adapter *adapter, path, MEDIA_PLAYER_INTERFACE, properties_changed, mp, NULL); + mp->seek_watch = g_dbus_add_signal_watch(conn, sender, + path, MEDIA_PLAYER_INTERFACE, + "Seeked", position_changed, + mp, NULL); mp->player = avrcp_register_player(adapter->btd_adapter, &player_cb, mp, media_player_free); if (!mp->player) { diff --git a/test/exchange-business-cards b/test/exchange-business-cards deleted file mode 100755 index 6805cf71..00000000 --- a/test/exchange-business-cards +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python - -import sys -import dbus - -bus = dbus.SessionBus() -client = dbus.Interface(bus.get_object("org.bluez.obex", "/org/bluez/obex"), - "org.bluez.obex.Client") - -if (len(sys.argv) < 4): - print "Usage: %s " % (sys.argv[0]) - sys.exit(1) - -print "Creating Session" -path = client.CreateSession(sys.argv[1], { "Target": "OPP" }) -opp = dbus.Interface(bus.get_object("org.bluez.obex", path), - "org.bluez.obex.ObjectPush") - -opp.ExchangeBusinessCards(sys.argv[2], sys.argv[3]) diff --git a/test/ftp-client b/test/ftp-client deleted file mode 100755 index ae3cbcb9..00000000 --- a/test/ftp-client +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/python - -from __future__ import absolute_import, print_function, unicode_literals - -import gobject - -import sys -import dbus -import dbus.service -import dbus.mainloop.glib -import os.path -from optparse import OptionParser - -BUS_NAME='org.bluez.obex' -PATH = '/org/bluez/obex' -CLIENT_INTERFACE='org.bluez.obex.Client1' -SESSION_INTERFACE='org.bluez.obex.Session1' -FILE_TRASNFER_INTERFACE='org.bluez.obex.FileTransfer1' -TRANSFER_INTERFACE='org.bluez.obex.Transfer1' - -def parse_options(): - parser.add_option("-d", "--device", dest="device", - help="Device to connect", metavar="DEVICE") - parser.add_option("-c", "--chdir", dest="new_dir", - help="Change current directory to DIR", metavar="DIR") - parser.add_option("-l", "--list", action="store_true", dest="list_dir", - help="List the current directory") - parser.add_option("-g", "--get", dest="get_file", - help="Get FILE", metavar="FILE") - parser.add_option("-p", "--put", dest="put_file", - help="Put FILE", metavar="FILE") - parser.add_option("-y", "--copy", dest="copy_file", - help="Copy FILE", metavar="FILE") - parser.add_option("-m", "--move", dest="move_file", - help="Move FILE", metavar="FILE") - parser.add_option("-n", "--destname", dest="dest_file", - help="Destination FILE", metavar="FILE") - parser.add_option("-r", "--remove", dest="remove_file", - help="Remove FILE", metavar="FILE") - parser.add_option("-v", "--verbose", action="store_true", - dest="verbose") - - return parser.parse_args() - -class FtpClient: - def __init__(self, session_path, verbose=False): - self.transferred = 0 - self.transfer_path = None - self.transfer_size = 0 - self.verbose = verbose - bus = dbus.SessionBus() - obj = bus.get_object(BUS_NAME, session_path) - self.session = dbus.Interface(obj, SESSION_INTERFACE) - self.ftp = dbus.Interface(obj, FILE_TRASNFER_INTERFACE) - bus.add_signal_receiver(self.properties_changed, - dbus_interface="org.freedesktop.DBus.Properties", - signal_name="PropertiesChanged", - path_keyword="path") - - def create_transfer_reply(self, path, properties): - self.transfer_path = path - self.transfer_size = properties["Size"] - if self.verbose: - print("Transfer created: %s" % path) - - def generic_reply(self): - if self.verbose: - print("Operation succeeded") - - def error(self, err): - print(err) - mainloop.quit() - - def properties_changed(self, interface, properties, invalidated, path): - if path != self.transfer_path: - return - - if properties['Status'] == 'complete' or \ - properties['Status'] == 'error': - if self.verbose: - print("Transfer %s" % properties['Status']) - mainloop.quit() - return - - if properties["Transferred"] == None: - return - - speed = (value - self.transferred) / 1000 - print("Transfer progress %d/%d at %d kBps" % (value, - self.transfer_size, - speed)) - self.transferred = value - - def change_folder(self, new_dir): - for node in new_dir.split("/"): - self.ftp.ChangeFolder(node) - - def list_folder(self): - for i in self.ftp.ListFolder(): - if i["Type"] == "folder": - print("%s/" % (i["Name"])) - else: - print("%s" % (i["Name"])) - - def put_file(self, filename): - self.ftp.PutFile(os.path.abspath(filename), - os.path.basename(filename), - reply_handler=self.create_transfer_reply, - error_handler=self.error) - - def get_file(self, filename): - self.ftp.GetFile(os.path.abspath(filename), - os.path.basename(filename), - reply_handler=self.create_transfer_reply, - error_handler=self.error) - - def remove_file(self, filename): - self.ftp.Delete(filename, - reply_handler=self.generic_reply, - error_handler=self.error) - - def move_file(self, filename, destname): - self.ftp.MoveFile(filename, destname, - reply_handler=self.generic_reply, - error_handler=self.error) - - def copy_file(self, filename, destname): - self.ftp.CopyFile(filename, destname, - reply_handler=self.generic_reply, - error_handler=self.error) - -if __name__ == '__main__': - - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - parser = OptionParser() - - (options, args) = parse_options() - - if not options.device: - parser.print_help() - sys.exit(0) - - bus = dbus.SessionBus() - mainloop = gobject.MainLoop() - - client = dbus.Interface(bus.get_object(BUS_NAME, PATH,), - CLIENT_INTERFACE) - - print("Creating Session") - path = client.CreateSession(options.device, { "Target": "ftp" }) - - ftp_client = FtpClient(path, options.verbose) - - if options.new_dir: - ftp_client.change_folder(options.new_dir) - - if options.list_dir: - ftp_client.list_folder() - - if options.get_file: - ftp_client.get_file(options.get_file) - - if options.put_file: - ftp_client.put_file(options.put_file) - - if options.move_file: - ftp_client.move_file(options.move_file, options.dest_file) - - if options.copy_file: - ftp_client.copy_file(options.copy_file, options.dest_file) - - if options.remove_file: - ftp_client.remove_file(options.remove_file) - - mainloop.run() diff --git a/test/get-managed-objects b/test/get-managed-objects deleted file mode 100755 index 3156f658..00000000 --- a/test/get-managed-objects +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/python - -from __future__ import absolute_import, print_function, unicode_literals - -import dbus - -bus = dbus.SystemBus() - -manager = dbus.Interface(bus.get_object("org.bluez", "/"), - "org.freedesktop.DBus.ObjectManager") - -objects = manager.GetManagedObjects() - -for path in objects.keys(): - print("[ %s ]" % (path)) - - interfaces = objects[path] - - for interface in interfaces.keys(): - if interface in ["org.freedesktop.DBus.Introspectable", - "org.freedesktop.DBus.Properties"]: - continue - - print(" %s" % (interface)) - - properties = interfaces[interface] - - for key in properties.keys(): - print(" %s = %s" % (key, properties[key])) diff --git a/test/get-obex-capabilities b/test/get-obex-capabilities deleted file mode 100755 index e8afbad2..00000000 --- a/test/get-obex-capabilities +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python - -import sys -import dbus - -bus = dbus.SessionBus() -client = dbus.Interface(bus.get_object("org.bluez.obex", "/org/bluez/obex"), - "org.bluez.obex.Client") - -if (len(sys.argv) < 3): - print "Usage: %s " % (sys.argv[0]) - sys.exit(1) - -print "Creating Session" -session_path = client.CreateSession(sys.argv[1], { "Target": sys.argv[2] }) -session = dbus.Interface(bus.get_object("org.bluez.obex", session_path), - "org.bluez.obex.Session") - -print session.GetCapabilities() diff --git a/test/list-folders b/test/list-folders deleted file mode 100755 index 7321a152..00000000 --- a/test/list-folders +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/python - -import sys -import dbus - - -def list_folder(folder): - bus = dbus.SessionBus() - client = dbus.Interface(bus.get_object("org.bluez.obex", - "/org/bluez/obex"), - "org.bluez.obex.Client") - - path = client.CreateSession(sys.argv[1], { "Target": "ftp" }) - - ftp = dbus.Interface(bus.get_object("org.bluez.obex", path), - "org.bluez.obex.FileTransfer") - - if folder: - for node in folder.split("/"): - ftp.ChangeFolder(node) - - for i in ftp.ListFolder(): - if i["Type"] == "folder": - print "%s/" % (i["Name"]) - else: - print "%s" % (i["Name"]) - - -if __name__ == '__main__': - - if len(sys.argv) < 2: - print "Usage: %s [folder]" % (sys.argv[0]) - sys.exit(1) - - folder = None - if len(sys.argv) == 3: - folder = sys.argv[2] - - list_folder(folder) diff --git a/test/map-client b/test/map-client deleted file mode 100755 index f3c657f7..00000000 --- a/test/map-client +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/python - -from __future__ import absolute_import, print_function, unicode_literals - -import gobject - -import sys -import os -import dbus -import dbus.mainloop.glib -from optparse import OptionParser - -from pprint import pformat - -BUS_NAME='org.bluez.obex' -PATH = '/org/bluez/obex' -CLIENT_INTERFACE = 'org.bluez.obex.Client1' -SESSION_INTERFACE = 'org.bluez.obex.Session1' -MESSAGE_ACCESS_INTERFACE = 'org.bluez.obex.MessageAccess1' -MESSAGE_INTERFACE = 'org.bluez.obex.Message1' -TRANSFER_INTERFACE = 'org.bluez.obex.Transfer1' - -def unwrap(x): - """Hack to unwrap D-Bus values, so that they're easier to read when - printed. Taken from d-feet """ - - if isinstance(x, list): - return map(unwrap, x) - - if isinstance(x, tuple): - return tuple(map(unwrap, x)) - - if isinstance(x, dict): - return dict([(unwrap(k), unwrap(v)) for k, v in x.iteritems()]) - - for t in [unicode, str, long, int, float, bool]: - if isinstance(x, t): - return t(x) - - return x - -def parse_options(): - parser.add_option("-d", "--device", dest="device", - help="Device to connect", metavar="DEVICE") - parser.add_option("-c", "--chdir", dest="new_dir", - help="Change current directory to DIR", metavar="DIR") - parser.add_option("-l", "--lsdir", action="store_true", dest="ls_dir", - help="List folders in current directory") - parser.add_option("-v", "--verbose", action="store_true", dest="verbose") - parser.add_option("-L", "--lsmsg", action="store", dest="ls_msg", - help="List messages in supplied CWD subdir") - parser.add_option("-g", "--get", action="store", dest="get_msg", - help="Get message contents") - parser.add_option("-p", "--push", action="store", dest="push_msg", - help="Push message") - parser.add_option("--get-properties", action="store", dest="get_msg_properties", - help="Get message properties") - parser.add_option("--mark-read", action="store", dest="mark_msg_read", - help="Marks the messages as read") - parser.add_option("--mark-unread", action="store", dest="mark_msg_unread", - help="Marks the messages as unread") - parser.add_option("--mark-deleted", action="store", dest="mark_msg_deleted", - help="Deletes the message from the folder") - parser.add_option("--mark-undeleted", action="store", dest="mark_msg_undeleted", - help="Undeletes the message") - parser.add_option("-u", "--update-inbox", action="store_true", dest="update_inbox", - help="Checks for new mails") - - return parser.parse_args() - -def set_folder(session, new_dir): - session.SetFolder(new_dir) - -class MapClient: - def __init__(self, session_path, verbose=False): - self.progress = 0 - self.transfer_path = None - self.props = dict() - self.verbose = verbose - self.path = session_path - bus = dbus.SessionBus() - obj = bus.get_object(BUS_NAME, session_path) - self.session = dbus.Interface(obj, SESSION_INTERFACE) - self.map = dbus.Interface(obj, MESSAGE_ACCESS_INTERFACE) - bus.add_signal_receiver(self.properties_changed, - dbus_interface="org.freedesktop.DBus.Properties", - signal_name="PropertiesChanged", - path_keyword="path") - - def create_transfer_reply(self, path, properties): - self.transfer_path = path - self.props[path] = properties - if self.verbose: - print("Transfer created: %s (file %s)" % (path, - properties["Filename"])) - - def generic_reply(self): - if self.verbose: - print("Operation succeeded") - - def error(self, err): - print(err) - mainloop.quit() - - def transfer_complete(self, path): - if self.verbose: - print("Transfer finished") - properties = self.props.get(path) - if properties == None: - return - f = open(properties["Filename"], "r") - os.remove(properties["Filename"]) - print(f.readlines()) - - 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 set_folder(self, new_dir): - self.map.SetFolder(new_dir) - - def list_folders(self): - for i in self.map.ListFolders(dict()): - print("%s/" % (i["Name"])) - - def list_messages(self, folder): - ret = self.map.ListMessages(folder, dict()) - print(pformat(unwrap(ret))) - - def get_message(self, handle): - self.map.ListMessages("", dict()) - path = self.path + "/message" + handle - obj = bus.get_object(BUS_NAME, path) - msg = dbus.Interface(obj, MESSAGE_INTERFACE) - msg.Get("", True, reply_handler=self.create_transfer_reply, - error_handler=self.error) - - def push_message(self, filename): - self.map.PushMessage(filename, "telecom/msg/outbox", dict(), - reply_handler=self.create_transfer_reply, - error_handler=self.error) - - def get_message_properties(self, handle): - self.map.ListMessages("", dict()) - path = self.path + "/message" + handle - obj = bus.get_object(BUS_NAME, path) - msg = dbus.Interface(obj, "org.freedesktop.DBus.Properties") - ret = msg.GetAll(MESSAGE_INTERFACE) - print(pformat(unwrap(ret))) - - def set_message_property(self, handle, prop, flag): - self.map.ListMessages("", dict()) - path = self.path + "/message" + handle - obj = bus.get_object(BUS_NAME, path) - msg = dbus.Interface(obj, MESSAGE_INTERFACE) - msg.SetProperty (prop, flag); - - def update_inbox(self): - self.map.UpdateInbox() - - -if __name__ == '__main__': - - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - parser = OptionParser() - - (options, args) = parse_options() - - if not options.device: - parser.print_help() - exit(0) - - bus = dbus.SessionBus() - mainloop = gobject.MainLoop() - - client = dbus.Interface(bus.get_object(BUS_NAME, PATH), - CLIENT_INTERFACE) - - print("Creating Session") - path = client.CreateSession(options.device, { "Target": "map" }) - - map_client = MapClient(path, options.verbose) - - if options.new_dir: - map_client.set_folder(options.new_dir) - - if options.ls_dir: - map_client.list_folders() - - if options.ls_msg is not None: - map_client.list_messages(options.ls_msg) - - if options.get_msg is not None: - map_client.get_message(options.get_msg) - - if options.push_msg is not None: - map_client.push_message(options.push_msg) - - if options.get_msg_properties is not None: - map_client.get_message_properties(options.get_msg_properties) - - if options.mark_msg_read is not None: - map_client.set_message_property(options.mark_msg_read, "Read", True) - - if options.mark_msg_unread is not None: - map_client.set_message_property(options.mark_msg_unread, "Read", False) - - if options.mark_msg_deleted is not None: - map_client.set_message_property(options.mark_msg_deleted, "Deleted", True) - - if options.mark_msg_undeleted is not None: - map_client.set_message_property(options.mark_msg_undeleted, "Deleted", False) - - if options.update_inbox: - map_client.update_inbox() - - mainloop.run() diff --git a/test/opp-client b/test/opp-client deleted file mode 100755 index 878c263c..00000000 --- a/test/opp-client +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/python - -from __future__ import absolute_import, print_function, unicode_literals - -import sys -import dbus -import gobject -import dbus.mainloop.glib -import os.path -from optparse import OptionParser - -BUS_NAME='org.bluez.obex' -PATH = '/org/bluez/obex' -CLIENT_INTERFACE='org.bluez.obex.Client1' -SESSION_INTERFACE='org.bluez.obex.Session1' -OBJECT_PUSH_INTERFACE='org.bluez.obex.ObjectPush1' -TRANSFER_INTERFACE='org.bluez.obex.Transfer1' - -def parse_options(): - parser.add_option("-d", "--device", dest="device", - help="Device to connect", metavar="DEVICE") - parser.add_option("-p", "--pull", dest="pull_to_file", - help="Pull vcard and store in FILE", metavar="FILE") - parser.add_option("-s", "--send", dest="send_file", - help="Send FILE", metavar="FILE") - parser.add_option("-v", "--verbose", action="store_true", - dest="verbose") - - return parser.parse_args() - -class OppClient: - def __init__(self, session_path, verbose=False): - self.transferred = 0 - self.transfer_path = None - self.verbose = verbose - bus = dbus.SessionBus() - obj = bus.get_object(BUS_NAME, session_path) - self.session = dbus.Interface(obj, SESSION_INTERFACE) - self.opp = dbus.Interface(obj, OBJECT_PUSH_INTERFACE) - bus.add_signal_receiver(self.properties_changed, - dbus_interface="org.freedesktop.DBus.Properties", - signal_name="PropertiesChanged", - path_keyword="path") - - def create_transfer_reply(self, path, properties): - self.transfer_path = path - self.transfer_size = properties["Size"] - if self.verbose: - print("Transfer created: %s" % path) - - def error(self, err): - print(err) - mainloop.quit() - - def properties_changed(self, interface, properties, invalidated, path): - if path != self.transfer_path: - return - - if "Status" in properties and \ - (properties["Status"] == "complete" or \ - properties["Status"] == "error"): - if self.verbose: - print("Transfer %s" % properties["Status"]) - mainloop.quit() - return - - if "Transferred" not in properties: - return - - value = properties["Transferred"] - speed = (value - self.transferred) / 1000 - print("Transfer progress %d/%d at %d kBps" % (value, - self.transfer_size, - speed)) - self.transferred = value - - def pull_business_card(self, filename): - self.opp.PullBusinessCard(os.path.abspath(filename), - reply_handler=self.create_transfer_reply, - error_handler=self.error) - - def send_file(self, filename): - self.opp.SendFile(os.path.abspath(filename), - reply_handler=self.create_transfer_reply, - error_handler=self.error) - -if __name__ == '__main__': - - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - parser = OptionParser() - - (options, args) = parse_options() - - if not options.device: - parser.print_help() - sys.exit(0) - - bus = dbus.SessionBus() - mainloop = gobject.MainLoop() - - client = dbus.Interface(bus.get_object(BUS_NAME, PATH), - CLIENT_INTERFACE) - - print("Creating Session") - path = client.CreateSession(options.device, { "Target": "OPP" }) - - opp_client = OppClient(path, options.verbose) - - if options.pull_to_file: - opp_client.pull_business_card(options.pull_to_file) - - if options.send_file: - opp_client.send_file(options.send_file) - - mainloop.run() diff --git a/test/pbap-client b/test/pbap-client deleted file mode 100755 index c02833bd..00000000 --- a/test/pbap-client +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/python - -from __future__ import absolute_import, print_function, unicode_literals - -import gobject - -import sys -import os -import dbus -import dbus.service -import dbus.mainloop.glib - -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"]) - - mainloop.run() diff --git a/test/simple-obex-agent b/test/simple-obex-agent deleted file mode 100755 index f15e9d1d..00000000 --- a/test/simple-obex-agent +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/python - -from __future__ import absolute_import, print_function, unicode_literals - -import gobject - -import sys -import dbus -import dbus.service -import dbus.mainloop.glib - -BUS_NAME = 'org.bluez.obex' -PATH = '/org/bluez/obex' -AGENT_MANAGER_INTERFACE = 'org.bluez.obex.AgentManager1' -AGENT_INTERFACE = 'org.bluez.obex.Agent1' -TRANSFER_INTERFACE = 'org.bluez.obex.Transfer1' - -def ask(prompt): - try: - return raw_input(prompt) - except: - return input(prompt) - -class Agent(dbus.service.Object): - def __init__(self, conn=None, obj_path=None): - dbus.service.Object.__init__(self, conn, obj_path) - self.pending_auth = False - - @dbus.service.method(AGENT_INTERFACE, in_signature="o", - out_signature="s") - def AuthorizePush(self, path): - transfer = dbus.Interface(bus.get_object(BUS_NAME, path), - 'org.freedesktop.DBus.Properties') - properties = transfer.GetAll(TRANSFER_INTERFACE); - - self.pending_auth = True - auth = ask("Authorize (%s, %s) (Y/n):" % (path, - properties['Name'])) - - if auth == "n" or auth == "N": - self.pending_auth = False - raise dbus.DBusException( - "org.bluez.obex.Error.Rejected: " - "Not Authorized") - - self.pending_auth = False - - return properties['Name'] - - @dbus.service.method(AGENT_INTERFACE, in_signature="", - out_signature="") - def Cancel(self): - print("Authorization Canceled") - self.pending_auth = False - -if __name__ == '__main__': - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - - bus = dbus.SessionBus() - manager = dbus.Interface(bus.get_object(BUS_NAME, PATH), - AGENT_MANAGER_INTERFACE) - - path = "/test/agent" - agent = Agent(bus, path) - - mainloop = gobject.MainLoop() - - manager.RegisterAgent(path) - print("Agent registered") - - cont = True - while cont: - try: - mainloop.run() - except KeyboardInterrupt: - if agent.pending_auth: - agent.Cancel() - elif len(transfers) > 0: - for a in transfers: - a.cancel() - else: - cont = False - - # manager.UnregisterAgent(path) - # print "Agent unregistered" diff --git a/test/test-alert b/test/test-alert old mode 100755 new mode 100644 diff --git a/test/test-cyclingspeed b/test/test-cyclingspeed old mode 100755 new mode 100644 diff --git a/test/test-heartrate b/test/test-heartrate old mode 100755 new mode 100644 diff --git a/test/test-hfp b/test/test-hfp old mode 100755 new mode 100644 diff --git a/test/test-profile b/test/test-profile old mode 100755 new mode 100644 diff --git a/tools/bdaddr.1 b/tools/bdaddr.1 deleted file mode 100644 index efb77d2e..00000000 --- a/tools/bdaddr.1 +++ /dev/null @@ -1,68 +0,0 @@ -.TH BDADDR 1 "Sep 27 2005" BlueZ "Linux System Administration" -.SH NAME -bdaddr \- Utility for changing the Bluetooth device address -.SH SYNOPSIS -.B bdaddr -.br -.B bdaddr -h -.br -.B bdaddr [-i ] [-r] [-t] [new bdaddr] - -.SH DESCRIPTION -.LP -.B -bdaddr -is used to query or set the local Bluetooth device address (BD_ADDR). If run -with no arguments, -.B -bdaddr -prints the chip manufacturer's name, and the current BD_ADDR. If the IEEE OUI -index file "oui.txt" is installed on the system, the BD_ADDR owner will be -displayed. If the optional [new bdaddr] argument is given, the device will be -reprogrammed with that address. This can either be permanent or temporary, as -specified by the -t flag. In both cases, the device must be reset before the -new address will become active. This can be done with a 'soft' reset by -specifying the -r flag, or a 'hard' reset by removing and replugging the -device. A 'hard' reset will cause the address to revert to the current -non-volatile value. -.PP -.B -bdaddr -uses manufacturer specific commands to set the address, and is therefore -device specific. For this reason, not all devices are supported, and not all -options are supported on all devices. -Current supported manufacturers are: -.B Ericsson, Cambridge Silicon Radio (CSR), Texas Instruments (TI), Zeevo -and -.B ST Microelectronics (ST) - -.SH OPTIONS -.TP -.BI -h -Gives a list of possible commands. -.TP -.BI -i\ -Specify a particular device to operate on. If not specified, default is the -first available device. -.TP -.BI -r -Reset device and make new BD_ADDR active. -.B -CSR -devices only. -.TP -.BI -t -Temporary change. Do not write to non-volatile memory. -.B -CSR -devices only. -.SH FILES -.TP -.I -/usr/share/misc/oui.txt -IEEE Organizationally Unique Identifier master file. -Manually update from: http://standards.ieee.org/regauth/oui/oui.txt -.SH AUTHORS -Written by Marcel Holtmann , -man page by Adam Laurie -.PP diff --git a/tools/btmgmt.c b/tools/btmgmt.c index 51332278..1d71d74f 100644 --- a/tools/btmgmt.c +++ b/tools/btmgmt.c @@ -900,7 +900,7 @@ static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc, struct mgmt_cp_set_discoverable cp; if (argc < 2) { - printf("Usage: btmgmt %s [timeout]\n", argv[0]); + printf("Usage: btmgmt %s [timeout]\n", argv[0]); exit(EXIT_FAILURE); } @@ -910,6 +910,8 @@ static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc, cp.val = 1; else if (strcasecmp(argv[1], "off") == 0) cp.val = 0; + else if (strcasecmp(argv[1], "limited") == 0) + cp.val = 2; else cp.val = atoi(argv[1]); diff --git a/tools/example.psr b/tools/example.psr deleted file mode 100644 index bbbec73a..00000000 --- a/tools/example.psr +++ /dev/null @@ -1,12 +0,0 @@ -// PSKEY_BDADDR -&0001 = 0001 2821 005b 6789 -// PSKEY_ANA_FTRIM -&01f6 = 0025 -// PSKEY_HOST_INTERFACE -&01f9 = 0001 -// PSKEY_UART_BAUD_RATE -&0204 = 01d8 -// PSKEY_ANA_FREQ -&01fe = 0004 -// PSKEY_UART_CONFIG -&0205 = 0006 diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c index 90eae67e..2ef72cfe 100644 --- a/tools/mgmt-tester.c +++ b/tools/mgmt-tester.c @@ -1880,6 +1880,32 @@ static const struct generic_data unblock_device_invalid_param_test_1 = { .expect_len = sizeof(unblock_device_invalid_param_rsp_1), }; +static const char set_static_addr_valid_param[] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0xc0 }; + +static const struct generic_data set_static_addr_success_test = { + .send_opcode = MGMT_OP_SET_STATIC_ADDRESS, + .send_param = set_static_addr_valid_param, + .send_len = sizeof(set_static_addr_valid_param), + .expect_status = MGMT_STATUS_SUCCESS, +}; + +static const struct generic_data set_static_addr_failure_test = { + .send_opcode = MGMT_OP_SET_STATIC_ADDRESS, + .send_param = set_static_addr_valid_param, + .send_len = sizeof(set_static_addr_valid_param), + .expect_status = MGMT_STATUS_REJECTED, +}; + +static const char set_scan_params_valid_param[] = { 0x60, 0x00, 0x30, 0x00 }; + +static const struct generic_data set_scan_params_success_test = { + .send_opcode = MGMT_OP_SET_SCAN_PARAMS, + .send_param = set_scan_params_valid_param, + .send_len = sizeof(set_scan_params_valid_param), + .expect_status = MGMT_STATUS_SUCCESS, +}; + static void powered_delay(void *user_data) { tester_setup_complete(); @@ -3067,5 +3093,16 @@ int main(int argc, char *argv[]) &unblock_device_invalid_param_test_1, NULL, test_command_generic); + test_bredrle("Set Static Address - Success", + &set_static_addr_success_test, + NULL, test_command_generic); + test_bredrle("Set Static Address - Failure", + &set_static_addr_failure_test, + setup_powered, test_command_generic); + + test_bredrle("Set Scan Parameters - Success", + &set_scan_params_success_test, + NULL, test_command_generic); + return tester_run(); } diff --git a/tools/mpris-player.c b/tools/mpris-player.c index 03b8875d..c94330cb 100644 --- a/tools/mpris-player.c +++ b/tools/mpris-player.c @@ -543,8 +543,8 @@ static void remove_player(DBusConnection *conn, const char *sender) g_free(owner); } -static gboolean properties_changed(DBusConnection *conn, - DBusMessage *msg, void *user_data) +static gboolean player_signal(DBusConnection *conn, DBusMessage *msg, + void *user_data) { DBusMessage *signal; DBusMessageIter iter, args; @@ -558,17 +558,15 @@ static gboolean properties_changed(DBusConnection *conn, if (owner == NULL) goto done; - signal = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES, - "PropertiesChanged"); + signal = dbus_message_new_signal(path, dbus_message_get_interface(msg), + dbus_message_get_member(msg)); if (signal == NULL) { - fprintf(stderr, "Unable to allocate new %s.PropertisChanged" - " signal", DBUS_INTERFACE_PROPERTIES); + fprintf(stderr, "Unable to allocate new %s.%s signal", + dbus_message_get_interface(msg), + dbus_message_get_member(msg)); goto done; } - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - dbus_message_iter_init_append(signal, &args); append_iter(&args, &iter); @@ -2512,7 +2510,7 @@ int main(int argc, char *argv[]) { GOptionContext *context; GError *error = NULL; - guint owner_watch, properties_watch; + guint owner_watch, properties_watch, signal_watch; struct sigaction sa; context = g_option_context_new(NULL); @@ -2554,10 +2552,14 @@ int main(int argc, char *argv[]) name_owner_changed, NULL, NULL); - properties_watch = g_dbus_add_properties_watch(session, NULL, NULL, MPRIS_PLAYER_INTERFACE, - properties_changed, + player_signal, + NULL, NULL); + + signal_watch = g_dbus_add_signal_watch(session, NULL, NULL, + MPRIS_PLAYER_INTERFACE, + NULL, player_signal, NULL, NULL); memset(&sa, 0, sizeof(sa)); @@ -2578,6 +2580,7 @@ int main(int argc, char *argv[]) g_dbus_remove_watch(session, owner_watch); g_dbus_remove_watch(session, properties_watch); + g_dbus_remove_watch(session, signal_watch); g_dbus_client_unref(client); diff --git a/tools/obexctl.c b/tools/obexctl.c new file mode 100644 index 00000000..0491b514 --- /dev/null +++ b/tools/obexctl.c @@ -0,0 +1,2400 @@ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2013 Intel Corporation. All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* String display constants */ +#define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF +#define COLORED_CHG COLOR_YELLOW "CHG" COLOR_OFF +#define COLORED_DEL COLOR_RED "DEL" COLOR_OFF + +#define PROMPT_ON COLOR_BLUE "[obex]" COLOR_OFF "# " +#define PROMPT_OFF "[obex]# " + +#define OBEX_SESSION_INTERFACE "org.bluez.obex.Session1" +#define OBEX_TRANSFER_INTERFACE "org.bluez.obex.Transfer1" +#define OBEX_CLIENT_INTERFACE "org.bluez.obex.Client1" +#define OBEX_OPP_INTERFACE "org.bluez.obex.ObjectPush1" +#define OBEX_FTP_INTERFACE "org.bluez.obex.FileTransfer1" +#define OBEX_PBAP_INTERFACE "org.bluez.obex.PhonebookAccess1" +#define OBEX_MAP_INTERFACE "org.bluez.obex.MessageAccess1" +#define OBEX_MSG_INTERFACE "org.bluez.obex.Message1" + +static GMainLoop *main_loop; +static DBusConnection *dbus_conn; +static GDBusProxy *default_session; +static GSList *sessions = NULL; +static GSList *opps = NULL; +static GSList *ftps = NULL; +static GSList *pbaps = NULL; +static GSList *maps = NULL; +static GSList *msgs = NULL; +static GSList *transfers = NULL; +static GDBusProxy *client = NULL; + +struct transfer_data { + uint64_t transferred; + uint64_t size; +}; + +static void connect_handler(DBusConnection *connection, void *user_data) +{ + rl_set_prompt(PROMPT_ON); + printf("\r"); + rl_on_new_line(); + rl_redisplay(); +} + +static void disconnect_handler(DBusConnection *connection, void *user_data) +{ + rl_set_prompt(PROMPT_OFF); + printf("\r"); + rl_on_new_line(); + rl_redisplay(); +} + +static void cmd_quit(int argc, char *argv[]) +{ + g_main_loop_quit(main_loop); +} + +static void connect_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to connect: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("Connection successful\n"); +} + +static void append_variant(DBusMessageIter *iter, int type, void *val) +{ + DBusMessageIter value; + char sig[2] = { type, '\0' }; + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value); + + dbus_message_iter_append_basic(&value, type, val); + + dbus_message_iter_close_container(iter, &value); +} + +static void dict_append_entry(DBusMessageIter *dict, const char *key, + int type, void *val) +{ + DBusMessageIter entry; + + if (type == DBUS_TYPE_STRING) { + const char *str = *((const char **) val); + if (str == NULL) + return; + } + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + append_variant(&entry, type, val); + + dbus_message_iter_close_container(dict, &entry); +} + +struct connect_args { + char *dev; + char *target; +}; + +static void connect_args_free(void *data) +{ + struct connect_args *args = data; + + g_free(args->dev); + g_free(args->target); + g_free(args); +} + +static void connect_setup(DBusMessageIter *iter, void *user_data) +{ + struct connect_args *args = user_data; + DBusMessageIter dict; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->dev); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + if (args->target == NULL) + goto done; + + dict_append_entry(&dict, "Target", DBUS_TYPE_STRING, &args->target); + +done: + dbus_message_iter_close_container(iter, &dict); +} + +static void cmd_connect(int argc, char *argv[]) +{ + struct connect_args *args; + const char *target = "opp"; + + if (argc < 2) { + rl_printf("Missing device address argument\n"); + return; + } + + if (!client) { + rl_printf("Client proxy not available\n"); + return; + } + + if (argc > 2) + target = argv[2]; + + args = g_new0(struct connect_args, 1); + args->dev = g_strdup(argv[1]); + args->target = g_strdup(target); + + if (g_dbus_proxy_method_call(client, "CreateSession", connect_setup, + connect_reply, args, connect_args_free) == FALSE) { + rl_printf("Failed to connect\n"); + return; + } + + rl_printf("Attempting to connect to %s\n", argv[1]); +} + +static void disconnect_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to disconnect: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("Disconnection successful\n"); +} + +static void disconnect_setup(DBusMessageIter *iter, void *user_data) +{ + GDBusProxy *proxy = user_data; + const char *path; + + path = g_dbus_proxy_get_path(proxy); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); +} + +static GDBusProxy *find_session(const char *path) +{ + GSList *l; + + for (l = sessions; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + + if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) + return proxy; + } + + return NULL; +} + +static void cmd_disconnect(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (argc > 1) + proxy = find_session(argv[1]); + else + proxy = default_session; + + if (proxy == NULL) { + rl_printf("Session not available\n"); + return; + } + + if (g_dbus_proxy_method_call(client, "RemoveSession", disconnect_setup, + disconnect_reply, proxy, NULL) == FALSE) { + rl_printf("Failed to disconnect\n"); + return; + } + + rl_printf("Attempting to disconnect to %s\n", + g_dbus_proxy_get_path(proxy)); +} + +static char *proxy_description(GDBusProxy *proxy, const char *title, + const char *description) +{ + const char *path; + + path = g_dbus_proxy_get_path(proxy); + + return g_strdup_printf("%s%s%s%s %s ", + description ? "[" : "", + description ? : "", + description ? "] " : "", + title, path); +} + +static void print_proxy(GDBusProxy *proxy, const char *title, + const char *description) +{ + char *str; + + str = proxy_description(proxy, title, description); + + rl_printf("%s%s\n", str, default_session == proxy ? "[default]" : ""); + + g_free(str); +} + +static void cmd_list(int argc, char *arg[]) +{ + GSList *l; + + for (l = sessions; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + print_proxy(proxy, "Session", NULL); + } +} + +static bool check_default_session(void) +{ + if (!default_session) { + rl_printf("No default session available\n"); + return FALSE; + } + + return TRUE; +} + +static void print_iter(const char *label, const char *name, + DBusMessageIter *iter) +{ + dbus_bool_t valbool; + dbus_uint64_t valu64; + dbus_uint32_t valu32; + dbus_uint16_t valu16; + dbus_int16_t vals16; + const char *valstr; + DBusMessageIter subiter; + + if (iter == NULL) { + rl_printf("%s%s is nil\n", label, name); + return; + } + + switch (dbus_message_iter_get_arg_type(iter)) { + case DBUS_TYPE_INVALID: + rl_printf("%s%s is invalid\n", label, name); + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + dbus_message_iter_get_basic(iter, &valstr); + rl_printf("%s%s: %s\n", label, name, valstr); + break; + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_get_basic(iter, &valbool); + rl_printf("%s%s: %s\n", label, name, + valbool == TRUE ? "yes" : "no"); + break; + case DBUS_TYPE_UINT64: + dbus_message_iter_get_basic(iter, &valu64); + rl_printf("%s%s: %" PRIu64 "\n", label, name, valu64); + break; + case DBUS_TYPE_UINT32: + dbus_message_iter_get_basic(iter, &valu32); + rl_printf("%s%s: 0x%08x\n", label, name, valu32); + break; + case DBUS_TYPE_UINT16: + dbus_message_iter_get_basic(iter, &valu16); + rl_printf("%s%s: 0x%04x\n", label, name, valu16); + break; + case DBUS_TYPE_INT16: + dbus_message_iter_get_basic(iter, &vals16); + rl_printf("%s%s: %d\n", label, name, vals16); + break; + case DBUS_TYPE_VARIANT: + dbus_message_iter_recurse(iter, &subiter); + print_iter(label, name, &subiter); + break; + case DBUS_TYPE_ARRAY: + dbus_message_iter_recurse(iter, &subiter); + while (dbus_message_iter_get_arg_type(&subiter) != + DBUS_TYPE_INVALID) { + print_iter(label, name, &subiter); + dbus_message_iter_next(&subiter); + } + break; + case DBUS_TYPE_DICT_ENTRY: + dbus_message_iter_recurse(iter, &subiter); + dbus_message_iter_get_basic(&subiter, &valstr); + dbus_message_iter_next(&subiter); + print_iter(label, valstr, &subiter); + break; + default: + rl_printf("%s%s has unsupported type\n", label, name); + break; + } +} + +static void print_property(GDBusProxy *proxy, const char *name) +{ + DBusMessageIter iter; + + if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE) + return; + + print_iter("\t", name, &iter); +} + +static void cmd_show(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (argc < 2) { + if (check_default_session() == FALSE) + return; + + proxy = default_session; + } else { + proxy = find_session(argv[1]); + if (!proxy) { + rl_printf("Session %s not available\n", argv[1]); + return; + } + } + + rl_printf("Session %s\n", g_dbus_proxy_get_path(proxy)); + + print_property(proxy, "Destination"); + print_property(proxy, "Target"); +} + +static void set_default_session(GDBusProxy *proxy) +{ + char *desc; + DBusMessageIter iter; + + default_session = proxy; + + if (proxy == NULL) { + desc = g_strdup(PROMPT_ON); + goto done; + } + + if (g_dbus_proxy_get_property(proxy, "Destination", &iter)) + dbus_message_iter_get_basic(&iter, &desc); + + desc = g_strdup_printf(COLOR_BLUE "[%s]" COLOR_OFF "# ", desc); + +done: + rl_set_prompt(desc); + rl_redisplay(); + g_free(desc); +} + +static void cmd_select(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (argc < 2) { + rl_printf("Missing session address argument\n"); + return; + } + + proxy = find_session(argv[1]); + if (proxy == NULL) { + rl_printf("Session %s not available\n", argv[1]); + return; + } + + if (default_session == proxy) + return; + + set_default_session(proxy); + + print_proxy(proxy, "Session", NULL); +} + +static GDBusProxy *find_transfer(const char *path) +{ + GSList *l; + + for (l = transfers; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + + if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) + return proxy; + } + + return NULL; +} + +static GDBusProxy *find_message(const char *path) +{ + GSList *l; + + for (l = msgs; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + + if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) + return proxy; + } + + return NULL; +} + +static void transfer_info(GDBusProxy *proxy, int argc, char *argv[]) +{ + rl_printf("Transfer %s\n", g_dbus_proxy_get_path(proxy)); + + print_property(proxy, "Session"); + print_property(proxy, "Name"); + print_property(proxy, "Type"); + print_property(proxy, "Status"); + print_property(proxy, "Time"); + print_property(proxy, "Size"); + print_property(proxy, "Transferred"); + print_property(proxy, "Filename"); +} + +static void message_info(GDBusProxy *proxy, int argc, char *argv[]) +{ + rl_printf("Message %s\n", g_dbus_proxy_get_path(proxy)); + + print_property(proxy, "Folder"); + print_property(proxy, "Subject"); + print_property(proxy, "Timestamp"); + print_property(proxy, "Sender"); + print_property(proxy, "SenderAddress"); + print_property(proxy, "ReplyTo"); + print_property(proxy, "Recipient"); + print_property(proxy, "RecipientAddress"); + print_property(proxy, "Type"); + print_property(proxy, "Size"); + print_property(proxy, "Status"); + print_property(proxy, "Priority"); + print_property(proxy, "Read"); + print_property(proxy, "Deleted"); + print_property(proxy, "Sent"); + print_property(proxy, "Protected"); +} + +static void cmd_info(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (argc < 2) { + rl_printf("Missing object path argument\n"); + return; + } + + proxy = find_transfer(argv[1]); + if (proxy) { + transfer_info(proxy, argc, argv); + return; + } + + proxy = find_message(argv[1]); + if (proxy) { + message_info(proxy, argc, argv); + return; + } + + rl_printf("Object %s not available\n", argv[1]); +} + +static void cancel_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to cancel: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("Cancel successful\n"); +} + +static void cmd_cancel(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (argc < 2) { + rl_printf("Missing transfer address argument\n"); + return; + } + + proxy = find_transfer(argv[1]); + if (!proxy) { + rl_printf("Transfer %s not available\n", argv[1]); + return; + } + + if (g_dbus_proxy_method_call(proxy, "Cancel", NULL, cancel_reply, NULL, + NULL) == FALSE) { + rl_printf("Failed to cancel transfer\n"); + return; + } + + rl_printf("Attempting to cancel transfer %s\n", + g_dbus_proxy_get_path(proxy)); +} + +static GDBusProxy *find_opp(const char *path) +{ + GSList *l; + + for (l = opps; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + + if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) + return proxy; + } + + return NULL; +} + +static GDBusProxy *find_map(const char *path) +{ + GSList *l; + + for (l = maps; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + + if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) + return proxy; + } + + return NULL; +} + +static void print_dict_iter(DBusMessageIter *iter) +{ + DBusMessageIter dict; + int ctype; + + ctype = dbus_message_iter_get_arg_type(iter); + if (ctype != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(iter, &dict); + + while ((ctype = dbus_message_iter_get_arg_type(&dict)) != + DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *key; + + if (ctype != DBUS_TYPE_DICT_ENTRY) + return; + + dbus_message_iter_recurse(&dict, &entry); + if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) + return; + + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + + print_iter("\t", key, &entry); + + dbus_message_iter_next(&dict); + } +} + +static void print_transfer_iter(DBusMessageIter *iter) +{ + const char *path; + + dbus_message_iter_get_basic(iter, &path); + + rl_printf("Transfer %s\n", path); + + dbus_message_iter_next(iter); + + print_dict_iter(iter); +} + +static void send_reply(DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to send: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + print_transfer_iter(&iter); +} + +static void send_setup(DBusMessageIter *iter, void *user_data) +{ + const char *file = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file); +} + +static void opp_send(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing file argument\n"); + return; + } + + if (g_dbus_proxy_method_call(proxy, "SendFile", send_setup, send_reply, + g_strdup(argv[1]), g_free) == FALSE) { + rl_printf("Failed to send\n"); + return; + } + + rl_printf("Attempting to send %s to %s\n", argv[1], + g_dbus_proxy_get_path(proxy)); +} + +static void push_reply(DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to PushMessage: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + print_transfer_iter(&iter); +} + +static void push_setup(DBusMessageIter *iter, void *user_data) +{ + const char *file = user_data; + const char *folder = ""; + DBusMessageIter dict; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file); + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_close_container(iter, &dict); +} + +static void map_send(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing file argument\n"); + return; + } + + if (g_dbus_proxy_method_call(proxy, "PushMessage", push_setup, + push_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to send\n"); + return; + } + + rl_printf("Attempting to send %s to %s\n", argv[1], + g_dbus_proxy_get_path(proxy)); +} + +static void cmd_send(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (!check_default_session()) + return; + + proxy = find_opp(g_dbus_proxy_get_path(default_session)); + if (proxy) { + opp_send(proxy, argc, argv); + return; + } + + proxy = find_map(g_dbus_proxy_get_path(default_session)); + if (proxy) { + map_send(proxy, argc, argv); + return; + } + + rl_printf("Command not supported\n"); +} + +static void change_folder_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to ChangeFolder: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("ChangeFolder successful\n"); +} + +static void change_folder_setup(DBusMessageIter *iter, void *user_data) +{ + const char *folder = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder); +} + +static void select_reply(DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to Select: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + rl_printf("Select successful\n"); +} + +static void select_setup(DBusMessageIter *iter, void *user_data) +{ + const char *folder = user_data; + const char *location = "int"; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &location); + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder); +} + +static void setfolder_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to SetFolder: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("SetFolder successful\n"); +} + +static void setfolder_setup(DBusMessageIter *iter, void *user_data) +{ + const char *folder = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder); +} + +static GDBusProxy *find_ftp(const char *path) +{ + GSList *l; + + for (l = ftps; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + + if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) + return proxy; + } + + return NULL; +} + +static GDBusProxy *find_pbap(const char *path) +{ + GSList *l; + + for (l = pbaps; l; l = g_slist_next(l)) { + GDBusProxy *proxy = l->data; + + if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0) + return proxy; + } + + return NULL; +} + +static void ftp_cd(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing path argument\n"); + return; + } + + if (g_dbus_proxy_method_call(proxy, "ChangeFolder", change_folder_setup, + change_folder_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to ChangeFolder\n"); + return; + } + + rl_printf("Attempting to ChangeFolder to %s\n", argv[1]); +} + +static void pbap_cd(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing path argument\n"); + return; + } + + if (g_dbus_proxy_method_call(proxy, "Select", select_setup, + select_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to Select\n"); + return; + } + + rl_printf("Attempting to Select to %s\n", argv[1]); +} + +static void map_cd(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing path argument\n"); + return; + } + + if (g_dbus_proxy_method_call(proxy, "SetFolder", setfolder_setup, + setfolder_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to SetFolder\n"); + return; + } + + rl_printf("Attempting to SetFolder to %s\n", argv[1]); +} + +static void cmd_cd(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (!check_default_session()) + return; + + proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + if (proxy) { + ftp_cd(proxy, argc, argv); + return; + } + + proxy = find_pbap(g_dbus_proxy_get_path(default_session)); + if (proxy) { + pbap_cd(proxy, argc, argv); + return; + } + + proxy = find_map(g_dbus_proxy_get_path(default_session)); + if (proxy) { + map_cd(proxy, argc, argv); + return; + } + + rl_printf("Command not supported\n"); +} + +static void list_folder_reply(DBusMessage *message, void *user_data) +{ + DBusMessageIter iter, array; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to ListFolder: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(&iter, &array); + + while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { + print_dict_iter(&array); + dbus_message_iter_next(&array); + } +} + +static void ftp_ls(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (g_dbus_proxy_method_call(proxy, "ListFolder", NULL, + list_folder_reply, NULL, + NULL) == FALSE) { + rl_printf("Failed to ls\n"); + return; + } + + rl_printf("Attempting to ListFolder\n"); +} + +static void parse_list_reply(DBusMessage *message) +{ + DBusMessageIter iter, array; + + dbus_message_iter_init(message, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(&iter, &array); + + while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { + DBusMessageIter entry; + const char *vcard; + + if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT) + return; + + dbus_message_iter_recurse(&array, &entry); + + dbus_message_iter_get_basic(&entry, &vcard); + dbus_message_iter_next(&entry); + print_iter("\t", vcard, &entry); + dbus_message_iter_next(&array); + } +} + +static void list_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to List: %s\n", error.name); + dbus_error_free(&error); + return; + } + + parse_list_reply(message); +} + +static void list_setup(DBusMessageIter *iter, void *user_data) +{ + DBusMessageIter dict; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_close_container(iter, &dict); +} + +static void search_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to Search: %s\n", error.name); + dbus_error_free(&error); + return; + } + + parse_list_reply(message); +} + +static void search_setup(DBusMessageIter *iter, void *user_data) +{ + const char *value = user_data; + const char *field; + DBusMessageIter dict; + + field = isalpha(value[0]) ? "name" : "number"; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field); + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &value); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_close_container(iter, &dict); +} + +static void pbap_search(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (g_dbus_proxy_method_call(proxy, "Search", search_setup, + search_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to Search\n"); + return; + } + + rl_printf("Attempting to Search\n"); +} + +static void list_folders_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + DBusMessageIter iter, array; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to ListFolders: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(&iter, &array); + + while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { + print_dict_iter(&array); + dbus_message_iter_next(&array); + } +} + +static void list_folders_setup(DBusMessageIter *iter, void *user_data) +{ + DBusMessageIter dict; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_close_container(iter, &dict); +} + +static void list_messages_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + DBusMessageIter iter, array; + int ctype; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to ListFolders: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + return; + + dbus_message_iter_recurse(&iter, &array); + + while ((ctype = dbus_message_iter_get_arg_type(&array)) == + DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry; + const char *obj; + + dbus_message_iter_recurse(&array, &entry); + dbus_message_iter_get_basic(&entry, &obj); + rl_printf("\t%s\n", obj); + dbus_message_iter_next(&array); + } +} + +static void list_messages_setup(DBusMessageIter *iter, void *user_data) +{ + const char *folder = user_data; + DBusMessageIter dict; + + if (strcmp(folder, "*") == 0) + folder = ""; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_close_container(iter, &dict); +} + +static void pbap_ls(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc > 1) { + pbap_search(proxy, argc, argv); + return; + } + + if (g_dbus_proxy_method_call(proxy, "List", list_setup, list_reply, + NULL, NULL) == FALSE) { + rl_printf("Failed to List\n"); + return; + } + + rl_printf("Attempting to List\n"); +} + +static void map_ls_messages(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (g_dbus_proxy_method_call(proxy, "ListMessages", list_messages_setup, + list_messages_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to ListMessages\n"); + return; + } + + rl_printf("Attempting to ListMessages\n"); +} + +static void map_ls(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc > 1) { + map_ls_messages(proxy, argc, argv); + return; + } + + if (g_dbus_proxy_method_call(proxy, "ListFolders", list_folders_setup, + list_folders_reply, NULL, + NULL) == FALSE) { + rl_printf("Failed to ListFolders\n"); + return; + } + + rl_printf("Attempting to ListFolders\n"); +} + +static void cmd_ls(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (!check_default_session()) + return; + + proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + if (proxy) { + ftp_ls(proxy, argc, argv); + return; + } + + proxy = find_pbap(g_dbus_proxy_get_path(default_session)); + if (proxy) { + pbap_ls(proxy, argc, argv); + return; + } + + proxy = find_map(g_dbus_proxy_get_path(default_session)); + if (proxy) { + map_ls(proxy, argc, argv); + return; + } + + rl_printf("Command not supported\n"); +} + +struct cp_args { + char *source; + char *target; +}; + +static void cp_free(void *data) +{ + struct cp_args *args = data; + + g_free(args->source); + g_free(args->target); + g_free(args); +} + +static struct cp_args *cp_new(char *argv[]) +{ + struct cp_args *args; + const char *source; + const char *target; + + source = rindex(argv[1], ':'); + if (source == NULL) + source = argv[1]; + else + source++; + + target = rindex(argv[2], ':'); + if (target == NULL) + target = argv[2]; + else + target++; + + args = g_new0(struct cp_args, 1); + args->source = g_strdup(source); + args->target = g_strdup(target); + + return args; +} + +static void cp_setup(DBusMessageIter *iter, void *user_data) +{ + struct cp_args *args = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source); + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target); +} + +static void copy_file_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to CopyFile: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("CopyFile successful\n"); +} + +static void ftp_copy(GDBusProxy *proxy, int argc, char *argv[]) +{ + struct cp_args *args; + + args = cp_new(argv); + + if (g_dbus_proxy_method_call(proxy, "CopyFile", cp_setup, + copy_file_reply, args, cp_free) == FALSE) { + rl_printf("Failed to CopyFile\n"); + return; + } + + rl_printf("Attempting to CopyFile\n"); +} + +static void get_file_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + DBusMessageIter iter; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to GetFile: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + print_transfer_iter(&iter); +} + +static void get_file_setup(DBusMessageIter *iter, void *user_data) +{ + struct cp_args *args = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target); + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source); +} + +static void ftp_get(GDBusProxy *proxy, int argc, char *argv[]) +{ + struct cp_args *args; + + if (rindex(argv[2], ':') == NULL) + return ftp_copy(proxy, argc, argv); + + args = cp_new(argv); + + if (g_dbus_proxy_method_call(proxy, "GetFile", get_file_setup, + get_file_reply, args, cp_free) == FALSE) { + rl_printf("Failed to GetFile\n"); + return; + } + + rl_printf("Attempting to GetFile\n"); +} + +static void put_file_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + DBusMessageIter iter; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to PutFile: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + print_transfer_iter(&iter); +} + +static void ftp_put(GDBusProxy *proxy, int argc, char *argv[]) +{ + struct cp_args *args; + + if (rindex(argv[2], ':') != NULL) { + rl_printf("Invalid target file argument\n"); + return; + } + + args = cp_new(argv); + + if (g_dbus_proxy_method_call(proxy, "PutFile", cp_setup, put_file_reply, + args, cp_free) == FALSE) { + rl_printf("Failed to PutFile\n"); + return; + } + + rl_printf("Attempting to PutFile\n"); +} + +static void ftp_cp(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing source file argument\n"); + return; + } + + if (argc < 3) { + rl_printf("Missing target file argument\n"); + return; + } + + if (rindex(argv[1], ':') == NULL) + return ftp_get(proxy, argc, argv); + + return ftp_put(proxy, argc, argv); +} + +static void pull_all_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to PullAll: %s\n", error.name); + dbus_error_free(&error); + return; + } + + + rl_printf("PullAll successful\n"); +} + +static void pull_all_setup(DBusMessageIter *iter, void *user_data) +{ + const char *file = user_data; + DBusMessageIter dict; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_close_container(iter, &dict); +} + +static void pbap_pull_all(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (g_dbus_proxy_method_call(proxy, "PullAll", pull_all_setup, + pull_all_reply, g_strdup(argv[2]), + g_free) == FALSE) { + rl_printf("Failed to PullAll\n"); + return; + } + + rl_printf("Attempting to PullAll\n"); +} + +static void pull_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to Pull: %s\n", error.name); + dbus_error_free(&error); + return; + } + + + rl_printf("Pull successful\n"); +} + +static void pull_setup(DBusMessageIter *iter, void *user_data) +{ + struct cp_args *args = user_data; + DBusMessageIter dict; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source); + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target); + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + &dict); + + dbus_message_iter_close_container(iter, &dict); +} + +static void pbap_pull(GDBusProxy *proxy, int argc, char *argv[]) +{ + struct cp_args *args; + + args = cp_new(argv); + + if (g_dbus_proxy_method_call(proxy, "Pull", pull_setup, pull_reply, + args, cp_free) == FALSE) { + rl_printf("Failed to Pull\n"); + return; + } + + rl_printf("Attempting to Pull\n"); +} + +static void pbap_cp(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing source file argument\n"); + return; + } + + if (argc < 3) { + rl_printf("Missing target file argument\n"); + return; + } + + if (strcmp(argv[1], "*") == 0) + return pbap_pull_all(proxy, argc, argv); + + return pbap_pull(proxy, argc, argv); +} + +static void get_reply(DBusMessage *message, void *user_data) +{ + DBusMessageIter iter; + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to Get: %s\n", error.name); + dbus_error_free(&error); + return; + } + + dbus_message_iter_init(message, &iter); + + print_transfer_iter(&iter); +} + +static void get_setup(DBusMessageIter *iter, void *user_data) +{ + const char *file = user_data; + dbus_bool_t attachment = TRUE; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file); + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &attachment); +} + +static void map_cp(GDBusProxy *proxy, int argc, char *argv[]) +{ + GDBusProxy *obj; + + if (argc < 2) { + rl_printf("Missing message argument\n"); + return; + } + + obj = find_message(argv[1]); + if (obj == NULL) { + rl_printf("Invalid message argument\n"); + return; + } + + if (argc < 3) { + rl_printf("Missing target file argument\n"); + return; + } + + if (g_dbus_proxy_method_call(obj, "Get", get_setup, get_reply, + g_strdup(argv[2]), g_free) == FALSE) { + rl_printf("Failed to Get\n"); + return; + } + + rl_printf("Attempting to Get\n"); +} + +static void cmd_cp(int argc, char *argv[]) +{ + + GDBusProxy *proxy; + + if (!check_default_session()) + return; + + proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + if (proxy) { + ftp_cp(proxy, argc, argv); + return; + } + + proxy = find_pbap(g_dbus_proxy_get_path(default_session)); + if (proxy) { + pbap_cp(proxy, argc, argv); + return; + } + + proxy = find_map(g_dbus_proxy_get_path(default_session)); + if (proxy) { + map_cp(proxy, argc, argv); + return; + } + + rl_printf("Command not supported\n"); +} + +static void move_file_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to MoveFile: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("MoveFile successful\n"); +} + +static void cmd_mv(int argc, char *argv[]) +{ + GDBusProxy *proxy; + struct cp_args *args; + + if (!check_default_session()) + return; + + if (argc < 2) { + rl_printf("Missing source file argument\n"); + return; + } + + if (argc < 3) { + rl_printf("Missing target file argument\n"); + return; + } + + proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + if (proxy == NULL) { + rl_printf("Command not supported\n"); + return; + } + + args = cp_new(argv); + + if (g_dbus_proxy_method_call(proxy, "MoveFile", cp_setup, + move_file_reply, args, cp_free) == FALSE) { + rl_printf("Failed to MoveFile\n"); + return; + } + + rl_printf("Attempting to MoveFile\n"); +} + +static void delete_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to Delete: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("Delete successful\n"); +} + +static void delete_setup(DBusMessageIter *iter, void *user_data) +{ + const char *file = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file); +} + +static void ftp_rm(GDBusProxy *proxy, int argc, char *argv[]) +{ + if (argc < 2) { + rl_printf("Missing file argument\n"); + return; + } + + if (g_dbus_proxy_method_call(proxy, "Delete", delete_setup, + delete_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to Delete\n"); + return; + } + + rl_printf("Attempting to Delete\n"); +} + +static void set_delete_reply(const DBusError *error, void *user_data) +{ + if (dbus_error_is_set(error)) + rl_printf("Failed to set Deleted: %s\n", error->name); + else + rl_printf("Set Deleted successful\n"); +} + +static void map_rm(GDBusProxy *proxy, int argc, char *argv[]) +{ + GDBusProxy *msg; + dbus_bool_t value = TRUE; + + if (argc < 2) { + rl_printf("Missing message argument\n"); + return; + } + + msg = find_message(argv[1]); + if (msg == NULL) { + rl_printf("Invalid message argument\n"); + return; + } + + if (g_dbus_proxy_set_property_basic(msg, "Deleted", DBUS_TYPE_BOOLEAN, + &value, set_delete_reply, + NULL, NULL) == FALSE) { + rl_printf("Failed to set Deleted\n"); + return; + } + + rl_printf("Attempting to set Deleted\n"); +} + +static void cmd_rm(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (!check_default_session()) + return; + + proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + if (proxy) { + ftp_rm(proxy, argc, argv); + return; + } + + proxy = find_map(g_dbus_proxy_get_path(default_session)); + if (proxy) { + map_rm(proxy, argc, argv); + return; + } + + rl_printf("Command not supported\n"); +} + +static void create_folder_reply(DBusMessage *message, void *user_data) +{ + DBusError error; + + dbus_error_init(&error); + + if (dbus_set_error_from_message(&error, message) == TRUE) { + rl_printf("Failed to CreateFolder: %s\n", error.name); + dbus_error_free(&error); + return; + } + + rl_printf("CreateFolder successful\n"); +} + +static void create_folder_setup(DBusMessageIter *iter, void *user_data) +{ + const char *folder = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder); +} + +static void cmd_mkdir(int argc, char *argv[]) +{ + GDBusProxy *proxy; + + if (!check_default_session()) + return; + + if (argc < 2) { + rl_printf("Missing folder argument\n"); + return; + } + + proxy = find_ftp(g_dbus_proxy_get_path(default_session)); + if (proxy == NULL) { + rl_printf("Command not supported\n"); + return; + } + + if (g_dbus_proxy_method_call(proxy, "CreateFolder", create_folder_setup, + create_folder_reply, g_strdup(argv[1]), + g_free) == FALSE) { + rl_printf("Failed to CreateFolder\n"); + return; + } + + rl_printf("Attempting to CreateFolder\n"); +} + +static const struct { + const char *cmd; + const char *arg; + void (*func) (int argc, char *argv[]); + const char *desc; +} cmd_table[] = { + { "connect", " [uuid]", cmd_connect, "Connect session" }, + { "disconnect", "[session]", cmd_disconnect, "Disconnect session" }, + { "list", NULL, cmd_list, "List available sessions" }, + { "show", "[session]", cmd_show, "Session information" }, + { "select", "", cmd_select, "Select default session" }, + { "info", "", cmd_info, "Object information" }, + { "cancel", "", cmd_cancel, "Cancel transfer" }, + { "send", "", cmd_send, "Send file" }, + { "cd", "", cmd_cd, "Change current folder" }, + { "ls", NULL, cmd_ls, "List current folder" }, + { "cp", " ", cmd_cp, + "Copy source file to destination file" }, + { "mv", " ", cmd_mv, + "Move source file to destination file" }, + { "rm", "", cmd_rm, "Delete file" }, + { "mkdir", "", cmd_mkdir, "Create folder" }, + { "quit", NULL, cmd_quit, "Quit program" }, + { "exit", NULL, cmd_quit }, + { "help" }, + {} +}; + +static char *cmd_generator(const char *text, int state) +{ + static int index, len; + const char *cmd; + + if (!state) { + index = 0; + len = strlen(text); + } + + while ((cmd = cmd_table[index].cmd)) { + index++; + + if (!strncmp(cmd, text, len)) + return strdup(cmd); + } + + return NULL; +} + +static char **cmd_completion(const char *text, int start, int end) +{ + char **matches = NULL; + + if (start == 0) { + rl_completion_display_matches_hook = NULL; + matches = rl_completion_matches(text, cmd_generator); + } + + if (!matches) + rl_attempted_completion_over = 1; + + return matches; +} + +static void rl_handler(char *input) +{ + int argc; + char **argv = NULL; + int i; + + if (!input) { + rl_insert_text("quit"); + rl_redisplay(); + rl_crlf(); + g_main_loop_quit(main_loop); + return; + } + + if (!strlen(input)) + goto done; + + add_history(input); + + argv = g_strsplit(input, " ", -1); + if (argv == NULL) + goto done; + + for (argc = 0; argv[argc];) + argc++; + + if (argc == 0) + goto done; + + for (i = 0; cmd_table[i].cmd; i++) { + if (strcmp(argv[0], cmd_table[i].cmd)) + continue; + + if (cmd_table[i].func) { + cmd_table[i].func(argc, argv); + goto done; + } + } + + if (strcmp(argv[0], "help")) { + printf("Invalid command\n"); + goto done; + } + + printf("Available commands:\n"); + + for (i = 0; cmd_table[i].cmd; i++) { + if (cmd_table[i].desc) + printf(" %s %-*s %s\n", cmd_table[i].cmd, + (int)(25 - strlen(cmd_table[i].cmd)), + cmd_table[i].arg ? : "", + cmd_table[i].desc ? : ""); + } + +done: + g_strfreev(argv); + free(input); +} + +static gboolean option_version = FALSE; + +static GOptionEntry options[] = { + { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, + "Show version information and exit" }, + { NULL }, +}; + +static gboolean signal_handler(GIOChannel *channel, GIOCondition condition, + gpointer user_data) +{ + static unsigned int __terminated = 0; + struct signalfd_siginfo si; + ssize_t result; + int fd; + + if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) { + g_main_loop_quit(main_loop); + return FALSE; + } + + fd = g_io_channel_unix_get_fd(channel); + + result = read(fd, &si, sizeof(si)); + if (result != sizeof(si)) + return FALSE; + + switch (si.ssi_signo) { + case SIGINT: + rl_replace_line("", 0); + rl_crlf(); + rl_on_new_line(); + rl_redisplay(); + break; + case SIGTERM: + if (__terminated == 0) { + rl_replace_line("", 0); + rl_crlf(); + g_main_loop_quit(main_loop); + } + + __terminated = 1; + break; + } + + return TRUE; +} + +static guint setup_signalfd(void) +{ + GIOChannel *channel; + guint source; + sigset_t mask; + int fd; + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { + perror("Failed to set signal mask"); + return 0; + } + + fd = signalfd(-1, &mask, 0); + if (fd < 0) { + perror("Failed to create signal descriptor"); + return 0; + } + + channel = g_io_channel_unix_new(fd); + + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + + source = g_io_add_watch(channel, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + signal_handler, NULL); + + g_io_channel_unref(channel); + + return source; +} + +static gboolean input_handler(GIOChannel *channel, GIOCondition condition, + gpointer user_data) +{ + if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { + g_main_loop_quit(main_loop); + return FALSE; + } + + rl_callback_read_char(); + return TRUE; +} + +static guint setup_standard_input(void) +{ + GIOChannel *channel; + guint source; + + channel = g_io_channel_unix_new(fileno(stdin)); + + source = g_io_add_watch(channel, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + input_handler, NULL); + + g_io_channel_unref(channel); + + return source; +} + +static void client_added(GDBusProxy *proxy) +{ + if (client == NULL) + client = proxy; + + print_proxy(proxy, "Client", COLORED_NEW); +} + +static void session_added(GDBusProxy *proxy) +{ + sessions = g_slist_append(sessions, proxy); + + if (default_session == NULL) + set_default_session(proxy); + + print_proxy(proxy, "Session", COLORED_NEW); +} + +static void print_transferred(struct transfer_data *data, const char *str, + DBusMessageIter *iter) +{ + dbus_uint64_t valu64; + uint64_t speed; + int seconds, minutes; + + dbus_message_iter_get_basic(iter, &valu64); + speed = valu64 - data->transferred; + data->transferred = valu64; + + if (data->size == 0) { + rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s)\n", + str, valu64, speed / 1000); + return; + } + + seconds = (data->size - data->transferred) / speed; + minutes = seconds / 60; + seconds %= 60; + rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s %02u:%02u)\n", + str, valu64, speed / 1000, minutes, seconds); +} + +static void transfer_property_changed(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter, void *user_data) +{ + struct transfer_data *data = user_data; + char *str; + + str = proxy_description(proxy, "Transfer", COLORED_CHG); + + if (strcmp(name, "Transferred") == 0) { + print_transferred(data, str, iter); + goto done; + } + + if (strcmp(name, "Size") == 0) + dbus_message_iter_get_basic(iter, &data->size); + + print_iter(str, name, iter); + +done: + g_free(str); +} + +static void transfer_destroy(GDBusProxy *proxy, void *user_data) +{ + struct transfer_data *data = user_data; + + g_free(data); +} + +static void transfer_added(GDBusProxy *proxy) +{ + struct transfer_data *data; + DBusMessageIter iter; + + transfers = g_slist_append(transfers, proxy); + + print_proxy(proxy, "Transfer", COLORED_NEW); + + data = g_new0(struct transfer_data, 1); + + if (g_dbus_proxy_get_property(proxy, "Transfered", &iter)) + dbus_message_iter_get_basic(&iter, &data->transferred); + + if (g_dbus_proxy_get_property(proxy, "Size", &iter)) + dbus_message_iter_get_basic(&iter, &data->size); + + g_dbus_proxy_set_property_watch(proxy, transfer_property_changed, data); + g_dbus_proxy_set_removed_watch(proxy, transfer_destroy, data); +} + +static void opp_added(GDBusProxy *proxy) +{ + opps = g_slist_append(opps, proxy); + + print_proxy(proxy, "ObjectPush", COLORED_NEW); +} + +static void ftp_added(GDBusProxy *proxy) +{ + ftps = g_slist_append(ftps, proxy); + + print_proxy(proxy, "FileTransfer", COLORED_NEW); +} + +static void pbap_added(GDBusProxy *proxy) +{ + pbaps = g_slist_append(pbaps, proxy); + + print_proxy(proxy, "PhonebookAccess", COLORED_NEW); +} + +static void map_added(GDBusProxy *proxy) +{ + maps = g_slist_append(maps, proxy); + + print_proxy(proxy, "MessageAccess", COLORED_NEW); +} + +static void msg_added(GDBusProxy *proxy) +{ + msgs = g_slist_append(msgs, proxy); + + print_proxy(proxy, "Message", COLORED_NEW); +} + +static void proxy_added(GDBusProxy *proxy, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, OBEX_CLIENT_INTERFACE)) + client_added(proxy); + else if (!strcmp(interface, OBEX_SESSION_INTERFACE)) + session_added(proxy); + else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE)) + transfer_added(proxy); + else if (!strcmp(interface, OBEX_OPP_INTERFACE)) + opp_added(proxy); + else if (!strcmp(interface, OBEX_FTP_INTERFACE)) + ftp_added(proxy); + else if (!strcmp(interface, OBEX_PBAP_INTERFACE)) + pbap_added(proxy); + else if (!strcmp(interface, OBEX_MAP_INTERFACE)) + map_added(proxy); + else if (!strcmp(interface, OBEX_MSG_INTERFACE)) + msg_added(proxy); +} + +static void client_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "Client", COLORED_DEL); + + if (client == proxy) + client = NULL; +} + +static void session_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "Session", COLORED_DEL); + + if (default_session == proxy) + set_default_session(NULL); + + sessions = g_slist_remove(sessions, proxy); +} + +static void transfer_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "Transfer", COLORED_DEL); + + transfers = g_slist_remove(transfers, proxy); +} + +static void opp_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "ObjectPush", COLORED_DEL); + + opps = g_slist_remove(opps, proxy); +} + +static void ftp_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "FileTransfer", COLORED_DEL); + + ftps = g_slist_remove(ftps, proxy); +} + +static void pbap_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "PhonebookAccess", COLORED_DEL); + + pbaps = g_slist_remove(pbaps, proxy); +} + +static void map_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "MessageAccess", COLORED_DEL); + + maps = g_slist_remove(maps, proxy); +} + +static void msg_removed(GDBusProxy *proxy) +{ + print_proxy(proxy, "Message", COLORED_DEL); + + msgs = g_slist_remove(msgs, proxy); +} + +static void proxy_removed(GDBusProxy *proxy, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, OBEX_CLIENT_INTERFACE)) + client_removed(proxy); + else if (!strcmp(interface, OBEX_SESSION_INTERFACE)) + session_removed(proxy); + else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE)) + transfer_removed(proxy); + else if (!strcmp(interface, OBEX_OPP_INTERFACE)) + opp_removed(proxy); + else if (!strcmp(interface, OBEX_FTP_INTERFACE)) + ftp_removed(proxy); + else if (!strcmp(interface, OBEX_PBAP_INTERFACE)) + pbap_removed(proxy); + else if (!strcmp(interface, OBEX_MAP_INTERFACE)) + map_removed(proxy); + else if (!strcmp(interface, OBEX_MSG_INTERFACE)) + msg_removed(proxy); +} + +static void session_property_changed(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter) +{ + char *str; + + str = proxy_description(proxy, "Session", COLORED_CHG); + print_iter(str, name, iter); + g_free(str); +} + +static void property_changed(GDBusProxy *proxy, const char *name, + DBusMessageIter *iter, void *user_data) +{ + const char *interface; + + interface = g_dbus_proxy_get_interface(proxy); + + if (!strcmp(interface, OBEX_SESSION_INTERFACE)) + session_property_changed(proxy, name, iter); +} + +int main(int argc, char *argv[]) +{ + GOptionContext *context; + GError *error = NULL; + GDBusClient *client; + guint signal, input; + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, options, NULL); + + if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) { + if (error != NULL) { + g_printerr("%s\n", error->message); + g_error_free(error); + } else + g_printerr("An unknown error occurred\n"); + exit(1); + } + + g_option_context_free(context); + + if (option_version == TRUE) { + printf("%s\n", VERSION); + exit(0); + } + + main_loop = g_main_loop_new(NULL, FALSE); + dbus_conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL); + + rl_attempted_completion_function = cmd_completion; + + rl_erase_empty_line = 1; + rl_callback_handler_install(NULL, rl_handler); + + rl_set_prompt(PROMPT_OFF); + rl_redisplay(); + + input = setup_standard_input(); + signal = setup_signalfd(); + client = g_dbus_client_new(dbus_conn, "org.bluez.obex", + "/org/bluez/obex"); + + g_dbus_client_set_connect_watch(client, connect_handler, NULL); + g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL); + + g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed, + property_changed, NULL); + + g_main_loop_run(main_loop); + + g_dbus_client_unref(client); + g_source_remove(signal); + g_source_remove(input); + + rl_message(""); + rl_callback_handler_remove(); + + dbus_connection_unref(dbus_conn); + g_main_loop_unref(main_loop); + + return 0; +} diff --git a/tools/sdptool.1 b/tools/sdptool.1 index 88ad818d..ea959333 100644 --- a/tools/sdptool.1 +++ b/tools/sdptool.1 @@ -91,9 +91,15 @@ the \fB--handle\fP option. .IP "" 10 You can specify a channel to add the service on using the \fB--channel\fP option. +.IP "" 10 +NOTE: Local adapters configuration will not be updated and this command should +be used only for SDP testing. .IP "\fBdel record_handle\fP" 10 Remove a service from the local SDP database. +.IP "" 10 +NOTE: Local adapters configuration will not be updated and this command should +be used only for SDP testing. .IP "\fBget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\fP" 10 Retrieve a service from the local SDP database. diff --git a/tools/update_compids.sh b/tools/update_compids.sh deleted file mode 100755 index 38d1fff3..00000000 --- a/tools/update_compids.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# Download the list of company IDs from bluetooth.org and generate a diff which -# can be applied to source tree to update bt_compidtostr(). Usage: -# -# 1) ./tools/update_compids.sh | git apply -p0 -# 2) Inspect changes to make sure they are sane -# 3) git commit -m "lib: Update list of company identifiers" lib/bluetooth.c -# -# Requires html2text: http://www.mbayer.de/html2text/ -# -set -e -u - -tmpdir=$(mktemp -d) -trap "rm -rf $tmpdir" EXIT - -mkdir $tmpdir/lib -cp lib/bluetooth.c $tmpdir/lib/bluetooth.c.orig -cp lib/bluetooth.c $tmpdir/lib/bluetooth.c - -cd $tmpdir - -path=en-us/specification/assigned-numbers/company-identifiers -# Use "iconv -c" to strip unwanted unicode characters -# Fixups: -# - strip tags of type "checkbox" because html2text generates UTF-8 for -# them in some distros even when using -ascii (e.g. Fedora) -# - replace " " (non-breaking space) with whitespace manually, because -# some versions incorrectly convert it into "\xC2\xA0" -curl https://www.bluetooth.org/$path | iconv -c -f utf8 -t ascii | \ - sed '//dev/null - -# Some versions of html2text do not replace & (e.g. Fedora) -sed -i 's/&/\&/g' identifiers.txt - -sed -n '/^const char \*bt_compidtostr(int compid)/,/^}/p' \ - lib/bluetooth.c > old.c - -echo -e 'const char *bt_compidtostr(int compid)\n{\n\tswitch (compid) {' > new.c -cat identifiers.txt | - perl -ne 'm/^(\d+)\s+0x[0-9a-f]+\s+(.*)/i && - print "\tcase $1:\n\t\treturn \"$2\";\n"' >> new.c -if ! grep -q "return \"" new.c; then - echo "ERROR: could not parse company IDs from bluetooth.org" >&2 - exit 1 -fi -if [ -n "$(tr -d '[:print:]\t\n' < new.c)" ]; then - echo -n "ERROR: invalid non-ASCII characters found while parsing" >&2 - echo -n " company IDs. Please identify offending sequence and fix" >&2 - echo " tools/update_compids.sh accordingly." >&2 - exit 1 -fi -echo -e '\tcase 65535:\n\t\treturn "internal use";' >> new.c -echo -e '\tdefault:\n\t\treturn "not assigned";\n\t}\n}' >> new.c - -diff -Naur old.c new.c | patch -sp0 lib/bluetooth.c -diff -Naur lib/bluetooth.c.orig lib/bluetooth.c diff --git a/ylwrap b/ylwrap deleted file mode 100755 index 92536350..00000000 --- a/ylwrap +++ /dev/null @@ -1,226 +0,0 @@ -#! /bin/sh -# ylwrap - wrapper for lex/yacc invocations. - -scriptversion=2011-08-25.18; # UTC - -# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, -# 2007, 2009, 2010, 2011 Free Software Foundation, Inc. -# -# Written by Tom Tromey . -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - -# This file is maintained in Automake, please report -# bugs to or send patches to -# . - -case "$1" in - '') - echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 - exit 1 - ;; - --basedir) - basedir=$2 - shift 2 - ;; - -h|--h*) - cat <<\EOF -Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... - -Wrapper for lex/yacc invocations, renaming files as desired. - - INPUT is the input file - OUTPUT is one file PROG generates - DESIRED is the file we actually want instead of OUTPUT - PROGRAM is program to run - ARGS are passed to PROG - -Any number of OUTPUT,DESIRED pairs may be used. - -Report bugs to . -EOF - exit $? - ;; - -v|--v*) - echo "ylwrap $scriptversion" - exit $? - ;; -esac - - -# The input. -input="$1" -shift -case "$input" in - [\\/]* | ?:[\\/]*) - # Absolute path; do nothing. - ;; - *) - # Relative path. Make it absolute. - input="`pwd`/$input" - ;; -esac - -pairlist= -while test "$#" -ne 0; do - if test "$1" = "--"; then - shift - break - fi - pairlist="$pairlist $1" - shift -done - -# The program to run. -prog="$1" -shift -# Make any relative path in $prog absolute. -case "$prog" in - [\\/]* | ?:[\\/]*) ;; - *[\\/]*) prog="`pwd`/$prog" ;; -esac - -# FIXME: add hostname here for parallel makes that run commands on -# other machines. But that might take us over the 14-char limit. -dirname=ylwrap$$ -do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' -trap "ret=129; $do_exit" 1 -trap "ret=130; $do_exit" 2 -trap "ret=141; $do_exit" 13 -trap "ret=143; $do_exit" 15 -mkdir $dirname || exit 1 - -cd $dirname - -case $# in - 0) "$prog" "$input" ;; - *) "$prog" "$@" "$input" ;; -esac -ret=$? - -if test $ret -eq 0; then - set X $pairlist - shift - first=yes - # Since DOS filename conventions don't allow two dots, - # the DOS version of Bison writes out y_tab.c instead of y.tab.c - # and y_tab.h instead of y.tab.h. Test to see if this is the case. - y_tab_nodot="no" - if test -f y_tab.c || test -f y_tab.h; then - y_tab_nodot="yes" - fi - - # The directory holding the input. - input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` - # Quote $INPUT_DIR so we can use it in a regexp. - # FIXME: really we should care about more than `.' and `\'. - input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` - - while test "$#" -ne 0; do - from="$1" - # Handle y_tab.c and y_tab.h output by DOS - if test $y_tab_nodot = "yes"; then - if test $from = "y.tab.c"; then - from="y_tab.c" - else - if test $from = "y.tab.h"; then - from="y_tab.h" - fi - fi - fi - if test -f "$from"; then - # If $2 is an absolute path name, then just use that, - # otherwise prepend `../'. - case "$2" in - [\\/]* | ?:[\\/]*) target="$2";; - *) target="../$2";; - esac - - # We do not want to overwrite a header file if it hasn't - # changed. This avoid useless recompilations. However the - # parser itself (the first file) should always be updated, - # because it is the destination of the .y.c rule in the - # Makefile. Divert the output of all other files to a temporary - # file so we can compare them to existing versions. - if test $first = no; then - realtarget="$target" - target="tmp-`echo $target | sed s/.*[\\/]//g`" - fi - # Edit out `#line' or `#' directives. - # - # We don't want the resulting debug information to point at - # an absolute srcdir; it is better for it to just mention the - # .y file with no path. - # - # We want to use the real output file name, not yy.lex.c for - # instance. - # - # We want the include guards to be adjusted too. - FROM=`echo "$from" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` - TARGET=`echo "$2" | sed \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ - -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` - - sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \ - -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$? - - # Check whether header files must be updated. - if test $first = no; then - if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then - echo "$2" is unchanged - rm -f "$target" - else - echo updating "$2" - mv -f "$target" "$realtarget" - fi - fi - else - # A missing file is only an error for the first file. This - # is a blatant hack to let us support using "yacc -d". If -d - # is not specified, we don't want an error when the header - # file is "missing". - if test $first = yes; then - ret=1 - fi - fi - shift - shift - first=no - done -else - ret=$? -fi - -# Remove the directory. -cd .. -rm -rf $dirname - -exit $ret - -# Local Variables: -# mode: shell-script -# sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: -- cgit v1.2.3