Imported Upstream version 0.48 upstream upstream/0.48
authorAnas Nashif <anas.nashif@intel.com>
Tue, 15 Jan 2013 04:20:15 +0000 (20:20 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Tue, 15 Jan 2013 04:20:15 +0000 (20:20 -0800)
43 files changed:
ChangeLog
Makefile.am
Makefile.in
btio/btio.c
btio/btio.h
client/bluetooth.c
client/map.c
client/pbap.c
client/transfer.c
client/transfer.h
configure
configure.ac
doc/client-api.txt
gdbus/gdbus.h
gdbus/mainloop.c
gdbus/object.c
gdbus/watch.c
gobex/gobex-apparam.c [new file with mode: 0644]
gobex/gobex-apparam.h [new file with mode: 0644]
gobex/gobex-debug.h
gobex/gobex-header.c
gobex/gobex-header.h
gobex/gobex.c
plugins/bluetooth.c
plugins/filesystem.c
plugins/irmc.c
plugins/mas.c
plugins/messages-dummy.c
plugins/messages-tracker.c
plugins/messages.h
plugins/pbap.c
plugins/phonebook-ebook.c
plugins/phonebook-tracker.c
plugins/phonebook.h
src/map_ap.c [deleted file]
src/map_ap.h
src/server.c
test/map-client
test/pbap-client
tools/test-client.c
tools/test-server.c
unit/test-gobex-apparam.c [new file with mode: 0644]
unit/test-gobex-header.c

index 89a2607..eda7900 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+ver 0.48:
+       Fix issue with phonebook contacts query.
+       Add support for phonebook client filters.
+       Add support for message status handling.
+       Add support for OBEX application parameter API.
+
 ver 0.47:
        Update client session API.
        Change D-Bus namespace to org.bluez.obex.
index 97a1553..724dd5d 100644 (file)
@@ -20,7 +20,8 @@ gobex_sources = gobex/gobex.h gobex/gobex.c \
                        gobex/gobex-defs.h gobex/gobex-defs.c \
                        gobex/gobex-packet.c gobex/gobex-packet.h \
                        gobex/gobex-header.c gobex/gobex-header.h \
-                       gobex/gobex-transfer.c gobex/gobex-debug.h
+                       gobex/gobex-transfer.c gobex/gobex-debug.h \
+                       gobex/gobex-apparam.h gobex/gobex-apparam.c
 
 noinst_PROGRAMS =
 libexec_PROGRAMS =
@@ -62,7 +63,7 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
 
 builtin_modules += mas
 builtin_sources += plugins/mas.c plugins/messages.h \
-                       src/map_ap.c src/map_ap.h
+                       src/map_ap.h
 
 builtin_modules += irmc
 builtin_sources += plugins/irmc.c
@@ -126,7 +127,7 @@ client_obex_client_SOURCES = $(gdbus_sources) $(gobex_sources) \
                                client/transport.h client/transport.c \
                                client/dbus.h client/dbus.c \
                                client/driver.h client/driver.c \
-                               src/map_ap.h src/map_ap.c
+                               src/map_ap.h
 
 client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 endif
@@ -165,11 +166,12 @@ plugins/phonebook.c: plugins/@PHONEBOOK_DRIVER@
 plugins/messages.c: plugins/@MESSAGES_DRIVER@
        $(AM_V_GEN)$(LN_S) @abs_top_srcdir@/$< $@
 
-TESTS = unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \
-                                               unit/test-gobex-transfer
+TESTS = unit/test-gobex-apparam unit/test-gobex-header unit/test-gobex-packet \
+                               unit/test-gobex unit/test-gobex-transfer
 
 noinst_PROGRAMS += unit/test-gobex-header unit/test-gobex-packet \
-                               unit/test-gobex unit/test-gobex-transfer
+                       unit/test-gobex unit/test-gobex-transfer \
+                       unit/test-gobex-apparam
 
 unit_test_gobex_SOURCES = $(gobex_sources) unit/test-gobex.c \
                                                        unit/util.c unit/util.h
@@ -187,6 +189,10 @@ unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
                                                unit/test-gobex-transfer.c
 unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
 
+unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-apparam.c
+unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
+
 if READLINE
 noinst_PROGRAMS += tools/test-client
 tools_test_client_SOURCES = $(gobex_sources) $(btio_sources) \
index 3286903..056839e 100644 (file)
@@ -55,7 +55,8 @@ build_triplet = @build@
 host_triplet = @host@
 noinst_PROGRAMS = unit/test-gobex-header$(EXEEXT) \
        unit/test-gobex-packet$(EXEEXT) unit/test-gobex$(EXEEXT) \
-       unit/test-gobex-transfer$(EXEEXT) $(am__EXEEXT_3) \
+       unit/test-gobex-transfer$(EXEEXT) \
+       unit/test-gobex-apparam$(EXEEXT) $(am__EXEEXT_3) \
        tools/test-server$(EXEEXT)
 libexec_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
 @SERVER_TRUE@am__append_1 = src/obexd.service.in
@@ -66,7 +67,8 @@ libexec_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
 @SERVER_TRUE@am__append_6 = src/obexd
 @CLIENT_TRUE@am__append_7 = client/obex-client.service.in
 @CLIENT_TRUE@am__append_8 = client/obex-client
-TESTS = unit/test-gobex-header$(EXEEXT) \
+TESTS = unit/test-gobex-apparam$(EXEEXT) \
+       unit/test-gobex-header$(EXEEXT) \
        unit/test-gobex-packet$(EXEEXT) unit/test-gobex$(EXEEXT) \
        unit/test-gobex-transfer$(EXEEXT)
 @READLINE_TRUE@am__append_9 = tools/test-client
@@ -126,7 +128,8 @@ am__client_obex_client_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \
        gobex/gobex.c gobex/gobex-defs.h gobex/gobex-defs.c \
        gobex/gobex-packet.c gobex/gobex-packet.h gobex/gobex-header.c \
        gobex/gobex-header.h gobex/gobex-transfer.c \
-       gobex/gobex-debug.h btio/btio.h btio/btio.c client/main.c \
+       gobex/gobex-debug.h gobex/gobex-apparam.h \
+       gobex/gobex-apparam.c btio/btio.h btio/btio.c client/main.c \
        src/log.h src/log.c client/manager.h client/manager.c \
        client/session.h client/session.c client/bluetooth.h \
        client/bluetooth.c client/sync.h client/sync.c client/pbap.h \
@@ -134,13 +137,13 @@ am__client_obex_client_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \
        client/opp.c client/map.h client/map.c client/transfer.h \
        client/transfer.c client/transport.h client/transport.c \
        client/dbus.h client/dbus.c client/driver.h client/driver.c \
-       src/map_ap.h src/map_ap.c
+       src/map_ap.h
 am__dirstamp = $(am__leading_dot)dirstamp
 am__objects_1 = gdbus/mainloop.$(OBJEXT) gdbus/watch.$(OBJEXT) \
        gdbus/object.$(OBJEXT) gdbus/polkit.$(OBJEXT)
 am__objects_2 = gobex/gobex.$(OBJEXT) gobex/gobex-defs.$(OBJEXT) \
        gobex/gobex-packet.$(OBJEXT) gobex/gobex-header.$(OBJEXT) \
-       gobex/gobex-transfer.$(OBJEXT)
+       gobex/gobex-transfer.$(OBJEXT) gobex/gobex-apparam.$(OBJEXT)
 am__objects_3 = btio/btio.$(OBJEXT)
 @CLIENT_TRUE@am_client_obex_client_OBJECTS = $(am__objects_1) \
 @CLIENT_TRUE@  $(am__objects_2) $(am__objects_3) \
@@ -151,7 +154,7 @@ am__objects_3 = btio/btio.$(OBJEXT)
 @CLIENT_TRUE@  client/opp.$(OBJEXT) client/map.$(OBJEXT) \
 @CLIENT_TRUE@  client/transfer.$(OBJEXT) \
 @CLIENT_TRUE@  client/transport.$(OBJEXT) client/dbus.$(OBJEXT) \
-@CLIENT_TRUE@  client/driver.$(OBJEXT) src/map_ap.$(OBJEXT)
+@CLIENT_TRUE@  client/driver.$(OBJEXT)
 client_obex_client_OBJECTS = $(am_client_obex_client_OBJECTS)
 client_obex_client_DEPENDENCIES =
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -163,12 +166,13 @@ am__src_obexd_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \
        plugins/filesystem.h plugins/pcsuite.c plugins/opp.c \
        plugins/ftp.c plugins/ftp.h plugins/pbap.c plugins/phonebook.h \
        plugins/vcard.h plugins/vcard.c plugins/mas.c \
-       plugins/messages.h src/map_ap.c src/map_ap.h plugins/irmc.c \
+       plugins/messages.h src/map_ap.h plugins/irmc.c \
        plugins/syncevolution.c btio/btio.h btio/btio.c gobex/gobex.h \
        gobex/gobex.c gobex/gobex-defs.h gobex/gobex-defs.c \
        gobex/gobex-packet.c gobex/gobex-packet.h gobex/gobex-header.c \
        gobex/gobex-header.h gobex/gobex-transfer.c \
-       gobex/gobex-debug.h src/main.c src/obexd.h src/plugin.h \
+       gobex/gobex-debug.h gobex/gobex-apparam.h \
+       gobex/gobex-apparam.c src/main.c src/obexd.h src/plugin.h \
        src/plugin.c src/log.h src/log.c src/manager.h src/manager.c \
        src/obex.h src/obex.c src/obex-priv.h src/mimetype.h \
        src/mimetype.c src/service.h src/service.c src/transport.h \
@@ -181,7 +185,7 @@ am__src_obexd_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \
 @SERVER_TRUE@  $(am__objects_5) plugins/opp.$(OBJEXT) \
 @SERVER_TRUE@  plugins/ftp.$(OBJEXT) plugins/pbap.$(OBJEXT) \
 @SERVER_TRUE@  plugins/vcard.$(OBJEXT) plugins/mas.$(OBJEXT) \
-@SERVER_TRUE@  src/map_ap.$(OBJEXT) plugins/irmc.$(OBJEXT) \
+@SERVER_TRUE@  plugins/irmc.$(OBJEXT) \
 @SERVER_TRUE@  plugins/syncevolution.$(OBJEXT)
 @SERVER_TRUE@am_src_obexd_OBJECTS = $(am__objects_1) $(am__objects_6) \
 @SERVER_TRUE@  $(am__objects_3) $(am__objects_2) \
@@ -203,7 +207,8 @@ src_obexd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 am__tools_test_client_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \
        gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \
        gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \
-       gobex/gobex-transfer.c gobex/gobex-debug.h btio/btio.h \
+       gobex/gobex-transfer.c gobex/gobex-debug.h \
+       gobex/gobex-apparam.h gobex/gobex-apparam.c btio/btio.h \
        btio/btio.c tools/test-client.c
 @READLINE_TRUE@am_tools_test_client_OBJECTS = $(am__objects_2) \
 @READLINE_TRUE@        $(am__objects_3) tools/test-client.$(OBJEXT)
@@ -217,6 +222,11 @@ am_unit_test_gobex_OBJECTS = $(am__objects_2) \
        unit/test-gobex.$(OBJEXT) unit/util.$(OBJEXT)
 unit_test_gobex_OBJECTS = $(am_unit_test_gobex_OBJECTS)
 unit_test_gobex_DEPENDENCIES =
+am_unit_test_gobex_apparam_OBJECTS = $(am__objects_2) \
+       unit/util.$(OBJEXT) unit/test-gobex-apparam.$(OBJEXT)
+unit_test_gobex_apparam_OBJECTS =  \
+       $(am_unit_test_gobex_apparam_OBJECTS)
+unit_test_gobex_apparam_DEPENDENCIES =
 am_unit_test_gobex_header_OBJECTS = $(am__objects_2) \
        unit/test-gobex-header.$(OBJEXT) unit/util.$(OBJEXT)
 unit_test_gobex_header_OBJECTS = $(am_unit_test_gobex_header_OBJECTS)
@@ -259,6 +269,7 @@ am__v_GEN_0 = @echo "  GEN   " $@;
 SOURCES = $(client_obex_client_SOURCES) $(src_obexd_SOURCES) \
        $(nodist_src_obexd_SOURCES) $(tools_test_client_SOURCES) \
        $(tools_test_server_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)
@@ -266,6 +277,7 @@ DIST_SOURCES = $(am__client_obex_client_SOURCES_DIST) \
        $(am__src_obexd_SOURCES_DIST) \
        $(am__tools_test_client_SOURCES_DIST) \
        $(tools_test_server_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)
@@ -462,7 +474,8 @@ gobex_sources = gobex/gobex.h gobex/gobex.c \
                        gobex/gobex-defs.h gobex/gobex-defs.c \
                        gobex/gobex-packet.c gobex/gobex-packet.h \
                        gobex/gobex-header.c gobex/gobex-header.h \
-                       gobex/gobex-transfer.c gobex/gobex-debug.h
+                       gobex/gobex-transfer.c gobex/gobex-debug.h \
+                       gobex/gobex-apparam.h gobex/gobex-apparam.c
 
 @SERVER_TRUE@confdir = $(sysconfdir)/obex
 @SERVER_TRUE@builtin_modules = bluetooth $(am__append_2) filesystem \
@@ -473,8 +486,8 @@ gobex_sources = gobex/gobex.h gobex/gobex.c \
 @SERVER_TRUE@  $(am__append_5) plugins/opp.c plugins/ftp.c \
 @SERVER_TRUE@  plugins/ftp.h plugins/pbap.c plugins/phonebook.h \
 @SERVER_TRUE@  plugins/vcard.h plugins/vcard.c plugins/mas.c \
-@SERVER_TRUE@  plugins/messages.h src/map_ap.c src/map_ap.h \
-@SERVER_TRUE@  plugins/irmc.c plugins/syncevolution.c
+@SERVER_TRUE@  plugins/messages.h src/map_ap.h plugins/irmc.c \
+@SERVER_TRUE@  plugins/syncevolution.c
 @SERVER_TRUE@builtin_nodist = plugins/phonebook.c plugins/messages.c
 @SERVER_TRUE@src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) $(btio_sources) \
 @SERVER_TRUE@                  $(gobex_sources) src/main.c src/obexd.h \
@@ -510,7 +523,7 @@ gobex_sources = gobex/gobex.h gobex/gobex.c \
 @CLIENT_TRUE@                          client/transport.h client/transport.c \
 @CLIENT_TRUE@                          client/dbus.h client/dbus.c \
 @CLIENT_TRUE@                          client/driver.h client/driver.c \
-@CLIENT_TRUE@                          src/map_ap.h src/map_ap.c
+@CLIENT_TRUE@                          src/map_ap.h
 
 @CLIENT_TRUE@client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 service_DATA = $(service_in_files:.service.in=.service)
@@ -551,6 +564,10 @@ unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
                                                unit/test-gobex-transfer.c
 
 unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
+unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-apparam.c
+
+unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
 @READLINE_TRUE@tools_test_client_SOURCES = $(gobex_sources) $(btio_sources) \
 @READLINE_TRUE@                                                        tools/test-client.c
 
@@ -730,6 +747,8 @@ gobex/gobex-header.$(OBJEXT): gobex/$(am__dirstamp) \
        gobex/$(DEPDIR)/$(am__dirstamp)
 gobex/gobex-transfer.$(OBJEXT): gobex/$(am__dirstamp) \
        gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/gobex-apparam.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
 btio/$(am__dirstamp):
        @$(MKDIR_P) btio
        @: > btio/$(am__dirstamp)
@@ -777,8 +796,6 @@ client/dbus.$(OBJEXT): client/$(am__dirstamp) \
        client/$(DEPDIR)/$(am__dirstamp)
 client/driver.$(OBJEXT): client/$(am__dirstamp) \
        client/$(DEPDIR)/$(am__dirstamp)
-src/map_ap.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
 client/obex-client$(EXEEXT): $(client_obex_client_OBJECTS) $(client_obex_client_DEPENDENCIES) $(EXTRA_client_obex_client_DEPENDENCIES) client/$(am__dirstamp)
        @rm -f client/obex-client$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(client_obex_client_OBJECTS) $(client_obex_client_LDADD) $(LIBS)
@@ -860,6 +877,11 @@ unit/util.$(OBJEXT): unit/$(am__dirstamp) \
 unit/test-gobex$(EXEEXT): $(unit_test_gobex_OBJECTS) $(unit_test_gobex_DEPENDENCIES) $(EXTRA_unit_test_gobex_DEPENDENCIES) unit/$(am__dirstamp)
        @rm -f unit/test-gobex$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(unit_test_gobex_OBJECTS) $(unit_test_gobex_LDADD) $(LIBS)
+unit/test-gobex-apparam.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex-apparam$(EXEEXT): $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_DEPENDENCIES) $(EXTRA_unit_test_gobex_apparam_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-gobex-apparam$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_LDADD) $(LIBS)
 unit/test-gobex-header.$(OBJEXT): unit/$(am__dirstamp) \
        unit/$(DEPDIR)/$(am__dirstamp)
 unit/test-gobex-header$(EXEEXT): $(unit_test_gobex_header_OBJECTS) $(unit_test_gobex_header_DEPENDENCIES) $(EXTRA_unit_test_gobex_header_DEPENDENCIES) unit/$(am__dirstamp)
@@ -896,6 +918,7 @@ mostlyclean-compile:
        -rm -f gdbus/object.$(OBJEXT)
        -rm -f gdbus/polkit.$(OBJEXT)
        -rm -f gdbus/watch.$(OBJEXT)
+       -rm -f gobex/gobex-apparam.$(OBJEXT)
        -rm -f gobex/gobex-defs.$(OBJEXT)
        -rm -f gobex/gobex-header.$(OBJEXT)
        -rm -f gobex/gobex-packet.$(OBJEXT)
@@ -917,7 +940,6 @@ mostlyclean-compile:
        -rm -f src/log.$(OBJEXT)
        -rm -f src/main.$(OBJEXT)
        -rm -f src/manager.$(OBJEXT)
-       -rm -f src/map_ap.$(OBJEXT)
        -rm -f src/mimetype.$(OBJEXT)
        -rm -f src/obex.$(OBJEXT)
        -rm -f src/plugin.$(OBJEXT)
@@ -926,6 +948,7 @@ mostlyclean-compile:
        -rm -f src/transport.$(OBJEXT)
        -rm -f tools/test-client.$(OBJEXT)
        -rm -f tools/test-server.$(OBJEXT)
+       -rm -f unit/test-gobex-apparam.$(OBJEXT)
        -rm -f unit/test-gobex-header.$(OBJEXT)
        -rm -f unit/test-gobex-packet.$(OBJEXT)
        -rm -f unit/test-gobex-transfer.$(OBJEXT)
@@ -953,6 +976,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/object.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/polkit.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/watch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-apparam.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-defs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-header.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-packet.Po@am__quote@
@@ -974,7 +998,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/log.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/map_ap.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mimetype.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/obex.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/plugin.Po@am__quote@
@@ -983,6 +1006,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/transport.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/test-client.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/test-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-apparam.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-header.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-packet.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-transfer.Po@am__quote@
index 9781ec4..44c2f9b 100644 (file)
 #endif
 
 #define ERROR_FAILED(gerr, str, err) \
-               g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+               g_set_error(gerr, BT_IO_ERROR, err, \
                                str ": %s (%d)", strerror(err), err)
 
 #define DEFAULT_DEFER_TIMEOUT 30
 
+typedef enum {
+       BT_IO_L2CAP,
+       BT_IO_RFCOMM,
+       BT_IO_SCO,
+       BT_IO_INVALID,
+} BtIOType;
+
 struct set_opts {
        bdaddr_t src;
        bdaddr_t dst;
+       BtIOType type;
+       uint8_t dst_type;
        int defer;
        int sec_level;
        uint8_t channel;
@@ -84,6 +93,48 @@ struct server {
        GDestroyNotify destroy;
 };
 
+static BtIOType bt_io_get_type(GIOChannel *io, GError **gerr)
+{
+       int sk = g_io_channel_unix_get_fd(io);
+       int domain, proto, err;
+       socklen_t len;
+
+       domain = 0;
+       len = sizeof(domain);
+       err = getsockopt(sk, SOL_SOCKET, SO_DOMAIN, &domain, &len);
+       if (err < 0) {
+               ERROR_FAILED(gerr, "getsockopt(SO_DOMAIN)", errno);
+               return BT_IO_INVALID;
+       }
+
+       if (domain != AF_BLUETOOTH) {
+               g_set_error(gerr, BT_IO_ERROR, EINVAL,
+                               "BtIO socket domain not AF_BLUETOOTH");
+               return BT_IO_INVALID;
+       }
+
+       proto = 0;
+       len = sizeof(proto);
+       err = getsockopt(sk, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
+       if (err < 0) {
+               ERROR_FAILED(gerr, "getsockopt(SO_PROTOCOL)", errno);
+               return BT_IO_INVALID;
+       }
+
+       switch (proto) {
+       case BTPROTO_RFCOMM:
+               return BT_IO_RFCOMM;
+       case BTPROTO_SCO:
+               return BT_IO_SCO;
+       case BTPROTO_L2CAP:
+               return BT_IO_L2CAP;
+       default:
+               g_set_error(gerr, BT_IO_ERROR, EINVAL,
+                                       "Unknown BtIO socket type");
+               return BT_IO_INVALID;
+       }
+}
+
 static void server_remove(struct server *server)
 {
        if (server->destroy)
@@ -123,19 +174,28 @@ static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct accept *accept = user_data;
-       GError *err = NULL;
+       GError *gerr = NULL;
 
        /* If the user aborted this accept attempt */
        if ((cond & G_IO_NVAL) || check_nval(io))
                return FALSE;
 
-       if (cond & (G_IO_HUP | G_IO_ERR))
-               g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
-                               "HUP or ERR on socket");
+       if (cond & (G_IO_HUP | G_IO_ERR)) {
+               int err, sk_err, sock = g_io_channel_unix_get_fd(io);
+               socklen_t len = sizeof(sk_err);
 
-       accept->connect(io, err, accept->user_data);
+               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+                       err = -errno;
+               else
+                       err = -sk_err;
+
+               if (err < 0)
+                       ERROR_FAILED(&gerr, "HUP or ERR on socket", -err);
+       }
+
+       accept->connect(io, gerr, accept->user_data);
 
-       g_clear_error(&err);
+       g_clear_error(&gerr);
 
        return FALSE;
 }
@@ -145,32 +205,26 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
 {
        struct connect *conn = user_data;
        GError *gerr = NULL;
+       int err, sk_err, sock;
+       socklen_t len = sizeof(sk_err);
 
        /* If the user aborted this connect attempt */
        if ((cond & G_IO_NVAL) || check_nval(io))
                return FALSE;
 
-       if (cond & G_IO_OUT) {
-               int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io);
-               socklen_t len = sizeof(sk_err);
+       sock = g_io_channel_unix_get_fd(io);
 
-               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
-                       err = -errno;
-               else
-                       err = -sk_err;
+       if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+               err = -errno;
+       else
+               err = -sk_err;
 
-               if (err < 0)
-                       g_set_error(&gerr, BT_IO_ERROR,
-                                       BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
-                                       strerror(-err), -err);
-       } else if (cond & (G_IO_HUP | G_IO_ERR))
-               g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-                               "HUP or ERR on socket");
+       if (err < 0)
+               ERROR_FAILED(&gerr, "connect error", -err);
 
        conn->connect(io, gerr, conn->user_data);
 
-       if (gerr)
-               g_error_free(gerr);
+       g_clear_error(&gerr);
 
        return FALSE;
 }
@@ -280,8 +334,8 @@ static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm,
        return 0;
 }
 
-static int l2cap_connect(int sock, const bdaddr_t *dst,
-                                       uint16_t psm, uint16_t cid)
+static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type,
+                                               uint16_t psm, uint16_t cid)
 {
        int err;
        struct sockaddr_l2 addr;
@@ -294,6 +348,8 @@ static int l2cap_connect(int sock, const bdaddr_t *dst,
        else
                addr.l2_psm = htobs(psm);
 
+       addr.l2_bdaddr_type = dst_type;
+
        err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
                return -errno;
@@ -387,7 +443,7 @@ static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
        int ret;
 
        if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
-               g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+               g_set_error(err, BT_IO_ERROR, EINVAL,
                                "Valid security level range is %d-%d",
                                BT_SECURITY_LOW, BT_SECURITY_HIGH);
                return FALSE;
@@ -693,11 +749,13 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
        memset(opts, 0, sizeof(*opts));
 
        /* Set defaults */
+       opts->type = BT_IO_SCO;
        opts->defer = DEFAULT_DEFER_TIMEOUT;
        opts->master = -1;
        opts->mode = L2CAP_MODE_BASIC;
        opts->flushable = -1;
        opts->priority = 0;
+       opts->dst_type = BDADDR_BREDR;
 
        while (opt != BT_IO_OPT_INVALID) {
                switch (opt) {
@@ -714,6 +772,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                case BT_IO_OPT_DEST_BDADDR:
                        bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
                        break;
+               case BT_IO_OPT_DEST_TYPE:
+                       opts->dst_type = va_arg(args, int);
+                       break;
                case BT_IO_OPT_DEFER_TIMEOUT:
                        opts->defer = va_arg(args, int);
                        break;
@@ -721,12 +782,15 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                        opts->sec_level = va_arg(args, int);
                        break;
                case BT_IO_OPT_CHANNEL:
+                       opts->type = BT_IO_RFCOMM;
                        opts->channel = va_arg(args, int);
                        break;
                case BT_IO_OPT_PSM:
+                       opts->type = BT_IO_L2CAP;
                        opts->psm = va_arg(args, int);
                        break;
                case BT_IO_OPT_CID:
+                       opts->type = BT_IO_L2CAP;
                        opts->cid = va_arg(args, int);
                        break;
                case BT_IO_OPT_MTU:
@@ -757,7 +821,7 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                        opts->priority = va_arg(args, int);
                        break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -875,6 +939,9 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                case BT_IO_OPT_DEST_BDADDR:
                        bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
                        break;
+               case BT_IO_OPT_DEST_TYPE:
+                       ERROR_FAILED(err, "Not implemented", EINVAL);
+                       return FALSE;
                case BT_IO_OPT_DEFER_TIMEOUT:
                        len = sizeof(int);
                        if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
@@ -950,7 +1017,7 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                        *(va_arg(args, uint32_t *)) = priority;
                        break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -1057,7 +1124,7 @@ static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
                        memcpy(va_arg(args, uint8_t *), dev_class, 3);
                        break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -1140,7 +1207,7 @@ static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
                        memcpy(va_arg(args, uint8_t *), dev_class, 3);
                        break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -1159,19 +1226,17 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
        sock = g_io_channel_unix_get_fd(io);
 
        switch (type) {
-       case BT_IO_L2RAW:
        case BT_IO_L2CAP:
-       case BT_IO_L2ERTM:
                return l2cap_get(sock, err, opt1, args);
        case BT_IO_RFCOMM:
                return rfcomm_get(sock, err, opt1, args);
        case BT_IO_SCO:
                return sco_get(sock, err, opt1, args);
+       default:
+               g_set_error(err, BT_IO_ERROR, EINVAL,
+                               "Unknown BtIO type %d", type);
+               return FALSE;
        }
-
-       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                       "Unknown BtIO type %d", type);
-       return FALSE;
 }
 
 gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
@@ -1204,13 +1269,13 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
        return TRUE;
 }
 
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
-                                                       BtIOOption opt1, ...)
+gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
        va_list args;
        gboolean ret;
        struct set_opts opts;
        int sock;
+       BtIOType type;
 
        va_start(args, opt1);
        ret = parse_set_opts(&opts, err, opt1, args);
@@ -1219,12 +1284,14 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
        if (!ret)
                return ret;
 
+       type = bt_io_get_type(io, err);
+       if (type == BT_IO_INVALID)
+               return FALSE;
+
        sock = g_io_channel_unix_get_fd(io);
 
        switch (type) {
-       case BT_IO_L2RAW:
        case BT_IO_L2CAP:
-       case BT_IO_L2ERTM:
                return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
                                opts.mode, opts.master, opts.flushable,
                                opts.priority, err);
@@ -1232,18 +1299,23 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
                return rfcomm_set(sock, opts.sec_level, opts.master, err);
        case BT_IO_SCO:
                return sco_set(sock, opts.mtu, err);
+       default:
+               g_set_error(err, BT_IO_ERROR, EINVAL,
+                               "Unknown BtIO type %d", type);
+               return FALSE;
        }
 
-       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                       "Unknown BtIO type %d", type);
-       return FALSE;
 }
 
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
-                                                       BtIOOption opt1, ...)
+gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
        va_list args;
        gboolean ret;
+       BtIOType type;
+
+       type = bt_io_get_type(io, err);
+       if (type == BT_IO_INVALID)
+               return FALSE;
 
        va_start(args, opt1);
        ret = get_valist(io, type, err, opt1, args);
@@ -1252,25 +1324,13 @@ gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
        return ret;
 }
 
-static GIOChannel *create_io(BtIOType type, gboolean server,
-                                       struct set_opts *opts, GError **err)
+static GIOChannel *create_io(gboolean server, struct set_opts *opts,
+                                                               GError **err)
 {
        int sock;
        GIOChannel *io;
 
-       switch (type) {
-       case BT_IO_L2RAW:
-               sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
-               if (sock < 0) {
-                       ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
-                       return NULL;
-               }
-               if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
-                                                       opts->cid, err) < 0)
-                       goto failed;
-               if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, 0, err))
-                       goto failed;
-               break;
+       switch (opts->type) {
        case BT_IO_L2CAP:
                sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
                if (sock < 0) {
@@ -1285,20 +1345,6 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                                opts->priority, err))
                        goto failed;
                break;
