ndef: org.neard.Record export
authorSamuel Ortiz <sameo@linux.intel.com>
Thu, 9 Jun 2011 17:56:11 +0000 (19:56 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 21 Oct 2011 06:54:04 +0000 (23:54 -0700)
Each record will be accesible through that interface, and each tag tracks
its own record list.

12 files changed:
doc/target-api.txt
include/dbus.h
include/ndef.h
include/tag.h
plugins/nfctype2.c
src/main.c
src/ndef.c
src/near.h
src/tag.c
src/target.c
test/dump-record [new file with mode: 0755]
test/dump-target [new file with mode: 0755]

index 12101b0..753558e 100644 (file)
@@ -3,7 +3,7 @@ Target hierarchy
 
 Service                org.neard
 Interface      org.neard.Target
-Object path    [variable prefix]/{nfc0,nfc1,...}/target_UID
+Object path    [variable prefix]/{nfc0}/{target0, target1...}
 
 Method         dict GetProperties()
 
@@ -45,7 +45,36 @@ Properties   string Type [readonly]
                        "Type 4" and "NFC-DEP"
                        This is only valid for tag type targets.
 
-               array{dict} Records [readwrite]
+               array{object} Records [readwrite]
 
-                       List of NDEF records.
+                       List of NDEF records object paths.
                        This is only valid for tag type targets.
+
+
+Record hierarchy
+================
+
+Service                org.neard
+Interface      org.neard.Record
+Object path    [variable prefix]/{nfc0}/{target0}/{record0,record1,...}
+
+Method         dict GetProperties()
+
+                       Returns all properties for the record. See the
+                       properties section for available properties.
+
+                       Possible Errors: org.neard.Error.DoesNotExist
+
+Properties     boolean SmartPoster [readonly]
+
+               boolean HandOver [readonly]
+
+               string Type [readonly]
+
+               string Language [readonly]
+
+               string Encoding [readonly]
+
+               array{byte} Value [readonly]
+
+               string Representation [readonly]
index 68f4cea..874e016 100644 (file)
@@ -31,6 +31,7 @@
 
 #define NFC_ADAPTER_INTERFACE  NFC_SERVICE ".Adapter"
 #define NFC_TARGET_INTERFACE   NFC_SERVICE ".Target"
+#define NFC_RECORD_INTERFACE   NFC_SERVICE ".Record"
 
 typedef void (* near_dbus_append_cb_t) (DBusMessageIter *iter,
                                                        void *user_data);
index fa2661e..c4aee9c 100644 (file)
 #ifndef __NEAR_NDEF_H
 #define __NEAR_NDEF_H
 
-struct near_ndef_record {
-       uint8_t tnf;
+#include <near/tag.h>
 
-       uint8_t *type;
-       size_t type_length;
+struct near_ndef_record;
 
-       uint8_t *payload;
-       size_t payload_length;
-};
-
-struct near_ndef {
-       gboolean smart_poster;
-       gboolean handover;
-
-       uint32_t n_records;
-       GList *records;
-};
+int near_ndef_parse(struct near_tag *tag, uint8_t *ndef_data, size_t ndef_length);
 
 #endif
index 0d9280b..a8643dd 100644 (file)
@@ -26,8 +26,6 @@
 
 #include <glib.h>
 
-#include <near/ndef.h>
-
 #define NFC_HEADER_SIZE 1
 
 #define        NEAR_TAG_NFC_TYPE1   0x1
index 214f2de..31e6363 100644 (file)
@@ -137,7 +137,7 @@ static int data_parse(struct type2_tag *tag, uint8_t *data, uint16_t length)
                case TLV_NDEF:
                        DBG("NDEF found %d bytes long", tlv_length(tlv));
 
-                       near_tag_add_ndef(tag->tag, tlv_data(tlv),
+                       near_ndef_parse(tag->tag, tlv_data(tlv),
                                                tlv_length(tlv));
 
                        break;
index 2701964..b6ea0bf 100644 (file)
@@ -145,6 +145,7 @@ int main(int argc, char *argv[])
        __near_netlink_init();
        __near_target_init();
        __near_adapter_init();
+       __near_ndef_init();
        __near_manager_init(conn);
 
        __near_plugin_init(option_plugin, option_noplugin);
@@ -159,6 +160,7 @@ int main(int argc, char *argv[])
        __near_plugin_cleanup();
 
        __near_manager_cleanup();
+       __near_ndef_cleanup();
        __near_adapter_cleanup();
        __near_target_cleanup();
        __near_netlink_cleanup();
index aeded8f..9acc25a 100644 (file)
 #define RECORD_TNF_UNKNOWN   0x05
 #define RECORD_TNF_UNCHANGED 0x06
 
+#define RECORD_TNF_WKT_TEXT             'T'
+#define RECORD_TNF_WKT_URI              'U'
+#define RECORD_TNF_WKT_SIZE             's'
+#define RECORD_TNF_WKT_TYPE             't'
+#define RECORD_TNF_WKT_SMART_POSTER     "Sp"
+#define RECORD_TNF_WKT_REC_ACTION       "act"
+#define RECORD_TNF_WKT_HANDOVER_REQUEST "Hr"
+#define RECORD_TNF_WKT_HANDOVER_SELECT  "Hs"
+#define RECORD_TNF_WKT_HANDOVER_CARRIER "Hc"
+
 #define RECORD_MB(record)  (((record)[0] & 0x80) >> 7)
 #define RECORD_ME(record)  (((record)[0] & 0x40) >> 6)
 #define RECORD_CF(record)  (((record)[0] & 0x20) >> 5)
 #define RECORD_IL(record)  (((record)[0] & 0x8)  >> 3)
 #define RECORD_TNF(record) ((record)[0] & 0x7)
 
-void __near_ndef_destroy(struct near_ndef *ndef)
+struct near_ndef_record {
+       char *path;
+
+       uint8_t tnf;
+       gboolean smart_poster;
+       gboolean hand_over;
+
+       uint8_t *type;
+       size_t type_length;
+
+       uint8_t *payload;
+       size_t payload_length;
+};
+
+static DBusConnection *connection = NULL;
+
+char *__near_ndef_record_get_path(struct near_ndef_record *record)
 {
-       
+       return record->path;
+}
+
+void __near_ndef_record_free(struct near_ndef_record *record)
+{
+       g_dbus_unregister_interface(connection, record->path,
+                                               NFC_RECORD_INTERFACE);
+
+       g_free(record->path);
+       g_free(record);
 }
 
+
 static gboolean record_sp(uint8_t tnf, uint8_t *type, size_t type_length)
 {
        DBG("tnf 0x%x type length %zu", tnf, type_length);
@@ -140,21 +176,231 @@ static uint8_t record_payload_offset(uint8_t *record, size_t *payload_length)
        return offset;
 }
 
-struct near_ndef *__near_ndef_create(uint8_t *ndef_data, size_t ndef_length)
+static void append_rtd_text(struct near_ndef_record *record,
+                                       DBusMessageIter *dict)
 {
-       struct near_ndef *ndef;
-       struct near_ndef_record *record;
-       uint8_t *raw_record, payload_offset, type_offset;
+       uint8_t utf, language_length;
+       char *encoding, *language, *value;
+
+       DBG("");
+
+       utf = (record->payload[0] & 0x80) >> 7;
+       if (utf == 0)
+               encoding = "UTF-8";
+       else
+               encoding = "UTF-16";
+
+       DBG("encoding %s", encoding);
+
+       language_length  = record->payload[0] & 0x1f;
+       language = g_strndup((char *)&record->payload[1], language_length);
+
+       DBG("language %s", language);
+
+       value = g_strndup((char *)&record->payload[1 + language_length],
+                               record->payload_length - 1 -language_length);
+
+       DBG("value %s", value);
+
+       near_dbus_dict_append_basic(dict, "Encoding",
+                                   DBUS_TYPE_STRING, &encoding);
+
+       near_dbus_dict_append_basic(dict, "Language",
+                                   DBUS_TYPE_STRING, &language);
+
+       near_dbus_dict_append_basic(dict, "Representation",
+                                   DBUS_TYPE_STRING, &value);
+
+       g_free(language);
+       g_free(value);
+}
+
+static void append_rtd_uri(struct near_ndef_record *record,
+                                       DBusMessageIter *dict)
+{
+       char *prefix, *value, *uri;
+
+       switch (record->payload[0]) {
+       case 0x0:
+               prefix = NULL;
+               break;
+       case 0x1:
+               prefix = "http://www.";
+               break;
+       case 0x2:
+               prefix = "https://www.";
+               break;
+       case 0x3:
+               prefix = "http://";
+               break;
+       case 0x4:
+               prefix = "https://";
+               break;
+       case 0x5:
+               prefix = "tel:";
+               break;
+       case 0x6:
+               prefix = "mailto:";
+               break;
+       case 0x7:
+               prefix = "ftp://anonymous:anonymous@";
+               break;
+       case 0x8:
+               prefix = "ftp://ftp.";
+               break;
+       case 0x9:
+               prefix = "ftps://";
+               break;
+       }
+
+       uri = g_strndup((char *)&record->payload[1],
+                               record->payload_length - 1);
+       value = g_strdup_printf("%s%s", prefix, uri);
+
+       DBG("value %s", value);
+
+       near_dbus_dict_append_basic(dict, "Representation",
+                                   DBUS_TYPE_STRING, &value);
+
+       g_free(uri);
+       g_free(value);
+}
+
+static void append_rtd(struct near_ndef_record *record, DBusMessageIter *dict)
+{
+       char *type = (char *) record->type;
+       char *dbus_type = NULL;
+
+       DBG("");
+
+       if (record->type_length == 1) {
+               switch (record->type[0]) {
+               case RECORD_TNF_WKT_TEXT:
+                       dbus_type = "Text";
+                       append_rtd_text(record, dict);
+                       break;
+               case RECORD_TNF_WKT_URI:
+                       dbus_type = "URI";
+                       append_rtd_uri(record, dict);
+                       break;
+               case RECORD_TNF_WKT_SIZE:
+                       dbus_type = "Size";
+                       break;
+               case RECORD_TNF_WKT_TYPE:
+                       dbus_type = "MIME Type";
+                       break;
+               }
+       } else if (record->type_length == 2) {
+               if (strncmp(type, RECORD_TNF_WKT_SMART_POSTER, 2))
+                       dbus_type = "Smart Poster";
+               if (strncmp(type, RECORD_TNF_WKT_HANDOVER_REQUEST, 2))
+                       dbus_type = "Hand Over Request";
+               if (strncmp(type, RECORD_TNF_WKT_HANDOVER_SELECT, 2))
+                       dbus_type = "Hand Over Select";
+               if (strncmp(type, RECORD_TNF_WKT_HANDOVER_CARRIER, 2))
+                       dbus_type = "Hand Over Carrier";
+       } else if (record->type_length == 3)
+               if (strncmp(type, RECORD_TNF_WKT_REC_ACTION, 3))
+                       dbus_type = "Recommended Action";
+
+       if (dbus_type != NULL)
+               near_dbus_dict_append_basic(dict, "Type",
+                                   DBUS_TYPE_STRING, &dbus_type);
+
+}
+
+static void append_record(struct near_ndef_record *record,
+                                       DBusMessageIter *dict)
+{
+       char *type = NULL;
+       gboolean representable = FALSE;
+
+       if (record->tnf == RECORD_TNF_WELLKNOWN)
+               return append_rtd(record, dict);
+
+       switch (record->tnf) {
+       case RECORD_TNF_EMPTY:
+               type = "Empty";
+
+       case RECORD_TNF_MIME:
+               type = "MIME";
+               representable = TRUE;
+
+       case RECORD_TNF_URI:
+               type = "URI";
+               representable = TRUE;
+       case RECORD_TNF_EXTERNAL:
+               type = "NFC Forum External";
+       case RECORD_TNF_UNKNOWN:
+               type = "Unknown";
+       case RECORD_TNF_UNCHANGED:
+               type = "Unchanged";
+
+       }
+
+       near_dbus_dict_append_basic(dict, "Type",
+                                   DBUS_TYPE_STRING, &type);
+
+       if (representable == TRUE) {
+               char *value;
+
+               value = g_strndup((char *)record->payload,
+                                       record->payload_length);
+
+               near_dbus_dict_append_basic(dict, "Representation",
+                                   DBUS_TYPE_STRING, &value);
 
-       ndef = g_try_malloc0(sizeof(struct near_ndef));
-       if (ndef == NULL)
+               g_free(value);
+       }
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct near_ndef_record *record = data;
+       DBusMessage *reply;
+       DBusMessageIter array, dict;
+
+       DBG("conn %p", conn);
+
+       reply = dbus_message_new_method_return(msg);
+       if (reply == NULL)
                return NULL;
 
-       ndef->n_records = 0;
+       dbus_message_iter_init_append(reply, &array);
+
+       near_dbus_dict_open(&array, &dict);
+
+       near_dbus_dict_append_basic(&dict, "SmartPoster",
+                                   DBUS_TYPE_BOOLEAN, &record->smart_poster);
+
+       near_dbus_dict_append_basic(&dict, "HandOver",
+                                   DBUS_TYPE_BOOLEAN, &record->hand_over);
+
+       append_record(record, &dict);
+
+       near_dbus_dict_close(&array, &dict);
+
+       return reply;
+}
+
+static GDBusMethodTable record_methods[] = {
+       { "GetProperties",     "",      "a{sv}", get_properties     },
+       { },
+};
+
+int near_ndef_parse(struct near_tag *tag,
+                       uint8_t *ndef_data, size_t ndef_length)
+{
+       struct near_ndef_record *record;
+       uint8_t *raw_record, payload_offset, type_offset;
+       gboolean smart_poster;
+
        raw_record = ndef_data;
 
        while (1) {
                uint8_t mb, me, sr, tnf, il;
+               uint32_t n_records, target_idx, adapter_idx;
                size_t i, type_length;
        
                mb = RECORD_MB(raw_record);
@@ -164,13 +410,11 @@ struct near_ndef *__near_ndef_create(uint8_t *ndef_data, size_t ndef_length)
                tnf = RECORD_TNF(raw_record);
                DBG("Record MB 0x%x ME 0x%x SR 0x%x IL 0x%x TNF 0x%x", mb, me, sr, il, tnf);
 
-               if (ndef->n_records == 0 && mb != 1)
-                       return NULL;
-
                type_offset = record_type_offset(raw_record, &type_length);
 
-               ndef->smart_poster = record_sp(tnf, raw_record + type_offset, type_length);
-               if (ndef->smart_poster == TRUE) {
+               smart_poster = record_sp(tnf, raw_record + type_offset,
+                                                               type_length);
+               if (smart_poster == TRUE) {
                        size_t payload_length;
 
                        DBG("Smart Poster");
@@ -183,10 +427,8 @@ struct near_ndef *__near_ndef_create(uint8_t *ndef_data, size_t ndef_length)
                }
 
                record = g_try_malloc0(sizeof(struct near_ndef_record));
-               if (record == NULL) {
-                       __near_ndef_destroy(ndef);
-                       return NULL;
-               }
+               if (record == NULL)
+                       return -ENOMEM;
 
                record->tnf = tnf;
 
@@ -196,11 +438,25 @@ struct near_ndef *__near_ndef_create(uint8_t *ndef_data, size_t ndef_length)
                type_offset = record_type_offset(raw_record, &record->type_length);
                record->type = raw_record + type_offset;
 
+               record->smart_poster = smart_poster;
+
+               n_records = __near_tag_n_records(tag);
+               target_idx = near_tag_get_target_idx(tag);
+               adapter_idx = near_tag_get_adapter_idx(tag);
+               record->path = g_strdup_printf("%s/nfc%d/target%d/record%d",
+                                               NFC_PATH, adapter_idx, target_idx,
+                                               n_records); 
+
                for (i = 0; i < record->payload_length; i++)
                        DBG("Payload[%d] %c 0x%x", i, record->payload[i], record->payload[i]);
 
-               ndef->n_records += 1;
-               ndef->records = g_list_append(ndef->records, record);
+               DBG("Record path %s", record->path);
+               __near_tag_add_record(tag, record);
+
+               g_dbus_register_interface(connection, record->path,
+                                       NFC_RECORD_INTERFACE,
+                                       record_methods, NULL,
+                                               NULL, record, NULL);
 
                if (me == 1)
                        break;
@@ -208,5 +464,18 @@ struct near_ndef *__near_ndef_create(uint8_t *ndef_data, size_t ndef_length)
                raw_record = record->payload + record->payload_length;
        }
 
-       return ndef;
+       return 0;
+}
+
+int __near_ndef_init(void)
+{
+       DBG("");
+
+       connection = near_dbus_get_connection();
+
+       return 0;
+}
+
+void __near_ndef_cleanup(void)
+{
 }
index 2edfd6b..7483b56 100644 (file)
@@ -102,8 +102,18 @@ void __near_target_remove(uint32_t target_idx);
 int __near_target_init(void);
 void __near_target_cleanup(void);
 
+#include <near/ndef.h>
+
+int __near_ndef_init(void);
+void __near_ndef_cleanup(void);
+void __near_ndef_record_free(struct near_ndef_record *record);
+char *__near_ndef_record_get_path(struct near_ndef_record *record);
+
 #include <near/tag.h>
 
+void __near_tag_append_records(struct near_tag *tag, DBusMessageIter *iter);
+uint32_t __near_tag_n_records(struct near_tag *tag);
+int __near_tag_add_record(struct near_tag *tag, struct near_ndef_record *record);
 struct near_tag *__near_tag_new(uint32_t adapter_idx, uint32_t target_idx,
                                size_t data_length);
 void __near_tag_free(struct near_tag *tag);
@@ -124,8 +134,3 @@ void __near_netlink_cleanup(void);
 
 int __near_plugin_init(const char *pattern, const char *exclude);
 void __near_plugin_cleanup(void);
-
-#include <near/ndef.h>
-
-void __near_ndef_destroy(struct near_ndef *ndef);
-struct near_ndef *__near_ndef_create(uint8_t *ndef_data, size_t ndef_length);
index 446435a..8bf6bb7 100644 (file)
--- a/src/tag.c
+++ b/src/tag.c
@@ -45,11 +45,29 @@ struct near_tag {
        size_t data_length;
        uint8_t *data;
 
-       GList *ndef_list;
+       uint32_t n_records;
+       GList *records;
 };
 
 static GList *driver_list = NULL;
 
+void __near_tag_append_records(struct near_tag *tag, DBusMessageIter *iter)
+{
+       GList *list;
+
+       for (list = tag->records; list; list = list->next) {
+               struct near_ndef_record *record = list->data;
+               char *path;
+
+               path = __near_ndef_record_get_path(record);
+               if (path == NULL)
+                       continue;
+
+               dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+                                                       &path);
+       }
+}
+
 static int tag_initialize(struct near_tag *tag,
                        uint32_t adapter_idx, uint32_t target_idx,
                                size_t data_length)
@@ -58,6 +76,7 @@ static int tag_initialize(struct near_tag *tag,
 
        tag->adapter_idx = adapter_idx;
        tag->target_idx = target_idx;
+       tag->n_records = 0;
 
        if (data_length > 0) {
                tag->data_length = data_length;
@@ -87,10 +106,35 @@ struct near_tag *__near_tag_new(uint32_t adapter_idx, uint32_t target_idx, size_
 
 void __near_tag_free(struct near_tag *tag)
 {
+       GList *list;
+
+       for (list = tag->records; list; list = list->next) {
+               struct near_ndef_record *record = list->data;
+
+               __near_ndef_record_free(record);
+       }
+
+       g_list_free(tag->records);
        g_free(tag->data);
        g_free(tag);
 }
 
+uint32_t __near_tag_n_records(struct near_tag *tag)
+{
+       return tag->n_records;
+}
+
+int __near_tag_add_record(struct near_tag *tag,
+                               struct near_ndef_record *record)
+{
+       DBG("");
+
+       tag->n_records++;
+       tag->records = g_list_append(tag->records, record);
+
+       return 0;
+}
+
 int near_tag_set_uid(struct near_tag *tag, uint8_t *uid, size_t uid_length)
 {
        if (uid_length > TAG_UID_MAX_LEN)
@@ -122,19 +166,6 @@ uint32_t near_tag_get_target_idx(struct near_tag *tag)
        return tag->target_idx;
 }
 
-int near_tag_add_ndef(struct near_tag *tag, uint8_t *ndef_data, size_t ndef_length)
-{
-       struct near_ndef *ndef;
-
-       ndef = __near_ndef_create(ndef_data, ndef_length);
-       if (ndef == NULL)
-               return -ENOMEM;
-
-       tag->ndef_list = g_list_append(tag->ndef_list, ndef);
-
-       return 0;
-}
-
 int near_tag_driver_register(struct near_tag_driver *driver)
 {
        DBG("");
index a641e3a..43e9008 100644 (file)
@@ -190,6 +190,18 @@ static const char *type2string(enum near_target_type type)
        return NULL;
 }
 
+static void append_records(DBusMessageIter *iter, void *user_data)
+{
+       struct near_target *target = user_data;
+
+       DBG("");
+
+       if (target->tag == NULL)
+               return;
+
+       __near_tag_append_records(target->tag, iter);
+}
+
 static DBusMessage *get_properties(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
@@ -217,10 +229,14 @@ static DBusMessage *get_properties(DBusConnection *conn,
                near_dbus_dict_append_array(&dict, "Protocols",
                                DBUS_TYPE_STRING, append_protocols, target);
 
-       if (target->type == NEAR_TARGET_TYPE_TAG)
+       if (target->type == NEAR_TARGET_TYPE_TAG) {
                near_dbus_dict_append_array(&dict, "TagType",
                                DBUS_TYPE_STRING, append_tag_type, target);
 
+               near_dbus_dict_append_array(&dict, "Records",
+                               DBUS_TYPE_OBJECT_PATH, append_records, target);
+       }
+
        near_dbus_dict_close(&array, &dict);
 
        return reply;
diff --git a/test/dump-record b/test/dump-record
new file mode 100755 (executable)
index 0000000..37d6573
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+
+def extract_list(list):
+       val = "["
+       for i in list:
+               val += " " + str(i)
+       val += " ]"
+       return val
+
+bus = dbus.SessionBus()
+
+record = dbus.Interface(bus.get_object("org.neard", sys.argv[1]),
+                                               "org.neard.Record")
+
+properties = record.GetProperties()
+
+print "[ %s ]" % (sys.argv[1])
+
+for key in properties.keys():
+    if key in ["SmartPoster", "HandOver"]:
+            if properties[key] == dbus.Boolean(1):
+                val = "true"
+            else:
+                val = "false"
+    else:
+       val = str(properties[key])
+
+    print "        %s = %s" % (key, val)
\ No newline at end of file
diff --git a/test/dump-target b/test/dump-target
new file mode 100755 (executable)
index 0000000..416e609
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+
+bus = dbus.SessionBus()
+
+def extract_list(list):
+       val = "["
+       for i in list:
+               val += " " + str(i)
+       val += " ]"
+       
+       return val
+
+def extract_record(key, list):
+       for i in list:
+               record = dbus.Interface(bus.get_object("org.neard", i),
+                                               "org.neard.Record")
+
+               properties = record.GetProperties()
+               print "        Record = [ %s ]" % (str(i))
+
+               for key in properties.keys():
+                       if key in ["SmartPoster", "HandOver"]:
+                               if properties[key] == dbus.Boolean(1):
+                                       val = "true"
+                               else:
+                                       val = "false"
+                       else:
+                               val = str(properties[key])
+
+                       print "                %s = %s" % (key, val)
+
+
+target = dbus.Interface(bus.get_object("org.neard", sys.argv[1]),
+                                               "org.neard.Target")
+
+properties = target.GetProperties()
+
+print "[ %s ]" % (sys.argv[1])
+
+for key in properties.keys():
+    if key in ["TagType"]:
+        val = extract_list(properties[key])
+       print "        %s = %s" % (key, val)
+    elif key in ["Type"]:
+       val = str(properties[key])
+       print "        %s = %s" % (key, val)
+
+    if key in ["Records"]:
+        extract_record(key, properties[key])
+
+