+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.
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 =
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
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
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
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) \
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
@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
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 \
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) \
@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@)
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 \
@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) \
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)
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)
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)
$(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)
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 \
@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 \
@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)
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
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)
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)
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)
-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)
-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)
-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)
@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@
@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@
@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@
#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;
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)
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;
}
{
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;
}
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;
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;
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;
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) {
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;
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:
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;
}
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,
*(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;
}
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;
}
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;
}
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,
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);
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);
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);
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) {
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) {
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;
}
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;
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);
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;
}
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;
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);
if (ret == FALSE)
return NULL;
- io = create_io(type, TRUE, &opts, err);
+ io = create_io(TRUE, &opts, err);
if (io == NULL)
return NULL;
#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,
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
g_io_channel_unref(session->io);
}
+ if (session->sdp)
+ sdp_close(session->sdp);
+
if (session->conn)
dbus_connection_unref(session->conn);
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,
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,
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);
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;
#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;
uint64_t size;
char *status;
uint8_t flags;
+ DBusMessage *msg;
};
struct map_parser {
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)) {
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;
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);
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;
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) },
{ }
};
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;
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;
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;
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;
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)
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)) {
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) },
{ }
};
#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",
struct pbap_data {
struct obc_session *session;
char *path;
- guint8 format;
- guint8 order;
- uint64_t filter;
};
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,
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;
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,
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)
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,
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;
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"))
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,
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) },
#define OBC_TRANSFER_ERROR obc_transfer_error_quark()
+#define FIRST_PACKET_TIMEOUT 60
+
static guint64 counter = 0;
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;
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);
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;
"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;
struct obc_transfer *transfer = user_data;
GObexPacket *req;
GObexHeader *hdr;
+ GObexApparam *apparam;
const guint8 *buf;
gsize len;
guint8 rspcode;
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);
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,
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)
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,
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,
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,
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);
#! /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.
# 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=''
# 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]...
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
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.
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 $@
# Define the identity of the package.
PACKAGE='obexd'
- VERSION='0.47'
+ VERSION='0.48'
cat >>confdefs.h <<_ACEOF
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
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
_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
# 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
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\\"
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)
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)
"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
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.
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
{ "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
=======================
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.
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.
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
=================
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.
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()
#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);
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,
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, { } }
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
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;
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;
}
#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 {
const GDBusMethodTable *methods;
const GDBusSignalTable *signals;
const GDBusPropertyTable *properties;
+ GSList *pending_prop;
void *user_data;
GDBusDestroyFunction destroy;
};
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)
{
}
}
+#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 &
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");
}
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,
{
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)
dbus_message_unref(secdata->message);
g_free(secdata);
return;
- }
+ }
}
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;
dbus_message_unref(secdata->message);
g_free(secdata);
return;
- }
+ }
}
void g_dbus_pending_error(DBusConnection *connection,
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,
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)
{
.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,
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,
}
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>");
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;
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,
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;
}
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;
g_free(data->introspect);
data->introspect = NULL;
- object_path_unref(connection, path);
+ object_path_unref(connection, data->path);
return TRUE;
}
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;
+}
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,
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;
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");
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);
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);
{
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)
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;
}
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;
{
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);
}
--- /dev/null
+/*
+ *
+ * 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);
+}
--- /dev/null
+/*
+ *
+ * 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 */
#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) {
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",
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;
#include <glib.h>
#include <gobex/gobex-defs.h>
+#include <gobex/gobex-apparam.h>
/* Header ID's */
#define G_OBEX_HDR_INVALID 0x00
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);
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;
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;
} 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;
}
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:
{ "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,
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;
}
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)
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,
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,
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,
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,
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);
}
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);
#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>
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)
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("");
"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");
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");
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,
{
struct irmc_session *irmc = context;
int ret = 0;
- const char *p;
+ char *path;
DBG("name %s context %p", name, 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)
#include <inttypes.h>
#include <gobex/gobex.h>
+#include <gobex/gobex-apparam.h>
#include "obexd.h"
#include "plugin.h"
#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
gboolean finished;
gboolean nth_call;
GString *buffer;
- map_ap_t *inparams;
- map_ap_t *outparams;
+ GObexApparam *inparams;
+ GObexApparam *outparams;
gboolean ap_sent;
};
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;
}
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)
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)
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)
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;
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;
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);
/* 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("");
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("");
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("");
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,
.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,
.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,
int messages_get_messages_listing(void *session, const char *name,
uint16_t max, uint16_t offset,
+ uint8_t subject_len,
const struct messages_filter *filter,
messages_get_messages_listing_cb callback,
void *user_data)
return -ENOSYS;
}
-int messages_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;
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)
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)
{
}
* 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.
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);
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.
*
#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;
struct pbap_object {
GString *buffer;
- GByteArray *aparams;
+ GObexApparam *apparam;
gboolean firstpacket;
gboolean lastpart;
struct pbap_session *session;
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)
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);
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);
/* 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;
}
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, ¶m->order);
+ g_obex_apparam_get_uint8(apparam, SEARCHATTRIB_TAG,
+ ¶m->searchattrib);
+ g_obex_apparam_get_uint8(apparam, FORMAT_TAG, ¶m->format);
+ g_obex_apparam_get_uint16(apparam, MAXLISTCOUNT_TAG,
+ ¶m->maxlistcount);
+ g_obex_apparam_get_uint16(apparam, LISTSTARTOFFSET_TAG,
+ ¶m->liststartoffset);
+ g_obex_apparam_get_uint64(apparam, FILTER_TAG, ¶m->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)
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);
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;
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;
*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;
}
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:
/* 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;
}
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;
{
struct query_context *data;
- if (g_strcmp0("/telecom/pb.vcf", name) != 0) {
+ if (g_strcmp0(PB_CONTACTS, name) != 0) {
if (err)
*err = -ENOENT;
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;
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;
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;
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;
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;
}
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;
}
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
#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;
/* list attributes only */
uint8_t order;
uint8_t searchattrib;
- uint8_t *searchval;
+ char *searchval;
};
/*
+++ /dev/null
-/*
- *
- * 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;
-}
*
*/
-#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 */
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);
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
-#include <errno.h>
#include <string.h>
#include <inttypes.h>
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()
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)
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()
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
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:]))
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;
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);
--- /dev/null
+/*
+ *
+ * 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;
+}
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)
{
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;
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;
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);
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();