-       case BT_IO_L2ERTM:
-               sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
-               if (sock < 0) {
-                       ERROR_FAILED(err, "socket(STREAM, L2CAP)", errno);
-                       return NULL;
-               }
-               if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
-                                                       opts->cid, err) < 0)
-                       goto failed;
-               if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
-                               opts->mode, opts->master, opts->flushable,
-                               opts->priority, err))
-                       goto failed;
-               break;
        case BT_IO_RFCOMM:
                sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
                if (sock < 0) {
@@ -1323,8 +1369,8 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                        goto failed;
                break;
        default:
-               g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                               "Unknown BtIO type %d", type);
+               g_set_error(err, BT_IO_ERROR, EINVAL,
+                               "Unknown BtIO type %d", opts->type);
                return NULL;
        }
 
@@ -1341,9 +1387,9 @@ failed:
        return NULL;
 }
 
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
-                               gpointer user_data, GDestroyNotify destroy,
-                               GError **gerr, BtIOOption opt1, ...)
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+                               GDestroyNotify destroy, GError **gerr,
+                               BtIOOption opt1, ...)
 {
        GIOChannel *io;
        va_list args;
@@ -1358,19 +1404,16 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
        if (ret == FALSE)
                return NULL;
 
-       io = create_io(type, FALSE, &opts, gerr);
+       io = create_io(FALSE, &opts, gerr);
        if (io == NULL)
                return NULL;
 
        sock = g_io_channel_unix_get_fd(io);
 
-       switch (type) {
-       case BT_IO_L2RAW:
-               err = l2cap_connect(sock, &opts.dst, 0, opts.cid);
-               break;
+       switch (opts.type) {
        case BT_IO_L2CAP:
-       case BT_IO_L2ERTM:
-               err = l2cap_connect(sock, &opts.dst, opts.psm, opts.cid);
+               err = l2cap_connect(sock, &opts.dst, opts.dst_type,
+                                                       opts.psm, opts.cid);
                break;
        case BT_IO_RFCOMM:
                err = rfcomm_connect(sock, &opts.dst, opts.channel);
@@ -1379,14 +1422,13 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
                err = sco_connect(sock, &opts.dst);
                break;
        default:
-               g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                                               "Unknown BtIO type %d", type);
+               g_set_error(gerr, BT_IO_ERROR, EINVAL,
+                                       "Unknown BtIO type %d", opts.type);
                return NULL;
        }
 
        if (err < 0) {
-               g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-                               "connect: %s (%d)", strerror(-err), -err);
+               ERROR_FAILED(gerr, "connect", -err);
                g_io_channel_unref(io);
                return NULL;
        }
@@ -1396,10 +1438,9 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
        return io;
 }
 
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
-                               BtIOConfirm confirm, gpointer user_data,
-                               GDestroyNotify destroy, GError **err,
-                               BtIOOption opt1, ...)
+GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
+                               gpointer user_data, GDestroyNotify destroy,
+                               GError **err, BtIOOption opt1, ...)
 {
        GIOChannel *io;
        va_list args;
@@ -1407,12 +1448,6 @@ GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
        int sock;
        gboolean ret;
 
-       if (type == BT_IO_L2RAW) {
-               g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                               "Server L2CAP RAW sockets not supported");
-               return NULL;
-       }
-
        va_start(args, opt1);
        ret = parse_set_opts(&opts, err, opt1, args);
        va_end(args);
@@ -1420,7 +1455,7 @@ GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
        if (ret == FALSE)
                return NULL;
 
-       io = create_io(type, TRUE, &opts, err);
+       io = create_io(TRUE, &opts, err);
        if (io == NULL)
                return NULL;
 
index 429e8c0..a6ff5a2 100644 (file)
 
 #include <glib.h>
 
-typedef enum {
-       BT_IO_ERROR_DISCONNECTED,
-       BT_IO_ERROR_CONNECT_FAILED,
-       BT_IO_ERROR_FAILED,
-       BT_IO_ERROR_INVALID_ARGS,
-} BtIOError;
-
 #define BT_IO_ERROR bt_io_error_quark()
 
 GQuark bt_io_error_quark(void);
 
 typedef enum {
-       BT_IO_L2RAW,
-       BT_IO_L2CAP,
-       BT_IO_L2ERTM,
-       BT_IO_RFCOMM,
-       BT_IO_SCO,
-} BtIOType;
-
-typedef enum {
        BT_IO_OPT_INVALID = 0,
        BT_IO_OPT_SOURCE,
        BT_IO_OPT_SOURCE_BDADDR,
        BT_IO_OPT_DEST,
        BT_IO_OPT_DEST_BDADDR,
+       BT_IO_OPT_DEST_TYPE,
        BT_IO_OPT_DEFER_TIMEOUT,
        BT_IO_OPT_SEC_LEVEL,
        BT_IO_OPT_KEY_SIZE,
@@ -92,19 +78,16 @@ typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
 gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
                                        GDestroyNotify destroy, GError **err);
 
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
-                                               BtIOOption opt1, ...);
+gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...);
 
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
-                                               BtIOOption opt1, ...);
+gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...);
 
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+                               GDestroyNotify destroy, GError **gerr,
+                               BtIOOption opt1, ...);
+
+GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
                                gpointer user_data, GDestroyNotify destroy,
                                GError **err, BtIOOption opt1, ...);
 
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
-                               BtIOConfirm confirm, gpointer user_data,
-                               GDestroyNotify destroy, GError **err,
-                               BtIOOption opt1, ...);
-
 #endif
index 0d91ea1..d233e5c 100644 (file)
@@ -160,6 +160,9 @@ static void session_destroy(struct bluetooth_session *session)
                g_io_channel_unref(session->io);
        }
 
+       if (session->sdp)
+               sdp_close(session->sdp);
+
        if (session->conn)
                dbus_connection_unref(session->conn);
 
@@ -191,7 +194,7 @@ static GIOChannel *transport_connect(const bdaddr_t *src, const bdaddr_t *dst,
        DBG("port %u", port);
 
        if (port > 31) {
-               io = bt_io_connect(BT_IO_L2CAP, function, user_data,
+               io = bt_io_connect(function, user_data,
                                NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, src,
                                BT_IO_OPT_DEST_BDADDR, dst,
@@ -202,7 +205,7 @@ static GIOChannel *transport_connect(const bdaddr_t *src, const bdaddr_t *dst,
                                BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                BT_IO_OPT_INVALID);
        } else {
-               io = bt_io_connect(BT_IO_RFCOMM, function, user_data,
+               io = bt_io_connect(function, user_data,
                                NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, src,
                                BT_IO_OPT_DEST_BDADDR, dst,
@@ -578,6 +581,7 @@ static guint bluetooth_connect(const char *source, const char *destination,
 
        session->id = ++id;
        session->func = func;
+       session->port = port;
        session->user_data = user_data;
 
        session->conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
@@ -631,7 +635,7 @@ static int bluetooth_getpacketopt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
        if (type != SOCK_SEQPACKET)
                return -EINVAL;
 
-       if (!bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, &omtu,
+       if (!bt_io_get(io, NULL, BT_IO_OPT_OMTU, &omtu,
                                                BT_IO_OPT_IMTU, &imtu,
                                                BT_IO_OPT_INVALID))
                return -EINVAL;
index e606cb2..dc72e4b 100644 (file)
 
 #include <errno.h>
 #include <string.h>
+#include <stdio.h>
 #include <glib.h>
 #include <gdbus.h>
 
+#include <gobex-apparam.h>
+
 #include "dbus.h"
 #include "log.h"
+#include "map_ap.h"
 
 #include "map.h"
 #include "transfer.h"
 #define ERROR_INTERFACE "org.bluez.obex.Error"
 #define MAS_UUID "00001132-0000-1000-8000-00805f9b34fb"
 
+#define DEFAULT_COUNT 1024
+#define DEFAULT_OFFSET 0
+
+#define CHARSET_UTF8 1
+
+static const char * const filter_list[] = {
+       "subject",
+       "timestamp",
+       "sender",
+       "sender-address",
+       "recipient",
+       "recipient-address",
+       "type",
+       "size",
+       "status",
+       "text",
+       "attachment",
+       "priority",
+       "read",
+       "sent",
+       "protected",
+       "replyto",
+       NULL
+};
+
+#define FILTER_BIT_MAX 15
+#define FILTER_ALL     0xFF
+
+#define STATUS_READ 0
+#define STATUS_DELETE 1
+#define FILLER_BYTE 0x30
+
 struct map_data {
        struct obc_session *session;
        DBusMessage *msg;
@@ -72,6 +108,7 @@ struct map_msg {
        uint64_t size;
        char *status;
        uint8_t flags;
+       DBusMessage *msg;
 };
 
 struct map_parser {
@@ -209,17 +246,21 @@ done:
        dbus_message_unref(map->msg);
 }
 
-static DBusMessage *map_get_folder_listing(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
+static DBusMessage *get_folder_listing(struct map_data *map,
+                                                       DBusMessage *message,
+                                                       GObexApparam *apparam)
 {
-       struct map_data *map = user_data;
        struct obc_transfer *transfer;
        GError *err = NULL;
        DBusMessage *reply;
 
        transfer = obc_transfer_get("x-obex/folder-listing", NULL, NULL, &err);
-       if (transfer == NULL)
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
                goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
 
        if (obc_session_queue(map->session, transfer, folder_listing_cb, map,
                                                                &err)) {
@@ -234,6 +275,88 @@ fail:
        return reply;
 }
 
+static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       guint16 num;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &num);
+
+       return g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET, num);
+}
+
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint16 num;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &num);
+
+       return g_obex_apparam_set_uint16(apparam, MAP_AP_MAXLISTCOUNT, num);
+}
+
+static GObexApparam *parse_folder_filters(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+               const char *key;
+               DBusMessageIter value, entry;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "Offset") == 0) {
+                       if (parse_offset(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "MaxCount") == 0) {
+                       if (parse_max_count(apparam, &value) == NULL)
+                               return NULL;
+               }
+
+               dbus_message_iter_next(&array);
+       }
+
+       return apparam;
+}
+
+static DBusMessage *map_list_folders(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       dbus_message_iter_init(message, &args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAP_AP_MAXLISTCOUNT,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET,
+                                                       DEFAULT_OFFSET);
+
+       if (parse_folder_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return get_folder_listing(map, message, apparam);
+}
+
 static void map_msg_free(void *data)
 {
        struct map_msg *msg = data;
@@ -258,11 +381,14 @@ static DBusMessage *map_msg_get(DBusConnection *connection,
        struct map_msg *msg = user_data;
        struct obc_transfer *transfer;
        const char *target_file;
+       gboolean attachment;
        GError *err = NULL;
        DBusMessage *reply;
+       GObexApparam *apparam;
 
        if (dbus_message_get_args(message, NULL,
                                DBUS_TYPE_STRING, &target_file,
+                               DBUS_TYPE_BOOLEAN, &attachment,
                                DBUS_TYPE_INVALID) == FALSE)
                return g_dbus_create_error(message,
                                ERROR_INTERFACE ".InvalidArguments", NULL);
@@ -272,6 +398,13 @@ static DBusMessage *map_msg_get(DBusConnection *connection,
        if (transfer == NULL)
                goto fail;
 
+       apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_ATTACHMENT,
+                                                               attachment);
+       apparam = g_obex_apparam_set_uint8(apparam, MAP_AP_CHARSET,
+                                                               CHARSET_UTF8);
+
+       obc_transfer_set_apparam(transfer, apparam);
+
        if (!obc_session_queue(msg->data->session, transfer, NULL, NULL, &err))
                goto fail;
 
@@ -284,12 +417,197 @@ fail:
        return reply;
 }
 
+static void set_message_status_cb(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct map_msg *msg = user_data;
+       DBusMessage *reply;
+
+       if (err != NULL) {
+               reply = g_dbus_create_error(msg->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto done;
+       }
+
+       reply = dbus_message_new_method_return(msg->msg);
+       if (reply == NULL) {
+               reply = g_dbus_create_error(msg->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+       }
+
+done:
+       g_dbus_send_message(conn, reply);
+       dbus_message_unref(msg->msg);
+       msg->msg = NULL;
+}
+
+static DBusMessage *map_msg_set_property(DBusConnection *connection,
+                                               DBusMessage *message,
+                                               void *user_data)
+{
+       struct map_msg *msg = user_data;
+       struct obc_transfer *transfer;
+       char *property;
+       gboolean status;
+       GError *err = NULL;
+       DBusMessage *reply;
+       GObexApparam *apparam;
+       char contents[2];
+       int op;
+       DBusMessageIter args, variant;
+
+       dbus_message_iter_init(message, &args);
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &property);
+       dbus_message_iter_next(&args);
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_recurse(&args, &variant);
+       if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_BOOLEAN)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&variant, &status);
+
+       /* MAP supports modifying only these two properties. */
+       if (property && strcasecmp(property, "Read") == 0) {
+               op = STATUS_READ;
+               if (status)
+                       msg->flags |= MAP_MSG_FLAG_READ;
+               else
+                       msg->flags &= ~MAP_MSG_FLAG_READ;
+       } else if (property && strcasecmp(property, "Deleted") == 0)
+               op = STATUS_DELETE;
+       else {
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       contents[0] = FILLER_BYTE;
+       contents[1] = '\0';
+
+       transfer = obc_transfer_put("x-bt/messageStatus", msg->handle, NULL,
+                                                       contents,
+                                                       sizeof(contents), &err);
+       if (transfer == NULL)
+               goto fail;
+
+       apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_STATUSINDICATOR,
+                                                               op);
+       apparam = g_obex_apparam_set_uint8(apparam, MAP_AP_STATUSVALUE,
+                                                               status);
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (!obc_session_queue(msg->data->session, transfer,
+                               set_message_status_cb, msg, &err))
+               goto fail;
+
+       msg->msg = dbus_message_ref(message);
+       return NULL;
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *map_msg_get_properties(DBusConnection *connection,
+                                               DBusMessage *message,
+                                               void *user_data)
+{
+       struct map_msg *msg = user_data;
+       GError *err = NULL;
+       DBusMessage *reply;
+       DBusMessageIter iter, data_array;
+       gboolean flag;
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL) {
+               reply = g_dbus_create_error(message,
+                                               ERROR_INTERFACE ".Failed",
+                                               NULL);
+               goto done;
+       }
+
+       dbus_message_iter_init_append(reply, &iter);
+       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,
+                                       &data_array);
+
+
+       obex_dbus_dict_append(&data_array, "Subject",
+                               DBUS_TYPE_STRING, &msg->subject);
+       obex_dbus_dict_append(&data_array, "Timestamp",
+                               DBUS_TYPE_STRING, &msg->timestamp);
+       obex_dbus_dict_append(&data_array, "Sender",
+                               DBUS_TYPE_STRING, &msg->sender);
+       obex_dbus_dict_append(&data_array, "SenderAddress",
+                               DBUS_TYPE_STRING, &msg->sender_address);
+       obex_dbus_dict_append(&data_array, "ReplyTo",
+                               DBUS_TYPE_STRING, &msg->replyto);
+       obex_dbus_dict_append(&data_array, "Recipient",
+                               DBUS_TYPE_STRING, &msg->recipient);
+       obex_dbus_dict_append(&data_array, "RecipientAddress",
+                               DBUS_TYPE_STRING, &msg->recipient_address);
+       obex_dbus_dict_append(&data_array, "Type",
+                               DBUS_TYPE_STRING, &msg->type);
+       obex_dbus_dict_append(&data_array, "Status",
+                               DBUS_TYPE_STRING, &msg->status);
+       obex_dbus_dict_append(&data_array, "Size",
+                               DBUS_TYPE_UINT64, &msg->size);
+
+       flag = (msg->flags & MAP_MSG_FLAG_PRIORITY) != 0;
+       obex_dbus_dict_append(&data_array, "Priority",
+                               DBUS_TYPE_BOOLEAN, &flag);
+
+       flag = (msg->flags & MAP_MSG_FLAG_READ) != 0;
+       obex_dbus_dict_append(&data_array, "Read",
+                               DBUS_TYPE_BOOLEAN, &flag);
+
+       flag = (msg->flags & MAP_MSG_FLAG_SENT) != 0;
+       obex_dbus_dict_append(&data_array, "Sent",
+                               DBUS_TYPE_BOOLEAN, &flag);
+
+       flag = (msg->flags & MAP_MSG_FLAG_PROTECTED) != 0;
+       obex_dbus_dict_append(&data_array, "Protected",
+                               DBUS_TYPE_BOOLEAN, &flag);
+
+       dbus_message_iter_close_container(&iter, &data_array);
+
+
+done:
+       if (err)
+               g_error_free(err);
+
+       return reply;
+}
+
 static const GDBusMethodTable map_msg_methods[] = {
        { GDBUS_METHOD("Get",
-                       GDBUS_ARGS({ "targetfile", "s" }),
+                       GDBUS_ARGS({ "targetfile", "s" },
+                                               { "attachment", "b" }),
                        GDBUS_ARGS({ "transfer", "o" },
                                                { "properties", "a{sv}" }),
                        map_msg_get) },
+       { GDBUS_METHOD("GetProperties",
+                       NULL,
+                       GDBUS_ARGS({ "properties", "a{sv}" }),
+                       map_msg_get_properties) },
+       { GDBUS_ASYNC_METHOD("SetProperty",
+                       GDBUS_ARGS({ "property", "sv" }), NULL,
+                       map_msg_set_property) },
        { }
 };
 
@@ -400,7 +718,7 @@ static void parse_size(struct map_msg *msg, const char *value,
 static void parse_priority(struct map_msg *msg, const char *value,
                                                        DBusMessageIter *iter)
 {
-       gboolean flag = strcasecmp(value, "no");
+       gboolean flag = strcasecmp(value, "no") != 0;
 
        if (flag)
                msg->flags |= MAP_MSG_FLAG_PRIORITY;
@@ -413,7 +731,7 @@ static void parse_priority(struct map_msg *msg, const char *value,
 static void parse_read(struct map_msg *msg, const char *value,
                                                        DBusMessageIter *iter)
 {
-       gboolean flag = strcasecmp(value, "no");
+       gboolean flag = strcasecmp(value, "no") != 0;
 
        if (flag)
                msg->flags |= MAP_MSG_FLAG_READ;
@@ -426,7 +744,7 @@ static void parse_read(struct map_msg *msg, const char *value,
 static void parse_sent(struct map_msg *msg, const char *value,
                                                        DBusMessageIter *iter)
 {
-       gboolean flag = strcasecmp(value, "no");
+       gboolean flag = strcasecmp(value, "no") != 0;
 
        if (flag)
                msg->flags |= MAP_MSG_FLAG_SENT;
@@ -439,7 +757,7 @@ static void parse_sent(struct map_msg *msg, const char *value,
 static void parse_protected(struct map_msg *msg, const char *value,
                                                        DBusMessageIter *iter)
 {
-       gboolean flag = strcasecmp(value, "no");
+       gboolean flag = strcasecmp(value, "no") != 0;
 
        if (flag)
                msg->flags |= MAP_MSG_FLAG_PROTECTED;
@@ -490,7 +808,7 @@ static void msg_element(GMarkupParseContext *ctxt, const gchar *element,
                        break;
        }
 
-       msg = g_hash_table_lookup(data->messages, key);
+       msg = g_hash_table_lookup(data->messages, values[i]);
        if (msg == NULL) {
                msg = map_msg_create(data, values[i]);
                if (msg == NULL)
@@ -594,27 +912,22 @@ done:
        dbus_message_unref(map->msg);
 }
 
-static DBusMessage *map_get_message_listing(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
+static DBusMessage *get_message_listing(struct map_data *map,
+                                                       DBusMessage *message,
+                                                       const char *folder,
+                                                       GObexApparam *apparam)
 {
-       struct map_data *map = user_data;
        struct obc_transfer *transfer;
-       const char *folder;
-       DBusMessageIter msg_iter;
        GError *err = NULL;
        DBusMessage *reply;
 
-       dbus_message_iter_init(message, &msg_iter);
-
-       if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_STRING)
-               return g_dbus_create_error(message,
-                               ERROR_INTERFACE ".InvalidArguments", NULL);
-
-       dbus_message_iter_get_basic(&msg_iter, &folder);
-
        transfer = obc_transfer_get("x-bt/MAP-msg-listing", folder, NULL, &err);
-       if (transfer == NULL)
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
                goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
 
        if (obc_session_queue(map->session, transfer, message_listing_cb, map,
                                                                &err)) {
@@ -629,18 +942,380 @@ fail:
        return reply;
 }
 
+static uint64_t get_filter_mask(const char *filterstr)
+{
+       int i;
+
+       if (!filterstr)
+               return 0;
+
+       if (!g_ascii_strcasecmp(filterstr, "ALL"))
+               return FILTER_ALL;
+
+       for (i = 0; filter_list[i] != NULL; i++)
+               if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
+                       return 1ULL << i;
+
+       return 0;
+}
+
+static int set_field(guint32 *filter, const char *filterstr)
+{
+       guint64 mask;
+
+       mask = get_filter_mask(filterstr);
+
+       if (mask == 0)
+               return -EINVAL;
+
+       *filter |= mask;
+       return 0;
+}
+
+static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+       guint32 filter = 0;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+               const char *string;
+
+               dbus_message_iter_get_basic(&array, &string);
+
+               if (set_field(&filter, string) < 0)
+                       return NULL;
+
+               dbus_message_iter_next(&array);
+       }
+
+       return g_obex_apparam_set_uint32(apparam, MAP_AP_PARAMETERMASK,
+                                                               filter);
+}
+
+static GObexApparam *parse_filter_type(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+       guint8 types = 0;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+               const char *string;
+
+               dbus_message_iter_get_basic(&array, &string);
+
+               if (!g_ascii_strcasecmp(string, "sms"))
+                       types |= 0x03; /* SMS_GSM and SMS_CDMA */
+               else if (!g_ascii_strcasecmp(string, "email"))
+                       types |= 0x04; /* EMAIL */
+               else if (!g_ascii_strcasecmp(string, "mms"))
+                       types |= 0x08; /* MMS */
+               else
+                       return NULL;
+       }
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERMESSAGETYPE,
+                                                                       types);
+}
+
+static GObexApparam *parse_period_begin(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERPERIODBEGIN,
+                                                               string);
+}
+
+static GObexApparam *parse_period_end(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERPERIODEND,
+                                                               string);
+}
+
+static GObexApparam *parse_filter_read(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint8 status = 0;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &status);
+
+       status = (status) ? 0x01 : 0x02;
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERREADSTATUS,
+                                                               status);
+}
+
+static GObexApparam *parse_filter_recipient(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERRECIPIENT,
+                                                               string);
+}
+
+static GObexApparam *parse_filter_sender(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERORIGINATOR,
+                                                               string);
+}
+
+static GObexApparam *parse_filter_priority(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint8 priority;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &priority);
+
+       priority = (priority) ? 0x01 : 0x02;
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERPRIORITY,
+                                                               priority);
+}
+
+static GObexApparam *parse_message_filters(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+
+       DBG("");
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+               const char *key;
+               DBusMessageIter value, entry;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "Offset") == 0) {
+                       if (parse_offset(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "MaxCount") == 0) {
+                       if (parse_max_count(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Fields") == 0) {
+                       if (parse_fields(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Types") == 0) {
+                       if (parse_filter_type(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "PeriodBegin") == 0) {
+                       if (parse_period_begin(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "PeriodEnd") == 0) {
+                       if (parse_period_end(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Read") == 0) {
+                       if (parse_filter_read(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Recipient") == 0) {
+                       if (parse_filter_recipient(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Sender") == 0) {
+                       if (parse_filter_sender(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Priority") == 0) {
+                       if (parse_filter_priority(apparam, &value) == NULL)
+                               return NULL;
+               }
+
+               dbus_message_iter_next(&array);
+       }
+
+       return apparam;
+}
+
+static DBusMessage *map_list_messages(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       const char *folder;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &folder);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAP_AP_MAXLISTCOUNT,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET,
+                                                       DEFAULT_OFFSET);
+
+       dbus_message_iter_next(&args);
+
+       if (parse_message_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return get_message_listing(map, message, folder, apparam);
+}
+
+static gchar **get_filter_strs(uint64_t filter, gint *size)
+{
+       gchar **list, **item;
+       gint i;
+
+       list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
+
+       item = list;
+
+       for (i = 0; filter_list[i] != NULL; i++)
+               if (filter & (1ULL << i))
+                       *(item++) = g_strdup(filter_list[i]);
+
+       *item = NULL;
+       *size = item - list;
+       return list;
+}
+
+static DBusMessage *map_list_filter_fields(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       gchar **filters = NULL;
+       gint size;
+       DBusMessage *reply;
+
+       filters = get_filter_strs(FILTER_ALL, &size);
+       reply = dbus_message_new_method_return(message);
+       dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_STRING, &filters, size,
+                               DBUS_TYPE_INVALID);
+
+       g_strfreev(filters);
+       return reply;
+}
+
+static void update_inbox_cb(struct obc_session *session,
+                               struct obc_transfer *transfer,
+                               GError *err, void *user_data)
+{
+       struct map_data *map = user_data;
+       DBusMessage *reply;
+
+       if (err != NULL) {
+               reply = g_dbus_create_error(map->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto done;
+       }
+
+       reply = dbus_message_new_method_return(map->msg);
+
+done:
+       g_dbus_send_message(conn, reply);
+       dbus_message_unref(map->msg);
+}
+
+static DBusMessage *map_update_inbox(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       DBusMessage *reply;
+       char contents[2];
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+
+       contents[0] = FILLER_BYTE;
+       contents[1] = '\0';
+
+       transfer = obc_transfer_put("x-bt/MAP-messageUpdate", NULL, NULL,
+                                               contents, sizeof(contents),
+                                               &err);
+       if (transfer == NULL)
+               goto fail;
+
+       if (!obc_session_queue(map->session, transfer, update_inbox_cb,
+                                                               map, &err))
+               goto fail;
+
+       map->msg = dbus_message_ref(message);
+
+       return NULL;
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
 static const GDBusMethodTable map_methods[] = {
        { GDBUS_ASYNC_METHOD("SetFolder",
                                GDBUS_ARGS({ "name", "s" }), NULL,
                                map_setpath) },
-       { GDBUS_ASYNC_METHOD("GetFolderListing",
-                                       GDBUS_ARGS({ "filter", "a{ss}" }),
-                                       GDBUS_ARGS({ "content", "aa{sv}" }),
-                                       map_get_folder_listing) },
-       { GDBUS_ASYNC_METHOD("GetMessageListing",
-                       GDBUS_ARGS({ "folder", "s" }, { "filter", "a{ss}" }),
+       { GDBUS_ASYNC_METHOD("ListFolders",
+                       GDBUS_ARGS({ "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "content", "aa{sv}" }),
+                       map_list_folders) },
+       { GDBUS_ASYNC_METHOD("ListMessages",
+                       GDBUS_ARGS({ "folder", "s" }, { "filter", "a{sv}" }),
                        GDBUS_ARGS({ "messages", "a{oa{sv}}" }),
-                       map_get_message_listing) },
+                       map_list_messages) },
+       { GDBUS_METHOD("ListFilterFields",
+                       NULL,
+                       GDBUS_ARGS({ "fields", "as" }),
+                       map_list_filter_fields) },
+       { GDBUS_ASYNC_METHOD("UpdateInbox",
+                       NULL,
+                       NULL,
+                       map_update_inbox) },
        { }
 };
 
index 48dbac1..6444605 100644 (file)
@@ -33,6 +33,7 @@
 #include <gdbus.h>
 
 #include <bluetooth/bluetooth.h>
+#include <gobex-apparam.h>
 
 #include "log.h"
 
 #define PHONEBOOKSIZE_TAG      0X08
 #define NEWMISSEDCALLS_TAG     0X09
 
-/* The following length is in the unit of byte */
-#define ORDER_LEN              1
-#define SEARCHATTRIB_LEN       1
-#define MAXLISTCOUNT_LEN       2
-#define LISTSTARTOFFSET_LEN    2
-#define FILTER_LEN             8
-#define FORMAT_LEN             1
-#define PHONEBOOKSIZE_LEN      2
-#define NEWMISSEDCALLS_LEN     1
-
-#define get_be16(val)  GUINT16_FROM_BE(bt_get_unaligned((guint16 *) val))
-
 static const char *filter_list[] = {
        "VERSION",
        "FN",
@@ -127,9 +116,6 @@ static const char *filter_list[] = {
 struct pbap_data {
        struct obc_session *session;
        char *path;
-       guint8 format;
-       guint8 order;
-       uint64_t filter;
 };
 
 struct pending_request {
@@ -137,38 +123,6 @@ struct pending_request {
        DBusMessage *msg;
 };
 
-struct pullphonebook_apparam {
-       uint8_t     filter_tag;
-       uint8_t     filter_len;
-       uint64_t    filter;
-       uint8_t     format_tag;
-       uint8_t     format_len;
-       uint8_t     format;
-       uint8_t     maxlistcount_tag;
-       uint8_t     maxlistcount_len;
-       uint16_t    maxlistcount;
-       uint8_t     liststartoffset_tag;
-       uint8_t     liststartoffset_len;
-       uint16_t    liststartoffset;
-} __attribute__ ((packed));
-
-struct pullvcardentry_apparam {
-        uint8_t     filter_tag;
-        uint8_t     filter_len;
-        uint64_t    filter;
-        uint8_t     format_tag;
-        uint8_t     format_len;
-        uint8_t     format;
-} __attribute__ ((packed));
-
-struct apparam_hdr {
-       uint8_t         tag;
-       uint8_t         len;
-       uint8_t         val[0];
-} __attribute__ ((packed));
-
-#define APPARAM_HDR_SIZE 2
-
 static DBusConnection *conn = NULL;
 
 static struct pending_request *pending_request_new(struct pbap_data *pbap,
@@ -232,14 +186,14 @@ static gchar *build_phonebook_path(const char *location, const char *item)
 
        if (!g_ascii_strcasecmp(location, "INT") ||
                        !g_ascii_strcasecmp(location, "INTERNAL"))
-               path = g_strdup("telecom");
+               path = g_strdup("/telecom");
        else if (!g_ascii_strncasecmp(location, "SIM", 3)) {
                if (strlen(location) == 3)
                        tmp = g_strdup("SIM1");
                else
                        tmp = g_ascii_strup(location, 4);
 
-               path = g_build_filename(tmp, "telecom", NULL);
+               path = g_build_filename("/", tmp, "telecom", NULL);
                g_free(tmp);
        } else
                return NULL;
@@ -295,48 +249,19 @@ static void pbap_setpath_cb(struct obc_session *session,
 static void read_return_apparam(struct obc_transfer *transfer,
                                guint16 *phone_book_size, guint8 *new_missed_calls)
 {
-       const struct apparam_hdr *hdr;
-       size_t size;
+       GObexApparam *apparam;
 
        *phone_book_size = 0;
        *new_missed_calls = 0;
 
-       hdr = obc_transfer_get_params(transfer, &size);
-       if (hdr == NULL)
+       apparam = obc_transfer_get_apparam(transfer);
+       if (apparam == NULL)
                return;
 
-       if (size < APPARAM_HDR_SIZE)
-               return;
-
-       while (size > APPARAM_HDR_SIZE) {
-               if (hdr->len > size - APPARAM_HDR_SIZE) {
-                       error("Unexpected PBAP pullphonebook app"
-                                       " length, tag %d, len %d",
-                                       hdr->tag, hdr->len);
-                       return;
-               }
-
-               switch (hdr->tag) {
-               case PHONEBOOKSIZE_TAG:
-                       if (hdr->len == PHONEBOOKSIZE_LEN) {
-                               guint16 val;
-                               memcpy(&val, hdr->val, sizeof(val));
-                               *phone_book_size = get_be16(&val);
-                       }
-                       break;
-               case NEWMISSEDCALLS_TAG:
-                       if (hdr->len == NEWMISSEDCALLS_LEN)
-                               *new_missed_calls = hdr->val[0];
-                       break;
-               default:
-                       error("Unexpected PBAP pullphonebook app"
-                                       " parameter, tag %d, len %d",
-                                       hdr->tag, hdr->len);
-               }
-
-               size -= APPARAM_HDR_SIZE + hdr->len;
-               hdr += APPARAM_HDR_SIZE + hdr->len;
-       }
+       g_obex_apparam_get_uint16(apparam, PHONEBOOKSIZE_TAG,
+                                                       phone_book_size);
+       g_obex_apparam_get_uint8(apparam, NEWMISSEDCALLS_TAG,
+                                                       new_missed_calls);
 }
 
 static void phonebook_size_callback(struct obc_session *session,
@@ -414,165 +339,75 @@ send:
        pending_request_free(request);
 }
 
-static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
-                                               DBusMessage *message,
-                                               guint8 type, const char *name,
-                                               const char *targetfile,
-                                               uint64_t filter, guint8 format,
-                                               guint16 maxlistcount,
-                                               guint16 liststartoffset,
-                                               GError **err)
+static GObexApparam *parse_format(GObexApparam *apparam, DBusMessageIter *iter)
 {
-       struct pending_request *request;
-       struct obc_transfer *transfer;
-       struct pullphonebook_apparam apparam;
-       session_callback_t func;
+       const char *string;
+       guint8 format;
 
-       transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, err);
-       if (transfer == NULL)
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
                return NULL;
 
-       apparam.filter_tag = FILTER_TAG;
-       apparam.filter_len = FILTER_LEN;
-       apparam.filter = GUINT64_TO_BE(filter);
-       apparam.format_tag = FORMAT_TAG;
-       apparam.format_len = FORMAT_LEN;
-       apparam.format = format;
-       apparam.maxlistcount_tag = MAXLISTCOUNT_TAG;
-       apparam.maxlistcount_len = MAXLISTCOUNT_LEN;
-       apparam.maxlistcount = GUINT16_TO_BE(maxlistcount);
-       apparam.liststartoffset_tag = LISTSTARTOFFSET_TAG;
-       apparam.liststartoffset_len = LISTSTARTOFFSET_LEN;
-       apparam.liststartoffset = GUINT16_TO_BE(liststartoffset);
+       dbus_message_iter_get_basic(iter, &string);
 
-       switch (type) {
-       case PULLPHONEBOOK:
-               func = NULL;
-               request = NULL;
-               break;
-       case GETPHONEBOOKSIZE:
-               func = phonebook_size_callback;
-               request = pending_request_new(pbap, message);
-               break;
-       default:
-               error("Unexpected type : 0x%2x", type);
+       if (!string || g_str_equal(string, ""))
+               format = FORMAT_VCARD21;
+       else if (!g_ascii_strcasecmp(string, "vcard21"))
+               format = FORMAT_VCARD21;
+       else if (!g_ascii_strcasecmp(string, "vcard30"))
+               format = FORMAT_VCARD30;
+       else
                return NULL;
-       }
 
-       obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
+       return g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
+}
 
-       if (!obc_session_queue(pbap->session, transfer, func, request, err)) {
-               if (request != NULL)
-                       pending_request_free(request);
+static GObexApparam *parse_order(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       const char *string;
+       guint8 order;
 
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
                return NULL;
-       }
-
 
-       return transfer;
-}
+       dbus_message_iter_get_basic(iter, &string);
 
-static guint8 *fill_apparam(guint8 *dest, void *buf, guint8 tag, guint8 len)
-{
-       if (dest && buf) {
-               *dest++ = tag;
-               *dest++ = len;
-               memcpy(dest, buf, len);
-               dest += len;
-       }
+       if (!string || g_str_equal(string, ""))
+               order = ORDER_INDEXED;
+       else if (!g_ascii_strcasecmp(string, "indexed"))
+               order = ORDER_INDEXED;
+       else if (!g_ascii_strcasecmp(string, "alphanumeric"))
+               order = ORDER_ALPHANUMERIC;
+       else if (!g_ascii_strcasecmp(string, "phonetic"))
+               order = ORDER_PHONETIC;
+       else
+               return NULL;
 
-       return dest;
+       return g_obex_apparam_set_uint8(apparam, ORDER_TAG, order);
 }
 
-static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
-                                       DBusMessage *message, const char *name,
-                                       guint8 order, char *searchval, guint8 attrib,
-                                       guint16 count, guint16 offset)
+static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
 {
-       struct pending_request *request;
-       struct obc_transfer *transfer;
-       guint8 *p, apparam[272];
-       gint apparam_size;
-       GError *err = NULL;
-       DBusMessage *reply;
-
-       transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
-       if (transfer == NULL)
-               goto fail;
+       guint16 num;
 
-       /* trunc the searchval string if it's length exceed the max value of guint8 */
-       if (strlen(searchval) > 254)
-               searchval[255] = '\0';
-
-       apparam_size = APPARAM_HDR_SIZE + ORDER_LEN +
-                       (APPARAM_HDR_SIZE + strlen(searchval) + 1) +
-                       (APPARAM_HDR_SIZE + SEARCHATTRIB_LEN) +
-                       (APPARAM_HDR_SIZE + MAXLISTCOUNT_LEN) +
-                       (APPARAM_HDR_SIZE + LISTSTARTOFFSET_LEN);
-
-       p = apparam;
-
-       p = fill_apparam(p, &order, ORDER_TAG, ORDER_LEN);
-       p = fill_apparam(p, searchval, SEARCHVALUE_TAG, strlen(searchval) + 1);
-       p = fill_apparam(p, &attrib, SEARCHATTRIB_TAG, SEARCHATTRIB_LEN);
-
-       count = GUINT16_TO_BE(count);
-       p = fill_apparam(p, &count, MAXLISTCOUNT_TAG, MAXLISTCOUNT_LEN);
-
-       offset = GUINT16_TO_BE(offset);
-       fill_apparam(p, &offset, LISTSTARTOFFSET_TAG, LISTSTARTOFFSET_LEN);
-
-       request = pending_request_new(pbap, message);
-
-       obc_transfer_set_params(transfer, apparam, apparam_size);
-
-       if (obc_session_queue(pbap->session, transfer,
-                               pull_vcard_listing_callback, request, &err))
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
                return NULL;
 
-       pending_request_free(request);
+       dbus_message_iter_get_basic(iter, &num);
 
-fail:
-       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
-                                                               err->message);
-       g_error_free(err);
-       return reply;
+       return g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG, num);
 }
 
-static int set_format(struct pbap_data *pbap, const char *formatstr)
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
 {
-       if (!formatstr || g_str_equal(formatstr, "")) {
-               pbap->format = FORMAT_VCARD21;
-               return 0;
-       }
+       guint16 num;
 
-       if (!g_ascii_strcasecmp(formatstr, "vcard21"))
-               pbap->format = FORMAT_VCARD21;
-       else if (!g_ascii_strcasecmp(formatstr, "vcard30"))
-               pbap->format = FORMAT_VCARD30;
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
-static int set_order(struct pbap_data *pbap, const char *orderstr)
-{
-       if (!orderstr || g_str_equal(orderstr, "")) {
-               pbap->order = ORDER_INDEXED;
-               return 0;
-       }
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+               return NULL;
 
-       if (!g_ascii_strcasecmp(orderstr, "indexed"))
-               pbap->order = ORDER_INDEXED;
-       else if (!g_ascii_strcasecmp(orderstr, "alphanumeric"))
-               pbap->order = ORDER_ALPHANUMERIC;
-       else if (!g_ascii_strcasecmp(orderstr, "phonetic"))
-               pbap->order = ORDER_PHONETIC;
-       else
-               return -EINVAL;
+       dbus_message_iter_get_basic(iter, &num);
 
-       return 0;
+       return g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, num);
 }
 
 static uint64_t get_filter_mask(const char *filterstr)
@@ -600,53 +435,174 @@ static uint64_t get_filter_mask(const char *filterstr)
                return 0;
 }
 
-static int add_filter(struct pbap_data *pbap, const char *filterstr)
+static int set_field(guint64 *filter, const char *filterstr)
 {
-       uint64_t mask;
+       guint64 mask;
 
        mask = get_filter_mask(filterstr);
 
        if (mask == 0)
                return -EINVAL;
 
-       pbap->filter |= mask;
+       *filter |= mask;
        return 0;
 }
 
-static int remove_filter(struct pbap_data *pbap, const char *filterstr)
+static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
 {
-       uint64_t mask;
+       DBusMessageIter array;
+       guint64 filter = 0;
 
-       mask = get_filter_mask(filterstr);
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
 
-       if (mask == 0)
-               return -EINVAL;
+       dbus_message_iter_recurse(iter, &array);
 
-       pbap->filter &= ~mask;
-       return 0;
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+               const char *string;
+
+               dbus_message_iter_get_basic(&array, &string);
+
+               if (set_field(&filter, string) < 0)
+                       return NULL;
+
+               dbus_message_iter_next(&array);
+       }
+
+       return g_obex_apparam_set_uint64(apparam, FILTER_TAG, filter);
 }
 
-static gchar **get_filter_strs(uint64_t filter, gint *size)
+static GObexApparam *parse_filters(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
 {
-       gchar **list, **item;
-       gint i;
-       gint filter_list_size = sizeof(filter_list) / sizeof(filter_list[0]) - 1;
+       DBusMessageIter array;
 
-       list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
 
-       item = list;
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+               const char *key;
+               DBusMessageIter value, entry;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "Format") == 0) {
+                       if (parse_format(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Order") == 0) {
+                       if (parse_order(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Offset") == 0) {
+                       if (parse_offset(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "MaxCount") == 0) {
+                       if (parse_max_count(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Fields") == 0) {
+                       if (parse_fields(apparam, &value) == NULL)
+                               return NULL;
+               }
 
-       for (i = 0; i < filter_list_size; i++)
-               if (filter & (1ULL << i))
-                       *(item++) = g_strdup(filter_list[i]);
+               dbus_message_iter_next(&array);
+       }
 
-       for (i = filter_list_size; i <= FILTER_BIT_MAX; i++)
-               if (filter & (1ULL << i))
-                       *(item++) = g_strdup_printf("%s%d", "BIT", i);
+       return apparam;
+}
 
-       *item = NULL;
-       *size = item - list;
-       return list;
+static DBusMessage *pull_phonebook(struct pbap_data *pbap,
+                                               DBusMessage *message,
+                                               guint8 type,
+                                               const char *targetfile,
+                                               GObexApparam *apparam)
+{
+       struct pending_request *request;
+       struct obc_transfer *transfer;
+       char *name;
+       session_callback_t func;
+       DBusMessage *reply;
+       GError *err = NULL;
+
+       name = g_strconcat(g_path_skip_root(pbap->path), ".vcf", NULL);
+
+       transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       switch (type) {
+       case PULLPHONEBOOK:
+               func = NULL;
+               request = NULL;
+               break;
+       case GETPHONEBOOKSIZE:
+               func = phonebook_size_callback;
+               request = pending_request_new(pbap, message);
+               break;
+       default:
+               error("Unexpected type : 0x%2x", type);
+               return NULL;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (!obc_session_queue(pbap->session, transfer, func, request, &err)) {
+               if (request != NULL)
+                       pending_request_free(request);
+
+               goto fail;
+       }
+
+       g_free(name);
+
+       if (targetfile == NULL)
+               return NULL;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       g_free(name);
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
+                                       DBusMessage *message, const char *name,
+                                       GObexApparam *apparam)
+{
+       struct pending_request *request;
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       request = pending_request_new(pbap, message);
+       if (obc_session_queue(pbap->session, transfer,
+                               pull_vcard_listing_callback, request, &err))
+               return NULL;
+
+       pending_request_free(request);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
 }
 
 static DBusMessage *pbap_select(DBusConnection *connection,
@@ -700,74 +656,54 @@ static DBusMessage *pbap_pull_all(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
        struct pbap_data *pbap = user_data;
-       struct obc_transfer *transfer;
        const char *targetfile;
-       char *name;
-       GError *err = NULL;
+       GObexApparam *apparam;
+       DBusMessageIter args;
 
        if (!pbap->path)
                return g_dbus_create_error(message,
                                        ERROR_INTERFACE ".Forbidden",
                                        "Call Select first of all");
 
-       if (dbus_message_get_args(message, NULL,
-                       DBUS_TYPE_STRING, &targetfile,
-                       DBUS_TYPE_INVALID) == FALSE)
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
                return g_dbus_create_error(message,
                                ERROR_INTERFACE ".InvalidArguments", NULL);
 
-       name = g_strconcat(pbap->path, ".vcf", NULL);
+       dbus_message_iter_get_basic(&args, &targetfile);
+       dbus_message_iter_next(&args);
 
-       transfer = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
-                               targetfile, pbap->filter, pbap->format,
-                               DEFAULT_COUNT, DEFAULT_OFFSET, &err);
-       g_free(name);
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
 
-       if (transfer == NULL) {
-               DBusMessage *reply = g_dbus_create_error(message,
-                                       ERROR_INTERFACE ".Failed", "%s",
-                                       err->message);
-               g_error_free(err);
-               return reply;
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
        }
 
-       return obc_transfer_create_dbus_reply(transfer, message);
+       return pull_phonebook(pbap, message, PULLPHONEBOOK, targetfile,
+                                                               apparam);
 }
 
-static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
+static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
+                               const char *name, const char *targetfile,
+                               GObexApparam *apparam)
 {
-       struct pbap_data *pbap = user_data;
        struct obc_transfer *transfer;
-       struct pullvcardentry_apparam apparam;
-       const char *name, *targetfile;
        DBusMessage *reply;
        GError *err = NULL;
 
-       if (!pbap->path)
-               return g_dbus_create_error(message,
-                               ERROR_INTERFACE ".Forbidden",
-                               "Call Select first of all");
-
-       if (dbus_message_get_args(message, NULL,
-                       DBUS_TYPE_STRING, &name,
-                       DBUS_TYPE_STRING, &targetfile,
-                       DBUS_TYPE_INVALID) == FALSE)
-               return g_dbus_create_error(message,
-                               ERROR_INTERFACE ".InvalidArguments", NULL);
-
        transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
-       if (transfer == NULL)
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
                goto fail;
+       }
 
-       apparam.filter_tag = FILTER_TAG;
-       apparam.filter_len = FILTER_LEN;
-       apparam.filter = GUINT64_TO_BE(pbap->filter);
-       apparam.format_tag = FORMAT_TAG;
-       apparam.format_len = FORMAT_LEN;
-       apparam.format = pbap->format;
-
-       obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
+       obc_transfer_set_apparam(transfer, apparam);
 
        if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
                goto fail;
@@ -781,39 +717,81 @@ fail:
        return reply;
 }
 
-static DBusMessage *pbap_list(DBusConnection *connection,
+static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
        struct pbap_data *pbap = user_data;
+       GObexApparam *apparam;
+       const char *name, *targetfile;
+       DBusMessageIter args;
 
        if (!pbap->path)
                return g_dbus_create_error(message,
-                                       ERROR_INTERFACE ".Forbidden",
-                                       "Call Select first of all");
+                               ERROR_INTERFACE ".Forbidden",
+                               "Call Select first of all");
+
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &name);
+       dbus_message_iter_next(&args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &targetfile);
+       dbus_message_iter_next(&args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
 
-       return pull_vcard_listing(pbap, message, "", pbap->order, "",
-                               ATTRIB_NAME, DEFAULT_COUNT, DEFAULT_OFFSET);
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return pull_vcard(pbap, message, name, targetfile, apparam);
 }
 
-static DBusMessage *pbap_search(DBusConnection *connection,
+static DBusMessage *pbap_list(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
        struct pbap_data *pbap = user_data;
-       char *field, *value;
-       guint8 attrib;
-
-       if (dbus_message_get_args(message, NULL,
-                       DBUS_TYPE_STRING, &field,
-                       DBUS_TYPE_STRING, &value,
-                       DBUS_TYPE_INVALID) == FALSE)
-               return g_dbus_create_error(message,
-                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       GObexApparam *apparam;
+       DBusMessageIter args;
 
        if (!pbap->path)
                return g_dbus_create_error(message,
                                        ERROR_INTERFACE ".Forbidden",
                                        "Call Select first of all");
 
+       dbus_message_iter_init(message, &args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
+
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return pull_vcard_listing(pbap, message, "", apparam);
+}
+
+static GObexApparam *parse_attribute(GObexApparam *apparam, const char *field)
+{
+       guint8 attrib;
+
        if (!field || g_str_equal(field, ""))
                attrib = ATTRIB_NAME;
        else if (!g_ascii_strcasecmp(field, "name"))
@@ -823,133 +801,101 @@ static DBusMessage *pbap_search(DBusConnection *connection,
        else if (!g_ascii_strcasecmp(field, "sound"))
                attrib = ATTRIB_SOUND;
        else
-               return g_dbus_create_error(message,
-                               ERROR_INTERFACE ".InvalidArguments", NULL);
+               return NULL;
 
-       return pull_vcard_listing(pbap, message, "", pbap->order, value,
-                                       attrib, DEFAULT_COUNT, DEFAULT_OFFSET);
+       return g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
 }
 
-static DBusMessage *pbap_get_size(DBusConnection *connection,
+static DBusMessage *pbap_search(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
        struct pbap_data *pbap = user_data;
-       DBusMessage *reply;
-       struct obc_transfer *transfer;
-       char *name;
-       GError *err = NULL;
+       char *field, *value;
+       GObexApparam *apparam;
+       DBusMessageIter args;
 
        if (!pbap->path)
                return g_dbus_create_error(message,
                                        ERROR_INTERFACE ".Forbidden",
                                        "Call Select first of all");
 
-       name = g_strconcat(pbap->path, ".vcf", NULL);
-
-       transfer = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name, NULL,
-                               pbap->filter, pbap->format, 0,
-                               DEFAULT_OFFSET, &err);
-
-       g_free(name);
-
-       if (transfer != NULL)
-               return NULL;
+       dbus_message_iter_init(message, &args);
 
-       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
-                                                               err->message);
-       g_error_free(err);
-       return reply;
-}
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
 
-static DBusMessage *pbap_set_format(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
-{
-       struct pbap_data *pbap = user_data;
-       const char *format;
+       dbus_message_iter_get_basic(&args, &field);
+       dbus_message_iter_next(&args);
 
-       if (dbus_message_get_args(message, NULL,
-                       DBUS_TYPE_STRING, &format,
-                       DBUS_TYPE_INVALID) == FALSE)
+       apparam = parse_attribute(NULL, field);
+       if (apparam == NULL)
                return g_dbus_create_error(message,
                                ERROR_INTERFACE ".InvalidArguments", NULL);
 
-       if (set_format(pbap, format) < 0)
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
                return g_dbus_create_error(message,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "InvalidFormat");
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
 
-       return dbus_message_new_method_return(message);
-}
+       dbus_message_iter_get_basic(&args, &value);
+       dbus_message_iter_next(&args);
 
-static DBusMessage *pbap_set_order(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
-{
-       struct pbap_data *pbap = user_data;
-       const char *order;
+       apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
+       apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG, value);
 
-       if (dbus_message_get_args(message, NULL,
-                       DBUS_TYPE_STRING, &order,
-                       DBUS_TYPE_INVALID) == FALSE)
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
                return g_dbus_create_error(message,
                                ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
 
-       if (set_order(pbap, order) < 0)
-               return g_dbus_create_error(message,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "InvalidFilter");
-
-       return dbus_message_new_method_return(message);
+       return pull_vcard_listing(pbap, message, "", apparam);
 }
 
-static DBusMessage *pbap_set_filter(DBusConnection *connection,
+static DBusMessage *pbap_get_size(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
        struct pbap_data *pbap = user_data;
-       char **filters, **item;
-       gint size;
-       uint64_t oldfilter = pbap->filter;
+       GObexApparam *apparam;
+       DBusMessageIter args;
 
-       if (dbus_message_get_args(message, NULL, DBUS_TYPE_ARRAY,
-                       DBUS_TYPE_STRING, &filters, &size,
-                       DBUS_TYPE_INVALID) == FALSE)
+       if (!pbap->path)
                return g_dbus_create_error(message,
-                               ERROR_INTERFACE ".InvalidArguments", NULL);
+                                       ERROR_INTERFACE ".Forbidden",
+                                       "Call Select first of all");
 
-       remove_filter(pbap, "ALL");
-       if (size == 0)
-               goto done;
+       dbus_message_iter_init(message, &args);
 
-       for (item = filters; *item; item++) {
-               if (add_filter(pbap, *item) < 0) {
-                       pbap->filter = oldfilter;
-                       g_strfreev(filters);
-                       return g_dbus_create_error(message,
-                                       ERROR_INTERFACE ".InvalidArguments",
-                                       "InvalidFilters");
-               }
-       }
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
 
-done:
-       g_strfreev(filters);
-       return dbus_message_new_method_return(message);
+       return pull_phonebook(pbap, message, GETPHONEBOOKSIZE, NULL, apparam);
 }
 
-static DBusMessage *pbap_get_filter(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
+static gchar **get_filter_strs(uint64_t filter, gint *size)
 {
-       struct pbap_data *pbap = user_data;
-       gchar **filters = NULL;
-       gint size;
-       DBusMessage *reply;
+       gchar **list, **item;
+       gint i;
 
-       filters = get_filter_strs(pbap->filter, &size);
-       reply = dbus_message_new_method_return(message);
-       dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_STRING, &filters, size,
-                               DBUS_TYPE_INVALID);
+       list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
 
-       g_strfreev(filters);
-       return reply;
+       item = list;
+
+       for (i = 0; filter_list[i] != NULL; i++)
+               if (filter & (1ULL << i))
+                       *(item++) = g_strdup(filter_list[i]);
+
+       for (; i <= FILTER_BIT_MAX; i++)
+               if (filter & (1ULL << i))
+                       *(item++) = g_strdup_printf("%s%d", "BIT", i);
+
+       *item = NULL;
+       *size = item - list;
+       return list;
 }
 
 static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
@@ -974,37 +920,29 @@ static const GDBusMethodTable pbap_methods[] = {
                        GDBUS_ARGS({ "location", "s" }, { "phonebook", "s" }),
                        NULL, pbap_select) },
        { GDBUS_METHOD("PullAll",
-                       GDBUS_ARGS({ "targetfile", "s" }),
+                       GDBUS_ARGS({ "targetfile", "s" },
+                                       { "filters", "a{sv}" }),
                        GDBUS_ARGS({ "transfer", "o" },
                                        { "properties", "a{sv}" }),
                        pbap_pull_all) },
        { GDBUS_METHOD("Pull",
-                       GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" }),
+                       GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" },
+                                       { "filters", "a{sv}" }),
                        GDBUS_ARGS({ "transfer", "o" },
                                        { "properties", "a{sv}" }),
                        pbap_pull_vcard) },
        { GDBUS_ASYNC_METHOD("List",
-                               NULL, GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
-                               pbap_list) },
+                       GDBUS_ARGS({ "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+                       pbap_list) },
        { GDBUS_ASYNC_METHOD("Search",
-                               GDBUS_ARGS({ "field", "s" }, { "value", "s" }),
-                               GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
-                               pbap_search) },
+                       GDBUS_ARGS({ "field", "s" }, { "value", "s" },
+                                       { "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+                       pbap_search) },
        { GDBUS_ASYNC_METHOD("GetSize",
                                NULL, GDBUS_ARGS({ "size", "q" }),
                                pbap_get_size) },
-       { GDBUS_METHOD("SetFormat",
-                               GDBUS_ARGS({ "format", "s" }), NULL,
-                               pbap_set_format) },
-       { GDBUS_METHOD("SetOrder",
-                               GDBUS_ARGS({ "order", "s" }), NULL,
-                               pbap_set_order) },
-       { GDBUS_METHOD("SetFilter",
-                               GDBUS_ARGS({ "fields", "as" }), NULL,
-                               pbap_set_filter) },
-       { GDBUS_METHOD("GetFilter",
-                               NULL, GDBUS_ARGS({ "fields", "as" }),
-                               pbap_get_filter) },
        { GDBUS_METHOD("ListFilterFields",
                                NULL, GDBUS_ARGS({ "fields", "as" }),
                                pbap_list_filter_fields) },
index 76f6681..cac3884 100644 (file)
@@ -48,6 +48,8 @@
 
 #define OBC_TRANSFER_ERROR obc_transfer_error_quark()
 
+#define FIRST_PACKET_TIMEOUT 60
+
 static guint64 counter = 0;
 
 struct transfer_callback {
@@ -55,15 +57,10 @@ struct transfer_callback {
        void *data;
 };
 
-struct obc_transfer_params {
-       void *data;
-       size_t size;
-};
-
 struct obc_transfer {
        GObex *obex;
+       GObexApparam *apparam;
        guint8 op;
-       struct obc_transfer_params *params;
        struct transfer_callback *callback;
        DBusConnection *conn;
        DBusMessage *msg;
@@ -271,10 +268,8 @@ static void obc_transfer_free(struct obc_transfer *transfer)
        if (transfer->fd > 0)
                close(transfer->fd);
 
-       if (transfer->params != NULL) {
-               g_free(transfer->params->data);
-               g_free(transfer->params);
-       }
+       if (transfer->apparam != NULL)
+               g_obex_apparam_free(transfer->apparam);
 
        if (transfer->conn)
                dbus_connection_unref(transfer->conn);
@@ -403,7 +398,8 @@ struct obc_transfer *obc_transfer_put(const char *type, const char *name,
        struct stat st;
        int perr;
 
-       if (filename == NULL || strcmp(filename, "") == 0) {
+       if ((filename == NULL || strcmp(filename, "") == 0) &&
+                                                       contents == NULL) {
                g_set_error(err, OBC_TRANSFER_ERROR, -EINVAL,
                                                "Invalid filename given");
                return NULL;
@@ -430,6 +426,7 @@ struct obc_transfer *obc_transfer_put(const char *type, const char *name,
                                        "Writing all contents to file failed");
                        goto fail;
                }
+               lseek(transfer->fd, 0, SEEK_SET);
        } else {
                if (!transfer_open(transfer, O_RDONLY, 0, err))
                        goto fail;
@@ -527,6 +524,7 @@ static void get_xfer_progress_first(GObex *obex, GError *err, GObexPacket *rsp,
        struct obc_transfer *transfer = user_data;
        GObexPacket *req;
        GObexHeader *hdr;
+       GObexApparam *apparam;
        const guint8 *buf;
        gsize len;
        guint8 rspcode;
@@ -548,17 +546,9 @@ static void get_xfer_progress_first(GObex *obex, GError *err, GObexPacket *rsp,
 
        hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_APPARAM);
        if (hdr) {
-               g_obex_header_get_bytes(hdr, &buf, &len);
-               if (len != 0) {
-                       if (transfer->params == NULL)
-                               transfer->params =
-                                       g_new0(struct obc_transfer_params, 1);
-                       else
-                               g_free(transfer->params->data);
-
-                       transfer->params->data = g_memdup(buf, len);
-                       transfer->params->size = len;
-               }
+               apparam = g_obex_header_get_apparam(hdr);
+               if (apparam != NULL)
+                       obc_transfer_set_apparam(transfer, apparam);
        }
 
        hdr = g_obex_packet_get_body(rsp);
@@ -640,6 +630,7 @@ static gboolean report_progress(gpointer data)
 static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
 {
        GObexPacket *req;
+       GObexHeader *hdr;
 
        if (transfer->xfer > 0) {
                g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
@@ -657,12 +648,13 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
                g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type,
                                                strlen(transfer->type) + 1);
 
-       if (transfer->params != NULL)
-               g_obex_packet_add_bytes(req, G_OBEX_HDR_APPARAM,
-                                               transfer->params->data,
-                                               transfer->params->size);
+       if (transfer->apparam != NULL) {
+               hdr = g_obex_header_new_apparam(transfer->apparam);
+               g_obex_packet_add_header(req, hdr);
+       }
 
-       transfer->xfer = g_obex_send_req(transfer->obex, req, -1,
+       transfer->xfer = g_obex_send_req(transfer->obex, req,
+                                               FIRST_PACKET_TIMEOUT,
                                                get_xfer_progress_first,
                                                transfer, err);
        if (transfer->xfer == 0)
@@ -680,6 +672,7 @@ static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
 static gboolean transfer_start_put(struct obc_transfer *transfer, GError **err)
 {
        GObexPacket *req;
+       GObexHeader *hdr;
 
        if (transfer->xfer > 0) {
                g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
@@ -700,10 +693,10 @@ static gboolean transfer_start_put(struct obc_transfer *transfer, GError **err)
        if (transfer->size < UINT32_MAX)
                g_obex_packet_add_uint32(req, G_OBEX_HDR_LENGTH, transfer->size);
 
-       if (transfer->params != NULL)
-               g_obex_packet_add_bytes(req, G_OBEX_HDR_APPARAM,
-                                               transfer->params->data,
-                                               transfer->params->size);
+       if (transfer->apparam != NULL) {
+               hdr = g_obex_header_new_apparam(transfer->apparam);
+               g_obex_packet_add_header(req, hdr);
+       }
 
        transfer->xfer = g_obex_put_req_pkt(transfer->obex, req,
                                        put_xfer_progress, xfer_complete,
@@ -741,31 +734,20 @@ guint8 obc_transfer_get_operation(struct obc_transfer *transfer)
        return transfer->op;
 }
 
-void obc_transfer_set_params(struct obc_transfer *transfer,
-                                               const void *data, size_t size)
+void obc_transfer_set_apparam(struct obc_transfer *transfer, void *data)
 {
-       if (transfer->params != NULL) {
-               g_free(transfer->params->data);
-               g_free(transfer->params);
-       }
+       if (transfer->apparam != NULL)
+               g_obex_apparam_free(transfer->apparam);
 
        if (data == NULL)
                return;
 
-       transfer->params = g_new0(struct obc_transfer_params, 1);
-       transfer->params->data = g_memdup(data, size);
-       transfer->params->size = size;
+       transfer->apparam = data;
 }
 
-const void *obc_transfer_get_params(struct obc_transfer *transfer, size_t *size)
+void *obc_transfer_get_apparam(struct obc_transfer *transfer)
 {
-       if (transfer->params == NULL)
-               return NULL;
-
-       if (size != NULL)
-               *size = transfer->params->size;
-
-       return transfer->params->data;
+       return transfer->apparam;
 }
 
 int obc_transfer_get_contents(struct obc_transfer *transfer, char **contents,
index 968903a..f7d0423 100644 (file)
@@ -50,10 +50,8 @@ gboolean obc_transfer_start(struct obc_transfer *transfer, void *obex,
                                                                GError **err);
 guint8 obc_transfer_get_operation(struct obc_transfer *transfer);
 
-void obc_transfer_set_params(struct obc_transfer *transfer,
-                                               const void *data, size_t size);
-const void *obc_transfer_get_params(struct obc_transfer *transfer,
-                                                               size_t *size);
+void obc_transfer_set_apparam(struct obc_transfer *transfer, void *data);
+void *obc_transfer_get_apparam(struct obc_transfer *transfer);
 int obc_transfer_get_contents(struct obc_transfer *transfer, char **contents,
                                                                size_t *size);
 
index 768e8e7..41da84e 100755 (executable)
--- 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 obexd 0.47.
+# Generated by GNU Autoconf 2.69 for obexd 0.48.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='obexd'
 PACKAGE_TARNAME='obexd'
-PACKAGE_VERSION='0.47'
-PACKAGE_STRING='obexd 0.47'
+PACKAGE_VERSION='0.48'
+PACKAGE_STRING='obexd 0.48'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1372,7 +1372,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 obexd 0.47 to adapt to many kinds of systems.
+\`configure' configures obexd 0.48 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1442,7 +1442,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of obexd 0.47:";;
+     short | recursive ) echo "Configuration of obexd 0.48:";;
    esac
   cat <<\_ACEOF
 
@@ -1586,7 +1586,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-obexd configure 0.47
+obexd configure 0.48
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1951,7 +1951,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 obexd $as_me 0.47, which was
+It was created by obexd $as_me 0.48, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2767,7 +2767,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='obexd'
- VERSION='0.47'
+ VERSION='0.48'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -12137,12 +12137,12 @@ if test -n "$BLUEZ_CFLAGS"; then
     pkg_cv_BLUEZ_CFLAGS="$BLUEZ_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.99\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "bluez >= 4.99") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.100\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "bluez >= 4.100") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_BLUEZ_CFLAGS=`$PKG_CONFIG --cflags "bluez >= 4.99" 2>/dev/null`
+  pkg_cv_BLUEZ_CFLAGS=`$PKG_CONFIG --cflags "bluez >= 4.100" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -12154,12 +12154,12 @@ if test -n "$BLUEZ_LIBS"; then
     pkg_cv_BLUEZ_LIBS="$BLUEZ_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.99\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "bluez >= 4.99") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.100\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "bluez >= 4.100") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_BLUEZ_LIBS=`$PKG_CONFIG --libs "bluez >= 4.99" 2>/dev/null`
+  pkg_cv_BLUEZ_LIBS=`$PKG_CONFIG --libs "bluez >= 4.100" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -12180,18 +12180,18 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-               BLUEZ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "bluez >= 4.99" 2>&1`
+               BLUEZ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "bluez >= 4.100" 2>&1`
         else
-               BLUEZ_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "bluez >= 4.99" 2>&1`
+               BLUEZ_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "bluez >= 4.100" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
        echo "$BLUEZ_PKG_ERRORS" >&5
 
-       as_fn_error $? "BlueZ >= 4.99 is required" "$LINENO" 5
+       as_fn_error $? "BlueZ >= 4.100 is required" "$LINENO" 5
 elif test $pkg_failed = untried; then
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-       as_fn_error $? "BlueZ >= 4.99 is required" "$LINENO" 5
+       as_fn_error $? "BlueZ >= 4.100 is required" "$LINENO" 5
 else
        BLUEZ_CFLAGS=$pkg_cv_BLUEZ_CFLAGS
        BLUEZ_LIBS=$pkg_cv_BLUEZ_LIBS
@@ -13334,7 +13334,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 obexd $as_me 0.47, which was
+This file was extended by obexd $as_me 0.48, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -13400,7 +13400,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="\\
-obexd config.status 0.47
+obexd config.status 0.48
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 69d71b2..69d636f 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(obexd, 0.47)
+AC_INIT(obexd, 0.48)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
 AM_CONFIG_HEADER(config.h)
@@ -79,8 +79,8 @@ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4, dummy=yes,
 AC_SUBST(DBUS_CFLAGS)
 AC_SUBST(DBUS_LIBS)
 
-PKG_CHECK_MODULES(BLUEZ, bluez >= 4.99, dummy=yes,
-                               AC_MSG_ERROR(BlueZ >= 4.99 is required))
+PKG_CHECK_MODULES(BLUEZ, bluez >= 4.100, dummy=yes,
+                               AC_MSG_ERROR(BlueZ >= 4.100 is required))
 AC_SUBST(BLUEZ_CFLAGS)
 AC_SUBST(BLUEZ_LIBS)
 
index 839a78c..19c8541 100644 (file)
@@ -206,7 +206,7 @@ Methods             void Select(string location, string phonebook)
                                "mch":  missing call history
                                "cch":  combination of ich och mch
 
-               object, dict PullAll(string targetfile)
+               object, dict PullAll(string targetfile, dict filters)
 
                        Return the entire phonebook object from the PSE server
                        in plain string with vcard format, and store it in
@@ -222,14 +222,21 @@ Methods           void Select(string location, string phonebook)
                        The properties of this transfer are also returned along
                        with the object path, to avoid a call to GetProperties.
 
-               array{string vcard, string name} List()
+                       Possible filters: Format, Order, Offset, MaxCount and
+                       Fields
+
+               array{string vcard, string name} List(dict filters)
 
                        Return an array of vcard-listing data where every entry
                        consists of a pair of strings containing the vcard
                        handle and the contact name. For example:
                                "1.vcf" : "John"
 
-               object, dict Pull(string vcard, string targetfile)
+                       Possible filters: Order, Offset and MaxCount
+
+
+               object, dict
+               Pull(string vcard, string targetfile, dict filters)
 
                        Given a vcard handle, retrieve the vcard in the current
                        phonebook object and store it in a local file.
@@ -244,8 +251,11 @@ Methods            void Select(string location, string phonebook)
                        The properties of this transfer are also returned along
                        with the object path, to avoid a call to GetProperties.
 
+                       Possbile filters: Format and Fields
+
+
                array{string vcard, string name}
-               Search(string field, string value)
+               Search(string field, string value, dict filters)
 
                        Search for entries matching the given condition and
                        return an array of vcard-listing data where every entry
@@ -258,47 +268,47 @@ Methods           void Select(string location, string phonebook)
                                { "name" (default) | "number" | "sound" }
                        value : the string value to search for
 
+
+                       Possible filters: Order, Offset and MaxCount
+
                uint16 GetSize()
 
                        Return the number of entries in the selected phonebook
                        object that are actually used (i.e. indexes that
                        correspond to non-NULL entries).
 
-               void SetFormat(string format)
+               array{string} ListFilterFields()
 
-                       Indicate the format of the vcard that should be return
-                       by related methods.
+                       Return All Available fields that can be used in Fields
+                       filter.
 
-                       format : { "vcard21" (default) | "vcard30" }
+Filter:                string Format:
 
-               void SetOrder(string order)
+                       Items vcard format
 
-                       Indicate the sorting method of the vcard-listing data
-                       returned by List and Search methods.
+                       Possible values: "vcard21" (default) or "vcard30"
 
-                       order : { "indexed" (default) | "alphanumeric" |
-                                       "phonetic" }
+               string Order:
 
-               void SetFilter(array{string})
+                       Items order
 
-                       Indicate fields that should be contained in vcards
-                       return by related methods.
+                       Possible values: "indexed" (default), "alphanumeric" or
+                       "phonetic"
 
-                       Give an empty array will clear the filter and return
-                       all fields available in vcards. And this is the default
-                       behavior.
+               uint16 Offset:
 
-                       Possible filter fields : "VERSION", "FN", ..., "ALL",
-                       "bit[0-63]"
+                       Offset of the first item, default is 0
 
-               array{string} ListFilterFields()
+               uint16 MaxCount:
+
+                       Maximum number of items, default is unlimited (65535)
+
+               array{string} Fields:
 
-                       Return All Available fields that can be used in
-                       SetFilter method.
+                       Item vcard fields, default is all values.
 
-               array{string} GetFilter()
+                       Possible values can be query with ListFilterFields.
 
-                       Return the current filter setting
 
 Synchronization hierarchy
 =======================
@@ -358,7 +368,7 @@ Methods             void SetFolder(string name)
                        Set working directory for current session, *name* may
                        be the directory name or '..[/dir]'.
 
-               array{dict} GetFolderListing(dict filter)
+               array{dict} ListFolders(dict filter)
 
                        Returns a dictionary containing information about
                        the current folder content.
@@ -367,12 +377,22 @@ Methods           void SetFolder(string name)
 
                                string Name : Folder name
 
-               array{object, dict} GetMessageListing(string folder,
-                                                               dict filter)
+                       Possible filters: Offset and MaxCount
+
+               array{string} ListFilterFields()
+
+                       Return all available fields that can be used in Fields
+                       filter.
+
+               array{object, dict} ListMessages(string folder, dict filter)
 
                        Returns an array containing the messages found in the
                        given folder.
 
+                       Possible Filters: Offset, MaxCount, Fields, Type,
+                       PeriodStart, PeriodEnd, Status, Recipient, Sender,
+                       Priority
+
                        Each message is represented by an object path followed
                        by a dictionary of the properties.
 
@@ -440,6 +460,64 @@ Methods            void SetFolder(string name)
 
                                        Message protected flag
 
+               void UpdateInbox(void)
+
+                       Request remote to update its inbox.
+
+
+Filter:                uint16 Offset:
+
+                       Offset of the first item, default is 0
+
+               uint16 MaxCount:
+
+                       Maximum number of items, default is 1024
+
+               array{string} Fields:
+
+                       Message fields, default is all values.
+
+                       Possible values can be query with ListFilterFields.
+
+               array{string} Types:
+
+                       Filter messages by type.
+
+                       Possible values: "sms", "email", "mms".
+
+               string PeriodBegin:
+
+                       Filter messages by starting period.
+
+                       Possible values: Date in "YYYYMMDDTHHMMSS" format.
+
+               string PeriodEnd:
+
+                       Filter messages by ending period.
+
+                       Possible values: Date in "YYYYMMDDTHHMMSS" format.
+
+               boolean Read:
+
+                       Filter messages by read flag.
+
+                       Possible values: True for read or False for unread
+
+               string Recipient:
+
+                       Filter messages by recipient address.
+
+               string Sender:
+
+                       Filter messages by sender address.
+
+               gboolean Priority:
+
+                       Filter messages by priority flag.
+
+                       Possible values: True for high priority or False for
+                       non-high priority
+
 Message hierarchy
 =================
 
@@ -447,7 +525,7 @@ Service             org.bluez.obex.client
 Interface      org.bluez.obex.Message
 Object path    [variable prefix]/{session0,session1,...}/{message0,...}
 
-Methods                object, dict Get(string targetfile)
+Methods                object, dict Get(string targetfile, boolean attachment)
 
                        Download message and store it in the target file.
 
@@ -461,12 +539,91 @@ Methods           object, dict Get(string targetfile)
                        The properties of this transfer are also returned along
                        with the object path, to avoid a call to GetProperties.
 
+               dict GetProperties()
+
+                       Returns all properties for the message. See the
+                       properties section for available properties.
+
+               void SetProperty (string name, variant value)
+
+                       Sets value to the mentioned property.
+
+                       Possible properties: Read and Deleted.
+
+
+Properties     string Subject [readonly]
+
+                       Message subject
+
+               string Timestamp [readonly]
+
+                       Message timestamp
+
+               string Sender [readonly]
+
+                       Message sender name
+
+               string SenderAddress [readonly]
+
+                       Message sender address
+
+               string ReplyTo [readonly]
+
+                       Message Reply-To address
+
+               string Recipient [readonly]
+
+                       Message recipient name
+
+               string RecipientAddress [readonly]
+
+                       Message recipient address
+
+               string Type [readonly]
+
+                       Message type
+
+                       Possible values: "EMAIL", "SMS_GSM",
+                       "SMS_CDMA" and "MMS"
+
+               uint64 Size [readonly]
+
+                       Message size in bytes
+
+               string Status [readonly]
+
+                       Message reception status
+
+                       Possible values: "complete",
+                       "fractioned" and "notification"
+
+               boolean Priority [readonly]
+
+                       Message priority flag
+
+               boolean Read [read/write]
+
+                       Message read flag
+
+               boolean Deleted [writeonly]
+
+                       Message read flag
+
+               boolean Sent [readonly]
+
+                       Message sent flag
+
+               boolean Protected [readonly]
+
+                       Message protected flag
+
+
 Transfer hierarchy
 ==================
 
 Service                org.bluez.obex.client
 Interface      org.bluez.obex.Transfer
-Object path    [variable prefix]/{transfer0,transfer1,...}
+Object path    [variable prefix]/{session0,session1,...}/{transfer0,...}
 
 Methods                dict GetProperties()
 
index 0a8a27c..dd21f86 100644 (file)
@@ -31,6 +31,17 @@ extern "C" {
 #include <dbus/dbus.h>
 #include <glib.h>
 
+typedef enum GDBusMethodFlags GDBusMethodFlags;
+typedef enum GDBusSignalFlags GDBusSignalFlags;
+typedef enum GDBusPropertyFlags GDBusPropertyFlags;
+typedef enum GDBusSecurityFlags GDBusSecurityFlags;
+
+typedef struct GDBusArgInfo GDBusArgInfo;
+typedef struct GDBusMethodTable GDBusMethodTable;
+typedef struct GDBusSignalTable GDBusSignalTable;
+typedef struct GDBusPropertyTable GDBusPropertyTable;
+typedef struct GDBusSecurityTable GDBusSecurityTable;
+
 typedef void (* GDBusWatchFunction) (DBusConnection *connection,
                                                        void *user_data);
 
@@ -55,6 +66,18 @@ typedef void (* GDBusDestroyFunction) (void *user_data);
 typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
                                        DBusMessage *message, void *user_data);
 
+typedef gboolean (*GDBusPropertyGetter)(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data);
+
+typedef guint32 GDBusPendingPropertySet;
+
+typedef void (*GDBusPropertySetter)(const GDBusPropertyTable *property,
+                       DBusMessageIter *value, GDBusPendingPropertySet id,
+                       void *data);
+
+typedef gboolean (*GDBusPropertyExists)(const GDBusPropertyTable *property,
+                                                               void *data);
+
 typedef guint32 GDBusPendingReply;
 
 typedef void (* GDBusSecurityFunction) (DBusConnection *connection,
@@ -62,58 +85,61 @@ typedef void (* GDBusSecurityFunction) (DBusConnection *connection,
                                                gboolean interaction,
                                                GDBusPendingReply pending);
 
-typedef enum {
+enum GDBusMethodFlags {
        G_DBUS_METHOD_FLAG_DEPRECATED = (1 << 0),
        G_DBUS_METHOD_FLAG_NOREPLY    = (1 << 1),
        G_DBUS_METHOD_FLAG_ASYNC      = (1 << 2),
-} GDBusMethodFlags;
+};
 
-typedef enum {
+enum GDBusSignalFlags {
        G_DBUS_SIGNAL_FLAG_DEPRECATED = (1 << 0),
-} GDBusSignalFlags;
+};
 
-typedef enum {
+enum GDBusPropertyFlags {
        G_DBUS_PROPERTY_FLAG_DEPRECATED = (1 << 0),
-} GDBusPropertyFlags;
+};
 
-typedef enum {
+enum GDBusSecurityFlags {
        G_DBUS_SECURITY_FLAG_DEPRECATED        = (1 << 0),
        G_DBUS_SECURITY_FLAG_BUILTIN           = (1 << 1),
        G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION = (1 << 2),
-} GDBusSecurityFlags;
+};
 
-typedef struct {
+struct GDBusArgInfo {
        const char *name;
        const char *signature;
-} GDBusArgInfo;
+};
 
-typedef struct {
+struct GDBusMethodTable {
        const char *name;
        GDBusMethodFunction function;
        GDBusMethodFlags flags;
        unsigned int privilege;
        const GDBusArgInfo *in_args;
        const GDBusArgInfo *out_args;
-} GDBusMethodTable;
+};
 
-typedef struct {
+struct GDBusSignalTable {
        const char *name;
        GDBusSignalFlags flags;
        const GDBusArgInfo *args;
-} GDBusSignalTable;
+};
 
-typedef struct {
+struct GDBusPropertyTable {
        const char *name;
        const char *type;
+       GDBusPropertyGetter get;
+       GDBusPropertySetter set;
+       GDBusPropertyExists exists;
        GDBusPropertyFlags flags;
-} GDBusPropertyTable;
+};
 
-typedef struct {
+struct GDBusSecurityTable {
        unsigned int privilege;
        const char *action;
        GDBusSecurityFlags flags;
        GDBusSecurityFunction function;
-} GDBusSecurityTable;
+};
 
 #define GDBUS_ARGS(args...) (const GDBusArgInfo[]) { args, { } }
 
@@ -217,9 +243,28 @@ guint g_dbus_add_signal_watch(DBusConnection *connection,
                                const char *interface, const char *member,
                                GDBusSignalFunction function, void *user_data,
                                GDBusDestroyFunction destroy);
+guint g_dbus_add_properties_watch(DBusConnection *connection,
+                               const char *sender, const char *path,
+                               const char *interface,
+                               GDBusSignalFunction function, void *user_data,
+                               GDBusDestroyFunction destroy);
 gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag);
 void g_dbus_remove_all_watches(DBusConnection *connection);
 
+void g_dbus_pending_property_success(GDBusPendingPropertySet id);
+void g_dbus_pending_property_error_valist(GDBusPendingReply id,
+                       const char *name, const char *format, va_list args);
+void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
+                                               const char *format, ...);
+void g_dbus_emit_property_changed(DBusConnection *connection,
+                               const char *path, const char *interface,
+                               const char *name);
+gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
+                               const char *interface, DBusMessageIter *iter);
+
+gboolean g_dbus_attach_object_manager(DBusConnection *connection);
+gboolean g_dbus_detach_object_manager(DBusConnection *connection);
+
 #ifdef __cplusplus
 }
 #endif
index cff326f..099b67f 100644 (file)
@@ -92,8 +92,9 @@ static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
        struct watch_info *info = data;
        unsigned int flags = 0;
        DBusDispatchStatus status;
+       DBusConnection *conn;
 
-       dbus_connection_ref(info->conn);
+       conn = dbus_connection_ref(info->conn);
 
        if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
        if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
@@ -102,10 +103,10 @@ static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
 
        dbus_watch_handle(info->watch, flags);
 
-       status = dbus_connection_get_dispatch_status(info->conn);
-       queue_dispatch(info->conn, status);
+       status = dbus_connection_get_dispatch_status(conn);
+       queue_dispatch(conn, status);
 
-       dbus_connection_unref(info->conn);
+       dbus_connection_unref(conn);
 
        return TRUE;
 }
index 900e7ab..7cbd612 100644 (file)
 #define error(fmt...)
 #define debug(fmt...)
 
+#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
+
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
+#endif
+
+#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
+#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
+#endif
+
 struct generic_data {
        unsigned int refcount;
+       DBusConnection *conn;
+       char *path;
        GSList *interfaces;
+       GSList *objects;
+       GSList *added;
+       GSList *removed;
+       guint process_id;
+       gboolean pending_prop;
        char *introspect;
+       struct generic_data *parent;
 };
 
 struct interface_data {
@@ -48,6 +66,7 @@ struct interface_data {
        const GDBusMethodTable *methods;
        const GDBusSignalTable *signals;
        const GDBusPropertyTable *properties;
+       GSList *pending_prop;
        void *user_data;
        GDBusDestroyFunction destroy;
 };
@@ -59,6 +78,19 @@ struct security_data {
        void *iface_user_data;
 };
 
+struct property_data {
+       DBusConnection *conn;
+       GDBusPendingPropertySet id;
+       DBusMessage *message;
+};
+
+static struct generic_data *root;
+
+static gboolean process_changes(gpointer user_data);
+static void process_properties_from_interface(struct generic_data *data,
+                                               struct interface_data *iface);
+static void process_property_changes(struct generic_data *data);
+
 static void print_arguments(GString *gstr, const GDBusArgInfo *args,
                                                const char *direction)
 {
@@ -76,10 +108,21 @@ static void print_arguments(GString *gstr, const GDBusArgInfo *args,
        }
 }
 
+#define G_DBUS_ANNOTATE(prefix_, name_, value_)                                \
+       prefix_ "<annotation name=\"org.freedesktop.DBus." name_ "\" "  \
+       "value=\"" value_ "\"/>\n"
+
+#define G_DBUS_ANNOTATE_DEPRECATED(prefix_) \
+       G_DBUS_ANNOTATE(prefix_, "Deprecated", "true")
+
+#define G_DBUS_ANNOTATE_NOREPLY(prefix_) \
+       G_DBUS_ANNOTATE(prefix_, "Method.NoReply", "true")
+
 static void generate_interface_xml(GString *gstr, struct interface_data *iface)
 {
        const GDBusMethodTable *method;
        const GDBusSignalTable *signal;
+       const GDBusPropertyTable *property;
 
        for (method = iface->methods; method && method->name; method++) {
                gboolean deprecated = method->flags &
@@ -90,19 +133,22 @@ static void generate_interface_xml(GString *gstr, struct interface_data *iface)
                if (!deprecated && !noreply &&
                                !(method->in_args && method->in_args->name) &&
                                !(method->out_args && method->out_args->name))
-                       g_string_append_printf(gstr, "\t\t<method name=\"%s\"/>\n",
-                                                               method->name);
+                       g_string_append_printf(gstr,
+                                               "\t\t<method name=\"%s\"/>\n",
+                                               method->name);
                else {
-                       g_string_append_printf(gstr, "\t\t<method name=\"%s\">\n",
-                                                               method->name);
+                       g_string_append_printf(gstr,
+                                               "\t\t<method name=\"%s\">\n",
+                                               method->name);
                        print_arguments(gstr, method->in_args, "in");
                        print_arguments(gstr, method->out_args, "out");
 
                        if (deprecated)
-                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n");
-
+                               g_string_append_printf(gstr,
+                                       G_DBUS_ANNOTATE_DEPRECATED("\t\t\t"));
                        if (noreply)
-                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n");
+                               g_string_append_printf(gstr,
+                                       G_DBUS_ANNOTATE_NOREPLY("\t\t\t"));
 
                        g_string_append_printf(gstr, "\t\t</method>\n");
                }
@@ -113,19 +159,40 @@ static void generate_interface_xml(GString *gstr, struct interface_data *iface)
                                                G_DBUS_SIGNAL_FLAG_DEPRECATED;
 
                if (!deprecated && !(signal->args && signal->args->name))
-                       g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
-                                                               signal->name);
+                       g_string_append_printf(gstr,
+                                               "\t\t<signal name=\"%s\"/>\n",
+                                               signal->name);
                else {
-                       g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
-                                                               signal->name);
+                       g_string_append_printf(gstr,
+                                               "\t\t<signal name=\"%s\">\n",
+                                               signal->name);
                        print_arguments(gstr, signal->args, NULL);
 
                        if (deprecated)
-                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n");
+                               g_string_append_printf(gstr,
+                                       G_DBUS_ANNOTATE_DEPRECATED("\t\t\t"));
 
                        g_string_append_printf(gstr, "\t\t</signal>\n");
                }
        }
+
+       for (property = iface->properties; property && property->name;
+                                                               property++) {
+               gboolean deprecated = property->flags &
+                                       G_DBUS_PROPERTY_FLAG_DEPRECATED;
+
+               g_string_append_printf(gstr, "\t\t<property name=\"%s\""
+                                       " type=\"%s\" access=\"%s%s\"",
+                                       property->name, property->type,
+                                       property->get ? "read" : "",
+                                       property->set ? "write" : "");
+
+               if (!deprecated)
+                       g_string_append_printf(gstr, "/>\n");
+               else
+                       g_string_append_printf(gstr,
+                               G_DBUS_ANNOTATE_DEPRECATED(">\n\t\t\t"));
+       }
 }
 
 static void generate_introspection_xml(DBusConnection *conn,
@@ -226,7 +293,7 @@ void g_dbus_pending_success(DBusConnection *connection,
 {
        GSList *list;
 
-        for (list = pending_security; list; list = list->next) {
+       for (list = pending_security; list; list = list->next) {
                struct security_data *secdata = list->data;
 
                if (secdata->pending != pending)
@@ -240,7 +307,7 @@ void g_dbus_pending_success(DBusConnection *connection,
                dbus_message_unref(secdata->message);
                g_free(secdata);
                return;
-        }
+       }
 }
 
 void g_dbus_pending_error_valist(DBusConnection *connection,
@@ -249,7 +316,7 @@ void g_dbus_pending_error_valist(DBusConnection *connection,
 {
        GSList *list;
 
-        for (list = pending_security; list; list = list->next) {
+       for (list = pending_security; list; list = list->next) {
                struct security_data *secdata = list->data;
                DBusMessage *reply;
 
@@ -268,7 +335,7 @@ void g_dbus_pending_error_valist(DBusConnection *connection,
                dbus_message_unref(secdata->message);
                g_free(secdata);
                return;
-        }
+       }
 }
 
 void g_dbus_pending_error(DBusConnection *connection,
@@ -364,12 +431,177 @@ static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
        return FALSE;
 }
 
-static void generic_unregister(DBusConnection *connection, void *user_data)
+static GDBusPendingPropertySet next_pending_property = 1;
+static GSList *pending_property_set;
+
+static struct property_data *remove_pending_property_data(
+                                               GDBusPendingPropertySet id)
 {
-       struct generic_data *data = user_data;
+       struct property_data *propdata;
+       GSList *l;
 
-       g_free(data->introspect);
-       g_free(data);
+       for (l = pending_property_set; l != NULL; l = l->next) {
+               propdata = l->data;
+               if (propdata->id != id)
+                       continue;
+
+               break;
+       }
+
+       if (l == NULL)
+               return NULL;
+
+       pending_property_set = g_slist_delete_link(pending_property_set, l);
+
+       return propdata;
+}
+
+void g_dbus_pending_property_success(GDBusPendingPropertySet id)
+{
+       struct property_data *propdata;
+
+       propdata = remove_pending_property_data(id);
+       if (propdata == NULL)
+               return;
+
+       g_dbus_send_reply(propdata->conn, propdata->message,
+                                                       DBUS_TYPE_INVALID);
+       dbus_message_unref(propdata->message);
+       g_free(propdata);
+}
+
+void g_dbus_pending_property_error_valist(GDBusPendingReply id,
+                                       const char *name, const char *format,
+                                       va_list args)
+{
+       struct property_data *propdata;
+       DBusMessage *reply;
+
+       propdata = remove_pending_property_data(id);
+       if (propdata == NULL)
+               return;
+
+       reply = g_dbus_create_error_valist(propdata->message, name, format,
+                                                                       args);
+       if (reply != NULL) {
+               dbus_connection_send(propdata->conn, reply, NULL);
+               dbus_message_unref(reply);
+       }
+
+       dbus_message_unref(propdata->message);
+       g_free(propdata);
+}
+
+void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
+                                               const char *format, ...)
+{
+       va_list args;
+
+       va_start(args, format);
+
+       g_dbus_pending_property_error_valist(id, name, format, args);
+
+       va_end(args);
+}
+
+static void reset_parent(gpointer data, gpointer user_data)
+{
+       struct generic_data *child = data;
+       struct generic_data *parent = user_data;
+
+       child->parent = parent;
+}
+
+static void append_property(struct interface_data *iface,
+                       const GDBusPropertyTable *p, DBusMessageIter *dict)
+{
+       DBusMessageIter entry, value;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &p->name);
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, p->type,
+                                                               &value);
+
+       p->get(p, &value, iface->user_data);
+
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_properties(struct interface_data *data,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter dict;
+       const GDBusPropertyTable *p;
+
+       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);
+
+       for (p = data->properties; p && p->name; p++) {
+               if (p->get == NULL)
+                       continue;
+
+               if (p->exists != NULL && !p->exists(p, data->user_data))
+                       continue;
+
+               append_property(data, p, &dict);
+       }
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void append_interface(gpointer data, gpointer user_data)
+{
+       struct interface_data *iface = data;
+       DBusMessageIter *array = user_data;
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
+       append_properties(data, &entry);
+       dbus_message_iter_close_container(array, &entry);
+}
+
+static void emit_interfaces_added(struct generic_data *data)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter, array;
+
+       if (root == NULL || data == root)
+               return;
+
+       signal = dbus_message_new_signal(root->path,
+                                       DBUS_INTERFACE_OBJECT_MANAGER,
+                                       "InterfacesAdded");
+       if (signal == NULL)
+               return;
+
+       dbus_message_iter_init_append(signal, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                                               &data->path);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_ARRAY_AS_STRING
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_VARIANT_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+       g_slist_foreach(data->added, append_interface, &array);
+       g_slist_free(data->added);
+       data->added = NULL;
+
+       dbus_message_iter_close_container(&iter, &array);
+
+       g_dbus_send_message(data->conn, signal);
 }
 
 static struct interface_data *find_interface(GSList *interfaces,
@@ -410,6 +642,370 @@ static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
        return TRUE;
 }
 
+static gboolean remove_interface(struct generic_data *data, const char *name)
+{
+       struct interface_data *iface;
+
+       iface = find_interface(data->interfaces, name);
+       if (iface == NULL)
+               return FALSE;
+
+       process_properties_from_interface(data, iface);
+
+       data->interfaces = g_slist_remove(data->interfaces, iface);
+
+       if (iface->destroy) {
+               iface->destroy(iface->user_data);
+               iface->user_data = NULL;
+       }
+
+       /*
+        * Interface being removed was just added, on the same mainloop
+        * iteration? Don't send any signal
+        */
+       if (g_slist_find(data->added, iface)) {
+               data->added = g_slist_remove(data->added, iface);
+               g_free(iface->name);
+               g_free(iface);
+               return TRUE;
+       }
+
+       if (data->parent == NULL) {
+               g_free(iface->name);
+               g_free(iface);
+               return TRUE;
+       }
+
+       data->removed = g_slist_prepend(data->removed, iface->name);
+       g_free(iface);
+
+       if (data->process_id > 0)
+               return TRUE;
+
+       data->process_id = g_idle_add(process_changes, data);
+
+       return TRUE;
+}
+
+static struct generic_data *invalidate_parent_data(DBusConnection *conn,
+                                               const char *child_path)
+{
+       struct generic_data *data = NULL, *child = NULL, *parent = NULL;
+       char *parent_path, *slash;
+
+       parent_path = g_strdup(child_path);
+       slash = strrchr(parent_path, '/');
+       if (slash == NULL)
+               goto done;
+
+       if (slash == parent_path && parent_path[1] != '\0')
+               parent_path[1] = '\0';
+       else
+               *slash = '\0';
+
+       if (!strlen(parent_path))
+               goto done;
+
+       if (dbus_connection_get_object_path_data(conn, parent_path,
+                                                       (void *) &data) == FALSE) {
+               goto done;
+       }
+
+       parent = invalidate_parent_data(conn, parent_path);
+
+       if (data == NULL) {
+               data = parent;
+               if (data == NULL)
+                       goto done;
+       }
+
+       g_free(data->introspect);
+       data->introspect = NULL;
+
+       if (!dbus_connection_get_object_path_data(conn, child_path,
+                                                       (void *) &child))
+               goto done;
+
+       if (child == NULL || g_slist_find(data->objects, child) != NULL)
+               goto done;
+
+       data->objects = g_slist_prepend(data->objects, child);
+       child->parent = data;
+
+done:
+       g_free(parent_path);
+       return data;
+}
+
+static inline const GDBusPropertyTable *find_property(const GDBusPropertyTable *properties,
+                                                       const char *name)
+{
+       const GDBusPropertyTable *p;
+
+       for (p = properties; p && p->name; p++) {
+               if (strcmp(name, p->name) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+static DBusMessage *properties_get(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct generic_data *data = user_data;
+       struct interface_data *iface;
+       const GDBusPropertyTable *property;
+       const char *interface, *name;
+       DBusMessageIter iter, value;
+       DBusMessage *reply;
+
+       if (!dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &interface,
+                                       DBUS_TYPE_STRING, &name,
+                                       DBUS_TYPE_INVALID))
+               return NULL;
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                               "No such interface '%s'", interface);
+
+       property = find_property(iface->properties, name);
+       if (property == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                               "No such property '%s'", name);
+
+       if (property->exists != NULL &&
+                       !property->exists(property, iface->user_data))
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "No such property '%s'", name);
+
+       if (property->get == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                               "Property '%s' is not readable", name);
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               return NULL;
+
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                               property->type, &value);
+
+       if (!property->get(property, &value, iface->user_data)) {
+               dbus_message_unref(reply);
+               return NULL;
+       }
+
+       dbus_message_iter_close_container(&iter, &value);
+
+       return reply;
+}
+
+static DBusMessage *properties_get_all(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct generic_data *data = user_data;
+       struct interface_data *iface;
+       const char *interface;
+       DBusMessageIter iter;
+       DBusMessage *reply;
+
+       if (!dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &interface,
+                                       DBUS_TYPE_INVALID))
+               return NULL;
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "No such interface '%s'", interface);
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               return NULL;
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       append_properties(iface, &iter);
+
+       return reply;
+}
+
+static DBusMessage *properties_set(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct generic_data *data = user_data;
+       DBusMessageIter iter, sub;
+       struct interface_data *iface;
+       const GDBusPropertyTable *property;
+       const char *name, *interface;
+       struct property_data *propdata;
+
+       if (!dbus_message_iter_init(message, &iter))
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                                       "No arguments given");
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "Invalid argument type: '%c'",
+                                       dbus_message_iter_get_arg_type(&iter));
+
+       dbus_message_iter_get_basic(&iter, &interface);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "Invalid argument type: '%c'",
+                                       dbus_message_iter_get_arg_type(&iter));
+
+       dbus_message_iter_get_basic(&iter, &name);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "Invalid argument type: '%c'",
+                                       dbus_message_iter_get_arg_type(&iter));
+
+       dbus_message_iter_recurse(&iter, &sub);
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "No such interface '%s'", interface);
+
+       property = find_property(iface->properties, name);
+       if (property == NULL)
+               return g_dbus_create_error(message,
+                                               DBUS_ERROR_UNKNOWN_PROPERTY,
+                                               "No such property '%s'", name);
+
+       if (property->set == NULL)
+               return g_dbus_create_error(message,
+                                       DBUS_ERROR_PROPERTY_READ_ONLY,
+                                       "Property '%s' is not writable", name);
+
+       if (property->exists != NULL &&
+                       !property->exists(property, iface->user_data))
+               return g_dbus_create_error(message,
+                                               DBUS_ERROR_UNKNOWN_PROPERTY,
+                                               "No such property '%s'", name);
+
+       propdata = g_new(struct property_data, 1);
+       propdata->id = next_pending_property++;
+       propdata->message = dbus_message_ref(message);
+       propdata->conn = connection;
+       pending_property_set = g_slist_prepend(pending_property_set, propdata);
+
+       property->set(property, &sub, propdata->id, iface->user_data);
+
+       return NULL;
+}
+
+static const GDBusMethodTable properties_methods[] = {
+       { GDBUS_METHOD("Get",
+                       GDBUS_ARGS({ "interface", "s" }, { "name", "s" }),
+                       GDBUS_ARGS({ "value", "v" }),
+                       properties_get) },
+       { GDBUS_ASYNC_METHOD("Set",
+                       GDBUS_ARGS({ "interface", "s" }, { "name", "s" },
+                                                       { "value", "v" }),
+                       NULL,
+                       properties_set) },
+       { GDBUS_METHOD("GetAll",
+                       GDBUS_ARGS({ "interface", "s" }),
+                       GDBUS_ARGS({ "properties", "a{sv}" }),
+                       properties_get_all) },
+       { }
+};
+
+static const GDBusSignalTable properties_signals[] = {
+       { GDBUS_SIGNAL("PropertiesChanged",
+                       GDBUS_ARGS({ "interface", "s" },
+                                       { "changed_properties", "a{sv}" },
+                                       { "invalidated_properties", "as"})) },
+       { }
+};
+
+static void append_name(gpointer data, gpointer user_data)
+{
+       char *name = data;
+       DBusMessageIter *iter = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
+}
+
+static void emit_interfaces_removed(struct generic_data *data)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter, array;
+
+       if (root == NULL || data == root)
+               return;
+
+       signal = dbus_message_new_signal(root->path,
+                                       DBUS_INTERFACE_OBJECT_MANAGER,
+                                       "InterfacesRemoved");
+       if (signal == NULL)
+               return;
+
+       dbus_message_iter_init_append(signal, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                                               &data->path);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &array);
+
+       g_slist_foreach(data->removed, append_name, &array);
+       g_slist_free_full(data->removed, g_free);
+       data->removed = NULL;
+
+       dbus_message_iter_close_container(&iter, &array);
+
+       g_dbus_send_message(data->conn, signal);
+}
+
+static gboolean process_changes(gpointer user_data)
+{
+       struct generic_data *data = user_data;
+
+       data->process_id = 0;
+
+       if (data->added != NULL)
+               emit_interfaces_added(data);
+
+       /* Flush pending properties */
+       if (data->pending_prop == TRUE)
+               process_property_changes(data);
+
+       if (data->removed != NULL)
+               emit_interfaces_removed(data);
+
+       return FALSE;
+}
+
+static void generic_unregister(DBusConnection *connection, void *user_data)
+{
+       struct generic_data *data = user_data;
+       struct generic_data *parent = data->parent;
+
+       if (parent != NULL)
+               parent->objects = g_slist_remove(parent->objects, data);
+
+       if (data->process_id > 0) {
+               g_source_remove(data->process_id);
+               process_changes(data);
+       }
+
+       g_slist_foreach(data->objects, reset_parent, data->parent);
+       g_slist_free(data->objects);
+
+       dbus_connection_unref(data->conn);
+       g_free(data->introspect);
+       g_free(data->path);
+       g_free(data);
+}
+
 static DBusHandlerResult generic_message(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
@@ -450,48 +1046,100 @@ static DBusObjectPathVTable generic_table = {
        .message_function       = generic_message,
 };
 
-static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
+static const GDBusMethodTable introspect_methods[] = {
+       { GDBUS_METHOD("Introspect", NULL,
+                       GDBUS_ARGS({ "xml", "s" }), introspect) },
+       { }
+};
+
+static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
 {
-       struct generic_data *data = NULL;
-       char *parent_path, *slash;
+       DBusMessageIter array;
 
-       parent_path = g_strdup(child_path);
-       slash = strrchr(parent_path, '/');
-       if (slash == NULL)
-               goto done;
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_ARRAY_AS_STRING
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_VARIANT_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
 
-       if (slash == parent_path && parent_path[1] != '\0')
-               parent_path[1] = '\0';
-       else
-               *slash = '\0';
+       g_slist_foreach(data->interfaces, append_interface, &array);
 
-       if (!strlen(parent_path))
-               goto done;
+       dbus_message_iter_close_container(iter, &array);
+}
 
-       if (dbus_connection_get_object_path_data(conn, parent_path,
-                                                       (void *) &data) == FALSE) {
-               goto done;
-       }
+static void append_object(gpointer data, gpointer user_data)
+{
+       struct generic_data *child = data;
+       DBusMessageIter *array = user_data;
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+                                                               &child->path);
+       append_interfaces(child, &entry);
+       dbus_message_iter_close_container(array, &entry);
+
+       g_slist_foreach(child->objects, append_object, user_data);
+}
 
-       invalidate_parent_data(conn, parent_path);
+static DBusMessage *get_objects(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct generic_data *data = user_data;
+       DBusMessage *reply;
+       DBusMessageIter iter;
+       DBusMessageIter array;
 
-       if (data == NULL)
-               goto done;
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               return NULL;
 
-       g_free(data->introspect);
-       data->introspect = NULL;
+       dbus_message_iter_init_append(reply, &iter);
 
-done:
-       g_free(parent_path);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_OBJECT_PATH_AS_STRING
+                                       DBUS_TYPE_ARRAY_AS_STRING
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_ARRAY_AS_STRING
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &array);
+
+       g_slist_foreach(data->objects, append_object, &array);
+
+       dbus_message_iter_close_container(&iter, &array);
+
+       return reply;
 }
 
-static const GDBusMethodTable introspect_methods[] = {
-       { GDBUS_METHOD("Introspect", NULL,
-                       GDBUS_ARGS({ "xml", "s" }), introspect) },
+static const GDBusMethodTable manager_methods[] = {
+       { GDBUS_METHOD("GetManagedObjects", NULL,
+               GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
        { }
 };
 
-static void add_interface(struct generic_data *data, const char *name,
+static const GDBusSignalTable manager_signals[] = {
+       { GDBUS_SIGNAL("InterfacesAdded",
+               GDBUS_ARGS({ "object", "o" },
+                               { "interfaces", "a{sa{sv}}" })) },
+       { GDBUS_SIGNAL("InterfacesRemoved",
+               GDBUS_ARGS({ "object", "o" }, { "interfaces", "as" })) },
+       { }
+};
+
+static void add_interface(struct generic_data *data,
+                               const char *name,
                                const GDBusMethodTable *methods,
                                const GDBusSignalTable *signals,
                                const GDBusPropertyTable *properties,
@@ -509,6 +1157,14 @@ static void add_interface(struct generic_data *data, const char *name,
        iface->destroy = destroy;
 
        data->interfaces = g_slist_append(data->interfaces, iface);
+       if (data->parent == NULL)
+               return;
+
+       data->added = g_slist_append(data->added, iface);
+       if (data->process_id > 0)
+               return;
+
+       data->process_id = g_idle_add(process_changes, data);
 }
 
 static struct generic_data *object_path_ref(DBusConnection *connection,
@@ -525,6 +1181,8 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
        }
 
        data = g_new0(struct generic_data, 1);
+       data->conn = dbus_connection_ref(connection);
+       data->path = g_strdup(path);
        data->refcount = 1;
 
        data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
@@ -538,31 +1196,12 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
 
        invalidate_parent_data(connection, path);
 
-       add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
-                       introspect_methods, NULL, NULL, data, NULL);
+       add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods,
+                                               NULL, NULL, data, NULL);
 
        return data;
 }
 
-static gboolean remove_interface(struct generic_data *data, const char *name)
-{
-       struct interface_data *iface;
-
-       iface = find_interface(data->interfaces, name);
-       if (iface == NULL)
-               return FALSE;
-
-       data->interfaces = g_slist_remove(data->interfaces, iface);
-
-       if (iface->destroy)
-               iface->destroy(iface->user_data);
-
-       g_free(iface->name);
-       g_free(iface);
-
-       return TRUE;
-}
-
 static void object_path_unref(DBusConnection *connection, const char *path)
 {
        struct generic_data *data = NULL;
@@ -580,10 +1219,11 @@ static void object_path_unref(DBusConnection *connection, const char *path)
                return;
 
        remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
+       remove_interface(data, DBUS_INTERFACE_PROPERTIES);
 
-       invalidate_parent_data(connection, path);
+       invalidate_parent_data(data->conn, data->path);
 
-       dbus_connection_unregister_object_path(connection, path);
+       dbus_connection_unregister_object_path(data->conn, data->path);
 }
 
 static gboolean check_signal(DBusConnection *conn, const char *path,
@@ -645,8 +1285,8 @@ static dbus_bool_t emit_signal_valist(DBusConnection *conn,
                goto fail;
 
        if (g_dbus_args_have_signature(args, signal) == FALSE) {
-               error("%s.%s: expected signature'%s' but got '%s'",
-                               interface, name, args, signature);
+               error("%s.%s: got unexpected signature '%s'", interface, name,
+                                       dbus_message_get_signature(signal));
                ret = FALSE;
                goto fail;
        }
@@ -678,8 +1318,14 @@ gboolean g_dbus_register_interface(DBusConnection *connection,
                return FALSE;
        }
 
-       add_interface(data, name, methods, signals,
-                       properties, user_data, destroy);
+       if (properties != NULL && !find_interface(data->interfaces,
+                                               DBUS_INTERFACE_PROPERTIES))
+               add_interface(data, DBUS_INTERFACE_PROPERTIES,
+                               properties_methods, properties_signals, NULL,
+                               data, NULL);
+
+       add_interface(data, name, methods, signals, properties, user_data,
+                                                               destroy);
 
        g_free(data->introspect);
        data->introspect = NULL;
@@ -708,7 +1354,7 @@ gboolean g_dbus_unregister_interface(DBusConnection *connection,
        g_free(data->introspect);
        data->introspect = NULL;
 
-       object_path_unref(connection, path);
+       object_path_unref(connection, data->path);
 
        return TRUE;
 }
@@ -856,3 +1502,158 @@ gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
        return emit_signal_valist(connection, path, interface,
                                                        name, type, args);
 }
+
+static void process_properties_from_interface(struct generic_data *data,
+                                               struct interface_data *iface)
+{
+       GSList *l;
+       DBusMessage *signal;
+       DBusMessageIter iter, dict, array;
+       GSList *invalidated;
+
+       if (iface->pending_prop == NULL)
+               return;
+
+       signal = dbus_message_new_signal(data->path,
+                       DBUS_INTERFACE_PROPERTIES, "PropertiesChanged");
+       if (signal == NULL) {
+               error("Unable to allocate new " DBUS_INTERFACE_PROPERTIES
+                                               ".PropertiesChanged signal");
+               return;
+       }
+
+       iface->pending_prop = g_slist_reverse(iface->pending_prop);
+
+       dbus_message_iter_init_append(signal, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &iface->name);
+       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);
+
+       invalidated = NULL;
+
+       for (l = iface->pending_prop; l != NULL; l = l->next) {
+               GDBusPropertyTable *p = l->data;
+
+               if (p->get == NULL)
+                       continue;
+
+               if (p->exists != NULL && !p->exists(p, iface->user_data)) {
+                       invalidated = g_slist_prepend(invalidated, p);
+                       continue;
+               }
+
+               append_property(iface, p, &dict);
+       }
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_STRING_AS_STRING, &array);
+       for (l = invalidated; l != NULL; l = g_slist_next(l)) {
+               GDBusPropertyTable *p = l->data;
+
+               dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+                                                               &p->name);
+       }
+       g_slist_free(invalidated);
+       dbus_message_iter_close_container(&iter, &array);
+
+       g_dbus_send_message(data->conn, signal);
+
+       g_slist_free(iface->pending_prop);
+       iface->pending_prop = NULL;
+}
+
+static void process_property_changes(struct generic_data *data)
+{
+       GSList *l;
+
+       for (l = data->interfaces; l != NULL; l = l->next) {
+               struct interface_data *iface = l->data;
+
+               process_properties_from_interface(data, iface);
+       }
+
+       data->pending_prop = FALSE;
+}
+
+void g_dbus_emit_property_changed(DBusConnection *connection,
+                               const char *path, const char *interface,
+                               const char *name)
+{
+       const GDBusPropertyTable *property;
+       struct generic_data *data;
+       struct interface_data *iface;
+
+       if (!dbus_connection_get_object_path_data(connection, path,
+                                       (void **) &data) || data == NULL)
+               return;
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return;
+
+       property = find_property(iface->properties, name);
+       if (property == NULL) {
+               error("Could not find property %s in %p", name,
+                                                       iface->properties);
+               return;
+       }
+
+       data->pending_prop = TRUE;
+       iface->pending_prop = g_slist_prepend(iface->pending_prop,
+                                               (void *) property);
+
+       if (!data->process_id) {
+               data->process_id = g_idle_add(process_changes, data);
+               return;
+       }
+}
+
+gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
+                               const char *interface, DBusMessageIter *iter)
+{
+       struct generic_data *data;
+       struct interface_data *iface;
+
+       if (!dbus_connection_get_object_path_data(connection, path,
+                                       (void **) &data) || data == NULL)
+               return FALSE;
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return FALSE;
+
+       append_properties(iface, iter);
+
+       return TRUE;
+}
+
+gboolean g_dbus_attach_object_manager(DBusConnection *connection)
+{
+       struct generic_data *data;
+
+       data = object_path_ref(connection, "/");
+       if (data == NULL)
+               return FALSE;
+
+       add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER,
+                                       manager_methods, manager_signals,
+                                       NULL, data, NULL);
+       root = data;
+
+       return TRUE;
+}
+
+gboolean g_dbus_detach_object_manager(DBusConnection *connection)
+{
+       if (!g_dbus_unregister_interface(connection, "/",
+                                       DBUS_INTERFACE_OBJECT_MANAGER))
+               return FALSE;
+
+       root = NULL;
+
+       return TRUE;
+}
index d749176..9e4f994 100644 (file)
@@ -78,7 +78,7 @@ struct filter_data {
        gboolean registered;
 };
 
-static struct filter_data *filter_data_find(DBusConnection *connection,
+static struct filter_data *filter_data_find_match(DBusConnection *connection,
                                                        const char *name,
                                                        const char *owner,
                                                        const char *path,
@@ -95,28 +95,39 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
                if (connection != data->connection)
                        continue;
 
-               if (name && data->name &&
-                               g_str_equal(name, data->name) == FALSE)
+               if (g_strcmp0(name, data->name) != 0)
                        continue;
 
-               if (owner && data->owner &&
-                               g_str_equal(owner, data->owner) == FALSE)
+               if (g_strcmp0(owner, data->owner) != 0)
                        continue;
 
-               if (path && data->path &&
-                               g_str_equal(path, data->path) == FALSE)
+               if (g_strcmp0(path, data->path) != 0)
                        continue;
 
-               if (interface && data->interface &&
-                               g_str_equal(interface, data->interface) == FALSE)
+               if (g_strcmp0(interface, data->interface) != 0)
                        continue;
 
-               if (member && data->member &&
-                               g_str_equal(member, data->member) == FALSE)
+               if (g_strcmp0(member, data->member) != 0)
                        continue;
 
-               if (argument && data->argument &&
-                               g_str_equal(argument, data->argument) == FALSE)
+               if (g_strcmp0(argument, data->argument) != 0)
+                       continue;
+
+               return data;
+       }
+
+       return NULL;
+}
+
+static struct filter_data *filter_data_find(DBusConnection *connection)
+{
+       GSList *current;
+
+       for (current = listeners;
+                       current != NULL; current = current->next) {
+               struct filter_data *data = current->data;
+
+               if (connection != data->connection)
                        continue;
 
                return data;
@@ -204,7 +215,7 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
        struct filter_data *data;
        const char *name = NULL, *owner = NULL;
 
-       if (filter_data_find(connection, NULL, NULL, NULL, NULL, NULL, NULL) == NULL) {
+       if (filter_data_find(connection) == NULL) {
                if (!dbus_connection_add_filter(connection,
                                        message_filter, NULL, NULL)) {
                        error("dbus_connection_add_filter() failed");
@@ -221,16 +232,16 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
                name = sender;
 
 proceed:
-       data = filter_data_find(connection, name, owner, path, interface,
-                                       member, argument);
+       data = filter_data_find_match(connection, name, owner, path,
+                                               interface, member, argument);
        if (data)
                return data;
 
        data = g_new0(struct filter_data, 1);
 
        data->connection = dbus_connection_ref(connection);
-       data->name = name ? g_strdup(name) : NULL;
-       data->owner = owner ? g_strdup(owner) : NULL;
+       data->name = g_strdup(name);
+       data->owner = g_strdup(owner);
        data->path = g_strdup(path);
        data->interface = g_strdup(interface);
        data->member = g_strdup(member);
@@ -378,8 +389,7 @@ static gboolean filter_data_remove_callback(struct filter_data *data,
        listeners = g_slist_remove(listeners, data);
 
        /* Remove filter if there are no listeners left for the connection */
-       if (filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
-                                                               NULL) == NULL)
+       if (filter_data_find(connection) == NULL)
                dbus_connection_remove_filter(connection, message_filter,
                                                NULL);
 
@@ -501,6 +511,7 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 {
        struct filter_data *data;
        const char *sender, *path, *iface, *member, *arg = NULL;
+       GSList *current, *delete_listener = NULL;
 
        /* Only filter signals */
        if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
@@ -512,39 +523,69 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
        member = dbus_message_get_member(message);
        dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
 
-       /* Sender is always bus name */
-       data = filter_data_find(connection, NULL, sender, path, iface, member,
-                                       arg);
-       if (data == NULL) {
-               error("Got %s.%s signal which has no listeners", iface, member);
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
+       /* Sender is always the owner */
 
-       if (data->handle_func) {
-               data->lock = TRUE;
+       for (current = listeners; current != NULL; current = current->next) {
+               data = current->data;
 
-               data->handle_func(connection, message, data);
+               if (connection != data->connection)
+                       continue;
 
-               data->callbacks = data->processed;
-               data->processed = NULL;
-               data->lock = FALSE;
+               if (data->owner && g_str_equal(sender, data->owner) == FALSE)
+                       continue;
+
+               if (data->path && g_str_equal(path, data->path) == FALSE)
+                       continue;
+
+               if (data->interface && g_str_equal(iface,
+                                               data->interface) == FALSE)
+                       continue;
+
+               if (data->member && g_str_equal(member, data->member) == FALSE)
+                       continue;
+
+               if (data->argument && g_str_equal(arg,
+                                               data->argument) == FALSE)
+                       continue;
+
+               if (data->handle_func) {
+                       data->lock = TRUE;
+
+                       data->handle_func(connection, message, data);
+
+                       data->callbacks = data->processed;
+                       data->processed = NULL;
+                       data->lock = FALSE;
+               }
+
+               if (!data->callbacks)
+                       delete_listener = g_slist_prepend(delete_listener,
+                                                               current);
        }
 
-       if (data->callbacks)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+       for (current = delete_listener; current != NULL;
+                                       current = delete_listener->next) {
+               GSList *l = current->data;
 
-       remove_match(data);
+               data = l->data;
 
-       listeners = g_slist_remove(listeners, data);
+               /* Has any other callback added callbacks back to this data? */
+               if (data->callbacks != NULL)
+                       continue;
+
+               remove_match(data);
+               listeners = g_slist_delete_link(listeners, l);
+
+               filter_data_free(data);
+       }
+
+       g_slist_free(delete_listener);
 
        /* Remove filter if there are no listeners left for the connection */
-       if (filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
-                                                               NULL) == NULL)
+       if (filter_data_find(connection) == NULL)
                dbus_connection_remove_filter(connection, message_filter,
                                                NULL);
 
-       filter_data_free(data);
-
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
@@ -711,6 +752,34 @@ guint g_dbus_add_signal_watch(DBusConnection *connection,
        return cb->id;
 }
 
+guint g_dbus_add_properties_watch(DBusConnection *connection,
+                               const char *sender, const char *path,
+                               const char *interface,
+                               GDBusSignalFunction function, void *user_data,
+                               GDBusDestroyFunction destroy)
+{
+       struct filter_data *data;
+       struct filter_callback *cb;
+
+       data = filter_data_get(connection, signal_filter, sender, path,
+                               DBUS_INTERFACE_PROPERTIES, "PropertiesChanged",
+                               interface);
+       if (data == NULL)
+               return 0;
+
+       cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
+                                       user_data);
+       if (cb == NULL)
+               return 0;
+
+       if (data->name != NULL && data->name_watch == 0)
+               data->name_watch = g_dbus_add_service_watch(connection,
+                                                       data->name, NULL,
+                                                       NULL, NULL, NULL);
+
+       return cb->id;
+}
+
 gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
 {
        struct filter_data *data;
@@ -737,8 +806,7 @@ void g_dbus_remove_all_watches(DBusConnection *connection)
 {
        struct filter_data *data;
 
-       while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL,
-                                       NULL, NULL))) {
+       while ((data = filter_data_find(connection))) {
                listeners = g_slist_remove(listeners, data);
                filter_data_call_and_free(data);
        }
diff --git a/gobex/gobex-apparam.c b/gobex/gobex-apparam.c
new file mode 100644 (file)
index 0000000..442a3f1
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "gobex-apparam.h"
+#include "gobex-debug.h"
+
+struct _GObexApparam {
+       GHashTable *tags;
+};
+
+struct apparam_tag {
+       guint8 id;
+       guint8 len;
+       union {
+               /* Data is stored in network order */
+               char string[0];
+               guint8 data[0];
+               guint8 u8;
+               guint16 u16;
+               guint32 u32;
+               guint64 u64;
+       } value;
+} __attribute__ ((packed));
+
+static struct apparam_tag *tag_new(guint8 id, guint8 len, const void *data)
+{
+       struct apparam_tag *tag;
+
+       tag = g_malloc0(2 + len);
+       tag->id = id;
+       tag->len = len;
+       memcpy(tag->value.data, data, len);
+
+       return tag;
+}
+
+static GObexApparam *g_obex_apparam_new(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_new0(GObexApparam, 1);
+       apparam->tags = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                                       NULL, g_free);
+
+       return apparam;
+}
+
+static struct apparam_tag *apparam_tag_decode(const void *data, gsize size,
+                                                       gsize *parsed)
+{
+       struct apparam_tag *tag;
+       const guint8 *ptr = data;
+       guint8 id;
+       guint8 len;
+
+       if (size < 2)
+               return NULL;
+
+       id = ptr[0];
+       len = ptr[1];
+
+       if (len > size - 2)
+               return NULL;
+
+       tag = tag_new(id, len, ptr + 2);
+       if (tag == NULL)
+               return NULL;
+
+       *parsed = 2 + tag->len;
+
+       return tag;
+}
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size)
+{
+       GObexApparam *apparam;
+       GHashTable *tags;
+       gsize count = 0;
+
+       if (size < 2)
+               return NULL;
+
+       apparam = g_obex_apparam_new();
+
+       tags = apparam->tags;
+       while (count < size) {
+               struct apparam_tag *tag;
+               gsize parsed;
+               guint id;
+
+               tag = apparam_tag_decode(data + count, size - count, &parsed);
+               if (tag == NULL)
+                       break;
+
+               id = tag->id;
+               g_hash_table_insert(tags, GUINT_TO_POINTER(id), tag);
+
+               count += parsed;
+       }
+
+       if (count != size) {
+               g_obex_apparam_free(apparam);
+               return NULL;
+       }
+
+       return apparam;
+}
+
+static gssize tag_encode(struct apparam_tag *tag, void *buf, gsize len)
+{
+       gsize count = 2 + tag->len;
+
+       if (len < count)
+               return -ENOBUFS;
+
+       memcpy(buf, tag, count);
+
+       return count;
+}
+
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
+{
+       gsize count = 0;
+       gssize ret;
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_hash_table_iter_init(&iter, apparam->tags);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               struct apparam_tag *tag = value;
+
+               ret = tag_encode(tag, buf + count, len - count);
+               if (ret < 0)
+                       return ret;
+
+               count += ret;
+       }
+
+       return count;
+}
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+                                               const void *value, gsize len)
+{
+       struct apparam_tag *tag;
+       guint uid = id;
+
+       if (apparam == NULL)
+               apparam = g_obex_apparam_new();
+
+       tag = tag_new(id, len, value);
+       g_hash_table_replace(apparam->tags, GUINT_TO_POINTER(uid), tag);
+
+       return apparam;
+}
+
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 value)
+{
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &value, 1);
+}
+
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 value)
+{
+       guint16 num = g_htons(value);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &num, 2);
+}
+
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 value)
+{
+       guint32 num = g_htonl(value);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &num, 4);
+}
+
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 value)
+{
+       guint64 num = GUINT64_TO_BE(value);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %"
+                                               G_GUINT64_FORMAT, id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &num, 8);
+}
+
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+                                                       const char *value)
+{
+       gsize len;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %s", id, value);
+
+       len = strlen(value) + 1;
+       if (len > G_MAXUINT8) {
+               ((char *) value)[G_MAXUINT8 - 1] = '\0';
+               len = G_MAXUINT8;
+       }
+
+       return g_obex_apparam_set_bytes(apparam, id, value, len);
+}
+
+static struct apparam_tag *g_obex_apparam_find_tag(GObexApparam *apparam,
+                                                               guint id)
+{
+       return g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+}
+
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       *dest = tag->value.u8;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+       return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       if (tag->len < sizeof(*dest))
+               return FALSE;
+
+       *dest = g_ntohs(tag->value.u16);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+       return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       if (tag->len < sizeof(*dest))
+               return FALSE;
+
+       *dest = g_ntohl(tag->value.u32);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+       return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       if (tag->len < sizeof(*dest))
+               return FALSE;
+
+       *dest = GUINT64_FROM_BE(tag->value.u64);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%" G_GUINT64_FORMAT, *dest);
+
+       return TRUE;
+}
+
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id)
+{
+       struct apparam_tag *tag;
+       char *string;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return NULL;
+
+       string = g_strndup(tag->value.string, tag->len);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%s", string);
+
+       return string;
+}
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+                                       const guint8 **val, gsize *len)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       *len = tag->len;
+       *val = tag->value.data;
+
+       return TRUE;
+}
+
+void g_obex_apparam_free(GObexApparam *apparam)
+{
+       g_hash_table_unref(apparam->tags);
+       g_free(apparam);
+}
diff --git a/gobex/gobex-apparam.h b/gobex/gobex-apparam.h
new file mode 100644 (file)
index 0000000..46e20d2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GOBEX_APPARAM_H
+#define __GOBEX_APPARAM_H
+
+#include <glib.h>
+
+typedef struct _GObexApparam GObexApparam;
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size);
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize size);
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+                                               const void *value, gsize size);
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 value);
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 value);
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 value);
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 value);
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+                                                       const char *value);
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+                                       const guint8 **val, gsize *len);
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 *value);
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 *value);
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 *value);
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 *value);
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id);
+
+void g_obex_apparam_free(GObexApparam *apparam);
+
+#endif /* __GOBEX_APPARAM_H */
index 589104e..14e2bcd 100644 (file)
 #define G_OBEX_DEBUG_HEADER    (1 << 4)
 #define G_OBEX_DEBUG_PACKET    (1 << 5)
 #define G_OBEX_DEBUG_DATA      (1 << 6)
