All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling
@ 2011-09-02  8:57 Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 2/8] MAP Tracker: Fix memory issue in folder listing Bartosz Szatkowski
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 plugins/messages-tracker.c |   11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 43321f6..eebfca3 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -124,13 +124,13 @@ static void create_folder_tree()
 {
 	struct message_folder *parent, *child;
 
-	folder_tree = create_folder("/", NULL);
+	folder_tree = create_folder("/", "FILTER (!BOUND(?msg))");
 
-	parent = create_folder("telecom", NULL);
+	parent = create_folder("telecom", "FILTER (!BOUND(?msg))");
 	folder_tree->subfolders = g_slist_append(folder_tree->subfolders,
 								parent);
 
-	child = create_folder("msg", NULL);
+	child = create_folder("msg", "FILTER (!BOUND(?msg))");
 	parent->subfolders = g_slist_append(parent->subfolders, child);
 
 	parent = child;
@@ -217,7 +217,10 @@ int messages_set_folder(void *s, const char *name, gboolean cdup)
 									NULL);
 	g_free(tmp);
 
-	newabs = g_build_filename("/", newrel, NULL);
+	if (newrel[0] != '/')
+		newabs = g_build_filename("/", newrel, NULL);
+	else
+		newabs = g_strdup(newrel);
 
 	session->folder = get_folder(newabs);
 	if (session->folder == NULL) {
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH obexd 2/8] MAP Tracker: Fix memory issue in folder listing
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
@ 2011-09-02  8:57 ` Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 3/8] MAP Tracker: Add support for DBus connection Bartosz Szatkowski
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 plugins/messages-tracker.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index eebfca3..218a016 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -40,7 +40,7 @@ struct message_folder {
 struct session {
 	char *cwd;
 	struct message_folder *folder;
-	const char *name;
+	char *name;
 	uint16_t max;
 	uint16_t offset;
 	void *user_data;
@@ -279,6 +279,7 @@ static gboolean async_get_folder_listing(void *s) {
 							session->user_data);
 
 	g_free(path);
+	g_free(session->name);
 
 	return FALSE;
 }
@@ -289,7 +290,7 @@ int messages_get_folder_listing(void *s, const char *name,
 					void *user_data)
 {
 	struct session *session = s;
-	session->name = name;
+	session->name = g_strdup(name);
 	session->max = max;
 	session->offset = offset;
 	session->folder_list_cb = callback;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH obexd 3/8] MAP Tracker: Add support for DBus connection
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 2/8] MAP Tracker: Fix memory issue in folder listing Bartosz Szatkowski
@ 2011-09-02  8:57 ` Bartosz Szatkowski
  2011-09-06 13:44   ` Johan Hedberg
  2011-09-02  8:57 ` [PATCH obexd 4/8] MAP Tracker Add basic support for messages listing Bartosz Szatkowski
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 plugins/messages-tracker.c |   32 ++++++++++++++++++++++++++++++++
 1 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 218a016..efcd007 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -28,7 +28,9 @@
 #include <errno.h>
 #include <glib.h>
 #include <string.h>
+#include <gdbus.h>
 
