diff -pruN 0.46-1/client/bluetooth.c 0.46-1ubuntu7/client/bluetooth.c
--- 0.46-1/client/bluetooth.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/client/bluetooth.c	2014-04-10 18:41:34.000000000 +0000
@@ -56,11 +56,9 @@ struct bluetooth_session {
 	bdaddr_t src;
 	bdaddr_t dst;
 	uint16_t port;
-	DBusConnection *conn; /* system bus connection */
 	sdp_session_t *sdp;
 	GIOChannel *io;
 	GSList *pending_calls;
-	char *adapter;
 	char *service;
 	obc_transport_func func;
 	void *user_data;
@@ -73,60 +71,6 @@ static GQuark obc_bt_error_quark(void)
 	return g_quark_from_static_string("obc-bluetooth-error-quark");
 }
 
-static int send_method_call(struct bluetooth_session *session,
-					const char *path,
-					const char *interface,
-					const char *method,
-					DBusPendingCallNotifyFunction cb,
-					int type, ...)
-{
-	DBusMessage *msg;
-	DBusPendingCall *call;
-	va_list args;
-
-	msg = dbus_message_new_method_call(BT_BUS_NAME, path, interface,
-								method);
-	if (!msg) {
-		error("Unable to allocate new D-Bus %s message", method);
-		return -ENOMEM;
-	}
-
-	va_start(args, type);
-
-	if (!dbus_message_append_args_valist(msg, type, args)) {
-		dbus_message_unref(msg);
-		va_end(args);
-		return -EINVAL;
-	}
-
-	va_end(args);
-
-	if (!cb) {
-		g_dbus_send_message(session->conn, msg);
-		return 0;
-	}
-
-	if (!dbus_connection_send_with_reply(session->conn, msg, &call, -1)) {
-		error("Sending %s failed", method);
-		dbus_message_unref(msg);
-		return -EIO;
-	}
-
-	dbus_pending_call_set_notify(call, cb, session, NULL);
-
-	session->pending_calls = g_slist_prepend(session->pending_calls, call);
-
-	return 0;
-}
-
-static void finalize_call(DBusPendingCall *call)
-{
-	if (!dbus_pending_call_get_completed(call))
-		dbus_pending_call_cancel(call);
-
-	dbus_pending_call_unref(call);
-}
-
 static void session_destroy(struct bluetooth_session *session)
 {
 	GSList *l;
@@ -138,31 +82,15 @@ static void session_destroy(struct bluet
 
 	sessions = g_slist_remove(sessions, session);
 
-	if (session->adapter)
-		send_method_call(session, session->adapter, BT_ADAPTER_IFACE,
-						"ReleaseSession", NULL,
-						DBUS_TYPE_INVALID);
-
-	l = session->pending_calls;
-
-	while (l) {
-		DBusPendingCall *call = l->data;
-		l = l->next;
-
-		session->pending_calls = g_slist_remove(session->pending_calls, call);
-		finalize_call(call);
-	}
-
 	if (session->io != NULL) {
 		g_io_channel_shutdown(session->io, TRUE, NULL);
 		g_io_channel_unref(session->io);
 	}
 
-	if (session->conn)
-		dbus_connection_unref(session->conn);
+	if (session->sdp)
+		sdp_close(session->sdp);
 
 	g_free(session->service);
-	g_free(session->adapter);
 	g_free(session);
 }
 
@@ -453,111 +381,6 @@ static int session_connect(struct blueto
 	return err;
 }
 
-static void adapter_reply(DBusPendingCall *call, void *user_data)
-{
-	struct bluetooth_session *session = user_data;
-	DBusError err;
-	DBusMessage *reply;
-	GError *gerr = NULL;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	session->pending_calls = g_slist_remove(session->pending_calls, call);
-	finalize_call(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("manager replied with an error: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-
-		goto failed;
-	}
-
-	if (session_connect(session) == 0)
-		goto proceed;
-
-failed:
-	g_set_error(&gerr, OBC_BT_ERROR, -EINVAL,
-					"Unable to request session");
-	if (session->func)
-		session->func(session->io, gerr, session->user_data);
-	g_clear_error(&gerr);
-
-	session_destroy(session);
-
-proceed:
-	dbus_message_unref(reply);
-}
-
-static int request_session(struct bluetooth_session *session, const char *adapter)
-{
-	session->adapter = g_strdup(adapter);
-	return send_method_call(session, adapter, BT_ADAPTER_IFACE,
-					"RequestSession", adapter_reply,
-					DBUS_TYPE_INVALID);
-}
-
-static void manager_reply(DBusPendingCall *call, void *user_data)
-{
-	struct bluetooth_session *session = user_data;
-	DBusError err;
-	DBusMessage *reply;
-	char *adapter;
-	GError *gerr = NULL;
-
-	reply = dbus_pending_call_steal_reply(call);
-
-	session->pending_calls = g_slist_remove(session->pending_calls, call);
-	finalize_call(call);
-
-	dbus_error_init(&err);
-	if (dbus_set_error_from_message(&err, reply)) {
-		error("manager replied with an error: %s, %s",
-				err.name, err.message);
-		dbus_error_free(&err);
-
-		goto failed;
-	}
-
-	if (!dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_OBJECT_PATH, &adapter,
-				DBUS_TYPE_INVALID))
-		goto failed;
-
-	DBG("adapter path %s", adapter);
-
-	if (request_session(session, adapter) == 0)
-		goto proceed;
-
-failed:
-	g_set_error(&gerr, OBC_BT_ERROR, -EINVAL, "No adapter found");
-	if (session->func)
-		session->func(session->io, gerr, session->user_data);
-	g_clear_error(&gerr);
-
-	session_destroy(session);
-
-proceed:
-	dbus_message_unref(reply);
-}
-
-static int find_adapter(struct bluetooth_session *session, const char *source)
-{
-	if (source == NULL) {
-		bacpy(&session->src, BDADDR_ANY);
-		return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
-					"DefaultAdapter", manager_reply,
-					DBUS_TYPE_INVALID);
-	}
-
-	str2ba(source, &session->src);
-	return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
-					"FindAdapter", manager_reply,
-					DBUS_TYPE_STRING, &source,
-					DBUS_TYPE_INVALID);
-}
-
 static guint bluetooth_connect(const char *source, const char *destination,
 				const char *service, uint16_t port,
 				obc_transport_func func, void *user_data)
