[meego-commits] 6239: Changes to Trunk/obexd

Peter Zhu peter.j.zhu at intel.com
Wed Aug 4 03:25:15 UTC 2010


Hi,
I have made the following changes to obexd in project Trunk. Please review and accept ASAP.

Thank You,
Peter Zhu

[This message was auto-generated]

---

Request #6239:

  submit:   Trunk:Testing/obexd(r11) -> Trunk/obexd


Message:
    Move to Trunk

State:   new          2010-08-03T15:17:35 peter
Comment: None



changes files:
--------------
--- obexd.changes
+++ obexd.changes
@@ -0,0 +1,3 @@
+* Fri Jul 30 2010 Zhu Yanhai <yanhai.zhu at linux.intel.com> - 0.29
+- Upgrade to 0.29.
+

old:
----
  obexd-0.26.tar.gz

new:
----
  obexd-0.29.tar.gz

spec files:
-----------
--- obexd.spec
+++ obexd.spec
@@ -7,7 +7,7 @@
 
 Name:       obexd
 Summary:    D-Bus service for Obex Client access
-Version:    0.26
+Version:    0.29
 Release:    1
 Group:      System/Daemons
 License:    GPLv2+

other changes:
--------------

++++++ obexd-0.26.tar.gz -> obexd-0.29.tar.gz
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,35 @@
+ver 0.29:
+	Fix security requirements for legacy devices.
+	Fix empty 'N:' parameter handling for vCards.
+	Fix order of contacts in the combined calls folder.
+	Fix not replying error when transfer could not be started.
+	Fix not unregistering transfer when completed.
+	Fix memory leak when freeing transfer parameters.
+	Fix issues with handling of driver reset.
+	Add support for responding to Auth Challenge.
+	Add support for dynamic debug feature.
+
+ver 0.28:
+	Fix broken assumption about contacts.
+	Fix issue with exporting empty contacts.
+	Fix issue with not always including the TEL header.
+	Fix wrong response code for PBAP PUT operation.
+	Fix handling of Tracker optional parameters.
+	Fix queries for incoming and outgoing folders.
+	Fix ordering during folder listing.
+	Fix complex logic discovering the type of call.
+	Add support for the X-IRMC-CALL-DATETIME field.
+
+ver 0.27:
+	Fix GET name handling with FTP service.
+	Fix service driver matching when who is not specified.
+	Fix object name not being updated when agent changes it.
+	Fix inconsistency when using vCard version 2.1.
+	Fix wrong response code to PUT requests for PBAP.
+	Fix crash on PBAP SetPhoneBook function.
+	Add support for transport drivers.
+	Add support for Nokia backup plugin.
+
 ver 0.26:
 	Fix the order of the calls handles.
 	Fix crash when receiving small objects.
--- Makefile.am
+++ Makefile.am
@@ -29,9 +29,22 @@
 builtin_sources =
 builtin_nodist =
 
+builtin_modules += bluetooth
+builtin_sources += plugins/bluetooth.c
+
+if USB
+builtin_modules += usb
+builtin_sources += plugins/usb.c
+endif
+
 builtin_modules += filesystem
 builtin_sources += plugins/filesystem.c plugins/filesystem.h
 
+if NOKIA_BACKUP
+builtin_modules += backup
+builtin_sources += plugins/nokia-backup.c
+endif
+
 builtin_modules += opp
 builtin_sources += plugins/opp.c
 
@@ -51,11 +64,13 @@
 
 src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) \
 			src/main.c src/obexd.h src/plugin.h src/plugin.c \
-			src/logging.h src/logging.c src/btio.h src/btio.c \
+			src/log.h src/log.c src/btio.h src/btio.c \
 			src/dbus.h src/manager.c src/obex.h src/obex.c \
-			src/obex-priv.h src/bluetooth.h src/bluetooth.c \
+			src/obex-priv.h \
 			src/mimetype.h src/mimetype.c \
-			src/service.h src/service.c
+			src/service.h src/service.c \
+			src/transport.h src/transport.c \
+			src/server.h src/server.c
 
 src_obexd_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @GTHREAD_LIBS@ \
 					@EBOOK_LIBS@ @OPENOBEX_LIBS@ \
@@ -91,10 +106,11 @@
 
 client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) client/main.c \
 				client/session.h client/session.c \
-				src/logging.h src/logging.c \
+				src/log.h src/log.c \
 				client/pbap.h client/pbap.c \
 				client/sync.h client/sync.c \
-				client/transfer.h client/transfer.c
+				client/transfer.h client/transfer.c \
+				src/btio.c src/btio.h
 
 client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @OPENOBEX_LIBS@ @BLUEZ_LIBS@
 endif
--- Makefile.in
+++ Makefile.in
@@ -38,10 +38,14 @@
 host_triplet = @host@
 libexec_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
 @SERVER_TRUE at am__append_1 = src/obexd.service.in
- at SERVER_TRUE@am__append_2 = src/obexd
+ at SERVER_TRUE@@USB_TRUE at am__append_2 = usb
+ at SERVER_TRUE@@USB_TRUE at am__append_3 = plugins/usb.c
+ at NOKIA_BACKUP_TRUE@@SERVER_TRUE at am__append_4 = backup
+ at NOKIA_BACKUP_TRUE@@SERVER_TRUE at am__append_5 = plugins/nokia-backup.c
+ at SERVER_TRUE@am__append_6 = src/obexd
 @SERVER_TRUE at noinst_PROGRAMS = test/obex-test$(EXEEXT)
- at CLIENT_TRUE@am__append_3 = client/obex-client.service.in
- at CLIENT_TRUE@am__append_4 = client/obex-client
+ at CLIENT_TRUE@am__append_7 = client/obex-client.service.in
+ at CLIENT_TRUE@am__append_8 = client/obex-client
 subdir = .
 DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
 	$(srcdir)/Makefile.in $(srcdir)/config.h.in \
@@ -90,9 +94,10 @@
 	gdbus/object.c gdbus/watch.c gwobex/gw-obex.h gwobex/gw-obex.c \
 	gwobex/obex-priv.h gwobex/obex-priv.c gwobex/obex-xfer.h \
 	gwobex/obex-xfer.c gwobex/utils.h gwobex/utils.c gwobex/log.h \
-	client/main.c client/session.h client/session.c src/logging.h \
-	src/logging.c client/pbap.h client/pbap.c client/sync.h \
-	client/sync.c client/transfer.h client/transfer.c
+	client/main.c client/session.h client/session.c src/log.h \
+	src/log.c client/pbap.h client/pbap.c client/sync.h \
+	client/sync.c client/transfer.h client/transfer.c src/btio.c \
+	src/btio.h
 am__dirstamp = $(am__leading_dot)dirstamp
 am__objects_1 = gdbus/mainloop.$(OBJEXT) gdbus/object.$(OBJEXT) \
 	gdbus/watch.$(OBJEXT)
@@ -100,36 +105,42 @@
 	gwobex/obex-xfer.$(OBJEXT) gwobex/utils.$(OBJEXT)
 @CLIENT_TRUE at am_client_obex_client_OBJECTS = $(am__objects_1) \
 @CLIENT_TRUE@	$(am__objects_2) client/main.$(OBJEXT) \
- at CLIENT_TRUE@	client/session.$(OBJEXT) src/logging.$(OBJEXT) \
+ at CLIENT_TRUE@	client/session.$(OBJEXT) src/log.$(OBJEXT) \
 @CLIENT_TRUE@	client/pbap.$(OBJEXT) client/sync.$(OBJEXT) \
- at CLIENT_TRUE@	client/transfer.$(OBJEXT)
+ at CLIENT_TRUE@	client/transfer.$(OBJEXT) src/btio.$(OBJEXT)
 client_obex_client_OBJECTS = $(am_client_obex_client_OBJECTS)
 client_obex_client_DEPENDENCIES =
 AM_V_lt = $(am__v_lt_$(V))
 am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
 am__v_lt_0 = --silent
 am__src_obexd_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \
-	gdbus/object.c gdbus/watch.c plugins/filesystem.c \
-	plugins/filesystem.h plugins/opp.c plugins/ftp.c \
+	gdbus/object.c gdbus/watch.c plugins/bluetooth.c plugins/usb.c \
+	plugins/filesystem.c plugins/filesystem.h \
+	plugins/nokia-backup.c plugins/opp.c plugins/ftp.c \
 	plugins/pbap.c plugins/phonebook.h plugins/vcard.h \
 	plugins/vcard.c plugins/syncevolution.c src/main.c src/obexd.h \
-	src/plugin.h src/plugin.c src/logging.h src/logging.c \
-	src/btio.h src/btio.c src/dbus.h src/manager.c src/obex.h \
-	src/obex.c src/obex-priv.h src/bluetooth.h src/bluetooth.c \
-	src/mimetype.h src/mimetype.c src/service.h src/service.c
- at SERVER_TRUE@am__objects_3 = plugins/filesystem.$(OBJEXT) \
- at SERVER_TRUE@	plugins/opp.$(OBJEXT) plugins/ftp.$(OBJEXT) \
- at SERVER_TRUE@	plugins/pbap.$(OBJEXT) plugins/vcard.$(OBJEXT) \
+	src/plugin.h src/plugin.c src/log.h src/log.c src/btio.h \
+	src/btio.c src/dbus.h src/manager.c src/obex.h src/obex.c \
+	src/obex-priv.h src/mimetype.h src/mimetype.c src/service.h \
+	src/service.c src/transport.h src/transport.c src/server.h \
+	src/server.c
+ at SERVER_TRUE@@USB_TRUE at am__objects_3 = plugins/usb.$(OBJEXT)
+ at NOKIA_BACKUP_TRUE@@SERVER_TRUE at am__objects_4 = plugins/nokia-backup.$(OBJEXT)
+ at SERVER_TRUE@am__objects_5 = plugins/bluetooth.$(OBJEXT) \
+ at SERVER_TRUE@	$(am__objects_3) plugins/filesystem.$(OBJEXT) \
+ at SERVER_TRUE@	$(am__objects_4) plugins/opp.$(OBJEXT) \
+ at SERVER_TRUE@	plugins/ftp.$(OBJEXT) plugins/pbap.$(OBJEXT) \
+ at SERVER_TRUE@	plugins/vcard.$(OBJEXT) \
 @SERVER_TRUE@	plugins/syncevolution.$(OBJEXT)
- at SERVER_TRUE@am_src_obexd_OBJECTS = $(am__objects_1) $(am__objects_3) \
+ at SERVER_TRUE@am_src_obexd_OBJECTS = $(am__objects_1) $(am__objects_5) \
 @SERVER_TRUE@	src/main.$(OBJEXT) src/plugin.$(OBJEXT) \
- at SERVER_TRUE@	src/logging.$(OBJEXT) src/btio.$(OBJEXT) \
+ at SERVER_TRUE@	src/log.$(OBJEXT) src/btio.$(OBJEXT) \
 @SERVER_TRUE@	src/manager.$(OBJEXT) src/obex.$(OBJEXT) \
- at SERVER_TRUE@	src/bluetooth.$(OBJEXT) src/mimetype.$(OBJEXT) \
- at SERVER_TRUE@	src/service.$(OBJEXT)
- at SERVER_TRUE@am__objects_4 = plugins/phonebook.$(OBJEXT)
- at SERVER_TRUE@am__objects_5 = $(am__objects_4)
- at SERVER_TRUE@nodist_src_obexd_OBJECTS = $(am__objects_5)
+ at SERVER_TRUE@	src/mimetype.$(OBJEXT) src/service.$(OBJEXT) \
+ at SERVER_TRUE@	src/transport.$(OBJEXT) src/server.$(OBJEXT)
+ at SERVER_TRUE@am__objects_6 = plugins/phonebook.$(OBJEXT)
+ at SERVER_TRUE@am__objects_7 = $(am__objects_6)
+ at SERVER_TRUE@nodist_src_obexd_OBJECTS = $(am__objects_7)
 src_obexd_OBJECTS = $(am_src_obexd_OBJECTS) \
 	$(nodist_src_obexd_OBJECTS)
 src_obexd_DEPENDENCIES =
@@ -319,7 +330,7 @@
 top_srcdir = @top_srcdir@
 AM_MAKEFLAGS = --no-print-directory
 servicedir = $(datarootdir)/dbus-1/services
-service_in_files = $(am__append_1) $(am__append_3)
+service_in_files = $(am__append_1) $(am__append_7)
 doc_files = doc/obexd-api.txt doc/agent-api.txt doc/client-api.txt
 test_files = test/simple-agent test/send-files \
 		test/pull-business-card test/exchange-business-cards \
@@ -332,20 +343,24 @@
 			gwobex/utils.h gwobex/utils.c gwobex/log.h
 
 @SERVER_TRUE at confdir = $(sysconfdir)/obex
- at SERVER_TRUE@builtin_modules = filesystem opp ftp pbap syncevolution
- at SERVER_TRUE@builtin_sources = plugins/filesystem.c \
- at SERVER_TRUE@	plugins/filesystem.h plugins/opp.c plugins/ftp.c \
+ at SERVER_TRUE@builtin_modules = bluetooth $(am__append_2) filesystem \
+ at SERVER_TRUE@	$(am__append_4) opp ftp pbap syncevolution
+ at SERVER_TRUE@builtin_sources = plugins/bluetooth.c $(am__append_3) \
+ at SERVER_TRUE@	plugins/filesystem.c plugins/filesystem.h \
+ at SERVER_TRUE@	$(am__append_5) plugins/opp.c plugins/ftp.c \
 @SERVER_TRUE@	plugins/pbap.c plugins/phonebook.h \
 @SERVER_TRUE@	plugins/vcard.h plugins/vcard.c \
 @SERVER_TRUE@	plugins/syncevolution.c
 @SERVER_TRUE at builtin_nodist = plugins/phonebook.c
 @SERVER_TRUE at src_obexd_SOURCES = $(gdbus_sources) $(builtin_sources) \
 @SERVER_TRUE@			src/main.c src/obexd.h src/plugin.h src/plugin.c \
- at SERVER_TRUE@			src/logging.h src/logging.c src/btio.h src/btio.c \
+ at SERVER_TRUE@			src/log.h src/log.c src/btio.h src/btio.c \
 @SERVER_TRUE@			src/dbus.h src/manager.c src/obex.h src/obex.c \
- at SERVER_TRUE@			src/obex-priv.h src/bluetooth.h src/bluetooth.c \
+ at SERVER_TRUE@			src/obex-priv.h \
 @SERVER_TRUE@			src/mimetype.h src/mimetype.c \
- at SERVER_TRUE@			src/service.h src/service.c
+ at SERVER_TRUE@			src/service.h src/service.c \
+ at SERVER_TRUE@			src/transport.h src/transport.c \
+ at SERVER_TRUE@			src/server.h src/server.c
 
 @SERVER_TRUE at src_obexd_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @GTHREAD_LIBS@ \
 @SERVER_TRUE@					@EBOOK_LIBS@ @OPENOBEX_LIBS@ \
@@ -360,10 +375,11 @@
 @SERVER_TRUE at test_obex_test_LDADD = @OPENOBEX_LIBS@ @BLUEZ_LIBS@ @GLIB_LIBS@
 @CLIENT_TRUE at client_obex_client_SOURCES = $(gdbus_sources) $(gwobex_sources) client/main.c \
 @CLIENT_TRUE@				client/session.h client/session.c \
- at CLIENT_TRUE@				src/logging.h src/logging.c \
+ at CLIENT_TRUE@				src/log.h src/log.c \
 @CLIENT_TRUE@				client/pbap.h client/pbap.c \
 @CLIENT_TRUE@				client/sync.h client/sync.c \
- at CLIENT_TRUE@				client/transfer.h client/transfer.c
+ at CLIENT_TRUE@				client/transfer.h client/transfer.c \
+ at CLIENT_TRUE@				src/btio.c src/btio.h
 
 @CLIENT_TRUE at client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @OPENOBEX_LIBS@ @BLUEZ_LIBS@
 service_DATA = $(service_in_files:.service.in=.service)
@@ -567,14 +583,14 @@
 src/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) src/$(DEPDIR)
 	@: > src/$(DEPDIR)/$(am__dirstamp)
-src/logging.$(OBJEXT): src/$(am__dirstamp) \
-	src/$(DEPDIR)/$(am__dirstamp)
+src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 client/pbap.$(OBJEXT): client/$(am__dirstamp) \
 	client/$(DEPDIR)/$(am__dirstamp)
 client/sync.$(OBJEXT): client/$(am__dirstamp) \
 	client/$(DEPDIR)/$(am__dirstamp)
 client/transfer.$(OBJEXT): client/$(am__dirstamp) \
 	client/$(DEPDIR)/$(am__dirstamp)
+src/btio.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 client/obex-client$(EXEEXT): $(client_obex_client_OBJECTS) $(client_obex_client_DEPENDENCIES) client/$(am__dirstamp)
 	@rm -f client/obex-client$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(client_obex_client_OBJECTS) $(client_obex_client_LDADD) $(LIBS)
@@ -584,8 +600,14 @@
 plugins/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) plugins/$(DEPDIR)
 	@: > plugins/$(DEPDIR)/$(am__dirstamp)
+plugins/bluetooth.$(OBJEXT): plugins/$(am__dirstamp) \
+	plugins/$(DEPDIR)/$(am__dirstamp)
+plugins/usb.$(OBJEXT): plugins/$(am__dirstamp) \
+	plugins/$(DEPDIR)/$(am__dirstamp)
 plugins/filesystem.$(OBJEXT): plugins/$(am__dirstamp) \
 	plugins/$(DEPDIR)/$(am__dirstamp)
+plugins/nokia-backup.$(OBJEXT): plugins/$(am__dirstamp) \
+	plugins/$(DEPDIR)/$(am__dirstamp)
 plugins/opp.$(OBJEXT): plugins/$(am__dirstamp) \
 	plugins/$(DEPDIR)/$(am__dirstamp)
 plugins/ftp.$(OBJEXT): plugins/$(am__dirstamp) \
@@ -599,16 +621,17 @@
 src/main.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/plugin.$(OBJEXT): src/$(am__dirstamp) \
 	src/$(DEPDIR)/$(am__dirstamp)
-src/btio.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
 src/manager.$(OBJEXT): src/$(am__dirstamp) \
 	src/$(DEPDIR)/$(am__dirstamp)
 src/obex.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
-src/bluetooth.$(OBJEXT): src/$(am__dirstamp) \
-	src/$(DEPDIR)/$(am__dirstamp)
 src/mimetype.$(OBJEXT): src/$(am__dirstamp) \
 	src/$(DEPDIR)/$(am__dirstamp)
 src/service.$(OBJEXT): src/$(am__dirstamp) \
 	src/$(DEPDIR)/$(am__dirstamp)
+src/transport.$(OBJEXT): src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/server.$(OBJEXT): src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
 plugins/phonebook.$(OBJEXT): plugins/$(am__dirstamp) \
 	plugins/$(DEPDIR)/$(am__dirstamp)
 src/obexd$(EXEEXT): $(src_obexd_OBJECTS) $(src_obexd_DEPENDENCIES) src/$(am__dirstamp)
@@ -640,22 +663,26 @@
 	-rm -f gwobex/obex-priv.$(OBJEXT)
 	-rm -f gwobex/obex-xfer.$(OBJEXT)
 	-rm -f gwobex/utils.$(OBJEXT)
+	-rm -f plugins/bluetooth.$(OBJEXT)
 	-rm -f plugins/filesystem.$(OBJEXT)
 	-rm -f plugins/ftp.$(OBJEXT)
+	-rm -f plugins/nokia-backup.$(OBJEXT)
 	-rm -f plugins/opp.$(OBJEXT)
 	-rm -f plugins/pbap.$(OBJEXT)
 	-rm -f plugins/phonebook.$(OBJEXT)
 	-rm -f plugins/syncevolution.$(OBJEXT)
+	-rm -f plugins/usb.$(OBJEXT)
 	-rm -f plugins/vcard.$(OBJEXT)
-	-rm -f src/bluetooth.$(OBJEXT)
 	-rm -f src/btio.$(OBJEXT)
-	-rm -f src/logging.$(OBJEXT)
+	-rm -f src/log.$(OBJEXT)
 	-rm -f src/main.$(OBJEXT)
 	-rm -f src/manager.$(OBJEXT)
 	-rm -f src/mimetype.$(OBJEXT)
 	-rm -f src/obex.$(OBJEXT)
 	-rm -f src/plugin.$(OBJEXT)
+	-rm -f src/server.$(OBJEXT)
 	-rm -f src/service.$(OBJEXT)
+	-rm -f src/transport.$(OBJEXT)
 	-rm -f test/main.$(OBJEXT)
 
 distclean-compile:
@@ -673,22 +700,26 @@
 @AMDEP_TRUE@@am__include@ @am__quote at gwobex/$(DEPDIR)/obex-priv.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at gwobex/$(DEPDIR)/obex-xfer.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at gwobex/$(DEPDIR)/utils.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/bluetooth.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/filesystem.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/ftp.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/nokia-backup.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/opp.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/pbap.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/phonebook.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/syncevolution.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/usb.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at plugins/$(DEPDIR)/vcard.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/bluetooth.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/btio.Po at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/logging.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/log.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/main.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/manager.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/mimetype.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/obex.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/plugin.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/server.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/service.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/transport.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/main.Po at am__quote@
 
 .c.o:
--- client/main.c
+++ client/main.c
@@ -34,7 +34,7 @@
 #include <glib.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "transfer.h"
 #include "session.h"
 
@@ -544,12 +544,24 @@
 
 static GMainLoop *event_loop = NULL;
 
-static gboolean option_debug = FALSE;
+static char *option_debug = NULL;
 static gboolean option_stderr = FALSE;
 
+static gboolean parse_debug(const char *key, const char *value,
+				gpointer user_data, GError **error)
+{
+	if (value)
+		option_debug = g_strdup(value);
+	else
+		option_debug = g_strdup("*");
+
+	return TRUE;
+}
+
 static GOptionEntry options[] = {
-	{ "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
-				"Enable debug information output" },
+	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+				G_OPTION_ARG_CALLBACK, parse_debug,
+				"Enable debug information output", "DEBUG" },
 	{ "stderr", 's', 0, G_OPTION_ARG_NONE, &option_stderr,
 				"Write log information to stderr" },
 	{ NULL },
@@ -567,7 +579,6 @@
 	DBusConnection *conn;
 	DBusError derr;
 	GError *gerr = NULL;
-	int log_option;
 
 	context = g_option_context_new(NULL);
 	g_option_context_add_main_entries(context, options, NULL);
@@ -600,17 +611,9 @@
 
 	event_loop = g_main_loop_new(NULL, FALSE);
 
-	log_option = LOG_NDELAY | LOG_PID;
+	__obex_log_init(option_debug, !option_stderr);
 
-	if (option_stderr == TRUE)
-		log_option |= LOG_PERROR;
-
-	openlog("obex-client", log_option, LOG_DAEMON);
-
-	if (option_debug == TRUE) {
-		info("Enabling debug information");
-		enable_debug();
-	}
+	DBG("Entering main loop");
 
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_handler = sig_term;
@@ -625,5 +628,7 @@
 
 	g_main_loop_unref(event_loop);
 
+	__obex_log_cleanup();
+
 	return 0;
 }
--- client/pbap.c
+++ client/pbap.c
@@ -30,7 +30,7 @@
 #include <glib.h>
 #include <gdbus.h>
 
-#include "logging.h"
+#include "log.h"
 #include "transfer.h"
 #include "session.h"
 #include "pbap.h"
@@ -246,7 +246,7 @@
 	if (!path)
 		return OBEX_RSP_BAD_REQUEST;
 
