346 lines
7.3 KiB
C
346 lines
7.3 KiB
C
/*
|
|
*
|
|
* 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)
|
|
{
|
|
}
|