+#define G_OBEX_DEBUG_APPARAM   (1 << 7)
 
 extern guint gobex_debug;
 
 #define g_obex_debug(level, format, ...) \
        if (gobex_debug & level) \
-               g_debug("%s:%s() " format, __FILE__, __FUNCTION__, \
-                                                       ## __VA_ARGS__)
+               g_log("gobex", G_LOG_LEVEL_DEBUG, "%s:%s() " format, __FILE__, \
+                                               __FUNCTION__, ## __VA_ARGS__)
 
-static inline void g_obex_dump(const char *prefix, const void *buf,
-                                                               gsize len)
+static inline void g_obex_dump(guint level, const char *prefix,
+                                       const void *buf, gsize len)
 {
        const guint8 *data = buf;
        int n = 0;
 
-       if (!(gobex_debug & G_OBEX_DEBUG_DATA))
+       if (!(gobex_debug & level))
                return;
 
        while (len > 0) {
index 56dd9b2..80e8e4e 100644 (file)
@@ -337,6 +337,19 @@ gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
        return TRUE;
 }
 
+GObexApparam *g_obex_header_get_apparam(GObexHeader *header)
+{
+       gboolean ret;
+       const guint8 *val;
+       gsize len;
+
+       ret = g_obex_header_get_bytes(header, &val, &len);
+       if (!ret)
+               return NULL;
+
+       return g_obex_apparam_decode(val, len);
+}
+
 gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val)
 {
        g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
@@ -411,6 +424,18 @@ GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len)
        return header;
 }
 
+GObexHeader *g_obex_header_new_apparam(GObexApparam *apparam)
+{
+       guint8 buf[1024];
+       gssize len;
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       if (len < 0)
+               return NULL;
+
+       return g_obex_header_new_bytes(G_OBEX_HDR_APPARAM, buf, len);
+}
+
 GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val)
 {
        GObexHeader *header;
index 2ee8364..196cb20 100644 (file)
@@ -25,6 +25,7 @@
 #include <glib.h>
 
 #include <gobex/gobex-defs.h>
+#include <gobex/gobex-apparam.h>
 
 /* Header ID's */
 #define G_OBEX_HDR_INVALID     0x00
@@ -77,11 +78,13 @@ gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
                                                                gsize *len);
 gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val);
 gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val);
