From 67e2aa650792d03249063ce45bb12f2cab7e0cc2 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 3 Nov 2009 11:05:00 -0300 Subject: [PATCH] obexd: Introduce service drivers and move command code from core to plugins. Service driver should make possible to implement any service outside of the core mantaining it lean. --- obexd/plugins/ebook.c | 742 ++++++++++++++++++++++++++++------- obexd/plugins/filesystem.c | 3 +- obexd/plugins/ftp.c | 476 ++++++++++++++++++++++ obexd/{src => plugins}/opp.c | 81 +++- obexd/src/bluetooth.c | 35 +- obexd/src/bluetooth.h | 3 +- obexd/src/ftp.c | 345 ---------------- obexd/src/main.c | 21 +- obexd/src/manager.c | 246 ++---------- obexd/src/obex.c | 129 ++---- obexd/src/obex.h | 38 +- obexd/src/pbap.c | 528 ------------------------- obexd/src/phonebook.c | 171 -------- obexd/src/phonebook.h | 86 ---- obexd/src/service.c | 106 +++++ obexd/src/service.h | 40 ++ 16 files changed, 1417 insertions(+), 1633 deletions(-) create mode 100644 obexd/plugins/ftp.c rename obexd/{src => plugins}/opp.c (58%) delete mode 100644 obexd/src/ftp.c delete mode 100644 obexd/src/pbap.c delete mode 100644 obexd/src/phonebook.c delete mode 100644 obexd/src/phonebook.h create mode 100644 obexd/src/service.c create mode 100644 obexd/src/service.h diff --git a/obexd/plugins/ebook.c b/obexd/plugins/ebook.c index 9faecabba..a5b43c8df 100644 --- a/obexd/plugins/ebook.c +++ b/obexd/plugins/ebook.c @@ -27,13 +27,47 @@ #endif #include +#include +#include +#include -#include -#include -#include +#include +#include #include +#include "plugin.h" +#include "logging.h" +#include "obex.h" +#include "service.h" + +#define PHONEBOOK_TYPE "x-bt/phonebook" +#define VCARDLISTING_TYPE "x-bt/vcard-listing" +#define VCARDENTRY_TYPE "x-bt/vcard" + +#define ORDER_TAG 0x01 +#define SEARCHVALUE_TAG 0x02 +#define SEARCHATTRIB_TAG 0x03 +#define MAXLISTCOUNT_TAG 0x04 +#define LISTSTARTOFFSET_TAG 0x05 +#define FILTER_TAG 0x06 +#define FORMAT_TAG 0X07 +#define PHONEBOOKSIZE_TAG 0X08 +#define NEWMISSEDCALLS_TAG 0X09 + +/* The following length is in the unit of byte */ +#define ORDER_LEN 1 +#define SEARCHATTRIB_LEN 1 +#define MAXLISTCOUNT_LEN 2 +#define LISTSTARTOFFSET_LEN 2 +#define FILTER_LEN 8 +#define FORMAT_LEN 1 +#define PHONEBOOKSIZE_LEN 2 +#define NEWMISSEDCALLS_LEN 1 + +#define MCH "telecom/mch.vcf" +#define SIM1_MCH "SIM1/telecom/mch.vcf" + #define DEFAULT_COUNT 65535 #define EOL_CHARS "\n" @@ -47,15 +81,82 @@ #define QUERY_GIVEN_NAME "(contains \"given_name\" \"%s\")" #define QUERY_PHONE "(contains \"phone\" \"%s\")" +#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 " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +" + +struct apparam_hdr { + uint8_t tag; + uint8_t len; + uint8_t val[0]; +} __attribute__ ((packed)); + +struct apparam_field { + guint64 filter; + guint16 maxlistcount; + guint16 liststartoffset; + guint8 format; + guint8 order; + guint8 searchattrib; + guint8 *searchval; +}; + struct phonebook_data { - struct phonebook_context *context; - guint64 filter; - guint8 format; - guint16 maxlistcount; - guint16 liststartoffset; - guint16 index; + obex_t *obex; + obex_object_t *obj; + struct apparam_field params; }; +static const guint8 PBAP_TARGET[TARGET_SIZE] = { + 0x79, 0x61, 0x35, 0xF0, 0xF0, 0xC5, 0x11, 0xD8, + 0x09, 0x66, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66 }; + static char *vcard_attribs[29] = { EVC_VERSION, EVC_FN, EVC_N, EVC_PHOTO, EVC_BDAY, EVC_ADR, EVC_LABEL, EVC_TEL, EVC_EMAIL, EVC_MAILER, NULL, EVC_GEO, @@ -64,37 +165,23 @@ static char *vcard_attribs[29] = { EVC_VERSION, EVC_FN, EVC_N, EVC_PHOTO, EVC_UID, EVC_KEY, EVC_NICKNAME, EVC_CATEGORIES, EVC_PRODID, NULL, NULL, NULL }; -static int ebook_create(struct phonebook_context *context) -{ - DBG("context %p", context); - - return 0; -} - -static void ebook_destroy(struct phonebook_context *context) -{ - DBG("context %p", context); -} - static void ebookpull_cb(EBook *book, EBookStatus status, GList *list, gpointer user_data) { struct phonebook_data *pb_data = user_data; - struct phonebook_context *context = pb_data->context; - guint64 filter = pb_data->filter; - guint8 format = pb_data->format; - guint16 liststartoffset = pb_data->liststartoffset, offset = 0; - guint16 maxlistcount = pb_data->maxlistcount, count = 0; + struct apparam_field *params = &pb_data->params; + struct obex_session *session = OBEX_GetUserData(pb_data->obex); + guint16 offset = 0, count = 0; GList *contacts = list; GString *pb; gchar *result; - gint32 str_len; + gint32 size; pb = g_string_new(NULL); /* Mandatory attributes for vCard 3.0 are VERSION, N, FN and TEL */ - if (filter != 0 && format == EVC_FORMAT_VCARD_30) - filter = filter | 0x87; + if (params->filter != 0 && params->format == EVC_FORMAT_VCARD_30) + params->filter |= 0x87; for (; contacts != NULL; contacts = g_list_next(contacts)) { EContact *contact = NULL; @@ -102,12 +189,12 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *list, GList *attrib_list = NULL, *l; char *vcard; - if (offset < liststartoffset) { + if (offset < params->liststartoffset) { offset++; continue; } - if (count < maxlistcount) + if (count < params->maxlistcount) count++; else break; @@ -116,8 +203,8 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *list, evcard = E_VCARD(contact); attrib_list = e_vcard_get_attributes(evcard); - if (!filter) { - vcard = e_vcard_to_string(evcard, format); + if (!params->filter) { + vcard = e_vcard_to_string(evcard, params->format); goto done; } @@ -131,7 +218,7 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *list, int mask; mask = 1 << i; - if (!(filter & mask)) + if (!(params->filter & mask)) continue; if (g_strcmp0(vcard_attribs[i], attrib_name)) continue; @@ -142,7 +229,7 @@ static void ebookpull_cb(EBook *book, EBookStatus status, GList *list, break; } } - vcard = e_vcard_to_string(evcard_filtered, format); + vcard = e_vcard_to_string(evcard_filtered, params->format); g_object_unref(evcard_filtered); done: g_string_append_printf(pb, "%s\n", vcard); @@ -150,47 +237,38 @@ done: g_string_append_printf(pb, "%s\n", vcard); } result = g_string_free(pb, FALSE); - str_len = strlen(result); - phonebook_return(context, result, str_len); + size = strlen(result); + + if (size != 0) { + session->buf = g_realloc(session->buf, session->size + size); + memcpy(session->buf + session->size, result, size); + session->size += size; + } - if (str_len != 0) - phonebook_return(context, NULL, 0); + session->finished = 1; + OBEX_ResumeRequest(session->obex); g_free(result); g_free(pb_data); - phonebook_unref(context); g_object_unref(book); } -static int ebook_pullphonebook(struct phonebook_context *context, - gchar *objname, guint64 filter, guint8 format, - guint16 maxlistcount, guint16 liststartoffset, - guint16 *phonebooksize, guint8 *newmissedcalls) +static int ebook_pullphonebook(obex_t *obex, obex_object_t *obj, + struct apparam_field params) { struct phonebook_data *pb_data; EBook *book; EBookQuery *query; - DBG("context %p", context); - - if (maxlistcount == 0) { - *phonebooksize = DEFAULT_COUNT; - return 0; - } - - if (format != EVC_FORMAT_VCARD_30) { + if (params.format != EVC_FORMAT_VCARD_30) { DBG("libebook does not support e_vcard_to_string_vcard_21()"); return -1; } - phonebook_ref(context); - pb_data = g_new0(struct phonebook_data, 1); - pb_data->context = context; - pb_data->filter = filter; - pb_data->format = format; - pb_data->maxlistcount = maxlistcount; - pb_data->liststartoffset = liststartoffset; + pb_data->obex = obex; + pb_data->obj = obj; + pb_data->params = params; book = e_book_new_default_addressbook(NULL); @@ -202,6 +280,8 @@ static int ebook_pullphonebook(struct phonebook_context *context, e_book_query_unref(query); + OBEX_SuspendRequest(obex, obj); + return 0; } @@ -209,13 +289,13 @@ static void ebooklist_cb(EBook *book, EBookStatus status, GList *list, gpointer user_data) { struct phonebook_data *pb_data = user_data; - struct phonebook_context *context = pb_data->context; - guint16 liststartoffset = pb_data->liststartoffset, offset = 0; - guint16 maxlistcount = pb_data->maxlistcount, count = 0; + struct apparam_field *params = &pb_data->params; + struct obex_session *session = OBEX_GetUserData(pb_data->obex); + guint16 offset = 0, count = 0; GString *listing; GList *contacts = list; gchar *result; - gint32 str_len; + gint32 size; listing = g_string_new(VL_VERSION); listing = g_string_append(listing, VL_TYPE); @@ -228,12 +308,12 @@ static void ebooklist_cb(EBook *book, EBookStatus status, GList *list, GList *name_values = NULL; gchar *name = NULL, *name_part = NULL, *element = NULL; - if (offset < liststartoffset) { + if (offset < params->liststartoffset) { offset++; continue; } - if (count < maxlistcount) + if (count < params->maxlistcount) count++; else break; @@ -267,23 +347,24 @@ static void ebooklist_cb(EBook *book, EBookStatus status, GList *list, listing = g_string_append(listing, VL_BODY_END); result = g_string_free(listing, FALSE); - str_len = strlen(result); - phonebook_return(context, result, str_len); + size = strlen(result); + + if (size != 0) { + session->buf = g_realloc(session->buf, session->size + size); + memcpy(session->buf + session->size, result, size); + session->size += size; + } - if (str_len != 0) - phonebook_return(context, NULL, 0); + session->finished = 1; + OBEX_ResumeRequest(session->obex); g_free(result); g_free(pb_data); - phonebook_unref(context); g_object_unref(book); } -static int ebook_pullvcardlisting(struct phonebook_context *context, - gchar *objname, guint8 order, guint8 *searchval, - guint8 searchattrib, guint16 maxlistcount, - guint16 liststartoffset, guint16 *phonebooksize, - guint8 *newmissedcalls) +static int ebook_pullvcardlisting(obex_t *obex, obex_object_t *obj, + struct apparam_field params) { struct phonebook_data *pb_data; EBook *book; @@ -291,25 +372,10 @@ static int ebook_pullvcardlisting(struct phonebook_context *context, gchar *str1 = NULL, *str2 = NULL; gchar **value_list = NULL; - DBG("context %p", context); - - if (maxlistcount == 0) { - *phonebooksize = DEFAULT_COUNT; - return 0; - } - - /* libebook does not support sound attribute */ - if (searchattrib >= 2) { - DBG("libebook does not support sound attribute"); - return -1; - } - - phonebook_ref(context); - pb_data = g_new0(struct phonebook_data, 1); - pb_data->context = context; - pb_data->maxlistcount = maxlistcount; - pb_data->liststartoffset = liststartoffset; + pb_data->obex = obex; + pb_data->obj = obj; + pb_data->params = params; book = e_book_new_default_addressbook(NULL); @@ -317,13 +383,13 @@ static int ebook_pullvcardlisting(struct phonebook_context *context, /* All the vCards shall be returned if SearchValue header is * not specified */ - if (!searchval || !strlen((char *)searchval)) { + if (!params.searchval || !strlen((char *) params.searchval)) { query = e_book_query_any_field_contains(""); goto done; } - if (searchattrib == 0) { - value_list = g_strsplit((gchar *)searchval, ";", 5); + if (params.searchattrib == 0) { + value_list = g_strsplit((gchar *) params.searchval, ";", 5); if (value_list[0]) str1 = g_strdup_printf(QUERY_FAMILY_NAME, @@ -340,8 +406,8 @@ static int ebook_pullvcardlisting(struct phonebook_context *context, else query = query1; } else { - str1 = g_strdup_printf(QUERY_PHONE, searchval); - query = e_book_query_from_string((const char *)searchval); + str1 = g_strdup_printf(QUERY_PHONE, params.searchval); + query = e_book_query_from_string((char *) params.searchval); } done: @@ -356,6 +422,8 @@ done: e_book_query_unref(query); g_strfreev(value_list); + OBEX_SuspendRequest(obex, obj); + return 0; } @@ -363,18 +431,19 @@ static void ebookpullentry_cb(EBook *book, EBookStatus status, GList *list, gpointer user_data) { struct phonebook_data *pb_data = user_data; - struct phonebook_context *context = pb_data->context; - guint64 filter = pb_data->filter; - guint8 format = pb_data->format; - guint16 index = pb_data->index, i = 0; + struct apparam_field *params = &pb_data->params; + struct obex_session *session = OBEX_GetUserData(pb_data->obex); + guint16 i = 0, index; GList *contacts = list, *attrib_list = NULL, *l; EContact *contact = NULL; EVCard *evcard = NULL, *evcard_filtered = NULL; - gint32 str_len = 0; + gint32 size = 0; char *vcard = NULL; - if (filter != 0 && format == EVC_FORMAT_VCARD_30) - filter = filter | 0x87; + if (params->filter != 0 && params->format == EVC_FORMAT_VCARD_30) + params->filter |= 0x87; + + sscanf(session->name, "%hu.vcf", &index); for (; contacts != NULL; contacts = g_list_next(contacts)) { if (i < index) { @@ -385,8 +454,8 @@ static void ebookpullentry_cb(EBook *book, EBookStatus status, GList *list, contact = E_CONTACT(contacts->data); evcard = E_VCARD(contact); - if (!filter) { - vcard = e_vcard_to_string(evcard, format); + if (!params->filter) { + vcard = e_vcard_to_string(evcard, params->format); break; } @@ -400,7 +469,7 @@ static void ebookpullentry_cb(EBook *book, EBookStatus status, GList *list, int mask; mask = 1 << i; - if (!(filter & mask)) + if (!(params->filter & mask)) continue; if (g_strcmp0(vcard_attribs[i], attrib_name)) continue; @@ -412,50 +481,42 @@ static void ebookpullentry_cb(EBook *book, EBookStatus status, GList *list, break; } } - vcard = e_vcard_to_string(evcard_filtered, format); + vcard = e_vcard_to_string(evcard_filtered, params->format); g_object_unref(evcard_filtered); break; } - if (vcard) - str_len = strlen(vcard); - - phonebook_return(context, vcard, str_len); + if (vcard) { + size = strlen(vcard); + session->buf = g_realloc(session->buf, session->size + size); + memcpy(session->buf + session->size, vcard, size); + session->size += size; + } - if (str_len != 0) - phonebook_return(context, NULL, 0); + session->finished = 1; + OBEX_ResumeRequest(session->obex); g_free(vcard); g_free(pb_data); - phonebook_unref(context); g_object_unref(book); } -static int ebook_pullvcardentry(struct phonebook_context *context, - gchar *objname, guint64 filter, guint8 format) +static int ebook_pullvcardentry(obex_t *obex, obex_object_t *obj, + struct apparam_field params) { struct phonebook_data *pb_data; EBook *book; EBookQuery *query; - gint index; - gchar *ptr = NULL; - - DBG("context %p", context); - if (format != EVC_FORMAT_VCARD_30) { + if (params.format != EVC_FORMAT_VCARD_30) { DBG("libebook does not support e_vcard_to_string_vcard_21()"); return -1; } - phonebook_ref(context); - - ptr = g_strrstr(objname, "/"); - sscanf(ptr, "/%d.vcf", &index); pb_data = g_new0(struct phonebook_data, 1); - pb_data->context = context; - pb_data->filter = filter; - pb_data->format = format; - pb_data->index = index; + pb_data->obex = obex; + pb_data->obj = obj; + pb_data->params = params; book = e_book_new_default_addressbook(NULL); @@ -465,26 +526,427 @@ static int ebook_pullvcardentry(struct phonebook_context *context, e_book_async_get_contacts(book, query, ebookpullentry_cb, pb_data); + OBEX_SuspendRequest(obex, obj); + return 0; } -static struct phonebook_driver ebook_driver = { - .name = "ebook", - .create = ebook_create, - .destroy = ebook_destroy, - .pullphonebook = ebook_pullphonebook, - .pullvcardlisting = ebook_pullvcardlisting, - .pullvcardentry = ebook_pullvcardentry, +static int pbap_parse_apparam_header(obex_t *obex, obex_object_t *obj, + struct apparam_field *apparam) +{ + obex_headerdata_t hd; + guint8 hi; + guint32 hlen; + + while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) { + void *ptr = (void *) hd.bs; + uint32_t len = hlen; + + if (hi != OBEX_HDR_APPARAM) + continue; + + if (hlen < APPARAM_HDR_SIZE) { + g_free(apparam->searchval); + error("PBAP pullphonebook app parameters header" + " is too short: %d", hlen); + return -1; + } + + while (len > APPARAM_HDR_SIZE) { + struct apparam_hdr *hdr = ptr; + + if (hdr->len > len - APPARAM_HDR_SIZE) { + g_free(apparam->searchval); + error("Unexpected PBAP pullphonebook app" + " length, tag %d, len %d", + hdr->tag, hdr->len); + return -1; + } + + switch (hdr->tag) { + case ORDER_TAG: + if (hdr->len == ORDER_LEN) + apparam->order = hdr->val[0]; + break; + case SEARCHATTRIB_TAG: + if (hdr->len == SEARCHATTRIB_LEN) + apparam->searchattrib = hdr->val[0]; + break; + case SEARCHVALUE_TAG: + apparam->searchval = g_try_malloc(hdr->len + 1); + if (apparam->searchval != NULL) { + memcpy(apparam->searchval, hdr->val, + hdr->len); + apparam->searchval[hdr->len] = '\0'; + } + break; + case FILTER_TAG: + if (hdr->len == FILTER_LEN) { + guint64 val; + memcpy(&val, hdr->val, sizeof(val)); + apparam->filter = get_be64(&val); + } + break; + case FORMAT_TAG: + if (hdr->len == FORMAT_LEN) + apparam->format = hdr->val[0]; + break; + case MAXLISTCOUNT_TAG: + if (hdr->len == MAXLISTCOUNT_LEN) { + guint16 val; + memcpy(&val, hdr->val, sizeof(val)); + apparam->maxlistcount = get_be16(&val); + } + break; + case LISTSTARTOFFSET_TAG: + if (hdr->len == LISTSTARTOFFSET_LEN) { + guint16 val; + memcpy(&val, hdr->val, sizeof(val)); + apparam->liststartoffset = get_be16(&val); + } + break; + default: + g_free(apparam->searchval); + error("Unexpected PBAP pullphonebook app" + " parameter, tag %d, len %d", + hdr->tag, hdr->len); + return -1; + } + + ptr += APPARAM_HDR_SIZE + hdr->len; + len -= APPARAM_HDR_SIZE + hdr->len; + } + + /* Ignore multiple app param headers */ + break; + } + + return 0; +} + +/* Add app parameter header, that is sent back to PBAP client */ +static int pbap_add_result_apparam_header(obex_t *obex, obex_object_t *obj, + guint16 maxlistcount, gchar *path_name, + guint16 phonebooksize, + guint8 newmissedcalls, gboolean *addbody) +{ + guint8 rspsize = 0; + gboolean addmissedcalls = FALSE; + obex_headerdata_t hd; + + if (maxlistcount == 0) { + rspsize += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN; + *addbody = FALSE; + } + + if (g_str_equal(path_name, SIM1_MCH) == TRUE || + g_str_equal(path_name, MCH) == TRUE) { + rspsize += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN; + addmissedcalls = TRUE; + } + + if (rspsize > 0) { + void *buf, *ptr; + + buf = g_try_malloc0(rspsize); + if (buf == NULL) + return -ENOMEM; + + ptr = buf; + + if (maxlistcount == 0) { + struct apparam_hdr *hdr = ptr; + guint16 val = GUINT16_TO_BE(phonebooksize); + + hdr->tag = PHONEBOOKSIZE_TAG; + hdr->len = PHONEBOOKSIZE_LEN; + memcpy(hdr->val, &val, sizeof(val)); + + ptr += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN; + } + + if (addmissedcalls == TRUE) { + struct apparam_hdr *hdr = ptr; + + hdr->tag = NEWMISSEDCALLS_TAG; + hdr->len = NEWMISSEDCALLS_LEN; + hdr->val[0] = newmissedcalls; + + ptr += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN; + } + + hd.bs = buf; + OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_APPARAM, + hd, rspsize, 0); + g_free(buf); + } + + return 0; +} + +static int pbap_pullphonebook(obex_t *obex, obex_object_t *obj, + gboolean *addbody) +{ + struct obex_session *session = OBEX_GetUserData(obex); + struct apparam_field params; + guint8 newmissedcalls = 0; + guint16 phonebooksize = 0; + int err; + + memset(¶ms, 0, sizeof(struct apparam_field)); + + err = pbap_parse_apparam_header(obex, obj, ¶ms); + if (err < 0) + return err; + + if (params.maxlistcount == 0) { + phonebooksize = DEFAULT_COUNT; + goto done; + } + + err = ebook_pullphonebook(obex, obj, params); + if (err < 0) + return err; + +done: + return pbap_add_result_apparam_header(obex, obj, params.maxlistcount, + session->name, phonebooksize, + newmissedcalls, addbody); +} + +static int pbap_pullvcardlisting(obex_t *obex, obex_object_t *obj, + gboolean *addbody) +{ + struct obex_session *session = OBEX_GetUserData(obex); + gchar *fullname; + struct apparam_field params; + guint8 newmissedcalls = 0; + guint16 phonebooksize = 0; + int err; + + memset(¶ms, 0, sizeof(struct apparam_field)); + + err = pbap_parse_apparam_header(obex, obj, ¶ms); + if (err < 0) + return err; + + if (params.maxlistcount == 0) { + phonebooksize = DEFAULT_COUNT; + goto proceed; + } + + /* libebook does not support sound attribute */ + if (params.searchattrib >= 2) { + DBG("libebook does not support sound attribute"); + goto done; + } + + err = ebook_pullvcardlisting(obex, obj, params); + if (err < 0) + goto done; + +proceed: + + fullname = g_build_filename(session->current_folder, session->name, + NULL); + if (fullname != NULL) + fullname = g_strconcat(fullname, ".vcf", NULL); + + err = pbap_add_result_apparam_header(obex, obj, params.maxlistcount, + fullname, phonebooksize, + newmissedcalls, addbody); + g_free(fullname); + +done: + g_free(params.searchval); + return err; +} + +static int pbap_pullvcardentry(obex_t *obex, obex_object_t *obj) +{ + struct apparam_field params; + int err; + + memset(¶ms, 0, sizeof(struct apparam_field)); + err = pbap_parse_apparam_header(obex, obj, ¶ms); + if (err < 0) + return err; + + err = ebook_pullvcardentry(obex, obj, params); + + g_free(params.searchval); + return err; +} + +static void pbap_get(obex_t *obex, obex_object_t *obj) +{ + struct obex_session *session = OBEX_GetUserData(obex); + obex_headerdata_t hd; + gboolean addbody = TRUE; + int err; + + if (session == NULL) + return; + + if (session->type == NULL) + goto fail; + + if (g_str_equal(session->type, VCARDLISTING_TYPE) == FALSE + && session->name == NULL) + goto fail; + + OBEX_ObjectReParseHeaders(obex, obj); + + if (g_str_equal(session->type, PHONEBOOK_TYPE) == TRUE) + err = pbap_pullphonebook(obex, obj, &addbody); + else if (g_str_equal(session->type, VCARDLISTING_TYPE) == TRUE) + err = pbap_pullvcardlisting(obex, obj, &addbody); + else if (g_str_equal(session->type, VCARDENTRY_TYPE) == TRUE) + err = pbap_pullvcardentry(obex, obj); + else + goto fail; + + if (err < 0) + goto fail; + + if (addbody == TRUE) { + OBEX_SuspendRequest(obex, obj); + session->size = 0; + + /* Add body header */ + hd.bs = NULL; + OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, + hd, 0, OBEX_FL_STREAM_START); + } + + OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); + + return; + +fail: + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); +} + +static gboolean pbap_is_valid_folder(struct obex_session *session) +{ + if (session->current_folder == NULL) { + if (g_str_equal(session->name, "telecom") == TRUE || + g_str_equal(session->name, "SIM1") == TRUE) + return TRUE; + } else if (g_str_equal(session->current_folder, "SIM1") == TRUE) { + if (g_str_equal(session->name, "telecom") == TRUE) + return TRUE; + } else if (g_str_equal(session->current_folder, "telecom") == TRUE || + g_str_equal(session->current_folder, "SIM1/telecom") == TRUE) { + if (g_str_equal(session->name, "pb") == TRUE || + g_str_equal(session->name, "ich") == TRUE || + g_str_equal(session->name, "och") == TRUE || + g_str_equal(session->name, "mch") == TRUE || + g_str_equal(session->name, "cch") == TRUE) + return TRUE; + } + + return FALSE; +} + +static void pbap_setpath(obex_t *obex, obex_object_t *obj) +{ + struct obex_session *session = OBEX_GetUserData(obex); + guint8 *nonhdr; + gchar *fullname; + + if (OBEX_ObjectGetNonHdrData(obj, &nonhdr) != 2) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, + OBEX_RSP_PRECONDITION_FAILED); + error("Set path failed: flag and constants not found!"); + return; + } + + /* Check "Backup" flag */ + if ((nonhdr[0] & 0x01) == 0x01) { + debug("Set to parent path"); + + if (session->current_folder == NULL) { + /* we are already in top level folder */ + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, + OBEX_RSP_FORBIDDEN); + return; + } + + fullname = g_path_get_dirname(session->current_folder); + g_free(session->current_folder); + + if (strlen(fullname) == 1 && *fullname == '.') + session->current_folder = NULL; + else + session->current_folder = g_strdup(fullname); + + g_free(fullname); + + debug("Set to parent path: %s", session->current_folder); + + OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + return; + } + + if (!session->name) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_BAD_REQUEST); + error("Set path failed: name missing!"); + return; + } + + if (strlen(session->name) == 0) { + debug("Set to root"); + + g_free(session->current_folder); + session->current_folder = NULL; + + OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + return; + } + + /* Check and set to name path */ + if (strstr(session->name, "/")) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + error("Set path failed: name incorrect!"); + return; + } + + if (pbap_is_valid_folder(session) == FALSE) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); + return; + } + + if (session->current_folder == NULL) + fullname = g_build_filename("", session->name, NULL); + else + fullname = g_build_filename(session->current_folder, session->name, NULL); + + debug("Fullname: %s", fullname); + + g_free(session->current_folder); + session->current_folder = fullname; + OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); +} + +struct obex_service_driver driver = { + .name = "Phonebook Access server", + .service = OBEX_PBAP, + .channel = PBAP_CHANNEL, + .record = PBAP_RECORD, + .target = PBAP_TARGET, + .get = pbap_get, + .setpath = pbap_setpath }; static int ebook_init(void) { - return phonebook_driver_register(&ebook_driver); + return obex_service_driver_register(&driver); } static void ebook_exit(void) { - phonebook_driver_unregister(&ebook_driver); + obex_service_driver_unregister(&driver); } OBEX_PLUGIN_DEFINE("ebook", ebook_init, ebook_exit) diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c index e275bf2ad..4a06c989d 100644 --- a/obexd/plugins/filesystem.c +++ b/obexd/plugins/filesystem.c @@ -48,6 +48,7 @@ #include "logging.h" #include "mimetype.h" #include "obex.h" +#include "service.h" #define EOL_CHARS "\n" @@ -266,7 +267,7 @@ static ssize_t folder_read(gpointer object, void *buf, size_t count) if (os->finished) return 0; - pcsuite = os->server->services & OBEX_PCSUITE ? TRUE : FALSE; + pcsuite = os->service->service & OBEX_PCSUITE ? TRUE : FALSE; listing = g_string_new(FL_VERSION); listing = g_string_append(listing, pcsuite ? FL_TYPE_PCSUITE : FL_TYPE); diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c new file mode 100644 index 000000000..82f16f223 --- /dev/null +++ b/obexd/plugins/ftp.c @@ -0,0 +1,476 @@ +/* + * + * OBEX Server + * + * Copyright (C) 2007-2008 Nokia Corporation + * Copyright (C) 2007-2008 Instituto Nokia de Tecnologia (INdT) + * Copyright (C) 2007-2009 Marcel Holtmann + * + * + * 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "plugin.h" +#include "logging.h" +#include "obex.h" +#include "dbus.h" +#include "mimetype.h" +#include "service.h" + +#define LST_TYPE "x-obex/folder-listing" +#define CAP_TYPE "x-obex/capability" + +#define FTP_CHANNEL 10 +#define FTP_RECORD " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +" + +#define PCSUITE_CHANNEL 24 +#define PCSUITE_RECORD " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +" + +static const guint8 FTP_TARGET[TARGET_SIZE] = { + 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2, + 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 }; + +static gint folder_listing(struct obex_session *os, size_t *size) +{ + return os_prepare_get(os, os->current_folder, size); +} + +static gint get_capability(struct obex_session *os, size_t *size) +{ + return os_prepare_get(os, os->server->capability, size); +} + +static gint get_by_type(struct obex_session *os, gchar *type, size_t *size) +{ + if (type == NULL) + return -ENOENT; + + if (g_str_equal(type, CAP_TYPE)) + return get_capability(os, size); + + if (g_str_equal(type, LST_TYPE)) + return folder_listing(os, size); + + return FALSE; +} + +static gint ftp_prepare_get(struct obex_session *os, gchar *file, + size_t *size) +{ + gboolean root; + + root = g_str_equal(os->server->folder, os->current_folder); + + if (!root || !os->server->symlinks) { + struct stat dstat; + gint err; + + if (lstat(file, &dstat) < 0) { + err = -errno; + debug("lstat: %s(%d)", strerror(errno), errno); + return err; + } + + if (S_ISLNK(dstat.st_mode)) + return -EPERM; + } + + return os_prepare_get(os, file, size); +} + +static void ftp_get(obex_t *obex, obex_object_t *obj) +{ + obex_headerdata_t hv; + struct obex_session *os; + size_t size; + gint err; + gchar *path; + + os = OBEX_GetUserData(obex); + if (os == NULL) + return; + + if (os->current_folder == NULL) { + err = -ENOENT; + goto fail; + } + + err = get_by_type(os, os->type, &size); + if (err < 0) { + if (!os->name) + goto fail; + + path = g_build_filename(os->current_folder, os->name, NULL); + + err = ftp_prepare_get(os, path, &size); + + g_free(path); + + if (err < 0) + goto fail; + } + + hv.bq4 = size; + os->size = size; + OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_LENGTH, hv, 4, 0); + + /* Add body header */ + hv.bs = NULL; + if (size == 0) + OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY, + hv, 0, OBEX_FL_FIT_ONE_PACKET); + else + OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY, + hv, 0, OBEX_FL_STREAM_START); + + OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, + OBEX_RSP_SUCCESS); + + return; + +fail: + switch (err) { + case -ENOENT: + OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); + break; + default: + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + } +} + +static gint ftp_delete(struct obex_session *os) +{ + gchar *path; + int ret = 0; + + if (!(os->current_folder && os->name)) + return -EINVAL; + + path = g_build_filename(os->current_folder, os->name, NULL); + + if (os->driver->remove(path) < 0) + ret = -errno; + + g_free(path); + + return ret; +} + +static gint ftp_chkput(obex_t *obex, obex_object_t *obj) +{ + struct obex_session *os; + + os = OBEX_GetUserData(obex); + if (os == NULL) + return -EINVAL; + + if (os->size == OBJECT_SIZE_DELETE) + return 0; + + return os_prepare_put(os); +} + +static void ftp_put(obex_t *obex, obex_object_t *obj) +{ + struct obex_session *os; + int ret = 0; + + os = OBEX_GetUserData(obex); + if (os == NULL) + return; + + if (os->current_folder == NULL) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + return; + } + + if (os->name == NULL) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_BAD_REQUEST, OBEX_RSP_BAD_REQUEST); + return; + } + + if (os->size == OBJECT_SIZE_DELETE) + ret = ftp_delete(os); + + switch (ret) { + case 0: + OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); + break; + case -ENOENT: + OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); + break; + case -ENOTEMPTY: + OBEX_ObjectSetRsp(obj, OBEX_RSP_PRECONDITION_FAILED, + OBEX_RSP_PRECONDITION_FAILED); + break; + default: + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + break; + } +} + +static void ftp_setpath(obex_t *obex, obex_object_t *obj) +{ + struct obex_session *os; + guint8 *nonhdr; + gchar *fullname; + struct stat dstat; + gboolean root; + int err; + + os = OBEX_GetUserData(obex); + + if (OBEX_ObjectGetNonHdrData(obj, &nonhdr) != 2) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, + OBEX_RSP_PRECONDITION_FAILED); + error("Set path failed: flag and constants not found!"); + return; + } + + root = g_str_equal(os->server->folder, os->current_folder); + + /* Check flag "Backup" */ + if ((nonhdr[0] & 0x01) == 0x01) { + debug("Set to parent path"); + + if (root) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + return; + } + + fullname = g_path_get_dirname(os->current_folder); + g_free(os->current_folder); + os->current_folder = g_strdup(fullname); + g_free(fullname); + + debug("Set to parent path: %s", os->current_folder); + + OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + return; + } + + if (!os->name) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_BAD_REQUEST); + debug("Set path failed: name missing!"); + return; + } + + if (strlen(os->name) == 0) { + debug("Set to root"); + g_free(os->current_folder); + os->current_folder = g_strdup(os->server->folder); + + OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + return; + } + + /* Check and set to name path */ + if (strstr(os->name, "/") || strcmp(os->name, "..") == 0) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + error("Set path failed: name incorrect!"); + return; + } + + fullname = g_build_filename(os->current_folder, os->name, NULL); + + debug("Fullname: %s", fullname); + + if (root && os->server->symlinks) + err = stat(fullname, &dstat); + else + err = lstat(fullname, &dstat); + + if (err < 0) { + int err = errno; + debug("%s: %s(%d)", root ? "stat" : "lstat", + strerror(err), err); + if (err == ENOENT) + goto not_found; + + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + goto done; + } + + if (S_ISDIR(dstat.st_mode) && (dstat.st_mode & S_IRUSR) && + (dstat.st_mode & S_IXUSR)) { + g_free(os->current_folder); + os->current_folder = g_strdup(fullname); + OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + goto done; + } + + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + goto done; + +not_found: + if (nonhdr[0] != 0) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); + goto done; + } + + if (mkdir(fullname, 0755) < 0) { + OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); + goto done; + } + + g_free(os->current_folder); + os->current_folder = g_strdup(fullname); + OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + +done: + g_free(fullname); +} + +struct obex_service_driver pcsuite = { + .name = "Nokia OBEX PC Suite Services", + .service = OBEX_PCSUITE, + .channel = PCSUITE_CHANNEL, + .record = PCSUITE_RECORD, + .target = FTP_TARGET, + .get = ftp_get, + .put = ftp_put, + .chkput = ftp_chkput, + .setpath = ftp_setpath +}; + +struct obex_service_driver ftp = { + .name = "File Transfer server", + .service = OBEX_FTP, + .channel = FTP_CHANNEL, + .record = FTP_RECORD, + .target = FTP_TARGET, + .get = ftp_get, + .put = ftp_put, + .chkput = ftp_chkput, + .setpath = ftp_setpath +}; + +static int ftp_init(void) +{ + int err; + + err = obex_service_driver_register(&ftp); + if (err < 0) + return err; + + return obex_service_driver_register(&pcsuite); +} + +static void ftp_exit(void) +{ + obex_service_driver_unregister(&ftp); + obex_service_driver_unregister(&pcsuite); +} + +OBEX_PLUGIN_DEFINE("ftp", ftp_init, ftp_exit) diff --git a/obexd/src/opp.c b/obexd/plugins/opp.c similarity index 58% rename from obexd/src/opp.c rename to obexd/plugins/opp.c index a8dce1361..7d5a73551 100644 --- a/obexd/src/opp.c +++ b/obexd/plugins/opp.c @@ -34,6 +34,8 @@ #include +#include "plugin.h" +#include "service.h" #include "logging.h" #include "obex.h" #include "dbus.h" @@ -41,7 +43,58 @@ #define VCARD_TYPE "text/x-vcard" #define VCARD_FILE CONFIGDIR "/vcard.vcf" -gint opp_chkput(obex_t *obex, obex_object_t *obj) +#define OPP_CHANNEL 9 +#define OPP_RECORD " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +" + +static gint opp_chkput(obex_t *obex, obex_object_t *obj) { struct obex_session *os; gchar *new_folder, *new_name; @@ -82,7 +135,7 @@ skip_auth: return os_prepare_put(os); } -void opp_put(obex_t *obex, obex_object_t *obj) +static void opp_put(obex_t *obex, obex_object_t *obj) { struct obex_session *os; @@ -103,7 +156,7 @@ void opp_put(obex_t *obex, obex_object_t *obj) OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); } -void opp_get(obex_t *obex, obex_object_t *obj) +static void opp_get(obex_t *obex, obex_object_t *obj) { struct obex_session *os; obex_headerdata_t hv; @@ -145,3 +198,25 @@ void opp_get(obex_t *obex, obex_object_t *obj) fail: OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); } + +struct obex_service_driver driver = { + .name = "Object Push server", + .service = OBEX_OPP, + .channel = OPP_CHANNEL, + .record = OPP_RECORD, + .get = opp_get, + .put = opp_put, + .chkput = opp_chkput, +}; + +static int opp_init(void) +{ + return obex_service_driver_register(&driver); +} + +static void opp_exit(void) +{ + obex_service_driver_unregister(&driver); +} + +OBEX_PLUGIN_DEFINE("opp", opp_init, opp_exit) diff --git a/obexd/src/bluetooth.c b/obexd/src/bluetooth.c index 9cf2acfd6..7cbfda14c 100644 --- a/obexd/src/bluetooth.c +++ b/obexd/src/bluetooth.c @@ -48,6 +48,7 @@ #include "obex.h" #include "dbus.h" #include "btio.h" +#include "service.h" #define BT_RX_MTU 32767 #define BT_TX_MTU 32767 @@ -57,6 +58,7 @@ static GSList *servers = NULL; static void confirm_event(GIOChannel *io, gpointer user_data) { struct server *server = user_data; + struct obex_service_driver *driver; GError *err = NULL; char address[18]; guint8 channel; @@ -73,7 +75,9 @@ static void confirm_event(GIOChannel *io, gpointer user_data) info("New connection from: %s, channel %u", address, channel); - if (server->services != OBEX_OPP) { + driver = (struct obex_service_driver *) server->drivers->data; + + if (driver->service != OBEX_OPP) { if (request_service_authorization(server, io, address) < 0) goto drop; @@ -95,18 +99,21 @@ drop: static gint server_start(struct server *server) { GError *err = NULL; + struct obex_service_driver *driver; + + driver = (struct obex_service_driver *) server->drivers->data; /* Listen */ if (server->secure) server->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event, server, NULL, &err, - BT_IO_OPT_CHANNEL, server->channel, + BT_IO_OPT_CHANNEL, driver->channel, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID); else server->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event, server, NULL, &err, - BT_IO_OPT_CHANNEL, server->channel, + BT_IO_OPT_CHANNEL, driver->channel, BT_IO_OPT_INVALID); if (!server->io) goto failed; @@ -137,21 +144,23 @@ static gint server_stop(struct server *server) return 0; } -static gint server_register(guint16 service, const gchar *name, guint8 channel, - const gchar *folder, gboolean secure, - gboolean auto_accept, gboolean symlinks, - const gchar *capability) +static gint server_register(guint16 service, const gchar *folder, + gboolean secure, gboolean auto_accept, + gboolean symlinks, const gchar *capability) { struct server *server; + GSList *drivers; + + drivers = obex_service_driver_list(service); + if (drivers == NULL) + return -EINVAL; server = g_new0(struct server, 1); - server->services = service; - server->name = g_strdup(name); + server->drivers = drivers; server->folder = g_strdup(folder); server->auto_accept = auto_accept; server->symlinks = symlinks; server->capability = g_strdup(capability); - server->channel = channel; server->secure = secure; server->rx_mtu = BT_RX_MTU; server->tx_mtu = BT_TX_MTU; @@ -161,13 +170,11 @@ static gint server_register(guint16 service, const gchar *name, guint8 channel, return 0; } -gint bluetooth_init(guint service, const gchar *name, const gchar *folder, - guint8 channel, gboolean secure, +gint bluetooth_init(guint service, const gchar *folder, gboolean secure, gboolean auto_accept, gboolean symlinks, const gchar *capability) { - return server_register(service, name, channel, folder, - secure, auto_accept, symlinks, + return server_register(service, folder, secure, auto_accept, symlinks, capability); } diff --git a/obexd/src/bluetooth.h b/obexd/src/bluetooth.h index 787117787..2c16bd934 100644 --- a/obexd/src/bluetooth.h +++ b/obexd/src/bluetooth.h @@ -27,8 +27,7 @@ #include #endif -gint bluetooth_init(guint service, const gchar *name, const gchar *folder, - guint8 channel, gboolean secure, +gint bluetooth_init(guint service, const gchar *folder, gboolean secure, gboolean auto_accept, gboolean symlinks, const gchar *capability); void bluetooth_exit(void); diff --git a/obexd/src/ftp.c b/obexd/src/ftp.c deleted file mode 100644 index ffbcf73aa..000000000 --- a/obexd/src/ftp.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * - * OBEX Server - * - * Copyright (C) 2007-2008 Nokia Corporation - * Copyright (C) 2007-2008 Instituto Nokia de Tecnologia (INdT) - * Copyright (C) 2007-2009 Marcel Holtmann - * - * - * 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "logging.h" -#include "obex.h" -#include "dbus.h" -#include "mimetype.h" - -#define LST_TYPE "x-obex/folder-listing" -#define CAP_TYPE "x-obex/capability" - -static gint folder_listing(struct obex_session *os, size_t *size) -{ - return os_prepare_get(os, os->current_folder, size); -} - -static gint get_capability(struct obex_session *os, size_t *size) -{ - return os_prepare_get(os, os->server->capability, size); -} - -static gint get_by_type(struct obex_session *os, gchar *type, size_t *size) -{ - if (type == NULL) - return -ENOENT; - - if (g_str_equal(type, CAP_TYPE)) - return get_capability(os, size); - - if (g_str_equal(type, LST_TYPE)) - return folder_listing(os, size); - - return FALSE; -} - -static gint ftp_prepare_get(struct obex_session *os, gchar *file, - size_t *size) -{ - gboolean root; - - root = g_str_equal(os->server->folder, os->current_folder); - - if (!root || !os->server->symlinks) { - struct stat dstat; - gint err; - - if (lstat(file, &dstat) < 0) { - err = -errno; - debug("lstat: %s(%d)", strerror(errno), errno); - return err; - } - - if (S_ISLNK(dstat.st_mode)) - return -EPERM; - } - - return os_prepare_get(os, file, size); -} - -void ftp_get(obex_t *obex, obex_object_t *obj) -{ - obex_headerdata_t hv; - struct obex_session *os; - size_t size; - gint err; - gchar *path; - - os = OBEX_GetUserData(obex); - if (os == NULL) - return; - - if (os->current_folder == NULL) { - err = -ENOENT; - goto fail; - } - - err = get_by_type(os, os->type, &size); - if (err < 0) { - if (!os->name) - goto fail; - - path = g_build_filename(os->current_folder, os->name, NULL); - - err = ftp_prepare_get(os, path, &size); - - g_free(path); - - if (err < 0) - goto fail; - } - - hv.bq4 = size; - os->size = size; - OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_LENGTH, hv, 4, 0); - - /* Add body header */ - hv.bs = NULL; - if (size == 0) - OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY, - hv, 0, OBEX_FL_FIT_ONE_PACKET); - else - OBEX_ObjectAddHeader (obex, obj, OBEX_HDR_BODY, - hv, 0, OBEX_FL_STREAM_START); - - OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, - OBEX_RSP_SUCCESS); - - return; - -fail: - switch (err) { - case -ENOENT: - OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); - break; - default: - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - } -} - -static gint ftp_delete(struct obex_session *os) -{ - gchar *path; - int ret = 0; - - if (!(os->current_folder && os->name)) - return -EINVAL; - - path = g_build_filename(os->current_folder, os->name, NULL); - - if (os->driver->remove(path) < 0) - ret = -errno; - - g_free(path); - - return ret; -} - -gint ftp_chkput(obex_t *obex, obex_object_t *obj) -{ - struct obex_session *os; - - os = OBEX_GetUserData(obex); - if (os == NULL) - return -EINVAL; - - if (os->size == OBJECT_SIZE_DELETE) - return 0; - - return os_prepare_put(os); -} - -void ftp_put(obex_t *obex, obex_object_t *obj) -{ - struct obex_session *os; - int ret = 0; - - os = OBEX_GetUserData(obex); - if (os == NULL) - return; - - if (os->current_folder == NULL) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - return; - } - - if (os->name == NULL) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_BAD_REQUEST, OBEX_RSP_BAD_REQUEST); - return; - } - - if (os->size == OBJECT_SIZE_DELETE) - ret = ftp_delete(os); - - switch (ret) { - case 0: - OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); - break; - case -ENOENT: - OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); - break; - case -ENOTEMPTY: - OBEX_ObjectSetRsp(obj, OBEX_RSP_PRECONDITION_FAILED, - OBEX_RSP_PRECONDITION_FAILED); - break; - default: - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - break; - } -} - -void ftp_setpath(obex_t *obex, obex_object_t *obj) -{ - struct obex_session *os; - guint8 *nonhdr; - gchar *fullname; - struct stat dstat; - gboolean root; - int err; - - os = OBEX_GetUserData(obex); - - if (OBEX_ObjectGetNonHdrData(obj, &nonhdr) != 2) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, - OBEX_RSP_PRECONDITION_FAILED); - error("Set path failed: flag and constants not found!"); - return; - } - - root = g_str_equal(os->server->folder, os->current_folder); - - /* Check flag "Backup" */ - if ((nonhdr[0] & 0x01) == 0x01) { - debug("Set to parent path"); - - if (root) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - return; - } - - fullname = g_path_get_dirname(os->current_folder); - g_free(os->current_folder); - os->current_folder = g_strdup(fullname); - g_free(fullname); - - debug("Set to parent path: %s", os->current_folder); - - OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); - return; - } - - if (!os->name) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_BAD_REQUEST); - debug("Set path failed: name missing!"); - return; - } - - if (strlen(os->name) == 0) { - debug("Set to root"); - g_free(os->current_folder); - os->current_folder = g_strdup(os->server->folder); - - OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); - return; - } - - /* Check and set to name path */ - if (strstr(os->name, "/") || strcmp(os->name, "..") == 0) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - error("Set path failed: name incorrect!"); - return; - } - - fullname = g_build_filename(os->current_folder, os->name, NULL); - - debug("Fullname: %s", fullname); - - if (root && os->server->symlinks) - err = stat(fullname, &dstat); - else - err = lstat(fullname, &dstat); - - if (err < 0) { - int err = errno; - debug("%s: %s(%d)", root ? "stat" : "lstat", - strerror(err), err); - if (err == ENOENT) - goto not_found; - - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - goto done; - } - - if (S_ISDIR(dstat.st_mode) && (dstat.st_mode & S_IRUSR) && - (dstat.st_mode & S_IXUSR)) { - g_free(os->current_folder); - os->current_folder = g_strdup(fullname); - OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); - goto done; - } - - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - goto done; - -not_found: - if (nonhdr[0] != 0) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); - goto done; - } - - if (mkdir(fullname, 0755) < 0) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - goto done; - } - - g_free(os->current_folder); - os->current_folder = g_strdup(fullname); - OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); - -done: - g_free(fullname); -} diff --git a/obexd/src/main.c b/obexd/src/main.c index abd2bccfb..dcf13d1fa 100644 --- a/obexd/src/main.c +++ b/obexd/src/main.c @@ -49,6 +49,7 @@ #include "bluetooth.h" #include "obexd.h" #include "obex.h" +#include "service.h" #define OPP_CHANNEL 9 #define FTP_CHANNEL 10 @@ -109,7 +110,7 @@ int tty_init(int services, const gchar *root_path, } server = g_new0(struct server, 1); - server->services = services; + server->drivers = obex_service_driver_list(services); server->folder = g_strdup(root_path); server->auto_accept = TRUE; server->capability = g_strdup(capability); @@ -382,28 +383,26 @@ int main(int argc, char *argv[]) if (option_opp == TRUE) { services |= OBEX_OPP; - bluetooth_init(OBEX_OPP, "Object Push server", option_root, - OPP_CHANNEL, FALSE, option_autoaccept, - option_symlinks, NULL); + bluetooth_init(OBEX_OPP, option_root, FALSE, + option_autoaccept, option_symlinks, + NULL); } if (option_ftp == TRUE) { services |= OBEX_FTP; - bluetooth_init(OBEX_FTP, "File Transfer server", option_root, - FTP_CHANNEL, TRUE, option_autoaccept, - option_symlinks, option_capability); + bluetooth_init(OBEX_FTP, option_root, TRUE, + option_autoaccept, option_symlinks, + option_capability); } if (option_pbap == TRUE) { services |= OBEX_PBAP; - bluetooth_init(OBEX_PBAP, "Phonebook Access server", NULL, - PBAP_CHANNEL, TRUE, FALSE, FALSE, NULL); + bluetooth_init(OBEX_PBAP, NULL, TRUE, FALSE, FALSE, NULL); } if (option_pcsuite == TRUE) { services |= OBEX_PCSUITE; - bluetooth_init(OBEX_PCSUITE, "Nokia OBEX PC Suite Services", - option_root, PCSUITE_CHANNEL, TRUE, + bluetooth_init(OBEX_PCSUITE, option_root, TRUE, option_autoaccept, option_symlinks, option_capability); } diff --git a/obexd/src/manager.c b/obexd/src/manager.c index 95b87013b..7ac0eb866 100644 --- a/obexd/src/manager.c +++ b/obexd/src/manager.c @@ -43,178 +43,7 @@ #include "dbus.h" #include "logging.h" #include "btio.h" - -static const gchar *opp_record = " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; - -static const gchar *ftp_record = " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; - -static const gchar *pbap_record = " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; - -static const gchar *pcsuite_record = -" \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; +#include "service.h" #define TRANSFER_INTERFACE OPENOBEX_SERVICE ".Transfer" #define SESSION_INTERFACE OPENOBEX_SERVICE ".Session" @@ -429,6 +258,17 @@ static DBusMessage *unregister_agent(DBusConnection *conn, return dbus_message_new_method_return(msg); } +static char *target2str(const uint8_t *t) +{ + if (!t) + return NULL; + + return g_strdup_printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-" + "%02X%02X-%02X%02X%02X%02X%02X%02X", + t[0], t[1], t[2], t[3], t[4], t[5], t[6],t[7], + t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]); +} + static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -436,9 +276,7 @@ static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; - gchar uuid[37]; - const gchar *ptr = uuid; - const uint8_t *t = os->target; + gchar *uuid; reply = dbus_message_new_method_return(msg); if (!reply) @@ -451,12 +289,11 @@ static DBusMessage *get_properties(DBusConnection *conn, DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Target */ - sprintf(uuid, "%02X%02X%02X%02X-%02X%02X-%02X%02X-" - "%02X%02X-%02X%02X%02X%02X%02X%02X", - t[0], t[1], t[2], t[3], t[4], t[5], t[6],t[7], - t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]); + uuid = target2str(os->service->target); dbus_message_iter_append_dict_entry(&dict, "Target", - DBUS_TYPE_STRING, &ptr); + DBUS_TYPE_STRING, &uuid); + g_free(uuid); + /* Root folder */ dbus_message_iter_append_dict_entry(&dict, "Root", DBUS_TYPE_STRING, &os->server->folder); @@ -515,32 +352,6 @@ static GDBusMethodTable session_methods[] = { { } }; -static gchar *create_xml_record(const char *name, - uint16_t service, uint8_t channel) -{ - gchar *xml; - - switch (service) { - case OBEX_OPP: - xml = g_markup_printf_escaped(opp_record, channel, name); - break; - case OBEX_FTP: - xml = g_markup_printf_escaped(ftp_record, channel, name); - break; - case OBEX_PBAP: - xml = g_markup_printf_escaped(pbap_record, channel, name); - break; - case OBEX_PCSUITE: - xml = g_markup_printf_escaped(pcsuite_record, channel, name); - break; - default: - xml = NULL; - break; - } - - return xml; -} - static void add_record_reply(DBusPendingCall *call, gpointer user_data) { struct server *server = user_data; @@ -555,13 +366,17 @@ static void add_record_reply(DBusPendingCall *call, gpointer user_data) dbus_error_free(&derr); handle = 0; } else { + struct obex_service_driver *driver; + dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID); server->handle = handle; + driver = (struct obex_service_driver *) server->drivers->data; + debug("Registered: %s, handle: 0x%x, folder: %s", - server->name, handle, server->folder); + driver->name, handle, server->folder); } dbus_message_unref(reply); @@ -596,6 +411,7 @@ failed: void register_record(struct server *server, gpointer user_data) { + struct obex_service_driver *driver; gchar *xml; gint ret; @@ -608,7 +424,9 @@ void register_record(struct server *server, gpointer user_data) return; } - xml = create_xml_record(server->name, server->services, server->channel); + driver = (struct obex_service_driver *) server->drivers->data; + xml = g_markup_printf_escaped(driver->record, driver->channel, + driver->name); ret = add_record(any->path, xml, server); g_free(xml); } @@ -616,7 +434,6 @@ void register_record(struct server *server, gpointer user_data) static void find_adapter_any_reply(DBusPendingCall *call, gpointer user_data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct server *server; const char *path; gchar *xml; GSList *l; @@ -637,9 +454,12 @@ static void find_adapter_any_reply(DBusPendingCall *call, gpointer user_data) any->path = g_strdup(path); for (l = any->servers; l; l = l->next) { - server = l->data; - xml = create_xml_record(server->name, - server->services, server->channel); + struct server *server = l->data; + struct obex_service_driver *driver; + + driver = (struct obex_service_driver *) server->drivers->data; + xml = g_markup_printf_escaped(driver->record, driver->channel, + driver->name); add_record(path, xml, server); g_free(xml); } @@ -1207,3 +1027,5 @@ void unregister_session(guint32 id) g_free(path); } + + diff --git a/obexd/src/obex.c b/obexd/src/obex.c index 212c3699a..9c5cec6fc 100644 --- a/obexd/src/obex.c +++ b/obexd/src/obex.c @@ -48,21 +48,12 @@ #include "obex.h" #include "dbus.h" #include "mimetype.h" +#include "service.h" /* Default MTU's */ #define DEFAULT_RX_MTU 32767 #define DEFAULT_TX_MTU 32767 -#define TARGET_SIZE 16 - -static const guint8 FTP_TARGET[TARGET_SIZE] = { - 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2, - 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 }; - -static const guint8 PBAP_TARGET[TARGET_SIZE] = { - 0x79, 0x61, 0x35, 0xF0, 0xF0, 0xC5, 0x11, 0xD8, - 0x09, 0x66, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66 }; - /* Connection ID */ static guint32 cid = 0x0000; @@ -74,24 +65,6 @@ typedef struct { guint16 mtu; } __attribute__ ((packed)) obex_connect_hdr_t; -struct obex_commands opp = { - .get = opp_get, - .put = opp_put, - .chkput = opp_chkput, -}; - -struct obex_commands ftp = { - .get = ftp_get, - .put = ftp_put, - .chkput = ftp_chkput, - .setpath = ftp_setpath, -}; - -struct obex_commands pbap = { - .get = pbap_get, - .setpath = pbap_setpath, -}; - static void os_reset_session(struct obex_session *os) { if (os->object) { @@ -146,9 +119,6 @@ static void obex_session_free(struct obex_session *os) if (os->io) g_io_channel_unref(os->io); - if (os->target && !memcmp(os->target, PBAP_TARGET, TARGET_SIZE)) - pbap_phonebook_context_destroy(os); - g_free(os); } @@ -233,31 +203,18 @@ static void cmd_connect(struct obex_session *os, if (hi != OBEX_HDR_TARGET || hlen != TARGET_SIZE) continue; - if (memcmp(hd.bs, FTP_TARGET, TARGET_SIZE) == 0 && - os->server->services & - (OBEX_FTP | OBEX_PCSUITE)) { - os->target = FTP_TARGET; - os->services = OBEX_FTP | OBEX_PCSUITE; - os->cmds = &ftp; - break; - } - - if (memcmp(hd.bs, PBAP_TARGET, TARGET_SIZE) == 0 && - os->server->services & OBEX_PBAP) { - os->target = PBAP_TARGET; - os->services = OBEX_PBAP; - os->cmds = &pbap; - pbap_phonebook_context_create(os); + os->service = obex_service_driver_find(os->server->drivers, hd.bs); + if (os->service) break; - } error("Connect attempt to a non-supported target"); OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); return; } - if (os->target == NULL) { - if (os->server->services & OBEX_OPP) { + if (os->service == NULL) { + os->service = obex_service_driver_find(os->server->drivers, NULL); + if (os->service) { register_transfer(os->cid, os); /* OPP doesn't contains target or connection id. */ OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); @@ -273,7 +230,7 @@ static void cmd_connect(struct obex_session *os, emit_session_created(cid); /* Append received UUID in WHO header */ - hd.bs = os->target; + hd.bs = os->service->target; OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_WHO, hd, TARGET_SIZE, OBEX_FL_FIT_ONE_PACKET); @@ -296,7 +253,7 @@ static gboolean chk_cid(obex_t *obex, obex_object_t *obj, guint32 cid) os = OBEX_GetUserData(obex); /* Object Push doesn't provide a connection id. */ - if (os->target == NULL) + if (os->service == NULL) return TRUE; while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) { @@ -321,10 +278,10 @@ static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj) guint hlen; guint8 hi; - if (!os->cmds) { + if (!os->service) { OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); return; - } else if (!os->cmds->get) { + } else if (!os->service->get) { OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED, OBEX_RSP_NOT_IMPLEMENTED); return; @@ -384,13 +341,13 @@ static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj) os->type = g_strndup((const gchar *) hd.bs, hlen); debug("OBEX_HDR_TYPE: %s", os->type); - os->driver = obex_mime_type_driver_find(os->target, os->type); + os->driver = obex_mime_type_driver_find(os->service->target, os->type); break; } } if (!os->driver) { - os->driver = obex_mime_type_driver_find(os->target, NULL); + os->driver = obex_mime_type_driver_find(os->service->target, NULL); if (!os->driver) { error("No driver found"); OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED, @@ -399,7 +356,7 @@ static void cmd_get(struct obex_session *os, obex_t *obex, obex_object_t *obj) } } - os->cmds->get(obex, obj); + os->service->get(obex, obj); } static void cmd_setpath(struct obex_session *os, @@ -409,10 +366,10 @@ static void cmd_setpath(struct obex_session *os, guint32 hlen; guint8 hi; - if (!os->cmds) { + if (!os->service) { OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); return; - } else if (!os->cmds->setpath) { + } else if (!os->service->setpath) { OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED, OBEX_RSP_NOT_IMPLEMENTED); return; @@ -448,7 +405,7 @@ static void cmd_setpath(struct obex_session *os, break; } - os->cmds->setpath(obex, obj); + os->service->setpath(obex, obj); } int os_prepare_get(struct obex_session *os, gchar *filename, size_t *size) @@ -456,11 +413,6 @@ int os_prepare_get(struct obex_session *os, gchar *filename, size_t *size) gint err; gpointer object; - if (!os->driver) { - error("No driver to handle %s", os->type); - return -ENOENT; - } - object = os->driver->open(filename, O_RDONLY, 0, size); if (object == NULL) { err = -errno; @@ -496,7 +448,6 @@ static gint obex_write_stream(struct obex_session *os, if (os->aborted) return -EPERM; - if (os->object == NULL) { if (os->buf == NULL && os->finished == FALSE) return -EIO; @@ -534,10 +485,6 @@ add_header: OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, hd, len, OBEX_FL_STREAM_DATA); - if (!memcmp(os->target, PBAP_TARGET, TARGET_SIZE)) - if (os->offset == os->size && os->finished == FALSE) - OBEX_SuspendRequest(obex, obj); - return len; } @@ -558,7 +505,7 @@ gint os_prepare_put(struct obex_session *os) g_free(path); - if (os->target == NULL) + if (os->service == NULL) emit_transfer_started(os->cid); if (!os->buf) { @@ -703,7 +650,7 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj) os->type = g_strndup((const gchar *) hd.bs, hlen); debug("OBEX_HDR_TYPE: %s", os->type); - os->driver = obex_mime_type_driver_find(os->target, os->type); + os->driver = obex_mime_type_driver_find(os->service->target, os->type); break; case OBEX_HDR_BODY: @@ -732,7 +679,7 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj) } if (!os->driver) { - os->driver = obex_mime_type_driver_find(os->target, NULL); + os->driver = obex_mime_type_driver_find(os->service->target, NULL); if (!os->driver) { error("No driver found"); OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED, @@ -741,10 +688,10 @@ static gboolean check_put(obex_t *obex, obex_object_t *obj) } } - if (!os->cmds || !os->cmds->chkput) + if (!os->service || !os->service->chkput) goto done; - ret = os->cmds->chkput(obex, obj); + ret = os->service->chkput(obex, obj); switch (ret) { case 0: break; @@ -775,10 +722,10 @@ done: static void cmd_put(struct obex_session *os, obex_t *obex, obex_object_t *obj) { - if (!os->cmds) { + if (!os->service) { OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); return; - } else if (!os->cmds->put) { + } else if (!os->service->put) { OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_IMPLEMENTED, OBEX_RSP_NOT_IMPLEMENTED); return; @@ -791,7 +738,7 @@ static void cmd_put(struct obex_session *os, obex_t *obex, obex_object_t *obj) return; } - os->cmds->put(obex, obj); + os->service->put(obex, obj); } static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, @@ -806,12 +753,12 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, switch (evt) { case OBEX_EV_PROGRESS: /* Just emit progress for Object Push */ - if (os->target == NULL) + if (os->service == NULL) emit_transfer_progress(os->cid, os->size, os->offset); break; case OBEX_EV_ABORT: os->aborted = TRUE; - if (os->target == NULL) + if (os->service == NULL) emit_transfer_completed(os->cid, FALSE); os_reset_session(os); OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); @@ -824,7 +771,7 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, case OBEX_CMD_PUT: case OBEX_CMD_GET: os_session_mark_aborted(os); - if (os->target == NULL) + if (os->service == NULL) emit_transfer_completed(os->cid, !os->aborted); os_reset_session(os); break; @@ -854,7 +801,7 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, case OBEX_EV_REQCHECK: switch (cmd) { case OBEX_CMD_PUT: - if (os->cmds && os->cmds->put) + if (os->service && os->service->put) check_put(obex, obj); break; default: @@ -918,7 +865,6 @@ static void obex_event(obex_t *obex, obex_object_t *obj, gint mode, void server_free(struct server *server) { - g_free(server->name); g_free(server->folder); g_free(server->capability); g_free(server->devnode); @@ -932,7 +878,7 @@ static void obex_handle_destroy(gpointer user_data) os = OBEX_GetUserData(obex); - if (os->target == NULL) { + if (os->service == NULL) { /* Got an error during a transfer. */ if (os->object) emit_transfer_completed(os->cid, os->offset == os->size); @@ -951,9 +897,17 @@ static void obex_handle_destroy(gpointer user_data) static gboolean tty_reinit(gpointer data) { struct server *server = data; + GSList *l; + guint services = 0; + + for (l = server->drivers; l; l = l->next) { + struct obex_service_driver *driver = l->data; + + services |= driver->service; + } - tty_init(server->services, server->folder, server->capability, - server->symlinks, server->devnode); + tty_init(services, server->folder, server->capability, + server->symlinks, server->devnode); server_free(server); @@ -1000,10 +954,9 @@ gint obex_session_start(GIOChannel *io, struct server *server) os = g_new0(struct obex_session, 1); - os->target = NULL; + os->service = NULL; - if (server->services & OBEX_OPP) - os->cmds = &opp; + os->service = obex_service_driver_find(server->drivers, NULL); os->current_folder = g_strdup(server->folder); os->server = server; diff --git a/obexd/src/obex.h b/obexd/src/obex.h index 13ecf81dd..eb4cb1abb 100644 --- a/obexd/src/obex.h +++ b/obexd/src/obex.h @@ -29,8 +29,6 @@ #include -#include "phonebook.h" - #define OBJECT_SIZE_UNKNOWN -1 #define OBJECT_SIZE_DELETE -2 @@ -40,39 +38,32 @@ #define OBEX_PBAP (1 << 4) #define OBEX_PCSUITE (1 << 5) -struct obex_mime_type_driver; +#define TARGET_SIZE 16 -struct obex_commands { - void (*get) (obex_t *obex, obex_object_t *obj); - void (*put) (obex_t *obex, obex_object_t *obj); - gint (*chkput) (obex_t *obex, obex_object_t *obj); - void (*setpath) (obex_t *obex, obex_object_t *obj); -}; +struct obex_service_driver; +struct obex_mime_type_driver; struct server { - guint16 services; gboolean auto_accept; - gchar *name; gchar *folder; gboolean symlinks; gchar *capability; guint32 handle; - uint8_t channel; gchar *devnode; gboolean secure; GIOChannel *io; guint watch; guint16 tx_mtu; guint16 rx_mtu; + GSList *drivers; }; struct obex_session { GIOChannel *io; guint32 cid; - guint16 services; guint16 tx_mtu; guint16 rx_mtu; - uint8_t cmd; + guint8 cmd; gchar *name; gchar *type; time_t time; @@ -82,12 +73,10 @@ struct obex_session { gint32 size; gpointer object; gboolean aborted; - const guint8 *target; - struct obex_commands *cmds; + struct obex_service_driver *service; struct server *server; gboolean checked; obex_t *obex; - struct phonebook_context *pbctx; struct obex_mime_type_driver *driver; gboolean finished; }; @@ -96,21 +85,6 @@ gint obex_session_start(GIOChannel *io, struct server *server); struct obex_session *obex_get_session(gpointer object); gint obex_tty_session_stop(void); -void opp_get(obex_t *obex, obex_object_t *obj); -void opp_put(obex_t *obex, obex_object_t *obj); -gint opp_chkput(obex_t *obex, obex_object_t *obj); - -void ftp_get(obex_t *obex, obex_object_t *obj); -void ftp_put(obex_t *obex, obex_object_t *obj); -gint ftp_chkput(obex_t *obex, obex_object_t *obj); -void ftp_setpath(obex_t *obex, obex_object_t *obj); - -void pbap_get(obex_t *obex, obex_object_t *obj); -void pbap_setpath(obex_t *obex, obex_object_t *obj); -gboolean pbap_phonebook_context_create(struct obex_session *session); -void pbap_phonebook_context_destroy(struct obex_session *session); -struct obex_session *pbap_get_session(struct phonebook_context *context); - gint os_prepare_get(struct obex_session *os, gchar *file, size_t *size); gint os_prepare_put(struct obex_session *os); diff --git a/obexd/src/pbap.c b/obexd/src/pbap.c deleted file mode 100644 index 5f1fb734a..000000000 --- a/obexd/src/pbap.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * - * OBEX Server - * - * Copyright (C) 2007-2009 Marcel Holtmann - * - * - * 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 -#endif - -#include -#include -#include - -#include -#include - -#include "logging.h" -#include "obex.h" - -#define PHONEBOOK_TYPE "x-bt/phonebook" -#define VCARDLISTING_TYPE "x-bt/vcard-listing" -#define VCARDENTRY_TYPE "x-bt/vcard" - -#define ORDER_TAG 0x01 -#define SEARCHVALUE_TAG 0x02 -#define SEARCHATTRIB_TAG 0x03 -#define MAXLISTCOUNT_TAG 0x04 -#define LISTSTARTOFFSET_TAG 0x05 -#define FILTER_TAG 0x06 -#define FORMAT_TAG 0X07 -#define PHONEBOOKSIZE_TAG 0X08 -#define NEWMISSEDCALLS_TAG 0X09 - -/* The following length is in the unit of byte */ -#define ORDER_LEN 1 -#define SEARCHATTRIB_LEN 1 -#define MAXLISTCOUNT_LEN 2 -#define LISTSTARTOFFSET_LEN 2 -#define FILTER_LEN 8 -#define FORMAT_LEN 1 -#define PHONEBOOKSIZE_LEN 2 -#define NEWMISSEDCALLS_LEN 1 - -#define MCH "telecom/mch.vcf" -#define SIM1_MCH "SIM1/telecom/mch.vcf" - -struct apparam_hdr { - uint8_t tag; - uint8_t len; - uint8_t val[0]; -} __attribute__ ((packed)); -#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) - -struct apparam_field { - guint64 filter; - guint16 maxlistcount; - guint16 liststartoffset; - guint8 format; - guint8 order; - guint8 searchattrib; - guint8 *searchval; -}; - -static GSList *session_list = NULL; - -static int pbap_parse_apparam_header(obex_t *obex, obex_object_t *obj, - struct apparam_field *apparam) -{ - obex_headerdata_t hd; - guint8 hi; - guint32 hlen; - - while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) { - void *ptr = (void *) hd.bs; - uint32_t len = hlen; - - if (hi != OBEX_HDR_APPARAM) - continue; - - if (hlen < APPARAM_HDR_SIZE) { - g_free(apparam->searchval); - error("PBAP pullphonebook app parameters header" - " is too short: %d", hlen); - return -1; - } - - while (len > APPARAM_HDR_SIZE) { - struct apparam_hdr *hdr = ptr; - - if (hdr->len > len - APPARAM_HDR_SIZE) { - g_free(apparam->searchval); - error("Unexpected PBAP pullphonebook app" - " length, tag %d, len %d", - hdr->tag, hdr->len); - return -1; - } - - switch (hdr->tag) { - case ORDER_TAG: - if (hdr->len == ORDER_LEN) - apparam->order = hdr->val[0]; - break; - case SEARCHATTRIB_TAG: - if (hdr->len == SEARCHATTRIB_LEN) - apparam->searchattrib = hdr->val[0]; - break; - case SEARCHVALUE_TAG: - apparam->searchval = g_try_malloc(hdr->len + 1); - if (apparam->searchval != NULL) { - memcpy(apparam->searchval, hdr->val, - hdr->len); - apparam->searchval[hdr->len] = '\0'; - } - break; - case FILTER_TAG: - if (hdr->len == FILTER_LEN) { - guint64 val; - memcpy(&val, hdr->val, sizeof(val)); - apparam->filter = get_be64(&val); - } - break; - case FORMAT_TAG: - if (hdr->len == FORMAT_LEN) - apparam->format = hdr->val[0]; - break; - case MAXLISTCOUNT_TAG: - if (hdr->len == MAXLISTCOUNT_LEN) { - guint16 val; - memcpy(&val, hdr->val, sizeof(val)); - apparam->maxlistcount = get_be16(&val); - } - break; - case LISTSTARTOFFSET_TAG: - if (hdr->len == LISTSTARTOFFSET_LEN) { - guint16 val; - memcpy(&val, hdr->val, sizeof(val)); - apparam->liststartoffset = get_be16(&val); - } - break; - default: - g_free(apparam->searchval); - error("Unexpected PBAP pullphonebook app" - " parameter, tag %d, len %d", - hdr->tag, hdr->len); - return -1; - } - - ptr += APPARAM_HDR_SIZE + hdr->len; - len -= APPARAM_HDR_SIZE + hdr->len; - } - - /* Ignore multiple app param headers */ - break; - } - - return 0; -} - -/* Add app parameter header, that is sent back to PBAP client */ -static int pbap_add_result_apparam_header(obex_t *obex, obex_object_t *obj, - guint16 maxlistcount, gchar *path_name, - guint16 phonebooksize, - guint8 newmissedcalls, gboolean *addbody) -{ - guint8 rspsize = 0; - gboolean addmissedcalls = FALSE; - obex_headerdata_t hd; - - if (maxlistcount == 0) { - rspsize += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN; - *addbody = FALSE; - } - - if (g_str_equal(path_name, SIM1_MCH) == TRUE || - g_str_equal(path_name, MCH) == TRUE) { - rspsize += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN; - addmissedcalls = TRUE; - } - - if (rspsize > 0) { - void *buf, *ptr; - - buf = g_try_malloc0(rspsize); - if (buf == NULL) - return -ENOMEM; - - ptr = buf; - - if (maxlistcount == 0) { - struct apparam_hdr *hdr = ptr; - guint16 val = GUINT16_TO_BE(phonebooksize); - - hdr->tag = PHONEBOOKSIZE_TAG; - hdr->len = PHONEBOOKSIZE_LEN; - memcpy(hdr->val, &val, sizeof(val)); - - ptr += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN; - } - - if (addmissedcalls == TRUE) { - struct apparam_hdr *hdr = ptr; - - hdr->tag = NEWMISSEDCALLS_TAG; - hdr->len = NEWMISSEDCALLS_LEN; - hdr->val[0] = newmissedcalls; - - ptr += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN; - } - - hd.bs = buf; - OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_APPARAM, - hd, rspsize, 0); - g_free(buf); - } - - return 0; -} - -static int pbap_pullphonebook(obex_t *obex, obex_object_t *obj, - gboolean *addbody) -{ - struct obex_session *session = OBEX_GetUserData(obex); - struct apparam_field apparam; - guint8 newmissedcalls = 0; - guint16 phonebooksize = 0; - int err; - - memset(&apparam, 0, sizeof(struct apparam_field)); - - err = pbap_parse_apparam_header(obex, obj, &apparam); - if (err < 0) - return err; - - err = phonebook_pullphonebook(session->pbctx, session->name, - apparam.filter, apparam.format, - apparam.maxlistcount, - apparam.liststartoffset, - &phonebooksize, &newmissedcalls); - if (err < 0) - return err; - - return pbap_add_result_apparam_header(obex, obj, apparam.maxlistcount, - session->name, phonebooksize, - newmissedcalls, addbody); -} - -static int pbap_pullvcardlisting(obex_t *obex, obex_object_t *obj, - gboolean *addbody) -{ - struct obex_session *session = OBEX_GetUserData(obex); - gchar *fullname; - struct apparam_field apparam; - guint8 newmissedcalls = 0; - guint16 phonebooksize = 0; - int err; - - memset(&apparam, 0, sizeof(struct apparam_field)); - - err = pbap_parse_apparam_header(obex, obj, &apparam); - if (err < 0) - return err; - - fullname = g_build_filename(session->current_folder, - session->name, NULL); - err = phonebook_pullvcardlisting(session->pbctx, fullname, - apparam.order, apparam.searchval, - apparam.searchattrib, - apparam.maxlistcount, - apparam.liststartoffset, - &phonebooksize, &newmissedcalls); - if (err < 0) - goto done; - - g_free(fullname); - - fullname = g_build_filename(session->current_folder, session->name, - NULL); - if (fullname != NULL) - fullname = g_strconcat(fullname, ".vcf", NULL); - - err = pbap_add_result_apparam_header(obex, obj, apparam.maxlistcount, - fullname, phonebooksize, - newmissedcalls, addbody); - -done: - g_free(apparam.searchval); - g_free(fullname); - return err; -} - -static int pbap_pullvcardentry(obex_t *obex, obex_object_t *obj) -{ - struct obex_session *session = OBEX_GetUserData(obex); - gchar *fullname; - struct apparam_field apparam; - int err; - - memset(&apparam, 0, sizeof(struct apparam_field)); - err = pbap_parse_apparam_header(obex, obj, &apparam); - if (err < 0) - return err; - - fullname = g_build_filename(session->current_folder, - session->name, NULL); - err = phonebook_pullvcardentry(session->pbctx, fullname, - apparam.filter, apparam.format); - - g_free(apparam.searchval); - g_free(fullname); - return err; -} - -void pbap_get(obex_t *obex, obex_object_t *obj) -{ - struct obex_session *session = OBEX_GetUserData(obex); - obex_headerdata_t hd; - gboolean addbody = TRUE; - int err; - - if (session == NULL) - return; - - if (session->type == NULL) - goto fail; - - if (g_str_equal(session->type, VCARDLISTING_TYPE) == FALSE - && session->name == NULL) - goto fail; - - OBEX_ObjectReParseHeaders(obex, obj); - - if (g_str_equal(session->type, PHONEBOOK_TYPE) == TRUE) - err = pbap_pullphonebook(obex, obj, &addbody); - else if (g_str_equal(session->type, VCARDLISTING_TYPE) == TRUE) - err = pbap_pullvcardlisting(obex, obj, &addbody); - else if (g_str_equal(session->type, VCARDENTRY_TYPE) == TRUE) - err = pbap_pullvcardentry(obex, obj); - else - goto fail; - - if (err < 0) - goto fail; - - if (addbody == TRUE) { - OBEX_SuspendRequest(obex, obj); - session->size = 0; - - /* Add body header */ - hd.bs = NULL; - OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY, - hd, 0, OBEX_FL_STREAM_START); - } - - OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); - - return; - -fail: - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); -} - -static gboolean pbap_is_valid_folder(struct obex_session *session) -{ - if (session->current_folder == NULL) { - if (g_str_equal(session->name, "telecom") == TRUE || - g_str_equal(session->name, "SIM1") == TRUE) - return TRUE; - } else if (g_str_equal(session->current_folder, "SIM1") == TRUE) { - if (g_str_equal(session->name, "telecom") == TRUE) - return TRUE; - } else if (g_str_equal(session->current_folder, "telecom") == TRUE || - g_str_equal(session->current_folder, "SIM1/telecom") == TRUE) { - if (g_str_equal(session->name, "pb") == TRUE || - g_str_equal(session->name, "ich") == TRUE || - g_str_equal(session->name, "och") == TRUE || - g_str_equal(session->name, "mch") == TRUE || - g_str_equal(session->name, "cch") == TRUE) - return TRUE; - } - - return FALSE; -} - -void pbap_setpath(obex_t *obex, obex_object_t *obj) -{ - struct obex_session *session = OBEX_GetUserData(obex); - guint8 *nonhdr; - gchar *fullname; - - if (OBEX_ObjectGetNonHdrData(obj, &nonhdr) != 2) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, - OBEX_RSP_PRECONDITION_FAILED); - error("Set path failed: flag and constants not found!"); - return; - } - - /* Check "Backup" flag */ - if ((nonhdr[0] & 0x01) == 0x01) { - debug("Set to parent path"); - - if (session->current_folder == NULL) { - /* we are already in top level folder */ - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, - OBEX_RSP_FORBIDDEN); - return; - } - - fullname = g_path_get_dirname(session->current_folder); - g_free(session->current_folder); - - if (strlen(fullname) == 1 && *fullname == '.') - session->current_folder = NULL; - else - session->current_folder = g_strdup(fullname); - - g_free(fullname); - - debug("Set to parent path: %s", session->current_folder); - - OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); - return; - } - - if (!session->name) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_BAD_REQUEST); - error("Set path failed: name missing!"); - return; - } - - if (strlen(session->name) == 0) { - debug("Set to root"); - - g_free(session->current_folder); - session->current_folder = NULL; - - OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); - return; - } - - /* Check and set to name path */ - if (strstr(session->name, "/")) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN); - error("Set path failed: name incorrect!"); - return; - } - - if (pbap_is_valid_folder(session) == FALSE) { - OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND); - return; - } - - if (session->current_folder == NULL) - fullname = g_build_filename("", session->name, NULL); - else - fullname = g_build_filename(session->current_folder, session->name, NULL); - - debug("Fullname: %s", fullname); - - g_free(session->current_folder); - session->current_folder = fullname; - OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); -} - -gboolean pbap_phonebook_context_create(struct obex_session *session) -{ - struct phonebook_context *context; - struct phonebook_driver *driver; - - driver = phonebook_get_driver(NULL); - if (driver == NULL) - return FALSE; - - context = phonebook_create(driver); - if (context == NULL) - return FALSE; - - session->pbctx = context; - - session_list = g_slist_append(session_list, session); - - return TRUE; -} - -void pbap_phonebook_context_destroy(struct obex_session *session) -{ - struct phonebook_context *context; - - context = session->pbctx; - phonebook_unref(context); - - session_list = g_slist_remove(session_list, session); -} - -struct obex_session *pbap_get_session(struct phonebook_context *context) -{ - GSList *current; - - for (current = session_list; current != NULL; current = current->next) { - struct obex_session *session = current->data; - if (session->pbctx == context) - return session; - } - - return NULL; -} diff --git a/obexd/src/phonebook.c b/obexd/src/phonebook.c deleted file mode 100644 index cdbc319fb..000000000 --- a/obexd/src/phonebook.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * OBEX Server - * - * Copyright (C) 2007-2009 Marcel Holtmann - * - * - * 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 -#endif - -#include -#include -#include - -#include -#include - -#include "logging.h" -#include "obex.h" - -static GSList *driver_list = NULL; - -int phonebook_driver_register(struct phonebook_driver *driver) -{ - DBG("driver %p name %s", driver, driver->name); - - driver_list = g_slist_append(driver_list, driver); - - return 0; -} - -void phonebook_driver_unregister(struct phonebook_driver *driver) -{ - DBG("driver %p name %s", driver, driver->name); - - driver_list = g_slist_remove(driver_list, driver); -} - -struct phonebook_context *phonebook_create(struct phonebook_driver *driver) -{ - struct phonebook_context *context; - - if (driver == NULL) - return NULL; - - context = g_try_new0(struct phonebook_context, 1); - if (context == NULL) - return NULL; - - DBG("context %p", context); - - context->refcount = 1; - context->driver = driver; - - if (driver->create) { - if (driver->create(context) < 0) { - g_free(context); - return NULL; - } - } - - return context; -} - -struct phonebook_context *phonebook_ref(struct phonebook_context *context) -{ - DBG("context %p refcount %d", context, - g_atomic_int_get(&context->refcount) + 1); - - g_atomic_int_inc(&context->refcount); - - return context; -} - -void phonebook_unref(struct phonebook_context *context) -{ - DBG("context %p refcount %d", context, - g_atomic_int_get(&context->refcount) - 1); - - if (g_atomic_int_dec_and_test(&context->refcount) == TRUE) { - if (context->driver->destroy) - context->driver->destroy(context); - g_free(context); - } -} - -int phonebook_pullphonebook(struct phonebook_context *context, gchar *objname, - guint64 filter, guint8 format, guint16 maxlistcount, - guint16 liststartoffset, guint16 *phonebooksize, - guint8 *newmissedcalls) -{ - if (!context->driver->pullphonebook) - return -1; - - return context->driver->pullphonebook(context, objname, filter, format, - maxlistcount, liststartoffset, phonebooksize, - newmissedcalls); -} - -int phonebook_pullvcardlisting(struct phonebook_context *context, - gchar *objname, guint8 order, guint8 *searchval, - guint8 searchattrib, guint16 maxlistcount, - guint16 liststartoffset, guint16 *phonebooksize, - guint8 *newmissedcalls) -{ - if (!context->driver->pullvcardlisting) - return -1; - - return context->driver->pullvcardlisting(context, objname, order, - searchval, searchattrib, maxlistcount, - liststartoffset, phonebooksize, newmissedcalls); -} - -int phonebook_pullvcardentry(struct phonebook_context *context, gchar *objname, - guint64 filter, guint8 format) -{ - if (!context->driver->pullvcardentry) - return -1; - - return context->driver->pullvcardentry(context, objname, filter, - format); -} - -/* if buf is NULL or size is 0, this indicate that no more result will - * be returned by PBAP plugin - * */ -void phonebook_return(struct phonebook_context *context, - char *buf, int size) -{ - struct obex_session *session; - - DBG("context %p", context); - - session = pbap_get_session(context); - - if (buf == NULL || size == 0) { - session->finished = 1; - OBEX_ResumeRequest(session->obex); - return; - } - - session->buf = g_realloc(session->buf, session->size + size); - memcpy(session->buf + session->size, buf, size); - session->size += size; - - OBEX_ResumeRequest(session->obex); -} - -struct phonebook_driver *phonebook_get_driver(const char *name) -{ - DBG("name %s", name); - - return g_slist_nth_data(driver_list, 0); -} diff --git a/obexd/src/phonebook.h b/obexd/src/phonebook.h deleted file mode 100644 index ecf5e4ffb..000000000 --- a/obexd/src/phonebook.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * OBEX Server - * - * Copyright (C) 2007-2009 Marcel Holtmann - * - * - * 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 - * - */ - -#include - -struct phonebook_driver; - -struct phonebook_context { - gint refcount; - - struct phonebook_driver *driver; - void *driver_data; -}; - -extern struct phonebook_context *phonebook_create( - struct phonebook_driver *driver); -extern struct phonebook_context *phonebook_ref( - struct phonebook_context *context); -extern void phonebook_unref(struct phonebook_context *context); - -static inline void *phonebook_get_data(struct phonebook_context *context) -{ - return context->driver_data; -} - -static inline void phonebook_set_data(struct phonebook_context *context, - void *data) -{ - context->driver_data = data; -} - -extern int phonebook_pullphonebook(struct phonebook_context *context, - gchar *objname, guint64 filter, guint8 format, - guint16 maxlistcount, guint16 liststartoffset, - guint16 *phonebooksize, guint8 *newmissedcalls); -extern int phonebook_pullvcardlisting(struct phonebook_context *context, - gchar *objname, guint8 order, guint8 *searchval, - guint8 searchattrib, guint16 maxlistcount, - guint16 liststartoffset, guint16 *phonebooksize, - guint8 *newmissedcalls); -extern int phonebook_pullvcardentry(struct phonebook_context *context, - gchar *objname, guint64 filter, guint8 format); -extern void phonebook_return(struct phonebook_context *context, - char *buf, int size); - -struct phonebook_driver { - const char *name; - int (*create) (struct phonebook_context *context); - void (*destroy) (struct phonebook_context *context); - int (*pullphonebook) (struct phonebook_context *context, - gchar *objname, guint64 filter, guint8 format, - guint16 maxlistcount, guint16 liststartoffset, - guint16 *phonebooksize, guint8 *newmissedcalls); - int (*pullvcardlisting) (struct phonebook_context *context, - gchar *objname, guint8 order, guint8 *searchval, - guint8 searchattrib, guint16 maxlistcount, - guint16 liststartoffset, guint16 *phonebooksize, - guint8 *newmissedcalls); - int (*pullvcardentry) (struct phonebook_context *context, - gchar *objname, guint64 filter, guint8 format); -}; - -extern int phonebook_driver_register(struct phonebook_driver *driver); -extern void phonebook_driver_unregister(struct phonebook_driver *driver); - -struct phonebook_driver *phonebook_get_driver(const char *name); diff --git a/obexd/src/service.c b/obexd/src/service.c new file mode 100644 index 000000000..2a5494dc8 --- /dev/null +++ b/obexd/src/service.c @@ -0,0 +1,106 @@ +/* + * + * OBEX Server + * + * Copyright (C) 2007-2009 Marcel Holtmann + * + * + * 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 +#endif + +#include +#include +#include + +#include +#include + +#include "service.h" +#include "logging.h" +#include "obex.h" + +static GSList *drivers = NULL; + +struct obex_service_driver *obex_service_driver_find(GSList *list, const guint8 *target) +{ + GSList *l; + + for (l = list; l; l = l->next) { + struct obex_service_driver *driver = l->data; + + if (driver->target == NULL && target == NULL) + return driver; + + if (driver->target && target && + memcmp(driver->target, target, TARGET_SIZE) == 0) + return driver; + } + + return NULL; +} + +GSList *obex_service_driver_list(guint16 services) +{ + GSList *l; + GSList *list = NULL; + + for (l = drivers; l && services; l = l->next) { + struct obex_service_driver *driver = l->data; + + if (driver->service & services) { + list = g_slist_append(list, driver); + services &= ~driver->service; + } + } + + return list; +} + +int obex_service_driver_register(struct obex_service_driver *driver) +{ + if (!driver) { + error("Invalid driver"); + return -EINVAL; + } + + if (obex_service_driver_list(driver->service)) { + error("Permission denied: service %s already registered", + driver->name); + return -EPERM; + } + + debug("driver %p service %s registered", driver, driver->name); + + drivers = g_slist_append(drivers, driver); + + return 0; +} + +void obex_service_driver_unregister(struct obex_service_driver *driver) +{ + if (!g_slist_find(drivers, driver)) { + error("Unable to unregister: No such driver %p", driver); + return; + } + + debug("driver %p service %s unregistered", driver, driver->name); + + drivers = g_slist_remove(drivers, driver); +} diff --git a/obexd/src/service.h b/obexd/src/service.h new file mode 100644 index 000000000..2cf344306 --- /dev/null +++ b/obexd/src/service.h @@ -0,0 +1,40 @@ +/* + * + * OBEX Server + * + * Copyright (C) 2007-2009 Marcel Holtmann + * + * + * 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 + * + */ + +struct obex_service_driver { + const char *name; + guint16 service; + guint8 channel; + const guint8 *target; + const gchar *record; + void (*get) (obex_t *obex, obex_object_t *obj); + void (*put) (obex_t *obex, obex_object_t *obj); + gint (*chkput) (obex_t *obex, obex_object_t *obj); + void (*setpath) (obex_t *obex, obex_object_t *obj); +}; + +int obex_service_driver_register(struct obex_service_driver *driver); +void obex_service_driver_unregister(struct obex_service_driver *driver); +GSList *obex_service_driver_list(guint16 services); +struct obex_service_driver *obex_service_driver_find(GSList *drivers, + const guint8 *uuid); -- 2.47.3