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