+GObexApparam *g_obex_header_get_apparam(GObexHeader *header);
 
 GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str);
 GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len);
 GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val);
 GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val);
+GObexHeader *g_obex_header_new_apparam(GObexApparam *apparam);
 
 GSList *g_obex_header_create_list(guint8 first_hdr_id, va_list args,
                                                        gsize *total_len);
index b20542d..7c136af 100644 (file)
@@ -267,7 +267,7 @@ static gboolean write_stream(GObex *obex, GError **err)
        if (status != G_IO_STATUS_NORMAL)
                return FALSE;
 
-       g_obex_dump("<", buf, bytes_written);
+       g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
 
        obex->tx_sent += bytes_written;
        obex->tx_data -= bytes_written;
@@ -290,7 +290,7 @@ static gboolean write_packet(GObex *obex, GError **err)
        if (bytes_written != obex->tx_data)
                return FALSE;
 
-       g_obex_dump("<", buf, bytes_written);
+       g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
 
        obex->tx_sent += bytes_written;
        obex->tx_data -= bytes_written;
@@ -1078,7 +1078,7 @@ read_body:
        } while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len);
 
 done:
-       g_obex_dump(">", obex->rx_buf, obex->rx_data);
+       g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
 
        return TRUE;
 }
@@ -1124,7 +1124,7 @@ static gboolean read_packet(GObex *obex, GError **err)
                return FALSE;
        }
 
