Add ability to provide binding settings
[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 void queue_cb(int signum, void *arg)
543 {
544         afb_req_t request = arg;
545         afb_req_reply(request, NULL, NULL, NULL);
546         afb_req_unref(request);
547 }
548
549 static void queue(afb_req_t request)
550 {
551         afb_req_addref(request);
552         afb_api_queue_job(afb_req_get_api(request), queue_cb, request, NULL, 0);
553 }
554
555 static void settings(afb_req_t request)
556 {
557         afb_api_t api = afb_req_get_api(request);
558         struct json_object *object = afb_api_settings(api);
559         afb_req_reply(request, json_object_get(object), NULL, NULL);
560 }
561
562 static void rootdir (afb_req_t request)
563 {
564         ssize_t s;
565         afb_api_t api = afb_req_get_api(request);
566         int fd = afb_api_rootdir_get_fd(api);
567         char buffer[150], root[1025];
568         sprintf(buffer, "/proc/self/fd/%d", fd);
569         s = readlink(buffer, root, sizeof root - 1);
570         if (s < 0)
571                 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
572         else {
573                 root[s] = 0;
574                 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
575         }
576 }
577
578 static void locale (afb_req_t request)
579 {
580         char buffer[150], root[1025];
581         const char *lang, *file;
582         ssize_t s;
583         json_object *json = afb_req_json(request), *x;
584         afb_api_t api = afb_req_get_api(request);
585         int fd;
586
587         lang = NULL;
588         if (json_object_is_type(json, json_type_string))
589                 file = json_object_get_string(json);
590         else {
591                 if (!json_object_object_get_ex(json, "file", &x)) {
592                         afb_req_reply(request, NULL, "invalid", "no file");
593                         return;
594                 }
595                 file = json_object_get_string(x);
596                 if (json_object_object_get_ex(json, "lang", &x))
597                         lang = json_object_get_string(x);
598         }
599
600         fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
601         if (fd < 0)
602                 afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
603         else {
604                 sprintf(buffer, "/proc/self/fd/%d", fd);
605                 s = readlink(buffer, root, sizeof root - 1);
606                 if (s < 0)
607                         afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
608                 else {
609                         root[s] = 0;
610                         afb_req_reply(request, json_object_new_string(root), NULL, NULL);
611                 }
612                 close(fd);
613         }
614 }
615
616 static void api (afb_req_t request);
617
618 /**
619  * Definition of an authorization entry
620  */
621 static struct afb_auth auths[] = {
622         {       /* 0 */
623                 .type = afb_auth_Or,
624                 .first = &auths[1],
625                 .next = &auths[9],
626         },
627         {       /* 1 */
628                 .type = afb_auth_And,
629                 .first = &auths[2],
630                 .next = &auths[3],
631         },
632         {       /* 2 */
633                 .type = afb_auth_Yes
634         },
635         {       /* 3 */
636                 .type = afb_auth_And,
637                 .first = &auths[4],
638                 .next = &auths[5],
639         },
640         {       /* 4 */
641                 .type = afb_auth_LOA,
642                 .loa = 0
643         },
644         {       /* 5 */
645                 .type = afb_auth_Or,
646                 .first = &auths[6],
647                 .next = &auths[7],
648         },
649         {       /* 6 */
650                 .type = afb_auth_No
651         },
652         {       /* 7 */
653                 .type = afb_auth_Not,
654                 .first = &auths[8]
655         },
656         {       /* 8 */
657                 .type = afb_auth_Yes
658         },
659         {       /* 9 */
660                 .type = afb_auth_And,
661                 .first = &auths[10],
662                 .next = &auths[13],
663         },
664         {       /* 10 */
665                 .type = afb_auth_Or,
666                 .first = &auths[12],
667                 .next = &auths[11],
668         },
669         {       /* 11 */
670                 .type = afb_auth_Not,
671                 .first = &auths[13]
672         },
673         {       /* 12 */
674                 .type = afb_auth_Token
675         },
676         {       /* 13 */
677                 .type = afb_auth_And,
678                 .first = &auths[14],
679                 .next = &auths[17],
680         },
681         {       /* 14 */
682                 .type = afb_auth_Or,
683                 .first = &auths[16],
684                 .next = &auths[15],
685         },
686         {       /* 15 */
687                 .type = afb_auth_Not,
688                 .first = &auths[16]
689         },
690         {       /* 16 */
691                 .type = afb_auth_Permission,
692                 .text = "permission"
693         },
694         {       /* 17 */
695                 .type = afb_auth_Yes
696         }
697 };
698
699
700 // NOTE: this sample does not use session to keep test a basic as possible
701 //       in real application most APIs should be protected with AFB_SESSION_CHECK
702 static const struct afb_verb_v3 verbs[]= {
703   { .verb="ping",        .callback=pingSample },
704   { .verb="pingfail",    .callback=pingFail },
705   { .verb="pingnull",    .callback=pingNull },
706   { .verb="pingbug",     .callback=pingBug },
707   { .verb="pingJson",    .callback=pingJson },
708   { .verb="pingevent",   .callback=pingEvent },
709   { .verb="subcall",     .callback=subcall },
710   { .verb="subcallreq",  .callback=subcallreq },
711   { .verb="subcallsync", .callback=subcallsync },
712   { .verb="eventadd",    .callback=eventadd },
713   { .verb="eventdel",    .callback=eventdel },
714   { .verb="eventsub",    .callback=eventsub },
715   { .verb="eventunsub",  .callback=eventunsub },
716   { .verb="eventpush",   .callback=eventpush },
717   { .verb="call",        .callback=call },
718   { .verb="callsync",    .callback=callsync },
719   { .verb="verbose",     .callback=verbose },
720   { .verb="broadcast",   .callback=broadcast },
721   { .verb="hasperm",     .callback=hasperm },
722   { .verb="appid",       .callback=appid },
723   { .verb="uid",         .callback=uid },
724   { .verb="exit",        .callback=exitnow },
725   { .verb="close",       .callback=closess, .session=AFB_SESSION_CLOSE },
726   { .verb="set-loa",     .callback=setloa, .auth = &auths[0] },
727   { .verb="has-loa-1",   .callback=ok, .session=AFB_SESSION_LOA_1 },
728   { .verb="has-loa-2",   .callback=ok, .session=AFB_SESSION_LOA_2 },
729   { .verb="has-loa-3",   .callback=ok, .session=AFB_SESSION_LOA_3 },
730   { .verb="setctx",      .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
731   { .verb="setctxif",    .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
732   { .verb="getctx",      .callback=getctx },
733   { .verb="reftok",      .callback=ok, .session=AFB_SESSION_CHECK | AFB_SESSION_REFRESH },
734   { .verb="info",        .callback=info },
735   { .verb="eventloop",   .callback=eventloop },
736   { .verb="dbus",        .callback=dbus },
737   { .verb="reply-count", .callback=replycount },
738   { .verb="get",         .callback=get},
739   { .verb="ref",         .callback=ref},
740   { .verb="rootdir",     .callback=rootdir},
741   { .verb="locale",      .callback=locale},
742   { .verb="api",         .callback=api},
743   { .verb="mute",        .callback=mute},
744   { .verb="queue",       .callback=queue},
745   { .verb="settings",    .callback=settings},
746   { .verb=NULL}
747 };
748
749 static void pingSample2 (struct afb_req_x1 req)
750 {
751         pingSample(req.closure);
752 }
753
754 static const struct afb_verb_v2 apiverbs2[]= {
755   { .verb="ping",        .callback=pingSample2 },
756   { .verb="ping2",        .callback=pingSample2 },
757   { .verb=NULL }
758 };
759
760 static int apipreinit(void *closure, afb_api_t api)
761 {
762         afb_api_set_verbs_v2(api, apiverbs2);
763         afb_api_set_verbs_v3(api, verbs);
764         return 0;
765 }
766
767 static void apiverb (afb_req_t request)
768 {
769         afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
770                 afb_req_get_called_api(request), afb_req_get_called_verb(request));
771 }
772
773 static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
774 {
775         struct json_object *obj = closure;
776         afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
777                 json_object_get_string(obj), event, json_object_get_string(args));
778 }
779
780 static void api (afb_req_t request)
781 {
782         struct api *sapi, **psapi;
783         const char *action, *apiname, *verbname, *pattern;
784         json_object *json = afb_req_json(request), *x, *closure;
785         afb_api_t api = afb_req_get_api(request), oapi;
786
787         /* get the action */
788         if (!json_object_object_get_ex(json, "action", &x)) {
789                 afb_req_reply(request, NULL, "invalid", "no action");
790                 goto end;
791         }
792         action = json_object_get_string(x);
793
794         /* get the verb */
795         verbname = json_object_object_get_ex(json, "verb", &x) ?
796                 json_object_get_string(x) : NULL;
797
798         /* get the pattern */
799         pattern = json_object_object_get_ex(json, "pattern", &x) ?
800                 json_object_get_string(x) : NULL;
801
802         /* get the closure */
803         closure = NULL;
804         json_object_object_get_ex(json, "closure", &closure);
805
806         /* get the api */
807         if (json_object_object_get_ex(json, "api", &x)) {
808                 apiname = json_object_get_string(x);
809                 sapi = searchapi(apiname, &psapi);
810                 oapi = sapi ? sapi->api : NULL;
811         } else {
812                 oapi = api;
813                 apiname = afb_api_name(api);
814                 sapi = searchapi(apiname, &psapi);
815         }
816
817         /* search the sapi */
818         if (!strcasecmp(action, "create")) {
819                 if (!apiname) {
820                         afb_req_reply(request, NULL, "invalid", "no api");
821                         goto end;
822                 }
823                 if (sapi) {
824                         afb_req_reply(request, NULL, "already-exist", NULL);
825                         goto end;
826                 }
827                 sapi = malloc (sizeof * sapi + strlen(apiname));
828                 if (!sapi) {
829                         afb_req_reply(request, NULL, "out-of-memory", NULL);
830                         goto end;
831                 }
832                 sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
833                 if (!sapi->api) {
834                         afb_req_reply_f(request, NULL, "cant-create", "%m");
835                         goto end;
836                 }
837                 strcpy(sapi->name, apiname);
838                 sapi->next = NULL;
839                 *psapi = sapi;
840         } else {
841                 if (!oapi) {
842                         afb_req_reply(request, NULL, "cant-find-api", NULL);
843                         goto end;
844                 }
845                 if (!strcasecmp(action, "destroy")) {
846                         if (!sapi) {
847                                 afb_req_reply(request, NULL, "cant-destroy", NULL);
848                                 goto end;
849                         }
850                         afb_api_delete_api(oapi);
851                         *psapi = sapi->next;
852                         free(sapi);
853                 } else if (!strcasecmp(action, "addverb")) {
854                         if (!verbname){
855                                 afb_req_reply(request, NULL, "invalid", "no verb");
856                                 goto end;
857                         }
858                         afb_api_add_verb(oapi, verbname, NULL, apiverb, NULL, NULL, 0, !!strchr(verbname, '*'));
859                 } else if (!strcasecmp(action, "delverb")) {
860                         if (!verbname){
861                                 afb_req_reply(request, NULL, "invalid", "no verb");
862                                 goto end;
863                         }
864                         afb_api_del_verb(oapi, verbname, NULL);
865                 } else if (!strcasecmp(action, "addhandler")) {
866                         if (!pattern){
867                                 afb_req_reply(request, NULL, "invalid", "no pattern");
868                                 goto end;
869                         }
870                         afb_api_event_handler_add(oapi, pattern, apievhndl, json_object_get(closure));
871                 } else if (!strcasecmp(action, "delhandler")) {
872                         if (!pattern){
873                                 afb_req_reply(request, NULL, "invalid", "no pattern");
874                                 goto end;
875                         }
876                         closure = NULL;
877                         afb_api_event_handler_del(oapi, pattern, (void**)&closure);
878                         json_object_put(closure);
879                 } else if (!strcasecmp(action, "seal")) {
880                         afb_api_seal(oapi);
881                 } else {
882                         afb_req_reply_f(request, NULL, "invalid", "unknown action %s", action ?: "NULL");
883                         goto end;
884                 }
885         }
886         afb_req_reply(request, NULL, NULL, NULL);
887 end:    return;
888 }
889
890 /*************************************************************/
891
892 static int preinit(afb_api_t api)
893 {
894         AFB_NOTICE("hello binding comes to live");
895 #if defined(PREINIT_PROVIDE_CLASS)
896         afb_api_provide_class(api, PREINIT_PROVIDE_CLASS);
897 #endif
898 #if defined(PREINIT_REQUIRE_CLASS)
899         afb_api_require_class(api, PREINIT_REQUIRE_CLASS);
900 #endif
901         return 0;
902 }
903
904 static int init(afb_api_t api)
905 {
906         AFB_NOTICE("hello binding starting");
907 #if defined(INIT_REQUIRE_API)
908         afb_api_require_api(api, INIT_REQUIRE_API, 1);
909 #endif
910         afb_api_add_alias(api, api->apiname, "fakename");
911         return 0;
912 }
913
914 static void onevent(afb_api_t api, const char *event, struct json_object *object)
915 {
916         AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
917 }
918
919 const struct afb_binding_v3 afbBindingV3 = {
920         .api = APINAME,
921         .specification = NULL,
922         .verbs = verbs,
923         .preinit = preinit,
924         .init = init,
925         .onevent = onevent
926 };
927