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