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