-	if (pbapdata->path != NULL && 	g_str_equal(pbapdata->path, path))
+	if (pbapdata->path != NULL && g_str_equal(pbapdata->path, path))
 		return 0;
 
 	if (gw_obex_chdir(session->obex, "", &err) == FALSE) {
@@ -337,6 +337,9 @@
 	DBusMessage *reply;
 	char *buf = "";
 
+	if (session->msg == NULL)
+		goto done;
+
 	reply = dbus_message_new_method_return(session->msg);
 
 	if (transfer->filled > 0)
@@ -350,6 +353,9 @@
 	g_dbus_send_message(session->conn, reply);
 	dbus_message_unref(session->msg);
 	session->msg = NULL;
+
+done:
+	transfer_unregister(transfer);
 }
 
 static void phonebook_size_callback(struct session_data *session,
@@ -360,6 +366,9 @@
 	guint16 phone_book_size;
 	guint8 new_missed_calls;
 
+	if (session->msg == NULL)
+		goto done;
+
 	reply = dbus_message_new_method_return(session->msg);
 
 	read_return_apparam(session, &phone_book_size, &new_missed_calls);
@@ -372,6 +381,9 @@
 	g_dbus_send_message(session->conn, reply);
 	dbus_message_unref(session->msg);
 	session->msg = NULL;
+
+done:
+	transfer_unregister(transfer);
 }
 
 static void pull_vcard_listing_callback(struct session_data *session,
@@ -383,6 +395,9 @@
 	DBusMessageIter iter, array;
 	int i;
 
+	if (session->msg == NULL)
+		goto complete;
+
 	reply = dbus_message_new_method_return(session->msg);
 
 	if (transfer->filled == 0)
@@ -412,6 +427,8 @@
 	g_dbus_send_message(session->conn, reply);
 	dbus_message_unref(session->msg);
 	session->msg = NULL;
+complete:
+	transfer_unregister(transfer);
 }
 
 static DBusMessage *pull_phonebook(struct session_data *session,
@@ -710,7 +727,8 @@
 
 	if (!pbapdata->path)
 		return g_dbus_create_error(message,
-				ERROR_INF ".Forbidden", "Call Select first of all");
+				ERROR_INF ".Forbidden",
+				"Call Select first of all");
 
 	if (dbus_message_get_args(message, NULL,
 			DBUS_TYPE_STRING, &name,
--- client/session.c
+++ client/session.c
@@ -40,11 +40,12 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include "logging.h"
+#include "log.h"
 #include "pbap.h"
 #include "sync.h"
 #include "transfer.h"
 #include "session.h"
+#include "btio.h"
 
 #define AGENT_INTERFACE  "org.openobex.Agent"
 
@@ -71,7 +72,7 @@
 	void *data;
 };
 
-struct agent_pending {
+struct pending_data {
 	DBusPendingCall *call;
 	session_callback_t cb;
 	struct transfer_data *transfer;
@@ -81,7 +82,7 @@
 	char *name;
 	char *path;
 	guint watch;
-	struct agent_pending *pending;
+	struct pending_data *pending;
 };
 
 static void session_prepare_put(struct session_data *session, void *data);
@@ -90,12 +91,12 @@
 {
 	g_atomic_int_inc(&session->refcount);
 
-	debug("session_ref(%p): ref=%d", session, session->refcount);
+	DBG("%p: ref=%d", session, session->refcount);
 
 	return session;
 }
 
-static void free_pending(struct agent_pending *pending)
+static void free_pending(struct pending_data *pending)
 {
 	if (pending->call)
 		dbus_pending_call_unref(pending->call);
@@ -156,12 +157,12 @@
 	g_dbus_unregister_interface(session->conn, session->path,
 					SESSION_INTERFACE);
 
-	debug("Session(%p) unregistered %s", session, session->path);
+	DBG("Session(%p) unregistered %s", session, session->path);
 }
 
 static void session_free(struct session_data *session)
 {
-	debug("session_free(%p)", session);
+	DBG("%p", session);
 
 	if (session->agent)
 		agent_release(session);
@@ -194,7 +195,7 @@
 
 	ret = g_atomic_int_dec_and_test(&session->refcount);
 
-	debug("session_unref(%p): ref=%d", session, session->refcount);
+	DBG("%p: ref=%d", session, session->refcount);
 
 	if (ret == FALSE)
 		return;
@@ -202,16 +203,17 @@
 	session_free(session);
 }
 
-static gboolean rfcomm_callback(GIOChannel *io, GIOCondition cond,
-							gpointer user_data)
+static void rfcomm_callback(GIOChannel *io, GError *err, gpointer user_data)
 {
 	struct callback_data *callback = user_data;
 	struct session_data *session = callback->session;
 	GwObex *obex;
 	int fd;
 
-	if (cond & (G_IO_NVAL | G_IO_ERR))
+	if (err != NULL) {
+		error("%s", err->message);
 		goto done;
+	}
 
 	fd = g_io_channel_unix_get_fd(io);
 
@@ -227,63 +229,27 @@
 	session_unref(callback->session);
 
 	g_free(callback);
-
-	return FALSE;
 }
 
 static int rfcomm_connect(const bdaddr_t *src,
 				const bdaddr_t *dst, uint8_t channel,
-					GIOFunc function, gpointer user_data)
+					BtIOConnect function, gpointer user_data)
 {
 	GIOChannel *io;
-	struct sockaddr_rc addr;
-	int sk;
-
-	sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-	if (sk < 0)
-		return -EIO;
+	GError *err = NULL;
 
-	memset(&addr, 0, sizeof(addr));
-	addr.rc_family = AF_BLUETOOTH;
-	bacpy(&addr.rc_bdaddr, src);
-
-	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		close(sk);
-		return -EIO;
-	}
-
-	io = g_io_channel_unix_new(sk);
-	if (io == NULL) {
-		close(sk);
-		return -ENOMEM;
-	}
-
-	if (g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK,
-						NULL) != G_IO_STATUS_NORMAL) {
-		g_io_channel_unref(io);
-		close(sk);
-		return -EPERM;
-	}
-
-	memset(&addr, 0, sizeof(addr));
-	addr.rc_family = AF_BLUETOOTH;
-	bacpy(&addr.rc_bdaddr, dst);
-	addr.rc_channel = channel;
-
-	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		if (errno != EAGAIN && errno != EINPROGRESS) {
-			g_io_channel_unref(io);
-			close(sk);
-			return -EIO;
-		}
-	}
-
-	g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-							function, user_data);
-
-	g_io_channel_unref(io);
+	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, channel,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	if (io != NULL)
+		return 0;
 
