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>
28 #include <json-c/json.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 = (int)(stpcpy(beg, entry.d_name)
259 /* call the function */
264 rc = readdir_r(dir, &entry, &e);
271 * called for each version directory.
273 static int recordapp(struct enumdata *data)
275 return addapp(&data->apps, data->path);
279 * called for each application directory.
280 * enumerate directories of the existing versions.
282 static int enumvers(struct enumdata *data)
284 int rc = enumentries(data, recordapp);
285 return !rc || errno != ENOTDIR ? 0 : rc;
289 * Adds the directory of 'path' and 'type' to the afm_db object 'afdb'.
290 * Returns 0 in case of success.
291 * Returns -1 and set errno in case of error
292 * Possible errno values: ENOMEM, ENAMETOOLONG
294 static int add_dir(struct afm_db *afdb, const char *path, enum dir_type type)
296 struct afm_db_dir *dir;
303 if (len >= PATH_MAX) {
304 errno = ENAMETOOLONG;
308 /* avoiding duplications */
310 while(dir != NULL && (strcmp(dir->path, path) || dir->type != type))
315 /* allocates the structure */
316 dir = malloc(strlen(path) + sizeof * dir);
325 strcpy(dir->path, path);
326 if (afdb->dirtail == NULL)
329 afdb->dirtail->next = dir;
335 * Creates an afm_db object and returns it with one reference added.
336 * Return NULL with errno = ENOMEM if memory exhausted.
338 struct afm_db *afm_db_create()
340 struct afm_db *afdb = malloc(sizeof * afdb);
345 afdb->dirhead = NULL;
346 afdb->dirtail = NULL;
347 afdb->applications.pubarr = NULL;
348 afdb->applications.direct = NULL;
349 afdb->applications.byapp = NULL;
355 * Adds a reference to an existing afm_db.
357 void afm_db_addref(struct afm_db *afdb)
364 * Removes a reference to an existing afm_db object.
365 * Removes the objet if there no more reference to it.
367 void afm_db_unref(struct afm_db *afdb)
369 struct afm_db_dir *dir;
372 if (!--afdb->refcount) {
373 /* no more reference, clean the memory used by the object */
374 apps_put(&afdb->applications);
375 while (afdb->dirhead != NULL) {
377 afdb->dirhead = dir->next;
385 * Adds the root directory of 'path' to the afm_db object 'afdb'.
386 * Be aware that no check is done on the directory of 'path' that will
387 * only be used within calls to the function 'afm_db_update_applications'.
388 * Returns 0 in case of success.
389 * Returns -1 and set errno in case of error
390 * Possible errno values: ENOMEM, ENAMETOOLONG
392 int afm_db_add_root(struct afm_db *afdb, const char *path)
394 return add_dir(afdb, path, type_root);
398 * Adds the application directory of 'path' to the afm_db object 'afdb'.
399 * Be aware that no check is done on the directory of 'path' that will
400 * only be used within calls to the function 'afm_db_update_applications'.
401 * Returns 0 in case of success.
402 * Returns -1 and set errno in case of error
403 * Possible errno values: ENOMEM, ENAMETOOLONG
405 int afm_db_add_application(struct afm_db *afdb, const char *path)
407 return add_dir(afdb, path, type_app);
411 * Regenerate the list of applications of the afm_bd object 'afdb'.
412 * Returns 0 in case of success.
413 * Returns -1 and set errno in case of error
415 int afm_db_update_applications(struct afm_db *afdb)
418 struct enumdata edata;
419 struct afm_apps oldapps;
420 struct afm_db_dir *dir;
422 /* create the result */
423 edata.apps.pubarr = json_object_new_array();
424 edata.apps.direct = json_object_new_object();
425 edata.apps.byapp = json_object_new_object();
426 if (edata.apps.pubarr == NULL || edata.apps.direct == NULL
427 || edata.apps.byapp == NULL) {
431 /* for each directory of afdb */
432 for (dir = afdb->dirhead ; dir != NULL ; dir = dir->next) {
433 if (dir->type == type_root) {
434 edata.length = (int)(stpcpy(edata.path, dir->path)
436 assert(edata.length < (int)sizeof edata.path);
437 /* enumerate the applications */
438 rc = enumentries(&edata, enumvers);
442 rc = addapp(&edata.apps, dir->path);
445 /* commit the result */
446 oldapps = afdb->applications;
447 afdb->applications = edata.apps;
452 apps_put(&edata.apps);
457 * Ensure that applications of the afm_bd object 'afdb' are listed.
458 * Returns 0 in case of success.
459 * Returns -1 and set errno in case of error
461 int afm_db_ensure_applications(struct afm_db *afdb)
463 return afdb->applications.pubarr ? 0 : afm_db_update_applications(afdb);
467 * Get the list of the applications public data of the afm_db object 'afdb'.
468 * The list is returned as a JSON-array that must be released using
470 * Returns NULL in case of error.
472 struct json_object *afm_db_application_list(struct afm_db *afdb)
474 return afm_db_ensure_applications(afdb) ? NULL
475 : json_object_get(afdb->applications.pubarr);
479 * Get the private data of the applications of 'id' in the afm_db object 'afdb'.
480 * It returns a JSON-object that must be released using 'json_object_put'.
481 * Returns NULL in case of error.
483 struct json_object *afm_db_get_application(struct afm_db *afdb, const char *id)
485 struct json_object *result;
486 if (!afm_db_ensure_applications(afdb) && json_object_object_get_ex(
487 afdb->applications.direct, id, &result))
488 return json_object_get(result);
493 * Get the public data of the applications of 'id' in the afm_db object 'afdb'.
494 * It returns a JSON-object that must be released using 'json_object_put'.
495 * Returns NULL in case of error.
497 struct json_object *afm_db_get_application_public(struct afm_db *afdb,
500 struct json_object *result;
501 struct json_object *priv = afm_db_get_application(afdb, id);
504 if (json_object_object_get_ex(priv, "public", &result))
505 json_object_get(result);
508 json_object_put(priv);
515 #if defined(TESTAPPFWK)
519 struct afm_db *afdb = afm_db_create();
520 afm_db_add_root(afdb,FWK_APP_DIR);
521 afm_db_update_applications(afdb);
522 printf("array = %s\n", json_object_to_json_string_ext(afdb->applications.pubarr, 3));
523 printf("direct = %s\n", json_object_to_json_string_ext(afdb->applications.direct, 3));
524 printf("byapp = %s\n", json_object_to_json_string_ext(afdb->applications.byapp, 3));