+#include "log.h"
 #include "messages.h"
 
 struct message_folder {
@@ -49,6 +51,7 @@ struct session {
 };
 
 static struct message_folder *folder_tree = NULL;
+static DBusConnection *session_connection = NULL;
 
 static struct message_folder *get_folder(const char *folder)
 {
@@ -148,8 +151,37 @@ static void create_folder_tree()
 	parent->subfolders = g_slist_append(parent->subfolders, child);
 }
 
+static DBusConnection *dbus_get_connection(DBusBusType type)
+{
+	DBusError err;
+	DBusConnection *tmp;
+
+	dbus_error_init(&err);
+
+	tmp = dbus_bus_get(type, &err);
+
+	if (dbus_error_is_set(&err))
+		error("Connection Error (%s)", err.message);
+
+	if (!tmp)
+		error("Error when getting on bus");
+
+	dbus_error_free(&err);
+
+	return tmp;
+}
+
 int messages_init(void)
 {
+	DBusError err;
+	dbus_error_init(&err);
+
+	if (session_connection == NULL)
+		session_connection = dbus_get_connection(DBUS_BUS_SESSION);
+
+	if (!session_connection)
+		return -1;
+
 	create_folder_tree();
 
 	return 0;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH obexd 4/8] MAP Tracker Add basic support for messages listing
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 2/8] MAP Tracker: Fix memory issue in folder listing Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 3/8] MAP Tracker: Add support for DBus connection Bartosz Szatkowski
@ 2011-09-02  8:57 ` Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 5/8] MAP Tracker Add filter support in " Bartosz Szatkowski
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 plugins/messages-tracker.c |  447 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 438 insertions(+), 9 deletions(-)

diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index efcd007..96a180e 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -33,6 +33,81 @@
 #include "log.h"
 #include "messages.h"
 
+#define TRACKER_SERVICE "org.freedesktop.Tracker1"
+#define TRACKER_RESOURCES_PATH "/org/freedesktop/Tracker1/Resources"
+#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
+
+#define QUERY_RESPONSE_SIZE 13
+#define MESSAGE_HANDLE_SIZE 16
+#define MESSAGE_HANDLE_PREFIX_LEN 8
+
+/*
+ * As stated in MAP errata bmessage-body-content-length-property should be
+ * length of: "BEGIN:MSG<CRLF>" + <message content> + "END:MSG<CRLF>"
+ */
+#define BMESSAGE_BASE_LEN (9 + 2 + 2 + 7 + 2)
+
+#define MESSAGE_HANDLE 0
+#define MESSAGE_SUBJECT 1
+#define MESSAGE_SDATE 2
+#define MESSAGE_RDATE 3
+#define MESSAGE_FROM_N 4
+#define MESSAGE_FROM_LASTN 5
+#define MESSAGE_FROM_PHONE 6
+#define MESSAGE_TO_N 7
+#define MESSAGE_TO_LASTN 8
+#define MESSAGE_TO_PHONE 9
+#define MESSAGE_READ 10
+#define MESSAGE_SENT 11
+#define MESSAGE_CONTENT 12
+
+#define LIST_MESSAGES_QUERY						\
+"SELECT "								\
+"?msg "									\
+"nmo:messageSubject(?msg) "						\
+"nmo:sentDate(?msg) "							\
+"nmo:receivedDate(?msg) "						\
+"nco:nameGiven(?from_c) "						\
+"nco:nameFamily(?from_c) "						\
+"nco:phoneNumber(?from_phone) "						\
+"nco:nameGiven(?to_c) "							\
+"nco:nameFamily(?to_c) "						\
+"nco:phoneNumber(?to_phone) "						\
+"nmo:isRead(?msg) "							\
+"nmo:isSent(?msg) "							\
+"nie:plainTextContent(?msg) "						\
+"WHERE { "								\
+	"?msg a nmo:SMSMessage . "					\
+	"%s "								\
+	"%s "								\
+	"OPTIONAL { "							\
+		"?msg nmo:from ?from . "				\
+		"?from nco:hasPhoneNumber ?from_phone . "		\
+		"?from_phone maemo:localPhoneNumber ?from_lphone . "	\
+		"OPTIONAL { "						\
+			"?from_c a nco:PersonContact . "		\
+			"OPTIONAL {?from_c nco:hasPhoneNumber ?phone .} "\
+			"OPTIONAL {?from_c nco:hasAffiliation ?af . "	\
+				"?af nco:hasPhoneNumber ?phone . } "	\
+			"?phone maemo:localPhoneNumber ?from_lphone . "	\
+		"} "							\
+	"} "								\
+	"OPTIONAL { "							\
+		"?msg nmo:to ?to . "					\
+		"?to nco:hasPhoneNumber ?to_phone . "			\
+		"?to_phone maemo:localPhoneNumber ?to_lphone . "	\
+		"OPTIONAL { "						\
+			"?to_c a nco:PersonContact . "			\
+			"OPTIONAL {?to_c nco:hasPhoneNumber ?phone1 .} "\
+			"OPTIONAL {?to_c nco:hasAffiliation ?af . "	\
+				"?af nco:hasPhoneNumber ?phone1 . } "	\
+			"?phone1 maemo:localPhoneNumber ?to_lphone "	\
+		"} "							\
+	"} "								\
+"} ORDER BY DESC(nmo:sentDate(?msg)) "
+
+typedef void (*reply_list_foreach_cb)(const char **reply, void *user_data);
+
 struct message_folder {
 	char *name;
 	GSList *subfolders;
@@ -45,14 +120,183 @@ struct session {
 	char *name;
 	uint16_t max;
 	uint16_t offset;
+	uint16_t size;
 	void *user_data;
-	void (*folder_list_cb)(void *session, int err, uint16_t size,
-					const char *name, void *user_data);
+	gboolean count;
+	gboolean new_message;
+	gboolean aborted;
+	reply_list_foreach_cb generate_response;
+	union {
+		messages_folder_listing_cb folder_list;
+		messages_get_messages_listing_cb messages_list;
+	} cb;
 };
 
 static struct message_folder *folder_tree = NULL;
 static DBusConnection *session_connection = NULL;
 
+static gboolean trace_call(void *data)
+{
+	DBusPendingCall *call = data;
+
+	if (dbus_pending_call_get_completed(call) == TRUE) {
+		dbus_pending_call_unref(call);
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void new_call(DBusPendingCall *call)
+{
+	g_timeout_add_seconds(5, trace_call, call);
+}
+
+static void free_msg_data(struct messages_message *msg)
+{
+	g_free(msg->handle);
+	g_free(msg->subject);
+	g_free(msg->datetime);
+	g_free(msg->sender_name);
+	g_free(msg->sender_addressing);
+	g_free(msg->replyto_addressing);
+	g_free(msg->recipient_name);
+	g_free(msg->recipient_addressing);
+	g_free(msg->type);
+	g_free(msg->reception_status);
+	g_free(msg->size);
+	g_free(msg->attachment_size);
+
+	g_free(msg);
+}
+
+static char **string_array_from_iter(DBusMessageIter iter, int array_len)
+{
+	DBusMessageIter sub;
+	char **result;
+	int i;
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+		return NULL;
+
+	result = g_new0(char *, array_len + 1);
+
+	dbus_message_iter_recurse(&iter, &sub);
+
+	i = 0;
+	while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
+		char *arg;
+
+		if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
+			g_free(result);
+
+			return NULL;
+		}
+
+		dbus_message_iter_get_basic(&sub, &arg);
+
+		result[i++] = arg;
+
+		dbus_message_iter_next(&sub);
+	}
+
+	return result;
+}
+
+static void query_reply(DBusPendingCall *call, void *user_data)
+{
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	struct session *session = user_data;
+	DBusMessageIter iter, element;
+	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 done;
+	}
+
+	dbus_message_iter_init(reply, &iter);
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+		error("SparqlQuery reply is not an array");
+
+		goto done;
+	}
+
+	dbus_message_iter_recurse(&iter, &element);
+
+	while (dbus_message_iter_get_arg_type(&element) != DBUS_TYPE_INVALID) {
+		char **node;
+
+		if (dbus_message_iter_get_arg_type(&element)
+							!= DBUS_TYPE_ARRAY) {
+			error("Element is not an array\n");
+
+			goto done;
+		}
+
+		node = string_array_from_iter(element, QUERY_RESPONSE_SIZE);
+
+		session->generate_response((const char **) node, session);
+
+		g_free(node);
+
+		dbus_message_iter_next(&element);
+	}
+
+done:
+	session->generate_response(NULL, session);
+
+	dbus_message_unref(reply);
+}
+
+static DBusPendingCall *query_tracker(char *query, void *user_data, int *err)
+{
+	DBusPendingCall *call;
+	DBusMessage *msg;
+
+	msg = dbus_message_new_method_call(TRACKER_SERVICE,
+						TRACKER_RESOURCES_PATH,
+						TRACKER_RESOURCES_INTERFACE,
+						"SparqlQuery");
+	if (msg == NULL) {
+		if (err)
+			*err = -EPERM;
+
+		return NULL;
+	}
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &query,
+							 DBUS_TYPE_INVALID);
+
+	if (dbus_connection_send_with_reply(session_connection, msg, &call,
+								-1) == FALSE) {
+		error("Could not send dbus message");
+
+		dbus_message_unref(msg);
+		if (err)
+			*err = -EPERM;
+
+		return NULL;
+	}
+
+	dbus_pending_call_set_notify(call, query_reply, user_data, NULL);
+
+	dbus_message_unref(msg);
+
+	return call;
+}
+
+static char *folder2query(const struct message_folder *folder,
+							const char *query)
+{
+	return g_strdup_printf(query, folder->query, "");
+}
+
 static struct message_folder *get_folder(const char *folder)
 {
 	GSList *folders = folder_tree->subfolders;
@@ -151,6 +395,24 @@ static void create_folder_tree()
 	parent->subfolders = g_slist_append(parent->subfolders, child);
 }
 
+static char *merge_names(const char *name, const char *lastname)
+{
+	char *tmp = NULL;
+
+	if (strlen(lastname) != 0) {
+		if (strlen(name) == 0)
+			tmp = g_strdup(lastname);
+		else
+			tmp = g_strdup_printf("%s %s", name, lastname);
+
+	} else if (strlen(name) != 0)
+		tmp = g_strdup(name);
+	else
+		tmp = g_strdup("");
+
+	return tmp;
+}
+
 static DBusConnection *dbus_get_connection(DBusBusType type)
 {
 	DBusError err;
@@ -171,6 +433,120 @@ static DBusConnection *dbus_get_connection(DBusBusType type)
 	return tmp;
 }
 
+static struct messages_message *pull_message_data(const char **reply)
+{
+	struct messages_message *data = g_new0(struct messages_message, 1);
+
+	data->handle = g_strdup(reply[MESSAGE_HANDLE]
+						+ MESSAGE_HANDLE_PREFIX_LEN);
+
+	if (strlen(reply[MESSAGE_SUBJECT]) != 0)
+		data->subject = g_strdup(reply[MESSAGE_SUBJECT]);
+	else
+		data->subject = g_strdup(reply[MESSAGE_CONTENT]);
+
+	data->mask |= PMASK_SUBJECT;
+
+	if (strlen(reply[MESSAGE_SDATE]) != 0) {
+		char **date = g_strsplit_set(reply[MESSAGE_SDATE], ":-Z", -1);
+
+		data->datetime = g_strjoinv(NULL, date);
+		g_strfreev(date);
+	} else if (strlen(reply[MESSAGE_RDATE]) != 0) {
+		char **date = g_strsplit_set(reply[MESSAGE_RDATE], ":-Z", -1);
+
+		data->datetime = g_strjoinv(NULL, date);
+		g_strfreev(date);
+	} else {
+		data->datetime = g_strdup("");
+	}
+
+	data->mask |= PMASK_DATETIME;
+
+	data->sender_name = merge_names(reply[MESSAGE_FROM_N],
+					reply[MESSAGE_FROM_LASTN]);
+	data->mask |= PMASK_SENDER_NAME;
+
+	data->sender_addressing = g_strdup(reply[MESSAGE_FROM_PHONE]);
+	data->mask |= PMASK_SENDER_ADDRESSING;
+
+	data->recipient_name = merge_names(reply[MESSAGE_TO_N],
+						reply[MESSAGE_TO_LASTN]);
+	data->mask |= PMASK_RECIPIENT_NAME;
+
+	data->recipient_addressing = g_strdup(reply[MESSAGE_TO_PHONE]);
+	data->mask |= PMASK_RECIPIENT_ADDRESSING;
+
+	data->type = g_strdup("SMS_GSM");
+	data->mask |= PMASK_TYPE;
+
+	data->size = g_strdup_printf("%d", strlen(reply[MESSAGE_CONTENT]) +
+					BMESSAGE_BASE_LEN);
+	data->mask |= PMASK_SIZE;
+
+	data->text = TRUE;
+	data->mask |= PMASK_TEXT;
+
+	data->reception_status = g_strdup("complete");
+	data->mask |= PMASK_RECEPTION_STATUS;
+
+	data->attachment_size = g_strdup("0");
+	data->mask |= PMASK_ATTACHMENT_SIZE;
+
+	data->priority = FALSE;
+	data->mask |= PMASK_PRIORITY;
+
+	data->read = g_strcmp0(reply[MESSAGE_READ], "true") == 0 ? TRUE : FALSE;
+	data->mask |= PMASK_READ;
+
+	data->sent = g_strcmp0(reply[MESSAGE_SENT], "true") == 0 ? TRUE : FALSE;
+	data->mask |= PMASK_SENT;
+
+	data->protect = FALSE;
+	data->mask |= PMASK_PROTECTED;
+
+	return data;
+}
+
+static void get_messages_listing_resp(const char **reply, void *user_data)
+{
+	struct session *session = user_data;
+	struct messages_message *msg_data;
+
+	DBG("reply %p", reply);
+
+	if (reply == NULL)
+		goto done;
+
+	if (session->aborted)
+		return;
+
+	msg_data = pull_message_data(reply);
+
+	session->size++;
+
+	if (!msg_data->read)
+			session->new_message = TRUE;
+
+	if (session->count == TRUE) {
+		free_msg_data(msg_data);
+		return;
+	}
+
+	if (session->size > session->offset)
+		session->cb.messages_list(session, -EAGAIN, 1,
+						session->new_message, msg_data,
+						session->user_data);
+
+	free_msg_data(msg_data);
+	return;
+
+done:
+	session->cb.messages_list(session, 0, session->size,
+						session->new_message, NULL,
+						session->user_data);
+}
+
 int messages_init(void)
 {
 	DBusError err;
@@ -302,12 +678,12 @@ static gboolean async_get_folder_listing(void *s) {
 		struct message_folder *dir_data = dir->data;
 
 		if (count == FALSE && session->offset <= folder_count)
-			session->folder_list_cb(session, -EAGAIN, 0,
+			session->cb.folder_list(session, -EAGAIN, 1,
 					dir_data->name, session->user_data);
 	}
 
  done:
-	session->folder_list_cb(session, 0, folder_count, NULL,
+	session->cb.folder_list(session, 0, folder_count, NULL,
 							session->user_data);
 
 	g_free(path);
@@ -325,7 +701,7 @@ int messages_get_folder_listing(void *s, const char *name,
 	session->name = g_strdup(name);
 	session->max = max;
 	session->offset = offset;
-	session->folder_list_cb = callback;
+	session->cb.folder_list = callback;
 	session->user_data = user_data;
 
 	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing,
@@ -334,14 +710,64 @@ int messages_get_folder_listing(void *s, const char *name,
 	return 0;
 }
 
-int messages_get_messages_listing(void *session,
-				const char *name,
+int messages_get_messages_listing(void *s, const char *name,
 				uint16_t max, uint16_t offset,
 				const struct messages_filter *filter,
 				messages_get_messages_listing_cb callback,
 				void *user_data)
 {
-	return -EINVAL;
+	struct session *session = s;
+	char *path, *query;
+	struct message_folder *folder = NULL;
+	DBusPendingCall *call;
+	int err = 0;
+
+	if (name == NULL || strlen(name) == 0) {
+		path = g_strdup(session->cwd);
+
+		folder = session->folder;
+		if (folder == NULL)
+			folder = get_folder(path);
+	} else {
+		if (strchr(name, '/') != NULL)
+			return -EBADR;
+
+		path = g_build_filename(session->cwd, name, NULL);
+		folder = get_folder(path);
+	}
+
+	g_free(path);
+
+	if (folder == NULL)
+		return -ENOENT;
+
+	query = folder2query(folder, LIST_MESSAGES_QUERY);
+	if (query == NULL)
+		return -ENOENT;
+
+	session->generate_response = get_messages_listing_resp;
+	session->cb.messages_list = callback;
+	session->offset = offset;
+	session->max = max;
+	session->user_data = user_data;
+	session->new_message = FALSE;
+	session->count = FALSE;
+	session->size = 0;
+	session->aborted = FALSE;
+
+	if (max == 0) {
+		session->max = 0xffff;
+		session->offset = 0;
+		session->count = TRUE;
+	}
+
+	call = query_tracker(query, session, &err);
+	if (err == 0)
+		new_call(call);
+
+	g_free(query);
+
+	return err;
 }
 
 int messages_get_message(void *session,
@@ -353,6 +779,9 @@ int messages_get_message(void *session,
 	return -EINVAL;
 }
 
-void messages_abort(void *session)
+void messages_abort(void *s)
 {
+	struct session *session = s;
+
+	session->aborted = TRUE;
 }
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH obexd 5/8] MAP Tracker Add filter support in messages listing
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
                   ` (2 preceding siblings ...)
  2011-09-02  8:57 ` [PATCH obexd 4/8] MAP Tracker Add basic support for messages listing Bartosz Szatkowski
@ 2011-09-02  8:57 ` Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 6/8] MAP Tracker: Add support for pulling messages Bartosz Szatkowski
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 plugins/messages-tracker.c |  102 +++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 101 insertions(+), 1 deletions(-)

diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 96a180e..8624381 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -126,6 +126,7 @@ struct session {
 	gboolean new_message;
 	gboolean aborted;
 	reply_list_foreach_cb generate_response;
+	struct messages_filter *filter;
 	union {
 		messages_folder_listing_cb folder_list;
 		messages_get_messages_listing_cb messages_list;
@@ -171,6 +172,22 @@ static void free_msg_data(struct messages_message *msg)
 	g_free(msg);
 }
 
+static struct messages_filter *copy_messages_filter(
+					const struct messages_filter *orig)
+{
+	struct messages_filter *filter = g_new0(struct messages_filter, 1);
+	filter->parameter_mask = orig->parameter_mask;
+	filter->type = orig->type;
+	filter->period_begin = g_strdup(orig->period_begin);
+	filter->period_end = g_strdup(orig->period_end);
+	filter->read_status = orig->read_status;
+	filter->recipient = g_strdup(orig->recipient);
+	filter->originator = g_strdup(orig->originator);
+	filter->priority = orig->priority;
+
+	return filter;
+}
+
 static char **string_array_from_iter(DBusMessageIter iter, int array_len)
 {
 	DBusMessageIter sub;
@@ -433,6 +450,81 @@ static DBusConnection *dbus_get_connection(DBusBusType type)
 	return tmp;
 }
 
+static gboolean filter_message(struct messages_message *message,
+						struct messages_filter *filter)
+{
+	if (filter->type != 0) {
+		if (g_strcmp0(message->type, "SMS_GSM") == 0 &&
+				(filter->type & 0x01))
+			return FALSE;
+
+		if (g_strcmp0(message->type, "SMS_CDMA") == 0 &&
+				(filter->type & 0x02))
+			return FALSE;
+
+		if (g_strcmp0(message->type, "SMS_EMAIL") == 0 &&
+				(filter->type & 0x04))
+			return FALSE;
+
+		if (g_strcmp0(message->type, "SMS_MMS") == 0 &&
+				(filter->type & 0x08))
+			return FALSE;
+	}
+
+	if (filter->read_status != 0) {
+		if (filter->read_status == 0x01 && message->read != FALSE)
+			return FALSE;
+
+		if (filter->read_status == 0x02 && message->read != TRUE)
+			return FALSE;
+	}
+
+	if (filter->priority != 0) {
+		if (filter->priority == 0x01 && message->priority == FALSE)
+			return FALSE;
+
+		if (filter->priority == 0x02 && message->priority == TRUE)
+			return FALSE;
+	}
+
+	if (filter->period_begin != NULL &&
+			g_strcmp0(filter->period_begin, message->datetime) > 0)
+		return FALSE;
+
+	if (filter->period_end != NULL &&
+			g_strcmp0(filter->period_end, message->datetime) < 0)
+		return FALSE;
+
+	if (filter->originator != NULL) {
+		char *orig = g_strdup_printf("*%s*", filter->originator);
+
+		if (g_pattern_match_simple(orig,
+					message->sender_addressing) == FALSE &&
+				g_pattern_match_simple(orig,
+					message->sender_name) == FALSE) {
+			g_free(orig);
+			return FALSE;
+		}
+		g_free(orig);
+	}
+
+	if (filter->recipient != NULL) {
+		char *recip = g_strdup_printf("*%s*", filter->recipient);
+
+		if (g_pattern_match_simple(recip,
+					message->recipient_addressing) == FALSE
+				&& g_pattern_match_simple(recip,
+					message->recipient_name) == FALSE) {
+			g_free(recip);
+			return FALSE;
+		}
+
+		g_free(recip);
+	}
+
+	return TRUE;
+}
+
 static struct messages_message *pull_message_data(const char **reply)
 {
 	struct messages_message *data = g_new0(struct messages_message, 1);
@@ -533,7 +625,8 @@ static void get_messages_listing_resp(const char **reply, void *user_data)
 		return;
 	}
 
-	if (session->size > session->offset)
+	if (session->size > session->offset &&
+				filter_message(msg_data, session->filter))
 		session->cb.messages_list(session, -EAGAIN, 1,
 						session->new_message, msg_data,
 						session->user_data);
@@ -545,6 +638,12 @@ done:
 	session->cb.messages_list(session, 0, session->size,
 						session->new_message, NULL,
 						session->user_data);
+
+	g_free(session->filter->period_begin);
+	g_free(session->filter->period_end);
+	g_free(session->filter->originator);
+	g_free(session->filter->recipient);
+	g_free(session->filter);
 }
 
 int messages_init(void)
@@ -745,6 +844,7 @@ int messages_get_messages_listing(void *s, const char *name,
 	if (query == NULL)
 		return -ENOENT;
 
+	session->filter = copy_messages_filter(filter);
 	session->generate_response = get_messages_listing_resp;
 	session->cb.messages_list = callback;
 	session->offset = offset;
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH obexd 6/8] MAP Tracker: Add support for pulling messages
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
                   ` (3 preceding siblings ...)
  2011-09-02  8:57 ` [PATCH obexd 5/8] MAP Tracker Add filter support in " Bartosz Szatkowski