-       g_obex_dump(">", obex->rx_buf, obex->rx_data);
+       g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
 
        return TRUE;
 fail:
@@ -1236,6 +1236,7 @@ static GDebugKey keys[] = {
        { "header",     G_OBEX_DEBUG_HEADER },
        { "packet",     G_OBEX_DEBUG_PACKET },
        { "data",       G_OBEX_DEBUG_DATA },
+       { "apparam",    G_OBEX_DEBUG_APPARAM },
 };
 
 GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
@@ -1246,9 +1247,11 @@ GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
 
        if (gobex_debug == 0) {
                const char *env = g_getenv("GOBEX_DEBUG");
-               if (env)
-                       gobex_debug = g_parse_debug_string(env, keys, 6);
-               else
+
+               if (env) {
+                       gobex_debug = g_parse_debug_string(env, keys, 7);
+                       g_setenv("G_MESSAGES_DEBUG", "gobex", FALSE);
+               } else
                        gobex_debug = G_OBEX_DEBUG_NONE;
        }
 
index 79de9a2..2506aec 100644 (file)
@@ -325,9 +325,8 @@ static void connect_event(GIOChannel *io, GError *err, void *user_data)
        stream = FALSE;
 
        /* Read MTU if io is an L2CAP socket */
-       bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, &omtu,
-                                               BT_IO_OPT_IMTU, &imtu,
-                                               BT_IO_OPT_INVALID);
+       bt_io_get(io, NULL, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_IMTU, &imtu,
+                                                       BT_IO_OPT_INVALID);
 
 done:
        if (obex_server_new_connection(server, io, omtu, imtu, stream) < 0)
@@ -520,7 +519,7 @@ static void confirm_rfcomm(GIOChannel *io, void *user_data)
        char address[18];
        uint8_t channel;
 