@@ -576,22 +399,18 @@ 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);
-	if (session->conn == NULL) {
-		g_free(session);
-		return 0;
-	}
-
-	session->service = g_strdup(service);
 	str2ba(destination, &session->dst);
+	str2ba(source, &session->src);
 
-	if (find_adapter(session, source) < 0) {
+	if (session_connect(session) < 0) {
 		g_free(session);
 		return 0;
 	}
 
+	session->service = g_strdup(service);
 	sessions = g_slist_prepend(sessions, session);
 
 	return session->id;
diff -pruN 0.46-1/debian/changelog 0.46-1ubuntu7/debian/changelog
--- 0.46-1/debian/changelog	2012-05-31 23:40:25.000000000 +0000
+++ 0.46-1ubuntu7/debian/changelog	2014-04-10 16:59:55.000000000 +0000
@@ -1,3 +1,54 @@
+obexd (0.46-1ubuntu7) trusty; urgency=medium
+
+  * debian/patches/backport_session_code.patch: Backport session request code
+    from bluez 5 which does away with the session request calls to BlueZ.
+    (LP: #1285948)
+
+ -- Mathieu Trudel-Lapierre <mathieu-tl@ubuntu.com>  Thu, 10 Apr 2014 12:59:53 -0400
+
+obexd (0.46-1ubuntu6) trusty; urgency=medium
+
+  * Avoid double source removals during tests (LP: #1263259).
+
+ -- Colin Watson <cjwatson@ubuntu.com>  Mon, 06 Jan 2014 12:49:34 +0000
+
+obexd (0.46-1ubuntu5) saucy; urgency=low
+
+  * Build against libical 1.0
+
+ -- Jonathan Riddell <jriddell@ubuntu.com>  Thu, 13 Jun 2013 13:23:56 +0100
+
+obexd (0.46-1ubuntu4) saucy; urgency=low
+
+  * Remove obsolete libebook BD; using the "dummy" (ical) phonebook driver.
+
+ -- Iain Lane <iain.lane@canonical.com>  Wed, 29 May 2013 17:07:08 +0100
+
+obexd (0.46-1ubuntu3) raring; urgency=low
+
+  * Add sys/types.h includes to fix the build failure with glibc-2.17.
+
+ -- Matthias Klose <doko@ubuntu.com>  Tue, 02 Apr 2013 18:59:34 +0100
+
+obexd (0.46-1ubuntu2) quantal; urgency=low
+
+  * debian/rules:
+    - Drop --with-phonebook=ebook. It won't build against EDS 3.5.
+
+ -- Mathieu Trudel-Lapierre <mathieu-tl@ubuntu.com>  Wed, 12 Sep 2012 10:16:39 -0400
+
+obexd (0.46-1ubuntu1) quantal-proposed; urgency=low
+
+  * Rebase on Debian unstable, remaining Ubuntu changes:
+  * debian/patches/tests-may-block.patch:
+    - Don't pass SOCK_NONBLOCK as an option for the socket type to socketpair(),
+      this doesn't work on buildds.
+  * debian/control:
+    - Drop libopenobex1 from Build-Depends, it's no longer needed and replaced
+      by gobex (in source).
+
+ -- Robert Ancell <robert.ancell@canonical.com>  Tue, 03 Jul 2012 13:23:53 +1200
+
 obexd (0.46-1) unstable; urgency=low
 
   * New upstream release.
@@ -30,6 +81,28 @@ obexd (0.44-1) unstable; urgency=low
 
  -- Nobuhiro Iwamatsu <iwamatsu@debian.org>  Tue, 24 Jan 2012 12:02:33 +0900
 
+obexd (0.44-0ubuntu1) precise; urgency=low
+
+  * New upstream release.
+
+ -- Mathieu Trudel-Lapierre <mathieu-tl@ubuntu.com>  Wed, 18 Jan 2012 13:01:09 -0500
+
+obexd (0.43-0ubuntu2) precise; urgency=low
+
+  * debian/patches/tests-may-block.patch: don't pass SOCK_NONBLOCK as an option
+    for the socket type to socketpair(), this doesn't work on buildds.
+  * debian/source/format: switch to format 3.0 (quilt) so patches get applied.
+
+ -- Mathieu Trudel-Lapierre <mathieu-tl@ubuntu.com>  Fri, 06 Jan 2012 14:47:19 -0500
+
+obexd (0.43-0ubuntu1) precise; urgency=low
+
+  * New upstream release. (LP: #879923)
+  * debian/control: drop libopenobex1 from Build-Depends, it's no longer needed
+    and replaced by gobex (in source).
+
+ -- Mathieu Trudel-Lapierre <mathieu-tl@ubuntu.com>  Thu, 05 Jan 2012 17:33:25 -0500
+
 obexd (0.42-1) unstable; urgency=low
 
   * New upstream release.
diff -pruN 0.46-1/debian/control 0.46-1ubuntu7/debian/control
--- 0.46-1/debian/control	2012-06-06 04:44:34.000000000 +0000
+++ 0.46-1ubuntu7/debian/control	2014-04-10 13:36:32.000000000 +0000
@@ -1,15 +1,14 @@
 Source: obexd
 Section: admin
 Priority: optional
-Maintainer: Debian Bluetooth Maintainers <pkg-bluetooth-maintainers@lists.alioth.debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-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~),
                libglib2.0-dev,
                libdbus-1-dev,
-               libopenobex1-dev,
                libbluetooth-dev (>= 4.99),
-               libebook1.2-dev,
-               libical-dev
+               libical-dev (>= 1.0)
 Vcs-Svn: svn://svn.debian.org/svn/pkg-bluetooth/packages/obexd
 Vcs-Browser: http://svn.debian.org/wsvn/pkg-bluetooth/packages/obexd/
 Homepage: http://www.bluez.org
diff -pruN 0.46-1/debian/patches/backport_session_code.patch 0.46-1ubuntu7/debian/patches/backport_session_code.patch
--- 0.46-1/debian/patches/backport_session_code.patch	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/debian/patches/backport_session_code.patch	2014-04-10 16:03:30.000000000 +0000
@@ -0,0 +1,258 @@
+From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
+Subject: Backport session establishing code from BlueZ 5.
+Last-Update: 2014-04-10
+
+---
+ client/bluetooth.c |  193 +----------------------------------------------------
+ 1 file changed, 6 insertions(+), 187 deletions(-)
+
+Index: b/client/bluetooth.c
+===================================================================
+--- a/client/bluetooth.c
++++ b/client/bluetooth.c
+@@ -56,11 +56,9 @@ struct bluetooth_session {
+ 	bdaddr_t src;
+ 	bdaddr_t dst;
+ 	uint16_t port;
+-	DBusConnection *conn; /* system bus connection */
+ 	sdp_session_t *sdp;
+ 	GIOChannel *io;
+ 	GSList *pending_calls;
+-	char *adapter;
+ 	char *service;
+ 	obc_transport_func func;
+ 	void *user_data;
+@@ -73,60 +71,6 @@ static GQuark obc_bt_error_quark(void)
+ 	return g_quark_from_static_string("obc-bluetooth-error-quark");
+ }
+ 
+-static int send_method_call(struct bluetooth_session *session,
+-					const char *path,
+-					const char *interface,
+-					const char *method,
+-					DBusPendingCallNotifyFunction cb,
+-					int type, ...)
+-{
+-	DBusMessage *msg;
+-	DBusPendingCall *call;
+-	va_list args;
+-
+-	msg = dbus_message_new_method_call(BT_BUS_NAME, path, interface,
+-								method);
+-	if (!msg) {
+-		error("Unable to allocate new D-Bus %s message", method);
+-		return -ENOMEM;
+-	}
+-
+-	va_start(args, type);
+-
+-	if (!dbus_message_append_args_valist(msg, type, args)) {
+-		dbus_message_unref(msg);
+-		va_end(args);
+-		return -EINVAL;
+-	}
+-
+-	va_end(args);
+-
+-	if (!cb) {
+-		g_dbus_send_message(session->conn, msg);
+-		return 0;
+-	}
+-
+-	if (!dbus_connection_send_with_reply(session->conn, msg, &call, -1)) {
+-		error("Sending %s failed", method);
+-		dbus_message_unref(msg);
+-		return -EIO;
+-	}
+-
+-	dbus_pending_call_set_notify(call, cb, session, NULL);
+-
+-	session->pending_calls = g_slist_prepend(session->pending_calls, call);
+-
+-	return 0;
+-}
+-
+-static void finalize_call(DBusPendingCall *call)
+-{
+-	if (!dbus_pending_call_get_completed(call))
+-		dbus_pending_call_cancel(call);
+-
+-	dbus_pending_call_unref(call);
+-}
+-
+ static void session_destroy(struct bluetooth_session *session)
+ {
+ 	GSList *l;
+@@ -138,31 +82,15 @@ static void session_destroy(struct bluet
+ 
+ 	sessions = g_slist_remove(sessions, session);
+ 
+-	if (session->adapter)
+-		send_method_call(session, session->adapter, BT_ADAPTER_IFACE,
+-						"ReleaseSession", NULL,
+-						DBUS_TYPE_INVALID);
+-
+-	l = session->pending_calls;
+-
+-	while (l) {
+-		DBusPendingCall *call = l->data;
+-		l = l->next;
+-
+-		session->pending_calls = g_slist_remove(session->pending_calls, call);
+-		finalize_call(call);
+-	}
+-
+ 	if (session->io != NULL) {
+ 		g_io_channel_shutdown(session->io, TRUE, NULL);
+ 		g_io_channel_unref(session->io);
+ 	}
+ 
+-	if (session->conn)
+-		dbus_connection_unref(session->conn);
++	if (session->sdp)
++		sdp_close(session->sdp);
+ 
+ 	g_free(session->service);
+-	g_free(session->adapter);
+ 	g_free(session);
+ }
+ 
+@@ -453,111 +381,6 @@ static int session_connect(struct blueto
+ 	return err;
+ }
+ 
+-static void adapter_reply(DBusPendingCall *call, void *user_data)
+-{
+-	struct bluetooth_session *session = user_data;
+-	DBusError err;
+-	DBusMessage *reply;
+-	GError *gerr = NULL;
+-
+-	reply = dbus_pending_call_steal_reply(call);
+-
+-	session->pending_calls = g_slist_remove(session->pending_calls, call);
+-	finalize_call(call);
+-
+-	dbus_error_init(&err);
+-	if (dbus_set_error_from_message(&err, reply)) {
+-		error("manager replied with an error: %s, %s",
+-				err.name, err.message);
+-		dbus_error_free(&err);
+-
+-		goto failed;
+-	}
+-
+-	if (session_connect(session) == 0)
+-		goto proceed;
+-
+-failed:
+-	g_set_error(&gerr, OBC_BT_ERROR, -EINVAL,
+-					"Unable to request session");
+-	if (session->func)
+-		session->func(session->io, gerr, session->user_data);
+-	g_clear_error(&gerr);
+-
+-	session_destroy(session);
+-
+-proceed:
+-	dbus_message_unref(reply);
+-}
+-
+-static int request_session(struct bluetooth_session *session, const char *adapter)
+-{
+-	session->adapter = g_strdup(adapter);
+-	return send_method_call(session, adapter, BT_ADAPTER_IFACE,
+-					"RequestSession", adapter_reply,
+-					DBUS_TYPE_INVALID);
+-}
+-
+-static void manager_reply(DBusPendingCall *call, void *user_data)
+-{
+-	struct bluetooth_session *session = user_data;
+-	DBusError err;
+-	DBusMessage *reply;
+-	char *adapter;
+-	GError *gerr = NULL;
+-
+-	reply = dbus_pending_call_steal_reply(call);
+-
+-	session->pending_calls = g_slist_remove(session->pending_calls, call);
+-	finalize_call(call);
+-
+-	dbus_error_init(&err);
+-	if (dbus_set_error_from_message(&err, reply)) {
+-		error("manager replied with an error: %s, %s",
+-				err.name, err.message);
+-		dbus_error_free(&err);
+-
+-		goto failed;
+-	}
+-
+-	if (!dbus_message_get_args(reply, NULL,
+-				DBUS_TYPE_OBJECT_PATH, &adapter,
+-				DBUS_TYPE_INVALID))
+-		goto failed;
+-
+-	DBG("adapter path %s", adapter);
+-
+-	if (request_session(session, adapter) == 0)
+-		goto proceed;
+-
+-failed:
+-	g_set_error(&gerr, OBC_BT_ERROR, -EINVAL, "No adapter found");
+-	if (session->func)
+-		session->func(session->io, gerr, session->user_data);
+-	g_clear_error(&gerr);
+-
+-	session_destroy(session);
+-
+-proceed:
+-	dbus_message_unref(reply);
+-}
+-
+-static int find_adapter(struct bluetooth_session *session, const char *source)
+-{
+-	if (source == NULL) {
+-		bacpy(&session->src, BDADDR_ANY);
+-		return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
+-					"DefaultAdapter", manager_reply,
+-					DBUS_TYPE_INVALID);
+-	}
+-
+-	str2ba(source, &session->src);
+-	return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
+-					"FindAdapter", manager_reply,
+-					DBUS_TYPE_STRING, &source,
+-					DBUS_TYPE_INVALID);
+-}
+-
+ static guint bluetooth_connect(const char *source, const char *destination,
+ 				const char *service, uint16_t port,
+ 				obc_transport_func func, void *user_data)
+@@ -576,22 +399,18 @@ 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);
+-	if (session->conn == NULL) {
+-		g_free(session);
+-		return 0;
+-	}
+-
+-	session->service = g_strdup(service);
+ 	str2ba(destination, &session->dst);
++	str2ba(source, &session->src);
+ 
+-	if (find_adapter(session, source) < 0) {
++	if (session_connect(session) < 0) {
+ 		g_free(session);
+ 		return 0;
+ 	}
+ 
++	session->service = g_strdup(service);
+ 	sessions = g_slist_prepend(sessions, session);
+ 
+ 	return session->id;
diff -pruN 0.46-1/debian/patches/includes.diff 0.46-1ubuntu7/debian/patches/includes.diff
--- 0.46-1/debian/patches/includes.diff	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/debian/patches/includes.diff	2014-04-10 13:36:32.000000000 +0000
@@ -0,0 +1,39 @@
+Index: b/plugins/filesystem.h
+===================================================================
+--- a/plugins/filesystem.h	2012-05-17 15:12:17.000000000 +0000
++++ b/plugins/filesystem.h	2013-04-02 16:59:27.433752030 +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);
+Index: b/src/mimetype.h
+===================================================================
+--- a/src/mimetype.h	2012-05-17 15:12:17.000000000 +0000
++++ b/src/mimetype.h	2013-04-02 16:59:20.197702060 +0000
+@@ -21,6 +21,8 @@
+  *
+  */
+ 
++#include <sys/types.h>
++
+ typedef gboolean (*obex_object_io_func) (void *object, int flags, int err,
+ 							void *user_data);
+ 
+Index: b/src/obex.h
+===================================================================
+--- a/src/obex.h	2012-05-17 15:12:17.000000000 +0000
++++ b/src/obex.h	2013-04-02 16:59:07.709616787 +0000
+@@ -22,6 +22,8 @@
+  *
+  */
+ 
++#include <sys/types.h>
++
+ #define OBJECT_SIZE_UNKNOWN -1
+ #define OBJECT_SIZE_DELETE -2
+ 
diff -pruN 0.46-1/debian/patches/series 0.46-1ubuntu7/debian/patches/series
--- 0.46-1/debian/patches/series	2012-05-31 22:58:21.000000000 +0000
+++ 0.46-1ubuntu7/debian/patches/series	2014-04-10 15:03:31.000000000 +0000
@@ -1 +1,5 @@
 Remove_left_over_glib-helper.h_support.patch
+test-may-block.patch
+includes.diff
+test-avoid-double-source-removals.patch
+backport_session_code.patch
diff -pruN 0.46-1/debian/patches/test-avoid-double-source-removals.patch 0.46-1ubuntu7/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.46-1ubuntu7/debian/patches/test-avoid-double-source-removals.patch	2014-04-10 13:36:32.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/patches/test-may-block.patch 0.46-1ubuntu7/debian/patches/test-may-block.patch
--- 0.46-1/debian/patches/test-may-block.patch	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/debian/patches/test-may-block.patch	2014-04-10 13:36:32.000000000 +0000
@@ -0,0 +1,23 @@
+From: Mathieu Trudel-Lapierre <mathieu.trudel-lapierre@canonical.com>
+Subject: Don't pass SOCK_NONBLOCK option for the socket type to socketpair()
+Forwarded: not-needed
+
+The reason for this is that it's only supported starting with kernel 2.6.27.
+Unfortunately, the Ubuntu buildds run on 2.6.24 at this time, so fail the tests
+because the parameter is invalid there. We should be able to work around this
+safely by just not passing this option. This will allow keeping the tests
+running ;)
+
+Index: obexd-0.43/unit/util.c
+===================================================================
+--- obexd-0.43.orig/unit/util.c	2011-12-21 18:24:49.000000000 -0500
++++ obexd-0.43/unit/util.c	2012-01-06 14:00:12.360087805 -0500
+@@ -87,7 +87,7 @@
+ 	GObexTransportType transport_type;
+ 	int sv[2];
+ 
+-	if (socketpair(AF_UNIX, sock_type | SOCK_NONBLOCK, 0, sv) < 0) {
++	if (socketpair(AF_UNIX, sock_type, 0, sv) < 0) {
+ 		g_printerr("socketpair: %s", strerror(errno));
+ 		abort();
+ 	}
diff -pruN 0.46-1/debian/rules 0.46-1ubuntu7/debian/rules
--- 0.46-1/debian/rules	2012-06-06 04:54:28.000000000 +0000
+++ 0.46-1ubuntu7/debian/rules	2014-04-10 13:36:32.000000000 +0000
@@ -8,5 +8,4 @@ include /usr/share/dpkg/buildflags.mk
 
 override_dh_auto_configure:
 	dh_auto_configure -- --enable-usb \
-			--enable-pcsuite \
-			--with-phonebook=ebook
+			--enable-pcsuite
diff -pruN 0.46-1/.pc/applied-patches 0.46-1ubuntu7/.pc/applied-patches
--- 0.46-1/.pc/applied-patches	2014-04-10 18:41:34.177012336 +0000
+++ 0.46-1ubuntu7/.pc/applied-patches	2014-04-10 18:41:34.405018332 +0000
@@ -1 +1,5 @@
 Remove_left_over_glib-helper.h_support.patch
+test-may-block.patch
+includes.diff
+test-avoid-double-source-removals.patch
+backport_session_code.patch
diff -pruN 0.46-1/.pc/backport_session_code.patch/client/bluetooth.c 0.46-1ubuntu7/.pc/backport_session_code.patch/client/bluetooth.c
--- 0.46-1/.pc/backport_session_code.patch/client/bluetooth.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/.pc/backport_session_code.patch/client/bluetooth.c	2012-05-17 15:12:17.000000000 +0000
@@ -0,0 +1,665 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  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 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 <inttypes.h>
+
+#include <glib.h>
+#include <gdbus.h>
+#include <btio.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "log.h"
+#include "transport.h"
+#include "bluetooth.h"
+
+#define BT_BUS_NAME		"org.bluez"
+#define BT_PATH			"/"
+#define BT_ADAPTER_IFACE	"org.bluez.Adapter"
+#define BT_MANAGER_IFACE	"org.bluez.Manager"
+
+#define BT_RX_MTU 32767
+#define BT_TX_MTU 32767
+
+#define OBC_BT_ERROR obc_bt_error_quark()
+
+struct bluetooth_session {
+	guint id;
+	bdaddr_t src;
+	bdaddr_t dst;
+	uint16_t port;
+	DBusConnection *conn; /* system bus connection */
+	sdp_session_t *sdp;
+	GIOChannel *io;
+	GSList *pending_calls;
+	char *adapter;
+	char *service;
+	obc_transport_func func;
+	void *user_data;
+};
+
+static GSList *sessions = NULL;
+
+static GQuark obc_bt_error_quark(void)
+{
+	return g_quark_from_static_string("obc-bluetooth-error-quark");
+}
+
+static int send_method_call(struct bluetooth_session *session,
+					const char *path,
+					const char *interface,
+					const char *method,
+					DBusPendingCallNotifyFunction cb,
+					int type, ...)
+{
+	DBusMessage *msg;
+	DBusPendingCall *call;
+	va_list args;
+
+	msg = dbus_message_new_method_call(BT_BUS_NAME, path, interface,
+								method);
+	if (!msg) {
+		error("Unable to allocate new D-Bus %s message", method);
+		return -ENOMEM;
+	}
+
+	va_start(args, type);
+
+	if (!dbus_message_append_args_valist(msg, type, args)) {
+		dbus_message_unref(msg);
+		va_end(args);
+		return -EINVAL;
+	}
+
+	va_end(args);
+
+	if (!cb) {
+		g_dbus_send_message(session->conn, msg);
+		return 0;
+	}
+
+	if (!dbus_connection_send_with_reply(session->conn, msg, &call, -1)) {
+		error("Sending %s failed", method);
+		dbus_message_unref(msg);
+		return -EIO;
+	}
+
+	dbus_pending_call_set_notify(call, cb, session, NULL);
+
+	session->pending_calls = g_slist_prepend(session->pending_calls, call);
+
+	return 0;
+}
+
+static void finalize_call(DBusPendingCall *call)
+{
+	if (!dbus_pending_call_get_completed(call))
+		dbus_pending_call_cancel(call);
+
+	dbus_pending_call_unref(call);
+}
+
+static void session_destroy(struct bluetooth_session *session)
+{
+	GSList *l;
+
+	DBG("%p", session);
+
+	if (g_slist_find(sessions, session) == NULL)
+		return;
+
+	sessions = g_slist_remove(sessions, session);
+
+	if (session->adapter)
+		send_method_call(session, session->adapter, BT_ADAPTER_IFACE,
+						"ReleaseSession", NULL,
+						DBUS_TYPE_INVALID);
+
+	l = session->pending_calls;
+
+	while (l) {
+		DBusPendingCall *call = l->data;
+		l = l->next;
+
+		session->pending_calls = g_slist_remove(session->pending_calls, call);
+		finalize_call(call);
+	}
+
+	if (session->io != NULL) {
+		g_io_channel_shutdown(session->io, TRUE, NULL);
+		g_io_channel_unref(session->io);
+	}
+
+	if (session->conn)
+		dbus_connection_unref(session->conn);
+
+	g_free(session->service);
+	g_free(session->adapter);
+	g_free(session);
+}
+
+static void transport_callback(GIOChannel *io, GError *err, gpointer user_data)
+{
+	struct bluetooth_session *session = user_data;
+
+	DBG("");
+
+	if (session->func)
+		session->func(io, err, session->user_data);
+
+	if (err != NULL)
+		session_destroy(session);
+}
+
+static GIOChannel *transport_connect(const bdaddr_t *src, const bdaddr_t *dst,
+					uint16_t port, BtIOConnect function,
+					gpointer user_data)
+{
+	GIOChannel *io;
+	GError *err = NULL;
+
+	DBG("port %u", port);
+
+	if (port > 31) {
+		io = bt_io_connect(BT_IO_L2CAP, function, user_data,
+				NULL, &err,
+				BT_IO_OPT_SOURCE_BDADDR, src,
+				BT_IO_OPT_DEST_BDADDR, dst,
+				BT_IO_OPT_PSM, port,
+				BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+				BT_IO_OPT_OMTU, BT_TX_MTU,
+				BT_IO_OPT_IMTU, BT_RX_MTU,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	} else {
+		io = bt_io_connect(BT_IO_RFCOMM, function, user_data,
+				NULL, &err,
+				BT_IO_OPT_SOURCE_BDADDR, src,
+				BT_IO_OPT_DEST_BDADDR, dst,
+				BT_IO_OPT_CHANNEL, port,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	}
+
+	if (io != NULL)
+		return io;
+
+	error("%s", err->message);
+	g_error_free(err);
+	return NULL;
+}
+
+static void search_callback(uint8_t type, uint16_t status,
+			uint8_t *rsp, size_t size, void *user_data)
+{
+	struct bluetooth_session *session = user_data;
+	unsigned int scanned, bytesleft = size;
+	int seqlen = 0;
+	uint8_t dataType;
+	uint16_t port = 0;
+	GError *gerr = NULL;
+
+	if (status || type != SDP_SVC_SEARCH_ATTR_RSP)
+		goto failed;
+
+	scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
+	if (!scanned || !seqlen)
+		goto failed;
+
+	rsp += scanned;
+	bytesleft -= scanned;
+	do {
+		sdp_record_t *rec;
+		sdp_list_t *protos;
+		sdp_data_t *data;
+		int recsize, ch = -1;
+
+		recsize = 0;
+		rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
+		if (!rec)
+			break;
+
+		if (!recsize) {
+			sdp_record_free(rec);
+			break;
+		}
+
+		if (!sdp_get_access_protos(rec, &protos)) {
+			ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+			sdp_list_foreach(protos,
+					(sdp_list_func_t) sdp_list_free, NULL);
+			sdp_list_free(protos, NULL);
+			protos = NULL;
+		}
+
+		data = sdp_data_get(rec, 0x0200);
+		/* PSM must be odd and lsb of upper byte must be 0 */
+		if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001)
+			ch = data->val.uint16;
+
+		sdp_record_free(rec);
+
+		if (ch > 0) {
+			port = ch;
+			break;
+		}
+
+		scanned += recsize;
+		rsp += recsize;
+		bytesleft -= recsize;
+	} while (scanned < size && bytesleft > 0);
+
+	if (port == 0)
+		goto failed;
+
+	session->port = port;
+
+	g_io_channel_set_close_on_unref(session->io, FALSE);
+	g_io_channel_unref(session->io);
+
+	session->io = transport_connect(&session->src, &session->dst, port,
+						transport_callback, session);
+	if (session->io != NULL) {
+		sdp_close(session->sdp);
+		session->sdp = NULL;
+		return;
+	}
+
+failed:
+	if (session->io != NULL) {
+		g_io_channel_shutdown(session->io, TRUE, NULL);
+		g_io_channel_unref(session->io);
+		session->io = NULL;
+	}
+
+	g_set_error(&gerr, OBC_BT_ERROR, -EIO,
+					"Unable to find service record");
+	if (session->func)
+		session->func(session->io, gerr, session->user_data);
+
+	g_clear_error(&gerr);
+
+	session_destroy(session);
+}
+
+static gboolean process_callback(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct bluetooth_session *session = user_data;
+
+	if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+		return FALSE;
+
+	if (sdp_process(session->sdp) < 0)
+		return FALSE;
+
+	return TRUE;
+}
+
+static int bt_string2uuid(uuid_t *uuid, const char *string)
+{
+	uint32_t data0, data4;
+	uint16_t data1, data2, data3, data5;
+
+	if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
+				&data0, &data1, &data2, &data3, &data4, &data5) == 6) {
+		uint8_t val[16];
+
+		data0 = g_htonl(data0);
+		data1 = g_htons(data1);
+		data2 = g_htons(data2);
+		data3 = g_htons(data3);
+		data4 = g_htonl(data4);
+		data5 = g_htons(data5);
+
+		memcpy(&val[0], &data0, 4);
+		memcpy(&val[4], &data1, 2);
+		memcpy(&val[6], &data2, 2);
+		memcpy(&val[8], &data3, 2);
+		memcpy(&val[10], &data4, 4);
+		memcpy(&val[14], &data5, 2);
+
+		sdp_uuid128_create(uuid, val);
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static gboolean service_callback(GIOChannel *io, GIOCondition cond,
+							gpointer user_data)
+{
+	struct bluetooth_session *session = user_data;
+	sdp_list_t *search, *attrid;
+	uint32_t range = 0x0000ffff;
+	GError *gerr = NULL;
+	uuid_t uuid;
+
+	if (cond & G_IO_NVAL)
+		return FALSE;
+
+	if (cond & G_IO_ERR)
+		goto failed;
+
+	if (sdp_set_notify(session->sdp, search_callback, session) < 0)
+		goto failed;
+
+	if (bt_string2uuid(&uuid, session->service) < 0)
+		goto failed;
+
+	search = sdp_list_append(NULL, &uuid);
+	attrid = sdp_list_append(NULL, &range);
+
+	if (sdp_service_search_attr_async(session->sdp,
+				search, SDP_ATTR_REQ_RANGE, attrid) < 0) {
+		sdp_list_free(attrid, NULL);
+		sdp_list_free(search, NULL);
+		goto failed;
+	}
+
+	sdp_list_free(attrid, NULL);
+	sdp_list_free(search, NULL);
+
+	g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+						process_callback, session);
+
+	return FALSE;
+
+failed:
+	g_io_channel_shutdown(session->io, TRUE, NULL);
+	g_io_channel_unref(session->io);
+	session->io = NULL;
+
+	g_set_error(&gerr, OBC_BT_ERROR, -EIO,
+					"Unable to find service record");
+	if (session->func)
+		session->func(session->io, gerr, session->user_data);
+	g_clear_error(&gerr);
+
+	session_destroy(session);
+	return FALSE;
+}
+
+static sdp_session_t *service_connect(const bdaddr_t *src, const bdaddr_t *dst,
+					GIOFunc function, gpointer user_data)
+{
+	struct bluetooth_session *session = user_data;
+	sdp_session_t *sdp;
+	GIOChannel *io;
+
+	sdp = sdp_connect(src, dst, SDP_NON_BLOCKING);
+	if (sdp == NULL)
+		return NULL;
+
+	io = g_io_channel_unix_new(sdp_get_socket(sdp));
+	if (io == NULL) {
+		sdp_close(sdp);
+		return NULL;
+	}
+
+	g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+							function, user_data);
+
+	session->io = io;
+
+	return sdp;
+}
+
+static int session_connect(struct bluetooth_session *session)
+{
+	int err;
+
+	if (session->port > 0) {
+		session->io = transport_connect(&session->src, &session->dst,
+							session->port,
+							transport_callback,
+							session);
+		err = (session->io == NULL) ? -EINVAL : 0;
+	} else {
+		session->sdp = service_connect(&session->src, &session->dst,
+						service_callback, session);
+		err = (session->sdp == NULL) ? -ENOMEM : 0;
+	}
+
+	return err;
+}
+
+static void adapter_reply(DBusPendingCall *call, void *user_data)
+{
+	struct bluetooth_session *session = user_data;
+	DBusError err;
+	DBusMessage *reply;
+	GError *gerr = NULL;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	session->pending_calls = g_slist_remove(session->pending_calls, call);
+	finalize_call(call);
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("manager replied with an error: %s, %s",
+				err.name, err.message);
+		dbus_error_free(&err);
+
+		goto failed;
+	}
+
+	if (session_connect(session) == 0)
+		goto proceed;
+
+failed:
+	g_set_error(&gerr, OBC_BT_ERROR, -EINVAL,
+					"Unable to request session");
+	if (session->func)
+		session->func(session->io, gerr, session->user_data);
+	g_clear_error(&gerr);
+
+	session_destroy(session);
+
+proceed:
+	dbus_message_unref(reply);
+}
+
+static int request_session(struct bluetooth_session *session, const char *adapter)
+{
+	session->adapter = g_strdup(adapter);
+	return send_method_call(session, adapter, BT_ADAPTER_IFACE,
+					"RequestSession", adapter_reply,
+					DBUS_TYPE_INVALID);
+}
+
+static void manager_reply(DBusPendingCall *call, void *user_data)
+{
+	struct bluetooth_session *session = user_data;
+	DBusError err;
+	DBusMessage *reply;
+	char *adapter;
+	GError *gerr = NULL;
+
+	reply = dbus_pending_call_steal_reply(call);
+
+	session->pending_calls = g_slist_remove(session->pending_calls, call);
+	finalize_call(call);
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		error("manager replied with an error: %s, %s",
+				err.name, err.message);
+		dbus_error_free(&err);
+
+		goto failed;
+	}
+
+	if (!dbus_message_get_args(reply, NULL,
+				DBUS_TYPE_OBJECT_PATH, &adapter,
+				DBUS_TYPE_INVALID))
+		goto failed;
+
+	DBG("adapter path %s", adapter);
+
+	if (request_session(session, adapter) == 0)
+		goto proceed;
+
+failed:
+	g_set_error(&gerr, OBC_BT_ERROR, -EINVAL, "No adapter found");
+	if (session->func)
+		session->func(session->io, gerr, session->user_data);
+	g_clear_error(&gerr);
+
+	session_destroy(session);
+
+proceed:
+	dbus_message_unref(reply);
+}
+
+static int find_adapter(struct bluetooth_session *session, const char *source)
+{
+	if (source == NULL) {
+		bacpy(&session->src, BDADDR_ANY);
+		return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
+					"DefaultAdapter", manager_reply,
+					DBUS_TYPE_INVALID);
+	}
+
+	str2ba(source, &session->src);
+	return send_method_call(session, BT_PATH, BT_MANAGER_IFACE,
+					"FindAdapter", manager_reply,
+					DBUS_TYPE_STRING, &source,
+					DBUS_TYPE_INVALID);
+}
+
+static guint bluetooth_connect(const char *source, const char *destination,
+				const char *service, uint16_t port,
+				obc_transport_func func, void *user_data)
+{
+	struct bluetooth_session *session;
+	static guint id = 0;
+
+	DBG("");
+
+	if (destination == NULL)
+		return 0;
+
+	session = g_try_malloc0(sizeof(*session));
+	if (session == NULL)
+		return 0;
+
+	session->id = ++id;
+	session->func = func;
+	session->user_data = user_data;
+
+	session->conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+	if (session->conn == NULL) {
+		g_free(session);
+		return 0;
+	}
+
+	session->service = g_strdup(service);
+	str2ba(destination, &session->dst);
+
+	if (find_adapter(session, source) < 0) {
+		g_free(session);
+		return 0;
+	}
+
+	sessions = g_slist_prepend(sessions, session);
+
+	return session->id;
+}
+
+static void bluetooth_disconnect(guint id)
+{
+	GSList *l;
+
+	DBG("");
+
+	for (l = sessions; l; l = l->next) {
+		struct bluetooth_session *session = l->data;
+
+		if (session->id == id) {
+			session_destroy(session);
+			return;
+		}
+	}
+}
+
+static int bluetooth_getpacketopt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
+{
+	int sk = g_io_channel_unix_get_fd(io);
+	int type;
+	int omtu = -1;
+	int imtu = -1;
+	socklen_t len = sizeof(int);
+
+	DBG("");
+
+	if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+		return -errno;
+
+	if (type != SOCK_SEQPACKET)
+		return -EINVAL;
+
+	if (!bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_OMTU, &omtu,
+						BT_IO_OPT_IMTU, &imtu,
+						BT_IO_OPT_INVALID))
+		return -EINVAL;
+
+	if (tx_mtu)
+		*tx_mtu = omtu;
+
+	if (rx_mtu)
+		*rx_mtu = imtu;
+
+	return 0;
+}
+
+static struct obc_transport bluetooth = {
+	.name = "Bluetooth",
+	.connect = bluetooth_connect,
+	.getpacketopt = bluetooth_getpacketopt,
+	.disconnect = bluetooth_disconnect,
+};
+
+int bluetooth_init(void)
+{
+	DBG("");
+
+	return obc_transport_register(&bluetooth);
+}
+
+void bluetooth_exit(void)
+{
+	DBG("");
+
+	obc_transport_unregister(&bluetooth);
+}
diff -pruN 0.46-1/.pc/includes.diff/plugins/filesystem.h 0.46-1ubuntu7/.pc/includes.diff/plugins/filesystem.h
--- 0.46-1/.pc/includes.diff/plugins/filesystem.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/.pc/includes.diff/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/includes.diff/src/mimetype.h 0.46-1ubuntu7/.pc/includes.diff/src/mimetype.h
--- 0.46-1/.pc/includes.diff/src/mimetype.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/.pc/includes.diff/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/includes.diff/src/obex.h 0.46-1ubuntu7/.pc/includes.diff/src/obex.h
--- 0.46-1/.pc/includes.diff/src/obex.h	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/.pc/includes.diff/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/test-avoid-double-source-removals.patch/unit/test-gobex.c 0.46-1ubuntu7/.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.46-1ubuntu7/.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.46-1ubuntu7/.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.46-1ubuntu7/.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.46-1ubuntu7/.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.46-1ubuntu7/.pc/test-avoid-double-source-removals.patch/unit/util.c	2014-04-10 18:41:34.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, 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.46-1ubuntu7/.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.46-1ubuntu7/.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/.pc/test-may-block.patch/unit/util.c 0.46-1ubuntu7/.pc/test-may-block.patch/unit/util.c
--- 0.46-1/.pc/test-may-block.patch/unit/util.c	1970-01-01 00:00:00.000000000 +0000
+++ 0.46-1ubuntu7/.pc/test-may-block.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/plugins/filesystem.h 0.46-1ubuntu7/plugins/filesystem.h
--- 0.46-1/plugins/filesystem.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/plugins/filesystem.h	2014-04-10 18:41:34.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/src/mimetype.h 0.46-1ubuntu7/src/mimetype.h
--- 0.46-1/src/mimetype.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/src/mimetype.h	2014-04-10 18:41:34.000000000 +0000
@@ -21,6 +21,8 @@
  *
  */
 
