4 author: José Bollo <jose.bollo@iot.bzh>
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
10 http://www.apache.org/licenses/LICENSE-2.0
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.
26 #include <sys/types.h>
30 #include "utils-json.h"
35 * The json object recorded by application widget
36 * has the following contents:
38 * id: STRING, the application identifier without version info
39 * path: STRING, the path of the root directory for the application
40 * content: STRING, the relative path to the entryu point of the application
41 * type: STRING, the mime type describing the type 'content'
42 * plugins: ARRAY, array of plugins
44 * STRING, path to the plugin
46 * public: OBJECT, public content describing the application widget
48 * id: STRING, the application identifier "idaver"
49 * version: STRING, the full version of the application
50 * width: INTEGER, the width indication or 0
51 * height: INTEGER, the height indication or 0
52 * name: STRING, the name of the application
53 * description: STRING, the description of the application
54 * shortname: STRING, the short name of the application
55 * author: STRING, the author of the application
60 * The structure afm_apps records the data about applications
61 * for several accesses.
64 struct json_object *pubarr; /* array of the public data of apps */
65 struct json_object *direct; /* hash of applications by their "idaver" */
66 struct json_object *byapp; /* hash of applications by their id */
70 * Two types of directory are handled:
71 * - root directories: contains subdirectories appid/version
72 * containing the applications
73 * - application directories: it contains an application
76 type_root, /* type for root directory */
77 type_app /* type for application directory */
81 * Structure for recording a path to application(s)
82 * in the list of directories.
85 struct afm_db_dir *next; /* link to the next item of the list */
86 enum dir_type type; /* the type of the path */
87 char path[1]; /* the path of the directory */
91 * The structure afm_db records the applications
92 * for a set of directories recorded as a linked list
95 int refcount; /* count of references to the structure */
96 struct afm_db_dir *dirhead; /* first directory of the set */
97 struct afm_db_dir *dirtail; /* last directory of the set */
98 struct afm_apps applications; /* the data about applications */
102 * The structure enumdata records data used when enumerating
103 * application directories of a root directory.
106 char path[PATH_MAX]; /* "current" computed path */
107 int length; /* length of path */
108 struct afm_apps apps; /* */
112 * Release the data of the afm_apps object 'apps'.
114 static void apps_put(struct afm_apps *apps)
116 json_object_put(apps->pubarr);
117 json_object_put(apps->direct);
118 json_object_put(apps->byapp);
122 * Adds the application widget 'desc' of the directory 'path' to the
123 * afm_apps object 'apps'.
124 * Returns 0 in case of success.
125 * Returns -1 and set errno in case of error
127 static int addwgt(struct afm_apps *apps, const char *path,
128 const struct wgt_desc *desc)
130 const struct wgt_desc_feature *feat;
131 struct json_object *priv, *pub, *bya, *plugs, *str;
133 /* create the application structure */
134 priv = json_object_new_object();
138 pub = j_add_new_object(priv, "public");
142 plugs = j_add_new_array(priv, "plugins");
146 if(!j_add_string(priv, "id", desc->id)
147 || !j_add_string(priv, "path", path)
148 || !j_add_string(priv, "content", desc->content_src)
149 || !j_add_string(priv, "type", desc->content_type)
150 || !j_add_string(pub, "id", desc->idaver)
151 || !j_add_string(pub, "version", desc->version)
152 || !j_add_integer(pub, "width", desc->width)
153 || !j_add_integer(pub, "height", desc->height)
154 || !j_add_string(pub, "name", desc->name)
155 || !j_add_string(pub, "description", desc->description)
156 || !j_add_string(pub, "shortname", desc->name_short)
157 || !j_add_string(pub, "author", desc->author))
160 /* extract plugins from features */
161 feat = desc->features;
163 static const char prefix[] = FWK_PREFIX_PLUGIN;
164 if (!memcmp(feat->name, prefix, sizeof prefix - 1)) {
165 str = json_object_new_string (
166 feat->name + sizeof prefix - 1);
169 if (json_object_array_add(plugs, str)) {
170 json_object_put(str);
177 /* record the application structure */
178 if (!j_add(apps->direct, desc->idaver, priv))
181 if (json_object_array_add(apps->pubarr, pub))
183 json_object_get(pub);
185 if (!json_object_object_get_ex(apps->byapp, desc->id, &bya)) {
186 bya = j_add_new_object(apps->byapp, desc->id);
191 if (!j_add(bya, desc->version, priv))
193 json_object_get(priv);
197 json_object_put(priv);
202 * Adds the application widget in the directory 'path' to the
203 * afm_apps object 'apps'.
204 * Returns 0 in case of success.
205 * Returns -1 and set errno in case of error
207 static int addapp(struct afm_apps *apps, const char *path)
210 struct wgt_info *info;
212 /* connect to the widget */
213 info = wgt_info_createat(AT_FDCWD, path, 0, 1, 0);
216 return 0; /* silently ignore bad directories */
219 /* adds the widget */
220 rc = addwgt(apps, path, wgt_info_desc(info));
221 wgt_info_unref(info);
226 * Enumerate the directories designated by 'data' and call the
227 * function 'callto' for each of them.
229 static int enumentries(struct enumdata *data, int (*callto)(struct enumdata *))
234 struct dirent entry, *e;
237 /* opens the directory */
238 dir = opendir(data->path);
242 /* prepare appending entry names */
243 beg = data->path + data->length;
246 /* enumerate entries */
247 rc = readdir_r(dir, &entry, &e);
249 if (entry.d_name[0] != '.' || (entry.d_name[1]
250 && (entry.d_name[1] != '.' || entry.d_name[2]))) {
252 len = strlen(entry.d_name);
253 if (beg + len >= data->path + sizeof data->path) {
254 errno = ENAMETOOLONG;
257 data->length = stpcpy(beg, entry.d_name) - data->path;
258 /* call the function */
263 rc = readdir_r(dir, &entry, &e);
270 * called for each version directory.
272 static int recordapp(struct enumdata *data)
274 return addapp(&data->apps, data->path);
278 * called for each application directory.
279 * enumerate directories of the existing versions.
281 static int enumvers(struct enumdata *data)
283 int rc = enumentries(data, recordapp);
284 return !rc || errno != ENOTDIR ? 0 : rc;
288 * Adds the directory of 'path' and 'type' to the afm_db object 'afdb'.
289 * Returns 0 in case of success.
290 * Returns -1 and set errno in case of error
291 * Possible errno values: ENOMEM, ENAMETOOLONG
293 static int add_dir(struct afm_db *afdb, const char *path, enum dir_type type)
295 struct afm_db_dir *dir;
302 if (len >= PATH_MAX) {
303 errno = ENAMETOOLONG;
307 /* avoiding duplications */
309 while(dir != NULL && (strcmp(dir->path, path) || dir->type != type))
314 /* allocates the structure */
315 dir = malloc(strlen(path) + sizeof * dir);
324 strcpy(dir->path, path);
325 if (afdb->dirtail == NULL)
328 afdb->dirtail->next = dir;
334 * Creates an afm_db object and returns it with one reference added.
335 * Return NULL with errno = ENOMEM if memory exhausted.
337 struct afm_db *afm_db_create()
339 struct afm_db *afdb = malloc(sizeof * afdb);
344 afdb->dirhead = NULL;
345 afdb->dirtail = NULL;
346 afdb->applications.pubarr = NULL;
347 afdb->applications.direct = NULL;
348 afdb->applications.byapp = NULL;
354 * Adds a reference to an existing afm_db.
356 void afm_db_addref(struct afm_db *afdb)
363 * Removes a reference to an existing afm_db object.
364 * Removes the objet if there no more reference to it.
366 void afm_db_unref(struct afm_db *afdb)
368 struct afm_db_dir *dir;
371 if (!--afdb->refcount) {
372 /* no more reference, clean the memory used by the object */
373 apps_put(&afdb->applications);
374 while (afdb->dirhead != NULL) {
376 afdb->dirhead = dir->next;
384 * Adds the root directory of 'path' to the afm_db object 'afdb'.
385 * Be aware that no check is done on the directory of 'path' that will
386 * only be used within calls to the function 'afm_db_update_applications'.
387 * Returns 0 in case of success.
388 * Returns -1 and set errno in case of error
389 * Possible errno values: ENOMEM, ENAMETOOLONG
391 int afm_db_add_root(struct afm_db *afdb, const char *path)
393 return add_dir(afdb, path, type_root);
397 * Adds the application directory of 'path' to the afm_db object 'afdb'.
398 * Be aware that no check is done on the directory of 'path' that will
399 * only be used within calls to the function 'afm_db_update_applications'.
400 * Returns 0 in case of success.
401 * Returns -1 and set errno in case of error
402 * Possible errno values: ENOMEM, ENAMETOOLONG
404 int afm_db_add_application(struct afm_db *afdb, const char *path)
406 return add_dir(afdb, path, type_app);
410 * Regenerate the list of applications of the afm_bd object 'afdb'.
411 * Returns 0 in case of success.
412 * Returns -1 and set errno in case of error
414 int afm_db_update_applications(struct afm_db *afdb)
417 struct enumdata edata;
418 struct afm_apps oldapps;
419 struct afm_db_dir *dir;
421 /* create the result */
422 edata.apps.pubarr = json_object_new_array();
423 edata.apps.direct = json_object_new_object();
424 edata.apps.byapp = json_object_new_object();
425 if (edata.apps.pubarr == NULL || edata.apps.direct == NULL
426 || edata.apps.byapp == NULL) {
430 /* for each directory of afdb */
431 for (dir = afdb->dirhead ; dir != NULL ; dir = dir->next) {
432 if (dir->type == type_root) {
433 edata.length = stpcpy(edata.path, dir->path)
435 assert(edata.length < sizeof edata.path);
436 /* enumerate the applications */
437 rc = enumentries(&edata, enumvers);
441 rc = addapp(&edata.apps, dir->path);
444 /* commit the result */
445 oldapps = afdb->applications;
446 afdb->applications = edata.apps;
451 apps_put(&edata.apps);
456 * Ensure that applications of the afm_bd object 'afdb' are listed.
457 * Returns 0 in case of success.
458 * Returns -1 and set errno in case of error
460 int afm_db_ensure_applications(struct afm_db *afdb)
462 return afdb->applications.pubarr ? 0 : afm_db_update_applications(afdb);
466 * Get the list of the applications public data of the afm_db object 'afdb'.
467 * The list is returned as a JSON-array that must be released using
469 * Returns NULL in case of error.
471 struct json_object *afm_db_application_list(struct afm_db *afdb)
473 return afm_db_ensure_applications(afdb) ? NULL
474 : json_object_get(afdb->applications.pubarr);
478 * Get the private data of the applications of 'id' in the afm_db object 'afdb'.
479 * It returns a JSON-object that must be released using 'json_object_put'.
480 * Returns NULL in case of error.
482 struct json_object *afm_db_get_application(struct afm_db *afdb, const char *id)
484 struct json_object *result;
485 if (!afm_db_ensure_applications(afdb) && json_object_object_get_ex(
486 afdb->applications.direct, id, &result))
487 return json_object_get(result);
492 * Get the public data of the applications of 'id' in the afm_db object 'afdb'.
493 * It returns a JSON-object that must be released using 'json_object_put'.
494 * Returns NULL in case of error.
496 struct json_object *afm_db_get_application_public(struct afm_db *afdb,
499 struct json_object *result;
500 struct json_object *priv = afm_db_get_application(afdb, id);
503 if (json_object_object_get_ex(priv, "public", &result))
504 json_object_get(result);
507 json_object_put(priv);
514 #if defined(TESTAPPFWK)
518 struct afm_db *afdb = afm_db_create();
519 afm_db_add_root(afdb,FWK_APP_DIR);
520 afm_db_update_applications(afdb);
521 printf("array = %s\n", json_object_to_json_string_ext(afdb->applications.pubarr, 3));
522 printf("direct = %s\n", json_object_to_json_string_ext(afdb->applications.direct, 3));
523 printf("byapp = %s\n", json_object_to_json_string_ext(afdb->applications.byapp, 3));