/* * * 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 #endif #include #include #include #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) { }