| /* | |
| * | |
| * OBEX Server | |
| * | |
| * 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 | |
| * | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| #include <config.h> | |
| #endif | |
| #include <errno.h> | |
| #include <glib.h> | |
| #include <string.h> | |
| #include "messages.h" | |
| struct message_folder { | |
| char *name; | |
| GSList *subfolders; | |
| char *query; | |
| }; | |
| 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); | |
| }; | |
| 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_strcmp0(folder->name, path[i]) == 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 struct message_folder *create_folder(const char *name, const char *query) | |
| { | |
| struct message_folder *folder = g_new0(struct message_folder, 1); | |
| folder->name = g_strdup(name); | |
| folder->query = g_strdup(query); | |
| return folder; | |
| } | |
| static void destroy_folder_tree(void *root) | |
| { | |
| struct message_folder *folder = root; | |
| GSList *tmp, *next; | |
| if (folder == NULL) | |
| return; | |
| g_free(folder->name); | |
| g_free(folder->query); | |
| 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 void create_folder_tree(void) | |
| { | |
| struct message_folder *parent, *child; | |
| folder_tree = create_folder("/", "FILTER (!BOUND(?msg))"); | |
| parent = create_folder("telecom", "FILTER (!BOUND(?msg))"); | |
| folder_tree->subfolders = g_slist_append(folder_tree->subfolders, | |
| parent); | |
| child = create_folder("msg", "FILTER (!BOUND(?msg))"); | |
| parent->subfolders = g_slist_append(parent->subfolders, child); | |
| parent = child; | |
| child = create_folder("inbox", "?msg nmo:isSent \"false\" ; " | |
| "nmo:isDeleted \"false\" ; " | |
| "nmo:isDraft \"false\". "); | |
| parent->subfolders = g_slist_append(parent->subfolders, child); | |
| child = create_folder("sent", "?msg nmo:isDeleted \"false\" ; " | |
| "nmo:isSent \"true\" . "); | |
| parent->subfolders = g_slist_append(parent->subfolders, child); | |
| child = create_folder("deleted", "?msg nmo:isDeleted \"true\" . "); | |
| parent->subfolders = g_slist_append(parent->subfolders, child); | |
| } | |
| int messages_init(void) | |
| { | |
| create_folder_tree(); | |
| return 0; | |
| } | |
| void messages_exit(void) | |
| { | |
| destroy_folder_tree(folder_tree); | |
| } | |
| int messages_connect(void **s) | |
| { | |
| struct session *session = g_new0(struct session, 1); | |
| session->cwd = g_strdup("/"); | |
| session->folder = folder_tree; | |
| *s = session; | |
| return 0; | |
| } | |
| void messages_disconnect(void *s) | |
| { | |
| struct session *session = s; | |
| g_free(session->cwd); | |
| g_free(session); | |
| } | |
| int messages_set_notification_registration(void *session, | |
| void (*send_event)(void *session, | |
| const struct messages_event *event, void *user_data), | |
| void *user_data) | |
| { | |
| return -ENOSYS; | |
| } | |
| 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) | |
| { | |
| 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); | |
| 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) | |
| { | |
| return -ENOSYS; | |
| } | |
| int messages_get_message(void *session, const char *handle, | |
| unsigned long flags, | |
| messages_get_message_cb callback, | |
| void *user_data) | |
| { | |
| return -ENOSYS; | |
| } | |
| int messages_update_inbox(void *session, messages_status_cb callback, | |
| void *user_data) | |
| { | |
| return -ENOSYS; | |
| } | |
| int messages_set_read(void *session, const char *handle, uint8_t value, | |
| messages_status_cb callback, void *user_data) | |
| { | |
| return -ENOSYS; | |
| } | |
| int messages_set_delete(void *session, const char *handle, uint8_t value, | |
| messages_status_cb callback, | |
| void *user_data) | |
| { | |
| return -ENOSYS; | |
| } | |
| void messages_abort(void *session) | |
| { | |
| } |