+#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.h 0.46-1ubuntu7/src/obex.h
--- 0.46-1/src/obex.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/src/obex.h	2014-04-10 18:41:34.000000000 +0000
@@ -22,6 +22,8 @@
  *
  */
 
+#include <sys/types.h>
+
 #define OBJECT_SIZE_UNKNOWN -1
 #define OBJECT_SIZE_DELETE -2
 
diff -pruN 0.46-1/unit/test-gobex.c 0.46-1ubuntu7/unit/test-gobex.c
--- 0.46-1/unit/test-gobex.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/unit/test-gobex.c	2014-04-10 18:41:34.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-transfer.c 0.46-1ubuntu7/unit/test-gobex-transfer.c
--- 0.46-1/unit/test-gobex-transfer.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/unit/test-gobex-transfer.c	2014-04-10 18:41:34.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.46-1ubuntu7/unit/util.c
--- 0.46-1/unit/util.c	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/unit/util.c	2014-04-10 18:41:34.000000000 +0000
@@ -87,7 +87,7 @@ void create_endpoints(GObex **obex, GIOC
 	GObexTransportType transport_type;
 	int sv[2];
 
-	if (socketpair(AF_UNIX, sock_type | SOCK_NONBLOCK, 0, sv) < 0) {
+	if (socketpair(AF_UNIX, sock_type, 0, sv) < 0) {
 		g_printerr("socketpair: %s", strerror(errno));
 		abort();
 	}
@@ -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.46-1ubuntu7/unit/util.h
--- 0.46-1/unit/util.h	2012-05-17 15:12:17.000000000 +0000
+++ 0.46-1ubuntu7/unit/util.h	2014-04-10 18:41:34.000000000 +0000
@@ -41,6 +41,7 @@ struct test_data {
 	guint id;
 	gsize total;
 	GMainLoop *mainloop;
+	gboolean io_completed;
 };
 
 #define TEST_ERROR test_error_quark()
