854 lines
18 KiB
C
854 lines
18 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 <string.h>
|
||
|
#include <errno.h>
|
||
|
#include <glib.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <inttypes.h>
|
||
|
|
||
|
#include <gobex/gobex.h>
|
||
|
#include <gobex/gobex-apparam.h>
|
||
|
|
||
|
#include "obexd.h"
|
||
|
#include "plugin.h"
|
||
|
#include "log.h"
|
||
|
#include "obex.h"
|
||
|
#include "service.h"
|
||
|
#include "mimetype.h"
|
||
|
#include "filesystem.h"
|
||
|
#include "manager.h"
|
||
|
#include "map_ap.h"
|
||
|
|
||
|
#include "messages.h"
|
||
|
|
||
|
#define READ_STATUS_REQ 0
|
||
|
#define DELETE_STATUS_REQ 1
|
||
|
|
||
|
#define XML_DECL "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||
|
|
||
|
/* Building blocks for x-obex/folder-listing */
|
||
|
#define FL_DTD "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">"
|
||
|
#define FL_BODY_BEGIN "<folder-listing version=\"1.0\">"
|
||
|
#define FL_BODY_EMPTY "<folder-listing version=\"1.0\"/>"
|
||
|
#define FL_PARENT_FOLDER_ELEMENT "<parent-folder/>"
|
||
|
#define FL_FOLDER_ELEMENT "<folder name=\"%s\"/>"
|
||
|
#define FL_BODY_END "</folder-listing>"
|
||
|
|
||
|
#define ML_BODY_BEGIN "<MAP-msg-listing version=\"1.0\">"
|
||
|
#define ML_BODY_END "</MAP-msg-listing>"
|
||
|
|
||
|
struct mas_session {
|
||
|
struct mas_request *request;
|
||
|
void *backend_data;
|
||
|
gboolean finished;
|
||
|
gboolean nth_call;
|
||
|
GString *buffer;
|
||
|
GObexApparam *inparams;
|
||
|
GObexApparam *outparams;
|
||
|
gboolean ap_sent;
|
||
|
};
|
||
|
|
||
|
static const uint8_t MAS_TARGET[TARGET_SIZE] = {
|
||
|
0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, 0xdb,
|
||
|
0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 };
|
||
|
|
||
|
static int get_params(struct obex_session *os, struct mas_session *mas)
|
||
|
{
|
||
|
const uint8_t *buffer;
|
||
|
ssize_t size;
|
||
|
|
||
|
size = obex_get_apparam(os, &buffer);
|
||
|
if (size < 0)
|
||
|
size = 0;
|
||
|
|
||
|
mas->inparams = g_obex_apparam_decode(buffer, size);
|
||
|
if (mas->inparams == NULL) {
|
||
|
DBG("Error when parsing parameters!");
|
||
|
return -EBADR;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void reset_request(struct mas_session *mas)
|
||
|
{
|
||
|
if (mas->buffer) {
|
||
|
g_string_free(mas->buffer, TRUE);
|
||
|
mas->buffer = NULL;
|
||
|
}
|
||
|
|
||
|
if (mas->inparams) {
|
||
|
g_obex_apparam_free(mas->inparams);
|
||
|
mas->inparams = NULL;
|
||
|
}
|
||
|
|
||
|
if (mas->outparams) {
|
||
|
g_obex_apparam_free(mas->outparams);
|
||
|
mas->outparams = NULL;
|
||
|
}
|
||
|
|
||
|
mas->nth_call = FALSE;
|
||
|
mas->finished = FALSE;
|
||
|
mas->ap_sent = FALSE;
|
||
|
}
|
||
|
|
||
|
static void mas_clean(struct mas_session *mas)
|
||
|
{
|
||
|
reset_request(mas);
|
||
|
g_free(mas);
|
||
|
}
|
||
|
|
||
|
static void *mas_connect(struct obex_session *os, int *err)
|
||
|
{
|
||
|
struct mas_session *mas;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
mas = g_new0(struct mas_session, 1);
|
||
|
|
||
|
*err = messages_connect(&mas->backend_data);
|
||
|
if (*err < 0)
|
||
|
goto failed;
|
||
|
|
||
|
manager_register_session(os);
|
||
|
|
||
|
return mas;
|
||
|
|
||
|
failed:
|
||
|
g_free(mas);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void mas_disconnect(struct obex_session *os, void *user_data)
|
||
|
{
|
||
|
struct mas_session *mas = user_data;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
manager_unregister_session(os);
|
||
|
messages_disconnect(mas->backend_data);
|
||
|
|
||
|
mas_clean(mas);
|
||
|
}
|
||
|
|
||
|
static int mas_get(struct obex_session *os, void *user_data)
|
||
|
{
|
||
|
struct mas_session *mas = user_data;
|
||
|
const char *type = obex_get_type(os);
|
||
|
const char *name = obex_get_name(os);
|
||
|
int ret;
|
||
|
|
||
|
DBG("GET: name %s type %s mas %p",
|
||
|
name, type, mas);
|
||
|
|
||
|
if (type == NULL)
|
||
|
return -EBADR;
|
||
|
|
||
|
ret = get_params(os, mas);
|
||
|
if (ret < 0)
|
||
|
goto failed;
|
||
|
|
||
|
ret = obex_get_stream_start(os, name);
|
||
|
if (ret < 0)
|
||
|
goto failed;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
failed:
|
||
|
reset_request(mas);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int mas_put(struct obex_session *os, void *user_data)
|
||
|
{
|
||
|
struct mas_session *mas = user_data;
|
||
|
const char *type = obex_get_type(os);
|
||
|
const char *name = obex_get_name(os);
|
||
|
int ret;
|
||
|
|
||
|
DBG("PUT: name %s type %s mas %p", name, type, mas);
|
||
|
|
||
|
if (type == NULL)
|
||
|
return -EBADR;
|
||
|
|
||
|
ret = get_params(os, mas);
|
||
|
if (ret < 0)
|
||
|
goto failed;
|
||
|
|
||
|
ret = obex_put_stream_start(os, name);
|
||
|
if (ret < 0)
|
||
|
goto failed;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
failed:
|
||
|
reset_request(mas);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/* FIXME: Preserve whitespaces */
|
||
|
static void g_string_append_escaped_printf(GString *string,
|
||
|
const char *format, ...)
|
||
|
{
|
||
|
va_list ap;
|
||
|
char *escaped;
|
||
|
|
||
|
va_start(ap, format);
|
||
|
escaped = g_markup_vprintf_escaped(format, ap);
|
||
|
g_string_append(string, escaped);
|
||
|
g_free(escaped);
|
||
|
va_end(ap);
|
||
|
}
|
||
|
|
||
|
static const char *yesorno(gboolean a)
|
||
|
{
|
||
|
if (a)
|
||
|
return "yes";
|
||
|
|
||
|
return "no";
|
||
|
}
|
||
|
|
||
|
static void get_messages_listing_cb(void *session, int err, uint16_t size,
|
||
|
gboolean newmsg,
|
||
|
const struct messages_message *entry,
|
||
|
void *user_data)
|
||
|
{
|
||
|
struct mas_session *mas = user_data;
|
||
|
uint16_t max = 1024;
|
||
|
|
||
|
if (err < 0 && err != -EAGAIN) {
|
||
|
obex_object_set_io_flags(mas, G_IO_ERR, err);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
|
||
|
|
||
|
if (max == 0) {
|
||
|
if (!entry)
|
||
|
mas->finished = TRUE;
|
||
|
|
||
|
goto proceed;
|
||
|
}
|
||
|
|
||
|
if (!mas->nth_call) {
|
||
|
g_string_append(mas->buffer, ML_BODY_BEGIN);
|
||
|
mas->nth_call = TRUE;
|
||
|
}
|
||
|
|
||
|
if (!entry) {
|
||
|
g_string_append(mas->buffer, ML_BODY_END);
|
||
|
mas->finished = TRUE;
|
||
|
|
||
|
goto proceed;
|
||
|
}
|
||
|
|
||
|
g_string_append(mas->buffer, "<msg");
|
||
|
|
||
|
g_string_append_escaped_printf(mas->buffer, " handle=\"%s\"",
|
||
|
entry->handle);
|
||
|
|
||
|
if (entry->mask & PMASK_SUBJECT)
|
||
|
g_string_append_escaped_printf(mas->buffer, " subject=\"%s\"",
|
||
|
entry->subject);
|
||
|
|
||
|
if (entry->mask & PMASK_DATETIME)
|
||
|
g_string_append_escaped_printf(mas->buffer, " datetime=\"%s\"",
|
||
|
entry->datetime);
|
||
|
|
||
|
if (entry->mask & PMASK_SENDER_NAME)
|
||
|
g_string_append_escaped_printf(mas->buffer,
|
||
|
" sender_name=\"%s\"",
|
||
|
entry->sender_name);
|
||
|
|
||
|
if (entry->mask & PMASK_SENDER_ADDRESSING)
|
||
|
g_string_append_escaped_printf(mas->buffer,
|
||
|
" sender_addressing=\"%s\"",
|
||
|
entry->sender_addressing);
|
||
|
|
||
|
if (entry->mask & PMASK_REPLYTO_ADDRESSING)
|
||
|
g_string_append_escaped_printf(mas->buffer,
|
||
|
" replyto_addressing=\"%s\"",
|
||
|
entry->replyto_addressing);
|
||
|
|
||
|
if (entry->mask & PMASK_RECIPIENT_NAME)
|
||
|
g_string_append_escaped_printf(mas->buffer,
|
||
|
" recipient_name=\"%s\"",
|
||
|
entry->recipient_name);
|
||
|
|
||
|
if (entry->mask & PMASK_RECIPIENT_ADDRESSING)
|
||
|
g_string_append_escaped_printf(mas->buffer,
|
||
|
" recipient_addressing=\"%s\"",
|
||
|
entry->recipient_addressing);
|
||
|
|
||
|
if (entry->mask & PMASK_TYPE)
|
||
|
g_string_append_escaped_printf(mas->buffer, " type=\"%s\"",
|
||
|
entry->type);
|
||
|
|
||
|
if (entry->mask & PMASK_RECEPTION_STATUS)
|
||
|
g_string_append_escaped_printf(mas->buffer,
|
||
|
" reception_status=\"%s\"",
|
||
|
entry->reception_status);
|
||
|
|
||
|
if (entry->mask & PMASK_SIZE)
|
||
|
g_string_append_escaped_printf(mas->buffer, " size=\"%s\"",
|
||
|
entry->size);
|
||
|
|
||
|
if (entry->mask & PMASK_ATTACHMENT_SIZE)
|
||
|
g_string_append_escaped_printf(mas->buffer,
|
||
|
" attachment_size=\"%s\"",
|
||
|
entry->attachment_size);
|
||
|
|
||
|
if (entry->mask & PMASK_TEXT)
|
||
|
g_string_append_escaped_printf(mas->buffer, " text=\"%s\"",
|
||
|
yesorno(entry->text));
|
||
|
|
||
|
if (entry->mask & PMASK_READ)
|
||
|
g_string_append_escaped_printf(mas->buffer, " read=\"%s\"",
|
||
|
yesorno(entry->read));
|
||
|
|
||
|
if (entry->mask & PMASK_SENT)
|
||
|
g_string_append_escaped_printf(mas->buffer, " sent=\"%s\"",
|
||
|
yesorno(entry->sent));
|
||
|
|
||
|
if (entry->mask & PMASK_PROTECTED)
|
||
|
g_string_append_escaped_printf(mas->buffer, " protected=\"%s\"",
|
||
|
yesorno(entry->protect));
|
||
|
|
||
|
if (entry->mask & PMASK_PRIORITY)
|
||
|
g_string_append_escaped_printf(mas->buffer, " priority=\"%s\"",
|
||
|
yesorno(entry->priority));
|
||
|
|
||
|
g_string_append(mas->buffer, "/>\n");
|
||
|
|
||
|
proceed:
|
||
|
if (!entry) {
|
||
|
mas->outparams = g_obex_apparam_set_uint16(mas->outparams,
|
||
|
MAP_AP_MESSAGESLISTINGSIZE,
|
||
|
size);
|
||
|
mas->outparams = g_obex_apparam_set_uint8(mas->outparams,
|
||
|
MAP_AP_NEWMESSAGE,
|
||
|
newmsg ? 1 : 0);
|
||
|
}
|
||
|
|
||
|
if (err != -EAGAIN)
|
||
|
obex_object_set_io_flags(mas, G_IO_IN, 0);
|
||
|
}
|
||
|
|
||
|
static void get_message_cb(void *session, int err, gboolean fmore,
|
||
|
const char *chunk, void *user_data)
|
||
|
{
|
||
|
struct mas_session *mas = user_data;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
if (err < 0 && err != -EAGAIN) {
|
||
|
obex_object_set_io_flags(mas, G_IO_ERR, err);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!chunk) {
|
||
|
mas->finished = TRUE;
|
||
|
goto proceed;
|
||
|
}
|
||
|
|
||
|
g_string_append(mas->buffer, chunk);
|
||
|
|
||
|
proceed:
|
||
|
if (err != -EAGAIN)
|
||
|
obex_object_set_io_flags(mas, G_IO_IN, 0);
|
||
|
}
|
||
|
|
||
|
static void get_folder_listing_cb(void *session, int err, uint16_t size,
|
||
|
const char *name, void *user_data)
|
||
|
{
|
||
|
struct mas_session *mas = user_data;
|
||
|
uint16_t max = 1024;
|
||
|
|
||
|
if (err < 0 && err != -EAGAIN) {
|
||
|
obex_object_set_io_flags(mas, G_IO_ERR, err);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
|
||
|
|
||
|
if (max == 0) {
|
||
|
if (err != -EAGAIN)
|
||
|
mas->outparams = g_obex_apparam_set_uint16(
|
||
|
mas->outparams,
|
||
|
MAP_AP_FOLDERLISTINGSIZE,
|
||
|
size);
|
||
|
|
||
|
if (!name)
|
||
|
mas->finished = TRUE;
|
||
|
|
||
|
goto proceed;
|
||
|
}
|
||
|
|
||
|
if (!mas->nth_call) {
|
||
|
g_string_append(mas->buffer, XML_DECL);
|
||
|
g_string_append(mas->buffer, FL_DTD);
|
||
|
if (!name) {
|
||
|
g_string_append(mas->buffer, FL_BODY_EMPTY);
|
||
|
mas->finished = TRUE;
|
||
|
goto proceed;
|
||
|
}
|
||
|
g_string_append(mas->buffer, FL_BODY_BEGIN);
|
||
|
mas->nth_call = TRUE;
|
||
|
}
|
||
|
|
||
|
if (!name) {
|
||
|
g_string_append(mas->buffer, FL_BODY_END);
|
||
|
mas->finished = TRUE;
|
||
|
goto proceed;
|
||
|
}
|
||
|
|
||
|
if (g_strcmp0(name, "..") == 0)
|
||
|
g_string_append(mas->buffer, FL_PARENT_FOLDER_ELEMENT);
|
||
|
else
|
||
|
g_string_append_escaped_printf(mas->buffer, FL_FOLDER_ELEMENT,
|
||
|
name);
|
||
|
|
||
|
proceed:
|
||
|
if (err != -EAGAIN)
|
||
|
obex_object_set_io_flags(mas, G_IO_IN, err);
|
||
|
}
|
||
|
|
||
|
static void set_status_cb(void *session, int err, void *user_data)
|
||
|
{
|
||
|
struct mas_session *mas = user_data;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
mas->finished = TRUE;
|
||
|
|
||
|
if (err < 0)
|
||
|
obex_object_set_io_flags(mas, G_IO_ERR, err);
|
||
|
else
|
||
|
obex_object_set_io_flags(mas, G_IO_OUT, 0);
|
||
|
}
|
||
|
|
||
|
static int mas_setpath(struct obex_session *os, void *user_data)
|
||
|
{
|
||
|
const char *name;
|
||
|
const uint8_t *nonhdr;
|
||
|
struct mas_session *mas = user_data;
|
||
|
|
||
|
if (obex_get_non_header_data(os, &nonhdr) != 2) {
|
||
|
error("Set path failed: flag and constants not found!");
|
||
|
return -EBADR;
|
||
|
}
|
||
|
|
||
|
name = obex_get_name(os);
|
||
|
|
||
|
DBG("SETPATH: name %s nonhdr 0x%x%x", name, nonhdr[0], nonhdr[1]);
|
||
|
|
||
|
if ((nonhdr[0] & 0x02) != 0x02) {
|
||
|
DBG("Error: requested directory creation");
|
||
|
return -EBADR;
|
||
|
}
|
||
|
|
||
|
return messages_set_folder(mas->backend_data, name, nonhdr[0] & 0x01);
|
||
|
}
|
||
|
|
||
|
static void *folder_listing_open(const char *name, int oflag, mode_t mode,
|
||
|
void *driver_data, size_t *size, int *err)
|
||
|
{
|
||
|
struct mas_session *mas = driver_data;
|
||
|
/* 1024 is the default when there was no MaxListCount sent */
|
||
|
uint16_t max = 1024;
|
||
|
uint16_t offset = 0;
|
||
|
|
||
|
if (oflag != O_RDONLY) {
|
||
|
*err = -EBADR;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
DBG("name = %s", name);
|
||
|
|
||
|
g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
|
||
|
g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
|
||
|
|
||
|
*err = messages_get_folder_listing(mas->backend_data, name, max,
|
||
|
offset, get_folder_listing_cb, mas);
|
||
|
|
||
|
mas->buffer = g_string_new("");
|
||
|
|
||
|
if (*err < 0)
|
||
|
return NULL;
|
||
|
else
|
||
|
return mas;
|
||
|
}
|
||
|
|
||
|
static void *msg_listing_open(const char *name, int oflag, mode_t mode,
|
||
|
void *driver_data, size_t *size, int *err)
|
||
|
{
|
||
|
struct mas_session *mas = driver_data;
|
||
|
struct messages_filter filter = { 0, };
|
||
|
/* 1024 is the default when there was no MaxListCount sent */
|
||
|
uint16_t max = 1024;
|
||
|
uint16_t offset = 0;
|
||
|
/* If MAP client does not specify the subject length,
|
||
|
then subject_len = 0 and subject should be sent unaltered. */
|
||
|
uint8_t subject_len = 0;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
if (oflag != O_RDONLY) {
|
||
|
*err = -EBADR;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
|
||
|
g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
|
||
|
g_obex_apparam_get_uint8(mas->inparams, MAP_AP_SUBJECTLENGTH,
|
||
|
&subject_len);
|
||
|
|
||
|
g_obex_apparam_get_uint32(mas->inparams, MAP_AP_PARAMETERMASK,
|
||
|
&filter.parameter_mask);
|
||
|
g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
|
||
|
&filter.type);
|
||
|
filter.period_begin = g_obex_apparam_get_string(mas->inparams,
|
||
|
MAP_AP_FILTERPERIODBEGIN);
|
||
|
filter.period_end = g_obex_apparam_get_string(mas->inparams,
|
||
|
MAP_AP_FILTERPERIODEND);
|
||
|
g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERREADSTATUS,
|
||
|
&filter.read_status);
|
||
|
filter.recipient = g_obex_apparam_get_string(mas->inparams,
|
||
|
MAP_AP_FILTERRECIPIENT);
|
||
|
filter.originator = g_obex_apparam_get_string(mas->inparams,
|
||
|
MAP_AP_FILTERORIGINATOR);
|
||
|
g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERPRIORITY,
|
||
|
&filter.priority);
|
||
|
|
||
|
*err = messages_get_messages_listing(mas->backend_data, name, max,
|
||
|
offset, subject_len, &filter,
|
||
|
get_messages_listing_cb, mas);
|
||
|
|
||
|
mas->buffer = g_string_new("");
|
||
|
|
||
|
if (*err < 0)
|
||
|
return NULL;
|
||
|
else
|
||
|
return mas;
|
||
|
}
|
||
|
|
||
|
static void *message_open(const char *name, int oflag, mode_t mode,
|
||
|
void *driver_data, size_t *size, int *err)
|
||
|
{
|
||
|
struct mas_session *mas = driver_data;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
if (oflag != O_RDONLY) {
|
||
|
DBG("Message pushing unsupported");
|
||
|
*err = -ENOSYS;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
*err = messages_get_message(mas->backend_data, name, 0,
|
||
|
get_message_cb, mas);
|
||
|
|
||
|
mas->buffer = g_string_new("");
|
||
|
|
||
|
if (*err < 0)
|
||
|
return NULL;
|
||
|
else
|
||
|
return mas;
|
||
|
}
|
||
|
|
||
|
static void *message_update_open(const char *name, int oflag, mode_t mode,
|
||
|
void *driver_data, size_t *size,
|
||
|
int *err)
|
||
|
{
|
||
|
struct mas_session *mas = driver_data;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
if (oflag == O_RDONLY) {
|
||
|
*err = -EBADR;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
*err = messages_update_inbox(mas->backend_data, set_status_cb, mas);
|
||
|
if (*err < 0)
|
||
|
return NULL;
|
||
|
else
|
||
|
return mas;
|
||
|
}
|
||
|
|
||
|
static void *message_set_status_open(const char *name, int oflag, mode_t mode,
|
||
|
void *driver_data, size_t *size,
|
||
|
int *err)
|
||
|
|
||
|
{
|
||
|
struct mas_session *mas = driver_data;
|
||
|
uint8_t indicator;
|
||
|
uint8_t value;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
if (oflag == O_RDONLY) {
|
||
|
*err = -EBADR;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSINDICATOR,
|
||
|
&indicator)) {
|
||
|
*err = -EBADR;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSVALUE,
|
||
|
&value)) {
|
||
|
*err = -EBADR;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (indicator == READ_STATUS_REQ)
|
||
|
*err = messages_set_read(mas->backend_data, name, value,
|
||
|
set_status_cb, mas);
|
||
|
else if (indicator == DELETE_STATUS_REQ)
|
||
|
*err = messages_set_delete(mas->backend_data, name, value,
|
||
|
set_status_cb, mas);
|
||
|
else
|
||
|
*err = -EBADR;
|
||
|
|
||
|
if (*err < 0)
|
||
|
return NULL;
|
||
|
|
||
|
return mas;
|
||
|
}
|
||
|
|
||
|
static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
|
||
|
uint8_t *hi)
|
||
|
{
|
||
|
struct mas_session *mas = object;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
if (mas->buffer->len == 0 && !mas->finished)
|
||
|
return -EAGAIN;
|
||
|
|
||
|
*hi = G_OBEX_HDR_APPARAM;
|
||
|
|
||
|
if (mas->ap_sent)
|
||
|
return 0;
|
||
|
|
||
|
mas->ap_sent = TRUE;
|
||
|
return g_obex_apparam_encode(mas->outparams, buf, mtu);
|
||
|
}
|
||
|
|
||
|
static void *any_open(const char *name, int oflag, mode_t mode,
|
||
|
void *driver_data, size_t *size, int *err)
|
||
|
{
|
||
|
DBG("");
|
||
|
|
||
|
*err = -ENOSYS;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static ssize_t any_write(void *object, const void *buf, size_t count)
|
||
|
{
|
||
|
DBG("");
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t any_read(void *obj, void *buf, size_t count)
|
||
|
{
|
||
|
struct mas_session *mas = obj;
|
||
|
ssize_t len;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
len = string_read(mas->buffer, buf, count);
|
||
|
|
||
|
if (len == 0 && !mas->finished)
|
||
|
return -EAGAIN;
|
||
|
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
static int any_close(void *obj)
|
||
|
{
|
||
|
struct mas_session *mas = obj;
|
||
|
|
||
|
DBG("");
|
||
|
|
||
|
if (!mas->finished)
|
||
|
messages_abort(mas->backend_data);
|
||
|
|
||
|
reset_request(mas);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static struct obex_service_driver mas = {
|
||
|
.name = "Message Access server",
|
||
|
.service = OBEX_MAS,
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.connect = mas_connect,
|
||
|
.get = mas_get,
|
||
|
.put = mas_put,
|
||
|
.setpath = mas_setpath,
|
||
|
.disconnect = mas_disconnect,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver mime_map = {
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.mimetype = NULL,
|
||
|
.open = any_open,
|
||
|
.close = any_close,
|
||
|
.read = any_read,
|
||
|
.write = any_write,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver mime_message = {
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.mimetype = "x-bt/message",
|
||
|
.open = message_open,
|
||
|
.close = any_close,
|
||
|
.read = any_read,
|
||
|
.write = any_write,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver mime_folder_listing = {
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.mimetype = "x-obex/folder-listing",
|
||
|
.get_next_header = any_get_next_header,
|
||
|
.open = folder_listing_open,
|
||
|
.close = any_close,
|
||
|
.read = any_read,
|
||
|
.write = any_write,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver mime_msg_listing = {
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.mimetype = "x-bt/MAP-msg-listing",
|
||
|
.get_next_header = any_get_next_header,
|
||
|
.open = msg_listing_open,
|
||
|
.close = any_close,
|
||
|
.read = any_read,
|
||
|
.write = any_write,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver mime_notification_registration = {
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.mimetype = "x-bt/MAP-NotificationRegistration",
|
||
|
.open = any_open,
|
||
|
.close = any_close,
|
||
|
.read = any_read,
|
||
|
.write = any_write,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver mime_message_status = {
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.mimetype = "x-bt/messageStatus",
|
||
|
.open = message_set_status_open,
|
||
|
.close = any_close,
|
||
|
.read = any_read,
|
||
|
.write = any_write,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver mime_message_update = {
|
||
|
.target = MAS_TARGET,
|
||
|
.target_size = TARGET_SIZE,
|
||
|
.mimetype = "x-bt/MAP-messageUpdate",
|
||
|
.open = message_update_open,
|
||
|
.close = any_close,
|
||
|
.read = any_read,
|
||
|
.write = any_write,
|
||
|
};
|
||
|
|
||
|
static struct obex_mime_type_driver *map_drivers[] = {
|
||
|
&mime_map,
|
||
|
&mime_message,
|
||
|
&mime_folder_listing,
|
||
|
&mime_msg_listing,
|
||
|
&mime_notification_registration,
|
||
|
&mime_message_status,
|
||
|
&mime_message_update,
|
||
|
NULL
|
||
|
};
|
||
|
|
||
|
static int mas_init(void)
|
||
|
{
|
||
|
int err;
|
||
|
int i;
|
||
|
|
||
|
err = messages_init();
|
||
|
if (err < 0)
|
||
|
return err;
|
||
|
|
||
|
for (i = 0; map_drivers[i] != NULL; ++i) {
|
||
|
err = obex_mime_type_driver_register(map_drivers[i]);
|
||
|
if (err < 0)
|
||
|
goto failed;
|
||
|
}
|
||
|
|
||
|
err = obex_service_driver_register(&mas);
|
||
|
if (err < 0)
|
||
|
goto failed;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
failed:
|
||
|
for (--i; i >= 0; --i)
|
||
|
obex_mime_type_driver_unregister(map_drivers[i]);
|
||
|
|
||
|
messages_exit();
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
static void mas_exit(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
obex_service_driver_unregister(&mas);
|
||
|
|
||
|
for (i = 0; map_drivers[i] != NULL; ++i)
|
||
|
obex_mime_type_driver_unregister(map_drivers[i]);
|
||
|
|
||
|
messages_exit();
|
||
|
}
|
||
|
|
||
|
OBEX_PLUGIN_DEFINE(mas, mas_init, mas_exit)
|