-	return 0;
+	error("%s", err->message);
+	g_error_free(err);
+	return -EIO;
 }
 
 static void search_callback(uint8_t type, uint16_t status,
@@ -520,7 +486,7 @@
 {
 	struct transfer_data *transfer;
 
-	debug("session_shutdown(%p)", session);
+	DBG("%p", session);
 	transfer = session->pending ? session->pending->data : NULL;
 
 	session_ref(session);
@@ -800,7 +766,7 @@
 {
 	struct session_data *session = user_data;
 	struct agent_data *agent = session->agent;
-	struct agent_pending *pending = agent->pending;
+	struct pending_data *pending = agent->pending;
 	DBusMessage *reply = dbus_pending_call_steal_reply(call);
 	const char *name;
 	DBusError derr;
@@ -810,14 +776,16 @@
 		error("Replied with an error: %s, %s",
 				derr.name, derr.message);
 		dbus_error_free(&derr);
-		goto fail;
+		dbus_message_unref(reply);
+		transfer_unregister(pending->transfer);
+		return;
 	}
 
 	dbus_message_get_args(reply, NULL,
 			DBUS_TYPE_STRING, &name,
 			DBUS_TYPE_INVALID);
 
-	debug("Agent.Request() reply: %s", name);
+	DBG("Agent.Request() reply: %s", name);
 
 	if (strlen(name)) {
 		g_free(pending->transfer->name);
@@ -825,14 +793,22 @@
 	}
 
 	pending->cb(session, pending->transfer);
-
+	dbus_message_unref(reply);
 	free_pending(pending);
 	agent->pending = NULL;
 
 	return;
+}
 
-fail:
-	transfer_unregister(pending->transfer);
+static gboolean session_request_proceed(gpointer data)
+{
+	struct pending_data *pending = data;
+	struct transfer_data *transfer = pending->transfer;
+
+	pending->cb(transfer->session, transfer);
+	free_pending(pending);
+
+	return FALSE;
 }
 
 static int session_request(struct session_data *session, session_callback_t cb,
@@ -840,11 +816,14 @@
 {
 	struct agent_data *agent = session->agent;
 	DBusMessage *message;
-	DBusPendingCall *call;
-	struct agent_pending *pending;
+	struct pending_data *pending;
+
+	pending = g_new0(struct pending_data, 1);
+	pending->cb = cb;
+	pending->transfer = transfer;
 
 	if (agent == NULL || transfer->path == NULL) {
-		cb(session, transfer);
+		g_idle_add(session_request_proceed, pending);
 		return 0;
 	}
 
@@ -855,23 +834,20 @@
 			DBUS_TYPE_OBJECT_PATH, &transfer->path,
 			DBUS_TYPE_INVALID);
 
-
-	if (!dbus_connection_send_with_reply(session->conn, message, &call, -1)) {
+	if (!dbus_connection_send_with_reply(session->conn, message,
+						&pending->call, -1)) {
 		dbus_message_unref(message);
 		return -ENOMEM;
 	}
 
-	dbus_message_unref(message);
-
-	pending = g_new0(struct agent_pending, 1);
-	pending->call = call;
-	pending->cb = cb;
-	pending->transfer = transfer;
 	agent->pending = pending;
 
-	dbus_pending_call_set_notify(call, session_request_reply, session, NULL);
+	dbus_message_unref(message);
+
+	dbus_pending_call_set_notify(pending->call, session_request_reply,
+					session, NULL);
 
-	debug("Agent.Request(\"%s\")", transfer->path);
+	DBG("Agent.Request(\"%s\")", transfer->path);
 
 	return 0;
 }
@@ -921,7 +897,7 @@
 
 done:
 
-	debug("Transfer(%p) complete", transfer);
+	DBG("Transfer(%p) complete", transfer);
 
 	session_terminate_transfer(session, transfer);
 }
@@ -1004,7 +980,7 @@
 	g_dbus_send_message(session->conn, message);
 
 done:
-	debug("Transfer(%p) progress: %ld bytes", transfer,
+	DBG("Transfer(%p) progress: %ld bytes", transfer,
 			(long int ) transferred);
 
 	if (transferred == transfer->size)
@@ -1031,31 +1007,43 @@
 static void session_prepare_get(struct session_data *session, void *data)
 {
 	struct transfer_data *transfer = data;
+	int err;
+
+	err = transfer_get(transfer, transfer_progress, session);
+	if (err < 0) {
+		session_notify_error(session, transfer, strerror(-err));
+		return;
+	}
 
-	if (transfer_get(transfer, transfer_progress, session) < 0)
-		transfer_unregister(transfer);
+	DBG("Transfer(%p) started", transfer);
 }
 
 int session_get(struct session_data *session, const char *type,
 		const char *filename, const char *targetname,
-		const guint8  *apparam, gint apparam_size,
+		const guint8 *apparam, gint apparam_size,
 		session_callback_t func)
 {
 	struct transfer_data *transfer;
-	struct transfer_params *params;
+	struct transfer_params *params = NULL;
 	int err;
 
 	if (session->obex == NULL)
 		return -ENOTCONN;
 
-	params = g_new0(struct transfer_params, 1);
-	params->data = apparam;
-	params->size = apparam_size;
+	if (apparam != NULL) {
+		params = g_new0(struct transfer_params, 1);
+		params->data = g_new(guint8, apparam_size);
+		memcpy(params->data, apparam, apparam_size);
+		params->size = apparam_size;
+	}
 
 	transfer = transfer_register(session, filename, targetname, type,
 					params);
 	if (transfer == NULL) {
-		g_free(params);
+		if (params != NULL) {
+			g_free(params->data);
+			g_free(params);
+		}
 		return -EIO;
 	}
 
@@ -1332,7 +1320,7 @@
 		return -EIO;
 	}
 
-	debug("Session(%p) registered %s", session, session->path);
+	DBG("Session(%p) registered %s", session, session->path);
 
 	return 0;
 }
@@ -1350,9 +1338,15 @@
 static void session_prepare_put(struct session_data *session, void *data)
 {
 	struct transfer_data *transfer = data;
+	int err;
+
+	err = transfer_put(transfer, transfer_progress, session);
+	if (err < 0) {
+		session_notify_error(session, transfer, strerror(-err));
+		return;
+	}
 
-	if (transfer_put(transfer, transfer_progress, session) < 0)
-		transfer_unregister(transfer);
+	DBG("Transfer(%p) started", transfer);
 }
 
 int session_put(struct session_data *session, char *buf, const char *targetname)
--- client/transfer.c
+++ client/transfer.c
@@ -35,7 +35,7 @@
 #include <gdbus.h>
 #include <gw-obex.h>
 
-#include "logging.h"
+#include "log.h"
 #include "transfer.h"
 #include "session.h"
 
@@ -146,6 +146,8 @@
 {
 	struct session_data *session = transfer->session;
 
+	DBG("%p", transfer);
+
 	if (transfer->xfer) {
 		gw_obex_xfer_close(transfer->xfer, NULL);
 		gw_obex_xfer_free(transfer->xfer);
@@ -158,7 +160,11 @@
 
 	session_unref(session);
 
-	g_free(transfer->params);
+	if (transfer->params != NULL) {
+		g_free(transfer->params->data);
+		g_free(transfer->params);
+	}
+
 	g_free(transfer->callback);
 	g_free(transfer->filename);
 	g_free(transfer->name);
@@ -200,9 +206,9 @@
 		return NULL;
 	}
 
-	debug("Transfer(%p) registered %s", transfer, transfer->path);
-
 done:
+	DBG("%p registered %s", transfer, transfer->path);
+
 	session->pending = g_slist_append(session->pending, transfer);
 
 	return transfer;
@@ -215,11 +221,10 @@
 	if (transfer->path) {
 		g_dbus_unregister_interface(session->conn,
 			transfer->path, TRANSFER_INTERFACE);
-
-		debug("Transfer(%p) unregistered %s", transfer,
-					transfer->path);
 	}
 
+	DBG("%p unregistered %s", transfer, transfer->path);
+
 	transfer_free(transfer);
 }
 
@@ -240,18 +245,20 @@
 
 	if (gw_obex_xfer_read(xfer, transfer->buffer + transfer->filled,
 			bsize, &bread, &transfer->err) == FALSE)
-		goto done;
+		goto fail;
 
 	transfer->filled += bread;
 
 	if (gw_obex_xfer_object_done(xfer)) {
-		if (transfer->buffer[transfer->filled - 1] == '\0')
+		if (transfer->filled > 0 &&
+				transfer->buffer[transfer->filled - 1] == '\0')
 			goto done;
 
 		bsize = transfer->buffer_len - transfer->filled;
 		if (bsize < 1) {
 			transfer->buffer_len += DEFAULT_BUFFER_SIZE;
-			transfer->buffer = g_realloc(transfer->buffer, transfer->buffer_len);
+			transfer->buffer = g_realloc(transfer->buffer,
+						transfer->buffer_len);
 		}
 
 		transfer->buffer[transfer->filled] = '\0';
@@ -262,6 +269,7 @@
 
 done:
 	transfer->size = strlen(transfer->buffer);
+fail:
 	if (callback)
 		callback->func(transfer, transfer->size, transfer->err,
 				callback->data);
@@ -406,14 +414,15 @@
 	if (transfer->xfer != NULL)
 		return -EALREADY;
 
-	if (g_strcmp0(transfer->type, "x-bt/vcard-listing") == 0 ||
-			g_strcmp0(transfer->type, "x-obex/folder-listing") == 0)
+	if (transfer->type != NULL &&
+			(strncmp(transfer->type, "x-obex/", 7) == 0 ||
+			strncmp(transfer->type, "x-bt/", 5) == 0))
 		cb = get_xfer_listing_progress;
 	else {
 		int fd = open(transfer->name ? : transfer->filename,
 				O_WRONLY | O_CREAT, 0600);
 
-		if (transfer->fd < 0) {
+		if (fd < 0) {
 			error("open(): %s(%d)", strerror(errno), errno);
 			return -errno;
 		}
--- client/transfer.h
+++ client/transfer.h
@@ -24,7 +24,7 @@
 #include <gw-obex.h>
 
 struct transfer_params {
-	const guint8 *data;
+	guint8 *data;
 	gint size;
 };
 
--- configure
+++ configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63 for obexd 0.26.
+# Generated by GNU Autoconf 2.63 for obexd 0.29.
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
 # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
@@ -743,8 +743,8 @@
 # Identity of this package.
 PACKAGE_NAME='obexd'
 PACKAGE_TARNAME='obexd'
-PACKAGE_VERSION='0.26'
-PACKAGE_STRING='obexd 0.26'
+PACKAGE_VERSION='0.29'
+PACKAGE_STRING='obexd 0.29'
 PACKAGE_BUGREPORT=''
 
 ac_default_prefix=/usr/local
@@ -790,6 +790,10 @@
 LIBOBJS
 CLIENT_FALSE
 CLIENT_TRUE
+NOKIA_BACKUP_FALSE
+NOKIA_BACKUP_TRUE
+USB_FALSE
+USB_TRUE
 SERVER_FALSE
 SERVER_TRUE
 PHONEBOOK_DRIVER
@@ -933,6 +937,8 @@
 enable_debug
 with_phonebook
 enable_server
+enable_usb
+enable_nokia_backup
 enable_client
 '
       ac_precious_vars='build_alias
@@ -1511,7 +1517,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures obexd 0.26 to adapt to many kinds of systems.
+\`configure' configures obexd 0.29 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1581,7 +1587,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of obexd 0.26:";;
+     short | recursive ) echo "Configuration of obexd 0.29:";;
    esac
   cat <<\_ACEOF
 
@@ -1603,6 +1609,8 @@
   --disable-optimization  disable code optimization through compiler
   --enable-debug          enable compiling with debugging information
   --disable-server        disable compilation of OBEX server
+  --enable-usb            enable usb plugin
+  --enable-nokia-backup   enable nokia-backup plugin
   --disable-client        disable compilation of OBEX client
 
 Optional Packages:
@@ -1711,7 +1719,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-obexd configure 0.26
+obexd configure 0.29
 generated by GNU Autoconf 2.63
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1725,7 +1733,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by obexd $as_me 0.26, which was
+It was created by obexd $as_me 0.29, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   $ $0 $@
@@ -2575,7 +2583,7 @@
 
 # Define the identity of the package.
  PACKAGE='obexd'
- VERSION='0.26'
+ VERSION='0.29'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -4871,13 +4879,13 @@
 else
   lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:4874: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:4882: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:4877: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:4885: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:4880: output\"" >&5)
+  (eval echo "\"\$as_me:4888: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -6083,7 +6091,7 @@
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6086 "configure"' > conftest.$ac_ext
+  echo '#line 6094 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -7906,11 +7914,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:7909: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:7917: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:7913: \$? = $ac_status" >&5
+   echo "$as_me:7921: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8245,11 +8253,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8248: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8256: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8252: \$? = $ac_status" >&5
+   echo "$as_me:8260: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8350,11 +8358,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8353: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8361: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8357: \$? = $ac_status" >&5
+   echo "$as_me:8365: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -8405,11 +8413,11 @@
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8408: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8416: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8412: \$? = $ac_status" >&5
+   echo "$as_me:8420: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -11208,7 +11216,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11211 "configure"
+#line 11219 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11304,7 +11312,7 @@
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11307 "configure"
+#line 11315 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12579,6 +12587,40 @@
 fi
 
 
+# Check whether --enable-usb was given.
+if test "${enable_usb+set}" = set; then
+  enableval=$enable_usb;
+	enable_usb=${enableval}
+
+fi
+
+ if test "${enable_usb}" = "yes" &&
+				test "${enable_server}" != "no"; then
+  USB_TRUE=
+  USB_FALSE='#'
+else
+  USB_TRUE='#'
+  USB_FALSE=
+fi
+
+
+# Check whether --enable-nokia_backup was given.
+if test "${enable_nokia_backup+set}" = set; then
+  enableval=$enable_nokia_backup;
+	enable_nokia_backup=${enableval}
+
+fi
+
+ if test "${enable_nokia_backup}" = "yes" &&
+				test "${enable_server}" != "no"; then
+  NOKIA_BACKUP_TRUE=
+  NOKIA_BACKUP_FALSE='#'
+else
+  NOKIA_BACKUP_TRUE='#'
+  NOKIA_BACKUP_FALSE=
+fi
+
+
 # Check whether --enable-client was given.
 if test "${enable_client+set}" = set; then
   enableval=$enable_client;
@@ -12730,6 +12772,20 @@
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${USB_TRUE}" && test -z "${USB_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"USB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"USB\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${NOKIA_BACKUP_TRUE}" && test -z "${NOKIA_BACKUP_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"NOKIA_BACKUP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"NOKIA_BACKUP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 if test -z "${CLIENT_TRUE}" && test -z "${CLIENT_FALSE}"; then
   { { $as_echo "$as_me:$LINENO: error: conditional \"CLIENT\" was never defined.
 Usually this means the macro was only invoked conditionally." >&5
@@ -13059,7 +13115,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by obexd $as_me 0.26, which was
+This file was extended by obexd $as_me 0.29, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -13122,7 +13178,7 @@
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-obexd config.status 0.26
+obexd config.status 0.29
 configured by $0, generated by GNU Autoconf 2.63,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
--- configure.ac
+++ configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(obexd, 0.26)
+AC_INIT(obexd, 0.29)
 
 AM_INIT_AUTOMAKE([foreign subdir-objects])
 AM_CONFIG_HEADER(config.h)
@@ -144,6 +144,20 @@
 ])
 AM_CONDITIONAL(SERVER, test "${enable_server}" != "no")
 
+AC_ARG_ENABLE(usb, AC_HELP_STRING([--enable-usb],
+				[enable usb plugin]), [
+	enable_usb=${enableval}
+])
+AM_CONDITIONAL(USB, test "${enable_usb}" = "yes" &&
+				test "${enable_server}" != "no")
+
+AC_ARG_ENABLE(nokia_backup, AC_HELP_STRING([--enable-nokia-backup],
+				[enable nokia-backup plugin]), [
+	enable_nokia_backup=${enableval}
+])
+AM_CONDITIONAL(NOKIA_BACKUP, test "${enable_nokia_backup}" = "yes" &&
+				test "${enable_server}" != "no")
+
 AC_ARG_ENABLE(client, AC_HELP_STRING([--disable-client],
 				[disable compilation of OBEX client]), [
 	enable_client=${enableval}
--- plugins/bluetooth.c
+++ plugins/bluetooth.c
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "server.h"
+#include "obex.h"
+#include "transport.h"
+#include "service.h"
+#include "log.h"
+#include "btio.h"
+
+#define BT_RX_MTU 32767
+#define BT_TX_MTU 32767
+
+#define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */
+
+struct pending_request {
+	DBusPendingCall *call;
+	struct bluetooth_service *service;
+	char *adapter_path;
+	char address[18];
+	unsigned int watch;
+	GIOChannel *io;
+};
+
+struct bluetooth_service {
+	struct obex_server *server;
+	struct obex_service_driver *driver;
+	uint32_t handle;
+};
+
+struct adapter_any {
+	char *path;		/* Adapter ANY path */
+	GSList *services;	/* List of services to register records */
+};
+
+static DBusConnection *connection = NULL;
+static struct adapter_any *any = NULL;
+
+static void add_record_reply(DBusPendingCall *call, void *user_data)
+{
+	struct bluetooth_service *service = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+	uint32_t handle;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		error("bluetooth: Replied with an error: %s, %s",
+				derr.name, derr.message);
+		dbus_error_free(&derr);
+		handle = 0;
+	} else {
+		dbus_message_get_args(reply, NULL,
+				DBUS_TYPE_UINT32, &handle,
+				DBUS_TYPE_INVALID);
+
+		service->handle = handle;
+
+		DBG("Registered: %s, handle: 0x%x",
+				service->driver->name, service->handle);
+	}
+
+	dbus_message_unref(reply);
+}
+
+static int add_record(const char *path, const char *xml,
+			struct bluetooth_service *service)
+{
+	DBusMessage *msg;
+	DBusPendingCall *call;
+	int ret = 0;
+
+	msg = dbus_message_new_method_call("org.bluez", path,
+					"org.bluez.Service", "AddRecord");
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &xml,
+			DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(connection,
+				msg, &call, -1) == FALSE) {
+		ret = -1;
+		goto failed;
+	}
+
+	dbus_pending_call_set_notify(call, add_record_reply, service, NULL);
+	dbus_pending_call_unref(call);
+
+failed:
+	dbus_message_unref(msg);
+	return ret;
+}
+
+static struct bluetooth_service *find_service(
+					struct obex_service_driver *driver,
+					uint8_t channel)
+{
+	GSList *l;
+
+	for (l = any->services; l; l = l->next) {
+		struct bluetooth_service *service = l->data;
+
+		if (driver != NULL && service->driver != driver)
+			continue;
+
+		if (channel != 0 && service->driver->channel != channel)
+			continue;
+
+		return service;
+	}
+
+	return NULL;
+}
+
+static void register_record(struct obex_server *server)
+{
+	const GSList *l;
+
+	if (connection == NULL)
+		return;
+
+	for (l = server->drivers; l; l = l->next) {
+		struct obex_service_driver *driver = l->data;
+		struct bluetooth_service *service;
+		char *xml;
+
+		service = find_service(driver, 0);
+		if (service == NULL) {
+			service = g_new0(struct bluetooth_service, 1);
+			service->driver = driver;
+			service->server = server;
+			any->services = g_slist_append(any->services, service);
+		}
+
+		/* Service already has a record registered */
+		if (service->handle != 0)
+			continue;
+
+		/* Adapter ANY is not available yet: Add record later */
+		if (any->path == NULL)
+			continue;
+
+		xml = g_markup_printf_escaped(driver->record, driver->channel,
+						driver->name);
+		add_record(any->path, xml, service);
+		g_free(xml);
+	}
+}
+
+static void find_adapter_any_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	const char *path;
+	GSList *l;
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		error("bluetooth: Replied with an error: %s, %s",
+				derr.name, derr.message);
+		dbus_error_free(&derr);
+		goto done;
+	}
+
+	dbus_message_get_args(reply, NULL,
+			DBUS_TYPE_OBJECT_PATH, &path,
+			DBUS_TYPE_INVALID);
+	any->path = g_strdup(path);
+
+	for (l = any->services; l; l = l->next) {
+		struct bluetooth_service *service = l->data;
+		char *xml;
+
+		xml = g_markup_printf_escaped(service->driver->record,
+						service->driver->channel,
+						service->driver->name);
+		add_record(any->path, xml, service);
+		g_free(xml);
+	}
+
+done:
+	dbus_message_unref(reply);
+}
+
+static DBusPendingCall *find_adapter(const char *pattern,
+				DBusPendingCallNotifyFunction function,
+				void *user_data)
+{
+	DBusMessage *msg;
+	DBusPendingCall *call;
+
+	DBG("FindAdapter(%s)", pattern);
+
+	msg = dbus_message_new_method_call("org.bluez", "/",
+					"org.bluez.Manager", "FindAdapter");
+	if (!msg)
+		return NULL;
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &pattern,
+			DBUS_TYPE_INVALID);
+
+	if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
+		dbus_message_unref(msg);
+		return NULL;
+	}
+
+	dbus_pending_call_set_notify(call, function, user_data, NULL);
+
+	dbus_message_unref(msg);
+
+	return call;
+}
+
+static void name_acquired(DBusConnection *conn, void *user_data)
+{
+	DBusPendingCall *call;
+
+	call = find_adapter("any", find_adapter_any_reply, NULL);
+	if (call)
+		dbus_pending_call_unref(call);
+}
+
+static void name_released(DBusConnection *conn, void *user_data)
+{
+	GSList *l;
+
+	/* reset handles so the services got register next time */
+	for (l = any->services; l; l = l->next) {
+		struct bluetooth_service *service = l->data;
+
+		service->handle = 0;
+	}
+
+	g_free(any->path);
+	any->path = NULL;
+
+}
+
+static void service_cancel(struct pending_request *pending)
+{
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call("org.bluez",
+					pending->adapter_path,
+					"org.bluez.Service",
+					"CancelAuthorization");
+
+	g_dbus_send_message(connection, msg);
+}
+
+static void pending_request_free(struct pending_request *pending)
+{
+	if (pending->call)
+		dbus_pending_call_unref(pending->call);
+	g_io_channel_unref(pending->io);
+	g_free(pending->adapter_path);
+	g_free(pending);
+}
+
+static void connect_event(GIOChannel *io, GError *err, void *user_data)
+{
+	struct bluetooth_service *service = user_data;
+	struct obex_server *server = service->server;
+
+	if (err)
+		goto drop;
+
+	if (obex_server_new_connection(server, io, BT_TX_MTU, BT_RX_MTU) < 0)
+		g_io_channel_shutdown(io, TRUE, NULL);
+
+	return;
+
+drop:
+	error("%s", err->message);
+	g_io_channel_shutdown(io, TRUE, NULL);
+	return;
+}
+
+static void service_reply(DBusPendingCall *call, void *user_data)
+{
+	struct pending_request *pending = user_data;
+	GIOChannel *io = pending->io;
+	struct bluetooth_service *service = pending->service;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusError derr;
+	GError *err = NULL;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		error("bluetooth: RequestAuthorization error: %s, %s",
+				derr.name, derr.message);
+
+		if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
+			service_cancel(pending);
+
+		dbus_error_free(&derr);
+		g_io_channel_shutdown(io, TRUE, NULL);
+		goto done;
+	}
+
+	DBG("RequestAuthorization succeeded");
+
+	if (!bt_io_accept(io, connect_event, service, NULL, &err)) {
+		error("%s", err->message);
+		g_error_free(err);
+		g_io_channel_shutdown(io, TRUE, NULL);
+	}
+
+done:
+	g_source_remove(pending->watch);
+	pending_request_free(pending);
+	dbus_message_unref(reply);
+}
+
+static gboolean service_error(GIOChannel *io, GIOCondition cond,
+			void *user_data)
+{
+	struct pending_request *pending = user_data;
+
+	service_cancel(pending);
+
+	dbus_pending_call_cancel(pending->call);
+
+	pending_request_free(pending);
+
+	return FALSE;
+}
+
+static void find_adapter_reply(DBusPendingCall *call, void *user_data)
+{
+	struct pending_request *pending = user_data;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	DBusMessage *msg;
+	DBusPendingCall *pcall;
+	const char *path, *paddr = pending->address;
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	if (dbus_set_error_from_message(&derr, reply)) {
+		error("Replied with an error: %s, %s",
+				derr.name, derr.message);
+		dbus_error_free(&derr);
+		goto failed;
+	}
+
+	dbus_message_get_args(reply, NULL,
+			DBUS_TYPE_OBJECT_PATH, &path,
+			DBUS_TYPE_INVALID);
+
+	DBG("FindAdapter -> %s", path);
+	pending->adapter_path = g_strdup(path);
+	dbus_message_unref(reply);
+
+	msg = dbus_message_new_method_call("org.bluez", path,
+			"org.bluez.Service", "RequestAuthorization");
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr,
+			DBUS_TYPE_UINT32, &pending->service->handle,
+			DBUS_TYPE_INVALID);
+
+	if (!dbus_connection_send_with_reply(connection,
+					msg, &pcall, TIMEOUT)) {
+		dbus_message_unref(msg);
+		goto failed;
+	}
+
+	dbus_message_unref(msg);
+
+	DBG("RequestAuthorization(%s, %x)", paddr,
+			pending->service->handle);
+
+	if (!dbus_pending_call_set_notify(pcall, service_reply, pending,
+								NULL)) {
+		dbus_pending_call_unref(pcall);
+		goto failed;
+	}
+
+	dbus_pending_call_unref(pending->call);
+	pending->call = pcall;
+
+	/* Catches errors before authorization response comes */
+	pending->watch = g_io_add_watch(pending->io,
+					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					service_error, pending);
+
+	return;
+
+failed:
+	g_io_channel_shutdown(pending->io, TRUE, NULL);
+	pending_request_free(pending);
+}
+
+static int request_service_authorization(struct bluetooth_service *service,
+					GIOChannel *io, const char *address)
+{
+	struct pending_request *pending;
+	char source[18];
+	GError *err = NULL;
+
+	if (connection == NULL || any->path == NULL)
+		return -1;
+
+	bt_io_get(io, BT_IO_RFCOMM, &err,
+			BT_IO_OPT_SOURCE, source,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		return -EINVAL;
+	}
+
+	pending = g_new0(struct pending_request, 1);
+	pending->call = find_adapter(source, find_adapter_reply, pending);
+	if (!pending->call) {
+		g_free(pending);
+		return -ENOMEM;
+	}
+
+	pending->service = service;
+	pending->io = g_io_channel_ref(io);
+	memcpy(pending->address, address, sizeof(pending->address));
+
+	return 0;
+}
+
+static void confirm_event(GIOChannel *io, void *user_data)
+{
+	struct bluetooth_service *service;
+	GError *err = NULL;
+	char address[18];
+	uint8_t channel;
+
+	bt_io_get(io, BT_IO_RFCOMM, &err,
+			BT_IO_OPT_DEST, address,
+			BT_IO_OPT_CHANNEL, &channel,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	info("bluetooth: New connection from: %s, channel %u", address,
+			channel);
+
+	service = find_service(NULL, channel);
+	if (service == NULL) {
+		error("bluetooth: Unable to find service");
+		goto drop;
+	}
+
+	if (service->driver->service != OBEX_OPP) {
+		if (request_service_authorization(service, io, address) < 0)
+			goto drop;
+
+		return;
+	}
+
+	if (!bt_io_accept(io, connect_event, service, NULL, &err)) {
+		error("%s", err->message);
+		g_error_free(err);
+		goto drop;
+	}
+
+	return;
+
+drop:
+	g_io_channel_shutdown(io, TRUE, NULL);
+}
+
+static GIOChannel *start(struct obex_server *server,
+				struct obex_service_driver *service,
+				BtIOSecLevel sec_level)
+{
+	GIOChannel *io;
+	GError *err = NULL;
+
+	io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event,
+				server, NULL, &err,
+				BT_IO_OPT_CHANNEL, service->channel,
+				BT_IO_OPT_SEC_LEVEL, sec_level,
+				BT_IO_OPT_INVALID);
+	if (io == NULL) {
+		error("bluetooth: unable to listen in channel %d: %s",
+				service->channel, err->message);
+		g_error_free(err);
+	} else
+		DBG("listening on channel %d", service->channel);
+
+	return io;
+}
+
+static void *bluetooth_start(struct obex_server *server, int *err)
+{
+	BtIOSecLevel sec_level;
+	GSList *ios = NULL;
+	const GSList *l;
+
+	if (server->secure == TRUE)
+		sec_level = BT_IO_SEC_MEDIUM;
+	else
+		sec_level = BT_IO_SEC_LOW;
+
+	for (l = server->drivers; l; l = l->next) {
+		struct obex_service_driver *service = l->data;
+		GIOChannel *io;
+
+		io = start(server, service, sec_level);
+		if (io == NULL)
+			continue;
+
+		ios = g_slist_prepend(ios, io);
+	}
+
+	register_record(server);
+
+	return ios;
+}
+
+static void stop(gpointer data, gpointer user_data)
+{
+	GIOChannel *io = data;
+
+	g_io_channel_shutdown(io, TRUE, NULL);
+	g_io_channel_unref(io);
+}
+
+static void bluetooth_stop(void *data)
+{
+	GSList *ios = data;
+
+	g_slist_foreach(ios, stop, NULL);
+	g_slist_free(ios);
+}
+
+static struct obex_transport_driver driver = {
+	.name = "bluetooth",
+	.start = bluetooth_start,
+	.stop = bluetooth_stop
+};
+
+static unsigned int listener_id = 0;
+
+static int bluetooth_init(void)
+{
+	any = g_new0(struct adapter_any, 1);
+
+	connection = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
+	if (connection == NULL)
+		return -EPERM;
+
+	listener_id = g_dbus_add_service_watch(connection, "org.bluez",
+				name_acquired, name_released, NULL, NULL);
+
+	return obex_transport_driver_register(&driver);
+}
+
+static void bluetooth_exit(void)
+{
+	g_dbus_remove_watch(connection, listener_id);
+
+	if (any) {
+		g_slist_foreach(any->services, (GFunc) g_free, NULL);
+		g_slist_free(any->services);
+		g_free(any->path);
+		g_free(any);
+	}
+
+	if (connection)
+		dbus_connection_unref(connection);
+
+	obex_transport_driver_unregister(&driver);
+}
+
+OBEX_PLUGIN_DEFINE(bluetooth, bluetooth_init, bluetooth_exit)
--- plugins/filesystem.c
+++ plugins/filesystem.c
@@ -45,7 +45,7 @@
 #include <openobex/obex_const.h>
 
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 #include "obex.h"
 #include "mimetype.h"
 #include "service.h"
@@ -138,6 +138,7 @@
 	char *folder;
 	gboolean root;
 	int fd = open(name, oflag, mode);
+	uint64_t avail;
 
 	if (fd < 0) {
 		if (err)
@@ -181,7 +182,8 @@
 	if (size == NULL)
 		goto done;
 
-	if (buf.f_bsize * buf.f_bavail < *size) {
+	avail = (uint64_t) buf.f_bsize * buf.f_bavail;
+	if (avail < *size) {
 		if (err)
 			*err = -ENOSPC;
 		goto failed;
@@ -245,6 +247,9 @@
 	char buf[128];
 
 	object->pid = -1;
+	object->watch = 0;
+
+	DBG("pid: %d status: %d", pid, status);
 
 	if (WEXITSTATUS(status) != EXIT_SUCCESS) {
 		memset(buf, 0, sizeof(buf));
@@ -270,6 +275,8 @@
 		return -EPERM;
 	}
 
+	DBG("executing %s pid %d", argv[0], pid);
+
 	return pid;
 }
 
@@ -316,9 +323,6 @@
 
 	object->watch = g_child_watch_add(object->pid, script_exited, object);
 
-	if (size)
-		*size = 1;
-
 done:
 	if (err)
 		*err = 0;
@@ -397,7 +401,7 @@
 			ret = lstat(fullname, &fstat);
 
 		if (ret < 0) {
-			debug("%s: %s(%d)", root ? "stat" : "lstat",
+			DBG("%s: %s(%d)", root ? "stat" : "lstat",
 					strerror(errno), errno);
 			g_free(filename);
 			g_free(fullname);
@@ -510,19 +514,30 @@
 static int capability_close(void *object)
 {
 	struct capability_object *obj = object;
+	int err = 0;
+
+	if (obj->pid < 0)
+		goto done;
 
-	if (obj->pid >= 0) {
+	if (obj->watch)
 		g_source_remove(obj->watch);
-		kill(obj->pid, SIGTERM);
-		g_spawn_close_pid(obj->pid);
+
+	g_spawn_close_pid(obj->pid);
+
+	DBG("kill: pid %d", obj->pid);
+	err = kill(obj->pid, SIGTERM);
+	if (err < 0) {
+		err = -errno;
+		error("kill: %s (%d)", strerror(-err), -err);
 	}
 
+done:
 	if (obj->buffer != NULL)
 		g_string_free(obj->buffer, TRUE);
 
 	g_free(obj);
 
-	return 0;
+	return err;
 }
 
 static struct obex_mime_type_driver file = {
--- plugins/ftp.c
+++ plugins/ftp.c
@@ -45,7 +45,7 @@
 #include <openobex/obex_const.h>
 
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 #include "obex.h"
 #include "dbus.h"
 #include "mimetype.h"
@@ -161,17 +161,25 @@
 {
 	struct obex_session *os = ftp->os;
 	const char *capability = obex_get_capability_path(os);
+	const char *name = obex_get_name(os);
+	char *path;
+	int err;
 
-	if (type == NULL)
-		return obex_get_stream_start(os, ftp->folder);
+	if (type == NULL && name == NULL)
+		return -EBADR;
 
-	if (g_str_equal(type, CAP_TYPE))
+	if (g_strcmp0(type, CAP_TYPE) == 0)
 		return obex_get_stream_start(os, capability);
 
-	if (g_str_equal(type, LST_TYPE))
+	if (g_strcmp0(type, LST_TYPE) == 0)
 		return obex_get_stream_start(os, ftp->folder);
 
-	return -ENOENT;
+	path = g_build_filename(ftp->folder, name, NULL);
+	err = obex_get_stream_start(os, path);
+
+	g_free(path);
+
+	return err;
 }
 
 static void *ftp_connect(struct obex_session *os, int *err)
@@ -293,7 +301,7 @@
 
 	/* Check flag "Backup" */
 	if ((nonhdr[0] & 0x01) == 0x01) {
-		debug("Set to parent path");
+		DBG("Set to parent path");
 
 		if (root)
 			return -EPERM;
@@ -302,18 +310,18 @@
 		set_folder(ftp, fullname);
 		g_free(fullname);
 
-		debug("Set to parent path: %s", ftp->folder);
+		DBG("Set to parent path: %s", ftp->folder);
 
 		return 0;
 	}
 
 	if (!name) {
-		debug("Set path failed: name missing!");
+		DBG("Set path failed: name missing!");
 		return -EINVAL;
 	}
 
 	if (strlen(name) == 0) {
-		debug("Set to root");
+		DBG("Set to root");
 		set_folder(ftp, root_folder);
 		return 0;
 	}
@@ -326,7 +334,7 @@
 
 	fullname = g_build_filename(ftp->folder, name, NULL);
 
-	debug("Fullname: %s", fullname);
+	DBG("Fullname: %s", fullname);
 
 	if (root && obex_get_symlinks(os))
 		err = stat(fullname, &dstat);
@@ -339,7 +347,7 @@
 		if (err == -ENOENT)
 			goto not_found;
 
-		debug("%s: %s(%d)", root ? "stat" : "lstat",
+		DBG("%s: %s(%d)", root ? "stat" : "lstat",
 				strerror(-err), -err);
 
 		goto done;
@@ -362,7 +370,7 @@
 
 	if (mkdir(fullname, 0755) <  0) {
 		err = -errno;
-		debug("mkdir: %s(%d)", strerror(-err), -err);
+		DBG("mkdir: %s(%d)", strerror(-err), -err);
 		goto done;
 	}
 
--- plugins/nokia-backup.c
+++ plugins/nokia-backup.c
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2010  Nokia Corporation
+ *  Copyright (C) 2010  Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <wait.h>
+
+#include <glib.h>
+#include "gdbus.h"
+
+
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "mimetype.h"
+#include "service.h"
+
+#define BACKUP_BUS_NAME		"com.nokia.backup.plugin"
+#define BACKUP_PATH		"/com/nokia/backup"
+#define BACKUP_PLUGIN_INTERFACE	"com.nokia.backup.plugin"
+#define BACKUP_DBUS_TIMEOUT	(1000 * 60 * 15)
+
+static const uint8_t FTP_TARGET[TARGET_SIZE] = {
+	0xF9, 0xEC, 0x7B, 0xC4,  0x95, 0x3C, 0x11, 0xD2,
+	0x98, 0x4E, 0x52, 0x54,  0x00, 0xDC, 0x9E, 0x09  };
+
+struct backup_object{
+	gchar *cmd;
+	int fd;
+	int oflag;
+	int error_code;
+	mode_t mode;
+	DBusPendingCall *pending_call;
+	DBusConnection *conn;
+};
+
+static void on_backup_dbus_notify(DBusPendingCall *pending_call,
+					void *user_data)
+{
+	struct backup_object *obj = user_data;
+	DBusMessage *reply;
+	const char *filename;
+	int error_code;
+
+	DBG("Notification received for pending call - %s", obj->cmd);
+
+	reply = dbus_pending_call_steal_reply(pending_call);
+
+	if (reply && dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32,
+					&error_code, DBUS_TYPE_STRING,
+					&filename, DBUS_TYPE_INVALID)) {
+
+		obj->error_code = error_code;
+
+		if (filename) {
+			DBG("Notification - file path = %s, error_code = %d",
+					filename, error_code);
+			if (error_code == 0)
+				obj->fd = open(filename,obj->oflag,obj->mode);
+		}
+
+	} else
+		DBG("Notification timed out or connection got closed");
+
+	if (reply)
+		dbus_message_unref(reply);
+
+	dbus_pending_call_unref(pending_call);
+	obj->pending_call = NULL;
+	dbus_connection_unref(obj->conn);
+	obj->conn = NULL;
+
+	if (obj->fd >= 0) {
+		DBG("File opened, setting io flags, cmd = %s",
+				obj->cmd);
+		if (obj->oflag == O_RDONLY)
+			obex_object_set_io_flags(user_data, G_IO_IN, 0);
+		else
+			obex_object_set_io_flags(user_data, G_IO_OUT, 0);
+	} else {
+		DBG("File open error, setting io error, cmd = %s",
+				obj->cmd);
+		obex_object_set_io_flags(user_data, G_IO_ERR, -EPERM);
+	}
+}
+
+static gboolean send_backup_dbus_message(const char *oper,
+					struct backup_object *obj,
+					size_t *size)
+{
+	DBusConnection *conn;
+	DBusMessage *msg;
+	DBusPendingCall *pending_call;
+	gboolean ret = FALSE;
+	dbus_uint32_t file_size;
+
+	file_size = size ? *size : 0;
+
+	conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
+
+	if (conn == NULL)
+		return FALSE;
+
+	msg = dbus_message_new_method_call(BACKUP_BUS_NAME, BACKUP_PATH,
+						BACKUP_PLUGIN_INTERFACE,
+						"request");
+	if (msg == NULL) {
+		dbus_connection_unref(conn);
+		return FALSE;
+	}
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &oper,
+					DBUS_TYPE_STRING, &obj->cmd,
+					DBUS_TYPE_INT32, &file_size,
+					DBUS_TYPE_INVALID);
+
+	if (strcmp(oper, "open") == 0) {
+		ret = dbus_connection_send_with_reply(conn, msg, &pending_call,
+							BACKUP_DBUS_TIMEOUT);
+		dbus_message_unref(msg);
+		if (ret) {
+			obj->conn = conn;
+			obj->pending_call = pending_call;
+			ret = dbus_pending_call_set_notify(pending_call,
+							on_backup_dbus_notify,
+							obj, NULL);
+		} else
+			dbus_connection_unref(conn);
+	} else {
+		ret = dbus_connection_send(conn, msg, NULL);
+		dbus_message_unref(msg);
+		dbus_connection_unref(conn);
+	}
+
+	return ret;
+}
+
+static void *backup_open(const char *name, int oflag, mode_t mode,
+				void *context, size_t *size, int *err)
+{
+	struct backup_object *obj = g_new0(struct backup_object, 1);
+
+	DBG("cmd = %s", name);
+
+	obj->cmd = g_path_get_basename(name);
+	obj->oflag = oflag;
+	obj->mode = mode;
+	obj->fd = -1;
+	obj->pending_call = NULL;
+	obj->conn = NULL;
+	obj->error_code = 0;
+
+	if (send_backup_dbus_message("open", obj, size) == FALSE) {
+		g_free(obj);
+		obj = NULL;
+	}
+
+	if (err)
+		*err = 0;
+
+	return obj;
+}
+
+static int backup_close(void *object)
+{
+	struct backup_object *obj = object;
+	size_t size = 0;
+
+	DBG("cmd = %s", obj->cmd);
+
+	if (obj->fd != -1)
+		close(obj->fd);
+
+	if (obj->pending_call) {
+		dbus_pending_call_cancel(obj->pending_call);
+		dbus_pending_call_unref(obj->pending_call);
+		dbus_connection_unref(obj->conn);
+	}
+
+	send_backup_dbus_message("close", obj, &size);
+
+	g_free(obj->cmd);
+	g_free(obj);
+
+	return 0;
+}
+
+static ssize_t backup_read(void *object, void *buf, size_t count, uint8_t *hi)
+{
+	struct backup_object *obj = object;
+	ssize_t ret = 0;
+
+	*hi = OBEX_HDR_BODY;
+
+	if (obj->pending_call) {
+		DBG("cmd = %s, IN WAITING STAGE", obj->cmd);
+		return -EAGAIN;
+	}
+
+	if (obj->fd != -1) {
+		DBG("cmd = %s, READING DATA", obj->cmd);
+		ret = read(obj->fd, buf, count);
+		if (ret < 0)
+			ret = -errno;
+	} else {
+		DBG("cmd = %s, PERMANENT FAILURE", obj->cmd);
+		ret = obj->error_code ? -obj->error_code : -ENOENT;
+	}
+
+	return ret;
+}
+
+static ssize_t backup_write(void *object, const void *buf, size_t count)
+{
+	struct backup_object *obj = object;
+	ssize_t ret = 0;
+
+	if (obj->pending_call) {
+		DBG("cmd = %s, IN WAITING STAGE", obj->cmd);
+		return -EAGAIN;
+	}
+
+	if (obj->fd != -1) {
+		ret = write(obj->fd, buf, count);
+
+		DBG("cmd = %s, WRITTING", obj->cmd);
+
+		if (ret < 0) {
+			error("backup: cmd = %s", obj->cmd);
+			ret = -errno;
+		}
+	} else {
+		error("backup: cmd = %s", obj->cmd);
+		ret = obj->error_code ? -obj->error_code : -ENOENT;
+	}
+
+	return ret;
+}
+
+static struct obex_mime_type_driver backup = {
+	.target = FTP_TARGET,
+	.mimetype = "application/vnd.nokia-backup",
+	.open = backup_open,
+	.close = backup_close,
+	.read = backup_read,
+	.write = backup_write,
+};
+
+static int backup_init(void)
+{
+	return obex_mime_type_driver_register(&backup);
+}
+
+static void backup_exit(void)
+{
+	obex_mime_type_driver_unregister(&backup);
+}
+
+OBEX_PLUGIN_DEFINE(backup, backup_init, backup_exit)
--- plugins/opp.c
+++ plugins/opp.c
@@ -37,7 +37,7 @@
 #include "plugin.h"
 #include "obex.h"
 #include "service.h"
-#include "logging.h"
+#include "log.h"
 #include "dbus.h"
 
 #define VCARD_TYPE "text/x-vcard"
@@ -140,6 +140,9 @@
 	if (name == NULL || strlen(name) == 0)
 		return -EBADR;
 
+	if (g_strcmp0(name, obex_get_name(os)) != 0)
+		obex_set_name(os, name);
+
 	path = g_build_filename(folder, name, NULL);
 
 	manager_emit_transfer_started(os);
--- plugins/pbap.c
+++ plugins/pbap.c
@@ -41,7 +41,7 @@
 #include <openobex/obex_const.h>
 
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 #include "obex.h"
 #include "service.h"
 #include "phonebook.h"
@@ -389,21 +389,21 @@
 		pbap->buffer = g_string_new_len(aparam, sizeof(aparam));
 		goto done;
 	}
-
-	/* Computing off set considering first entry of the phonebook */
-	l = g_slist_nth(pbap->cache.entries, pbap->params->liststartoffset);
-
 	/*
 	 * Don't free the sorted list content: this list contains
 	 * only the reference for the "real" cache entry.
 	 */
-	sorted = sort_entries(l, pbap->params->order,
+	sorted = sort_entries(pbap->cache.entries, pbap->params->order,
 			pbap->params->searchattrib,
 			(const char *) pbap->params->searchval);
 
+	/* Computing offset considering first entry of the phonebook */
+	l = g_slist_nth(sorted, pbap->params->liststartoffset);
+
 	pbap->buffer = g_string_new(VCARD_LISTING_BEGIN);
-	for (l = sorted; l && max; l = l->next, max--) {
+	for (; l && max; l = l->next, max--) {
 		const struct cache_entry *entry = l->data;
+
 		g_string_append_printf(pbap->buffer, VCARD_LISTING_ELEMENT,
 						entry->handle, entry->name);
 	}
@@ -431,7 +431,7 @@
 
 	id = cache_find(&pbap->cache, pbap->find_handle);
 	if (id == NULL) {
-		debug("Entry %d not found on cache", pbap->find_handle);
+		DBG("Entry %d not found on cache", pbap->find_handle);
 		obex_object_set_io_flags(pbap, G_IO_ERR, -ENOENT);
 		return;
 	}
@@ -657,7 +657,7 @@
 static int pbap_chkput(struct obex_session *os, void *user_data)
 {
 	/* Rejects all PUTs */
-	return -EINVAL;
+	return -EBADR;
 }
 
 static struct obex_service_driver pbap = {
@@ -698,9 +698,6 @@
 	if (ret < 0)
 		goto fail;
 
-	if (size)
-		*size = OBJECT_SIZE_UNKNOWN;
-
 	return pbap;
 
 fail:
@@ -737,9 +734,6 @@
 		goto fail;
 
 done:
-	if (size)
-		*size = OBJECT_SIZE_UNKNOWN;
-
 	return pbap;
 
 fail:
@@ -789,9 +783,6 @@
 	if (ret < 0)
 		goto fail;
 
-	if (size)
-		*size = OBJECT_SIZE_UNKNOWN;
-
 	return pbap;
 
 fail:
--- plugins/phonebook-dummy.c
+++ plugins/phonebook-dummy.c
@@ -41,7 +41,7 @@
 #include <libical/vobject.h>
 #include <libical/vcc.h>
 
-#include "logging.h"
+#include "log.h"
 #include "phonebook.h"
 
 typedef void (*vcard_func_t) (const char *file, VObject *vo, void *user_data);
@@ -221,7 +221,7 @@
 	dp = opendir(dummy->folder);
 	if (dp == NULL) {
 		int err = errno;
-		debug("opendir(): %s(%d)", strerror(err), err);
+		DBG("opendir(): %s(%d)", strerror(err), err);
 		goto done;
 	}
 
@@ -257,12 +257,18 @@
 	VObject *property, *subproperty;
 	GString *name;
 	const char *tel;
-	unsigned int handle;
+	long unsigned int handle;
 
 	property = isAPropertyOf(v, VCNameProp);
 	if (!property)
 		return;
 
+	if (sscanf(filename, "%lu.vcf", &handle) != 1)
+		return;
+
+	if (handle > UINT32_MAX)
+		return;
+
 	/* LastName; FirstName; MiddleName; Prefix; Suffix */
 
 	name = g_string_new("");
@@ -294,16 +300,11 @@
 				fakeCString(vObjectUStringZValue(subproperty)));
 
 	property = isAPropertyOf(v, VCTelephoneProp);
-	if (!property)
-		goto done;
 
-	tel = fakeCString(vObjectUStringZValue(property));
-	if (sscanf(filename, "%u.vcf", &handle) == 1)
-		handle = handle > UINT32_MAX ? UINT32_MAX : handle;
-		query->entry_cb(filename, handle, name->str, NULL, tel,
-							query->user_data);
+	tel = property ? fakeCString(vObjectUStringZValue(property)) : NULL;
 
-done:
+	query->entry_cb(filename, handle, name->str, NULL, tel,
+							query->user_data);
 	g_string_free(name, TRUE);
 }
 
@@ -493,7 +494,7 @@
 	fd = open(filename, O_RDONLY);
 	if (fd < 0) {
 		int err = errno;
-		debug("open(): %s(%d)", strerror(err), err);
+		DBG("open(): %s(%d)", strerror(err), err);
 		return -ENOENT;
 	}
 
@@ -521,7 +522,7 @@
 
 	if (dp == NULL) {
 		int err = errno;
-		debug("opendir(): %s(%d)", strerror(err), err);
+		DBG("opendir(): %s(%d)", strerror(err), err);
 		return -ENOENT;
 	}
 
--- plugins/phonebook-ebook.c
+++ plugins/phonebook-ebook.c
@@ -36,7 +36,7 @@
 
 #include <libebook/e-book.h>
 
-#include "logging.h"
+#include "log.h"
 #include "obex.h"
 #include "service.h"
 #include "phonebook.h"
--- plugins/phonebook-tracker.c
+++ plugins/phonebook-tracker.c
@@ -22,13 +22,15 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <time.h>
+#include <stdio.h>
 #include <errno.h>
 #include <glib.h>
 #include <dbus/dbus.h>
 #include <openobex/obex.h>
 #include <openobex/obex_const.h>
 
-#include "logging.h"
+#include "log.h"
 #include "obex.h"
 #include "service.h"
 #include "mimetype.h"
@@ -40,7 +42,7 @@
 #define TRACKER_RESOURCES_PATH "/org/freedesktop/Tracker1/Resources"
 #define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
 
-#define TRACKER_DEFAULT_CONTACT_ME "<urn:nco:default-contact-me>"
+#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
 
 #define CONTACTS_QUERY_ALL						\
 	"SELECT nco:phoneNumber(?h) nco:fullname(?c) "			\
@@ -49,26 +51,27 @@
 	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) "		\
 	"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) "	\
 	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) "				\
+	"nco:postalcode(?p) nco:country(?p) \"NOTACALL\" \"false\" "	\
+	"\"false\" ?c "							\
 	"WHERE { "							\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:PersonContact . "				\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
+	"OPTIONAL { ?c nco:hasEmailAddress ?e . } "			\
+	"OPTIONAL { ?c nco:hasPostalAddress ?p . } "			\
 	"OPTIONAL { "							\
 		"?c nco:hasAffiliation ?a . "				\
 		"?a nco:hasPhoneNumber ?w . "				\
-		"?c nco:hasEmailAddress ?e . "				\
-		"?c nco:hasPostalAddress ?p . "				\
 	"} "								\
 	"}"
 
 #define CONTACTS_QUERY_ALL_LIST						\
-	"SELECT nco:contactUID(?c) nco:nameFamily(?c) "			\
+	"SELECT ?c nco:nameFamily(?c) "					\
 	"nco:nameGiven(?c) nco:nameAdditional(?c) "			\
 	"nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c) "	\
 	"nco:phoneNumber(?h) "						\
 	"WHERE { "							\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:PersonContact . "				\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
 	"}"
 
 #define MISSED_CALLS_QUERY						\
@@ -78,24 +81,25 @@
 	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) "		\
 	"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) "	\
 	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) "				\
+	"nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) "	\
+	"nmo:isSent(?call) nmo:isAnswered(?call) ?c "			\
 	"WHERE { "							\
 		"?call a nmo:Call ; "					\
 		"nmo:from ?c ; "					\
 		"nmo:isSent false ; "					\
 		"nmo:isAnswered false ."				\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
+	"OPTIONAL { ?c nco:hasEmailAddress ?e . } "			\
+	"OPTIONAL { ?c nco:hasPostalAddress ?p . } "			\
 	"OPTIONAL { "							\
 		"?c nco:hasAffiliation ?a . "				\
 		"?a nco:hasPhoneNumber ?w . "				\
-		"?c nco:hasEmailAddress ?e . "				\
-		"?c nco:hasPostalAddress ?p . "				\
 	"} "								\
 	"} ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define MISSED_CALLS_LIST						\
-	"SELECT nco:contactUID(?c) nco:nameFamily(?c) "			\
+	"SELECT ?c nco:nameFamily(?c) "					\
 	"nco:nameGiven(?c) nco:nameAdditional(?c) "			\
 	"nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c) "	\
 	"nco:phoneNumber(?h) "						\
@@ -104,8 +108,8 @@
 		"nmo:from ?c ; "					\
 		"nmo:isSent false ; "					\
 		"nmo:isAnswered false ."				\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
 	"} ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define INCOMING_CALLS_QUERY						\
@@ -115,23 +119,24 @@
 	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) "		\
 	"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) "	\
 	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) "				\
+	"nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) "	\
+	"nmo:isSent(?call) nmo:isAnswered(?call) ?c "			\
 	"WHERE { "							\
 		"?call a nmo:Call ; "					\
 		"nmo:from ?c ; "					\
 		"nmo:isSent false . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
+	"OPTIONAL { ?c nco:hasEmailAddress ?e . } "			\
+	"OPTIONAL { ?c nco:hasPostalAddress ?p . } "			\
 	"OPTIONAL { "							\
 		"?c nco:hasAffiliation ?a . "				\
 		"?a nco:hasPhoneNumber ?w . "				\
-		"?c nco:hasEmailAddress ?e . "				\
-		"?c nco:hasPostalAddress ?p . "				\
 	"} "								\
 	"} ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define INCOMING_CALLS_LIST						\
-	"SELECT nco:contactUID(?c) nco:nameFamily(?c) "			\
+	"SELECT ?c nco:nameFamily(?c) "					\
 	"nco:nameGiven(?c) nco:nameAdditional(?c) "			\
 	"nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c) "	\
 	"nco:phoneNumber(?h) "						\
@@ -139,8 +144,8 @@
 		"?call a nmo:Call ; "					\
 		"nmo:from ?c ; "					\
 		"nmo:isSent false . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
 	"} ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define OUTGOING_CALLS_QUERY						\
@@ -150,23 +155,24 @@
 	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) "		\
 	"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) "	\
 	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) "				\
+	"nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) "	\
+	"nmo:isSent(?call) nmo:isAnswered(?call) ?c "			\
 	"WHERE { "							\
 		"?call a nmo:Call ; "					\
 		"nmo:to ?c ; "						\
 		"nmo:isSent true . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "			\
+	"OPTIONAL { ?c nco:hasEmailAddress ?e . } "			\
+	"OPTIONAL { ?c nco:hasPostalAddress ?p . } "			\
 	"OPTIONAL { "							\
 		"?c nco:hasAffiliation ?a . "				\
 		"?a nco:hasPhoneNumber ?w . "				\
-		"?c nco:hasEmailAddress ?e . "				\
-		"?c nco:hasPostalAddress ?p . "				\
 	"} "								\
 	"} ORDER BY DESC(nmo:sentDate(?call))"
 
 #define OUTGOING_CALLS_LIST						\
-	"SELECT nco:contactUID(?c) nco:nameFamily(?c) "			\
+	"SELECT ?c nco:nameFamily(?c) "					\
 	"nco:nameGiven(?c) nco:nameAdditional(?c) "			\
 	"nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c) "	\
 	"nco:phoneNumber(?h) "						\
@@ -174,8 +180,8 @@
 		"?call a nmo:Call ; "					\
 		"nmo:to ?c ; "						\
 		"nmo:isSent true . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+	"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "				\
 	"} ORDER BY DESC(nmo:sentDate(?call))"
 
 #define COMBINED_CALLS_QUERY						\
@@ -185,72 +191,72 @@
 	"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) "		\
 	"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) "	\
 	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) "				\
+	"nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) "	\
+	"nmo:isSent(?call) nmo:isAnswered(?call) ?c "			\
 	"WHERE { "							\
 	"{ "								\
 		"?call a nmo:Call ; "					\
 		"nmo:to ?c ; "						\
 		"nmo:isSent true . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+		"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "		\
+		"OPTIONAL { ?c nco:hasEmailAddress ?e . } "		\
+		"OPTIONAL { ?c nco:hasPostalAddress ?p . } "		\
 		"OPTIONAL { "						\
 			"?c nco:hasAffiliation ?a . "			\
 			"?a nco:hasPhoneNumber ?w . "			\
-			"?c nco:hasEmailAddress ?e . "			\
-			"?c nco:hasPostalAddress ?p . "			\
 		"} "							\
 	"} UNION { "							\
 		"?call a nmo:Call ; "					\
 		"nmo:from ?c ; "					\
 		"nmo:isSent false . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+		"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "		\
+		"OPTIONAL { ?c nco:hasEmailAddress ?e . } "		\
+		"OPTIONAL { ?c nco:hasPostalAddress ?p . } "		\
 		"OPTIONAL { "						\
 			"?c nco:hasAffiliation ?a . "			\
 			"?a nco:hasPhoneNumber ?w . "			\
-			"?c nco:hasEmailAddress ?e . "			\
-			"?c nco:hasPostalAddress ?p . "			\
 		"} "							\
-	"} } "
+	"} } ORDER BY DESC(nmo:receivedDate(?call))"
 
 #define COMBINED_CALLS_LIST						\
-	"SELECT nco:contactUID(?c) nco:nameFamily(?c) "			\
-	"nco:nameGiven(?c) nco:nameAdditional(?c) "			\
-	"nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c) "	\
-	"nco:phoneNumber(?h) "						\
+	"SELECT ?c nco:nameFamily(?c) nco:nameGiven(?c) "		\
+	"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) "		\
+	"nco:nameHonorificSuffix(?c) nco:phoneNumber(?h) "		\
 	"WHERE { "							\
 	"{ "								\
 		"?call a nmo:Call ; "					\
 		"nmo:to ?c ; "						\
 		"nmo:isSent true . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"?c a nco:Contact . "					\
+		"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "		\
 	"} UNION { "							\
 		"?call a nmo:Call ; "					\
 		"nmo:from ?c ; "					\
 		"nmo:isSent false . "					\
-		"?c a nco:PersonContact ; "				\
-		"nco:hasPhoneNumber ?h . "				\
-	"} } "
+		"?c a nco:Contact . "					\
+		"OPTIONAL { ?c nco:hasPhoneNumber ?h . } "		\
+	"} } ORDER BY DESC(nmo:receivedDate(?call))"
 
 
 #define CONTACTS_QUERY_FROM_URI						\
-	"SELECT nco:phoneNumber(?h) nco:fullname(?c) "			\
-	"nco:nameFamily(?c) nco:nameGiven(?c) nco:nameAdditional(?c) "	\
-	"nco:nameHonorificPrefix(?c) nco:nameHonorificSuffix(?c)  "	\
-	"nco:emailAddress(?e) "						\
+	"SELECT nco:phoneNumber(?h) nco:fullname(<%s>) "		\
+	"nco:nameFamily(<%s>) nco:nameGiven(<%s>) "			\
+	"nco:nameAdditional(<%s>) nco:nameHonorificPrefix(<%s>) "	\
+	"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) "		\
 	"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) "	\
 	"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) "	\
-	"nco:postalcode(?p) nco:country(?p) "				\
+	"nco:postalcode(?p) nco:country(?p) \"NOTACALL\" \"false\" "	\
+	"\"false\" <%s> "							\
 	"WHERE { "							\
-		"?c a nco:PersonContact ; "				\
-		"nco:contactUID <%s> ; "				\
-		"nco:hasPhoneNumber ?h . "				\
+		"<%s> a nco:Contact . "					\
+	"OPTIONAL { <%s> nco:hasPhoneNumber ?h . } "			\
+	"OPTIONAL { <%s> nco:hasEmailAddress ?e . } "			\
+	"OPTIONAL { <%s> nco:hasPostalAddress ?p . } "			\
 	"OPTIONAL { "							\
-		"?c nco:hasAffiliation ?a . "				\
+		"<%s> nco:hasAffiliation ?a . "				\
 		"?a nco:hasPhoneNumber ?w . "				\
-		"?c nco:hasEmailAddress ?e . "				\
-		"?c nco:hasPostalAddress ?p . "				\
 	"} "								\
 	"}"
 
@@ -305,6 +311,9 @@
 
 static gboolean folder_is_valid(const char *folder)
 {
+	if (folder == NULL)
+		return FALSE;
+
 	if (g_str_equal(folder, "/"))
 		return TRUE;
 	else if (g_str_equal(folder, "/telecom"))
@@ -418,6 +427,7 @@
 		node = string_array_from_iter(element, pending->num_fields);
 		pending->callback(node, pending->num_fields,
 							pending->user_data);
+
 		g_free(node);
 
 		dbus_message_iter_next(&element);
@@ -467,6 +477,68 @@
 	return 0;
 }
 
+static char *iso8601_utc_to_localtime(const char *datetime)
+{
+	time_t time;
+	struct tm tm, *local;
+	char localdate[32];
+	char tz;
+	int nr;
+
+	memset(&tm, 0, sizeof(tm));
+
+	nr = sscanf(datetime, "%04u-%02u-%02uT%02u:%02u:%02u%c",
+			&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+			&tm.tm_hour, &tm.tm_min, &tm.tm_sec,
+			&tz);
+	if (nr < 6) {
+		/* Invalid time format */
+		return g_strdup("");
+	}
+
+	/* Time already in localtime */
+	if (nr == 6)
+		return g_strdup(datetime);
+
+	tm.tm_year -= 1900;	/* Year since 1900 */
+	tm.tm_mon--;		/* Months since January, values 0-11 */
+
+	time = mktime(&tm);
+	time -= timezone;
+
+	local = localtime(&time);
+
+	strftime(localdate, sizeof(localdate), "%Y-%m-%dT%H:%M:%S", local);
+
+	return g_strdup(localdate);
+}
+
+static void set_call_type(struct phonebook_contact *contact,
+				const char *datetime, const char *is_sent,
+				const char *is_answered)
+{
+	gboolean sent, answered;
+
+	if (g_strcmp0(datetime, "NOTACALL") == 0) {
+		contact->calltype = CALL_TYPE_NOT_A_CALL;
+		return;
+	}
+
+	sent = g_str_equal(is_sent, "true");
+	answered = g_str_equal(is_answered, "true");
+
+	if (sent == FALSE) {
+		if (answered == FALSE)
+			contact->calltype = CALL_TYPE_MISSED;
+		else
+			contact->calltype = CALL_TYPE_INCOMING;
+	} else
+		contact->calltype = CALL_TYPE_OUTGOING;
+
+	/* Tracker gives time in the ISO 8601 format, UTC time */
+	contact->datetime = iso8601_utc_to_localtime(datetime);
+}
+
 static void pull_contacts(char **reply, int num_fields, void *user_data)
 {
 	struct phonebook_data *data = user_data;
@@ -474,7 +546,7 @@
 	struct phonebook_contact *contact;
 	struct phonebook_number *number;
 	GString *vcards = data->vcards;
-	int last_index;
+	int last_index, i;
 
 	DBG("reply %p", reply);
 
@@ -485,6 +557,16 @@
 	if (data->vcardentry)
 		goto add_entry;
 
+	/* Last four fields are always present, ignoring them */
+	for (i = 0; i < num_fields - 4; i++) {
+		if (reply[i][0] != '\0')
+			break;
+	}
+
+	if (i == num_fields - 4 &&
+			!g_str_equal(reply[19], TRACKER_DEFAULT_CONTACT_ME))
+		return;
+
 	data->index++;
 
 	/* Just interested in knowing the phonebook size */
@@ -493,7 +575,7 @@
 
 	last_index = params->liststartoffset + params->maxlistcount;
 
-	if (data->index < params->liststartoffset || data->index > last_index)
+	if (data->index <= params->liststartoffset || data->index > last_index)
 		return;
 
 add_entry:
@@ -513,6 +595,8 @@
 	contact->postal = g_strdup(reply[14]);
 	contact->country = g_strdup(reply[15]);
 
+	set_call_type(contact, reply[16], reply[17], reply[18]);
+
 	number = g_new0(struct phonebook_number, 1);
 	number->tel = g_strdup(reply[0]);
 	number->type = 0; /* HOME */
@@ -548,12 +632,27 @@
 {
 	struct cache_data *cache = user_data;
 	char *formatted;
+	int i;
 
 	if (reply == NULL)
 		goto done;
 
-	formatted = g_strdup_printf("%s;%s;%s;%s;%s", reply[1], reply[2],
-						reply[3], reply[4], reply[5]);
+	/* the first element is the URI, always not empty */
+	for (i = 1; i < num_fields; i++) {
+		if (reply[i][0] != '\0')
+			break;
+	}
+
+	if (i == num_fields &&
+			!g_str_equal(reply[0], TRACKER_DEFAULT_CONTACT_ME))
+		return;
+
+	if (i == 6)
+		formatted = g_strdup(reply[6]);
+	else
+		formatted = g_strdup_printf("%s;%s;%s;%s;%s",
+					reply[1], reply[2], reply[3], reply[4],
+					reply[5]);
 
 	/* The owner vCard must have the 0 handle */
 	if (strcmp(reply[0], TRACKER_DEFAULT_CONTACT_ME) == 0)
@@ -588,7 +687,8 @@
 {
 	char *tmp1, *tmp2, *base, *path = NULL;
 	gboolean root, child;
-	int ret, len;
+	int ret = 0;
+	int len;
 
 	root = (g_strcmp0("/", current_folder) == 0);
 	child = (new_folder && strlen(new_folder) != 0);
@@ -622,7 +722,6 @@
 		len = tmp2 - (current_folder + 1);
 
 		g_free(tmp1);
-		g_free(tmp2);
 
 		if (len == 0)
 			base = g_strdup("/");
@@ -645,13 +744,11 @@
 	}
 
 done:
-
-	if (!folder_is_valid(path)) {
+	if (ret || !folder_is_valid(path)) {
 		g_free(path);
 		path = NULL;
-		ret = -ENOENT;
-	} else
-		ret = 0;
+		ret = ret ? ret : -ENOENT;
+	}
 
 	if (err)
 		*err = ret;
@@ -677,7 +774,7 @@
 	data->user_data = user_data;
 	data->cb = cb;
 
-	return query_tracker(query, 16, pull_contacts, data);
+	return query_tracker(query, 20, pull_contacts, data);
 }
 
 int phonebook_get_entry(const char *folder, const char *id,
@@ -697,9 +794,10 @@
 	data->cb = cb;
 	data->vcardentry = TRUE;
 
-	query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id);
+	query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id, id,
+						id, id, id, id, id, id, id);
 
-	ret = query_tracker(query, 16, pull_contacts, data);
+	ret = query_tracker(query, 20, pull_contacts, data);
 
 	g_free(query);
 
--- plugins/syncevolution.c
+++ plugins/syncevolution.c
@@ -41,7 +41,7 @@
 #include "obex.h"
 #include "service.h"
 #include "mimetype.h"
-#include "logging.h"
+#include "log.h"
 #include "dbus.h"
 #include "btio.h"
 #include "obexd.h"
@@ -170,7 +170,7 @@
 		goto failed;
 	}
 
-	debug("Got conn object %s from syncevolution", path);
+	DBG("Got conn object %s from syncevolution", path);
 	context->conn_obj = g_strdup(path);
 
 	context->reply_watch = g_dbus_add_signal_watch(conn, NULL, path,
--- plugins/usb.c
+++ plugins/usb.c
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#include "plugin.h"
+#include "server.h"
+#include "obex.h"
+#include "transport.h"
+#include "service.h"
+#include "log.h"
+
+static GIOChannel *usb_io = NULL;
+static guint usb_reconnecting = 0;
+static guint usb_watch = 0;
+static DBusConnection *connection = NULL;
+
+#define USB_RX_MTU 65535
+#define USB_TX_MTU 65535
+#define USB_DEVNODE "/dev/ttyGS0"
+
+static int usb_connect(struct obex_server *server);
+
+static void usb_disconnect(struct obex_server *server)
+{
+	if (usb_reconnecting > 0) {
+		g_source_remove(usb_reconnecting);
+		usb_reconnecting = 0;
+	}
+
+	if (usb_watch > 0) {
+		g_source_remove(usb_watch);
+		usb_watch = 0;
+	}
+
+	/* already disconnected */
+	if (usb_io == NULL)
+		return;
+
+	g_io_channel_shutdown(usb_io, TRUE, NULL);
+	g_io_channel_unref(usb_io);
+	usb_io = NULL;
+	DBG("disconnected");
+}
+
+static gboolean usb_reconnect(void *data)
+{
+	struct obex_server *server = data;
+
+	DBG("reconnecting");
+	usb_reconnecting = 0;
+	usb_connect(server);
+
+	return FALSE;
+}
+
+static gboolean usb_watchdog(GIOChannel *io, GIOCondition cond,
+				void *user_data)
+{
+	struct obex_server *server = user_data;
+
+	usb_watch = 0;
+	usb_disconnect(server);
+
+	if ((cond & G_IO_NVAL) == FALSE)
+		usb_reconnecting = g_idle_add(usb_reconnect, server);
+
+	return FALSE;
+}
+
+static int usb_connect(struct obex_server *server)
+{
+	struct termios options;
+	int fd, err, arg;
+	glong flags;
+
+	if (usb_reconnecting > 0) {
+		g_source_remove(usb_reconnecting);
+		usb_reconnecting = 0;
+	}
+
+	/* already connected */
+	if (usb_io != NULL)
+		return 0;
+
+	fd = open(USB_DEVNODE, O_RDWR | O_NOCTTY);
+	if (fd < 0)
+		return fd;
+
+	flags = fcntl(fd, F_GETFL);
+	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+
+	tcgetattr(fd, &options);
+	cfmakeraw(&options);
+	options.c_oflag &= ~ONLCR;
+	tcsetattr(fd, TCSANOW, &options);
+
+	arg = fcntl(fd, F_GETFL);
+	if (arg < 0) {
+		err = -errno;
+		goto failed;
+	}
+
+	arg |= O_NONBLOCK;
+	if (fcntl(fd, F_SETFL, arg) < 0) {
+		err = -errno;
+		goto failed;
+	}
+
+	usb_io = g_io_channel_unix_new(fd);
+	g_io_channel_set_close_on_unref(usb_io, TRUE);
+
+	err = obex_server_new_connection(server, usb_io,
+					USB_TX_MTU, USB_RX_MTU);
+	if (err < 0)
+		goto failed;
+
+	usb_watch = g_io_add_watch(usb_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					usb_watchdog, server);
+
+	DBG("Successfully opened %s", USB_DEVNODE);
+
+	return 0;
+
+failed:
+	error("usb: %s (%d)", strerror(-err), -err);
+	if (usb_io == NULL)
+		close(fd);
+	else
+		usb_disconnect(server);
+	return err;
+}
+
+static void sig_usb(int sig)
+{
+}
+
+static gboolean handle_signal(DBusConnection *connection,
+				DBusMessage *message, void *user_data)
+{
+	struct obex_server *server = user_data;
+	const char *state;
+
+	dbus_message_get_args(message, NULL,
+				DBUS_TYPE_STRING, &state,
+				DBUS_TYPE_INVALID);
+
+	if (g_str_equal(state, "ovi_suite") == TRUE)
+		usb_connect(server);
+	else if (g_str_equal(state, "USB disconnected") == TRUE)
+		usb_disconnect(server);
+
+	return TRUE;
+}
+
+static void usb_stop(void *data)
+{
+	guint id = GPOINTER_TO_UINT(data);
+	g_source_remove(id);
+}
+
+static void *usb_start(struct obex_server *server, int *err)
+{
+	guint id;
+
+	id = g_dbus_add_signal_watch(connection, NULL, NULL,
+					"com.meego.usb_moded",
+					"sig_usb_state_ind",
+					handle_signal, server, NULL);
+	if (err != NULL)
+		*err = 0;
+
+	return GUINT_TO_POINTER(id);
+}
+
+static struct obex_transport_driver driver = {
+	.name = "usb",
+	.service = OBEX_PCSUITE,
+	.start = usb_start,
+	.stop = usb_stop
+};
+
+static int usb_init(void)
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = sig_usb;
+	sigaction(SIGUSR1, &sa, NULL);
+	sigaction(SIGHUP, &sa, NULL);
+
+	connection = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
+	if (connection == NULL)
+		return -EPERM;
+
+	return obex_transport_driver_register(&driver);
+}
+
+static void usb_exit(void)
+{
+	if (connection)
+		dbus_connection_unref(connection);
+
+	obex_transport_driver_unregister(&driver);
+}
+
+OBEX_PLUGIN_DEFINE(usb, usb_init, usb_exit)
--- plugins/vcard.c
+++ plugins/vcard.c
@@ -133,9 +133,43 @@
 		vcard_printf(vcards, "VERSION:2.1");
 }
 
+/* check if there is at least one contact field with personal data present */
+static gboolean contact_fields_present(struct phonebook_contact * contact)
+{
+	if (contact->family && strlen(contact->family) > 0)
+		return TRUE;
+
+	if (contact->given && strlen(contact->given) > 0)
+		return TRUE;
+
+	if (contact->additional && strlen(contact->additional) > 0)
+		return TRUE;
+
+	if (contact->prefix && strlen(contact->prefix) > 0)
+		return TRUE;
+
+	if (contact->suffix && strlen(contact->suffix) > 0)
+		return TRUE;
+
+	/* none of the personal data fields are present*/
+	return FALSE;
+}
+
 static void vcard_printf_name(GString *vcards,
 					struct phonebook_contact *contact)
 {
+	if (contact_fields_present(contact) == FALSE) {
+		/* If fields are empty, add only 'N:' as parameter.
+		 * This is crucial for some devices (Nokia BH-903) which
+		 * have problems with history listings and can't determine
+		 * that a parameter is really empty if there are unnecessary
+		 * characters after 'N:' (e.g. 'N:;;;;').
+		 * We need to add only'N:' param - without semicolons.
+		 */
+		vcard_printf(vcards, "N:");
+		return;
+	}
+
 	vcard_printf(vcards, "N:%s;%s;%s;%s;%s", contact->family,
 				contact->given, contact->additional,
 				contact->prefix, contact->suffix);
@@ -148,38 +182,57 @@
 	vcard_printf(vcards, "FN:%s", field);
 }
 
-static void vcard_printf_number(GString *vcards, const char *number, int type,
+static void vcard_printf_number(GString *vcards, uint8_t format,
+					const char *number, int type,
 					enum phonebook_number_type category)
 {
-	char *pref = "", *intl = "", *category_string = "";
+	const char *intl = "", *category_string = "";
 	char buf[128];
 
-	if (!number || !strlen(number) || !type)
+	/* TEL is a mandatory field, include even if empty */
+	if (!number || !strlen(number) || !type) {
+		vcard_printf(vcards, "TEL:");
 		return;
+	}
 
 	switch (category) {
 	case TEL_TYPE_HOME:
-		category_string = "HOME,VOICE";
+		if (format == FORMAT_VCARD21)
+			category_string = "HOME;VOICE";
+		else if (format == FORMAT_VCARD30)
+			category_string = "TYPE=HOME;TYPE=VOICE";
 		break;
 	case TEL_TYPE_MOBILE:
-		category_string = "CELL,VOICE";
+		if (format == FORMAT_VCARD21)
+			category_string = "CELL;VOICE";
+		else if (format == FORMAT_VCARD30)
+			category_string = "TYPE=CELL;TYPE=VOICE";
 		break;
 	case TEL_TYPE_FAX:
-		category_string = "FAX";
+		if (format == FORMAT_VCARD21)
+			category_string = "FAX";
+		else if (format == FORMAT_VCARD30)
+			category_string = "TYPE=FAX";
 		break;
 	case TEL_TYPE_WORK:
-		category_string = "WORK,VOICE";
+		if (format == FORMAT_VCARD21)
+			category_string = "WORK;VOICE";
+		else if (format == FORMAT_VCARD30)
+			category_string = "TYPE=WORK;TYPE=VOICE";
 		break;
 	case TEL_TYPE_OTHER:
-		category_string = "VOICE";
+		if (format == FORMAT_VCARD21)
+			category_string = "VOICE";
+		else if (format == FORMAT_VCARD30)
+			category_string = "TYPE=VOICE";
 		break;
 	}
 
 	if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
 		intl = "+";
 
-	snprintf(buf, sizeof(buf), "TEL;TYPE=\%s%s:\%s\%s", pref,
-			category_string, intl, number);
+	snprintf(buf, sizeof(buf), "TEL;%s:%s\%s", category_string, intl, number);
+
 	vcard_printf(vcards, buf, number);
 }
 
@@ -206,6 +259,33 @@
 					contact->postal, contact->country);
 }
 
+static void vcard_printf_datetime(GString *vcards,
+					struct phonebook_contact *contact)
+{
+	const char *type;
+
+	switch (contact->calltype) {
+	case CALL_TYPE_MISSED:
+		type = "MISSED";
+		break;
+
+	case CALL_TYPE_INCOMING:
+		type = "RECEIVED";
+		break;
+
+	case CALL_TYPE_OUTGOING:
+		type = "DIALED";
+		break;
+
+	case CALL_TYPE_NOT_A_CALL:
+	default:
+		return;
+	}
+
+	vcard_printf(vcards, "X-IRMC-CALL-DATETIME;%s:%s", type,
+							contact->datetime);
+}
+
 static void vcard_printf_end(GString *vcards)
 {
 	vcard_printf(vcards, "END:VCARD");
@@ -227,18 +307,11 @@
 
 	vcard_printf_begin(vcards, format);
 
-	if (filter & FILTER_FN) {
-		char* fullname;
-		if (contact->fullname == NULL || contact->fullname[0] == '\0') {
-			struct phonebook_number *number;
-
-			number = contact->numbers->data;
-			fullname = number->tel;
-		} else
-			fullname = contact->fullname;
+	if (filter & FILTER_N)
+		vcard_printf_name(vcards, contact);
 
-		vcard_printf_fullname(vcards, fullname);
-	}
+	if (filter & FILTER_FN)
+		vcard_printf_fullname(vcards, contact->fullname);
 
 	if (filter & FILTER_TEL) {
 		GSList *l;
@@ -246,20 +319,20 @@
 		for (l = contact->numbers; l; l = l->next) {
 			struct phonebook_number *number = l->data;
 
-			vcard_printf_number(vcards, number->tel, 1,
+			vcard_printf_number(vcards, format, number->tel, 1,
 								number->type);
 		}
 	}
 
-	if (filter & FILTER_N)
-		vcard_printf_name(vcards, contact);
-
 	if (filter & FILTER_EMAIL)
 		vcard_printf_email(vcards, contact->email);
 
 	if (filter & FILTER_ADR)
 		vcard_printf_adr(vcards, contact);
 
+	if (filter & FILTER_X_IRMC_CALL_DATETIME)
+		vcard_printf_datetime(vcards, contact);
+
 	vcard_printf_end(vcards);
 }
 
@@ -293,5 +366,6 @@
 	g_free(contact->region);
 	g_free(contact->postal);
 	g_free(contact->country);
+	g_free(contact->datetime);
 	g_free(contact);
 }
--- plugins/vcard.h
+++ plugins/vcard.h
@@ -27,6 +27,13 @@
 	TEL_TYPE_OTHER,
 };
 
+enum phonebook_call_type {
+	CALL_TYPE_NOT_A_CALL,
+	CALL_TYPE_MISSED,
+	CALL_TYPE_INCOMING,
+	CALL_TYPE_OUTGOING,
+};
+
 struct phonebook_number {
 	char *tel;
 	int type;
@@ -48,6 +55,8 @@
 	char *region;
 	char *postal;
 	char *country;
+	char *datetime;
+	int calltype;
 };
 
 void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
--- src/bluetooth.c
+++ src/bluetooth.c
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2007-2010  Nokia Corporation
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <glib.h>
-
-#include <openobex/obex.h>
-
-#include "logging.h"
-#include "bluetooth.h"
-#include "obex.h"
-#include "obex-priv.h"
-#include "dbus.h"
-#include "btio.h"
-#include "service.h"
-
-#define BT_RX_MTU 32767
-#define BT_TX_MTU 32767
-
-static GSList *servers = NULL;
-
-static void confirm_event(GIOChannel *io, void *user_data)
-{
-	struct server *server = user_data;
-	struct obex_service_driver *driver;
-	GError *err = NULL;
-	char address[18];
-	uint8_t channel;
-
-	bt_io_get(io, BT_IO_RFCOMM, &err,
-			BT_IO_OPT_DEST, address,
-			BT_IO_OPT_CHANNEL, &channel,
-			BT_IO_OPT_INVALID);
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-		goto drop;
-	}
-
-	info("New connection from: %s, channel %u", address, channel);
-
-	driver = (struct obex_service_driver *) server->drivers->data;
-
-	if (driver->service != OBEX_OPP) {
-		if (request_service_authorization(server, io, address) < 0)
-			goto drop;
-
-		return;
-	}
-
-	if (!bt_io_accept(io, obex_connect_cb, server, NULL, &err)) {
-		error("%s", err->message);
-		g_error_free(err);
-		goto drop;
-	}
-
-	return;
-
-drop:
-	g_io_channel_shutdown(io, TRUE, NULL);
-}
-
-static int server_start(struct server *server)
-{
-	GError *err = NULL;
-	struct obex_service_driver *driver;
-	BtIOSecLevel sec_level;
-
-	driver = (struct obex_service_driver *) server->drivers->data;
-
-	if (server->secure)
-		sec_level = BT_IO_SEC_MEDIUM;
-	else
-		sec_level = BT_IO_SEC_LOW;
-
-	server->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event,
-					server, NULL, &err,
-					BT_IO_OPT_CHANNEL, driver->channel,
-					BT_IO_OPT_SEC_LEVEL, sec_level,
-					BT_IO_OPT_INVALID);
-	if (!server->io)
-		goto failed;
-
-	return 0;
-
-failed:
-	error("Bluetooth server register failed: %s", err->message);
-	g_error_free(err);
-
-	return -EINVAL;
-}
-
-static int server_stop(struct server *server)
-{
-	if (!server->io)
-		return -EINVAL;
-
-	if (server->watch) {
-		g_source_remove(server->watch);
-		server->watch = 0;
-	}
-
-	g_io_channel_shutdown(server->io, TRUE, NULL);
-	g_io_channel_unref(server->io);
-	server->io = NULL;
-
-	return 0;
-}
-
-static int server_register(uint16_t service, const char *folder,
-				gboolean secure, gboolean auto_accept,
-				gboolean symlinks, const char *capability)
-{
-	struct server *server;
-	GSList *drivers;
-
-	drivers = obex_service_driver_list(service);
-	if (drivers == NULL)
-		return -EINVAL;
-
-	server = g_new0(struct server, 1);
-	server->drivers = drivers;
-	server->folder = g_strdup(folder);
-	server->auto_accept = auto_accept;
-	server->symlinks = symlinks;
-	server->capability = g_strdup(capability);
-	server->secure = secure;
-	server->rx_mtu = BT_RX_MTU;
-	server->tx_mtu = BT_TX_MTU;
-
-	servers = g_slist_append(servers, server);
-
-	return 0;
-}
-
-int bluetooth_init(unsigned int service, const char *folder, gboolean secure,
-				gboolean auto_accept, gboolean symlinks,
-				const char *capability)
-{
-	return server_register(service, folder, secure, auto_accept, symlinks,
-								capability);
-}
-
-void bluetooth_exit(void)
-{
-	return;
-}
-
-void bluetooth_start(void)
-{
-	GSList *l;
-
-	for (l = servers; l; l = l->next) {
-		struct server *server = l->data;
-
-		if (server_start(server) < 0)
-			continue;
-
-		register_record(server);
-	}
-}
-
-void bluetooth_stop(void)
-{
-	GSList *l;
-
-	for (l = servers; l; l = l->next) {
-		struct server *server = l->data;
-
-		server_stop(server);
-	}
-}
--- src/bluetooth.h
+++ src/bluetooth.h
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2007-2010  Nokia Corporation
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-int bluetooth_init(unsigned int service, const char *folder, gboolean secure,
-				gboolean auto_accept, gboolean symlinks,
-				const char *capability);
-void bluetooth_exit(void);
-void bluetooth_start(void);
-void bluetooth_stop(void);
--- src/log.c
+++ src/log.c
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <openobex/obex.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+void info(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	vsyslog(LOG_INFO, format, ap);
+
+	va_end(ap);
+}
+
+void error(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	vsyslog(LOG_ERR, format, ap);
+
+	va_end(ap);
+}
+
+void obex_debug(const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	vsyslog(LOG_DEBUG, format, ap);
+
+	va_end(ap);
+}
+
+extern struct obex_debug_desc __start___debug[];
+extern struct obex_debug_desc __stop___debug[];
+
+static gchar **enabled = NULL;
+
+static gboolean is_enabled(struct obex_debug_desc *desc)
+{
+	int i;
+
+	if (enabled == NULL)
+		return 0;
+
+	for (i = 0; enabled[i] != NULL; i++) {
+		if (desc->name != NULL && g_pattern_match_simple(enabled[i],
+							desc->name) == TRUE)
+			return 1;
+		if (desc->file != NULL && g_pattern_match_simple(enabled[i],
+							desc->file) == TRUE)
+			return 1;
+	}
+
+	return 0;
+}
+
+void __obex_log_enable_debug()
+{
+	struct obex_debug_desc *desc;
+
+	for (desc = __start___debug; desc < __stop___debug; desc++)
+		desc->flags |= OBEX_DEBUG_FLAG_PRINT;
+}
+
+void __obex_log_init(const char *debug, int detach)
+{
+	int option = LOG_NDELAY | LOG_PID;
+	struct obex_debug_desc *desc;
+	const char *name = NULL, *file = NULL;
+
+	if (debug != NULL)
+		enabled = g_strsplit_set(debug, ":, ", 0);
+
+	for (desc = __start___debug; desc < __stop___debug; desc++) {
+		if (file != NULL || name != NULL) {
+			if (g_strcmp0(desc->file, file) == 0) {
+				if (desc->name == NULL)
+					desc->name = name;
+			} else
+				file = NULL;
+		}
+
+		if (is_enabled(desc))
+			desc->flags |= OBEX_DEBUG_FLAG_PRINT;
+	}
+
+	if (!detach)
+		option |= LOG_PERROR;
+
+	openlog("obexd", option, LOG_DAEMON);
+
+	syslog(LOG_INFO, "OBEX daemon %s", VERSION);
+}
+
+void __obex_log_cleanup(void)
+{
+	closelog();
+
+	g_strfreev(enabled);
+}
--- src/log.h
+++ src/log.h
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at 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
+ *
+ */
+
+void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void obex_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void __obex_log_init(const char *debug, int detach);
+void __obex_log_cleanup(void);
+void __obex_log_enable_debug(void);
+
+struct obex_debug_desc {
+	const char *name;
+	const char *file;
+#define OBEX_DEBUG_FLAG_DEFAULT (0)
+#define OBEX_DEBUG_FLAG_PRINT   (1 << 0)
+	unsigned int flags;
+} __attribute__((aligned(8)));
+
+/**
+ * DBG:
+ * @fmt: format string
+ * @arg...: list of arguments
+ *
+ * Simple macro around debug() which also include the function
+ * name it is called in.
+ */
+#define DBG(fmt, arg...) do { \
+	static struct obex_debug_desc __obex_debug_desc \
+	__attribute__((used, section("__debug"), aligned(8))) = { \
+		.file = __FILE__, .flags = OBEX_DEBUG_FLAG_DEFAULT, \
+	}; \
+	if (__obex_debug_desc.flags & OBEX_DEBUG_FLAG_PRINT) \
+		obex_debug("%s:%s() " fmt,  __FILE__, __FUNCTION__ , ## arg); \
+} while (0)
--- src/logging.c
+++ src/logging.c
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <syslog.h>
-
-#include <openobex/obex.h>
-
-#include "logging.h"
-
-static volatile int debug_enabled = 0;
-
-static inline void vinfo(const char *format, va_list ap)
-{
-	vsyslog(LOG_INFO, format, ap);
-}
-
-void info(const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-
-	vinfo(format, ap);
-
-	va_end(ap);
-}
-
-void error(const char *format, ...)
-{
-	va_list ap;
-
-	va_start(ap, format);
-
-	vsyslog(LOG_ERR, format, ap);
-
-	va_end(ap);
-}
-
-void debug(const char *format, ...)
-{
-	va_list ap;
-
-	if (!debug_enabled)
-		return;
-
-	va_start(ap, format);
-
-	vsyslog(LOG_DEBUG, format, ap);
-
-	va_end(ap);
-}
-
-void toggle_debug(void)
-{
-	debug_enabled = (debug_enabled + 1) % 2;
-}
-
-void enable_debug(void)
-{
-	debug_enabled = 1;
-}
-
-void disable_debug(void)
-{
-	debug_enabled = 0;
-}
-
-void start_logging(const char *ident, const char *message, ...)
-{
-	va_list ap;
-
-	openlog(ident, LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-
-	va_start(ap, message);
-
-	vinfo(message, ap);
-
-	va_end(ap);
-}
-
-void stop_logging(void)
-{
-	closelog();
-}
-
-static struct {
-	int evt;
-	const char *name;
-} obex_event[] = {
-	/* Progress has been made */
-	{ OBEX_EV_PROGRESS,	"PROGRESS"	},
-	/* An incoming request is about to come */
-	{ OBEX_EV_REQHINT,	"REQHINT"	},
-	/* An incoming request has arrived */
-	{ OBEX_EV_REQ,		"REQ"		},
-	/* Request has finished */
-	{ OBEX_EV_REQDONE,	"REQDONE"	},
-	/* Link has been disconnected */
-	{ OBEX_EV_LINKERR,	"LINKERR"	},
-	/* Malformed data encountered */
-	{ OBEX_EV_PARSEERR,	"PARSEERR"	},
-	/* Connection accepted */
-	{ OBEX_EV_ACCEPTHINT,	"ACCEPTHINT"	},
-	/* Request was aborted */
-	{ OBEX_EV_ABORT,	"ABORT"		},
-	/* Need to feed more data when sending a stream */
-	{ OBEX_EV_STREAMEMPTY,	"STREAMEMPTY"	},
-	/* Time to pick up data when receiving a stream */
-	{ OBEX_EV_STREAMAVAIL,	"STREAMAVAIL"	},
-	/* Unexpected data, not fatal */
-	{ OBEX_EV_UNEXPECTED,	"UNEXPECTED"	},
-	/* First packet of an incoming request has been parsed */
-	{ OBEX_EV_REQCHECK,	"REQCHECK"	},
-	{ 0xFF,			NULL		},
-};
-
-/* Possible commands */
-static struct {
-	int cmd;
-	const char *name;
-} obex_command[] = {
-	{ OBEX_CMD_CONNECT,	"CONNECT"	},
-	{ OBEX_CMD_DISCONNECT,	"DISCONNECT"	},
-	{ OBEX_CMD_PUT,		"PUT"		},
-	{ OBEX_CMD_GET,		"GET"		},
-	{ OBEX_CMD_SETPATH,	"SETPATH"	},
-	{ OBEX_CMD_SESSION,	"SESSION"	},
-	{ OBEX_CMD_ABORT,	"ABORT"		},
-	{ OBEX_FINAL,		"FINAL"		},
-	{ 0xFF,			NULL		},
-};
-
-/* Possible Response */
-static struct {
-	int rsp;
-	const char *name;
-} obex_response[] = {
-	{ OBEX_RSP_CONTINUE,			"CONTINUE"		},
-	{ OBEX_RSP_SWITCH_PRO,			"SWITCH_PRO"		},
-	{ OBEX_RSP_SUCCESS,			"SUCCESS"		},
-	{ OBEX_RSP_CREATED, 			"CREATED"		},
-	{ OBEX_RSP_ACCEPTED,			"ACCEPTED"		},
-	{ OBEX_RSP_NON_AUTHORITATIVE,		"NON_AUTHORITATIVE"	},
-	{ OBEX_RSP_NO_CONTENT,			"NO_CONTENT"		},
-	{ OBEX_RSP_RESET_CONTENT,		"RESET_CONTENT"		},
-	{ OBEX_RSP_PARTIAL_CONTENT,		"PARTIAL_CONTENT"	},
-	{ OBEX_RSP_MULTIPLE_CHOICES,		"MULTIPLE_CHOICES"	},
-	{ OBEX_RSP_MOVED_PERMANENTLY,		"MOVED_PERMANENTLY"	},
-	{ OBEX_RSP_MOVED_TEMPORARILY,		"MOVED_TEMPORARILY"	},
-	{ OBEX_RSP_SEE_OTHER,			"SEE_OTHER"		},
-	{ OBEX_RSP_NOT_MODIFIED,		"NOT_MODIFIED"		},
-	{ OBEX_RSP_USE_PROXY,			"USE_PROXY"		},
-	{ OBEX_RSP_BAD_REQUEST,			"BAD_REQUEST"		},
-	{ OBEX_RSP_UNAUTHORIZED,		"UNAUTHORIZED"		},
-	{ OBEX_RSP_PAYMENT_REQUIRED,		"PAYMENT_REQUIRED"	},
-	{ OBEX_RSP_FORBIDDEN,			"FORBIDDEN"		},
-	{ OBEX_RSP_NOT_FOUND,			"NOT_FOUND"		},
-	{ OBEX_RSP_METHOD_NOT_ALLOWED,		"METHOD_NOT_ALLOWED"	},
-	{ OBEX_RSP_NOT_ACCEPTABLE,		"NOT_ACCEPTABLE"	},
-	{ OBEX_RSP_PROXY_AUTH_REQUIRED,		"PROXY_AUTH_REQUIRED"	},
-	{ OBEX_RSP_REQUEST_TIME_OUT,		"REQUEST_TIME_OUT"	},
-	{ OBEX_RSP_CONFLICT,			"CONFLICT"		},
-	{ OBEX_RSP_GONE,			"GONE"			},
-	{ OBEX_RSP_LENGTH_REQUIRED,		"LENGTH_REQUIRED"	},
-	{ OBEX_RSP_PRECONDITION_FAILED,		"PRECONDITION_FAILED"	},
-	{ OBEX_RSP_REQ_ENTITY_TOO_LARGE,	"REQ_ENTITY_TOO_LARGE"	},
-	{ OBEX_RSP_REQ_URL_TOO_LARGE,		"REQ_URL_TOO_LARGE"	},
-	{ OBEX_RSP_UNSUPPORTED_MEDIA_TYPE,	"UNSUPPORTED_MEDIA_TYPE"},
-	{ OBEX_RSP_INTERNAL_SERVER_ERROR,	"INTERNAL_SERVER_ERROR"	},
-	{ OBEX_RSP_NOT_IMPLEMENTED,		"NOT_IMPLEMENTED"	},
-	{ OBEX_RSP_BAD_GATEWAY,			"BAD_GATEWAY"		},
-	{ OBEX_RSP_SERVICE_UNAVAILABLE,		"SERVICE_UNAVAILABLE"	},
-	{ OBEX_RSP_GATEWAY_TIMEOUT,		"GATEWAY_TIMEOUT"	},
-	{ OBEX_RSP_VERSION_NOT_SUPPORTED,	"VERSION_NOT_SUPPORTED"	},
-	{ OBEX_RSP_DATABASE_FULL,		"DATABASE_FULL"		},
-	{ OBEX_RSP_DATABASE_LOCKED,		"DATABASE_LOCKED"	},
-	{ 0xFF,					NULL			},
-};
-
-void obex_debug(int evt, int cmd, int rsp)
-{
-	const char *evtstr = NULL, *cmdstr = NULL, *rspstr = NULL;
-	int i;
-
-	if (!debug_enabled)
-		return;
-
-	for (i = 0; obex_event[i].evt != 0xFF; i++) {
-		if (obex_event[i].evt != evt)
-			continue;
-		evtstr = obex_event[i].name;
-	}
-
-	for (i = 0; obex_command[i].cmd != 0xFF; i++) {
-		if (obex_command[i].cmd != cmd)
-			continue;
-		cmdstr = obex_command[i].name;
-	}
-
-	for (i = 0; obex_response[i].rsp != 0xFF; i++) {
-		if (obex_response[i].rsp != rsp)
-			continue;
-		rspstr = obex_response[i].name;
-	}
-
-	debug("%s(0x%x), %s(0x%x), %s(0x%x)", evtstr, evt, cmdstr, cmd,
-								rspstr, rsp);
-}
--- src/logging.h
+++ src/logging.h
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at 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
- *
- */
-
-void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
-void obex_debug(int evt, int cmd, int rsp);
-void toggle_debug(void);
-void enable_debug(void);
-void disable_debug(void);
-void start_logging(const char *ident, const char *message, ...);
-void stop_logging(void);
-
-#define DBG(fmt, arg...)  debug("%s: " fmt "\n" , __FUNCTION__ , ## arg)
-//#define DBG(fmt, arg...)
--- src/main.c
+++ src/main.c
@@ -45,11 +45,11 @@
 #include <openobex/obex.h>
 #include <openobex/obex_const.h>
 
-#include "logging.h"
-#include "bluetooth.h"
+#include "log.h"
 #include "obexd.h"
 #include "obex.h"
 #include "obex-priv.h"
+#include "server.h"
 #include "service.h"
 
 #define DEFAULT_ROOT_PATH "/tmp"
@@ -58,92 +58,6 @@
 
 static GMainLoop *main_loop = NULL;
 
-static int services = 0;
-static gboolean tty_needs_reinit = FALSE;
-static gboolean tty_open_allowed = TRUE;
-static int signal_pipe[2];
-
-#define TTY_RX_MTU 65535
-#define TTY_TX_MTU 65535
-
-int tty_init(int services, const char *root_path,
-		const char *capability, gboolean symlinks,
-		const char *devnode)
-{
-	struct server *server;
-	struct termios options;
-	int fd, err, arg;
-	glong flags;
-	GIOChannel *io = NULL;
-
-	tty_needs_reinit = TRUE;
-
-	if (!tty_open_allowed)
-		return -EACCES;
-
-	fd = open(devnode, O_RDWR | O_NOCTTY);
-	if (fd < 0)
-		return fd;
-
-	flags = fcntl(fd, F_GETFL);
-	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
-
-	tcgetattr(fd, &options);
-	cfmakeraw(&options);
-	options.c_oflag &= ~ONLCR;
-	tcsetattr(fd, TCSANOW, &options);
-
-	arg = fcntl(fd, F_GETFL);
-	if (arg < 0) {
-		err = -errno;
-		goto failed;
-	}
-
-	arg |= O_NONBLOCK;
-	if (fcntl(fd, F_SETFL, arg) < 0) {
-		err = -errno;
-		goto failed;
-	}
-
-	server = g_new0(struct server, 1);
-	server->drivers = obex_service_driver_list(services);
-	server->folder = g_strdup(root_path);
-	server->auto_accept = TRUE;
-	server->capability = g_strdup(capability);
-	server->devnode = g_strdup(devnode);
-	server->rx_mtu = TTY_RX_MTU;
-	server->tx_mtu = TTY_TX_MTU;
-	server->symlinks = symlinks;
-
-	io = g_io_channel_unix_new(fd);
-	g_io_channel_set_close_on_unref(io, TRUE);
-
-	err = obex_session_start(io, server);
-	g_io_channel_unref(io);
-
-	if (err < 0) {
-		server_free(server);
-		goto failed;
-	}
-
-	tty_needs_reinit = FALSE;
-
-	debug("Successfully opened %s", devnode);
-
-	return 0;
-
-failed:
-	error("tty_init(): %s (%d)", strerror(-err), -err);
-	if (io == NULL)
-		close(fd);
-	return err;
-}
-
-void tty_closed(void)
-{
-	tty_needs_reinit = TRUE;
-}
-
 static void sig_term(int sig)
 {
 	info("Terminating due to signal %d", sig);
@@ -152,16 +66,15 @@
 
 static void sig_debug(int sig)
 {
-	toggle_debug();
+	__obex_log_enable_debug();
 }
 
 static gboolean option_detach = TRUE;
-static gboolean option_debug = FALSE;
+static char *option_debug = NULL;
 
 static char *option_root = NULL;
 static char *option_root_setup = NULL;
 static char *option_capability = NULL;
-static char *option_devnode = NULL;
 
 static gboolean option_autoaccept = FALSE;
 static gboolean option_opp = FALSE;
@@ -171,12 +84,24 @@
 static gboolean option_symlinks = FALSE;
 static gboolean option_syncevolution = FALSE;
 
+static gboolean parse_debug(const char *key, const char *value,
+				gpointer user_data, GError **error)
+{
+	if (value)
+		option_debug = g_strdup(value);
+	else
+		option_debug = g_strdup("*");
+
+	return TRUE;
+}
+
 static GOptionEntry options[] = {
 	{ "nodaemon", 'n', G_OPTION_FLAG_REVERSE,
 				G_OPTION_ARG_NONE, &option_detach,
 				"Don't run as daemon in background" },
-	{ "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
-				"Enable debug information output" },
+	{ "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+				G_OPTION_ARG_CALLBACK, parse_debug,
+				"Enable debug information output", "DEBUG" },
 	{ "root", 'r', 0, G_OPTION_ARG_STRING, &option_root,
 				"Specify root folder location", "PATH" },
 	{ "root-setup", 'S', 0, G_OPTION_ARG_STRING, &option_root_setup,
@@ -185,8 +110,6 @@
 				"Enable symlinks on root folder" },
 	{ "capability", 'c', 0, G_OPTION_ARG_STRING, &option_capability,
 				"Specify capability file", "FILE" },
-	{ "tty", 't', 0, G_OPTION_ARG_STRING, &option_devnode,
-				"Specify the TTY device", "DEVICE" },
 	{ "auto-accept", 'a', 0, G_OPTION_ARG_NONE, &option_autoaccept,
 				"Automatically accept push requests" },
 	{ "opp", 'o', 0, G_OPTION_ARG_NONE, &option_opp,
@@ -212,67 +135,6 @@
 	return option_symlinks;
 }
 
-static void sig_tty(int sig)
-{
-	if (write(signal_pipe[1], &sig, sizeof(sig)) != sizeof(sig))
-		error("unable to write to signal pipe");
-}
-
-static gboolean handle_signal(GIOChannel *io, GIOCondition cond,
-				void *user_data)
-{
-	int sig, fd = g_io_channel_unix_get_fd(io);
-
-	if (read(fd, &sig, sizeof(sig)) != sizeof(sig)) {
-		error("handle_signal: unable to read signal from pipe");
-		return TRUE;
-	}
-
-	switch (sig) {
-	case SIGUSR1:
-		debug("SIGUSR1");
-		tty_open_allowed = TRUE;
-		if (tty_needs_reinit)
-			tty_init(services, option_root, option_capability,
-					option_symlinks, option_devnode);
-		break;
-	case SIGHUP:
-		debug("SIGHUP");
-		tty_open_allowed = FALSE;
-		obex_tty_session_stop();
-		break;
-	default:
-		error("handle_signal: got unexpected signal %d", sig);
-		break;
-	}
-
-	return TRUE;
-}
-
-static int devnode_setup(void)
-{
-	struct sigaction sa;
-	GIOChannel *pipe_io;
-
-	if (pipe(signal_pipe) < 0)
-		return -errno;
-
-	pipe_io = g_io_channel_unix_new(signal_pipe[0]);
-	g_io_add_watch(pipe_io, G_IO_IN, handle_signal, NULL);
-	g_io_channel_unref(pipe_io);
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sa_handler = sig_tty;
-	sigaction(SIGUSR1, &sa, NULL);
-	sigaction(SIGHUP, &sa, NULL);
-
-	if (option_pcsuite)
-		tty_open_allowed = FALSE;
-
-	return tty_init(services, option_root, option_capability,
-			option_symlinks, option_devnode);
-}
-
 static gboolean is_dir(const char *dir) {
 	struct stat st;
 
@@ -295,7 +157,7 @@
 	if (root_setup == NULL)
 		return FALSE;
 
-	debug("Setting up %s using %s", root, root_setup);
+	DBG("Setting up %s using %s", root, root_setup);
 
 	if (!g_spawn_sync(NULL, argv, NULL, 0, NULL, NULL, NULL, NULL,
 							&status, NULL)) {
@@ -317,7 +179,6 @@
 	GOptionContext *context;
 	GError *err = NULL;
 	struct sigaction sa;
-	int log_option = LOG_NDELAY | LOG_PID;
 
 #ifdef NEED_THREADS
 	if (g_thread_supported() == FALSE)
@@ -343,8 +204,7 @@
 			perror("Can't start daemon");
 			exit(1);
 		}
-	} else
-		log_option |= LOG_PERROR;
+	}
 
 	if (option_opp == FALSE && option_ftp == FALSE &&
 				option_pbap == FALSE &&
@@ -354,12 +214,9 @@
 		exit(EXIT_FAILURE);
 	}
 
-	openlog("obexd", log_option, LOG_DAEMON);
+	__obex_log_init(option_debug, option_detach);
 
-	if (option_debug == TRUE) {
-		info("Enabling debug information");
-		enable_debug();
-	}
+	DBG("Entering main loop");
 
 	main_loop = g_main_loop_new(NULL, FALSE);
 
@@ -391,40 +248,27 @@
 	if (option_capability == NULL)
 		option_capability = g_strdup(DEFAULT_CAP_FILE);
 
-	if (option_opp == TRUE) {
-		services |= OBEX_OPP;
-		bluetooth_init(OBEX_OPP, option_root, FALSE,
+	if (option_opp == TRUE)
+		obex_server_init(OBEX_OPP, option_root, FALSE,
 				option_autoaccept, option_symlinks,
 				NULL);
-	}
 
-	if (option_ftp == TRUE) {
-		services |= OBEX_FTP;
-		bluetooth_init(OBEX_FTP, option_root, TRUE,
+	if (option_ftp == TRUE)
+		obex_server_init(OBEX_FTP, option_root, TRUE,
 				option_autoaccept, option_symlinks,
 				option_capability);
-	}
 
-	if (option_pbap == TRUE) {
-		services |= OBEX_PBAP;
-		bluetooth_init(OBEX_PBAP, NULL, TRUE, FALSE, FALSE, NULL);
-	}
+	if (option_pbap == TRUE)
+		obex_server_init(OBEX_PBAP, NULL, TRUE, FALSE, FALSE, NULL);
 
-	if (option_pcsuite == TRUE) {
-		services |= OBEX_PCSUITE;
-		bluetooth_init(OBEX_PCSUITE, option_root, TRUE,
+	if (option_pcsuite == TRUE)
+		obex_server_init(OBEX_PCSUITE, option_root, TRUE,
 				option_autoaccept, option_symlinks,
 				option_capability);
-	}
 
-	if (option_syncevolution == TRUE) {
-		services |= OBEX_SYNCEVOLUTION;
-		bluetooth_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
+	if (option_syncevolution == TRUE)
+		obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
 							FALSE, NULL);
-	}
-
-	if (option_devnode)
-		devnode_setup();
 
 	if (!root_folder_setup(option_root, option_root_setup)) {
 		error("Unable to setup root folder %s", option_root);
@@ -441,7 +285,7 @@
 
 	g_main_loop_run(main_loop);
 
-	bluetooth_exit();
+	obex_server_exit();
 
 	plugin_cleanup();
 
@@ -449,11 +293,10 @@
 
 	g_main_loop_unref(main_loop);
 
-	g_free(option_devnode);
 	g_free(option_capability);
 	g_free(option_root);
 
-	closelog();
+	__obex_log_cleanup();
 
 	return 0;
 }
--- src/manager.c
+++ src/manager.c
@@ -37,12 +37,12 @@
 
 #include <openobex/obex.h>
 
-#include "bluetooth.h"
 #include "obexd.h"
 #include "obex.h"
 #include "obex-priv.h"
+#include "server.h"
 #include "dbus.h"
-#include "logging.h"
+#include "log.h"
 #include "btio.h"
 #include "service.h"
 
@@ -65,24 +65,7 @@
 
 static struct agent *agent = NULL;
 
-struct pending_request {
-	DBusPendingCall *call;
-	struct server *server;
-	char *adapter_path;
-	char address[18];
-	unsigned int watch;
-	GIOChannel *io;
-};
-
-struct adapter_any {
-	char *path;		/* Adapter ANY path */
-	GSList *servers;	/* List of servers to register records */
-};
-
 static DBusConnection *connection = NULL;
-static DBusConnection *system_conn = NULL;
-static struct adapter_any *any = NULL;
-static unsigned int listener_id = 0;
 
 static void agent_free(struct agent *agent)
 {
@@ -201,7 +184,7 @@
 
 static void agent_disconnected(DBusConnection *conn, void *user_data)
 {
-	debug("Agent exited");
+	DBG("Agent exited");
 	agent_free(agent);
 	agent = NULL;
 }
@@ -227,7 +210,7 @@
 	agent->watch_id = g_dbus_add_disconnect_watch(conn, sender,
 					agent_disconnected, NULL, NULL);
 
-	debug("Agent registered");
+	DBG("Agent registered");
 
 	return dbus_message_new_method_return(msg);
 }
@@ -257,7 +240,7 @@
 	agent_free(agent);
 	agent = NULL;
 
-	debug("Agent unregistered");
+	DBG("Agent unregistered");
 
 	return dbus_message_new_method_return(msg);
 }
@@ -356,183 +339,15 @@
 	{ }
 };
 
-static void add_record_reply(DBusPendingCall *call, void *user_data)
-{
-	struct server *server = user_data;
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusError derr;
-	uint32_t handle;
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("Replied with an error: %s, %s",
-				derr.name, derr.message);
-		dbus_error_free(&derr);
-		handle = 0;
-	} else {
-		struct obex_service_driver *driver;
-
-		dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_UINT32, &handle,
-				DBUS_TYPE_INVALID);
-		server->handle = handle;
-
-		driver = (struct obex_service_driver *) server->drivers->data;
-
-		debug("Registered: %s, handle: 0x%x, folder: %s",
-				driver->name, handle, server->folder);
-	}
-
-	dbus_message_unref(reply);
-}
-
-static int add_record(const char *path,
-		const char *xml, struct server *server)
-{
-	DBusMessage *msg;
-	DBusPendingCall *call;
-	int ret = 0;
-
-	msg = dbus_message_new_method_call("org.bluez", path,
-					"org.bluez.Service", "AddRecord");
-
-	dbus_message_append_args(msg, DBUS_TYPE_STRING, &xml,
-			DBUS_TYPE_INVALID);
-
-	if (dbus_connection_send_with_reply(system_conn,
-				msg, &call, -1) == FALSE) {
-		ret = -1;
-		goto failed;
-	}
-
-	dbus_pending_call_set_notify(call, add_record_reply, server, NULL);
-	dbus_pending_call_unref(call);
-
-failed:
-	dbus_message_unref(msg);
-	return ret;
-}
-
-void register_record(struct server *server)
-{
-	struct obex_service_driver *driver;
-	char *xml;
-	int ret;
-
-	if (system_conn == NULL)
-		return;
-
-	if (any->path == NULL) {
-		/* Adapter ANY is not available yet: Add record later */
-		any->servers = g_slist_append(any->servers, server);
-		return;
-	}
-
-	driver = (struct obex_service_driver *) server->drivers->data;
-	xml = g_markup_printf_escaped(driver->record, driver->channel,
-					driver->name);
-	ret = add_record(any->path, xml, server);
-	g_free(xml);
-}
-
-static void find_adapter_any_reply(DBusPendingCall *call, void *user_data)
-{
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	const char *path;
-	char *xml;
-	GSList *l;
-	DBusError derr;
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("Replied with an error: %s, %s",
-				derr.name, derr.message);
-		dbus_error_free(&derr);
-		bluetooth_stop();
-		goto done;
-	}
-
-	dbus_message_get_args(reply, NULL,
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_INVALID);
-	any->path = g_strdup(path);
-
-	for (l = any->servers; l; l = l->next) {
-		struct server *server = l->data;
-		struct obex_service_driver *driver;
-
-		driver = (struct obex_service_driver *) server->drivers->data;
-		xml = g_markup_printf_escaped(driver->record, driver->channel,
-						driver->name);
-		add_record(path, xml, server);
-		g_free(xml);
-	}
-
-done:
-	g_slist_free(any->servers);
-	any->servers = NULL;
-
-	dbus_message_unref(reply);
-}
-
-static DBusPendingCall *find_adapter(const char *pattern,
-				DBusPendingCallNotifyFunction function,
-				void *user_data)
-{
-	DBusMessage *msg;
-	DBusPendingCall *call;
-
-	debug("FindAdapter(%s)", pattern);
-
-	msg = dbus_message_new_method_call("org.bluez", "/",
-					"org.bluez.Manager", "FindAdapter");
-	if (!msg)
-		return NULL;
-
-	dbus_message_append_args(msg, DBUS_TYPE_STRING, &pattern,
-			DBUS_TYPE_INVALID);
-
-	if (!dbus_connection_send_with_reply(system_conn, msg, &call, -1)) {
-		dbus_message_unref(msg);
-		return NULL;
-	}
-
-	dbus_pending_call_set_notify(call, function, user_data, NULL);
-
-	dbus_message_unref(msg);
-
-	return call;
-}
-
-static void name_acquired(DBusConnection *conn, void *user_data)
-{
-	DBusPendingCall *call;
-
-	call = find_adapter("any", find_adapter_any_reply, NULL);
-	if (call)
-		dbus_pending_call_unref(call);
-
-	bluetooth_start();
-}
-
-static void name_released(DBusConnection *conn, void *user_data)
-{
-	g_free(any->path);
-	any->path = NULL;
-	bluetooth_stop();
-}
-
 gboolean manager_init(void)
 {
 	DBusError err;
 
 	DBG("");
 
-	any = g_new0(struct adapter_any, 1);
-
 	dbus_error_init(&err);
 
-	connection = g_dbus_setup_private(DBUS_BUS_SESSION, OPENOBEX_SERVICE,
+	connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OPENOBEX_SERVICE,
 									&err);
 	if (connection == NULL) {
 		if (dbus_error_is_set(&err) == TRUE) {
@@ -543,16 +358,6 @@
 		return FALSE;
 	}
 
-	system_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
-	if (system_conn == NULL) {
-		dbus_connection_unref(connection);
-		connection = NULL;
-		return FALSE;
-	}
-
-	listener_id = g_dbus_add_service_watch(system_conn, "org.bluez",
-				name_acquired, name_released, NULL, NULL);
-
 	return g_dbus_register_interface(connection, OPENOBEX_MANAGER_PATH,
 					OPENOBEX_MANAGER_INTERFACE,
 					manager_methods, manager_signals, NULL,
@@ -571,16 +376,6 @@
 	if (agent)
 		agent_free(agent);
 
-	g_dbus_remove_watch(system_conn, listener_id);
-
-	if (any) {
-		g_free(any->path);
-		g_free(any);
-	}
-
-	if (system_conn)
-		dbus_connection_unref(system_conn);
-
 	dbus_connection_unref(connection);
 }
 
@@ -696,7 +491,7 @@
 				DBUS_TYPE_INVALID)) {
 		/* Splits folder and name */
 		const char *slash = strrchr(name, '/');
-		debug("Agent replied with %s", name);
+		DBG("Agent replied with %s", name);
 		if (!slash) {
 			agent->new_name = g_strdup(name);
 			agent->new_folder = NULL;
@@ -809,174 +604,6 @@
 
 	return 0;
 }
-
-static void service_cancel(struct pending_request *pending)
-{
-	DBusMessage *msg;
-
-	msg = dbus_message_new_method_call("org.bluez",
-					pending->adapter_path,
-					"org.bluez.Service",
-					"CancelAuthorization");
-
-	g_dbus_send_message(system_conn, msg);
-}
-
-static void pending_request_free(struct pending_request *pending)
-{
-	if (pending->call)
-		dbus_pending_call_unref(pending->call);
-	g_io_channel_unref(pending->io);
-	g_free(pending->adapter_path);
-	g_free(pending);
-}
-
-static void service_reply(DBusPendingCall *call, void *user_data)
-{
-	struct pending_request *pending = user_data;
-	GIOChannel *io = pending->io;
-	struct server *server = pending->server;
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusError derr;
-	GError *err = NULL;
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("RequestAuthorization error: %s, %s",
-				derr.name, derr.message);
-
-		if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
-			service_cancel(pending);
-
-		dbus_error_free(&derr);
-		g_io_channel_shutdown(io, TRUE, NULL);
-		goto done;
-	}
-
-	debug("RequestAuthorization succeeded");
-
-	if (!bt_io_accept(io, obex_connect_cb, server, NULL, &err)) {
-		error("%s", err->message);
-		g_error_free(err);
-		g_io_channel_shutdown(io, TRUE, NULL);
-	}
-
-done:
-	g_source_remove(pending->watch);
-	pending_request_free(pending);
-	dbus_message_unref(reply);
-}
-
-static gboolean service_error(GIOChannel *io, GIOCondition cond,
-			void *user_data)
-{
-	struct pending_request *pending = user_data;
-
-	service_cancel(pending);
-
-	dbus_pending_call_cancel(pending->call);
-
-	pending_request_free(pending);
-
-	return FALSE;
-}
-
-static void find_adapter_reply(DBusPendingCall *call, void *user_data)
-{
-	struct pending_request *pending = user_data;
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusMessage *msg;
-	DBusPendingCall *pcall;
-	const char *path, *paddr = pending->address;
-	DBusError derr;
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("Replied with an error: %s, %s",
-				derr.name, derr.message);
-		dbus_error_free(&derr);
-		goto failed;
-	}
-
-	dbus_message_get_args(reply, NULL,
-			DBUS_TYPE_OBJECT_PATH, &path,
-			DBUS_TYPE_INVALID);
-
-	debug("FindAdapter -> %s", path);
-	pending->adapter_path = g_strdup(path);
-	dbus_message_unref(reply);
-
-	msg = dbus_message_new_method_call("org.bluez", path,
-			"org.bluez.Service", "RequestAuthorization");
-
-	dbus_message_append_args(msg, DBUS_TYPE_STRING, &paddr,
-			DBUS_TYPE_UINT32, &pending->server->handle,
-			DBUS_TYPE_INVALID);
-
-	if (!dbus_connection_send_with_reply(system_conn,
-					msg, &pcall, TIMEOUT)) {
-		dbus_message_unref(msg);
-		goto failed;
-	}
-
-	dbus_message_unref(msg);
-
-	debug("RequestAuthorization(%s, %x)", paddr, pending->server->handle);
-
-	if (!dbus_pending_call_set_notify(pcall, service_reply, pending,
-								NULL)) {
-		dbus_pending_call_unref(pcall);
-		goto failed;
-	}
-
-	dbus_pending_call_unref(pending->call);
-	pending->call = pcall;
-
-	/* Catches errors before authorization response comes */
-	pending->watch = g_io_add_watch(pending->io,
-					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-					service_error, pending);
-
-	return;
-
-failed:
-	g_io_channel_shutdown(pending->io, TRUE, NULL);
-	pending_request_free(pending);
-}
-
-int request_service_authorization(struct server *server, GIOChannel *io,
-					const char *address)
-{
-	struct pending_request *pending;
-	char source[18];
-	GError *err = NULL;
-
-	if (system_conn == NULL || any->path == NULL)
-		return -1;
-
-	bt_io_get(io, BT_IO_RFCOMM, &err,
-			BT_IO_OPT_SOURCE, source,
-			BT_IO_OPT_INVALID);
-	if (err) {
-		error("%s", err->message);
-		g_error_free(err);
-		return -EINVAL;
-	}
-
-	pending = g_new0(struct pending_request, 1);
-	pending->call = find_adapter(source, find_adapter_reply, pending);
-	if (!pending->call) {
-		g_free(pending);
-		return -ENOMEM;
-	}
-
-	pending->server = server;
-	pending->io = g_io_channel_ref(io);
-	memcpy(pending->address, address, sizeof(pending->address));
-
-
-	return 0;
-}
 
 void manager_register_session(struct obex_session *os)
 {
--- src/mimetype.c
+++ src/mimetype.c
@@ -32,7 +32,7 @@
 #include <openobex/obex.h>
 #include <openobex/obex_const.h>
 
-#include "logging.h"
+#include "log.h"
 #include "obex.h"
 #include "mimetype.h"
 
@@ -117,7 +117,7 @@
 	return 0;
 }
 
-struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target,
+static struct obex_mime_type_driver *find_driver(const uint8_t *target,
 				const char *mimetype, const uint8_t *who,
 				unsigned int who_size)
 {
@@ -139,6 +139,33 @@
 	return NULL;
 }
 
+struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target,
+				const char *mimetype, const uint8_t *who,
+				unsigned int who_size)
+{
+	struct obex_mime_type_driver *driver;
+
+	driver = find_driver(target, mimetype, who, who_size);
+	if (driver == NULL) {
+		if (who != NULL) {
+			/* Fallback to non-who specific */
+			driver = find_driver(target, mimetype, NULL, 0);
+			if (driver != NULL)
+				return driver;
+		}
+
+		if (mimetype != NULL)
+			/* Fallback to target default */
+			driver = find_driver(target, NULL, NULL, 0);
+
+		if (driver == NULL)
+			/* Fallback to general default */
+			driver = find_driver(NULL, NULL, NULL, 0);
+	}
+
+	return driver;
+}
+
 int obex_mime_type_driver_register(struct obex_mime_type_driver *driver)
 {
 	if (!driver) {
@@ -146,7 +173,7 @@
 		return -EINVAL;
 	}
 
-	if (obex_mime_type_driver_find(driver->target, driver->mimetype,
+	if (find_driver(driver->target, driver->mimetype,
 					driver->who, driver->who_size)) {
 		error("Permission denied: %s could not be registered",
 				driver->mimetype);
@@ -156,7 +183,7 @@
 	if (driver->set_io_watch == NULL)
 		driver->set_io_watch = set_io_watch;
 
-	debug("driver %p mimetype %s registered", driver, driver->mimetype);
+	DBG("driver %p mimetype %s registered", driver, driver->mimetype);
 
 	drivers = g_slist_append(drivers, driver);
 
@@ -170,7 +197,7 @@
 		return;
 	}
 
-	debug("driver %p mimetype %s unregistered", driver, driver->mimetype);
+	DBG("driver %p mimetype %s unregistered", driver, driver->mimetype);
 
 	drivers = g_slist_remove(drivers, driver);
 }
--- src/obex-priv.h
+++ src/obex-priv.h
@@ -22,21 +22,6 @@
  *
  */
 
-struct server {
-	gboolean auto_accept;
-	char *folder;
-	gboolean symlinks;
-	char *capability;
-	uint32_t handle;
-	char *devnode;
-	gboolean secure;
-	GIOChannel *io;
-	unsigned int watch;
-	uint16_t tx_mtu;
-	uint16_t rx_mtu;
-	GSList *drivers;
-};
-
 struct obex_session {
 	GIOChannel *io;
 	uint32_t cid;
@@ -55,7 +40,7 @@
 	gboolean aborted;
 	struct obex_service_driver *service;
 	void *service_data;
-	struct server *server;
+	struct obex_server *server;
 	gboolean checked;
 	obex_t *obex;
 	obex_object_t *obj;
@@ -63,9 +48,5 @@
 	gboolean finished;
 };
 
-int obex_session_start(GIOChannel *io, struct server *server);
-void server_free(struct server *server);
-
-void register_record(struct server *server);
-int request_service_authorization(struct server *server, GIOChannel *io,
-							const char *address);
+int obex_session_start(GIOChannel *io, uint16_t tx_mtu, uint16_t rx_mtu,
+			struct obex_server *server);
--- src/obex.c
+++ src/obex.c
@@ -42,18 +42,32 @@
 
 #include <openobex/obex.h>
 
-#include "logging.h"
+#include "log.h"
 #include "obex.h"
 #include "obex-priv.h"
+#include "server.h"
 #include "dbus.h"
 #include "mimetype.h"
 #include "service.h"
+#include "transport.h"
 #include "btio.h"
 
 /* Default MTU's */
 #define DEFAULT_RX_MTU 32767
 #define DEFAULT_TX_MTU 32767
 
+/* Challenge request */
+#define NONCE_TAG 0x00
+#define OPTIONS_TAG 0x01 /* Optional */
+#define REALM_TAG 0x02 /* Optional */
+
+#define NONCE_LEN 16
+
+/* Challenge response */
+#define DIGEST_TAG 0x00
+#define USER_ID_TAG 0x01 /* Optional */
+#define DIGEST_NONCE_TAG 0x02 /* Optional */
+
 /* Connection ID */
 static uint32_t cid = 0x0000;
 
@@ -65,6 +79,144 @@
 	uint16_t mtu;
 } __attribute__ ((packed)) obex_connect_hdr_t;
 
+struct auth_header {
+	uint8_t tag;
+	uint8_t len;
+	uint8_t val[0];
+} __attribute__ ((packed));
+
+static struct {
+	int evt;
+	const char *name;
+} obex_event[] = {
+	/* Progress has been made */
+	{ OBEX_EV_PROGRESS,	"PROGRESS"	},
+	/* An incoming request is about to come */
+	{ OBEX_EV_REQHINT,	"REQHINT"	},
+	/* An incoming request has arrived */
+	{ OBEX_EV_REQ,		"REQ"		},
+	/* Request has finished */
+	{ OBEX_EV_REQDONE,	"REQDONE"	},
+	/* Link has been disconnected */
+	{ OBEX_EV_LINKERR,	"LINKERR"	},
+	/* Malformed data encountered */
+	{ OBEX_EV_PARSEERR,	"PARSEERR"	},
+	/* Connection accepted */
+	{ OBEX_EV_ACCEPTHINT,	"ACCEPTHINT"	},
+	/* Request was aborted */
+	{ OBEX_EV_ABORT,	"ABORT"		},
+	/* Need to feed more data when sending a stream */
+	{ OBEX_EV_STREAMEMPTY,	"STREAMEMPTY"	},
+	/* Time to pick up data when receiving a stream */
+	{ OBEX_EV_STREAMAVAIL,	"STREAMAVAIL"	},
+	/* Unexpected data, not fatal */
+	{ OBEX_EV_UNEXPECTED,	"UNEXPECTED"	},
+	/* First packet of an incoming request has been parsed */
+	{ OBEX_EV_REQCHECK,	"REQCHECK"	},
+	{ 0xFF,			NULL		},
+};
+
+/* Possible commands */
+static struct {
+	int cmd;
+	const char *name;
+} obex_command[] = {
+	{ OBEX_CMD_CONNECT,	"CONNECT"	},
+	{ OBEX_CMD_DISCONNECT,	"DISCONNECT"	},
+	{ OBEX_CMD_PUT,		"PUT"		},
+	{ OBEX_CMD_GET,		"GET"		},
+	{ OBEX_CMD_SETPATH,	"SETPATH"	},
+	{ OBEX_CMD_SESSION,	"SESSION"	},
+	{ OBEX_CMD_ABORT,	"ABORT"		},
+	{ OBEX_FINAL,		"FINAL"		},
+	{ 0xFF,			NULL		},
+};
+
+/* Possible Response */
+static struct {
+	int rsp;
+	const char *name;
+} obex_response[] = {
+	{ OBEX_RSP_CONTINUE,			"CONTINUE"		},
+	{ OBEX_RSP_SWITCH_PRO,			"SWITCH_PRO"		},
+	{ OBEX_RSP_SUCCESS,			"SUCCESS"		},
+	{ OBEX_RSP_CREATED,			"CREATED"		},
+	{ OBEX_RSP_ACCEPTED,			"ACCEPTED"		},
+	{ OBEX_RSP_NON_AUTHORITATIVE,		"NON_AUTHORITATIVE"	},
+	{ OBEX_RSP_NO_CONTENT,			"NO_CONTENT"		},
+	{ OBEX_RSP_RESET_CONTENT,		"RESET_CONTENT"		},
+	{ OBEX_RSP_PARTIAL_CONTENT,		"PARTIAL_CONTENT"	},
+	{ OBEX_RSP_MULTIPLE_CHOICES,		"MULTIPLE_CHOICES"	},
+	{ OBEX_RSP_MOVED_PERMANENTLY,		"MOVED_PERMANENTLY"	},
+	{ OBEX_RSP_MOVED_TEMPORARILY,		"MOVED_TEMPORARILY"	},
+	{ OBEX_RSP_SEE_OTHER,			"SEE_OTHER"		},
+	{ OBEX_RSP_NOT_MODIFIED,		"NOT_MODIFIED"		},
+	{ OBEX_RSP_USE_PROXY,			"USE_PROXY"		},
+	{ OBEX_RSP_BAD_REQUEST,			"BAD_REQUEST"		},
+	{ OBEX_RSP_UNAUTHORIZED,		"UNAUTHORIZED"		},
+	{ OBEX_RSP_PAYMENT_REQUIRED,		"PAYMENT_REQUIRED"	},
+	{ OBEX_RSP_FORBIDDEN,			"FORBIDDEN"		},
+	{ OBEX_RSP_NOT_FOUND,			"NOT_FOUND"		},
+	{ OBEX_RSP_METHOD_NOT_ALLOWED,		"METHOD_NOT_ALLOWED"	},
+	{ OBEX_RSP_NOT_ACCEPTABLE,		"NOT_ACCEPTABLE"	},
+	{ OBEX_RSP_PROXY_AUTH_REQUIRED,		"PROXY_AUTH_REQUIRED"	},
+	{ OBEX_RSP_REQUEST_TIME_OUT,		"REQUEST_TIME_OUT"	},
+	{ OBEX_RSP_CONFLICT,			"CONFLICT"		},
+	{ OBEX_RSP_GONE,			"GONE"			},
+	{ OBEX_RSP_LENGTH_REQUIRED,		"LENGTH_REQUIRED"	},
+	{ OBEX_RSP_PRECONDITION_FAILED,		"PRECONDITION_FAILED"	},
+	{ OBEX_RSP_REQ_ENTITY_TOO_LARGE,	"REQ_ENTITY_TOO_LARGE"	},
+	{ OBEX_RSP_REQ_URL_TOO_LARGE,		"REQ_URL_TOO_LARGE"	},
+	{ OBEX_RSP_UNSUPPORTED_MEDIA_TYPE,	"UNSUPPORTED_MEDIA_TYPE"},
+	{ OBEX_RSP_INTERNAL_SERVER_ERROR,	"INTERNAL_SERVER_ERROR"	},
+	{ OBEX_RSP_NOT_IMPLEMENTED,		"NOT_IMPLEMENTED"	},
+	{ OBEX_RSP_BAD_GATEWAY,			"BAD_GATEWAY"		},
+	{ OBEX_RSP_SERVICE_UNAVAILABLE,		"SERVICE_UNAVAILABLE"	},
+	{ OBEX_RSP_GATEWAY_TIMEOUT,		"GATEWAY_TIMEOUT"	},
+	{ OBEX_RSP_VERSION_NOT_SUPPORTED,	"VERSION_NOT_SUPPORTED"	},
+	{ OBEX_RSP_DATABASE_FULL,		"DATABASE_FULL"		},
+	{ OBEX_RSP_DATABASE_LOCKED,		"DATABASE_LOCKED"	},
+	{ 0xFF,					NULL			},
+};
+
+static void print_event(int evt, int cmd, int rsp)
+{
+	const char *evtstr = NULL, *cmdstr = NULL, *rspstr = NULL;
+	int i;
+	static int lastevt, lastcmd;
+
+	if (evt < 0)
+		evt = lastevt;
+	else
+		lastevt = evt;
+
+	if (cmd < 0)
+		cmd = lastcmd;
+	else
+		lastcmd = cmd;
+
+	for (i = 0; obex_event[i].evt != 0xFF; i++) {
+		if (obex_event[i].evt != evt)
+			continue;
+		evtstr = obex_event[i].name;
+	}
+
+	for (i = 0; obex_command[i].cmd != 0xFF; i++) {
+		if (obex_command[i].cmd != cmd)
+			continue;
+		cmdstr = obex_command[i].name;
+	}
+
+	for (i = 0; obex_response[i].rsp != 0xFF; i++) {
+		if (obex_response[i].rsp != rsp)
+			continue;
+		rspstr = obex_response[i].name;
+	}
+
+	obex_debug("%s(0x%x), %s(0x%x), %s(0x%x)", evtstr, evt, cmdstr, cmd,
+								rspstr, rsp);
+}
+
 static void os_set_response(obex_object_t *obj, int err)
 {
 	uint8_t rsp;
@@ -106,17 +258,33 @@
 		lastrsp = OBEX_RSP_INTERNAL_SERVER_ERROR;
 	}
 
+	print_event(-1, -1, rsp);
+
 	OBEX_ObjectSetRsp(obj, rsp, lastrsp);
 }
 
+static void os_session_mark_aborted(struct obex_session *os)
+{
+	/* the session was already cancelled/aborted or size in unknown */
+	if (os->aborted || os->size == OBJECT_SIZE_UNKNOWN)
+		return;
+
+	os->aborted = (os->size != os->offset);
+}
+
 static void os_reset_session(struct obex_session *os)
 {
+	os_session_mark_aborted(os);
+	if (os->service->reset)
+		os->service->reset(os, os->service_data);
+
 	if (os->object) {
 		os->driver->set_io_watch(os->object, NULL, NULL);
 		os->driver->close(os->object);
 		os->object = NULL;
 		os->obj = NULL;
-		if (os->aborted && os->cmd == OBEX_CMD_PUT && os->path)
+		if (os->aborted && os->cmd == OBEX_CMD_PUT && os->path &&
+				os->driver->remove)
 			os->driver->remove(os->path);
 	}
 
@@ -145,16 +313,6 @@
 	os->finished = 0;
 }
 
-static void os_session_mark_aborted(struct obex_session *os)
-{
-	/* the session was alredy cancelled/aborted */
-	if (os->aborted)
-		return;
-
-	os->aborted = os->size == OBJECT_SIZE_UNKNOWN ? FALSE :
-							os->size != os->offset;
-}
-
 static void obex_session_free(struct obex_session *os)
 {
 	sessions = g_slist_remove(sessions, os);
@@ -214,6 +372,53 @@
 	return time;
 }
 
+static uint8_t *extract_nonce(const uint8_t *buffer, unsigned int hlen)
+{
+	struct auth_header *hdr;
+	uint8_t *nonce = NULL;
+	uint32_t len = 0;
+
+	while (len < hlen) {
+		hdr = (void *) buffer + len;
+
+		switch (hdr->tag) {
+		case NONCE_TAG:
+			if (hdr->len != NONCE_LEN)
+				return NULL;
+
+			nonce = hdr->val;
+			break;
+		}
+
+		len += hdr->len + sizeof(struct auth_header);
+	}
+
+	return nonce;
+}
+
+static uint8_t *challenge_response(const uint8_t *nonce)
+{
+	GChecksum *md5;
+	uint8_t *result;
+	size_t size;
+
+	result = g_new0(uint8_t, NONCE_LEN);
+
+	md5 = g_checksum_new(G_CHECKSUM_MD5);
+	if (md5 == NULL)
+		return result;
+
+	g_checksum_update(md5, nonce, NONCE_LEN);
+	g_checksum_update(md5, (uint8_t *) ":BlueZ", 6);
+
+	size = NONCE_LEN;
+	g_checksum_get_digest(md5, result, &size);
+
+	g_checksum_free(md5);
+
+	return result;
+}
+
 static void cmd_connect(struct obex_session *os,
 			obex_t *obex, obex_object_t *obj)
 {
@@ -223,26 +428,26 @@
 	unsigned int hlen, newsize;
 	uint16_t mtu;
 	uint8_t hi;
-	const uint8_t *target = NULL, *who = NULL;
+	const uint8_t *target = NULL, *who = NULL, *nonce = NULL;
 	unsigned int target_size = 0, who_size = 0;
 	int err;
 
 	if (OBEX_ObjectGetNonHdrData(obj, &buffer) != sizeof(*nonhdr)) {
 		OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
-		debug("Invalid OBEX CONNECT packet");
+		DBG("Invalid OBEX CONNECT packet");
 		return;
 	}
 
 	nonhdr = (obex_connect_hdr_t *) buffer;
 	mtu = g_ntohs(nonhdr->mtu);
-	debug("Version: 0x%02x. Flags: 0x%02x  OBEX packet length: %d",
+	DBG("Version: 0x%02x. Flags: 0x%02x  OBEX packet length: %d",
 			nonhdr->version, nonhdr->flags, mtu);
 	/* Leave space for headers */
 	newsize = mtu - 200;
 
 	os->tx_mtu = newsize;
 
-	debug("Resizing stream chunks to %d", newsize);
+	DBG("Resizing stream chunks to %d", newsize);
 
 	/* connection id will be used to track the sessions, even for OPP */
 	os->cid = ++cid;
@@ -257,6 +462,15 @@
 			target = hd.bs;
 			target_size = hlen;
 			break;
+		case OBEX_HDR_AUTHCHAL:
+			if (nonce) {
+				DBG("Ignoring multiple challenge headers");
+				break;
+			}
+
+			nonce = extract_nonce(hd.bs, hlen);
+			DBG("AUTH CHALLENGE REQUEST");
+			break;
 		}
 	}
 
@@ -270,7 +484,7 @@
 		return;
 	}
 
-	debug("Selected driver: %s", os->service->name);
+	DBG("Selected driver: %s", os->service->name);
 
 	if (!os->service->connect) {
 		OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
@@ -289,6 +503,21 @@
 				OBEX_FL_FIT_ONE_PACKET);
 	}
 
+	if (err == 0 && nonce) {
+		uint8_t challenge[18];
+		struct auth_header *hdr = (struct auth_header *) challenge;
+		uint8_t *response = challenge_response(nonce);
+
+		hdr->tag = DIGEST_TAG;
+		hdr->len = NONCE_LEN;
+		memcpy(hdr->val, response, NONCE_LEN);
+
+		g_free(response);
+
+		hd.bs = challenge;
+		OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_AUTHRESP, hd, 18, 0);
+	}
+
 	os_set_response(obj, err);
 }
 
@@ -329,6 +558,10 @@
 	int32_t len = 0;
 	const uint8_t *buffer;
 
+	DBG("name=%s type=%s rx_mtu=%d file=%p",
+		os->name ? os->name : "", os->type ? os->type : "",
+		os->rx_mtu, os->object);
+
 	if (os->aborted)
 		return -EPERM;
 
@@ -355,7 +588,7 @@
 	memcpy(os->buf + os->pending, buffer, size);
 	os->pending += size;
 	if (os->object == NULL) {
-		debug("Stored %u bytes into temporary buffer", os->pending);
+		DBG("Stored %u bytes into temporary buffer", os->pending);
 		return 0;
 	}
 
@@ -391,7 +624,7 @@
 	unsigned int flags;
 	uint8_t hi;
 
-	debug("obex_write_stream: name=%s type=%s tx_mtu=%d file=%p",
+	DBG("name=%s type=%s tx_mtu=%d file=%p",
 		os->name ? os->name : "", os->type ? os->type : "",
 		os->tx_mtu, os->object);
 
@@ -465,28 +698,10 @@
 		ret = obex_read_stream(os, os->obex, os->obj);
 
 proceed:
-	switch (ret) {
-	case -EINVAL:
-		OBEX_ObjectSetRsp(os->obj, OBEX_RSP_BAD_REQUEST,
-				OBEX_RSP_BAD_REQUEST);
-		break;
-	case -EPERM:
-		OBEX_ObjectSetRsp(os->obj, OBEX_RSP_FORBIDDEN,
-					OBEX_RSP_FORBIDDEN);
-		break;
-	case -ENOENT:
-		OBEX_ObjectSetRsp(os->obj, OBEX_RSP_NOT_FOUND,
-							OBEX_RSP_NOT_FOUND);
-		break;
-	default:
-		if (ret < 0)
-			OBEX_ObjectSetRsp(os->obj,
-					OBEX_RSP_INTERNAL_SERVER_ERROR,
-					OBEX_RSP_INTERNAL_SERVER_ERROR);
-		break;
-	}
-
-	OBEX_ResumeRequest(os->obex);
+	if (ret < 0)
+		OBEX_CancelRequest(os->obex, TRUE);
+	else
+		OBEX_ResumeRequest(os->obex);
 
 	return FALSE;
 }
@@ -514,7 +729,7 @@
 		switch (hi) {
 		case OBEX_HDR_NAME:
 			if (os->name) {
-				debug("Ignoring multiple name headers");
+				DBG("Ignoring multiple name headers");
 				break;
 			}
 
@@ -523,11 +738,11 @@
 
 			os->name = g_convert((const char *) hd.bs, hlen,
 					"UTF8", "UTF16BE", NULL, NULL, NULL);
-			debug("OBEX_HDR_NAME: %s", os->name);
+			DBG("OBEX_HDR_NAME: %s", os->name);
 			break;
 		case OBEX_HDR_TYPE:
 			if (os->type) {
-				debug("Ignoring multiple type headers");
+				DBG("Ignoring multiple type headers");
 				break;
 			}
 
@@ -539,14 +754,14 @@
 				break;
 
 			if (!g_utf8_validate((const char *) hd.bs, -1, NULL)) {
-				debug("Invalid type header: %s", hd.bs);
+				DBG("Invalid type header: %s", hd.bs);
 				break;
 			}
 
 			/* FIXME: x-obex/folder-listing - type is mandatory */
 
 			os->type = g_strndup((const char *) hd.bs, hlen);
-			debug("OBEX_HDR_TYPE: %s", os->type);
+			DBG("OBEX_HDR_TYPE: %s", os->type);
 			os->driver = obex_mime_type_driver_find(
 						os->service->target, os->type,
 						os->service->who,
@@ -555,22 +770,17 @@
 		}
 	}
 
-	if (!os->driver) {
-		/* Fallback to target default */
+	if (os->type == NULL)
 		os->driver = obex_mime_type_driver_find(os->service->target,
-							NULL, NULL, 0);
-		if (!os->driver) {
-			/* Fallback to general default */
-			os->driver = obex_mime_type_driver_find(NULL,
-							NULL, NULL, 0);
-			if (!os->driver) {
-				error("No driver found");
-				OBEX_ObjectSetRsp(obj,
-						OBEX_RSP_NOT_IMPLEMENTED,
-						OBEX_RSP_NOT_IMPLEMENTED);
-				return;
-			}
-		}
+							NULL,
+							os->service->who,
+							os->service->who_size);
+
+	if (!os->driver) {
+		error("No driver found");
+		OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
+					OBEX_RSP_NOT_IMPLEMENTED);
+		return;
 	}
 
 	err = os->service->get(os, obj, &stream, os->service_data);
@@ -633,7 +843,7 @@
 			continue;
 
 		if (os->name) {
-			debug("Ignoring multiple name headers");
+			DBG("Ignoring multiple name headers");
 			break;
 		}
 
@@ -647,7 +857,7 @@
 		os->name = g_convert((const char *) hd.bs, hlen,
 				"UTF8", "UTF16BE", NULL, NULL, NULL);
 
-		debug("Set path name: %s", os->name);
+		DBG("Set path name: %s", os->name);
 		break;
 	}
 
@@ -659,7 +869,7 @@
 {
 	int err;
 	void *object;
-	size_t size;
+	size_t size = OBJECT_SIZE_UNKNOWN;
 
 	object = os->driver->open(filename, O_RDONLY, 0, os->service_data,
 								&size, &err);
@@ -700,7 +910,7 @@
 	os->path = g_strdup(filename);
 
 	if (!os->buf) {
-		debug("PUT request checked, no buffered data");
+		DBG("PUT request checked, no buffered data");
 		return 0;
 	}
 
@@ -734,7 +944,7 @@
 		switch (hi) {
 		case OBEX_HDR_NAME:
 			if (os->name) {
-				debug("Ignoring multiple name headers");
+				DBG("Ignoring multiple name headers");
 				break;
 			}
 
@@ -743,12 +953,12 @@
 
 			os->name = g_convert((const char *) hd.bs, hlen,
 					"UTF8", "UTF16BE", NULL, NULL, NULL);
-			debug("OBEX_HDR_NAME: %s", os->name);
+			DBG("OBEX_HDR_NAME: %s", os->name);
 			break;
 
 		case OBEX_HDR_TYPE:
 			if (os->type) {
-				debug("Ignoring multiple type headers");
+				DBG("Ignoring multiple type headers");
 				break;
 			}
 
@@ -760,12 +970,12 @@
 				break;
 
 			if (!g_utf8_validate((const char *) hd.bs, -1, NULL)) {
-				debug("Invalid type header: %s", hd.bs);
+				DBG("Invalid type header: %s", hd.bs);
 				break;
 			}
 
 			os->type = g_strndup((const char *) hd.bs, hlen);
-			debug("OBEX_HDR_TYPE: %s", os->type);
+			DBG("OBEX_HDR_TYPE: %s", os->type);
 			os->driver = obex_mime_type_driver_find(
 						os->service->target, os->type,
 						os->service->who,
@@ -779,7 +989,7 @@
 
 		case OBEX_HDR_LENGTH:
 			os->size = hd.bq4;
-			debug("OBEX_HDR_LENGTH: %d", os->size);
+			DBG("OBEX_HDR_LENGTH: %d", os->size);
 			break;
 		case OBEX_HDR_TIME:
 			os->time = parse_iso8610((const char *) hd.bs, hlen);
@@ -789,22 +999,17 @@
 
 	OBEX_ObjectReParseHeaders(obex, obj);
 
-	if (!os->driver) {
-		/* Fallback to target default */
+	if (os->type == NULL)
 		os->driver = obex_mime_type_driver_find(os->service->target,
-							NULL, NULL, 0);
-		if (!os->driver) {
-			/* Fallback to general default */
-			os->driver = obex_mime_type_driver_find(NULL,
-							NULL, NULL, 0);
-			if (!os->driver) {
-				error("No driver found");
-				OBEX_ObjectSetRsp(obj,
-						OBEX_RSP_NOT_IMPLEMENTED,
-						OBEX_RSP_NOT_IMPLEMENTED);
-				return FALSE;
-			}
-		}
+							NULL,
+							os->service->who,
+							os->service->who_size);
+
+	if (!os->driver) {
+		error("No driver found");
+		OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
+					OBEX_RSP_NOT_IMPLEMENTED);
+		return FALSE;
 	}
 
 	if (!os->service->chkput)
@@ -827,7 +1032,7 @@
 		os->driver->set_io_watch(os->object, handle_async_io, os);
 		return TRUE;
 	default:
-		debug("Unhandled chkput error: %d", ret);
+		DBG("Unhandled chkput error: %d", ret);
 		OBEX_ObjectSetRsp(obj, OBEX_RSP_INTERNAL_SERVER_ERROR,
 				OBEX_RSP_INTERNAL_SERVER_ERROR);
 		return FALSE;
@@ -835,7 +1040,7 @@
 	}
 
 	if (os->size == OBJECT_SIZE_DELETE || os->size == OBJECT_SIZE_UNKNOWN) {
-		debug("Got a PUT without a Length");
+		DBG("Got a PUT without a Length");
 		goto done;
 	}
 
@@ -852,10 +1057,6 @@
 	if (!os->service) {
 		OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
 		return;
-	} else if (!os->service->put) {
-		OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
-				OBEX_RSP_NOT_IMPLEMENTED);
-		return;
 	}
 
 	g_return_if_fail(chk_cid(obex, obj, os->cid));
@@ -865,17 +1066,24 @@
 			return;
 	}
 
+	if (!os->service->put) {
+		OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
+				OBEX_RSP_NOT_IMPLEMENTED);
+		return;
+	}
+
 	err = os->service->put(os, os->service_data);
 	if (err < 0)
 		os_set_response(obj, err);
 }
 
-static void obex_event(obex_t *obex, obex_object_t *obj, int mode,
+static void obex_event_cb(obex_t *obex, obex_object_t *obj, int mode,
 					int evt, int cmd, int rsp)
 {
 	struct obex_session *os;
+	int err;
 
-	obex_debug(evt, cmd, rsp);
+	print_event(evt, cmd, rsp);
 
 	os = OBEX_GetUserData(obex);
 
@@ -886,8 +1094,6 @@
 		break;
 	case OBEX_EV_ABORT:
 		os->aborted = TRUE;
-		if (os->service->reset)
-			os->service->reset(os, os->service_data);
 		os_reset_session(os);
 		OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
 		break;
@@ -902,9 +1108,6 @@
 		case OBEX_CMD_GET:
 		case OBEX_CMD_SETPATH:
 		default:
-			os_session_mark_aborted(os);
-			if (os->service->reset)
-				os->service->reset(os, os->service_data);
 			os_reset_session(os);
 			break;
 		}
@@ -955,49 +1158,32 @@
 			cmd_put(os, obex, obj);
 			break;
 		default:
-			debug("Unknown request: 0x%X", cmd);
+			DBG("Unknown request: 0x%X", cmd);
 			OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
 						OBEX_RSP_NOT_IMPLEMENTED);
 			break;
 		}
 		break;
 	case OBEX_EV_STREAMAVAIL:
-		switch (obex_read_stream(os, obex, obj)) {
-		case 0:
-			break;
-		case -EPERM:
-			OBEX_ObjectSetRsp(obj,
-				OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
-			break;
-		case -EAGAIN:
+		err = obex_read_stream(os, obex, obj);
+		if (err == -EAGAIN) {
 			OBEX_SuspendRequest(obex, obj);
 			os->obj = obj;
 			os->driver->set_io_watch(os->object, handle_async_io,
 									os);
-			break;
-		default:
-			OBEX_ObjectSetRsp(obj,
-				OBEX_RSP_INTERNAL_SERVER_ERROR,
-				OBEX_RSP_INTERNAL_SERVER_ERROR);
-			break;
-		}
+		} else if (err < 0)
+			os_set_response(obj, err);
 
 		break;
 	case OBEX_EV_STREAMEMPTY:
-		switch (obex_write_stream(os, obex, obj)) {
-		case -EPERM:
-			OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN,
-							OBEX_RSP_FORBIDDEN);
-			break;
-		case -EAGAIN:
+		err = obex_write_stream(os, obex, obj);
+		if (err == -EAGAIN) {
 			OBEX_SuspendRequest(obex, obj);
 			os->obj = obj;
 			os->driver->set_io_watch(os->object, handle_async_io,
 									os);
-			break;
-		default:
-			break;
-		}
+		} else if (err < 0)
+			os_set_response(obj, err);
 
 		break;
 	case OBEX_EV_LINKERR:
@@ -1008,24 +1194,18 @@
 		break;
 
 	default:
-		debug("Unknown evt %d", evt);
+		DBG("Unknown evt %d", evt);
 		break;
 	}
 }
 
-void server_free(struct server *server)
-{
-	g_free(server->folder);
-	g_free(server->capability);
-	g_free(server->devnode);
-	g_free(server);
-}
-
 static void obex_handle_destroy(void *user_data)
 {
 	struct obex_session *os;
 	obex_t *obex = user_data;
 
+	DBG("");
+
 	os = OBEX_GetUserData(obex);
 
 	if (os->service && os->service->disconnect)
@@ -1036,73 +1216,29 @@
 	OBEX_Cleanup(obex);
 }
 
-static gboolean tty_reinit(void *data)
-{
-	struct server *server = data;
-	GSList *l;
-	unsigned int services = 0;
-
-	for (l = server->drivers; l; l = l->next) {
-		struct obex_service_driver *driver = l->data;
-
-		services |= driver->service;
-	}
-
-	tty_init(services, server->folder, server->capability,
-			server->symlinks, server->devnode);
-
-	server_free(server);
-
-	return FALSE;
-}
-
 static gboolean obex_handle_input(GIOChannel *io,
 				GIOCondition cond, void *user_data)
 {
 	obex_t *obex = user_data;
-	struct obex_session *os = OBEX_GetUserData(obex);
 
 	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
 		error("obex_handle_input: poll event %s%s%s",
 				(cond & G_IO_HUP) ? "HUP " : "",
 				(cond & G_IO_ERR) ? "ERR " : "",
 				(cond & G_IO_NVAL) ? "NVAL " : "");
-		goto failed;
+		return FALSE;
 	}
 
 	if (OBEX_HandleInput(obex, 1) < 0) {
 		error("Handle input error");
-		goto failed;
+		return FALSE;
 	}
 
 	return TRUE;
-
-failed:
-	if (os->server->devnode) {
-		if (cond & G_IO_NVAL)
-			tty_closed();
-		else
-			g_idle_add(tty_reinit, os->server);
-	}
-
-	return FALSE;
-}
-
-void obex_connect_cb(GIOChannel *io, GError *err, void *user_data)
-{
-	struct server *server = user_data;
-
-	if (err) {
-		error("%s", err->message);
-		g_io_channel_shutdown(io, TRUE, NULL);
-		return;
-	}
-
-	if (obex_session_start(io, server) < 0)
-		g_io_channel_shutdown(io, TRUE, NULL);
 }
 
-int obex_session_start(GIOChannel *io, struct server *server)
+int obex_session_start(GIOChannel *io, uint16_t tx_mtu, uint16_t rx_mtu,
+			struct obex_server *server)
 {
 	struct obex_session *os;
 	obex_t *obex;
@@ -1110,14 +1246,14 @@
 
 	os = g_new0(struct obex_session, 1);
 
-	os->service = obex_service_driver_find(server->drivers, NULL, 0,
-						NULL, 0);
+	os->service = obex_service_driver_find(server->drivers, NULL,
+							0, NULL, 0);
 	os->server = server;
-	os->rx_mtu = server->rx_mtu ? server->rx_mtu : DEFAULT_RX_MTU;
-	os->tx_mtu = server->tx_mtu ? server->tx_mtu : DEFAULT_TX_MTU;
+	os->rx_mtu = rx_mtu != 0 ? rx_mtu : DEFAULT_RX_MTU;
+	os->tx_mtu = tx_mtu != 0 ? tx_mtu : DEFAULT_TX_MTU;
 	os->size = OBJECT_SIZE_DELETE;
 
-	obex = OBEX_Init(OBEX_TRANS_FD, obex_event, 0);
+	obex = OBEX_Init(OBEX_TRANS_FD, obex_event_cb, 0);
 	if (!obex) {
 		obex_session_free(os);
 		return -EIO;
@@ -1147,23 +1283,16 @@
 	return 0;
 }
 
-int obex_tty_session_stop(void)
+const char *obex_get_name(struct obex_session *os)
 {
-	GSList *l;
-
-	for (l = sessions; l != NULL; l = l->next) {
-		struct obex_session *os = l->data;
-
-		if (os->server->devnode && os->io)
-			g_io_channel_shutdown(os->io, TRUE, NULL);
-	}
-
-	return 0;
+	return os->name;
 }
 
-const char *obex_get_name(struct obex_session *os)
+void obex_set_name(struct obex_session *os, const char *name)
 {
-	return os->name;
+	g_free(os->name);
+	os->name = g_strdup(name);
+	DBG("Name changed: %s", os->name);
 }
 
 ssize_t obex_get_size(struct obex_session *os)
--- src/obex.h
+++ src/obex.h
@@ -29,7 +29,7 @@
 #define OBJECT_SIZE_UNKNOWN -1
 #define OBJECT_SIZE_DELETE -2
 
-#define OBEX_OPP	(1 << 0)
+#define OBEX_OPP	(1 << 1)
 #define OBEX_FTP	(1 << 2)
 #define OBEX_BIP	(1 << 3)
 #define OBEX_PBAP	(1 << 4)
@@ -45,6 +45,7 @@
 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);
+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);
 const char *obex_get_root_folder(struct obex_session *os);
@@ -62,10 +63,5 @@
 const char *obex_option_root_folder(void);
 gboolean obex_option_symlinks(void);
 
-int tty_init(int service, const char *folder, const char *capability,
-				gboolean symlinks, const char *devnode);
-int obex_tty_session_stop(void);
-void tty_closed(void);
-
 /* Just a thin wrapper around memcmp to deal with NULL values */
 int memcmp0(const void *a, const void *b, size_t n);
--- src/plugin.c
+++ src/plugin.c
@@ -34,7 +34,7 @@
 
 #include "obexd.h"
 #include "plugin.h"
-#include "logging.h"
+#include "log.h"
 
 /*
  * Plugins that are using libraries with threads and their own mainloop
@@ -74,7 +74,7 @@
 	}
 
 	plugins = g_slist_append(plugins, plugin);
-	debug("Plugin %s loaded", desc->name);
+	DBG("Plugin %s loaded", desc->name);
 
 	return TRUE;
 }
@@ -90,12 +90,12 @@
 	if (strlen(PLUGINDIR) == 0)
 		return FALSE;
 
-	debug("Loading builtin plugins");
+	DBG("Loading builtin plugins");
 
 	for (i = 0; __obex_builtin[i]; i++)
 		add_plugin(NULL,  __obex_builtin[i]);
 
-	debug("Loading plugins %s", PLUGINDIR);
+	DBG("Loading plugins %s", PLUGINDIR);
 
 	dir = g_dir_open(PLUGINDIR, 0, NULL);
 	if (!dir)
@@ -142,7 +142,7 @@
 {
 	GSList *list;
 
-	debug("Cleanup plugins");
+	DBG("Cleanup plugins");
 
 	for (list = plugins; list; list = list->next) {
 		struct obex_plugin *plugin = list->data;
--- src/server.c
+++ src/server.c
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <openobex/obex.h>
+
+#include "log.h"
+#include "obex.h"
+#include "obex-priv.h"
+#include "server.h"
+#include "dbus.h"
+#include "service.h"
+#include "transport.h"
+
+static GSList *servers = NULL;
+
+static void obex_server_free(struct obex_server *server)
+{
+	g_free(server->folder);
+	g_free(server->capability);
+	g_free(server);
+}
+
+int obex_server_init(uint16_t service, const char *folder,
+				gboolean secure, gboolean auto_accept,
+				gboolean symlinks, const char *capability)
+{
+	GSList *drivers;
+	GSList *transports;
+	GSList *l;
+
+	drivers = obex_service_driver_list(service);
+	if (drivers == NULL) {
+		DBG("No service driver registered");
+		return -EINVAL;
+	}
+
+	transports = obex_transport_driver_list();
+	if (transports == NULL) {
+		DBG("No transport driver registered");
+		return -EINVAL;
+	}
+
+	for (l = transports; l; l = l->next) {
+		struct obex_transport_driver *transport = l->data;
+		struct obex_server *server;
+		int err;
+
+		if (transport->service != 0 &&
+				(transport->service & service) == FALSE)
+			continue;
+
+		server = g_new0(struct obex_server, 1);
+		server->transport = transport;
+		server->drivers = drivers;
+		server->folder = g_strdup(folder);
+		server->auto_accept = auto_accept;
+		server->symlinks = symlinks;
+		server->capability = g_strdup(capability);
+		server->secure = secure;
+
+		server->transport_data = transport->start(server, &err);
+		if (server->transport_data == NULL) {
+			DBG("Unable to start %s transport: %s (%d)",
+					transport->name, strerror(err), err);
+			obex_server_free(server);
+			continue;
+		}
+
+		servers = g_slist_prepend(servers, server);
+	}
+
+	return 0;
+}
+
+void obex_server_exit(void)
+{
+	GSList *l;
+
+	for (l = servers; l; l = l->next) {
+		struct obex_server *server = l->data;
+
+		server->transport->stop(server->transport_data);
+		obex_server_free(server);
+	}
+
+	g_slist_free(servers);
+
+	return;
+}
+
+struct obex_service_driver *obex_server_find_driver(
+						struct obex_server *server,
+						uint8_t channel)
+{
+	GSList *l;
+
+	for (l = server->drivers; l; l = l->next) {
+		struct obex_service_driver *driver = l->data;
+
+		if (driver->channel == channel)
+			return driver;
+	}
+
+	return NULL;
+}
+
+int obex_server_new_connection(struct obex_server *server, GIOChannel *io,
+				uint16_t tx_mtu, uint16_t rx_mtu)
+{
+	return obex_session_start(io, tx_mtu, rx_mtu, server);
+}
--- src/server.h
+++ src/server.h
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at 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
+ *
+ */
+
+struct obex_server {
+	struct obex_transport_driver *transport;
+	void *transport_data;
+	gboolean auto_accept;
+	char *folder;
+	gboolean symlinks;
+	char *capability;
+	gboolean secure;
+	GIOChannel *io;
+	unsigned int watch;
+	GSList *drivers;
+};
+
+int obex_server_init(uint16_t service, const char *folder, gboolean secure,
+		gboolean auto_accept, gboolean symlinks,
+		const char *capability);
+
+void obex_server_exit(void);
+
+struct obex_service_driver *obex_server_find_driver(struct obex_server *server,
+							uint8_t channel);
+int obex_server_new_connection(struct obex_server *server, GIOChannel *io,
+				uint16_t tx_mtu, uint16_t rx_mtu);
--- src/service.c
+++ src/service.c
@@ -33,7 +33,7 @@
 
 #include "obex.h"
 #include "service.h"
-#include "logging.h"
+#include "log.h"
 
 static GSList *drivers = NULL;
 
@@ -46,7 +46,8 @@
 	for (l = drivers; l; l = l->next) {
 		struct obex_service_driver *driver = l->data;
 
-		if (memcmp0(who, driver->who, who_size))
+		/* who is optional, so only check for it if not NULL */
+		if (who != NULL && memcmp0(who, driver->who, who_size))
 			continue;
 
 		if (memcmp0(target, driver->target, target_size) == 0)
@@ -86,7 +87,7 @@
 		return -EPERM;
 	}
 
-	debug("driver %p service %s registered", driver, driver->name);
+	DBG("driver %p service %s registered", driver, driver->name);
 
 	/* Drivers that support who has priority */
 	if (driver->who)
@@ -104,7 +105,7 @@
 		return;
 	}
 
-	debug("driver %p service %s unregistered", driver, driver->name);
+	DBG("driver %p service %s unregistered", driver, driver->name);
 
 	drivers = g_slist_remove(drivers, driver);
 }
--- src/transport.c
+++ src/transport.c
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+
+#include <openobex/obex.h>
+
+#include "obex.h"
+#include "server.h"
+#include "transport.h"
+#include "log.h"
+
+static GSList *drivers = NULL;
+
+static struct obex_transport_driver *obex_transport_driver_find(
+							const char *name)
+{
+	GSList *l;
+
+	for (l = drivers; l; l = l->next) {
+		struct obex_transport_driver *driver = l->data;
+
+		if (g_strcmp0(name, driver->name) == 0)
+			return driver;
+	}
+
+	return NULL;
+}
+
+GSList *obex_transport_driver_list()
+{
+	return drivers;
+}
+
+int obex_transport_driver_register(struct obex_transport_driver *driver)
+{
+	if (!driver) {
+		error("Invalid driver");
+		return -EINVAL;
+	}
+
+	if (obex_transport_driver_find(driver->name) != NULL) {
+		error("Permission denied: transport %s already registered",
+			driver->name);
+		return -EPERM;
+	}
+
+	DBG("driver %p transport %s registered", driver, driver->name);
+
+	drivers = g_slist_prepend(drivers, driver);
+
+	return 0;
+}
+
+void obex_transport_driver_unregister(struct obex_transport_driver *driver)
+{
+	if (!g_slist_find(drivers, driver)) {
+		error("Unable to unregister: No such driver %p", driver);
+		return;
+	}
+
+	DBG("driver %p transport %s unregistered", driver, driver->name);
+
+	drivers = g_slist_remove(drivers, driver);
+}
--- src/transport.h
+++ src/transport.h
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel at 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
+ *
+ */
+
+struct obex_transport_driver {
+	const char *name;
+	uint16_t service;
+	void *(*start) (struct obex_server *server, int *err);
+	void (*stop) (void *data);
+};
+
+int obex_transport_driver_register(struct obex_transport_driver *driver);
+void obex_transport_driver_unregister(struct obex_transport_driver *driver);
+GSList *obex_transport_driver_list(void);
--- test/pbap-client
+++ test/pbap-client
@@ -18,12 +18,6 @@
 print "\n--- Select Phonebook internal:pb ---\n"
 pbap.Select("int", "pb")
 
-print "\n--- PullAll ---\n"
-pbap.SetFormat("vcard30")
-pbap.SetFilter(["VERSION", "FN", "TEL"]);
-ret = pbap.PullAll()
-print "%s" % (ret)
-
 print "\n--- GetSize ---\n"
 ret = pbap.GetSize()
 print "Size = %d\n" % (ret)
@@ -32,15 +26,13 @@
 ret = pbap.List()
 for item in ret:
 	print "%s : %s" % (item[0], item[1])
-
-if len(ret) > 0:
-	print "\n--- Pull First Available vCard ---\n"
 	pbap.SetFormat("vcard30")
 	pbap.SetFilter(["VERSION", "FN", "TEL"]);
-	ret = pbap.Pull(ret[0][0])
+	ret = pbap.Pull(item[0])
 	print "%s" % (ret)
 
-print "\n--- List All Available Filter Fields ---\n"
-ret = pbap.ListFilterFields()
-for item in ret:
-	print "%s" % (item)
+print "\n--- PullAll ---\n"
+pbap.SetFormat("vcard30")
+pbap.SetFilter(["VERSION", "FN", "TEL"]);
+ret = pbap.PullAll()
+print "%s" % (ret)

++++++ obexd.yaml
--- obexd.yaml
+++ obexd.yaml
@@ -1,6 +1,6 @@
 Name: obexd
 Summary: D-Bus service for Obex Client access
-Version: 0.26
+Version: 0.29
 Release: 1
 Group: System/Daemons
 License: GPLv2+



More information about the MeeGo-commits mailing list