diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c
index 0a1c6f8..7404738 100644
--- a/obexd/plugins/ftp.c
+++ b/obexd/plugins/ftp.c
}
static int ftp_get(struct obex_session *os, obex_object_t *obj,
- gpointer user_data)
+ gboolean *stream, gpointer user_data)
{
struct ftp_session *ftp = user_data;
const char *type = obex_get_type(os);
if (ret < 0)
return ret;
+ if (stream)
+ *stream = TRUE;
+
return 0;
}
diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c
index 30b7560..c99e686 100644
--- a/obexd/plugins/opp.c
+++ b/obexd/plugins/opp.c
}
static int opp_get(struct obex_session *os, obex_object_t *obj,
- gpointer user_data)
+ gboolean *stream, gpointer user_data)
{
const char *type;
} else
return -EPERM;
+ if (stream)
+ *stream = TRUE;
+
return 0;
}
diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c
index 544aac7..fc0eabe 100644
--- a/obexd/plugins/pbap.c
+++ b/obexd/plugins/pbap.c
#include <glib.h>
#include <stdlib.h>
#include <unistd.h>
+#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct obex_session *os;
struct apparam_field *params;
gchar *folder;
- GString *buffer;
+ GString *buffer;
+ guint16 phonebooksize;
+ obex_object_t *object;
};
static const guint8 PBAP_TARGET[TARGET_SIZE] = {
pbap->folder = new_folder ? g_strdup(new_folder) : NULL;
}
+static void phonebook_size_result(const gchar *buffer, size_t bufsize,
+ gint vcards, gint missed, gpointer user_data)
+{
+ struct pbap_session *pbap = user_data;
+
+ pbap->phonebooksize = vcards;
+
+ obex_object_set_io_flags(pbap, G_IO_IN, 0);
+}
+
+static void query_result(const gchar *buffer, size_t bufsize,
+ gint vcards, gint missed, gpointer user_data)
+{
+ struct pbap_session *pbap = user_data;
+
+ if (!pbap->buffer)
+ pbap->buffer = g_string_new_len(buffer, bufsize);
+ else
+ pbap->buffer = g_string_append_len(pbap->buffer, buffer, bufsize);
+
+ obex_object_set_io_flags(pbap, G_IO_IN, 0);
+}
+
static struct apparam_field *parse_aparam(const guint8 *buffer, guint32 hlen)
{
struct apparam_field *param;
}
static int pbap_get(struct obex_session *os, obex_object_t *obj,
- gpointer user_data)
+ gboolean *stream, gpointer user_data)
{
struct pbap_session *pbap = user_data;
const gchar *type = obex_get_type(os);
g_free(pbap->params);
}
+ if (params->maxlistcount == 0)
+ *stream = FALSE;
+ else
+ *stream = TRUE;
+
pbap->params = params;
+ pbap->object = obj;
ret = obex_get_stream_start(os, path, pbap);
failed:
.chkput = pbap_chkput
};
-static void query_result(const gchar *buffer, size_t bufsize,
- gint vcards, gint missed, gpointer user_data)
-{
- struct pbap_session *pbap = user_data;
-
- if (!pbap->buffer)
- pbap->buffer = g_string_new_len(buffer, bufsize);
- else
- pbap->buffer = g_string_append_len(pbap->buffer, buffer, bufsize);
-
- obex_object_set_io_flags(pbap, G_IO_IN, 0);
-}
-
static gpointer vobject_open(const char *name, int oflag, mode_t mode,
gpointer context, size_t *size, int *err)
{
goto fail;
}
- ret = phonebook_pull(name, pbap->params, query_result, pbap);
+ /*
+ * Zero means that the PCE wants to know the number of used indexes in
+ * the phone book of interest. PSE shall ignore all other application
+ * parameter that may be present in the request.
+ */
+ if (pbap->params->maxlistcount == 0)
+ ret = phonebook_pull(name, pbap->params,
+ phonebook_size_result, pbap);
+ else
+ ret = phonebook_pull(name, pbap->params, query_result, pbap);
+
if (ret < 0)
goto fail;
{
struct pbap_session *pbap = object;
+ /* PhoneBookSize */
+ if (pbap->params->maxlistcount == 0) {
+ guint8 data[4];
+ guint16 phonebooksize;
+ struct aparam_header *hdr = (struct aparam_header *) data;
+
+ phonebooksize = htons(pbap->phonebooksize);
+ hdr->tag = PHONEBOOKSIZE_TAG;
+ hdr->len = PHONEBOOKSIZE_LEN;
+ memcpy(hdr->val, &phonebooksize, sizeof(phonebooksize));
+
+ obex_aparam_write(pbap->os, pbap->object, data, sizeof(data));
+
+ return 0;
+ }
+
+ /* Stream data */
if (pbap->buffer)
return string_read(pbap->buffer, buf, count);
diff --git a/obexd/plugins/phonebook-ebook.c b/obexd/plugins/phonebook-ebook.c
index 528adf3..997e1b2 100644
--- a/obexd/plugins/phonebook-ebook.c
+++ b/obexd/plugins/phonebook-ebook.c
/* FIXME: Missing 0.vcf */
+ /* PCE wants only the number of indexes in the phonebook */
+ if (maxcount == 0)
+ goto done;
+
for (; l && count < maxcount; l = g_list_next(l), count++) {
EContact *contact;
EVCard *evcard;
g_free(vcard);
}
+done:
data->cb(string->str, string->len,
g_list_length(contacts), 0, data->user_data);
diff --git a/obexd/plugins/syncevolution.c b/obexd/plugins/syncevolution.c
index 2354991..12cf78b 100644
--- a/obexd/plugins/syncevolution.c
+++ b/obexd/plugins/syncevolution.c
return 0;
}
-static int synce_get(struct obex_session *os, obex_object_t *obj, gpointer user_data)
+static int synce_get(struct obex_session *os, obex_object_t *obj,
+ gboolean *stream, gpointer user_data)
{
+ if (stream)
+ *stream = TRUE;
+
return obex_get_stream_start(os, NULL, os);
}
diff --git a/obexd/src/obex-priv.h b/obexd/src/obex-priv.h
index 932f275..8406bc0 100644
--- a/obexd/src/obex-priv.h
+++ b/obexd/src/obex-priv.h
obex_object_t *obj;
struct obex_mime_type_driver *driver;
gboolean finished;
+ gboolean stream;
};
gint obex_session_start(GIOChannel *io, struct server *server);
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
index a2c7346..aa0dfb1 100644
--- a/obexd/src/obex.c
+++ b/obexd/src/obex.c
return ret;
}
+static gint obex_read_stream(struct obex_session *os, obex_t *obex,
+ obex_object_t *obj)
+{
+ gint size;
+ gint32 len = 0;
+ const guint8 *buffer;
+
+ if (os->aborted)
+ return -EPERM;
+
+ /* workaround: client didn't send the object lenght */
+ if (os->size == OBJECT_SIZE_DELETE)
+ os->size = OBJECT_SIZE_UNKNOWN;
+
+ size = OBEX_ObjectReadStream(obex, obj, &buffer);
+ if (size < 0) {
+ error("Error on OBEX stream");
+ return -EIO;
+ }
+
+ if (size > os->rx_mtu) {
+ error("Received more data than RX_MAX");
+ return -EIO;
+ }
+
+ if (os->object == NULL && size > 0) {
+ os->buf = g_realloc(os->buf, os->offset + size);
+ memcpy(os->buf + os->offset, buffer, size);
+ os->offset += size;
+
+ debug("Stored %u bytes into temporary buffer", size);
+
+ return 0;
+ }
+
+ while (len < size) {
+ gint w;
+
+ w = os->driver->write(os->object, buffer + len, size - len);
+ if (w < 0) {
+ if (w == -EINTR)
+ continue;
+ else
+ return w;
+ }
+
+ len += w;
+ }
+
+ os->offset += len;
+
+ return 0;
+}
+
+static gint obex_write_stream(struct obex_session *os,
+ obex_t *obex, obex_object_t *obj)
+{
+ obex_headerdata_t hd;
+ gint32 len;
+ guint8 *ptr;
+
+ debug("obex_write_stream: name=%s type=%s tx_mtu=%d file=%p",
+ os->name ? os->name : "", os->type ? os->type : "",
+ os->tx_mtu, os->object);
+
+ if (os->aborted)
+ return -EPERM;
+
+ if (os->object == NULL) {
+ if (os->buf == NULL && os->finished == FALSE)
+ return -EIO;
+
+ len = MIN(os->size - os->offset, os->tx_mtu);
+ ptr = os->buf + os->offset;
+ goto add_header;
+ }
+
+ len = os->driver->read(os->object, os->buf, os->tx_mtu);
+ if (len < 0) {
+ error("read(): %s (%d)", strerror(-len), -len);
+ if (len == -EAGAIN)
+ return len;
+ else if (len == -ENOSTR)
+ return 0;
+
+ g_free(os->buf);
+ os->buf = NULL;
+ return len;
+ }
+
+ if (!os->stream)
+ return 0;
+
+ ptr = os->buf;
+
+add_header:
+
+ hd.bs = ptr;
+
+ if (len == 0) {
+ OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, 0,
+ OBEX_FL_STREAM_DATAEND);
+ g_free(os->buf);
+ os->buf = NULL;
+ return len;
+ }
+
+ os->offset += len;
+
+ OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, len,
+ OBEX_FL_STREAM_DATA);
+
+ return len;
+}
+
+static gboolean handle_async_io(gpointer object, int flags, int err,
+ gpointer user_data)
+{
+ struct obex_session *os = user_data;
+ int ret = 0;
+
+ if (err < 0) {
+ ret = err;
+ goto proceed;
+ }
+
+ if (flags & (G_IO_IN | G_IO_PRI))
+ ret = obex_write_stream(os, os->obex, os->obj);
+ else if (flags & G_IO_OUT)
+ ret = obex_read_stream(os, os->obex, os->obj);
+
+proceed:
+ switch (ret) {
+ case -EINVAL:
+ OBEX_ObjectSetRsp(os->obj, OBEX_RSP_BAD_REQUEST,
+ OBEX_RSP_BAD_REQUEST);
+ case -EPERM:
+ OBEX_ObjectSetRsp(os->obj, OBEX_RSP_FORBIDDEN,
+ OBEX_RSP_FORBIDDEN);
+ break;
+ default:
+ if (ret < 0)
+ OBEX_ObjectSetRsp(os->obj,
+ OBEX_RSP_INTERNAL_SERVER_ERROR,
+ OBEX_RSP_INTERNAL_SERVER_ERROR);
+ break;
+ }
+
+ OBEX_ResumeRequest(os->obex);
+
+ return FALSE;
+}
+
static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj)
{
obex_headerdata_t hd;
}
}
- err = os->service->get(os, obj, os->service_data);
- if (err == 0) {
- if (os->size != OBJECT_SIZE_UNKNOWN) {
- hd.bq4 = os->size;
- OBEX_ObjectAddHeader(obex, obj,
- OBEX_HDR_LENGTH, hd, 4, 0);
- }
+ err = os->service->get(os, obj, &os->stream, os->service_data);
- /* Add body header */
- hd.bs = NULL;
- if (os->size == 0)
- OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
- hd, 0, OBEX_FL_FIT_ONE_PACKET);
- else
- OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
- hd, 0, OBEX_FL_STREAM_START);
+ if (err < 0)
+ goto done;
+
+ if (os->size != OBJECT_SIZE_UNKNOWN) {
+ hd.bq4 = os->size;
+ OBEX_ObjectAddHeader(obex, obj,
+ OBEX_HDR_LENGTH, hd, 4, 0);
}
+ /* Add body header */
+ hd.bs = NULL;
+ if (os->size == 0)
+ OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
+ hd, 0, OBEX_FL_FIT_ONE_PACKET);
+ else if (!os->stream) {
+ /* Asynchronous operation that doesn't use stream */
+ OBEX_SuspendRequest(obex, obj);
+ os->obj = obj;
+ os->driver->set_io_watch(os->object, handle_async_io, os);
+ return;
+ } else
+ /* Standard data stream */
+ OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY,
+ hd, 0, OBEX_FL_STREAM_START);
+
+done:
os_set_response(obj, err);
}
return err;
}
-static gint obex_write_stream(struct obex_session *os,
- obex_t *obex, obex_object_t *obj)
-{
- obex_headerdata_t hd;
- gint32 len;
- guint8 *ptr;
-
- debug("obex_write_stream: name=%s type=%s tx_mtu=%d file=%p",
- os->name ? os->name : "", os->type ? os->type : "",
- os->tx_mtu, os->object);
-
- if (os->aborted)
- return -EPERM;
-
- if (os->object == NULL) {
- if (os->buf == NULL && os->finished == FALSE)
- return -EIO;
-
- len = MIN(os->size - os->offset, os->tx_mtu);
- ptr = os->buf + os->offset;
- goto add_header;
- }
-
- len = os->driver->read(os->object, os->buf, os->tx_mtu);
- if (len < 0) {
- error("read(): %s (%d)", strerror(-len), -len);
- if (len == -EAGAIN)
- return len;
-
- g_free(os->buf);
- os->buf = NULL;
- return len;
- }
-
- ptr = os->buf;
-
-add_header:
-
- hd.bs = ptr;
-
- if (len == 0) {
- OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, 0,
- OBEX_FL_STREAM_DATAEND);
- g_free(os->buf);
- os->buf = NULL;
- return len;
- }
-
- os->offset += len;
-
- OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, len,
- OBEX_FL_STREAM_DATA);
-
- return len;
-}
-
int obex_put_stream_start(struct obex_session *os,
const gchar *filename, gpointer driver_data)
{
return 0;
}
-static gint obex_read_stream(struct obex_session *os, obex_t *obex,
- obex_object_t *obj)
-{
- gint size;
- gint32 len = 0;
- const guint8 *buffer;
-
- if (os->aborted)
- return -EPERM;
-
- /* workaround: client didn't send the object lenght */
- if (os->size == OBJECT_SIZE_DELETE)
- os->size = OBJECT_SIZE_UNKNOWN;
-
- size = OBEX_ObjectReadStream(obex, obj, &buffer);
- if (size < 0) {
- error("Error on OBEX stream");
- return -EIO;
- }
-
- if (size > os->rx_mtu) {
- error("Received more data than RX_MAX");
- return -EIO;
- }
-
- if (os->object == NULL && size > 0) {
- os->buf = g_realloc(os->buf, os->offset + size);
- memcpy(os->buf + os->offset, buffer, size);
- os->offset += size;
-
- debug("Stored %u bytes into temporary buffer", size);
-
- return 0;
- }
-
- while (len < size) {
- gint w;
-
- w = os->driver->write(os->object, buffer + len, size - len);
- if (w < 0) {
- if (w == -EINTR)
- continue;
- else
- return w;
- }
-
- len += w;
- }
-
- os->offset += len;
-
- return 0;
-}
-
-static gboolean handle_async_io(gpointer object, int flags, int err,
- gpointer user_data)
-{
- struct obex_session *os = user_data;
- int ret = 0;
-
- if (err < 0) {
- ret = err;
- goto proceed;
- }
-
- if (flags & (G_IO_IN | G_IO_PRI))
- ret = obex_write_stream(os, os->obex, os->obj);
- else if (flags & G_IO_OUT)
- ret = obex_read_stream(os, os->obex, os->obj);
-
-proceed:
- switch (ret) {
- case -EINVAL:
- OBEX_ObjectSetRsp(os->obj, OBEX_RSP_BAD_REQUEST,
- OBEX_RSP_BAD_REQUEST);
- break;
- case -EPERM:
- OBEX_ObjectSetRsp(os->obj, OBEX_RSP_FORBIDDEN,
- OBEX_RSP_FORBIDDEN);
- break;
- default:
- if (ret < 0)
- OBEX_ObjectSetRsp(os->obj,
- OBEX_RSP_INTERNAL_SERVER_ERROR,
- OBEX_RSP_INTERNAL_SERVER_ERROR);
- break;
- }
-
- OBEX_ResumeRequest(os->obex);
-
- return FALSE;
-}
-
static gboolean check_put(obex_t *obex, obex_object_t *obj)
{
struct obex_session *os;
return -EBADR;
}
+int obex_aparam_write(struct obex_session *os,
+ obex_object_t *obj, const guint8 *data, guint size)
+{
+ obex_headerdata_t hd;
+
+ hd.bs = data;
+
+ return OBEX_ObjectAddHeader(os->obex, obj,
+ OBEX_HDR_APPARAM, hd, size, 0);
+}
+
int memcmp0(const void *a, const void *b, size_t n)
{
if (a == NULL)
diff --git a/obexd/src/obex.h b/obexd/src/obex.h
index 64591f6..00336c7 100644
--- a/obexd/src/obex.h
+++ b/obexd/src/obex.h
char *obex_get_id(struct obex_session *os);
ssize_t obex_aparam_read(struct obex_session *os,
obex_object_t *obj, const guint8 **buffer);
+int obex_aparam_write(struct obex_session *os,
+ obex_object_t *obj, const guint8 *buffer, guint size);
const gchar *obex_option_root_folder(void);
gboolean obex_option_symlinks(void);
diff --git a/obexd/src/service.h b/obexd/src/service.h
index 1ff9603..81185d9 100644
--- a/obexd/src/service.h
+++ b/obexd/src/service.h
const gchar *record;
gpointer (*connect) (struct obex_session *os, int *err);
void (*progress) (struct obex_session *os, gpointer user_data);
- int (*get) (struct obex_session *os, obex_object_t *obj, gpointer user_data);
+ int (*get) (struct obex_session *os, obex_object_t *obj,
+ gboolean *stream, gpointer user_data);
int (*put) (struct obex_session *os, gpointer user_data);
gint (*chkput) (struct obex_session *os, gpointer user_data);
int (*setpath) (struct obex_session *os, obex_object_t *obj, gpointer user_data);