From f53123b6a1a26128ae0bc3e2ad40bfd57933ba14 Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 4 Mar 2010 19:53:01 -0300 Subject: [PATCH] obexd: Added PBAP application parameter parser function --- obexd/plugins/filesystem.c | 31 +++--- obexd/plugins/ftp.c | 6 +- obexd/plugins/opp.c | 2 +- obexd/plugins/pbap.c | 172 ++++++++++++++++++++++++-------- obexd/plugins/phonebook-dummy.c | 5 +- obexd/plugins/phonebook-ebook.c | 5 +- obexd/plugins/phonebook.h | 10 +- obexd/plugins/syncevolution.c | 5 +- obexd/src/mimetype.h | 3 +- obexd/src/obex.c | 31 +++++- obexd/src/obex.h | 5 +- 11 files changed, 202 insertions(+), 73 deletions(-) diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c index c110c8063..c88d96572 100644 --- a/obexd/plugins/filesystem.c +++ b/obexd/plugins/filesystem.c @@ -124,7 +124,7 @@ static gchar *file_stat_line(gchar *filename, struct stat *fstat, } static gpointer filesystem_open(const char *name, int oflag, mode_t mode, - size_t *size, struct obex_session *os, int *err) + gpointer context, size_t *size, int *err) { struct stat stats; struct statvfs buf; @@ -247,7 +247,7 @@ static int capability_exec(const char **argv, int *output, int *err) } static gpointer capability_open(const char *name, int oflag, mode_t mode, - size_t *size, struct obex_session *os, int *err) + gpointer context, size_t *size, int *err) { struct capability_object *object = NULL; gchar *buf; @@ -306,9 +306,10 @@ fail: return NULL; } -static gpointer folder_open(const char *folder, int oflag, mode_t mode, - size_t *size, struct obex_session *os, int *err) +static gpointer folder_open(const char *name, int oflag, mode_t mode, + gpointer context, size_t *size, int *err) { + struct obex_session *os = context; struct stat fstat, dstat; struct dirent *ep; GString *object; @@ -323,9 +324,9 @@ static gpointer folder_open(const char *folder, int oflag, mode_t mode, object = g_string_append(object, FL_BODY_BEGIN); - root = g_str_equal(folder, obex_get_root_folder(os)); + root = g_str_equal(name, obex_get_root_folder(os)); - dp = opendir(folder); + dp = opendir(name); if (dp == NULL) { if (err) *err = -ENOENT; @@ -334,10 +335,10 @@ static gpointer folder_open(const char *folder, int oflag, mode_t mode, symlinks = obex_get_symlinks(os); if (root && symlinks) - ret = stat(folder, &dstat); + ret = stat(name, &dstat); else { object = g_string_append(object, FL_PARENT_FOLDER_ELEMENT); - ret = lstat(folder, &dstat); + ret = lstat(name, &dstat); } if (ret < 0) { @@ -347,20 +348,20 @@ static gpointer folder_open(const char *folder, int oflag, mode_t mode, } while ((ep = readdir(dp))) { - gchar *name; + gchar *filename; gchar *fullname; gchar *line; if (ep->d_name[0] == '.') continue; - name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL); + filename = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL); if (name == NULL) { error("g_filename_to_utf8: invalid filename"); continue; } - fullname = g_build_filename(folder, ep->d_name, NULL); + fullname = g_build_filename(name, ep->d_name, NULL); if (root && symlinks) ret = stat(fullname, &fstat); @@ -370,20 +371,20 @@ static gpointer folder_open(const char *folder, int oflag, mode_t mode, if (ret < 0) { debug("%s: %s(%d)", root ? "stat" : "lstat", strerror(errno), errno); - g_free(name); + g_free(filename); g_free(fullname); continue; } g_free(fullname); - line = file_stat_line(name, &fstat, &dstat, root, pcsuite); + line = file_stat_line(filename, &fstat, &dstat, root, pcsuite); if (line == NULL) { - g_free(name); + g_free(filename); continue; } - g_free(name); + g_free(filename); object = g_string_append(object, line); g_free(line); diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c index cbb3db28f..7b70ed095 100644 --- a/obexd/plugins/ftp.c +++ b/obexd/plugins/ftp.c @@ -165,10 +165,10 @@ static gint get_by_type(struct ftp_session *ftp, const gchar *type) return -ENOENT; if (g_str_equal(type, CAP_TYPE)) - return obex_stream_start(os, capability); + return obex_stream_start(os, capability, NULL); if (g_str_equal(type, LST_TYPE)) - return obex_stream_start(os, ftp->folder); + return obex_stream_start(os, ftp->folder, os); return -ENOENT; } @@ -195,7 +195,7 @@ static gint ftp_prepare_get(struct ftp_session *ftp, gchar *file) return -EPERM; } - return obex_stream_start(os, file); + return obex_stream_start(os, file, NULL); } static gpointer ftp_connect(struct obex_session *os, int *err) diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c index f9448d188..a28b0e97b 100644 --- a/obexd/plugins/opp.c +++ b/obexd/plugins/opp.c @@ -177,7 +177,7 @@ static int opp_get(struct obex_session *os, obex_object_t *obj, return -EPERM; if (g_str_equal(type, VCARD_TYPE)) { - if (obex_stream_start(os, VCARD_FILE) < 0) + if (obex_stream_start(os, VCARD_FILE, NULL) < 0) return -ENOENT; } else diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c index 579995efb..95dbc1454 100644 --- a/obexd/plugins/pbap.c +++ b/obexd/plugins/pbap.c @@ -78,11 +78,6 @@ #define APPARAM_HDR_SIZE 2 -#define get_be64(val) GUINT64_FROM_BE(bt_get_unaligned((guint64 *) val)) -#define get_be16(val) GUINT16_FROM_BE(bt_get_unaligned((guint16 *) val)) - -#define put_be16(val, ptr) bt_put_unaligned(GUINT16_TO_BE(val), (guint16 *) ptr) - #define PBAP_CHANNEL 15 #define PBAP_RECORD " \ @@ -126,21 +121,17 @@ \ " -struct apparam_hdr { +struct aparam_header { uint8_t tag; uint8_t len; uint8_t val[0]; } __attribute__ ((packed)); -struct phonebook_query { - const char *type; - GString *buffer; - struct obex_session *os; -}; - struct pbap_session { struct obex_session *os; + struct apparam_field *params; gchar *folder; + GString *buffer; }; static const guint8 PBAP_TARGET[TARGET_SIZE] = { @@ -154,6 +145,81 @@ static void set_folder(struct pbap_session *pbap, const char *new_folder) pbap->folder = new_folder ? g_strdup(new_folder) : NULL; } +static struct apparam_field *parse_aparam(const guint8 *buffer, guint32 hlen) +{ + struct apparam_field *param; + struct aparam_header *hdr; + guint32 len = 0; + guint16 val16; + guint64 val64; + + param = g_new0(struct apparam_field, 1); + + while (len < hlen) { + hdr = (void *) buffer + len; + + switch (hdr->tag) { + case ORDER_TAG: + if (hdr->len != ORDER_LEN) + goto failed; + + param->order = hdr->val[0]; + break; + + case SEARCHATTRIB_TAG: + if (hdr->len != SEARCHATTRIB_LEN) + goto failed; + + param->searchattrib = hdr->val[0]; + break; + case SEARCHVALUE_TAG: + param->searchval = g_try_malloc0(hdr->len + 1); + if (param->searchval) + memcpy(param->searchval, hdr->val, hdr->len); + break; + case FILTER_TAG: + if (hdr->len != FILTER_LEN) + goto failed; + + memcpy(&val64, hdr->val, sizeof(val64)); + param->filter = GUINT64_FROM_BE(val64); + + break; + case FORMAT_TAG: + if (hdr->len != FORMAT_LEN) + goto failed; + + param->format = hdr->val[0]; + break; + case MAXLISTCOUNT_TAG: + if (hdr->len != MAXLISTCOUNT_LEN) + goto failed; + + memcpy(&val16, hdr->val, sizeof(val16)); + param->maxlistcount = GUINT16_FROM_BE(val16); + break; + case LISTSTARTOFFSET_TAG: + if (hdr->len != LISTSTARTOFFSET_LEN) + goto failed; + + memcpy(&val16, hdr->val, sizeof(val16)); + param->liststartoffset = GUINT16_FROM_BE(val16); + break; + default: + goto failed; + } + + len += hdr->len + sizeof(struct aparam_header); + } + + return param; + +failed: + g_free(param); + + return NULL; +} + static gpointer pbap_connect(struct obex_session *os, int *err) { struct pbap_session *pbap; @@ -176,7 +242,10 @@ static int pbap_get(struct obex_session *os, obex_object_t *obj, struct pbap_session *pbap = user_data; const gchar *type = obex_get_type(os); const gchar *name = obex_get_name(os); + struct apparam_field *params; + const guint8 *buffer; gchar *path; + ssize_t rsize; gint ret; if (type == NULL) @@ -200,7 +269,27 @@ static int pbap_get(struct obex_session *os, obex_object_t *obj, else return -EBADR; - ret = obex_stream_start(os, path); + rsize = obex_aparam_read(os, obj, &buffer); + if (rsize < 0) { + ret = -EBADR; + goto failed; + } + + params = parse_aparam(buffer, rsize); + if (params == NULL) { + ret = -EBADR; + goto failed; + } + + if (pbap->params) { + g_free(pbap->params->searchval); + g_free(pbap->params); + } + + pbap->params = params; + ret = obex_stream_start(os, path, pbap); + +failed: g_free(path); return ret; @@ -246,6 +335,11 @@ static void pbap_disconnect(struct obex_session *os, manager_unregister_session(os); + if (pbap->params) { + g_free(pbap->params->searchval); + g_free(pbap->params); + } + g_free(pbap->folder); g_free(pbap); } @@ -274,67 +368,61 @@ struct obex_service_driver pbap = { static void query_result(const gchar *buffer, size_t bufsize, gint vcards, gint missed, gpointer user_data) { - struct phonebook_query *query = user_data; + struct pbap_session *pbap = user_data; - if (!query->buffer) - query->buffer = g_string_new_len(buffer, bufsize); + if (!pbap->buffer) + pbap->buffer = g_string_new_len(buffer, bufsize); else - query->buffer = g_string_append_len(query->buffer, buffer, bufsize); + pbap->buffer = g_string_append_len(pbap->buffer, buffer, bufsize); - obex_object_set_io_flags(query, G_IO_IN, 0); + obex_object_set_io_flags(pbap, G_IO_IN, 0); } static gpointer vobject_open(const char *name, int oflag, mode_t mode, - size_t *size, struct obex_session *os, int *err) + gpointer context, size_t *size, int *err) { - const gchar *type = obex_get_type(os); - struct phonebook_query *query; + struct pbap_session *pbap = context; + int ret; - if (oflag != O_RDONLY) + if (oflag != O_RDONLY) { + ret = -EPERM; goto fail; + } - /* TODO: mch? */ - - /* TODO: get application parameter */ - query = g_new0(struct phonebook_query, 1); - query->type = type; - query->os = os; - - if (phonebook_query(name, query_result, query) < 0) { - g_free(query); + ret = phonebook_pull(name, pbap->params, query_result, pbap); + if (ret < 0) goto fail; - } if (size) *size = OBJECT_SIZE_UNKNOWN; - return query; + return pbap; fail: if (err) - *err = -EPERM; + *err = ret; return NULL; } static ssize_t vobject_read(gpointer object, void *buf, size_t count) { - struct phonebook_query *query = object; + struct pbap_session *pbap = object; - if (query->buffer) - return string_read(query->buffer, buf, count); + if (pbap->buffer) + return string_read(pbap->buffer, buf, count); return -EAGAIN; } static int vobject_close(gpointer object) { - struct phonebook_query *query = object; + struct pbap_session *pbap = object; - if (query->buffer) - string_free(query->buffer); - - g_free(query); + if (pbap->buffer) { + string_free(pbap->buffer); + pbap->buffer = NULL; + } return 0; } diff --git a/obexd/plugins/phonebook-dummy.c b/obexd/plugins/phonebook-dummy.c index 3915f8781..8bff79dd4 100644 --- a/obexd/plugins/phonebook-dummy.c +++ b/obexd/plugins/phonebook-dummy.c @@ -43,6 +43,7 @@ struct dummy_data { phonebook_cb cb; gpointer user_data; + const struct apparam_field *apparams; }; int phonebook_init(void) @@ -69,13 +70,15 @@ int phonebook_set_folder(const gchar *current_folder, return 0; } -int phonebook_query(const gchar *name, phonebook_cb cb, gpointer user_data) +int phonebook_pull(const gchar *name, const struct apparam_field *params, + phonebook_cb cb, gpointer user_data) { struct dummy_data *dummy; dummy = g_new0(struct dummy_data, 1); dummy->cb = cb; dummy->user_data = user_data; + dummy->apparams = params; g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, dummy_result, dummy, g_free); diff --git a/obexd/plugins/phonebook-ebook.c b/obexd/plugins/phonebook-ebook.c index 66e2462b9..f47d3fdea 100644 --- a/obexd/plugins/phonebook-ebook.c +++ b/obexd/plugins/phonebook-ebook.c @@ -53,6 +53,7 @@ #define QUERY_PHONE "(contains \"phone\" \"%s\")" struct query_data { + const struct apparam_field *params; phonebook_cb cb; gpointer user_data; }; @@ -161,7 +162,8 @@ int phonebook_set_folder(const gchar *current_folder, return ret; } -gint phonebook_query(const gchar *name, phonebook_cb cb, gpointer user_data) +gint phonebook_pull(const gchar *name, const struct apparam_field *params, + phonebook_cb cb, gpointer user_data) { struct query_data *data; EBookQuery *query; @@ -170,6 +172,7 @@ gint phonebook_query(const gchar *name, phonebook_cb cb, gpointer user_data) data = g_new0(struct query_data, 1); data->cb = cb; + data->params = params; data->user_data = user_data; e_book_async_get_contacts(ebook, query, ebookpull_cb, data); diff --git a/obexd/plugins/phonebook.h b/obexd/plugins/phonebook.h index b5bc10ec3..9eaf09511 100644 --- a/obexd/plugins/phonebook.h +++ b/obexd/plugins/phonebook.h @@ -22,10 +22,15 @@ */ struct apparam_field { - guint64 filter; + /* list and pull attributes */ guint16 maxlistcount; guint16 liststartoffset; + + /* pull and vcard attributes */ + guint64 filter; guint8 format; + + /* list attributes only */ guint8 order; guint8 searchattrib; guint8 *searchval; @@ -40,4 +45,5 @@ void phonebook_exit(void); int phonebook_set_folder(const gchar *current_folder, const gchar *new_folder, guint8 flags); -int phonebook_query(const gchar *name, phonebook_cb cb, gpointer user_data); +int phonebook_pull(const gchar *name, const struct apparam_field *params, + phonebook_cb cb, gpointer user_data); diff --git a/obexd/plugins/syncevolution.c b/obexd/plugins/syncevolution.c index a352ede4d..411cdf280 100644 --- a/obexd/plugins/syncevolution.c +++ b/obexd/plugins/syncevolution.c @@ -230,7 +230,7 @@ static int synce_put(struct obex_session *os, gpointer user_data) static int synce_get(struct obex_session *os, obex_object_t *obj, gpointer user_data) { - return 0; + return obex_stream_start(os, NULL, os); } static void close_cb(DBusPendingCall *call, void *user_data) @@ -255,8 +255,9 @@ static void synce_disconnect(struct obex_session *os, gpointer user_data) } static gpointer synce_open(const char *name, int oflag, mode_t mode, - size_t *size, struct obex_session *os, int *err) + gpointer user_data, size_t *size, int *err) { + struct obex_session *os = user_data; DBusConnection *conn; struct synce_context *context; diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h index 69059cfe9..248b1b4f8 100644 --- a/obexd/src/mimetype.h +++ b/obexd/src/mimetype.h @@ -27,8 +27,9 @@ typedef gboolean (*obex_object_io_func) (gpointer object, int flags, int err, struct obex_mime_type_driver { const guint8 *target; const char *mimetype; + gpointer context; gpointer (*open) (const char *name, int oflag, mode_t mode, - size_t *size, struct obex_session *os, int *err); + gpointer context, size_t *size, int *err); int (*close) (gpointer object); ssize_t (*read) (gpointer object, void *buf, size_t count); ssize_t (*write) (gpointer object, const void *buf, size_t count); diff --git a/obexd/src/obex.c b/obexd/src/obex.c index 59e30e063..717b2644f 100644 --- a/obexd/src/obex.c +++ b/obexd/src/obex.c @@ -456,18 +456,20 @@ static void cmd_setpath(struct obex_session *os, os_set_response(obj, err); } -int obex_stream_start(struct obex_session *os, const gchar *filename) +int obex_stream_start(struct obex_session *os, + const gchar *filename, gpointer context) { gint err; gpointer object; size_t size; - object = os->driver->open(filename, O_RDONLY, 0, &size, os, &err); + object = os->driver->open(filename, O_RDONLY, 0, context, &size, &err); if (object == NULL) { error("open(%s): %s (%d)", filename, strerror(-err), -err); goto fail; } + os->driver->context = context; os->object = object; os->offset = 0; os->size = size; @@ -480,6 +482,7 @@ int obex_stream_start(struct obex_session *os, const gchar *filename) fail: if (object) os->driver->close(object); + return err; } @@ -544,9 +547,10 @@ gint obex_prepare_put(struct obex_session *os, const gchar *filename) gint len; int err; - os->object = os->driver->open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600, + os->object = os->driver->open(filename, O_WRONLY | O_CREAT | O_TRUNC, + 0600, os->driver->context, os->size != OBJECT_SIZE_UNKNOWN ? - (size_t *) &os->size : NULL, os, &err); + (size_t *) &os->size : NULL, &err); if (os->object == NULL) { error("open(%s): %s (%d)", filename, strerror(-err), -err); return -EPERM; @@ -1170,3 +1174,22 @@ char *obex_get_id(struct obex_session *os) return g_strdup_printf("%s+%d", address, channel); } + +ssize_t obex_aparam_read(struct obex_session *os, + obex_object_t *obj, const guint8 **buffer) +{ + obex_headerdata_t hd; + guint8 hi; + guint32 hlen; + + OBEX_ObjectReParseHeaders(os->obex, obj); + + while (OBEX_ObjectGetNextHeader(os->obex, obj, &hi, &hd, &hlen)) { + if (hi == OBEX_HDR_APPARAM) { + *buffer = hd.bs; + return hlen; + } + } + + return -EBADR; +} diff --git a/obexd/src/obex.h b/obexd/src/obex.h index 7a8942a4a..f1a4f077b 100644 --- a/obexd/src/obex.h +++ b/obexd/src/obex.h @@ -42,7 +42,8 @@ struct obex_session; void obex_connect_cb(GIOChannel *io, GError *err, gpointer user_data); -int obex_stream_start(struct obex_session *os, const gchar *filename); +int obex_stream_start(struct obex_session *os, + const gchar *filename, gpointer user_data); gint obex_prepare_put(struct obex_session *os, const gchar *filename); const char *obex_get_name(struct obex_session *os); ssize_t obex_get_size(struct obex_session *os); @@ -54,6 +55,8 @@ const char *obex_get_capability_path(struct obex_session *os); gboolean obex_get_auto_accept(struct obex_session *os); 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 tty_init(gint service, const gchar *folder, const gchar *capability, gboolean symlinks, const gchar *devnode); -- 2.47.3