From 2b11b9cf81c53d0542259b1e11ff9b962de9deb2 Mon Sep 17 00:00:00 2001 From: Wu zheng Date: Wed, 23 Oct 2013 11:10:20 +0800 Subject: [PATCH] Add messages TIZEN driver Change-Id: I9404203308571f1d03527afd345d0112d6e973be --- Makefile.obexd | 2 +- obexd/plugins/messages-tizen.c | 742 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 743 insertions(+), 1 deletion(-) create mode 100644 obexd/plugins/messages-tizen.c diff --git a/Makefile.obexd b/Makefile.obexd index 3760867..326562a 100644 --- a/Makefile.obexd +++ b/Makefile.obexd @@ -46,7 +46,7 @@ endif obexd_builtin_modules += mas obexd_builtin_sources += obexd/plugins/mas.c obexd/src/map_ap.h \ obexd/plugins/messages.h \ - obexd/plugins/messages-dummy.c + obexd/plugins/messages-tizen.c obexd_builtin_modules += mns obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \ diff --git a/obexd/plugins/messages-tizen.c b/obexd/plugins/messages-tizen.c new file mode 100644 index 0000000..a668c7a --- /dev/null +++ b/obexd/plugins/messages-tizen.c @@ -0,0 +1,742 @@ +/* + * + * OBEX Server + * + * Copyright (C) 2009-2010 Intel Corporation + * Copyright (C) 2007-2010 Marcel Holtmann + * + * + * 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 +#endif + +#include +#include +#include +#include "log.h" +#include "messages.h" + +#include + +#define QUERY_GET_FOLDER_TREE "GetFolderTree" +#define QUERY_GET_MSG_LIST "GetMessageList" +#define QUERY_GET_MESSAGE "GetMessage" +#define QUERY_UPDATE_MESSAGE "UpdateMessage" +#define QUERY_MESSAGE_STATUS "MessageStatus" +#define QUERY_NOTI_REGISTRATION "NotiRegistration" + +#define BT_MAP_SERVICE_OBJECT_PATH "/org/bluez/map_agent" +#define BT_MAP_SERVICE_NAME "org.bluez.map_agent" +#define BT_MAP_SERVICE_INTERFACE "org.bluez.MapAgent" + +static DBusConnection *g_conn = NULL; + +struct mns_reg_data { + int notification_status; + char *remote_addr; +}; + +struct message_folder { + char *name; + GSList *subfolders; +}; + +struct session { + char *cwd; + struct message_folder *folder; + char *name; + uint16_t max; + uint16_t offset; + void *user_data; + void (*folder_list_cb)(void *session, int err, uint16_t size, + const char *name, void *user_data); + struct messages_message *msg; + const struct messages_filter *filter; + void (*msg_list_cb)(void *session, int err, int size, gboolean newmsg, + const struct messages_message *entry, + void *user_data); + void (*get_msg_cb)(void *session, int err, gboolean fmore, + const char *chunk, void *user_data); + void (*msg_update_cb)(void *session, int err, void *user_data); + void (*msg_status_cb)(void *session, int err, void *user_data); +}; + +static struct message_folder *folder_tree = NULL; + +static struct message_folder *get_folder(const char *folder) +{ + GSList *folders = folder_tree->subfolders; + struct message_folder *last = NULL; + char **path; + int i; + + if (g_strcmp0(folder, "/") == 0) + return folder_tree; + + path = g_strsplit(folder, "/", 0); + + for (i = 1; path[i] != NULL; i++) { + gboolean match_found = FALSE; + GSList *l; + + for (l = folders; l != NULL; l = g_slist_next(l)) { + struct message_folder *folder = l->data; + + if (g_ascii_strncasecmp(folder->name, path[i], + strlen(folder->name)) == 0) { + match_found = TRUE; + last = l->data; + folders = folder->subfolders; + break; + } + } + + if (!match_found) { + g_strfreev(path); + return NULL; + } + } + + g_strfreev(path); + + return last; +} + +static void destroy_folder_tree(void *root) +{ + struct message_folder *folder = root; + GSList *tmp, *next; + + if (folder == NULL) + return; + + g_free(folder->name); + + tmp = folder->subfolders; + while (tmp != NULL) { + next = g_slist_next(tmp); + destroy_folder_tree(tmp->data); + tmp = next; + } + g_slist_free(folder->subfolders); + g_free(folder); +} + +static struct message_folder *create_folder(const char *name) +{ + struct message_folder *folder = g_new0(struct message_folder, 1); + + folder->name = g_strdup(name); + return folder; +} + +static void create_folder_tree() +{ + + struct message_folder *parent, *child; + + folder_tree = create_folder("/"); + + parent = create_folder("telecom"); + folder_tree->subfolders = g_slist_append(folder_tree->subfolders, + parent); + + child = create_folder("msg"); + parent->subfolders = g_slist_append(parent->subfolders, child); +} + +int messages_init(void) +{ + g_conn = dbus_bus_get(DBUS_BUS_SESSION, NULL); + if (!g_conn) { + error("Can't get on session bus"); + return -1; + } + + create_folder_tree(); + return 0; +} + +void messages_exit(void) +{ + destroy_folder_tree(folder_tree); + + if (g_conn) { + dbus_connection_unref(g_conn); + g_conn = NULL; + } +} + +static void message_get_folder_list(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter; + DBusMessageIter iter_struct; + DBusMessageIter entry; + DBusError derr; + const char *name = NULL; + struct message_folder *parent = {0,}, *child = {0,}; + GSList *l; + + DBG("+\n"); + + for (l = folder_tree->subfolders; l != NULL; l = parent->subfolders) + parent = l->data; + + DBG("Last child folder = %s\n", parent->name); + 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); + } else { + dbus_message_iter_init(reply, &iter); + dbus_message_iter_recurse(&iter, &iter_struct); + + while (dbus_message_iter_get_arg_type(&iter_struct) == + DBUS_TYPE_STRUCT) { + dbus_message_iter_recurse(&iter_struct, &entry); + + dbus_message_iter_get_basic(&entry, &name); + DBG("Folder name = %s\n", name); + child = create_folder(name); + parent->subfolders = g_slist_append(parent->subfolders, + child); + dbus_message_iter_next(&iter_struct); + } + } + dbus_message_unref(reply); + DBG("-\n"); +} + +static void message_get_msg_list(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter; + DBusMessageIter iter_struct; + DBusMessageIter entry; + DBusError derr; + const char *msg_handle; + const char *msg_type; + const char *msg_time; + struct session *session = user_data; + struct messages_message *data = g_new0(struct messages_message, 1); + + DBG("+\n"); + + 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); + } else { + dbus_message_iter_init(reply, &iter); + dbus_message_iter_recurse(&iter, &iter_struct); + + while (dbus_message_iter_get_arg_type(&iter_struct) == + DBUS_TYPE_STRUCT) { + dbus_message_iter_recurse(&iter_struct, &entry); + dbus_message_iter_get_basic(&entry, &msg_handle); + DBG("Msg handle = %s\n", msg_handle); + data->handle = g_strdup(msg_handle); + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &msg_type); + DBG("Msg Type = %s\n", msg_type); + data->mask |= PMASK_TYPE; + data->type = g_strdup(msg_type); + dbus_message_iter_next(&entry); + dbus_message_iter_get_basic(&entry, &msg_time); + DBG("Msg date & time = %s\n", msg_time); + data->mask |= PMASK_DATETIME; + data->datetime = g_strdup(msg_time); + + session->msg_list_cb(session, -EAGAIN, 1, + TRUE, + data, + session->user_data); + dbus_message_iter_next(&iter_struct); + } + session->msg_list_cb(session, 0, 0, + FALSE, + NULL, + session->user_data); + } + dbus_message_unref(reply); + DBG("-\n"); +} + +static void message_get_msg(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter; + DBusMessageIter iter_struct; + DBusMessageIter entry; + DBusError derr; + struct session *session = user_data; + char *msg_body; + + DBG("+\n"); + + 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); + } else { + dbus_message_iter_init(reply, &iter); + dbus_message_iter_recurse(&iter, &iter_struct); + + if (dbus_message_iter_get_arg_type(&iter_struct) == + DBUS_TYPE_STRUCT) { + dbus_message_iter_recurse(&iter_struct, &entry); + dbus_message_iter_get_basic(&entry, &msg_body); + DBG("Msg handle = %s\n", msg_body); + } + session->get_msg_cb(session, -EAGAIN, FALSE, + msg_body, session->user_data); + session->get_msg_cb(session, 0, FALSE, + NULL, session->user_data); + } + dbus_message_unref(reply); + DBG("-\n"); +} + +int messages_connect(void **s) +{ + DBusPendingCall *call; + DBusMessage *message; + DBG("+\n"); + + struct session *session = g_new0(struct session, 1); + + session->cwd = g_strdup("/"); + session->folder = folder_tree; + + *s = session; + + message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME, + BT_MAP_SERVICE_OBJECT_PATH, + BT_MAP_SERVICE_INTERFACE, + QUERY_GET_FOLDER_TREE); + if (!message) { + error("Can't allocate new message"); + return -1; + } + + if (dbus_connection_send_with_reply(g_conn, message, &call, -1) == + FALSE) { + error("Could not send dbus message"); + dbus_message_unref(message); + return -1; + } + + dbus_pending_call_set_notify(call, message_get_folder_list, session, + NULL); + dbus_message_unref(message); + DBG("-\n"); + return 0; +} + +void messages_disconnect(void *s) +{ + DBG("+\n"); + struct session *session = s; + + g_free(session->cwd); + g_free(session); + + DBG("-\n"); +} + +int messages_set_notification_registration(void *session, + void (*send_event)(void *session, + const struct messages_event *event, void *user_data), + void *user_data) +{ + return -EINVAL; +} + +int messages_set_folder(void *s, const char *name, gboolean cdup) +{ + struct session *session = s; + char *newrel = NULL; + char *newabs; + char *tmp; + + if (name && (strchr(name, '/') || strcmp(name, "..") == 0)) + return -EBADR; + + if (cdup) { + if (session->cwd[0] == 0) + return -ENOENT; + + newrel = g_path_get_dirname(session->cwd); + + /* We use empty string for indication of the root directory */ + if (newrel[0] == '.' && newrel[1] == 0) + newrel[0] = 0; + } + + tmp = newrel; + if (!cdup && (!name || name[0] == 0)) + newrel = g_strdup(""); + else + newrel = g_build_filename(newrel ? newrel : session->cwd, name, + NULL); + g_free(tmp); + + if (newrel[0] != '/') + newabs = g_build_filename("/", newrel, NULL); + else + newabs = g_strdup(newrel); + + session->folder = get_folder(newabs); + if (session->folder == NULL) { + g_free(newrel); + g_free(newabs); + + return -ENOENT; + } + + g_free(newrel); + g_free(session->cwd); + session->cwd = newabs; + + return 0; +} + +static gboolean async_get_folder_listing(void *s) +{ + struct session *session = s; + 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; + + path = g_build_filename(session->cwd, session->name, NULL); + + if (path == NULL || strlen(path) == 0) + goto done; + + folder = get_folder(path); + + if (folder == NULL) + goto done; + + if (session->max == 0) { + session->max = 0xffff; + session->offset = 0; + count = TRUE; + } + + for (dir = folder->subfolders; dir && + (folder_count - session->offset) < session->max; + folder_count++, dir = g_slist_next(dir)) { + struct message_folder *dir_data = dir->data; + + if (count == FALSE && session->offset <= folder_count) + session->folder_list_cb(session, -EAGAIN, 0, + dir_data->name, session->user_data); + } + + done: + session->folder_list_cb(session, 0, folder_count, NULL, + session->user_data); + + g_free(path); + g_free(session->name); + + return FALSE; +} + +int messages_get_folder_listing(void *s, const char *name, + uint16_t max, uint16_t offset, + messages_folder_listing_cb callback, + void *user_data) +{ + DBG("+\n"); + struct session *session = s; + session->name = g_strdup(name); + session->max = max; + session->offset = offset; + session->folder_list_cb = callback; + session->user_data = user_data; + + g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing, + session, NULL); + + DBG("-\n"); + return 0; +} + +int messages_get_messages_listing(void *session, const char *name, + uint16_t max, uint16_t offset, + uint8_t subject_len, + const struct messages_filter *filter, + messages_get_messages_listing_cb callback, + void *user_data) +{ + DBusPendingCall *call; + DBusMessage *message; + struct session *s = session; + + if (strlen(name) != 0) + s->name = g_strdup(name); + else + s->name = g_strdup(s->cwd); + + s->max = max; + s->offset = offset; + s->filter = filter; + s->msg_list_cb = (void *)callback; + s->user_data = user_data; + + message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME, + BT_MAP_SERVICE_OBJECT_PATH, + BT_MAP_SERVICE_INTERFACE, + QUERY_GET_MSG_LIST); + if (!message) { + error("Can't allocate new message"); + g_free(s->name); + return -1; + } + dbus_message_append_args(message, DBUS_TYPE_STRING, &s->name, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(g_conn, message, &call, -1) == + FALSE) { + error("Could not send dbus message"); + dbus_message_unref(message); + g_free(s->name); + return -1; + } + dbus_pending_call_set_notify(call, message_get_msg_list, s, NULL); + dbus_message_unref(message); + g_free(s->name); + DBG("-\n"); + return 1; +} + +int messages_get_message(void *session, + const char *handle, + unsigned long flags, + messages_get_message_cb callback, + void *user_data) +{ + DBusPendingCall *call; + DBusMessage *message; + struct session *s = session; + char *message_name; + DBG("+\n"); + + if (NULL != handle) { + message_name = g_strdup(handle); + DBG("Message handle = %s\n", handle); + } else { + return -1; + } + s->get_msg_cb = callback; + s->user_data = user_data; + + message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME, + BT_MAP_SERVICE_OBJECT_PATH, + BT_MAP_SERVICE_INTERFACE, + QUERY_GET_MESSAGE); + if (!message) { + error("Can't allocate new message"); + g_free(message_name); + return -1; + } + dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(g_conn, message, &call, -1) == + FALSE) { + error("Could not send dbus message"); + dbus_message_unref(message); + g_free(message_name); + return -1; + } + dbus_pending_call_set_notify(call, message_get_msg, s, NULL); + dbus_message_unref(message); + g_free(message_name); + DBG("-\n"); + return 1; +} + +static void message_update_msg(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter; + DBusError derr; + struct session *session = user_data; + int err; + DBG("+\n"); + + 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); + } else { + dbus_message_iter_init(reply, &iter); + if (dbus_message_iter_get_arg_type(&iter) == + DBUS_TYPE_INT32) { + dbus_message_iter_get_basic(&iter, &err); + DBG("Error : %d\n", err); + session->msg_update_cb(session, err, + session->user_data); + } + } + dbus_message_unref(reply); + DBG("-\n"); +} + +int messages_update_inbox(void *session, + messages_status_cb callback, + void *user_data) +{ + DBusPendingCall *call; + DBusMessage *message; + struct session *s = session; + + DBG("+\n"); + + s->msg_update_cb = callback; + s->user_data = user_data; + + message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME, + BT_MAP_SERVICE_OBJECT_PATH, + BT_MAP_SERVICE_INTERFACE, + QUERY_UPDATE_MESSAGE); + if (!message) { + error("Can't allocate new message"); + return -1; + } + + if (dbus_connection_send_with_reply(g_conn, message, &call, -1) == + FALSE) { + error("Could not send dbus message"); + dbus_message_unref(message); + return -1; + } + dbus_pending_call_set_notify(call, message_update_msg, s, NULL); + dbus_message_unref(message); + DBG("-\n"); + return 1; +} + +static void message_status_msg(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter; + DBusError derr; + struct session *session = user_data; + int err; + + DBG("+\n"); + + 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); + } else { + dbus_message_iter_init(reply, &iter); + if (dbus_message_iter_get_arg_type(&iter) == + DBUS_TYPE_INT32) { + dbus_message_iter_get_basic(&iter, &err); + DBG("Error : %d\n", err); + session->msg_status_cb(session, err, + session->user_data); + } + } + dbus_message_unref(reply); + DBG("-\n"); +} + +static int messages_set_message_status(void *session, const char *handle, + int indicator, int value, + messages_status_cb callback, + void *user_data) +{ + DBusPendingCall *call; + DBusMessage *message; + struct session *s = session; + char *message_name; + + DBG("+\n"); + + if (NULL == handle) + return -1; + + message_name = g_strdup(handle); + DBG("Message handle = %s\n", handle); + + s->msg_status_cb = callback; + s->user_data = user_data; + + message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME, + BT_MAP_SERVICE_OBJECT_PATH, + BT_MAP_SERVICE_INTERFACE, + QUERY_MESSAGE_STATUS); + if (!message) { + error("Can't allocate new message"); + g_free(message_name); + return -1; + } + + dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name, + DBUS_TYPE_INT32, &indicator, + DBUS_TYPE_INT32, &value, + DBUS_TYPE_INVALID); + + if (dbus_connection_send_with_reply(g_conn, message, &call, -1) == + FALSE) { + error("Could not send dbus message"); + g_free(message_name); + dbus_message_unref(message); + return -1; + } + dbus_pending_call_set_notify(call, message_status_msg, s, NULL); + dbus_message_unref(message); + g_free(message_name); + DBG("-\n"); + return 1; +} + +int messages_set_read(void *session, const char *handle, uint8_t value, + messages_status_cb callback, void *user_data) +{ + return messages_set_message_status(session, handle, 0, + value, callback, user_data); +} + +int messages_set_delete(void *session, const char *handle, uint8_t value, + messages_status_cb callback, + void *user_data) +{ + return messages_set_message_status(session, handle, 0, + value, callback, user_data); +} + +void messages_abort(void *session) +{ +} -- 2.7.4