@ 2011-09-02  8:57 ` Bartosz Szatkowski
  2011-09-02 13:36   ` [PATCH " Bartosz Szatkowski
  2011-09-02  8:57 ` [PATCH obexd 7/8] MAP Tracker: Add abort support in folder listing Bartosz Szatkowski
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 Makefile.am                |    3 +-
 plugins/bmsg.c             |  322 ++++++++++++++++++++++++++++++++++++++++++++
 plugins/bmsg.h             |   86 ++++++++++++
 plugins/messages-tracker.c |  171 ++++++++++++++++++++++--
 4 files changed, 569 insertions(+), 13 deletions(-)
 create mode 100644 plugins/bmsg.c
 create mode 100644 plugins/bmsg.h

diff --git a/Makefile.am b/Makefile.am
index 374fa1d..9cf3d02 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -66,7 +66,8 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
 			plugins/vcard.h plugins/vcard.c
 
 builtin_modules += mas
-builtin_sources += plugins/mas.c plugins/messages.h
+builtin_sources += plugins/mas.c plugins/messages.h \
+			   plugins/bmsg.h plugins/bmsg.c
 
 builtin_modules += irmc
 builtin_sources += plugins/irmc.c
diff --git a/plugins/bmsg.c b/plugins/bmsg.c
new file mode 100644
index 0000000..b843ff3
--- /dev/null
+++ b/plugins/bmsg.c
@@ -0,0 +1,322 @@
+/*
+ *  bMessage (MAP) format helpers
+ *
+ *  Copyright (C) 2010, 2011  Bartosz Szatkowski <bulislaw@linux.com>
+ *
+ *
+ *  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
+ *
+ */
+
+#include "bmsg.h"
+
+static GString *parse_vcard(struct bmsg_vcard *vcard)
+{
+	GString *buf;
+
+	if (vcard == NULL)
+		return NULL;
+
+	if (vcard->version == NULL)
+		return NULL;
+
+	if (vcard->n == NULL)
+		return NULL;
+
+	buf = g_string_new("");
+
+	g_string_append_printf(buf, "BEGIN:VCARD\r\n");
+	g_string_append_printf(buf, "VERSION:%s\r\n", vcard->version);
+
+	if (vcard->n != NULL)
+		g_string_append_printf(buf, "N:%s\r\n", vcard->n);
+
+	if (vcard->fn != NULL)
+		g_string_append_printf(buf, "FN:%s\r\n", vcard->fn);
+
+	if (vcard->tel != NULL)
+		g_string_append_printf(buf, "TEL:%s\r\n", vcard->tel);
+
+	if (vcard->email != NULL)
+		g_string_append_printf(buf, "EMAIL:%s\r\n", vcard->email);
+
+	g_string_append_printf(buf, "END:VCARD\r\n");
+
+	return buf;
+}
+
+static void free_glist_vcard(void *item, void *user_data)
+{
+	struct bmsg_vcard *tmp = item;
+
+	if (tmp == NULL)
+		return;
+
+	g_free(tmp->version);
+	g_free(tmp->n);
+	g_free(tmp->fn);
+	g_free(tmp->tel);
+	g_free(tmp->email);
+	g_free(item);
+}
+
+static void string_append_glist_vcard(void *list_item, void *list)
+{
+	GString *buf = list;
+	GString *item = parse_vcard(list_item);
+
+	g_string_append(buf, item->str);
+
+	g_string_free(item, TRUE);
+}
+
+static void envelope_destroy(struct bmsg_envelope *env)
+{
+	if (env->recipients) {
+		g_list_foreach(env->recipients, free_glist_vcard, NULL);
+		g_list_free(env->recipients);
+	}
+
+	if (env->content == NULL)
+		return;
+
+	g_free(env->content->encoding);
+	g_free(env->content->charset);
+	g_free(env->content->lang);
+	g_free(env->content->content);
+	g_free(env->content);
+}
+
+void bmsg_init(struct bmsg *msg, const char *version, const char *status,
+		const char *type, const char *folder)
+{
+	msg->version = g_strdup(version);
+	msg->status = g_strdup(status);
+	msg->type = g_strdup(type);
+	msg->folder = g_strdup(folder);
+	msg->envelopes = g_array_sized_new(FALSE, TRUE,
+					sizeof(struct bmsg_envelope *),
+					MAX_ENVELOPES_NUM);
+}
+
+void bmsg_destroy(struct bmsg *msg)
+{
+	unsigned i;
+
+	g_free(msg->version);
+	g_free(msg->status);
+	g_free(msg->type);
+	g_free(msg->folder);
+
+	if (msg->originators) {
+		g_list_foreach(msg->originators, free_glist_vcard, NULL);
+		g_list_free(msg->originators);
+	}
+
+	if (msg->envelopes == NULL)
+		return;
+
+	for (i = 0; i < msg->envelopes->len; i++) {
+		struct bmsg_envelope *tmp = g_array_index(msg->envelopes,
+						struct bmsg_envelope *, i);
+
+		envelope_destroy(tmp);
+		g_free(tmp);
+	}
+
+	g_array_free(msg->envelopes, TRUE);
+
+	g_free(msg);
+}
+
+static struct bmsg_vcard *make_vcard(const char *version, const char *name,
+					const char *fullname, const char *tel,
+					const char *email)
+{
+	struct bmsg_vcard *vcard = g_new0(struct bmsg_vcard, 1);
+
+	vcard->version = g_strdup(version);
+	vcard->n = g_strdup(name);
+	vcard->fn = g_strdup(fullname);
+	vcard->tel = g_strdup(tel);
+	vcard->email = g_strdup(email);
+
+	return vcard;
+}
+
+void bmsg_add_originator(struct bmsg *msg, const char *version,
+				 const char *name, const char *fullname,
+				 const char *tel, const char *email)
+{
+	struct bmsg_vcard *buf = make_vcard(version, name, fullname, tel,
+									email);
+	msg->originators = g_list_append(msg->originators, buf);
+}
+
+gboolean bmsg_add_envelope(struct bmsg *msg)
+{
+	struct bmsg_envelope *tmp;
+
+	if (msg->envelopes->len == MAX_ENVELOPES_NUM)
+		return FALSE;
+
+	if (msg->envelopes->len && g_array_index(msg->envelopes,
+				struct bmsg_envelope *,
+				msg->envelopes->len - 1)->content != NULL)
+		 return FALSE;
+
+	tmp = g_new0(struct bmsg_envelope, 1);
+
+	g_array_append_val(msg->envelopes, tmp);
+
+	return TRUE;
+}
+
+gboolean bmsg_add_content(struct bmsg *msg, gint32 part_id, char *encoding,
+			char *charset, char *lang, const char *content)
+{
+	struct bmsg_envelope *tmp;
+	struct bmsg_content *cont;
+
+	if (content == NULL)
+		return FALSE;
+
+	if (msg->envelopes->len == 0)
+		return FALSE;
+
+	tmp = g_array_index(msg->envelopes, struct bmsg_envelope *,
+						msg->envelopes->len - 1);
+
+	if (tmp->content != NULL)
+		return FALSE;
+
+	cont = g_new0(struct bmsg_content, 1);
+	cont->part_id = part_id;
+
+	if (encoding)
+		cont->encoding = g_strdup(encoding);
+
+	if (charset)
+		cont->charset = g_strdup(charset);
+
+	if (lang)
+		cont->lang = g_strdup(lang);
+
+	cont->content = g_strdup(content);
+
+	tmp->content = cont;
+
+	return TRUE;
+}
+
+static GString *parse_content(struct bmsg_content *cont)
+{
+	GString *buf = g_string_new("");
+
+	g_string_append_printf(buf, "BEGIN:BBODY\r\n");
+
+	if (cont->part_id != -1)
+		g_string_append_printf(buf, "PARTID:%d\r\n", cont->part_id);
+
+	if (cont->encoding != NULL)
+		g_string_append_printf(buf, "ENCODING:%s\r\n", cont->encoding);
+
+	if (cont->charset != NULL)
+		g_string_append_printf(buf, "CHARSET:%s\r\n", cont->charset);
+
+	if (cont->lang != NULL)
+		g_string_append_printf(buf, "LANGUAGE:%s\r\n", cont->lang);
+
+	if (cont->len > 0)
+		g_string_append_printf(buf, "LENGTH:%d\r\n", cont->len);
+	else
+		g_string_append_printf(buf, "LENGTH:%d\r\n",
+							strlen(cont->content) +
+							BMESSAGE_BASE_LEN);
+
+	g_string_append_printf(buf, "BEGIN:MSG\r\n%s\r\nEND:MSG\r\n",
+								cont->content);
+	g_string_append_printf(buf, "END:BBODY\r\n");
+
+	return buf;
+}
+
+static GString *parse_envelope(struct bmsg *msg, unsigned num)
+{
+	GString *buf;
+	struct bmsg_envelope *env;
+	GString *tmp;
+
+	if (num >= msg->envelopes->len)
+		return NULL;
+
+	buf = g_string_new("");
+
+	env = g_array_index(msg->envelopes, struct bmsg_envelope *, num);
+
+	g_string_append_printf(buf, "BEGIN:BENV\r\n");
+	g_list_foreach(env->recipients, string_append_glist_vcard, buf);
+
+	tmp = parse_envelope(msg, num + 1);
+	if (tmp == NULL) {
+		if (env->content == NULL) {
+			g_string_free(buf, TRUE);
+
+			return NULL;
+		}
+
+		tmp = parse_content(env->content);
+	}
+
+	g_string_append_printf(buf, "%s", tmp->str);
+	g_string_free(tmp, TRUE);
+
+	g_string_append_printf(buf, "END:BENV\r\n");
+
+	return buf;
+}
+
+char *bmsg_text(struct bmsg *msg)
+{
+	GString *buf = g_string_new("");
+	GString *env;
+	char *ret;
+
+	g_string_append_printf(buf, "BEGIN:BMSG\r\n");
+
+	g_string_append_printf(buf, "VERSION:%s\r\n", msg->version);
+	g_string_append_printf(buf, "STATUS:%s\r\n", msg->status);
+	g_string_append_printf(buf, "TYPE:%s\r\n", msg->type);
+	g_string_append_printf(buf, "FOLDER:%s\r\n", msg->folder);
+
+	g_list_foreach(msg->originators, string_append_glist_vcard, buf);
+
+	env = parse_envelope(msg, 0);
+	if (env == NULL) {
+		g_string_free(buf, TRUE);
+
+		return NULL;
+	}
+
+	g_string_append_printf(buf, "%s", env->str);
+	g_string_free(env, TRUE);
+
+	g_string_append_printf(buf, "END:BMSG\r\n");
+
+	ret = g_strdup(buf->str);
+	g_string_free(buf, TRUE);
+
+	return ret;
+}
diff --git a/plugins/bmsg.h b/plugins/bmsg.h
new file mode 100644
index 0000000..9aba380
--- /dev/null
+++ b/plugins/bmsg.h
@@ -0,0 +1,86 @@
+/*
+ *  bMessage (MAP) format helpers
+ *
+ *  Copyright (C) 2010, 2011  Bartosz Szatkowski <bulislaw@linux.com>
+ *
+ *
+ *  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
+ *
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+
+#define MAX_ENVELOPES_NUM 3
+
+#define BMSG_VERSION_1_0 "1.0"
+
+#define BMSG_READ "READ"
+#define BMSG_UNREAD "UNREAD"
+
+#define BMSG_EMAIL "EMAIL"
+#define BMSG_SMS "SMS_GSM"
+#define BMSG_CDMA "SMS_CDMA"
+#define BMSG_MMS "MMS"
+
+/*
+ * As stated in MAP errata bmessage-body-content-length-property should be
+ * length of: "BEGIN:MSG<CRLF>" + <message content> + "END:MSG<CRLF>"
+ */
+#define BMESSAGE_BASE_LEN (9 + 2 + 2 + 7 + 2)
+
+struct bmsg_vcard {
+	char *version;
+	char *n;
+	char *fn;
+	char *tel;
+	char *email;
+};
+
+struct bmsg_content {
+	gint32 part_id;
+	unsigned int len;
+	char *encoding;
+	char *charset;
+	char *lang;
+	char *content;
+};
+
+struct bmsg_envelope {
+	GList *recipients;
+	struct bmsg_content *content;
+};
+
+struct bmsg {
+	char *version;
+	char *status;
+	char *type;
+	char *folder;
+	GList *originators;
+	GArray *envelopes;
+};
+
+void bmsg_init(struct bmsg *msg, const char *version, const char *status,
+					const char *type, const char *folder);
+void bmsg_destroy(struct bmsg *msg);
+void bmsg_add_originator(struct bmsg *msg, const char *version,
+				const char *name, const char *fullname,
+				const char *tel, const char *email);
+gboolean bmsg_add_envelope(struct bmsg *msg);
+gboolean bmsg_add_content(struct bmsg *msg, gint32 part_id, char *encoding,
+			char *charset, char *lang, const char* content);
+struct bmsg * bmsg_parse(char *string);
+char * bmsg_text(struct bmsg *msg);
diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 8624381..f00ab6d 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -32,6 +32,7 @@
 
 #include "log.h"
 #include "messages.h"
+#include "bmsg.h"
 
 #define TRACKER_SERVICE "org.freedesktop.Tracker1"
 #define TRACKER_RESOURCES_PATH "/org/freedesktop/Tracker1/Resources"
@@ -41,11 +42,9 @@
 #define MESSAGE_HANDLE_SIZE 16
 #define MESSAGE_HANDLE_PREFIX_LEN 8
 
-/*
- * As stated in MAP errata bmessage-body-content-length-property should be
- * length of: "BEGIN:MSG<CRLF>" + <message content> + "END:MSG<CRLF>"
- */
-#define BMESSAGE_BASE_LEN (9 + 2 + 2 + 7 + 2)
+#define SMS_DEFAULT_CHARSET "UTF-8"
+
+#define MESSAGES_FILTER_BY_HANDLE "FILTER (xsd:string(?msg) = \"message:%s\" ) ."
 
 #define MESSAGE_HANDLE 0
 #define MESSAGE_SUBJECT 1
@@ -127,9 +126,11 @@ struct session {
 	gboolean aborted;
 	reply_list_foreach_cb generate_response;
 	struct messages_filter *filter;
+	unsigned long flags;
 	union {
 		messages_folder_listing_cb folder_list;
 		messages_get_messages_listing_cb messages_list;
+		messages_get_message_cb message;
 	} cb;
 };
 
@@ -188,6 +189,26 @@ static struct messages_filter *copy_messages_filter(
 	return filter;
 }
 
+static char *fill_handle(const char *handle)
+{
+	int fill_size = MESSAGE_HANDLE_SIZE - strlen(handle);
+	char *fill = g_strnfill(fill_size, '0');
+	char *ret = g_strdup_printf("%s%s", fill, handle);
+
+	g_free(fill);
+
+	return ret;
+}
+
+static char *strip_handle(const char *handle)
+{
+	const char *ptr_new = handle;
+
+	while (*ptr_new++ == '0') ;
+
+	return g_strdup(ptr_new - 1);
+}
+
 static char **string_array_from_iter(DBusMessageIter iter, int array_len)
 {
 	DBusMessageIter sub;
@@ -258,7 +279,9 @@ static void query_reply(DBusPendingCall *call, void *user_data)
 
 		node = string_array_from_iter(element, QUERY_RESPONSE_SIZE);
 
-		session->generate_response((const char **) node, session);
+		if (node != NULL)
+			session->generate_response((const char **) node,
+								session);
 
 		g_free(node);
 
@@ -430,6 +453,39 @@ static char *merge_names(const char *name, const char *lastname)
 	return tmp;
 }
 
+static char *message2folder(const struct messages_message *data)
+{
+	if (data->sent == TRUE)
+		return g_strdup("telecom/msg/sent");
+
+	if (data->sent == FALSE)
+		return g_strdup("telecom/msg/inbox");
+
+	return NULL;
+}
+
+static char *path2query(const char *folder, const char *query,
+							const char *user_rule)
+{
+	if (g_str_has_suffix(folder, "telecom/msg/inbox") == TRUE)
+		return g_strdup_printf(query, "?msg nmo:isSent \"false\" ; "
+					"nmo:isDeleted \"false\" ; "
+					"nmo:isDraft \"false\". ", user_rule);
+
+	if (g_str_has_suffix(folder, "telecom/msg/sent") == TRUE)
+		return g_strdup_printf(query, "?msg nmo:isSent \"true\" ; "
+				"nmo:isDeleted \"false\" . ", user_rule);
+
+	if (g_str_has_suffix(folder, "telecom/msg/deleted") == TRUE)
+		return g_strdup_printf(query, "?msg nmo:isDeleted \"true\" . ",
+					user_rule);
+
+	if (g_str_has_suffix(folder, "telecom/msg") == TRUE)
+		return g_strdup_printf(query, "", user_rule);
+
+	return NULL;
+}
+
 static DBusConnection *dbus_get_connection(DBusBusType type)
 {
 	DBusError err;
@@ -646,6 +702,64 @@ done:
 	g_free(session->filter);
 }
 
+static void get_message_resp(const char **reply, void *s)
+{
+	struct session *session = s;
+	struct messages_message *msg_data;
+	struct bmsg *bmsg;
+	char *final_bmsg, *status, *folder, *handle;
+	int err;
+
+	DBG("reply %p", reply);
+
+	if (reply == NULL)
+		goto done;
+
+	if (session->aborted)
+		goto aborted;
+
+	msg_data = pull_message_data(reply);
+	handle = fill_handle(msg_data->handle);
+	g_free(msg_data->handle);
+	msg_data->handle = handle;
+
+	status = msg_data->read ? "READ" : "UNREAD";
+
+	folder = message2folder(msg_data);
+
+	bmsg = g_new0(struct bmsg, 1);
+	bmsg_init(bmsg, BMSG_VERSION_1_0, status, BMSG_SMS, folder);
+	bmsg_add_originator(bmsg, "2.1", reply[MESSAGE_FROM_LASTN],
+					msg_data->sender_name,
+					msg_data->sender_addressing, NULL);
+	bmsg_add_envelope(bmsg);
+	bmsg_add_content(bmsg, -1, NULL, SMS_DEFAULT_CHARSET, NULL,
+						reply[MESSAGE_CONTENT]);
+
+	final_bmsg = bmsg_text(bmsg);
+
+	session->cb.message(session, 0, FALSE, final_bmsg, session->user_data);
+
+	bmsg_destroy(bmsg);
+	g_free(folder);
+	g_free(final_bmsg);
+
+	session->count++;
+
+	return;
+
+done:
+	if (session->count == 0)
+		err = -ENOENT;
+	else
+		err = 0;
+
+	session->cb.message(session, err, FALSE, NULL, session->user_data);
+
+aborted:
+	g_free(session->name);
+}
+
 int messages_init(void)
 {
 	DBusError err;
@@ -870,13 +984,46 @@ int messages_get_messages_listing(void *s, const char *name,
 	return err;
 }
 
-int messages_get_message(void *session,
-		const char *handle,
-		unsigned long flags,
-		messages_get_message_cb callback,
-		void *user_data)
+int messages_get_message(void *s, const char *h, unsigned long flags,
+				messages_get_message_cb cb, void *user_data)
 {
-	return -EINVAL;
+	struct session *session = s;
+	DBusPendingCall *call;
+	int err = 0;
+	char *handle = strip_handle(h);
+	char *query_handle = g_strdup_printf(MESSAGES_FILTER_BY_HANDLE, handle);
+	char *query = path2query("telecom/msg", LIST_MESSAGES_QUERY,
+								 query_handle);
+
+	if (query == NULL) {
+		err = -ENOENT;
+
+		goto failed;
+	}
+
+	if (flags & MESSAGES_FRACTION || flags & MESSAGES_NEXT) {
+		err = -EBADR;
+
+		goto failed;
+	}
+
+	session->name = g_strdup(handle);
+	session->flags = flags;
+	session->cb.message = cb;
+	session->generate_response = get_message_resp;
+	session->user_data = user_data;
+	session->aborted = FALSE;
+
+	call = query_tracker(query, session, &err);
+	if (err == 0)
+		new_call(call);
+
+failed:
+	g_free(query_handle);
+	g_free(query);
+	g_free(handle);
+
+	return err;
 }
 
 void messages_abort(void *s)
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH obexd 7/8] MAP Tracker: Add abort support in folder listing
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
                   ` (4 preceding siblings ...)
  2011-09-02  8:57 ` [PATCH obexd 6/8] MAP Tracker: Add support for pulling messages Bartosz Szatkowski
@ 2011-09-02  8:57 ` Bartosz Szatkowski
  2011-09-02  8:58 ` [PATCH obexd 8/8] MAP Tracker: Refactor session struct Bartosz Szatkowski
  2011-09-27  9:46 ` [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Johan Hedberg
  7 siblings, 0 replies; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:57 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 plugins/messages-tracker.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index f00ab6d..29f3ccd 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -869,6 +869,9 @@ static gboolean async_get_folder_listing(void *s) {
 	if (session->name && strchr(session->name, '/') != NULL)
 		goto done;
 
+	if (session->aborted)
+		goto aborted;
+
 	path = g_build_filename(session->cwd, session->name, NULL);
 
 	if (path == NULL || strlen(path) == 0)
@@ -895,11 +898,13 @@ static gboolean async_get_folder_listing(void *s) {
 					dir_data->name, session->user_data);
 	}
 
- done:
+done:
 	session->cb.folder_list(session, 0, folder_count, NULL,
 							session->user_data);
 
 	g_free(path);
+
+aborted:
 	g_free(session->name);
 
 	return FALSE;
@@ -916,6 +921,7 @@ int messages_get_folder_listing(void *s, const char *name,
 	session->offset = offset;
 	session->cb.folder_list = callback;
 	session->user_data = user_data;
+	session->aborted = FALSE;
 
 	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing,
 						session, NULL);
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH obexd 8/8] MAP Tracker: Refactor session struct
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
                   ` (5 preceding siblings ...)
  2011-09-02  8:57 ` [PATCH obexd 7/8] MAP Tracker: Add abort support in folder listing Bartosz Szatkowski
@ 2011-09-02  8:58 ` Bartosz Szatkowski
  2011-09-27  9:46 ` [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Johan Hedberg
  7 siblings, 0 replies; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02  8:58 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

Session struct grown to rather large size, and it become necessary to
reset some flags and counter for each request. After refactorization
there is one struct exclusive for each request and it is freed after
request is completed.
---
 plugins/messages-tracker.c |  154 ++++++++++++++++++++++++++------------------
 1 files changed, 90 insertions(+), 64 deletions(-)

diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 29f3ccd..ada4a42 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -113,9 +113,7 @@ struct message_folder {
 	char *query;
 };
 
-struct session {
-	char *cwd;
-	struct message_folder *folder;
+struct request {
 	char *name;
 	uint16_t max;
 	uint16_t offset;
@@ -134,6 +132,14 @@ struct session {
 	} cb;
 };
 
+struct session {
+	char *cwd;
+	struct message_folder *folder;
+	gboolean aborted;
+	void *event_user_data;
+	struct request *request;
+};
+
 static struct message_folder *folder_tree = NULL;
 static DBusConnection *session_connection = NULL;
 
@@ -280,7 +286,7 @@ static void query_reply(DBusPendingCall *call, void *user_data)
 		node = string_array_from_iter(element, QUERY_RESPONSE_SIZE);
 
 		if (node != NULL)
-			session->generate_response((const char **) node,
+			session->request->generate_response((const char **) node,
 								session);
 
 		g_free(node);
@@ -289,7 +295,7 @@ static void query_reply(DBusPendingCall *call, void *user_data)
 	}
 
 done:
-	session->generate_response(NULL, session);
+	session->request->generate_response(NULL, session);
 
 	dbus_message_unref(reply);
 }
@@ -659,6 +665,7 @@ static struct messages_message *pull_message_data(const char **reply)
 static void get_messages_listing_resp(const char **reply, void *user_data)
 {
 	struct session *session = user_data;
+	struct request *request = session->request;
 	struct messages_message *msg_data;
 
 	DBG("reply %p", reply);
@@ -667,44 +674,48 @@ static void get_messages_listing_resp(const char **reply, void *user_data)
 		goto done;
 
 	if (session->aborted)
-		return;
+		goto aborted;
 
 	msg_data = pull_message_data(reply);
 
-	session->size++;
+	request->size++;
 
 	if (!msg_data->read)
-			session->new_message = TRUE;
+			request->new_message = TRUE;
 
-	if (session->count == TRUE) {
+	if (request->count == TRUE) {
 		free_msg_data(msg_data);
 		return;
 	}
 
-	if (session->size > session->offset &&
-				filter_message(msg_data, session->filter))
-		session->cb.messages_list(session, -EAGAIN, 1,
-						session->new_message, msg_data,
-						session->user_data);
+	if (request->size > request->offset && filter_message(msg_data,
+							request->filter))
+		request->cb.messages_list(session, -EAGAIN, 1,
+						request->new_message, msg_data,
+						request->user_data);
 
 	free_msg_data(msg_data);
 	return;
 
 done:
-	session->cb.messages_list(session, 0, session->size,
-						session->new_message, NULL,
-						session->user_data);
-
-	g_free(session->filter->period_begin);
-	g_free(session->filter->period_end);
-	g_free(session->filter->originator);
-	g_free(session->filter->recipient);
-	g_free(session->filter);
+	request->cb.messages_list(session, 0, request->size,
+						request->new_message, NULL,
+						request->user_data);
+
+aborted:
+	g_free(request->filter->period_begin);
+	g_free(request->filter->period_end);
+	g_free(request->filter->originator);
+	g_free(request->filter->recipient);
+	g_free(request->filter);
+
+	g_free(request);
 }
 
 static void get_message_resp(const char **reply, void *s)
 {
 	struct session *session = s;
+	struct request *request = session->request;
 	struct messages_message *msg_data;
 	struct bmsg *bmsg;
 	char *final_bmsg, *status, *folder, *handle;
@@ -738,26 +749,27 @@ static void get_message_resp(const char **reply, void *s)
 
 	final_bmsg = bmsg_text(bmsg);
 
-	session->cb.message(session, 0, FALSE, final_bmsg, session->user_data);
+	request->cb.message(session, 0, FALSE, final_bmsg, request->user_data);
 
 	bmsg_destroy(bmsg);
 	g_free(folder);
 	g_free(final_bmsg);
 
-	session->count++;
+	request->count++;
 
 	return;
 
 done:
-	if (session->count == 0)
+	if (request->count == 0)
 		err = -ENOENT;
 	else
 		err = 0;
 
-	session->cb.message(session, err, FALSE, NULL, session->user_data);
+	request->cb.message(session, err, FALSE, NULL, request->user_data);
 
 aborted:
-	g_free(session->name);
+	g_free(request->name);
+	g_free(request);
 }
 
 int messages_init(void)
@@ -860,19 +872,20 @@ int messages_set_folder(void *s, const char *name, gboolean cdup)
 
 static gboolean async_get_folder_listing(void *s) {
 	struct session *session = s;
+	struct request *request = session->request;
 	gboolean count = FALSE;
 	int folder_count = 0;
 	char *path = NULL;
 	struct message_folder *folder;
 	GSList *dir;
 
-	if (session->name && strchr(session->name, '/') != NULL)
-		goto done;
-
 	if (session->aborted)
 		goto aborted;
 
-	path = g_build_filename(session->cwd, session->name, NULL);
+	if (request->name && strchr(request->name, '/') != NULL)
+		goto done;
+
+	path = g_build_filename(session->cwd, request->name, NULL);
 
 	if (path == NULL || strlen(path) == 0)
 		goto done;
@@ -882,30 +895,32 @@ static gboolean async_get_folder_listing(void *s) {
 	if (folder == NULL)
 		goto done;
 
-	if (session->max == 0) {
-		session->max = 0xffff;
-		session->offset = 0;
+	if (request->max == 0) {
+		request->max = 0xffff;
+		request->offset = 0;
 		count = TRUE;
 	}
 
 	for (dir = folder->subfolders; dir &&
-				(folder_count - session->offset) < session->max;
+				(folder_count - request->offset) < request->max;
 				folder_count++, dir = g_slist_next(dir)) {
 		struct message_folder *dir_data = dir->data;
 
-		if (count == FALSE && session->offset <= folder_count)
-			session->cb.folder_list(session, -EAGAIN, 1,
-					dir_data->name, session->user_data);
+		if (count == FALSE && request->offset <= folder_count)
+			request->cb.folder_list(session, -EAGAIN, 1,
+							dir_data->name,
+							request->user_data);
 	}
 
 done:
-	session->cb.folder_list(session, 0, folder_count, NULL,
-							session->user_data);
+	request->cb.folder_list(session, 0, folder_count, NULL,
+							request->user_data);
 
 	g_free(path);
 
 aborted:
-	g_free(session->name);
+	g_free(request->name);
+	g_free(request);
 
 	return FALSE;
 }
@@ -916,12 +931,16 @@ int messages_get_folder_listing(void *s, const char *name,
 					void *user_data)
 {
 	struct session *session = s;
-	session->name = g_strdup(name);
-	session->max = max;
-	session->offset = offset;
-	session->cb.folder_list = callback;
-	session->user_data = user_data;
+	struct request *request = g_new0(struct request, 1);
+
+	request->name = g_strdup(name);
+	request->max = max;
+	request->offset = offset;
+	request->cb.folder_list = callback;
+	request->user_data = user_data;
+
 	session->aborted = FALSE;
+	session->request = request;
 
 	g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing,
 						session, NULL);
@@ -936,6 +955,7 @@ int messages_get_messages_listing(void *s, const char *name,
 				void *user_data)
 {
 	struct session *session = s;
+	struct request *request;
 	char *path, *query;
 	struct message_folder *folder = NULL;
 	DBusPendingCall *call;
@@ -964,21 +984,22 @@ int messages_get_messages_listing(void *s, const char *name,
 	if (query == NULL)
 		return -ENOENT;
 
-	session->filter = copy_messages_filter(filter);
-	session->generate_response = get_messages_listing_resp;
-	session->cb.messages_list = callback;
-	session->offset = offset;
-	session->max = max;
-	session->user_data = user_data;
-	session->new_message = FALSE;
-	session->count = FALSE;
-	session->size = 0;
+	request = g_new0(struct request, 1);
+
+	request->filter = copy_messages_filter(filter);
+	request->generate_response = get_messages_listing_resp;
+	request->cb.messages_list = callback;
+	request->offset = offset;
+	request->max = max;
+	request->user_data = user_data;
+
 	session->aborted = FALSE;
+	session->request = request;
 
 	if (max == 0) {
-		session->max = 0xffff;
-		session->offset = 0;
-		session->count = TRUE;
+		request->max = 0xffff;
+		request->offset = 0;
+		request->count = TRUE;
 	}
 
 	call = query_tracker(query, session, &err);
@@ -994,6 +1015,7 @@ int messages_get_message(void *s, const char *h, unsigned long flags,
 				messages_get_message_cb cb, void *user_data)
 {
 	struct session *session = s;
+	struct request *request;
 	DBusPendingCall *call;
 	int err = 0;
 	char *handle = strip_handle(h);
@@ -1013,12 +1035,16 @@ int messages_get_message(void *s, const char *h, unsigned long flags,
 		goto failed;
 	}
 
-	session->name = g_strdup(handle);
-	session->flags = flags;
-	session->cb.message = cb;
-	session->generate_response = get_message_resp;
-	session->user_data = user_data;
+	request = g_new0(struct request, 1);
+
+	request->name = g_strdup(handle);
+	request->flags = flags;
+	request->cb.message = cb;
+	request->generate_response = get_message_resp;
+	request->user_data = user_data;
+
 	session->aborted = FALSE;
+	session->request = request;
 
 	call = query_tracker(query, session, &err);
 	if (err == 0)
-- 
1.7.4.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 6/8] MAP Tracker: Add support for pulling messages
  2011-09-02  8:57 ` [PATCH obexd 6/8] MAP Tracker: Add support for pulling messages Bartosz Szatkowski
@ 2011-09-02 13:36   ` Bartosz Szatkowski
  0 siblings, 0 replies; 11+ messages in thread
From: Bartosz Szatkowski @ 2011-09-02 13:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bartosz Szatkowski

---
 Makefile.am                |    3 +-
 plugins/bmsg.c             |  322 ++++++++++++++++++++++++++++++++++++++++++++
 plugins/bmsg.h             |   86 ++++++++++++
 plugins/messages-tracker.c |  171 ++++++++++++++++++++++--
 4 files changed, 569 insertions(+), 13 deletions(-)
 create mode 100644 plugins/bmsg.c
 create mode 100644 plugins/bmsg.h

diff --git a/Makefile.am b/Makefile.am
index 374fa1d..9cf3d02 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -66,7 +66,8 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
 			plugins/vcard.h plugins/vcard.c
 
 builtin_modules += mas
-builtin_sources += plugins/mas.c plugins/messages.h
+builtin_sources += plugins/mas.c plugins/messages.h \
+			   plugins/bmsg.h plugins/bmsg.c
 
 builtin_modules += irmc
 builtin_sources += plugins/irmc.c
diff --git a/plugins/bmsg.c b/plugins/bmsg.c
new file mode 100644
index 0000000..0adb938
--- /dev/null
+++ b/plugins/bmsg.c
@@ -0,0 +1,322 @@
+/*
+ *  bMessage (MAP) format helpers
+ *
+ *  Copyright (C) 2010-2011  Nokia Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include "bmsg.h"
+
+static GString *parse_vcard(struct bmsg_vcard *vcard)
+{
+	GString *buf;
+
+	if (vcard == NULL)
+		return NULL;
+
+	if (vcard->version == NULL)
+		return NULL;
+
+	if (vcard->n == NULL)
+		return NULL;
+
+	buf = g_string_new("");
+
+	g_string_append_printf(buf, "BEGIN:VCARD\r\n");
+	g_string_append_printf(buf, "VERSION:%s\r\n", vcard->version);
+
+	if (vcard->n != NULL)
+		g_string_append_printf(buf, "N:%s\r\n", vcard->n);
+
+	if (vcard->fn != NULL)
+		g_string_append_printf(buf, "FN:%s\r\n", vcard->fn);
+
+	if (vcard->tel != NULL)
+		g_string_append_printf(buf, "TEL:%s\r\n", vcard->tel);
+
+	if (vcard->email != NULL)
+		g_string_append_printf(buf, "EMAIL:%s\r\n", vcard->email);
+
+	g_string_append_printf(buf, "END:VCARD\r\n");
+
+	return buf;
+}
+
+static void free_glist_vcard(void *item, void *user_data)
+{
+	struct bmsg_vcard *tmp = item;
+
+	if (tmp == NULL)
+		return;
+
+	g_free(tmp->version);
+	g_free(tmp->n);
+	g_free(tmp->fn);
+	g_free(tmp->tel);
+	g_free(tmp->email);
+	g_free(item);
+}
+
+static void string_append_glist_vcard(void *list_item, void *list)
+{
+	GString *buf = list;
+	GString *item = parse_vcard(list_item);
+
+	g_string_append(buf, item->str);
+
+	g_string_free(item, TRUE);
+}
+
+static void envelope_destroy(struct bmsg_envelope *env)
+{
+	if (env->recipients) {
+		g_list_foreach(env->recipients, free_glist_vcard, NULL);
+		g_list_free(env->recipients);
+	}
+
+	if (env->content == NULL)
+		return;
+
+	g_free(env->content->encoding);
+	g_free(env->content->charset);
+	g_free(env->content->lang);
+	g_free(env->content->content);
+	g_free(env->content);
+}
+
+void bmsg_init(struct bmsg *msg, const char *version, const char *status,
+		const char *type, const char *folder)
+{
+	msg->version = g_strdup(version);
+	msg->status = g_strdup(status);
+	msg->type = g_strdup(type);
+	msg->folder = g_strdup(folder);
+	msg->envelopes = g_array_sized_new(FALSE, TRUE,
+					sizeof(struct bmsg_envelope *),
+					MAX_ENVELOPES_NUM);
+}
+
+void bmsg_destroy(struct bmsg *msg)
+{
+	unsigned i;
+
+	g_free(msg->version);
+	g_free(msg->status);
+	g_free(msg->type);
+	g_free(msg->folder);
+
+	if (msg->originators) {
+		g_list_foreach(msg->originators, free_glist_vcard, NULL);
+		g_list_free(msg->originators);
+	}
+
+	if (msg->envelopes == NULL)
+		return;
+
+	for (i = 0; i < msg->envelopes->len; i++) {
+		struct bmsg_envelope *tmp = g_array_index(msg->envelopes,
+						struct bmsg_envelope *, i);
+
+		envelope_destroy(tmp);
+		g_free(tmp);
+	}
+
+	g_array_free(msg->envelopes, TRUE);
+
+	g_free(msg);
+}
+
+static struct bmsg_vcard *make_vcard(const char *version, const char *name,
+					const char *fullname, const char *tel,
+					const char *email)
+{
+	struct bmsg_vcard *vcard = g_new0(struct bmsg_vcard, 1);
+
+	vcard->version = g_strdup(version);
+	vcard->n = g_strdup(name);
+	vcard->fn = g_strdup(fullname);
+	vcard->tel = g_strdup(tel);
+	vcard->email = g_strdup(email);
+
+	return vcard;
+}
+
+void bmsg_add_originator(struct bmsg *msg, const char *version,
+				 const char *name, const char *fullname,
+				 const char *tel, const char *email)
+{
+	struct bmsg_vcard *buf = make_vcard(version, name, fullname, tel,
+									email);
+	msg->originators = g_list_append(msg->originators, buf);
+}
+
+gboolean bmsg_add_envelope(struct bmsg *msg)
+{
+	struct bmsg_envelope *tmp;
+
+	if (msg->envelopes->len == MAX_ENVELOPES_NUM)
+		return FALSE;
+
+	if (msg->envelopes->len && g_array_index(msg->envelopes,
+				struct bmsg_envelope *,
+				msg->envelopes->len - 1)->content != NULL)
+		 return FALSE;
+
+	tmp = g_new0(struct bmsg_envelope, 1);
+
+	g_array_append_val(msg->envelopes, tmp);
+
+	return TRUE;
+}
+
+gboolean bmsg_add_content(struct bmsg *msg, gint32 part_id, char *encoding,
+			char *charset, char *lang, const char *content)
+{
+	struct bmsg_envelope *tmp;
+	struct bmsg_content *cont;
+
+	if (content == NULL)
+		return FALSE;
+
+	if (msg->envelopes->len == 0)
+		return FALSE;
+
+	tmp = g_array_index(msg->envelopes, struct bmsg_envelope *,
+						msg->envelopes->len - 1);
+
+	if (tmp->content != NULL)
+		return FALSE;
+
+	cont = g_new0(struct bmsg_content, 1);
+	cont->part_id = part_id;
+
+	if (encoding)
+		cont->encoding = g_strdup(encoding);
+
+	if (charset)
+		cont->charset = g_strdup(charset);
+
+	if (lang)
+		cont->lang = g_strdup(lang);
+
+	cont->content = g_strdup(content);
+
+	tmp->content = cont;
+
+	return TRUE;
+}
+
+static GString *parse_content(struct bmsg_content *cont)
+{
+	GString *buf = g_string_new("");
+
+	g_string_append_printf(buf, "BEGIN:BBODY\r\n");
+
+	if (cont->part_id != -1)
+		g_string_append_printf(buf, "PARTID:%d\r\n", cont->part_id);
+
+	if (cont->encoding != NULL)
+		g_string_append_printf(buf, "ENCODING:%s\r\n", cont->encoding);
+
+	if (cont->charset != NULL)
+		g_string_append_printf(buf, "CHARSET:%s\r\n", cont->charset);
+
+	if (cont->lang != NULL)
+		g_string_append_printf(buf, "LANGUAGE:%s\r\n", cont->lang);
+
+	if (cont->len > 0)
+		g_string_append_printf(buf, "LENGTH:%d\r\n", cont->len);
+	else
+		g_string_append_printf(buf, "LENGTH:%d\r\n",
+							strlen(cont->content) +
+							BMESSAGE_BASE_LEN);
+
+	g_string_append_printf(buf, "BEGIN:MSG\r\n%s\r\nEND:MSG\r\n",
+								cont->content);
+	g_string_append_printf(buf, "END:BBODY\r\n");
+
+	return buf;
+}
+
+static GString *parse_envelope(struct bmsg *msg, unsigned num)
+{
+	GString *buf;
+	struct bmsg_envelope *env;
+	GString *tmp;
+
+	if (num >= msg->envelopes->len)
+		return NULL;
+
+	buf = g_string_new("");
+
+	env = g_array_index(msg->envelopes, struct bmsg_envelope *, num);
+
+	g_string_append_printf(buf, "BEGIN:BENV\r\n");
+	g_list_foreach(env->recipients, string_append_glist_vcard, buf);
+
+	tmp = parse_envelope(msg, num + 1);
+	if (tmp == NULL) {
+		if (env->content == NULL) {
+			g_string_free(buf, TRUE);
+
+			return NULL;
+		}
+
+		tmp = parse_content(env->content);
+	}
+
+	g_string_append_printf(buf, "%s", tmp->str);
+	g_string_free(tmp, TRUE);
+
+	g_string_append_printf(buf, "END:BENV\r\n");
+
+	return buf;
+}
+
+char *bmsg_text(struct bmsg *msg)
+{
+	GString *buf = g_string_new("");
+	GString *env;
+	char *ret;
+
+	g_string_append_printf(buf, "BEGIN:BMSG\r\n");
+
+	g_string_append_printf(buf, "VERSION:%s\r\n", msg->version);
+	g_string_append_printf(buf, "STATUS:%s\r\n", msg->status);
+	g_string_append_printf(buf, "TYPE:%s\r\n", msg->type);
+	g_string_append_printf(buf, "FOLDER:%s\r\n", msg->folder);
+
+	g_list_foreach(msg->originators, string_append_glist_vcard, buf);
+
+	env = parse_envelope(msg, 0);
+	if (env == NULL) {
+		g_string_free(buf, TRUE);
+
+		return NULL;
+	}
+
+	g_string_append_printf(buf, "%s", env->str);
+	g_string_free(env, TRUE);
+
+	g_string_append_printf(buf, "END:BMSG\r\n");
+
+	ret = g_strdup(buf->str);
+	g_string_free(buf, TRUE);
+
+	return ret;
+}
diff --git a/plugins/bmsg.h b/plugins/bmsg.h
new file mode 100644
index 0000000..23050ed
--- /dev/null
+++ b/plugins/bmsg.h
@@ -0,0 +1,86 @@
+/*
+ *  bMessage (MAP) format helpers
+ *
+ *  Copyright (C) 2010-2011  Nokia Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include <string.h>
+
+#define MAX_ENVELOPES_NUM 3
+
+#define BMSG_VERSION_1_0 "1.0"
+
+#define BMSG_READ "READ"
+#define BMSG_UNREAD "UNREAD"
+
+#define BMSG_EMAIL "EMAIL"
+#define BMSG_SMS "SMS_GSM"
+#define BMSG_CDMA "SMS_CDMA"
+#define BMSG_MMS "MMS"
+
+/*
+ * As stated in MAP errata bmessage-body-content-length-property should be
+ * length of: "BEGIN:MSG<CRLF>" + <message content> + "END:MSG<CRLF>"
+ */
+#define BMESSAGE_BASE_LEN (9 + 2 + 2 + 7 + 2)
+
+struct bmsg_vcard {
+	char *version;
+	char *n;
+	char *fn;
+	char *tel;
+	char *email;
+};
+
+struct bmsg_content {
+	gint32 part_id;
+	unsigned int len;
+	char *encoding;
+	char *charset;
+	char *lang;
+	char *content;
+};
+
+struct bmsg_envelope {
+	GList *recipients;
+	struct bmsg_content *content;
+};
+
+struct bmsg {
+	char *version;
+	char *status;
+	char *type;
+	char *folder;
+	GList *originators;
+	GArray *envelopes;
+};
+
+void bmsg_init(struct bmsg *msg, const char *version, const char *status,
+					const char *type, const char *folder);
+void bmsg_destroy(struct bmsg *msg);
+void bmsg_add_originator(struct bmsg *msg, const char *version,
+				const char *name, const char *fullname,
+				const char *tel, const char *email);
+gboolean bmsg_add_envelope(struct bmsg *msg);
+gboolean bmsg_add_content(struct bmsg *msg, gint32 part_id, char *encoding,
+			char *charset, char *lang, const char* content);
+struct bmsg * bmsg_parse(char *string);
+char * bmsg_text(struct bmsg *msg);
diff --git a/plugins/messages-tracker.c b/plugins/messages-tracker.c
index 8624381..f00ab6d 100644
--- a/plugins/messages-tracker.c
+++ b/plugins/messages-tracker.c
@@ -32,6 +32,7 @@
 
 #include "log.h"
 #include "messages.h"
+#include "bmsg.h"
 
 #define TRACKER_SERVICE "org.freedesktop.Tracker1"
 #define TRACKER_RESOURCES_PATH "/org/freedesktop/Tracker1/Resources"
@@ -41,11 +42,9 @@
 #define MESSAGE_HANDLE_SIZE 16
 #define MESSAGE_HANDLE_PREFIX_LEN 8
 
-/*
- * As stated in MAP errata bmessage-body-content-length-property should be
- * length of: "BEGIN:MSG<CRLF>" + <message content> + "END:MSG<CRLF>"
- */
-#define BMESSAGE_BASE_LEN (9 + 2 + 2 + 7 + 2)
+#define SMS_DEFAULT_CHARSET "UTF-8"
+
+#define MESSAGES_FILTER_BY_HANDLE "FILTER (xsd:string(?msg) = \"message:%s\" ) ."
 
 #define MESSAGE_HANDLE 0
 #define MESSAGE_SUBJECT 1
@@ -127,9 +126,11 @@ struct session {
 	gboolean aborted;
 	reply_list_foreach_cb generate_response;
 	struct messages_filter *filter;
+	unsigned long flags;
 	union {
 		messages_folder_listing_cb folder_list;
 		messages_get_messages_listing_cb messages_list;
+		messages_get_message_cb message;
 	} cb;
 };
 
@@ -188,6 +189,26 @@ static struct messages_filter *copy_messages_filter(
 	return filter;
 }
 
+static char *fill_handle(const char *handle)
+{
+	int fill_size = MESSAGE_HANDLE_SIZE - strlen(handle);
+	char *fill = g_strnfill(fill_size, '0');
+	char *ret = g_strdup_printf("%s%s", fill, handle);
+
+	g_free(fill);
+
+	return ret;
+}
+
+static char *strip_handle(const char *handle)
+{
+	const char *ptr_new = handle;
+
+	while (*ptr_new++ == '0') ;
+
+	return g_strdup(ptr_new - 1);
+}
+
 static char **string_array_from_iter(DBusMessageIter iter, int array_len)
 {
 	DBusMessageIter sub;
@@ -258,7 +279,9 @@ static void query_reply(DBusPendingCall *call, void *user_data)
 
 		node = string_array_from_iter(element, QUERY_RESPONSE_SIZE);
 
-		session->generate_response((const char **) node, session);
+		if (node != NULL)
+			session->generate_response((const char **) node,
+								session);
 
 		g_free(node);
 
@@ -430,6 +453,39 @@ static char *merge_names(const char *name, const char *lastname)
 	return tmp;
 }
 
+static char *message2folder(const struct messages_message *data)
+{
+	if (data->sent == TRUE)
+		return g_strdup("telecom/msg/sent");
+
+	if (data->sent == FALSE)
+		return g_strdup("telecom/msg/inbox");
+
+	return NULL;
+}
+
+static char *path2query(const char *folder, const char *query,
+							const char *user_rule)
+{
+	if (g_str_has_suffix(folder, "telecom/msg/inbox") == TRUE)
+		return g_strdup_printf(query, "?msg nmo:isSent \"false\" ; "
+					"nmo:isDeleted \"false\" ; "
+					"nmo:isDraft \"false\". ", user_rule);
+
+	if (g_str_has_suffix(folder, "telecom/msg/sent") == TRUE)
+		return g_strdup_printf(query, "?msg nmo:isSent \"true\" ; "
+				"nmo:isDeleted \"false\" . ", user_rule);
+
+	if (g_str_has_suffix(folder, "telecom/msg/deleted") == TRUE)
+		return g_strdup_printf(query, "?msg nmo:isDeleted \"true\" . ",
+					user_rule);
+
+	if (g_str_has_suffix(folder, "telecom/msg") == TRUE)
+		return g_strdup_printf(query, "", user_rule);
+
+	return NULL;
+}
+
 static DBusConnection *dbus_get_connection(DBusBusType type)
 {
 	DBusError err;
@@ -646,6 +702,64 @@ done:
 	g_free(session->filter);
 }
 
+static void get_message_resp(const char **reply, void *s)
+{
+	struct session *session = s;
+	struct messages_message *msg_data;
+	struct bmsg *bmsg;
+	char *final_bmsg, *status, *folder, *handle;
+	int err;
+
+	DBG("reply %p", reply);
+
+	if (reply == NULL)
+		goto done;
+
+	if (session->aborted)
+		goto aborted;
+
+	msg_data = pull_message_data(reply);
+	handle = fill_handle(msg_data->handle);
+	g_free(msg_data->handle);
+	msg_data->handle = handle;
+
+	status = msg_data->read ? "READ" : "UNREAD";
+
+	folder = message2folder(msg_data);
+
+	bmsg = g_new0(struct bmsg, 1);
+	bmsg_init(bmsg, BMSG_VERSION_1_0, status, BMSG_SMS, folder);
+	bmsg_add_originator(bmsg, "2.1", reply[MESSAGE_FROM_LASTN],
+					msg_data->sender_name,
+					msg_data->sender_addressing, NULL);
+	bmsg_add_envelope(bmsg);
+	bmsg_add_content(bmsg, -1, NULL, SMS_DEFAULT_CHARSET, NULL,
+						reply[MESSAGE_CONTENT]);
+
+	final_bmsg = bmsg_text(bmsg);
+
+	session->cb.message(session, 0, FALSE, final_bmsg, session->user_data);
+
+	bmsg_destroy(bmsg);
+	g_free(folder);
+	g_free(final_bmsg);
+
+	session->count++;
+
+	return;
+
+done:
+	if (session->count == 0)
+		err = -ENOENT;
+	else
+		err = 0;
+
+	session->cb.message(session, err, FALSE, NULL, session->user_data);
+
+aborted:
+	g_free(session->name);
+}
+
 int messages_init(void)
 {
 	DBusError err;
@@ -870,13 +984,46 @@ int messages_get_messages_listing(void *s, const char *name,
 	return err;
 }
 
-int messages_get_message(void *session,
-		const char *handle,
-		unsigned long flags,
-		messages_get_message_cb callback,
-		void *user_data)
+int messages_get_message(void *s, const char *h, unsigned long flags,
+				messages_get_message_cb cb, void *user_data)
 {
-	return -EINVAL;
+	struct session *session = s;
+	DBusPendingCall *call;
+	int err = 0;
+	char *handle = strip_handle(h);
+	char *query_handle = g_strdup_printf(MESSAGES_FILTER_BY_HANDLE, handle);
+	char *query = path2query("telecom/msg", LIST_MESSAGES_QUERY,
+								 query_handle);
+
+	if (query == NULL) {
+		err = -ENOENT;
+
+		goto failed;
+	}
+
+	if (flags & MESSAGES_FRACTION || flags & MESSAGES_NEXT) {
+		err = -EBADR;
+
+		goto failed;
+	}
+
+	session->name = g_strdup(handle);
+	session->flags = flags;
+	session->cb.message = cb;
+	session->generate_response = get_message_resp;
+	session->user_data = user_data;
+	session->aborted = FALSE;
+
+	call = query_tracker(query, session, &err);
+	if (err == 0)
+		new_call(call);
+
+failed:
+	g_free(query_handle);
+	g_free(query);
+	g_free(handle);
+
+	return err;
 }
 
 void messages_abort(void *s)
-- 
1.7.6.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH obexd 3/8] MAP Tracker: Add support for DBus connection
  2011-09-02  8:57 ` [PATCH obexd 3/8] MAP Tracker: Add support for DBus connection Bartosz Szatkowski
@ 2011-09-06 13:44   ` Johan Hedberg
  0 siblings, 0 replies; 11+ messages in thread
From: Johan Hedberg @ 2011-09-06 13:44 UTC (permalink / raw)
  To: Bartosz Szatkowski; +Cc: linux-bluetooth

Hi Bartosz,

On Fri, Sep 02, 2011, Bartosz Szatkowski wrote:
> ---
>  plugins/messages-tracker.c |   32 ++++++++++++++++++++++++++++++++
>  1 files changed, 32 insertions(+), 0 deletions(-)

I think you might be breaking some record for "number of issues per
lines of code" with this patch. If you're not already doing internal
patch reviews you should probably consider starting this practice.

> +static DBusConnection *dbus_get_connection(DBusBusType type)
> +{
> +	DBusError err;
> +	DBusConnection *tmp;
> +
> +	dbus_error_init(&err);
> +
> +	tmp = dbus_bus_get(type, &err);
> +
> +	if (dbus_error_is_set(&err))
> +		error("Connection Error (%s)", err.message);
> +
> +	if (!tmp)
> +		error("Error when getting on bus");
> +
> +	dbus_error_free(&err);
> +
> +	return tmp;
> +}

- Just get rid of this helper function and call dbus_bus_get() directly
  in messages_init

- Avoid variables with generic names like tmp. Instead call it e.g.
  conn. I saw this elsewhere in your patches too -- please fix those.

- Your error handling is messed up. You should only call dbus_error_free
  when you know that dbus_error_is_set is true. Also, if you check for
  the DBusError you shouldn't need to check for NULL.

>  int messages_init(void)
>  {
> +	DBusError err;
> +	dbus_error_init(&err);

What's the purpose of err? All you do with it is call dbus_error_init.
It's not used anywhere later in this function.

In its simplest form all you would have needed is:

	if (session_bus == NULL)
		session_bus = dbus_but_get(DBUS_BUS_SESSION, NULL);

	if (session_bus == NULL) {
		error("Unable to connect to the session bus");
		return -1;
	}

Is it valid behavior for messages_init to be called multiple times? If
not then the first NULL-check isn't really needed (at most you could
have an assert there).

> +	if (session_connection == NULL)
> +		session_connection = dbus_get_connection(DBUS_BUS_SESSION);
> +
> +	if (!session_connection)
> +		return -1;
> +

Either check for NULL with == or with ! but don't mix them. I know we
have inconsistencies within the source tree but try to at least be
consistent within your own code.

Also, you're introducing a memory leak: you should call
dbus_connection_unref and set session_bus to NULL in the messages_exit
function.

Johan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling
  2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
                   ` (6 preceding siblings ...)
  2011-09-02  8:58 ` [PATCH obexd 8/8] MAP Tracker: Refactor session struct Bartosz Szatkowski
@ 2011-09-27  9:46 ` Johan Hedberg
  7 siblings, 0 replies; 11+ messages in thread
From: Johan Hedberg @ 2011-09-27  9:46 UTC (permalink / raw)
  To: Bartosz Szatkowski; +Cc: linux-bluetooth

Hi Bartosz,

On Fri, Sep 02, 2011, Bartosz Szatkowski wrote:
> ---
>  plugins/messages-tracker.c |   11 +++++++----
>  1 files changed, 7 insertions(+), 4 deletions(-)

Patches 1 and 2 have been applied. I didn't see any response to the
issues raised for patch 3 (I might have forgotten though if that
discussion happened on IRC).

Johan

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2011-09-27  9:46 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-02  8:57 [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Bartosz Szatkowski
2011-09-02  8:57 ` [PATCH obexd 2/8] MAP Tracker: Fix memory issue in folder listing Bartosz Szatkowski
2011-09-02  8:57 ` [PATCH obexd 3/8] MAP Tracker: Add support for DBus connection Bartosz Szatkowski
2011-09-06 13:44   ` Johan Hedberg
2011-09-02  8:57 ` [PATCH obexd 4/8] MAP Tracker Add basic support for messages listing Bartosz Szatkowski
2011-09-02  8:57 ` [PATCH obexd 5/8] MAP Tracker Add filter support in " Bartosz Szatkowski
2011-09-02  8:57 ` [PATCH obexd 6/8] MAP Tracker: Add support for pulling messages Bartosz Szatkowski
2011-09-02 13:36   ` [PATCH " Bartosz Szatkowski
2011-09-02  8:57 ` [PATCH obexd 7/8] MAP Tracker: Add abort support in folder listing Bartosz Szatkowski
2011-09-02  8:58 ` [PATCH obexd 8/8] MAP Tracker: Refactor session struct Bartosz Szatkowski
2011-09-27  9:46 ` [PATCH obexd 1/8] MAP Tracker: Fix folder and path handling Johan Hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.