3b7cb36aad69c5f50fd68a501c59266ca141a270
[src/app-framework-main.git] / src / wgt-info.c
1 /*
2  Copyright (C) 2015-2020 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 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <assert.h>
23 #include <ctype.h>
24
25 #include <libxml/tree.h>
26
27 #include "verbose.h"
28 #include "wgt.h"
29 #include "wgt-config.h"
30 #include "wgt-strings.h"
31 #include "wgt-info.h"
32
33 struct wgt_info {
34         int refcount;
35         struct wgt *wgt;
36         struct wgt_desc desc;
37 };
38
39 static int getpropbool(xmlNodePtr node, const char *prop, int def)
40 {
41         int result;
42         char *val = xmlGetProp(node, prop);
43         if (!val)
44                 result = def;
45         else {
46                 if (!strcmp(val, "true"))
47                         result = 1;
48                 else if (!strcmp(val, "false"))
49                         result = 0;
50                 else
51                         result = def;
52                 xmlFree(val);
53         }
54         return result;
55 }
56
57 static int getpropnum(xmlNodePtr node, const char *prop, int def)
58 {
59         int result;
60         char *val = xmlGetProp(node, prop);
61         if (!val)
62                 result = def;
63         else {
64                 result = atoi(val);
65                 xmlFree(val);
66         }
67         return result;
68 }
69
70 static xmlChar *optprop(xmlNodePtr node, const char *prop)
71 {
72         return node ? xmlGetProp(node, prop) : NULL;
73 }
74
75 static xmlChar *optcontent(xmlNodePtr node)
76 {
77         return node ? xmlNodeGetContent(node) : NULL;
78 }
79
80 static char *mkver(char *version)
81 {
82         unsigned int lver;
83         char c, *r;
84         if (version) {
85                 c = version[lver = 0];
86                 while(c && c != ' ' && c != '.')
87                         c = version[++lver];
88                 if (c == '.') {
89                         c = version[++lver];
90                         while(c && c != ' ' && c != '.')
91                                 c = version[++lver];
92                 }
93                 r = malloc(lver + 1);
94                 if (r) {
95                         memcpy(r, version, lver);
96                         r[lver] = 0;
97                         return r;
98                 }
99         }
100         return NULL;
101 }
102
103 static char *mkidaver(char *id, char *ver)
104 {
105         size_t lid, lver;
106         char *r;
107         if (id && ver) {
108                 lid = strlen(id);
109                 lver = strlen(ver);
110                 r = malloc(2 + lid + lver);
111                 if (r) {
112                         memcpy(r, id, lid);
113                         r[lid] = '@';
114                         memcpy(r + lid + 1, ver, lver);
115                         r[lid + lver + 1] = 0;
116                         return r;
117                 }
118         }
119         return NULL;
120 }
121
122 static void make_lowercase(char *s)
123 {
124         if (s) {
125                 while(*s) {
126                         *s = (char)tolower(*s);
127                         s++;
128                 }
129         }
130 }
131
132 static int fill_desc(struct wgt_desc *desc, int want_icons, int want_features, int want_preferences)
133 {
134         xmlNodePtr node, pnode;
135         struct wgt_desc_icon *icon, **icontail;
136         struct wgt_desc_feature *feature, **featuretail;
137         struct wgt_desc_preference *preference, **preferencetail;
138         struct wgt_desc_param *param, **paramtail;
139
140         node = wgt_config_widget();
141         if (!node) {
142                 WARNING("no widget");
143                 errno = EINVAL;
144                 return -1;
145         }
146         desc->id = xmlGetProp(node, string_id);
147         make_lowercase(desc->id);
148         desc->version = xmlGetProp(node, string_version);
149         desc->ver = mkver(desc->version);
150         make_lowercase(desc->ver);
151         desc->idaver = mkidaver(desc->id, desc->ver);
152         desc->width = getpropnum(node, string_width, 0);
153         desc->height = getpropnum(node, string_height, 0);
154         desc->viewmodes = xmlGetProp(node, string_viewmodes);
155         desc->defaultlocale = xmlGetProp(node, string_defaultlocale);
156
157         node = wgt_config_name();
158         desc->name = optcontent(node);
159         desc->name_short = optprop(node, string_short);
160
161         node = wgt_config_description();
162         desc->description = optcontent(node);
163
164         node = wgt_config_author();
165         desc->author = optcontent(node);
166         desc->author_href = optprop(node, string_href);
167         desc->author_email = optprop(node, string_email);
168
169         node = wgt_config_license();
170         desc->license = optcontent(node);
171         desc->license_href = optprop(node, string_href);
172         
173         node = wgt_config_content();
174         desc->content_src = optprop(node, string_src);
175         if (node && desc->content_src == NULL) {
176                 WARNING("content without src");
177                 errno = EINVAL;
178                 return -1;
179         }
180         desc->content_type = optprop(node, string_type);
181         desc->content_encoding = optprop(node, string_encoding);
182
183         if (want_icons) {
184                 icontail = &desc->icons;
185                 node = wgt_config_first_icon();
186                 while (node) {
187                         icon = malloc(sizeof * icon);
188                         if (icon == NULL) {
189                                 errno = ENOMEM;
190                                 return -1;
191                         }
192                         icon->src = xmlGetProp(node, string_src);
193                         icon->width = getpropnum(node, string_width, 0);
194                         icon->height = getpropnum(node, string_height, 0);
195
196                         icon->next = NULL;
197                         *icontail = icon;
198
199                         if (icon->src == NULL) {
200                                 WARNING("icon without src");
201                                 errno = EINVAL;
202                                 return -1;
203                         }
204                         icontail = &icon->next;
205                         node = wgt_config_next_icon(node);
206                 }
207         }
208
209         if (want_features) {
210                 featuretail = &desc->features;
211                 node = wgt_config_first_feature();
212                 while (node) {
213                         feature = malloc(sizeof * feature);
214                         if (feature == NULL) {
215                                 errno = ENOMEM;
216                                 return -1;
217                         }
218                         feature->name = xmlGetProp(node, string_name);
219                         feature->required = getpropbool(node, string_required, 1);
220                         feature->params = NULL;
221
222                         feature->next = NULL;
223                         *featuretail = feature;
224
225                         if (feature->name == NULL) {
226                                 WARNING("feature without name");
227                                 errno = EINVAL;
228                                 return -1;
229                         }
230
231                         paramtail = &feature->params;
232                         pnode = wgt_config_first_param(node);
233                         while (pnode) {
234                                 param = malloc(sizeof * param);
235                                 if (param == NULL) {
236                                         errno = ENOMEM;
237                                         return -1;
238                                 }
239                                 param->name = xmlGetProp(pnode, string_name);
240                                 param->value = xmlGetProp(pnode, string_value);
241
242                                 param->next = NULL;
243                                 *paramtail = param;
244
245                                 if (param->name == NULL || param->value == NULL) {
246                                         WARNING("param without name or value");
247                                         errno = EINVAL;
248                                         return -1;
249                                 }
250
251                                 paramtail = &param->next;
252                                 pnode = wgt_config_next_param(pnode);
253                         }
254
255                         featuretail = &feature->next;
256                         node = wgt_config_next_feature(node);
257                 }
258         }
259
260         if (want_preferences) {
261                 preferencetail = &desc->preferences;
262                 node = wgt_config_first_preference();
263                 while (node) {
264                         preference = malloc(sizeof * preference);
265                         if (preference == NULL) {
266                                 errno = ENOMEM;
267                                 return -1;
268                         }
269                         preference->name = xmlGetProp(node, string_name);
270                         preference->value = xmlGetProp(node, string_value);
271                         preference->readonly = getpropbool(node, string_readonly, 0);
272
273                         *preferencetail = preference;
274                         preference->next = NULL;
275
276                         if (preference->name == NULL) {
277                                 WARNING("preference without name");
278                                 errno = EINVAL;
279                                 return -1;
280                         }
281
282                         preferencetail = &preference->next;
283                         node = wgt_config_next_preference(node);
284                 }
285         }
286         return 0;
287 }
288
289 static void free_desc(struct wgt_desc *desc)
290 {
291         struct wgt_desc_icon *icon;
292         struct wgt_desc_feature *feature;
293         struct wgt_desc_preference *preference;
294         struct wgt_desc_param *param;
295
296         xmlFree(desc->id);
297         xmlFree(desc->version);
298         free(desc->ver);
299         free(desc->idaver);
300         xmlFree(desc->viewmodes);
301         xmlFree(desc->defaultlocale);
302         xmlFree(desc->name);
303         xmlFree(desc->name_short);
304         xmlFree(desc->description);
305         xmlFree(desc->author);
306         xmlFree(desc->author_href);
307         xmlFree(desc->author_email);
308         xmlFree(desc->license);
309         xmlFree(desc->license_href);
310         xmlFree(desc->content_src);
311         xmlFree(desc->content_type);
312         xmlFree(desc->content_encoding);
313
314         while(desc->icons) {
315                 icon = desc->icons;
316                 desc->icons = icon->next;
317                 xmlFree(icon->src);
318                 free(icon);
319         }
320
321         while(desc->features) {
322                 feature = desc->features;
323                 desc->features = feature->next;
324                 xmlFree(feature->name);
325                 while(feature->params) {
326                         param = feature->params;
327                         feature->params = param->next;
328                         xmlFree(param->name);
329                         xmlFree(param->value);
330                         free(param);
331                 }
332                 free(feature);
333         }
334
335         while(desc->preferences) {
336                 preference = desc->preferences;
337                 desc->preferences = preference->next;
338                 xmlFree(preference->name);
339                 xmlFree(preference->value);
340                 free(preference);
341         }
342 }
343
344 static void dump_desc(struct wgt_desc *desc, FILE *f, const char *prefix)
345 {
346         struct wgt_desc_icon *icon;
347         struct wgt_desc_feature *feature;
348         struct wgt_desc_preference *preference;
349         struct wgt_desc_param *param;
350
351         if (desc->id) fprintf(f, "%sid: %s\n", prefix, desc->id);
352         if (desc->version) fprintf(f, "%sversion: %s\n", prefix, desc->version);
353         if (desc->ver) fprintf(f, "%sver: %s\n", prefix, desc->ver);
354         if (desc->idaver) fprintf(f, "%sidaver: %s\n", prefix, desc->idaver);
355         if (desc->width) fprintf(f, "%swidth: %d\n", prefix, desc->width);
356         if (desc->height) fprintf(f, "%sheight: %d\n", prefix, desc->height);
357         if (desc->viewmodes) fprintf(f, "%sviewmodes: %s\n", prefix, desc->viewmodes);
358         if (desc->defaultlocale) fprintf(f, "%sdefaultlocale: %s\n", prefix, desc->defaultlocale);
359         if (desc->name) fprintf(f, "%sname: %s\n", prefix, desc->name);
360         if (desc->name_short) fprintf(f, "%sname_short: %s\n", prefix, desc->name_short);
361         if (desc->description) fprintf(f, "%sdescription: %s\n", prefix, desc->description);
362         if (desc->author) fprintf(f, "%sauthor: %s\n", prefix, desc->author);
363         if (desc->author_href) fprintf(f, "%sauthor_href: %s\n", prefix, desc->author_href);
364         if (desc->author_email) fprintf(f, "%sauthor_email: %s\n", prefix, desc->author_email);
365         if (desc->license) fprintf(f, "%slicense: %s\n", prefix, desc->license);
366         if (desc->license_href) fprintf(f, "%slicense_href: %s\n", prefix, desc->license_href);
367         if (desc->content_src) fprintf(f, "%scontent_src: %s\n", prefix, desc->content_src);
368         if (desc->content_type) fprintf(f, "%scontent_type: %s\n", prefix, desc->content_type);
369         if (desc->content_encoding) fprintf(f, "%scontent_encoding: %s\n", prefix, desc->content_encoding);
370
371         icon = desc->icons;
372         while(icon) {
373                 fprintf(f, "%s+ icon src: %s\n", prefix, icon->src);
374                 if (icon->width) fprintf(f, "%s       width: %d\n", prefix, icon->width);
375                 if (icon->height) fprintf(f, "%s       height: %d\n", prefix, icon->height);
376                 icon = icon->next;
377         }
378
379         feature = desc->features;
380         while(feature) {
381                 fprintf(f, "%s+ feature name: %s\n", prefix, feature->name);
382                 fprintf(f, "%s          required: %s\n", prefix, feature->required ? "true" : "false");
383                 param = feature->params;
384                 while(param) {
385                         fprintf(f, "%s          + param name: %s\n", prefix, param->name);
386                         fprintf(f, "%s                  value: %s\n", prefix, param->value);
387                         param = param->next;
388                 }
389                 feature = feature->next;
390         }
391
392         preference = desc->preferences;
393         while(preference) {
394                 fprintf(f, "%s+ preference name: %s\n", prefix, preference->name);
395                 if (preference->value) fprintf(f, "%s             value: %s\n", prefix, preference->value);
396                 fprintf(f, "%s             readonly: %s\n", prefix, preference->readonly ? "true" : "false");
397                 preference = preference->next;
398         }
399 }
400
401 struct wgt_info *wgt_info_create(struct wgt *wgt, int icons, int features, int preferences)
402 {
403         int rc;
404         struct wgt_info *result;
405
406         assert(wgt);
407         assert(wgt_is_connected(wgt));
408         rc = wgt_config_open(wgt);
409         if (rc) {
410                 errno = EINVAL;
411                 return NULL;
412         }
413
414         result = calloc(sizeof * result, 1);
415         if (!result) {
416                 wgt_config_close();
417                 errno = ENOMEM;
418                 return NULL;
419         }
420         result->refcount = 1;
421         result->wgt = wgt;
422         wgt_addref(wgt);
423
424         rc = fill_desc(&result->desc, icons, features, preferences);
425         wgt_config_close();
426         if (rc) {
427                 wgt_info_unref(result);
428                 return NULL;
429         }
430         return result;
431 }
432
433 struct wgt_info *wgt_info_createat(int dirfd, const char *pathname, int icons, int features, int preferences)
434 {
435         struct wgt_info *result = NULL;
436         struct wgt *wgt = wgt_createat(dirfd, pathname);
437         if (wgt) {
438                 result = wgt_info_create(wgt, icons, features, preferences);
439                 wgt_unref(wgt);
440         }
441         return result;
442 }
443
444 const struct wgt_desc *wgt_info_desc(struct wgt_info *ifo)
445 {
446         assert(ifo);
447         return &ifo->desc;
448 }
449
450 struct wgt *wgt_info_wgt(struct wgt_info *ifo)
451 {
452         assert(ifo);
453         assert(ifo->wgt);
454         return ifo->wgt;
455 }
456
457 void wgt_info_addref(struct wgt_info *ifo)
458 {
459         assert(ifo);
460         assert(ifo->refcount > 0);
461         ifo->refcount++;
462 }
463
464 void wgt_info_unref(struct wgt_info *ifo)
465 {
466         assert(ifo);
467         assert(ifo->refcount > 0);
468         if (--ifo->refcount)
469                 return;
470
471         free_desc(&ifo->desc);
472         wgt_unref(ifo->wgt);
473         free(ifo);
474 }
475
476 void wgt_info_dump(struct wgt_info *ifo, int fd, const char *prefix)
477 {
478         FILE *f;
479
480         assert(ifo);
481         f = fdopen(fd, "w");
482         if (f == NULL)
483                 WARNING("can't fdopen in wgt_info_dump");
484         else {
485                 dump_desc(&ifo->desc, f, prefix);
486                 fclose(f);
487         }
488 }
489
490 const struct wgt_desc_feature *wgt_info_feature(struct wgt_info *ifo, const char *name)
491 {
492         const struct wgt_desc_feature *result = ifo->desc.features;
493         while(result && strcmp(result->name, name))
494                 result = result->next;
495         return result;
496 }
497
498 const char *wgt_info_param(const struct wgt_desc_feature *feature, const char *name)
499 {
500         const struct wgt_desc_param *param = feature->params;
501         while(param) {
502                 if (0 == strcmp(name, param->name))
503                         return param->value;
504                 param = param->next;
505         }
506         return NULL;
507 }
508