[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