diff -pruN 0.46-1/aclocal.m4 0.48-2.1/aclocal.m4
--- 0.46-1/aclocal.m4	2012-05-17 15:12:32.000000000 +0000
+++ 0.48-2.1/aclocal.m4	2012-11-30 07:59:27.000000000 +0000
@@ -1,4 +1,4 @@
-# generated automatically by aclocal 1.11.3 -*- Autoconf -*-
+# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
 # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
@@ -2526,17 +2526,6 @@ freebsd* | dragonfly*)
   esac
   ;;
 
-gnu*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
 haiku*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
@@ -2653,7 +2642,7 @@ linux*oldld* | linux*aout* | linux*coff*
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
@@ -3269,10 +3258,6 @@ freebsd* | dragonfly*)
   fi
   ;;
 
-gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
 haiku*)
   lt_cv_deplibs_check_method=pass_all
   ;;
@@ -3311,7 +3296,7 @@ irix5* | irix6* | nonstopux*)
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
@@ -4063,7 +4048,7 @@ m4_if([$1], [CXX], [
 	    ;;
 	esac
 	;;
-      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
 	case $cc_basename in
 	  KCC*)
 	    # KAI C++ Compiler
@@ -4362,7 +4347,7 @@ m4_if([$1], [CXX], [
       _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
       ;;
 
-    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
       case $cc_basename in
       # old Intel for x86_64 which still supported -KPIC.
       ecc*)
@@ -6251,9 +6236,6 @@ if test "$_lt_caught_CXX_error" != yes;
         _LT_TAGVAR(ld_shlibs, $1)=yes
         ;;
 
-      gnu*)
-        ;;
-
       haiku*)
         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
         _LT_TAGVAR(link_all_deplibs, $1)=yes
@@ -6415,7 +6397,7 @@ if test "$_lt_caught_CXX_error" != yes;
         _LT_TAGVAR(inherit_rpath, $1)=yes
         ;;
 
-      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
         case $cc_basename in
           KCC*)
 	    # Kuck and Associates, Inc. (KAI) C++ Compiler
@@ -8804,7 +8786,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
 [am__api_version='1.11'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.11.3], [],
+m4_if([$1], [1.11.6], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -8820,7 +8802,7 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.11.3])dnl
+[AM_AUTOMAKE_VERSION([1.11.6])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
diff -pruN 0.46-1/btio/btio.c 0.48-2.1/btio/btio.c
--- 0.46-1/btio/btio.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/btio/btio.c	2012-11-30 07:59:13.000000000 +0000
@@ -43,14 +43,23 @@
 #endif
 
 #define ERROR_FAILED(gerr, str, err) \
-		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+		g_set_error(gerr, BT_IO_ERROR, err, \
 				str ": %s (%d)", strerror(err), err)
 
 #define DEFAULT_DEFER_TIMEOUT 30
 
+typedef enum {
+	BT_IO_L2CAP,
+	BT_IO_RFCOMM,
+	BT_IO_SCO,
+	BT_IO_INVALID,
+} BtIOType;
+
 struct set_opts {
 	bdaddr_t src;
 	bdaddr_t dst;
+	BtIOType type;
+	uint8_t dst_type;
 	int defer;
 	int sec_level;
 	uint8_t channel;
@@ -84,6 +93,48 @@ struct server {
 	GDestroyNotify destroy;
 };
 
+static BtIOType bt_io_get_type(GIOChannel *io, GError **gerr)
+{
+	int sk = g_io_channel_unix_get_fd(io);
+	int domain, proto, err;
+	socklen_t len;
+
+	domain = 0;
+	len = sizeof(domain);
+	err = getsockopt(sk, SOL_SOCKET, SO_DOMAIN, &domain, &len);
+	if (err < 0) {
+		ERROR_FAILED(gerr, "getsockopt(SO_DOMAIN)", errno);
+		return BT_IO_INVALID;
+	}
+
+	if (domain != AF_BLUETOOTH) {
+		g_set_error(gerr, BT_IO_ERROR, EINVAL,
+				"BtIO socket domain not AF_BLUETOOTH");
+		return BT_IO_INVALID;
+	}
+
+	proto = 0;
+	len = sizeof(proto);
+	err = getsockopt(sk, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
+	if (err < 0) {
+		ERROR_FAILED(gerr, "getsockopt(SO_PROTOCOL)", errno);
+		return BT_IO_INVALID;
+	}
+
+	switch (proto) {
+	case BTPROTO_RFCOMM:
+		return BT_IO_RFCOMM;
+	case BTPROTO_SCO:
+		return BT_IO_SCO;
+	case BTPROTO_L2CAP:
+		return BT_IO_L2CAP;
+	default:
+		g_set_error(gerr, BT_IO_ERROR, EINVAL,
+					"Unknown BtIO socket type");
+		return BT_IO_INVALID;
+	}
+}
+
 static void server_remove(struct server *server)
 {
 	if (server->destroy)
@@ -123,19 +174,28 @@ static gboolean accept_cb(GIOChannel *io
 							gpointer user_data)
 {
 	struct accept *accept = user_data;
-	GError *err = NULL;
+	GError *gerr = NULL;
 
 	/* If the user aborted this accept attempt */
 	if ((cond & G_IO_NVAL) || check_nval(io))
 		return FALSE;
 
-	if (cond & (G_IO_HUP | G_IO_ERR))
-		g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
-				"HUP or ERR on socket");
+	if (cond & (G_IO_HUP | G_IO_ERR)) {
+		int err, sk_err, sock = g_io_channel_unix_get_fd(io);
+		socklen_t len = sizeof(sk_err);
 
-	accept->connect(io, err, accept->user_data);
+		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+			err = -errno;
+		else
+			err = -sk_err;
+
+		if (err < 0)
+			ERROR_FAILED(&gerr, "HUP or ERR on socket", -err);
+	}
+
+	accept->connect(io, gerr, accept->user_data);
 
-	g_clear_error(&err);
+	g_clear_error(&gerr);
 
 	return FALSE;
 }
@@ -145,32 +205,26 @@ static gboolean connect_cb(GIOChannel *i
 {
 	struct connect *conn = user_data;
 	GError *gerr = NULL;
+	int err, sk_err, sock;
+	socklen_t len = sizeof(sk_err);
 
 	/* If the user aborted this connect attempt */
 	if ((cond & G_IO_NVAL) || check_nval(io))
 		return FALSE;
 
-	if (cond & G_IO_OUT) {
-		int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io);
-		socklen_t len = sizeof(sk_err);
+	sock = g_io_channel_unix_get_fd(io);
 
-		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
-			err = -errno;
-		else
-			err = -sk_err;
+	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+		err = -errno;
+	else
+		err = -sk_err;
 
-		if (err < 0)
-			g_set_error(&gerr, BT_IO_ERROR,
-					BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
-					strerror(-err), -err);
-	} else if (cond & (G_IO_HUP | G_IO_ERR))
-		g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-				"HUP or ERR on socket");
+	if (err < 0)
+		ERROR_FAILED(&gerr, "connect error", -err);
 
 	conn->connect(io, gerr, conn->user_data);
 
-	if (gerr)
-		g_error_free(gerr);
+	g_clear_error(&gerr);
 
 	return FALSE;
 }
@@ -280,8 +334,8 @@ static int l2cap_bind(int sock, const bd
 	return 0;
 }
 
-static int l2cap_connect(int sock, const bdaddr_t *dst,
-					uint16_t psm, uint16_t cid)
+static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type,
+						uint16_t psm, uint16_t cid)
 {
 	int err;
 	struct sockaddr_l2 addr;
@@ -294,6 +348,8 @@ static int l2cap_connect(int sock, const
 	else
 		addr.l2_psm = htobs(psm);
 
+	addr.l2_bdaddr_type = dst_type;
+
 	err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
 	if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS))
 		return -errno;
@@ -387,7 +443,7 @@ static gboolean set_sec_level(int sock,
 	int ret;
 
 	if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
-		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+		g_set_error(err, BT_IO_ERROR, EINVAL,
 				"Valid security level range is %d-%d",
 				BT_SECURITY_LOW, BT_SECURITY_HIGH);
 		return FALSE;
@@ -693,11 +749,13 @@ static gboolean parse_set_opts(struct se
 	memset(opts, 0, sizeof(*opts));
 
 	/* Set defaults */
+	opts->type = BT_IO_SCO;
 	opts->defer = DEFAULT_DEFER_TIMEOUT;
 	opts->master = -1;
 	opts->mode = L2CAP_MODE_BASIC;
 	opts->flushable = -1;
 	opts->priority = 0;
+	opts->dst_type = BDADDR_BREDR;
 
 	while (opt != BT_IO_OPT_INVALID) {
 		switch (opt) {
@@ -714,6 +772,9 @@ static gboolean parse_set_opts(struct se
 		case BT_IO_OPT_DEST_BDADDR:
 			bacpy(&opts->dst, va_arg(args, const bdaddr_t *));
 			break;
+		case BT_IO_OPT_DEST_TYPE:
+			opts->dst_type = va_arg(args, int);
+			break;
 		case BT_IO_OPT_DEFER_TIMEOUT:
 			opts->defer = va_arg(args, int);
 			break;
@@ -721,12 +782,15 @@ static gboolean parse_set_opts(struct se
 			opts->sec_level = va_arg(args, int);
 			break;
 		case BT_IO_OPT_CHANNEL:
+			opts->type = BT_IO_RFCOMM;
 			opts->channel = va_arg(args, int);
 			break;
 		case BT_IO_OPT_PSM:
+			opts->type = BT_IO_L2CAP;
 			opts->psm = va_arg(args, int);
 			break;
 		case BT_IO_OPT_CID:
+			opts->type = BT_IO_L2CAP;
 			opts->cid = va_arg(args, int);
 			break;
 		case BT_IO_OPT_MTU:
@@ -757,7 +821,7 @@ static gboolean parse_set_opts(struct se
 			opts->priority = va_arg(args, int);
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -875,6 +939,9 @@ static gboolean l2cap_get(int sock, GErr
 		case BT_IO_OPT_DEST_BDADDR:
 			bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
 			break;
+		case BT_IO_OPT_DEST_TYPE:
+			ERROR_FAILED(err, "Not implemented", EINVAL);
+			return FALSE;
 		case BT_IO_OPT_DEFER_TIMEOUT:
 			len = sizeof(int);
 			if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP,
@@ -950,7 +1017,7 @@ static gboolean l2cap_get(int sock, GErr
 			*(va_arg(args, uint32_t *)) = priority;
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -1057,7 +1124,7 @@ static gboolean rfcomm_get(int sock, GEr
 			memcpy(va_arg(args, uint8_t *), dev_class, 3);
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -1140,7 +1207,7 @@ static gboolean sco_get(int sock, GError
 			memcpy(va_arg(args, uint8_t *), dev_class, 3);
 			break;
 		default:
-			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+			g_set_error(err, BT_IO_ERROR, EINVAL,
 					"Unknown option %d", opt);
 			return FALSE;
 		}
@@ -1159,19 +1226,17 @@ static gboolean get_valist(GIOChannel *i
 	sock = g_io_channel_unix_get_fd(io);
 
 	switch (type) {
-	case BT_IO_L2RAW:
 	case BT_IO_L2CAP:
-	case BT_IO_L2ERTM:
 		return l2cap_get(sock, err, opt1, args);
 	case BT_IO_RFCOMM:
 		return rfcomm_get(sock, err, opt1, args);
 	case BT_IO_SCO:
 		return sco_get(sock, err, opt1, args);
+	default:
+		g_set_error(err, BT_IO_ERROR, EINVAL,
+				"Unknown BtIO type %d", type);
+		return FALSE;
 	}
-
-	g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-			"Unknown BtIO type %d", type);
-	return FALSE;
 }
 
 gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
@@ -1204,13 +1269,13 @@ gboolean bt_io_accept(GIOChannel *io, Bt
 	return TRUE;
 }
 
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
-							BtIOOption opt1, ...)
+gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
 	va_list args;
 	gboolean ret;
 	struct set_opts opts;
 	int sock;
+	BtIOType type;
 
 	va_start(args, opt1);
 	ret = parse_set_opts(&opts, err, opt1, args);
@@ -1219,12 +1284,14 @@ gboolean bt_io_set(GIOChannel *io, BtIOT
 	if (!ret)
 		return ret;
 
+	type = bt_io_get_type(io, err);
+	if (type == BT_IO_INVALID)
+		return FALSE;
+
 	sock = g_io_channel_unix_get_fd(io);
 
 	switch (type) {
-	case BT_IO_L2RAW:
 	case BT_IO_L2CAP:
-	case BT_IO_L2ERTM:
 		return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu,
 				opts.mode, opts.master, opts.flushable,
 				opts.priority, err);
@@ -1232,18 +1299,23 @@ gboolean bt_io_set(GIOChannel *io, BtIOT
 		return rfcomm_set(sock, opts.sec_level, opts.master, err);
 	case BT_IO_SCO:
 		return sco_set(sock, opts.mtu, err);
+	default:
+		g_set_error(err, BT_IO_ERROR, EINVAL,
+				"Unknown BtIO type %d", type);
+		return FALSE;
 	}
 
-	g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-			"Unknown BtIO type %d", type);
-	return FALSE;
 }
 
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
-							BtIOOption opt1, ...)
+gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
 	va_list args;
 	gboolean ret;
+	BtIOType type;
+
+	type = bt_io_get_type(io, err);
+	if (type == BT_IO_INVALID)
+		return FALSE;
 
 	va_start(args, opt1);
 	ret = get_valist(io, type, err, opt1, args);
@@ -1252,25 +1324,13 @@ gboolean bt_io_get(GIOChannel *io, BtIOT
 	return ret;
 }
 
-static GIOChannel *create_io(BtIOType type, gboolean server,
-					struct set_opts *opts, GError **err)
+static GIOChannel *create_io(gboolean server, struct set_opts *opts,
+								GError **err)
 {
 	int sock;
 	GIOChannel *io;
 
-	switch (type) {
-	case BT_IO_L2RAW:
-		sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
-		if (sock < 0) {
-			ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);
-			return NULL;
-		}
-		if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
-							opts->cid, err) < 0)
-			goto failed;
-		if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, 0, err))
-			goto failed;
-		break;
+	switch (opts->type) {
 	case BT_IO_L2CAP:
 		sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
 		if (sock < 0) {
@@ -1285,20 +1345,6 @@ static GIOChannel *create_io(BtIOType ty
 				opts->priority, err))
 			goto failed;
 		break;
-	case BT_IO_L2ERTM:
-		sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
-		if (sock < 0) {
-			ERROR_FAILED(err, "socket(STREAM, L2CAP)", errno);
-			return NULL;
-		}
-		if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0,
-							opts->cid, err) < 0)
-			goto failed;
-		if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu,
-				opts->mode, opts->master, opts->flushable,
-				opts->priority, err))
-			goto failed;
-		break;
 	case BT_IO_RFCOMM:
 		sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
 		if (sock < 0) {
@@ -1323,8 +1369,8 @@ static GIOChannel *create_io(BtIOType ty
 			goto failed;
 		break;
 	default:
-		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-				"Unknown BtIO type %d", type);
+		g_set_error(err, BT_IO_ERROR, EINVAL,
+				"Unknown BtIO type %d", opts->type);
 		return NULL;
 	}
 
@@ -1341,9 +1387,9 @@ failed:
 	return NULL;
 }
 
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
-				gpointer user_data, GDestroyNotify destroy,
-				GError **gerr, BtIOOption opt1, ...)
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+				GDestroyNotify destroy, GError **gerr,
+				BtIOOption opt1, ...)
 {
 	GIOChannel *io;
 	va_list args;
@@ -1358,19 +1404,16 @@ GIOChannel *bt_io_connect(BtIOType type,
 	if (ret == FALSE)
 		return NULL;
 
-	io = create_io(type, FALSE, &opts, gerr);
+	io = create_io(FALSE, &opts, gerr);
 	if (io == NULL)
 		return NULL;
 
 	sock = g_io_channel_unix_get_fd(io);
 
-	switch (type) {
-	case BT_IO_L2RAW:
-		err = l2cap_connect(sock, &opts.dst, 0, opts.cid);
-		break;
+	switch (opts.type) {
 	case BT_IO_L2CAP:
-	case BT_IO_L2ERTM:
-		err = l2cap_connect(sock, &opts.dst, opts.psm, opts.cid);
+		err = l2cap_connect(sock, &opts.dst, opts.dst_type,
+							opts.psm, opts.cid);
 		break;
 	case BT_IO_RFCOMM:
 		err = rfcomm_connect(sock, &opts.dst, opts.channel);
@@ -1379,14 +1422,13 @@ GIOChannel *bt_io_connect(BtIOType type,
 		err = sco_connect(sock, &opts.dst);
 		break;
 	default:
-		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-						"Unknown BtIO type %d", type);
+		g_set_error(gerr, BT_IO_ERROR, EINVAL,
+					"Unknown BtIO type %d", opts.type);
 		return NULL;
 	}
 
 	if (err < 0) {
-		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-				"connect: %s (%d)", strerror(-err), -err);
+		ERROR_FAILED(gerr, "connect", -err);
 		g_io_channel_unref(io);
 		return NULL;
 	}
@@ -1396,10 +1438,9 @@ GIOChannel *bt_io_connect(BtIOType type,
 	return io;
 }
 
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
-				BtIOConfirm confirm, gpointer user_data,
-				GDestroyNotify destroy, GError **err,
-				BtIOOption opt1, ...)
+GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
+				gpointer user_data, GDestroyNotify destroy,
+				GError **err, BtIOOption opt1, ...)
 {
 	GIOChannel *io;
 	va_list args;
@@ -1407,12 +1448,6 @@ GIOChannel *bt_io_listen(BtIOType type,
 	int sock;
 	gboolean ret;
 
-	if (type == BT_IO_L2RAW) {
-		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-				"Server L2CAP RAW sockets not supported");
-		return NULL;
-	}
-
 	va_start(args, opt1);
 	ret = parse_set_opts(&opts, err, opt1, args);
 	va_end(args);
@@ -1420,7 +1455,7 @@ GIOChannel *bt_io_listen(BtIOType type,
 	if (ret == FALSE)
 		return NULL;
 
-	io = create_io(type, TRUE, &opts, err);
+	io = create_io(TRUE, &opts, err);
 	if (io == NULL)
 		return NULL;
 
diff -pruN 0.46-1/btio/btio.h 0.48-2.1/btio/btio.h
--- 0.46-1/btio/btio.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/btio/btio.h	2012-11-30 07:59:13.000000000 +0000
@@ -26,31 +26,17 @@
 
 #include <glib.h>
 
-typedef enum {
-	BT_IO_ERROR_DISCONNECTED,
-	BT_IO_ERROR_CONNECT_FAILED,
-	BT_IO_ERROR_FAILED,
-	BT_IO_ERROR_INVALID_ARGS,
-} BtIOError;
-
 #define BT_IO_ERROR bt_io_error_quark()
 
 GQuark bt_io_error_quark(void);
 
 typedef enum {
-	BT_IO_L2RAW,
-	BT_IO_L2CAP,
-	BT_IO_L2ERTM,
-	BT_IO_RFCOMM,
-	BT_IO_SCO,
-} BtIOType;
-
-typedef enum {
 	BT_IO_OPT_INVALID = 0,
 	BT_IO_OPT_SOURCE,
 	BT_IO_OPT_SOURCE_BDADDR,
 	BT_IO_OPT_DEST,
 	BT_IO_OPT_DEST_BDADDR,
+	BT_IO_OPT_DEST_TYPE,
 	BT_IO_OPT_DEFER_TIMEOUT,
 	BT_IO_OPT_SEC_LEVEL,
 	BT_IO_OPT_KEY_SIZE,
@@ -92,19 +78,16 @@ typedef void (*BtIOConnect)(GIOChannel *
 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
diff -pruN 0.46-1/ChangeLog 0.48-2.1/ChangeLog
--- 0.46-1/ChangeLog	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/ChangeLog	2012-11-30 07:59:13.000000000 +0000
@@ -1,3 +1,13 @@
+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.
+
 ver 0.46:
 	Update client transfer API.
 	Fix issue with using invalid PSM numbers.
diff -pruN 0.46-1/client/agent.c 0.48-2.1/client/agent.c
--- 0.46-1/client/agent.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/agent.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,252 +0,0 @@
-/*
- *
- *  OBEX Client
- *
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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 <errno.h>
-
-#include "log.h"
-#include "agent.h"
-
-#define AGENT_INTERFACE  "org.openobex.Agent"
-
-struct pending_request {
-	DBusPendingCall *call;
-	DBusPendingCallNotifyFunction function;
-	void *data;
-	DBusFreeFunction destroy;
-};
-
-struct obc_agent {
-	DBusConnection *conn;
-	char *name;
-	char *path;
-	guint watch;
-	GFunc destroy;
-	void *data;
-	struct pending_request *pending;
-};
-
-static void pending_request_free(struct pending_request *req)
-{
-	if (req->call)
-		dbus_pending_call_unref(req->call);
-
-	if (req->destroy)
-		req->destroy(req->data);
-
-	g_free(req);
-}
-
-void obc_agent_free(struct obc_agent *agent)
-{
-	if (agent->watch)
-		g_dbus_remove_watch(agent->conn, agent->watch);
-
-	if (agent->pending) {
-		if (agent->pending->call)
-			dbus_pending_call_cancel(agent->pending->call);
-		pending_request_free(agent->pending);
-	}
-
-	dbus_connection_unref(agent->conn);
-	g_free(agent->name);
-	g_free(agent->path);
-	g_free(agent);
-}
-
-static void agent_disconnected(DBusConnection *connection, void *user_data)
-{
-	struct obc_agent *agent = user_data;
-
-	agent->watch = 0;
-
-	if (agent->destroy)
-		agent->destroy(agent, agent->data);
-
-	obc_agent_free(agent);
-}
-
-struct obc_agent *obc_agent_create(DBusConnection *conn, const char *name,
-					const char *path, GFunc destroy,
-					void *user_data)
-{
-	struct obc_agent *agent;
-
-	agent = g_new0(struct obc_agent, 1);
-	agent->conn = dbus_connection_ref(conn);
-	agent->name = g_strdup(name);
-	agent->path = g_strdup(path);
-	agent->destroy = destroy;
-	agent->data = user_data;
-
-	agent->watch = g_dbus_add_disconnect_watch(conn, name,
-							agent_disconnected,
-							agent, NULL);
-
-	return agent;
-}
-
-static void agent_request_reply(DBusPendingCall *call, void *user_data)
-{
-	struct obc_agent *agent = user_data;
-	struct pending_request *req = agent->pending;
-
-	agent->pending = NULL;
-
-	if (req->function)
-		req->function(call, req->data);
-
-	pending_request_free(req);
-}
-
-int obc_agent_request(struct obc_agent *agent, const char *path,
-				DBusPendingCallNotifyFunction function,
-				void *user_data, DBusFreeFunction destroy)
-{
-	struct pending_request *req;
-	DBusMessage *message;
-
-	if (agent->pending)
-		return -EBUSY;
-
-	DBG("%s", path);
-
-	message = dbus_message_new_method_call(agent->name,
-			agent->path, AGENT_INTERFACE, "Request");
-
-	dbus_message_append_args(message,
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_INVALID);
-
-	req = g_new0(struct pending_request, 1);
-	req->function = function;
-	req->destroy = destroy;
-	req->data = user_data;
-
-	if (!dbus_connection_send_with_reply(agent->conn, message,
-						&req->call, -1)) {
-		g_free(req);
-		dbus_message_unref(message);
-		return -ENOMEM;
-	}
-
-	agent->pending = req;
-
-	dbus_message_unref(message);
-
-	dbus_pending_call_set_notify(req->call, agent_request_reply,
-					agent, NULL);
-
-	return 0;
-}
-
-void obc_agent_notify_progress(struct obc_agent *agent, const char *path,
-							guint64 transferred)
-{
-	DBusMessage *message;
-
-	DBG("%s", path);
-
-	message = dbus_message_new_method_call(agent->name,
-			agent->path, AGENT_INTERFACE, "Progress");
-	if (message == NULL)
-		return;
-
-	dbus_message_set_no_reply(message, TRUE);
-
-	dbus_message_append_args(message,
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_UINT64, &transferred,
-			DBUS_TYPE_INVALID);
-
-	g_dbus_send_message(agent->conn, message);
-}
-
-void obc_agent_notify_complete(struct obc_agent *agent, const char *path)
-{
-	DBusMessage *message;
-
-	DBG("%s", path);
-
-	message = dbus_message_new_method_call(agent->name,
-			agent->path, AGENT_INTERFACE, "Complete");
-	if (message == NULL)
-		return;
-
-	dbus_message_set_no_reply(message, TRUE);
-
-	dbus_message_append_args(message,
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_INVALID);
-
-	g_dbus_send_message(agent->conn, message);
-}
-
-void obc_agent_notify_error(struct obc_agent *agent, const char *path,
-							const char *err)
-{
-	DBusMessage *message;
-
-	DBG("%s", path);
-
-	message = dbus_message_new_method_call(agent->name,
-			agent->path, AGENT_INTERFACE, "Error");
-	if (message == NULL)
-		return;
-
-	dbus_message_set_no_reply(message, TRUE);
-
-	dbus_message_append_args(message,
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_STRING, &err,
-			DBUS_TYPE_INVALID);
-
-	g_dbus_send_message(agent->conn, message);
-}
-
-void obc_agent_release(struct obc_agent *agent)
-{
-	DBusMessage *message;
-
-	DBG("");
-
-	message = dbus_message_new_method_call(agent->name,
-			agent->path, AGENT_INTERFACE, "Release");
-
-	dbus_message_set_no_reply(message, TRUE);
-
-	g_dbus_send_message(agent->conn, message);
-}
-
-const char *obc_agent_get_name(struct obc_agent *agent)
-{
-	return agent->name;
-}
-
-const char *obc_agent_get_path(struct obc_agent *agent)
-{
-	return agent->path;
-}
diff -pruN 0.46-1/client/agent.h 0.48-2.1/client/agent.h
--- 0.46-1/client/agent.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/agent.h	1970-01-01 00:00:00.000000000 +0000
@@ -1,43 +0,0 @@
-/*
- *
- *  OBEX Client
- *
- *  Copyright (C) 2007-2010  Intel Corporation
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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
- *
- */
-
-#include <gdbus.h>
-
-struct obc_agent;
-
-struct obc_agent *obc_agent_create(DBusConnection *conn, const char *name,
-					const char *path, GFunc destroy,
-					void *user_data);
-void obc_agent_free(struct obc_agent *agent);
-const char *obc_agent_get_name(struct obc_agent *agent);
-const char *obc_agent_get_path(struct obc_agent *agent);
-int obc_agent_request(struct obc_agent *agent, const char *path,
-				DBusPendingCallNotifyFunction function,
-				void *user_data, DBusFreeFunction destroy);
-void obc_agent_notify_progress(struct obc_agent *agent, const char *path,
-							guint64 transferred);
-void obc_agent_notify_complete(struct obc_agent *agent, const char *path);
-void obc_agent_notify_error(struct obc_agent *agent, const char *path,
-							const char *err);
-void obc_agent_release(struct obc_agent *agent);
diff -pruN 0.46-1/client/bluetooth.c 0.48-2.1/client/bluetooth.c
--- 0.46-1/client/bluetooth.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/bluetooth.c	2012-11-30 07:59:13.000000000 +0000
@@ -116,6 +116,8 @@ static int send_method_call(struct bluet
 
 	session->pending_calls = g_slist_prepend(session->pending_calls, call);
 
+	dbus_message_unref(msg);
+
 	return 0;
 }
 
@@ -158,6 +160,9 @@ static void session_destroy(struct bluet
 		g_io_channel_unref(session->io);
 	}
 
+	if (session->sdp)
+		sdp_close(session->sdp);
+
 	if (session->conn)
 		dbus_connection_unref(session->conn);
 
@@ -189,7 +194,7 @@ static GIOChannel *transport_connect(con
 	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,
@@ -200,7 +205,7 @@ static GIOChannel *transport_connect(con
 				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,
@@ -576,6 +581,7 @@ static guint bluetooth_connect(const cha
 
 	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);
@@ -629,7 +635,7 @@ static int bluetooth_getpacketopt(GIOCha
 	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;
diff -pruN 0.46-1/client/dbus.c 0.48-2.1/client/dbus.c
--- 0.46-1/client/dbus.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/client/dbus.c	2012-07-26 17:09:25.000000000 +0000
@@ -0,0 +1,256 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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 <glib.h>
+#include <gdbus.h>
+
+#include "log.h"
+#include "dbus.h"
+
+static void append_variant(DBusMessageIter *iter,
+				int type, void *value)
+{
+	char sig[2];
+	DBusMessageIter valueiter;
+
+	sig[0] = type;
+	sig[1] = 0;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+						sig, &valueiter);
+
+	dbus_message_iter_append_basic(&valueiter, type, value);
+
+	dbus_message_iter_close_container(iter, &valueiter);
+}
+
+void obex_dbus_dict_append(DBusMessageIter *dict,
+			const char *key, int type, void *value)
+{
+	DBusMessageIter keyiter;
+
+	if (type == DBUS_TYPE_STRING) {
+		const char *str = *((const char **) value);
+		if (str == NULL)
+			return;
+	}
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+							NULL, &keyiter);
+
+	dbus_message_iter_append_basic(&keyiter, DBUS_TYPE_STRING, &key);
+
+	append_variant(&keyiter, type, value);
+
+	dbus_message_iter_close_container(dict, &keyiter);
+}
+
+static void append_array_variant(DBusMessageIter *iter, int type, void *val)
+{
+	DBusMessageIter variant, array;
+	char typesig[2];
+	char arraysig[3];
+	const char **str_array = *(const char ***) val;
+	int i;
+
+	arraysig[0] = DBUS_TYPE_ARRAY;
+	arraysig[1] = typesig[0] = type;
+	arraysig[2] = typesig[1] = '\0';
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+						arraysig, &variant);
+
+	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+						typesig, &array);
+
+	for (i = 0; str_array[i]; i++)
+		dbus_message_iter_append_basic(&array, type,
+						&(str_array[i]));
+
+	dbus_message_iter_close_container(&variant, &array);
+
+	dbus_message_iter_close_container(iter, &variant);
+}
+
+void obex_dbus_dict_append_array(DBusMessageIter *dict, const char *key,
+				int type, void *val)
+{
+	DBusMessageIter entry;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+						NULL, &entry);
+
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+	append_array_variant(&entry, type, val);
+
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_dict_variant(DBusMessageIter *iter, int type, void *val)
+{
+	DBusMessageIter variant, array, entry;
+	char typesig[5];
+	char arraysig[6];
+	const void **val_array = *(const void ***) val;
+	int i;
+
+	arraysig[0] = DBUS_TYPE_ARRAY;
+	arraysig[1] = typesig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR;
+	arraysig[2] = typesig[1] = DBUS_TYPE_STRING;
+	arraysig[3] = typesig[2] = type;
+	arraysig[4] = typesig[3] = DBUS_DICT_ENTRY_END_CHAR;
+	arraysig[5] = typesig[4] = '\0';
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+						arraysig, &variant);
+
+	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+						typesig, &array);
+
+	for (i = 0; val_array[i]; i += 2) {
+		dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY,
+							NULL, &entry);
+
+		dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
+						&(val_array[i + 0]));
+
+		/*
+		 * D-Bus expects a char** or uint8* depending on the type
+		 * given. Since we are dealing with an array through a void**
+		 * (and thus val_array[i] is a pointer) we need to
+		 * differentiate DBUS_TYPE_STRING from the others. The other
+		 * option would be the user to pass the exact type to this
+		 * function, instead of a pointer to it. However in this case
+		 * a cast from type to void* would be needed, which is not
+		 * good.
+		 */
+		if (type == DBUS_TYPE_STRING) {
+			dbus_message_iter_append_basic(&entry, type,
+							&(val_array[i + 1]));
+		} else {
+			dbus_message_iter_append_basic(&entry, type,
+							val_array[i + 1]);
+		}
+
+		dbus_message_iter_close_container(&array, &entry);
+	}
+
+	dbus_message_iter_close_container(&variant, &array);
+
+	dbus_message_iter_close_container(iter, &variant);
+}
+
+void obex_dbus_dict_append_dict(DBusMessageIter *dict, const char *key,
+				int type, void *val)
+{
+	DBusMessageIter entry;
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+						NULL, &entry);
+
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+	append_dict_variant(&entry, type, val);
+
+	dbus_message_iter_close_container(dict, &entry);
+}
+
+int obex_dbus_signal_property_changed(DBusConnection *conn,
+					const char *path,
+					const char *interface,
+					const char *name,
+					int type, void *value)
+{
+	DBusMessage *signal;
+	DBusMessageIter iter;
+
+	signal = dbus_message_new_signal(path, interface, "PropertyChanged");
+	if (signal == NULL) {
+		error("Unable to allocate new %s.PropertyChanged signal",
+				interface);
+		return -1;
+	}
+
+	dbus_message_iter_init_append(signal, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+	append_variant(&iter, type, value);
+
+	return g_dbus_send_message(conn, signal);
+}
+
+int obex_dbus_signal_array_property_changed(DBusConnection *conn,
+						const char *path,
+						const char *interface,
+						const char *name,
+						int type, void *value)
+
+{
+	DBusMessage *signal;
+	DBusMessageIter iter;
+
+	signal = dbus_message_new_signal(path, interface, "PropertyChanged");
+	if (signal == NULL) {
+		error("Unable to allocate new %s.PropertyChanged signal",
+				interface);
+		return -1;
+	}
+
+	dbus_message_iter_init_append(signal, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+	append_array_variant(&iter, type, value);
+
+	return g_dbus_send_message(conn, signal);
+}
+
+int obex_dbus_signal_dict_property_changed(DBusConnection *conn,
+						const char *path,
+						const char *interface,
+						const char *name,
+						int type, void *value)
+
+{
+	DBusMessage *signal;
+	DBusMessageIter iter;
+
+	signal = dbus_message_new_signal(path, interface, "PropertyChanged");
+	if (signal == NULL) {
+		error("Unable to allocate new %s.PropertyChanged signal",
+				interface);
+		return -1;
+	}
+
+	dbus_message_iter_init_append(signal, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+	append_dict_variant(&iter, type, value);
+
+	return g_dbus_send_message(conn, signal);
+}
diff -pruN 0.46-1/client/dbus.h 0.48-2.1/client/dbus.h
--- 0.46-1/client/dbus.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/client/dbus.h	2012-07-26 17:09:25.000000000 +0000
@@ -0,0 +1,66 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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 __OBEX_DBUS_H
+#define __OBEX_DBUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dbus/dbus.h>
+
+/* Essentially a{sv} */
+#define OBC_PROPERTIES_ARRAY_SIGNATURE DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
+					DBUS_TYPE_STRING_AS_STRING \
+					DBUS_TYPE_VARIANT_AS_STRING \
+					DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+
+void obex_dbus_dict_append(DBusMessageIter *dict, const char *key, int type,
+				void *value);
+
+void obex_dbus_dict_append_array(DBusMessageIter *dict, const char *key,
+					int type, void *val);
+
+void obex_dbus_dict_append_dict(DBusMessageIter *dict, const char *key,
+					int type, void *val);
+
+int obex_dbus_signal_property_changed(DBusConnection *conn, const char *path,
+					const char *interface, const char *name,
+					int type, void *value);
+
+int obex_dbus_signal_array_property_changed(DBusConnection *conn,
+						const char *path,
+						const char *interface,
+						const char *name, int type,
+						void *value);
+
+int obex_dbus_signal_dict_property_changed(DBusConnection *conn,
+						const char *path,
+						const char *interface,
+						const char *name, int type,
+						void *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OBEX_DBUS_H */
diff -pruN 0.46-1/client/ftp.c 0.48-2.1/client/ftp.c
--- 0.46-1/client/ftp.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/ftp.c	2012-07-26 17:09:25.000000000 +0000
@@ -30,6 +30,7 @@
 
 #include <gdbus.h>
 
+#include "dbus.h"
 #include "log.h"
 
 #include "transfer.h"
@@ -41,7 +42,8 @@
 	"\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09"
 #define OBEX_FTP_UUID_LEN 16
 
-#define FTP_INTERFACE "org.openobex.FileTransfer"
+#define FTP_INTERFACE "org.bluez.obex.FileTransfer"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
 #define FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
 #define PCSUITE_UUID "00005005-0000-1000-8000-0002ee000001"
 
@@ -57,7 +59,7 @@ static void async_cb(struct obc_session
 	DBusMessage *reply, *msg = user_data;
 
 	if (err != NULL)
-		reply = g_dbus_create_error(msg, "org.openobex.Error.Failed",
+		reply = g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
 						"%s", err->message);
 	else
 		reply = dbus_message_new_method_return(msg);
@@ -78,13 +80,13 @@ static DBusMessage *change_folder(DBusCo
 				DBUS_TYPE_STRING, &folder,
 				DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	obc_session_setpath(session, folder, async_cb, message, &err);
 	if (err != NULL) {
 		DBusMessage *reply;
 		reply =  g_dbus_create_error(message,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"%s", err->message);
 		g_error_free(err);
 		return reply;
@@ -95,39 +97,6 @@ static DBusMessage *change_folder(DBusCo
 	return NULL;
 }
 
-static void append_variant(DBusMessageIter *iter, int type, void *val)
-{
-	DBusMessageIter value;
-	char sig[2] = { type, '\0' };
-
-	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
-
-	dbus_message_iter_append_basic(&value, type, val);
-
-	dbus_message_iter_close_container(iter, &value);
-}
-
-static void dict_append_entry(DBusMessageIter *dict,
-			const char *key, int type, void *val)
-{
-	DBusMessageIter entry;
-
-	if (type == DBUS_TYPE_STRING) {
-		const char *str = *((const char **) val);
-		if (str == NULL)
-			return;
-	}
-
-	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-							NULL, &entry);
-
-	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
-	append_variant(&entry, type, val);
-
-	dbus_message_iter_close_container(dict, &entry);
-}
-
 static void xml_element(GMarkupParseContext *ctxt,
 			const gchar *element,
 			const gchar **names,
@@ -147,7 +116,7 @@ static void xml_element(GMarkupParseCont
 			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
-	dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &element);
+	obex_dbus_dict_append(&dict, "Type", DBUS_TYPE_STRING, &element);
 
 	/* FIXME: User, Group, Other permission must be reviewed */
 
@@ -157,9 +126,11 @@ static void xml_element(GMarkupParseCont
 		if (g_str_equal("Size", key) == TRUE) {
 			guint64 size;
 			size = g_ascii_strtoll(values[i], NULL, 10);
-			dict_append_entry(&dict, key, DBUS_TYPE_UINT64, &size);
+			obex_dbus_dict_append(&dict, key, DBUS_TYPE_UINT64,
+								&size);
 		} else
-			dict_append_entry(&dict, key, DBUS_TYPE_STRING, &values[i]);
+			obex_dbus_dict_append(&dict, key, DBUS_TYPE_STRING,
+								&values[i]);
 	}
 
 	dbus_message_iter_close_container(iter, &dict);
@@ -173,24 +144,6 @@ static const GMarkupParser parser = {
 	NULL
 };
 
-static void get_file_callback(struct obc_session *session,
-						struct obc_transfer *transfer,
-						GError *err, void *user_data)
-{
-	DBusMessage *msg = user_data;
-	DBusMessage *reply;
-
-	if (err)
-		reply = g_dbus_create_error(msg,
-					"org.openobex.Error.Failed",
-					"%s", err->message);
-	else
-		reply = dbus_message_new_method_return(msg);
-
-	g_dbus_send_message(conn, reply);
-	dbus_message_unref(msg);
-}
-
 static void list_folder_callback(struct obc_session *session,
 						struct obc_transfer *transfer,
 						GError *err, void *user_data)
@@ -236,13 +189,13 @@ static DBusMessage *create_folder(DBusCo
 				DBUS_TYPE_STRING, &folder,
 				DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	obc_session_mkdir(session, folder, async_cb, message, &err);
 	if (err != NULL) {
 		DBusMessage *reply;
 		reply = g_dbus_create_error(message,
-				"org.openobex.Error.Failed",
+				ERROR_INTERFACE ".Failed",
 				"%s", err->message);
 		g_error_free(err);
 		return reply;
@@ -273,7 +226,7 @@ static DBusMessage *list_folder(DBusConn
 	}
 
 fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
 								err->message);
 	g_error_free(err);
 	return reply;
@@ -294,20 +247,19 @@ static DBusMessage *get_file(DBusConnect
 				DBUS_TYPE_STRING, &source_file,
 				DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	transfer = obc_transfer_get(NULL, source_file, target_file, &err);
 	if (transfer == NULL)
 		goto fail;
 
-	if (obc_session_queue(session, transfer, get_file_callback, message,
-								&err)) {
-		dbus_message_ref(message);
-		return NULL;
-	}
+	if (!obc_session_queue(session, transfer, NULL, NULL, &err))
+		goto fail;
+
+	return obc_transfer_create_dbus_reply(transfer, message);
 
 fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
 								err->message);
 	g_error_free(err);
 	return reply;
@@ -328,7 +280,7 @@ static DBusMessage *put_file(DBusConnect
 					DBUS_TYPE_STRING, &targetfile,
 					DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments",
+				ERROR_INTERFACE ".InvalidArguments",
 				"Invalid arguments in method call");
 
 	transfer = obc_transfer_put(NULL, targetfile, sourcefile, NULL, 0,
@@ -336,11 +288,13 @@ static DBusMessage *put_file(DBusConnect
 	if (transfer == NULL)
 		goto fail;
 
-	if (obc_session_queue(session, transfer, NULL, NULL, &err))
-		return dbus_message_new_method_return(message);
+	if (!obc_session_queue(session, transfer, NULL, NULL, &err))
+		goto fail;
+
+	return obc_transfer_create_dbus_reply(transfer, message);
 
 fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
 								err->message);
 	g_error_free(err);
 	return reply;
@@ -359,14 +313,13 @@ static DBusMessage *copy_file(DBusConnec
 				DBUS_TYPE_STRING, &destname,
 				DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	obc_session_copy(session, filename, destname, async_cb, message, &err);
 	if (err != NULL) {
 		DBusMessage *reply;
-		reply = g_dbus_create_error(message,
-						"org.openobex.Error.Failed",
-						"%s", err->message);
+		reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+							"%s", err->message);
 		g_error_free(err);
 		return reply;
 	}
@@ -389,14 +342,13 @@ static DBusMessage *move_file(DBusConnec
 				DBUS_TYPE_STRING, &destname,
 				DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	obc_session_move(session, filename, destname, async_cb, message, &err);
 	if (err != NULL) {
 		DBusMessage *reply;
-		reply = g_dbus_create_error(message,
-						"org.openobex.Error.Failed",
-						"%s", err->message);
+		reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+							"%s", err->message);
 		g_error_free(err);
 		return reply;
 	}
@@ -418,14 +370,13 @@ static DBusMessage *delete(DBusConnectio
 				DBUS_TYPE_STRING, &file,
 				DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	obc_session_delete(session, file, async_cb, message, &err);
 	if (err != NULL) {
 		DBusMessage *reply;
-		reply = g_dbus_create_error(message,
-						"org.openobex.Error.Failed",
-						"%s", err->message);
+		reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+							"%s", err->message);
 		g_error_free(err);
 		return reply;
 	}
@@ -435,23 +386,29 @@ static DBusMessage *delete(DBusConnectio
 	return NULL;
 }
 
-static GDBusMethodTable ftp_methods[] = {
-	{ "ChangeFolder",	"s", "",	change_folder,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "CreateFolder",	"s", "",	create_folder,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "ListFolder",		"", "aa{sv}",	list_folder,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "GetFile",		"ss", "",	get_file,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "PutFile",		"ss", "",	put_file,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "CopyFile",		"ss", "",	copy_file,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "MoveFile",		"ss", "",	move_file,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "Delete",		"s", "",	delete,
-						G_DBUS_METHOD_FLAG_ASYNC },
+static const GDBusMethodTable ftp_methods[] = {
+	{ GDBUS_ASYNC_METHOD("ChangeFolder",
+		GDBUS_ARGS({ "folder", "s" }), NULL, change_folder) },
+	{ GDBUS_ASYNC_METHOD("CreateFolder",
+		GDBUS_ARGS({ "folder", "s" }), NULL, create_folder) },
+	{ GDBUS_ASYNC_METHOD("ListFolder",
+		NULL, GDBUS_ARGS({ "folderinfo", "aa{sv}" }), list_folder) },
+	{ GDBUS_METHOD("GetFile",
+		GDBUS_ARGS({ "targetfile", "s" }, { "sourcefile", "s" }),
+		GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+		get_file) },
+	{ GDBUS_METHOD("PutFile",
+		GDBUS_ARGS({ "sourcefile", "s" }, { "targetfile", "s" }),
+		GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+		put_file) },
+	{ GDBUS_ASYNC_METHOD("CopyFile",
+		GDBUS_ARGS({ "sourcefile", "s" }, { "targetfile", "s" }), NULL,
+		copy_file) },
+	{ GDBUS_ASYNC_METHOD("MoveFile",
+		GDBUS_ARGS({ "sourcefile", "s" }, { "targetfile", "s" }), NULL,
+		move_file) },
+	{ GDBUS_ASYNC_METHOD("Delete",
+		GDBUS_ARGS({ "file", "s" }), NULL, delete) },
 	{ }
 };
 
diff -pruN 0.46-1/client/manager.c 0.48-2.1/client/manager.c
--- 0.46-1/client/manager.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/manager.c	2012-07-26 17:09:25.000000000 +0000
@@ -45,18 +45,15 @@
 #include "sync.h"
 #include "map.h"
 
-#define CLIENT_SERVICE  "org.openobex.client"
+#define CLIENT_SERVICE		"org.bluez.obex.client"
 
-#define CLIENT_INTERFACE  "org.openobex.Client"
-#define CLIENT_PATH       "/"
+#define CLIENT_INTERFACE	"org.bluez.obex.Client"
+#define ERROR_INTERFACE		"org.bluez.obex.Error"
+#define CLIENT_PATH		"/"
 
 struct send_data {
 	DBusConnection *connection;
 	DBusMessage *message;
-	gchar *sender;
-	gchar *agent;
-	char *filename;
-	GPtrArray *files;
 };
 
 static GSList *sessions = NULL;
@@ -84,65 +81,32 @@ static void create_callback(struct obc_s
 						GError *err, void *user_data)
 {
 	struct send_data *data = user_data;
-	unsigned int i;
+	const char *path;
 
 	if (err != NULL) {
 		DBusMessage *error = g_dbus_create_error(data->message,
-					"org.openobex.Error.Failed",
+					ERROR_INTERFACE ".Failed",
 					"%s", err->message);
 		g_dbus_send_message(data->connection, error);
 		shutdown_session(session);
 		goto done;
 	}
 
-	if (obc_session_get_target(session) != NULL) {
-		const char *path;
 
-		path = obc_session_register(session, unregister_session);
+	path = obc_session_register(session, unregister_session);
 
-		g_dbus_send_reply(data->connection, data->message,
+	g_dbus_send_reply(data->connection, data->message,
 				DBUS_TYPE_OBJECT_PATH, &path,
 				DBUS_TYPE_INVALID);
-		goto done;
-	}
-
-	g_dbus_send_reply(data->connection, data->message, DBUS_TYPE_INVALID);
-
-	obc_session_set_agent(session, data->sender, data->agent);
-
-	for (i = 0; i < data->files->len; i++) {
-		const gchar *filename = g_ptr_array_index(data->files, i);
-		gchar *basename = g_path_get_basename(filename);
-		struct obc_transfer *transfer;
-
-		transfer = obc_transfer_put(NULL, basename, filename, NULL, 0,
-									NULL);
-
-		g_free(basename);
-		if (transfer == NULL)
-			break;
-
-		if (!obc_session_queue(session, transfer, NULL, NULL, NULL))
-			break;
-	}
-
-	/* No need to keep a reference for SendFiles */
-	sessions = g_slist_remove(sessions, session);
-	obc_session_unref(session);
 
 done:
-	if (data->files)
-		g_ptr_array_free(data->files, TRUE);
 	dbus_message_unref(data->message);
 	dbus_connection_unref(data->connection);
-	g_free(data->sender);
-	g_free(data->agent);
 	g_free(data);
 }
 
 static int parse_device_dict(DBusMessageIter *iter,
-		const char **source, const char **dest, const char **target,
-		uint8_t *channel)
+		const char **source, const char **target, uint8_t *channel)
 {
 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
 		DBusMessageIter entry, value;
@@ -158,8 +122,6 @@ static int parse_device_dict(DBusMessage
 		case DBUS_TYPE_STRING:
 			if (g_str_equal(key, "Source") == TRUE)
 				dbus_message_iter_get_basic(&value, source);
-			else if (g_str_equal(key, "Destination") == TRUE)
-				dbus_message_iter_get_basic(&value, dest);
 			else if (g_str_equal(key, "Target") == TRUE)
 				dbus_message_iter_get_basic(&value, target);
 			break;
@@ -175,205 +137,6 @@ static int parse_device_dict(DBusMessage
 	return 0;
 }
 
-static DBusMessage *send_files(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	DBusMessageIter iter, array;
-	struct obc_session *session;
-	GPtrArray *files;
-	struct send_data *data;
-	const char *agent, *source = NULL, *dest = NULL, *target = NULL;
-	const char *sender;
-	uint8_t channel = 0;
-
-	dbus_message_iter_init(message, &iter);
-	dbus_message_iter_recurse(&iter, &array);
-
-	parse_device_dict(&array, &source, &dest, &target, &channel);
-	if (dest == NULL)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &array);
-
-	files = g_ptr_array_new();
-	if (files == NULL)
-		return g_dbus_create_error(message,
-					"org.openobex.Error.NoMemory", NULL);
-
-	while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
-		char *value;
-
-		dbus_message_iter_get_basic(&array, &value);
-		g_ptr_array_add(files, value);
-
-		dbus_message_iter_next(&array);
-	}
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_get_basic(&iter, &agent);
-
-	if (files->len == 0) {
-		g_ptr_array_free(files, TRUE);
-		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
-	}
-
-	sender = dbus_message_get_sender(message);
-
-	data = g_try_malloc0(sizeof(*data));
-	if (data == NULL) {
-		g_ptr_array_free(files, TRUE);
-		return g_dbus_create_error(message,
-					"org.openobex.Error.NoMemory", NULL);
-	}
-
-	data->connection = dbus_connection_ref(connection);
-	data->message = dbus_message_ref(message);
-	data->sender = g_strdup(sender);
-	data->agent = g_strdup(agent);
-	data->files = files;
-
-	session = obc_session_create(source, dest, "OPP", channel, sender,
-							create_callback, data);
-	if (session != NULL) {
-		sessions = g_slist_append(sessions, session);
-		return NULL;
-	}
-
-	g_ptr_array_free(data->files, TRUE);
-	dbus_message_unref(data->message);
-	dbus_connection_unref(data->connection);
-	g_free(data->sender);
-	g_free(data->agent);
-	g_free(data);
-
-	return g_dbus_create_error(message, "org.openobex.Error.Failed", NULL);
-}
-
-static void pull_complete_callback(struct obc_session *session,
-					struct obc_transfer *transfer,
-					GError *err, void *user_data)
-{
-	struct send_data *data = user_data;
-
-	if (err != NULL) {
-		DBusMessage *error = g_dbus_create_error(data->message,
-					"org.openobex.Error.Failed",
-					"%s", err->message);
-		g_dbus_send_message(data->connection, error);
-		goto done;
-	}
-
-	g_dbus_send_reply(data->connection, data->message, DBUS_TYPE_INVALID);
-
-done:
-	shutdown_session(session);
-	dbus_message_unref(data->message);
-	dbus_connection_unref(data->connection);
-	g_free(data->filename);
-	g_free(data->sender);
-	g_free(data);
-}
-
-static void pull_obc_session_callback(struct obc_session *session,
-						struct obc_transfer *transfer,
-						GError *err, void *user_data)
-{
-	struct send_data *data = user_data;
-	struct obc_transfer *pull;
-	DBusMessage *reply;
-	GError *gerr = NULL;
-
-	if (err != NULL) {
-		reply = g_dbus_create_error(data->message,
-						"org.openobex.Error.Failed",
-						"%s", err->message);
-		goto fail;
-	}
-
-	pull = obc_transfer_get("text/x-vcard", NULL, data->filename, &gerr);
-
-	if (!obc_session_queue(session, pull, pull_complete_callback, data,
-								&gerr)) {
-		reply = g_dbus_create_error(data->message,
-						"org.openobex.Error.Failed",
-						"%s", gerr->message);
-		g_error_free(gerr);
-		goto fail;
-	}
-
-	return;
-
-fail:
-	g_dbus_send_message(data->connection, reply);
-	shutdown_session(session);
-	dbus_message_unref(data->message);
-	dbus_connection_unref(data->connection);
-	g_free(data->filename);
-	g_free(data->sender);
-	g_free(data);
-}
-
-static DBusMessage *pull_business_card(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	DBusMessageIter iter, dict;
-	struct obc_session *session;
-	struct send_data *data;
-	const char *source = NULL, *dest = NULL, *target = NULL;
-	const char *name = NULL;
-	uint8_t channel = 0;
-
-	dbus_message_iter_init(message, &iter);
-	dbus_message_iter_recurse(&iter, &dict);
-
-	parse_device_dict(&dict, &source, &dest, &target, &channel);
-	if (dest == NULL)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
-
-	dbus_message_iter_next(&iter);
-
-	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
-
-	dbus_message_iter_get_basic(&iter, &name);
-
-	data = g_try_malloc0(sizeof(*data));
-	if (data == NULL)
-		return g_dbus_create_error(message,
-					"org.openobex.Error.NoMemory", NULL);
-
-	data->connection = dbus_connection_ref(connection);
-	data->message = dbus_message_ref(message);
-	data->sender = g_strdup(dbus_message_get_sender(message));
-	data->filename = g_strdup(name);
-
-	session = obc_session_create(source, dest, "OPP", channel, data->sender,
-					pull_obc_session_callback, data);
-	if (session != NULL) {
-		sessions = g_slist_append(sessions, session);
-		return NULL;
-	}
-
-	dbus_message_unref(data->message);
-	dbus_connection_unref(data->connection);
-	g_free(data->sender);
-	g_free(data->filename);
-	g_free(data);
-
-	return g_dbus_create_error(message, "org.openobex.Error.Failed", NULL);
-}
-
-static DBusMessage *exchange_business_cards(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	return g_dbus_create_error(message, "org.openobex.Error.Failed", NULL);
-}
-
 static struct obc_session *find_session(const char *path)
 {
 	GSList *l;
@@ -398,24 +161,35 @@ static DBusMessage *create_session(DBusC
 	uint8_t channel = 0;
 
 	dbus_message_iter_init(message, &iter);
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	dbus_message_iter_get_basic(&iter, &dest);
+	dbus_message_iter_next(&iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
 	dbus_message_iter_recurse(&iter, &dict);
 
-	parse_device_dict(&dict, &source, &dest, &target, &channel);
+	parse_device_dict(&dict, &source, &target, &channel);
 	if (dest == NULL || target == NULL)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	data = g_try_malloc0(sizeof(*data));
 	if (data == NULL)
 		return g_dbus_create_error(message,
-					"org.openobex.Error.NoMemory", NULL);
+				ERROR_INTERFACE ".Error.NoMemory", NULL);
 
 	data->connection = dbus_connection_ref(connection);
 	data->message = dbus_message_ref(message);
-	data->sender = g_strdup(dbus_message_get_sender(message));
 
-	session = obc_session_create(source, dest, target, channel, data->sender,
-							create_callback, data);
+	session = obc_session_create(source, dest, target, channel,
+					dbus_message_get_sender(message),
+					create_callback, data);
 	if (session != NULL) {
 		sessions = g_slist_append(sessions, session);
 		return NULL;
@@ -423,10 +197,9 @@ static DBusMessage *create_session(DBusC
 
 	dbus_message_unref(data->message);
 	dbus_connection_unref(data->connection);
-	g_free(data->sender);
 	g_free(data);
 
-	return g_dbus_create_error(message, "org.openobex.Error.Failed", NULL);
+	return g_dbus_create_error(message, ERROR_INTERFACE ".Failed", NULL);
 }
 
 static DBusMessage *remove_session(DBusConnection *connection,
@@ -439,17 +212,17 @@ static DBusMessage *remove_session(DBusC
 			DBUS_TYPE_OBJECT_PATH, &path,
 			DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	session = find_session(path);
 	if (session == NULL)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	sender = dbus_message_get_sender(message);
 	if (g_str_equal(sender, obc_session_get_owner(session)) == FALSE)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.NotAuthorized",
+				ERROR_INTERFACE ".NotAuthorized",
 				"Not Authorized");
 
 	shutdown_session(session);
@@ -457,143 +230,12 @@ static DBusMessage *remove_session(DBusC
 	return dbus_message_new_method_return(message);
 }
 
-static void capabilities_complete_callback(struct obc_session *session,
-						struct obc_transfer *transfer,
-						GError *err, void *user_data)
-{
-	struct send_data *data = user_data;
-	char *contents;
-	size_t size;
-	int perr;
-
-	if (err != NULL) {
-		DBusMessage *error = g_dbus_create_error(data->message,
-					"org.openobex.Error.Failed",
-					"%s", err->message);
-		g_dbus_send_message(data->connection, error);
-		goto done;
-	}
-
-	perr = obc_transfer_get_contents(transfer, &contents, &size);
-	if (perr < 0) {
-		DBusMessage *error = g_dbus_create_error(data->message,
-						"org.openobex.Error.Failed",
-						"Error reading contents: %s",
-						strerror(-perr));
-		g_dbus_send_message(data->connection, error);
-		goto done;
-	}
-
-	g_dbus_send_reply(data->connection, data->message,
-			DBUS_TYPE_STRING, &contents,
-			DBUS_TYPE_INVALID);
-	g_free(contents);
-
-done:
-
-	shutdown_session(session);
-	dbus_message_unref(data->message);
-	dbus_connection_unref(data->connection);
-	g_free(data->sender);
-	g_free(data);
-}
-
-static void capability_obc_session_callback(struct obc_session *session,
-						struct obc_transfer *transfer,
-						GError *err, void *user_data)
-{
-	struct send_data *data = user_data;
-	struct obc_transfer *pull;
-	DBusMessage *reply;
-	GError *gerr = NULL;
-
-	if (err != NULL) {
-		reply = g_dbus_create_error(data->message,
-					"org.openobex.Error.Failed",
-					"%s", err->message);
-		goto fail;
-	}
-
-	pull = obc_transfer_get("x-obex/capability", NULL, data->filename,
-									&gerr);
-
-	if (!obc_session_queue(session, pull, capabilities_complete_callback,
-								data, &gerr)) {
-		reply = g_dbus_create_error(data->message,
-					"org.openobex.Error.Failed",
-					"%s", gerr->message);
-		g_error_free(gerr);
-		goto fail;
-	}
-
-	return;
-
-fail:
-	g_dbus_send_message(data->connection, reply);
-	shutdown_session(session);
-	dbus_message_unref(data->message);
-	dbus_connection_unref(data->connection);
-	g_free(data->sender);
-	g_free(data);
-}
-
-static DBusMessage *get_capabilities(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	DBusMessageIter iter, dict;
-	struct obc_session *session;
-	struct send_data *data;
-	const char *source = NULL, *dest = NULL, *target = NULL;
-	uint8_t channel = 0;
-
-	dbus_message_iter_init(message, &iter);
-	dbus_message_iter_recurse(&iter, &dict);
-
-	parse_device_dict(&dict, &source, &dest, &target, &channel);
-	if (dest == NULL)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments", NULL);
-
-	data = g_try_malloc0(sizeof(*data));
-	if (data == NULL)
-		return g_dbus_create_error(message,
-					"org.openobex.Error.NoMemory", NULL);
-
-	data->connection = dbus_connection_ref(connection);
-	data->message = dbus_message_ref(message);
-	data->sender = g_strdup(dbus_message_get_sender(message));
-
-	if (!target)
-		target = "OPP";
-
-	session = obc_session_create(source, dest, target, channel, data->sender,
-					capability_obc_session_callback, data);
-	if (session != NULL) {
-		sessions = g_slist_append(sessions, session);
-		return NULL;
-	}
-
-	dbus_message_unref(data->message);
-	dbus_connection_unref(data->connection);
-	g_free(data->sender);
-	g_free(data);
-
-	return g_dbus_create_error(message, "org.openobex.Error.Failed", NULL);
-}
-
-static GDBusMethodTable client_methods[] = {
-	{ "SendFiles", "a{sv}aso", "", send_files,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "PullBusinessCard", "a{sv}s", "", pull_business_card,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "ExchangeBusinessCards", "a{sv}ss", "", exchange_business_cards,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "CreateSession", "a{sv}", "o", create_session,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "RemoveSession", "o", "", remove_session,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "GetCapabilities", "a{sv}", "s", get_capabilities,
-						G_DBUS_METHOD_FLAG_ASYNC },
+static const GDBusMethodTable client_methods[] = {
+	{ GDBUS_ASYNC_METHOD("CreateSession",
+			GDBUS_ARGS({ "destination", "s" }, { "args", "a{sv}" }),
+			GDBUS_ARGS({ "session", "o" }), create_session) },
+	{ GDBUS_ASYNC_METHOD("RemoveSession",
+			GDBUS_ARGS({ "session", "o" }), NULL, remove_session) },
 	{ }
 };
 
diff -pruN 0.46-1/client/map.c 0.48-2.1/client/map.c
--- 0.46-1/client/map.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/map.c	2012-11-30 07:59:13.000000000 +0000
@@ -26,10 +26,15 @@
 
 #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"
@@ -40,12 +45,75 @@
 	"\xBB\x58\x2B\x40\x42\x0C\x11\xDB\xB0\xDE\x08\x00\x20\x0C\x9A\x66"
 #define OBEX_MAS_UUID_LEN 16
 
-#define MAP_INTERFACE  "org.openobex.MessageAccess"
+#define MAP_INTERFACE "org.bluez.obex.MessageAccess"
+#define MAP_MSG_INTERFACE "org.bluez.obex.Message"
+#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;
+	GHashTable *messages;
+};
+
+#define MAP_MSG_FLAG_PRIORITY	0x01
+#define MAP_MSG_FLAG_READ	0x02
+#define MAP_MSG_FLAG_SENT	0x04
+#define MAP_MSG_FLAG_PROTECTED	0x08
+
+struct map_msg {
+	struct map_data *data;
+	char *path;
+	char *handle;
+	char *subject;
+	char *timestamp;
+	char *sender;
+	char *sender_address;
+	char *replyto;
+	char *recipient;
+	char *recipient_address;
+	char *type;
+	uint64_t size;
+	char *status;
+	uint8_t flags;
+	DBusMessage *msg;
+};
+
+struct map_parser {
+	struct map_data *data;
+	DBusMessageIter *iter;
 };
 
 static DBusConnection *conn = NULL;
@@ -59,7 +127,7 @@ static void simple_cb(struct obc_session
 
 	if (err != NULL)
 		reply = g_dbus_create_error(map->msg,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"%s", err->message);
 	else
 		reply = dbus_message_new_method_return(map->msg);
@@ -78,14 +146,14 @@ static DBusMessage *map_setpath(DBusConn
 	if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &folder,
 						DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-					"org.openobex.Error.InvalidArguments",
+					ERROR_INTERFACE ".InvalidArguments",
 					NULL);
 
 	obc_session_setpath(map->session, folder, simple_cb, map, &err);
 	if (err != NULL) {
 		DBusMessage *reply;
 		reply =  g_dbus_create_error(message,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"%s", err->message);
 		g_error_free(err);
 		return reply;
@@ -96,19 +164,54 @@ static DBusMessage *map_setpath(DBusConn
 	return NULL;
 }
 
-static void buffer_cb(struct obc_session *session,
+static void folder_element(GMarkupParseContext *ctxt, const gchar *element,
+				const gchar **names, const gchar **values,
+				gpointer user_data, GError **gerr)
+{
+	DBusMessageIter dict, *iter = user_data;
+	const gchar *key;
+	gint i;
+
+	if (strcasecmp("folder", element) != 0)
+		return;
+
+	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 (i = 0, key = names[i]; key; key = names[++i]) {
+		if (strcasecmp("name", key) == 0)
+			obex_dbus_dict_append(&dict, "Name", DBUS_TYPE_STRING,
+								&values[i]);
+	}
+
+	dbus_message_iter_close_container(iter, &dict);
+}
+
+static const GMarkupParser folder_parser = {
+	folder_element,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static void folder_listing_cb(struct obc_session *session,
 						struct obc_transfer *transfer,
 						GError *err, void *user_data)
 {
 	struct map_data *map = user_data;
+	GMarkupParseContext *ctxt;
 	DBusMessage *reply;
+	DBusMessageIter iter, array;
 	char *contents;
 	size_t size;
 	int perr;
 
 	if (err != NULL) {
 		reply = g_dbus_create_error(map->msg,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"%s", err->message);
 		goto done;
 	}
@@ -116,94 +219,1123 @@ static void buffer_cb(struct obc_session
 	perr = obc_transfer_get_contents(transfer, &contents, &size);
 	if (perr < 0) {
 		reply = g_dbus_create_error(map->msg,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"Error reading contents: %s",
 						strerror(-perr));
 		goto done;
 	}
 
-	reply = g_dbus_create_reply(map->msg, DBUS_TYPE_STRING, &contents,
-							DBUS_TYPE_INVALID);
-
+	reply = dbus_message_new_method_return(map->msg);
+	if (reply == NULL)
+		return;
+
+	dbus_message_iter_init_append(reply, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			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, &array);
+	ctxt = g_markup_parse_context_new(&folder_parser, 0, &array, NULL);
+	g_markup_parse_context_parse(ctxt, contents, size, NULL);
+	g_markup_parse_context_free(ctxt);
+	dbus_message_iter_close_container(&iter, &array);
 	g_free(contents);
+
 done:
 	g_dbus_send_message(conn, reply);
 	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, buffer_cb, map, &err)) {
+	if (obc_session_queue(map->session, transfer, folder_listing_cb, map,
+								&err)) {
 		map->msg = dbus_message_ref(message);
 		return NULL;
 	}
 
 fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
 								err->message);
 	g_error_free(err);
 	return reply;
 }
 
-static DBusMessage *map_get_message_listing(DBusConnection *connection,
+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;
+
+	g_free(msg->path);
+	g_free(msg->subject);
+	g_free(msg->handle);
+	g_free(msg->timestamp);
+	g_free(msg->sender);
+	g_free(msg->sender_address);
+	g_free(msg->replyto);
+	g_free(msg->recipient);
+	g_free(msg->recipient_address);
+	g_free(msg->type);
+	g_free(msg->status);
+	g_free(msg);
+}
+
+static DBusMessage *map_msg_get(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct map_msg *msg = user_data;
 	struct obc_transfer *transfer;
-	const char *folder;
-	DBusMessageIter msg_iter;
+	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);
 
-	dbus_message_iter_init(message, &msg_iter);
+	transfer = obc_transfer_get("x-bt/message", msg->handle, target_file,
+									&err);
+	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 obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+	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(&msg_iter) != DBUS_TYPE_STRING)
+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,
-				"org.openobex.Error.InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
-	dbus_message_iter_get_basic(&msg_iter, &folder);
+	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);
 
-	transfer = obc_transfer_get("x-bt/MAP-msg-listing", folder, NULL, &err);
+	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;
 
-	if (obc_session_queue(map->session, transfer, buffer_cb, map, &err)) {
+	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" },
+						{ "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 struct map_msg *map_msg_create(struct map_data *data, const char *handle)
+{
+	struct map_msg *msg;
+
+	msg = g_new0(struct map_msg, 1);
+	msg->data = data;
+	msg->path = g_strdup_printf("%s/message%s",
+					obc_session_get_path(data->session),
+					handle);
+
+	if (!g_dbus_register_interface(conn, msg->path, MAP_MSG_INTERFACE,
+						map_msg_methods, NULL, NULL,
+						msg, map_msg_free)) {
+		map_msg_free(msg);
+		return NULL;
+	}
+
+	msg->handle = g_strdup(handle);
+	g_hash_table_insert(data->messages, msg->handle, msg);
+
+	return msg;
+}
+
+static void parse_subject(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->subject);
+	msg->subject = g_strdup(value);
+	obex_dbus_dict_append(iter, "Subject", DBUS_TYPE_STRING, &value);
+}
+
+static void parse_datetime(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->timestamp);
+	msg->timestamp = g_strdup(value);
+	obex_dbus_dict_append(iter, "Timestamp", DBUS_TYPE_STRING, &value);
+}
+
+static void parse_sender(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->sender);
+	msg->sender = g_strdup(value);
+	obex_dbus_dict_append(iter, "Sender", DBUS_TYPE_STRING, &value);
+}
+
+static void parse_sender_address(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->sender_address);
+	msg->sender_address = g_strdup(value);
+	obex_dbus_dict_append(iter, "SenderAddress", DBUS_TYPE_STRING,
+								&value);
+}
+
+static void parse_replyto(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->replyto);
+	msg->replyto = g_strdup(value);
+	obex_dbus_dict_append(iter, "ReplyTo", DBUS_TYPE_STRING, &value);
+}
+
+static void parse_recipient(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->recipient);
+	msg->recipient = g_strdup(value);
+	obex_dbus_dict_append(iter, "Recipient", DBUS_TYPE_STRING, &value);
+}
+
+static void parse_recipient_address(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->recipient_address);
+	msg->recipient_address = g_strdup(value);
+	obex_dbus_dict_append(iter, "RecipientAddress", DBUS_TYPE_STRING,
+								&value);
+}
+
+static void parse_type(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->type);
+	msg->type = g_strdup(value);
+	obex_dbus_dict_append(iter, "Type", DBUS_TYPE_STRING, &value);
+}
+
+static void parse_status(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	g_free(msg->status);
+	msg->status = g_strdup(value);
+	obex_dbus_dict_append(iter, "Status", DBUS_TYPE_STRING, &value);
+}
+
+static void parse_size(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	msg->size = g_ascii_strtoll(value, NULL, 10);
+	obex_dbus_dict_append(iter, "Size", DBUS_TYPE_UINT64, &msg->size);
+}
+
+static void parse_priority(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	gboolean flag = strcasecmp(value, "no") != 0;
+
+	if (flag)
+		msg->flags |= MAP_MSG_FLAG_PRIORITY;
+	else
+		msg->flags &= ~MAP_MSG_FLAG_PRIORITY;
+
+	obex_dbus_dict_append(iter, "Priority", DBUS_TYPE_BOOLEAN, &flag);
+}
+
+static void parse_read(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	gboolean flag = strcasecmp(value, "no") != 0;
+
+	if (flag)
+		msg->flags |= MAP_MSG_FLAG_READ;
+	else
+		msg->flags &= ~MAP_MSG_FLAG_READ;
+
+	obex_dbus_dict_append(iter, "Read", DBUS_TYPE_BOOLEAN, &flag);
+}
+
+static void parse_sent(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	gboolean flag = strcasecmp(value, "no") != 0;
+
+	if (flag)
+		msg->flags |= MAP_MSG_FLAG_SENT;
+	else
+		msg->flags &= ~MAP_MSG_FLAG_SENT;
+
+	obex_dbus_dict_append(iter, "Sent", DBUS_TYPE_BOOLEAN, &flag);
+}
+
+static void parse_protected(struct map_msg *msg, const char *value,
+							DBusMessageIter *iter)
+{
+	gboolean flag = strcasecmp(value, "no") != 0;
+
+	if (flag)
+		msg->flags |= MAP_MSG_FLAG_PROTECTED;
+	else
+		msg->flags &= ~MAP_MSG_FLAG_PROTECTED;
+
+	obex_dbus_dict_append(iter, "Protected", DBUS_TYPE_BOOLEAN, &flag);
+}
+
+static struct map_msg_parser {
+	const char *name;
+	void (*func) (struct map_msg *msg, const char *value,
+							DBusMessageIter *iter);
+} msg_parsers[] = {
+		{ "subject", parse_subject },
+		{ "datetime", parse_datetime },
+		{ "sender_name", parse_sender },
+		{ "sender_addressing", parse_sender_address },
+		{ "replyto_addressing", parse_replyto },
+		{ "recipient_name", parse_recipient },
+		{ "recipient_addressing", parse_recipient_address },
+		{ "type", parse_type },
+		{ "reception_status", parse_status },
+		{ "size", parse_size },
+		{ "priority", parse_priority },
+		{ "read", parse_read },
+		{ "sent", parse_sent },
+		{ "protected", parse_protected },
+		{ }
+};
+
+static void msg_element(GMarkupParseContext *ctxt, const gchar *element,
+				const gchar **names, const gchar **values,
+				gpointer user_data, GError **gerr)
+{
+	struct map_parser *parser = user_data;
+	struct map_data *data = parser->data;
+	DBusMessageIter entry, dict, *iter = parser->iter;
+	struct map_msg *msg;
+	const gchar *key;
+	gint i;
+
+	if (strcasecmp("msg", element) != 0)
+		return;
+
+	for (i = 0, key = names[i]; key; key = names[++i]) {
+		if (strcasecmp(key, "handle") == 0)
+			break;
+	}
+
+	msg = g_hash_table_lookup(data->messages, values[i]);
+	if (msg == NULL) {
+		msg = map_msg_create(data, values[i]);
+		if (msg == NULL)
+			return;
+	}
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
+								&entry);
+
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+								&msg->path);
+
+	dbus_message_iter_open_container(&entry, 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 (i = 0, key = names[i]; key; key = names[++i]) {
+		struct map_msg_parser *parser;
+
+		for (parser = msg_parsers; parser && parser->name; parser++) {
+			if (strcasecmp(key, parser->name) == 0) {
+				parser->func(msg, values[i], &dict);
+				break;
+			}
+		}
+	}
+
+	dbus_message_iter_close_container(&entry, &dict);
+	dbus_message_iter_close_container(iter, &entry);
+}
+
+static const GMarkupParser msg_parser = {
+	msg_element,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+static void message_listing_cb(struct obc_session *session,
+						struct obc_transfer *transfer,
+						GError *err, void *user_data)
+{
+	struct map_data *map = user_data;
+	struct map_parser *parser;
+	GMarkupParseContext *ctxt;
+	DBusMessage *reply;
+	DBusMessageIter iter, array;
+	char *contents;
+	size_t size;
+	int perr;
+
+	if (err != NULL) {
+		reply = g_dbus_create_error(map->msg,
+						ERROR_INTERFACE ".Failed",
+						"%s", err->message);
+		goto done;
+	}
+
+	perr = obc_transfer_get_contents(transfer, &contents, &size);
+	if (perr < 0) {
+		reply = g_dbus_create_error(map->msg,
+						ERROR_INTERFACE ".Failed",
+						"Error reading contents: %s",
+						strerror(-perr));
+		goto done;
+	}
+
+	reply = dbus_message_new_method_return(map->msg);
+	if (reply == NULL)
+		return;
+
+	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_OBJECT_PATH_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);
+
+	parser = g_new(struct map_parser, 1);
+	parser->data = map;
+	parser->iter = &array;
+
+	ctxt = g_markup_parse_context_new(&msg_parser, 0, parser, NULL);
+	g_markup_parse_context_parse(ctxt, contents, size, NULL);
+	g_markup_parse_context_free(ctxt);
+	dbus_message_iter_close_container(&iter, &array);
+	g_free(contents);
+	g_free(parser);
+
+done:
+	g_dbus_send_message(conn, reply);
+	dbus_message_unref(map->msg);
+}
+
+static DBusMessage *get_message_listing(struct map_data *map,
+							DBusMessage *message,
+							const char *folder,
+							GObexApparam *apparam)
+{
+	struct obc_transfer *transfer;
+	GError *err = NULL;
+	DBusMessage *reply;
+
+	transfer = obc_transfer_get("x-bt/MAP-msg-listing", folder, NULL, &err);
+	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)) {
 		map->msg = dbus_message_ref(message);
 		return NULL;
 	}
 
 fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
 								err->message);
 	g_error_free(err);
 	return reply;
 }
 
-static GDBusMethodTable map_methods[] = {
-	{ "SetFolder",		"s", "",	map_setpath,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "GetFolderListing",	"a{ss}", "s",	map_get_folder_listing,
-						G_DBUS_METHOD_FLAG_ASYNC },
-	{ "GetMessageListing",	"sa{ss}", "s",	map_get_message_listing,
-						G_DBUS_METHOD_FLAG_ASYNC },
+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("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_list_messages) },
+	{ GDBUS_METHOD("ListFilterFields",
+			NULL,
+			GDBUS_ARGS({ "fields", "as" }),
+			map_list_filter_fields) },
+	{ GDBUS_ASYNC_METHOD("UpdateInbox",
+			NULL,
+			NULL,
+			map_update_inbox) },
 	{ }
 };
 
+static void map_msg_remove(void *data)
+{
+	struct map_msg *msg = data;
+	char *path;
+
+	path = msg->path;
+	msg->path = NULL;
+	g_dbus_unregister_interface(conn, path, MAP_MSG_INTERFACE);
+	g_free(path);
+}
+
 static void map_free(void *data)
 {
 	struct map_data *map = data;
 
 	obc_session_unref(map->session);
+	g_hash_table_unref(map->messages);
 	g_free(map);
 }
 
@@ -221,6 +1353,8 @@ static int map_probe(struct obc_session
 		return -ENOMEM;
 
 	map->session = obc_session_ref(session);
+	map->messages = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+								map_msg_remove);
 
 	if (!g_dbus_register_interface(conn, path, MAP_INTERFACE, map_methods,
 					NULL, NULL, map, map_free)) {
diff -pruN 0.46-1/client/obex-client.service.in 0.48-2.1/client/obex-client.service.in
--- 0.46-1/client/obex-client.service.in	2008-10-04 13:11:13.000000000 +0000
+++ 0.48-2.1/client/obex-client.service.in	2012-07-26 17:09:25.000000000 +0000
@@ -1,3 +1,3 @@
 [D-BUS Service]
-Name=org.openobex.client
+Name=org.bluez.obex.client
 Exec=@libexecdir@/obex-client
diff -pruN 0.46-1/client/opp.c 0.48-2.1/client/opp.c
--- 0.46-1/client/opp.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/opp.c	2012-07-26 17:09:25.000000000 +0000
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include <errno.h>
 #include <gdbus.h>
 
 #include "log.h"
@@ -35,22 +36,179 @@
 #include "opp.h"
 
 #define OPP_UUID "00001105-0000-1000-8000-00805f9b34fb"
+#define OPP_INTERFACE "org.bluez.obex.ObjectPush"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+
+struct opp_data {
+	struct obc_session *session;
+};
+
+static DBusConnection *conn = NULL;
+
+static DBusMessage *opp_send_file(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct opp_data *opp = user_data;
+	struct obc_transfer *transfer;
+	DBusMessage *reply;
+	char *filename;
+	char *basename;
+	GError *err = NULL;
+
+	if (dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &filename,
+					DBUS_TYPE_INVALID) == FALSE)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	basename = g_path_get_basename(filename);
+
+	transfer = obc_transfer_put(NULL, basename, filename, NULL, 0, &err);
+
+	g_free(basename);
+
+	if (transfer == NULL)
+		goto fail;
+
+	if (!obc_session_queue(opp->session, transfer, NULL, NULL, &err))
+		goto fail;
+
+	return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+	reply = g_dbus_create_error(message,
+				ERROR_INTERFACE ".Failed", "%s", err->message);
+	g_error_free(err);
+	return reply;
+}
+
+static DBusMessage *opp_pull_business_card(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct opp_data *opp = user_data;
+	struct obc_transfer *pull;
+	DBusMessage *reply;
+	const char *filename = NULL;
+	GError *err = NULL;
+
+	if (dbus_message_get_args(message, NULL,
+				DBUS_TYPE_STRING, &filename,
+				DBUS_TYPE_INVALID) == FALSE)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+
+	pull = obc_transfer_get("text/x-vcard", NULL, filename, &err);
+	if (pull == NULL)
+		goto fail;
+
+	if (!obc_session_queue(opp->session, pull, NULL, NULL, &err))
+		goto fail;
+
+	return obc_transfer_create_dbus_reply(pull, message);
+
+fail:
+	reply = g_dbus_create_error(message,
+				ERROR_INTERFACE ".Failed", "%s", err->message);
+	g_error_free(err);
+	return reply;
+}
+
+static DBusMessage *opp_exchange_business_cards(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	return g_dbus_create_error(message, ERROR_INTERFACE ".Failed", NULL);
+}
+
+static const GDBusMethodTable opp_methods[] = {
+	{ GDBUS_METHOD("SendFile",
+		GDBUS_ARGS({ "sourcefile", "s" }),
+		GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+		opp_send_file) },
+	{ GDBUS_METHOD("PullBusinessCard",
+		GDBUS_ARGS({ "targetfile", "s" }),
+		GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+		opp_pull_business_card) },
+	{ GDBUS_METHOD("ExchangeBusinessCards",
+		GDBUS_ARGS({ "clientfile", "s" }, { "targetfile", "s" }),
+		GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+		opp_exchange_business_cards) },
+	{ }
+};
+
+static void opp_free(void *data)
+{
+	struct opp_data *opp = data;
+
+	obc_session_unref(opp->session);
+	g_free(opp);
+}
+
+static int opp_probe(struct obc_session *session)
+{
+	struct opp_data *opp;
+	const char *path;
+
+	path = obc_session_get_path(session);
+
+	DBG("%s", path);
+
+	opp = g_try_new0(struct opp_data, 1);
+	if (!opp)
+		return -ENOMEM;
+
+	opp->session = obc_session_ref(session);
+
+	if (!g_dbus_register_interface(conn, path, OPP_INTERFACE, opp_methods,
+						NULL, NULL, opp, opp_free)) {
+		opp_free(opp);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void opp_remove(struct obc_session *session)
+{
+	const char *path = obc_session_get_path(session);
+
+	DBG("%s", path);
+
+	g_dbus_unregister_interface(conn, path, OPP_INTERFACE);
+}
 
 static struct obc_driver opp = {
 	.service = "OPP",
 	.uuid = OPP_UUID,
+	.probe = opp_probe,
+	.remove = opp_remove
 };
 
 int opp_init(void)
 {
+	int err;
+
 	DBG("");
 
-	return obc_driver_register(&opp);
+	conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+	if (!conn)
+		return -EIO;
+
+	err = obc_driver_register(&opp);
+	if (err < 0) {
+		dbus_connection_unref(conn);
+		conn = NULL;
+		return err;
+	}
+
+	return 0;
 }
 
 void opp_exit(void)
 {
 	DBG("");
 
+	dbus_connection_unref(conn);
+	conn = NULL;
+
 	obc_driver_unregister(&opp);
 }
diff -pruN 0.46-1/client/pbap.c 0.48-2.1/client/pbap.c
--- 0.46-1/client/pbap.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/pbap.c	2012-11-30 07:59:13.000000000 +0000
@@ -33,6 +33,7 @@
 #include <gdbus.h>
 
 #include <bluetooth/bluetooth.h>
+#include <gobex-apparam.h>
 
 #include "log.h"
 
@@ -45,8 +46,6 @@
 	"\x79\x61\x35\xF0\xF0\xC5\x11\xD8\x09\x66\x08\x00\x20\x0C\x9A\x66"
 #define OBEX_PBAP_UUID_LEN 16
 
-#define ERROR_INF PBAP_INTERFACE ".Error"
-
 #define FORMAT_VCARD21	0x0
 #define FORMAT_VCARD30	0x1
 
@@ -74,18 +73,6 @@
 #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",
@@ -122,15 +109,13 @@ static const char *filter_list[] = {
 #define FILTER_BIT_MAX	63
 #define FILTER_ALL	0xFFFFFFFFFFFFFFFFULL
 
-#define PBAP_INTERFACE  "org.openobex.PhonebookAccess"
+#define PBAP_INTERFACE "org.bluez.obex.PhonebookAccess"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
 #define PBAP_UUID "0000112f-0000-1000-8000-00805f9b34fb"
 
 struct pbap_data {
 	struct obc_session *session;
 	char *path;
-	guint8 format;
-	guint8 order;
-	uint64_t filter;
 };
 
 struct pending_request {
@@ -138,38 +123,6 @@ struct pending_request {
 	DBusMessage *msg;
 };
 
-struct pullphonebook_apparam {
-	uint8_t     filter_tag;
-	uint8_t     filter_len;
-	uint64_t    filter;
-	uint8_t     format_tag;
-	uint8_t     format_len;
-	uint8_t     format;
-	uint8_t     maxlistcount_tag;
-	uint8_t     maxlistcount_len;
-	uint16_t    maxlistcount;
-	uint8_t     liststartoffset_tag;
-	uint8_t     liststartoffset_len;
-	uint16_t    liststartoffset;
-} __attribute__ ((packed));
-
-struct pullvcardentry_apparam {
-        uint8_t     filter_tag;
-        uint8_t     filter_len;
-        uint64_t    filter;
-        uint8_t     format_tag;
-        uint8_t     format_len;
-        uint8_t     format;
-} __attribute__ ((packed));
-
-struct apparam_hdr {
-	uint8_t		tag;
-	uint8_t		len;
-	uint8_t		val[0];
-} __attribute__ ((packed));
-
-#define APPARAM_HDR_SIZE 2
-
 static DBusConnection *conn = NULL;
 
 static struct pending_request *pending_request_new(struct pbap_data *pbap,
@@ -233,14 +186,14 @@ static gchar *build_phonebook_path(const
 
 	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;
@@ -284,8 +237,8 @@ static void pbap_setpath_cb(struct obc_s
 
 	if (err) {
 		DBusMessage *reply = g_dbus_create_error(request->msg,
-							ERROR_INF ".Failed",
-							"%s", err->message);
+						ERROR_INTERFACE ".Failed",
+						"%s", err->message);
 		g_dbus_send_message(conn, reply);
 	} else
 		g_dbus_send_reply(conn, request->msg, DBUS_TYPE_INVALID);
@@ -296,87 +249,19 @@ static void pbap_setpath_cb(struct obc_s
 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;
-	}
-}
-
-static void pull_phonebook_callback(struct obc_session *session,
-						struct obc_transfer *transfer,
-						GError *err, void *user_data)
-{
-	struct pending_request *request = user_data;
-	DBusMessage *reply;
-	char *contents;
-	size_t size;
-	int perr;
-
-	if (err) {
-		reply = g_dbus_create_error(request->msg,
-						"org.openobex.Error.Failed",
-						"%s", err->message);
-		goto send;
-	}
-
-	perr = obc_transfer_get_contents(transfer, &contents, &size);
-	if (perr < 0) {
-		reply = g_dbus_create_error(request->msg,
-						"org.openobex.Error.Failed",
-						"Error reading contents: %s",
-						strerror(-perr));
-		goto send;
-	}
-
-	reply = dbus_message_new_method_return(request->msg);
-
-	dbus_message_append_args(reply,
-			DBUS_TYPE_STRING, &contents,
-			DBUS_TYPE_INVALID);
-
-	g_free(contents);
-
-send:
-	g_dbus_send_message(conn, reply);
-	pending_request_free(request);
+	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,
@@ -390,7 +275,7 @@ static void phonebook_size_callback(stru
 
 	if (err) {
 		reply = g_dbus_create_error(request->msg,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"%s", err->message);
 		goto send;
 	}
@@ -422,7 +307,7 @@ static void pull_vcard_listing_callback(
 
 	if (err) {
 		reply = g_dbus_create_error(request->msg,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"%s", err->message);
 		goto send;
 	}
@@ -430,7 +315,7 @@ static void pull_vcard_listing_callback(
 	perr = obc_transfer_get_contents(transfer, &contents, &size);
 	if (perr < 0) {
 		reply = g_dbus_create_error(request->msg,
-						"org.openobex.Error.Failed",
+						ERROR_INTERFACE ".Failed",
 						"Error reading contents: %s",
 						strerror(-perr));
 		goto send;
@@ -454,165 +339,75 @@ send:
 	pending_request_free(request);
 }
 
-static DBusMessage *pull_phonebook(struct pbap_data *pbap,
-					DBusMessage *message, guint8 type,
-					const char *name, uint64_t filter,
-					guint8 format, guint16 maxlistcount,
-					guint16 liststartoffset)
+static GObexApparam *parse_format(GObexApparam *apparam, DBusMessageIter *iter)
 {
-	struct pending_request *request;
-	struct pullphonebook_apparam apparam;
-	struct obc_transfer *transfer;
-	session_callback_t func;
-	GError *err = NULL;
-	DBusMessage *reply;
-
-	transfer = obc_transfer_get("x-bt/phonebook", name, NULL, &err);
-	if (transfer == NULL)
-		goto fail;
-
-	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);
+	const char *string;
+	guint8 format;
 
-	switch (type) {
-	case PULLPHONEBOOK:
-		func = pull_phonebook_callback;
-		break;
-	case GETPHONEBOOKSIZE:
-		func = phonebook_size_callback;
-		break;
-	default:
-		error("Unexpected type : 0x%2x", type);
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
 		return NULL;
-	}
-
-	request = pending_request_new(pbap, message);
 
-	obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
+	dbus_message_iter_get_basic(iter, &string);
 
-	if (obc_session_queue(pbap->session, transfer, func, request, &err))
+	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;
 
-	pending_request_free(request);
-
-fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
-								err->message);
-	g_error_free(err);
-	return reply;
+	return g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
 }
 
-static guint8 *fill_apparam(guint8 *dest, void *buf, guint8 tag, guint8 len)
+static GObexApparam *parse_order(GObexApparam *apparam, DBusMessageIter *iter)
 {
-	if (dest && buf) {
-		*dest++ = tag;
-		*dest++ = len;
-		memcpy(dest, buf, len);
-		dest += len;
-	}
-
-	return dest;
-}
-
-static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
-					DBusMessage *message, const char *name,
-					guint8 order, char *searchval, guint8 attrib,
-					guint16 count, guint16 offset)
-{
-	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;
-
-	/* 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);
-	p = fill_apparam(p, &offset, LISTSTARTOFFSET_TAG, LISTSTARTOFFSET_LEN);
+	const char *string;
+	guint8 order;
 
-	request = pending_request_new(pbap, message);
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+		return NULL;
 
-	obc_transfer_set_params(transfer, apparam, apparam_size);
+	dbus_message_iter_get_basic(iter, &string);
 
-	if (obc_session_queue(pbap->session, transfer,
-				pull_vcard_listing_callback, request, &err))
+	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;
 
-	pending_request_free(request);
-
-fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
-								err->message);
-	g_error_free(err);
-	return reply;
+	return g_obex_apparam_set_uint8(apparam, ORDER_TAG, order);
 }
 
-static int set_format(struct pbap_data *pbap, const char *formatstr)
+static GObexApparam *parse_offset(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;
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+		return NULL;
 
-	return 0;
+	dbus_message_iter_get_basic(iter, &num);
+
+	return g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG, num);
 }
 
-static int set_order(struct pbap_data *pbap, const char *orderstr)
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+							DBusMessageIter *iter)
 {
-	if (!orderstr || g_str_equal(orderstr, "")) {
-		pbap->order = ORDER_INDEXED;
-		return 0;
-	}
+	guint16 num;
 
-	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;
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+		return NULL;
 
-	return 0;
+	dbus_message_iter_get_basic(iter, &num);
+
+	return g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, num);
 }
 
 static uint64_t get_filter_mask(const char *filterstr)
@@ -640,56 +435,174 @@ static uint64_t get_filter_mask(const ch
 		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;
+
+	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, "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;
+		}
 
-	list = g_try_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
+		dbus_message_iter_next(&array);
+	}
 
-	if (!list)
+	return apparam;
+}
+
+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;
+	}
 
-	item = list;
+	obc_transfer_set_apparam(transfer, apparam);
 
-	for (i = 0; i < filter_list_size; i++)
-		if (filter & (1ULL << i))
-			*(item++) = g_strdup(filter_list[i]);
+	if (!obc_session_queue(pbap->session, transfer, func, request, &err)) {
+		if (request != NULL)
+			pending_request_free(request);
 
-	for (i = filter_list_size; i <= FILTER_BIT_MAX; i++)
-		if (filter & (1ULL << i))
-			*(item++) = g_strdup_printf("%s%d", "BIT", i);
+		goto fail;
+	}
 
-	*item = NULL;
-	*size = item - list;
-	return list;
+	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,
@@ -706,12 +619,13 @@ static DBusMessage *pbap_select(DBusConn
 			DBUS_TYPE_STRING, &item,
 			DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-				ERROR_INF ".InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
 	path = build_phonebook_path(location, item);
 	if (path == NULL)
 		return g_dbus_create_error(message,
-				ERROR_INF ".InvalidArguments", "Invalid path");
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid path");
 
 	if (pbap->path != NULL && g_str_equal(pbap->path, path)) {
 		g_free(path);
@@ -724,7 +638,7 @@ static DBusMessage *pbap_select(DBusConn
 									&err);
 	if (err != NULL) {
 		DBusMessage *reply;
-		reply =  g_dbus_create_error(message, ERROR_INF ".Failed",
+		reply =  g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
 							"%s", err->message);
 		g_error_free(err);
 		g_free(path);
@@ -742,102 +656,141 @@ static DBusMessage *pbap_pull_all(DBusCo
 					DBusMessage *message, void *user_data)
 {
 	struct pbap_data *pbap = user_data;
-	DBusMessage * err;
-	char *name;
+	const char *targetfile;
+	GObexApparam *apparam;
+	DBusMessageIter args;
 
 	if (!pbap->path)
 		return g_dbus_create_error(message,
-				ERROR_INF ".Forbidden", "Call Select first of all");
+					ERROR_INTERFACE ".Forbidden",
+					"Call Select first of all");
 
-	name = g_strconcat(pbap->path, ".vcf", NULL);
+	dbus_message_iter_init(message, &args);
 
-	err = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
-				pbap->filter, pbap->format,
-				DEFAULT_COUNT, DEFAULT_OFFSET);
-	g_free(name);
-	return err;
-}
+	if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
-static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	struct pbap_data *pbap = user_data;
-	struct pullvcardentry_apparam apparam;
-	const char *name;
-	struct pending_request *request;
-	struct obc_transfer *transfer;
-	GError *err = NULL;
-	DBusMessage *reply;
+	dbus_message_iter_get_basic(&args, &targetfile);
+	dbus_message_iter_next(&args);
 
-	if (!pbap->path)
-		return g_dbus_create_error(message,
-				ERROR_INF ".Forbidden",
-				"Call Select first of all");
+	apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+							DEFAULT_COUNT);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							DEFAULT_OFFSET);
 
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &name,
-			DBUS_TYPE_INVALID) == FALSE)
+	if (parse_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
 		return g_dbus_create_error(message,
-				ERROR_INF ".InvalidArguments", NULL);
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
 
-	transfer = obc_transfer_get("x-bt/vcard", name, NULL, &err);
-	if (transfer == NULL)
-		goto fail;
+	return pull_phonebook(pbap, message, PULLPHONEBOOK, targetfile,
+								apparam);
+}
 
-	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;
+static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
+				const char *name, const char *targetfile,
+				GObexApparam *apparam)
+{
+	struct obc_transfer *transfer;
+	DBusMessage *reply;
+	GError *err = NULL;
 
-	request = pending_request_new(pbap, message);
+	transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
+	if (transfer == NULL) {
+		g_obex_apparam_free(apparam);
+		goto fail;
+	}
 
-	obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
+	obc_transfer_set_apparam(transfer, apparam);
 
-	if (obc_session_queue(pbap->session, transfer, pull_phonebook_callback,
-								request, &err))
-		return NULL;
+	if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
+		goto fail;
 
-	pending_request_free(request);
+	return obc_transfer_create_dbus_reply(transfer, message);
 
 fail:
-	reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
 								err->message);
 	g_error_free(err);
 	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_INF ".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;
+	GObexApparam *apparam;
+	DBusMessageIter args;
 
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &field,
-			DBUS_TYPE_STRING, &value,
-			DBUS_TYPE_INVALID) == FALSE)
+	if (!pbap->path)
 		return g_dbus_create_error(message,
-				ERROR_INF ".InvalidArguments", NULL);
+					ERROR_INTERFACE ".Forbidden",
+					"Call Select first of all");
 
-	if (!pbap->path)
+	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_INF ".Forbidden", "Call Select first of all");
+				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;
@@ -848,119 +801,101 @@ static DBusMessage *pbap_search(DBusConn
 	else if (!g_ascii_strcasecmp(field, "sound"))
 		attrib = ATTRIB_SOUND;
 	else
-		return g_dbus_create_error(message,
-				ERROR_INF ".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 * err;
-	char *name;
+	char *field, *value;
+	GObexApparam *apparam;
+	DBusMessageIter args;
 
 	if (!pbap->path)
 		return g_dbus_create_error(message,
-				ERROR_INF ".Forbidden", "Call Select first of all");
+					ERROR_INTERFACE ".Forbidden",
+					"Call Select first of all");
 
-	name = g_strconcat(pbap->path, ".vcf", NULL);
+	dbus_message_iter_init(message, &args);
 
-	err = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name,
-				pbap->filter, pbap->format, 0,
-				DEFAULT_OFFSET);
-	g_free(name);
-	return err;
-}
+	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_INF ".InvalidArguments", NULL);
+				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_INF ".InvalidArguments", "InvalidFormat");
-
-	return dbus_message_new_method_return(message);
-}
+				ERROR_INTERFACE ".InvalidArguments", NULL);
 
-static DBusMessage *pbap_set_order(DBusConnection *connection,
-					DBusMessage *message, void *user_data)
-{
-	struct pbap_data *pbap = user_data;
-	const char *order;
+	dbus_message_iter_get_basic(&args, &value);
+	dbus_message_iter_next(&args);
 
-	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &order,
-			DBUS_TYPE_INVALID) == FALSE)
-		return g_dbus_create_error(message,
-				ERROR_INF ".InvalidArguments", NULL);
+	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 (set_order(pbap, order) < 0)
+	if (parse_filters(apparam, &args) == NULL) {
+		g_obex_apparam_free(apparam);
 		return g_dbus_create_error(message,
-				ERROR_INF ".InvalidArguments", "InvalidFilter");
+				ERROR_INTERFACE ".InvalidArguments", NULL);
+	}
 
-	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_INF ".InvalidArguments", NULL);
+					ERROR_INTERFACE ".Forbidden",
+					"Call Select first of all");
 
-	remove_filter(pbap, "ALL");
-	if (size == 0)
-		goto done;
-
-	for (item = filters; *item; item++) {
-		if (add_filter(pbap, *item) < 0) {
-			pbap->filter = oldfilter;
-			g_strfreev(filters);
-			return g_dbus_create_error(message,
-					ERROR_INF ".InvalidArguments", "InvalidFilters");
-		}
-	}
+	dbus_message_iter_init(message, &args);
 
-done:
-	g_strfreev(filters);
-	return dbus_message_new_method_return(message);
+	apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							DEFAULT_OFFSET);
+
+	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,
@@ -980,24 +915,37 @@ static DBusMessage *pbap_list_filter_fie
 	return reply;
 }
 
-static GDBusMethodTable pbap_methods[] = {
-	{ "Select",	"ss",	"",	pbap_select,
-					G_DBUS_METHOD_FLAG_ASYNC },
-	{ "PullAll",	"",	"s",	pbap_pull_all,
-					G_DBUS_METHOD_FLAG_ASYNC },
-	{ "Pull",	"s",	"s",	pbap_pull_vcard,
-					G_DBUS_METHOD_FLAG_ASYNC },
-	{ "List",	"",	"a(ss)",	pbap_list,
-					G_DBUS_METHOD_FLAG_ASYNC },
-	{ "Search",	"ss",	"a(ss)",	pbap_search,
-					G_DBUS_METHOD_FLAG_ASYNC },
-	{ "GetSize",	"",	"q",	pbap_get_size,
-					G_DBUS_METHOD_FLAG_ASYNC },
-	{ "SetFormat",	"s",	"",	pbap_set_format },
-	{ "SetOrder",	"s",	"",	pbap_set_order },
-	{ "SetFilter",	"as",	"",	pbap_set_filter },
-	{ "GetFilter",	"",	"as",	pbap_get_filter },
-	{ "ListFilterFields", "",	"as",	pbap_list_filter_fields },
+static const GDBusMethodTable pbap_methods[] = {
+	{ GDBUS_ASYNC_METHOD("Select",
+			GDBUS_ARGS({ "location", "s" }, { "phonebook", "s" }),
+			NULL, pbap_select) },
+	{ GDBUS_METHOD("PullAll",
+			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" },
+					{ "filters", "a{sv}" }),
+			GDBUS_ARGS({ "transfer", "o" },
+					{ "properties", "a{sv}" }),
+			pbap_pull_vcard) },
+	{ GDBUS_ASYNC_METHOD("List",
+			GDBUS_ARGS({ "filters", "a{sv}" }),
+			GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+			pbap_list) },
+	{ GDBUS_ASYNC_METHOD("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("ListFilterFields",
+				NULL, GDBUS_ARGS({ "fields", "as" }),
+				pbap_list_filter_fields) },
 	{ }
 };
 
diff -pruN 0.46-1/client/session.c 0.48-2.1/client/session.c
--- 0.46-1/client/session.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/session.c	2012-07-26 17:09:25.000000000 +0000
@@ -3,6 +3,7 @@
  *  OBEX Client
  *
  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -37,15 +38,16 @@
 #include <gdbus.h>
 #include <gobex.h>
 
+#include "dbus.h"
 #include "log.h"
 #include "transfer.h"
 #include "session.h"
-#include "agent.h"
 #include "driver.h"
 #include "transport.h"
 
-#define SESSION_INTERFACE  "org.openobex.Session"
-#define SESSION_BASEPATH   "/org/openobex"
+#define SESSION_INTERFACE "org.bluez.obex.Session"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+#define SESSION_BASEPATH "/org/bluez/obex"
 
 #define OBEX_IO_ERROR obex_io_error_quark()
 #define OBEX_IO_ERROR_FIRST (0xff + 1)
@@ -68,7 +70,6 @@ struct pending_request {
 	guint req_id;
 	struct obc_session *session;
 	struct obc_transfer *transfer;
-	GFunc auth_complete;
 	session_callback_t func;
 	void *data;
 };
@@ -91,22 +92,21 @@ struct obc_session {
 	gchar *path;		/* Session path */
 	DBusConnection *conn;
 	GObex *obex;
-	struct obc_agent *agent;
 	struct pending_request *p;
 	gchar *owner;		/* Session owner */
 	guint watch;
 	GQueue *queue;
+	guint queue_complete_id;
 };
 
 static GSList *sessions = NULL;
 
-static void session_start_transfer(gpointer data, gpointer user_data);
+static void session_process_queue(struct obc_session *session);
 static void session_terminate_transfer(struct obc_session *session,
 					struct obc_transfer *transfer,
 					GError *gerr);
-static void transfer_progress(struct obc_transfer *transfer,
-					gint64 transferred, GError *err,
-					void *user_data);
+static void transfer_complete(struct obc_transfer *transfer,
+					GError *err, void *user_data);
 
 static GQuark obex_io_error_quark(void)
 {
@@ -141,7 +141,6 @@ static void session_unregistered(struct
 
 static struct pending_request *pending_request_new(struct obc_session *session,
 						struct obc_transfer *transfer,
-						GFunc auth_complete,
 						session_callback_t func,
 						void *data)
 {
@@ -152,7 +151,6 @@ static struct pending_request *pending_r
 	p->id = ++id;
 	p->session = obc_session_ref(session);
 	p->transfer = transfer;
-	p->auth_complete = auth_complete;
 	p->func = func;
 	p->data = data;
 
@@ -174,10 +172,8 @@ static void session_free(struct obc_sess
 {
 	DBG("%p", session);
 
-	if (session->agent) {
-		obc_agent_release(session->agent);
-		obc_agent_free(session->agent);
-	}
+	if (session->queue_complete_id != 0)
+		g_source_remove(session->queue_complete_id);
 
 	if (session->queue) {
 		g_queue_foreach(session->queue, (GFunc) pending_request_free,
@@ -528,94 +524,6 @@ void obc_session_shutdown(struct obc_ses
 	obc_session_unref(session);
 }
 
-static DBusMessage *assign_agent(DBusConnection *connection,
-				DBusMessage *message, void *user_data)
-{
-	struct obc_session *session = user_data;
-	const gchar *sender, *path;
-
-	if (dbus_message_get_args(message, NULL,
-					DBUS_TYPE_OBJECT_PATH, &path,
-					DBUS_TYPE_INVALID) == FALSE)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments",
-				"Invalid arguments in method call");
-
-	sender = dbus_message_get_sender(message);
-
-	if (obc_session_set_agent(session, sender, path) < 0)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.AlreadyExists",
-				"Already exists");
-
-	return dbus_message_new_method_return(message);
-}
-
-static DBusMessage *release_agent(DBusConnection *connection,
-				DBusMessage *message, void *user_data)
-{
-	struct obc_session *session = user_data;
-	struct obc_agent *agent = session->agent;
-	const gchar *sender;
-	gchar *path;
-
-	if (dbus_message_get_args(message, NULL,
-					DBUS_TYPE_OBJECT_PATH, &path,
-					DBUS_TYPE_INVALID) == FALSE)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.InvalidArguments",
-				"Invalid arguments in method call");
-
-	sender = dbus_message_get_sender(message);
-
-	if (agent == NULL)
-		return dbus_message_new_method_return(message);
-
-	if (g_str_equal(sender, obc_agent_get_name(agent)) == FALSE ||
-			g_str_equal(path, obc_agent_get_path(agent)) == FALSE)
-		return g_dbus_create_error(message,
-				"org.openobex.Error.NotAuthorized",
-				"Not Authorized");
-
-	obc_agent_free(agent);
-
-	return dbus_message_new_method_return(message);
-}
-
-static void append_entry(DBusMessageIter *dict,
-				const char *key, int type, void *val)
-{
-	DBusMessageIter entry, value;
-	const char *signature;
-
-	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-								NULL, &entry);
-
-	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
-	switch (type) {
-	case DBUS_TYPE_STRING:
-		signature = DBUS_TYPE_STRING_AS_STRING;
-		break;
-	case DBUS_TYPE_BYTE:
-		signature = DBUS_TYPE_BYTE_AS_STRING;
-		break;
-	case DBUS_TYPE_UINT64:
-		signature = DBUS_TYPE_UINT64_AS_STRING;
-		break;
-	default:
-		signature = DBUS_TYPE_VARIANT_AS_STRING;
-		break;
-	}
-
-	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
-							signature, &value);
-	dbus_message_iter_append_basic(&value, type, val);
-	dbus_message_iter_close_container(&entry, &value);
-
-	dbus_message_iter_close_container(dict, &entry);
-}
-
 static DBusMessage *session_get_properties(DBusConnection *connection,
 				DBusMessage *message, void *user_data)
 {
@@ -635,114 +543,103 @@ static DBusMessage *session_get_properti
 			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
 	if (session->source != NULL)
-		append_entry(&dict, "Source", DBUS_TYPE_STRING,
+		obex_dbus_dict_append(&dict, "Source", DBUS_TYPE_STRING,
 							&session->source);
 
-	append_entry(&dict, "Destination", DBUS_TYPE_STRING,
+	obex_dbus_dict_append(&dict, "Destination", DBUS_TYPE_STRING,
 							&session->destination);
 
-	append_entry(&dict, "Channel", DBUS_TYPE_BYTE, &session->channel);
+	obex_dbus_dict_append(&dict, "Channel", DBUS_TYPE_BYTE,
+							&session->channel);
 
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
 }
 
-static GDBusMethodTable session_methods[] = {
-	{ "GetProperties",	"", "a{sv}",	session_get_properties	},
-	{ "AssignAgent",	"o", "",	assign_agent	},
-	{ "ReleaseAgent",	"o", "",	release_agent	},
-	{ }
-};
-
-static void session_request_reply(DBusPendingCall *call, gpointer user_data)
+static void capabilities_complete_callback(struct obc_session *session,
+						struct obc_transfer *transfer,
+						GError *err, void *user_data)
 {
-	struct obc_session *session = user_data;
-	struct pending_request *p = session->p;
-	struct obc_transfer *transfer = p->transfer;
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	const char *name;
-	DBusError derr;
-	int err;
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		GError *gerr = NULL;
+	DBusMessage *message = user_data;
+	char *contents;
+	size_t size;
+	int perr;
 
-		error("Replied with an error: %s, %s",
-				derr.name, derr.message);
-		dbus_error_free(&derr);
-		dbus_message_unref(reply);
-
-		g_set_error(&gerr, OBEX_IO_ERROR, -ECANCELED, "%s",
-								derr.message);
-		session_terminate_transfer(session, transfer, gerr);
-		g_clear_error(&gerr);
+	if (err != NULL) {
+		DBusMessage *error = g_dbus_create_error(message,
+					ERROR_INTERFACE ".Failed",
+					"%s", err->message);
+		g_dbus_send_message(session->conn, error);
+		goto done;
+	}
 
-		return;
+	perr = obc_transfer_get_contents(transfer, &contents, &size);
+	if (perr < 0) {
+		DBusMessage *error = g_dbus_create_error(message,
+						ERROR_INTERFACE ".Failed",
+						"Error reading contents: %s",
+						strerror(-perr));
+		g_dbus_send_message(session->conn, error);
+		goto done;
 	}
 
-	dbus_message_get_args(reply, NULL,
-			DBUS_TYPE_STRING, &name,
-			DBUS_TYPE_INVALID);
+	g_dbus_send_reply(session->conn, message,
+						DBUS_TYPE_STRING, &contents,
+						DBUS_TYPE_INVALID);
+	g_free(contents);
 
-	DBG("Agent.Request() reply: %s", name);
+done:
+	dbus_message_unref(message);
+}
 
-	if (strlen(name) == 0)
-		goto done;
+static DBusMessage *get_capabilities(DBusConnection *connection,
+					DBusMessage *message, void *user_data)
+{
+	struct obc_session *session = user_data;
+	struct obc_transfer *pull;
+	DBusMessage *reply;
+	GError *gerr = NULL;
 
-	if (obc_transfer_get_operation(transfer) == G_OBEX_OP_PUT) {
-		obc_transfer_set_name(transfer, name);
-		goto done;
-	}
+	pull = obc_transfer_get("x-obex/capability", NULL, NULL, &gerr);
+	if (pull == NULL)
+		goto fail;
 
-	err = obc_transfer_set_filename(transfer, name);
-	if (err < 0) {
-		GError *gerr = NULL;
+	if (!obc_session_queue(session, pull, capabilities_complete_callback,
+								message, &gerr))
+		goto fail;
 
-		g_set_error(&gerr, OBEX_IO_ERROR, err,
-						"Unable to set filename");
-		session_terminate_transfer(session, transfer, gerr);
-		g_clear_error(&gerr);
-		return;
-	}
+	dbus_message_ref(message);
 
-done:
-	if (p->auth_complete)
-		p->auth_complete(session, transfer);
+	return NULL;
 
-	dbus_message_unref(reply);
+fail:
+	reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+								gerr->message);
+	g_error_free(gerr);
+	return reply;
 
-	return;
 }
 
-static gboolean session_request_proceed(gpointer data)
+static const GDBusMethodTable session_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+				NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+				session_get_properties) },
+	{ GDBUS_ASYNC_METHOD("GetCapabilities",
+				NULL, GDBUS_ARGS({ "capabilities", "s" }),
+				get_capabilities) },
+	{ }
+};
+
+static gboolean session_queue_complete(gpointer data)
 {
 	struct obc_session *session = data;
-	struct pending_request *p = session->p;
-	struct obc_transfer *transfer = p->transfer;
-
-	if (p->auth_complete)
-		p->auth_complete(p->session, transfer);
-
-	return FALSE;
-}
 
-static int pending_request_auth(struct pending_request *p)
-{
-	struct obc_session *session = p->session;
-	struct obc_agent *agent = session->agent;
-	const char *path;
+	session_process_queue(session);
 
-	path = obc_transfer_get_path(p->transfer);
+	session->queue_complete_id = 0;
 
-	if (agent == NULL || path == NULL) {
-		g_idle_add(session_request_proceed, session);
-		return 0;
-	}
-
-	return obc_agent_request(agent, path, session_request_reply, session,
-									NULL);
+	return FALSE;
 }
 
 guint obc_session_queue(struct obc_session *session,
@@ -751,8 +648,6 @@ guint obc_session_queue(struct obc_sessi
 				GError **err)
 {
 	struct pending_request *p;
-	const char *agent;
-	int perr;
 
 	if (session->obex == NULL) {
 		obc_transfer_unregister(transfer);
@@ -761,33 +656,20 @@ guint obc_session_queue(struct obc_sessi
 		return 0;
 	}
 
-	if (session->agent)
-		agent = obc_agent_get_name(session->agent);
-	else
-		agent = NULL;
-
-	if (!obc_transfer_register(transfer, session->conn, agent, err)) {
+	if (!obc_transfer_register(transfer, session->conn, session->path,
+							session->owner, err)) {
 		obc_transfer_unregister(transfer);
 		return 0;
 	}
 
-	obc_transfer_set_callback(transfer, transfer_progress, session);
+	obc_transfer_set_callback(transfer, transfer_complete, session);
 
-	p = pending_request_new(session, transfer, session_start_transfer,
-							func, user_data);
-	if (session->p) {
-		g_queue_push_tail(session->queue, p);
-		return p->id;
-	}
-
-	perr = pending_request_auth(p);
-	if (perr < 0) {
-		g_set_error(err, OBEX_IO_ERROR, perr, "Authorization failed");
-		pending_request_free(p);
-		return 0;
-	}
+	p = pending_request_new(session, transfer, func, user_data);
+	g_queue_push_tail(session->queue, p);
 
-	session->p = p;
+	if (session->queue_complete_id == 0)
+		session->queue_complete_id = g_idle_add(
+					session_queue_complete, session);
 
 	return p->id;
 }
@@ -805,22 +687,19 @@ static void session_process_queue(struct
 	obc_session_ref(session);
 
 	while ((p = g_queue_pop_head(session->queue))) {
-		int err;
+		GError *gerr = NULL;
 
-		err = pending_request_auth(p);
-		if (err == 0) {
+		DBG("Transfer(%p) started", p->transfer);
+
+		if (obc_transfer_start(p->transfer, session->obex, &gerr)) {
 			session->p = p;
 			break;
 		}
 
-		if (p->func) {
-			GError *gerr = NULL;
-
-			g_set_error(&gerr, OBEX_IO_ERROR, err,
-							"Authorization failed");
+		if (p->func)
 			p->func(session, p->transfer, gerr, p->data);
-			g_error_free(gerr);
-		}
+
+		g_clear_error(&gerr);
 
 		pending_request_free(p);
 	}
@@ -874,18 +753,6 @@ static void session_terminate_transfer(s
 static void session_notify_complete(struct obc_session *session,
 				struct obc_transfer *transfer)
 {
-	struct obc_agent *agent = session->agent;
-	const char *path;
-
-	path = obc_transfer_get_path(transfer);
-
-	if (agent == NULL || path == NULL)
-		goto done;
-
-	obc_agent_notify_complete(agent, path);
-
-done:
-
 	DBG("Transfer(%p) complete", transfer);
 
 	session_terminate_transfer(session, transfer, NULL);
@@ -895,52 +762,20 @@ static void session_notify_error(struct
 				struct obc_transfer *transfer,
 				GError *err)
 {
-	struct obc_agent *agent = session->agent;
-	const char *path;
-
-	path = obc_transfer_get_path(transfer);
-	if (agent == NULL || path == NULL)
-		goto done;
-
-	obc_agent_notify_error(agent, path, err->message);
-
-done:
 	error("Transfer(%p) Error: %s", transfer, err->message);
 
 	session_terminate_transfer(session, transfer, err);
 }
 
-static void session_notify_progress(struct obc_session *session,
-					struct obc_transfer *transfer,
-					gint64 transferred)
-{
-	struct obc_agent *agent = session->agent;
-	const char *path;
-
-	path = obc_transfer_get_path(transfer);
-	if (agent == NULL || path == NULL)
-		goto done;
-
-	obc_agent_notify_progress(agent, path, transferred);
-
-done:
-	DBG("Transfer(%p) progress: %ld bytes", transfer,
-			(long int ) transferred);
-
-	if (transferred == obc_transfer_get_size(transfer))
-		session_notify_complete(session, transfer);
-}
-
-static void transfer_progress(struct obc_transfer *transfer,
-					gint64 transferred, GError *err,
-					void *user_data)
+static void transfer_complete(struct obc_transfer *transfer,
+					GError *err, void *user_data)
 {
 	struct obc_session *session = user_data;
 
 	if (err != 0)
 		goto fail;
 
-	session_notify_progress(session, transfer, transferred);
+	session_notify_complete(session, transfer);
 
 	return;
 
@@ -948,21 +783,6 @@ fail:
 	session_notify_error(session, transfer, err);
 }
 
-static void session_start_transfer(gpointer data, gpointer user_data)
-{
-	struct obc_session *session = data;
-	struct obc_transfer *transfer = user_data;
-	GError *err = NULL;
-
-	if (!obc_transfer_start(transfer, session->obex, &err)) {
-		session_notify_error(session, transfer, err);
-		g_clear_error(&err);
-		return;
-	}
-
-	DBG("Transfer(%p) started", transfer);
-}
-
 const char *obc_session_register(struct obc_session *session,
 						GDBusDestroyFunction destroy)
 {
@@ -993,49 +813,6 @@ fail:
 	return NULL;
 }
 
-static void agent_destroy(gpointer data, gpointer user_data)
-{
-	struct obc_session *session = user_data;
-
-	session->agent = NULL;
-}
-
-int obc_session_set_agent(struct obc_session *session, const char *name,
-							const char *path)
-{
-	struct obc_agent *agent;
-
-	if (session == NULL)
-		return -EINVAL;
-
-	if (session->agent)
-		return -EALREADY;
-
-	agent = obc_agent_create(session->conn, name, path, agent_destroy,
-								session);
-
-	if (session->watch == 0)
-		obc_session_set_owner(session, name, owner_disconnected);
-
-	session->agent = agent;
-
-	return 0;
-}
-
-const char *obc_session_get_agent(struct obc_session *session)
-{
-	struct obc_agent *agent;
-
-	if (session == NULL)
-		return NULL;
-
-	agent = session->agent;
-	if (agent == NULL)
-		return NULL;
-
-	return obc_agent_get_name(session->agent);
-}
-
 const char *obc_session_get_owner(struct obc_session *session)
 {
 	if (session == NULL)
@@ -1140,7 +917,7 @@ guint obc_session_setpath(struct obc_ses
 	data->user_data = user_data;
 	data->remaining = g_strsplit(path, "/", 3);
 
-	p = pending_request_new(session, NULL, NULL, setpath_complete, data);
+	p = pending_request_new(session, NULL, setpath_complete, data);
 
 	/* Relative path */
 	if (path[0] != '/') {
@@ -1215,7 +992,7 @@ guint obc_session_mkdir(struct obc_sessi
 	}
 
 
-	p = pending_request_new(session, NULL, NULL, func, user_data);
+	p = pending_request_new(session, NULL, func, user_data);
 
 	p->req_id = g_obex_mkdir(session->obex, folder, async_cb, p, err);
 	if (*err != NULL) {
@@ -1244,7 +1021,7 @@ guint obc_session_copy(struct obc_sessio
 		return 0;
 	}
 
-	p = pending_request_new(session, NULL, NULL, func, user_data);
+	p = pending_request_new(session, NULL, func, user_data);
 
 	p->req_id = g_obex_copy(session->obex, srcname, destname, async_cb, p,
 									err);
@@ -1274,7 +1051,7 @@ guint obc_session_move(struct obc_sessio
 		return 0;
 	}
 
-	p = pending_request_new(session, NULL, NULL, func, user_data);
+	p = pending_request_new(session, NULL, func, user_data);
 
 	p->req_id = g_obex_move(session->obex, srcname, destname, async_cb, p,
 									err);
@@ -1304,7 +1081,7 @@ guint obc_session_delete(struct obc_sess
 		return 0;
 	}
 
-	p = pending_request_new(session, NULL, NULL, func, user_data);
+	p = pending_request_new(session, NULL, func, user_data);
 
 	p->req_id = g_obex_delete(session->obex, file, async_cb, p, err);
 	if (*err != NULL) {
diff -pruN 0.46-1/client/session.h 0.48-2.1/client/session.h
--- 0.46-1/client/session.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/session.h	2012-07-26 17:09:25.000000000 +0000
@@ -3,6 +3,7 @@
  *  OBEX Client
  *
  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -47,10 +48,6 @@ int obc_session_set_owner(struct obc_ses
 			GDBusWatchFunction func);
 const char *obc_session_get_owner(struct obc_session *session);
 
-int obc_session_set_agent(struct obc_session *session, const char *name,
-							const char *path);
-const char *obc_session_get_agent(struct obc_session *session);
-
 const char *obc_session_get_path(struct obc_session *session);
 const char *obc_session_get_target(struct obc_session *session);
 
diff -pruN 0.46-1/client/sync.c 0.48-2.1/client/sync.c
--- 0.46-1/client/sync.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/sync.c	2012-07-26 17:09:25.000000000 +0000
@@ -42,7 +42,7 @@
 #define OBEX_SYNC_UUID "IRMC-SYNC"
 #define OBEX_SYNC_UUID_LEN 9
 
-#define SYNC_INTERFACE	"org.openobex.Synchronization"
+#define SYNC_INTERFACE "org.bluez.obex.Synchronization"
 #define ERROR_INF SYNC_INTERFACE ".Error"
 #define SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb"
 
@@ -84,53 +84,22 @@ static DBusMessage *sync_setlocation(DBu
 	return dbus_message_new_method_return(message);
 }
 
-static void sync_getphonebook_callback(struct obc_session *session,
-					struct obc_transfer *transfer,
-					GError *err, void *user_data)
-{
-	struct sync_data *sync = user_data;
-	DBusMessage *reply;
-	char *contents;
-	size_t size;
-	int perr;
-
-	if (err) {
-		reply = g_dbus_create_error(sync->msg,
-						"org.openobex.Error.Failed",
-						"%s", err->message);
-		goto send;
-	}
-
-	perr = obc_transfer_get_contents(transfer, &contents, &size);
-	if (perr < 0) {
-		reply = g_dbus_create_error(sync->msg,
-						"org.openobex.Error.Failed",
-						"Error reading contents: %s",
-						strerror(-perr));
-		goto send;
-	}
-
-	reply = dbus_message_new_method_return(sync->msg);
-
-	dbus_message_append_args(reply, DBUS_TYPE_STRING, &contents,
-							DBUS_TYPE_INVALID);
-
-	g_free(contents);
-
-send:
-	g_dbus_send_message(conn, reply);
-	dbus_message_unref(sync->msg);
-	sync->msg = NULL;
-}
-
 static DBusMessage *sync_getphonebook(DBusConnection *connection,
 			DBusMessage *message, void *user_data)
 {
 	struct sync_data *sync = user_data;
 	struct obc_transfer *transfer;
+	const char *target_file;
 	GError *err = NULL;
 	DBusMessage *reply;
 
+	if (dbus_message_get_args(message, NULL,
+					DBUS_TYPE_STRING, &target_file,
+					DBUS_TYPE_INVALID) == FALSE)
+		return g_dbus_create_error(message,
+				ERROR_INF ".InvalidArguments",
+				"Invalid arguments in method call");
+
 	if (sync->msg)
 		return g_dbus_create_error(message,
 			ERROR_INF ".InProgress", "Transfer in progress");
@@ -139,17 +108,15 @@ static DBusMessage *sync_getphonebook(DB
 	if (!sync->phonebook_path)
 		sync->phonebook_path = g_strdup("telecom/pb.vcf");
 
-	transfer = obc_transfer_get("phonebook", sync->phonebook_path, NULL,
-									&err);
+	transfer = obc_transfer_get("phonebook", sync->phonebook_path,
+							target_file, &err);
 	if (transfer == NULL)
 		goto fail;
 
-	if (obc_session_queue(sync->session, transfer,
-						sync_getphonebook_callback,
-						sync, &err)) {
-		sync->msg = dbus_message_ref(message);
-		return NULL;
-	}
+	if (!obc_session_queue(sync->session, transfer, NULL, NULL, &err))
+		goto fail;
+
+	return obc_transfer_create_dbus_reply(transfer, message);
 
 fail:
 	reply = g_dbus_create_error(message, ERROR_INF ".Failed", "%s",
@@ -163,27 +130,30 @@ static DBusMessage *sync_putphonebook(DB
 {
 	struct sync_data *sync = user_data;
 	struct obc_transfer *transfer;
-	const char *buf;
+	const char *source_file;
 	GError *err = NULL;
 	DBusMessage *reply;
 
 	if (dbus_message_get_args(message, NULL,
-			DBUS_TYPE_STRING, &buf,
-			DBUS_TYPE_INVALID) == FALSE)
+					DBUS_TYPE_STRING, &source_file,
+					DBUS_TYPE_INVALID) == FALSE)
 		return g_dbus_create_error(message,
-			ERROR_INF ".InvalidArguments", NULL);
+				ERROR_INF ".InvalidArguments",
+				"Invalid arguments in method call");
 
 	/* set default phonebook_path to memory internal phonebook */
 	if (!sync->phonebook_path)
 		sync->phonebook_path = g_strdup("telecom/pb.vcf");
 
-	transfer = obc_transfer_put(NULL, sync->phonebook_path, NULL, buf,
-							strlen(buf), &err);
+	transfer = obc_transfer_put(NULL, sync->phonebook_path, source_file,
+							NULL, 0, &err);
 	if (transfer == NULL)
 		goto fail;
 
-	if (obc_session_queue(sync->session, transfer, NULL, NULL, &err))
-		return dbus_message_new_method_return(message);
+	if (!obc_session_queue(sync->session, transfer, NULL, NULL, &err))
+		goto fail;
+
+	return obc_transfer_create_dbus_reply(transfer, message);
 
 fail:
 	reply = g_dbus_create_error(message, ERROR_INF ".Failed", "%s",
@@ -192,13 +162,21 @@ fail:
 	return reply;
 }
 
-static GDBusMethodTable sync_methods[] = {
-	{ "SetLocation", "s", "", sync_setlocation },
-	{ "GetPhonebook", "", "s", sync_getphonebook,
-			G_DBUS_METHOD_FLAG_ASYNC },
-	{ "PutPhonebook", "s", "", sync_putphonebook,
-			G_DBUS_METHOD_FLAG_ASYNC },
-	{}
+static const GDBusMethodTable sync_methods[] = {
+	{ GDBUS_METHOD("SetLocation",
+			GDBUS_ARGS({ "location", "s" }), NULL,
+			sync_setlocation) },
+	{ GDBUS_METHOD("GetPhonebook",
+			GDBUS_ARGS({ "targetfile", "s" }),
+			GDBUS_ARGS({ "transfer", "o" },
+					{ "properties", "a{sv}" }),
+			sync_getphonebook) },
+	{ GDBUS_METHOD("PutPhonebook",
+			GDBUS_ARGS({ "sourcefile", "s" }),
+			GDBUS_ARGS({ "transfer", "o" },
+					{ "properties", "a{sv}" }),
+			sync_putphonebook) },
+	{ }
 };
 
 static void sync_free(void *data)
diff -pruN 0.46-1/client/transfer.c 0.48-2.1/client/transfer.c
--- 0.46-1/client/transfer.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/transfer.c	2012-11-30 07:59:13.000000000 +0000
@@ -3,6 +3,7 @@
  *  OBEX Client
  *
  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -38,14 +39,17 @@
 #include <gdbus.h>
 #include <gobex.h>
 
+#include "dbus.h"
 #include "log.h"
 #include "transfer.h"
 
-#define TRANSFER_INTERFACE  "org.openobex.Transfer"
-#define TRANSFER_BASEPATH   "/org/openobex"
+#define TRANSFER_INTERFACE "org.bluez.obex.Transfer"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
 
 #define OBC_TRANSFER_ERROR obc_transfer_error_quark()
 
+#define FIRST_PACKET_TIMEOUT 60
+
 static guint64 counter = 0;
 
 struct transfer_callback {
@@ -53,19 +57,14 @@ 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;
-	char *agent;		/* Transfer agent */
+	char *owner;		/* Transfer initiator */
 	char *path;		/* Transfer path */
 	gchar *filename;	/* Transfer file location */
 	char *name;		/* Transfer object name */
@@ -74,6 +73,8 @@ struct obc_transfer {
 	guint xfer;
 	gint64 size;
 	gint64 transferred;
+	gint64 progress;
+	guint progress_id;
 };
 
 static GQuark obc_transfer_error_quark(void)
@@ -81,38 +82,19 @@ static GQuark obc_transfer_error_quark(v
 	return g_quark_from_static_string("obc-transfer-error-quark");
 }
 
-static void append_entry(DBusMessageIter *dict,
-				const char *key, int type, void *val)
+static void obc_transfer_append_dbus_properties(struct obc_transfer *transfer,
+							DBusMessageIter *dict)
 {
-	DBusMessageIter entry, value;
-	const char *signature;
+	obex_dbus_dict_append(dict, "Name", DBUS_TYPE_STRING, &transfer->name);
+	obex_dbus_dict_append(dict, "Size", DBUS_TYPE_UINT64, &transfer->size);
 
-	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-								NULL, &entry);
-
-	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
-	switch (type) {
-	case DBUS_TYPE_STRING:
-		signature = DBUS_TYPE_STRING_AS_STRING;
-		break;
-	case DBUS_TYPE_BYTE:
-		signature = DBUS_TYPE_BYTE_AS_STRING;
-		break;
-	case DBUS_TYPE_UINT64:
-		signature = DBUS_TYPE_UINT64_AS_STRING;
-		break;
-	default:
-		signature = DBUS_TYPE_VARIANT_AS_STRING;
-		break;
-	}
-
-	dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
-							signature, &value);
-	dbus_message_iter_append_basic(&value, type, val);
-	dbus_message_iter_close_container(&entry, &value);
-
-	dbus_message_iter_close_container(dict, &entry);
+	if (transfer->filename != NULL)
+		obex_dbus_dict_append(dict, "Filename", DBUS_TYPE_STRING,
+							&transfer->filename);
+
+	if (transfer->obex != NULL)
+		obex_dbus_dict_append(dict, "Progress", DBUS_TYPE_UINT64,
+						&transfer->progress);
 }
 
 static DBusMessage *obc_transfer_get_properties(DBusConnection *connection,
@@ -127,21 +109,51 @@ static DBusMessage *obc_transfer_get_pro
 		return NULL;
 
 	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, &dict);
-
-	append_entry(&dict, "Name", DBUS_TYPE_STRING, &transfer->name);
-	append_entry(&dict, "Size", DBUS_TYPE_UINT64, &transfer->size);
-	append_entry(&dict, "Filename", DBUS_TYPE_STRING, &transfer->filename);
+						OBC_PROPERTIES_ARRAY_SIGNATURE,
+						&dict);
+
+	obc_transfer_append_dbus_properties(transfer, &dict);
 
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
 }
 
+static void obc_transfer_append_dbus_data(struct obc_transfer *transfer,
+							DBusMessageIter *iter)
+{
+	const char *path = transfer->path;
+	DBusMessageIter entry, dict;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &entry);
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, &path);
+	dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY,
+						OBC_PROPERTIES_ARRAY_SIGNATURE,
+						&dict);
+
+	obc_transfer_append_dbus_properties(transfer, &dict);
+
+	dbus_message_iter_close_container(&entry, &dict);
+	dbus_message_iter_close_container(iter, &entry);
+}
+
+DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer,
+							DBusMessage *message)
+{
+	DBusMessage *reply;
+	DBusMessageIter iter;
+
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL)
+		return NULL;
+
+	dbus_message_iter_init_append(reply, &iter);
+	obc_transfer_append_dbus_data(transfer, &iter);
+
+	return reply;
+}
+
 static void abort_complete(GObex *obex, GError *err, gpointer user_data)
 {
 	struct obc_transfer *transfer = user_data;
@@ -161,28 +173,17 @@ static void abort_complete(GObex *obex,
 		return;
 
 	if (err) {
-		callback->func(transfer, transfer->transferred, err,
-							callback->data);
+		callback->func(transfer, err, callback->data);
 	} else {
 		GError *abort_err;
 
 		abort_err = g_error_new(OBC_TRANSFER_ERROR, -ECANCELED, "%s",
 						"Transfer cancelled by user");
-		callback->func(transfer, transfer->transferred, abort_err,
-							callback->data);
+		callback->func(transfer, abort_err, callback->data);
 		g_error_free(abort_err);
 	}
 }
 
-static gboolean obc_transfer_abort(struct obc_transfer *transfer)
-{
-	if (transfer->xfer == 0)
-		return FALSE;
-
-	return g_obex_cancel_transfer(transfer->xfer, abort_complete,
-								transfer);
-}
-
 static DBusMessage *obc_transfer_cancel(DBusConnection *connection,
 					DBusMessage *message, void *user_data)
 {
@@ -190,14 +191,39 @@ static DBusMessage *obc_transfer_cancel(
 	const gchar *sender;
 
 	sender = dbus_message_get_sender(message);
-	if (g_strcmp0(transfer->agent, sender) != 0)
+	if (g_strcmp0(transfer->owner, sender) != 0)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.NotAuthorized",
+				ERROR_INTERFACE ".NotAuthorized",
 				"Not Authorized");
 
-	if (!obc_transfer_abort(transfer))
+	if (transfer->msg != NULL)
 		return g_dbus_create_error(message,
-				"org.openobex.Error.Failed",
+				ERROR_INTERFACE ".InProgress",
+				"Cancellation already in progress");
+
+	if (transfer->xfer == 0) {
+		struct transfer_callback *callback = transfer->callback;
+
+		if (callback != NULL) {
+			GError *err;
+
+			err = g_error_new(OBC_TRANSFER_ERROR, -ECANCELED, "%s",
+						"Transfer cancelled by user");
+			callback->func(transfer, err, callback->data);
+			g_error_free(err);
+		}
+
+		return dbus_message_new_method_return(message);
+	}
+
+	if (transfer->progress_id != 0) {
+		g_source_remove(transfer->progress_id);
+		transfer->progress_id = 0;
+	}
+
+	if (!g_obex_cancel_transfer(transfer->xfer, abort_complete, transfer))
+		return g_dbus_create_error(message,
+				ERROR_INTERFACE ".Failed",
 				"Failed");
 
 	transfer->msg = dbus_message_ref(message);
@@ -205,9 +231,21 @@ static DBusMessage *obc_transfer_cancel(
 	return NULL;
 }
 
-static GDBusMethodTable obc_transfer_methods[] = {
-	{ "GetProperties", "", "a{sv}", obc_transfer_get_properties },
-	{ "Cancel", "", "", obc_transfer_cancel, G_DBUS_METHOD_FLAG_ASYNC },
+static const GDBusMethodTable obc_transfer_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+				NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+				obc_transfer_get_properties) },
+	{ GDBUS_ASYNC_METHOD("Cancel", NULL, NULL,
+				obc_transfer_cancel) },
+	{ }
+};
+
+static const GDBusSignalTable obc_transfer_signals[] = {
+	{ GDBUS_SIGNAL("PropertyChanged",
+		GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+	{ GDBUS_SIGNAL("Complete", NULL) },
+	{ GDBUS_SIGNAL("Error",
+		GDBUS_ARGS({ "code", "s" }, { "message", "s" })) },
 	{ }
 };
 
@@ -218,6 +256,11 @@ static void obc_transfer_free(struct obc
 	if (transfer->xfer)
 		g_obex_cancel_transfer(transfer->xfer, NULL, NULL);
 
+	if (transfer->progress_id != 0) {
+		g_source_remove(transfer->progress_id);
+		transfer->progress_id = 0;
+	}
+
 	if (transfer->op == G_OBEX_OP_GET &&
 					transfer->transferred != transfer->size)
 		remove(transfer->filename);
@@ -225,10 +268,8 @@ static void obc_transfer_free(struct obc
 	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);
@@ -240,7 +281,7 @@ static void obc_transfer_free(struct obc
 		g_obex_unref(transfer->obex);
 
 	g_free(transfer->callback);
-	g_free(transfer->agent);
+	g_free(transfer->owner);
 	g_free(transfer->filename);
 	g_free(transfer->name);
 	g_free(transfer->type);
@@ -266,21 +307,15 @@ static struct obc_transfer *obc_transfer
 
 gboolean obc_transfer_register(struct obc_transfer *transfer,
 						DBusConnection *conn,
-						const char *agent,
+						const char *path,
+						const char *owner,
 						GError **err)
 {
-	/* for OBEX specific mime types we don't need to register a transfer */
-	if (transfer->type != NULL &&
-			(strncmp(transfer->type, "x-obex/", 7) == 0 ||
-			strncmp(transfer->type, "x-bt/", 5) == 0))
-		goto done;
-
-	transfer->agent = g_strdup(agent);
+	transfer->owner = g_strdup(owner);
 
-	transfer->path = g_strdup_printf("%s/transfer%ju",
-			TRANSFER_BASEPATH, counter++);
+	transfer->path = g_strdup_printf("%s/transfer%ju", path, counter++);
 
-	transfer->conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+	transfer->conn = dbus_connection_ref(conn);
 	if (transfer->conn == NULL) {
 		g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
 						"Unable to connect to D-Bus");
@@ -289,14 +324,13 @@ gboolean obc_transfer_register(struct ob
 
 	if (g_dbus_register_interface(transfer->conn, transfer->path,
 				TRANSFER_INTERFACE,
-				obc_transfer_methods, NULL, NULL,
-				transfer, NULL) == FALSE) {
+				obc_transfer_methods, obc_transfer_signals,
+				NULL, transfer, NULL) == FALSE) {
 		g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
 						"Unable to register to D-Bus");
 		return FALSE;
 	}
 
-done:
 	DBG("%p registered %s", transfer, transfer->path);
 
 	return TRUE;
@@ -306,8 +340,9 @@ static gboolean transfer_open(struct obc
 						mode_t mode, GError **err)
 {
 	int fd;
+	char *filename;
 
-	if (transfer->filename != NULL) {
+	if (transfer->filename != NULL && strcmp(transfer->filename, "") != 0) {
 		fd = open(transfer->filename, flags, mode);
 		if (fd < 0) {
 			error("open(): %s(%d)", strerror(errno), errno);
@@ -318,13 +353,19 @@ static gboolean transfer_open(struct obc
 		goto done;
 	}
 
-	fd = g_file_open_tmp("obex-clientXXXXXX", &transfer->filename, err);
+	fd = g_file_open_tmp("obex-clientXXXXXX", &filename, err);
 	if (fd < 0) {
 		error("g_file_open_tmp(): %s", (*err)->message);
 		return FALSE;
 	}
 
-	remove(transfer->filename);
+	if (transfer->filename == NULL) {
+		remove(filename); /* remove always only if NULL was given */
+		g_free(filename);
+	} else {
+		g_free(transfer->filename);
+		transfer->filename = filename;
+	}
 
 done:
 	transfer->fd = fd;
@@ -357,6 +398,13 @@ struct obc_transfer *obc_transfer_put(co
 	struct stat st;
 	int perr;
 
+	if ((filename == NULL || strcmp(filename, "") == 0) &&
+							contents == NULL) {
+		g_set_error(err, OBC_TRANSFER_ERROR, -EINVAL,
+						"Invalid filename given");
+		return NULL;
+	}
+
 	transfer = obc_transfer_create(G_OBEX_OP_PUT, filename, name, type);
 
 	if (contents != NULL) {
@@ -367,23 +415,27 @@ struct obc_transfer *obc_transfer_put(co
 
 		w = write(transfer->fd, contents, size);
 		if (w < 0) {
-			error("write(): %s(%d)", strerror(errno), errno);
-			perr = -errno;
+			perr = errno;
+			error("write(): %s(%d)", strerror(perr), perr);
+			g_set_error(err, OBC_TRANSFER_ERROR, -perr,
+						"Writing to file failed");
 			goto fail;
 		} else if ((size_t) w != size) {
 			error("Unable to write all contents to file");
-			perr = -EFAULT;
+			g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
+					"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;
 	}
 
-	perr = fstat(transfer->fd, &st);
-	if (perr < 0) {
-		error("fstat(): %s(%d)", strerror(errno), errno);
-		g_set_error(err, OBC_TRANSFER_ERROR, -errno,
+	if (fstat(transfer->fd, &st) < 0) {
+		perr = errno;
+		error("fstat(): %s(%d)", strerror(perr), perr);
+		g_set_error(err, OBC_TRANSFER_ERROR, -perr,
 						"Unable to get file status");
 		goto fail;
 	}
@@ -413,7 +465,6 @@ static gboolean get_xfer_progress(const
 							gpointer user_data)
 {
 	struct obc_transfer *transfer = user_data;
-	struct transfer_callback *callback = transfer->callback;
 
 	if (transfer->fd > 0) {
 		gint w;
@@ -425,10 +476,6 @@ static gboolean get_xfer_progress(const
 		transfer->transferred += w;
 	}
 
-	if (callback && transfer->transferred != transfer->size)
-		callback->func(transfer, transfer->transferred, NULL,
-							callback->data);
-
 	return TRUE;
 }
 
@@ -439,14 +486,36 @@ static void xfer_complete(GObex *obex, G
 
 	transfer->xfer = 0;
 
-	if (err)
-		goto done;
+	if (transfer->progress_id != 0) {
+		g_source_remove(transfer->progress_id);
+		transfer->progress_id = 0;
+	}
 
-	transfer->size = transfer->transferred;
+	if (err == NULL) {
+		transfer->size = transfer->transferred;
+
+		if (transfer->path != NULL)
+			g_dbus_emit_signal(transfer->conn, transfer->path,
+						TRANSFER_INTERFACE, "Complete",
+						DBUS_TYPE_INVALID);
+	} else {
+		const char *code = ERROR_INTERFACE ".Failed";
+
+		if (transfer->op == G_OBEX_OP_GET && transfer->filename != NULL)
+			remove(transfer->filename);
+
+		if (transfer->path != NULL)
+			g_dbus_emit_signal(transfer->conn, transfer->path,
+						TRANSFER_INTERFACE, "Error",
+						DBUS_TYPE_STRING,
+						&code,
+						DBUS_TYPE_STRING,
+						&err->message,
+						DBUS_TYPE_INVALID);
+	}
 
-done:
 	if (callback)
-		callback->func(transfer, transfer->size, err, callback->data);
+		callback->func(transfer, err, callback->data);
 }
 
 static void get_xfer_progress_first(GObex *obex, GError *err, GObexPacket *rsp,
@@ -455,6 +524,7 @@ static void get_xfer_progress_first(GObe
 	struct obc_transfer *transfer = user_data;
 	GObexPacket *req;
 	GObexHeader *hdr;
+	GObexApparam *apparam;
 	const guint8 *buf;
 	gsize len;
 	guint8 rspcode;
@@ -476,17 +546,9 @@ static void get_xfer_progress_first(GObe
 
 	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);
@@ -513,17 +575,12 @@ static void get_xfer_progress_first(GObe
 static gssize put_xfer_progress(void *buf, gsize len, gpointer user_data)
 {
 	struct obc_transfer *transfer = user_data;
-	struct transfer_callback *callback = transfer->callback;
 	gssize size;
 
 	size = read(transfer->fd, buf, len);
 	if (size <= 0)
 		return size;
 
-	if (callback)
-		callback->func(transfer, transfer->transferred, NULL,
-							callback->data);
-
 	transfer->transferred += size;
 
 	return size;
@@ -547,9 +604,33 @@ gboolean obc_transfer_set_callback(struc
 	return TRUE;
 }
 
+static gboolean report_progress(gpointer data)
+{
+	struct obc_transfer *transfer = data;
+
+	if (transfer->transferred == transfer->progress)
+		return TRUE;
+
+	transfer->progress = transfer->transferred;
+
+	if (transfer->transferred == transfer->size) {
+		transfer->progress_id = 0;
+		return FALSE;
+	}
+
+	obex_dbus_signal_property_changed(transfer->conn,
+						transfer->path,
+						TRANSFER_INTERFACE, "Progress",
+						DBUS_TYPE_INT64,
+						&transfer->progress);
+
+	return TRUE;
+}
+
 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,
@@ -567,23 +648,31 @@ static gboolean transfer_start_get(struc
 		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)
 		return FALSE;
 
+	if (transfer->path == NULL)
+		return TRUE;
+
+	transfer->progress_id = g_timeout_add_seconds(1, report_progress,
+								transfer);
+
 	return TRUE;
 }
 
 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,
@@ -604,10 +693,10 @@ static gboolean transfer_start_put(struc
 	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,
@@ -615,6 +704,12 @@ static gboolean transfer_start_put(struc
 	if (transfer->xfer == 0)
 		return FALSE;
 
+	if (transfer->path == NULL)
+		return TRUE;
+
+	transfer->progress_id = g_timeout_add_seconds(1, report_progress,
+								transfer);
+
 	return TRUE;
 }
 
@@ -639,31 +734,20 @@ guint8 obc_transfer_get_operation(struct
 	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,
@@ -701,29 +785,6 @@ int obc_transfer_get_contents(struct obc
 
 	return 0;
 }
-
-void obc_transfer_set_name(struct obc_transfer *transfer, const char *name)
-{
-	g_free(transfer->name);
-	transfer->name = g_strdup(name);
-}
-
-int obc_transfer_set_filename(struct obc_transfer *transfer,
-					const char *filename)
-{
-	int err;
-
-	err = rename(transfer->filename, filename);
-	if (err < 0) {
-		error("rename(): %s (%d)", strerror(errno), errno);
-		return -errno;
-	}
-
-	g_free(transfer->filename);
-	transfer->filename = g_strdup(filename);
-
-	return 0;
-}
 
 const char *obc_transfer_get_path(struct obc_transfer *transfer)
 {
diff -pruN 0.46-1/client/transfer.h 0.48-2.1/client/transfer.h
--- 0.46-1/client/transfer.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/client/transfer.h	2012-11-30 07:59:13.000000000 +0000
@@ -3,6 +3,7 @@
  *  OBEX Client
  *
  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -24,8 +25,7 @@
 struct obc_transfer;
 
 typedef void (*transfer_callback_t) (struct obc_transfer *transfer,
-					gint64 transferred, GError *err,
-					void *user_data);
+					GError *err, void *user_data);
 
 struct obc_transfer *obc_transfer_get(const char *type, const char *name,
 					const char *filename, GError **err);
@@ -36,7 +36,8 @@ struct obc_transfer *obc_transfer_put(co
 
 gboolean obc_transfer_register(struct obc_transfer *transfer,
 					DBusConnection *conn,
-					const char *agent,
+					const char *path,
+					const char *owner,
 					GError **err);
 
 void obc_transfer_unregister(struct obc_transfer *transfer);
@@ -49,15 +50,13 @@ gboolean obc_transfer_start(struct obc_t
 								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);
 
-void obc_transfer_set_name(struct obc_transfer *transfer, const char *name);
-int obc_transfer_set_filename(struct obc_transfer *transfer,
-					const char *filename);
 const char *obc_transfer_get_path(struct obc_transfer *transfer);
 gint64 obc_transfer_get_size(struct obc_transfer *transfer);
+
+DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer,
+							DBusMessage *message);
diff -pruN 0.46-1/compile 0.48-2.1/compile
--- 0.46-1/compile	2012-05-17 15:12:36.000000000 +0000
+++ 0.48-2.1/compile	2012-11-30 07:59:31.000000000 +0000
@@ -1,7 +1,7 @@
 #! /bin/sh
 # Wrapper for compilers which do not understand '-c -o'.
 
-scriptversion=2012-01-04.17; # UTC
+scriptversion=2012-03-05.13; # UTC
 
 # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free
 # Software Foundation, Inc.
@@ -79,6 +79,48 @@ func_file_conv ()
   esac
 }
 
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
 # func_cl_wrapper cl arg...
 # Adjust compile command to suit cl
 func_cl_wrapper ()
@@ -109,43 +151,34 @@ func_cl_wrapper ()
 	      ;;
 	  esac
 	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
 	-I*)
 	  func_file_conv "${1#-I}" mingw
 	  set x "$@" -I"$file"
 	  shift
 	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
 	-l*)
-	  lib=${1#-l}
-	  found=no
-	  save_IFS=$IFS
-	  IFS=';'
-	  for dir in $lib_path $LIB
-	  do
-	    IFS=$save_IFS
-	    if $shared && test -f "$dir/$lib.dll.lib"; then
-	      found=yes
-	      set x "$@" "$dir/$lib.dll.lib"
-	      break
-	    fi
-	    if test -f "$dir/$lib.lib"; then
-	      found=yes
-	      set x "$@" "$dir/$lib.lib"
-	      break
-	    fi
-	  done
-	  IFS=$save_IFS
-
-	  test "$found" != yes && set x "$@" "$lib.lib"
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
 	  shift
 	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
 	-L*)
-	  func_file_conv "${1#-L}"
-	  if test -z "$lib_path"; then
-	    lib_path=$file
-	  else
-	    lib_path="$lib_path;$file"
-	  fi
-	  linker_opts="$linker_opts -LIBPATH:$file"
+	  func_cl_dashL "${1#-L}"
 	  ;;
 	-static)
 	  shared=false
diff -pruN 0.46-1/config.sub 0.48-2.1/config.sub
--- 0.46-1/config.sub	2012-05-17 15:12:36.000000000 +0000
+++ 0.48-2.1/config.sub	2012-11-30 07:59:31.000000000 +0000
@@ -4,7 +4,7 @@
 #   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #   2011, 2012 Free Software Foundation, Inc.
 
-timestamp='2012-02-10'
+timestamp='2012-04-18'
 
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
@@ -225,6 +225,12 @@ case $os in
 	-isc*)
 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
 		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
 	-lynx*)
 		os=-lynxos
 		;;
@@ -1537,6 +1543,9 @@ case $basic_machine in
 	c4x-* | tic4x-*)
 		os=-coff
 		;;
+	hexagon-*)
+		os=-elf
+		;;
 	tic54x-*)
 		os=-coff
 		;;
diff -pruN 0.46-1/configure 0.48-2.1/configure
--- 0.46-1/configure	2012-05-17 15:12:38.000000000 +0000
+++ 0.48-2.1/configure	2012-11-30 07:59:33.000000000 +0000
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for obexd 0.46.
+# Generated by GNU Autoconf 2.69 for obexd 0.48.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='obexd'
 PACKAGE_TARNAME='obexd'
-PACKAGE_VERSION='0.46'
-PACKAGE_STRING='obexd 0.46'
+PACKAGE_VERSION='0.48'
+PACKAGE_STRING='obexd 0.48'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1372,7 +1372,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures obexd 0.46 to adapt to many kinds of systems.
+\`configure' configures obexd 0.48 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1442,7 +1442,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of obexd 0.46:";;
+     short | recursive ) echo "Configuration of obexd 0.48:";;
    esac
   cat <<\_ACEOF
 
@@ -1586,7 +1586,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-obexd configure 0.46
+obexd configure 0.48
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1951,7 +1951,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by obexd $as_me 0.46, which was
+It was created by obexd $as_me 0.48, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2767,7 +2767,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='obexd'
- VERSION='0.46'
+ VERSION='0.48'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -5748,10 +5748,6 @@ freebsd* | dragonfly*)
   fi
   ;;
 
-gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
 haiku*)
   lt_cv_deplibs_check_method=pass_all
   ;;
@@ -5790,7 +5786,7 @@ irix5* | irix6* | nonstopux*)
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
@@ -8415,7 +8411,7 @@ lt_prog_compiler_static=
       lt_prog_compiler_static='-non_shared'
       ;;
 
-    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
       case $cc_basename in
       # old Intel for x86_64 which still supported -KPIC.
       ecc*)
@@ -10585,17 +10581,6 @@ freebsd* | dragonfly*)
   esac
   ;;
 
-gnu*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
 haiku*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
@@ -10712,7 +10697,7 @@ linux*oldld* | linux*aout* | linux*coff*
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
@@ -12152,12 +12137,12 @@ if test -n "$BLUEZ_CFLAGS"; then
     pkg_cv_BLUEZ_CFLAGS="$BLUEZ_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.99\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "bluez >= 4.99") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.100\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "bluez >= 4.100") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_BLUEZ_CFLAGS=`$PKG_CONFIG --cflags "bluez >= 4.99" 2>/dev/null`
+  pkg_cv_BLUEZ_CFLAGS=`$PKG_CONFIG --cflags "bluez >= 4.100" 2>/dev/null`
 		      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -12169,12 +12154,12 @@ if test -n "$BLUEZ_LIBS"; then
     pkg_cv_BLUEZ_LIBS="$BLUEZ_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.99\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "bluez >= 4.99") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bluez >= 4.100\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "bluez >= 4.100") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_BLUEZ_LIBS=`$PKG_CONFIG --libs "bluez >= 4.99" 2>/dev/null`
+  pkg_cv_BLUEZ_LIBS=`$PKG_CONFIG --libs "bluez >= 4.100" 2>/dev/null`
 		      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -12195,18 +12180,18 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-	        BLUEZ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "bluez >= 4.99" 2>&1`
+	        BLUEZ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "bluez >= 4.100" 2>&1`
         else
-	        BLUEZ_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "bluez >= 4.99" 2>&1`
+	        BLUEZ_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "bluez >= 4.100" 2>&1`
         fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$BLUEZ_PKG_ERRORS" >&5
 
-	as_fn_error $? "BlueZ >= 4.99 is required" "$LINENO" 5
+	as_fn_error $? "BlueZ >= 4.100 is required" "$LINENO" 5
 elif test $pkg_failed = untried; then
      	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-	as_fn_error $? "BlueZ >= 4.99 is required" "$LINENO" 5
+	as_fn_error $? "BlueZ >= 4.100 is required" "$LINENO" 5
 else
 	BLUEZ_CFLAGS=$pkg_cv_BLUEZ_CFLAGS
 	BLUEZ_LIBS=$pkg_cv_BLUEZ_LIBS
@@ -13349,7 +13334,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_wri
 # 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.46, 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
@@ -13415,7 +13400,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-obexd config.status 0.46
+obexd config.status 0.48
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -pruN 0.46-1/configure.ac 0.48-2.1/configure.ac
--- 0.46-1/configure.ac	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/configure.ac	2012-11-30 07:59:13.000000000 +0000
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(obexd, 0.46)
+AC_INIT(obexd, 0.48)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
 AM_CONFIG_HEADER(config.h)
@@ -79,8 +79,8 @@ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4, d
 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)
 
diff -pruN 0.46-1/debian/changelog 0.48-2.1/debian/changelog
--- 0.46-1/debian/changelog	2012-05-31 23:40:25.000000000 +0000
+++ 0.48-2.1/debian/changelog	2014-10-15 22:01:30.000000000 +0000
@@ -1,7 +1,62 @@
+obexd (0.48-2.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Include patch test-avoid-double-source-removals.patch
+    from Ubuntu to avoid double source removals during tests.
+    (Closes: #746128)
+
+ -- Tobias Hansen <thansen@debian.org>  Wed, 15 Oct 2014 23:59:01 +0200
+
+obexd (0.48-2) unstable; urgency=low
+
+  * Update debian/rules.
+    - Fix FTBFS with evolution-data-server 3.8. (Closes: #722023)
+      Remove "--with-phonebook=ebook" from configure.
+
+ -- Nobuhiro Iwamatsu <iwamatsu@debian.org>  Fri, 20 Sep 2013 08:26:38 +0900
+
+obexd (0.48-1) unstable; urgency=low
+
+  * New upstream release.
+  * Fix FTBFS with eglibc-2.17. (Closes: #701434)
+  * Update debian/control.
+    - Dump version of libbluetooth-dev to 4.101.
+    - Dump Standard-Version to 3.9.4.
+    - Update Vcs-Svn and Vcs-Browser field.
+    - Remove Section field from obexd-client and obexd-server.
+    - Remove dpkg-dev from Build-Depends.
+    - Add autotools-dev to Build-Depends.
+  * Update debian/rules.
+    - Use autotools_dev addon. Fix lintian warning of
+      outdated-autotools-helper-file.
+
+ -- Nobuhiro Iwamatsu <iwamatsu@debian.org>  Tue, 23 Jul 2013 08:56:32 +0900
+
+obexd (0.47-2) experimental; urgency=low
+
+  * Update debian/control.
+    - Remove obex-data-server from Conflicts field. (Closes: #695013, #565318)
+      Version 0.47 changed the D-Bus namespace to use org.bluez.obex
+      instead of org.openobex.
+  * Update debian/rules.
+    - Add --disable-silent-rules to configure.
+
+ -- Nobuhiro Iwamatsu <iwamatsu@debian.org>  Thu, 10 Jan 2013 19:17:00 +0900
+
+obexd (0.47-1) experimental; urgency=low
+
+  * New upstream release.
+  * Update debian/obexd-client.examples.
+  * Remove patches/Remove_left_over_glib-helper.h_support.patch.
+    Applied to current release.
+
+ -- Nobuhiro Iwamatsu <iwamatsu@debian.org>  Sat, 28 Jul 2012 05:56:26 +0900
+
 obexd (0.46-1) unstable; urgency=low
 
   * New upstream release.
   * Change source format from 1.0 to 3.0 (quilt).
+  * Dump compat of debhelper.
   * Update debian/rules.
     Add support hardending option.
   * Fix build by glib-helper.h.
diff -pruN 0.46-1/debian/control 0.48-2.1/debian/control
--- 0.46-1/debian/control	2012-06-06 04:44:34.000000000 +0000
+++ 0.48-2.1/debian/control	2013-07-25 03:44:36.000000000 +0000
@@ -3,20 +3,20 @@ Section: admin
 Priority: optional
 Maintainer: Debian Bluetooth Maintainers <pkg-bluetooth-maintainers@lists.alioth.debian.org>
 Uploaders: Nobuhiro Iwamatsu <iwamatsu@debian.org>
-Build-Depends: debhelper (>= 8), dpkg-dev (>= 1.16.1~),
+Build-Depends: debhelper (>= 8),
+               autotools-dev,
                libglib2.0-dev,
                libdbus-1-dev,
                libopenobex1-dev,
-               libbluetooth-dev (>= 4.99),
+               libbluetooth-dev (>= 4.101),
                libebook1.2-dev,
                libical-dev
-Vcs-Svn: svn://svn.debian.org/svn/pkg-bluetooth/packages/obexd
-Vcs-Browser: http://svn.debian.org/wsvn/pkg-bluetooth/packages/obexd/
+Vcs-Svn: svn://anonscm.debian.org/svn/pkg-bluetooth/packages/obexd/trunk
+Vcs-Browser: http://anonscm.debian.org/viewvc/pkg-bluetooth/packages/obexd/trunk/
 Homepage: http://www.bluez.org
-Standards-Version: 3.9.3
+Standards-Version: 3.9.4
 
 Package: obexd-client
-Section: admin
 Depends: ${shlibs:Depends}, ${misc:Depends}
 Architecture: any
 Description: D-Bus OBEX client
@@ -29,9 +29,7 @@ Description: D-Bus OBEX client
  In this package the client is included.
 
 Package: obexd-server
-Section: admin
 Depends: ${shlibs:Depends}, ${misc:Depends}
-Conflicts: obex-data-server
 Architecture: any
 Description: D-Bus OBEX server
  Implementation of OBEX(OBject EXchange) client and server as a D-Bus service
diff -pruN 0.46-1/debian/obexd-client.examples 0.48-2.1/debian/obexd-client.examples
--- 0.46-1/debian/obexd-client.examples	2012-01-24 04:14:49.000000000 +0000
+++ 0.48-2.1/debian/obexd-client.examples	2013-07-25 03:44:36.000000000 +0000
@@ -2,6 +2,7 @@ test/exchange-business-cards
 test/ftp-client
 test/list-folders
 test/pbap-client
-test/pull-business-card
-test/send-files
+test/opp-client
+test/simple-agent
+test/map-client
 debian/README.examples
diff -pruN 0.46-1/debian/patches/fix_build_libc-2.17 0.48-2.1/debian/patches/fix_build_libc-2.17
--- 0.46-1/debian/patches/fix_build_libc-2.17	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/debian/patches/fix_build_libc-2.17	2013-07-25 03:44:36.000000000 +0000
@@ -0,0 +1,37 @@
+Description: Fix FTBFS with libc 2.17
+Origin: upstream
+Bug-Debian: http://bugs.debian.org/701434
+Forwarded: no. Because obexd will merge to bluez.
+Last-Update: 2013-06-04
+
+--- obexd-0.48.orig/src/mimetype.h
++++ obexd-0.48/src/mimetype.h
+@@ -20,6 +20,7 @@
+  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+  *
+  */
++#include <sys/types.h>
+ 
+ typedef gboolean (*obex_object_io_func) (void *object, int flags, int err,
+ 							void *user_data);
+--- obexd-0.48.orig/src/obex.h
++++ obexd-0.48/src/obex.h
+@@ -21,6 +21,7 @@
+  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+  *
+  */
++#include <sys/types.h>
+ 
+ #define OBJECT_SIZE_UNKNOWN -1
+ #define OBJECT_SIZE_DELETE -2
+--- obexd-0.48.orig/plugins/filesystem.h
++++ obexd-0.48/plugins/filesystem.h
+@@ -21,6 +21,8 @@
+  *
+  */
+ 
++#include <sys/types.h>
++
+ ssize_t string_read(void *object, void *buf, size_t count);
+ gboolean is_filename(const char *name);
+ int verify_path(const char *path);
diff -pruN 0.46-1/debian/patches/Remove_left_over_glib-helper.h_support.patch 0.48-2.1/debian/patches/Remove_left_over_glib-helper.h_support.patch
--- 0.46-1/debian/patches/Remove_left_over_glib-helper.h_support.patch	2012-05-31 23:39:03.000000000 +0000
+++ 0.48-2.1/debian/patches/Remove_left_over_glib-helper.h_support.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-Origin: http://git.kernel.org/?p=bluetooth/obexd.git;a=commit;h=1ae7e0cceccf301fef421f615e784e08efb581ee
-Bug: None
-Bug-Debian: None
-Bug-Ubuntu: None
-Forwarded: no
-Reviewed-By: No, this patch already applied in upstream.
-Last-Update: 2012/06/01
-
-From 1ae7e0cceccf301fef421f615e784e08efb581ee Mon Sep 17 00:00:00 2001
-From: Paul Seidler <pl.seidler@googlemail.com>
-Date: Mon, 21 May 2012 16:59:27 +0200
-Subject: [PATCH] Remove left over glib-helper.h support
-
----
- plugins/phonebook-ebook.c   |    1 -
- plugins/phonebook-tracker.c |    1 -
- 2 files changed, 0 insertions(+), 2 deletions(-)
-
-diff --git a/plugins/phonebook-ebook.c b/plugins/phonebook-ebook.c
-index c2e8649..a1f06b5 100644
---- a/plugins/phonebook-ebook.c
-+++ b/plugins/phonebook-ebook.c
-@@ -37,7 +37,6 @@
- #include "obex.h"
- #include "service.h"
- #include "phonebook.h"
--#include "glib-helper.h"
- 
- #define QUERY_FN "(contains \"family_name\" \"%s\")"
- #define QUERY_NAME "(contains \"given_name\" \"%s\")"
-diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
-index da82ff5..96635c4 100644
---- a/plugins/phonebook-tracker.c
-+++ b/plugins/phonebook-tracker.c
-@@ -35,7 +35,6 @@
- #include "mimetype.h"
- #include "phonebook.h"
- #include "vcard.h"
--#include "glib-helper.h"
- 
- #define TRACKER_SERVICE "org.freedesktop.Tracker1"
- #define TRACKER_RESOURCES_PATH "/org/freedesktop/Tracker1/Resources"
--- 
-1.7.6.5
diff -pruN 0.46-1/debian/patches/series 0.48-2.1/debian/patches/series
--- 0.46-1/debian/patches/series	2012-05-31 22:58:21.000000000 +0000
+++ 0.48-2.1/debian/patches/series	2014-10-15 21:58:14.000000000 +0000
@@ -1 +1,2 @@
-Remove_left_over_glib-helper.h_support.patch
+fix_build_libc-2.17
+test-avoid-double-source-removals.patch
diff -pruN 0.46-1/debian/patches/test-avoid-double-source-removals.patch 0.48-2.1/debian/patches/test-avoid-double-source-removals.patch
--- 0.46-1/debian/patches/test-avoid-double-source-removals.patch	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/debian/patches/test-avoid-double-source-removals.patch	2014-10-15 21:58:14.000000000 +0000
@@ -0,0 +1,132 @@
+From 8464a28d7b9d6612c29bd5d5bf8e3f3bdb5f13a6 Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@ubuntu.com>
+Date: Mon, 6 Jan 2014 12:04:14 +0000
+Subject: [PATCH] unit: Fix test failures with glib 2.39.0
+
+glib 2.39.0 made this change:
+
+   - g_source_remove() will now throw a critical in the case that you
+     try to remove a non-existent source.  We expect that there is some
+     code in the wild that will fall afoul of this new critical but
+     considering that we now reuse source IDs, this code is already
+     broken and should probably be fixed.
+
+This patch fixes the test suite to keep better track of whether sources have
+already been removed and avoid double-removals.
+
+Forwarded: http://marc.info/?l=linux-bluetooth&m=138901175212889&w=2
+Last-Update: 2014-01-06
+
+Index: b/unit/test-gobex-transfer.c
+===================================================================
+--- a/unit/test-gobex-transfer.c
++++ b/unit/test-gobex-transfer.c
+@@ -1800,7 +1800,8 @@
+ 
+ 	g_source_remove(timer_id);
+ 	g_io_channel_unref(io);
+-	g_source_remove(io_id);
++	if (!d.io_completed)
++		g_source_remove(io_id);
+ 	g_obex_unref(obex);
+ 
+ 	g_assert_no_error(d.err);
+@@ -2055,7 +2056,8 @@
+ 
+ 	g_source_remove(timer_id);
+ 	g_io_channel_unref(io);
+-	g_source_remove(io_id);
++	if (!d.io_completed)
++		g_source_remove(io_id);
+ 	g_obex_unref(obex);
+ 
+ 	g_assert_no_error(d.err);
+Index: b/unit/test-gobex.c
+===================================================================
+--- a/unit/test-gobex.c
++++ b/unit/test-gobex.c
+@@ -230,7 +230,7 @@
+ 	GError *gerr = NULL;
+ 	GIOChannel *io;
+ 	GIOCondition cond;
+-	guint io_id, timer_id, test_time;
++	guint timer_id, test_time;
+ 	GObex *obex;
+ 
+ 	create_endpoints(&obex, &io, transport_type);
+@@ -239,7 +239,7 @@
+ 	g_assert_no_error(gerr);
+ 
+ 	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+-	io_id = g_io_add_watch(io, cond, send_rsp_func, &gerr);
++	g_io_add_watch(io, cond, send_rsp_func, &gerr);
+ 
+ 	mainloop = g_main_loop_new(NULL, FALSE);
+ 
+@@ -257,7 +257,6 @@
+ 
+ 	g_source_remove(timer_id);
+ 	g_io_channel_unref(io);
+-	g_source_remove(io_id);
+ 	g_obex_unref(obex);
+ 
+ 	g_assert_no_error(gerr);
+@@ -461,6 +460,7 @@
+ 	GError *err;
+ 	const guint8 *buf;
+ 	gsize len;
++	gboolean completed;
+ };
+ 
+ static gboolean rcv_data(GIOChannel *io, GIOCondition cond, gpointer user_data)
+@@ -500,6 +500,7 @@
+ 
+ done:
+ 	g_main_loop_quit(mainloop);
++	r->completed = TRUE;
+ 	return FALSE;
+ }
+ 
+@@ -541,7 +542,8 @@
+ 
+ 	g_source_remove(timer_id);
+ 	g_io_channel_unref(io);
+-	g_source_remove(io_id);
++	if (!r.completed)
++		g_source_remove(io_id);
+ 	g_obex_unref(obex);
+ 
+ 	g_assert_no_error(r.err);
+@@ -656,7 +658,8 @@
+ 
+ 	g_source_remove(timer_id);
+ 	g_io_channel_unref(io);
+-	g_source_remove(io_id);
++	if (!r.completed)
++		g_source_remove(io_id);
+ 	g_obex_unref(obex);
+ 
+ 	g_assert_no_error(r.err);
+Index: b/unit/util.c
+===================================================================
+--- a/unit/util.c
++++ b/unit/util.c
+@@ -189,5 +189,6 @@
+ 
+ failed:
+ 	g_main_loop_quit(d->mainloop);
++	d->io_completed = TRUE;
+ 	return FALSE;
+ }
+Index: b/unit/util.h
+===================================================================
+--- a/unit/util.h
++++ b/unit/util.h
+@@ -41,6 +41,7 @@
+ 	guint id;
+ 	gsize total;
+ 	GMainLoop *mainloop;
++	gboolean io_completed;
+ };
+ 
+ #define TEST_ERROR test_error_quark()
diff -pruN 0.46-1/debian/rules 0.48-2.1/debian/rules
--- 0.46-1/debian/rules	2012-06-06 04:54:28.000000000 +0000
+++ 0.48-2.1/debian/rules	2013-09-19 23:25:17.000000000 +0000
@@ -4,9 +4,11 @@ DPKG_EXPORT_BUILDFLAGS = 1
 include /usr/share/dpkg/buildflags.mk
 
 %:
-	dh $@
+	dh $@ --with autotools_dev
 
 override_dh_auto_configure:
+	dh_autotools-dev_updateconfig
+
 	dh_auto_configure -- --enable-usb \
 			--enable-pcsuite \
-			--with-phonebook=ebook
+			--disable-silent-rules
diff -pruN 0.46-1/depcomp 0.48-2.1/depcomp
--- 0.46-1/depcomp	2012-05-17 15:12:37.000000000 +0000
+++ 0.48-2.1/depcomp	2012-11-30 07:59:32.000000000 +0000
@@ -1,10 +1,10 @@
 #! /bin/sh
 # depcomp - compile a program generating dependencies as side-effects
 
-scriptversion=2011-12-04.11; # UTC
+scriptversion=2012-03-27.16; # UTC
 
 # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
-# 2011 Free Software Foundation, Inc.
+# 2011, 2012 Free Software Foundation, Inc.
 
 # 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
@@ -28,7 +28,7 @@ scriptversion=2011-12-04.11; # UTC
 
 case $1 in
   '')
-     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
      exit 1;
      ;;
   -h | --h*)
@@ -40,8 +40,8 @@ as side-effects.
 
 Environment variables:
   depmode     Dependency tracking mode.
-  source      Source file read by `PROGRAMS ARGS'.
-  object      Object file output by `PROGRAMS ARGS'.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
   DEPDIR      directory where to store dependencies.
   depfile     Dependency file to output.
   tmpdepfile  Temporary file to use when outputting dependencies.
@@ -57,6 +57,12 @@ EOF
     ;;
 esac
 
+# A tabulation character.
+tab='	'
+# A newline character.
+nl='
+'
+
 if test -z "$depmode" || test -z "$source" || test -z "$object"; then
   echo "depcomp: Variables source, object and depmode must be set" 1>&2
   exit 1
@@ -102,6 +108,12 @@ if test "$depmode" = msvc7msys; then
    depmode=msvc7
 fi
 
+if test "$depmode" = xlc; then
+   # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
+   gccflag=-qmakedep=gcc,-MF
+   depmode=gcc
+fi
+
 case "$depmode" in
 gcc3)
 ## gcc 3 implements dependency tracking that does exactly what
@@ -156,15 +168,14 @@ gcc)
 ## The second -e expression handles DOS-style file names with drive letters.
   sed -e 's/^[^:]*: / /' \
       -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
-## This next piece of magic avoids the `deleted header file' problem.
+## This next piece of magic avoids the "deleted header file" problem.
 ## The problem is that when a header file which appears in a .P file
 ## is deleted, the dependency causes make to die (because there is
 ## typically no way to rebuild the header).  We avoid this by adding
 ## dummy dependencies for each header file.  Too bad gcc doesn't do
 ## this for us directly.
-  tr ' ' '
-' < "$tmpdepfile" |
-## Some versions of gcc put a space before the `:'.  On the theory
+  tr ' ' "$nl" < "$tmpdepfile" |
+## Some versions of gcc put a space before the ':'.  On the theory
 ## that the space means something, we add a space to the output as
 ## well.  hp depmode also adds that space, but also prefixes the VPATH
 ## to the object.  Take care to not repeat it in the output.
@@ -203,18 +214,15 @@ sgi)
     # clever and replace this with sed code, as IRIX sed won't handle
     # lines with more than a fixed number of characters (4096 in
     # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
-    # the IRIX cc adds comments like `#:fec' to the end of the
+    # the IRIX cc adds comments like '#:fec' to the end of the
     # dependency line.
-    tr ' ' '
-' < "$tmpdepfile" \
+    tr ' ' "$nl" < "$tmpdepfile" \
     | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
-    tr '
-' ' ' >> "$depfile"
+    tr "$nl" ' ' >> "$depfile"
     echo >> "$depfile"
 
     # The second pass generates a dummy entry for each header file.
-    tr ' ' '
-' < "$tmpdepfile" \
+    tr ' ' "$nl" < "$tmpdepfile" \
    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
    >> "$depfile"
   else
@@ -226,10 +234,17 @@ sgi)
   rm -f "$tmpdepfile"
   ;;
 
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
 aix)
   # The C for AIX Compiler uses -M and outputs the dependencies
   # in a .u file.  In older versions, this file always lives in the
-  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
   # start of each line; $object doesn't have directory information.
   # Version 6 uses the directory in both cases.
   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
@@ -259,12 +274,11 @@ aix)
     test -f "$tmpdepfile" && break
   done
   if test -f "$tmpdepfile"; then
-    # Each line is of the form `foo.o: dependent.h'.
+    # Each line is of the form 'foo.o: dependent.h'.
     # Do two passes, one to just change these to
-    # `$object: dependent.h' and one to simply `dependent.h:'.
+    # '$object: dependent.h' and one to simply 'dependent.h:'.
     sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
-    # That's a tab and a space in the [].
-    sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+    sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
   else
     # The sourcefile does not contain any dependencies, so just
     # store a dummy comment line, to avoid errors with the Makefile
@@ -275,23 +289,26 @@ aix)
   ;;
 
 icc)
-  # Intel's C compiler understands `-MD -MF file'.  However on
-  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
+  # However on
+  #    $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
   # ICC 7.0 will fill foo.d with something like
   #    foo.o: sub/foo.c
   #    foo.o: sub/foo.h
-  # which is wrong.  We want:
+  # which is wrong.  We want
   #    sub/foo.o: sub/foo.c
   #    sub/foo.o: sub/foo.h
   #    sub/foo.c:
   #    sub/foo.h:
   # ICC 7.1 will output
   #    foo.o: sub/foo.c sub/foo.h
-  # and will wrap long lines using \ :
+  # and will wrap long lines using '\':
   #    foo.o: sub/foo.c ... \
   #     sub/foo.h ... \
   #     ...
-
+  # tcc 0.9.26 (FIXME still under development at the moment of writing)
+  # will emit a similar output, but also prepend the continuation lines
+  # with horizontal tabulation characters.
   "$@" -MD -MF "$tmpdepfile"
   stat=$?
   if test $stat -eq 0; then :
@@ -300,15 +317,21 @@ icc)
     exit $stat
   fi
   rm -f "$depfile"
-  # Each line is of the form `foo.o: dependent.h',
-  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Each line is of the form 'foo.o: dependent.h',
+  # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
   # Do two passes, one to just change these to
-  # `$object: dependent.h' and one to simply `dependent.h:'.
-  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
-  # Some versions of the HPUX 10.20 sed can't process this invocation
-  # correctly.  Breaking it into two sed invocations is a workaround.
-  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
-    sed -e 's/$/ :/' >> "$depfile"
+  # '$object: dependent.h' and one to simply 'dependent.h:'.
+  sed -e "s/^[ $tab][ $tab]*/  /" -e "s,^[^:]*:,$object :," \
+    < "$tmpdepfile" > "$depfile"
+  sed '
+    s/[ '"$tab"'][ '"$tab"']*/ /g
+    s/^ *//
+    s/ *\\*$//
+    s/^[^:]*: *//
+    /^$/d
+    /:$/d
+    s/$/ :/
+  ' < "$tmpdepfile" >> "$depfile"
   rm -f "$tmpdepfile"
   ;;
 
@@ -344,7 +367,7 @@ hp2)
   done
   if test -f "$tmpdepfile"; then
     sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
-    # Add `dependent.h:' lines.
+    # Add 'dependent.h:' lines.
     sed -ne '2,${
 	       s/^ *//
 	       s/ \\*$//
@@ -359,9 +382,9 @@ hp2)
 
 tru64)
    # The Tru64 compiler uses -MD to generate dependencies as a side
-   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
    # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
-   # dependencies in `foo.d' instead, so we check for that too.
+   # dependencies in 'foo.d' instead, so we check for that too.
    # Subdirectories are respected.
    dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
    test "x$dir" = "x$object" && dir=
@@ -407,8 +430,7 @@ tru64)
    done
    if test -f "$tmpdepfile"; then
       sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
-      # That's a tab and a space in the [].
-      sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+      sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
    else
       echo "#dummy" > "$depfile"
    fi
@@ -443,11 +465,11 @@ msvc7)
   p
 }' | $cygpath_u | sort -u | sed -n '
 s/ /\\ /g
-s/\(.*\)/	\1 \\/p
+s/\(.*\)/'"$tab"'\1 \\/p
 s/.\(.*\) \\/\1:/
 H
 $ {
-  s/.*/	/
+  s/.*/'"$tab"'/
   G
   p
 }' >> "$depfile"
@@ -478,7 +500,7 @@ dashmstdout)
     shift
   fi
 
-  # Remove `-o $object'.
+  # Remove '-o $object'.
   IFS=" "
   for arg
   do
@@ -498,15 +520,14 @@ dashmstdout)
   done
 
   test -z "$dashmflag" && dashmflag=-M
-  # Require at least two characters before searching for `:'
+  # Require at least two characters before searching for ':'
   # in the target name.  This is to cope with DOS-style filenames:
-  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
   "$@" $dashmflag |
-    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+    sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
   rm -f "$depfile"
   cat < "$tmpdepfile" > "$depfile"
-  tr ' ' '
-' < "$tmpdepfile" | \
+  tr ' ' "$nl" < "$tmpdepfile" | \
 ## Some versions of the HPUX 10.20 sed can't process this invocation
 ## correctly.  Breaking it into two sed invocations is a workaround.
     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@@ -562,8 +583,7 @@ makedepend)
   # makedepend may prepend the VPATH from the source file name to the object.
   # No need to regex-escape $object, excess matching of '.' is harmless.
   sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
-  sed '1,2d' "$tmpdepfile" | tr ' ' '
-' | \
+  sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
 ## Some versions of the HPUX 10.20 sed can't process this invocation
 ## correctly.  Breaking it into two sed invocations is a workaround.
     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@@ -583,7 +603,7 @@ cpp)
     shift
   fi
 
-  # Remove `-o $object'.
+  # Remove '-o $object'.
   IFS=" "
   for arg
   do
@@ -652,8 +672,8 @@ msvisualcpp)
   sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
   rm -f "$depfile"
   echo "$object : \\" > "$depfile"
-  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::	\1 \\:p' >> "$depfile"
-  echo "	" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
   sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
   rm -f "$tmpdepfile"
   ;;
diff -pruN 0.46-1/doc/agent-api.txt 0.48-2.1/doc/agent-api.txt
--- 0.46-1/doc/agent-api.txt	2010-04-23 15:52:33.000000000 +0000
+++ 0.48-2.1/doc/agent-api.txt	2012-07-26 17:09:25.000000000 +0000
@@ -9,7 +9,7 @@ Agent hierarchy
 ===============
 
 Service		unique name
-Interface	org.openobex.Agent
+Interface	org.bluez.obex.Agent
 Object path	freely definable
 
 Methods
@@ -21,8 +21,8 @@ Methods
 			Returns the full path (including the filename) where
 			the object shall be stored.
 
-			Possible errors: org.openobex.Error.Rejected
-			                 org.openobex.Error.Canceled
+			Possible errors: org.bluez.obex.Error.Rejected
+			                 org.bluez.obex.Error.Canceled
 
 		void Cancel()
 
diff -pruN 0.46-1/doc/client-api.txt 0.48-2.1/doc/client-api.txt
--- 0.46-1/doc/client-api.txt	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/doc/client-api.txt	2012-11-30 07:59:13.000000000 +0000
@@ -2,85 +2,116 @@ OBEX client API description
 ***************************
 
 Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+Copyright (C) 2011-2012  BMW Car IT GmbH. All rights reserved.
 
 
 Client hierarchy
 ================
 
-Service		org.openobex.client
-Interface	org.openobex.Client
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.Client
 Object path	/
 
-Methods		void SendFiles(dict device, array{string} files, object agent)
+Methods		object CreateSession(string destination, dict args)
 
-			Send one or multiple local files to the specified
-			device. The device is configured via properties. At
-			least the Destination property should be specified.
+			Create a new OBEX session for the given remote address.
 
-		void PullBusinessCard(dict device, string file)
+			The last parameter is a dictionary to hold optional or
+			type-specific parameters. Typical parameters that can
+			be set in this dictionary include the following:
 
-			Request the business card from a remote device and
-			store it in the local file.
-
-		void ExchangeBusinessCards(dict device, string clientfile,
-								string file)
-
-			Push the client's business card to the remote device
-			and then retrieve the remote business card and store
-			it in a local file.
+				string "Target" : type of session to be created
+				string "Source" : local address to be used
+				byte "Channel"
 
-		object CreateSession(dict device)
+			The currently supported targets are the following:
 
-			Create a new OBEX session. The device is configured
-			via properties like in SendFiles.
+				"FTP"
+				"MAP"
+				"OPP"
+				"PBAP"
+				"SYNC"
 
 		void RemoveSession(object session)
 
 			Unregister session and abort pending transfers.
 
-		string GetCapabilities(dict device)
+Session hierarchy
+=================
 
-			Get remote device capabilities.
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.Session
+Object path	[variable prefix]/{session0,session1,...}
 
-Properties	string Target
+Methods		dict GetProperties()
 
-		string Source
+			Returns all properties for the session.
 
-		string Destination
+		string GetCapabilities()
 
-		byte Channel
+			Get remote device capabilities.
 
-Session hierarchy
-=================
+Properties	string Source [readonly]
+
+		string Destination [readonly]
 
-Service		org.openobex.client
-Interface	org.openobex.Session
+		byte Channel [readonly]
+
+Object Push hierarchy
+=====================
+
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.ObjectPush
 Object path	[variable prefix]/{session0,session1,...}
 
-Methods		dict GetProperties()
+Methods		object, dict SendFile(string sourcefile)
 
-			Returns all properties for the session.
+			Send one local file to the remote device.
 
-		void AssignAgent(object agent)
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
 
-			Assign an OBEX agent to this session. This allows
-			detailed progress reports about the transactions.
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
 
-		void ReleaseAgent(object agent)
+		object, dict PullBusinessCard(string targetfile)
 
-			Release a previously assigned OBEX agent.
+			Request the business card from a remote device and
+			store it in the local file.
 
-Properties	string Source [readonly]
+			If an empty target file is given, a name will be
+			automatically calculated for the temporary file.
 
-		string Destination [readonly]
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
 
-		byte Channel [readonly]
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
+
+		object, dict ExchangeBusinessCards(string clientfile,
+							string targetfile)
+
+			Push the client's business card to the remote device
+			and then retrieve the remote business card and store
+			it in a local file.
+
+			If an empty target file is given, a name will be
+			automatically calculated for the temporary file.
+
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
 
 File Transfer hierarchy
 =======================
 
-Service		org.openobex.client
-Interface	org.openobex.FileTransfer
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.FileTransfer
 Object path	[variable prefix]/{session0,session1,...}
 
 Methods		void ChangeFolder(string folder)
@@ -108,21 +139,32 @@ Methods		void ChangeFolder(string folder
 				uint64 Accessed : Last access
 				uint64 Created : Creation date
 
-		void GetFile(string targetfile, string sourcefile)
+		object, dict GetFile(string targetfile, string sourcefile)
 
 			Copy the source file (from remote device) to the
 			target file (on local filesystem).
 
-			A new Transfer object is created to represent this
-			transaction.
+			If an empty target file is given, a name will be
+			automatically calculated for the temporary file.
 
-		void PutFile(string sourcefile, string targetfile)
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
+
+		object, dict PutFile(string sourcefile, string targetfile)
 
 			Copy the source file (from local filesystem) to the
 			target file (on remote device).
 
-			A new Transfer object is created to represent this
-			transaction.
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
 
 		void CopyFile(string sourcefile, string targetfile)
 
@@ -141,8 +183,8 @@ Methods		void ChangeFolder(string folder
 Phonebook Access hierarchy
 =======================
 
-Service		org.openobex.client
-Interface	org.openobex.PhonebookAccess
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.PhonebookAccess
 Object path	[variable prefix]/{session0,session1,...}
 
 Methods		void Select(string location, string phonebook)
@@ -164,78 +206,115 @@ Methods		void Select(string location, st
 				"mch":	missing call history
 				"cch":	combination of ich och mch
 
-		string PullAll()
+		object, dict PullAll(string targetfile, dict filters)
 
 			Return the entire phonebook object from the PSE server
-			in plain string with vcard format.
+			in plain string with vcard format, and store it in
+			a local file.
+
+			If an empty target file is given, a name will be
+			automatically calculated for the temporary file.
+
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
+
+			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"
+
+			Possible filters: Order, Offset and MaxCount
+
+
+		object, dict
+		Pull(string vcard, string targetfile, dict filters)
 
-		array{string vcard, string name} List()
+			Given a vcard handle, retrieve the vcard in the current
+			phonebook object and store it in a local file.
 
-			Return an array of vcard-listing data which contains the
-			vcard : name paired string, for example "1.vcf" :
-				"John".
+			If an empty target file is given, a name will be
+			automatically calculated for the temporary file.
 
-		string Pull(string vcard)
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
+
+			Possbile filters: Format and Fields
 
-			Retrieve the vcard in the current phonebook object
-			for example : Pull("0.vcf")
 
 		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
+			consists of a pair of strings containing the vcard
+			handle and the contact name.
 
-			Return an array of vcard-listing data which contains the
 			vcard : name paired string match the search condition.
 
 			field : the field in the vcard to search with
 				{ "name" (default) | "number" | "sound" }
 			value : the string value to search for
 
+
+			Possible filters: Order, Offset and MaxCount
+
 		uint16 GetSize()
 
-			Return the number of the non-null entries in the
-			selected phonebook object.
+			Return the number of entries in the selected phonebook
+			object that are actually used (i.e. indexes that
+			correspond to non-NULL entries).
+
+		array{string} ListFilterFields()
 
-		void SetFormat(string format)
+			Return All Available fields that can be used in Fields
+			filter.
 
-			Indicate the format of the vcard that should be return
-			by related methods.
+Filter:		string Format:
 
-			format : { "vcard21" (default) | "vcard30" }
+			Items vcard format
 
-		void SetOrder(string order)
+			Possible values: "vcard21" (default) or "vcard30"
 
-			Indicate the sorting method of the vcard-listing data
-			returned by List and Search methods.
+		string Order:
 
-			order : { "indexed" (default) | "alphanumeric" |
-					"phonetic" }
+			Items order
 
-		void SetFilter(array{string})
+			Possible values: "indexed" (default), "alphanumeric" or
+			"phonetic"
 
-			Indicate fields that should be contained in vcards
-			return by related methods.
+		uint16 Offset:
 
-			Give an empty array will clear the filter and return
-			all fields available in vcards. And this is the default
-			behavior.
+			Offset of the first item, default is 0
 
-			Possible filter fields : "VERSION", "FN", ..., "ALL",
-			"bit[0-63]"
+		uint16 MaxCount:
 
-		array{string} ListFilterFields()
+			Maximum number of items, default is unlimited (65535)
+
+		array{string} Fields:
 
-			Return All Available fields that can be used in
-			SefFilter 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
 =======================
 
-Service		org.openobex.client
-Interface	org.openobex.Synchronization
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.Synchronization
 Object path	[variable prefix]/{session0,session1,...}
 
 Methods		void SetLocation(string location)
@@ -251,20 +330,37 @@ Methods		void SetLocation(string locatio
 				"SIM2"
 				......
 
-		string GetPhonebook()
+		object, dict GetPhonebook(string targetfile)
 
 			Retrieve an entire Phonebook Object store from remote
-			device
+			device, and stores it in a local file.
+
+			If an empty target file is given, a name will be
+			automatically calculated for the temporary file.
+
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
 
-		void PutPhonebook(string obj)
+		object, dict PutPhonebook(string sourcefile)
 
-			Send an entire Phonebook Object store to remote device
+			Send an entire Phonebook Object store to remote device.
+
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			The properties of this transfer are also returned along
+			with the object path, to avoid a call to GetProperties.
 
 Message Access hierarchy
 =========================
 
-Service		org.openobex.client
-Interface	org.openobex.MessageAccess
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.MessageAccess
 Object path	[variable prefix]/{session0,session1,...}
 
 Methods		void SetFolder(string name)
@@ -272,12 +368,262 @@ Methods		void SetFolder(string name)
 			Set working directory for current session, *name* may
 			be the directory name or '..[/dir]'.
 
+		array{dict} ListFolders(dict filter)
+
+			Returns a dictionary containing information about
+			the current folder content.
+
+			The following keys are defined:
+
+				string Name : Folder name
+
+			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.
+
+			Properties:
+
+				string Subject:
+
+					Message subject
+
+				string Timestamp:
+
+					Message timestamp
+
+				string Sender:
+
+					Message sender name
+
+				string SenderAddress:
+
+					Message sender address
+
+				string ReplyTo:
+
+					Message Reply-To address
+
+				string Recipient:
+
+					Message recipient name
+
+				string RecipientAddress:
+
+					Message recipient address
+
+				string Type:
+
+					Message type
+
+					Possible values: "EMAIL", "SMS_GSM",
+					"SMS_CDMA" and "MMS"
+
+				uint64 Size:
+
+					Message size in bytes
+
+				string Status:
+
+					Message reception status
+
+					Possible values: "complete",
+					"fractioned" and "notification"
+
+				boolean Priority:
+
+					Message priority flag
+
+				boolean Read:
+
+					Message read flag
+
+				boolean Sent:
+
+					Message sent flag
+
+				boolean Protected:
+
+					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
+=================
+
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.Message
+Object path	[variable prefix]/{session0,session1,...}/{message0,...}
+
+Methods		object, dict Get(string targetfile, boolean attachment)
+
+			Download message and store it in the target file.
+
+			If an empty target file is given, a temporary file
+			will be automatically generated.
+
+			The returned path represents the newly created transfer,
+			which should be used to find out if the content has been
+			successfully transferred or if the operation fails.
+
+			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.openobex.client
-Interface	org.openobex.Transfer
-Object path	[variable prefix]/{transfer0,transfer1,...}
+Service		org.bluez.obex.client
+Interface	org.bluez.obex.Transfer
+Object path	[variable prefix]/{session0,session1,...}/{transfer0,...}
 
 Methods		dict GetProperties()
 
@@ -297,49 +643,25 @@ Properties	string Name [readonly]
 			Size of the transferred object. If the size is
 			unknown, then this property will not be present.
 
-		string Filename [readonly]
+		string Filename [readonly, optional]
 
 			Complete name of the file being received or sent.
 
-Agent hierarchy
-===============
-
-Service		unique name
-Interface	org.openobex.Agent
-Object path	freely definable
-
-Methods		void Release()
-
-			This method gets called when the service daemon
-			unregisters the agent. An agent can use it to do
-			cleanup tasks. There is no need to unregister the
-			agent, because when this method gets called it has
-			already been unregistered.
-
-		string Request(object transfer)
-
-			Accept or reject a new transfer (client and server)
-			and provide the filename for it.
-
-			In case of incoming transfers it is the filename
-			where to store the file and for outgoing transfers
-			it is the filename to show the remote device. If left
-			empty it will be calculated automatically.
+		uint64 Progress [readonly, optional]
 
-			Possible errors: org.openobex.Error.Rejected
-					 org.openobex.Error.Canceled
+			Number of bytes transferred. For queued transfers, this
+			value will not be present.
 
-		void Progress(object transfer, uint64 transferred)
+Signals		PropertyChanged(string name, variant value)
 
-			Progress within the transfer has been made. The
-			number of transferred bytes is given as second
-			argument for convenience.
+			This signal indicates a changed value of the given
+			property.
 
-		void Complete(object transfer)
+		void Complete()
 
 			Informs that the transfer has completed successfully.
 
-		void Error(object transfer, string message)
+		void Error(string code, string message)
 
 			Informs that the transfer has been terminated because
 			of some error.
diff -pruN 0.46-1/doc/obexd-api.txt 0.48-2.1/doc/obexd-api.txt
--- 0.46-1/doc/obexd-api.txt	2010-04-23 15:52:33.000000000 +0000
+++ 0.48-2.1/doc/obexd-api.txt	2012-07-26 17:09:25.000000000 +0000
@@ -8,8 +8,8 @@ Copyright (C) 2007-2010  Marcel Holtmann
 Manager hierarchy
 ===============
 
-Service		org.openobex
-Interface	org.openobex.Manager
+Service		org.bluez.obex
+Interface	org.bluez.obex.Manager
 Object path	/
 
 Methods
@@ -19,7 +19,7 @@ Methods
 			the user to accept/reject objects. Object push
 			service needs to authorize each received object.
 
-			Possible errors: org.openobex.Error.AlreadyExists
+			Possible errors: org.bluez.obex.Error.AlreadyExists
 
 		void UnregisterAgent(object agent)
 
@@ -27,7 +27,7 @@ Methods
 			registered. The object path parameter must match the
 			same value that has been used on registration.
 
-			Possible errors: org.openobex.Error.DoesNotExist
+			Possible errors: org.bluez.obex.Error.DoesNotExist
 
 Signals		SessionCreated(object session)
 			
@@ -54,8 +54,8 @@ Signals		SessionCreated(object session)
 Transfer hierarchy
 ===============
 
-Service		org.openobex
-Interface	org.openobex.Transfer
+Service		org.bluez.obex
+Interface	org.bluez.obex.Transfer
 Object path	/transfer{0, 1, 2, ...}
 
 Methods
@@ -70,8 +70,8 @@ Signals
 Session hierarchy
 ===============
 
-Service		org.openobex
-Interface	org.openobex.Session
+Service		org.bluez.obex
+Interface	org.bluez.obex.Session
 Object path	/session{0, 1, 2, ...}
 
 Methods
diff -pruN 0.46-1/gdbus/gdbus.h 0.48-2.1/gdbus/gdbus.h
--- 0.46-1/gdbus/gdbus.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gdbus/gdbus.h	2012-11-30 07:59:13.000000000 +0000
@@ -31,6 +31,17 @@ extern "C" {
 #include <dbus/dbus.h>
 #include <glib.h>
 
+typedef enum GDBusMethodFlags GDBusMethodFlags;
+typedef enum GDBusSignalFlags GDBusSignalFlags;
+typedef enum GDBusPropertyFlags GDBusPropertyFlags;
+typedef enum GDBusSecurityFlags GDBusSecurityFlags;
+
+typedef struct GDBusArgInfo GDBusArgInfo;
+typedef struct GDBusMethodTable GDBusMethodTable;
+typedef struct GDBusSignalTable GDBusSignalTable;
+typedef struct GDBusPropertyTable GDBusPropertyTable;
+typedef struct GDBusSecurityTable GDBusSecurityTable;
+
 typedef void (* GDBusWatchFunction) (DBusConnection *connection,
 							void *user_data);
 
@@ -55,6 +66,18 @@ typedef void (* GDBusDestroyFunction) (v
 typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
 					DBusMessage *message, void *user_data);
 
+typedef gboolean (*GDBusPropertyGetter)(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *data);
+
+typedef guint32 GDBusPendingPropertySet;
+
+typedef void (*GDBusPropertySetter)(const GDBusPropertyTable *property,
+			DBusMessageIter *value, GDBusPendingPropertySet id,
+			void *data);
+
+typedef gboolean (*GDBusPropertyExists)(const GDBusPropertyTable *property,
+								void *data);
+
 typedef guint32 GDBusPendingReply;
 
 typedef void (* GDBusSecurityFunction) (DBusConnection *connection,
@@ -62,53 +85,106 @@ typedef void (* GDBusSecurityFunction) (
 						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;
-	const char *reply;
+};
+
+struct GDBusMethodTable {
+	const char *name;
 	GDBusMethodFunction function;
 	GDBusMethodFlags flags;
 	unsigned int privilege;
-} GDBusMethodTable;
+	const GDBusArgInfo *in_args;
+	const GDBusArgInfo *out_args;
+};
 
-typedef struct {
+struct GDBusSignalTable {
 	const char *name;
-	const char *signature;
 	GDBusSignalFlags flags;
-} GDBusSignalTable;
+	const GDBusArgInfo *args;
+};
 
-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, { } }
+
+#define GDBUS_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function
+
+#define GDBUS_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_ASYNC
+
+#define GDBUS_DEPRECATED_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_DEPRECATED
+
+#define GDBUS_DEPRECATED_ASYNC_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_DEPRECATED
+
+#define GDBUS_NOREPLY_METHOD(_name, _in_args, _out_args, _function) \
+	.name = _name, \
+	.in_args = _in_args, \
+	.out_args = _out_args, \
+	.function = _function, \
+	.flags = G_DBUS_METHOD_FLAG_NOREPLY
+
+#define GDBUS_SIGNAL(_name, _args) \
+	.name = _name, \
+	.args = _args
+
+#define GDBUS_DEPRECATED_SIGNAL(_name, _args) \
+	.name = _name, \
+	.args = _args, \
+	.flags = G_DBUS_SIGNAL_FLAG_DEPRECATED
 
 gboolean g_dbus_register_interface(DBusConnection *connection,
 					const char *path, const char *name,
@@ -167,9 +243,28 @@ guint g_dbus_add_signal_watch(DBusConnec
 				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
diff -pruN 0.46-1/gdbus/mainloop.c 0.48-2.1/gdbus/mainloop.c
--- 0.46-1/gdbus/mainloop.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gdbus/mainloop.c	2012-11-30 07:59:13.000000000 +0000
@@ -92,8 +92,9 @@ static gboolean watch_func(GIOChannel *c
 	struct watch_info *info = data;
 	unsigned int flags = 0;
 	DBusDispatchStatus status;
+	DBusConnection *conn;
 
-	dbus_connection_ref(info->conn);
+	conn = dbus_connection_ref(info->conn);
 
 	if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
 	if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
@@ -102,10 +103,10 @@ static gboolean watch_func(GIOChannel *c
 
 	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;
 }
diff -pruN 0.46-1/gdbus/object.c 0.48-2.1/gdbus/object.c
--- 0.46-1/gdbus/object.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gdbus/object.c	2012-11-30 07:59:13.000000000 +0000
@@ -37,10 +37,28 @@
 #define error(fmt...)
 #define debug(fmt...)
 
+#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
+
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
+#endif
+
+#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
+#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
+#endif
+
 struct generic_data {
 	unsigned int refcount;
+	DBusConnection *conn;
+	char *path;
 	GSList *interfaces;
+	GSList *objects;
+	GSList *added;
+	GSList *removed;
+	guint process_id;
+	gboolean pending_prop;
 	char *introspect;
+	struct generic_data *parent;
 };
 
 struct interface_data {
@@ -48,6 +66,7 @@ struct interface_data {
 	const GDBusMethodTable *methods;
 	const GDBusSignalTable *signals;
 	const GDBusPropertyTable *properties;
+	GSList *pending_prop;
 	void *user_data;
 	GDBusDestroyFunction destroy;
 };
@@ -59,95 +78,121 @@ struct security_data {
 	void *iface_user_data;
 };
 
-static void print_arguments(GString *gstr, const char *sig,
-						const char *direction)
-{
-	int i;
-
-	for (i = 0; sig[i]; i++) {
-		char type[32];
-		int struct_level, dict_level;
-		unsigned int len;
-		gboolean complete;
-
-		complete = FALSE;
-		struct_level = dict_level = 0;
-		memset(type, 0, sizeof(type));
-
-		/* Gather enough data to have a single complete type */
-		for (len = 0; len < (sizeof(type) - 1) && sig[i]; len++, i++) {
-			switch (sig[i]) {
-			case '(':
-				struct_level++;
-				break;
-			case ')':
-				struct_level--;
-				if (struct_level <= 0 && dict_level <= 0)
-					complete = TRUE;
-				break;
-			case '{':
-				dict_level++;
-				break;
-			case '}':
-				dict_level--;
-				if (struct_level <= 0 && dict_level <= 0)
-					complete = TRUE;
-				break;
-			case 'a':
-				break;
-			default:
-				if (struct_level <= 0 && dict_level <= 0)
-					complete = TRUE;
-				break;
-			}
+struct property_data {
+	DBusConnection *conn;
+	GDBusPendingPropertySet id;
+	DBusMessage *message;
+};
 
-			type[len] = sig[i];
+static struct generic_data *root;
 
-			if (complete)
-				break;
-		}
+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)
+{
+	for (; args && args->name; args++) {
+		g_string_append_printf(gstr,
+					"\t\t\t<arg name=\"%s\" type=\"%s\"",
+					args->name, args->signature);
 
 		if (direction)
 			g_string_append_printf(gstr,
-					"\t\t\t<arg type=\"%s\" direction=\"%s\"/>\n",
-					type, direction);
+					" direction=\"%s\"/>\n", direction);
 		else
-			g_string_append_printf(gstr,
-					"\t\t\t<arg type=\"%s\"/>\n",
-					type);
+			g_string_append_printf(gstr, "/>\n");
+
 	}
 }
 
+#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++) {
-		if (!strlen(method->signature) && !strlen(method->reply))
-			g_string_append_printf(gstr, "\t\t<method name=\"%s\"/>\n",
-								method->name);
+		gboolean deprecated = method->flags &
+						G_DBUS_METHOD_FLAG_DEPRECATED;
+		gboolean noreply = method->flags &
+						G_DBUS_METHOD_FLAG_NOREPLY;
+
+		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);
 		else {
-			g_string_append_printf(gstr, "\t\t<method name=\"%s\">\n",
-								method->name);
-			print_arguments(gstr, method->signature, "in");
-			print_arguments(gstr, method->reply, "out");
+			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,
+					G_DBUS_ANNOTATE_DEPRECATED("\t\t\t"));
+			if (noreply)
+				g_string_append_printf(gstr,
+					G_DBUS_ANNOTATE_NOREPLY("\t\t\t"));
+
 			g_string_append_printf(gstr, "\t\t</method>\n");
 		}
 	}
 
 	for (signal = iface->signals; signal && signal->name; signal++) {
-		if (!strlen(signal->signature))
-			g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
-								signal->name);
+		gboolean deprecated = signal->flags &
+						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);
 		else {
-			g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
-								signal->name);
-			print_arguments(gstr, signal->signature, NULL);
+			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,
+					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,
@@ -196,11 +241,6 @@ static DBusMessage *introspect(DBusConne
 	struct generic_data *data = user_data;
 	DBusMessage *reply;
 
-	if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) {
-		error("Unexpected signature to introspect call");
-		return NULL;
-	}
-
 	if (data->introspect == NULL)
 		generate_introspection_xml(connection, data,
 						dbus_message_get_path(message));
@@ -253,7 +293,7 @@ void g_dbus_pending_success(DBusConnecti
 {
 	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)
@@ -267,7 +307,7 @@ void g_dbus_pending_success(DBusConnecti
 		dbus_message_unref(secdata->message);
 		g_free(secdata);
 		return;
-        }
+	}
 }
 
 void g_dbus_pending_error_valist(DBusConnection *connection,
@@ -276,7 +316,7 @@ void g_dbus_pending_error_valist(DBusCon
 {
 	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;
 
@@ -295,7 +335,7 @@ void g_dbus_pending_error_valist(DBusCon
 		dbus_message_unref(secdata->message);
 		g_free(secdata);
 		return;
-        }
+	}
 }
 
 void g_dbus_pending_error(DBusConnection *connection,
@@ -391,12 +431,177 @@ static gboolean check_privilege(DBusConn
 	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,
@@ -416,6 +621,391 @@ static struct interface_data *find_inter
 	return NULL;
 }
 
+static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
+							DBusMessage *message)
+{
+	const char *sig = dbus_message_get_signature(message);
+	const char *p = NULL;
+
+	for (; args && args->signature && *sig; args++) {
+		p = args->signature;
+
+		for (; *sig && *p; sig++, p++) {
+			if (*p != *sig)
+				return FALSE;
+		}
+	}
+
+	if (*sig || (p && *p) || (args && args->signature))
+		return FALSE;
+
+	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)
 {
@@ -436,8 +1026,8 @@ static DBusHandlerResult generic_message
 							method->name) == FALSE)
 			continue;
 
-		if (dbus_message_has_signature(message,
-						method->signature) == FALSE)
+		if (g_dbus_args_have_signature(method->in_args,
+							message) == FALSE)
 			continue;
 
 		if (check_privilege(connection, message, method,
@@ -456,47 +1046,100 @@ static DBusObjectPathVTable generic_tabl
 	.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;
 
-	invalidate_parent_data(conn, parent_path);
+	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);
 
-	if (data == NULL)
-		goto done;
+	g_slist_foreach(child->objects, append_object, user_data);
+}
 
-	g_free(data->introspect);
-	data->introspect = NULL;
+static DBusMessage *get_objects(DBusConnection *connection,
+				DBusMessage *message, void *user_data)
+{
+	struct generic_data *data = user_data;
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusMessageIter array;
 
-done:
-	g_free(parent_path);
+	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_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 GDBusMethodTable introspect_methods[] = {
-	{ "Introspect",	"",	"s", introspect	},
+static const GDBusMethodTable manager_methods[] = {
+	{ GDBUS_METHOD("GetManagedObjects", NULL,
+		GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
+	{ }
+};
+
+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,
+static void add_interface(struct generic_data *data,
+				const char *name,
 				const GDBusMethodTable *methods,
 				const GDBusSignalTable *signals,
 				const GDBusPropertyTable *properties,
@@ -514,6 +1157,14 @@ static void add_interface(struct generic
 	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,
@@ -530,6 +1181,8 @@ static struct generic_data *object_path_
 	}
 
 	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>");
@@ -543,31 +1196,12 @@ static struct generic_data *object_path_
 
 	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;
@@ -585,15 +1219,16 @@ static void object_path_unref(DBusConnec
 		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,
 				const char *interface, const char *name,
-				const char **args)
+				const GDBusArgInfo **args)
 {
 	struct generic_data *data = NULL;
 	struct interface_data *iface;
@@ -616,17 +1251,13 @@ static gboolean check_signal(DBusConnect
 
 	for (signal = iface->signals; signal && signal->name; signal++) {
 		if (!strcmp(signal->name, name)) {
-			*args = signal->signature;
-			break;
+			*args = signal->args;
+			return TRUE;
 		}
 	}
 
-	if (*args == NULL) {
-		error("No signal named %s on interface %s", name, interface);
-		return FALSE;
-	}
-
-	return TRUE;
+	error("No signal named %s on interface %s", name, interface);
+	return FALSE;
 }
 
 static dbus_bool_t emit_signal_valist(DBusConnection *conn,
@@ -638,7 +1269,7 @@ static dbus_bool_t emit_signal_valist(DB
 {
 	DBusMessage *signal;
 	dbus_bool_t ret;
-	const char *signature, *args;
+	const GDBusArgInfo *args;
 
 	if (!check_signal(conn, path, interface, name, &args))
 		return FALSE;
@@ -653,10 +1284,9 @@ static dbus_bool_t emit_signal_valist(DB
 	if (!ret)
 		goto fail;
 
-	signature = dbus_message_get_signature(signal);
-	if (strcmp(args, signature) != 0) {
-		error("%s.%s: expected signature'%s' but got '%s'",
-				interface, name, args, signature);
+	if (g_dbus_args_have_signature(args, signal) == FALSE) {
+		error("%s.%s: got unexpected signature '%s'", interface, name,
+					dbus_message_get_signature(signal));
 		ret = FALSE;
 		goto fail;
 	}
@@ -688,8 +1318,14 @@ gboolean g_dbus_register_interface(DBusC
 		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;
@@ -718,7 +1354,7 @@ gboolean g_dbus_unregister_interface(DBu
 	g_free(data->introspect);
 	data->introspect = NULL;
 
-	object_path_unref(connection, path);
+	object_path_unref(connection, data->path);
 
 	return TRUE;
 }
@@ -866,3 +1502,158 @@ gboolean g_dbus_emit_signal_valist(DBusC
 	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;
+}
diff -pruN 0.46-1/gdbus/watch.c 0.48-2.1/gdbus/watch.c
--- 0.46-1/gdbus/watch.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gdbus/watch.c	2012-11-30 07:59:13.000000000 +0000
@@ -78,7 +78,7 @@ struct filter_data {
 	gboolean registered;
 };
 
-static struct filter_data *filter_data_find(DBusConnection *connection,
+static struct filter_data *filter_data_find_match(DBusConnection *connection,
 							const char *name,
 							const char *owner,
 							const char *path,
@@ -95,28 +95,39 @@ static struct filter_data *filter_data_f
 		if (connection != data->connection)
 			continue;
 
-		if (name && data->name &&
-				g_str_equal(name, data->name) == FALSE)
+		if (g_strcmp0(name, data->name) != 0)
 			continue;
 
-		if (owner && data->owner &&
-				g_str_equal(owner, data->owner) == FALSE)
+		if (g_strcmp0(owner, data->owner) != 0)
 			continue;
 
-		if (path && data->path &&
-				g_str_equal(path, data->path) == FALSE)
+		if (g_strcmp0(path, data->path) != 0)
 			continue;
 
-		if (interface && data->interface &&
-				g_str_equal(interface, data->interface) == FALSE)
+		if (g_strcmp0(interface, data->interface) != 0)
 			continue;
 
-		if (member && data->member &&
-				g_str_equal(member, data->member) == FALSE)
+		if (g_strcmp0(member, data->member) != 0)
 			continue;
 
-		if (argument && data->argument &&
-				g_str_equal(argument, data->argument) == FALSE)
+		if (g_strcmp0(argument, data->argument) != 0)
+			continue;
+
+		return data;
+	}
+
+	return NULL;
+}
+
+static struct filter_data *filter_data_find(DBusConnection *connection)
+{
+	GSList *current;
+
+	for (current = listeners;
+			current != NULL; current = current->next) {
+		struct filter_data *data = current->data;
+
+		if (connection != data->connection)
 			continue;
 
 		return data;
@@ -204,7 +215,7 @@ static struct filter_data *filter_data_g
 	struct filter_data *data;
 	const char *name = NULL, *owner = NULL;
 
-	if (filter_data_find(connection, NULL, NULL, NULL, NULL, NULL, NULL) == NULL) {
+	if (filter_data_find(connection) == NULL) {
 		if (!dbus_connection_add_filter(connection,
 					message_filter, NULL, NULL)) {
 			error("dbus_connection_add_filter() failed");
@@ -221,16 +232,16 @@ static struct filter_data *filter_data_g
 		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);
@@ -376,15 +387,13 @@ static gboolean filter_data_remove_callb
 
 	connection = dbus_connection_ref(data->connection);
 	listeners = g_slist_remove(listeners, data);
-	filter_data_free(data);
 
 	/* Remove filter if there are no listeners left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
-					NULL);
-	if (data == NULL)
+	if (filter_data_find(connection) == NULL)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
 
+	filter_data_free(data);
 	dbus_connection_unref(connection);
 
 	return TRUE;
@@ -502,6 +511,7 @@ static DBusHandlerResult message_filter(
 {
 	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)
@@ -513,36 +523,66 @@ static DBusHandlerResult message_filter(
 	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 */
+
+	for (current = listeners; current != NULL; current = current->next) {
+		data = current->data;
+
+		if (connection != data->connection)
+			continue;
+
+		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;
+		if (data->handle_func) {
+			data->lock = TRUE;
 
-		data->handle_func(connection, message, data);
+			data->handle_func(connection, message, data);
 
-		data->callbacks = data->processed;
-		data->processed = NULL;
-		data->lock = FALSE;
+			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);
-	filter_data_free(data);
+		/* Has any other callback added callbacks back to this data? */
+		if (data->callbacks != NULL)
+			continue;
 
-	/* Remove filter if there no listener left for the connection */
-	data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
-					NULL);
-	if (data == NULL)
+		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)
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
 
@@ -712,6 +752,34 @@ guint g_dbus_add_signal_watch(DBusConnec
 	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;
@@ -738,8 +806,7 @@ void g_dbus_remove_all_watches(DBusConne
 {
 	struct filter_data *data;
 
-	while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL,
-					NULL, NULL))) {
+	while ((data = filter_data_find(connection))) {
 		listeners = g_slist_remove(listeners, data);
 		filter_data_call_and_free(data);
 	}
diff -pruN 0.46-1/gobex/gobex-apparam.c 0.48-2.1/gobex/gobex-apparam.c
--- 0.46-1/gobex/gobex-apparam.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/gobex/gobex-apparam.c	2012-11-30 07:59:13.000000000 +0000
@@ -0,0 +1,364 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "gobex-apparam.h"
+#include "gobex-debug.h"
+
+struct _GObexApparam {
+	GHashTable *tags;
+};
+
+struct apparam_tag {
+	guint8 id;
+	guint8 len;
+	union {
+		/* Data is stored in network order */
+		char string[0];
+		guint8 data[0];
+		guint8 u8;
+		guint16 u16;
+		guint32 u32;
+		guint64 u64;
+	} value;
+} __attribute__ ((packed));
+
+static struct apparam_tag *tag_new(guint8 id, guint8 len, const void *data)
+{
+	struct apparam_tag *tag;
+
+	tag = g_malloc0(2 + len);
+	tag->id = id;
+	tag->len = len;
+	memcpy(tag->value.data, data, len);
+
+	return tag;
+}
+
+static GObexApparam *g_obex_apparam_new(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_new0(GObexApparam, 1);
+	apparam->tags = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+							NULL, g_free);
+
+	return apparam;
+}
+
+static struct apparam_tag *apparam_tag_decode(const void *data, gsize size,
+							gsize *parsed)
+{
+	struct apparam_tag *tag;
+	const guint8 *ptr = data;
+	guint8 id;
+	guint8 len;
+
+	if (size < 2)
+		return NULL;
+
+	id = ptr[0];
+	len = ptr[1];
+
+	if (len > size - 2)
+		return NULL;
+
+	tag = tag_new(id, len, ptr + 2);
+	if (tag == NULL)
+		return NULL;
+
+	*parsed = 2 + tag->len;
+
+	return tag;
+}
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size)
+{
+	GObexApparam *apparam;
+	GHashTable *tags;
+	gsize count = 0;
+
+	if (size < 2)
+		return NULL;
+
+	apparam = g_obex_apparam_new();
+
+	tags = apparam->tags;
+	while (count < size) {
+		struct apparam_tag *tag;
+		gsize parsed;
+		guint id;
+
+		tag = apparam_tag_decode(data + count, size - count, &parsed);
+		if (tag == NULL)
+			break;
+
+		id = tag->id;
+		g_hash_table_insert(tags, GUINT_TO_POINTER(id), tag);
+
+		count += parsed;
+	}
+
+	if (count != size) {
+		g_obex_apparam_free(apparam);
+		return NULL;
+	}
+
+	return apparam;
+}
+
+static gssize tag_encode(struct apparam_tag *tag, void *buf, gsize len)
+{
+	gsize count = 2 + tag->len;
+
+	if (len < count)
+		return -ENOBUFS;
+
+	memcpy(buf, tag, count);
+
+	return count;
+}
+
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
+{
+	gsize count = 0;
+	gssize ret;
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_hash_table_iter_init(&iter, apparam->tags);
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		struct apparam_tag *tag = value;
+
+		ret = tag_encode(tag, buf + count, len - count);
+		if (ret < 0)
+			return ret;
+
+		count += ret;
+	}
+
+	return count;
+}
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+						const void *value, gsize len)
+{
+	struct apparam_tag *tag;
+	guint uid = id;
+
+	if (apparam == NULL)
+		apparam = g_obex_apparam_new();
+
+	tag = tag_new(id, len, value);
+	g_hash_table_replace(apparam->tags, GUINT_TO_POINTER(uid), tag);
+
+	return apparam;
+}
+
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+							guint8 value)
+{
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+	return g_obex_apparam_set_bytes(apparam, id, &value, 1);
+}
+
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+							guint16 value)
+{
+	guint16 num = g_htons(value);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+	return g_obex_apparam_set_bytes(apparam, id, &num, 2);
+}
+
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+							guint32 value)
+{
+	guint32 num = g_htonl(value);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+	return g_obex_apparam_set_bytes(apparam, id, &num, 4);
+}
+
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+							guint64 value)
+{
+	guint64 num = GUINT64_TO_BE(value);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %"
+						G_GUINT64_FORMAT, id, value);
+
+	return g_obex_apparam_set_bytes(apparam, id, &num, 8);
+}
+
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+							const char *value)
+{
+	gsize len;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %s", id, value);
+
+	len = strlen(value) + 1;
+	if (len > G_MAXUINT8) {
+		((char *) value)[G_MAXUINT8 - 1] = '\0';
+		len = G_MAXUINT8;
+	}
+
+	return g_obex_apparam_set_bytes(apparam, id, value, len);
+}
+
+static struct apparam_tag *g_obex_apparam_find_tag(GObexApparam *apparam,
+								guint id)
+{
+	return g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+}
+
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+							guint8 *dest)
+{
+	struct apparam_tag *tag;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+	tag = g_obex_apparam_find_tag(apparam, id);
+	if (tag == NULL)
+		return FALSE;
+
+	*dest = tag->value.u8;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+	return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+							guint16 *dest)
+{
+	struct apparam_tag *tag;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+	tag = g_obex_apparam_find_tag(apparam, id);
+	if (tag == NULL)
+		return FALSE;
+
+	if (tag->len < sizeof(*dest))
+		return FALSE;
+
+	*dest = g_ntohs(tag->value.u16);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+	return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+							guint32 *dest)
+{
+	struct apparam_tag *tag;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+	tag = g_obex_apparam_find_tag(apparam, id);
+	if (tag == NULL)
+		return FALSE;
+
+	if (tag->len < sizeof(*dest))
+		return FALSE;
+
+	*dest = g_ntohl(tag->value.u32);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+	return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+							guint64 *dest)
+{
+	struct apparam_tag *tag;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+	tag = g_obex_apparam_find_tag(apparam, id);
+	if (tag == NULL)
+		return FALSE;
+
+	if (tag->len < sizeof(*dest))
+		return FALSE;
+
+	*dest = GUINT64_FROM_BE(tag->value.u64);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%" G_GUINT64_FORMAT, *dest);
+
+	return TRUE;
+}
+
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id)
+{
+	struct apparam_tag *tag;
+	char *string;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+	tag = g_obex_apparam_find_tag(apparam, id);
+	if (tag == NULL)
+		return NULL;
+
+	string = g_strndup(tag->value.string, tag->len);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%s", string);
+
+	return string;
+}
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+					const guint8 **val, gsize *len)
+{
+	struct apparam_tag *tag;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+	tag = g_obex_apparam_find_tag(apparam, id);
+	if (tag == NULL)
+		return FALSE;
+
+	*len = tag->len;
+	*val = tag->value.data;
+
+	return TRUE;
+}
+
+void g_obex_apparam_free(GObexApparam *apparam)
+{
+	g_hash_table_unref(apparam->tags);
+	g_free(apparam);
+}
diff -pruN 0.46-1/gobex/gobex-apparam.h 0.48-2.1/gobex/gobex-apparam.h
--- 0.46-1/gobex/gobex-apparam.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/gobex/gobex-apparam.h	2012-11-30 07:59:13.000000000 +0000
@@ -0,0 +1,59 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_APPARAM_H
+#define __GOBEX_APPARAM_H
+
+#include <glib.h>
+
+typedef struct _GObexApparam GObexApparam;
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size);
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize size);
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+						const void *value, gsize size);
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+							guint8 value);
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+							guint16 value);
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+							guint32 value);
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+							guint64 value);
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+							const char *value);
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+					const guint8 **val, gsize *len);
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+							guint8 *value);
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+							guint16 *value);
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+							guint32 *value);
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+							guint64 *value);
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id);
+
+void g_obex_apparam_free(GObexApparam *apparam);
+
+#endif /* __GOBEX_APPARAM_H */
diff -pruN 0.46-1/gobex/gobex.c 0.48-2.1/gobex/gobex.c
--- 0.46-1/gobex/gobex.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gobex/gobex.c	2012-11-30 07:59:13.000000000 +0000
@@ -267,7 +267,7 @@ static gboolean write_stream(GObex *obex
 	if (status != G_IO_STATUS_NORMAL)
 		return FALSE;
 
-	g_obex_dump("<", buf, bytes_written);
+	g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
 
 	obex->tx_sent += bytes_written;
 	obex->tx_data -= bytes_written;
@@ -290,7 +290,7 @@ static gboolean write_packet(GObex *obex
 	if (bytes_written != obex->tx_data)
 		return FALSE;
 
-	g_obex_dump("<", buf, bytes_written);
+	g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
 
 	obex->tx_sent += bytes_written;
 	obex->tx_data -= bytes_written;
@@ -1078,7 +1078,7 @@ read_body:
 	} while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len);
 
 done:
-	g_obex_dump(">", obex->rx_buf, obex->rx_data);
+	g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
 
 	return TRUE;
 }
@@ -1124,7 +1124,7 @@ static gboolean read_packet(GObex *obex,
 		return FALSE;
 	}
 
-	g_obex_dump(">", obex->rx_buf, obex->rx_data);
+	g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
 
 	return TRUE;
 fail:
@@ -1236,6 +1236,7 @@ static GDebugKey keys[] = {
 	{ "header",	G_OBEX_DEBUG_HEADER },
 	{ "packet",	G_OBEX_DEBUG_PACKET },
 	{ "data",	G_OBEX_DEBUG_DATA },
+	{ "apparam",	G_OBEX_DEBUG_APPARAM },
 };
 
 GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
@@ -1246,9 +1247,11 @@ GObex *g_obex_new(GIOChannel *io, GObexT
 
 	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;
 	}
 
diff -pruN 0.46-1/gobex/gobex-debug.h 0.48-2.1/gobex/gobex-debug.h
--- 0.46-1/gobex/gobex-debug.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gobex/gobex-debug.h	2012-11-30 07:59:13.000000000 +0000
@@ -32,21 +32,22 @@
 #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) {
diff -pruN 0.46-1/gobex/gobex-header.c 0.48-2.1/gobex/gobex-header.c
--- 0.46-1/gobex/gobex-header.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gobex/gobex-header.c	2012-11-30 07:59:13.000000000 +0000
@@ -109,23 +109,23 @@ gssize g_obex_header_encode(GObexHeader
 		g_assert_cmpuint(utf16_len + 3, ==, header->hlen);
 		u16 = g_htons(utf16_len + 3);
 		ptr = put_bytes(ptr, &u16, sizeof(u16));
-		ptr = put_bytes(ptr, utf16, utf16_len);
+		put_bytes(ptr, utf16, utf16_len);
 		g_free(utf16);
 		break;
 	case G_OBEX_HDR_ENC_BYTES:
 		u16 = g_htons(header->hlen);
 		ptr = put_bytes(ptr, &u16, sizeof(u16));
 		if (header->extdata)
-			ptr = put_bytes(ptr, header->v.extdata, header->vlen);
+			put_bytes(ptr, header->v.extdata, header->vlen);
 		else
-			ptr = put_bytes(ptr, header->v.data, header->vlen);
+			put_bytes(ptr, header->v.data, header->vlen);
 		break;
 	case G_OBEX_HDR_ENC_UINT8:
 		*ptr = header->v.u8;
 		break;
 	case G_OBEX_HDR_ENC_UINT32:
 		u32 = g_htonl(header->v.u32);
-		ptr = put_bytes(ptr, &u32, sizeof(u32));
+		put_bytes(ptr, &u32, sizeof(u32));
 		break;
 	default:
 		g_assert_not_reached();
@@ -187,7 +187,7 @@ GObexHeader *g_obex_header_decode(const
 		}
 
 		header->v.string = g_convert((const char *) ptr, hdr_len - 5,
-						"UTF8", "UTF16BE",
+						"UTF-8", "UTF-16BE",
 						NULL, &str_len, &conv_err);
 		if (header->v.string == NULL) {
 			g_set_error(err, G_OBEX_ERROR,
@@ -263,7 +263,7 @@ GObexHeader *g_obex_header_decode(const
 		}
 		header->vlen = 4;
 		header->hlen = 5;
-		ptr = get_bytes(&header->v.u32, ptr, sizeof(header->v.u32));
+		get_bytes(&header->v.u32, ptr, sizeof(header->v.u32));
 		header->v.u32 = g_ntohl(header->v.u32);
 		*parsed = 5;
 		break;
@@ -337,6 +337,19 @@ gboolean g_obex_header_get_bytes(GObexHe
 	return TRUE;
 }
 
+GObexApparam *g_obex_header_get_apparam(GObexHeader *header)
+{
+	gboolean ret;
+	const guint8 *val;
+	gsize len;
+
+	ret = g_obex_header_get_bytes(header, &val, &len);
+	if (!ret)
+		return NULL;
+
+	return g_obex_apparam_decode(val, len);
+}
+
 gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val)
 {
 	g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
@@ -411,6 +424,18 @@ GObexHeader *g_obex_header_new_bytes(gui
 	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;
diff -pruN 0.46-1/gobex/gobex-header.h 0.48-2.1/gobex/gobex-header.h
--- 0.46-1/gobex/gobex-header.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/gobex/gobex-header.h	2012-11-30 07:59:13.000000000 +0000
@@ -25,6 +25,7 @@
 #include <glib.h>
 
 #include <gobex/gobex-defs.h>
+#include <gobex/gobex-apparam.h>
 
 /* Header ID's */
 #define G_OBEX_HDR_INVALID	0x00
@@ -77,11 +78,13 @@ gboolean g_obex_header_get_bytes(GObexHe
 								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);
diff -pruN 0.46-1/ltmain.sh 0.48-2.1/ltmain.sh
--- 0.46-1/ltmain.sh	2012-05-17 15:12:34.000000000 +0000
+++ 0.48-2.1/ltmain.sh	2012-11-30 07:59:30.000000000 +0000
@@ -70,7 +70,7 @@
 #         compiler:		$LTCC
 #         compiler flags:		$LTCFLAGS
 #         linker:		$LD (gnu? $with_gnu_ld)
-#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1
+#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1.1
 #         automake:	$automake_version
 #         autoconf:	$autoconf_version
 #
@@ -80,7 +80,7 @@
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION="2.4.2 Debian-2.4.2-1"
+VERSION="2.4.2 Debian-2.4.2-1.1"
 TIMESTAMP=""
 package_revision=1.3337
 
diff -pruN 0.46-1/Makefile.am 0.48-2.1/Makefile.am
--- 0.46-1/Makefile.am	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/Makefile.am	2012-11-30 07:59:13.000000000 +0000
@@ -7,10 +7,9 @@ service_in_files =
 
 doc_files = doc/obexd-api.txt doc/agent-api.txt doc/client-api.txt
 
-test_files = test/simple-agent test/send-files \
-		test/pull-business-card test/exchange-business-cards \
+test_files = test/simple-agent test/exchange-business-cards \
 		test/list-folders test/pbap-client test/ftp-client \
-		test/map-client
+		test/map-client test/opp-client
 
 gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \
 					gdbus/object.c gdbus/polkit.c
@@ -21,7 +20,8 @@ gobex_sources = gobex/gobex.h gobex/gobe
 			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 =
@@ -63,7 +63,7 @@ builtin_sources += plugins/pbap.c plugin
 
 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
@@ -124,10 +124,10 @@ client_obex_client_SOURCES = $(gdbus_sou
 				client/opp.h client/opp.c \
 				client/map.h client/map.c \
 				client/transfer.h client/transfer.c \
-				client/agent.h client/agent.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
@@ -166,11 +166,12 @@ plugins/phonebook.c: plugins/@PHONEBOOK_
 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
@@ -188,6 +189,10 @@ unit_test_gobex_transfer_SOURCES = $(gob
 						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) \
diff -pruN 0.46-1/Makefile.in 0.48-2.1/Makefile.in
--- 0.46-1/Makefile.in	2012-05-17 15:12:37.000000000 +0000
+++ 0.48-2.1/Makefile.in	2012-11-30 07:59:32.000000000 +0000
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -18,6 +18,23 @@
 
 
 VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
 pkgdatadir = $(datadir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
 pkglibdir = $(libdir)/@PACKAGE@
@@ -38,7 +55,8 @@ build_triplet = @build@
 host_triplet = @host@
 noinst_PROGRAMS = unit/test-gobex-header$(EXEEXT) \
 	unit/test-gobex-packet$(EXEEXT) unit/test-gobex$(EXEEXT) \
-	unit/test-gobex-transfer$(EXEEXT) $(am__EXEEXT_3) \
+	unit/test-gobex-transfer$(EXEEXT) \
+	unit/test-gobex-apparam$(EXEEXT) $(am__EXEEXT_3) \
 	tools/test-server$(EXEEXT)
 libexec_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
 @SERVER_TRUE@am__append_1 = src/obexd.service.in
@@ -49,7 +67,8 @@ libexec_PROGRAMS = $(am__EXEEXT_1) $(am_
 @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
@@ -109,21 +128,22 @@ am__client_obex_client_SOURCES_DIST = gd
 	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/pbap.c client/ftp.h client/ftp.c client/opp.h \
 	client/opp.c client/map.h client/map.c client/transfer.h \
-	client/transfer.c client/agent.h client/agent.c \
-	client/transport.h client/transport.c client/driver.h \
-	client/driver.c src/map_ap.h src/map_ap.c
+	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
 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) \
@@ -132,9 +152,9 @@ am__objects_3 = btio/btio.$(OBJEXT)
 @CLIENT_TRUE@	client/bluetooth.$(OBJEXT) client/sync.$(OBJEXT) \
 @CLIENT_TRUE@	client/pbap.$(OBJEXT) client/ftp.$(OBJEXT) \
 @CLIENT_TRUE@	client/opp.$(OBJEXT) client/map.$(OBJEXT) \
-@CLIENT_TRUE@	client/transfer.$(OBJEXT) client/agent.$(OBJEXT) \
-@CLIENT_TRUE@	client/transport.$(OBJEXT) \
-@CLIENT_TRUE@	client/driver.$(OBJEXT) src/map_ap.$(OBJEXT)
+@CLIENT_TRUE@	client/transfer.$(OBJEXT) \
+@CLIENT_TRUE@	client/transport.$(OBJEXT) client/dbus.$(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@)
@@ -146,12 +166,13 @@ am__src_obexd_SOURCES_DIST = gdbus/gdbus
 	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 \
@@ -164,7 +185,7 @@ am__src_obexd_SOURCES_DIST = gdbus/gdbus
 @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) \
@@ -186,7 +207,8 @@ src_obexd_LINK = $(LIBTOOL) $(AM_V_lt) -
 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)
@@ -200,6 +222,11 @@ am_unit_test_gobex_OBJECTS = $(am__objec
 	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)
@@ -242,6 +269,7 @@ am__v_GEN_0 = @echo "  GEN   " $@;
 SOURCES = $(client_obex_client_SOURCES) $(src_obexd_SOURCES) \
 	$(nodist_src_obexd_SOURCES) $(tools_test_client_SOURCES) \
 	$(tools_test_server_SOURCES) $(unit_test_gobex_SOURCES) \
+	$(unit_test_gobex_apparam_SOURCES) \
 	$(unit_test_gobex_header_SOURCES) \
 	$(unit_test_gobex_packet_SOURCES) \
 	$(unit_test_gobex_transfer_SOURCES)
@@ -249,9 +277,15 @@ DIST_SOURCES = $(am__client_obex_client_
 	$(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)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
 DATA = $(service_DATA)
 ETAGS = etags
 CTAGS = ctags
@@ -428,10 +462,9 @@ AM_MAKEFLAGS = --no-print-directory
 servicedir = $(datarootdir)/dbus-1/services
 service_in_files = $(am__append_1) $(am__append_7)
 doc_files = doc/obexd-api.txt doc/agent-api.txt doc/client-api.txt
-test_files = test/simple-agent test/send-files \
-		test/pull-business-card test/exchange-business-cards \
+test_files = test/simple-agent test/exchange-business-cards \
 		test/list-folders test/pbap-client test/ftp-client \
-		test/map-client
+		test/map-client test/opp-client
 
 gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \
 					gdbus/object.c gdbus/polkit.c
@@ -441,7 +474,8 @@ gobex_sources = gobex/gobex.h gobex/gobe
 			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 \
@@ -452,8 +486,8 @@ gobex_sources = gobex/gobex.h gobex/gobe
 @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 \
@@ -486,10 +520,10 @@ gobex_sources = gobex/gobex.h gobex/gobe
 @CLIENT_TRUE@				client/opp.h client/opp.c \
 @CLIENT_TRUE@				client/map.h client/map.c \
 @CLIENT_TRUE@				client/transfer.h client/transfer.c \
-@CLIENT_TRUE@				client/agent.h client/agent.c \
 @CLIENT_TRUE@				client/transport.h client/transport.c \
+@CLIENT_TRUE@				client/dbus.h client/dbus.c \
 @CLIENT_TRUE@				client/driver.h client/driver.c \
-@CLIENT_TRUE@				src/map_ap.h src/map_ap.c
+@CLIENT_TRUE@				src/map_ap.h
 
 @CLIENT_TRUE@client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 service_DATA = $(service_in_files:.service.in=.service)
@@ -530,6 +564,10 @@ unit_test_gobex_transfer_SOURCES = $(gob
 						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
 
@@ -594,7 +632,6 @@ distclean-hdr:
 	-rm -f config.h stamp-h1
 install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
 	@$(NORMAL_INSTALL)
-	test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
 	@list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
 	list2=; for p in $$list; do \
 	  if test -f $$p; then \
@@ -602,6 +639,8 @@ install-pluginLTLIBRARIES: $(plugin_LTLI
 	  else :; fi; \
 	done; \
 	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
 	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
 	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
 	}
@@ -625,8 +664,11 @@ clean-pluginLTLIBRARIES:
 	done
 install-libexecPROGRAMS: $(libexec_PROGRAMS)
 	@$(NORMAL_INSTALL)
-	test -z "$(libexecdir)" || $(MKDIR_P) "$(DESTDIR)$(libexecdir)"
 	@list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+	fi; \
 	for p in $$list; do echo "$$p $$p"; done | \
 	sed 's/$(EXEEXT)$$//' | \
 	while read p p1; do if test -f $$p || test -f $$p1; \
@@ -705,6 +747,8 @@ gobex/gobex-header.$(OBJEXT): gobex/$(am
 	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)
@@ -746,14 +790,12 @@ client/map.$(OBJEXT): client/$(am__dirst
 	client/$(DEPDIR)/$(am__dirstamp)
 client/transfer.$(OBJEXT): client/$(am__dirstamp) \
 	client/$(DEPDIR)/$(am__dirstamp)
-client/agent.$(OBJEXT): client/$(am__dirstamp) \
-	client/$(DEPDIR)/$(am__dirstamp)
 client/transport.$(OBJEXT): client/$(am__dirstamp) \
 	client/$(DEPDIR)/$(am__dirstamp)
+client/dbus.$(OBJEXT): client/$(am__dirstamp) \
+	client/$(DEPDIR)/$(am__dirstamp)
 client/driver.$(OBJEXT): client/$(am__dirstamp) \
 	client/$(DEPDIR)/$(am__dirstamp)
-src/map_ap.$(OBJEXT): src/$(am__dirstamp) \
-	src/$(DEPDIR)/$(am__dirstamp)
 client/obex-client$(EXEEXT): $(client_obex_client_OBJECTS) $(client_obex_client_DEPENDENCIES) $(EXTRA_client_obex_client_DEPENDENCIES) client/$(am__dirstamp)
 	@rm -f client/obex-client$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(client_obex_client_OBJECTS) $(client_obex_client_LDADD) $(LIBS)
@@ -835,6 +877,11 @@ unit/util.$(OBJEXT): unit/$(am__dirstamp
 unit/test-gobex$(EXEEXT): $(unit_test_gobex_OBJECTS) $(unit_test_gobex_DEPENDENCIES) $(EXTRA_unit_test_gobex_DEPENDENCIES) unit/$(am__dirstamp)
 	@rm -f unit/test-gobex$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(unit_test_gobex_OBJECTS) $(unit_test_gobex_LDADD) $(LIBS)
+unit/test-gobex-apparam.$(OBJEXT): unit/$(am__dirstamp) \
+	unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex-apparam$(EXEEXT): $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_DEPENDENCIES) $(EXTRA_unit_test_gobex_apparam_DEPENDENCIES) unit/$(am__dirstamp)
+	@rm -f unit/test-gobex-apparam$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_LDADD) $(LIBS)
 unit/test-gobex-header.$(OBJEXT): unit/$(am__dirstamp) \
 	unit/$(DEPDIR)/$(am__dirstamp)
 unit/test-gobex-header$(EXEEXT): $(unit_test_gobex_header_OBJECTS) $(unit_test_gobex_header_DEPENDENCIES) $(EXTRA_unit_test_gobex_header_DEPENDENCIES) unit/$(am__dirstamp)
@@ -854,8 +901,8 @@ unit/test-gobex-transfer$(EXEEXT): $(uni
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
 	-rm -f btio/btio.$(OBJEXT)
-	-rm -f client/agent.$(OBJEXT)
 	-rm -f client/bluetooth.$(OBJEXT)
+	-rm -f client/dbus.$(OBJEXT)
 	-rm -f client/driver.$(OBJEXT)
 	-rm -f client/ftp.$(OBJEXT)
 	-rm -f client/main.$(OBJEXT)
@@ -871,6 +918,7 @@ mostlyclean-compile:
 	-rm -f gdbus/object.$(OBJEXT)
 	-rm -f gdbus/polkit.$(OBJEXT)
 	-rm -f gdbus/watch.$(OBJEXT)
+	-rm -f gobex/gobex-apparam.$(OBJEXT)
 	-rm -f gobex/gobex-defs.$(OBJEXT)
 	-rm -f gobex/gobex-header.$(OBJEXT)
 	-rm -f gobex/gobex-packet.$(OBJEXT)
@@ -892,7 +940,6 @@ mostlyclean-compile:
 	-rm -f src/log.$(OBJEXT)
 	-rm -f src/main.$(OBJEXT)
 	-rm -f src/manager.$(OBJEXT)
-	-rm -f src/map_ap.$(OBJEXT)
 	-rm -f src/mimetype.$(OBJEXT)
 	-rm -f src/obex.$(OBJEXT)
 	-rm -f src/plugin.$(OBJEXT)
@@ -901,6 +948,7 @@ mostlyclean-compile:
 	-rm -f src/transport.$(OBJEXT)
 	-rm -f tools/test-client.$(OBJEXT)
 	-rm -f tools/test-server.$(OBJEXT)
+	-rm -f unit/test-gobex-apparam.$(OBJEXT)
 	-rm -f unit/test-gobex-header.$(OBJEXT)
 	-rm -f unit/test-gobex-packet.$(OBJEXT)
 	-rm -f unit/test-gobex-transfer.$(OBJEXT)
@@ -911,8 +959,8 @@ distclean-compile:
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/btio.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/agent.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/bluetooth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/dbus.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/driver.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/ftp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/main.Po@am__quote@
@@ -928,6 +976,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/object.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/polkit.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/watch.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-apparam.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-defs.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-header.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-packet.Po@am__quote@
@@ -949,7 +998,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/log.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/map_ap.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/mimetype.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/obex.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/plugin.Po@am__quote@
@@ -958,6 +1006,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/transport.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/test-client.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/test-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-apparam.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-header.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-packet.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-transfer.Po@am__quote@
@@ -1002,8 +1051,11 @@ distclean-libtool:
 	-rm -f libtool config.lt
 install-serviceDATA: $(service_DATA)
 	@$(NORMAL_INSTALL)
-	test -z "$(servicedir)" || $(MKDIR_P) "$(DESTDIR)$(servicedir)"
 	@list='$(service_DATA)'; test -n "$(servicedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(servicedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(servicedir)" || exit 1; \
+	fi; \
 	for p in $$list; do \
 	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
 	  echo "$$d$$p"; \
@@ -1262,7 +1314,7 @@ distcheck: dist
 	*.zip*) \
 	  unzip $(distdir).zip ;;\
 	esac
-	chmod -R a-w $(distdir); chmod a+w $(distdir)
+	chmod -R a-w $(distdir); chmod u+w $(distdir)
 	mkdir $(distdir)/_build
 	mkdir $(distdir)/_inst
 	chmod a-w $(distdir)
diff -pruN 0.46-1/.pc/applied-patches 0.48-2.1/.pc/applied-patches
--- 0.46-1/.pc/applied-patches	2014-10-16 04:43:28.574405718 +0000
+++ 0.48-2.1/.pc/applied-patches	2014-10-16 04:43:28.746410380 +0000
@@ -1 +1,2 @@
-Remove_left_over_glib-helper.h_support.patch
+fix_build_libc-2.17
+test-avoid-double-source-removals.patch
diff -pruN 0.46-1/.pc/fix_build_libc-2.17/plugins/filesystem.h 0.48-2.1/.pc/fix_build_libc-2.17/plugins/filesystem.h
--- 0.46-1/.pc/fix_build_libc-2.17/plugins/filesystem.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/.pc/fix_build_libc-2.17/plugins/filesystem.h	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,26 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+ssize_t string_read(void *object, void *buf, size_t count);
+gboolean is_filename(const char *name);
+int verify_path(const char *path);
diff -pruN 0.46-1/.pc/fix_build_libc-2.17/src/mimetype.h 0.48-2.1/.pc/fix_build_libc-2.17/src/mimetype.h
--- 0.46-1/.pc/fix_build_libc-2.17/src/mimetype.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/.pc/fix_build_libc-2.17/src/mimetype.h	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,55 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+typedef gboolean (*obex_object_io_func) (void *object, int flags, int err,
+							void *user_data);
+
+struct obex_mime_type_driver {
+	const uint8_t *target;
+	unsigned int target_size;
+	const char *mimetype;
+	const uint8_t *who;
+	unsigned int who_size;
+	void *(*open) (const char *name, int oflag, mode_t mode,
+			void *driver_data, size_t *size, int *err);
+	int (*close) (void *object);
+	ssize_t (*get_next_header)(void *object, void *buf, size_t mtu,
+								uint8_t *hi);
+	ssize_t (*read) (void *object, void *buf, size_t count);
+	ssize_t (*write) (void *object, const void *buf, size_t count);
+	int (*flush) (void *object);
+	int (*copy) (const char *name, const char *destname);
+	int (*move) (const char *name, const char *destname);
+	int (*remove) (const char *name);
+	int (*set_io_watch) (void *object, obex_object_io_func func,
+				void *user_data);
+};
+
+int obex_mime_type_driver_register(struct obex_mime_type_driver *driver);
+void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver);
+struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target,
+				unsigned int target_size,
+				const char *mimetype, const uint8_t *who,
+				unsigned int who_size);
+
+void obex_object_set_io_flags(void *object, int flags, int err);
diff -pruN 0.46-1/.pc/fix_build_libc-2.17/src/obex.h 0.48-2.1/.pc/fix_build_libc-2.17/src/obex.h
--- 0.46-1/.pc/fix_build_libc-2.17/src/obex.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/.pc/fix_build_libc-2.17/src/obex.h	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,51 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  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
+ *
+ */
+
+#define OBJECT_SIZE_UNKNOWN -1
+#define OBJECT_SIZE_DELETE -2
+
+#define TARGET_SIZE 16
+
+struct obex_session;
+
+int obex_get_stream_start(struct obex_session *os, const char *filename);
+int obex_put_stream_start(struct obex_session *os, const char *filename);
+const char *obex_get_name(struct obex_session *os);
+const char *obex_get_destname(struct obex_session *os);
+void obex_set_name(struct obex_session *os, const char *name);
+ssize_t obex_get_size(struct obex_session *os);
+const char *obex_get_type(struct obex_session *os);
+int obex_remove(struct obex_session *os, const char *path);
+int obex_copy(struct obex_session *os, const char *source,
+						const char *destination);
+int obex_move(struct obex_session *os, const char *source,
+						const char *destination);
+uint8_t obex_get_action_id(struct obex_session *os);
+ssize_t obex_get_apparam(struct obex_session *os, const uint8_t **buffer);
+ssize_t obex_get_non_header_data(struct obex_session *os,
+							const uint8_t **data);
+int obex_getpeername(struct obex_session *os, char **name);
+
+/* Just a thin wrapper around memcmp to deal with NULL values */
+int memncmp0(const void *a, size_t na, const void *b, size_t nb);
diff -pruN 0.46-1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-ebook.c 0.48-2.1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-ebook.c
--- 0.46-1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-ebook.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-ebook.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,708 +0,0 @@
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2009-2010  Intel Corporation
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  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 <errno.h>
-#include <glib.h>
-#include <bluetooth/bluetooth.h>
-
-#include <libebook/e-book.h>
-
-#include "log.h"
-#include "obex.h"
-#include "service.h"
-#include "phonebook.h"
-#include "glib-helper.h"
-
-#define QUERY_FN "(contains \"family_name\" \"%s\")"
-#define QUERY_NAME "(contains \"given_name\" \"%s\")"
-#define QUERY_PHONE "(contains \"phone\" \"%s\")"
-
-struct query_context {
-	const struct apparam_field *params;
-	phonebook_cb contacts_cb;
-	phonebook_entry_cb entry_cb;
-	phonebook_cache_ready_cb ready_cb;
-	EBookQuery *query;
-	unsigned int count;
-	GString *buf;
-	char *id;
-	unsigned queued_calls;
-	void *user_data;
-	GSList *ebooks;
-	gboolean canceled;
-};
-
-static char *attribute_mask[] = {
-/* 0 */		"VERSION",
-		"FN",
-		"N",
-		"PHOTO",
-		"BDAY",
-		"ADR",
-		"LABEL",
-		"TEL",
-/* 8 */		"EMAIL",
-		"MAILER",
-		"TZ",
-		"GEO",
-		"TITLE",
-		"ROLE",
-		"LOGO",
-		"AGENT",
-/* 16 */	"ORG",
-		"NOTE",
-		"REV",
-		"SOUND",
-		"URL",
-		"UID",
-		"KEY",
-		"NICKNAME",
-/* 24 */	"CATEGORIES",
-		"PROID",
-		"CLASS",
-		"SORT-STRING",
-/* 28 */	"X-IRMC-CALL-DATETIME",
-		NULL
-
-};
-
-static void close_ebooks(GSList *ebooks)
-{
-	g_slist_free_full(ebooks, g_object_unref);
-}
-
-static void free_query_context(struct query_context *data)
-{
-	g_free(data->id);
-
-	if (data->buf != NULL)
-		g_string_free(data->buf, TRUE);
-
-	if (data->query != NULL)
-		e_book_query_unref(data->query);
-
-	close_ebooks(data->ebooks);
-
-	g_free(data);
-}
-
-static char *evcard_to_string(EVCard *evcard, unsigned int format,
-							uint64_t filter)
-{
-	EVCard *evcard2;
-	GList *l;
-	char *vcard;
-
-	if (!filter)
-		return e_vcard_to_string(evcard, EVC_FORMAT_VCARD_30);
-		/* XXX There is no support for VCARD 2.1 at this time */
-
-	/*
-	 * Mandatory attributes for vCard 2.1 are VERSION ,N and TEL.
-	 * Mandatory attributes for vCard 3.0 are VERSION, N, FN and TEL
-	 */
-	filter = format == EVC_FORMAT_VCARD_30 ? filter | 0x87: filter | 0x85;
-
-	l = e_vcard_get_attributes(evcard);
-	evcard2 = e_vcard_new();
-	for (; l; l = g_list_next(l)) {
-		EVCardAttribute *attrib = l->data;
-		const char *name;
-		int i;
-
-		if (!attrib)
-			continue;
-
-		name = e_vcard_attribute_get_name(attrib);
-
-		for (i = 0; attribute_mask[i] != NULL; i++) {
-			if (!(filter & (1 << i)))
-				continue;
-			if (g_strcmp0(name, attribute_mask[i]) != 0)
-				continue;
-
-			e_vcard_add_attribute(evcard2,
-					e_vcard_attribute_copy(attrib));
-		}
-	}
-
-	vcard = e_vcard_to_string(evcard2, format);
-	g_object_unref(evcard2);
-
-	return vcard;
-}
-
-static void ebookpull_cb(EBook *book, const GError *gerr, GList *contacts,
-							void *user_data)
-{
-	struct query_context *data = user_data;
-	GList *l;
-	unsigned int count, maxcount;
-
-	data->queued_calls--;
-
-	if (data->canceled)
-		goto canceled;
-
-	if (gerr != NULL) {
-		error("E-Book query failed: %s", gerr->message);
-		goto done;
-	}
-
-	DBG("");
-
-	/*
-	 * When MaxListCount is zero, PCE wants to know the number of used
-	 * indexes in the phonebook of interest. All other parameters that
-	 * may be present in the request shall be ignored.
-	 */
-	maxcount = data->params->maxlistcount;
-	if (maxcount == 0) {
-		data->count += g_list_length(contacts);
-		goto done;
-	}
-
-	l = g_list_nth(contacts, data->params->liststartoffset);
-
-	for (count = 0; l && count + data->count < maxcount; l = g_list_next(l),
-								count++) {
-		EContact *contact = E_CONTACT(l->data);
-		EVCard *evcard = E_VCARD(contact);
-		char *vcard;
-
-		vcard = evcard_to_string(evcard, EVC_FORMAT_VCARD_30,
-						data->params->filter);
-
-		data->buf = g_string_append(data->buf, vcard);
-		data->buf = g_string_append(data->buf, "\r\n");
-		g_free(vcard);
-	}
-
-	DBG("collected %d vcards", count);
-
-	data->count += count;
-
-	g_list_free_full(contacts, g_object_unref);
-
-done:
-	if (data->queued_calls == 0) {
-		GString *buf = data->buf;
-		data->buf = NULL;
-
-		data->contacts_cb(buf->str, buf->len, data->count,
-						0, TRUE, data->user_data);
-
-		g_string_free(buf, TRUE);
-
-	}
-
-	return;
-
-canceled:
-	if (data->queued_calls == 0)
-		free_query_context(data);
-}
-
-static void ebook_entry_cb(EBook *book, const GError *gerr,
-				EContact *contact, void *user_data)
-{
-	struct query_context *data = user_data;
-	EVCard *evcard;
-	char *vcard;
-	size_t len;
-
-	data->queued_calls--;
-
-	if (data->canceled)
-		goto done;
-
-	if (gerr != NULL) {
-		error("E-Book query failed: %s", gerr->message);
-		goto done;
-	}
-
-	DBG("");
-
-	evcard = E_VCARD(contact);
-
-	vcard = evcard_to_string(evcard, EVC_FORMAT_VCARD_30,
-					data->params->filter);
-
-	len = vcard ? strlen(vcard) : 0;
-
-	data->count++;
-	data->contacts_cb(vcard, len, 1, 0, TRUE, data->user_data);
-
-	g_free(vcard);
-	g_object_unref(contact);
-
-	return;
-
-done:
-	if (data->queued_calls == 0) {
-		if (data->count == 0)
-			data->contacts_cb(NULL, 0, 1, 0, TRUE,
-						data->user_data);
-		else if (data->canceled)
-			free_query_context(data);
-	}
-}
-
-static char *evcard_name_attribute_to_string(EVCard *evcard)
-{
-	EVCardAttribute *attrib;
-	GList *l;
-	GString *name = NULL;
-
-	attrib = e_vcard_get_attribute(evcard, EVC_N);
-	if (!attrib)
-		return NULL;
-
-	for (l = e_vcard_attribute_get_values(attrib); l; l = l->next) {
-		const char *value = l->data;
-
-		if (!strlen(value))
-			continue;
-
-		if (!name)
-			name = g_string_new(value);
-		else {
-			name = g_string_append(name, ";");
-			name = g_string_append(name, l->data);
-		}
-	}
-
-	if (!name)
-		return NULL;
-
-	return g_string_free(name, FALSE);
-}
-
-static void cache_cb(EBook *book, const GError *gerr, GList *contacts,
-							void *user_data)
-{
-	struct query_context *data = user_data;
-	GList *l;
-
-	data->queued_calls--;
-
-	if (data->canceled)
-		goto canceled;
-
-	if (gerr != NULL) {
-		error("E-Book operation failed: %s", gerr->message);
-		goto done;
-	}
-
-	DBG("");
-
-	for (l = contacts; l; l = g_list_next(l)) {
-		EContact *contact = E_CONTACT(l->data);
-		EVCard *evcard = E_VCARD(contact);
-		EVCardAttribute *attrib;
-		char *uid, *tel, *name;
-
-		name = evcard_name_attribute_to_string(evcard);
-		if (!name)
-			continue;
-
-		attrib = e_vcard_get_attribute(evcard, EVC_UID);
-		if (!attrib)
-			continue;
-
-		uid = e_vcard_attribute_get_value(attrib);
-		if (!uid)
-			continue;
-
-		attrib = e_vcard_get_attribute(evcard, EVC_TEL);
-		if (attrib)
-			tel = e_vcard_attribute_get_value(attrib);
-		else
-			tel = g_strdup("");
-
-		data->entry_cb(uid, PHONEBOOK_INVALID_HANDLE, name, NULL,
-							tel, data->user_data);
-
-		g_free(name);
-		g_free(uid);
-		g_free(tel);
-	}
-
-	g_list_free_full(contacts, g_object_unref);
-
-done:
-	if (data->queued_calls == 0)
-		data->ready_cb(data->user_data);
-
-	return;
-
-canceled:
-	if (data->queued_calls == 0)
-		free_query_context(data);
-}
-
-static GSList *traverse_sources(GSList *ebooks, GSList *sources,
-							char **default_src) {
-	GError *gerr = NULL;
-
-	for (; sources != NULL; sources = g_slist_next(sources)) {
-		char *uri;
-		ESource *source = E_SOURCE(sources->data);
-		EBook *ebook = e_book_new(source, &gerr);
-
-		if (ebook == NULL) {
-			error("Can't create user's address book: %s",
-								gerr->message);
-			g_clear_error(&gerr);
-			continue;
-		}
-
-		uri = e_source_get_uri(source);
-		if (g_strcmp0(*default_src, uri) == 0) {
-			g_free(uri);
-			continue;
-		}
-		g_free(uri);
-
-		if (e_book_open(ebook, FALSE, &gerr) == FALSE) {
-			error("Can't open e-book address book: %s",
-							gerr->message);
-			g_object_unref(ebook);
-			g_clear_error(&gerr);
-			continue;
-		}
-
-		if (*default_src == NULL)
-			*default_src = e_source_get_uri(source);
-
-		DBG("%s address book opened", e_source_peek_name(source));
-
-		ebooks = g_slist_append(ebooks, ebook);
-	}
-
-	return ebooks;
-}
-
-int phonebook_init(void)
-{
-	g_type_init();
-
-	return 0;
-}
-
-static GSList *open_ebooks(void)
-{
-	GError *gerr = NULL;
-	ESourceList *src_list;
-	GSList *list;
-	gchar *default_src = NULL;
-	GSList *ebooks = NULL;
-
-	if (e_book_get_addressbooks(&src_list, &gerr) == FALSE) {
-		error("Can't list user's address books: %s", gerr->message);
-		g_error_free(gerr);
-		return NULL;
-	}
-
-	list = e_source_list_peek_groups(src_list);
-	while (list != NULL) {
-		ESourceGroup *group = E_SOURCE_GROUP(list->data);
-		GSList *sources = e_source_group_peek_sources(group);
-
-		ebooks = traverse_sources(ebooks, sources, &default_src);
-
-		list = list->next;
-	}
-
-	g_free(default_src);
-	g_object_unref(src_list);
-
-	return ebooks;
-}
-
-void phonebook_exit(void)
-{
-}
-
-char *phonebook_set_folder(const char *current_folder,
-		const char *new_folder, uint8_t flags, int *err)
-{
-	gboolean root, child;
-	char *fullname = NULL, *tmp1, *tmp2, *base;
-	int ret = 0, len;
-
-	root = (g_strcmp0("/", current_folder) == 0);
-	child = (new_folder && strlen(new_folder) != 0);
-
-	/* Evolution back-end will support telecom/pb folder only */
-
-	switch (flags) {
-	case 0x02:
-		/* Go back to root */
-		if (!child) {
-			fullname = g_strdup("/");
-			goto done;
-		}
-
-		/* Go down 1 level */
-		fullname = g_build_filename(current_folder, new_folder, NULL);
-		if (strcmp("/telecom", fullname) != 0 &&
-				strcmp("/telecom/pb", fullname) != 0) {
-			g_free(fullname);
-			fullname = NULL;
-			ret = -ENOENT;
-		}
-
-		break;
-	case 0x03:
-		/* Go up 1 level */
-		if (root) {
-			/* Already root */
-			ret = -EBADR;
-			goto done;
-		}
-
-		/*
-		 * Removing one level of the current folder. Current folder
-		 * contains AT LEAST one level since it is not at root folder.
-		 * Use glib utility functions to handle invalid chars in the
-		 * folder path properly.
-		 */
-		tmp1 = g_path_get_basename(current_folder);
-		tmp2 = g_strrstr(current_folder, tmp1);
-		len = tmp2 - (current_folder + 1);
-
-		g_free(tmp1);
-
-		if (len == 0)
-			base = g_strdup("/");
-		else
-			base = g_strndup(current_folder, len);
-
-		/* Return one level only */
-		if (!child) {
-			fullname = base;
-			goto done;
-		}
-
-		fullname = g_build_filename(base, new_folder, NULL);
-		if (strcmp(fullname, "/telecom") != 0 &&
-				strcmp(fullname, "/telecom/pb") != 0) {
-			g_free(fullname);
-			fullname = NULL;
-			ret = -ENOENT;
-		}
-
-		g_free(base);
-
-		break;
-	default:
-		ret = -EBADR;
-		break;
-	}
-
-done:
-	if (err)
-		*err = ret;
-
-	return fullname;
-}
-
-void phonebook_req_finalize(void *request)
-{
-	struct query_context *data = request;
-
-	if (data->queued_calls == 0)
-		free_query_context(data);
-	else
-		data->canceled = TRUE;
-}
-
-void *phonebook_pull(const char *name, const struct apparam_field *params,
-				phonebook_cb cb, void *user_data, int *err)
-{
-	struct query_context *data;
-
-	if (g_strcmp0("/telecom/pb.vcf", name) != 0) {
-		if (err)
-			*err = -ENOENT;
-
-		return NULL;
-	}
-
-	data = g_new0(struct query_context, 1);
-	data->contacts_cb = cb;
-	data->params = params;
-	data->user_data = user_data;
-	data->buf = g_string_new("");
-	data->query = e_book_query_any_field_contains("");
-	data->ebooks = open_ebooks();
-
-	if (err)
-		*err = data->ebooks == NULL ? -EIO : 0;
-
-	return data;
-}
-
-int phonebook_pull_read(void *request)
-{
-	struct query_context *data = request;
-	GSList *l;
-
-	if (!data)
-		return -ENOENT;
-
-	for (l = data->ebooks; l != NULL; l = g_slist_next(l)) {
-		EBook *ebook = l->data;
-
-		if (e_book_is_opened(ebook) == FALSE)
-			continue;
-
-		if (e_book_get_contacts_async(ebook, data->query,
-						ebookpull_cb, data) == TRUE)
-			data->queued_calls++;
-	}
-
-	if (data->queued_calls == 0)
-		return -ENOENT;
-
-	return 0;
-}
-
-void *phonebook_get_entry(const char *folder, const char *id,
-				const struct apparam_field *params,
-				phonebook_cb cb, void *user_data, int *err)
-{
-	struct query_context *data;
-	GSList *l;
-
-	data = g_new0(struct query_context, 1);
-	data->contacts_cb = cb;
-	data->params = params;
-	data->user_data = user_data;
-	data->id = g_strdup(id);
-	data->ebooks = open_ebooks();
-
-	for (l = data->ebooks; l != NULL; l = g_slist_next(l)) {
-		EBook *ebook = l->data;
-
-		if (e_book_is_opened(ebook) == FALSE)
-			continue;
-
-		if (e_book_get_contact_async(ebook, data->id,
-						ebook_entry_cb, data) == TRUE)
-			data->queued_calls++;
-	}
-
-	if (err)
-		*err = (data->queued_calls == 0 ? -ENOENT : 0);
-
-	return data;
-}
-
-void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
-{
-	struct query_context *data;
-	EBookQuery *query;
-	GSList *l;
-	EContact *me;
-	EVCard *evcard;
-	GError *gerr = NULL;
-	EBook *eb;
-	EVCardAttribute *attrib;
-	char *uid, *tel, *cname;
-
-	if (g_strcmp0("/telecom/pb", name) != 0) {
-		if (err)
-			*err = -ENOENT;
-
-		return NULL;
-	}
-
-	DBG("");
-
-	query = e_book_query_any_field_contains("");
-
-	data = g_new0(struct query_context, 1);
-	data->entry_cb = entry_cb;
-	data->ready_cb = ready_cb;
-	data->user_data = user_data;
-	data->query = query;
-	data->ebooks = open_ebooks();
-
-	/* Add 0.vcf */
-	if (e_book_get_self(&me, &eb, &gerr) == FALSE) {
-		g_error_free(gerr);
-		goto next;
-	}
-
-	evcard = E_VCARD(me);
-
-	cname = evcard_name_attribute_to_string(evcard);
-	if (!cname)
-		cname = g_strdup("");
-
-	attrib = e_vcard_get_attribute(evcard, EVC_UID);
-	uid = e_vcard_attribute_get_value(attrib);
-	if (!uid)
-		uid = g_strdup("");
-
-	attrib = e_vcard_get_attribute(evcard, EVC_TEL);
-	if (attrib)
-		tel =  e_vcard_attribute_get_value(attrib);
-	else
-		tel = g_strdup("");
-
-	data->entry_cb(uid, 0, cname, NULL, tel, data->user_data);
-
-	data->count++;
-
-	g_free(cname);
-	g_free(uid);
-	g_free(tel);
-	g_object_unref(eb);
-
-next:
-	for (l = data->ebooks; l != NULL; l = g_slist_next(l)) {
-		EBook *ebook = l->data;
-
-		if (e_book_is_opened(ebook) == FALSE)
-			continue;
-
-		if (e_book_get_contacts_async(ebook, query,
-						cache_cb, data) == TRUE)
-			data->queued_calls++;
-	}
-
-	if (err)
-		*err = (data->queued_calls == 0 ? -ENOENT : 0);
-
-	return data;
-}
diff -pruN 0.46-1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-tracker.c 0.48-2.1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-tracker.c
--- 0.46-1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-tracker.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/.pc/Remove_left_over_glib-helper.h_support.patch/plugins/phonebook-tracker.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,1715 +0,0 @@
-/*
- *  Phonebook access through D-Bus vCard and call history service
- *
- *  Copyright (C) 2010  Nokia Corporation
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <stdio.h>
-#include <errno.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <libtracker-sparql/tracker-sparql.h>
-
-#include "log.h"
-#include "obex.h"
-#include "service.h"
-#include "mimetype.h"
-#include "phonebook.h"
-#include "vcard.h"
-#include "glib-helper.h"
-
-#define TRACKER_SERVICE "org.freedesktop.Tracker1"
-#define TRACKER_RESOURCES_PATH "/org/freedesktop/Tracker1/Resources"
-#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
-
-#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define AFFILATION_HOME "Home"
-#define AFFILATION_WORK "Work"
-#define ADDR_FIELD_AMOUNT 7
-#define PULL_QUERY_COL_AMOUNT 23
-#define COUNT_QUERY_COL_AMOUNT 1
-
-#define COL_PHONE_AFF 0 /* work/home phone numbers */
-#define COL_FULL_NAME 1
-#define COL_FAMILY_NAME 2
-#define COL_GIVEN_NAME 3
-#define COL_ADDITIONAL_NAME 4
-#define COL_NAME_PREFIX 5
-#define COL_NAME_SUFFIX 6
-#define COL_ADDR_AFF 7 /* addresses from affilation */
-#define COL_BIRTH_DATE 8
-#define COL_NICKNAME 9
-#define COL_URL 10
-#define COL_PHOTO 11
-#define COL_ORG_ROLE 12
-#define COL_UID 13
-#define COL_TITLE 14
-#define COL_AFF_TYPE 15
-#define COL_ORG_NAME 16
-#define COL_ORG_DEPARTMENT 17
-#define COL_EMAIL_AFF 18 /* email's from affilation (work/home) */
-#define COL_DATE 19
-#define COL_SENT 20
-#define COL_ANSWERED 21
-#define CONTACTS_ID_COL 22
-#define CONTACT_ID_PREFIX "urn:uuid:"
-#define CALL_ID_PREFIX "message:"
-
-#define FAX_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#FaxNumber"
-#define MOBILE_NUM_TYPE "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#CellPhoneNumber"
-
-#define MAIN_DELIM "\30" /* Main delimiter between phones, addresses, emails*/
-#define SUB_DELIM "\31" /* Delimiter used in telephone number strings*/
-#define ADDR_DELIM "\37" /* Delimiter used for address data fields */
-#define MAX_FIELDS 100 /* Max amount of fields to be concatenated at once*/
-#define VCARDS_PART_COUNT 50 /* amount of vcards sent at once to PBAP core */
-#define QUERY_OFFSET_FORMAT "%s OFFSET %d"
-
-#define CONTACTS_QUERY_ALL						\
-"SELECT "								\
-"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?aff_number),"			\
-"\"\31\", nco:phoneNumber(?aff_number)), \"\30\")"			\
-"WHERE {"								\
-"	?_role nco:hasPhoneNumber ?aff_number"				\
-"}) "									\
-"nco:fullname(?_contact) "						\
-"nco:nameFamily(?_contact) "						\
-"nco:nameGiven(?_contact) "						\
-"nco:nameAdditional(?_contact) "					\
-"nco:nameHonorificPrefix(?_contact) "					\
-"nco:nameHonorificSuffix(?_contact) "					\
-"(SELECT GROUP_CONCAT(fn:concat("					\
-"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \"\37\","	\
-"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \"\37\","	\
-"tracker:coalesce(nco:locality(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:region(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:country(?aff_addr), \"\"), "			\
-"\"\31\", rdfs:label(?_role) ), "					\
-"\"\30\") "								\
-"WHERE {"								\
-"?_role nco:hasPostalAddress ?aff_addr"					\
-"}) "									\
-"nco:birthDate(?_contact) "						\
-"(SELECT "								\
-"	?nick "								\
-"	WHERE { "							\
-"		{ "							\
-"			?_contact nco:nickname ?nick "			\
-"		} UNION { "						\
-"			?_contact nco:hasAffiliation ?role . "		\
-"			?role nco:hasIMAddress ?im . "			\
-"			?im nco:imNickname ?nick "			\
-"		} "							\
-"	} "								\
-") "									\
-"(SELECT GROUP_CONCAT(fn:concat( "					\
-	"?url_val, \"\31\", tracker:coalesce(rdfs:label(?_role), \"\") "\
-	"), \"\30\") "							\
-	"WHERE {"							\
-		"?_role nco:url ?url_val . "				\
-"})"									\
-"nie:url(nco:photo(?_contact)) "					\
-"nco:role(?_role) "							\
-"nco:contactUID(?_contact) "						\
-"nco:title(?_role) "							\
-"rdfs:label(?_role) "							\
-"nco:fullname(nco:org(?_role))"						\
-"nco:department(?_role) "						\
-"(SELECT GROUP_CONCAT(fn:concat(?emailaddress,\"\31\","			\
-	"tracker:coalesce(rdfs:label(?_role), \"\")),"			\
-	"\"\30\") "							\
-	"WHERE { "							\
-	"?_role nco:hasEmailAddress "					\
-	"		[ nco:emailAddress ?emailaddress ] "		\
-	"}) "								\
-"\"NOTACALL\" \"false\" \"false\" "					\
-"?_contact "								\
-"WHERE {"								\
-"	?_contact a nco:PersonContact ."				\
-"	OPTIONAL {?_contact nco:hasAffiliation ?_role .}"		\
-"}"									\
-"ORDER BY tracker:id(?_contact)"
-
-#define CONTACTS_QUERY_ALL_LIST						\
-	"SELECT ?c nco:nameFamily(?c) "					\
-	"nco:nameGiven(?c) nco:nameAdditional(?c) "			\
-	"nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c) "	\
-	"(SELECT "							\
-		"?nick "						\
-		"WHERE { "						\
-			"{ "						\
-				"?c nco:nickname ?nick "		\
-			"} UNION { "					\
-				"?c nco:hasAffiliation ?role . "	\
-				"?role nco:hasIMAddress ?im . "		\
-				"?im nco:imNickname ?nick "		\
-			"} "						\
-		"} "							\
-	") "								\
-	"nco:phoneNumber(?h) "						\
-	"WHERE { "							\
-		"?c a nco:PersonContact . "				\
-	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
-	"OPTIONAL { "							\
-		"?c nco:hasAffiliation ?a . "				\
-		"?a nco:hasPhoneNumber ?h . "				\
-	"} "								\
-	"} GROUP BY ?c"
-
-#define CALLS_CONSTRAINTS(CONSTRAINT)					\
-" WHERE { "								\
-	"?_call a nmo:Call . "						\
-	"?_unb_contact a nco:Contact . "				\
-	"?_unb_contact nco:hasPhoneNumber ?_cpn . "			\
-CONSTRAINT								\
-	"OPTIONAL { "							\
-		"{ SELECT ?_contact ?_no ?_role ?_number "		\
-			"count(?_contact) as ?cnt "			\
-		"WHERE { "						\
-			"?_contact a nco:PersonContact . "		\
-			"{ "						\
-				"?_contact nco:hasAffiliation ?_role . "\
-				"?_role nco:hasPhoneNumber ?_number . " \
-			"} UNION { "					\
-				"?_contact nco:hasPhoneNumber ?_number" \
-			"} "						\
-			"?_number maemo:localPhoneNumber ?_no . "	\
-		"} GROUP BY ?_no } "					\
-		"FILTER(?cnt = 1) "					\
-		"?_cpn maemo:localPhoneNumber ?_no . "			\
-	"} "								\
-"} "
-
-#define CALLS_LIST(CONSTRAINT)						\
-"SELECT ?_call nco:nameFamily(?_contact) "				\
-	"nco:nameGiven(?_contact) nco:nameAdditional(?_contact) "	\
-	"nco:nameHonorificPrefix(?_contact) "				\
-	"nco:nameHonorificSuffix(?_contact) "				\
-	"(SELECT "							\
-		"?nick "						\
-		"WHERE { "						\
-			"{ "						\
-				"?_contact nco:nickname ?nick "		\
-			"} UNION { "					\
-				"?_contact nco:hasAffiliation ?role . "	\
-				"?role nco:hasIMAddress ?im . "		\
-				"?im nco:imNickname ?nick "		\
-			"} "						\
-		"} "							\
-	") "								\
-	"nco:phoneNumber(?_cpn) "					\
-CALLS_CONSTRAINTS(CONSTRAINT)						\
-"ORDER BY DESC(nmo:sentDate(?_call)) "
-
-#define CALLS_QUERY(CONSTRAINT)						\
-"SELECT "								\
-"(SELECT fn:concat(rdf:type(?role_number),"				\
-	"\"\31\", nco:phoneNumber(?role_number))"			\
-	"WHERE {"							\
-	"{"								\
-	"	?_role nco:hasPhoneNumber ?role_number "		\
-	"	FILTER (?role_number = ?_number)"			\
-	"} UNION { "							\
-		"?_unb_contact nco:hasPhoneNumber ?role_number . "	\
-	"	FILTER (!bound(?_role)) "				\
-	"}"								\
-"} GROUP BY nco:phoneNumber(?role_number) ) "				\
-	"nco:fullname(?_contact) "					\
-	"nco:nameFamily(?_contact) "					\
-	"nco:nameGiven(?_contact) "					\
-	"nco:nameAdditional(?_contact) "				\
-	"nco:nameHonorificPrefix(?_contact) "				\
-	"nco:nameHonorificSuffix(?_contact) "				\
-"(SELECT GROUP_CONCAT(fn:concat("					\
-	"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \"\37\","	\
-	"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \"\37\","\
-	"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \"\37\","\
-	"tracker:coalesce(nco:locality(?aff_addr), \"\"), \"\37\","	\
-	"tracker:coalesce(nco:region(?aff_addr), \"\"), \"\37\","	\
-	"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \"\37\","	\
-	"tracker:coalesce(nco:country(?aff_addr), \"\"), "		\
-	"\"\31\", rdfs:label(?c_role) ), "				\
-	"\"\30\") "							\
-	"WHERE {"							\
-	"?_contact nco:hasAffiliation ?c_role . "			\
-	"?c_role nco:hasPostalAddress ?aff_addr"			\
-	"}) "								\
-	"nco:birthDate(?_contact) "					\
-"(SELECT "								\
-	"?nick "							\
-	"WHERE { "							\
-	"	{ "							\
-	"	?_contact nco:nickname ?nick "				\
-	"		} UNION { "					\
-	"			?_contact nco:hasAffiliation ?role . "	\
-	"			?role nco:hasIMAddress ?im . "		\
-	"			?im nco:imNickname ?nick "		\
-	"		} "						\
-	"	} "							\
-	") "								\
-"(SELECT GROUP_CONCAT(fn:concat(?url_value, \"\31\", "			\
-	"tracker:coalesce(rdfs:label(?c_role), \"\")), \"\30\") "	\
-	"WHERE {"							\
-		"?_contact nco:hasAffiliation ?c_role . "		\
-		"?c_role nco:url ?url_value . "				\
-"})"									\
-	"nie:url(nco:photo(?_contact)) "				\
-	"nco:role(?_role) "						\
-	"nco:contactUID(?_contact) "					\
-	"nco:title(?_role) "						\
-	"rdfs:label(?_role) "						\
-	"nco:fullname(nco:org(?_role)) "				\
-	"nco:department(?_role) "					\
-"(SELECT GROUP_CONCAT(fn:concat(?emailaddress,\"\31\","			\
-	"tracker:coalesce(rdfs:label(?c_role), \"\")),"			\
-	"\"\30\") "							\
-	"WHERE { "							\
-	"?_contact nco:hasAffiliation ?c_role . "			\
-	"?c_role nco:hasEmailAddress "					\
-	"		[ nco:emailAddress ?emailaddress ] "		\
-	"}) "								\
-	"nmo:receivedDate(?_call) "					\
-	"nmo:isSent(?_call) "						\
-	"nmo:isAnswered(?_call) "					\
-	"?_call "							\
-CALLS_CONSTRAINTS(CONSTRAINT)						\
-"ORDER BY DESC(nmo:sentDate(?_call)) "
-
-#define MISSED_CONSTRAINT		\
-"?_call nmo:from ?_unb_contact . "	\
-"?_call nmo:isSent false . "		\
-"?_call nmo:isAnswered false . "
-
-#define INCOMING_CONSTRAINT		\
-"?_call nmo:from ?_unb_contact . "	\
-"?_call nmo:isSent false . "		\
-"?_call nmo:isAnswered true . "
-
-#define OUTGOING_CONSTRAINT		\
-"?_call nmo:to ?_unb_contact . "	\
-"?_call nmo:isSent true . "
-
-#define COMBINED_CONSTRAINT			\
-"{ "						\
-"	?_call nmo:from ?_unb_contact .  "	\
-"	?_call nmo:isSent false "		\
-"} UNION { "					\
-"	?_call nmo:to ?_unb_contact . "		\
-"	?_call nmo:isSent true "		\
-"} "
-
-#define CALL_URI_CONSTRAINT	\
-COMBINED_CONSTRAINT		\
-"FILTER (?_call = <%s>) "
-
-#define MISSED_CALLS_QUERY CALLS_QUERY(MISSED_CONSTRAINT)
-#define MISSED_CALLS_LIST CALLS_LIST(MISSED_CONSTRAINT)
-#define INCOMING_CALLS_QUERY CALLS_QUERY(INCOMING_CONSTRAINT)
-#define INCOMING_CALLS_LIST CALLS_LIST(INCOMING_CONSTRAINT)
-#define OUTGOING_CALLS_QUERY CALLS_QUERY(OUTGOING_CONSTRAINT)
-#define OUTGOING_CALLS_LIST CALLS_LIST(OUTGOING_CONSTRAINT)
-#define COMBINED_CALLS_QUERY CALLS_QUERY(COMBINED_CONSTRAINT)
-#define COMBINED_CALLS_LIST CALLS_LIST(COMBINED_CONSTRAINT)
-#define CONTACT_FROM_CALL_QUERY CALLS_QUERY(CALL_URI_CONSTRAINT)
-
-#define CONTACTS_QUERY_FROM_URI						\
-"SELECT "								\
-"(SELECT GROUP_CONCAT(fn:concat(rdf:type(?aff_number),"			\
-"\"\31\", nco:phoneNumber(?aff_number)), \"\30\")"			\
-"WHERE {"								\
-"	?_role nco:hasPhoneNumber ?aff_number"				\
-"}) "									\
-"nco:fullname(<%s>) "							\
-"nco:nameFamily(<%s>) "							\
-"nco:nameGiven(<%s>) "							\
-"nco:nameAdditional(<%s>) "						\
-"nco:nameHonorificPrefix(<%s>) "					\
-"nco:nameHonorificSuffix(<%s>) "					\
-"(SELECT GROUP_CONCAT(fn:concat("					\
-"tracker:coalesce(nco:pobox(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:extendedAddress(?aff_addr), \"\"), \"\37\","	\
-"tracker:coalesce(nco:streetAddress(?aff_addr), \"\"), \"\37\","	\
-"tracker:coalesce(nco:locality(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:region(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:postalcode(?aff_addr), \"\"), \"\37\","		\
-"tracker:coalesce(nco:country(?aff_addr), \"\"), "			\
-"\"\31\", rdfs:label(?_role) ), "					\
-"\"\30\") "								\
-"WHERE {"								\
-"?_role nco:hasPostalAddress ?aff_addr"					\
-"}) "									\
-"nco:birthDate(<%s>) "							\
-"(SELECT "								\
-"	?nick "								\
-"	WHERE { "							\
-"		{ "							\
-"			?_contact nco:nickname ?nick "			\
-"		} UNION { "						\
-"			?_contact nco:hasAffiliation ?role . "		\
-"			?role nco:hasIMAddress ?im . "			\
-"			?im nco:imNickname ?nick "			\
-"		} "							\
-"		FILTER (?_contact = <%s>)"				\
-"	} "								\
-") "									\
-"(SELECT GROUP_CONCAT(fn:concat( "					\
-	"?url_val, \"\31\", tracker:coalesce(rdfs:label(?_role), \"\") "\
-	"), \"\30\") "							\
-	"WHERE {"							\
-		"?_role nco:url ?url_val . "				\
-"})"									\
-"nie:url(nco:photo(<%s>)) "						\
-"nco:role(?_role) "							\
-"nco:contactUID(<%s>) "							\
-"nco:title(?_role) "							\
-"rdfs:label(?_role) "							\
-"nco:fullname(nco:org(?_role))"						\
-"nco:department(?_role) "						\
-"(SELECT GROUP_CONCAT(fn:concat(?emailaddress,\"\31\","			\
-	"tracker:coalesce(rdfs:label(?_role), \"\")),"			\
-	"\"\30\") "							\
-	"WHERE { "							\
-	"?_role nco:hasEmailAddress "					\
-	"		[ nco:emailAddress ?emailaddress ] "		\
-	"}) "								\
-"\"NOTACALL\" \"false\" \"false\" "					\
-"<%s> "									\
-"WHERE {"								\
-"	<%s> a nco:PersonContact ."					\
-"	OPTIONAL {<%s> nco:hasAffiliation ?_role .}"			\
-"}"
-
-#define CONTACTS_OTHER_QUERY_FROM_URI					\
-	"SELECT fn:concat(\"TYPE_OTHER\", \"\31\", nco:phoneNumber(?t))"\
-	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "			\
-	"\"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" \"\" "		\
-	" \"NOTACALL\" \"false\" \"false\" <%s> "			\
-	"WHERE { "							\
-		"<%s> a nco:Contact . "					\
-		"OPTIONAL { <%s> nco:hasPhoneNumber ?t . } "		\
-	"} "
-
-#define CONTACTS_COUNT_QUERY						\
-	"SELECT COUNT(?c) "						\
-	"WHERE {"							\
-		"?c a nco:PersonContact ."				\
-	"}"
-
-#define MISSED_CALLS_COUNT_QUERY					\
-	"SELECT COUNT(?call) WHERE {"					\
-		"?c a nco:Contact ;"					\
-		"nco:hasPhoneNumber ?h ."				\
-		"?call a nmo:Call ;"					\
-		"nmo:isSent false ;"					\
-		"nmo:from ?c ;"						\
-		"nmo:isAnswered false ."				\
-	"}"
-
-#define INCOMING_CALLS_COUNT_QUERY					\
-	"SELECT COUNT(?call) WHERE {"					\
-		"?c a nco:Contact ;"					\
-		"nco:hasPhoneNumber ?h ."				\
-		"?call a nmo:Call ;"					\
-		"nmo:isSent false ;"					\
-		"nmo:from ?c ;"						\
-		"nmo:isAnswered true ."					\
-	"}"
-
-#define OUTGOING_CALLS_COUNT_QUERY					\
-	"SELECT COUNT(?call) WHERE {"					\
-		"?c a nco:Contact ;"					\
-		"nco:hasPhoneNumber ?h ."				\
-		"?call a nmo:Call ;"					\
-		"nmo:isSent true ;"					\
-		"nmo:to ?c ."						\
-	"}"
-
-#define COMBINED_CALLS_COUNT_QUERY					\
-	"SELECT COUNT(?call) WHERE {"					\
-	"{"								\
-		"?c a nco:Contact ;"					\
-		"nco:hasPhoneNumber ?h ."				\
-		"?call a nmo:Call ;"					\
-		"nmo:isSent true ;"					\
-		"nmo:to ?c ."						\
-	"}UNION {"							\
-		"?c a nco:Contact ;"					\
-		"nco:hasPhoneNumber ?h ."				\
-		"?call a nmo:Call ;"					\
-		"nmo:from ?c ."						\
-	"}"								\
-	"}"
-
-#define NEW_MISSED_CALLS_COUNT_QUERY					\
-	"SELECT COUNT(?call) WHERE {"					\
-		"?c a nco:Contact ;"					\
-		"nco:hasPhoneNumber ?h ."				\
-		"?call a nmo:Call ;"					\
-		"nmo:isSent false ;"					\
-		"nmo:from ?c ;"						\
-		"nmo:isAnswered false ;"				\
-		"nmo:isRead false ."					\
-	"}"
-
-typedef int (*reply_list_foreach_t) (const char **reply, int num_fields,
-							void *user_data);
-
-typedef void (*add_field_t) (struct phonebook_contact *contact,
-						const char *value, int type);
-
-struct pending_reply {
-	reply_list_foreach_t callback;
-	void *user_data;
-	int num_fields;
-};
-
-struct contact_data {
-	char *id;
-	struct phonebook_contact *contact;
-};
-
-struct phonebook_data {
-	phonebook_cb cb;
-	void *user_data;
-	int index;
-	gboolean vcardentry;
-	const struct apparam_field *params;
-	GSList *contacts;
-	phonebook_cache_ready_cb ready_cb;
-	phonebook_entry_cb entry_cb;
-	int newmissedcalls;
-	GCancellable *query_canc;
-	char *req_name;
-	int vcard_part_count;
-	int tracker_index;
-};
-
-struct phonebook_index {
-	GArray *phonebook;
-	int index;
-};
-
-static TrackerSparqlConnection *connection = NULL;
-
-static const char *name2query(const char *name)
-{
-	if (g_str_equal(name, "/telecom/pb.vcf"))
-		return CONTACTS_QUERY_ALL;
-	else if (g_str_equal(name, "/telecom/ich.vcf"))
-		return INCOMING_CALLS_QUERY;
-	else if (g_str_equal(name, "/telecom/och.vcf"))
-		return OUTGOING_CALLS_QUERY;
-	else if (g_str_equal(name, "/telecom/mch.vcf"))
-		return MISSED_CALLS_QUERY;
-	else if (g_str_equal(name, "/telecom/cch.vcf"))
-		return COMBINED_CALLS_QUERY;
-
-	return NULL;
-}
-
-static const char *name2count_query(const char *name)
-{
-	if (g_str_equal(name, "/telecom/pb.vcf"))
-		return CONTACTS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/ich.vcf"))
-		return INCOMING_CALLS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/och.vcf"))
-		return OUTGOING_CALLS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/mch.vcf"))
-		return MISSED_CALLS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/cch.vcf"))
-		return COMBINED_CALLS_COUNT_QUERY;
-
-	return NULL;
-}
-
-static gboolean folder_is_valid(const char *folder)
-{
-	if (folder == NULL)
-		return FALSE;
-
-	if (g_str_equal(folder, "/"))
-		return TRUE;
-	else if (g_str_equal(folder, "/telecom"))
-		return TRUE;
-	else if (g_str_equal(folder, "/telecom/pb"))
-		return TRUE;
-	else if (g_str_equal(folder, "/telecom/ich"))
-		return TRUE;
-	else if (g_str_equal(folder, "/telecom/och"))
-		return TRUE;
-	else if (g_str_equal(folder, "/telecom/mch"))
-		return TRUE;
-	else if (g_str_equal(folder, "/telecom/cch"))
-		return TRUE;
-
-	return FALSE;
-}
-
-static const char *folder2query(const char *folder)
-{
-	if (g_str_equal(folder, "/telecom/pb"))
-		return CONTACTS_QUERY_ALL_LIST;
-	else if (g_str_equal(folder, "/telecom/ich"))
-		return INCOMING_CALLS_LIST;
-	else if (g_str_equal(folder, "/telecom/och"))
-		return OUTGOING_CALLS_LIST;
-	else if (g_str_equal(folder, "/telecom/mch"))
-		return MISSED_CALLS_LIST;
-	else if (g_str_equal(folder, "/telecom/cch"))
-		return COMBINED_CALLS_LIST;
-
-	return NULL;
-}
-
-static const char **string_array_from_cursor(TrackerSparqlCursor *cursor,
-								int array_len)
-{
-	const char **result;
-	int i;
-
-	result = g_new0(const char *, array_len);
-
-	for (i = 0; i < array_len; ++i) {
-		TrackerSparqlValueType type;
-
-		type = tracker_sparql_cursor_get_value_type(cursor, i);
-
-		if (type == TRACKER_SPARQL_VALUE_TYPE_BLANK_NODE ||
-				type == TRACKER_SPARQL_VALUE_TYPE_UNBOUND)
-			/* For null/unbound type filling result part with ""*/
-			result[i] = "";
-		else
-			/* Filling with string representation of content*/
-			result[i] = tracker_sparql_cursor_get_string(cursor, i,
-									NULL);
-	}
-
-	return result;
-}
-
-static void update_cancellable(struct phonebook_data *pdata,
-							GCancellable *canc)
-{
-	if (pdata->query_canc)
-		g_object_unref(pdata->query_canc);
-
-	pdata->query_canc = canc;
-}
-
-static void async_query_cursor_next_cb(GObject *source, GAsyncResult *result,
-							gpointer user_data)
-{
-	struct pending_reply *pending = user_data;
-	TrackerSparqlCursor *cursor = TRACKER_SPARQL_CURSOR(source);
-	GCancellable *cancellable;
-	GError *error = NULL;
-	gboolean success;
-	const char **node;
-	int err;
-
-	success = tracker_sparql_cursor_next_finish(
-						TRACKER_SPARQL_CURSOR(source),
-						result, &error);
-
-	if (!success) {
-		if (error) {
-			DBG("cursor_next error: %s", error->message);
-			g_error_free(error);
-		} else
-			/* When tracker_sparql_cursor_next_finish ends with
-			 * failure and no error is set, that means end of
-			 * results returned by query */
-			pending->callback(NULL, 0, pending->user_data);
-
-		goto failed;
-	}
-
-	node = string_array_from_cursor(cursor, pending->num_fields);
-	err = pending->callback(node, pending->num_fields, pending->user_data);
-	g_free(node);
-
-	/* Fetch next result only if processing current chunk ended with
-	 * success. Sometimes during processing data, we are able to determine
-	 * if there is no need to get more data from tracker - by example
-	 * stored amount of data parts is big enough for sending and we might
-	 * want to suspend processing or just some error occurred. */
-	if (!err) {
-		cancellable = g_cancellable_new();
-		update_cancellable(pending->user_data, cancellable);
-		tracker_sparql_cursor_next_async(cursor, cancellable,
-						async_query_cursor_next_cb,
-						pending);
-		return;
-	}
-
-failed:
-	g_object_unref(cursor);
-	g_free(pending);
-}
-
-static int query_tracker(const char *query, int num_fields,
-				reply_list_foreach_t callback, void *user_data)
-{
-	struct pending_reply *pending;
-	GCancellable *cancellable;
-	TrackerSparqlCursor *cursor;
-	GError *error = NULL;
-
-	DBG("");
-
-	if (connection == NULL)
-		connection = tracker_sparql_connection_get_direct(
-								NULL, &error);
-
-	if (!connection) {
-		if (error) {
-			DBG("direct-connection error: %s", error->message);
-			g_error_free(error);
-		}
-
-		return -EINTR;
-	}
-
-	cancellable = g_cancellable_new();
-	update_cancellable(user_data, cancellable);
-	cursor = tracker_sparql_connection_query(connection, query,
-							cancellable, &error);
-
-	if (cursor == NULL) {
-		if (error) {
-			DBG("connection_query error: %s", error->message);
-			g_error_free(error);
-		}
-
-		g_object_unref(cancellable);
-
-		return -EINTR;
-	}
-
-	pending = g_new0(struct pending_reply, 1);
-	pending->callback = callback;
-	pending->user_data = user_data;
-	pending->num_fields = num_fields;
-
-	/* Now asynchronously going through each row of results - callback
-	 * async_query_cursor_next_cb will be called ALWAYS, even if async
-	 * request was canceled */
-	tracker_sparql_cursor_next_async(cursor, cancellable,
-						async_query_cursor_next_cb,
-						pending);
-
-	return 0;
-}
-
-static char *iso8601_utc_to_localtime(const char *datetime)
-{
-	time_t time;
-	struct tm tm, *local;
-	char localdate[32];
-	int nr;
-
-	memset(&tm, 0, sizeof(tm));
-
-	nr = sscanf(datetime, "%04u-%02u-%02uT%02u:%02u:%02u",
-			&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
-			&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
-	if (nr < 6) {
-		/* Invalid time format */
-		error("sscanf(): %s (%d)", strerror(errno), errno);
-		return g_strdup("");
-	}
-
-	/* Time already in localtime */
-	if (!g_str_has_suffix(datetime, "Z")) {
-		strftime(localdate, sizeof(localdate), "%Y%m%dT%H%M%S", &tm);
-		return g_strdup(localdate);
-	}
-
-	tm.tm_year -= 1900;	/* Year since 1900 */
-	tm.tm_mon--;		/* Months since January, values 0-11 */
-
-	time = mktime(&tm);
-	time -= timezone;
-
-	local = localtime(&time);
-
-	strftime(localdate, sizeof(localdate), "%Y%m%dT%H%M%S", local);
-
-	return g_strdup(localdate);
-}
-
-static void set_call_type(struct phonebook_contact *contact,
-				const char *datetime, const char *is_sent,
-				const char *is_answered)
-{
-	gboolean sent, answered;
-
-	if (g_strcmp0(datetime, "NOTACALL") == 0) {
-		contact->calltype = CALL_TYPE_NOT_A_CALL;
-		return;
-	}
-
-	sent = g_str_equal(is_sent, "true");
-	answered = g_str_equal(is_answered, "true");
-
-	if (sent == FALSE) {
-		if (answered == FALSE)
-			contact->calltype = CALL_TYPE_MISSED;
-		else
-			contact->calltype = CALL_TYPE_INCOMING;
-	} else
-		contact->calltype = CALL_TYPE_OUTGOING;
-
-	/* Tracker gives time in the ISO 8601 format, UTC time */
-	contact->datetime = iso8601_utc_to_localtime(datetime);
-}
-
-static gboolean contact_matches(struct contact_data *c_data, const char *id,
-							const char *datetime)
-{
-	char *localtime;
-	int cmp_ret;
-
-	if (g_strcmp0(c_data->id, id) != 0)
-		return FALSE;
-
-	/* id is equal and not call history entry => contact matches */
-	if (c_data->contact->calltype == CALL_TYPE_NOT_A_CALL)
-		return TRUE;
-
-	/* for call history entries have to compare also timestamps of calls */
-	localtime = iso8601_utc_to_localtime(datetime);
-	cmp_ret = g_strcmp0(c_data->contact->datetime, localtime);
-	g_free(localtime);
-
-	return (cmp_ret == 0) ? TRUE : FALSE;
-}
-
-static struct phonebook_contact *find_contact(GSList *contacts, const char *id,
-							const char *datetime)
-{
-	GSList *l;
-
-	for (l = contacts; l; l = l->next) {
-		struct contact_data *c_data = l->data;
-
-		if (contact_matches(c_data, id, datetime))
-			return c_data->contact;
-	}
-
-	return NULL;
-}
-
-static struct phonebook_field *find_field(GSList *fields, const char *value,
-								int type)
-{
-	GSList *l;
-
-	for (l = fields; l; l = l->next) {
-		struct phonebook_field *field = l->data;
-		/* Returning phonebook number if phone values and type values
-		 * are equal */
-		if (g_strcmp0(field->text, value) == 0 && field->type == type)
-			return field;
-	}
-
-	return NULL;
-}
-
-static void add_phone_number(struct phonebook_contact *contact,
-						const char *phone, int type)
-{
-	struct phonebook_field *number;
-
-	if (phone == NULL || strlen(phone) == 0)
-		return;
-
-	/* Not adding number if there is already added with the same value */
-	if (find_field(contact->numbers, phone, type))
-		return;
-
-	number = g_new0(struct phonebook_field, 1);
-	number->text = g_strdup(phone);
-	number->type = type;
-
-	contact->numbers = g_slist_append(contact->numbers, number);
-}
-
-static void add_email(struct phonebook_contact *contact, const char *address,
-								int type)
-{
-	struct phonebook_field *email;
-
-	if (address == NULL || strlen(address) == 0)
-		return;
-
-	/* Not adding email if there is already added with the same value */
-	if (find_field(contact->emails, address, type))
-		return;
-
-	email = g_new0(struct phonebook_field, 1);
-	email->text = g_strdup(address);
-	email->type = type;
-
-	contact->emails = g_slist_append(contact->emails, email);
-}
-
-static gboolean addr_matches(struct phonebook_addr *a, struct phonebook_addr *b)
-{
-	GSList *la, *lb;
-
-	if (a->type != b->type)
-		return FALSE;
-
-	for (la = a->fields, lb = b->fields; la && lb;
-						la = la->next, lb = lb->next) {
-		char *field_a = la->data;
-		char *field_b = lb->data;
-
-		if (g_strcmp0(field_a, field_b) != 0)
-			return FALSE;
-	}
-
-	return TRUE;
-}
-
-/* generates phonebook_addr struct from tracker address data string. */
-static struct phonebook_addr *gen_addr(const char *address, int type)
-{
-	struct phonebook_addr *addr;
-	GSList *fields = NULL;
-	char **addr_parts;
-	int i;
-
-	/* This test handles cases when address points to empty string
-	 * (or address is NULL pointer) or string containing only six
-	 * separators. It indicates that none of address fields is present
-	 * and there is no sense to create dummy phonebook_addr struct */
-	if (address == NULL || strlen(address) < ADDR_FIELD_AMOUNT)
-		return NULL;
-
-	addr_parts = g_strsplit(address, ADDR_DELIM, ADDR_FIELD_AMOUNT);
-
-	for (i = 0; i < ADDR_FIELD_AMOUNT; ++i)
-		fields = g_slist_append(fields, g_strdup(addr_parts[i]));
-
-	g_strfreev(addr_parts);
-
-	addr = g_new0(struct phonebook_addr, 1);
-	addr->fields = fields;
-	addr->type = type;
-
-	return addr;
-}
-
-static void add_address(struct phonebook_contact *contact,
-					const char *address, int type)
-{
-	struct phonebook_addr *addr;
-	GSList *l;
-
-	addr = gen_addr(address, type);
-	if (addr == NULL)
-		return;
-
-	/* Not adding address if there is already added with the same value.
-	 * These type of checks have to be done because sometimes tracker
-	 * returns results for contact data in more than 1 row - then the same
-	 * address may be returned more than once in query results */
-	for (l = contact->addresses; l; l = l->next) {
-		struct phonebook_addr *tmp = l->data;
-
-		if (addr_matches(tmp, addr)) {
-			phonebook_addr_free(addr);
-			return;
-		}
-	}
-
-	contact->addresses = g_slist_append(contact->addresses, addr);
-}
-
-static void add_url(struct phonebook_contact *contact, const char *url_val,
-								int type)
-{
-	struct phonebook_field *url;
-
-	if (url_val == NULL || strlen(url_val) == 0)
-		return;
-
-	/* Not adding url if there is already added with the same value */
-	if (find_field(contact->urls, url_val, type))
-		return;
-
-	url = g_new0(struct phonebook_field, 1);
-
-	url->text = g_strdup(url_val);
-	url->type = type;
-
-	contact->urls = g_slist_append(contact->urls, url);
-}
-
-static GString *gen_vcards(GSList *contacts,
-					const struct apparam_field *params)
-{
-	GSList *l;
-	GString *vcards;
-
-	vcards = g_string_new(NULL);
-
-	/* Generating VCARD string from contacts and freeing used contacts */
-	for (l = contacts; l; l = l->next) {
-		struct contact_data *c_data = l->data;
-		phonebook_add_contact(vcards, c_data->contact,
-					params->filter, params->format);
-	}
-
-	return vcards;
-}
-
-static int pull_contacts_size(const char **reply, int num_fields,
-							void *user_data)
-{
-	struct phonebook_data *data = user_data;
-
-	if (num_fields < 0) {
-		data->cb(NULL, 0, num_fields, 0, TRUE, data->user_data);
-		return -EINTR;
-	}
-
-	if (reply != NULL) {
-		data->index = atoi(reply[0]);
-		return 0;
-	}
-
-	data->cb(NULL, 0, data->index, data->newmissedcalls, TRUE,
-							data->user_data);
-
-	return 0;
-	/*
-	 * phonebook_data is freed in phonebook_req_finalize. Useful in
-	 * cases when call is terminated.
-	 */
-}
-
-static void add_affiliation(char **field, const char *value)
-{
-	if (strlen(*field) > 0 || value == NULL || strlen(value) == 0)
-		return;
-
-	g_free(*field);
-
-	*field = g_strdup(value);
-}
-
-static void contact_init(struct phonebook_contact *contact,
-							const char **reply)
-{
-	if (reply[COL_FAMILY_NAME][0] == '\0' &&
-			reply[COL_GIVEN_NAME][0] == '\0' &&
-			reply[COL_ADDITIONAL_NAME][0] == '\0' &&
-			reply[COL_NAME_PREFIX][0] == '\0' &&
-			reply[COL_NAME_SUFFIX][0] == '\0') {
-		if (reply[COL_FULL_NAME][0] != '\0')
-			contact->family = g_strdup(reply[COL_FULL_NAME]);
-		else
-			contact->family = g_strdup(reply[COL_NICKNAME]);
-	} else {
-		contact->family = g_strdup(reply[COL_FAMILY_NAME]);
-		contact->given = g_strdup(reply[COL_GIVEN_NAME]);
-		contact->additional = g_strdup(reply[COL_ADDITIONAL_NAME]);
-		contact->prefix = g_strdup(reply[COL_NAME_PREFIX]);
-		contact->suffix = g_strdup(reply[COL_NAME_SUFFIX]);
-	}
-	contact->fullname = g_strdup(reply[COL_FULL_NAME]);
-	contact->birthday = g_strdup(reply[COL_BIRTH_DATE]);
-	contact->nickname = g_strdup(reply[COL_NICKNAME]);
-	contact->photo = g_strdup(reply[COL_PHOTO]);
-	contact->company = g_strdup(reply[COL_ORG_NAME]);
-	contact->department = g_strdup(reply[COL_ORG_DEPARTMENT]);
-	contact->role = g_strdup(reply[COL_ORG_ROLE]);
-	contact->uid = g_strdup(reply[COL_UID]);
-	contact->title = g_strdup(reply[COL_TITLE]);
-
-	set_call_type(contact, reply[COL_DATE], reply[COL_SENT],
-							reply[COL_ANSWERED]);
-}
-
-static enum phonebook_number_type get_phone_type(const char *affilation)
-{
-	if (g_strcmp0(AFFILATION_HOME, affilation) == 0)
-		return TEL_TYPE_HOME;
-	else if (g_strcmp0(AFFILATION_WORK, affilation) == 0)
-		return TEL_TYPE_WORK;
-
-	return TEL_TYPE_OTHER;
-}
-
-static void add_aff_number(struct phonebook_contact *contact,
-				const char *pnumber, const char *aff_type)
-{
-	char **num_parts;
-	char *type, *number;
-
-	/* For phone taken directly from contacts data, phone number string
-	 * is represented as number type and number string - those strings are
-	 * separated by SUB_DELIM string */
-	num_parts = g_strsplit(pnumber, SUB_DELIM, 2);
-
-	if (!num_parts)
-		return;
-
-	if (num_parts[0])
-		type = num_parts[0];
-	else
-		goto failed;
-
-	if (num_parts[1])
-		number = num_parts[1];
-	else
-		goto failed;
-
-	if (g_strrstr(type, FAX_NUM_TYPE))
-		add_phone_number(contact, number, TEL_TYPE_FAX);
-	else if (g_strrstr(type, MOBILE_NUM_TYPE))
-		add_phone_number(contact, number, TEL_TYPE_MOBILE);
-	else
-		/* if this is no fax/mobile phone, then adding phone number
-		 * type based on type of the affilation field */
-		add_phone_number(contact, number, get_phone_type(aff_type));
-
-failed:
-	g_strfreev(num_parts);
-}
-
-static void contact_add_numbers(struct phonebook_contact *contact,
-							const char **reply)
-{
-	char **aff_numbers;
-	int i;
-
-	/* Filling phone numbers from contact's affilation */
-	aff_numbers = g_strsplit(reply[COL_PHONE_AFF], MAIN_DELIM, MAX_FIELDS);
-
-	if (aff_numbers)
-		for (i = 0; aff_numbers[i]; ++i)
-			add_aff_number(contact, aff_numbers[i],
-							reply[COL_AFF_TYPE]);
-
-	g_strfreev(aff_numbers);
-}
-
-static enum phonebook_field_type get_field_type(const char *affilation)
-{
-	if (g_strcmp0(AFFILATION_HOME, affilation) == 0)
-		return FIELD_TYPE_HOME;
-	else if (g_strcmp0(AFFILATION_WORK, affilation) == 0)
-		return FIELD_TYPE_WORK;
-
-	return FIELD_TYPE_OTHER;
-}
-
-static void add_aff_field(struct phonebook_contact *contact,
-			const char *aff_email, add_field_t add_field_cb)
-{
-	char **email_parts;
-	char *type, *email;
-
-	/* Emails from affilation data, are represented as real email
-	 * string and affilation type - those strings are separated by
-	 * SUB_DELIM string */
-	email_parts = g_strsplit(aff_email, SUB_DELIM, 2);
-
-	if (!email_parts)
-		return;
-
-	if (email_parts[0])
-		email = email_parts[0];
-	else
-		goto failed;
-
-	if (email_parts[1])
-		type = email_parts[1];
-	else
-		goto failed;
-
-	add_field_cb(contact, email, get_field_type(type));
-
-failed:
-	g_strfreev(email_parts);
-}
-
-static void contact_add_emails(struct phonebook_contact *contact,
-							const char **reply)
-{
-	char **aff_emails;
-	int i;
-
-	/* Emails from affilation */
-	aff_emails = g_strsplit(reply[COL_EMAIL_AFF], MAIN_DELIM, MAX_FIELDS);
-
-	if (aff_emails)
-		for (i = 0; aff_emails[i] != NULL; ++i)
-			add_aff_field(contact, aff_emails[i], add_email);
-
-	g_strfreev(aff_emails);
-}
-
-static void contact_add_addresses(struct phonebook_contact *contact,
-							const char **reply)
-{
-	char **aff_addr;
-	int i;
-
-	/* Addresses from affilation */
-	aff_addr = g_strsplit(reply[COL_ADDR_AFF], MAIN_DELIM, MAX_FIELDS);
-
-	if (aff_addr)
-		for (i = 0; aff_addr[i] != NULL; ++i)
-			add_aff_field(contact, aff_addr[i], add_address);
-
-	g_strfreev(aff_addr);
-}
-
-static void contact_add_urls(struct phonebook_contact *contact,
-							const char **reply)
-{
-	char **aff_url;
-	int i;
-
-	/* Addresses from affilation */
-	aff_url = g_strsplit(reply[COL_URL], MAIN_DELIM, MAX_FIELDS);
-
-	if (aff_url)
-		for (i = 0; aff_url[i] != NULL; ++i)
-			add_aff_field(contact, aff_url[i], add_url);
-
-	g_strfreev(aff_url);
-}
-
-static void contact_add_organization(struct phonebook_contact *contact,
-							const char **reply)
-{
-	/* Adding fields connected by nco:hasAffiliation - they may be in
-	 * separate replies */
-	add_affiliation(&contact->title, reply[COL_TITLE]);
-	add_affiliation(&contact->company, reply[COL_ORG_NAME]);
-	add_affiliation(&contact->department, reply[COL_ORG_DEPARTMENT]);
-	add_affiliation(&contact->role, reply[COL_ORG_ROLE]);
-}
-
-static void free_data_contacts(struct phonebook_data *data)
-{
-	GSList *l;
-
-	/* freeing contacts */
-	for (l = data->contacts; l; l = l->next) {
-		struct contact_data *c_data = l->data;
-
-		g_free(c_data->id);
-		phonebook_contact_free(c_data->contact);
-		g_free(c_data);
-	}
-
-	g_slist_free(data->contacts);
-	data->contacts = NULL;
-}
-
-static void send_pull_part(struct phonebook_data *data,
-			const struct apparam_field *params, gboolean lastpart)
-{
-	GString *vcards;
-
-	DBG("");
-	vcards = gen_vcards(data->contacts, params);
-	data->cb(vcards->str, vcards->len, g_slist_length(data->contacts),
-			data->newmissedcalls, lastpart, data->user_data);
-
-	if (!lastpart)
-		free_data_contacts(data);
-	g_string_free(vcards, TRUE);
-}
-
-static int pull_contacts(const char **reply, int num_fields, void *user_data)
-{
-	struct phonebook_data *data = user_data;
-	const struct apparam_field *params = data->params;
-	struct phonebook_contact *contact;
-	struct contact_data *contact_data;
-	int last_index, i;
-	gboolean cdata_present = FALSE, part_sent = FALSE;
-	static char *temp_id = NULL;
-
-	if (num_fields < 0) {
-		data->cb(NULL, 0, num_fields, 0, TRUE, data->user_data);
-		goto fail;
-	}
-
-	DBG("reply %p", reply);
-	data->tracker_index++;
-
-	if (reply == NULL)
-		goto done;
-
-	/* Trying to find contact in recently added contacts. It is needed for
-	 * contacts that have more than one telephone number filled */
-	contact = find_contact(data->contacts, reply[CONTACTS_ID_COL],
-							reply[COL_DATE]);
-
-	/* If contact is already created then adding only new phone numbers */
-	if (contact) {
-		cdata_present = TRUE;
-		goto add_numbers;
-	}
-
-	/* We are doing a PullvCardEntry, no need for those checks */
-	if (data->vcardentry)
-		goto add_entry;
-
-	/* Last four fields are always present, ignoring them */
-	for (i = 0; i < num_fields - 4; i++) {
-		if (reply[i][0] != '\0')
-			break;
-	}
-
-	if (i == num_fields - 4 && !g_str_equal(reply[CONTACTS_ID_COL],
-						TRACKER_DEFAULT_CONTACT_ME))
-		return 0;
-
-	if (g_strcmp0(temp_id, reply[CONTACTS_ID_COL])) {
-		data->index++;
-		g_free(temp_id);
-		temp_id = g_strdup(reply[CONTACTS_ID_COL]);
-
-		/* Incrementing counter for vcards in current part of data,
-		 * but only if liststartoffset has been already reached */
-		if (data->index > params->liststartoffset)
-			data->vcard_part_count++;
-	}
-
-	if (data->vcard_part_count > VCARDS_PART_COUNT) {
-		DBG("Part of vcard data ready for sending...");
-		data->vcard_part_count = 0;
-		/* Sending part of data to PBAP core - more data can be still
-		 * fetched, so marking lastpart as FALSE */
-		send_pull_part(data, params, FALSE);
-
-		/* Later, after adding contact data, need to return -EINTR to
-		 * stop fetching more data for this request. Data will be
-		 * downloaded again from this point, when phonebook_pull_read
-		 * will be called again with current request as a parameter*/
-		part_sent = TRUE;
-	}
-
-	last_index = params->liststartoffset + params->maxlistcount;
-
-	if (data->index <= params->liststartoffset)
-		return 0;
-
-	/* max number of results achieved - need send vcards data that was
-	 * already collected and stop further data processing (these operations
-	 * will be invoked in "done" section) */
-	if (data->index > last_index && params->maxlistcount > 0) {
-		DBG("Maxlistcount achieved");
-		goto done;
-	}
-
-add_entry:
-	contact = g_new0(struct phonebook_contact, 1);
-	contact_init(contact, reply);
-
-add_numbers:
-	contact_add_numbers(contact, reply);
-	contact_add_emails(contact, reply);
-	contact_add_addresses(contact, reply);
-	contact_add_urls(contact, reply);
-	contact_add_organization(contact, reply);
-
-	DBG("contact %p", contact);
-
-	/* Adding contacts data to wrapper struct - this data will be used to
-	 * generate vcard list */
-	if (!cdata_present) {
-		contact_data = g_new0(struct contact_data, 1);
-		contact_data->contact = contact;
-		contact_data->id = g_strdup(reply[CONTACTS_ID_COL]);
-		data->contacts = g_slist_append(data->contacts, contact_data);
-	}
-
-	if (part_sent)
-		return -EINTR;
-
-	return 0;
-
-done:
-	/* Processing is end, this is definitely last part of transmission
-	 * (marking lastpart as TRUE) */
-	send_pull_part(data, params, TRUE);
-
-fail:
-	g_free(temp_id);
-	temp_id = NULL;
-
-	return -EINTR;
-	/*
-	 * phonebook_data is freed in phonebook_req_finalize. Useful in
-	 * cases when call is terminated.
-	 */
-}
-
-static int add_to_cache(const char **reply, int num_fields, void *user_data)
-{
-	struct phonebook_data *data = user_data;
-	char *formatted;
-	int i;
-
-	if (reply == NULL || num_fields < 0)
-		goto done;
-
-	/* the first element is the URI, always not empty */
-	for (i = 1; i < num_fields; i++) {
-		if (reply[i][0] != '\0')
-			break;
-	}
-
-	if (i == num_fields &&
-			!g_str_equal(reply[0], TRACKER_DEFAULT_CONTACT_ME))
-		return 0;
-
-	if (i == 7)
-		formatted = g_strdup(reply[7]);
-	else if (i == 6)
-		formatted = g_strdup(reply[6]);
-	else
-		formatted = g_strdup_printf("%s;%s;%s;%s;%s",
-					reply[1], reply[2], reply[3], reply[4],
-					reply[5]);
-
-	/* The owner vCard must have the 0 handle */
-	if (strcmp(reply[0], TRACKER_DEFAULT_CONTACT_ME) == 0)
-		data->entry_cb(reply[0], 0, formatted, "",
-						reply[6], data->user_data);
-	else
-		data->entry_cb(reply[0], PHONEBOOK_INVALID_HANDLE, formatted,
-					"", reply[6], data->user_data);
-
-	g_free(formatted);
-
-	return 0;
-
-done:
-	if (num_fields <= 0)
-		data->ready_cb(data->user_data);
-
-	return -EINTR;
-	/*
-	 * phonebook_data is freed in phonebook_req_finalize. Useful in
-	 * cases when call is terminated.
-	 */
-}
-
-int phonebook_init(void)
-{
-	g_thread_init(NULL);
-	g_type_init();
-
-	return 0;
-}
-
-void phonebook_exit(void)
-{
-}
-
-char *phonebook_set_folder(const char *current_folder, const char *new_folder,
-						uint8_t flags, int *err)
-{
-	char *tmp1, *tmp2, *base, *path = NULL;
-	gboolean root, child;
-	int ret = 0;
-	int len;
-
-	root = (g_strcmp0("/", current_folder) == 0);
-	child = (new_folder && strlen(new_folder) != 0);
-
-	switch (flags) {
-	case 0x02:
-		/* Go back to root */
-		if (!child) {
-			path = g_strdup("/");
-			goto done;
-		}
-
-		path = g_build_filename(current_folder, new_folder, NULL);
-		break;
-	case 0x03:
-		/* Go up 1 level */
-		if (root) {
-			/* Already root */
-			path = g_strdup("/");
-			goto done;
-		}
-
-		/*
-		 * Removing one level of the current folder. Current folder
-		 * contains AT LEAST one level since it is not at root folder.
-		 * Use glib utility functions to handle invalid chars in the
-		 * folder path properly.
-		 */
-		tmp1 = g_path_get_basename(current_folder);
-		tmp2 = g_strrstr(current_folder, tmp1);
-		len = tmp2 - (current_folder + 1);
-
-		g_free(tmp1);
-
-		if (len == 0)
-			base = g_strdup("/");
-		else
-			base = g_strndup(current_folder, len);
-
-		/* Return: one level only */
-		if (!child) {
-			path = base;
-			goto done;
-		}
-
-		path = g_build_filename(base, new_folder, NULL);
-		g_free(base);
-
-		break;
-	default:
-		ret = -EBADR;
-		break;
-	}
-
-done:
-	if (path && !folder_is_valid(path))
-		ret = -ENOENT;
-
-	if (ret < 0) {
-		g_free(path);
-		path = NULL;
-	}
-
-	if (err)
-		*err = ret;
-
-	return path;
-}
-
-static int pull_newmissedcalls(const char **reply, int num_fields,
-							void *user_data)
-{
-	struct phonebook_data *data = user_data;
-	reply_list_foreach_t pull_cb;
-	int col_amount, err;
-	const char *query;
-	int nmissed;
-
-	if (num_fields < 0) {
-		data->cb(NULL, 0, num_fields, 0, TRUE, data->user_data);
-
-		return -EINTR;
-	}
-
-	if (reply != NULL) {
-		nmissed = atoi(reply[0]);
-		data->newmissedcalls =
-			nmissed <= UINT8_MAX ? nmissed : UINT8_MAX;
-		DBG("newmissedcalls %d", data->newmissedcalls);
-
-		return 0;
-	}
-
-	if (data->params->maxlistcount == 0) {
-		query = name2count_query("/telecom/mch.vcf");
-		col_amount = COUNT_QUERY_COL_AMOUNT;
-		pull_cb = pull_contacts_size;
-	} else {
-		query = name2query("/telecom/mch.vcf");
-		col_amount = PULL_QUERY_COL_AMOUNT;
-		pull_cb = pull_contacts;
-	}
-
-	err = query_tracker(query, col_amount, pull_cb, data);
-	if (err < 0) {
-		data->cb(NULL, 0, err, 0, TRUE, data->user_data);
-
-		return -EINTR;
-	}
-
-	return 0;
-}
-
-void phonebook_req_finalize(void *request)
-{
-	struct phonebook_data *data = request;
-
-	DBG("");
-
-	if (!data)
-		return;
-
-	/* canceling asynchronous operation on tracker if any is active */
-	if (data->query_canc) {
-		g_cancellable_cancel(data->query_canc);
-		g_object_unref(data->query_canc);
-	}
-
-	free_data_contacts(data);
-	g_free(data->req_name);
-	g_free(data);
-}
-
-void *phonebook_pull(const char *name, const struct apparam_field *params,
-				phonebook_cb cb, void *user_data, int *err)
-{
-	struct phonebook_data *data;
-
-	DBG("name %s", name);
-
-	data = g_new0(struct phonebook_data, 1);
-	data->params = params;
-	data->user_data = user_data;
-	data->cb = cb;
-	data->req_name = g_strdup(name);
-
-	if (err)
-		*err = 0;
-
-	return data;
-}
-
-int phonebook_pull_read(void *request)
-{
-	struct phonebook_data *data = request;
-	reply_list_foreach_t pull_cb;
-	const char *query;
-	char *offset_query;
-	int col_amount;
-	int ret;
-
-	if (!data)
-		return -ENOENT;
-
-	data->newmissedcalls = 0;
-
-	if (g_strcmp0(data->req_name, "/telecom/mch.vcf") == 0 &&
-						data->tracker_index == 0) {
-		/* new missed calls amount should be counted only once - it
-		 * will be done during generating first part of results of
-		 * missed calls history */
-		query = NEW_MISSED_CALLS_COUNT_QUERY;
-		col_amount = COUNT_QUERY_COL_AMOUNT;
-		pull_cb = pull_newmissedcalls;
-	} else if (data->params->maxlistcount == 0) {
-		query = name2count_query(data->req_name);
-		col_amount = COUNT_QUERY_COL_AMOUNT;
-		pull_cb = pull_contacts_size;
-	} else {
-		query = name2query(data->req_name);
-		col_amount = PULL_QUERY_COL_AMOUNT;
-		pull_cb = pull_contacts;
-	}
-
-	if (query == NULL)
-		return -ENOENT;
-
-	if (pull_cb == pull_contacts && data->tracker_index > 0) {
-		/* Adding offset to pull query to download next parts of data
-		 * from tracker (phonebook_pull_read may be called many times
-		 * from PBAP core to fetch data partially) */
-		offset_query = g_strdup_printf(QUERY_OFFSET_FORMAT, query,
-							data->tracker_index);
-		ret = query_tracker(offset_query, col_amount, pull_cb, data);
-
-		g_free(offset_query);
-
-		return ret;
-	}
-
-	return query_tracker(query, col_amount, pull_cb, data);
-}
-
-void *phonebook_get_entry(const char *folder, const char *id,
-				const struct apparam_field *params,
-				phonebook_cb cb, void *user_data, int *err)
-{
-	struct phonebook_data *data;
-	char *query;
-	int ret;
-
-	DBG("folder %s id %s", folder, id);
-
-	data = g_new0(struct phonebook_data, 1);
-	data->user_data = user_data;
-	data->params = params;
-	data->cb = cb;
-	data->vcardentry = TRUE;
-
-	if (g_str_has_prefix(id, CONTACT_ID_PREFIX) == TRUE ||
-				g_strcmp0(id, TRACKER_DEFAULT_CONTACT_ME) == 0)
-		query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id,
-					id, id, id, id, id, id, id, id, id);
-	else if (g_str_has_prefix(id, CALL_ID_PREFIX) == TRUE)
-		query = g_strdup_printf(CONTACT_FROM_CALL_QUERY, id);
-	else
-		query = g_strdup_printf(CONTACTS_OTHER_QUERY_FROM_URI,
-								id, id, id);
-
-	ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
-	if (err)
-		*err = ret;
-
-	g_free(query);
-
-	return data;
-}
-
-void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
-		phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
-{
-	struct phonebook_data *data;
-	const char *query;
-	int ret;
-
-	DBG("name %s", name);
-
-	query = folder2query(name);
-	if (query == NULL) {
-		if (err)
-			*err = -ENOENT;
-		return NULL;
-	}
-
-	data = g_new0(struct phonebook_data, 1);
-	data->entry_cb = entry_cb;
-	data->ready_cb = ready_cb;
-	data->user_data = user_data;
-
-	ret = query_tracker(query, 8, add_to_cache, data);
-	if (err)
-		*err = ret;
-
-	return data;
-}
diff -pruN 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex.c 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex.c
--- 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex.c	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,1198 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <gobex/gobex.h>
+
+#include "util.h"
+
+#define FINAL_BIT 0x80
+
+static GMainLoop *mainloop = NULL;
+
+static uint8_t pkt_connect_req[] = { G_OBEX_OP_CONNECT | FINAL_BIT,
+					0x00, 0x07, 0x10, 0x00, 0x10, 0x00 };
+static uint8_t pkt_connect_rsp[] = { 0x20 | FINAL_BIT, 0x00, 0x07,
+					0x10, 0x00, 0x10, 0x00 };
+
+static uint8_t pkt_setpath_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT, 0x00, 0x10,
+					0x02, 0x00,
+					G_OBEX_HDR_NAME, 0x00, 0x0b,
+					0, 'd', 0, 'i', 0, 'r', 0, 0 };
+static uint8_t pkt_setpath_up_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT,
+					0x00, 0x05, 0x03, 0x00 };
+static uint8_t pkt_setpath_up_down_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT,
+					0x00, 0x10, 0x03, 0x00,
+					G_OBEX_HDR_NAME, 0x00, 0x0b,
+					0, 'd', 0, 'i', 0, 'r', 0, 0 };
+static uint8_t pkt_success_rsp[] = { 0x20 | FINAL_BIT, 0x00, 0x03 };
+
+static uint8_t pkt_mkdir_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT, 0x00, 0x10,
+					0x00, 0x00,
+					G_OBEX_HDR_NAME, 0x00, 0x0b,
+					0, 'd', 0, 'i', 0, 'r', 0, 0 };
+
+static uint8_t pkt_delete_req[] = { G_OBEX_OP_PUT | FINAL_BIT, 0x00, 0x16,
+		G_OBEX_HDR_NAME, 0x00, 0x13,
+		0, 'f', 0, 'o', 0, 'o', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static uint8_t pkt_copy_req[] = { G_OBEX_OP_ACTION | FINAL_BIT, 0x00, 0x1b,
+					G_OBEX_HDR_ACTION, 0x00,
+					G_OBEX_HDR_NAME, 0x00, 0x0b,
+					0, 'f', 0, 'o', 0, 'o', 0, 0,
+					G_OBEX_HDR_DESTNAME, 0x00, 0x0b,
+					0, 'b', 0, 'a', 0, 'r', 0, 0 };
+static uint8_t pkt_move_req[] = { G_OBEX_OP_ACTION | FINAL_BIT, 0x00, 0x1b,
+					G_OBEX_HDR_ACTION, 0x01,
+					G_OBEX_HDR_NAME, 0x00, 0x0b,
+					0, 'f', 0, 'o', 0, 'o', 0, 0,
+					G_OBEX_HDR_DESTNAME, 0x00, 0x0b,
+					0, 'b', 0, 'a', 0, 'r', 0, 0 };
+
+static uint8_t pkt_nval_connect_rsp[] = { 0x10 | FINAL_BIT, 0x00, 0x05,
+					0x10, 0x00, };
+static uint8_t pkt_abort_rsp[] = { 0x90, 0x00, 0x03 };
+static uint8_t pkt_nval_short_rsp[] = { 0x10 | FINAL_BIT, 0x12 };
+static uint8_t pkt_put_body[] = { G_OBEX_OP_PUT, 0x00, 0x0a,
+					G_OBEX_HDR_BODY, 0x00, 0x07,
+					1, 2, 3, 4 };
+
+static gboolean timeout(gpointer user_data)
+{
+	GError **err = user_data;
+
+	if (!g_main_loop_is_running(mainloop))
+		return FALSE;
+
+	g_set_error(err, TEST_ERROR, TEST_ERROR_TIMEOUT, "Timed out");
+
+	g_main_loop_quit(mainloop);
+
+	return FALSE;
+}
+
+static void connect_rsp(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	guint8 rsp_code;
+	gboolean final;
+	GError **test_err = user_data;
+
+	if (err != NULL) {
+		g_assert(*test_err == NULL);
+		*test_err = g_error_copy(err);
+		goto done;
+	}
+
+	rsp_code = g_obex_packet_get_operation(rsp, &final);
+	if (rsp_code != 0x20) {
+		g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Unexpected response 0x%02x", rsp_code);
+		goto done;
+	}
+
+	if (!final) {
+		g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Connect response didn't have final bit");
+		goto done;
+	}
+
+done:
+	g_main_loop_quit(mainloop);
+}
+
+static void nval_connect_rsp(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	GError **test_err = user_data;
+
+	if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR))
+		g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Did not get expected parse error");
+
+	g_main_loop_quit(mainloop);
+}
+
+static void timeout_rsp(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	GError **test_err = user_data;
+
+	if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT))
+		g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Did not get expected timeout error");
+
+	g_main_loop_quit(mainloop);
+}
+
+static gboolean recv_and_send(GIOChannel *io, void *data, gsize len,
+								GError **err)
+{
+	gsize bytes_written, rbytes;
+	char buf[255];
+	GIOStatus status;
+
+	status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+	if (status != G_IO_STATUS_NORMAL) {
+		g_set_error(err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"read failed with status %d", status);
+		return FALSE;
+	}
+
+	if (data == NULL)
+		return TRUE;
+
+	g_io_channel_write_chars(io, data, len, &bytes_written, NULL);
+	if (bytes_written != len) {
+		g_set_error(err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+						"Unable to write to socket");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean send_connect_rsp(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	GError **err = user_data;
+
+	if (!recv_and_send(io, pkt_connect_rsp, sizeof(pkt_connect_rsp), err))
+		g_main_loop_quit(mainloop);
+
+	return FALSE;
+}
+
+static gboolean send_nval_connect_rsp(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	GError **err = user_data;
+
+	if (!recv_and_send(io, pkt_nval_connect_rsp,
+					sizeof(pkt_nval_connect_rsp), err))
+		g_main_loop_quit(mainloop);
+
+	return FALSE;
+}
+
+static gboolean send_nval_short_rsp(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	GError **err = user_data;
+
+	if (!recv_and_send(io, pkt_nval_short_rsp,
+					sizeof(pkt_nval_short_rsp), err))
+		g_main_loop_quit(mainloop);
+
+	return FALSE;
+}
+
+static gboolean send_nothing(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	GError **err = user_data;
+
+	if (!recv_and_send(io, NULL, 0, err))
+		g_main_loop_quit(mainloop);
+
+	return FALSE;
+}
+
+static void send_req(GObexPacket *req, GObexResponseFunc rsp_func,
+				GIOFunc send_rsp_func, gint req_timeout,
+				int transport_type)
+{
+	GError *gerr = NULL;
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id, test_time;
+	GObex *obex;
+
+	create_endpoints(&obex, &io, transport_type);
+
+	g_obex_send_req(obex, req, req_timeout, rsp_func, &gerr, &gerr);
+	g_assert_no_error(gerr);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, send_rsp_func, &gerr);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	if (req_timeout > 0)
+		test_time = req_timeout + 1;
+	else
+		test_time = 1;
+
+	timer_id = g_timeout_add_seconds(test_time, timeout, &gerr);
+
+	g_main_loop_run(mainloop);
+
+	g_main_loop_unref(mainloop);
+	mainloop = NULL;
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(gerr);
+}
+
+static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func,
+					gint req_timeout, int transport_type)
+{
+	GObexPacket *req;
+	guint8 connect_data[] = { 0x10, 0x00, 0x10, 0x00 };
+
+	req = g_obex_packet_new(G_OBEX_OP_CONNECT, TRUE, G_OBEX_HDR_INVALID);
+	g_assert(req != NULL);
+
+	g_obex_packet_set_data(req, connect_data, sizeof(connect_data),
+							G_OBEX_DATA_REF);
+
+	send_req(req, rsp_func, send_rsp_func, req_timeout, transport_type);
+}
+
+static void test_send_connect_req_stream(void)
+{
+	send_connect(connect_rsp, send_connect_rsp, -1, SOCK_STREAM);
+}
+
+static void test_send_connect_req_pkt(void)
+{
+	send_connect(connect_rsp, send_connect_rsp, -1, SOCK_SEQPACKET);
+}
+
+static void test_send_nval_connect_req_stream(void)
+{
+	send_connect(nval_connect_rsp, send_nval_connect_rsp, -1, SOCK_STREAM);
+}
+
+static void test_send_nval_connect_req_pkt(void)
+{
+	send_connect(nval_connect_rsp, send_nval_connect_rsp, -1,
+							SOCK_SEQPACKET);
+}
+
+static void test_send_nval_connect_req_short_pkt(void)
+{
+	send_connect(nval_connect_rsp, send_nval_short_rsp, -1,
+							SOCK_SEQPACKET);
+}
+
+static void test_send_connect_req_timeout_stream(void)
+{
+	send_connect(timeout_rsp, send_nothing, 0, SOCK_STREAM);
+}
+
+static void test_send_connect_req_timeout_pkt(void)
+{
+	send_connect(timeout_rsp, send_nothing, 0, SOCK_SEQPACKET);
+}
+
+struct req_info {
+	GObex *obex;
+	guint id;
+	GError *err;
+};
+
+static void req_done(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	struct req_info *r = user_data;
+
+	if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED))
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Did not get expected cancelled error");
+
+	g_main_loop_quit(mainloop);
+}
+
+static void test_cancel_req_immediate(void)
+{
+	GObexPacket *req;
+	struct req_info r;
+	gboolean ret;
+
+	create_endpoints(&r.obex, NULL, SOCK_STREAM);
+
+	r.err = NULL;
+
+	req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_INVALID);
+	r.id = g_obex_send_req(r.obex, req, -1, req_done, &r, &r.err);
+	g_assert_no_error(r.err);
+	g_assert(r.id != 0);
+
+	ret = g_obex_cancel_req(r.obex, r.id, FALSE);
+	g_assert(ret == TRUE);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	g_main_loop_run(mainloop);
+
+	g_assert_no_error(r.err);
+
+	g_obex_unref(r.obex);
+	g_main_loop_unref(mainloop);
+}
+
+static gboolean cancel_server(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct req_info *r = user_data;
+	GIOStatus status;
+	gsize bytes_written, rbytes;
+	char buf[255];
+
+	status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+	if (status != G_IO_STATUS_NORMAL) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Reading data failed with status %d", status);
+		goto failed;
+	}
+
+	if (rbytes < 3) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Not enough data from socket");
+		goto failed;
+	}
+
+	if ((uint8_t) buf[0] == (G_OBEX_OP_PUT | FINAL_BIT)) {
+		if (!g_obex_cancel_req(r->obex, r->id, FALSE)) {
+			g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Cancelling request failed");
+			goto failed;
+		}
+		return TRUE;
+	}
+
+	if ((uint8_t) buf[0] != (G_OBEX_OP_ABORT | FINAL_BIT)) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Neither Put nor Abort packet received");
+		goto failed;
+	}
+
+	g_io_channel_write_chars(io, (gchar *) pkt_abort_rsp,
+				sizeof(pkt_abort_rsp), &bytes_written, NULL);
+	if (bytes_written != sizeof(pkt_abort_rsp)) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+						"Unable to write to socket");
+		goto failed;
+	}
+
+	return TRUE;
+
+failed:
+	g_main_loop_quit(mainloop);
+	return FALSE;
+}
+
+static void test_cancel_req_delay(int transport_type)
+{
+	GIOChannel *io;
+	guint io_id, timer_id;
+	struct req_info r;
+	GObexPacket *req;
+	GIOCondition cond;
+
+	create_endpoints(&r.obex, &io, transport_type);
+
+	r.err = NULL;
+
+	req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_INVALID);
+	r.id = g_obex_send_req(r.obex, req, -1, req_done, &r, &r.err);
+	g_assert_no_error(r.err);
+	g_assert(r.id != 0);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, cancel_server, &r);
+
+	timer_id = g_timeout_add_seconds(2, timeout, &r.err);
+
+	g_main_loop_run(mainloop);
+
+	g_assert_no_error(r.err);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(r.obex);
+	g_main_loop_unref(mainloop);
+}
+
+static void test_cancel_req_delay_stream(void)
+{
+	test_cancel_req_delay(SOCK_STREAM);
+}
+
+static void test_cancel_req_delay_pkt(void)
+{
+	test_cancel_req_delay(SOCK_SEQPACKET);
+}
+
+struct rcv_buf_info {
+	GError *err;
+	const guint8 *buf;
+	gsize len;
+};
+
+static gboolean rcv_data(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+	struct rcv_buf_info *r = user_data;
+	GIOStatus status;
+	gsize rbytes;
+	char buf[255];
+
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Unexpected condition %d on socket", cond);
+		goto done;
+	}
+
+	status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+	if (status != G_IO_STATUS_NORMAL) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Reading data failed with status %d", status);
+		goto done;
+	}
+
+	if (rbytes != r->len) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Got %zu bytes instead of %zu",
+				rbytes, sizeof(pkt_connect_req));
+		dump_bufs(r->buf, r->len, buf, rbytes);
+		goto done;
+	}
+
+	if (memcmp(buf, r->buf, rbytes) != 0) {
+		g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Mismatch with received data");
+		dump_bufs(r->buf, r->len, buf, rbytes);
+		goto done;
+	}
+
+done:
+	g_main_loop_quit(mainloop);
+	return FALSE;
+}
+
+static void test_send_connect(int transport_type)
+{
+	guint8 connect_data[] = { 0x10, 0x00, 0x10, 0x00 };
+	struct rcv_buf_info r;
+	GIOChannel *io;
+	GIOCondition cond;
+	GObexPacket *req;
+	guint io_id, timer_id;
+	GObex *obex;
+
+	create_endpoints(&obex, &io, transport_type);
+
+	memset(&r, 0, sizeof(r));
+	r.buf = pkt_connect_req;
+	r.len = sizeof(pkt_connect_req);
+
+	req = g_obex_packet_new(G_OBEX_OP_CONNECT, TRUE, G_OBEX_HDR_INVALID);
+	g_assert(req != NULL);
+
+	g_obex_packet_set_data(req, connect_data, sizeof(connect_data),
+							G_OBEX_DATA_REF);
+	g_obex_send(obex, req, &r.err);
+	g_assert_no_error(r.err);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, rcv_data, &r);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, timeout, &r.err);
+
+	g_main_loop_run(mainloop);
+
+	g_main_loop_unref(mainloop);
+	mainloop = NULL;
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(r.err);
+}
+
+static void test_send_connect_stream(void)
+{
+	test_send_connect(SOCK_STREAM);
+}
+
+static void test_send_connect_pkt(void)
+{
+	test_send_connect(SOCK_SEQPACKET);
+}
+
+static void unexpected_disconn(GObex *obex, GError *err, gpointer user_data)
+{
+	GError **test_err = user_data;
+
+	if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR))
+		g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Didn't get parse error as expected");
+
+	g_main_loop_quit(mainloop);
+}
+
+static void test_recv_unexpected(void)
+{
+	GError *err = NULL;
+	GObexPacket *req;
+	GIOChannel *io;
+	guint timer_id;
+	GObex *obex;
+	guint8 buf[255];
+	gssize len;
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	g_obex_set_disconnect_function(obex, unexpected_disconn, &err);
+
+	req = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
+	len = g_obex_packet_encode(req, buf, sizeof(buf));
+	g_obex_packet_free(req);
+	g_assert_cmpint(len, >=, 0);
+
+	g_io_channel_write_chars(io, (gchar *) buf, len, NULL, &err);
+	g_assert_no_error(err);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, timeout, &err);
+
+	g_main_loop_run(mainloop);
+
+	g_main_loop_unref(mainloop);
+	mainloop = NULL;
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_obex_unref(obex);
+
+	g_assert_no_error(err);
+}
+
+static gssize get_body_data(void *buf, gsize len, gpointer user_data)
+{
+	uint8_t data[] = { 1, 2, 3, 4 };
+
+	memcpy(buf, data, sizeof(data));
+
+	return sizeof(data);
+}
+
+static gssize get_body_data_fail(void *buf, gsize len, gpointer user_data)
+{
+	g_main_loop_quit(mainloop);
+	return -1;
+}
+
+static void test_send_on_demand(int transport_type, GObexDataProducer func)
+{
+	struct rcv_buf_info r;
+	GIOChannel *io;
+	GIOCondition cond;
+	GObexPacket *req;
+	guint io_id, timer_id;
+	GObex *obex;
+
+	create_endpoints(&obex, &io, transport_type);
+
+	memset(&r, 0, sizeof(r));
+	r.buf = pkt_put_body;
+	r.len = sizeof(pkt_put_body);
+
+	req = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, G_OBEX_HDR_INVALID);
+	g_obex_packet_add_body(req, func, &r);
+
+	g_obex_send(obex, req, &r.err);
+	g_assert_no_error(r.err);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, rcv_data, &r);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, timeout, &r.err);
+
+	g_main_loop_run(mainloop);
+
+	g_main_loop_unref(mainloop);
+	mainloop = NULL;
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(r.err);
+}
+
+static void test_send_on_demand_stream(void)
+{
+	test_send_on_demand(SOCK_STREAM, get_body_data);
+}
+
+static void test_send_on_demand_pkt(void)
+{
+	test_send_on_demand(SOCK_SEQPACKET, get_body_data);
+}
+
+static void test_send_on_demand_fail_stream(void)
+{
+	test_send_on_demand(SOCK_STREAM, get_body_data_fail);
+}
+
+static void test_send_on_demand_fail_pkt(void)
+{
+	test_send_on_demand(SOCK_SEQPACKET, get_body_data_fail);
+}
+
+static void handle_connect_req(GObex *obex, GObexPacket *req,
+							gpointer user_data)
+{
+	GError **test_err = user_data;
+
+	if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_CONNECT)
+		g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+						"Unexpected operation");
+	g_main_loop_quit(mainloop);
+
+}
+
+static void handle_connect_err(GObex *obex, GError *err, gpointer user_data)
+{
+	GError **test_err = user_data;
+
+	g_main_loop_quit(mainloop);
+
+	if (err != NULL)
+		*test_err = g_error_copy(err);
+	else
+		*test_err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Disconnected");
+}
+
+static void recv_connect(int transport_type)
+{
+	GError *gerr = NULL;
+	guint timer_id;
+	GObex *obex;
+	GIOChannel *io;
+	GIOStatus status;
+	gsize bytes_written;
+
+	create_endpoints(&obex, &io, transport_type);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+						handle_connect_req, &gerr);
+	g_obex_set_disconnect_function(obex, handle_connect_err, &gerr);
+
+	status = g_io_channel_write_chars(io, (gchar *) pkt_connect_req,
+						sizeof(pkt_connect_req),
+						&bytes_written, NULL);
+	g_assert_cmpint(status, ==, G_IO_STATUS_NORMAL);
+	g_assert_cmpuint(bytes_written, ==, sizeof(pkt_connect_req));
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, timeout, &gerr);
+
+	g_main_loop_run(mainloop);
+
+	g_source_remove(timer_id);
+	g_obex_unref(obex);
+	g_io_channel_unref(io);
+
+	g_main_loop_unref(mainloop);
+	mainloop = NULL;
+
+	g_assert_no_error(gerr);
+}
+
+static void test_recv_connect_stream(void)
+{
+	recv_connect(SOCK_STREAM);
+}
+
+static void test_recv_connect_pkt(void)
+{
+	recv_connect(SOCK_SEQPACKET);
+}
+
+static void disconn_ev(GObex *obex, GError *err, gpointer user_data)
+{
+	GError **test_err = user_data;
+
+	if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED))
+		g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Did not get expected disconnect error");
+
+	g_main_loop_quit(mainloop);
+}
+
+static void test_disconnect(void)
+{
+	GError *gerr = NULL;
+	guint timer_id;
+	GObex *obex;
+	GIOChannel *io;
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	g_obex_set_disconnect_function(obex, disconn_ev, &gerr);
+
+	timer_id = g_timeout_add_seconds(1, timeout, &gerr);
+
+	mainloop = g_main_loop_new(NULL, FALSE);
+
+	g_io_channel_shutdown(io, FALSE, NULL);
+
+	g_main_loop_run(mainloop);
+
+	g_assert_no_error(gerr);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_obex_unref(obex);
+
+	g_main_loop_unref(mainloop);
+	mainloop = NULL;
+}
+
+static void test_ref_unref(void)
+{
+	GObex *obex;
+
+	obex = create_gobex(STDIN_FILENO, G_OBEX_TRANSPORT_STREAM, FALSE);
+
+	g_assert(obex != NULL);
+
+	obex = g_obex_ref(obex);
+
+	g_obex_unref(obex);
+	g_obex_unref(obex);
+}
+
+static void test_basic(void)
+{
+	GObex *obex;
+
+	obex = create_gobex(STDIN_FILENO, G_OBEX_TRANSPORT_STREAM, FALSE);
+
+	g_assert(obex != NULL);
+
+	g_obex_unref(obex);
+}
+
+static void test_null_io(void)
+{
+	GObex *obex;
+
+	obex = g_obex_new(NULL, 0, -1, -1);
+
+	g_assert(obex == NULL);
+}
+
+static void req_complete(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (err != NULL)
+		d->err = g_error_copy(err);
+
+	g_main_loop_quit(d->mainloop);
+}
+
+static void test_connect(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ pkt_connect_req, sizeof(pkt_connect_req) } }, {
+				{ pkt_connect_rsp, sizeof(pkt_connect_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_connect(obex, req_complete, &d, &d.err, G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_setpath(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ pkt_setpath_req, sizeof(pkt_setpath_req) } }, {
+			{ pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_setpath(obex, "dir", req_complete, &d, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_setpath_up(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ pkt_setpath_up_req, sizeof(pkt_setpath_up_req) } }, {
+			{ pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_setpath(obex, "..", req_complete, &d, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_setpath_up_down(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ pkt_setpath_up_down_req,
+					sizeof(pkt_setpath_up_down_req) } }, {
+			{ pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_setpath(obex, "../dir", req_complete, &d, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_mkdir(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ pkt_mkdir_req, sizeof(pkt_mkdir_req) } }, {
+			{ pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_mkdir(obex, "dir", req_complete, &d, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_delete(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ pkt_delete_req, sizeof(pkt_delete_req) } }, {
+			{ pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_delete(obex, "foo.txt", req_complete, &d, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_copy(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ pkt_copy_req, sizeof(pkt_copy_req) } }, {
+			{ pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_copy(obex, "foo", "bar", req_complete, &d, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_move(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ pkt_move_req, sizeof(pkt_move_req) } }, {
+			{ pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_move(obex, "foo", "bar", req_complete, &d, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+int main(int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_func("/gobex/null_io", test_null_io);
+	g_test_add_func("/gobex/basic", test_basic);
+	g_test_add_func("/gobex/ref_unref", test_ref_unref);
+
+	g_test_add_func("/gobex/test_disconnect", test_disconnect);
+
+	g_test_add_func("/gobex/test_recv_connect_stream",
+						test_recv_connect_stream);
+	g_test_add_func("/gobex/test_recv_connect_pkt",
+						test_recv_connect_pkt);
+	g_test_add_func("/gobex/test_send_connect_stream",
+						test_send_connect_stream);
+	g_test_add_func("/gobex/test_send_connect_pkt",
+						test_send_connect_pkt);
+	g_test_add_func("/gobex/test_recv_unexpected",
+						test_recv_unexpected);
+	g_test_add_func("/gobex/test_send_on_demand_stream",
+						test_send_on_demand_stream);
+	g_test_add_func("/gobex/test_send_on_demand_pkt",
+						test_send_on_demand_pkt);
+	g_test_add_func("/gobex/test_send_on_demand_fail_stream",
+					test_send_on_demand_fail_stream);
+	g_test_add_func("/gobex/test_send_on_demand_fail_pkt",
+					test_send_on_demand_fail_pkt);
+	g_test_add_func("/gobex/test_send_connect_req_stream",
+					test_send_connect_req_stream);
+	g_test_add_func("/gobex/test_send_connect_req_pkt",
+					test_send_connect_req_pkt);
+	g_test_add_func("/gobex/test_send_nval_connect_req_stream",
+					test_send_nval_connect_req_stream);
+	g_test_add_func("/gobex/test_send_nval_connect_req_pkt",
+					test_send_nval_connect_req_pkt);
+	g_test_add_func("/gobex/test_send_nval_connect_req_short_pkt",
+					test_send_nval_connect_req_short_pkt);
+	g_test_add_func("/gobex/test_send_connect_req_timeout_stream",
+					test_send_connect_req_timeout_stream);
+	g_test_add_func("/gobex/test_send_connect_req_timeout_pkt",
+					test_send_connect_req_timeout_pkt);
+
+
+	g_test_add_func("/gobex/test_cancel_req_immediate",
+					test_cancel_req_immediate);
+	g_test_add_func("/gobex/test_cancel_req_delay_stream",
+					test_cancel_req_delay_stream);
+	g_test_add_func("/gobex/test_cancel_req_delay_pkt",
+					test_cancel_req_delay_pkt);
+
+	g_test_add_func("/gobex/test_connect", test_connect);
+
+	g_test_add_func("/gobex/test_setpath", test_setpath);
+	g_test_add_func("/gobex/test_setpath_up", test_setpath_up);
+	g_test_add_func("/gobex/test_setpath_up_down", test_setpath_up_down);
+
+	g_test_add_func("/gobex/test_mkdir", test_mkdir);
+
+	g_test_add_func("/gobex/test_delete", test_delete);
+
+	g_test_add_func("/gobex/test_copy", test_copy);
+	g_test_add_func("/gobex/test_move", test_move);
+
+	g_test_run();
+
+	return 0;
+}
diff -pruN 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex-transfer.c 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex-transfer.c
--- 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex-transfer.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/test-gobex-transfer.c	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,2257 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+#include <gobex/gobex.h>
+
+#include "util.h"
+
+#define FINAL_BIT 0x80
+#define RANDOM_PACKETS 4
+
+static guint8 put_req_first[] = { G_OBEX_OP_PUT, 0x00, 0x30,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+	G_OBEX_HDR_BODY, 0x00, 0x0d,
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static guint8 put_req_first_srm[] = { G_OBEX_OP_PUT, 0x00, 0x32,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+	G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE,
+	G_OBEX_HDR_BODY, 0x00, 0x0d,
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static guint8 put_req_zero[255] = { G_OBEX_OP_PUT, 0x00, 0xff,
+	G_OBEX_HDR_BODY, 0x00, 0xfc };
+
+static guint8 put_req_last[] = { G_OBEX_OP_PUT | FINAL_BIT, 0x00, 0x06,
+					G_OBEX_HDR_BODY_END, 0x00, 0x03 };
+
+static guint8 abort_req[] = { G_OBEX_OP_ABORT | FINAL_BIT, 0x00, 0x03 };
+
+static guint8 put_rsp_first[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+								0x00, 0x03 };
+static guint8 put_rsp_first_srm[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+							0x00, 0x05,
+							G_OBEX_HDR_SRM, 0x01 };
+static guint8 put_rsp_first_srm_wait[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+							0x00, 0x07,
+							G_OBEX_HDR_SRM, 0x01,
+							G_OBEX_HDR_SRMP, 0x01 };
+static guint8 put_rsp_last[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x03 };
+
+static guint8 get_req_first[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x23,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 get_req_first_app[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x2a,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+	G_OBEX_HDR_APPARAM, 0x00, 0x07,
+	0, 1, 2, 3  };
+
+static guint8 get_req_first_srm[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x25,
+	G_OBEX_HDR_SRM, 0x01,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 get_req_first_srm_wait[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x27,
+	G_OBEX_HDR_SRM, 0x01,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+	G_OBEX_HDR_SRMP, 0x01 };
+
+static guint8 get_req_last[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x03, };
+
+static guint8 get_rsp_first_app[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0x0A,
+					G_OBEX_HDR_APPARAM, 0x00, 0x07,
+					0, 1, 2, 3 };
+static guint8 get_rsp_first[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0x10,
+					G_OBEX_HDR_BODY, 0x00, 0x0d,
+					0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+static guint8 get_rsp_first_srm[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0x12,
+					G_OBEX_HDR_SRM, 0x01,
+					G_OBEX_HDR_BODY, 0x00, 0x0d,
+					0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+static guint8 get_rsp_first_srm_wait_next[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+					0x00, 0x14,
+					G_OBEX_HDR_SRM, 0x01,
+					G_OBEX_HDR_SRMP, 0x02,
+					G_OBEX_HDR_BODY, 0x00, 0x0d,
+					0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+static guint8 get_rsp_zero[255] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0xff,
+					G_OBEX_HDR_BODY, 0x00, 0xfc };
+static guint8 get_rsp_zero_wait_next[255] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+					0x00, 0xff,
+					G_OBEX_HDR_SRMP, 0x02,
+					G_OBEX_HDR_BODY, 0x00, 0xfa };
+static guint8 get_rsp_last[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x06,
+					G_OBEX_HDR_BODY_END, 0x00, 0x03 };
+
+static guint8 conn_req[] = { G_OBEX_OP_CONNECT | FINAL_BIT, 0x00, 0x07,
+					0x10, 0x00, 0x10, 0x00 };
+static guint8 conn_rsp[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x0c,
+					0x10, 0x00, 0x10, 0x00,
+					G_OBEX_HDR_CONNECTION, 0x00, 0x00,
+					0x00, 0x01 };
+
+static guint8 conn_req_srm[] = { G_OBEX_OP_CONNECT | FINAL_BIT, 0x00, 0x09,
+					0x10, 0x00, 0x10, 0x00,
+					G_OBEX_HDR_SRM, 0x02 };
+static guint8 conn_rsp_srm[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x0e,
+					0x10, 0x00, 0x10, 0x00,
+					G_OBEX_HDR_CONNECTION, 0x00, 0x00,
+					0x00, 0x01,
+					G_OBEX_HDR_SRM, 0x01 };
+
+static guint8 unavailable_rsp[] = { G_OBEX_RSP_SERVICE_UNAVAILABLE | FINAL_BIT,
+					0x00, 0x03 };
+
+static guint8 conn_get_req_first[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x28,
+	G_OBEX_HDR_CONNECTION, 0x00, 0x00, 0x00, 0x01,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 conn_get_req_wrg[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x28,
+	G_OBEX_HDR_CONNECTION, 0x00, 0x00, 0x00, 0xFF,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 conn_put_req_first[] = { G_OBEX_OP_PUT, 0x00, 0x35,
+	G_OBEX_HDR_CONNECTION, 0x00, 0x00, 0x00, 0x01,
+	G_OBEX_HDR_TYPE, 0x00, 0x0b,
+	'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+	G_OBEX_HDR_NAME, 0x00, 0x15,
+	0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+	G_OBEX_HDR_BODY, 0x00, 0x0d,
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static guint8 hdr_type[] = "foo/bar";
+static guint8 hdr_app[] = { 0, 1, 2, 3 };
+static guint8 body_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (err != NULL)
+		d->err = g_error_copy(err);
+
+	g_main_loop_quit(d->mainloop);
+}
+
+static gboolean resume_obex(gpointer user_data)
+{
+	g_obex_resume(user_data);
+	return FALSE;
+}
+
+static gssize provide_seq(void *buf, gsize len, gpointer user_data)
+{
+	struct test_data *d = user_data;
+	int fd;
+	gssize ret;
+
+	if (d->count == RANDOM_PACKETS - 1)
+		return 0;
+
+	fd = open("/dev/urandom", O_RDONLY | O_NOCTTY, 0);
+	if (fd < 0) {
+		g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"open(/dev/urandom): %s", strerror(errno));
+		g_main_loop_quit(d->mainloop);
+		return -1;
+	}
+
+	ret = read(fd, buf, len);
+	close(fd);
+	return ret;
+}
+
+static gssize provide_eagain(void *buf, gsize len, gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (d->count > 0)
+		return 0;
+
+	if (len < sizeof(body_data)) {
+		g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Got data request for only %zu bytes", len);
+		g_main_loop_quit(d->mainloop);
+		return -1;
+	}
+
+	if (d->provide_delay > 0) {
+		g_timeout_add(d->provide_delay, resume_obex, d->obex);
+		d->provide_delay = 0;
+		return -EAGAIN;
+	}
+
+	memcpy(buf, body_data, sizeof(body_data));
+
+	return sizeof(body_data);
+}
+
+static gssize provide_data(void *buf, gsize len, gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (d->total > 0)
+		return 0;
+
+	if (len < sizeof(body_data)) {
+		g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Got data request for only %zu bytes", len);
+		g_main_loop_quit(d->mainloop);
+		return -1;
+	}
+
+	memcpy(buf, body_data, sizeof(body_data));
+
+	if (d->provide_delay > 0) {
+		g_obex_suspend(d->obex);
+		g_timeout_add(d->provide_delay, resume_obex, d->obex);
+	}
+
+	d->total += sizeof(body_data);
+
+	return sizeof(body_data);
+}
+
+static void test_put_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_req_first, sizeof(put_req_first) },
+				{ put_req_last, sizeof(put_req_last) } }, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_put_req(obex, provide_data, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static gboolean rcv_data(const void *buf, gsize len, gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (len != sizeof(body_data))
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected byte count %zu", len);
+
+	if (memcmp(buf, body_data, sizeof(body_data)) != 0) {
+		dump_bufs(body_data, sizeof(body_data), buf, len);
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected byte count %zu", len);
+	}
+
+	return TRUE;
+}
+
+static void handle_put(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_PUT) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_put_rsp(obex, req, rcv_data, transfer_complete, d, &d->err,
+							G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_put_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } }, {
+				{ put_req_last, sizeof(put_req_last) },
+				{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put, &d);
+
+	g_io_channel_write_chars(io, (char *) put_req_first,
+					sizeof(put_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static gboolean rcv_seq(const void *buf, gsize len, gpointer user_data)
+{
+	return TRUE;
+}
+
+static void handle_put_seq(GObex *obex, GObexPacket *req,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_PUT) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_put_rsp(obex, req, rcv_seq, transfer_complete, d,
+						&d->err, G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_stream_put_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } }, {
+				{ put_req_zero, sizeof(put_req_zero) },
+				{ put_req_zero, sizeof(put_req_zero) },
+				{ put_req_last, sizeof(put_req_last) },
+				{ NULL, -1 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_seq,
+									&d);
+
+	g_io_channel_write_chars(io, (char *) put_req_first,
+					sizeof(put_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static gboolean cancel_transfer(gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (d->id > 0)
+		g_obex_cancel_transfer(d->id, transfer_complete, user_data);
+
+	return FALSE;
+}
+
+static gssize abort_data(void *buf, gsize len, gpointer user_data)
+{
+	g_idle_add_full(G_PRIORITY_HIGH, cancel_transfer, user_data, NULL);
+	return provide_data(buf, len, user_data);
+}
+
+static void test_stream_put_req_abort(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_req_first, sizeof(put_req_first) },
+				{ abort_req, sizeof(abort_req) } }, {
+				{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	d.id = g_obex_put_req(obex, abort_data, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_error(d.err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED);
+}
+
+static void test_stream_put_rsp_abort(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } }, {
+				{ put_req_zero, sizeof(put_req_zero) },
+				{ abort_req, sizeof(abort_req) },
+				{ NULL, -1 },
+				{ NULL, -1 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_seq, &d);
+
+	g_io_channel_write_chars(io, (char *) put_req_first,
+					sizeof(put_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_error(d.err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED);
+}
+
+static void handle_put_seq_wait(GObex *obex, GObexPacket *req,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_PUT) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_put_rsp(obex, req, rcv_seq, transfer_complete, d,
+					&d->err,
+					G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
+					G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_packet_put_rsp_wait(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+		{ put_rsp_first_srm_wait, sizeof(put_rsp_first_srm_wait) },
+		{ put_rsp_first, sizeof(put_rsp_first) },
+		{ NULL, -1 },
+		{ put_rsp_last, sizeof(put_rsp_last) } }, {
+		{ put_req_zero, sizeof(put_req_zero) },
+		{ put_req_zero, sizeof(put_req_zero) },
+		{ put_req_last, sizeof(put_req_last) },
+		{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_PUT,
+						handle_put_seq_wait, &d);
+
+	g_io_channel_write_chars(io, (char *) put_req_first_srm,
+					sizeof(put_req_first_srm), NULL,
+					&d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_packet_put_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ put_rsp_first_srm, sizeof(put_rsp_first_srm) },
+			{ NULL, -1 },
+			{ NULL, -1 },
+			{ put_rsp_last, sizeof(put_rsp_last) } }, {
+			{ put_req_zero, sizeof(put_req_zero) },
+			{ put_req_zero, sizeof(put_req_zero) },
+			{ put_req_last, sizeof(put_req_last) },
+			{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_seq, &d);
+
+	g_io_channel_write_chars(io, (char *) put_req_first_srm,
+					sizeof(put_req_first_srm), NULL,
+					&d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_get_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ get_req_first, sizeof(get_req_first) },
+				{ get_req_last, sizeof(get_req_last) } }, {
+				{ get_rsp_first, sizeof(get_rsp_first) },
+				{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_get_req(obex, rcv_data, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_stream_get_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ get_req_first, sizeof(get_req_first) },
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ get_req_last, sizeof(get_req_last) } }, {
+				{ get_rsp_first, sizeof(get_rsp_first) },
+				{ get_rsp_zero, sizeof(get_rsp_zero) },
+				{ get_rsp_zero, sizeof(get_rsp_zero) },
+				{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_packet_get_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ get_req_first_srm, sizeof(get_req_first_srm) },
+			{ NULL, -1 },
+			{ NULL, -1 },
+			{ get_req_last, sizeof(get_req_last) } }, {
+			{ get_rsp_first_srm, sizeof(get_rsp_first_srm) },
+			{ get_rsp_zero, sizeof(get_rsp_zero) },
+			{ get_rsp_zero, sizeof(get_rsp_zero) },
+			{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_packet_get_req_wait(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+		{ get_req_first_srm_wait, sizeof(get_req_first_srm_wait) },
+		{ get_req_last, sizeof(get_req_last) },
+		{ NULL, -1 },
+		{ get_req_last, sizeof(get_req_last) } }, {
+		{ get_rsp_first_srm, sizeof(get_rsp_first_srm) },
+		{ get_rsp_zero, sizeof(get_rsp_zero) },
+		{ get_rsp_zero, sizeof(get_rsp_zero) },
+		{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_packet_get_req_wait_next(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+		{ get_req_first_srm, sizeof(get_req_first_srm) },
+		{ get_req_last, sizeof(get_req_last) },
+		{ get_req_last, sizeof(get_req_last) },
+		{ get_req_last, sizeof(get_req_last) } }, {
+		{ get_rsp_first_srm_wait_next,
+		sizeof(get_rsp_first_srm_wait_next) },
+		{ get_rsp_zero_wait_next, sizeof(get_rsp_zero_wait_next) },
+		{ get_rsp_zero_wait_next, sizeof(get_rsp_zero_wait_next) },
+		{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_get_req_app(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ get_req_first_app, sizeof(get_req_first_app) },
+			{ get_req_last, sizeof(get_req_last) },
+			{ get_req_last, sizeof(get_req_last) } }, {
+			{ get_rsp_first_app, sizeof(get_rsp_first_app) },
+			{ get_rsp_first, sizeof(get_rsp_first) },
+			{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_get_req(obex, rcv_data, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_APPARAM, hdr_app, sizeof(hdr_app),
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 3);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void handle_get_eagain(GObex *obex, GObexPacket *req,
+						gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_GET) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_get_rsp(obex, provide_eagain, transfer_complete, d,
+						&d->err, G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void handle_get(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_GET) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_get_rsp(obex, provide_data, transfer_complete, d, &d->err,
+							G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_stream_put_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ put_req_last, sizeof(put_req_last) } }, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_put_req(obex, provide_seq, transfer_complete, &d, &d.err,
+					G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+					G_OBEX_HDR_NAME, "random.bin",
+					G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_packet_put_req_wait(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+		{ NULL, 0 },
+		{ NULL, 0 },
+		{ NULL, 0 },
+		{ put_req_last, sizeof(put_req_last) } }, {
+		{ put_rsp_first_srm_wait, sizeof(put_rsp_first_srm_wait) },
+		{ put_rsp_first, sizeof(put_rsp_first) },
+		{ NULL, 0 },
+		{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_put_req(obex, provide_seq, transfer_complete, &d, &d.err,
+					G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+					G_OBEX_HDR_NAME, "random.bin",
+					G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_packet_put_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ NULL, 0 },
+			{ NULL, 0 },
+			{ NULL, 0 },
+			{ put_req_last, sizeof(put_req_last) } }, {
+			{ put_rsp_first_srm, sizeof(put_rsp_first_srm) },
+			{ NULL, 0 },
+			{ NULL, 0 },
+			{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_put_req(obex, provide_seq, transfer_complete, &d, &d.err,
+					G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+					G_OBEX_HDR_NAME, "random.bin",
+					G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_put_req_eagain(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_req_first, sizeof(put_req_first) },
+				{ put_req_last, sizeof(put_req_last) } }, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+	d.provide_delay = 200;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_put_req(obex, provide_eagain, transfer_complete, &d, &d.err,
+					G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+					G_OBEX_HDR_NAME, "file.txt",
+					G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_get_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ get_rsp_first, sizeof(get_rsp_first) },
+				{ get_rsp_last, sizeof(get_rsp_last) } }, {
+				{ get_req_last, sizeof(get_req_last) },
+				{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get, &d);
+
+	g_io_channel_write_chars(io, (char *) get_req_first,
+					sizeof(get_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void handle_get_seq(GObex *obex, GObexPacket *req,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_GET) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_get_rsp(obex, provide_seq, transfer_complete, d,
+						&d->err, G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_stream_get_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ get_rsp_last, sizeof(get_rsp_last) } }, {
+				{ get_req_last, sizeof(get_req_last) },
+				{ get_req_last, sizeof(get_req_last) },
+				{ get_req_last, sizeof(get_req_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_seq, &d);
+
+	g_io_channel_write_chars(io, (char *) get_req_first,
+					sizeof(get_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_packet_get_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ get_rsp_last, sizeof(get_rsp_last) } }, {
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ get_req_last, sizeof(get_req_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_seq, &d);
+
+	g_io_channel_write_chars(io, (char *) get_req_first_srm,
+					sizeof(get_req_first_srm), NULL,
+					&d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void handle_get_seq_srm_wait(GObex *obex, GObexPacket *req,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_GET) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_get_rsp(obex, provide_seq, transfer_complete, d,
+					&d->err,
+					G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
+					G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_packet_get_rsp_wait(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ get_rsp_last, sizeof(get_rsp_last) } }, {
+				{ get_req_last, sizeof(get_req_last) },
+				{ NULL, 0 },
+				{ get_req_last, sizeof(get_req_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET,
+					handle_get_seq_srm_wait, &d);
+
+	g_io_channel_write_chars(io, (char *) get_req_first_srm,
+					sizeof(get_req_first_srm), NULL,
+					&d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void handle_get_app(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	GObexPacket *rsp;
+
+	if (op != G_OBEX_OP_GET) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	g_obex_add_request_function(d->obex, G_OBEX_OP_GET, handle_get, d);
+
+	rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
+				G_OBEX_HDR_APPARAM, hdr_app, sizeof(hdr_app),
+				G_OBEX_HDR_INVALID);
+
+	if (g_obex_send(d->obex, rsp, NULL) == FALSE)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_get_rsp_app(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ get_rsp_first_app, sizeof(get_rsp_first_app) },
+			{ get_rsp_first, sizeof(get_rsp_first) },
+			{ get_rsp_last, sizeof(get_rsp_last) } }, {
+			{ get_req_first, sizeof(get_req_first) },
+			{ get_req_last, sizeof(get_req_last) },
+			{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_app, &d);
+
+	g_io_channel_write_chars(io, (char *) get_req_first_app,
+					sizeof(get_req_first_app), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_put_req_delay(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_req_first, sizeof(put_req_first) },
+				{ put_req_last, sizeof(put_req_last) } }, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+	d.provide_delay = 200;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_put_req(obex, provide_data, transfer_complete, &d, &d.err,
+					G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+					G_OBEX_HDR_NAME, "file.txt",
+					G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_get_rsp_delay(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ get_rsp_first, sizeof(get_rsp_first) },
+				{ get_rsp_last, sizeof(get_rsp_last) } }, {
+				{ get_req_last, sizeof(get_req_last) },
+				{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+	d.provide_delay = 200;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get, &d);
+
+	g_io_channel_write_chars(io, (char *) get_req_first,
+					sizeof(get_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static gboolean rcv_data_delay(const void *buf, gsize len, gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (len != sizeof(body_data))
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected byte count %zu", len);
+
+	if (memcmp(buf, body_data, sizeof(body_data)) != 0) {
+		dump_bufs(body_data, sizeof(body_data), buf, len);
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected byte count %zu", len);
+	}
+
+	if (d->provide_delay > 0) {
+		g_obex_suspend(d->obex);
+		g_timeout_add(d->provide_delay, resume_obex, d->obex);
+	}
+
+	return TRUE;
+}
+
+static void handle_put_delay(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	guint id;
+
+	if (op != G_OBEX_OP_PUT) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	id = g_obex_put_rsp(obex, req, rcv_data_delay, transfer_complete, d,
+						&d->err, G_OBEX_HDR_INVALID);
+	if (id == 0)
+		g_main_loop_quit(d->mainloop);
+}
+
+static void test_put_rsp_delay(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } }, {
+				{ put_req_last, sizeof(put_req_last) },
+				{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+	d.provide_delay = 200;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_delay, &d);
+
+	g_io_channel_write_chars(io, (char *) put_req_first,
+					sizeof(put_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_get_req_delay(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ get_req_first, sizeof(get_req_first) },
+				{ get_req_last, sizeof(get_req_last) } }, {
+				{ get_rsp_first, sizeof(get_rsp_first) },
+				{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+	d.provide_delay = 200;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_get_req(obex, rcv_data_delay, transfer_complete, &d, &d.err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_get_rsp_eagain(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ get_rsp_first, sizeof(get_rsp_first) },
+				{ get_rsp_last, sizeof(get_rsp_last) } }, {
+				{ get_req_last, sizeof(get_req_last) },
+				{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+	d.provide_delay = 200;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_eagain,
+									&d);
+
+	g_io_channel_write_chars(io, (char *) get_req_first,
+					sizeof(get_req_first), NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void conn_complete(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (err != NULL)
+		d->err = g_error_copy(err);
+
+	g_main_loop_quit(d->mainloop);
+}
+
+static void test_conn_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ conn_req, sizeof(conn_req) } }, {
+				{ conn_rsp, sizeof(conn_rsp) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_connect(obex, conn_complete, &d, &d.err, G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void handle_conn_rsp(GObex *obex, GObexPacket *req,
+						gpointer user_data)
+{
+	struct test_data *d = user_data;
+	guint8 op = g_obex_packet_get_operation(req, NULL);
+	GObexPacket *rsp;
+
+	if (op != G_OBEX_OP_CONNECT) {
+		d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Unexpected opcode 0x%02x", op);
+		g_main_loop_quit(d->mainloop);
+		return;
+	}
+
+	rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE,
+						G_OBEX_HDR_CONNECTION, 1,
+						G_OBEX_HDR_INVALID);
+	g_obex_send(obex, rsp, &d->err);
+}
+
+static void test_conn_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ conn_rsp, sizeof(conn_rsp) } }, {
+			{ NULL, -1 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+						handle_conn_rsp, &d);
+
+	g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+								NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 1);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void conn_complete_get_req(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (err != NULL) {
+		d->err = g_error_copy(err);
+		g_main_loop_quit(d->mainloop);
+	}
+
+	g_obex_get_req(obex, rcv_data, transfer_complete, d, &d->err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_get_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ conn_req, sizeof(conn_req) },
+			{ conn_get_req_first, sizeof(conn_get_req_first) },
+			{ get_req_last, sizeof(get_req_last) }}, {
+			{ conn_rsp, sizeof(conn_rsp) } ,
+			{ get_rsp_first, sizeof(get_rsp_first) },
+			{ get_rsp_last, sizeof(get_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_connect(obex, conn_complete_get_req, &d, &d.err,
+							G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 3);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_conn_get_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ conn_rsp, sizeof(conn_rsp) },
+			{ get_rsp_first, sizeof(get_rsp_first) },
+			{ get_rsp_last, sizeof(get_rsp_last) } }, {
+			{ conn_get_req_first, sizeof(conn_get_req_first) },
+			{ get_req_last, sizeof(get_req_last) },
+			{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+						handle_conn_rsp, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_GET,
+						handle_get, &d);
+
+	g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+								NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void conn_complete_put_req(GObex *obex, GError *err, GObexPacket *rsp,
+							gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (err != NULL) {
+		d->err = g_error_copy(err);
+		g_main_loop_quit(d->mainloop);
+	}
+
+	g_obex_put_req(obex, provide_data, transfer_complete, d, &d->err,
+				G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+				G_OBEX_HDR_NAME, "file.txt",
+				G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_put_req(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ conn_req, sizeof(conn_req) },
+			{ conn_put_req_first, sizeof(conn_put_req_first) },
+			{ put_req_last, sizeof(put_req_last) }}, {
+			{ conn_rsp, sizeof(conn_rsp) } ,
+			{ put_rsp_first, sizeof(put_rsp_first) },
+			{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_connect(obex, conn_complete_put_req, &d, &d.err,
+							G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 3);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_conn_put_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ conn_rsp, sizeof(conn_rsp) },
+			{ put_rsp_first, sizeof(put_rsp_first) },
+			{ put_rsp_last, sizeof(put_rsp_last) } }, {
+			{ conn_put_req_first, sizeof(conn_put_req_first) },
+			{ put_req_last, sizeof(put_req_last) },
+			{ NULL, 0 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+						handle_conn_rsp, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_PUT,
+						handle_put, &d);
+
+	g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+								NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void test_conn_get_wrg_rsp(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+			{ conn_rsp, sizeof(conn_rsp) },
+			{ unavailable_rsp, sizeof(unavailable_rsp) } }, {
+			{ conn_get_req_wrg, sizeof(conn_get_req_wrg) },
+			{ NULL, -1 } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+						handle_conn_rsp, &d);
+
+	g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+								NULL, &d.err);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, 2);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void conn_complete_put_req_seq(GObex *obex, GError *err,
+					GObexPacket *rsp, gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (err != NULL) {
+		d->err = g_error_copy(err);
+		g_main_loop_quit(d->mainloop);
+	}
+
+	g_obex_put_req(obex, provide_seq, transfer_complete, d, &d->err,
+					G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+					G_OBEX_HDR_NAME, "random.bin",
+					G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_put_req_seq(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ conn_req, sizeof(conn_req) } ,
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ put_req_last, sizeof(put_req_last) } }, {
+				{ conn_rsp, sizeof(conn_rsp) } ,
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_first, sizeof(put_rsp_first) },
+				{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_STREAM);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_connect(obex, conn_complete_put_req_seq, &d, &d.err,
+							G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+static void conn_complete_put_req_seq_srm(GObex *obex, GError *err,
+					GObexPacket *rsp, gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (err != NULL) {
+		d->err = g_error_copy(err);
+		g_main_loop_quit(d->mainloop);
+	}
+
+	g_obex_put_req(obex, provide_seq, transfer_complete, d, &d->err,
+					G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+					G_OBEX_HDR_NAME, "random.bin",
+					G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_put_req_seq_srm(void)
+{
+	GIOChannel *io;
+	GIOCondition cond;
+	guint io_id, timer_id;
+	GObex *obex;
+	struct test_data d = { 0, NULL, {
+				{ conn_req_srm, sizeof(conn_req_srm) } ,
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ put_req_last, sizeof(put_req_last) } }, {
+				{ conn_rsp_srm, sizeof(conn_rsp_srm) } ,
+				{ NULL, 0 },
+				{ NULL, 0 },
+				{ put_rsp_last, sizeof(put_rsp_last) } } };
+
+	create_endpoints(&obex, &io, SOCK_SEQPACKET);
+	d.obex = obex;
+
+	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+	io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+	d.mainloop = g_main_loop_new(NULL, FALSE);
+
+	timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+	g_obex_connect(obex, conn_complete_put_req_seq_srm, &d, &d.err,
+					G_OBEX_HDR_SRM, G_OBEX_SRM_INDICATE,
+					G_OBEX_HDR_INVALID);
+	g_assert_no_error(d.err);
+
+	g_main_loop_run(d.mainloop);
+
+	g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+	g_main_loop_unref(d.mainloop);
+
+	g_source_remove(timer_id);
+	g_io_channel_unref(io);
+	g_source_remove(io_id);
+	g_obex_unref(obex);
+
+	g_assert_no_error(d.err);
+}
+
+int main(int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_func("/gobex/test_conn_req", test_conn_req);
+	g_test_add_func("/gobex/test_conn_rsp", test_conn_rsp);
+
+	g_test_add_func("/gobex/test_put_req", test_put_req);
+	g_test_add_func("/gobex/test_put_rsp", test_put_rsp);
+
+	g_test_add_func("/gobex/test_get_req", test_get_req);
+	g_test_add_func("/gobex/test_get_rsp", test_get_rsp);
+
+	g_test_add_func("/gobex/test_get_req_app", test_get_req_app);
+	g_test_add_func("/gobex/test_get_rsp_app", test_get_rsp_app);
+
+	g_test_add_func("/gobex/test_put_req_delay", test_put_req_delay);
+	g_test_add_func("/gobex/test_put_rsp_delay", test_put_rsp_delay);
+
+	g_test_add_func("/gobex/test_get_req_delay", test_get_req_delay);
+	g_test_add_func("/gobex/test_get_rsp_delay", test_get_rsp_delay);
+
+	g_test_add_func("/gobex/test_put_req_eagain", test_put_req_eagain);
+	g_test_add_func("/gobex/test_get_req_eagain", test_get_rsp_eagain);
+
+	g_test_add_func("/gobex/test_stream_put_req", test_stream_put_req);
+	g_test_add_func("/gobex/test_stream_put_rsp", test_stream_put_rsp);
+
+	g_test_add_func("/gobex/test_stream_put_req_abort",
+						test_stream_put_req_abort);
+	g_test_add_func("/gobex/test_stream_put_rsp_abort",
+						test_stream_put_rsp_abort);
+
+	g_test_add_func("/gobex/test_stream_get_req", test_stream_get_req);
+	g_test_add_func("/gobex/test_stream_get_rsp", test_stream_get_rsp);
+
+	g_test_add_func("/gobex/test_conn_get_req", test_conn_get_req);
+	g_test_add_func("/gobex/test_conn_get_rsp", test_conn_get_rsp);
+
+	g_test_add_func("/gobex/test_conn_put_req", test_conn_put_req);
+	g_test_add_func("/gobex/test_conn_put_rsp", test_conn_put_rsp);
+
+	g_test_add_func("/gobex/test_conn_get_wrg_rsp", test_conn_get_wrg_rsp);
+
+	g_test_add_func("/gobex/test_conn_put_req_seq",
+						test_conn_put_req_seq);
+
+	g_test_add_func("/gobex/test_packet_put_req", test_packet_put_req);
+	g_test_add_func("/gobex/test_packet_put_req_wait",
+						test_packet_put_req_wait);
+
+	g_test_add_func("/gobex/test_packet_put_rsp", test_packet_put_rsp);
+	g_test_add_func("/gobex/test_packet_put_rsp_wait",
+						test_packet_put_rsp_wait);
+
+	g_test_add_func("/gobex/test_packet_get_rsp", test_packet_get_rsp);
+	g_test_add_func("/gobex/test_packet_get_rsp_wait",
+						test_packet_get_rsp_wait);
+
+	g_test_add_func("/gobex/test_packet_get_req", test_packet_get_req);
+	g_test_add_func("/gobex/test_packet_get_req_wait",
+						test_packet_get_req_wait);
+
+	g_test_add_func("/gobex/test_packet_get_req_wait_next",
+						test_packet_get_req_wait_next);
+
+	g_test_add_func("/gobex/test_conn_put_req_seq_srm",
+						test_conn_put_req_seq_srm);
+
+	g_test_run();
+
+	return 0;
+}
diff -pruN 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/util.c 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/util.c
--- 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/util.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/util.c	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,193 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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 <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "util.h"
+
+GQuark test_error_quark(void)
+{
+	return g_quark_from_static_string("test-error-quark");
+}
+
+static void dump_bytes(const uint8_t *buf, size_t buf_len)
+{
+	size_t i;
+
+	for (i = 0; i < buf_len; i++)
+		g_printerr("%02x ", buf[i]);
+
+	g_printerr("\n");
+}
+
+void dump_bufs(const void *mem1, size_t len1, const void *mem2, size_t len2)
+{
+	g_printerr("\nExpected: ");
+	dump_bytes(mem1, len1);
+	g_printerr("Got:      ");
+	dump_bytes(mem2, len2);
+}
+
+void assert_memequal(const void *mem1, size_t len1,
+						const void *mem2, size_t len2)
+{
+	if (len1 == len2 && memcmp(mem1, mem2, len1) == 0)
+		return;
+
+	dump_bufs(mem1, len1, mem2, len2);
+
+	g_assert(0);
+}
+
+GObex *create_gobex(int fd, GObexTransportType transport_type,
+						gboolean close_on_unref)
+{
+	GIOChannel *io;
+	GObex *obex;
+
+	io = g_io_channel_unix_new(fd);
+	g_assert(io != NULL);
+
+	g_io_channel_set_close_on_unref(io, close_on_unref);
+
+	obex = g_obex_new(io, transport_type, -1, -1);
+	g_io_channel_unref(io);
+
+	return obex;
+}
+
+void create_endpoints(GObex **obex, GIOChannel **io, int sock_type)
+{
+	GObexTransportType transport_type;
+	int sv[2];
+
+	if (socketpair(AF_UNIX, sock_type | SOCK_NONBLOCK, 0, sv) < 0) {
+		g_printerr("socketpair: %s", strerror(errno));
+		abort();
+	}
+
+	if (sock_type == SOCK_STREAM)
+		transport_type = G_OBEX_TRANSPORT_STREAM;
+	else
+		transport_type = G_OBEX_TRANSPORT_PACKET;
+
+	*obex = create_gobex(sv[0], transport_type, TRUE);
+	g_assert(*obex != NULL);
+
+	if (io == NULL) {
+		close(sv[1]);
+		return;
+	}
+
+	*io = g_io_channel_unix_new(sv[1]);
+	g_assert(*io != NULL);
+
+	g_io_channel_set_encoding(*io, NULL, NULL);
+	g_io_channel_set_buffered(*io, FALSE);
+	g_io_channel_set_close_on_unref(*io, TRUE);
+}
+
+gboolean test_timeout(gpointer user_data)
+{
+	struct test_data *d = user_data;
+
+	if (!g_main_loop_is_running(d->mainloop))
+		return FALSE;
+
+	d->err = g_error_new(TEST_ERROR, TEST_ERROR_TIMEOUT, "Timed out");
+
+	g_main_loop_quit(d->mainloop);
+
+	return FALSE;
+}
+
+gboolean test_io_cb(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+	struct test_data *d = user_data;
+	GIOStatus status;
+	gsize bytes_written, rbytes, send_buf_len, expect_len;
+	char buf[65535];
+	const char *send_buf, *expect;
+
+	expect = d->recv[d->count].data;
+	expect_len = d->recv[d->count].len;
+	send_buf = d->send[d->count].data;
+	send_buf_len = d->send[d->count].len;
+
+	d->count++;
+
+	if (!(cond & G_IO_IN))
+		goto send;
+
+	status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+	if (status != G_IO_STATUS_NORMAL) {
+		g_print("io_cb count %u\n", d->count);
+		g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+				"Reading data failed with status %d", status);
+		goto failed;
+	}
+
+	if (rbytes < expect_len) {
+		g_print("io_cb count %u\n", d->count);
+		dump_bufs(expect, expect_len, buf, rbytes);
+		g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Not enough data from socket");
+		goto failed;
+	}
+
+	if (memcmp(buf, expect, expect_len) != 0) {
+		g_print("io_cb count %u\n", d->count);
+		dump_bufs(expect, expect_len, buf, rbytes);
+		g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+					"Received data is not correct");
+		goto failed;
+	}
+
+send:
+	if ((gssize) send_buf_len < 0)
+		goto failed;
+
+	g_io_channel_write_chars(io, send_buf, send_buf_len, &bytes_written,
+									NULL);
+	if (bytes_written != send_buf_len) {
+		g_print("io_cb count %u\n", d->count);
+		g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+						"Unable to write to socket");
+		goto failed;
+	}
+
+	if (d->recv[d->count].len < 0 || (gssize) expect_len < 0)
+		return test_io_cb(io, G_IO_OUT, user_data);
+
+	return TRUE;
+
+failed:
+	g_main_loop_quit(d->mainloop);
+	return FALSE;
+}
diff -pruN 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/util.h 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/util.h
--- 0.46-1/.pc/test-avoid-double-source-removals.patch/unit/util.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/.pc/test-avoid-double-source-removals.patch/unit/util.h	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,58 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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 <gobex/gobex.h>
+
+enum {
+	TEST_ERROR_TIMEOUT,
+	TEST_ERROR_UNEXPECTED,
+};
+
+struct test_buf {
+	const void *data;
+	gssize len;
+};
+
+struct test_data {
+	guint count;
+	GError *err;
+	struct test_buf recv[4];
+	struct test_buf send[4];
+	guint provide_delay;
+	GObex *obex;
+	guint id;
+	gsize total;
+	GMainLoop *mainloop;
+};
+
+#define TEST_ERROR test_error_quark()
+GQuark test_error_quark(void);
+
+void dump_bufs(const void *mem1, size_t len1, const void *mem2, size_t len2);
+void assert_memequal(const void *mem1, size_t len1,
+						const void *mem2, size_t len2);
+
+GObex *create_gobex(int fd, GObexTransportType transport_type,
+						gboolean close_on_unref);
+void create_endpoints(GObex **obex, GIOChannel **io, int sock_type);
+
+gboolean test_io_cb(GIOChannel *io, GIOCondition cond, gpointer user_data);
+gboolean test_timeout(gpointer user_data);
diff -pruN 0.46-1/plugins/bluetooth.c 0.48-2.1/plugins/bluetooth.c
--- 0.46-1/plugins/bluetooth.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/bluetooth.c	2012-11-30 07:59:13.000000000 +0000
@@ -325,9 +325,8 @@ static void connect_event(GIOChannel *io
 	stream = FALSE;
 
 	/* Read MTU if io is an L2CAP socket */
-	bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, &omtu,
-						BT_IO_OPT_IMTU, &imtu,
-						BT_IO_OPT_INVALID);
+	bt_io_get(io, NULL, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_IMTU, &imtu,
+							BT_IO_OPT_INVALID);
 
 done:
 	if (obex_server_new_connection(server, io, omtu, imtu, stream) < 0)
@@ -520,7 +519,7 @@ static void confirm_rfcomm(GIOChannel *i
 	char address[18];
 	uint8_t channel;
 
-	bt_io_get(io, BT_IO_RFCOMM, &err,
+	bt_io_get(io, &err,
 			BT_IO_OPT_SOURCE, source,
 			BT_IO_OPT_DEST, address,
 			BT_IO_OPT_CHANNEL, &channel,
@@ -545,7 +544,7 @@ static void confirm_l2cap(GIOChannel *io
 	char address[18];
 	uint16_t psm;
 
-	bt_io_get(io, BT_IO_L2CAP, &err,
+	bt_io_get(io, &err,
 			BT_IO_OPT_SOURCE, source,
 			BT_IO_OPT_DEST, address,
 			BT_IO_OPT_PSM, &psm,
@@ -576,7 +575,7 @@ static GSList *start(struct obex_server
 	else
 		sec_level = BT_IO_SEC_LOW;
 
-	io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_rfcomm,
+	io = bt_io_listen(NULL, confirm_rfcomm,
 				service, NULL, &err,
 				BT_IO_OPT_CHANNEL, service->channel,
 				BT_IO_OPT_SEC_LEVEL, sec_level,
@@ -595,7 +594,7 @@ static GSList *start(struct obex_server
 
 	psm = service->port == OBEX_PORT_RANDOM ? 0 : service->port;
 
-	io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_l2cap,
+	io = bt_io_listen(NULL, confirm_l2cap,
 			service, NULL, &err,
 			BT_IO_OPT_PSM, psm,
 			BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
@@ -610,7 +609,7 @@ static GSList *start(struct obex_server
 		service->port = 0;
 	} else {
 		l = g_slist_prepend(l, io);
-		bt_io_get(io, BT_IO_L2CAP, &err, BT_IO_OPT_PSM, &service->port,
+		bt_io_get(io, &err, BT_IO_OPT_PSM, &service->port,
 							BT_IO_OPT_INVALID);
 		DBG("listening on psm %d", service->port);
 	}
@@ -656,23 +655,10 @@ static void bluetooth_stop(void *data)
 
 static int bluetooth_getpeername(GIOChannel *io, char **name)
 {
-	int sk = g_io_channel_unix_get_fd(io);
 	GError *gerr = NULL;
 	char address[18];
-	int type;
-	socklen_t len = sizeof(int);
-
-	if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
-		return -errno;
 
-	if (type == SOCK_STREAM)
-		bt_io_get(io, BT_IO_RFCOMM, &gerr,
-				BT_IO_OPT_DEST, address,
-				BT_IO_OPT_INVALID);
-	else
-		bt_io_get(io, BT_IO_L2CAP, &gerr,
-				BT_IO_OPT_DEST, address,
-				BT_IO_OPT_INVALID);
+	bt_io_get(io, &gerr, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
 
 	if (gerr) {
 		error("%s", gerr->message);
diff -pruN 0.46-1/plugins/filesystem.c 0.48-2.1/plugins/filesystem.c
--- 0.46-1/plugins/filesystem.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/filesystem.c	2012-11-30 07:59:13.000000000 +0000
@@ -32,7 +32,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <dirent.h>
-#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
@@ -604,7 +603,7 @@ ssize_t string_read(void *object, void *
 
 	len = MIN(string->len, count);
 	memcpy(buf, string->str, len);
-	string = g_string_erase(string, 0, len);
+	g_string_erase(string, 0, len);
 
 	return len;
 }
diff -pruN 0.46-1/plugins/filesystem.h 0.48-2.1/plugins/filesystem.h
--- 0.46-1/plugins/filesystem.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/filesystem.h	2014-10-16 04:43:28.000000000 +0000
@@ -21,6 +21,8 @@
  *
  */
 
+#include <sys/types.h>
+
 ssize_t string_read(void *object, void *buf, size_t count);
 gboolean is_filename(const char *name);
 int verify_path(const char *path);
diff -pruN 0.46-1/plugins/irmc.c 0.48-2.1/plugins/irmc.c
--- 0.46-1/plugins/irmc.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/irmc.c	2012-11-30 07:59:13.000000000 +0000
@@ -172,7 +172,7 @@ static void query_result(const char *buf
 	/* loop around buffer and add X-IRMC-LUID attribs */
 	s = buffer;
 	while ((t = strstr(s, "UID:")) != NULL) {
-		/* add upto UID: into buffer */
+		/* add up to UID: into buffer */
 		irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
 		/*
 		 * add UID: line into buffer
@@ -226,7 +226,7 @@ static void *irmc_connect(struct obex_se
 	param->maxlistcount = 0; /* to count the number of vcards... */
 	param->filter = 0x200085; /* UID TEL N VERSION */
 	irmc->params = param;
-	irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+	irmc->request = phonebook_pull(PB_CONTACTS, irmc->params,
 					phonebook_size_result, irmc, err);
 	ret = phonebook_pull_read(irmc->request);
 	if (err)
@@ -281,7 +281,7 @@ static int irmc_chkput(struct obex_sessi
 	return -EBADR;
 }
 
-static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
+static int irmc_open_devinfo(struct irmc_session *irmc)
 {
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new("");
@@ -301,93 +301,56 @@ static void *irmc_open_devinfo(struct ir
 				"NOTE-TYPE-RX:NONE\r\n",
 				irmc->manu, irmc->model, irmc->sn);
 
-	return irmc;
+	return 0;
 }
 
-static void *irmc_open_pb(const char *name, struct irmc_session *irmc,
-								int *err)
+static int irmc_open_pb(struct irmc_session *irmc)
 {
-	GString *mybuf;
 	int ret;
 
-	if (!g_strcmp0(name, ".vcf")) {
-		/* how can we tell if the vcard count call already finished? */
-		irmc->request = phonebook_pull("telecom/pb.vcf", irmc->params,
+	/* how can we tell if the vcard count call already finished? */
+	irmc->request = phonebook_pull(PB_CONTACTS, irmc->params,
 						query_result, irmc, &ret);
-		if (ret < 0) {
-			DBG("phonebook_pull failed...");
-			goto fail;
-		}
-
-		ret = phonebook_pull_read(irmc->request);
-		if (ret < 0) {
-			DBG("phonebook_pull_read failed...");
-			goto fail;
-		}
+	if (ret < 0) {
+		DBG("phonebook_pull failed...");
+		return ret;
+	}
 
-		return irmc;
+	ret = phonebook_pull_read(irmc->request);
+	if (ret < 0) {
+		DBG("phonebook_pull_read failed...");
+		return ret;
 	}
 
-	if (!g_strcmp0(name, "/info.log")) {
-		mybuf = g_string_new("");
-		g_string_printf(mybuf, "Total-Records:%d\r\n"
+	return 0;
+}
+
+static int irmc_open_info(struct irmc_session *irmc)
+{
+	if (irmc->buffer == NULL)
+		irmc->buffer = g_string_new("");
+
+	g_string_printf(irmc->buffer, "Total-Records:%d\r\n"
 				"Maximum-Records:%d\r\n"
 				"IEL:2\r\n"
 				"DID:%s\r\n",
 				irmc->params->maxlistcount,
 				irmc->params->maxlistcount, irmc->did);
-	} else if (!strncmp(name, "/luid/", 6)) {
-		name += 6;
-		if (!g_strcmp0(name, "cc.log")) {
-			mybuf = g_string_new("");
-			g_string_printf(mybuf, "%d\r\n",
-						irmc->params->maxlistcount);
-		} else {
-			int l = strlen(name);
-			/* FIXME:
-			 * Reply the same to any *.log so we hopefully force a
-			 * full phonebook dump.
-			 * Is IEL:2 ok?
-			 */
-			if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
-				DBG("changelog request, force whole book");
-				mybuf = g_string_new("");
-				g_string_printf(mybuf, "SN:%s\r\n"
-							"DID:%s\r\n"
-							"Total-Records:%d\r\n"
-							"Maximum-Records:%d\r\n"
-							"*\r\n",
-						irmc->sn, irmc->did,
-						irmc->params->maxlistcount,
-						irmc->params->maxlistcount);
-			} else {
-				ret = -EBADR;
-				goto fail;
-			}
-		}
-	} else {
-		ret = -EBADR;
-		goto fail;
-	}
 
-	if (!irmc->buffer)
-		irmc->buffer = mybuf;
-	else {
-		irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
-		g_string_free(mybuf, TRUE);
-	}
+	return 0;
+}
 
-	return irmc;
+static int irmc_open_cc(struct irmc_session *irmc)
+{
+	if (irmc->buffer == NULL)
+		irmc->buffer = g_string_new("");
 
-fail:
-	if (err)
-		*err = ret;
+	g_string_printf(irmc->buffer, "%d\r\n", irmc->params->maxlistcount);
 
-	return NULL;
+	return 0;
 }
 
-static void *irmc_open_cal(const char *name, struct irmc_session *irmc,
-								int *err)
+static int irmc_open_cal(struct irmc_session *irmc)
 {
 	/* no suport yet. Just return an empty buffer. cal.vcs */
 	DBG("unsupported, returning empty buffer");
@@ -395,11 +358,10 @@ static void *irmc_open_cal(const char *n
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new("");
 
-	return irmc;
+	return 0;
 }
 
-static void *irmc_open_nt(const char *name, struct irmc_session *irmc,
-								int *err)
+static int irmc_open_nt(struct irmc_session *irmc)
 {
 	/* no suport yet. Just return an empty buffer. nt.vnt */
 	DBG("unsupported, returning empty buffer");
@@ -407,7 +369,25 @@ static void *irmc_open_nt(const char *na
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new("");
 
-	return irmc;
+	return 0;
+}
+
+static int irmc_open_luid(struct irmc_session *irmc)
+{
+	if (irmc->buffer == NULL)
+		irmc->buffer = g_string_new("");
+
+	DBG("changelog request, force whole book");
+	g_string_printf(irmc->buffer, "SN:%s\r\n"
+					"DID:%s\r\n"
+					"Total-Records:%d\r\n"
+					"Maximum-Records:%d\r\n"
+					"*\r\n",
+					irmc->sn, irmc->did,
+					irmc->params->maxlistcount,
+					irmc->params->maxlistcount);
+
+	return 0;
 }
 
 static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
@@ -415,7 +395,7 @@ static void *irmc_open(const char *name,
 {
 	struct irmc_session *irmc = context;
 	int ret = 0;
-	const char *p;
+	char *path;
 
 	DBG("name %s context %p", name, context);
 
@@ -423,20 +403,39 @@ static void *irmc_open(const char *name,
 		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)
diff -pruN 0.46-1/plugins/mas.c 0.48-2.1/plugins/mas.c
--- 0.46-1/plugins/mas.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/mas.c	2012-11-30 07:59:13.000000000 +0000
@@ -32,6 +32,7 @@
 #include <inttypes.h>
 
 #include <gobex/gobex.h>
+#include <gobex/gobex-apparam.h>
 
 #include "obexd.h"
 #include "plugin.h"
@@ -45,6 +46,9 @@
 
 #include "messages.h"
 
+#define READ_STATUS_REQ 0
+#define DELETE_STATUS_REQ 1
+
 /* Channel number according to bluez doc/assigned-numbers.txt */
 #define MAS_CHANNEL	16
 
@@ -112,8 +116,8 @@ struct mas_session {
 	gboolean finished;
 	gboolean nth_call;
 	GString *buffer;
-	map_ap_t *inparams;
-	map_ap_t *outparams;
+	GObexApparam *inparams;
+	GObexApparam *outparams;
 	gboolean ap_sent;
 };
 
@@ -130,14 +134,12 @@ static int get_params(struct obex_sessio
 	if (size < 0)
 		size = 0;
 
-	mas->inparams = map_ap_decode(buffer, size);
+	mas->inparams = g_obex_apparam_decode(buffer, size);
 	if (mas->inparams == NULL) {
 		DBG("Error when parsing parameters!");
 		return -EBADR;
 	}
 
-	mas->outparams = map_ap_new();
-
 	return 0;
 }
 
@@ -148,13 +150,19 @@ static void reset_request(struct mas_ses
 		mas->buffer = NULL;
 	}
 
-	map_ap_free(mas->inparams);
-	mas->inparams = NULL;
-	map_ap_free(mas->outparams);
-	mas->outparams = NULL;
+	if (mas->inparams) {
+		g_obex_apparam_free(mas->inparams);
+		mas->inparams = NULL;
+	}
+
+	if (mas->outparams) {
+		g_obex_apparam_free(mas->outparams);
+		mas->outparams = NULL;
+	}
 
 	mas->nth_call = FALSE;
 	mas->finished = FALSE;
+	mas->ap_sent = FALSE;
 }
 
 static void mas_clean(struct mas_session *mas)
@@ -289,7 +297,7 @@ static void get_messages_listing_cb(void
 		return;
 	}
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
 
 	if (max == 0) {
 		if (!entry)
@@ -390,10 +398,12 @@ static void get_messages_listing_cb(void
 
 proceed:
 	if (!entry) {
-		map_ap_set_u16(mas->outparams, MAP_AP_MESSAGESLISTINGSIZE,
-							size);
-		map_ap_set_u8(mas->outparams, MAP_AP_NEWMESSAGE,
-							newmsg ? 1 : 0);
+		mas->outparams = g_obex_apparam_set_uint16(mas->outparams,
+						MAP_AP_MESSAGESLISTINGSIZE,
+						size);
+		mas->outparams = g_obex_apparam_set_uint8(mas->outparams,
+						MAP_AP_NEWMESSAGE,
+						newmsg ? 1 : 0);
 	}
 
 	if (err != -EAGAIN)
@@ -435,12 +445,14 @@ static void get_folder_listing_cb(void *
 		return;
 	}
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
 
 	if (max == 0) {
 		if (err != -EAGAIN)
-			map_ap_set_u16(mas->outparams,
-					MAP_AP_FOLDERLISTINGSIZE, size);
+			mas->outparams = g_obex_apparam_set_uint16(
+						mas->outparams,
+						MAP_AP_FOLDERLISTINGSIZE,
+						size);
 
 		if (!name)
 			mas->finished = TRUE;
@@ -477,7 +489,7 @@ proceed:
 		obex_object_set_io_flags(mas, G_IO_IN, err);
 }
 
-static void update_inbox_cb(void *session, int err, void *user_data)
+static void set_status_cb(void *session, int err, void *user_data)
 {
 	struct mas_session *mas = user_data;
 
@@ -529,8 +541,8 @@ static void *folder_listing_open(const c
 
 	DBG("name = %s", name);
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
-	map_ap_get_u16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
 
 	*err = messages_get_folder_listing(mas->backend_data, name, max,
 					offset, get_folder_listing_cb, mas);
@@ -551,6 +563,9 @@ static void *msg_listing_open(const char
 	/* 1024 is the default when there was no MaxListCount sent */
 	uint16_t max = 1024;
 	uint16_t offset = 0;
+	/* If MAP client does not specify the subject length,
+	   then subject_len = 0 and subject should be sent unaltered. */
+	uint8_t subject_len = 0;
 
 	DBG("");
 
@@ -559,28 +574,30 @@ static void *msg_listing_open(const char
 		return NULL;
 	}
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
-	map_ap_get_u16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+	g_obex_apparam_get_uint8(mas->inparams, MAP_AP_SUBJECTLENGTH,
+						&subject_len);
 
-	map_ap_get_u32(mas->inparams, MAP_AP_PARAMETERMASK,
+	g_obex_apparam_get_uint32(mas->inparams, MAP_AP_PARAMETERMASK,
 						&filter.parameter_mask);
-	map_ap_get_u8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
+	g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
 						&filter.type);
-	filter.period_begin = map_ap_get_string(mas->inparams,
+	filter.period_begin = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERPERIODBEGIN);
-	filter.period_end = map_ap_get_string(mas->inparams,
+	filter.period_end = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERPERIODEND);
-	map_ap_get_u8(mas->inparams, MAP_AP_FILTERREADSTATUS,
+	g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERREADSTATUS,
 						&filter.read_status);
-	filter.recipient = map_ap_get_string(mas->inparams,
+	filter.recipient = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERRECIPIENT);
-	filter.originator = map_ap_get_string(mas->inparams,
+	filter.originator = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERORIGINATOR);
-	map_ap_get_u8(mas->inparams, MAP_AP_FILTERPRIORITY,
+	g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERPRIORITY,
 						&filter.priority);
 
 	*err = messages_get_messages_listing(mas->backend_data, name, max,
-			offset, &filter,
+			offset, subject_len, &filter,
 			get_messages_listing_cb, mas);
 
 	mas->buffer = g_string_new("");
@@ -624,24 +641,65 @@ static void *message_update_open(const c
 
 	DBG("");
 
-	if (oflag != O_WRONLY) {
+	if (oflag == O_RDONLY) {
 		*err = -EBADR;
 		return NULL;
 	}
 
-	*err = messages_update_inbox(mas->backend_data, update_inbox_cb, mas);
+	*err = messages_update_inbox(mas->backend_data, set_status_cb, mas);
 	if (*err < 0)
 		return NULL;
 	else
 		return mas;
 }
 
+static void *message_set_status_open(const char *name, int oflag, mode_t mode,
+					void *driver_data, size_t *size,
+					int *err)
+
+{
+	struct mas_session *mas = driver_data;
+	uint8_t indicator;
+	uint8_t value;
+
+	DBG("");
+
+	if (oflag == O_RDONLY) {
+		*err = -EBADR;
+		return NULL;
+	}
+
+	if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSINDICATOR,
+								&indicator)) {
+		*err = -EBADR;
+		return NULL;
+	}
+
+	if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSVALUE,
+								&value)) {
+		*err = -EBADR;
+		return NULL;
+	}
+
+	if (indicator == READ_STATUS_REQ)
+		*err = messages_set_read(mas->backend_data, name, value,
+							set_status_cb, mas);
+	else if (indicator == DELETE_STATUS_REQ)
+		*err = messages_set_delete(mas->backend_data, name, value,
+							set_status_cb, mas);
+	else
+		*err = -EBADR;
+
+	if (*err < 0)
+		return NULL;
+
+	return mas;
+}
+
 static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
 								uint8_t *hi)
 {
 	struct mas_session *mas = object;
-	size_t len;
-	uint8_t *apbuf;
 
 	DBG("");
 
@@ -654,18 +712,7 @@ static ssize_t any_get_next_header(void
 		return 0;
 
 	mas->ap_sent = TRUE;
-	apbuf = map_ap_encode(mas->outparams, &len);
-
-	if (len > mtu) {
-		DBG("MTU is to small to fit application parameters header!");
-		g_free(apbuf);
-
-		return -EIO;
-	}
-
-	memcpy(buf, apbuf, len);
-
-	return len;
+	return g_obex_apparam_encode(mas->outparams, buf, mtu);
 }
 
 static void *any_open(const char *name, int oflag, mode_t mode,
@@ -764,6 +811,7 @@ static struct obex_mime_type_driver mime
 	.target = MAS_TARGET,
 	.target_size = TARGET_SIZE,
 	.mimetype = "x-bt/MAP-msg-listing",
+	.get_next_header = any_get_next_header,
 	.open = msg_listing_open,
 	.close = any_close,
 	.read = any_read,
@@ -784,7 +832,7 @@ static struct obex_mime_type_driver mime
 	.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,
diff -pruN 0.46-1/plugins/messages-dummy.c 0.48-2.1/plugins/messages-dummy.c
--- 0.46-1/plugins/messages-dummy.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/messages-dummy.c	2012-11-30 07:59:13.000000000 +0000
@@ -331,6 +331,7 @@ int messages_get_folder_listing(void *s,
 
 int messages_get_messages_listing(void *session, const char *name,
 				uint16_t max, uint16_t offset,
+				uint8_t subject_len,
 				const struct messages_filter *filter,
 				messages_get_messages_listing_cb callback,
 				void *user_data)
@@ -346,11 +347,23 @@ int messages_get_message(void *session,
 	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)
 {
diff -pruN 0.46-1/plugins/messages.h 0.48-2.1/plugins/messages.h
--- 0.46-1/plugins/messages.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/messages.h	2012-11-30 07:59:13.000000000 +0000
@@ -215,6 +215,8 @@ int messages_get_folder_listing(void *se
  * session: Backend session.
  * name: Optional subdirectory name.
  * max: Maximum number of entries to retrieve.
+ * offset: Offset of the first entry.
+ * subject_len: Maximum string length of the "subject" parameter in the entries.
  * filter: Filter to apply on returned message listing.
  * size: Total size of listing to be returned.
  * newmsg: Indicates presence of unread messages.
@@ -229,6 +231,7 @@ typedef void (*messages_get_messages_lis
 
 int messages_get_messages_listing(void *session, const char *name,
 				uint16_t max, uint16_t offset,
+				uint8_t subject_len,
 				const struct messages_filter *filter,
 				messages_get_messages_listing_cb callback,
 				void *user_data);
@@ -265,17 +268,39 @@ int messages_get_message(void *session,
 					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 recieved from MCE.
+ * 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.
  *
diff -pruN 0.46-1/plugins/messages-tracker.c 0.48-2.1/plugins/messages-tracker.c
--- 0.46-1/plugins/messages-tracker.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/messages-tracker.c	2012-11-30 07:59:13.000000000 +0000
@@ -303,9 +303,9 @@ int messages_get_folder_listing(void *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)
@@ -321,11 +321,24 @@ int messages_get_message(void *session,
 	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)
 {
diff -pruN 0.46-1/plugins/pbap.c 0.48-2.1/plugins/pbap.c
--- 0.46-1/plugins/pbap.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/pbap.c	2012-11-30 07:59:13.000000000 +0000
@@ -39,6 +39,7 @@
 #include <inttypes.h>
 
 #include <gobex.h>
+#include <gobex-apparam.h>
 
 #include "obexd.h"
 #include "plugin.h"
@@ -64,16 +65,6 @@
 #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\" ?>	\
@@ -117,12 +108,6 @@
   </attribute>								\
 </record>"
 
-struct aparam_header {
-	uint8_t tag;
-	uint8_t len;
-	uint8_t val[0];
-} __attribute__ ((packed));
-
 struct cache {
 	gboolean valid;
 	uint32_t index;
@@ -147,7 +132,7 @@ struct pbap_session {
 
 struct pbap_object {
 	GString *buffer;
-	GByteArray *aparams;
+	GObexApparam *apparam;
 	gboolean firstpacket;
 	gboolean lastpart;
 	struct pbap_session *session;
@@ -229,33 +214,6 @@ static void cache_clear(struct cache *ca
 	cache->entries = NULL;
 }
 
-static GByteArray *append_aparam_header(GByteArray *buf, uint8_t tag,
-							const void *val)
-{
-	/* largest aparam is for phonebooksize (4 bytes) */
-	uint8_t aparam[sizeof(struct aparam_header) + PHONEBOOKSIZE_LEN];
-	struct aparam_header *hdr = (struct aparam_header *) aparam;
-
-	switch (tag) {
-	case PHONEBOOKSIZE_TAG:
-		hdr->tag = PHONEBOOKSIZE_TAG;
-		hdr->len = PHONEBOOKSIZE_LEN;
-		memcpy(hdr->val, val, PHONEBOOKSIZE_LEN);
-
-		return g_byte_array_append(buf,	aparam,
-			sizeof(struct aparam_header) + PHONEBOOKSIZE_LEN);
-	case NEWMISSEDCALLS_TAG:
-		hdr->tag = NEWMISSEDCALLS_TAG;
-		hdr->len = NEWMISSEDCALLS_LEN;
-		memcpy(hdr->val, val, NEWMISSEDCALLS_LEN);
-
-		return g_byte_array_append(buf,	aparam,
-			sizeof(struct aparam_header) + NEWMISSEDCALLS_LEN);
-	default:
-		return buf;
-	}
-}
-
 static void phonebook_size_result(const char *buffer, size_t bufsize,
 					int vcards, int missed,
 					gboolean lastpart, void *user_data)
@@ -275,15 +233,16 @@ static void phonebook_size_result(const
 
 	phonebooksize = htons(vcards);
 
-	pbap->obj->aparams = g_byte_array_new();
-	pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-					PHONEBOOKSIZE_TAG, &phonebooksize);
+	pbap->obj->apparam = g_obex_apparam_set_uint16(NULL, PHONEBOOKSIZE_TAG,
+								phonebooksize);
 
 	if (missed > 0)	{
 		DBG("missed %d", missed);
 
-		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-						NEWMISSEDCALLS_TAG, &missed);
+		pbap->obj->apparam = g_obex_apparam_set_uint16(
+							pbap->obj->apparam,
+							NEWMISSEDCALLS_TAG,
+							missed);
 	}
 
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
@@ -319,9 +278,10 @@ static void query_result(const char *buf
 
 		pbap->obj->firstpacket = TRUE;
 
-		pbap->obj->aparams = g_byte_array_new();
-		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-						NEWMISSEDCALLS_TAG, &missed);
+		pbap->obj->apparam = g_obex_apparam_set_uint16(
+							pbap->obj->apparam,
+							NEWMISSEDCALLS_TAG,
+							missed);
 	}
 
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
@@ -450,9 +410,10 @@ static int generate_response(void *user_
 		/* Ignore all other parameter and return PhoneBookSize */
 		uint16_t size = htons(g_slist_length(pbap->cache.entries));
 
-		pbap->obj->aparams = g_byte_array_new();
-		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-						PHONEBOOKSIZE_TAG, &size);
+		pbap->obj->apparam = g_obex_apparam_set_uint16(
+							pbap->obj->apparam,
+							PHONEBOOKSIZE_TAG,
+							size);
 
 		return 0;
 	}
@@ -527,85 +488,34 @@ static void cache_entry_done(void *user_
 
 static struct apparam_field *parse_aparam(const uint8_t *buffer, uint32_t hlen)
 {
+	GObexApparam *apparam;
 	struct apparam_field *param;
-	struct aparam_header *hdr;
-	uint64_t val64;
-	uint32_t len = 0;
-	uint16_t val16;
-
-	param = g_new0(struct apparam_field, 1);
-
-	while (len < hlen) {
-		hdr = (void *) buffer + len;
-
-		switch (hdr->tag) {
-		case ORDER_TAG:
-			if (hdr->len != ORDER_LEN)
-				goto failed;
-
-			param->order = hdr->val[0];
-			break;
-
-		case SEARCHATTRIB_TAG:
-			if (hdr->len != SEARCHATTRIB_LEN)
-				goto failed;
-
-			param->searchattrib = hdr->val[0];
-			break;
-		case SEARCHVALUE_TAG:
-			if (hdr->len == 0)
-				goto failed;
-
-			param->searchval = g_try_malloc0(hdr->len + 1);
-			if (param->searchval)
-				memcpy(param->searchval, hdr->val, hdr->len);
-			break;
-		case FILTER_TAG:
-			if (hdr->len != FILTER_LEN)
-				goto failed;
-
-			memcpy(&val64, hdr->val, sizeof(val64));
-			param->filter = GUINT64_FROM_BE(val64);
-
-			break;
-		case FORMAT_TAG:
-			if (hdr->len != FORMAT_LEN)
-				goto failed;
 
-			param->format = hdr->val[0];
-			break;
-		case MAXLISTCOUNT_TAG:
-			if (hdr->len != MAXLISTCOUNT_LEN)
-				goto failed;
+	apparam = g_obex_apparam_decode(buffer, hlen);
+	if (apparam == NULL)
+		return NULL;
 
-			memcpy(&val16, hdr->val, sizeof(val16));
-			param->maxlistcount = GUINT16_FROM_BE(val16);
-			break;
-		case LISTSTARTOFFSET_TAG:
-			if (hdr->len != LISTSTARTOFFSET_LEN)
-				goto failed;
-
-			memcpy(&val16, hdr->val, sizeof(val16));
-			param->liststartoffset = GUINT16_FROM_BE(val16);
-			break;
-		default:
-			goto failed;
-		}
+	param = g_new0(struct apparam_field, 1);
 
-		len += hdr->len + sizeof(struct aparam_header);
-	}
+	g_obex_apparam_get_uint8(apparam, ORDER_TAG, &param->order);
+	g_obex_apparam_get_uint8(apparam, SEARCHATTRIB_TAG,
+						&param->searchattrib);
+	g_obex_apparam_get_uint8(apparam, FORMAT_TAG, &param->format);
+	g_obex_apparam_get_uint16(apparam, MAXLISTCOUNT_TAG,
+						&param->maxlistcount);
+	g_obex_apparam_get_uint16(apparam, LISTSTARTOFFSET_TAG,
+						&param->liststartoffset);
+	g_obex_apparam_get_uint64(apparam, FILTER_TAG, &param->filter);
+	param->searchval = g_obex_apparam_get_string(apparam, SEARCHVALUE_TAG);
 
 	DBG("o %x sa %x sv %s fil %" G_GINT64_MODIFIER "x for %x max %x off %x",
 			param->order, param->searchattrib, param->searchval,
 			param->filter, param->format, param->maxlistcount,
 			param->liststartoffset);
 
-	return param;
-
-failed:
-	g_free(param);
+	g_obex_apparam_free(apparam);
 
-	return NULL;
+	return param;
 }
 
 static void *pbap_connect(struct obex_session *os, int *err)
@@ -839,8 +749,8 @@ static int vobject_close(void *object)
 	if (obj->buffer)
 		g_string_free(obj->buffer, TRUE);
 
-	if (obj->aparams)
-		g_byte_array_free(obj->aparams, TRUE);
+	if (obj->apparam)
+		g_obex_apparam_free(obj->apparam);
 
 	if (obj->request)
 		phonebook_req_finalize(obj->request);
@@ -952,27 +862,13 @@ fail:
 	return NULL;
 }
 
-static ssize_t array_read(GByteArray *array, void *buf, size_t count)
-{
-	ssize_t len;
-
-	if (array->len == 0)
-		return 0;
-
-	len = MIN(array->len, count);
-	memcpy(buf, array->data, len);
-	array = g_byte_array_remove_range(array, 0, len);
-
-	return len;
-}
-
 static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
 								uint8_t *hi)
 {
 	struct pbap_object *obj = object;
 	struct pbap_session *pbap = obj->session;
 
-	if (!obj->buffer && !obj->aparams)
+	if (!obj->buffer && !obj->apparam)
 		return -EAGAIN;
 
 	*hi = G_OBEX_HDR_APPARAM;
@@ -980,7 +876,7 @@ static ssize_t vobject_pull_get_next_hea
 	if (pbap->params->maxlistcount == 0 || obj->firstpacket) {
 		obj->firstpacket = FALSE;
 
-		return array_read(obj->aparams, buf, mtu);
+		return g_obex_apparam_encode(obj->apparam, buf, mtu);
 	}
 
 	return 0;
@@ -1031,7 +927,7 @@ static ssize_t vobject_list_get_next_hea
 	*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;
 }
diff -pruN 0.46-1/plugins/phonebook-dummy.c 0.48-2.1/plugins/phonebook-dummy.c
--- 0.46-1/plugins/phonebook-dummy.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/phonebook-dummy.c	2012-07-26 17:09:25.000000000 +0000
@@ -218,7 +218,7 @@ static gboolean read_dir(void *user_data
 	struct dummy_data *dummy = user_data;
 	GString *buffer;
 	DIR *dp;
-	uint16_t count, max, offset;
+	uint16_t count = 0, max, offset;
 
 	buffer = g_string_new("");
 
diff -pruN 0.46-1/plugins/phonebook-ebook.c 0.48-2.1/plugins/phonebook-ebook.c
--- 0.46-1/plugins/phonebook-ebook.c	2014-10-16 04:43:28.000000000 +0000
+++ 0.48-2.1/plugins/phonebook-ebook.c	2012-11-30 07:59:13.000000000 +0000
@@ -459,7 +459,7 @@ char *phonebook_set_folder(const char *c
 	root = (g_strcmp0("/", current_folder) == 0);
 	child = (new_folder && strlen(new_folder) != 0);
 
-	/* Evolution back-end will support telecom/pb folder only */
+	/* Evolution back-end will support /telecom/pb folder only */
 
 	switch (flags) {
 	case 0x02:
@@ -471,8 +471,8 @@ char *phonebook_set_folder(const char *c
 
 		/* Go down 1 level */
 		fullname = g_build_filename(current_folder, new_folder, NULL);
-		if (strcmp("/telecom", fullname) != 0 &&
-				strcmp("/telecom/pb", fullname) != 0) {
+		if (strcmp(PB_TELECOM_FOLDER, fullname) != 0 &&
+				strcmp(PB_CONTACTS_FOLDER, fullname) != 0) {
 			g_free(fullname);
 			fullname = NULL;
 			ret = -ENOENT;
@@ -511,8 +511,8 @@ char *phonebook_set_folder(const char *c
 		}
 
 		fullname = g_build_filename(base, new_folder, NULL);
-		if (strcmp(fullname, "/telecom") != 0 &&
-				strcmp(fullname, "/telecom/pb") != 0) {
+		if (strcmp(fullname, PB_TELECOM_FOLDER) != 0 &&
+				strcmp(fullname, PB_CONTACTS_FOLDER) != 0) {
 			g_free(fullname);
 			fullname = NULL;
 			ret = -ENOENT;
@@ -548,7 +548,7 @@ void *phonebook_pull(const char *name, c
 {
 	struct query_context *data;
 
-	if (g_strcmp0("/telecom/pb.vcf", name) != 0) {
+	if (g_strcmp0(PB_CONTACTS, name) != 0) {
 		if (err)
 			*err = -ENOENT;
 
@@ -638,7 +638,7 @@ void *phonebook_create_cache(const char
 	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;
 
diff -pruN 0.46-1/plugins/phonebook.h 0.48-2.1/plugins/phonebook.h
--- 0.46-1/plugins/phonebook.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/phonebook.h	2012-11-30 07:59:13.000000000 +0000
@@ -29,6 +29,26 @@
 #define VCARD_LISTING_ELEMENT "<card handle = \"%d.vcf\" name = \"%s\"/>" EOL
 #define VCARD_LISTING_END "</vCard-listing>"
 
+#define PB_TELECOM_FOLDER "/telecom"
+#define PB_CONTACTS_FOLDER "/telecom/pb"
+#define PB_CALENDAR_FOLDER "/telecom/cal"
+#define PB_NOTES_FOLDER "/telecom/nt"
+#define PB_CALLS_COMBINED_FOLDER "/telecom/cch"
+#define PB_CALLS_INCOMING_FOLDER "/telecom/ich"
+#define PB_CALLS_MISSED_FOLDER "/telecom/mch"
+#define PB_CALLS_OUTGOING_FOLDER "/telecom/och"
+#define PB_LUID_FOLDER "/telecom/luid"
+
+#define PB_CONTACTS "/telecom/pb.vcf"
+#define PB_CALLS_COMBINED "/telecom/cch.vcf"
+#define PB_CALLS_INCOMING "/telecom/ich.vcf"
+#define PB_CALLS_MISSED "/telecom/mch.vcf"
+#define PB_CALLS_OUTGOING "/telecom/och.vcf"
+#define PB_DEVINFO "/telecom/devinfo.txt"
+#define PB_INFO_LOG "/telecom/pb/info.log"
+#define PB_CC_LOG "/telecom/pb/luid/cc.log"
+
+
 struct apparam_field {
 	/* list and pull attributes */
 	uint16_t maxlistcount;
@@ -41,7 +61,7 @@ struct apparam_field {
 	/* list attributes only */
 	uint8_t order;
 	uint8_t searchattrib;
-	uint8_t *searchval;
+	char *searchval;
 };
 
 /*
diff -pruN 0.46-1/plugins/phonebook-tracker.c 0.48-2.1/plugins/phonebook-tracker.c
--- 0.46-1/plugins/phonebook-tracker.c	2014-10-16 04:43:28.000000000 +0000
+++ 0.48-2.1/plugins/phonebook-tracker.c	2012-11-30 07:59:13.000000000 +0000
@@ -513,15 +513,15 @@ static TrackerSparqlConnection *connecti
 
 static const char *name2query(const char *name)
 {
-	if (g_str_equal(name, "/telecom/pb.vcf"))
+	if (g_str_equal(name, PB_CONTACTS))
 		return CONTACTS_QUERY_ALL;
-	else if (g_str_equal(name, "/telecom/ich.vcf"))
+	else if (g_str_equal(name, PB_CALLS_INCOMING))
 		return INCOMING_CALLS_QUERY;
-	else if (g_str_equal(name, "/telecom/och.vcf"))
+	else if (g_str_equal(name, PB_CALLS_OUTGOING))
 		return OUTGOING_CALLS_QUERY;
-	else if (g_str_equal(name, "/telecom/mch.vcf"))
+	else if (g_str_equal(name, PB_CALLS_MISSED))
 		return MISSED_CALLS_QUERY;
-	else if (g_str_equal(name, "/telecom/cch.vcf"))
+	else if (g_str_equal(name, PB_CALLS_COMBINED))
 		return COMBINED_CALLS_QUERY;
 
 	return NULL;
@@ -529,15 +529,15 @@ static const char *name2query(const char
 
 static const char *name2count_query(const char *name)
 {
-	if (g_str_equal(name, "/telecom/pb.vcf"))
+	if (g_str_equal(name, PB_CONTACTS))
 		return CONTACTS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/ich.vcf"))
+	else if (g_str_equal(name, PB_CALLS_INCOMING))
 		return INCOMING_CALLS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/och.vcf"))
+	else if (g_str_equal(name, PB_CALLS_OUTGOING))
 		return OUTGOING_CALLS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/mch.vcf"))
+	else if (g_str_equal(name, PB_CALLS_MISSED))
 		return MISSED_CALLS_COUNT_QUERY;
-	else if (g_str_equal(name, "/telecom/cch.vcf"))
+	else if (g_str_equal(name, PB_CALLS_COMBINED))
 		return COMBINED_CALLS_COUNT_QUERY;
 
 	return NULL;
@@ -550,17 +550,17 @@ static gboolean folder_is_valid(const ch
 
 	if (g_str_equal(folder, "/"))
 		return TRUE;
-	else if (g_str_equal(folder, "/telecom"))
+	else if (g_str_equal(folder, PB_TELECOM_FOLDER))
 		return TRUE;
-	else if (g_str_equal(folder, "/telecom/pb"))
+	else if (g_str_equal(folder, PB_CONTACTS_FOLDER))
 		return TRUE;
-	else if (g_str_equal(folder, "/telecom/ich"))
+	else if (g_str_equal(folder, PB_CALLS_INCOMING_FOLDER))
 		return TRUE;
-	else if (g_str_equal(folder, "/telecom/och"))
+	else if (g_str_equal(folder, PB_CALLS_OUTGOING_FOLDER))
 		return TRUE;
-	else if (g_str_equal(folder, "/telecom/mch"))
+	else if (g_str_equal(folder, PB_CALLS_MISSED_FOLDER))
 		return TRUE;
-	else if (g_str_equal(folder, "/telecom/cch"))
+	else if (g_str_equal(folder, PB_CALLS_COMBINED_FOLDER))
 		return TRUE;
 
 	return FALSE;
@@ -568,15 +568,15 @@ static gboolean folder_is_valid(const ch
 
 static const char *folder2query(const char *folder)
 {
-	if (g_str_equal(folder, "/telecom/pb"))
+	if (g_str_equal(folder, PB_CONTACTS_FOLDER))
 		return CONTACTS_QUERY_ALL_LIST;
-	else if (g_str_equal(folder, "/telecom/ich"))
+	else if (g_str_equal(folder, PB_CALLS_INCOMING_FOLDER))
 		return INCOMING_CALLS_LIST;
-	else if (g_str_equal(folder, "/telecom/och"))
+	else if (g_str_equal(folder, PB_CALLS_OUTGOING_FOLDER))
 		return OUTGOING_CALLS_LIST;
-	else if (g_str_equal(folder, "/telecom/mch"))
+	else if (g_str_equal(folder, PB_CALLS_MISSED_FOLDER))
 		return MISSED_CALLS_LIST;
-	else if (g_str_equal(folder, "/telecom/cch"))
+	else if (g_str_equal(folder, PB_CALLS_COMBINED_FOLDER))
 		return COMBINED_CALLS_LIST;
 
 	return NULL;
@@ -1541,11 +1541,11 @@ static int pull_newmissedcalls(const cha
 	}
 
 	if (data->params->maxlistcount == 0) {
-		query = name2count_query("/telecom/mch.vcf");
+		query = name2count_query(PB_CALLS_MISSED);
 		col_amount = COUNT_QUERY_COL_AMOUNT;
 		pull_cb = pull_contacts_size;
 	} else {
-		query = name2query("/telecom/mch.vcf");
+		query = name2query(PB_CALLS_MISSED);
 		col_amount = PULL_QUERY_COL_AMOUNT;
 		pull_cb = pull_contacts;
 	}
@@ -1613,7 +1613,7 @@ int phonebook_pull_read(void *request)
 
 	data->newmissedcalls = 0;
 
-	if (g_strcmp0(data->req_name, "/telecom/mch.vcf") == 0 &&
+	if (g_strcmp0(data->req_name, PB_CALLS_MISSED) == 0 &&
 						data->tracker_index == 0) {
 		/* new missed calls amount should be counted only once - it
 		 * will be done during generating first part of results of
diff -pruN 0.46-1/plugins/syncevolution.c 0.48-2.1/plugins/syncevolution.c
--- 0.46-1/plugins/syncevolution.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/plugins/syncevolution.c	2012-07-26 17:09:25.000000000 +0000
@@ -365,8 +365,7 @@ static ssize_t synce_read(void *object,
 
 	append_dict_entry(&dict, "id", DBUS_TYPE_STRING, context->id);
 
-	snprintf(transport, sizeof(transport), "%s.obexd",
-					OPENOBEX_SERVICE);
+	snprintf(transport, sizeof(transport), "%s.obexd", OBEXD_SERVICE);
 	append_dict_entry(&dict, "transport", DBUS_TYPE_STRING, transport);
 
 	snprintf(transport_description, sizeof(transport_description),
diff -pruN 0.46-1/src/manager.c 0.48-2.1/src/manager.c
--- 0.46-1/src/manager.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/manager.c	2012-07-26 17:09:25.000000000 +0000
@@ -44,11 +44,12 @@
 #include "btio.h"
 #include "service.h"
 
-#define OPENOBEX_MANAGER_PATH "/"
-#define OPENOBEX_MANAGER_INTERFACE OPENOBEX_SERVICE ".Manager"
-#define ERROR_INTERFACE OPENOBEX_SERVICE ".Error"
-#define TRANSFER_INTERFACE OPENOBEX_SERVICE ".Transfer"
-#define SESSION_INTERFACE OPENOBEX_SERVICE ".Session"
+#define OBEX_MANAGER_PATH "/"
+#define OBEX_MANAGER_INTERFACE OBEXD_SERVICE ".Manager"
+#define ERROR_INTERFACE OBEXD_SERVICE ".Error"
+#define TRANSFER_INTERFACE OBEXD_SERVICE ".Transfer"
+#define SESSION_INTERFACE OBEXD_SERVICE ".Session"
+#define AGENT_INTERFACE OBEXD_SERVICE ".Agent"
 
 #define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */
 
@@ -310,32 +311,38 @@ static DBusMessage *transfer_cancel(DBus
 	return dbus_message_new_method_return(msg);
 }
 
-static GDBusMethodTable manager_methods[] = {
-	{ "RegisterAgent",	"o",	"",	register_agent		},
-	{ "UnregisterAgent",	"o",	"",	unregister_agent	},
+static const GDBusMethodTable manager_methods[] = {
+	{ GDBUS_METHOD("RegisterAgent",
+			GDBUS_ARGS({ "agent", "o" }), NULL, register_agent) },
+	{ GDBUS_METHOD("UnregisterAgent",
+			GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
 	{ }
 };
 
-static GDBusSignalTable manager_signals[] = {
-	{ "TransferStarted",	"o"	},
-	{ "TransferCompleted",	"ob"	},
-	{ "SessionCreated",	"o"	},
-	{ "SessionRemoved",	"o"	},
+static const GDBusSignalTable manager_signals[] = {
+	{ GDBUS_SIGNAL("TransferStarted", GDBUS_ARGS({ "transfer", "o"})) },
+	{ GDBUS_SIGNAL("TransferCompleted", GDBUS_ARGS({ "transfer", "o" },
+							{ "success", "b" })) },
+	{ GDBUS_SIGNAL("SessionCreated", GDBUS_ARGS({ "session", "o" })) },
+	{ GDBUS_SIGNAL("SessionRemoved", GDBUS_ARGS({ "session", "o" })) },
 	{ }
 };
 
-static GDBusMethodTable transfer_methods[] = {
-	{ "Cancel",	"",	"",	transfer_cancel	},
+static const GDBusMethodTable transfer_methods[] = {
+	{ GDBUS_METHOD("Cancel", NULL, NULL, transfer_cancel) },
 	{ }
 };
 
-static GDBusSignalTable transfer_signals[] = {
-	{ "Progress",	"ii"	},
+static const GDBusSignalTable transfer_signals[] = {
+	{ GDBUS_SIGNAL("Progress", GDBUS_ARGS({ "total", "i" },
+						{ "transferred", "i" })) },
 	{ }
 };
 
-static GDBusMethodTable session_methods[] = {
-	{ "GetProperties",	"",	"{sv}",	get_properties	},
+static const GDBusMethodTable session_methods[] = {
+	{ GDBUS_METHOD("GetProperties",
+				NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+				get_properties) },
 	{ }
 };
 
@@ -347,8 +354,7 @@ gboolean manager_init(void)
 
 	dbus_error_init(&err);
 
-	connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OPENOBEX_SERVICE,
-									&err);
+	connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OBEXD_SERVICE, &err);
 	if (connection == NULL) {
 		if (dbus_error_is_set(&err) == TRUE) {
 			fprintf(stderr, "%s\n", err.message);
@@ -358,8 +364,8 @@ gboolean manager_init(void)
 		return FALSE;
 	}
 
-	return g_dbus_register_interface(connection, OPENOBEX_MANAGER_PATH,
-					OPENOBEX_MANAGER_INTERFACE,
+	return g_dbus_register_interface(connection, OBEX_MANAGER_PATH,
+					OBEX_MANAGER_INTERFACE,
 					manager_methods, manager_signals, NULL,
 					NULL, NULL);
 }
@@ -368,8 +374,8 @@ void manager_cleanup(void)
 {
 	DBG("");
 
-	g_dbus_unregister_interface(connection, OPENOBEX_MANAGER_PATH,
-						OPENOBEX_MANAGER_INTERFACE);
+	g_dbus_unregister_interface(connection, OBEX_MANAGER_PATH,
+						OBEX_MANAGER_INTERFACE);
 
 	/* FIXME: Release agent? */
 
@@ -383,8 +389,8 @@ void manager_emit_transfer_started(struc
 {
 	char *path = g_strdup_printf("/transfer%u", os->id);
 
-	g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
-			OPENOBEX_MANAGER_INTERFACE, "TransferStarted",
+	g_dbus_emit_signal(connection, OBEX_MANAGER_PATH,
+			OBEX_MANAGER_INTERFACE, "TransferStarted",
 			DBUS_TYPE_OBJECT_PATH, &path,
 			DBUS_TYPE_INVALID);
 
@@ -395,8 +401,8 @@ static void emit_transfer_completed(stru
 {
 	char *path = g_strdup_printf("/transfer%u", os->id);
 
-	g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
-			OPENOBEX_MANAGER_INTERFACE, "TransferCompleted",
+	g_dbus_emit_signal(connection, OBEX_MANAGER_PATH,
+			OBEX_MANAGER_INTERFACE, "TransferCompleted",
 			DBUS_TYPE_OBJECT_PATH, &path,
 			DBUS_TYPE_BOOLEAN, &success,
 			DBUS_TYPE_INVALID);
@@ -405,14 +411,14 @@ static void emit_transfer_completed(stru
 }
 
 static void emit_transfer_progress(struct obex_session *os, uint32_t total,
-							uint32_t transfered)
+							uint32_t transferred)
 {
 	char *path = g_strdup_printf("/transfer%u", os->id);
 
 	g_dbus_emit_signal(connection, path,
 			TRANSFER_INTERFACE, "Progress",
 			DBUS_TYPE_INT32, &total,
-			DBUS_TYPE_INT32, &transfered,
+			DBUS_TYPE_INT32, &transferred,
 			DBUS_TYPE_INVALID);
 
 	g_free(path);
@@ -456,7 +462,7 @@ static void agent_cancel(void)
 		return;
 
 	msg = dbus_message_new_method_call(agent->bus_name, agent->path,
-					"org.openobex.Agent", "Cancel");
+						AGENT_INTERFACE, "Cancel");
 
 	g_dbus_send_message(connection, msg);
 }
@@ -542,7 +548,7 @@ int manager_request_authorization(struct
 	path = g_strdup_printf("/transfer%u", os->id);
 
 	msg = dbus_message_new_method_call(agent->bus_name, agent->path,
-					"org.openobex.Agent", "Authorize");
+						AGENT_INTERFACE, "Authorize");
 
 	dbus_message_append_args(msg,
 			DBUS_TYPE_OBJECT_PATH, &path,
@@ -610,8 +616,8 @@ void manager_register_session(struct obe
 		goto done;
 	}
 
-	g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
-			OPENOBEX_MANAGER_INTERFACE, "SessionCreated",
+	g_dbus_emit_signal(connection, OBEX_MANAGER_PATH,
+			OBEX_MANAGER_INTERFACE, "SessionCreated",
 			DBUS_TYPE_OBJECT_PATH, &path,
 			DBUS_TYPE_INVALID);
 
@@ -623,8 +629,8 @@ void manager_unregister_session(struct o
 {
 	char *path = g_strdup_printf("/session%u", GPOINTER_TO_UINT(os));
 
-	g_dbus_emit_signal(connection, OPENOBEX_MANAGER_PATH,
-			OPENOBEX_MANAGER_INTERFACE, "SessionRemoved",
+	g_dbus_emit_signal(connection, OBEX_MANAGER_PATH,
+			OBEX_MANAGER_INTERFACE, "SessionRemoved",
 			DBUS_TYPE_OBJECT_PATH, &path,
 			DBUS_TYPE_INVALID);
 
diff -pruN 0.46-1/src/manager.h 0.48-2.1/src/manager.h
--- 0.46-1/src/manager.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/manager.h	2012-07-26 17:09:25.000000000 +0000
@@ -23,7 +23,7 @@
 
 #include <dbus/dbus.h>
 
-#define OPENOBEX_SERVICE  "org.openobex"
+#define OBEXD_SERVICE  "org.bluez.obex"
 
 void manager_register_session(struct obex_session *os);
 void manager_unregister_session(struct obex_session *os);
diff -pruN 0.46-1/src/map_ap.c 0.48-2.1/src/map_ap.c
--- 0.46-1/src/map_ap.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/map_ap.c	1970-01-01 00:00:00.000000000 +0000
@@ -1,466 +0,0 @@
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2010-2011  Nokia Corporation
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include "log.h"
-
-#include "map_ap.h"
-
-enum ap_type {
-	APT_UINT8,
-	APT_UINT16,
-	APT_UINT32,
-	APT_STR
-};
-
-/* NOTE: ap_defs array has to be kept in sync with map_ap_tag. */
-static const struct ap_def {
-	const char *name;
-	enum ap_type type;
-} ap_defs[] = {
-	{ "MAXLISTCOUNT",		APT_UINT16 },
-	{ "STARTOFFSET",		APT_UINT16 },
-	{ "FILTERMESSAGETYPE",		APT_UINT8  },
-	{ "FILTERPERIODBEGIN",		APT_STR    },
-	{ "FILTERPERIODEND",		APT_STR    },
-	{ "FILTERREADSTATUS",		APT_UINT8  },
-	{ "FILTERRECIPIENT",		APT_STR    },
-	{ "FILTERORIGINATOR",		APT_STR    },
-	{ "FILTERPRIORITY",		APT_UINT8  },
-	{ "ATTACHMENT",			APT_UINT8  },
-	{ "TRANSPARENT",		APT_UINT8  },
-	{ "RETRY",			APT_UINT8  },
-	{ "NEWMESSAGE",			APT_UINT8  },
-	{ "NOTIFICATIONSTATUS",		APT_UINT8  },
-	{ "MASINSTANCEID",		APT_UINT8  },
-	{ "PARAMETERMASK",		APT_UINT32 },
-	{ "FOLDERLISTINGSIZE",		APT_UINT16 },
-	{ "MESSAGESLISTINGSIZE",	APT_UINT16 },
-	{ "SUBJECTLENGTH",		APT_UINT8  },
-	{ "CHARSET",			APT_UINT8  },
-	{ "FRACTIONREQUEST",		APT_UINT8  },
-	{ "FRACTIONDELIVER",		APT_UINT8  },
-	{ "STATUSINDICATOR",		APT_UINT8  },
-	{ "STATUSVALUE",		APT_UINT8  },
-	{ "MSETIME",			APT_STR    },
-};
-
-struct ap_entry {
-	enum map_ap_tag tag;
-	union {
-		uint32_t u32;
-		uint16_t u16;
-		uint8_t u8;
-		char *str;
-	} val;
-};
-
-/* This comes from OBEX specs */
-struct obex_ap_header {
-	uint8_t tag;
-	uint8_t len;
-	uint8_t val[0];
-} __attribute__ ((packed));
-
-static int find_ap_def_offset(uint8_t tag)
-{
-	if (tag == 0 || tag > G_N_ELEMENTS(ap_defs))
-		return -1;
-
-	return tag - 1;
-}
-
-static void ap_entry_dump(gpointer tag, gpointer val, gpointer user_data)
-{
-	struct ap_entry *entry = val;
-	int offset;
-
-	offset = find_ap_def_offset(GPOINTER_TO_INT(tag));
-
-	switch (ap_defs[offset].type) {
-	case APT_UINT8:
-		DBG("%-30s %08x", ap_defs[offset].name, entry->val.u8);
-		break;
-	case APT_UINT16:
-		DBG("%-30s %08x", ap_defs[offset].name, entry->val.u16);
-		break;
-	case APT_UINT32:
-		DBG("%-30s %08x", ap_defs[offset].name, entry->val.u32);
-		break;
-	case APT_STR:
-		DBG("%-30s %s", ap_defs[offset].name, entry->val.str);
-		break;
-	}
-}
-
-static void ap_entry_free(gpointer val)
-{
-	struct ap_entry *entry = val;
-	int offset;
-
-	offset = find_ap_def_offset(entry->tag);
-
-	if (offset >= 0 && ap_defs[offset].type == APT_STR)
-		g_free(entry->val.str);
-
-	g_free(entry);
-}
-
-map_ap_t *map_ap_new(void)
-{
-	return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
-								ap_entry_free);
-}
-
-void map_ap_free(map_ap_t *ap)
-{
-	if (!ap)
-		return;
-
-	g_hash_table_destroy(ap);
-}
-
-static void ap_decode_u8(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	if (hdr->len != 1) {
-		DBG("Value of tag %u is %u byte(s) long instead of expected "
-				"1 byte - skipped!", hdr->tag, hdr->len);
-		return;
-	}
-
-	map_ap_set_u8(ap, hdr->tag, hdr->val[0]);
-}
-
-static void ap_decode_u16(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	uint16_t val;
-
-	if (hdr->len != 2) {
-		DBG("Value of tag %u is %u byte(s) long instead of expected "
-				"2 bytes - skipped!", hdr->tag, hdr->len);
-		return;
-	}
-
-	memcpy(&val, hdr->val, sizeof(val));
-	map_ap_set_u16(ap, hdr->tag, GUINT16_FROM_BE(val));
-}
-
-static void ap_decode_u32(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	uint32_t val;
-
-	if (hdr->len != 4) {
-		DBG("Value of tag %u is %u byte(s) long instead of expected "
-				"4 bytes - skipped!", hdr->tag, hdr->len);
-		return;
-	}
-
-	memcpy(&val, hdr->val, sizeof(val));
-	map_ap_set_u32(ap, hdr->tag, GUINT32_FROM_BE(val));
-}
-
-static void ap_decode_str(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	char *val = g_malloc0(hdr->len + 1);
-
-	memcpy(val, hdr->val, hdr->len);
-	map_ap_set_string(ap, hdr->tag, val);
-
-	g_free(val);
-}
-
-map_ap_t *map_ap_decode(const uint8_t *buffer, size_t length)
-{
-	map_ap_t *ap;
-	struct obex_ap_header *hdr;
-	uint32_t done;
-	int offset;
-
-	ap = map_ap_new();
-	if (!ap)
-		return NULL;
-
-	for (done = 0;  done < length; done += hdr->len + sizeof(*hdr)) {
-		hdr = (struct obex_ap_header *)(buffer + done);
-
-		offset = find_ap_def_offset(hdr->tag);
-
-		if (offset < 0) {
-			DBG("Unknown tag %u (length %u) - skipped.",
-							hdr->tag, hdr->len);
-			continue;
-		}
-
-		switch (ap_defs[offset].type) {
-		case APT_UINT8:
-			ap_decode_u8(ap, hdr);
-			break;
-		case APT_UINT16:
-			ap_decode_u16(ap, hdr);
-			break;
-		case APT_UINT32:
-			ap_decode_u32(ap, hdr);
-			break;
-		case APT_STR:
-			ap_decode_str(ap, hdr);
-			break;
-		}
-	}
-
-	g_hash_table_foreach(ap, ap_entry_dump, NULL);
-
-	return ap;
-}
-
-static void ap_encode_u8(GByteArray *buf, struct ap_entry *entry)
-{
-	struct obex_ap_header *hdr;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 1);
-
-	hdr->tag = entry->tag;
-	hdr->len = 1;
-	hdr->val[0] = entry->val.u8;
-}
-
-static void ap_encode_u16(GByteArray *buf, struct ap_entry *entry)
-{
-	struct obex_ap_header *hdr;
-	uint16_t val;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 2);
-
-	hdr->tag = entry->tag;
-	hdr->len = 2;
-
-	val = GUINT16_TO_BE(entry->val.u16);
-	memcpy(hdr->val, &val, sizeof(val));
-}
-
-static void ap_encode_u32(GByteArray *buf, struct ap_entry *entry)
-{
-	uint32_t val;
-	struct obex_ap_header *hdr;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 4);
-
-	hdr->tag = entry->tag;
-	hdr->len = 4;
-
-	val = GUINT32_TO_BE(entry->val.u16);
-	memcpy(hdr->val, &val, sizeof(val));
-}
-
-static void ap_encode_str(GByteArray *buf, struct ap_entry *entry)
-{
-	size_t len;
-	struct obex_ap_header *hdr;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-	len = strlen(entry->val.str);
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + len);
-
-	hdr->tag = entry->tag;
-	hdr->len = len;
-
-	memcpy(hdr->val, entry->val.str, len);
-}
-
-uint8_t *map_ap_encode(map_ap_t *ap, size_t *length)
-{
-	GByteArray *buf;
-	GHashTableIter iter;
-	gpointer key, value;
-	struct ap_entry *entry;
-	int offset;
-
-	buf = g_byte_array_new();
-	g_hash_table_iter_init(&iter, ap);
-
-	while (g_hash_table_iter_next(&iter, &key, &value)) {
-		entry = (struct ap_entry *) value;
-		offset = find_ap_def_offset(entry->tag);
-
-		switch (ap_defs[offset].type) {
-		case APT_UINT8:
-			ap_encode_u8(buf, entry);
-			break;
-		case APT_UINT16:
-			ap_encode_u16(buf, entry);
-			break;
-		case APT_UINT32:
-			ap_encode_u32(buf, entry);
-			break;
-		case APT_STR:
-			ap_encode_str(buf, entry);
-			break;
-		}
-	}
-
-	*length = buf->len;
-
-	return g_byte_array_free(buf, FALSE);
-}
-
-gboolean map_ap_get_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT8)
-		return FALSE;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return FALSE;
-
-	*val = entry->val.u8;
-
-	return TRUE;
-}
-
-gboolean map_ap_get_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT16)
-		return FALSE;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return FALSE;
-
-	*val = entry->val.u16;
-
-	return TRUE;
-}
-
-gboolean map_ap_get_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT32)
-		return FALSE;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return FALSE;
-
-	*val = entry->val.u32;
-
-	return TRUE;
-}
-
-const char *map_ap_get_string(map_ap_t *ap, enum map_ap_tag tag)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_STR)
-		return NULL;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return NULL;
-
-	return entry->val.str;
-}
-
-gboolean map_ap_set_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT8)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.u8 = val;
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
-
-gboolean map_ap_set_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT16)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.u16 = val;
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
-
-gboolean map_ap_set_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT32)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.u32 = val;
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
-
-gboolean map_ap_set_string(map_ap_t *ap, enum map_ap_tag tag, const char *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_STR)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.str = g_strdup(val);
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
diff -pruN 0.46-1/src/map_ap.h 0.48-2.1/src/map_ap.h
--- 0.46-1/src/map_ap.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/map_ap.h	2012-11-30 07:59:13.000000000 +0000
@@ -21,9 +21,6 @@
  *
  */
 
-#include <glib.h>
-#include <inttypes.h>
-
 /* List of OBEX application parameters tags as per MAP specification. */
 enum map_ap_tag {
 	MAP_AP_MAXLISTCOUNT		= 0x01,		/* uint16_t	*/
@@ -52,63 +49,3 @@ enum map_ap_tag {
 	MAP_AP_STATUSVALUE		= 0x18,		/* uint8_t	*/
 	MAP_AP_MSETIME			= 0x19,		/* char *	*/
 };
-
-/* Data type representing MAP application parameters. Consider opaque. */
-typedef GHashTable map_ap_t;
-
-/* Creates a new empty MAP application parameters object. */
-map_ap_t *map_ap_new(void);
-
-/* Frees all the memory used by MAP application parameters object. */
-void map_ap_free(map_ap_t *ap);
-
-/* Parses given buffer that is a payload of OBEX application parameter header
- * with a given length. Returned value can be used in calls to map_ap_get_*()
- * and map_ap_set_*(). It has to be freed using map_ap_free(). It also takes
- * care of converting all the data to host byte order, so this is the byte
- * order used in map_ap_get_*()/map_ap_set_*().
- *
- * Returns NULL in case of failure.
- */
-map_ap_t *map_ap_decode(const uint8_t *buffer, size_t length);
-
-/* Takes all parameters currently set and packs them into a buffer with OBEX
- * application parameters header payload format.
- *
- * Returns newly allocated buffer of size 'length'. Free with g_free().
- */
-uint8_t *map_ap_encode(map_ap_t *ap, size_t *length);
-
-/* Following family of functions reads value of MAP parameter with given tag.
- * Use the one with appropriate type for a given tag, as noted above in
- * map_ap_tag declaration comments.
- *
- * Returns TRUE when value is present. FALSE if it is not or the function is
- * used get a parameter of a different type. When FALSE is returned, variable
- * pointed by 'val' is left intact.
- */
-gboolean map_ap_get_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t *val);
-gboolean map_ap_get_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t *val);
-gboolean map_ap_get_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t *val);
-
-/* Reads value of MAP parameter with given tag that is of a string type.
- *
- * Returns NULL if parameter is not present in ap or given tag is not of a
- * string type.
- */
-const char *map_ap_get_string(map_ap_t *ap, enum map_ap_tag tag);
-
-/* Following family of functions sets the value of MAP parameter with given
- * tag. Use the one with appropriate type for a given tag, as noted above in
- * map_ap_tag declaration comments.
- *
- * If there is already a parameter with given tag present, it will be
- * replaced. map_ap_set_string() makes its own copy of given string.
- *
- * Returns TRUE on success (the tag is known and the function chosen matches
- * the type of tag).
- */
-gboolean map_ap_set_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t val);
-gboolean map_ap_set_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t val);
-gboolean map_ap_set_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t val);
-gboolean map_ap_set_string(map_ap_t *ap, enum map_ap_tag tag, const char *val);
diff -pruN 0.46-1/src/mimetype.h 0.48-2.1/src/mimetype.h
--- 0.46-1/src/mimetype.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/mimetype.h	2014-10-16 04:43:28.000000000 +0000
@@ -20,6 +20,7 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+#include <sys/types.h>
 
 typedef gboolean (*obex_object_io_func) (void *object, int flags, int err,
 							void *user_data);
diff -pruN 0.46-1/src/obex.c 0.48-2.1/src/obex.c
--- 0.46-1/src/obex.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/obex.c	2012-07-26 17:09:25.000000000 +0000
@@ -656,7 +656,7 @@ static gboolean recv_data(const void *bu
 	if (os->aborted)
 		return FALSE;
 
-	/* workaround: client didn't send the object lenght */
+	/* workaround: client didn't send the object length */
 	if (os->size == OBJECT_SIZE_DELETE)
 		os->size = OBJECT_SIZE_UNKNOWN;
 
diff -pruN 0.46-1/src/obexd.service.in 0.48-2.1/src/obexd.service.in
--- 0.46-1/src/obexd.service.in	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/obexd.service.in	2012-07-26 17:09:25.000000000 +0000
@@ -1,3 +1,3 @@
 [D-BUS Service]
-Name=org.openobex
+Name=org.bluez.obex
 Exec=@libexecdir@/obexd --nodaemon
diff -pruN 0.46-1/src/obex.h 0.48-2.1/src/obex.h
--- 0.46-1/src/obex.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/obex.h	2014-10-16 04:43:28.000000000 +0000
@@ -21,6 +21,7 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+#include <sys/types.h>
 
 #define OBJECT_SIZE_UNKNOWN -1
 #define OBJECT_SIZE_DELETE -2
diff -pruN 0.46-1/src/server.c 0.48-2.1/src/server.c
--- 0.46-1/src/server.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/src/server.c	2012-11-30 07:59:13.000000000 +0000
@@ -31,7 +31,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
-#include <errno.h>
 #include <string.h>
 #include <inttypes.h>
 
diff -pruN 0.46-1/test/exchange-business-cards 0.48-2.1/test/exchange-business-cards
--- 0.46-1/test/exchange-business-cards	2009-05-02 15:52:30.000000000 +0000
+++ 0.48-2.1/test/exchange-business-cards	2012-07-26 17:09:25.000000000 +0000
@@ -4,12 +4,16 @@ import sys
 import dbus
 
 bus = dbus.SessionBus()
-client = dbus.Interface(bus.get_object("org.openobex.client", "/"),
-							"org.openobex.Client")
+client = dbus.Interface(bus.get_object("org.bluez.obex.client", "/"),
+					"org.bluez.obex.Client")
 
 if (len(sys.argv) < 4):
 	print "Usage: %s <device> <clientfile> <file>" % (sys.argv[0])
 	sys.exit(1)
 
-client.ExchangeBusinessCards({ "Destination": sys.argv[1] },
-						sys.argv[2], sys.argv[3])
+print "Creating Session"
+path = client.CreateSession(sys.argv[1], { "Target": "OPP" })
+opp = dbus.Interface(bus.get_object("org.bluez.obex.client", path),
+					"org.bluez.obex.ObjectPush")
+
+opp.ExchangeBusinessCards(sys.argv[2], sys.argv[3])
diff -pruN 0.46-1/test/ftp-client 0.48-2.1/test/ftp-client
--- 0.46-1/test/ftp-client	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/test/ftp-client	2012-07-26 17:09:25.000000000 +0000
@@ -9,162 +9,175 @@ import dbus.mainloop.glib
 import os.path
 from optparse import OptionParser
 
-class Agent(dbus.service.Object):
-    def __init__(self, conn=None, obj_path=None, verbose=False):
-        dbus.service.Object.__init__(self, conn, obj_path)
-        self.verbose = verbose
-
-    @dbus.service.method("org.openobex.Agent",
-                    in_signature="o", out_signature="s")
-    def Request(self, path):
-        return ""
-
-    @dbus.service.method("org.openobex.Agent",
-                    in_signature="ot", out_signature="")
-    def Progress(self, path, transferred):
-        if self.verbose:
-            print "Transfer progress (%d bytes)" % (transferred)
-        return
-
-    @dbus.service.method("org.openobex.Agent",
-                    in_signature="o", out_signature="")
-    def Complete(self, path):
-        if self.verbose:
-            print "Transfer finished"
-        mainloop.quit()
-
-    @dbus.service.method("org.openobex.Agent",
-                    in_signature="os", out_signature="")
-    def Error(self, path, error):
-        print "Transfer finished with an error: %s" % (error)
-        mainloop.quit()
-
-    @dbus.service.method("org.openobex.Agent",
-                    in_signature="", out_signature="")
-    def Release(self):
-        mainloop.quit()
-
-
 def parse_options():
-    parser.add_option("-d", "--device", dest="device",
-                      help="Device to connect", metavar="DEVICE")
-    parser.add_option("-c", "--chdir", dest="new_dir",
-                      help="Change current directory to DIR", metavar="DIR")
-    parser.add_option("-l", "--list", action="store_true", dest="list_dir",
-                      help="List the current directory")
-    parser.add_option("-g", "--get", dest="get_file",
-                      help="Get FILE", metavar="FILE")
-    parser.add_option("-p", "--put", dest="put_file",
-                      help="Put FILE", metavar="FILE")
-    parser.add_option("-y", "--copy", dest="copy_file",
-                      help="Copy FILE", metavar="FILE")
-    parser.add_option("-m", "--move", dest="move_file",
-                      help="Move FILE", metavar="FILE")
-    parser.add_option("-n", "--destname", dest="dest_file",
-                      help="Destination FILE", metavar="FILE")
-    parser.add_option("-r", "--remove", dest="remove_file",
-                      help="Remove FILE", metavar="FILE")
-    parser.add_option("-v", "--verbose", action="store_true", dest="verbose")
-
-    return parser.parse_args()
-
-def error(err):
-    print err
-
-def void_reply():
-    pass
-
-def change_folder(session, new_dir):
-    for node in new_dir.split("/"):
-        session.ChangeFolder(node)
-
-def list_folder(session):
-    for i in session.ListFolder():
-        if i["Type"] == "folder":
-            print "%s/" % (i["Name"])
-        else:
-            print "%s" % (i["Name"])
-
-def put_file(session, filename):
-    session.PutFile(os.path.abspath(filename),
-                    os.path.basename(filename),
-                    reply_handler=void_reply,
-                    error_handler=error)
-
-def get_file(session, filename):
-    session.GetFile(os.path.abspath(filename),
-                    os.path.basename(filename),
-                    reply_handler=void_reply,
-                    error_handler=error)
-
-def remove_file(session, filename):
-    session.Delete(filename,
-                    reply_handler=void_reply,
-                    error_handler=error)
-
-def move_file(session, filename, destname):
-    session.MoveFile(filename,
-                    destname,
-                    reply_handler=void_reply,
-                    error_handler=error)
-
-def copy_file(session, filename, destname):
-    session.CopyFile(filename,
-                    destname,
-                    reply_handler=void_reply,
-                    error_handler=error)
+	parser.add_option("-d", "--device", dest="device",
+			help="Device to connect", metavar="DEVICE")
+	parser.add_option("-c", "--chdir", dest="new_dir",
+			help="Change current directory to DIR", metavar="DIR")
+	parser.add_option("-l", "--list", action="store_true", dest="list_dir",
+			help="List the current directory")
+	parser.add_option("-g", "--get", dest="get_file",
+			help="Get FILE", metavar="FILE")
+	parser.add_option("-p", "--put", dest="put_file",
+			help="Put FILE", metavar="FILE")
+	parser.add_option("-y", "--copy", dest="copy_file",
+			help="Copy FILE", metavar="FILE")
+	parser.add_option("-m", "--move", dest="move_file",
+			help="Move FILE", metavar="FILE")
+	parser.add_option("-n", "--destname", dest="dest_file",
+			help="Destination FILE", metavar="FILE")
+	parser.add_option("-r", "--remove", dest="remove_file",
+			help="Remove FILE", metavar="FILE")
+	parser.add_option("-v", "--verbose", action="store_true",
+			dest="verbose")
+
+	return parser.parse_args()
+
+class FtpClient:
+	def __init__(self, session_path, verbose=False):
+		self.progress = 0
+		self.transfer_path = None
+		self.transfer_size = 0
+		self.verbose = verbose
+		bus = dbus.SessionBus()
+		obj = bus.get_object("org.bluez.obex.client", session_path)
+		self.session = dbus.Interface(obj, "org.bluez.obex.Session")
+		self.ftp = dbus.Interface(obj, "org.bluez.obex.FileTransfer")
+		bus.add_signal_receiver(self.transfer_complete,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Complete",
+				path_keyword="path")
+		bus.add_signal_receiver(self.transfer_error,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Error",
+				path_keyword="path")
+		if self.verbose:
+			bus.add_signal_receiver(self.transfer_progress,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="PropertyChanged",
+				path_keyword="path")
+
+	def create_transfer_reply(self, reply):
+		(path, properties) = reply
+		self.transfer_path = path
+		self.transfer_size = properties["Size"]
+		if self.verbose:
+			print "Transfer created: %s" % path
+
+	def generic_reply(self):
+		if self.verbose:
+			print "Operation succeeded"
+
+	def error(self, err):
+		print err
+		mainloop.quit()
+
+	def transfer_complete(self, path):
+		if path != self.transfer_path:
+			return
+		if self.verbose:
+			print "Transfer finished"
+		mainloop.quit()
+
+	def transfer_error(self, code, message, path):
+		if path != self.transfer_path:
+			return
+		print "Transfer finished with error %s: %s" % (code, message)
+		mainloop.quit()
+
+	def transfer_progress(self, prop, value, path):
+		if path != self.transfer_path:
+			return
+
+		if prop != "Progress":
+			return
+
+		speed = (value - self.progress) / 1000
+		print "Transfer progress %d/%d at %d kBps" % (value,
+							self.transfer_size,
+							speed)
+		self.progress = value
+
+	def change_folder(self, new_dir):
+		for node in new_dir.split("/"):
+			self.ftp.ChangeFolder(node)
+
+	def list_folder(self):
+		for i in self.ftp.ListFolder():
+			if i["Type"] == "folder":
+				print "%s/" % (i["Name"])
+			else:
+				print "%s" % (i["Name"])
+
+	def put_file(self, filename):
+		self.ftp.PutFile(os.path.abspath(filename),
+				os.path.basename(filename),
+				reply_handler=self.create_transfer_reply,
+				error_handler=self.error)
+
+	def get_file(self, filename):
+		self.ftp.GetFile(os.path.abspath(filename),
+				os.path.basename(filename),
+				reply_handler=self.create_transfer_reply,
+				error_handler=self.error)
+
+	def remove_file(self, filename):
+		self.ftp.Delete(filename,
+				reply_handler=self.generic_reply,
+				error_handler=self.error)
+
+	def move_file(self, filename, destname):
+		self.ftp.MoveFile(filename, destname,
+				reply_handler=self.generic_reply,
+				error_handler=self.error)
+
+	def copy_file(self, filename, destname):
+		self.ftp.CopyFile(filename, destname,
+				reply_handler=self.generic_reply,
+				error_handler=self.error)
 
 if  __name__ == '__main__':
 
-    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-
-    parser = OptionParser()
-
-    (options, args) = parse_options()
-
-    if not options.device:
-        parser.print_help()
-        sys.exit(0)
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
-    bus = dbus.SessionBus()
-    mainloop = gobject.MainLoop()
+	parser = OptionParser()
 
-    path = "/test/agent"
-    agent = Agent(bus, path, options.verbose)
+	(options, args) = parse_options()
 
-    client = dbus.Interface(bus.get_object("org.openobex.client", "/"),
-                            "org.openobex.Client")
+	if not options.device:
+		parser.print_help()
+		sys.exit(0)
 
-    session_path = client.CreateSession({ "Destination": options.device,
-                                          "Target": "ftp"})
+	bus = dbus.SessionBus()
+	mainloop = gobject.MainLoop()
 
-    session = dbus.Interface(bus.get_object("org.openobex.client", session_path),
-                 "org.openobex.Session")
+	client = dbus.Interface(bus.get_object("org.bluez.obex.client", "/"),
+				"org.bluez.obex.Client")
 
-    session.AssignAgent(path)
+	print "Creating Session"
+	path = client.CreateSession(options.device, { "Target": "ftp" })
 
-    ftp = dbus.Interface(bus.get_object("org.openobex.client", session_path),
-                 "org.openobex.FileTransfer")
+	ftp_client = FtpClient(path, options.verbose)
 
-    if options.new_dir:
-        change_folder(ftp, options.new_dir)
+	if options.new_dir:
+		ftp_client.change_folder(options.new_dir)
 
-    if options.list_dir:
-        list_folder(ftp)
+	if options.list_dir:
+		ftp_client.list_folder()
 
-    if options.get_file:
-        get_file(ftp, options.get_file)
+	if options.get_file:
+		ftp_client.get_file(options.get_file)
 
-    if options.put_file:
-        put_file(ftp, options.put_file)
+	if options.put_file:
+		ftp_client.put_file(options.put_file)
 
-    if options.move_file:
-        move_file(ftp, options.move_file, options.dest_file)
+	if options.move_file:
+		ftp_client.move_file(options.move_file, options.dest_file)
 
-    if options.copy_file:
-        copy_file(ftp, options.copy_file, options.dest_file)
+	if options.copy_file:
+		ftp_client.copy_file(options.copy_file, options.dest_file)
 
-    if options.remove_file:
-       remove_file(ftp, options.remove_file)
+	if options.remove_file:
+		ftp_client.remove_file(options.remove_file)
 
-    mainloop.run()
+	mainloop.run()
diff -pruN 0.46-1/test/list-folders 0.48-2.1/test/list-folders
--- 0.46-1/test/list-folders	2010-04-23 15:52:33.000000000 +0000
+++ 0.48-2.1/test/list-folders	2012-07-26 17:09:25.000000000 +0000
@@ -6,13 +6,13 @@ import dbus
 
 def list_folder(folder):
 	bus = dbus.SessionBus()
-	client = dbus.Interface(bus.get_object("org.openobex.client", "/"),
-				"org.openobex.Client")
+	client = dbus.Interface(bus.get_object("org.bluez.obex.client", "/"),
+				"org.bluez.obex.Client")
 
-	session_path = client.CreateSession({ "Destination": sys.argv[1], "Target": "ftp"})
+	path = client.CreateSession(sys.argv[1], { "Target": "ftp" })
 
-	ftp = dbus.Interface(bus.get_object("org.openobex.client", session_path),
-			     "org.openobex.FileTransfer")
+	ftp = dbus.Interface(bus.get_object("org.bluez.obex.client", path),
+				"org.bluez.obex.FileTransfer")
 
 	if folder:
 		for node in folder.split("/"):
diff -pruN 0.46-1/test/map-client 0.48-2.1/test/map-client
--- 0.46-1/test/map-client	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/test/map-client	2012-11-30 07:59:13.000000000 +0000
@@ -2,61 +2,206 @@
 
 import gobject
 
+import sys
+import os
 import dbus
 import dbus.mainloop.glib
 from optparse import OptionParser
 
+from pprint import pformat
+
+def unwrap(x):
+    """Hack to unwrap D-Bus values, so that they're easier to read when
+    printed. Taken from d-feet """
+
+    if isinstance(x, list):
+        return map(unwrap, x)
+
+    if isinstance(x, tuple):
+        return tuple(map(unwrap, x))
+
+    if isinstance(x, dict):
+        return dict([(unwrap(k), unwrap(v)) for k, v in x.iteritems()])
+
+    for t in [unicode, str, long, int, float, bool]:
+        if isinstance(x, t):
+            return t(x)
+
+    return x
+
 def parse_options():
-    parser.add_option("-d", "--device", dest="device",
-                      help="Device to connect", metavar="DEVICE")
-    parser.add_option("-c", "--chdir", dest="new_dir",
-                      help="Change current directory to DIR", metavar="DIR")
-    parser.add_option("-l", "--lsdir", action="store_true", dest="ls_dir",
-                      help="List folders in current directory")
-    parser.add_option("-v", "--verbose", action="store_true", dest="verbose")
-    parser.add_option("-L", "--lsmsg", action="store", dest="ls_msg",
-                      help="List messages in supplied CWD subdir")
+	parser.add_option("-d", "--device", dest="device",
+			help="Device to connect", metavar="DEVICE")
+	parser.add_option("-c", "--chdir", dest="new_dir",
+			help="Change current directory to DIR", metavar="DIR")
+	parser.add_option("-l", "--lsdir", action="store_true", dest="ls_dir",
+			help="List folders in current directory")
+	parser.add_option("-v", "--verbose", action="store_true", dest="verbose")
+	parser.add_option("-L", "--lsmsg", action="store", dest="ls_msg",
+			help="List messages in supplied CWD subdir")
+	parser.add_option("-g", "--get", action="store", dest="get_msg",
+			help="Get message contents")
+	parser.add_option("--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()
+	return parser.parse_args()
 
 def set_folder(session, new_dir):
-    for node in new_dir.split("/"):
-        session.SetFolder(node)
+	session.SetFolder(new_dir)
+
+class MapClient:
+	def __init__(self, session_path, verbose=False):
+		self.progress = 0
+		self.transfer_path = None
+		self.props = dict()
+		self.verbose = verbose
+		self.path = session_path
+		bus = dbus.SessionBus()
+		obj = bus.get_object("org.bluez.obex.client", session_path)
+		self.session = dbus.Interface(obj, "org.bluez.obex.Session")
+		self.map = dbus.Interface(obj, "org.bluez.obex.MessageAccess")
+		bus.add_signal_receiver(self.transfer_complete,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Complete",
+				path_keyword="path")
+		bus.add_signal_receiver(self.transfer_error,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Error",
+				path_keyword="path")
+
+	def create_transfer_reply(self, reply):
+		(path, properties) = reply
+		self.transfer_path = path
+		self.props[path] = properties
+		if self.verbose:
+			print "Transfer created: %s (file %s)" % (path,
+							properties["Filename"])
+
+	def generic_reply(self):
+		if self.verbose:
+			print "Operation succeeded"
+
+	def error(self, err):
+		print err
+		mainloop.quit()
+
+	def transfer_complete(self, path):
+		if path != self.transfer_path:
+			return
+		if self.verbose:
+			print "Transfer finished"
+		properties = self.props.get(path)
+		if properties == None:
+			return
+		f = open(properties["Filename"], "r")
+		os.remove(properties["Filename"])
+		print f.readlines()
+
+	def transfer_error(self, code, message, path):
+		if path != self.transfer_path:
+			return
+		print "Transfer finished with error %s: %s" % (code, message)
+		mainloop.quit()
+
+	def set_folder(self, new_dir):
+		self.map.SetFolder(new_dir)
+
+	def list_folders(self):
+		for i in self.map.ListFolders(dict()):
+			print "%s/" % (i["Name"])
+
+	def list_messages(self, folder):
+		ret = self.map.ListMessages(folder, dict())
+		print pformat(unwrap(ret))
+
+	def get_message(self, handle):
+		self.map.ListMessages("", dict())
+		path = self.path + "/message" + handle
+		obj = bus.get_object("org.bluez.obex.client", path)
+		msg = dbus.Interface(obj, "org.bluez.obex.Message")
+		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)
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	parser = OptionParser()
+
+	(options, args) = parse_options()
+
+	if not options.device:
+		parser.print_help()
+		exit(0)
+
+	bus = dbus.SessionBus()
+	mainloop = gobject.MainLoop()
+
+	client = dbus.Interface(bus.get_object("org.bluez.obex.client", "/"),
+				"org.bluez.obex.Client")
+
+	print "Creating Session"
+	path = client.CreateSession(options.device, { "Target": "map" })
 
-    parser = OptionParser()
+	map_client = MapClient(path, options.verbose)
 
-    (options, args) = parse_options()
+	if options.new_dir:
+		map_client.set_folder(options.new_dir)
 
-    if not options.device:
-        parser.print_help()
-        exit(0)
+	if options.ls_dir:
+		map_client.list_folders()
 
-    bus = dbus.SessionBus()
-    mainloop = gobject.MainLoop()
+	if options.ls_msg is not None:
+		map_client.list_messages(options.ls_msg)
 
-    client = dbus.Interface(bus.get_object("org.openobex.client", "/"),
-                            "org.openobex.Client")
+	if options.get_msg is not None:
+		map_client.get_message(options.get_msg)
 
-    session_path = client.CreateSession({ "Destination": options.device,
-                                          "Target": "map"})
+	if options.get_msg_properties is not None:
+		map_client.get_message_properties(options.get_msg_properties)
 
-    session = dbus.Interface(bus.get_object("org.openobex.client", session_path),
-                 "org.openobex.Session")
+	if options.mark_msg_read is not None:
+		map_client.set_message_property(options.mark_msg_read, "Read", True)
 
-    map = dbus.Interface(bus.get_object("org.openobex.client", session_path),
-                 "org.openobex.MessageAccess")
+	if options.mark_msg_unread is not None:
+		map_client.set_message_property(options.mark_msg_unread, "Read", False)
 
-    if options.new_dir:
-        set_folder(map, options.new_dir)
+	if options.mark_msg_deleted is not None:
+		map_client.set_message_property(options.mark_msg_deleted, "Deleted", True)
 
-    if options.ls_dir:
-        print map.GetFolderListing(dict())
+	if options.mark_msg_undeleted is not None:
+		map_client.set_message_property(options.mark_msg_undeleted, "Deleted", False)
 
-    if options.ls_msg is not None:
-	print map.GetMessageListing(options.ls_msg, dict())
+	if options.update_inbox:
+		map_client.update_inbox()
 
-    mainloop.run()
+	mainloop.run()
diff -pruN 0.46-1/test/opp-client 0.48-2.1/test/opp-client
--- 0.46-1/test/opp-client	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/test/opp-client	2012-07-26 17:09:25.000000000 +0000
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+import gobject
+import dbus.mainloop.glib
+import os.path
+from optparse import OptionParser
+
+def parse_options():
+	parser.add_option("-d", "--device", dest="device",
+			help="Device to connect", metavar="DEVICE")
+	parser.add_option("-p", "--pull", dest="pull_to_file",
+			help="Pull vcard and store in FILE", metavar="FILE")
+	parser.add_option("-s", "--send", dest="send_file",
+			help="Send FILE", metavar="FILE")
+	parser.add_option("-v", "--verbose", action="store_true",
+			dest="verbose")
+
+	return parser.parse_args()
+
+class OppClient:
+	def __init__(self, session_path, verbose=False):
+		self.progress = 0
+		self.transfer_path = None
+		self.verbose = verbose
+		bus = dbus.SessionBus()
+		obj = bus.get_object("org.bluez.obex.client", session_path)
+		self.session = dbus.Interface(obj, "org.bluez.obex.Session")
+		self.opp = dbus.Interface(obj, "org.bluez.obex.ObjectPush")
+		bus.add_signal_receiver(self.transfer_complete,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Complete",
+				path_keyword="path")
+		bus.add_signal_receiver(self.transfer_error,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Error",
+				path_keyword="path")
+		if self.verbose:
+			bus.add_signal_receiver(self.transfer_progress,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="PropertyChanged",
+				path_keyword="path")
+
+	def create_transfer_reply(self, reply):
+		(path, properties) = reply
+		self.transfer_path = path
+		self.transfer_size = properties["Size"]
+		if self.verbose:
+			print "Transfer created: %s" % path
+
+	def error(self, err):
+		print err
+		mainloop.quit()
+
+	def transfer_complete(self, path):
+		if path != self.transfer_path:
+			return
+		if self.verbose:
+			print "Transfer finished"
+		mainloop.quit()
+
+	def transfer_error(self, code, message, path):
+		if path != self.transfer_path:
+			return
+		print "Transfer finished with error %s: %s" % (code, message)
+		mainloop.quit()
+
+	def transfer_progress(self, prop, value, path):
+		if path != self.transfer_path:
+			return
+
+		if prop != "Progress":
+			return
+
+		speed = (value - self.progress) / 1000
+		print "Transfer progress %d/%d at %d kBps" % (value,
+							self.transfer_size,
+							speed)
+		self.progress = value
+
+	def pull_business_card(self, filename):
+		self.opp.PullBusinessCard(os.path.abspath(filename),
+				reply_handler=self.create_transfer_reply,
+				error_handler=self.error)
+
+	def send_file(self, filename):
+		self.opp.SendFile(os.path.abspath(filename),
+				reply_handler=self.create_transfer_reply,
+				error_handler=self.error)
+
+if  __name__ == '__main__':
+
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	parser = OptionParser()
+
+	(options, args) = parse_options()
+
+	if not options.device:
+		parser.print_help()
+		sys.exit(0)
+
+	bus = dbus.SessionBus()
+	mainloop = gobject.MainLoop()
+
+	client = dbus.Interface(bus.get_object("org.bluez.obex.client", "/"),
+				"org.bluez.obex.Client")
+
+	print "Creating Session"
+	path = client.CreateSession(options.device, { "Target": "OPP" })
+
+	opp_client = OppClient(path, options.verbose)
+
+	if options.pull_to_file:
+		opp_client.pull_business_card(options.pull_to_file)
+
+	if options.send_file:
+		opp_client.send_file(options.send_file)
+
+	mainloop.run()
diff -pruN 0.46-1/test/pbap-client 0.48-2.1/test/pbap-client
--- 0.46-1/test/pbap-client	2010-12-18 17:42:11.000000000 +0000
+++ 0.48-2.1/test/pbap-client	2012-11-30 07:59:13.000000000 +0000
@@ -1,41 +1,157 @@
 #!/usr/bin/python
 
+import gobject
+
 import sys
+import os
 import dbus
+import dbus.service
+import dbus.mainloop.glib
+
+class Transfer:
+	def __init__(self, callback_func):
+		self.callback_func = callback_func
+		self.path = None
+		self.filename = None
+
+class PbapClient:
+	def __init__(self, session_path):
+		self.transfers = 0
+		self.props = dict()
+		self.flush_func = None
+		bus = dbus.SessionBus()
+		obj = bus.get_object("org.bluez.obex.client", session_path)
+		self.session = dbus.Interface(obj, "org.bluez.obex.Session")
+		self.pbap = dbus.Interface(obj,
+					"org.bluez.obex.PhonebookAccess")
+		bus.add_signal_receiver(self.transfer_complete,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Complete",
+				path_keyword="path")
+		bus.add_signal_receiver(self.transfer_error,
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Error",
+				path_keyword="path")
+
+	def register(self, reply, transfer):
+		(path, properties) = reply
+		transfer.path = path
+		transfer.filename = properties["Filename"]
+		self.props[path] = transfer
+		print "Transfer created: %s (file %s)" % (path,
+							transfer.filename)
+
+	def error(self, err):
+		print err
+		mainloop.quit()
+
+	def transfer_complete(self, path):
+		req = self.props.get(path)
+		if req == None:
+			return
+		self.transfers -= 1
+		print "Transfer %s finished" % path
+		f = open(req.filename, "r")
+		os.remove(req.filename)
+		lines = f.readlines()
+		del self.props[path]
+		req.callback_func(lines)
+
+		if (len(self.props) == 0) and (self.transfers == 0):
+			if self.flush_func != None:
+				f = self.flush_func
+				self.flush_func = None
+				f()
+
+	def transfer_error(self, code, message, path):
+		req = self.props.get(path)
+		if req == None:
+			return
+		print "Transfer finished with error %s: %s" % (code, message)
+		mainloop.quit()
+
+	def pull(self, vcard, params, func):
+		req = Transfer(func)
+		self.pbap.Pull(vcard, "", params,
+				reply_handler=lambda r: self.register(r, req),
+				error_handler=self.error)
+		self.transfers += 1
+
+	def pull_all(self, params, func):
+		req = Transfer(func)
+		self.pbap.PullAll("", params,
+				reply_handler=lambda r: self.register(r, req),
+				error_handler=self.error)
+		self.transfers += 1
+
+	def flush_transfers(self, func):
+		if (len(self.props) == 0) and (self.transfers == 0):
+			return
+		self.flush_func = func
+
+	def interface(self):
+		return self.pbap
+
+if  __name__ == '__main__':
+
+	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+	bus = dbus.SessionBus()
+	mainloop = gobject.MainLoop()
+
+	client = dbus.Interface(bus.get_object("org.bluez.obex.client", "/"),
+				"org.bluez.obex.Client")
+
+	if (len(sys.argv) < 2):
+		print "Usage: %s <device>" % (sys.argv[0])
+		sys.exit(1)
+
+	print "Creating Session"
+	session_path = client.CreateSession(sys.argv[1], { "Target": "PBAP" })
+
+	pbap_client = PbapClient(session_path)
+
+	def process_result(lines, header):
+		if header != None:
+			print header
+		for line in lines:
+			print line,
+		print
+
+	def test_paths(paths):
+		if len(paths) == 0:
+			print
+			print "FINISHED"
+			mainloop.quit()
+			return
+
+		path = paths[0]
+
+		print "\n--- Select Phonebook %s ---\n" % (path)
+		pbap_client.interface().Select("int", path)
+
+		print "\n--- GetSize ---\n"
+		ret = pbap_client.interface().GetSize()
+		print "Size = %d\n" % (ret)
+
+		print "\n--- List vCard ---\n"
+		try:
+			ret = pbap_client.interface().List(dbus.Dictionary())
+		except:
+			ret = []
+
+		params = dbus.Dictionary({ "Format" : "vcard30",
+					"Fields" : [ "VERSION", "FN", "TEL"] })
+		for item in ret:
+			print "%s : %s" % (item[0], item[1])
+			pbap_client.pull(item[0], params,
+					lambda x: process_result(x, None))
+
+		pbap_client.pull_all(params, lambda x: process_result(x,
+							"\n--- PullAll ---\n"))
 
-bus = dbus.SessionBus()
+		pbap_client.flush_transfers(lambda: test_paths(paths[1:]))
 
-client = dbus.Interface(bus.get_object("org.openobex.client", "/"),
-						"org.openobex.Client")
+	test_paths(["PB", "ICH", "OCH", "MCH", "CCH"])
 
-print "Creating Session"
-session_path = client.CreateSession({"Destination": sys.argv[1], "Target": "PBAP"})
-pbap = dbus.Interface(bus.get_object("org.openobex.client", session_path),
-						"org.openobex.PhonebookAccess")
-session = dbus.Interface(bus.get_object("org.openobex.client", session_path),
-							"org.openobex.Session")
-
-paths = ["PB", "ICH", "OCH", "MCH", "CCH"]
-
-for path in paths:
-	print "\n--- Select Phonebook %s ---\n" % (path)
-	pbap.Select("int", path)
-
-	print "\n--- GetSize ---\n"
-	ret = pbap.GetSize()
-	print "Size = %d\n" % (ret)
-
-	print "\n--- List vCard ---\n"
-	ret = pbap.List()
-	for item in ret:
-		print "%s : %s" % (item[0], item[1])
-		pbap.SetFormat("vcard30")
-		pbap.SetFilter(["VERSION", "FN", "TEL"]);
-		ret = pbap.Pull(item[0])
-		print "%s" % (ret)
-
-	print "\n--- PullAll ---\n"
-	pbap.SetFormat("vcard30")
-	pbap.SetFilter(["VERSION", "FN", "TEL"]);
-	ret = pbap.PullAll()
-	print "%s" % (ret)
+	mainloop.run()
diff -pruN 0.46-1/test/pull-business-card 0.48-2.1/test/pull-business-card
--- 0.46-1/test/pull-business-card	2010-05-23 12:34:01.000000000 +0000
+++ 0.48-2.1/test/pull-business-card	1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-#!/usr/bin/python
-
-import sys
-import dbus
-import gobject
-import dbus.mainloop.glib
-
-def success():
-	mainloop.quit()
-	return
-
-def failure(error):
-	print error
-	mainloop.quit()
-	return
-
-
-if __name__ == '__main__':
-	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-
-	mainloop = gobject.MainLoop()
-
-	bus = dbus.SessionBus()
-	client = dbus.Interface(bus.get_object("org.openobex.client", "/"),
-							"org.openobex.Client")
-
-	if (len(sys.argv) < 3):
-		print "Usage: %s <device> <file>" % (sys.argv[0])
-		sys.exit(1)
-
-	client.PullBusinessCard({ "Destination": sys.argv[1] }, sys.argv[2],
-				reply_handler=success, error_handler=failure)
-
-	mainloop.run()
diff -pruN 0.46-1/test/send-files 0.48-2.1/test/send-files
--- 0.46-1/test/send-files	2010-04-23 15:52:33.000000000 +0000
+++ 0.48-2.1/test/send-files	1970-01-01 00:00:00.000000000 +0000
@@ -1,82 +0,0 @@
-#!/usr/bin/python
-
-import gobject
-
-import os
-import sys
-import time
-import dbus
-import dbus.service
-import dbus.mainloop.glib
-
-class Agent(dbus.service.Object):
-	def __init__(self, conn=None, obj_path=None):
-		dbus.service.Object.__init__(self, conn, obj_path)
-
-	@dbus.service.method("org.openobex.Agent",
-					in_signature="o", out_signature="s")
-	def Request(self, path):
-		print "Transfer Request"
-		self.transfer = dbus.Interface(bus.get_object("org.openobex.client",
-						path), "org.openobex.Transfer")
-		properties = self.transfer.GetProperties()
-		for key in properties.keys():
-			print "  %s = %s" % (key, properties[key])
-		self.start = True
-		return ""
-
-	@dbus.service.method("org.openobex.Agent",
-					in_signature="ot", out_signature="")
-	def Progress(self, path, transferred):
-		if (self.start):
-			print "Transfer Started"
-			properties = self.transfer.GetProperties()
-			self.transfer_size = properties['Size']
-			self.start_time = time.time()
-			self.start = False
-		else:
-			speed = transferred / abs((time.time() - self.start_time) * 1000)
-			progress = "(" + str(transferred) + "/" + str(self.transfer_size) + " bytes) @ " + str(int(speed)) + " kB/s"
-			out = "\rTransfer progress " + progress
-			sys.stdout.write(out)
-			sys.stdout.flush()
-		return
-
-	@dbus.service.method("org.openobex.Agent",
-					in_signature="o", out_signature="")
-	def Complete(self, path):
-		print "\nTransfer finished"
-		return
-
-	@dbus.service.method("org.openobex.Agent",
-					in_signature="os", out_signature="")
-	def Error(self, path, error):
-		print "\nTransfer finished with an error: %s" % (error)
-		return
-
-	@dbus.service.method("org.openobex.Agent",
-					in_signature="", out_signature="")
-	def Release(self):
-		mainloop.quit()
-		return
-
-if __name__ == '__main__':
-	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-
-	bus = dbus.SessionBus()
-	client = dbus.Interface(bus.get_object("org.openobex.client", "/"),
-							"org.openobex.Client")
-
-	if (len(sys.argv) < 3):
-		print "Usage: %s <device> <file> [file*]" % (sys.argv[0])
-		sys.exit(1)
-
-	path = "/test/agent"
-	agent = Agent(bus, path)
-
-	mainloop = gobject.MainLoop()
-	files = [os.path.realpath(f) for f in sys.argv[2:]]
-
-	client.SendFiles({ "Destination": sys.argv[1] }, files, path)
-
-	mainloop.run()
diff -pruN 0.46-1/test/simple-agent 0.48-2.1/test/simple-agent
--- 0.46-1/test/simple-agent	2009-05-02 15:52:30.000000000 +0000
+++ 0.48-2.1/test/simple-agent	2012-07-26 17:09:25.000000000 +0000
@@ -12,8 +12,8 @@ class Agent(dbus.service.Object):
 		dbus.service.Object.__init__(self, conn, obj_path)
 		self.pending_auth = False
 
-	@dbus.service.method("org.openobex.Agent",
-					in_signature="osssii", out_signature="s")
+	@dbus.service.method("org.bluez.obex.Agent", in_signature="osssii",
+							out_signature="s")
 	def Authorize(self, dpath, device, filename, ftype, length, time):
 		global transfers
 
@@ -23,8 +23,9 @@ class Agent(dbus.service.Object):
 
 		if auth == "n" or auth == "N":
 			self.pending_auth = False
-			raise dbus.DBusException("org.openobex.Error.Rejected: "
-									"Not Autorized")
+			raise dbus.DBusException(
+					"org.bluez.obex.Error.Rejected: "
+					"Not Autorized")
 
 		print "Full filename (including path):"
 		self.pending_auth = False
@@ -32,8 +33,8 @@ class Agent(dbus.service.Object):
 		transfers.append(Transfer(dpath, filename, 0, length))
 		return raw_input().strip("\n ")
 
-	@dbus.service.method("org.openobex.Agent",
-					in_signature="", out_signature="")
+	@dbus.service.method("org.bluez.obex.Agent", in_signature="",
+							out_signature="")
 	def Cancel(self):
 		print "Authorization Canceled"
 		self.pending_auth = False
@@ -53,9 +54,9 @@ class Transfer(object):
 		self.size = total
 
 	def cancel(self):
-		transfer_iface = dbus.Interface(bus.get_object("org.openobex",
-														self.dpath),
-										"org.openobex.Transfer")
+		transfer_iface = dbus.Interface(bus.get_object(
+						"org.bluez.obex", self.dpath),
+						"org.bluez.obex.Transfer")
 		transfer_iface.Cancel()
 
 	def __str__(self):
@@ -71,9 +72,9 @@ if __name__ == '__main__':
 	def new_transfer(dpath):
 		print "new transfer"
 		bus.add_signal_receiver(progress,
-								dbus_interface="org.openobex.Transfer",
-								signal_name="Progress",
-								path_keyword="dpath")
+				dbus_interface="org.bluez.obex.Transfer",
+				signal_name="Progress",
+				path_keyword="dpath")
 
 	def transfer_completed(dpath, success):
 		global transfers
@@ -96,15 +97,15 @@ if __name__ == '__main__':
 	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
 	bus = dbus.SessionBus()
-	manager = dbus.Interface(bus.get_object("org.openobex", "/"),
-							"org.openobex.Manager")
+	manager = dbus.Interface(bus.get_object("org.bluez.obex", "/"),
+						"org.bluez.obex.Manager")
 	bus.add_signal_receiver(new_transfer,
-							dbus_interface="org.openobex.Manager",
-							signal_name="TransferStarted")
+				dbus_interface="org.bluez.obex.Manager",
+				signal_name="TransferStarted")
 
 	bus.add_signal_receiver(transfer_completed,
-							dbus_interface="org.openobex.Manager",
-							signal_name="TransferCompleted")
+				dbus_interface="org.bluez.obex.Manager",
+				signal_name="TransferCompleted")
 
 	path = "/test/agent"
 	agent = Agent(bus, path)
diff -pruN 0.46-1/tools/test-client.c 0.48-2.1/tools/test-client.c
--- 0.46-1/tools/test-client.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/tools/test-client.c	2012-11-30 07:59:13.000000000 +0000
@@ -181,7 +181,7 @@ static void cmd_get(int argc, char **arg
 						G_OBEX_HDR_NAME, argv[1],
 						G_OBEX_HDR_INVALID);
 	if (err != NULL) {
-		g_printerr("put failed: %s\n", err->message);
+		g_printerr("get failed: %s\n", err->message);
 		g_error_free(err);
 		close(data->fd);
 		g_free(data);
@@ -344,69 +344,66 @@ static void conn_callback(GIOChannel *io
 	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;
diff -pruN 0.46-1/tools/test-server.c 0.48-2.1/tools/test-server.c
--- 0.46-1/tools/test-server.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/tools/test-server.c	2012-11-30 07:59:13.000000000 +0000
@@ -308,40 +308,40 @@ static gboolean bluetooth_watch(GIOChann
 	return FALSE;
 }
 
+static GIOChannel *l2cap_listen(GError **err)
+{
+	return bt_io_listen(bluetooth_accept, NULL, NULL,
+					NULL, err,
+					BT_IO_OPT_PSM, option_channel,
+					BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+					BT_IO_OPT_OMTU, option_omtu,
+					BT_IO_OPT_IMTU, option_imtu,
+					BT_IO_OPT_INVALID);
+}
+
+static GIOChannel *rfcomm_listen(GError **err)
+{
+	return bt_io_listen(bluetooth_accept, NULL, NULL,
+					NULL, err,
+					BT_IO_OPT_CHANNEL, option_channel,
+					BT_IO_OPT_INVALID);
+}
+
 static guint bluetooth_listen(void)
 {
 	GIOChannel *io;
 	guint id;
 	GError *err = NULL;
-	BtIOType type;
-	BtIOOption option;
 
 	if (option_channel == -1) {
 		g_printerr("Bluetooth channel not set\n");
 		return 0;
 	}
 
-	if (option_packet || option_channel > 31) {
-		type = option_packet ? BT_IO_L2CAP : BT_IO_L2ERTM;
-		option = BT_IO_OPT_PSM;
-	} else {
-		type = BT_IO_RFCOMM;
-		option = BT_IO_OPT_CHANNEL;
-	}
-
-	if (type == BT_IO_L2CAP)
-		io = bt_io_listen(type, bluetooth_accept, NULL, NULL,
-					NULL, &err,
-					option, option_channel,
-					BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
-					BT_IO_OPT_OMTU, option_omtu,
-					BT_IO_OPT_IMTU, option_imtu,
-					BT_IO_OPT_INVALID);
+	if (option_packet || option_channel > 31)
+		io = l2cap_listen(&err);
 	else
-		io = bt_io_listen(type, bluetooth_accept, NULL, NULL,
-					NULL, &err,
-					option, option_channel,
-					BT_IO_OPT_INVALID);
+		io = rfcomm_listen(&err);
 
 	if (io == NULL) {
 		g_printerr("%s\n", err->message);
diff -pruN 0.46-1/unit/test-gobex-apparam.c 0.48-2.1/unit/test-gobex-apparam.c
--- 0.46-1/unit/test-gobex-apparam.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.48-2.1/unit/test-gobex-apparam.c	2012-11-30 07:59:13.000000000 +0000
@@ -0,0 +1,422 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#include <gobex/gobex-apparam.h>
+
+#include "util.h"
+
+#define TAG_U8 0x00
+#define TAG_U16 0x01
+#define TAG_U32 0x02
+#define TAG_U64 0x03
+#define TAG_STRING 0x04
+#define TAG_BYTES 0x05
+
+static uint8_t tag_nval_short[] = { TAG_U8 };
+static uint8_t tag_nval_data[] = { TAG_U8, 0x01 };
+static uint8_t tag_nval2_short[] = { TAG_U8, 0x01, 0x1, TAG_U16 };
+static uint8_t tag_nval2_data[] = { TAG_U8, 0x01, 0x1, TAG_U16, 0x02 };
+static uint8_t tag_uint8[] = { TAG_U8, 0x01, 0x01 };
+static uint8_t tag_uint16[] = { TAG_U16, 0x02, 0x01, 0x02 };
+static uint8_t tag_uint32[] = { TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04 };
+static uint8_t tag_uint64[] = { TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+						0x05, 0x06, 0x07, 0x08 };
+static uint8_t tag_string[] = { TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+static uint8_t tag_bytes[257] = { TAG_BYTES, 0xFF };
+static uint8_t tag_multi[] = { TAG_U8, 0x01, 0x01,
+				TAG_U16, 0x02, 0x01, 0x02,
+				TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04,
+				TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+						0x05, 0x06, 0x07, 0x08,
+				TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+
+
+static GObexApparam *parse_and_decode(const void *data, gsize size)
+{
+	GObexApparam *apparam;
+	guint8 encoded[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_decode(data, size);
+
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, encoded, sizeof(encoded));
+
+	assert_memequal(data, size, encoded, len);
+
+	return apparam;
+}
+
+static void test_apparam_nval_short(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval_short,
+						sizeof(tag_nval_short));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval_data(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval_data,
+						sizeof(tag_nval_data));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_short(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval2_short,
+						sizeof(tag_nval2_short));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_data(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval2_data,
+						sizeof(tag_nval2_data));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_get_uint8(void)
+{
+	GObexApparam *apparam;
+	guint8 data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint8, sizeof(tag_uint8));
+
+	ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x01);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint16(void)
+{
+	GObexApparam *apparam;
+	uint16_t data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint16, sizeof(tag_uint16));
+
+	ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x0102);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint32(void)
+{
+	GObexApparam *apparam;
+	uint32_t data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint32, sizeof(tag_uint32));
+
+	ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x01020304);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint64(void)
+{
+	GObexApparam *apparam;
+	uint64_t data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint64, sizeof(tag_uint64));
+
+	ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x0102030405060708);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_string(void)
+{
+	GObexApparam *apparam;
+	char *string;
+
+	apparam = parse_and_decode(tag_string, sizeof(tag_string));
+
+	string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+	g_assert(string != NULL);
+	g_assert_cmpstr(string, ==, "ABC");
+
+	g_free(string);
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_bytes(void)
+{
+	GObexApparam *apparam;
+	const uint8_t *data;
+	gsize len;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_bytes, sizeof(tag_bytes));
+
+	ret = g_obex_apparam_get_bytes(apparam, TAG_BYTES, &data, &len);
+
+	g_assert(ret == TRUE);
+	assert_memequal(tag_bytes + 2, sizeof(tag_bytes) - 2, data, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_multi(void)
+{
+	GObexApparam *apparam;
+	char *string;
+	uint8_t data8;
+	uint16_t data16;
+	uint32_t data32;
+	uint64_t data64;
+	gboolean ret;
+
+	apparam = g_obex_apparam_decode(tag_multi, sizeof(tag_multi));
+
+	g_assert(apparam != NULL);
+
+	ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data8);
+
+	g_assert(ret == TRUE);
+	g_assert(data8 == 0x01);
+
+	ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data16);
+
+	g_assert(ret == TRUE);
+	g_assert(data16 == 0x0102);
+
+	ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data32);
+
+	g_assert(ret == TRUE);
+	g_assert(data32 == 0x01020304);
+
+	ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data64);
+
+	g_assert(ret == TRUE);
+	g_assert(data64 == 0x0102030405060708);
+
+	string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+	g_assert(string != NULL);
+	g_assert_cmpstr(string, ==, "ABC");
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint8(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint8, sizeof(tag_uint8), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint16(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint16(NULL, TAG_U16, 0x0102);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint16, sizeof(tag_uint16), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint32(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint32(NULL, TAG_U32, 0x01020304);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint32, sizeof(tag_uint32), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint64(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint64(NULL, TAG_U64, 0x0102030405060708);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint64, sizeof(tag_uint64), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_string(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_string(NULL, TAG_STRING, "ABC");
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_string, sizeof(tag_string), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_bytes(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_bytes(NULL, TAG_BYTES, tag_bytes + 2, 255);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_bytes, sizeof(tag_bytes), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_multi(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_uint16(apparam, TAG_U16, 0x0102);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_uint32(apparam, TAG_U32, 0x01020304);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_uint64(apparam, TAG_U64,
+							0x0102030405060708);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_string(apparam, TAG_STRING, "ABC");
+
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+
+	g_assert_cmpuint(len, ==, sizeof(tag_multi));
+
+	g_obex_apparam_free(apparam);
+}
+
+int main(int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_func("/gobex/test_apparam_nval_short",
+						test_apparam_nval_short);
+	g_test_add_func("/gobex/test_apparam_nval_data",
+						test_apparam_nval_data);
+
+	g_test_add_func("/gobex/test_apparam_nval2_short",
+						test_apparam_nval2_short);
+	g_test_add_func("/gobex/test_apparam_nval2_data",
+						test_apparam_nval2_data);
+
+	g_test_add_func("/gobex/test_apparam_get_uint8",
+						test_apparam_get_uint8);
+	g_test_add_func("/gobex/test_apparam_get_uint16",
+						test_apparam_get_uint16);
+	g_test_add_func("/gobex/test_apparam_get_uint32",
+						test_apparam_get_uint32);
+	g_test_add_func("/gobex/test_apparam_get_uint64",
+						test_apparam_get_uint64);
+	g_test_add_func("/gobex/test_apparam_get_string",
+						test_apparam_get_string);
+	g_test_add_func("/gobex/test_apparam_get_bytes",
+						test_apparam_get_bytes);
+	g_test_add_func("/gobex/test_apparam_get_multi",
+						test_apparam_get_multi);
+
+	g_test_add_func("/gobex/test_apparam_set_uint8",
+						test_apparam_set_uint8);
+	g_test_add_func("/gobex/test_apparam_set_uint16",
+						test_apparam_set_uint16);
+	g_test_add_func("/gobex/test_apparam_set_uint32",
+						test_apparam_set_uint32);
+	g_test_add_func("/gobex/test_apparam_set_uint64",
+						test_apparam_set_uint64);
+	g_test_add_func("/gobex/test_apparam_set_string",
+						test_apparam_set_string);
+	g_test_add_func("/gobex/test_apparam_set_bytes",
+						test_apparam_set_bytes);
+	g_test_add_func("/gobex/test_apparam_set_multi",
+						test_apparam_set_multi);
+
+	g_test_run();
+
+	return 0;
+}
diff -pruN 0.46-1/unit/test-gobex.c 0.48-2.1/unit/test-gobex.c
--- 0.46-1/unit/test-gobex.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/unit/test-gobex.c	2014-10-16 04:43:28.000000000 +0000
@@ -230,7 +230,7 @@ static void send_req(GObexPacket *req, G
 	GError *gerr = NULL;
 	GIOChannel *io;
 	GIOCondition cond;
-	guint io_id, timer_id, test_time;
+	guint timer_id, test_time;
 	GObex *obex;
 
 	create_endpoints(&obex, &io, transport_type);
@@ -239,7 +239,7 @@ static void send_req(GObexPacket *req, G
 	g_assert_no_error(gerr);
 
 	cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
-	io_id = g_io_add_watch(io, cond, send_rsp_func, &gerr);
+	g_io_add_watch(io, cond, send_rsp_func, &gerr);
 
 	mainloop = g_main_loop_new(NULL, FALSE);
 
@@ -257,7 +257,6 @@ static void send_req(GObexPacket *req, G
 
 	g_source_remove(timer_id);
 	g_io_channel_unref(io);
-	g_source_remove(io_id);
 	g_obex_unref(obex);
 
 	g_assert_no_error(gerr);
@@ -461,6 +460,7 @@ struct rcv_buf_info {
 	GError *err;
 	const guint8 *buf;
 	gsize len;
+	gboolean completed;
 };
 
 static gboolean rcv_data(GIOChannel *io, GIOCondition cond, gpointer user_data)
@@ -500,6 +500,7 @@ static gboolean rcv_data(GIOChannel *io,
 
 done:
 	g_main_loop_quit(mainloop);
+	r->completed = TRUE;
 	return FALSE;
 }
 
@@ -541,7 +542,8 @@ static void test_send_connect(int transp
 
 	g_source_remove(timer_id);
 	g_io_channel_unref(io);
-	g_source_remove(io_id);
+	if (!r.completed)
+		g_source_remove(io_id);
 	g_obex_unref(obex);
 
 	g_assert_no_error(r.err);
@@ -656,7 +658,8 @@ static void test_send_on_demand(int tran
 
 	g_source_remove(timer_id);
 	g_io_channel_unref(io);
-	g_source_remove(io_id);
+	if (!r.completed)
+		g_source_remove(io_id);
 	g_obex_unref(obex);
 
 	g_assert_no_error(r.err);
diff -pruN 0.46-1/unit/test-gobex-header.c 0.48-2.1/unit/test-gobex-header.c
--- 0.46-1/unit/test-gobex-header.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/unit/test-gobex-header.c	2012-11-30 07:59:13.000000000 +0000
@@ -47,6 +47,8 @@ static uint8_t hdr_bytes_nval_short[] =
 						0x01, 0x02, 0x03 };
 static uint8_t hdr_bytes_nval_data[] = { G_OBEX_HDR_BODY, 0xab };
 static uint8_t hdr_bytes_nval_len[] = { G_OBEX_HDR_BODY, 0x00, 0x00 };
+static uint8_t hdr_apparam[] = { G_OBEX_HDR_APPARAM, 0x00, 0x09, 0x00, 0x04,
+						0x01, 0x02, 0x03, 0x04 };
 
 static void test_header_name_empty(void)
 {
@@ -115,6 +117,27 @@ static void test_header_bytes(void)
 	g_obex_header_free(header);
 }
 
+static void test_header_apparam(void)
+{
+	GObexHeader *header;
+	GObexApparam *apparam;
+	uint8_t buf[1024];
+	size_t len;
+
+	apparam = g_obex_apparam_set_uint32(NULL, 0, 0x01020304);
+	g_assert(apparam != NULL);
+
+	header = g_obex_header_new_apparam(apparam);
+	g_assert(header != NULL);
+
+	len = g_obex_header_encode(header, buf, sizeof(buf));
+
+	assert_memequal(hdr_apparam, sizeof(hdr_apparam), buf, len);
+
+	g_obex_apparam_free(apparam);
+	g_obex_header_free(header);
+}
+
 static void test_header_uint8(void)
 {
 	GObexHeader *header;
@@ -247,6 +270,26 @@ static void test_header_encode_body(void
 	g_obex_header_free(header);
 }
 
+static void test_header_encode_apparam(void)
+{
+	GObexHeader *header;
+	GObexApparam *apparam;
+	gboolean ret;
+	guint32 data;
+
+	header = parse_and_encode(hdr_apparam, sizeof(hdr_apparam));
+
+	apparam = g_obex_header_get_apparam(header);
+	g_assert(apparam != NULL);
+
+	ret = g_obex_apparam_get_uint32(apparam, 0x00, &data);
+	g_assert(ret == TRUE);
+	g_assert(data == 0x01020304);
+
+	g_obex_apparam_free(apparam);
+	g_obex_header_free(header);
+}
+
 static void test_header_encode_actionid(void)
 {
 	GObexHeader *header;
@@ -507,6 +550,8 @@ int main(int argc, char *argv[])
 						test_header_encode_body);
 	g_test_add_func("/gobex/test_header_encode_connid",
 						test_header_encode_actionid);
+	g_test_add_func("/gobex/test_header_encode_apparam",
+						test_header_encode_apparam);
 
 	g_test_add_func("/gobex/test_header_name_empty",
 						test_header_name_empty);
@@ -517,6 +562,7 @@ int main(int argc, char *argv[])
 	g_test_add_func("/gobex/test_header_bytes", test_header_bytes);
 	g_test_add_func("/gobex/test_header_uint8", test_header_uint8);
 	g_test_add_func("/gobex/test_header_uint32", test_header_uint32);
+	g_test_add_func("/gobex/test_header_apparam", test_header_apparam);
 
 	g_test_run();
 
diff -pruN 0.46-1/unit/test-gobex-transfer.c 0.48-2.1/unit/test-gobex-transfer.c
--- 0.46-1/unit/test-gobex-transfer.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/unit/test-gobex-transfer.c	2014-10-16 04:43:28.000000000 +0000
@@ -1800,7 +1800,8 @@ static void test_conn_rsp(void)
 
 	g_source_remove(timer_id);
 	g_io_channel_unref(io);
-	g_source_remove(io_id);
+	if (!d.io_completed)
+		g_source_remove(io_id);
 	g_obex_unref(obex);
 
 	g_assert_no_error(d.err);
@@ -2055,7 +2056,8 @@ static void test_conn_get_wrg_rsp(void)
 
 	g_source_remove(timer_id);
 	g_io_channel_unref(io);
-	g_source_remove(io_id);
+	if (!d.io_completed)
+		g_source_remove(io_id);
 	g_obex_unref(obex);
 
 	g_assert_no_error(d.err);
diff -pruN 0.46-1/unit/util.c 0.48-2.1/unit/util.c
--- 0.46-1/unit/util.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/unit/util.c	2014-10-16 04:43:28.000000000 +0000
@@ -189,5 +189,6 @@ send:
 
 failed:
 	g_main_loop_quit(d->mainloop);
+	d->io_completed = TRUE;
 	return FALSE;
 }
diff -pruN 0.46-1/unit/util.h 0.48-2.1/unit/util.h
--- 0.46-1/unit/util.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.48-2.1/unit/util.h	2014-10-16 04:43:28.000000000 +0000
@@ -41,6 +41,7 @@ struct test_data {
 	guint id;
 	gsize total;
 	GMainLoop *mainloop;
+	gboolean io_completed;
 };
 
 #define TEST_ERROR test_error_quark()
