Prepare the Integration with systemd
[src/app-framework-main.git] / src / wgt-json.c
1 /*
2  Copyright 2015, 2016, 2017 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19 #define _GNU_SOURCE
20
21 #include <stdlib.h>
22 #include <assert.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <stdarg.h>
28 #include <sys/types.h>
29
30 #include <json-c/json.h>
31
32 #include "utils-json.h"
33 #include "wgt-info.h"
34 #include "wgt-json.h"
35 #include "wgt-strings.h"
36 #include "verbose.h"
37
38 /*
39 {
40   permissions: {
41         dict: {
42                 ID: { name: ID, level: LEVEL, index: INDEX },
43                 ...
44         },
45         list: [
46                 { name: ID, level: LEVEL, index: 0 },
47                 ...
48         }
49   },
50   targets: [
51                 { name: ID, level: LEVEL, index: 0 },
52                 ...
53         ]
54   }
55 }
56 */
57
58 struct paramaction
59 {
60         const char *name;
61         int (*action)(struct json_object *obj, const struct wgt_desc_param *param, void *closure);
62         void *closure;
63 };
64
65
66 /* apply params */
67 static int apply_params(struct json_object *obj, const struct wgt_desc_param *param, const struct paramaction *actions)
68 {
69         int rc;
70         const struct paramaction *a;
71
72         if (!obj)
73                 rc = -1;
74         else {
75                 rc = 0;
76                 while(param) {
77                         for (a = actions ; a->name && strcmp(a->name, param->name) ; a++);
78                         if (a->action && a->action(obj, param, a->closure) < 0)
79                                 rc = -1;
80                         param = param->next;
81                 }
82         }
83         return rc;
84 }
85
86 static int get_array(struct json_object **result, struct json_object *obj, const char *key, int create)
87 {
88         int rc = j_enter_m(&obj, &key, 1);
89         if (rc < 0)
90                 *result = NULL;
91         else if (!json_object_object_get_ex(obj, key, result)) {
92                 if (!create) {
93                         *result = NULL;
94                         rc = -ENOENT;
95                 } else {
96                         if (!(*result = j_add_new_array(obj, key)))
97                                 rc = -ENOMEM;
98                 }
99         }
100         return rc;
101 }
102
103 /* get the param of 'name' for the feature 'feat' */
104 static const char *get_target_name(const struct wgt_desc_feature *feat, const char *defval)
105 {
106         const struct wgt_desc_param *param = feat->params;
107         while (param && strcmp(param->name, string_sharp_target))
108                 param = param->next;
109         if (param) {
110                 defval = param->value;
111                 param = param->next;
112                 while (param) {
113                         if (!strcmp(param->name, string_sharp_target)) {
114                                 defval = NULL;
115                                 break;
116                         }
117                         param = param->next;
118                 }
119         }
120         return defval;
121 }
122
123 /* get the target */
124 static struct json_object *get_array_item_by_key(struct json_object *array, const char *key, const char *val)
125 {
126         struct json_object *result, *k;
127         int i, n;
128
129         n = json_object_array_length(array);
130         for (i = 0 ; i < n ; i++) {
131                 result = json_object_array_get_idx(array, i);
132                 if (result && json_object_object_get_ex(result, key, &k)
133                         && json_object_get_type(k) == json_type_string
134                         && !strcmp(json_object_get_string(k), val))
135                         return result;
136         }
137         return NULL;
138 }
139
140 static int get_target(struct json_object **result, struct json_object *targets, const char *name, int create)
141 {
142         int rc;
143         struct json_object *t;
144
145         t = get_array_item_by_key(targets, string_sharp_target, name);
146         if (t) {
147                 if (!create)
148                         rc = 0;
149                 else {
150                         ERROR("duplicated target name: %s", name);
151                         t = NULL;
152                         rc = -EEXIST;
153                 }
154         } else {
155                 if (!create) {
156                         ERROR("target name not found: %s", name);
157                         rc = -ENOENT;
158                 } else {
159                         t = j_add_new_object(targets, NULL);
160                         if (t && j_add_string(t, string_sharp_target, name))
161                                 rc = 0;
162                         else {
163                                 json_object_put(t);
164                                 t = NULL;
165                                 rc = -ENOMEM;
166                         }
167                 }
168         }
169         *result = t;
170         return rc;
171 }
172
173 static int make_target(struct json_object *targets, const struct wgt_desc_feature *feat)
174 {
175         const char *id;
176         struct json_object *target;
177
178         id = get_target_name(feat, NULL);
179         if (id == NULL) {
180                 ERROR("target of feature %s is missing or repeated", feat->name);
181                 return -EINVAL;
182         }
183
184         return get_target(&target, targets, id, 1);
185 }
186
187 static int add_icon(struct json_object *target, const char *src, int width, int height)
188 {
189         int rc;
190         struct json_object *icon, *array;
191
192         rc = get_array(&array, target, string_icon, 1);
193         if (rc >= 0) {
194                 icon = json_object_new_object();
195                 if(!icon
196                 || !j_add_string(icon, string_src, src)
197                 || (width > 0 && !j_add_integer(icon, string_width, width))
198                 || (height > 0 && !j_add_integer(icon, string_height, height))
199                 || !j_add(array, NULL, icon)) {
200                         json_object_put(icon);
201                         rc = -ENOMEM;
202                 }
203         }
204         return rc;
205 }
206
207 static int make_main_target(struct json_object *targets, const struct wgt_desc *desc)
208 {
209         int rc;
210         struct wgt_desc_icon *icon;
211         struct json_object *target;
212
213         /* create the target 'main' */
214         rc = get_target(&target, targets, string_main, 1);
215
216         /* adds icons if any */
217         icon = desc->icons;
218         while (rc >= 0 && icon) {
219                 rc = add_icon(target, icon->src, icon->width, icon->height);
220                 icon = icon->next;
221         }
222
223         if (rc >= 0)
224                 rc = j_add_many_strings_m(target,
225                         "content.src", desc->content_src,
226                         "content.type", desc->content_type,
227                         "content.encoding", desc->content_encoding,
228                         NULL) ? 0 : -errno;
229
230         if (rc >= 0)
231                 if((desc->width && !j_add_integer(target, string_width, desc->width))
232                 || (desc->height && !j_add_integer(target, string_height, desc->height)))
233                         rc = -ENOMEM;
234
235         return rc;
236 }
237
238 /***********************************************************************************************************/
239
240 static struct json_object *object_of_param(const struct wgt_desc_param *param)
241 {
242         struct json_object *value;
243
244         value = json_object_new_object();
245         if (value
246          && j_add_string(value, string_name, param->name)
247          && j_add_string(value, string_value, param->value))
248                 return value;
249
250         json_object_put(value);
251         return NULL;
252 }
253
254 static int add_param_simple(struct json_object *obj, const struct wgt_desc_param *param, void *closure)
255 {
256         return j_add_string_m(obj, param->name, param->value);
257 }
258
259 static int add_param_array(struct json_object *obj, const struct wgt_desc_param *param, void *closure)
260 {
261         struct json_object *array, *value;
262
263         if (!closure)
264                 array = obj;
265         else if (!json_object_object_get_ex(obj, closure, &array)) {
266                 array = j_add_new_array(obj, closure);
267                 if (!array)
268                         return -ENOMEM;
269         }
270         value = object_of_param(param);
271         if (value && j_add(array, NULL, value))
272                 return 0;
273
274         json_object_put(value);
275         return -ENOMEM;
276 }
277
278 static int add_param_object(struct json_object *obj, const struct wgt_desc_param *param, void *closure)
279 {
280         struct json_object *object, *value;
281
282         if (!closure)
283                 object = obj;
284         else if (!json_object_object_get_ex(obj, closure, &object)) {
285                 object = j_add_new_object(obj, closure);
286                 if (!object)
287                         return -ENOMEM;
288         }
289         value = object_of_param(param);
290         if (value && j_add(object, param->name, value))
291                 return 0;
292
293         json_object_put(value);
294         return -ENOMEM;
295 }
296
297 static int add_targeted_params(struct json_object *targets, const struct wgt_desc_feature *feat, struct paramaction actions[])
298 {
299         int rc;
300         const char *id;
301         struct json_object *obj;
302
303         id = get_target_name(feat, string_main);
304         rc = get_target(&obj, targets, id, 0);
305         return rc < 0 ? rc : apply_params(obj, feat->params, actions);
306 }
307
308 static int add_provided(struct json_object *targets, const struct wgt_desc_feature *feat)
309 {
310         static struct paramaction actions[] = {
311                 { .name = string_sharp_target, .action = NULL, .closure = NULL },
312                 { .name = NULL, .action = add_param_simple, .closure = NULL }
313         };
314         return add_targeted_params(targets, feat, actions);
315 }
316
317 static int add_required_binding(struct json_object *targets, const struct wgt_desc_feature *feat)
318 {
319         static struct paramaction actions[] = {
320                 { .name = string_sharp_target, .action = NULL, .closure = NULL },
321                 { .name = NULL, .action = add_param_array, .closure = (void*)string_required_binding }
322         };
323         return add_targeted_params(targets, feat, actions);
324 }
325
326
327 static int add_required_permission(struct json_object *targets, const struct wgt_desc_feature *feat)
328 {
329         static struct paramaction actions[] = {
330                 { .name = string_sharp_target, .action = NULL, .closure = NULL },
331                 { .name = NULL, .action = add_param_object, .closure = (void*)string_required_permission }
332         };
333         return add_targeted_params(targets, feat, actions);
334 }
335
336 static int add_defined_permission(struct json_object *defperm, const struct wgt_desc_feature *feat)
337 {
338         static struct paramaction actions[] = {
339                 { .name = NULL, .action = add_param_array, .closure = NULL }
340         };
341         return apply_params(defperm, feat->params, actions);
342 }
343
344 /***********************************************************************************************************/
345
346 static struct json_object *to_json(const struct wgt_desc *desc)
347 {
348         size_t prefixlen;
349         const struct wgt_desc_feature *feat;
350         const char *featname;
351         struct json_object *result, *targets, *permissions;
352         int rc, rc2;
353
354         /* create the application structure */
355         if(!(result = json_object_new_object())
356         || !(targets = j_add_new_array(result, string_targets))
357         || !(permissions = j_add_new_array(result, string_defined_permission))
358         )
359                 goto error;
360
361         /* first pass: declarations */
362         rc = make_main_target(targets, desc);
363         prefixlen = strlen(string_AGL_widget_prefix);
364         for (feat = desc->features ; feat ; feat = feat->next) {
365                 featname = feat->name;
366                 if (!memcmp(featname, string_AGL_widget_prefix, prefixlen)) {
367                         if (!feat->required) {
368                                 ERROR("feature %s can't be optional", featname);
369                                 if (!rc)
370                                         rc = -EINVAL;
371                         }
372                         featname += prefixlen;
373                         if (!strcmp(featname, string_provided_binding)
374                         ||  !strcmp(featname, string_provided_application)) {
375                                 rc2 = make_target(targets, feat);
376                                 if (rc2 < 0 && !rc)
377                                         rc = rc2;
378                         }
379                 }
380         }
381
382         /* second pass: definitions */
383         for (feat = desc->features ; feat ; feat = feat->next) {
384                 featname = feat->name;
385                 if (!memcmp(featname, string_AGL_widget_prefix, prefixlen)) {
386                         featname += prefixlen;
387                         if (!strcmp(featname, string_defined_permission)) {
388                                 rc2 = add_defined_permission(permissions, feat);
389                                 if (rc2 < 0 && !rc)
390                                         rc = rc2;
391                         }
392                         else if (!strcmp(featname, string_provided_application)
393                                 || !strcmp(featname, string_provided_binding)) {
394                                 rc2 = add_provided(targets, feat);
395                                 if (rc2 < 0 && !rc)
396                                         rc = rc2;
397                         }
398                         else if (!strcmp(featname, string_required_binding)) {
399                                 rc2 = add_required_binding(targets, feat);
400                                 if (rc2 < 0 && !rc)
401                                         rc = rc2;
402                         }
403                         else if (!strcmp(featname, string_required_permission)) {
404                                 rc2 = add_required_permission(targets, feat);
405                                 if (rc2 < 0 && !rc)
406                                         rc = rc2;
407                         }
408                 }
409         }
410
411         /* fills the main */
412         rc2 = j_add_many_strings_m(result,
413                 string_id, desc->id,
414                 string_idaver, desc->idaver,
415                 string_version, desc->version,
416                 "ver", desc->ver,
417                 "author.content", desc->author,
418                 "author.href", desc->author_href,
419                 "author.email", desc->author_email,
420                 "license.content", desc->license,
421                 "license.href", desc->license_href,
422                 "defaultlocale", desc->defaultlocale,
423                 "name.content", desc->name,
424                 "name.short", desc->name_short,
425                 "description", desc->description,
426                 NULL) ? 0 : -errno;
427         if (rc2 < 0 && !rc)
428                 rc = rc2;
429
430         /* */
431
432         /* */
433         if (!rc) {
434                 return result;
435         }
436
437 error:
438         json_object_put(result);
439         return NULL;
440 }
441
442 struct json_object *wgt_info_to_json(struct wgt_info *info)
443 {
444         return to_json(wgt_info_desc(info));
445 }
446
447 struct json_object *wgt_to_json(struct wgt *wgt)
448 {
449         struct json_object *result;
450         struct wgt_info *info;
451
452         info = wgt_info_create(wgt, 1, 1, 1);
453         if (info == NULL)
454                 result = NULL;
455         else {
456                 result = wgt_info_to_json(info);
457                 wgt_info_unref(info);
458         }
459         return result;
460 }
461
462 struct json_object *wgt_path_at_to_json(int dfd, const char *path)
463 {
464         struct json_object *result;
465         struct wgt_info *info;
466
467         info = wgt_info_createat(dfd, path, 1, 1, 1);
468         if (info == NULL)
469                 result = NULL;
470         else {
471                 result = wgt_info_to_json(info);
472                 wgt_info_unref(info);
473         }
474         return result;
475 }
476
477 struct json_object *wgt_path_to_json(const char *path)
478 {
479         return wgt_path_at_to_json(AT_FDCWD, path);
480 }
481
482