hello3: Add verb 'after'
[src/app-framework-binder.git] / bindings / samples / hello3.c
1 /*
2  * Copyright (C) 2015-2018 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <string.h>
20 #include <pthread.h>
21 #include <fcntl.h>
22 #include <math.h>
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include <json-c/json.h>
29
30 #define AFB_BINDING_VERSION 3
31 #include <afb/afb-binding.h>
32
33 #if !defined(APINAME)
34 #define APINAME "hello"
35 #endif
36
37 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
38
39 /**************************************************************************/
40
41 struct event
42 {
43         struct event *next;
44         afb_event_t event;
45         char tag[1];
46 };
47
48 static struct event *events = 0;
49
50 /* searchs the event of tag */
51 static struct event *event_get(const char *tag)
52 {
53         struct event *e = events;
54         while(e && strcmp(e->tag, tag))
55                 e = e->next;
56         return e;
57 }
58
59 /* deletes the event of tag */
60 static int event_del(const char *tag)
61 {
62         struct event *e, **p;
63
64         /* check exists */
65         e = event_get(tag);
66         if (!e) return -1;
67
68         /* unlink */
69         p = &events;
70         while(*p != e) p = &(*p)->next;
71         *p = e->next;
72
73         /* destroys */
74         afb_event_unref(e->event);
75         free(e);
76         return 0;
77 }
78
79 /* creates the event of tag */
80 static int event_add(const char *tag, const char *name)
81 {
82         struct event *e;
83
84         /* check valid tag */
85         e = event_get(tag);
86         if (e) return -1;
87
88         /* creation */
89         e = malloc(strlen(tag) + sizeof *e);
90         if (!e) return -1;
91         strcpy(e->tag, tag);
92
93         /* make the event */
94         e->event = afb_daemon_make_event(name);
95         if (!e->event) { free(e); return -1; }
96
97         /* link */
98         e->next = events;
99         events = e;
100         return 0;
101 }
102
103 static int event_subscribe(afb_req_t request, const char *tag)
104 {
105         struct event *e;
106         e = event_get(tag);
107         return e ? afb_req_subscribe(request, e->event) : -1;
108 }
109
110 static int event_unsubscribe(afb_req_t request, const char *tag)
111 {
112         struct event *e;
113         e = event_get(tag);
114         return e ? afb_req_unsubscribe(request, e->event) : -1;
115 }
116
117 static int event_push(struct json_object *args, const char *tag)
118 {
119         struct event *e;
120         e = event_get(tag);
121         return e ? afb_event_push(e->event, json_object_get(args)) : -1;
122 }
123
124 static int event_broadcast(struct json_object *args, const char *tag)
125 {
126         struct event *e;
127         e = event_get(tag);
128         return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1;
129 }
130
131 /**************************************************************************/
132
133 struct api
134 {
135         struct api *next;
136         afb_api_t api;
137         char name[1];
138 };
139
140 static struct api *apis = 0;
141
142 /* search the api of name */
143 static struct api *searchapi(const char *name, struct api ***previous)
144 {
145         struct api *a, **p = &apis;
146         while((a = *p) && strcmp(a->name, name))
147                 p = &a->next;
148         if (previous)
149                 *previous = p;
150         return a;
151 }
152
153 /**************************************************************************/
154
155 // Sample Generic Ping Debug API
156 static void ping(afb_req_t request, json_object *jresp, const char *tag)
157 {
158         static int pingcount = 0;
159         json_object *query = afb_req_json(request);
160         afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
161 }
162
163 static void pingSample (afb_req_t request)
164 {
165         ping(request, json_object_new_string ("Some String"), "pingSample");
166 }
167
168 static void pingFail (afb_req_t request)
169 {
170         afb_req_fail(request, "failed", "Ping Binder Daemon fails");
171 }
172
173 static void pingNull (afb_req_t request)
174 {
175         ping(request, NULL, "pingNull");
176 }
177
178 static void pingBug (afb_req_t request)
179 {
180         ping(NULL, NULL, "pingBug");
181 }
182
183 static void pingEvent(afb_req_t request)
184 {
185         json_object *query = afb_req_json(request);
186         afb_daemon_broadcast_event("event", json_object_get(query));
187         ping(request, json_object_get(query), "event");
188 }
189
190
191 // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
192 static void pingJson (afb_req_t request) {
193     json_object *jresp, *embed;
194
195     jresp = json_object_new_object();
196     json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
197     json_object_object_add(jresp, "myInt", json_object_new_int (1234));
198
199     embed  = json_object_new_object();
200     json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
201     json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
202
203     json_object_object_add(jresp,"eobj", embed);
204
205     ping(request, jresp, "pingJson");
206 }
207
208 static void subcallcb (void *prequest, int status, json_object *object, afb_req_t request)
209 {
210         if (status < 0)
211                 afb_req_fail(request, "failed", json_object_to_json_string(object));
212         else
213                 afb_req_success(request, json_object_get(object), NULL);
214 }
215
216 static void subcall (afb_req_t request)
217 {
218         const char *api = afb_req_value(request, "api");
219         const char *verb = afb_req_value(request, "verb");
220         const char *args = afb_req_value(request, "args");
221         json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
222
223         if (object == NULL)
224                 afb_req_fail(request, "failed", "bad arguments");
225         else
226                 afb_req_subcall_legacy(request, api, verb, object, subcallcb, NULL);
227 }
228
229 static void subcallreqcb (void *prequest, int status, json_object *object, afb_req_t request)
230 {
231         if (status < 0)
232                 afb_req_fail(request, "failed", json_object_to_json_string(object));
233         else
234                 afb_req_success(request, json_object_get(object), NULL);
235 }
236
237 static void subcallreq (afb_req_t request)
238 {
239         const char *api = afb_req_value(request, "api");
240         const char *verb = afb_req_value(request, "verb");
241         const char *args = afb_req_value(request, "args");
242         json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
243
244         if (object == NULL)
245                 afb_req_fail(request, "failed", "bad arguments");
246         else
247                 afb_req_subcall_legacy(request, api, verb, object, subcallreqcb, NULL);
248 }
249
250 static void subcallsync (afb_req_t request)
251 {
252         int rc;
253         const char *api = afb_req_value(request, "api");
254         const char *verb = afb_req_value(request, "verb");
255         const char *args = afb_req_value(request, "args");
256         json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
257
258         if (object == NULL)
259                 afb_req_fail(request, "failed", "bad arguments");
260         else {
261                 rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result);
262                 if (rc >= 0)
263                         afb_req_success(request, result, NULL);
264                 else {
265                         afb_req_fail(request, "failed", json_object_to_json_string(result));
266                         json_object_put(result);
267                 }
268         }
269 }
270
271 static void eventadd (afb_req_t request)
272 {
273         const char *tag = afb_req_value(request, "tag");
274         const char *name = afb_req_value(request, "name");
275
276         pthread_mutex_lock(&mutex);
277         if (tag == NULL || name == NULL)
278                 afb_req_fail(request, "failed", "bad arguments");
279         else if (0 != event_add(tag, name))
280                 afb_req_fail(request, "failed", "creation error");
281         else
282                 afb_req_success(request, NULL, NULL);
283         pthread_mutex_unlock(&mutex);
284 }
285
286 static void eventdel (afb_req_t request)
287 {
288         const char *tag = afb_req_value(request, "tag");
289
290         pthread_mutex_lock(&mutex);
291         if (tag == NULL)
292                 afb_req_fail(request, "failed", "bad arguments");
293         else if (0 != event_del(tag))
294                 afb_req_fail(request, "failed", "deletion error");
295         else
296                 afb_req_success(request, NULL, NULL);
297         pthread_mutex_unlock(&mutex);
298 }
299
300 static void eventsub (afb_req_t request)
301 {
302         const char *tag = afb_req_value(request, "tag");
303
304         pthread_mutex_lock(&mutex);
305         if (tag == NULL)
306                 afb_req_fail(request, "failed", "bad arguments");
307         else if (0 != event_subscribe(request, tag))
308                 afb_req_fail(request, "failed", "subscription error");
309         else
310                 afb_req_success(request, NULL, NULL);
311         pthread_mutex_unlock(&mutex);
312 }
313
314 static void eventunsub (afb_req_t request)
315 {
316         const char *tag = afb_req_value(request, "tag");
317
318         pthread_mutex_lock(&mutex);
319         if (tag == NULL)
320                 afb_req_fail(request, "failed", "bad arguments");
321         else if (0 != event_unsubscribe(request, tag))
322                 afb_req_fail(request, "failed", "unsubscription error");
323         else
324                 afb_req_success(request, NULL, NULL);
325         pthread_mutex_unlock(&mutex);
326 }
327
328 static void eventpush (afb_req_t request)
329 {
330         const char *tag = afb_req_value(request, "tag");
331         const char *data = afb_req_value(request, "data");
332         json_object *object = data ? json_tokener_parse(data) : NULL;
333
334         pthread_mutex_lock(&mutex);
335         if (tag == NULL)
336                 afb_req_fail(request, "failed", "bad arguments");
337         else if (0 > event_push(object, tag))
338                 afb_req_fail(request, "failed", "push error");
339         else
340                 afb_req_success(request, NULL, NULL);
341         pthread_mutex_unlock(&mutex);
342         json_object_put(object);
343 }
344
345 static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api)
346 {
347         afb_req_t request = prequest;
348         afb_req_reply(request, json_object_get(object), error, info);
349         afb_req_unref(request);
350 }
351
352 static void call (afb_req_t request)
353 {
354         const char *api = afb_req_value(request, "api");
355         const char *verb = afb_req_value(request, "verb");
356         const char *args = afb_req_value(request, "args");
357         json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
358
359         afb_service_call(api, verb, object, callcb, afb_req_addref(request));
360 }
361
362 static void callsync (afb_req_t request)
363 {
364         const char *api = afb_req_value(request, "api");
365         const char *verb = afb_req_value(request, "verb");
366         const char *args = afb_req_value(request, "args");
367         json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
368         json_object *result;
369         char *error, *info;
370
371         afb_service_call_sync(api, verb, object, &result, &error, &info);
372         afb_req_reply(request, result, error, info);
373         free(error);
374         free(info);
375 }
376
377 static void verbose (afb_req_t request)
378 {
379         int level = 5;
380         json_object *query = afb_req_json(request), *l;
381
382         if (json_object_is_type(query,json_type_int))
383                 level = json_object_get_int(query);
384         else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int))
385                 level = json_object_get_int(l);
386
387         if (!json_object_object_get_ex(query,"message",&l))
388                 l = query;
389
390         AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l));
391         afb_req_success(request, NULL, NULL);
392 }
393
394 static void exitnow (afb_req_t request)
395 {
396         int code = 0;
397         json_object *query = afb_req_json(request), *l;
398
399         if (json_object_is_type(query,json_type_int))
400                 code = json_object_get_int(query);
401         else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int))
402                 code = json_object_get_int(l);
403
404         if (!json_object_object_get_ex(query,"reason",&l))
405                 l = NULL;
406
407         AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown");
408         afb_req_success(request, NULL, NULL);
409         exit(code);
410 }
411
412 static void broadcast(afb_req_t request)
413 {
414         const char *tag = afb_req_value(request, "tag");
415         const char *name = afb_req_value(request, "name");
416         const char *data = afb_req_value(request, "data");
417         json_object *object = data ? json_tokener_parse(data) : NULL;
418
419         if (tag != NULL) {
420                 pthread_mutex_lock(&mutex);
421                 if (0 > event_broadcast(object, tag))
422                         afb_req_fail(request, "failed", "broadcast error");
423                 else
424                         afb_req_success(request, NULL, NULL);
425                 pthread_mutex_unlock(&mutex);
426         } else if (name != NULL) {
427                 if (0 > afb_daemon_broadcast_event(name, object))
428                         afb_req_fail(request, "failed", "broadcast error");
429                 else
430                         afb_req_success(request, NULL, NULL);
431         } else {
432                 afb_req_fail(request, "failed", "bad arguments");
433         }
434         json_object_put(object);
435 }
436
437 static void hasperm (afb_req_t request)
438 {
439         const char *perm = afb_req_value(request, "perm");
440         if (afb_req_has_permission(request, perm))
441                 afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)");
442         else
443                 afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)");
444 }
445
446 static void appid (afb_req_t request)
447 {
448         char *aid = afb_req_get_application_id(request);
449         afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?");
450         free(aid);
451 }
452
453 static void uid (afb_req_t request)
454 {
455         int uid = afb_req_get_uid(request);
456         afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid);
457 }
458
459 static void closess (afb_req_t request)
460 {
461         afb_req_session_close(request);
462         afb_req_reply(request, NULL, NULL, "session closed");
463 }
464
465 static void setloa (afb_req_t request)
466 {
467         int loa = json_object_get_int(afb_req_json(request));
468         afb_req_session_set_LOA(request, loa);
469         afb_req_reply_f(request, NULL, NULL, "LOA set to %d", loa);
470 }
471
472 static void ok (afb_req_t request)
473 {
474         afb_req_reply_f(request, NULL, NULL, NULL);
475 }
476
477 static void setctx (afb_req_t request)
478 {
479         struct json_object *x = afb_req_json(request);
480         afb_req_context(request, (int)(intptr_t)afb_req_get_vcbdata(request), (void*)json_object_get, (void*)json_object_put, x);
481         afb_req_reply(request, json_object_get(x), NULL, "context set");
482 }
483
484 static void getctx (afb_req_t request)
485 {
486         struct json_object *x = afb_req_context(request, 0, 0, 0, 0);
487         afb_req_reply(request, json_object_get(x), NULL, "returning the context");
488 }
489
490 static void info (afb_req_t request)
491 {
492         afb_req_reply(request, afb_req_get_client_info(request), NULL, NULL);
493 }
494
495 static void eventloop (afb_req_t request)
496 {
497         afb_api_t api = afb_req_get_api(request);
498         struct sd_event *ev = afb_api_get_event_loop(api);
499         afb_req_reply(request, NULL, ev ? NULL : "no-event-loop", NULL);
500 }
501
502 static void dbus (afb_req_t request)
503 {
504         afb_api_t api = afb_req_get_api(request);
505         json_object *json = afb_req_json(request);
506         struct sd_bus *bus = (json_object_get_boolean(json) ? afb_api_get_system_bus : afb_api_get_user_bus)(api);
507         afb_req_reply(request, NULL, bus ? NULL : "no-bus", NULL);
508 }
509
510 static void replycount (afb_req_t request)
511 {
512         json_object *json = afb_req_json(request);
513         int count = json_object_get_int(json);
514         while (count-- > 0)
515                 afb_req_reply(request, NULL, NULL, NULL);
516 }
517
518 static void get(afb_req_t request)
519 {
520         struct afb_arg arg = afb_req_get(request, "name");
521         const char *name, *value, *path;
522
523         if (!arg.name || !arg.value)
524                 afb_req_reply(request, NULL, "invalid", "the parameter 'name' is missing");
525         else {
526                 name = arg.name;
527                 value = afb_req_value(request, name);
528                 path = afb_req_path(request, name);
529                 afb_req_reply_f(request, NULL, NULL, "found for '%s': %s", name, value ?: path ?: "NULL");
530         }
531 }
532
533 static void ref(afb_req_t request)
534 {
535         afb_req_addref(request);
536         afb_req_reply(request, NULL, NULL, NULL);
537         afb_req_unref(request);
538 }
539
540 static void mute(afb_req_t request)
541 {
542 }
543
544 static void mutebug(afb_req_t request)
545 {
546         afb_req_addref(request);
547 }
548
549 void queue_cb(int signum, void *arg)
550 {
551         afb_req_t request = arg;
552         afb_req_reply(request, NULL, NULL, NULL);
553         afb_req_unref(request);
554 }
555
556 static void queue(afb_req_t request)
557 {
558         afb_req_addref(request);
559         afb_api_queue_job(afb_req_get_api(request), queue_cb, request, NULL, 0);
560 }
561
562 static void settings(afb_req_t request)
563 {
564         afb_api_t api = afb_req_get_api(request);
565         struct json_object *object = afb_api_settings(api);
566         afb_req_reply(request, json_object_get(object), NULL, NULL);
567 }
568
569 static void rootdir (afb_req_t request)
570 {
571         ssize_t s;
572         afb_api_t api = afb_req_get_api(request);
573         int fd = afb_api_rootdir_get_fd(api);
574         char buffer[150], root[1025];
575         sprintf(buffer, "/proc/self/fd/%d", fd);
576         s = readlink(buffer, root, sizeof root - 1);
577         if (s < 0)
578                 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
579         else {
580                 root[s] = 0;
581                 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
582         }
583 }
584
585 static void locale (afb_req_t request)
586 {
587         char buffer[150], root[1025];
588         const char *lang, *file;
589         ssize_t s;
590         json_object *json = afb_req_json(request), *x;
591         afb_api_t api = afb_req_get_api(request);
592         int fd;
593
594         lang = NULL;
595         if (json_object_is_type(json, json_type_string))
596                 file = json_object_get_string(json);
597         else {
598                 if (!json_object_object_get_ex(json, "file", &x)) {
599                         afb_req_reply(request, NULL, "invalid", "no file");
600                         return;
601                 }
602                 file = json_object_get_string(x);
603                 if (json_object_object_get_ex(json, "lang", &x))
604                         lang = json_object_get_string(x);
605         }
606
607         fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
608         if (fd < 0)
609                 afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
610         else {
611                 sprintf(buffer, "/proc/self/fd/%d", fd);
612                 s = readlink(buffer, root, sizeof root - 1);
613                 if (s < 0)
614                         afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
615                 else {
616                         root[s] = 0;
617                         afb_req_reply(request, json_object_new_string(root), NULL, NULL);
618                 }
619                 close(fd);
620         }
621 }
622
623 static void in_after (afb_req_t request)
624 {
625         int rc;
626         const char *ts, *ty;
627         char *te;
628         double td;
629         struct timespec t;
630         void (*calling)(afb_req_t);
631
632         /* get the type */
633         ty = afb_req_value(request, "type") ?: "call";
634         if (strcmp(ty, "call") && strcmp(ty, "callsync")
635          && strcmp(ty, "subcall") && strcmp(ty, "subcallsync"))
636                 return afb_req_reply(request, NULL, "invalid", "bad type");
637
638         /* get the delay */
639         ts = afb_req_value(request, "delay");
640         if (!ts)
641                 return afb_req_reply(request, NULL, "invalid", "no delay");
642         td = strtod(ts, &te);
643         if (*te || td < 0 || td > 3e6) /* a month is the biggest accepted */
644                 return afb_req_reply(request, NULL, "invalid", "bad delay");
645
646         /* wait for that time */
647         if (td > 0) {
648                 t.tv_nsec = (long)(1e6 * modf(td, &td));
649                 t.tv_sec = (time_t)td;
650                 do {
651                         rc = nanosleep(&t, &t);
652                 } while (rc != 0 && errno == EINTR);
653
654                 if (rc)
655                         return afb_req_reply(request, NULL, "error", "sleep failed");
656         }
657
658         /* do the call */
659         if (!strcmp(ty, "subcallsync"))
660                 subcall(request);
661         else if (!strcmp(ty, "subcall"))
662                 subcallsync(request);
663         else if (!strcmp(ty, "callsync"))
664                 callsync(request);
665         else
666                 call(request);
667 }
668
669 static void *thread_after (void *closure)
670 {
671         afb_req_t request = closure;
672         in_after (request);
673         afb_req_unref(request);
674         return NULL;
675 }
676
677 static void after (afb_req_t request)
678 {
679         int rc;
680         pthread_t tid;
681         pthread_attr_t attr;
682
683         afb_req_addref(request);
684
685         pthread_attr_init(&attr);
686         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
687         rc =pthread_create(&tid, &attr, thread_after, request);
688         pthread_attr_destroy(&attr);
689
690         if (rc != 0) {
691                 afb_req_unref(request);
692                 afb_req_reply(request, NULL, "cant-start", NULL);
693         }
694 }
695
696 static void api (afb_req_t request);
697
698 /**
699  * Definition of an authorization entry
700  */
701 static struct afb_auth auths[] = {
702         {       /* 0 */
703                 .type = afb_auth_Or,
704                 .first = &auths[1],
705                 .next = &auths[9],
706         },
707         {       /* 1 */
708                 .type = afb_auth_And,
709                 .first = &auths[2],
710                 .next = &auths[3],
711         },
712         {       /* 2 */
713                 .type = afb_auth_Yes
714         },
715         {       /* 3 */
716                 .type = afb_auth_And,
717                 .first = &auths[4],
718                 .next = &auths[5],
719         },
720         {       /* 4 */
721                 .type = afb_auth_LOA,
722                 .loa = 0
723         },
724         {       /* 5 */
725                 .type = afb_auth_Or,
726                 .first = &auths[6],
727                 .next = &auths[7],
728         },
729         {       /* 6 */
730                 .type = afb_auth_No
731         },
732         {       /* 7 */
733                 .type = afb_auth_Not,
734                 .first = &auths[8]
735         },
736         {       /* 8 */
737                 .type = afb_auth_Yes
738         },
739         {       /* 9 */
740                 .type = afb_auth_And,
741                 .first = &auths[10],
742                 .next = &auths[13],
743         },
744         {       /* 10 */
745                 .type = afb_auth_Or,
746                 .first = &auths[12],
747                 .next = &auths[11],
748         },
749         {       /* 11 */
750                 .type = afb_auth_Not,
751                 .first = &auths[13]
752         },
753         {       /* 12 */
754                 .type = afb_auth_Token
755         },
756         {       /* 13 */
757                 .type = afb_auth_And,
758                 .first = &auths[14],
759                 .next = &auths[17],
760         },
761         {       /* 14 */
762                 .type = afb_auth_Or,
763                 .first = &auths[16],
764                 .next = &auths[15],
765         },
766         {       /* 15 */
767                 .type = afb_auth_Not,
768                 .first = &auths[16]
769         },
770         {       /* 16 */
771                 .type = afb_auth_Permission,
772                 .text = "permission"
773         },
774         {       /* 17 */
775                 .type = afb_auth_Yes
776         }
777 };
778
779
780 // NOTE: this sample does not use session to keep test a basic as possible
781 //       in real application most APIs should be protected with AFB_SESSION_CHECK
782 static const struct afb_verb_v3 verbs[]= {
783   { .verb="ping",        .callback=pingSample },
784   { .verb="pingfail",    .callback=pingFail },
785   { .verb="pingnull",    .callback=pingNull },
786   { .verb="pingbug",     .callback=pingBug },
787   { .verb="pingJson",    .callback=pingJson },
788   { .verb="pingevent",   .callback=pingEvent },
789   { .verb="subcall",     .callback=subcall },
790   { .verb="subcallreq",  .callback=subcallreq },
791   { .verb="subcallsync", .callback=subcallsync },
792   { .verb="eventadd",    .callback=eventadd },
793   { .verb="eventdel",    .callback=eventdel },
794   { .verb="eventsub",    .callback=eventsub },
795   { .verb="eventunsub",  .callback=eventunsub },
796   { .verb="eventpush",   .callback=eventpush },
797   { .verb="call",        .callback=call },
798   { .verb="callsync",    .callback=callsync },
799   { .verb="verbose",     .callback=verbose },
800   { .verb="broadcast",   .callback=broadcast },
801   { .verb="hasperm",     .callback=hasperm },
802   { .verb="appid",       .callback=appid },
803   { .verb="uid",         .callback=uid },
804   { .verb="exit",        .callback=exitnow },
805   { .verb="close",       .callback=closess, .session=AFB_SESSION_CLOSE },
806   { .verb="set-loa",     .callback=setloa, .auth = &auths[0] },
807   { .verb="has-loa-1",   .callback=ok, .session=AFB_SESSION_LOA_1 },
808   { .verb="has-loa-2",   .callback=ok, .session=AFB_SESSION_LOA_2 },
809   { .verb="has-loa-3",   .callback=ok, .session=AFB_SESSION_LOA_3 },
810   { .verb="setctx",      .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
811   { .verb="setctxif",    .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
812   { .verb="getctx",      .callback=getctx },
813   { .verb="checktok",    .callback=ok, .session=AFB_SESSION_CHECK },
814   { .verb="reftok",      .callback=ok, .session=AFB_SESSION_CHECK | AFB_SESSION_REFRESH },
815   { .verb="info",        .callback=info },
816   { .verb="eventloop",   .callback=eventloop },
817   { .verb="dbus",        .callback=dbus },
818   { .verb="reply-count", .callback=replycount },
819   { .verb="get",         .callback=get},
820   { .verb="ref",         .callback=ref},
821   { .verb="rootdir",     .callback=rootdir},
822   { .verb="locale",      .callback=locale},
823   { .verb="api",         .callback=api},
824   { .verb="mute",        .callback=mute},
825   { .verb="mutebug",     .callback=mutebug},
826   { .verb="queue",       .callback=queue},
827   { .verb="settings",    .callback=settings},
828   { .verb="after",       .callback=after},
829   { .verb=NULL}
830 };
831
832 static void pingSample2 (struct afb_req_x1 req)
833 {
834         pingSample(req.closure);
835 }
836
837 static const struct afb_verb_v2 apiverbs2[]= {
838   { .verb="ping",        .callback=pingSample2 },
839   { .verb="ping2",        .callback=pingSample2 },
840   { .verb=NULL }
841 };
842
843 static int apipreinit(void *closure, afb_api_t api)
844 {
845         afb_api_set_verbs_v2(api, apiverbs2);
846         afb_api_set_verbs_v3(api, verbs);
847         return 0;
848 }
849
850 static void apiverb (afb_req_t request)
851 {
852         afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
853                 afb_req_get_called_api(request), afb_req_get_called_verb(request));
854 }
855
856 static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
857 {
858         struct json_object *obj = closure;
859         afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
860                 json_object_get_string(obj), event, json_object_get_string(args));
861 }
862
863 static void api (afb_req_t request)
864 {
865         struct api *sapi, **psapi;
866         const char *action, *apiname, *verbname, *pattern;
867         json_object *json = afb_req_json(request), *x, *closure;
868         afb_api_t api = afb_req_get_api(request), oapi;
869
870         /* get the action */
871         if (!json_object_object_get_ex(json, "action", &x)) {
872                 afb_req_reply(request, NULL, "invalid", "no action");
873                 goto end;
874         }
875         action = json_object_get_string(x);
876
877         /* get the verb */
878         verbname = json_object_object_get_ex(json, "verb", &x) ?
879                 json_object_get_string(x) : NULL;
880
881         /* get the pattern */
882         pattern = json_object_object_get_ex(json, "pattern", &x) ?
883                 json_object_get_string(x) : NULL;
884
885         /* get the closure */
886         closure = NULL;
887         json_object_object_get_ex(json, "closure", &closure);
888
889         /* get the api */
890         if (json_object_object_get_ex(json, "api", &x)) {
891                 apiname = json_object_get_string(x);
892                 sapi = searchapi(apiname, &psapi);
893                 oapi = sapi ? sapi->api : NULL;
894         } else {
895                 oapi = api;
896                 apiname = afb_api_name(api);
897                 sapi = searchapi(apiname, &psapi);
898         }
899
900         /* search the sapi */
901         if (!strcasecmp(action, "create")) {
902                 if (!apiname) {
903                         afb_req_reply(request, NULL, "invalid", "no api");
904                         goto end;
905                 }
906                 if (sapi) {
907                         afb_req_reply(request, NULL, "already-exist", NULL);
908                         goto end;
909                 }
910                 sapi = malloc (sizeof * sapi + strlen(apiname));
911                 if (!sapi) {
912                         afb_req_reply(request, NULL, "out-of-memory", NULL);
913                         goto end;
914                 }
915                 sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
916                 if (!sapi->api) {
917                         afb_req_reply_f(request, NULL, "cant-create", "%m");
918                         goto end;
919                 }
920                 strcpy(sapi->name, apiname);
921                 sapi->next = NULL;
922                 *psapi = sapi;
923         } else {
924                 if (!oapi) {
925                         afb_req_reply(request, NULL, "cant-find-api", NULL);
926                         goto end;
927                 }
928                 if (!strcasecmp(action, "destroy")) {
929                         if (!sapi) {
930                                 afb_req_reply(request, NULL, "cant-destroy", NULL);
931                                 goto end;
932                         }
933                         afb_api_delete_api(oapi);
934                         *psapi = sapi->next;
935                         free(sapi);
936                 } else if (!strcasecmp(action, "addverb")) {
937                         if (!verbname){
938                                 afb_req_reply(request, NULL, "invalid", "no verb");
939                                 goto end;
940                         }
941                         afb_api_add_verb(oapi, verbname, NULL, apiverb, NULL, NULL, 0, !!strchr(verbname, '*'));
942                 } else if (!strcasecmp(action, "delverb")) {
943                         if (!verbname){
944                                 afb_req_reply(request, NULL, "invalid", "no verb");
945                                 goto end;
946                         }
947                         afb_api_del_verb(oapi, verbname, NULL);
948                 } else if (!strcasecmp(action, "addhandler")) {
949                         if (!pattern){
950                                 afb_req_reply(request, NULL, "invalid", "no pattern");
951                                 goto end;
952                         }
953                         afb_api_event_handler_add(oapi, pattern, apievhndl, json_object_get(closure));
954                 } else if (!strcasecmp(action, "delhandler")) {
955                         if (!pattern){
956                                 afb_req_reply(request, NULL, "invalid", "no pattern");
957                                 goto end;
958                         }
959                         closure = NULL;
960                         afb_api_event_handler_del(oapi, pattern, (void**)&closure);
961                         json_object_put(closure);
962                 } else if (!strcasecmp(action, "seal")) {
963                         afb_api_seal(oapi);
964                 } else {
965                         afb_req_reply_f(request, NULL, "invalid", "unknown action %s", action ?: "NULL");
966                         goto end;
967                 }
968         }
969         afb_req_reply(request, NULL, NULL, NULL);
970 end:    return;
971 }
972
973 /*************************************************************/
974
975 static int preinit(afb_api_t api)
976 {
977         AFB_NOTICE("hello binding comes to live");
978 #if defined(PREINIT_PROVIDE_CLASS)
979         afb_api_provide_class(api, PREINIT_PROVIDE_CLASS);
980 #endif
981 #if defined(PREINIT_REQUIRE_CLASS)
982         afb_api_require_class(api, PREINIT_REQUIRE_CLASS);
983 #endif
984         return 0;
985 }
986
987 static int init(afb_api_t api)
988 {
989         AFB_NOTICE("hello binding starting");
990 #if defined(INIT_REQUIRE_API)
991         afb_api_require_api(api, INIT_REQUIRE_API, 1);
992 #endif
993         afb_api_add_alias(api, api->apiname, "fakename");
994         return 0;
995 }
996
997 static void onevent(afb_api_t api, const char *event, struct json_object *object)
998 {
999         AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
1000 }
1001
1002 const struct afb_binding_v3 afbBindingV3 = {
1003         .api = APINAME,
1004         .specification = NULL,
1005         .verbs = verbs,
1006         .preinit = preinit,
1007         .init = init,
1008         .onevent = onevent
1009 };
1010