2 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <sys/types.h>
28 #include <libxml/parser.h>
29 #include <libxml/tree.h>
35 #define DbgPrint(format, arg...) LOGD("[
\e[32m%s/%s
\e[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
36 #define ErrPrint(format, arg...) LOGE("[
\e[32m%s/%s
\e[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
43 * +----+-------+------+---------+-----------+------------+
44 * | id | appid | Icon | Name | extra_key | extra_data |
45 * +----+-------+------+---------+-----------+------------+
46 * | id | - | - | - | - | - |
47 * +----+-------+------+---------+-----------+------------+
49 * +----+------+------+
50 * | fk | lang | name |
51 * +----+------+------+
53 * +----+------+------+
56 #if !defined(LIBXML_TREE_ENABLED)
57 #error "LIBXML is not supporting the tree"
66 .dbfile = "/opt/dbspace/.shortcut_service.db",
70 static inline int begin_transaction(void)
75 ret = sqlite3_prepare_v2(s_info.handle, "BEGIN TRANSACTION", -1, &stmt, NULL);
76 if (ret != SQLITE_OK) {
77 DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
81 if (sqlite3_step(stmt) != SQLITE_DONE) {
82 DbgPrint("Failed to do update (%s)\n",
83 sqlite3_errmsg(s_info.handle));
84 sqlite3_finalize(stmt);
88 sqlite3_finalize(stmt);
92 static inline int rollback_transaction(void)
97 ret = sqlite3_prepare_v2(s_info.handle, "ROLLBACK TRANSACTION", -1, &stmt, NULL);
98 if (ret != SQLITE_OK) {
99 DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
103 if (sqlite3_step(stmt) != SQLITE_DONE) {
104 DbgPrint("Failed to do update (%s)\n",
105 sqlite3_errmsg(s_info.handle));
106 sqlite3_finalize(stmt);
110 sqlite3_finalize(stmt);
114 static inline int commit_transaction(void)
119 ret = sqlite3_prepare_v2(s_info.handle, "COMMIT TRANSACTION", -1, &stmt, NULL);
120 if (ret != SQLITE_OK) {
121 DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
125 if (sqlite3_step(stmt) != SQLITE_DONE) {
126 DbgPrint("Failed to do update (%s)\n",
127 sqlite3_errmsg(s_info.handle));
128 sqlite3_finalize(stmt);
132 sqlite3_finalize(stmt);
135 static inline void db_create_table(void)
138 static const char *ddl =
139 "CREATE TABLE shortcut_service ("
140 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
147 if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
148 ErrPrint("Failed to execute the DDL (%s)\n", err);
152 if (sqlite3_changes(s_info.handle) == 0)
153 ErrPrint("No changes to DB\n");
155 ddl = "CREATE TABLE shortcut_name (id INTEGER, lang TEXT, name TEXT)";
156 if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
157 ErrPrint("Failed to execute the DDL (%s)\n", err);
161 if (sqlite3_changes(s_info.handle) == 0)
162 ErrPrint("No changes to DB\n");
165 static inline int db_remove_record(const char *appid, const char *key, const char *data)
167 static const char *dml = "DELETE FROM shortcut_service WHERE appid = ? AND extra_key = ? AND extra_data = ?";
171 if (!appid || !key || !data) {
172 ErrPrint("Invalid argument\n");
176 ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
177 if (ret != SQLITE_OK) {
178 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
183 if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
184 ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle));
188 if (sqlite3_bind_text(stmt, 2, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
189 ErrPrint("Failed to bind a key(%s)\n", sqlite3_errmsg(s_info.handle));
193 if (sqlite3_bind_text(stmt, 3, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
194 ErrPrint("Failed to bind a data(%s)\n", sqlite3_errmsg(s_info.handle));
199 if (sqlite3_step(stmt) != SQLITE_DONE) {
201 ErrPrint("Failed to execute the DML for %s - %s(%s)\n", appid, key, data);
204 if (sqlite3_changes(s_info.handle) == 0)
205 DbgPrint("No changes\n");
209 sqlite3_clear_bindings(stmt);
210 sqlite3_finalize(stmt);
214 static inline int db_remove_name(int id)
216 static const char *dml = "DELETE FROM shortcut_name WHERE id = ?";
221 ErrPrint("Inavlid id\n");
225 ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
226 if (ret != SQLITE_OK) {
227 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
231 if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
232 ErrPrint("Failed to bind id(%d)\n", id);
238 if (sqlite3_step(stmt) != SQLITE_DONE) {
240 ErrPrint("Failed to execute the DML for %d\n", id);
244 if (sqlite3_changes(s_info.handle) == 0)
245 DbgPrint("No changes\n");
249 sqlite3_clear_bindings(stmt);
250 sqlite3_finalize(stmt);
254 static inline int db_insert_record(const char *appid, const char *icon, const char *name, const char *key, const char *data)
256 static const char *dml = "INSERT INTO shortcut_service (appid, icon, name, extra_key, extra_data) VALUES (?, ?, ?, ?, ?)";
261 ErrPrint("Failed to get appid\n");
266 ErrPrint("Failed to get name\n");
271 ErrPrint("Failed to get key\n");
276 ErrPrint("Faield to get key\n");
280 icon = icon ? icon : "";
282 ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
283 if (ret != SQLITE_OK) {
284 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
289 if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
290 ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle));
294 if (sqlite3_bind_text(stmt, 2, icon, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
295 ErrPrint("Failed to bind a icon(%s)\n", sqlite3_errmsg(s_info.handle));
299 if (sqlite3_bind_text(stmt, 3, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
300 ErrPrint("Failed to bind a name(%s)\n", sqlite3_errmsg(s_info.handle));
304 if (sqlite3_bind_text(stmt, 4, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
305 ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle));
309 if (sqlite3_bind_text(stmt, 5, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
310 ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle));
315 if (sqlite3_step(stmt) != SQLITE_DONE) {
316 ErrPrint("Failed to execute the DML for %s - %s\n", appid, name);
322 sqlite3_clear_bindings(stmt);
323 sqlite3_finalize(stmt);
327 static inline int db_insert_name(int id, const char *lang, const char *name)
329 static const char *dml = "INSERT INTO shortcut_name (id, lang, name) VALUES (?, ?, ?)";
333 if (id < 0 || !lang || !name) {
334 ErrPrint("Invalid parameters\n");
338 ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
339 if (ret != SQLITE_OK) {
340 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
344 if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
345 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
350 if (sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
351 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
356 if (sqlite3_bind_text(stmt, 3, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
357 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
363 if (sqlite3_step(stmt) != SQLITE_DONE) {
364 ErrPrint("Failed to execute the DML for %d %s %s\n", id, lang, name);
370 sqlite3_clear_bindings(stmt);
371 sqlite3_finalize(stmt);
375 static inline int db_get_id(const char *appid, const char *key, const char *data)
377 static const char *dml = "SELECT id FROM shortcut_service WHERE appid = ? AND extra_key = ? AND extra_data = ?";
381 if (!appid || !key || !data) {
382 ErrPrint("Invalid argument\n");
386 ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
387 if (ret != SQLITE_OK) {
388 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
393 if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
394 ErrPrint("Failed to bind a appid(%s) - %s\n", appid, sqlite3_errmsg(s_info.handle));
398 if (sqlite3_bind_text(stmt, 2, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
399 ErrPrint("Failed to bind a key(%s) - %s\n", key, sqlite3_errmsg(s_info.handle));
403 if (sqlite3_bind_text(stmt, 3, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
404 ErrPrint("Failed to bind a data(%s) - %s\n", data, sqlite3_errmsg(s_info.handle));
408 if (sqlite3_step(stmt) != SQLITE_ROW) {
409 ErrPrint("Failed to execute the DML for %s - %s, %s\n", appid, key, data);
414 ret = sqlite3_column_int(stmt, 0);
418 sqlite3_clear_bindings(stmt);
419 sqlite3_finalize(stmt);
423 static inline int db_init(void)
428 ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
429 if (ret != SQLITE_OK) {
430 ErrPrint("Failed to open a DB\n");
434 if (lstat(s_info.dbfile, &stat) < 0) {
435 ErrPrint("%s\n", strerror(errno));
436 db_util_close(s_info.handle);
437 s_info.handle = NULL;
441 if (!S_ISREG(stat.st_mode)) {
442 ErrPrint("Invalid file\n");
443 db_util_close(s_info.handle);
444 s_info.handle = NULL;
454 static inline int db_fini(void)
459 db_util_close(s_info.handle);
460 s_info.handle = NULL;
465 int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char *_appid)
467 xmlNodePtr node = NULL;
474 root = xmlDocGetRootElement(docPtr);
476 ErrPrint("Invalid node ptr\n");
480 if (!s_info.handle) {
485 for (root = root->children; root; root = root->next) {
486 if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list"))
491 ErrPrint("Root has no shortcut-list\n");
495 DbgPrint("AppID: %s\n", _appid);
496 root = root->children;
497 for (node = root; node; node = node->next) {
498 if (node->type == XML_ELEMENT_NODE)
499 DbgPrint("Element %s\n", node->name);
501 if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut"))
504 if (!xmlHasProp(node, (xmlChar *)"extra_data")
505 || !xmlHasProp(node, (xmlChar *)"extra_key")
506 || !xmlHasProp(node, (xmlChar *)"appid"))
508 DbgPrint("Invalid element %s\n", node->name);
512 appid = xmlGetProp(node, (xmlChar *)"appid");
513 key = xmlGetProp(node, (xmlChar *)"extra_key");
514 data = xmlGetProp(node, (xmlChar *)"extra_data");
516 DbgPrint("appid: %s\n", appid);
517 DbgPrint("key: %s\n", key);
518 DbgPrint("data: %s\n", data);
520 id = db_get_id((char *)appid, (char *)key, (char *)data);
522 ErrPrint("No records found\n");
530 if (db_remove_record((char *)appid, (char *)key, (char *)data) < 0) {
531 ErrPrint("Failed to remove a record\n");
532 rollback_transaction();
539 if (db_remove_name(id) < 0) {
540 ErrPrint("Failed to remove name records\n");
541 rollback_transaction();
547 commit_transaction();
554 * if (node->children)
555 * DbgPrint("Skip this node's children\n");
562 int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char *appid)
564 xmlNodePtr node = NULL;
565 xmlNodePtr child = NULL;
570 xmlChar *shortcut_appid;
576 struct dlist *i18n_list = NULL;
581 root = xmlDocGetRootElement(docPtr);
583 ErrPrint("Invalid node ptr\n");
587 if (!s_info.handle) {
592 for (root = root->children; root; root = root->next) {
593 if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list"))
598 ErrPrint("Root has no children\n");
602 DbgPrint("AppID: %s\n", appid);
604 root = root->children; /* Jump to children node */
605 for (node = root; node; node = node->next) {
606 if (node->type == XML_ELEMENT_NODE)
607 DbgPrint("Element %s\n", node->name);
609 if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut"))
612 if (!xmlHasProp(node, (xmlChar *)"extra_key") || !xmlHasProp(node, (xmlChar *)"extra_data")) {
613 DbgPrint("Invalid element %s\n", node->name);
617 key = xmlGetProp(node, (xmlChar *)"extra_key");
618 data = xmlGetProp(node, (xmlChar *)"extra_data");
619 shortcut_appid = xmlGetProp(node, (xmlChar *)"appid");
623 for (child = node->children; child; child = child->next) {
624 if (!xmlStrcasecmp(child->name, (const xmlChar *)"icon")) {
626 DbgPrint("Icon is duplicated\n");
630 icon = xmlNodeGetContent(child);
634 if (!xmlStrcasecmp(child->name, (const xmlChar *)"label")) {
636 lang = xmlNodeGetLang(child);
639 DbgPrint("Default name is duplicated\n");
641 name = xmlNodeGetContent(child);
642 DbgPrint("Default name is %s\n", name);
648 i18n = malloc(sizeof(*i18n));
650 ErrPrint("Heap: %s\n", strerror(errno));
655 i18n->name = xmlNodeGetContent(child);
656 i18n_list = dlist_append(i18n_list, i18n);
661 DbgPrint("appid: %s\n", appid);
662 DbgPrint("shortcut appid: %s\n", shortcut_appid);
663 DbgPrint("key: %s\n", key);
664 DbgPrint("data: %s\n", data);
665 DbgPrint("icon: %s\n", icon);
666 DbgPrint("Default name: %s\n", name);
668 if (!shortcut_appid) {
669 shortcut_appid = xmlStrdup((xmlChar *)appid);
670 DbgPrint("Use the default appid\n");
674 if (db_insert_record((char *)shortcut_appid, (char *)icon, (char *)name, (char *)key, (char *)data) < 0) {
675 ErrPrint("Failed to insert a new record\n");
676 rollback_transaction();
678 dlist_foreach_safe(i18n_list, l, n, i18n) {
679 i18n_list = dlist_remove(i18n_list, l);
685 id = db_get_id((char *)shortcut_appid, (char *)key, (char *)data);
687 ErrPrint("Failed to insert a new record\n");
688 rollback_transaction();
690 dlist_foreach_safe(i18n_list, l, n, i18n) {
691 i18n_list = dlist_remove(i18n_list, l);
697 dlist_foreach_safe(i18n_list, l, n, i18n) {
698 i18n_list = dlist_remove(i18n_list, l);
699 if (db_insert_name(id, (char *)i18n->lang, (char *)i18n->name) < 0)
700 ErrPrint("Failed to add i18n name: %s(%s)\n", i18n->name, i18n->lang);
705 commit_transaction();
713 xmlFree(shortcut_appid);
719 int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char *appid)
722 PKGMGR_PARSER_PLUGIN_UNINSTALL(docPtr, appid);
723 PKGMGR_PARSER_PLUGIN_INSTALL(docPtr, appid);
728 int main(int argc, char *argv[])
734 ErrPRint("Invalid argument: %s XML_FILENAME\n", argv[0]);
738 doc = xmlReadFile(argv[1], NULL, 0);
740 ErrPrint("Failed to parse %s\n", argv[1]);
744 root = xmlDocGetRootElement(doc);
747 install_shortcut("", root);