+static void eventloop (afb_req_t request)
+{
+ afb_api_t api = afb_req_get_api(request);
+ struct sd_event *ev = afb_api_get_event_loop(api);
+ afb_req_reply(request, NULL, ev ? NULL : "no-event-loop", NULL);
+}
+
+static void dbus (afb_req_t request)
+{
+ afb_api_t api = afb_req_get_api(request);
+ json_object *json = afb_req_json(request);
+ struct sd_bus *bus = (json_object_get_boolean(json) ? afb_api_get_system_bus : afb_api_get_user_bus)(api);
+ afb_req_reply(request, NULL, bus ? NULL : "no-bus", NULL);
+}
+
+static void replycount (afb_req_t request)
+{
+ json_object *json = afb_req_json(request);
+ int count = json_object_get_int(json);
+ while (count-- > 0)
+ afb_req_reply(request, NULL, NULL, NULL);
+}
+
+static void get(afb_req_t request)
+{
+ struct afb_arg arg = afb_req_get(request, "name");
+ const char *name, *value, *path;
+
+ if (!arg.name || !arg.value)
+ afb_req_reply(request, NULL, "invalid", "the parameter 'name' is missing");
+ else {
+ name = arg.name;
+ value = afb_req_value(request, name);
+ path = afb_req_path(request, name);
+ afb_req_reply_f(request, NULL, NULL, "found for '%s': %s", name, value ?: path ?: "NULL");
+ }
+}
+
+static void ref(afb_req_t request)
+{
+ afb_req_addref(request);
+ afb_req_reply(request, NULL, NULL, NULL);
+ afb_req_unref(request);
+}
+
+static void mute(afb_req_t request)
+{
+}
+
+static void mutebug(afb_req_t request)
+{
+ afb_req_addref(request);
+}
+
+void queue_cb(int signum, void *arg)
+{
+ afb_req_t request = arg;
+ afb_req_reply(request, NULL, NULL, NULL);
+ afb_req_unref(request);
+}
+
+static void queue(afb_req_t request)
+{
+ afb_req_addref(request);
+ afb_api_queue_job(afb_req_get_api(request), queue_cb, request, NULL, 0);
+}
+
+static void settings(afb_req_t request)
+{
+ afb_api_t api = afb_req_get_api(request);
+ struct json_object *object = afb_api_settings(api);
+ afb_req_reply(request, json_object_get(object), NULL, NULL);
+}
+
+static void rootdir (afb_req_t request)
+{
+ ssize_t s;
+ afb_api_t api = afb_req_get_api(request);
+ int fd = afb_api_rootdir_get_fd(api);
+ char buffer[150], root[1025];
+ sprintf(buffer, "/proc/self/fd/%d", fd);
+ s = readlink(buffer, root, sizeof root - 1);
+ if (s < 0)
+ afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
+ else {
+ root[s] = 0;
+ afb_req_reply(request, json_object_new_string(root), NULL, NULL);
+ }
+}
+
+static void locale (afb_req_t request)
+{
+ char buffer[150], root[1025];
+ const char *lang, *file;
+ ssize_t s;
+ json_object *json = afb_req_json(request), *x;
+ afb_api_t api = afb_req_get_api(request);
+ int fd;
+
+ lang = NULL;
+ if (json_object_is_type(json, json_type_string))
+ file = json_object_get_string(json);
+ else {
+ if (!json_object_object_get_ex(json, "file", &x)) {
+ afb_req_reply(request, NULL, "invalid", "no file");
+ return;
+ }
+ file = json_object_get_string(x);
+ if (json_object_object_get_ex(json, "lang", &x))
+ lang = json_object_get_string(x);
+ }
+
+ fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
+ if (fd < 0)
+ afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
+ else {
+ sprintf(buffer, "/proc/self/fd/%d", fd);
+ s = readlink(buffer, root, sizeof root - 1);
+ if (s < 0)
+ afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
+ else {
+ root[s] = 0;
+ afb_req_reply(request, json_object_new_string(root), NULL, NULL);
+ }
+ close(fd);
+ }
+}
+
+static void in_after (afb_req_t request)
+{
+ int rc;
+ const char *ts, *ty;
+ char *te;
+ double td;
+ struct timespec t;
+
+ /* get the type */
+ ty = afb_req_value(request, "type") ?: "call";
+ if (strcmp(ty, "call") && strcmp(ty, "callsync")
+ && strcmp(ty, "subcall") && strcmp(ty, "subcallsync"))
+ return afb_req_reply(request, NULL, "invalid", "bad type");
+
+ /* get the delay */
+ ts = afb_req_value(request, "delay");
+ if (!ts)
+ return afb_req_reply(request, NULL, "invalid", "no delay");
+ td = strtod(ts, &te);
+ if (*te || td < 0 || td > 3e6) /* a month is the biggest accepted */
+ return afb_req_reply(request, NULL, "invalid", "bad delay");
+
+ /* wait for that time */
+ if (td > 0) {
+ t.tv_nsec = (long)(1e6 * modf(td, &td));
+ t.tv_sec = (time_t)td;
+ do {
+ rc = nanosleep(&t, &t);
+ } while (rc != 0 && errno == EINTR);
+
+ if (rc)
+ return afb_req_reply(request, NULL, "error", "sleep failed");
+ }
+
+ /* do the call */
+ if (!strcmp(ty, "subcallsync"))
+ subcall(request);
+ else if (!strcmp(ty, "subcall"))
+ subcallsync(request);
+ else if (!strcmp(ty, "callsync"))
+ callsync(request);
+ else
+ call(request);
+}
+
+static void *thread_after (void *closure)
+{
+ afb_req_t request = closure;
+ in_after (request);
+ afb_req_unref(request);
+ return NULL;
+}
+
+static void after (afb_req_t request)
+{
+ int rc;
+ pthread_t tid;
+ pthread_attr_t attr;
+
+ afb_req_addref(request);
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ rc =pthread_create(&tid, &attr, thread_after, request);
+ pthread_attr_destroy(&attr);
+
+ if (rc != 0) {
+ afb_req_unref(request);
+ afb_req_reply(request, NULL, "cant-start", NULL);
+ }
+}
+
+static void api (afb_req_t request);
+
+/**
+ * Definition of an authorization entry
+ */
+static struct afb_auth auths[] = {
+ { /* 0 */
+ .type = afb_auth_Or,
+ .first = &auths[1],
+ .next = &auths[9],
+ },
+ { /* 1 */
+ .type = afb_auth_And,
+ .first = &auths[2],
+ .next = &auths[3],
+ },
+ { /* 2 */
+ .type = afb_auth_Yes
+ },
+ { /* 3 */
+ .type = afb_auth_And,
+ .first = &auths[4],
+ .next = &auths[5],
+ },
+ { /* 4 */
+ .type = afb_auth_LOA,
+ .loa = 0
+ },
+ { /* 5 */
+ .type = afb_auth_Or,
+ .first = &auths[6],
+ .next = &auths[7],
+ },
+ { /* 6 */
+ .type = afb_auth_No
+ },
+ { /* 7 */
+ .type = afb_auth_Not,
+ .first = &auths[8]
+ },
+ { /* 8 */
+ .type = afb_auth_Yes
+ },
+ { /* 9 */
+ .type = afb_auth_And,
+ .first = &auths[10],
+ .next = &auths[13],
+ },
+ { /* 10 */
+ .type = afb_auth_Or,
+ .first = &auths[12],
+ .next = &auths[11],
+ },
+ { /* 11 */
+ .type = afb_auth_Not,
+ .first = &auths[13]
+ },
+ { /* 12 */
+ .type = afb_auth_Token
+ },
+ { /* 13 */
+ .type = afb_auth_And,
+ .first = &auths[14],
+ .next = &auths[17],
+ },
+ { /* 14 */
+ .type = afb_auth_Or,
+ .first = &auths[16],
+ .next = &auths[15],
+ },
+ { /* 15 */
+ .type = afb_auth_Not,
+ .first = &auths[16]
+ },
+ { /* 16 */
+ .type = afb_auth_Permission,
+ .text = "permission"
+ },
+ { /* 17 */
+ .type = afb_auth_Yes
+ }
+};
+
+