From a5ebb33ef1cc26e9d6b973ca1775f071ad4ec637 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 18 Mar 2010 19:53:05 -0300 Subject: [PATCH] obexd: Implements PhonebookSize for PullPhoneBook function According to PBAP spec, when MaxListCount is zero, the PSE shall ignore all other application parameters that may be present in the request and return the PhonebookSize encoded in the application parameter. --- obexd/plugins/ftp.c | 5 +- obexd/plugins/opp.c | 5 +- obexd/plugins/pbap.c | 78 +++++-- obexd/plugins/phonebook-ebook.c | 5 + obexd/plugins/syncevolution.c | 6 +- obexd/src/obex-priv.h | 1 + obexd/src/obex.c | 353 +++++++++++++++++--------------- obexd/src/obex.h | 2 + obexd/src/service.h | 3 +- 9 files changed, 274 insertions(+), 184 deletions(-) diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c index 0a1c6f818..7404738e8 100644 --- a/obexd/plugins/ftp.c +++ b/obexd/plugins/ftp.c @@ -193,7 +193,7 @@ static gpointer ftp_connect(struct obex_session *os, int *err) } 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); @@ -206,6 +206,9 @@ static int ftp_get(struct obex_session *os, obex_object_t *obj, if (ret < 0) return ret; + if (stream) + *stream = TRUE; + return 0; } diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c index 30b7560cd..c99e68679 100644 --- a/obexd/plugins/opp.c +++ b/obexd/plugins/opp.c @@ -164,7 +164,7 @@ static int opp_put(struct obex_session *os, gpointer user_data) } static int opp_get(struct obex_session *os, obex_object_t *obj, - gpointer user_data) + gboolean *stream, gpointer user_data) { const char *type; @@ -183,6 +183,9 @@ static int opp_get(struct obex_session *os, obex_object_t *obj, } else return -EPERM; + if (stream) + *stream = TRUE; + return 0; } diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c index 544aac725..fc0eabeeb 100644 --- a/obexd/plugins/pbap.c +++ b/obexd/plugins/pbap.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -131,7 +132,9 @@ struct pbap_session { 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] = { @@ -145,6 +148,29 @@ static void set_folder(struct pbap_session *pbap, const char *new_folder) 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; @@ -237,7 +263,7 @@ static gpointer pbap_connect(struct obex_session *os, int *err) } 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); @@ -286,7 +312,13 @@ static int pbap_get(struct obex_session *os, obex_object_t *obj, 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: @@ -365,19 +397,6 @@ static struct obex_service_driver pbap = { .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) { @@ -389,7 +408,17 @@ static gpointer vobject_open(const char *name, int oflag, mode_t mode, 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; @@ -409,6 +438,23 @@ static ssize_t vobject_read(gpointer object, void *buf, size_t count) { 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 528adf365..997e1b2ae 100644 --- a/obexd/plugins/phonebook-ebook.c +++ b/obexd/plugins/phonebook-ebook.c @@ -70,6 +70,10 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *contacts, /* 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; @@ -82,6 +86,7 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *contacts, 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 23549914b..12cf78b45 100644 --- a/obexd/plugins/syncevolution.c +++ b/obexd/plugins/syncevolution.c @@ -228,8 +228,12 @@ static int synce_put(struct obex_session *os, gpointer user_data) 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 932f27537..8406bc07c 100644 --- a/obexd/src/obex-priv.h +++ b/obexd/src/obex-priv.h @@ -60,6 +60,7 @@ struct obex_session { 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 a2c7346ff..aa0dfb151 100644 --- a/obexd/src/obex.c +++ b/obexd/src/obex.c @@ -316,6 +316,159 @@ static gboolean chk_cid(obex_t *obex, obex_object_t *obj, guint32 cid) 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; @@ -397,24 +550,34 @@ static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj) } } - 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); } @@ -500,62 +663,6 @@ fail: 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) { @@ -599,99 +706,6 @@ int obex_put_stream_start(struct obex_session *os, 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; @@ -1229,6 +1243,17 @@ ssize_t obex_aparam_read(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 64591f646..00336c70a 100644 --- a/obexd/src/obex.h +++ b/obexd/src/obex.h @@ -58,6 +58,8 @@ int obex_remove(struct obex_session *os, const char *path); 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 1ff960366..81185d9ff 100644 --- a/obexd/src/service.h +++ b/obexd/src/service.h @@ -32,7 +32,8 @@ struct obex_service_driver { 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); -- 2.47.3