summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--guix.scm9
-rw-r--r--src/libdisfluid/Makefile.am1
-rw-r--r--src/libdisfluid/disfluid-activity-object.h100
-rw-r--r--src/libdisfluid/disfluid-tests.h154
-rw-r--r--src/libdisfluid/main.c1
6 files changed, 270 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac
index 2d8bec8..408eedc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -52,6 +52,11 @@ PKG_CHECK_MODULES([GNUTLS], [gnutls], [
CFLAGS="$CFLAGS $GNUTLS_CFLAGS"
LIBS="$LIBS $GNUTLS_LIBS"
], [AC_MSG_WARN([pkg-config does not know the "gnutls" module])])
+PKG_CHECK_MODULES([JANSSON], [jansson], [
+ CPPFLAGS="$CPPFLAGS $JANSSON_CFLAGS"
+ CFLAGS="$CFLAGS $JANSSON_CFLAGS"
+ LIBS="$LIBS $JANSSON_LIBS"
+], [AC_MSG_WARN([pkg-config does not know the "jansson" module])])
AS_IF([test "x$with_gobject" != xno],
[PKG_CHECK_MODULES([GOBJECT], [gobject-2.0],, [AC_MSG_WARN([pkg-config does not know the "gobject-2.0" module])])])
AS_IF([test "x$with_gtk" != xno],
@@ -59,7 +64,7 @@ AS_IF([test "x$with_gtk" != xno],
PKG_CHECK_MODULES([ADW], [libadwaita-1],, [AC_MSG_WARN([pkg-config does not know the "libadwaita-1" module])])])
# Checks for header files.
-AC_CHECK_HEADERS([check.h gnutls/gnutls.h gnutls/crypto.h],,
+AC_CHECK_HEADERS([check.h gnutls/gnutls.h gnutls/crypto.h jansson.h],,
[AC_MSG_ERROR([Required library headers not found.])])
SAVE_CPPFLAGS="$CPPFLAGS"
@@ -95,8 +100,9 @@ gl_VISIBILITY
# Checks for library functions.
AC_SEARCH_LIBS([srunner_create], [check])
AC_SEARCH_LIBS([gnutls_hmac_init], [gnutls])
+AC_SEARCH_LIBS([json_loads], [jansson])
-AC_CHECK_FUNCS([srunner_create gnutls_hmac_init],,
+AC_CHECK_FUNCS([srunner_create gnutls_hmac_init json_loads],,
[AC_MSG_ERROR([Required library functions not found.])])
SAVE_LIBS="$LIBS"
diff --git a/guix.scm b/guix.scm
index 78747a9..800f445 100644
--- a/guix.scm
+++ b/guix.scm
@@ -20,6 +20,7 @@
#:use-module (gnu packages tls)
#:use-module (gnu packages valgrind)
#:use-module (gnu packages version-control)
+ #:use-module (gnu packages web)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix build utils)
#:use-module (guix build-system gnu)
@@ -230,7 +231,9 @@
'("autopull.sh" "autogen.sh"))
(substitute* "bootstrap-funclib.sh"
(("\\$gnulib_tool \\$gnulib_tool_options")
- "sh $gnulib_tool $gnulib_tool_options"))))
+ "sh $gnulib_tool $gnulib_tool_options"))
+ (substitute* "maint.mk"
+ (("lcov") "lcov --no-external"))))
(add-after 'bootstrap 'fix-/bin/sh-in-po
(lambda _
(substitute*
@@ -351,7 +354,7 @@
gobject-introspection imagemagick
indent cppi vala lcov perl-gd))
(inputs
- (list gtk libadwaita check gnu-gettext gnutls))
+ (list gtk libadwaita check gnu-gettext gnutls jansson))
(home-page "https://labo.planete-kraus.eu/disfluid.git")
(synopsis "Demanding Interoperability to Strengthen the Free/Libre Web: Introducing Disfluid")
(description "This provides tools for web interoperability.")
@@ -395,4 +398,4 @@
(list valgrind (list glibc "debug") pkg-config
texinfo (texlive-updmap.cfg (list texlive)) tar gzip))
(inputs
- (list gnu-gettext gtk libadwaita check gnutls)))
+ (list gnu-gettext gtk libadwaita check gnutls jansson)))
diff --git a/src/libdisfluid/Makefile.am b/src/libdisfluid/Makefile.am
index 33000e8..55abf4e 100644
--- a/src/libdisfluid/Makefile.am
+++ b/src/libdisfluid/Makefile.am
@@ -1,6 +1,7 @@
lib_LTLIBRARIES += %D%/libdisfluid.la
%C%_libdisfluid_la_SOURCES = \
+ %D%/disfluid-activity-object.h \
%D%/disfluid-authors.h \
%D%/disfluid-append-only-file.h \
%D%/disfluid-cache-entry.h \
diff --git a/src/libdisfluid/disfluid-activity-object.h b/src/libdisfluid/disfluid-activity-object.h
new file mode 100644
index 0000000..d079f89
--- /dev/null
+++ b/src/libdisfluid/disfluid-activity-object.h
@@ -0,0 +1,100 @@
+#ifndef DISFLUID_ACTIVITY_OBJECT_INCLUDED
+# define DISFLUID_ACTIVITY_OBJECT_INCLUDED
+
+# include <config.h>
+# include "string-desc.h"
+# include <jansson.h>
+
+MAYBE_UNUSED static int
+activity_object_context_prefix (json_t * object,
+ string_desc_t * context_prefix);
+
+# include "disfluid-append-only-file.h"
+# include "safe-alloc.h"
+
+static bool
+activity_object_is_as (json_t * value, bool with_hash)
+{
+ static const char *as = "https://www.w3.org/ns/activitystreams#";
+ const size_t as_len_h = strlen (as);
+ const size_t as_len_s = as_len_h - 1;
+ size_t as_len = as_len_s;
+ if (with_hash)
+ {
+ as_len = as_len_h;
+ }
+ return (json_is_string (value)
+ && json_string_length (value) == as_len
+ && strncmp (json_string_value (value), as, as_len) == 0);
+}
+
+static int
+activity_object_context_prefix (json_t * object,
+ string_desc_t * context_prefix)
+{
+ context_prefix->_nbytes = 0;
+ context_prefix->_data = NULL;
+ if (!json_is_object (object))
+ {
+ return -1;
+ }
+ json_t *context = json_object_get (object, "@context");
+ if (activity_object_is_as (context, false))
+ {
+ /* This is the only context. */
+ context_prefix->_nbytes = 0;
+ context_prefix->_data = NULL;
+ return 0;
+ }
+ else if (json_is_object (context))
+ {
+ json_t *vocab = json_object_get (context, "@vocab");
+ if (activity_object_is_as (vocab, true))
+ {
+ /* Also not prefixed. */
+ context_prefix->_nbytes = 0;
+ context_prefix->_data = NULL;
+ return 0;
+ }
+ /* Maybe it is a value of the context object. */
+ const char *key;
+ json_t *value;
+ context_prefix->_nbytes = 0;
+ context_prefix->_data = NULL;
+ json_object_foreach (context, key, value)
+ {
+ if (key[0] != '@' && activity_object_is_as (value, true))
+ {
+ FREE (context_prefix->_data);
+ context_prefix->_nbytes = strlen (key) + 1; /* for the final : */
+ if (ALLOC_N (context_prefix->_data, context_prefix->_nbytes) < 0)
+ {
+ return -2;
+ }
+ memcpy (context_prefix->_data, key, context_prefix->_nbytes - 1);
+ context_prefix->_data[context_prefix->_nbytes - 1] = ':';
+ }
+ }
+ if (context_prefix->_data != NULL)
+ {
+ return 0;
+ }
+ }
+ else if (json_is_array (context))
+ {
+ size_t n = json_array_size (context);
+ for (size_t i = 0; i < n; i++)
+ {
+ json_t *value = json_array_get (context, i);
+ if (activity_object_is_as (value, false))
+ {
+ context_prefix->_nbytes = 0;
+ context_prefix->_data = NULL;
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+#endif /* not DISFLUID_ACTIVITY_OBJECT_INCLUDED */
diff --git a/src/libdisfluid/disfluid-tests.h b/src/libdisfluid/disfluid-tests.h
index bcc50b4..98cbdf3 100644
--- a/src/libdisfluid/disfluid-tests.h
+++ b/src/libdisfluid/disfluid-tests.h
@@ -20,6 +20,9 @@ static inline int test_append_count (const char *filename, size_t *n);
# include "disfluid-append-only-file.h"
# include "disfluid-trie.h"
# include "disfluid-cache-group.h"
+# include "disfluid-activity-object.h"
+
+# include <jansson.h>
# define BYTES * 1
@@ -1220,6 +1223,150 @@ START_TEST (test_aof_cache_group)
END_TEST
/* *INDENT-ON* */
+/* *INDENT-OFF* */
+START_TEST (test_activity_context_1)
+/* *INDENT-ON* */
+
+{
+ static const char *activity =
+ "{"
+ "\"@context\": \"https://www.w3.org/ns/activitystreams\","
+ "\"summary\": \"A note\","
+ "\"type\": \"Note\"," "\"content\": \"My dog has fleas.\"" "}";
+ json_error_t error;
+ json_t *object = json_loads (activity, 0, &error);
+ ck_assert_ptr_nonnull (object);
+ string_desc_t prefix;
+ int ctx_error = activity_object_context_prefix (object, &prefix);
+ ck_assert_int_eq (ctx_error, 0);
+ ck_assert_int_eq (prefix._nbytes, 0);
+ ck_assert_ptr_null (prefix._data);
+ json_decref (object);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+START_TEST (test_activity_context_2)
+/* *INDENT-ON* */
+
+{
+ static const char *activity =
+ "{"
+ "\"@context\": {"
+ "\"@vocab\": \"https://www.w3.org/ns/activitystreams#\","
+ "\"ext\": \"https://canine-extension.example/terms/\","
+ "\"@language\": \"en\""
+ "},"
+ "\"summary\": \"A note\","
+ "\"type\": \"Note\","
+ "\"content\": \"My dog has fleas.\","
+ "\"ext:nose\": 0," "\"ext:smell\": \"terrible\"" "}";
+ json_error_t error;
+ json_t *object = json_loads (activity, 0, &error);
+ ck_assert_ptr_nonnull (object);
+ string_desc_t prefix;
+ int ctx_error = activity_object_context_prefix (object, &prefix);
+ ck_assert_int_eq (ctx_error, 0);
+ ck_assert_int_eq (prefix._nbytes, 0);
+ ck_assert_ptr_null (prefix._data);
+ json_decref (object);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+START_TEST (test_activity_context_2bis)
+/* *INDENT-ON* */
+
+{
+ static const char *activity =
+ "{"
+ "\"@context\": {"
+ "\"@vocab\": \"https://example.com/\","
+ "\"as\": \"https://www.w3.org/ns/activitystreams#\","
+ "\"ext\": \"https://canine-extension.example/terms/\","
+ "\"@language\": \"en\""
+ "},"
+ "\"as:summary\": \"A note\","
+ "\"as:type\": \"Note\","
+ "\"as:content\": \"My dog has fleas.\","
+ "\"ext:nose\": 0," "\"ext:smell\": \"terrible\"" "}";
+ json_error_t error;
+ json_t *object = json_loads (activity, 0, &error);
+ ck_assert_ptr_nonnull (object);
+ string_desc_t prefix;
+ int ctx_error = activity_object_context_prefix (object, &prefix);
+ ck_assert_int_eq (ctx_error, 0);
+ ck_assert_int_eq (prefix._nbytes, 3);
+ ck_assert_int_eq (memcmp (prefix._data, "as:", 3), 0);
+ FREE (prefix._data);
+ json_decref (object);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+START_TEST (test_activity_context_3)
+/* *INDENT-ON* */
+
+{
+ static const char *activity =
+ "{"
+ "\"@context\": ["
+ "\"https://www.w3.org/ns/activitystreams\","
+ "{"
+ "\"css\": \"http://www.w3.org/ns/oa#styledBy\""
+ "}"
+ "],"
+ "\"summary\": \"A note\","
+ "\"type\": \"Note\","
+ "\"content\": \"My dog has fleas.\","
+ "\"css\": \"http://www.csszengarden.com/217/217.css?v=8may2013\"" "}";
+ json_error_t error;
+ json_t *object = json_loads (activity, 0, &error);
+ ck_assert_ptr_nonnull (object);
+ string_desc_t prefix;
+ int ctx_error = activity_object_context_prefix (object, &prefix);
+ ck_assert_int_eq (ctx_error, 0);
+ ck_assert_int_eq (prefix._nbytes, 0);
+ ck_assert_ptr_null (prefix._data);
+ json_decref (object);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+START_TEST (test_activity_context_none)
+/* *INDENT-ON* */
+
+{
+ static const char *activity =
+ "{"
+ "\"http://schema.org/name\": \"Manu Sporny\","
+ "\"http://schema.org/url\": {"
+ "\"@id\": \"http://manu.sporny.org/\""
+ "},"
+ "\"http://schema.org/image\": {"
+ "\"@id\": \"http://manu.sporny.org/images/manu.png\"" "}" "}";
+ json_error_t error;
+ json_t *object = json_loads (activity, 0, &error);
+ ck_assert_ptr_nonnull (object);
+ string_desc_t prefix;
+ int ctx_error = activity_object_context_prefix (object, &prefix);
+ ck_assert_int_lt (ctx_error, 0);
+ ck_assert_int_eq (prefix._nbytes, 0);
+ ck_assert_ptr_null (prefix._data);
+ json_decref (object);
+}
+/* *INDENT-OFF* */
+END_TEST
+/* *INDENT-ON* */
+
static inline char *
tests_read_whole_file (int file)
{
@@ -1281,6 +1428,13 @@ run_tests (size_t *n_tests, size_t *n_errors)
tcase_add_test (aof, test_aof_can_read_locked_file);
tcase_add_test (aof, test_aof_trie_fold);
suite_add_tcase (suite, aof);
+ TCase *activity = tcase_create (_("activity"));
+ tcase_add_test (activity, test_activity_context_1);
+ tcase_add_test (activity, test_activity_context_2);
+ tcase_add_test (activity, test_activity_context_2bis);
+ tcase_add_test (activity, test_activity_context_3);
+ tcase_add_test (activity, test_activity_context_none);
+ suite_add_tcase (suite, activity);
SRunner *runner = srunner_create (suite);
char log_file_name[] = "/tmp/disfluid-unit-tests-XXXXXX";
int log_file = mkstemp (log_file_name);
diff --git a/src/libdisfluid/main.c b/src/libdisfluid/main.c
index 3a6c5e3..792dc84 100644
--- a/src/libdisfluid/main.c
+++ b/src/libdisfluid/main.c
@@ -20,6 +20,7 @@
#define _(String) dgettext (PACKAGE, (String))
#define N_(String) (String)
+#include "disfluid-activity-object.h"
#include "disfluid-authors.h"
#include "disfluid-cache-entry.h"
#include "disfluid-cache-entry-key.h"