-       bt_io_get(io, BT_IO_RFCOMM, &err,
+       bt_io_get(io, &err,
                        BT_IO_OPT_SOURCE, source,
                        BT_IO_OPT_DEST, address,
                        BT_IO_OPT_CHANNEL, &channel,
@@ -545,7 +544,7 @@ static void confirm_l2cap(GIOChannel *io, void *user_data)
        char address[18];
        uint16_t psm;
 
-       bt_io_get(io, BT_IO_L2CAP, &err,
+       bt_io_get(io, &err,
                        BT_IO_OPT_SOURCE, source,
                        BT_IO_OPT_DEST, address,
                        BT_IO_OPT_PSM, &psm,
@@ -576,7 +575,7 @@ static GSList *start(struct obex_server *server,
        else
                sec_level = BT_IO_SEC_LOW;
 
-       io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_rfcomm,
+       io = bt_io_listen(NULL, confirm_rfcomm,
                                service, NULL, &err,
                                BT_IO_OPT_CHANNEL, service->channel,
                                BT_IO_OPT_SEC_LEVEL, sec_level,
@@ -595,7 +594,7 @@ static GSList *start(struct obex_server *server,
 
        psm = service->port == OBEX_PORT_RANDOM ? 0 : service->port;
 
-       io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_l2cap,
+       io = bt_io_listen(NULL, confirm_l2cap,
                        service, NULL, &err,
                        BT_IO_OPT_PSM, psm,
                        BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
@@ -610,7 +609,7 @@ static GSList *start(struct obex_server *server,
                service->port = 0;
        } else {
                l = g_slist_prepend(l, io);
-               bt_io_get(io, BT_IO_L2CAP, &err, BT_IO_OPT_PSM, &service->port,
+               bt_io_get(io, &err, BT_IO_OPT_PSM, &service->port,
                                                        BT_IO_OPT_INVALID);
                DBG("listening on psm %d", service->port);
        }
@@ -656,23 +655,10 @@ static void bluetooth_stop(void *data)
 
 static int bluetooth_getpeername(GIOChannel *io, char **name)
 {
-       int sk = g_io_channel_unix_get_fd(io);
        GError *gerr = NULL;
        char address[18];
-       int type;
-       socklen_t len = sizeof(int);
 
-       if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
-               return -errno;
-
-       if (type == SOCK_STREAM)
-               bt_io_get(io, BT_IO_RFCOMM, &gerr,
-                               BT_IO_OPT_DEST, address,
-                               BT_IO_OPT_INVALID);
-       else
-               bt_io_get(io, BT_IO_L2CAP, &gerr,
-                               BT_IO_OPT_DEST, address,
-                               BT_IO_OPT_INVALID);
+       bt_io_get(io, &gerr, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
 
        if (gerr) {
                error("%s", gerr->message);
index e664fc5..1132a34 100644 (file)
@@ -32,7 +32,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <dirent.h>
-#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
index 87f3b6c..c9c3521 100644 (file)
@@ -226,7 +226,7 @@ static void *irmc_connect(struct obex_session *os, int *err)
        param->maxlistcount = 0; /* to count the number of vcards... */
        param->filter = 0x200085; /* UID TEL N VERSION */
        irmc->params = param;
-       irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+       irmc->request = phonebook_pull(PB_CONTACTS, irmc->params,
                                        phonebook_size_result, irmc, err);
        ret = phonebook_pull_read(irmc->request);
        if (err)
@@ -281,7 +281,7 @@ static int irmc_chkput(struct obex_session *os, void *user_data)
        return -EBADR;
 }
 
-static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
+static int irmc_open_devinfo(struct irmc_session *irmc)
 {
        if (!irmc->buffer)
                irmc->buffer = g_string_new("");
@@ -301,93 +301,56 @@ static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
                                "NOTE-TYPE-RX:NONE\r\n",
                                irmc->manu, irmc->model, irmc->sn);
 
-       return irmc;
+       return 0;
 }
 
-static void *irmc_open_pb(const char *name, struct irmc_session *irmc,
-                                                               int *err)
+static int irmc_open_pb(struct irmc_session *irmc)
 {
-       GString *mybuf;
        int ret;
 
-       if (!g_strcmp0(name, ".vcf")) {
-               /* how can we tell if the vcard count call already finished? */
-               irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+       /* how can we tell if the vcard count call already finished? */
+       irmc->request = phonebook_pull(PB_CONTACTS, irmc->params,
                                                query_result, irmc, &ret);
-               if (ret < 0) {
-                       DBG("phonebook_pull failed...");
-                       goto fail;
-               }
-
-               ret = phonebook_pull_read(irmc->request);
-               if (ret < 0) {
-                       DBG("phonebook_pull_read failed...");
-                       goto fail;
-               }
+       if (ret < 0) {
+               DBG("phonebook_pull failed...");
+               return ret;
+       }
 
-               return irmc;
+       ret = phonebook_pull_read(irmc->request);
+       if (ret < 0) {
+               DBG("phonebook_pull_read failed...");
+               return ret;
        }
 
-       if (!g_strcmp0(name, "/info.log")) {
-               mybuf = g_string_new("");
-               g_string_printf(mybuf, "Total-Records:%d\r\n"
+       return 0;
+}
+
+static int irmc_open_info(struct irmc_session *irmc)
+{
+       if (irmc->buffer == NULL)
+               irmc->buffer = g_string_new("");
+
+       g_string_printf(irmc->buffer, "Total-Records:%d\r\n"
                                "Maximum-Records:%d\r\n"
                                "IEL:2\r\n"
                                "DID:%s\r\n",
                                irmc->params->maxlistcount,
                                irmc->params->maxlistcount, irmc->did);
-       } else if (!strncmp(name, "/luid/", 6)) {
-               name += 6;
-               if (!g_strcmp0(name, "cc.log")) {
-                       mybuf = g_string_new("");
-                       g_string_printf(mybuf, "%d\r\n",
-                                               irmc->params->maxlistcount);
-               } else {
-                       int l = strlen(name);
-                       /* FIXME:
-                        * Reply the same to any *.log so we hopefully force a
-                        * full phonebook dump.
-                        * Is IEL:2 ok?
-                        */
-                       if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
-                               DBG("changelog request, force whole book");
-                               mybuf = g_string_new("");
-                               g_string_printf(mybuf, "SN:%s\r\n"
-                                                       "DID:%s\r\n"
-                                                       "Total-Records:%d\r\n"
-                                                       "Maximum-Records:%d\r\n"
-                                                       "*\r\n",
-                                               irmc->sn, irmc->did,
-                                               irmc->params->maxlistcount,
-                                               irmc->params->maxlistcount);
-                       } else {
-                               ret = -EBADR;
-                               goto fail;
-                       }
-               }
-       } else {
-               ret = -EBADR;
-               goto fail;
-       }
 
-       if (!irmc->buffer)
-               irmc->buffer = mybuf;
-       else {
-               irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
-               g_string_free(mybuf, TRUE);
-       }
+       return 0;
+}
 
-       return irmc;
+static int irmc_open_cc(struct irmc_session *irmc)
+{
+       if (irmc->buffer == NULL)
+               irmc->buffer = g_string_new("");
 
-fail:
-       if (err)
-               *err = ret;
+       g_string_printf(irmc->buffer, "%d\r\n", irmc->params->maxlistcount);
 
-       return NULL;
+       return 0;
 }
 
-static void *irmc_open_cal(const char *name, struct irmc_session *irmc,
-                                                               int *err)
+static int irmc_open_cal(struct irmc_session *irmc)
 {
        /* no suport yet. Just return an empty buffer. cal.vcs */
        DBG("unsupported, returning empty buffer");
@@ -395,11 +358,10 @@ static void *irmc_open_cal(const char *name, struct irmc_session *irmc,
        if (!irmc->buffer)
                irmc->buffer = g_string_new("");
 
-       return irmc;
+       return 0;
 }
 
-static void *irmc_open_nt(const char *name, struct irmc_session *irmc,
-                                                               int *err)
+static int irmc_open_nt(struct irmc_session *irmc)
 {
        /* no suport yet. Just return an empty buffer. nt.vnt */
        DBG("unsupported, returning empty buffer");
@@ -407,7 +369,25 @@ static void *irmc_open_nt(const char *name, struct irmc_session *irmc,
        if (!irmc->buffer)
                irmc->buffer = g_string_new("");
 
-       return irmc;
+       return 0;
+}
+
+static int irmc_open_luid(struct irmc_session *irmc)
+{
+       if (irmc->buffer == NULL)
+               irmc->buffer = g_string_new("");
+
+       DBG("changelog request, force whole book");
+       g_string_printf(irmc->buffer, "SN:%s\r\n"
+                                       "DID:%s\r\n"
+                                       "Total-Records:%d\r\n"
+                                       "Maximum-Records:%d\r\n"
+                                       "*\r\n",
+                                       irmc->sn, irmc->did,
+                                       irmc->params->maxlistcount,
+                                       irmc->params->maxlistcount);
+
+       return 0;
 }
 
 static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
@@ -415,7 +395,7 @@ static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
 {
        struct irmc_session *irmc = context;
        int ret = 0;
-       const char *p;
+       char *path;
 
        DBG("name %s context %p", name, context);
 
@@ -423,20 +403,39 @@ static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
                ret = -EPERM;
                goto fail;
        }
-       if (name == NULL || strncmp(name, "telecom/", 8) != 0) {
+
+       if (name == NULL) {
                ret = -EBADR;
                goto fail;
        }
 
-       p = name + 8;
-       if (!g_strcmp0(p, "devinfo.txt"))
-               return irmc_open_devinfo(irmc, err);
-       else if (!strncmp(p, "pb", 2))
-               return irmc_open_pb(p+2, irmc, err);
-       else if (!strncmp(p, "cal", 3))
-               return irmc_open_cal(p+3, irmc, err);
-       else if (!strncmp(p, "nt", 2))
-               return irmc_open_nt(p+2, irmc, err);
+       /* Always contains the absolute path */
+       if (g_path_is_absolute(name))
+               path = g_strdup(name);
+       else
+               path = g_build_filename("/", name, NULL);
+
+       if (g_str_equal(path, PB_DEVINFO))
+               ret = irmc_open_devinfo(irmc);
+       else if (g_str_equal(path, PB_CONTACTS))
+               ret = irmc_open_pb(irmc);
+       else if (g_str_equal(path, PB_INFO_LOG))
+               ret = irmc_open_info(irmc);
+       else if (g_str_equal(path, PB_CC_LOG))
+               ret = irmc_open_cc(irmc);
+       else if (g_str_has_prefix(path, PB_CALENDAR_FOLDER))
+               ret = irmc_open_cal(irmc);
+       else if (g_str_has_prefix(path, PB_NOTES_FOLDER))
+               ret = irmc_open_nt(irmc);
+       else if (g_str_has_prefix(path, PB_LUID_FOLDER))
+               ret = irmc_open_luid(irmc);
+       else
+               ret = -EBADR;
+
+       g_free(path);
+
+       if (ret == 0)
+               return irmc;
 
 fail:
        if (err)
index 576c206..1b18059 100644 (file)
@@ -32,6 +32,7 @@
 #include <inttypes.h>
 
 #include <gobex/gobex.h>
+#include <gobex/gobex-apparam.h>
 
 #include "obexd.h"
 #include "plugin.h"
@@ -45,6 +46,9 @@
 
 #include "messages.h"
 
+#define READ_STATUS_REQ 0
+#define DELETE_STATUS_REQ 1
+
 /* Channel number according to bluez doc/assigned-numbers.txt */
 #define MAS_CHANNEL    16
 
@@ -112,8 +116,8 @@ struct mas_session {
        gboolean finished;
        gboolean nth_call;
        GString *buffer;
-       map_ap_t *inparams;
-       map_ap_t *outparams;
+       GObexApparam *inparams;
+       GObexApparam *outparams;
        gboolean ap_sent;
 };
 
@@ -130,14 +134,12 @@ static int get_params(struct obex_session *os, struct mas_session *mas)
        if (size < 0)
                size = 0;
 
-       mas->inparams = map_ap_decode(buffer, size);
+       mas->inparams = g_obex_apparam_decode(buffer, size);
        if (mas->inparams == NULL) {
                DBG("Error when parsing parameters!");
                return -EBADR;
        }
 
-       mas->outparams = map_ap_new();
-
        return 0;
 }
 
@@ -148,13 +150,19 @@ static void reset_request(struct mas_session *mas)
                mas->buffer = NULL;
        }
 
-       map_ap_free(mas->inparams);
-       mas->inparams = NULL;
-       map_ap_free(mas->outparams);
-       mas->outparams = NULL;
+       if (mas->inparams) {
+               g_obex_apparam_free(mas->inparams);
+               mas->inparams = NULL;
+       }
+
+       if (mas->outparams) {
+               g_obex_apparam_free(mas->outparams);
+               mas->outparams = NULL;
+       }
 
        mas->nth_call = FALSE;
        mas->finished = FALSE;
+       mas->ap_sent = FALSE;
 }
 
 static void mas_clean(struct mas_session *mas)
@@ -289,7 +297,7 @@ static void get_messages_listing_cb(void *session, int err, uint16_t size,
                return;
        }
 
-       map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
 
        if (max == 0) {
                if (!entry)
@@ -390,10 +398,12 @@ static void get_messages_listing_cb(void *session, int err, uint16_t size,
 
 proceed:
        if (!entry) {
-               map_ap_set_u16(mas->outparams, MAP_AP_MESSAGESLISTINGSIZE,
-                                                       size);
-               map_ap_set_u8(mas->outparams, MAP_AP_NEWMESSAGE,
-                                                       newmsg ? 1 : 0);
+               mas->outparams = g_obex_apparam_set_uint16(mas->outparams,
+                                               MAP_AP_MESSAGESLISTINGSIZE,
+                                               size);
+               mas->outparams = g_obex_apparam_set_uint8(mas->outparams,
+                                               MAP_AP_NEWMESSAGE,
+                                               newmsg ? 1 : 0);
        }
 
        if (err != -EAGAIN)
@@ -435,12 +445,14 @@ static void get_folder_listing_cb(void *session, int err, uint16_t size,
                return;
        }
 
-       map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
 
        if (max == 0) {
                if (err != -EAGAIN)
-                       map_ap_set_u16(mas->outparams,
-                                       MAP_AP_FOLDERLISTINGSIZE, size);
+                       mas->outparams = g_obex_apparam_set_uint16(
+                                               mas->outparams,
+                                               MAP_AP_FOLDERLISTINGSIZE,
+                                               size);
 
                if (!name)
                        mas->finished = TRUE;
@@ -477,7 +489,7 @@ proceed:
                obex_object_set_io_flags(mas, G_IO_IN, err);
 }
 
-static void update_inbox_cb(void *session, int err, void *user_data)
+static void set_status_cb(void *session, int err, void *user_data)
 {
        struct mas_session *mas = user_data;
 
@@ -529,8 +541,8 @@ static void *folder_listing_open(const char *name, int oflag, mode_t mode,
 
        DBG("name = %s", name);
 
-       map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
-       map_ap_get_u16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
 
        *err = messages_get_folder_listing(mas->backend_data, name, max,
                                        offset, get_folder_listing_cb, mas);
@@ -551,6 +563,9 @@ static void *msg_listing_open(const char *name, int oflag, mode_t mode,
        /* 1024 is the default when there was no MaxListCount sent */
        uint16_t max = 1024;
        uint16_t offset = 0;
+       /* If MAP client does not specify the subject length,
+          then subject_len = 0 and subject should be sent unaltered. */
+       uint8_t subject_len = 0;
 
        DBG("");
 
@@ -559,28 +574,30 @@ static void *msg_listing_open(const char *name, int oflag, mode_t mode,
                return NULL;
        }
 
-       map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
-       map_ap_get_u16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_SUBJECTLENGTH,
+                                               &subject_len);
 
-       map_ap_get_u32(mas->inparams, MAP_AP_PARAMETERMASK,
+       g_obex_apparam_get_uint32(mas->inparams, MAP_AP_PARAMETERMASK,
                                                &filter.parameter_mask);
-       map_ap_get_u8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
                                                &filter.type);
-       filter.period_begin = map_ap_get_string(mas->inparams,
+       filter.period_begin = g_obex_apparam_get_string(mas->inparams,
                                                MAP_AP_FILTERPERIODBEGIN);
-       filter.period_end = map_ap_get_string(mas->inparams,
+       filter.period_end = g_obex_apparam_get_string(mas->inparams,
                                                MAP_AP_FILTERPERIODEND);
-       map_ap_get_u8(mas->inparams, MAP_AP_FILTERREADSTATUS,
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERREADSTATUS,
                                                &filter.read_status);
-       filter.recipient = map_ap_get_string(mas->inparams,
+       filter.recipient = g_obex_apparam_get_string(mas->inparams,
                                                MAP_AP_FILTERRECIPIENT);
-       filter.originator = map_ap_get_string(mas->inparams,
+       filter.originator = g_obex_apparam_get_string(mas->inparams,
                                                MAP_AP_FILTERORIGINATOR);
-       map_ap_get_u8(mas->inparams, MAP_AP_FILTERPRIORITY,
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERPRIORITY,
                                                &filter.priority);
 
        *err = messages_get_messages_listing(mas->backend_data, name, max,
-                       offset, &filter,
+                       offset, subject_len, &filter,
                        get_messages_listing_cb, mas);
 
        mas->buffer = g_string_new("");
@@ -624,24 +641,65 @@ static void *message_update_open(const char *name, int oflag, mode_t mode,
 
        DBG("");
 
-       if (oflag != O_WRONLY) {
+       if (oflag == O_RDONLY) {
                *err = -EBADR;
                return NULL;
        }
 
-       *err = messages_update_inbox(mas->backend_data, update_inbox_cb, mas);
+       *err = messages_update_inbox(mas->backend_data, set_status_cb, mas);
        if (*err < 0)
                return NULL;
        else
                return mas;
 }
 
+static void *message_set_status_open(const char *name, int oflag, mode_t mode,
+                                       void *driver_data, size_t *size,
+                                       int *err)
+
+{
+       struct mas_session *mas = driver_data;
+       uint8_t indicator;
+       uint8_t value;
+
+       DBG("");
+
+       if (oflag == O_RDONLY) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSINDICATOR,
+                                                               &indicator)) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSVALUE,
+                                                               &value)) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       if (indicator == READ_STATUS_REQ)
+               *err = messages_set_read(mas->backend_data, name, value,
+                                                       set_status_cb, mas);
+       else if (indicator == DELETE_STATUS_REQ)
+               *err = messages_set_delete(mas->backend_data, name, value,
+                                                       set_status_cb, mas);
+       else
+               *err = -EBADR;
+
+       if (*err < 0)
+               return NULL;
+
+       return mas;
+}
+
 static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
                                                                uint8_t *hi)
 {
        struct mas_session *mas = object;
-       size_t len;
-       uint8_t *apbuf;
 
        DBG("");
 
@@ -654,18 +712,7 @@ static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
                return 0;
 
        mas->ap_sent = TRUE;
-       apbuf = map_ap_encode(mas->outparams, &len);
-
-       if (len > mtu) {
-               DBG("MTU is to small to fit application parameters header!");
-               g_free(apbuf);
-
-               return -EIO;
-       }
-
-       memcpy(buf, apbuf, len);
-
-       return len;
+       return g_obex_apparam_encode(mas->outparams, buf, mtu);
 }
 
 static void *any_open(const char *name, int oflag, mode_t mode,
@@ -764,6 +811,7 @@ static struct obex_mime_type_driver mime_msg_listing = {
        .target = MAS_TARGET,
        .target_size = TARGET_SIZE,
        .mimetype = "x-bt/MAP-msg-listing",
+       .get_next_header = any_get_next_header,
        .open = msg_listing_open,
        .close = any_close,
        .read = any_read,
@@ -784,7 +832,7 @@ static struct obex_mime_type_driver mime_message_status = {
        .target = MAS_TARGET,
        .target_size = TARGET_SIZE,
        .mimetype = "x-bt/messageStatus",
-       .open = any_open,
+       .open = message_set_status_open,
        .close = any_close,
        .read = any_read,
        .write = any_write,
index 833c31c..4c66f51 100644 (file)
@@ -331,6 +331,7 @@ int messages_get_folder_listing(void *s, const char *name, uint16_t max,
 
 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)
@@ -346,12 +347,24 @@ int messages_get_message(void *session, const char *handle,
        return -ENOSYS;
 }
 
-int messages_update_inbox(void *session, messages_update_inbox_cb callback,
+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 *s)
 {
        struct session *session = s;
index fb45210..60f3a80 100644 (file)
@@ -303,9 +303,9 @@ int messages_get_folder_listing(void *s, const char *name,
        return 0;
 }
 
-int messages_get_messages_listing(void *session,
-                               const char *name,
+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)
@@ -321,12 +321,25 @@ int messages_get_message(void *session, const char *handle,
        return -ENOSYS;
 }
 
-int messages_update_inbox(void *session, messages_update_inbox_cb callback,
+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)
 {
 }
index 83e087a..00a16b1 100644 (file)
@@ -215,6 +215,8 @@ int messages_get_folder_listing(void *session, const char *name, uint16_t max,
  * session: Backend session.
  * name: Optional subdirectory name.
  * max: Maximum number of entries to retrieve.
+ * offset: Offset of the first entry.
+ * subject_len: Maximum string length of the "subject" parameter in the entries.
  * filter: Filter to apply on returned message listing.
  * size: Total size of listing to be returned.
  * newmsg: Indicates presence of unread messages.
@@ -229,6 +231,7 @@ typedef void (*messages_get_messages_listing_cb)(void *session, int err,
 
 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);
@@ -265,17 +268,39 @@ int messages_get_message(void *session, const char *handle,
                                        messages_get_message_cb callback,
                                        void *user_data);
 
+typedef void (*messages_status_cb)(void *session, int err, void *user_data);
+
 /* Informs Message Server to Update Inbox via network.
  *
  * session: Backend session.
  * user_data: User data if any to be sent.
  * Callback shall be called for every update inbox request received from MCE.
  */
-typedef void (*messages_update_inbox_cb)(void *session, int err,
+int messages_update_inbox(void *session, messages_status_cb callback,
                                                        void *user_data);
+/* Informs Message Server to modify read status of a given message.
+ *
+ * session: Backend session.
+ * handle: Unique identifier to the message.
+ * value: Indicates the new value of the read status for a given message.
+ * Callback shall be called for every read status update request
+ *     recieved from MCE.
+ * user_data: User data if any to be sent.
+ */
+int messages_set_read(void *session, const char *handle, uint8_t value,
+                               messages_status_cb callback, void *user_data);
 
-int messages_update_inbox(void *session, messages_update_inbox_cb callback,
-                                                       void *user_data);
+/* Informs Message Server to modify delete status of a given message.
+ *
+ * session: Backend session.
+ * handle: Unique identifier to the message.
+ * value: Indicates the new value of the delete status for a given message.
+ * Callback shall be called for every delete status update request
+ *     recieved from MCE.
+ * user_data: User data if any to be sent.
+ */
+int messages_set_delete(void *session, const char *handle, uint8_t value,
+                               messages_status_cb callback, void *user_data);
 
 /* Aborts currently pending request.
  *
index c7e792a..c36fab2 100644 (file)
@@ -39,6 +39,7 @@
 #include <inttypes.h>
 
 #include <gobex.h>
+#include <gobex-apparam.h>
 
 #include "obexd.h"
 #include "plugin.h"
 #define PHONEBOOKSIZE_TAG      0X08
 #define NEWMISSEDCALLS_TAG     0X09
 
-/* The following length is in the unit of byte */
-#define ORDER_LEN              1
-#define SEARCHATTRIB_LEN       1
-#define MAXLISTCOUNT_LEN       2
-#define LISTSTARTOFFSET_LEN    2
-#define FILTER_LEN             8
-#define FORMAT_LEN             1
-#define PHONEBOOKSIZE_LEN      2
-#define NEWMISSEDCALLS_LEN     1
-
 #define PBAP_CHANNEL   15
 
 #define PBAP_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>       \
   </attribute>                                                         \
 </record>"
 
-struct aparam_header {
-       uint8_t tag;
-       uint8_t len;
-       uint8_t val[0];
-} __attribute__ ((packed));
-
 struct cache {
        gboolean valid;
        uint32_t index;
@@ -147,7 +132,7 @@ struct pbap_session {
 
 struct pbap_object {
        GString *buffer;
-       GByteArray *aparams;
+       GObexApparam *apparam;
        gboolean firstpacket;
        gboolean lastpart;
        struct pbap_session *session;
@@ -229,33 +214,6 @@ static void cache_clear(struct cache *cache)
        cache->entries = NULL;
 }
 
-static GByteArray *append_aparam_header(GByteArray *buf, uint8_t tag,
-                                                       const void *val)
-{
-       /* largest aparam is for phonebooksize (4 bytes) */
-       uint8_t aparam[sizeof(struct aparam_header) + PHONEBOOKSIZE_LEN];
-       struct aparam_header *hdr = (struct aparam_header *) aparam;
-
-       switch (tag) {
-       case PHONEBOOKSIZE_TAG:
-               hdr->tag = PHONEBOOKSIZE_TAG;
-               hdr->len = PHONEBOOKSIZE_LEN;
-               memcpy(hdr->val, val, PHONEBOOKSIZE_LEN);
-
-               return g_byte_array_append(buf, aparam,
-                       sizeof(struct aparam_header) + PHONEBOOKSIZE_LEN);
-       case NEWMISSEDCALLS_TAG:
-               hdr->tag = NEWMISSEDCALLS_TAG;
-               hdr->len = NEWMISSEDCALLS_LEN;
-               memcpy(hdr->val, val, NEWMISSEDCALLS_LEN);
-
-               return g_byte_array_append(buf, aparam,
-                       sizeof(struct aparam_header) + NEWMISSEDCALLS_LEN);
-       default:
-               return buf;
-       }
-}
-
 static void phonebook_size_result(const char *buffer, size_t bufsize,
                                        int vcards, int missed,
                                        gboolean lastpart, void *user_data)
@@ -275,15 +233,16 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 
        phonebooksize = htons(vcards);
 
-       pbap->obj->aparams = g_byte_array_new();
-       pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-                                       PHONEBOOKSIZE_TAG, &phonebooksize);
+       pbap->obj->apparam = g_obex_apparam_set_uint16(NULL, PHONEBOOKSIZE_TAG,
+                                                               phonebooksize);
 
        if (missed > 0) {
                DBG("missed %d", missed);
 
-               pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-                                               NEWMISSEDCALLS_TAG, &missed);
+               pbap->obj->apparam = g_obex_apparam_set_uint16(
+                                                       pbap->obj->apparam,
+                                                       NEWMISSEDCALLS_TAG,
+                                                       missed);
        }
 
        obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
@@ -319,9 +278,10 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 
                pbap->obj->firstpacket = TRUE;
 
-               pbap->obj->aparams = g_byte_array_new();
-               pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-                                               NEWMISSEDCALLS_TAG, &missed);
+               pbap->obj->apparam = g_obex_apparam_set_uint16(
+                                                       pbap->obj->apparam,
+                                                       NEWMISSEDCALLS_TAG,
+                                                       missed);
        }
 
        obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
@@ -450,9 +410,10 @@ static int generate_response(void *user_data)
                /* Ignore all other parameter and return PhoneBookSize */
                uint16_t size = htons(g_slist_length(pbap->cache.entries));
 
-               pbap->obj->aparams = g_byte_array_new();
-               pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-                                               PHONEBOOKSIZE_TAG, &size);
+               pbap->obj->apparam = g_obex_apparam_set_uint16(
+                                                       pbap->obj->apparam,
+                                                       PHONEBOOKSIZE_TAG,
+                                                       size);
 
                return 0;
        }
@@ -527,85 +488,34 @@ static void cache_entry_done(void *user_data)
 
 static struct apparam_field *parse_aparam(const uint8_t *buffer, uint32_t hlen)
 {
+       GObexApparam *apparam;
        struct apparam_field *param;
-       struct aparam_header *hdr;
-       uint64_t val64;
-       uint32_t len = 0;
-       uint16_t val16;
-
-       param = g_new0(struct apparam_field, 1);
-
-       while (len < hlen) {
-               hdr = (void *) buffer + len;
-
-               switch (hdr->tag) {
-               case ORDER_TAG:
-                       if (hdr->len != ORDER_LEN)
-                               goto failed;
-
-                       param->order = hdr->val[0];
-                       break;
-
-               case SEARCHATTRIB_TAG:
-                       if (hdr->len != SEARCHATTRIB_LEN)
-                               goto failed;
-
-                       param->searchattrib = hdr->val[0];
-                       break;
-               case SEARCHVALUE_TAG:
-                       if (hdr->len == 0)
-                               goto failed;
-
-                       param->searchval = g_try_malloc0(hdr->len + 1);
-                       if (param->searchval)
-                               memcpy(param->searchval, hdr->val, hdr->len);
-                       break;
-               case FILTER_TAG:
-                       if (hdr->len != FILTER_LEN)
-                               goto failed;
-
-                       memcpy(&val64, hdr->val, sizeof(val64));
-                       param->filter = GUINT64_FROM_BE(val64);
-
-                       break;
-               case FORMAT_TAG:
-                       if (hdr->len != FORMAT_LEN)
-                               goto failed;
 
-                       param->format = hdr->val[0];
-                       break;
-               case MAXLISTCOUNT_TAG:
-                       if (hdr->len != MAXLISTCOUNT_LEN)
-                               goto failed;
+       apparam = g_obex_apparam_decode(buffer, hlen);
+       if (apparam == NULL)
+               return NULL;
 
-                       memcpy(&val16, hdr->val, sizeof(val16));
-                       param->maxlistcount = GUINT16_FROM_BE(val16);
-                       break;
-               case LISTSTARTOFFSET_TAG:
-                       if (hdr->len != LISTSTARTOFFSET_LEN)
-                               goto failed;
-
-                       memcpy(&val16, hdr->val, sizeof(val16));
-                       param->liststartoffset = GUINT16_FROM_BE(val16);
-                       break;
-               default:
-                       goto failed;
-               }
+       param = g_new0(struct apparam_field, 1);
 
-               len += hdr->len + sizeof(struct aparam_header);
-       }
+       g_obex_apparam_get_uint8(apparam, ORDER_TAG, &param->order);
+       g_obex_apparam_get_uint8(apparam, SEARCHATTRIB_TAG,
+                                               &param->searchattrib);
+       g_obex_apparam_get_uint8(apparam, FORMAT_TAG, &param->format);
+       g_obex_apparam_get_uint16(apparam, MAXLISTCOUNT_TAG,
+                                               &param->maxlistcount);
+       g_obex_apparam_get_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                               &param->liststartoffset);
+       g_obex_apparam_get_uint64(apparam, FILTER_TAG, &param->filter);
+       param->searchval = g_obex_apparam_get_string(apparam, SEARCHVALUE_TAG);
 
        DBG("o %x sa %x sv %s fil %" G_GINT64_MODIFIER "x for %x max %x off %x",
                        param->order, param->searchattrib, param->searchval,
                        param->filter, param->format, param->maxlistcount,
                        param->liststartoffset);
 
-       return param;
-
-failed:
-       g_free(param);
+       g_obex_apparam_free(apparam);
 
-       return NULL;
+       return param;
 }
 
 static void *pbap_connect(struct obex_session *os, int *err)
@@ -839,8 +749,8 @@ static int vobject_close(void *object)
        if (obj->buffer)
                g_string_free(obj->buffer, TRUE);
 
-       if (obj->aparams)
-               g_byte_array_free(obj->aparams, TRUE);
+       if (obj->apparam)
+               g_obex_apparam_free(obj->apparam);
 
        if (obj->request)
                phonebook_req_finalize(obj->request);
@@ -952,27 +862,13 @@ fail:
        return NULL;
 }
 
-static ssize_t array_read(GByteArray *array, void *buf, size_t count)
-{
-       ssize_t len;
-
-       if (array->len == 0)
-               return 0;
-
-       len = MIN(array->len, count);
-       memcpy(buf, array->data, len);
-       g_byte_array_remove_range(array, 0, len);
-
-       return len;
-}
-
 static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
                                                                uint8_t *hi)
 {
        struct pbap_object *obj = object;
        struct pbap_session *pbap = obj->session;
 
-       if (!obj->buffer && !obj->aparams)
+       if (!obj->buffer && !obj->apparam)
                return -EAGAIN;
 
        *hi = G_OBEX_HDR_APPARAM;
@@ -980,7 +876,7 @@ static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
        if (pbap->params->maxlistcount == 0 || obj->firstpacket) {
                obj->firstpacket = FALSE;
 
-               return array_read(obj->aparams, buf, mtu);
+               return g_obex_apparam_encode(obj->apparam, buf, mtu);
        }
 
        return 0;
@@ -1031,7 +927,7 @@ static ssize_t vobject_list_get_next_header(void *object, void *buf, size_t mtu,
        *hi = G_OBEX_HDR_APPARAM;
 
        if (pbap->params->maxlistcount == 0)
-               return array_read(obj->aparams, buf, mtu);
+               return g_obex_apparam_encode(obj->apparam, buf, mtu);
 
        return 0;
 }
index a1f06b5..59a4eac 100644 (file)
@@ -459,7 +459,7 @@ char *phonebook_set_folder(const char *current_folder,
        root = (g_strcmp0("/", current_folder) == 0);
        child = (new_folder && strlen(new_folder) != 0);
 
-       /* Evolution back-end will support telecom/pb folder only */
+       /* Evolution back-end will support /telecom/pb folder only */
 
        switch (flags) {
        case 0x02:
@@ -471,8 +471,8 @@ char *phonebook_set_folder(const char *current_folder,
 
                /* Go down 1 level */
                fullname = g_build_filename(current_folder, new_folder, NULL);
-               if (strcmp("/telecom", fullname) != 0 &&
-                               strcmp("/telecom/pb", fullname) != 0) {
+               if (strcmp(PB_TELECOM_FOLDER, fullname) != 0 &&
+                               strcmp(PB_CONTACTS_FOLDER, fullname) != 0) {
                        g_free(fullname);
                        fullname = NULL;
                        ret = -ENOENT;
@@ -511,8 +511,8 @@ char *phonebook_set_folder(const char *current_folder,
                }
 
                fullname = g_build_filename(base, new_folder, NULL);
-               if (strcmp(fullname, "/telecom") != 0 &&
-                               strcmp(fullname, "/telecom/pb") != 0) {
+               if (strcmp(fullname, PB_TELECOM_FOLDER) != 0 &&
+                               strcmp(fullname, PB_CONTACTS_FOLDER) != 0) {
                        g_free(fullname);
                        fullname = NULL;
                        ret = -ENOENT;
@@ -548,7 +548,7 @@ void *phonebook_pull(const char *name, const struct apparam_field *params,
 {
        struct query_context *data;
 
-       if (g_strcmp0("/telecom/pb.vcf", name) != 0) {
+       if (g_strcmp0(PB_CONTACTS, name) != 0) {
                if (err)
                        *err = -ENOENT;
 
@@ -638,7 +638,7 @@ void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
        EVCardAttribute *attrib;
        char *uid, *tel, *cname;
 
-       if (g_strcmp0("/telecom/pb", name) != 0) {
+       if (g_strcmp0(PB_CONTACTS_FOLDER, name) != 0) {
                if (err)
                        *err = -ENOENT;
 
index 96635c4..2fd7ba1 100644 (file)
@@ -513,15 +513,15 @@ static TrackerSparqlConnection *connection = NULL;
 
 static const char *name2query(const char *name)
 {
-       if (g_str_equal(name, "/telecom/pb.vcf"))
+       if (g_str_equal(name, PB_CONTACTS))
                return CONTACTS_QUERY_ALL;
-       else if (g_str_equal(name, "/telecom/ich.vcf"))
+       else if (g_str_equal(name, PB_CALLS_INCOMING))
                return INCOMING_CALLS_QUERY;
-       else if (g_str_equal(name, "/telecom/och.vcf"))
+       else if (g_str_equal(name, PB_CALLS_OUTGOING))
                return OUTGOING_CALLS_QUERY;
-       else if (g_str_equal(name, "/telecom/mch.vcf"))
+       else if (g_str_equal(name, PB_CALLS_MISSED))
                return MISSED_CALLS_QUERY;
-       else if (g_str_equal(name, "/telecom/cch.vcf"))
+       else if (g_str_equal(name, PB_CALLS_COMBINED))
                return COMBINED_CALLS_QUERY;
 
        return NULL;
@@ -529,15 +529,15 @@ static const char *name2query(const char *name)
 
 static const char *name2count_query(const char *name)
 {
-       if (g_str_equal(name, "/telecom/pb.vcf"))
+       if (g_str_equal(name, PB_CONTACTS))
                return CONTACTS_COUNT_QUERY;
-       else if (g_str_equal(name, "/telecom/ich.vcf"))
+       else if (g_str_equal(name, PB_CALLS_INCOMING))
                return INCOMING_CALLS_COUNT_QUERY;
-       else if (g_str_equal(name, "/telecom/och.vcf"))
+       else if (g_str_equal(name, PB_CALLS_OUTGOING))
                return OUTGOING_CALLS_COUNT_QUERY;
-       else if (g_str_equal(name, "/telecom/mch.vcf"))
+       else if (g_str_equal(name, PB_CALLS_MISSED))
                return MISSED_CALLS_COUNT_QUERY;
-       else if (g_str_equal(name, "/telecom/cch.vcf"))
+       else if (g_str_equal(name, PB_CALLS_COMBINED))
                return COMBINED_CALLS_COUNT_QUERY;
 
        return NULL;
@@ -550,17 +550,17 @@ static gboolean folder_is_valid(const char *folder)
 
        if (g_str_equal(folder, "/"))
                return TRUE;
-       else if (g_str_equal(folder, "/telecom"))
+       else if (g_str_equal(folder, PB_TELECOM_FOLDER))
                return TRUE;
-       else if (g_str_equal(folder, "/telecom/pb"))
+       else if (g_str_equal(folder, PB_CONTACTS_FOLDER))
                return TRUE;
-       else if (g_str_equal(folder, "/telecom/ich"))
+       else if (g_str_equal(folder, PB_CALLS_INCOMING_FOLDER))
                return TRUE;
-       else if (g_str_equal(folder, "/telecom/och"))
+       else if (g_str_equal(folder, PB_CALLS_OUTGOING_FOLDER))
                return TRUE;
-       else if (g_str_equal(folder, "/telecom/mch"))
+       else if (g_str_equal(folder, PB_CALLS_MISSED_FOLDER))
                return TRUE;
-       else if (g_str_equal(folder, "/telecom/cch"))
+       else if (g_str_equal(folder, PB_CALLS_COMBINED_FOLDER))
                return TRUE;
 
        return FALSE;
@@ -568,15 +568,15 @@ static gboolean folder_is_valid(const char *folder)
 
 static const char *folder2query(const char *folder)
 {
-       if (g_str_equal(folder, "/telecom/pb"))
+       if (g_str_equal(folder, PB_CONTACTS_FOLDER))
                return CONTACTS_QUERY_ALL_LIST;
-       else if (g_str_equal(folder, "/telecom/ich"))
+       else if (g_str_equal(folder, PB_CALLS_INCOMING_FOLDER))
                return INCOMING_CALLS_LIST;
-       else if (g_str_equal(folder, "/telecom/och"))
+       else if (g_str_equal(folder, PB_CALLS_OUTGOING_FOLDER))
                return OUTGOING_CALLS_LIST;
-       else if (g_str_equal(folder, "/telecom/mch"))
+       else if (g_str_equal(folder, PB_CALLS_MISSED_FOLDER))
                return MISSED_CALLS_LIST;
-       else if (g_str_equal(folder, "/telecom/cch"))
+       else if (g_str_equal(folder, PB_CALLS_COMBINED_FOLDER))
                return COMBINED_CALLS_LIST;
 
        return NULL;
@@ -1541,11 +1541,11 @@ static int pull_newmissedcalls(const char **reply, int num_fields,
        }
 
        if (data->params->maxlistcount == 0) {
-               query = name2count_query("/telecom/mch.vcf");
+               query = name2count_query(PB_CALLS_MISSED);
                col_amount = COUNT_QUERY_COL_AMOUNT;
                pull_cb = pull_contacts_size;
        } else {
-               query = name2query("/telecom/mch.vcf");
+               query = name2query(PB_CALLS_MISSED);
                col_amount = PULL_QUERY_COL_AMOUNT;
                pull_cb = pull_contacts;
        }
@@ -1613,7 +1613,7 @@ int phonebook_pull_read(void *request)
 
        data->newmissedcalls = 0;
 
-       if (g_strcmp0(data->req_name, "/telecom/mch.vcf") == 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
index 00abc08..441cff2 100644 (file)
 #define VCARD_LISTING_ELEMENT "<card handle = \"%d.vcf\" name = \"%s\"/>" EOL
 #define VCARD_LISTING_END "</vCard-listing>"
 
+#define PB_TELECOM_FOLDER "/telecom"
+#define PB_CONTACTS_FOLDER "/telecom/pb"
+#define PB_CALENDAR_FOLDER "/telecom/cal"
+#define PB_NOTES_FOLDER "/telecom/nt"
+#define PB_CALLS_COMBINED_FOLDER "/telecom/cch"
+#define PB_CALLS_INCOMING_FOLDER "/telecom/ich"
+#define PB_CALLS_MISSED_FOLDER "/telecom/mch"
+#define PB_CALLS_OUTGOING_FOLDER "/telecom/och"
+#define PB_LUID_FOLDER "/telecom/luid"
+
+#define PB_CONTACTS "/telecom/pb.vcf"
+#define PB_CALLS_COMBINED "/telecom/cch.vcf"
+#define PB_CALLS_INCOMING "/telecom/ich.vcf"
+#define PB_CALLS_MISSED "/telecom/mch.vcf"
+#define PB_CALLS_OUTGOING "/telecom/och.vcf"
+#define PB_DEVINFO "/telecom/devinfo.txt"
+#define PB_INFO_LOG "/telecom/pb/info.log"
+#define PB_CC_LOG "/telecom/pb/luid/cc.log"
+
+
 struct apparam_field {
        /* list and pull attributes */
        uint16_t maxlistcount;
@@ -41,7 +61,7 @@ struct apparam_field {
        /* list attributes only */
        uint8_t order;
        uint8_t searchattrib;
-       uint8_t *searchval;
+       char *searchval;
 };
 
 /*
diff --git a/src/map_ap.c b/src/map_ap.c
deleted file mode 100644 (file)
index 6efc484..0000000
+++ /dev/null
@@ -1,466 +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 <config.h>
-#endif
-
-#include <string.h>
-
-#include "log.h"
-
-#include "map_ap.h"
-
-enum ap_type {
-       APT_UINT8,
-       APT_UINT16,
-       APT_UINT32,
-       APT_STR
-};
-
-/* NOTE: ap_defs array has to be kept in sync with map_ap_tag. */
-static const struct ap_def {
-       const char *name;
-       enum ap_type type;
-} ap_defs[] = {
-       { "MAXLISTCOUNT",               APT_UINT16 },
-       { "STARTOFFSET",                APT_UINT16 },
-       { "FILTERMESSAGETYPE",          APT_UINT8  },
-       { "FILTERPERIODBEGIN",          APT_STR    },
-       { "FILTERPERIODEND",            APT_STR    },
-       { "FILTERREADSTATUS",           APT_UINT8  },
-       { "FILTERRECIPIENT",            APT_STR    },
-       { "FILTERORIGINATOR",           APT_STR    },
-       { "FILTERPRIORITY",             APT_UINT8  },
-       { "ATTACHMENT",                 APT_UINT8  },
-       { "TRANSPARENT",                APT_UINT8  },
-       { "RETRY",                      APT_UINT8  },
-       { "NEWMESSAGE",                 APT_UINT8  },
-       { "NOTIFICATIONSTATUS",         APT_UINT8  },
-       { "MASINSTANCEID",              APT_UINT8  },
-       { "PARAMETERMASK",              APT_UINT32 },
-       { "FOLDERLISTINGSIZE",          APT_UINT16 },
-       { "MESSAGESLISTINGSIZE",        APT_UINT16 },
-       { "SUBJECTLENGTH",              APT_UINT8  },
-       { "CHARSET",                    APT_UINT8  },
-       { "FRACTIONREQUEST",            APT_UINT8  },
-       { "FRACTIONDELIVER",            APT_UINT8  },
-       { "STATUSINDICATOR",            APT_UINT8  },
-       { "STATUSVALUE",                APT_UINT8  },
-       { "MSETIME",                    APT_STR    },
-};
-
-struct ap_entry {
-       enum map_ap_tag tag;
-       union {
-               uint32_t u32;
-               uint16_t u16;
-               uint8_t u8;
-               char *str;
-       } val;
-};
-
-/* This comes from OBEX specs */
-struct obex_ap_header {
-       uint8_t tag;
-       uint8_t len;
-       uint8_t val[0];
-} __attribute__ ((packed));
-
-static int find_ap_def_offset(uint8_t tag)
-{
-       if (tag == 0 || tag > G_N_ELEMENTS(ap_defs))
-               return -1;
-
-       return tag - 1;
-}
-
-static void ap_entry_dump(gpointer tag, gpointer val, gpointer user_data)
-{
-       struct ap_entry *entry = val;
-       int offset;
-
-       offset = find_ap_def_offset(GPOINTER_TO_INT(tag));
-
-       switch (ap_defs[offset].type) {
-       case APT_UINT8:
-               DBG("%-30s %08x", ap_defs[offset].name, entry->val.u8);
-               break;
-       case APT_UINT16:
-               DBG("%-30s %08x", ap_defs[offset].name, entry->val.u16);
-               break;
-       case APT_UINT32:
-               DBG("%-30s %08x", ap_defs[offset].name, entry->val.u32);
-               break;
-       case APT_STR:
-               DBG("%-30s %s", ap_defs[offset].name, entry->val.str);
-               break;
-       }
-}
-
-static void ap_entry_free(gpointer val)
-{
-       struct ap_entry *entry = val;
-       int offset;
-
-       offset = find_ap_def_offset(entry->tag);
-
-       if (offset >= 0 && ap_defs[offset].type == APT_STR)
-               g_free(entry->val.str);
-
-       g_free(entry);
-}
-
-map_ap_t *map_ap_new(void)
-{
-       return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
-                                                               ap_entry_free);
-}
-
-void map_ap_free(map_ap_t *ap)
-{
-       if (!ap)
-               return;
-
-       g_hash_table_destroy(ap);
-}
-
-static void ap_decode_u8(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-       if (hdr->len != 1) {
-               DBG("Value of tag %u is %u byte(s) long instead of expected "
-                               "1 byte - skipped!", hdr->tag, hdr->len);
-               return;
-       }
-
-       map_ap_set_u8(ap, hdr->tag, hdr->val[0]);
-}
-
-static void ap_decode_u16(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-       uint16_t val;
-
-       if (hdr->len != 2) {
-               DBG("Value of tag %u is %u byte(s) long instead of expected "
-                               "2 bytes - skipped!", hdr->tag, hdr->len);
-               return;
-       }
-
-       memcpy(&val, hdr->val, sizeof(val));
-       map_ap_set_u16(ap, hdr->tag, GUINT16_FROM_BE(val));
-}
-
-static void ap_decode_u32(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-       uint32_t val;
-
-       if (hdr->len != 4) {
-               DBG("Value of tag %u is %u byte(s) long instead of expected "
-                               "4 bytes - skipped!", hdr->tag, hdr->len);
-               return;
-       }
-
-       memcpy(&val, hdr->val, sizeof(val));
-       map_ap_set_u32(ap, hdr->tag, GUINT32_FROM_BE(val));
-}
-
-static void ap_decode_str(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-       char *val = g_malloc0(hdr->len + 1);
-
-       memcpy(val, hdr->val, hdr->len);
-       map_ap_set_string(ap, hdr->tag, val);
-
-       g_free(val);
-}
-
-map_ap_t *map_ap_decode(const uint8_t *buffer, size_t length)
-{
-       map_ap_t *ap;
-       struct obex_ap_header *hdr;
-       uint32_t done;
-       int offset;
-
-       ap = map_ap_new();
-       if (!ap)
-               return NULL;
-
-       for (done = 0;  done < length; done += hdr->len + sizeof(*hdr)) {
-               hdr = (struct obex_ap_header *)(buffer + done);
-
-               offset = find_ap_def_offset(hdr->tag);
-
-               if (offset < 0) {
-                       DBG("Unknown tag %u (length %u) - skipped.",
-                                                       hdr->tag, hdr->len);
-                       continue;
-               }
-
-               switch (ap_defs[offset].type) {
-               case APT_UINT8:
-                       ap_decode_u8(ap, hdr);
-                       break;
-               case APT_UINT16:
-                       ap_decode_u16(ap, hdr);
-                       break;
-               case APT_UINT32:
-                       ap_decode_u32(ap, hdr);
-                       break;
-               case APT_STR:
-                       ap_decode_str(ap, hdr);
-                       break;
-               }
-       }
-
-       g_hash_table_foreach(ap, ap_entry_dump, NULL);
-
-       return ap;
-}
-
-static void ap_encode_u8(GByteArray *buf, struct ap_entry *entry)
-{
-       struct obex_ap_header *hdr;
-
-       hdr = (struct obex_ap_header *) buf->data + buf->len;
-       g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 1);
-
-       hdr->tag = entry->tag;
-       hdr->len = 1;
-       hdr->val[0] = entry->val.u8;
-}
-
-static void ap_encode_u16(GByteArray *buf, struct ap_entry *entry)
-{
-       struct obex_ap_header *hdr;
-       uint16_t val;
-
-       hdr = (struct obex_ap_header *) buf->data + buf->len;
-
-       g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 2);
-
-       hdr->tag = entry->tag;
-       hdr->len = 2;
-
-       val = GUINT16_TO_BE(entry->val.u16);
-       memcpy(hdr->val, &val, sizeof(val));
-}
-
-static void ap_encode_u32(GByteArray *buf, struct ap_entry *entry)
-{
-       uint32_t val;
-       struct obex_ap_header *hdr;
-
-       hdr = (struct obex_ap_header *) buf->data + buf->len;
-       g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 4);
-
-       hdr->tag = entry->tag;
-       hdr->len = 4;
-
-       val = GUINT32_TO_BE(entry->val.u16);
-       memcpy(hdr->val, &val, sizeof(val));
-}
-
-static void ap_encode_str(GByteArray *buf, struct ap_entry *entry)
-{
-       size_t len;
-       struct obex_ap_header *hdr;
-
-       hdr = (struct obex_ap_header *) buf->data + buf->len;
-       len = strlen(entry->val.str);
-       g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + len);
-
-       hdr->tag = entry->tag;
-       hdr->len = len;
-
-       memcpy(hdr->val, entry->val.str, len);
-}
-
-uint8_t *map_ap_encode(map_ap_t *ap, size_t *length)
-{
-       GByteArray *buf;
-       GHashTableIter iter;
-       gpointer key, value;
-       struct ap_entry *entry;
-       int offset;
-
-       buf = g_byte_array_new();
-       g_hash_table_iter_init(&iter, ap);
-
-       while (g_hash_table_iter_next(&iter, &key, &value)) {
-               entry = (struct ap_entry *) value;
-               offset = find_ap_def_offset(entry->tag);
-
-               switch (ap_defs[offset].type) {
-               case APT_UINT8:
-                       ap_encode_u8(buf, entry);
-                       break;
-               case APT_UINT16:
-                       ap_encode_u16(buf, entry);
-                       break;
-               case APT_UINT32:
-                       ap_encode_u32(buf, entry);
-                       break;
-               case APT_STR:
-                       ap_encode_str(buf, entry);
-                       break;
-               }
-       }
-
-       *length = buf->len;
-
-       return g_byte_array_free(buf, FALSE);
-}
-
-gboolean map_ap_get_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t *val)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_UINT8)
-               return FALSE;
-
-       entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-       if (entry == NULL)
-               return FALSE;
-
-       *val = entry->val.u8;
-
-       return TRUE;
-}
-
-gboolean map_ap_get_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t *val)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_UINT16)
-               return FALSE;
-
-       entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-       if (entry == NULL)
-               return FALSE;
-
-       *val = entry->val.u16;
-
-       return TRUE;
-}
-
-gboolean map_ap_get_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t *val)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_UINT32)
-               return FALSE;
-
-       entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-       if (entry == NULL)
-               return FALSE;
-
-       *val = entry->val.u32;
-
-       return TRUE;
-}
-
-const char *map_ap_get_string(map_ap_t *ap, enum map_ap_tag tag)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_STR)
-               return NULL;
-
-       entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-       if (entry == NULL)
-               return NULL;
-
-       return entry->val.str;
-}
-
-gboolean map_ap_set_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t val)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_UINT8)
-               return FALSE;
-
-       entry = g_new0(struct ap_entry, 1);
-       entry->tag = tag;
-       entry->val.u8 = val;
-
-       g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-       return TRUE;
-}
-
-gboolean map_ap_set_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t val)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_UINT16)
-               return FALSE;
-
-       entry = g_new0(struct ap_entry, 1);
-       entry->tag = tag;
-       entry->val.u16 = val;
-
-       g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-       return TRUE;
-}
-
-gboolean map_ap_set_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t val)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_UINT32)
-               return FALSE;
-
-       entry = g_new0(struct ap_entry, 1);
-       entry->tag = tag;
-       entry->val.u32 = val;
-
-       g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-       return TRUE;
-}
-
-gboolean map_ap_set_string(map_ap_t *ap, enum map_ap_tag tag, const char *val)
-{
-       struct ap_entry *entry;
-       int offset = find_ap_def_offset(tag);
-
-       if (offset < 0 || ap_defs[offset].type != APT_STR)
-               return FALSE;
-
-       entry = g_new0(struct ap_entry, 1);
-       entry->tag = tag;
-       entry->val.str = g_strdup(val);
-
-       g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-       return TRUE;
-}
index 24254af..da108fe 100644 (file)
@@ -21,9 +21,6 @@
  *
  */
 
-#include <glib.h>
-#include <inttypes.h>
-
 /* List of OBEX application parameters tags as per MAP specification. */
 enum map_ap_tag {
        MAP_AP_MAXLISTCOUNT             = 0x01,         /* uint16_t     */
@@ -52,63 +49,3 @@ enum map_ap_tag {
        MAP_AP_STATUSVALUE              = 0x18,         /* uint8_t      */
        MAP_AP_MSETIME                  = 0x19,         /* char *       */
 };
-
-/* Data type representing MAP application parameters. Consider opaque. */
-typedef GHashTable map_ap_t;
-
-/* Creates a new empty MAP application parameters object. */
-map_ap_t *map_ap_new(void);
-
-/* Frees all the memory used by MAP application parameters object. */
-void map_ap_free(map_ap_t *ap);
-
-/* Parses given buffer that is a payload of OBEX application parameter header
- * with a given length. Returned value can be used in calls to map_ap_get_*()
- * and map_ap_set_*(). It has to be freed using map_ap_free(). It also takes
- * care of converting all the data to host byte order, so this is the byte
- * order used in map_ap_get_*()/map_ap_set_*().
- *
- * Returns NULL in case of failure.
- */
-map_ap_t *map_ap_decode(const uint8_t *buffer, size_t length);
-
-/* Takes all parameters currently set and packs them into a buffer with OBEX
- * application parameters header payload format.
- *
- * Returns newly allocated buffer of size 'length'. Free with g_free().
- */
-uint8_t *map_ap_encode(map_ap_t *ap, size_t *length);
-
-/* Following family of functions reads value of MAP parameter with given tag.
- * Use the one with appropriate type for a given tag, as noted above in
- * map_ap_tag declaration comments.
- *
- * Returns TRUE when value is present. FALSE if it is not or the function is
- * used get a parameter of a different type. When FALSE is returned, variable
- * pointed by 'val' is left intact.
- */
-gboolean map_ap_get_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t *val);
-gboolean map_ap_get_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t *val);
-gboolean map_ap_get_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t *val);
-
-/* Reads value of MAP parameter with given tag that is of a string type.
- *
- * Returns NULL if parameter is not present in ap or given tag is not of a
- * string type.
- */
-const char *map_ap_get_string(map_ap_t *ap, enum map_ap_tag tag);
-
-/* Following family of functions sets the value of MAP parameter with given
- * tag. Use the one with appropriate type for a given tag, as noted above in
- * map_ap_tag declaration comments.
- *
- * If there is already a parameter with given tag present, it will be
- * replaced. map_ap_set_string() makes its own copy of given string.
- *
- * Returns TRUE on success (the tag is known and the function chosen matches
- * the type of tag).
- */
-gboolean map_ap_set_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t val);
-gboolean map_ap_set_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t val);
-gboolean map_ap_set_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t val);
-gboolean map_ap_set_string(map_ap_t *ap, enum map_ap_tag tag, const char *val);
index 52f7f1e..16be849 100644 (file)
@@ -31,7 +31,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <errno.h>
 #include <string.h>
 #include <inttypes.h>
 
index ac1a8ca..756ebb8 100755 (executable)
@@ -41,6 +41,18 @@ def parse_options():
                        help="List messages in supplied CWD subdir")
        parser.add_option("-g", "--get", action="store", dest="get_msg",
                        help="Get message contents")
+       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()
 
@@ -105,21 +117,40 @@ class MapClient:
                self.map.SetFolder(new_dir)
 
        def list_folders(self):
-               for i in self.map.GetFolderListing(dict()):
+               for i in self.map.ListFolders(dict()):
                        print "%s/" % (i["Name"])
 
        def list_messages(self, folder):
-               ret = self.map.GetMessageListing(folder, dict())
+               ret = self.map.ListMessages(folder, dict())
                print pformat(unwrap(ret))
 
        def get_message(self, handle):
-               self.map.GetMessageListing("", dict())
+               self.map.ListMessages("", dict())
                path = self.path + "/message" + handle
                obj = bus.get_object("org.bluez.obex.client", path)
                msg = dbus.Interface(obj, "org.bluez.obex.Message")
-               msg.Get("",reply_handler=self.create_transfer_reply,
+               msg.Get("", True, 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("org.bluez.obex.client", path)
+               msg = dbus.Interface(obj, "org.bluez.obex.Message")
+               ret = msg.GetProperties()
+               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("org.bluez.obex.client", path)
+               msg = dbus.Interface(obj, "org.bluez.obex.Message")
+               msg.SetProperty (prop, flag);
+
+       def update_inbox(self):
+               self.map.UpdateInbox()
+
+
 if  __name__ == '__main__':
 
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -155,4 +186,22 @@ if  __name__ == '__main__':
        if options.get_msg is not None:
                map_client.get_message(options.get_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()
index 498f8a3..fbe930c 100755 (executable)
@@ -70,16 +70,16 @@ class PbapClient:
                print "Transfer finished with error %s: %s" % (code, message)
                mainloop.quit()
 
-       def pull(self, vcard, func):
+       def pull(self, vcard, params, func):
                req = Transfer(func)
-               self.pbap.Pull(vcard, "",
+               self.pbap.Pull(vcard, "", params,
                                reply_handler=lambda r: self.register(r, req),
                                error_handler=self.error)
                self.transfers += 1
 
-       def pull_all(self, func):
+       def pull_all(self, params, func):
                req = Transfer(func)
-               self.pbap.PullAll("",
+               self.pbap.PullAll("", params,
                                reply_handler=lambda r: self.register(r, req),
                                error_handler=self.error)
                self.transfers += 1
@@ -135,18 +135,19 @@ if  __name__ == '__main__':
                print "Size = %d\n" % (ret)
 
                print "\n--- List vCard ---\n"
-               ret = pbap_client.interface().List()
+               try:
+                       ret = pbap_client.interface().List(dbus.Dictionary())
+               except:
+                       ret = []
+
+               params = dbus.Dictionary({ "Format" : "vcard30",
+                                       "Fields" : [ "VERSION", "FN", "TEL"] })
                for item in ret:
                        print "%s : %s" % (item[0], item[1])
-                       pbap_client.interface().SetFormat("vcard30")
-                       pbap_client.interface().SetFilter(["VERSION", "FN",
-                                                               "TEL"]);
-                       pbap_client.pull(item[0],
+                       pbap_client.pull(item[0], params,
                                        lambda x: process_result(x, None))
 
-               pbap_client.interface().SetFormat("vcard30")
-               pbap_client.interface().SetFilter(["VERSION", "FN", "TEL"]);
-               pbap_client.pull_all(lambda x: process_result(x,
+               pbap_client.pull_all(params, lambda x: process_result(x,
                                                        "\n--- PullAll ---\n"))
 
                pbap_client.flush_transfers(lambda: test_paths(paths[1:]))
index 81a2be0..8488a20 100644 (file)
@@ -344,69 +344,66 @@ static void conn_callback(GIOChannel *io, GError *err, gpointer user_data)
        transport_connect(io, transport);
 }
 
-static GIOChannel *bluetooth_connect(GObexTransportType transport)
+static GIOChannel *l2cap_connect(GObexTransportType transport, GError **err)
 {
-       GIOChannel *io;
-       GError *err = NULL;
-       BtIOType type;
-       BtIOOption option;
-
-       if (option_dest == NULL || option_channel < 0)
-               return NULL;
-
-       if (option_channel > 31) {
-               type = option_packet ? BT_IO_L2CAP : BT_IO_L2ERTM;
-               option = BT_IO_OPT_PSM;
-       } else {
-               type = BT_IO_RFCOMM;
-               option = BT_IO_OPT_CHANNEL;
-       }
-
-       if (option_source) {
-               if (type == BT_IO_L2CAP) {
-                       io = bt_io_connect(type, conn_callback,
+       if (option_source)
+               return bt_io_connect(conn_callback,
                                        GUINT_TO_POINTER(transport),
-                                       NULL, &err,
+                                       NULL, err,
                                        BT_IO_OPT_SOURCE, option_source,
                                        BT_IO_OPT_DEST, option_dest,
-                                       option, option_channel,
+                                       BT_IO_OPT_PSM, option_channel,
                                        BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
                                        BT_IO_OPT_OMTU, option_omtu,
                                        BT_IO_OPT_IMTU, option_imtu,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
-               } else {
-                       io = bt_io_connect(type, conn_callback,
+
+       return bt_io_connect(conn_callback,
                                        GUINT_TO_POINTER(transport),
-                                       NULL, &err,
-                                       BT_IO_OPT_SOURCE, option_source,
+                                       NULL, err,
                                        BT_IO_OPT_DEST, option_dest,
-                                       option, option_channel,
+                                       BT_IO_OPT_PSM, option_channel,
+                                       BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+                                       BT_IO_OPT_OMTU, option_omtu,
+                                       BT_IO_OPT_IMTU, option_imtu,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
-               }
-       } else {
-               if (type == BT_IO_L2CAP) {
-                       io = bt_io_connect(type, conn_callback,
+}
+
+static GIOChannel *rfcomm_connect(GObexTransportType transport, GError **err)
+{
+       if (option_source)
+               return bt_io_connect(conn_callback,
                                        GUINT_TO_POINTER(transport),
-                                       NULL, &err,
+                                       NULL, err,
+                                       BT_IO_OPT_SOURCE, option_source,
                                        BT_IO_OPT_DEST, option_dest,
-                                       option, option_channel,
-                                       BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
-                                       BT_IO_OPT_OMTU, option_omtu,
-                                       BT_IO_OPT_IMTU, option_imtu,
+                                       BT_IO_OPT_CHANNEL, option_channel,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
-               } else {
-                       io = bt_io_connect(type, conn_callback,
+
+       return bt_io_connect(conn_callback,
                                        GUINT_TO_POINTER(transport),
-                                       NULL, &err,
+                                       NULL, err,
                                        BT_IO_OPT_DEST, option_dest,
-                                       option, option_channel,
+                                       BT_IO_OPT_CHANNEL, option_channel,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
-               }
-       }
+}
+
+static GIOChannel *bluetooth_connect(GObexTransportType transport)
+{
+       GIOChannel *io;
+       GError *err = NULL;
+
+       if (option_dest == NULL || option_channel < 0)
+               return NULL;
+
+       if (option_channel > 31)
+               io = l2cap_connect(transport, &err);
+       else
+               io = rfcomm_connect(transport, &err);
 
        if (io != NULL)
                return io;
index 3a660f4..e37c56f 100644 (file)
@@ -308,40 +308,40 @@ static gboolean bluetooth_watch(GIOChannel *chan, GIOCondition cond, gpointer da
        return FALSE;
 }
 
+static GIOChannel *l2cap_listen(GError **err)
+{
+       return bt_io_listen(bluetooth_accept, NULL, NULL,
+                                       NULL, err,
+                                       BT_IO_OPT_PSM, option_channel,
+                                       BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+                                       BT_IO_OPT_OMTU, option_omtu,
+                                       BT_IO_OPT_IMTU, option_imtu,
+                                       BT_IO_OPT_INVALID);
+}
+
+static GIOChannel *rfcomm_listen(GError **err)
+{
+       return bt_io_listen(bluetooth_accept, NULL, NULL,
+                                       NULL, err,
+                                       BT_IO_OPT_CHANNEL, option_channel,
+                                       BT_IO_OPT_INVALID);
+}
+
 static guint bluetooth_listen(void)
 {
        GIOChannel *io;
        guint id;
        GError *err = NULL;
-       BtIOType type;
-       BtIOOption option;
 
        if (option_channel == -1) {
                g_printerr("Bluetooth channel not set\n");
                return 0;
        }
 
-       if (option_packet || option_channel > 31) {
-               type = option_packet ? BT_IO_L2CAP : BT_IO_L2ERTM;
-               option = BT_IO_OPT_PSM;
-       } else {
-               type = BT_IO_RFCOMM;
-               option = BT_IO_OPT_CHANNEL;
-       }
-
-       if (type == BT_IO_L2CAP)
-               io = bt_io_listen(type, bluetooth_accept, NULL, NULL,
-                                       NULL, &err,
-                                       option, option_channel,
-                                       BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
-                                       BT_IO_OPT_OMTU, option_omtu,
-                                       BT_IO_OPT_IMTU, option_imtu,
-                                       BT_IO_OPT_INVALID);
+       if (option_packet || option_channel > 31)
+               io = l2cap_listen(&err);
        else
-               io = bt_io_listen(type, bluetooth_accept, NULL, NULL,
-                                       NULL, &err,
-                                       option, option_channel,
-                                       BT_IO_OPT_INVALID);
+               io = rfcomm_listen(&err);
 
        if (io == NULL) {
                g_printerr("%s\n", err->message);
diff --git a/unit/test-gobex-apparam.c b/unit/test-gobex-apparam.c
new file mode 100644 (file)
index 0000000..573de99
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <gobex/gobex-apparam.h>
+
+#include "util.h"
+
+#define TAG_U8 0x00
+#define TAG_U16 0x01
+#define TAG_U32 0x02
+#define TAG_U64 0x03
+#define TAG_STRING 0x04
+#define TAG_BYTES 0x05
+
+static uint8_t tag_nval_short[] = { TAG_U8 };
+static uint8_t tag_nval_data[] = { TAG_U8, 0x01 };
+static uint8_t tag_nval2_short[] = { TAG_U8, 0x01, 0x1, TAG_U16 };
+static uint8_t tag_nval2_data[] = { TAG_U8, 0x01, 0x1, TAG_U16, 0x02 };
+static uint8_t tag_uint8[] = { TAG_U8, 0x01, 0x01 };
+static uint8_t tag_uint16[] = { TAG_U16, 0x02, 0x01, 0x02 };
+static uint8_t tag_uint32[] = { TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04 };
+static uint8_t tag_uint64[] = { TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+                                               0x05, 0x06, 0x07, 0x08 };
+static uint8_t tag_string[] = { TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+static uint8_t tag_bytes[257] = { TAG_BYTES, 0xFF };
+static uint8_t tag_multi[] = { TAG_U8, 0x01, 0x01,
+                               TAG_U16, 0x02, 0x01, 0x02,
+                               TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04,
+                               TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+                                               0x05, 0x06, 0x07, 0x08,
+                               TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+
+
+static GObexApparam *parse_and_decode(const void *data, gsize size)
+{
+       GObexApparam *apparam;
+       guint8 encoded[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_decode(data, size);
+
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, encoded, sizeof(encoded));
+
+       assert_memequal(data, size, encoded, len);
+
+       return apparam;
+}
+
+static void test_apparam_nval_short(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval_short,
+                                               sizeof(tag_nval_short));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval_data(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval_data,
+                                               sizeof(tag_nval_data));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_short(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval2_short,
+                                               sizeof(tag_nval2_short));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_data(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval2_data,
+                                               sizeof(tag_nval2_data));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_get_uint8(void)
+{
+       GObexApparam *apparam;
+       guint8 data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint8, sizeof(tag_uint8));
+
+       ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x01);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint16(void)
+{
+       GObexApparam *apparam;
+       uint16_t data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint16, sizeof(tag_uint16));
+
+       ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x0102);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint32(void)
+{
+       GObexApparam *apparam;
+       uint32_t data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint32, sizeof(tag_uint32));
+
+       ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x01020304);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint64(void)
+{
+       GObexApparam *apparam;
+       uint64_t data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint64, sizeof(tag_uint64));
+
+       ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x0102030405060708);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_string(void)
+{
+       GObexApparam *apparam;
+       char *string;
+
+       apparam = parse_and_decode(tag_string, sizeof(tag_string));
+
+       string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+       g_assert(string != NULL);
+       g_assert_cmpstr(string, ==, "ABC");
+
+       g_free(string);
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_bytes(void)
+{
+       GObexApparam *apparam;
+       const uint8_t *data;
+       gsize len;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_bytes, sizeof(tag_bytes));
+
+       ret = g_obex_apparam_get_bytes(apparam, TAG_BYTES, &data, &len);
+
+       g_assert(ret == TRUE);
+       assert_memequal(tag_bytes + 2, sizeof(tag_bytes) - 2, data, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_multi(void)
+{
+       GObexApparam *apparam;
+       char *string;
+       uint8_t data8;
+       uint16_t data16;
+       uint32_t data32;
+       uint64_t data64;
+       gboolean ret;
+
+       apparam = g_obex_apparam_decode(tag_multi, sizeof(tag_multi));
+
+       g_assert(apparam != NULL);
+
+       ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data8);
+
+       g_assert(ret == TRUE);
+       g_assert(data8 == 0x01);
+
+       ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data16);
+
+       g_assert(ret == TRUE);
+       g_assert(data16 == 0x0102);
+
+       ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data32);
+
+       g_assert(ret == TRUE);
+       g_assert(data32 == 0x01020304);
+
+       ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data64);
+
+       g_assert(ret == TRUE);
+       g_assert(data64 == 0x0102030405060708);
+
+       string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+       g_assert(string != NULL);
+       g_assert_cmpstr(string, ==, "ABC");
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint8(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint8, sizeof(tag_uint8), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint16(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint16(NULL, TAG_U16, 0x0102);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint16, sizeof(tag_uint16), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint32(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint32(NULL, TAG_U32, 0x01020304);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint32, sizeof(tag_uint32), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint64(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint64(NULL, TAG_U64, 0x0102030405060708);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint64, sizeof(tag_uint64), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_string(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_string(NULL, TAG_STRING, "ABC");
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_string, sizeof(tag_string), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_bytes(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_bytes(NULL, TAG_BYTES, tag_bytes + 2, 255);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_bytes, sizeof(tag_bytes), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_multi(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_uint16(apparam, TAG_U16, 0x0102);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_uint32(apparam, TAG_U32, 0x01020304);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_uint64(apparam, TAG_U64,
+                                                       0x0102030405060708);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_string(apparam, TAG_STRING, "ABC");
+
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+
+       g_assert_cmpuint(len, ==, sizeof(tag_multi));
+
+       g_obex_apparam_free(apparam);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/gobex/test_apparam_nval_short",
+                                               test_apparam_nval_short);
+       g_test_add_func("/gobex/test_apparam_nval_data",
+                                               test_apparam_nval_data);
+
+       g_test_add_func("/gobex/test_apparam_nval2_short",
+                                               test_apparam_nval2_short);
+       g_test_add_func("/gobex/test_apparam_nval2_data",
+                                               test_apparam_nval2_data);
+
+       g_test_add_func("/gobex/test_apparam_get_uint8",
+                                               test_apparam_get_uint8);
+       g_test_add_func("/gobex/test_apparam_get_uint16",
+                                               test_apparam_get_uint16);
+       g_test_add_func("/gobex/test_apparam_get_uint32",
+                                               test_apparam_get_uint32);
+       g_test_add_func("/gobex/test_apparam_get_uint64",
+                                               test_apparam_get_uint64);
+       g_test_add_func("/gobex/test_apparam_get_string",
+                                               test_apparam_get_string);
+       g_test_add_func("/gobex/test_apparam_get_bytes",
+                                               test_apparam_get_bytes);
+       g_test_add_func("/gobex/test_apparam_get_multi",
+                                               test_apparam_get_multi);
+
+       g_test_add_func("/gobex/test_apparam_set_uint8",
+                                               test_apparam_set_uint8);
+       g_test_add_func("/gobex/test_apparam_set_uint16",
+                                               test_apparam_set_uint16);
+       g_test_add_func("/gobex/test_apparam_set_uint32",
+                                               test_apparam_set_uint32);
+       g_test_add_func("/gobex/test_apparam_set_uint64",
+                                               test_apparam_set_uint64);
+       g_test_add_func("/gobex/test_apparam_set_string",
+                                               test_apparam_set_string);
+       g_test_add_func("/gobex/test_apparam_set_bytes",
+                                               test_apparam_set_bytes);
+       g_test_add_func("/gobex/test_apparam_set_multi",
+                                               test_apparam_set_multi);
+
+       g_test_run();
+
+       return 0;
+}
index 86e69f3..feb7d17 100644 (file)
@@ -47,6 +47,8 @@ static uint8_t hdr_bytes_nval_short[] = { G_OBEX_HDR_BODY, 0xab, 0xcd,
                                                0x01, 0x02, 0x03 };
 static uint8_t hdr_bytes_nval_data[] = { G_OBEX_HDR_BODY, 0xab };
 static uint8_t hdr_bytes_nval_len[] = { G_OBEX_HDR_BODY, 0x00, 0x00 };
+static uint8_t hdr_apparam[] = { G_OBEX_HDR_APPARAM, 0x00, 0x09, 0x00, 0x04,
+                                               0x01, 0x02, 0x03, 0x04 };
 
 static void test_header_name_empty(void)
 {
@@ -115,6 +117,27 @@ static void test_header_bytes(void)
        g_obex_header_free(header);
 }
 
+static void test_header_apparam(void)
+{
+       GObexHeader *header;
+       GObexApparam *apparam;
+       uint8_t buf[1024];
+       size_t len;
+
+       apparam = g_obex_apparam_set_uint32(NULL, 0, 0x01020304);
+       g_assert(apparam != NULL);
+
+       header = g_obex_header_new_apparam(apparam);
+       g_assert(header != NULL);
+
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_apparam, sizeof(hdr_apparam), buf, len);
+
+       g_obex_apparam_free(apparam);
+       g_obex_header_free(header);
+}
+
 static void test_header_uint8(void)
 {
        GObexHeader *header;
@@ -247,6 +270,26 @@ static void test_header_encode_body(void)
        g_obex_header_free(header);
 }
 
+static void test_header_encode_apparam(void)
+{
+       GObexHeader *header;
+       GObexApparam *apparam;
+       gboolean ret;
+       guint32 data;
+
+       header = parse_and_encode(hdr_apparam, sizeof(hdr_apparam));
+
+       apparam = g_obex_header_get_apparam(header);
+       g_assert(apparam != NULL);
+
+       ret = g_obex_apparam_get_uint32(apparam, 0x00, &data);
+       g_assert(ret == TRUE);
+       g_assert(data == 0x01020304);
+
+       g_obex_apparam_free(apparam);
+       g_obex_header_free(header);
+}
+
 static void test_header_encode_actionid(void)
 {
        GObexHeader *header;
@@ -507,6 +550,8 @@ int main(int argc, char *argv[])
                                                test_header_encode_body);
        g_test_add_func("/gobex/test_header_encode_connid",
                                                test_header_encode_actionid);
+       g_test_add_func("/gobex/test_header_encode_apparam",
+                                               test_header_encode_apparam);
 
        g_test_add_func("/gobex/test_header_name_empty",
                                                test_header_name_empty);
@@ -517,6 +562,7 @@ int main(int argc, char *argv[])
        g_test_add_func("/gobex/test_header_bytes", test_header_bytes);
        g_test_add_func("/gobex/test_header_uint8", test_header_uint8);
        g_test_add_func("/gobex/test_header_uint32", test_header_uint32);
+       g_test_add_func("/gobex/test_header_apparam", test_header_apparam);
 
        g_test_run();