[PATCH obexd 2/3] MAP: Folder listing support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This adds a basic (without parsing or sending back application
parameters) handling of folder listing requests for Message Access
Profile.
---
 plugins/mas.c      |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 plugins/messages.h |    6 ++-
 2 files changed, 105 insertions(+), 4 deletions(-)

diff --git a/plugins/mas.c b/plugins/mas.c
index e88a0f0..4e1e07f 100644
--- a/plugins/mas.c
+++ b/plugins/mas.c
@@ -37,6 +37,7 @@
 #include "obex.h"
 #include "service.h"
 #include "mimetype.h"
+#include "filesystem.h"
 #include "dbus.h"
 
 #include "messages.h"
@@ -97,19 +98,44 @@
 #define STATUS_TYPE		"x-bt/messageStatus"
 #define UPDATE_TYPE		"x-bt/MAP-messageUpdate"
 
+#define XML_DECL "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+
+/* Building blocks for x-obex/folder-listing */
+#define FL_DTD "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">"
+#define FL_BODY_BEGIN "<folder-listing version=\"1.0\">"
+#define FL_BODY_EMPTY "<folder-listing version=\"1.0\"/>"
+#define FL_PARENT_FOLDER_ELEMENT "<parent-folder/>"
+#define FL_FOLDER_ELEMENT "<folder name=\"%s\"/>"
+#define FL_BODY_END "</folder-listing>"
+
 struct mas_session {
 	struct mas_request *request;
 	void *backend_data;
 	const char *name;
 	const char *type;
+	gboolean nth_call;
+	gboolean finished;
+	GString *buffer;
 };
 
 static const uint8_t MAS_TARGET[TARGET_SIZE] = {
 			0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, 0xdb,
 			0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66  };
 
+static void reset_request(struct mas_session *mas)
+{
+	if (mas->buffer) {
+		g_string_free(mas->buffer, TRUE);
+		mas->buffer = NULL;
+	}
+
+	mas->nth_call = FALSE;
+	mas->finished = FALSE;
+}
+
 static void mas_clean(struct mas_session *mas)
 {
+	reset_request(mas);
 	g_free(mas);
 }
 
@@ -187,11 +213,65 @@ failed:
 	return ret;
 }
 
+/* FIXME: Preserve whitespaces */
+static void g_string_append_escaped_printf(GString *string, const gchar *format,
+		...)
+{
+	va_list ap;
+	char *escaped;
+
+	va_start(ap, format);
+	escaped = g_markup_vprintf_escaped(format, ap);
+	g_string_append(string, escaped);
+	g_free(escaped);
+	va_end(ap);
+}
+
+static void get_folder_listing_cb(void *session, int err, uint16_t size,
+					const char *name, void *user_data)
+{
+	struct mas_session *mas = user_data;
+
+	if (err < 0 && err != -EAGAIN) {
+		obex_object_set_io_flags(mas, G_IO_ERR, err);
+		return;
+	}
+
+	if (!mas->nth_call) {
+		g_string_append(mas->buffer, XML_DECL);
+		g_string_append(mas->buffer, FL_DTD);
+		if (!name) {
+			g_string_append(mas->buffer, FL_BODY_EMPTY);
+			mas->finished = TRUE;
+			goto proceed;
+		}
+		g_string_append(mas->buffer, FL_BODY_BEGIN);
+		mas->nth_call = TRUE;
+	}
+
+	if (!name) {
+		g_string_append(mas->buffer, FL_BODY_END);
+		mas->finished = TRUE;
+		goto proceed;
+	}
+
+	if (g_strcmp0(name, "..") == 0)
+		g_string_append(mas->buffer, FL_PARENT_FOLDER_ELEMENT);
+	else
+		g_string_append_escaped_printf(mas->buffer, FL_FOLDER_ELEMENT,
+									name);
+
+proceed:
+	if (err != -EAGAIN)
+		obex_object_set_io_flags(mas, G_IO_IN, err);
+}
+
 static int start_get(struct mas_session *mas)
 {
 	/* NOTE: type is case-insensitive! */
 	if (g_ascii_strcasecmp(mas->type, FOLDER_LISTING_TYPE) == 0)
-		return -EINVAL;
+		return messages_get_folder_listing(mas->backend_data, mas->name,
+					0xffff, 0, get_folder_listing_cb, mas);
 	else if (g_ascii_strcasecmp(mas->type, MESSAGES_LISTING_TYPE) == 0)
 		return -EINVAL;
 	else if (g_ascii_strcasecmp(mas->type, MESSAGE_TYPE) == 0)
@@ -262,6 +342,10 @@ static void *any_open(const char *name, int oflag, mode_t mode,
 	if (*err)
 		return NULL;
 
+	mas->finished = FALSE;
+	mas->nth_call = FALSE;
+	mas->buffer = g_string_new("");
+
 	return mas;
 }
 
@@ -274,15 +358,30 @@ static ssize_t any_write(void *object, const void *buf, size_t count)
 
 static ssize_t any_read(void *obj, void *buf, size_t count)
 {
+	struct mas_session *mas = obj;
+	ssize_t len;
+
 	DBG("");
 
-	return 0;
+	len = string_read(mas->buffer, buf, count);
+
+	if (len == 0 && !mas->finished)
+		return -EAGAIN;
+
+	return len;
 }
 
 static int any_close(void *obj)
 {
+	struct mas_session *mas = obj;
+
 	DBG("");
 
+	if (!mas->finished)
+		messages_abort(mas->backend_data);
+
+	reset_request(mas);
+
 	return 0;
 }
 
diff --git a/plugins/messages.h b/plugins/messages.h
index c862b07..d9348c7 100644
--- a/plugins/messages.h
+++ b/plugins/messages.h
@@ -202,11 +202,13 @@ int messages_set_folder(void *session, const char *name, gboolean cdup);
  * Callback shall be called for every entry of the listing. 'name' is the
  * subdirectory name.
  */
+typedef void (*messages_folder_listing_cb)(void *session, int err,
+		uint16_t size, const char *name, void *user_data);
+
 int messages_get_folder_listing(void *session,
 		const char *name,
 		uint16_t max, uint16_t offset,
-		void (*callback)(void *session, int err, uint16_t size,
-			const char *name, void *user_data),
+		messages_folder_listing_cb callback,
 		void *user_data);
 
 /* Retrieves messages listing from a current directory.
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux