efd338c9eaecc6a976d498e6128b5b982720625e
[src/app-framework-binder.git] / bindings / samples / hello3.c
1 /*
2  * Copyright (C) 2015-2019 "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, json_object_get(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
631         /* get the type */
632         ty = afb_req_value(request, "type") ?: "call";
633         if (strcmp(ty, "call") && strcmp(ty, "callsync")
634          && strcmp(ty, "subcall") && strcmp(ty, "subcallsync"))
635                 return afb_req_reply(request, NULL, "invalid", "bad type");
636
637         /* get the delay */
638         ts = afb_req_value(request, "delay");
639         if (!ts)
640                 return afb_req_reply(request, NULL, "invalid", "no delay");
641         td = strtod(ts, &te);
642         if (*te || td < 0 || td > 3e6) /* a month is the biggest accepted */
643                 return afb_req_reply(request, NULL, "invalid", "bad delay");
644
645         /* wait for that time */
646         if (td > 0) {
647                 t.tv_nsec = (long)(1e6 * modf(td, &td));
648                 t.tv_sec = (time_t)td;
649                 do {
650                         rc = nanosleep(&t, &t);
651                 } while (rc != 0 && errno == EINTR);
652
653                 if (rc)
654                         return afb_req_reply(request, NULL, "error", "sleep failed");
655         }
656
657         /* do the call */
658         if (!strcmp(ty, "subcallsync"))
659                 subcall(request);
660         else if (!strcmp(ty, "subcall"))
661                 subcallsync(request);
662         else if (!strcmp(ty, "callsync"))
663                 callsync(request);
664         else
665                 call(request);
666 }
667
668 static void *thread_after (void *closure)
669 {
670         afb_req_t request = closure;
671         in_after (request);
672         afb_req_unref(request);
673         return NULL;
674 }
675
676 static void after (afb_req_t request)
677 {
678         int rc;
679         pthread_t tid;
680         pthread_attr_t attr;
681
682         afb_req_addref(request);
683
684         pthread_attr_init(&attr);
685         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
686         rc =pthread_create(&tid, &attr, thread_after, request);
687         pthread_attr_destroy(&attr);
688
689         if (rc != 0) {
690                 afb_req_unref(request);
691                 afb_req_reply(request, NULL, "cant-start", NULL);
692         }
693 }
694
695 static void api (afb_req_t request);
696
697 /**
698  * Definition of an authorization entry
699  */
700 static struct afb_auth auths[] = {
701         {       /* 0 */
702                 .type = afb_auth_Or,
703                 .first = &auths[1],
704                 .next = &auths[9],
705         },
706         {       /* 1 */
707                 .type = afb_auth_And,
708                 .first = &auths[2],
709                 .next = &auths[3],
710         },
711         {       /* 2 */
712                 .type = afb_auth_Yes
713         },
714         {       /* 3 */
715                 .type = afb_auth_And,
716                 .first = &auths[4],
717                 .next = &auths[5],
718         },
719         {       /* 4 */
720                 .type = afb_auth_LOA,
721                 .loa = 0
722         },
723         {       /* 5 */
724                 .type = afb_auth_Or,
725                 .first = &auths[6],
726                 .next = &auths[7],
727         },
728         {       /* 6 */
729                 .type = afb_auth_No
730         },
731         {       /* 7 */
732                 .type = afb_auth_Not,
733                 .first = &auths[8]
734         },
735         {       /* 8 */
736                 .type = afb_auth_Yes
737         },
738         {       /* 9 */
739                 .type = afb_auth_And,
740                 .first = &auths[10],
741                 .next = &auths[13],
742         },
743         {       /* 10 */
744                 .type = afb_auth_Or,
745                 .first = &auths[12],
746                 .next = &auths[11],
747         },
748         {       /* 11 */
749                 .type = afb_auth_Not,
750                 .first = &auths[13]
751         },
752         {       /* 12 */
753                 .type = afb_auth_Token
754         },
755         {       /* 13 */
756                 .type = afb_auth_And,
757                 .first = &auths[14],
758                 .next = &auths[17],
759         },
760         {       /* 14 */
761                 .type = afb_auth_Or,
762                 .first = &auths[16],
763                 .next = &auths[15],
764         },
765         {       /* 15 */
766                 .type = afb_auth_Not,
767                 .first = &auths[16]
768         },
769         {       /* 16 */
770                 .type = afb_auth_Permission,
771                 .text = "permission"
772         },
773         {       /* 17 */
774                 .type = afb_auth_Yes
775         }
776 };
777
778
779 // NOTE: this sample does not use session to keep test a basic as possible
780 //       in real application most APIs should be protected with AFB_SESSION_CHECK
781 static const struct afb_verb_v3 verbs[]= {
782   { .verb="ping",        .callback=pingSample },
783   { .verb="pingfail",    .callback=pingFail },
784   { .verb="pingnull",    .callback=pingNull },
785   { .verb="pingbug",     .callback=pingBug },
786   { .verb="pingJson",    .callback=pingJson },
787   { .verb="pingevent",   .callback=pingEvent },
788   { .verb="subcall",     .callback=subcall },
789   { .verb="subcallreq",  .callback=subcallreq },
790   { .verb="subcallsync", .callback=subcallsync },
791   { .verb="eventadd",    .callback=eventadd },
792   { .verb="eventdel",    .callback=eventdel },
793   { .verb="eventsub",    .callback=eventsub },
794   { .verb="eventunsub",  .callback=eventunsub },
795   { .verb="eventpush",   .callback=eventpush },
796   { .verb="call",        .callback=call },
797   { .verb="callsync",    .callback=callsync },
798   { .verb="verbose",     .callback=verbose },
799   { .verb="broadcast",   .callback=broadcast },
800   { .verb="hasperm",     .callback=hasperm },
801   { .verb="appid",       .callback=appid },
802   { .verb="uid",         .callback=uid },
803   { .verb="exit",        .callback=exitnow },
804   { .verb="close",       .callback=closess, .session=AFB_SESSION_CLOSE },
805   { .verb="set-loa",     .callback=setloa, .auth = &auths[0] },
806   { .verb="has-loa-1",   .callback=ok, .session=AFB_SESSION_LOA_1 },
807   { .verb="has-loa-2",   .callback=ok, .session=AFB_SESSION_LOA_2 },
808   { .verb="has-loa-3",   .callback=ok, .session=AFB_SESSION_LOA_3 },
809   { .verb="setctx",      .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
810   { .verb="setctxif",    .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
811   { .verb="getctx",      .callback=getctx },
812   { .verb="checktok",    .callback=ok, .session=AFB_SESSION_CHECK },
813   { .verb="reftok",      .callback=ok, .session=AFB_SESSION_CHECK | AFB_SESSION_REFRESH },
814   { .verb="info",        .callback=info },
815   { .verb="eventloop",   .callback=eventloop },
816   { .verb="dbus",        .callback=dbus },
817   { .verb="reply-count", .callback=replycount },
818   { .verb="get",         .callback=get},
819   { .verb="ref",         .callback=ref},
820   { .verb="rootdir",     .callback=rootdir},
821   { .verb="locale",      .callback=locale},
822   { .verb="api",         .callback=api},
823   { .verb="mute",        .callback=mute},
824   { .verb="mutebug",     .callback=mutebug},
825   { .verb="queue",       .callback=queue},
826   { .verb="settings",    .callback=settings},
827   { .verb="after",       .callback=after},
828   { .verb=NULL}
829 };
830
831 static void pingSample2 (struct afb_req_x1 req)
832 {
833         pingSample(req.closure);
834 }
835
836 static const struct afb_verb_v2 apiverbs2[]= {
837   { .verb="ping",        .callback=pingSample2 },
838   { .verb="ping2",        .callback=pingSample2 },
839   { .verb=NULL }
840 };
841
842 static int apipreinit(void *closure, afb_api_t api)
843 {
844         afb_api_set_verbs_v2(api, apiverbs2);
845         afb_api_set_verbs_v3(api, verbs);
846         return 0;
847 }
848
849 static void apiverb (afb_req_t request)
850 {
851         afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
852                 afb_req_get_called_api(request), afb_req_get_called_verb(request));
853 }
854
855 static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
856 {
857         struct json_object *obj = closure;
858         afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
859                 json_object_get_string(obj), event, json_object_get_string(args));
860 }
861
862 static void api (afb_req_t request)
863 {
864         struct api *sapi, **psapi;
865         const char *action, *apiname, *verbname, *pattern;
866         json_object *json = afb_req_json(request), *x, *closure;
867         afb_api_t api = afb_req_get_api(request), oapi;
868
869         /* get the action */
870         if (!json_object_object_get_ex(json, "action", &x)) {
871                 afb_req_reply(request, NULL, "invalid", "no action");
872                 goto end;
873         }
874         action = json_object_get_string(x);
875
876         /* get the verb */
877         verbname = json_object_object_get_ex(json, "verb", &x) ?
878                 json_object_get_string(x) : NULL;
879
880         /* get the pattern */
881         pattern = json_object_object_get_ex(json, "pattern", &x) ?
882                 json_object_get_string(x) : NULL;
883
884         /* get the closure */
885         closure = NULL;
886         json_object_object_get_ex(json, "closure", &closure);
887
888         /* get the api */
889         if (json_object_object_get_ex(json, "api", &x)) {
890                 apiname = json_object_get_string(x);
891                 sapi = searchapi(apiname, &psapi);
892                 oapi = sapi ? sapi->api : NULL;
893         } else {
894                 oapi = api;
895                 apiname = afb_api_name(api);
896                 sapi = searchapi(apiname, &psapi);
897         }
898
899         /* search the sapi */
900         if (!strcasecmp(action, "create")) {
901                 if (!apiname) {
902                         afb_req_reply(request, NULL, "invalid", "no api");
903                         goto end;
904                 }
905                 if (sapi) {
906                         afb_req_reply(request, NULL, "already-exist", NULL);
907                         goto end;
908                 }
909                 sapi = malloc (sizeof * sapi + strlen(apiname));
910                 if (!sapi) {
911                         afb_req_reply(request, NULL, "out-of-memory", NULL);
912                         goto end;
913                 }
914                 sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
915                 if (!sapi->api) {
916                         free(sapi);
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