diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c
new file mode 100644
index 0000000..e275bf2
--- /dev/null
+++ b/obexd/plugins/filesystem.c
+/*
+ *
+ * OBEX Server
+ *
+ * Copyright (C) 2009 Intel Corporation
+ * Copyright (C) 2007-2009 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <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 <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include "plugin.h"
+#include "logging.h"
+#include "mimetype.h"
+#include "obex.h"
+
+#define EOL_CHARS "\n"
+
+#define FL_VERSION "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" EOL_CHARS
+
+#define FL_TYPE "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">" EOL_CHARS
+
+#define FL_TYPE_PCSUITE "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\"" EOL_CHARS \
+ " [ <!ATTLIST folder mem-type CDATA #IMPLIED> ]>" EOL_CHARS
+
+#define FL_BODY_BEGIN "<folder-listing version=\"1.0\">" EOL_CHARS
+
+#define FL_BODY_END "</folder-listing>" EOL_CHARS
+
+#define FL_PARENT_FOLDER_ELEMENT "<parent-folder/>" EOL_CHARS
+
+#define FL_FILE_ELEMENT "<file name=\"%s\" size=\"%lu\"" \
+ " %s accessed=\"%s\" " \
+ "modified=\"%s\" created=\"%s\"/>" EOL_CHARS
+
+#define FL_FOLDER_ELEMENT "<folder name=\"%s\" %s accessed=\"%s\" " \
+ "modified=\"%s\" created=\"%s\"/>" EOL_CHARS
+
+#define FL_FOLDER_ELEMENT_PCSUITE "<folder name=\"%s\" %s accessed=\"%s\"" \
+ " modified=\"%s\" mem-type=\"DEV\"" \
+ " created=\"%s\"/>" EOL_CHARS
+
+static const guint8 FTP_TARGET[TARGET_SIZE] = {
+ 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2,
+ 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 };
+
+static gchar *file_stat_line(gchar *filename, struct stat *fstat,
+ struct stat *dstat, gboolean root,
+ gboolean pcsuite)
+{
+ gchar perm[51], atime[18], ctime[18], mtime[18];
+ gchar *escaped, *ret = NULL;
+
+ snprintf(perm, 50, "user-perm=\"%s%s%s\" group-perm=\"%s%s%s\" "
+ "other-perm=\"%s%s%s\"",
+ (fstat->st_mode & S_IRUSR ? "R" : ""),
+ (fstat->st_mode & S_IWUSR ? "W" : ""),
+ (dstat->st_mode & S_IWUSR ? "D" : ""),
+ (fstat->st_mode & S_IRGRP ? "R" : ""),
+ (fstat->st_mode & S_IWGRP ? "W" : ""),
+ (dstat->st_mode & S_IWGRP ? "D" : ""),
+ (fstat->st_mode & S_IROTH ? "R" : ""),
+ (fstat->st_mode & S_IWOTH ? "W" : ""),
+ (dstat->st_mode & S_IWOTH ? "D" : ""));
+
+ strftime(atime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_atime));
+ strftime(ctime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_ctime));
+ strftime(mtime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_mtime));
+
+ escaped = g_markup_escape_text(filename, -1);
+
+ if (S_ISDIR(fstat->st_mode)) {
+ if (pcsuite && root && g_str_equal(filename, "Data"))
+ ret = g_strdup_printf(FL_FOLDER_ELEMENT_PCSUITE,
+ escaped, perm, atime,
+ mtime, ctime);
+ else
+ ret = g_strdup_printf(FL_FOLDER_ELEMENT, escaped, perm,
+ atime, mtime, ctime);
+ } else if (S_ISREG(fstat->st_mode))
+ ret = g_strdup_printf(FL_FILE_ELEMENT, escaped, fstat->st_size,
+ perm, atime, mtime, ctime);
+
+ g_free(escaped);
+
+ return ret;
+}
+
+static gpointer filesystem_open(const char *name, int oflag, mode_t mode,
+ size_t *size)
+{
+ struct stat stats;
+ struct statvfs buf;
+ int fd = open(name, oflag, mode);
+
+ if (fd < 0)
+ return NULL;
+
+ if (fstat(fd, &stats) < 0) {
+ error("fstat(fd=%d): %s (%d)", fd, strerror(errno), errno);
+ goto failed;
+ }
+
+ if (oflag == O_RDONLY) {
+ *size = stats.st_size;
+ return GINT_TO_POINTER(fd);
+ }
+
+ if (fstatvfs(fd, &buf) < 0)
+ goto failed;
+
+ if (buf.f_bsize * buf.f_bavail < *size) {
+ debug("Not enough free space on disk");
+ errno = -ENOSPC;
+ goto failed;
+ }
+
+ return GINT_TO_POINTER(fd);
+
+failed:
+ close(fd);
+ return NULL;
+}
+
+static int filesystem_close(gpointer object)
+{
+ return close(GPOINTER_TO_INT(object));
+}
+
+static ssize_t filesystem_read(gpointer object, void *buf, size_t count)
+{
+ return read(GPOINTER_TO_INT(object), buf, count);
+}
+
+static ssize_t filesystem_write(gpointer object, const void *buf, size_t count)
+{
+ return write(GPOINTER_TO_INT(object), buf, count);
+}
+
+static gpointer capability_open(const char *name, int oflag, mode_t mode,
+ size_t *size)
+{
+ GError *gerr = NULL;
+ gchar *buf;
+ gint exit;
+ gboolean ret;
+
+ if (oflag != O_RDONLY)
+ goto fail;
+
+ if (name[0] != '!') {
+ ret = g_file_get_contents(name, &buf, NULL, &gerr);
+ if (ret == FALSE) {
+ error("%s", gerr->message);
+ goto fail;
+ }
+
+ goto done;
+ }
+
+ ret = g_spawn_command_line_sync(name + 1, &buf, NULL, &exit, &gerr);
+ if (ret == FALSE) {
+ error("%s", gerr->message);
+ goto fail;
+ }
+
+ if (WEXITSTATUS(exit) != EXIT_SUCCESS) {
+ error("%s failed", name + 1);
+ g_free(buf);
+ goto fail;
+ }
+
+done:
+ if (size)
+ *size = strlen(buf);
+
+ return buf;
+
+fail:
+ if (gerr)
+ g_error_free(gerr);
+
+ errno = EPERM;
+ return NULL;
+}
+
+static int capability_close(gpointer object)
+{
+ g_free(object);
+ return 0;
+}
+
+static ssize_t capability_read(gpointer object, void *buf, size_t count)
+{
+ strncpy(buf, object, count);
+ return strlen(buf);
+}
+
+static gpointer folder_open(const char *name, int oflag, mode_t mode,
+ size_t *size)
+{
+ DIR *dir = opendir(name);
+
+ if (dir == NULL)
+ return NULL;
+
+ if (size)
+ *size = 1;
+
+ return dir;
+}
+
+static int folder_close(gpointer object)
+{
+ DIR *dir = (DIR *) object;
+
+ return closedir(dir);
+}
+
+static ssize_t folder_read(gpointer object, void *buf, size_t count)
+{
+ struct obex_session *os;
+ struct stat fstat, dstat;
+ struct dirent *ep;
+ DIR *dp = (DIR *) object;
+ GString *listing;
+ gboolean root, pcsuite;
+ gint err, len;
+
+ os = obex_get_session(object);
+ if (os->finished)
+ return 0;
+
+ pcsuite = os->server->services & OBEX_PCSUITE ? TRUE : FALSE;
+
+ listing = g_string_new(FL_VERSION);
+ listing = g_string_append(listing, pcsuite ? FL_TYPE_PCSUITE : FL_TYPE);
+
+ listing = g_string_append(listing, FL_BODY_BEGIN);
+
+ root = g_str_equal(os->current_folder, os->server->folder);
+
+ if (root && os->server->symlinks)
+ err = stat(os->current_folder, &dstat);
+ else {
+ listing = g_string_append(listing, FL_PARENT_FOLDER_ELEMENT);
+ err = lstat(os->current_folder, &dstat);
+ }
+
+ if (err < 0) {
+ err = -errno;
+ error("%s: %s(%d)", root ? "stat" : "lstat",
+ strerror(errno), errno);
+ goto failed;
+ }
+
+ while ((ep = readdir(dp))) {
+ gchar *name;
+ gchar *fullname;
+ gchar *line;
+
+ if (ep->d_name[0] == '.')
+ continue;
+
+ name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL);
+ if (name == NULL) {
+ error("g_filename_to_utf8: invalid filename");
+ continue;
+ }
+
+ fullname = g_build_filename(os->current_folder, ep->d_name, NULL);
+
+ if (root && os->server->symlinks)
+ err = stat(fullname, &fstat);
+ else
+ err = lstat(fullname, &fstat);
+
+ if (err < 0) {
+ debug("%s: %s(%d)", root ? "stat" : "lstat",
+ strerror(errno), errno);
+ g_free(name);
+ g_free(fullname);
+ continue;
+ }
+
+ g_free(fullname);
+
+ line = file_stat_line(name, &fstat, &dstat, root, pcsuite);
+ if (line == NULL) {
+ g_free(name);
+ continue;
+ }
+
+ g_free(name);
+
+ listing = g_string_append(listing, line);
+ g_free(line);
+ }
+
+ listing = g_string_append(listing, FL_BODY_END);
+ len = listing->len;
+ memcpy(buf, listing->str, len);
+ g_string_free(listing, TRUE);
+ os->finished = TRUE;
+
+ return len;
+
+failed:
+ g_string_free(listing, TRUE);
+ return err;
+}
+
+struct obex_mime_type_driver file = {
+ .open = filesystem_open,
+ .close = filesystem_close,
+ .read = filesystem_read,
+ .write = filesystem_write,
+ .remove = remove,
+};
+
+struct obex_mime_type_driver capability = {
+ .target = FTP_TARGET,
+ .mimetype = "x-obex/capability",
+ .open = capability_open,
+ .close = capability_close,
+ .read = capability_read,
+};
+
+struct obex_mime_type_driver folder = {
+ .target = FTP_TARGET,
+ .mimetype = "x-obex/folder-listing",
+ .open = folder_open,
+ .close = folder_close,
+ .read = folder_read,
+};
+
+static int filesystem_init(void)
+{
+ int err;
+
+ err = obex_mime_type_driver_register(&folder);
+ if (err < 0)
+ return err;
+
+ err = obex_mime_type_driver_register(&capability);
+ if (err < 0)
+ return err;
+
+ return obex_mime_type_driver_register(&file);
+}
+
+static void filesystem_exit(void)
+{
+ obex_mime_type_driver_unregister(&folder);
+ obex_mime_type_driver_unregister(&capability);
+ obex_mime_type_driver_unregister(&file);
+}
+
+OBEX_PLUGIN_DEFINE("filesystem", filesystem_init, filesystem_exit)
diff --git a/obexd/src/ftp.c b/obexd/src/ftp.c
index a53e43f..ffbcf73 100644
--- a/obexd/src/ftp.c
+++ b/obexd/src/ftp.c
#include "logging.h"
#include "obex.h"
#include "dbus.h"
+#include "mimetype.h"
#define LST_TYPE "x-obex/folder-listing"
#define CAP_TYPE "x-obex/capability"
-#define EOL_CHARS "\n"
-
-#define FL_VERSION "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" EOL_CHARS
-
-#define FL_TYPE "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">" EOL_CHARS
-
-#define FL_TYPE_PCSUITE "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\"" EOL_CHARS \
- " [ <!ATTLIST folder mem-type CDATA #IMPLIED> ]>" EOL_CHARS
-
-#define FL_BODY_BEGIN "<folder-listing version=\"1.0\">" EOL_CHARS
-
-#define FL_BODY_END "</folder-listing>" EOL_CHARS
-
-#define FL_PARENT_FOLDER_ELEMENT "<parent-folder/>" EOL_CHARS
-
-#define FL_FILE_ELEMENT "<file name=\"%s\" size=\"%lu\"" \
- " %s accessed=\"%s\" " \
- "modified=\"%s\" created=\"%s\"/>" EOL_CHARS
-
-#define FL_FOLDER_ELEMENT "<folder name=\"%s\" %s accessed=\"%s\" " \
- "modified=\"%s\" created=\"%s\"/>" EOL_CHARS
-
-#define FL_FOLDER_ELEMENT_PCSUITE "<folder name=\"%s\" %s accessed=\"%s\"" \
- " modified=\"%s\" mem-type=\"DEV\"" \
- " created=\"%s\"/>" EOL_CHARS
-
-static gchar *file_stat_line(gchar *filename, struct stat *fstat,
- struct stat *dstat, gboolean root,
- gboolean pcsuite)
-{
- gchar perm[51], atime[18], ctime[18], mtime[18];
- gchar *escaped, *ret = NULL;
-
- snprintf(perm, 50, "user-perm=\"%s%s%s\" group-perm=\"%s%s%s\" "
- "other-perm=\"%s%s%s\"",
- (fstat->st_mode & S_IRUSR ? "R" : ""),
- (fstat->st_mode & S_IWUSR ? "W" : ""),
- (dstat->st_mode & S_IWUSR ? "D" : ""),
- (fstat->st_mode & S_IRGRP ? "R" : ""),
- (fstat->st_mode & S_IWGRP ? "W" : ""),
- (dstat->st_mode & S_IWGRP ? "D" : ""),
- (fstat->st_mode & S_IROTH ? "R" : ""),
- (fstat->st_mode & S_IWOTH ? "W" : ""),
- (dstat->st_mode & S_IWOTH ? "D" : ""));
-
- strftime(atime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_atime));
- strftime(ctime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_ctime));
- strftime(mtime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_mtime));
-
- escaped = g_markup_escape_text(filename, -1);
-
- if (S_ISDIR(fstat->st_mode)) {
- if (pcsuite && root && g_str_equal(filename, "Data"))
- ret = g_strdup_printf(FL_FOLDER_ELEMENT_PCSUITE,
- escaped, perm, atime,
- mtime, ctime);
- else
- ret = g_strdup_printf(FL_FOLDER_ELEMENT, escaped, perm,
- atime, mtime, ctime);
- } else if (S_ISREG(fstat->st_mode))
- ret = g_strdup_printf(FL_FILE_ELEMENT, escaped, fstat->st_size,
- perm, atime, mtime, ctime);
-
- g_free(escaped);
-
- return ret;
-}
-
-static gint folder_listing(struct obex_session *os, guint32 *size)
+static gint folder_listing(struct obex_session *os, size_t *size)
{
- struct stat fstat, dstat;
- struct dirent *ep;
- DIR *dp;
- GString *listing;
- gboolean root, pcsuite;
- gint err;
-
- pcsuite = os->server->services & OBEX_PCSUITE ? TRUE : FALSE;
-
- listing = g_string_new(FL_VERSION);
- listing = g_string_append(listing, pcsuite ? FL_TYPE_PCSUITE : FL_TYPE);
-
- listing = g_string_append(listing, FL_BODY_BEGIN);
-
- root = g_str_equal(os->current_folder, os->server->folder);
-
- if (root && os->server->symlinks)
- err = stat(os->current_folder, &dstat);
- else {
- listing = g_string_append(listing, FL_PARENT_FOLDER_ELEMENT);
- err = lstat(os->current_folder, &dstat);
- }
-
- if (err < 0) {
- err = -errno;
- error("%s: %s(%d)", root ? "stat" : "lstat",
- strerror(errno), errno);
- goto failed;
- }
-
- dp = opendir(os->current_folder);
- if (dp == NULL) {
- err = -errno;
- error("opendir: failed to access %s", os->current_folder);
- goto failed;
- }
-
- while ((ep = readdir(dp))) {
- gchar *name;
- gchar *fullname;
- gchar *line;
-
- if (ep->d_name[0] == '.')
- continue;
-
- name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL);
- if (name == NULL) {
- error("g_filename_to_utf8: invalid filename");
- continue;
- }
-
- fullname = g_build_filename(os->current_folder, ep->d_name, NULL);
-
- if (root && os->server->symlinks)
- err = stat(fullname, &fstat);
- else
- err = lstat(fullname, &fstat);
-
- if (err < 0) {
- debug("%s: %s(%d)", root ? "stat" : "lstat",
- strerror(errno), errno);
- g_free(name);
- g_free(fullname);
- continue;
- }
-
- g_free(fullname);
-
- line = file_stat_line(name, &fstat, &dstat, root, pcsuite);
- if (line == NULL) {
- g_free(name);
- continue;
- }
-
- g_free(name);
-
- listing = g_string_append(listing, line);
- g_free(line);
- }
-
- closedir(dp);
-
- listing = g_string_append(listing, FL_BODY_END);
- *size = listing->len + 1;
- os->buf = (guint8*) g_string_free(listing, FALSE);
-
- return 0;
-
-failed:
- g_string_free(listing, TRUE);
- return err;
+ return os_prepare_get(os, os->current_folder, size);
}
-static gint get_capability(struct obex_session *os, guint32 *size)
+static gint get_capability(struct obex_session *os, size_t *size)
{
- GError *gerr = NULL;
- gchar *buf;
- gint exit;
- gboolean ret;
-
- if (os->server->capability == NULL)
- return -ENOENT;
-
- if (os->server->capability[0] != '!')
- return os_prepare_get(os, os->server->capability, size);
-
- ret = g_spawn_command_line_sync(os->server->capability + 1,
- &buf, NULL, &exit, &gerr);
- if (ret == FALSE) {
- error("g_spawn_command_line_sync: %s", gerr->message);
- g_error_free(gerr);
- return -EPERM;
- }
-
- if (WEXITSTATUS(exit) != EXIT_SUCCESS) {
- g_free(buf);
- return -EPERM;
- }
-
- os->buf = (guint8 *) buf;
- *size = strlen(buf);
-
- return 0;
+ return os_prepare_get(os, os->server->capability, size);
}
-static gint get_by_type(struct obex_session *os, gchar *type, guint32 *size)
+static gint get_by_type(struct obex_session *os, gchar *type, size_t *size)
{
if (type == NULL)
return -ENOENT;
}
static gint ftp_prepare_get(struct obex_session *os, gchar *file,
- guint32 *size)
+ size_t *size)
{
gboolean root;
{
obex_headerdata_t hv;
struct obex_session *os;
- guint32 size;
+ size_t size;
gint err;
gchar *path;
path = g_build_filename(os->current_folder, os->name, NULL);
- if (remove(path) < 0)
+ if (os->driver->remove(path) < 0)
ret = -errno;
g_free(path);
diff --git a/obexd/src/mimetype.c b/obexd/src/mimetype.c
new file mode 100644
index 0000000..b8e68c7
--- /dev/null
+++ b/obexd/src/mimetype.c
+/*
+ *
+ * OBEX Server
+ *
+ * Copyright (C) 2007-2009 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include "logging.h"
+#include "mimetype.h"
+#include "obex.h"
+
+static GSList *drivers = NULL;
+
+struct obex_mime_type_driver *obex_mime_type_driver_find(const guint8 *target, const char *mimetype)
+{
+ GSList *l;
+
+ for (l = drivers; l; l = l->next) {
+ struct obex_mime_type_driver *driver = l->data;
+
+ if (driver->target && target &&
+ memcmp(target, driver->target, TARGET_SIZE))
+ continue;
+
+ if (g_strcmp0(mimetype, driver->mimetype) == 0)
+ return driver;
+ }
+
+ return NULL;
+}
+
+int obex_mime_type_driver_register(struct obex_mime_type_driver *driver)
+{
+ if (!driver) {
+ error("Invalid driver");
+ return -EINVAL;
+ }
+
+ if (obex_mime_type_driver_find(driver->target, driver->mimetype)) {
+ error("Permission denied: %s could not be registered", driver->mimetype);
+ return -EPERM;
+ }
+
+ debug("driver %p mimetype %s registered", driver, driver->mimetype);
+
+ drivers = g_slist_append(drivers, driver);
+
+ return 0;
+}
+
+void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver)
+{
+ if (!g_slist_find(drivers, driver)) {
+ error("Unable to unregister: No such driver %p", driver);
+ return;
+ }
+
+ debug("driver %p mimetype %s unregistered", driver, driver->mimetype);
+
+ drivers = g_slist_remove(drivers, driver);
+}
diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h
new file mode 100644
index 0000000..8e2990e
--- /dev/null
+++ b/obexd/src/mimetype.h
+/*
+ *
+ * OBEX Server
+ *
+ * Copyright (C) 2007-2009 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define TARGET_SIZE 16
+
+struct obex_mime_type_driver {
+ const guint8 *target;
+ const char *mimetype;
+ gpointer (*open) (const char *name, int oflag, mode_t mode, size_t *size);
+ int (*close) (gpointer object);
+ ssize_t (*read) (gpointer object, void *buf, size_t count);
+ ssize_t (*write) (gpointer object, const void *buf, size_t count);
+ int (*remove) (const char *name);
+};
+
+int obex_mime_type_driver_register(struct obex_mime_type_driver *driver);
+void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver);
+struct obex_mime_type_driver *obex_mime_type_driver_find(const guint8 *target,
+ const char *mimetype);
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
index 9ec9c5b..212c369 100644
--- a/obexd/src/obex.c
+++ b/obexd/src/obex.c
#include "logging.h"
#include "obex.h"
#include "dbus.h"
+#include "mimetype.h"
/* Default MTU's */
#define DEFAULT_RX_MTU 32767
static void os_reset_session(struct obex_session *os)
{
- if (os->fd > 0) {
- close(os->fd);
- os->fd = -1;
+ if (os->object) {
+ os->driver->close(os->object);
+ os->object = NULL;
if (os->aborted && os->cmd == OBEX_CMD_PUT && os->current_folder) {
gchar *path;
path = g_build_filename(os->current_folder, os->name, NULL);
- unlink(path);
+ os->driver->remove(path);
g_free(path);
}
}
+
if (os->name) {
g_free(os->name);
os->name = NULL;
g_free(os->buf);
os->buf = NULL;
}
+ os->driver = NULL;
os->aborted = FALSE;
os->offset = 0;
os->size = OBJECT_SIZE_DELETE;
os->server->services &
(OBEX_FTP | OBEX_PCSUITE)) {
os->target = FTP_TARGET;
+ os->services = OBEX_FTP | OBEX_PCSUITE;
os->cmds = &ftp;
break;
}
if (memcmp(hd.bs, PBAP_TARGET, TARGET_SIZE) == 0 &&
os->server->services & OBEX_PBAP) {
os->target = PBAP_TARGET;
+ os->services = OBEX_PBAP;
os->cmds = &pbap;
pbap_phonebook_context_create(os);
break;
os->type = g_strndup((const gchar *) hd.bs, hlen);
debug("OBEX_HDR_TYPE: %s", os->type);
+ os->driver = obex_mime_type_driver_find(os->target, os->type);
break;
}
}
+ if (!os->driver) {
+ os->driver = obex_mime_type_driver_find(os->target, NULL);
+ if (!os->driver) {
+ error("No driver found");
+ OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
+ OBEX_RSP_NOT_IMPLEMENTED);
+ return;
+ }
+ }
+
os->cmds->get(obex, obj);
}
os->cmds->setpath(obex, obj);
}
-int os_prepare_get(struct obex_session *os, gchar *file, guint32 *size)
+int os_prepare_get(struct obex_session *os, gchar *filename, size_t *size)
{
- gint fd, err;
- struct stat stats;
+ gint err;
+ gpointer object;
- fd = open(file, O_RDONLY);
- if (fd < 0) {
- err = -errno;
- error("open(%s): %s (%d)", file, strerror(errno), errno);
- goto fail;
+ if (!os->driver) {
+ error("No driver to handle %s", os->type);
+ return -ENOENT;
}
- if (fstat(fd, &stats) < 0) {
+ object = os->driver->open(filename, O_RDONLY, 0, size);
+ if (object == NULL) {
err = -errno;
- error("fstat(fd=%d (%s)): %s (%d)", fd, file,
- strerror(errno), errno);
+ error("open(%s): %s (%d)", filename, strerror(errno), errno);
goto fail;
}
- os->fd = fd;
+ os->object = object;
os->offset = 0;
- if (stats.st_size > 0)
+ if (*size > 0)
os->buf = g_malloc0(os->tx_mtu);
- *size = stats.st_size;
-
return 0;
fail:
- if (fd >= 0)
- close(fd);
+ if (object)
+ os->driver->close(object);
return err;
}
gint32 len;
guint8 *ptr;
- debug("obex_write_stream: name=%s type=%s tx_mtu=%d fd=%d",
+ debug("obex_write_stream: name=%s type=%s tx_mtu=%d file=%p",
os->name ? os->name : "", os->type ? os->type : "",
- os->tx_mtu, os->fd);
+ os->tx_mtu, os->object);
if (os->aborted)
return -EPERM;
- if (os->fd < 0) {
+
+ if (os->object == NULL) {
if (os->buf == NULL && os->finished == FALSE)
return -EIO;
goto add_header;
}
- len = read(os->fd, os->buf, os->tx_mtu);
+ len = os->driver->read(os->object, os->buf, os->tx_mtu);
if (len < 0) {
gint err = errno;
error("read(): %s (%d)", strerror(err), err);
path = g_build_filename(os->current_folder, os->name, NULL);
- os->fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (os->fd < 0) {
+ os->object = os->driver->open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600,
+ (size_t *) &os->size);
+ if (os->object == NULL) {
error("open(%s): %s (%d)", path, strerror(errno), errno);
g_free(path);
return -EPERM;
while (len < os->offset) {
gint w;
- w = write(os->fd, os->buf + len, os->offset - len);
+ w = os->driver->write(os->object, os->buf + len, os->offset - len);
if (w < 0) {
gint err = errno;
error("write(%s): %s (%d)", path, strerror(errno),
return -EIO;
}
- if (os->fd < 0 && size > 0) {
+ if (os->object == NULL && size > 0) {
if (os->buf) {
error("Got more data but there is still a pending buffer");
return -EIO;
while (len < size) {
gint w;
- w = write(os->fd, buffer + len, size - len);
+ w = os->driver->write(os->object, buffer + len, size - len);
if (w < 0) {
gint err = errno;
if (err == EINTR)
static gboolean check_put(obex_t *obex, obex_object_t *obj)
{
struct obex_session *os;
- struct statvfs buf;
obex_headerdata_t hd;
guint hlen;
guint8 hi;
- long long unsigned int free;
int ret;
os = OBEX_GetUserData(obex);
os->type = g_strndup((const gchar *) hd.bs, hlen);
debug("OBEX_HDR_TYPE: %s", os->type);
+ os->driver = obex_mime_type_driver_find(os->target, os->type);
break;
case OBEX_HDR_BODY:
return FALSE;
}
+ if (!os->driver) {
+ os->driver = obex_mime_type_driver_find(os->target, NULL);
+ if (!os->driver) {
+ error("No driver found");
+ OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED,
+ OBEX_RSP_NOT_IMPLEMENTED);
+ return FALSE;
+ }
+ }
+
if (!os->cmds || !os->cmds->chkput)
goto done;
goto done;
}
- if (fstatvfs(os->fd, &buf) < 0) {
- int err = errno;
- error("fstatvfs(): %s(%d)", strerror(err), err);
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
- return FALSE;
- }
-
- free = (unsigned long long) buf.f_bsize * buf.f_bavail;
- debug("Free space in disk: %llu", free);
- if ((guint64) os->size > free) {
- debug("Free disk space not available");
- OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
- return FALSE;
- }
-
done:
os->checked = TRUE;
if (os->target == NULL) {
/* Got an error during a transfer. */
- if (os->fd >= 0)
+ if (os->object)
emit_transfer_completed(os->cid, os->offset == os->size);
unregister_transfer(os->cid);
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->fd = -1;
os->size = OBJECT_SIZE_DELETE;
obex = OBEX_Init(OBEX_TRANS_FD, obex_event, 0);
return 0;
}
+
+struct obex_session *obex_get_session(gpointer object)
+{
+ GSList *l;
+
+ for (l = sessions; l; l = l->next) {
+ struct obex_session *os = l->data;
+
+ if (os->object == object)
+ return os;
+ }
+
+ return NULL;
+}
diff --git a/obexd/src/obex.h b/obexd/src/obex.h
index 94a273e..13ecf81 100644
--- a/obexd/src/obex.h
+++ b/obexd/src/obex.h
#include "phonebook.h"
+#define OBJECT_SIZE_UNKNOWN -1
+#define OBJECT_SIZE_DELETE -2
+
#define OBEX_OPP (1 << 0)
#define OBEX_FTP (1 << 2)
#define OBEX_BIP (1 << 3)
#define OBEX_PBAP (1 << 4)
#define OBEX_PCSUITE (1 << 5)
-#define OBJECT_SIZE_UNKNOWN -1
-#define OBJECT_SIZE_DELETE -2
+struct obex_mime_type_driver;
struct obex_commands {
void (*get) (obex_t *obex, obex_object_t *obj);
struct obex_session {
GIOChannel *io;
guint32 cid;
+ guint16 services;
guint16 tx_mtu;
guint16 rx_mtu;
uint8_t cmd;
guint8 *buf;
gint32 offset;
gint32 size;
- gint fd;
+ gpointer object;
gboolean aborted;
const guint8 *target;
struct obex_commands *cmds;
gboolean checked;
obex_t *obex;
struct phonebook_context *pbctx;
+ struct obex_mime_type_driver *driver;
gboolean finished;
};
gint obex_session_start(GIOChannel *io, struct server *server);
+struct obex_session *obex_get_session(gpointer object);
gint obex_tty_session_stop(void);
void opp_get(obex_t *obex, obex_object_t *obj);
void pbap_phonebook_context_destroy(struct obex_session *session);
struct obex_session *pbap_get_session(struct phonebook_context *context);
-gint os_prepare_get(struct obex_session *os, gchar *file, guint32 *size);
+gint os_prepare_get(struct obex_session *os, gchar *file, size_t *size);
gint os_prepare_put(struct obex_session *os);
void server_free(struct server *server);
diff --git a/obexd/src/opp.c b/obexd/src/opp.c
index 9a50d68..a8dce13 100644
--- a/obexd/src/opp.c
+++ b/obexd/src/opp.c
{
struct obex_session *os;
obex_headerdata_t hv;
- guint32 size;
+ size_t size;
os = OBEX_GetUserData(obex);
if (os == NULL)
diff --git a/obexd/src/plugin.c b/obexd/src/plugin.c
index 6280085..b4c4a11 100644
--- a/obexd/src/plugin.c
+++ b/obexd/src/plugin.c
}
plugins = g_slist_append(plugins, plugin);
+ debug("Plugin %s loaded", desc->name);
return TRUE;
}