Update the shortcut pkgmgr plugin.
[platform/core/appfw/shortcut.git] / pkgmgr_shortcut / src / service_register.c
1 /*
2  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16 */
17
18 #include <stdio.h>
19 #include <errno.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <libgen.h>
24 #include <string.h>
25
26 #include <sqlite3.h>
27 #include <db-util.h>
28 #include <libxml/parser.h>
29 #include <libxml/tree.h>
30 #include <dlog.h>
31
32 #include "dlist.h"
33
34 #if !defined(FLOG)
35 #define DbgPrint(format, arg...)        SECURE_LOGD("[\e[32m%s/%s\e[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
36 #define ErrPrint(format, arg...)        SECURE_LOGE("[\e[32m%s/%s\e[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
37 #endif
38 /* End of a file */
39
40 /*!
41  * DB Table schema
42  *
43  * +----+-------+-------+------+---------+-----------+------------+
44  * | id | pkgid | appid | Icon |  Name   | extra_key | extra_data |
45  * +----+-------+-------+------+---------+-----------+------------+
46  * | id |   -   |   -   |   -  |    -    |     -     |     -      |
47  * +----+-------+-------+------+---------+-----------+------------+
48  *
49  * +----+-------+------+------+
50  * | fk | pkgid | lang | name |
51  * +----+-------+------+------+
52  * | id |   -   |   -  |      |
53  * +----+-------+------+------+
54  */
55
56 #if !defined(LIBXML_TREE_ENABLED)
57         #error "LIBXML is not supporting the tree"
58 #endif
59
60 int errno;
61
62 static struct {
63         const char *dbfile;
64         sqlite3 *handle;
65 } s_info = {
66         .dbfile = "/opt/dbspace/.shortcut_service.db",
67         .handle = NULL,
68 };
69
70 static inline int begin_transaction(void)
71 {
72         sqlite3_stmt *stmt;
73         int ret;
74
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));
78                 return EXIT_FAILURE;
79         }
80
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);
85                 return EXIT_FAILURE;
86         }
87
88         sqlite3_finalize(stmt);
89         return EXIT_SUCCESS;
90 }
91
92 static inline int rollback_transaction(void)
93 {
94         int ret;
95         sqlite3_stmt *stmt;
96
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));
100                 return EXIT_FAILURE;
101         }
102
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);
107                 return EXIT_FAILURE;
108         }
109
110         sqlite3_finalize(stmt);
111         return EXIT_SUCCESS;
112 }
113
114 static inline int commit_transaction(void)
115 {
116         sqlite3_stmt *stmt;
117         int ret;
118
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));
122                 return EXIT_FAILURE;
123         }
124
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);
129                 return EXIT_FAILURE;
130         }
131
132         sqlite3_finalize(stmt);
133         return EXIT_SUCCESS;
134 }
135 static void db_create_table(void)
136 {
137         char *err;
138         static const char *ddl =
139                 "CREATE TABLE shortcut_service ("
140                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
141                 "pkgid TEXT, "
142                 "appid TEXT, "
143                 "icon TEXT, "
144                 "name TEXT, "
145                 "extra_key TEXT, "
146                 "extra_data TEXT)";
147
148         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
149                 ErrPrint("Failed to execute the DDL (%s)\n", err);
150                 return;
151         }
152
153         if (sqlite3_changes(s_info.handle) == 0) {
154                 ErrPrint("No changes to DB\n");
155         }
156
157         ddl = "CREATE TABLE shortcut_name (id INTEGER, pkgid TEXT, lang TEXT, name TEXT)";
158         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
159                 ErrPrint("Failed to execute the DDL (%s)\n", err);
160                 return;
161         }
162
163         if (sqlite3_changes(s_info.handle) == 0) {
164                 ErrPrint("No changes to DB\n");
165         }
166 }
167
168 static void alter_shortcut_name(void)
169 {
170         char *err;
171         static const char *ddl = "ALTER TABLE shortcut_name ADD pkgid TEXT";
172
173         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
174                 ErrPrint("Failed to execute the DDL (%s)\n", err);
175                 return;
176         }
177
178         if (sqlite3_changes(s_info.handle) == 0) {
179                 ErrPrint("No changes to DB\n");
180         }
181 }
182
183 static void alter_shortcut_service(void)
184 {
185         char *err;
186         static const char *ddl = "ALTER TABLE shortcut_service ADD pkgid TEXT";
187
188         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
189                 ErrPrint("Failed to execute the DDL (%s)\n", err);
190                 return;
191         }
192
193         if (sqlite3_changes(s_info.handle) == 0) {
194                 ErrPrint("No changes to DB\n");
195         }
196 }
197
198 static int db_remove_by_pkgid(const char *pkgid)
199 {
200         static const char *dml = "DELETE FROM shortcut_service WHERE pkgid = ?";
201         sqlite3_stmt *stmt;
202         int ret;
203
204         if (!pkgid) {
205                 ErrPrint("Invalid argument\n");
206                 return -EINVAL;
207         }
208
209         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
210         if (ret != SQLITE_OK) {
211                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
212                 return -EIO;
213         }
214
215         ret = -EIO;
216         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
217                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
218                 goto out;
219         }
220
221         ret = 0;
222         if (sqlite3_step(stmt) != SQLITE_DONE) {
223                 ret = -EIO;
224                 ErrPrint("Failed to execute the DML for %s\n", pkgid);
225         } else {
226                 if (sqlite3_changes(s_info.handle) == 0) {
227                         DbgPrint("No changed\n");
228                 }
229         }
230
231 out:
232         sqlite3_reset(stmt);
233         sqlite3_clear_bindings(stmt);
234         sqlite3_finalize(stmt);
235         return ret;
236 }
237
238 static int do_upgrade_db_schema(void)
239 {
240         static const char *dml = ".schema";
241         sqlite3_stmt *stmt;
242         const char *schema;
243         char *table;
244         char *ddl;
245         int ret;
246         int bufsz;
247
248         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
249         if (ret != SQLITE_OK) {
250                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
251                 return -EIO;
252         }
253
254         ret = 0;
255         while (sqlite3_step(stmt) == SQLITE_ROW) {
256                 schema = (const char *)sqlite3_column_text(stmt, 0);
257                 if (!schema || !strlen(schema)) {
258                         continue;
259                 }
260
261                 bufsz = strlen(schema) + 1;
262
263                 table = malloc(bufsz);
264                 if (!table) {
265                         ErrPrint("Heap: %s\n", strerror(errno));
266                         ret = -ENOMEM;
267                         break;
268                 }
269
270                 ddl = malloc(bufsz);
271                 if (!ddl) {
272                         ErrPrint("Heap: %s\n", strerror(errno));
273                         free(table);
274                         ret = -ENOMEM;
275                         break;
276                 }
277
278                 if (sscanf(schema, "CREATE TABLE %s (%[^)])", table, ddl) != 2) {
279                         free(table);
280                         free(ddl);
281                         ErrPrint("Invalid syntax: (%s)\n", schema);
282                         continue;
283                 }
284
285                 if (!strcmp(table, "shortcut_name")) {
286                         if (!strstr(ddl, "pkgid")) {
287                                 alter_shortcut_name();
288                         }
289                 } else if (!strcmp(table, "shortcut_service")) {
290                         if (!strstr(ddl, "pkgid")) {
291                                 alter_shortcut_service();
292                         }
293                 } else {
294                         ErrPrint("Unknown table: %s\n", table);
295                 }
296
297                 free(table);
298                 free(ddl);
299                 ret++;
300         }
301
302         sqlite3_reset(stmt);
303         sqlite3_clear_bindings(stmt);
304         sqlite3_finalize(stmt);
305         return ret;
306 }
307
308
309 static int db_remove_record(const char *pkgid, const char *appid, const char *key, const char *data)
310 {
311         static const char *dml = "DELETE FROM shortcut_service WHERE appid = ? AND extra_key = ? AND extra_data = ? AND pkgid = ?";
312         sqlite3_stmt *stmt;
313         int ret;
314
315         if (!appid || !key || !data) {
316                 ErrPrint("Invalid argument\n");
317                 return -EINVAL;
318         }
319
320         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
321         if (ret != SQLITE_OK) {
322                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
323                 return -EIO;
324         }
325
326         ret = -EIO;
327         if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
328                 ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle));
329                 goto out;
330         }
331
332         if (sqlite3_bind_text(stmt, 2, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
333                 ErrPrint("Failed to bind a key(%s)\n", sqlite3_errmsg(s_info.handle));
334                 goto out;
335         }
336
337         if (sqlite3_bind_text(stmt, 3, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
338                 ErrPrint("Failed to bind a data(%s)\n", sqlite3_errmsg(s_info.handle));
339                 goto out;
340         }
341
342         if (sqlite3_bind_text(stmt, 4, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
343                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
344                 goto out;
345         }
346
347         ret = 0;
348         if (sqlite3_step(stmt) != SQLITE_DONE) {
349                 ret = -EIO;
350                 ErrPrint("Failed to execute the DML for %s - %s(%s)\n", appid, key, data);
351         }
352
353         if (sqlite3_changes(s_info.handle) == 0) {
354                 DbgPrint("No changes\n");
355         }
356
357 out:
358         sqlite3_reset(stmt);
359         sqlite3_clear_bindings(stmt);
360         sqlite3_finalize(stmt);
361         return ret;
362 }
363
364 static int db_remove_name_by_pkgid(const char *pkgid)
365 {
366         static const char *dml = "DELETE FROM shortcut_name WHERE pkgid = ?";
367         sqlite3_stmt *stmt;
368         int ret;
369
370         if (!pkgid) {
371                 ErrPrint("Invalid id\n");
372                 return -EINVAL;
373         }
374
375         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
376         if (ret != SQLITE_OK) {
377                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
378                 return -EIO;
379         }
380
381         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
382                 ErrPrint("Failed to bind pkgid(%s)\n", pkgid);
383                 return -EIO;
384         }
385
386         ret = 0;
387         if (sqlite3_step(stmt) != SQLITE_DONE) {
388                 ret = -EIO;
389                 ErrPrint("Failed to execute the DML for %s\n", pkgid);
390                 goto out;
391         }
392
393         if (sqlite3_changes(s_info.handle) == 0) {
394                 DbgPrint("No chnages\n");
395         }
396
397 out:
398         sqlite3_reset(stmt);
399         sqlite3_clear_bindings(stmt);
400         sqlite3_finalize(stmt);
401         return ret;
402 }
403
404 static int db_remove_name(int id)
405 {
406         static const char *dml = "DELETE FROM shortcut_name WHERE id = ?";
407         sqlite3_stmt *stmt;
408         int ret;
409
410         if (id < 0) {
411                 ErrPrint("Inavlid id\n");
412                 return -EINVAL;
413         }
414
415         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
416         if (ret != SQLITE_OK) {
417                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
418                 return -EIO;
419         }
420
421         if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
422                 ErrPrint("Failed to bind id(%d)\n", id);
423                 ret = -EIO;
424                 goto out;
425         }
426
427         ret = 0;
428         if (sqlite3_step(stmt) != SQLITE_DONE) {
429                 ret = -EIO;
430                 ErrPrint("Failed to execute the DML for %d\n", id);
431                 goto out;
432         }
433
434         if (sqlite3_changes(s_info.handle) == 0) {
435                 DbgPrint("No changes\n");
436         }
437
438 out:
439         sqlite3_reset(stmt);
440         sqlite3_clear_bindings(stmt);
441         sqlite3_finalize(stmt);
442         return ret;
443 }
444
445 static int db_insert_record(const char *pkgid, const char *appid, const char *icon, const char *name, const char *key, const char *data)
446 {
447         static const char *dml = "INSERT INTO shortcut_service (pkgid, appid, icon, name, extra_key, extra_data) VALUES (?, ?, ?, ?, ?, ?)";
448         sqlite3_stmt *stmt;
449         int ret;
450
451         if (!pkgid) {
452                 ErrPrint("Failed to get pkgid\n");
453                 return -EINVAL;
454         }
455
456         if (!appid) {
457                 ErrPrint("Failed to get appid\n");
458                 return -EINVAL;
459         }
460
461         if (!name) {
462                 ErrPrint("Failed to get name\n");
463                 return -EINVAL;
464         }
465
466         if (!key) {
467                 ErrPrint("Failed to get key\n");
468                 return -EINVAL;
469         }
470
471         if (!data) {
472                 ErrPrint("Faield to get key\n");
473                 return -EINVAL;
474         }
475
476         icon = icon ? icon : "";
477
478         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
479         if (ret != SQLITE_OK) {
480                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
481                 return -EIO;
482         }
483
484         ret = -EIO;
485         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
486                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
487                 goto out;
488         }
489
490         if (sqlite3_bind_text(stmt, 2, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
491                 ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle));
492                 goto out;
493         }
494
495         if (sqlite3_bind_text(stmt, 3, icon, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
496                 ErrPrint("Failed to bind a icon(%s)\n", sqlite3_errmsg(s_info.handle));
497                 goto out;
498         }
499
500         if (sqlite3_bind_text(stmt, 4, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
501                 ErrPrint("Failed to bind a name(%s)\n", sqlite3_errmsg(s_info.handle));
502                 goto out;
503         }
504
505         if (sqlite3_bind_text(stmt, 5, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
506                 ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle));
507                 goto out;
508         }
509
510         if (sqlite3_bind_text(stmt, 6, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
511                 ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle));
512                 goto out;
513         }
514
515         ret = 0;
516         if (sqlite3_step(stmt) != SQLITE_DONE) {
517                 ErrPrint("Failed to execute the DML for %s - %s\n", appid, name);
518                 ret = -EIO;
519         }
520
521 out:
522         sqlite3_reset(stmt);
523         sqlite3_clear_bindings(stmt);
524         sqlite3_finalize(stmt);
525         return ret;
526 }
527
528 static int db_insert_name(int id, const char *pkgid, const char *lang, const char *name)
529 {
530         static const char *dml = "INSERT INTO shortcut_name (id, pkgid, lang, name) VALUES (?, ?, ?, ?)";
531         sqlite3_stmt *stmt;
532         int ret;
533
534         if (id < 0 || !lang || !name) {
535                 ErrPrint("Invalid parameters\n");
536                 return -EINVAL;
537         }
538
539         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
540         if (ret != SQLITE_OK) {
541                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
542                 return -EIO;
543         }
544
545         if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
546                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
547                 ret = -EIO;
548                 goto out;
549         }
550
551         if (sqlite3_bind_text(stmt, 2, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
552                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
553                 ret = -EIO;
554                 goto out;
555         }
556
557         if (sqlite3_bind_text(stmt, 3, lang, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
558                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
559                 ret = -EIO;
560                 goto out;
561         }
562
563         if (sqlite3_bind_text(stmt, 4, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
564                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
565                 ret = -EIO;
566                 goto out;
567         }
568
569         ret = 0;
570         if (sqlite3_step(stmt) != SQLITE_DONE) {
571                 ErrPrint("Failed to execute the DML for %d %s %s\n", id, lang, name);
572                 ret = -EIO;
573         }
574
575 out:
576         sqlite3_reset(stmt);
577         sqlite3_clear_bindings(stmt);
578         sqlite3_finalize(stmt);
579         return ret;
580 }
581
582 static int db_get_id(const char *pkgid, const char *appid, const char *key, const char *data)
583 {
584         static const char *dml = "SELECT id FROM shortcut_service WHERE pkgid = ? AND appid = ? AND extra_key = ? AND extra_data = ?";
585         sqlite3_stmt *stmt;
586         int ret;
587
588         if (!appid || !key || !data) {
589                 ErrPrint("Invalid argument\n");
590                 return -EINVAL;
591         }
592
593         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
594         if (ret != SQLITE_OK) {
595                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
596                 return -EIO;
597         }
598
599         ret = -EIO;
600         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
601                 ErrPrint("Failed to bind a pkgid(%s) - %s\n", pkgid, sqlite3_errmsg(s_info.handle));
602                 goto out;
603         }
604
605         if (sqlite3_bind_text(stmt, 2, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
606                 ErrPrint("Failed to bind a appid(%s) - %s\n", appid, sqlite3_errmsg(s_info.handle));
607                 goto out;
608         }
609
610         if (sqlite3_bind_text(stmt, 3, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
611                 ErrPrint("Failed to bind a key(%s) - %s\n", key, sqlite3_errmsg(s_info.handle));
612                 goto out;
613         }
614
615         if (sqlite3_bind_text(stmt, 4, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
616                 ErrPrint("Failed to bind a data(%s) - %s\n", data, sqlite3_errmsg(s_info.handle));
617                 goto out;
618         }
619
620         if (sqlite3_step(stmt) != SQLITE_ROW) {
621                 ErrPrint("Failed to execute the DML for %s - %s, %s\n", appid, key, data);
622                 ret = -EIO;
623                 goto out;
624         }
625
626         ret = sqlite3_column_int(stmt, 0);
627
628 out:
629         sqlite3_reset(stmt);
630         sqlite3_clear_bindings(stmt);
631         sqlite3_finalize(stmt);
632         return ret;
633 }
634
635 static int db_init(void)
636 {
637         int ret;
638         struct stat stat;
639
640         ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
641         if (ret != SQLITE_OK) {
642                 ErrPrint("Failed to open a DB\n");
643                 return -EIO;
644         }
645
646         if (lstat(s_info.dbfile, &stat) < 0) {
647                 ErrPrint("%s\n", strerror(errno));
648                 db_util_close(s_info.handle);
649                 s_info.handle = NULL;
650                 return -EIO;
651         }
652
653         if (!S_ISREG(stat.st_mode)) {
654                 ErrPrint("Invalid file\n");
655                 db_util_close(s_info.handle);
656                 s_info.handle = NULL;
657                 return -EINVAL;
658         }
659
660         if (!stat.st_size) {
661                 db_create_table();
662         }
663
664         return 0;
665 }
666
667 static int db_fini(void)
668 {
669         if (!s_info.handle) {
670                 return 0;
671         }
672
673         db_util_close(s_info.handle);
674         s_info.handle = NULL;
675
676         return 0;
677 }
678
679 static int do_uninstall(const char *appid)
680 {
681         int ret;
682
683         ret = db_remove_by_pkgid(appid); 
684         if (ret < 0) {
685                 ErrPrint("Failed to remove a record: %s\n", appid);
686                 return ret;
687         }
688
689         ret = db_remove_name_by_pkgid(appid);
690         if (ret < 0) {
691                 ErrPrint("Failed to remove name records: %s\n", appid);
692                 return ret;
693         }
694
695         return 0;
696 }
697
698 static int do_install(xmlDocPtr docPtr, const char *appid)
699 {
700         xmlNodePtr node = NULL;
701         xmlNodePtr child = NULL;
702         xmlChar *key;
703         xmlChar *data;
704         xmlChar *name;
705         xmlChar *icon;
706         xmlChar *shortcut_appid;
707         xmlNodePtr root;
708         struct i18n_name {
709                 xmlChar *name;
710                 xmlChar *lang;
711         } *i18n;
712         struct dlist *i18n_list = NULL;
713         struct dlist *l;
714         struct dlist *n;
715         int id;
716
717         root = xmlDocGetRootElement(docPtr);
718         if (!root) {
719                 ErrPrint("Invalid node ptr\n");
720                 return -EINVAL;
721         }
722
723         for (root = root->children; root; root = root->next) {
724                 if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list")) {
725                         break;
726                 }
727         }
728
729         if (!root) {
730                 ErrPrint("Root has no children\n");
731                 return -EINVAL;
732         }
733
734         DbgPrint("AppID: %s\n", appid);
735
736         root = root->children; /* Jump to children node */
737         for (node = root; node; node = node->next) {
738                 if (node->type == XML_ELEMENT_NODE) {
739                         DbgPrint("Element %s\n", node->name);
740                 }
741
742                 if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut")) {
743                         continue;
744                 }
745
746                 if (!xmlHasProp(node, (xmlChar *)"extra_key") || !xmlHasProp(node, (xmlChar *)"extra_data")) {
747                         DbgPrint("Invalid element %s\n", node->name);
748                         continue;
749                 }
750
751                 key = xmlGetProp(node, (xmlChar *)"extra_key");
752                 data = xmlGetProp(node, (xmlChar *)"extra_data");
753                 shortcut_appid = xmlGetProp(node, (xmlChar *)"appid");
754
755                 icon = NULL;
756                 name = NULL;
757                 for (child = node->children; child; child = child->next) {
758                         if (!xmlStrcasecmp(child->name, (const xmlChar *)"icon")) {
759                                 if (icon) {
760                                         DbgPrint("Icon is duplicated\n");
761                                         continue;
762                                 }
763
764                                 icon = xmlNodeGetContent(child);
765                                 continue;
766                         }
767
768                         if (!xmlStrcasecmp(child->name, (const xmlChar *)"label")) {
769                                 xmlChar *lang;
770                                 lang = xmlNodeGetLang(child);
771                                 if (!lang) {
772                                         if (name) {
773                                                 DbgPrint("Default name is duplicated\n");
774                                         } else {
775                                                 name = xmlNodeGetContent(child);
776                                                 DbgPrint("Default name is %s\n", name);
777                                         }
778
779                                         continue;
780                                 }
781
782                                 i18n = malloc(sizeof(*i18n));
783                                 if (!i18n) {
784                                         ErrPrint("Heap: %s\n", strerror(errno));
785                                         break;
786                                 }
787
788                                 i18n->lang = lang;
789                                 i18n->name = xmlNodeGetContent(child);
790                                 i18n_list = dlist_append(i18n_list, i18n);
791                                 continue;
792                         }
793                 }
794
795                 DbgPrint("appid: %s\n", appid);
796                 DbgPrint("shortcut appid: %s\n", shortcut_appid);
797                 DbgPrint("key: %s\n", key);
798                 DbgPrint("data: %s\n", data);
799                 DbgPrint("icon: %s\n", icon);
800                 DbgPrint("Default name: %s\n", name);
801
802                 if (!shortcut_appid) {
803                         shortcut_appid = xmlStrdup((xmlChar *)appid);
804                         DbgPrint("Use the default appid\n");
805                 }
806
807                 begin_transaction();
808                 if (db_insert_record(appid, (char *)shortcut_appid, (char *)icon, (char *)name, (char *)key, (char *)data) < 0) {
809                         ErrPrint("Failed to insert a new record\n");
810                         rollback_transaction();
811
812                         dlist_foreach_safe(i18n_list, l, n, i18n) {
813                                 i18n_list = dlist_remove(i18n_list, l);
814                                 xmlFree(i18n->lang);
815                                 xmlFree(i18n->name);
816                                 free(i18n);
817                         }
818                 } else {
819                         id = db_get_id((char *)appid, (char *)shortcut_appid, (char *)key, (char *)data);
820                         if (id < 0) {
821                                 ErrPrint("Failed to insert a new record\n");
822                                 rollback_transaction();
823
824                                 dlist_foreach_safe(i18n_list, l, n, i18n) {
825                                         i18n_list = dlist_remove(i18n_list, l);
826                                         xmlFree(i18n->lang);
827                                         xmlFree(i18n->name);
828                                         free(i18n);
829                                 }
830                         } else {
831                                 dlist_foreach_safe(i18n_list, l, n, i18n) {
832                                         i18n_list = dlist_remove(i18n_list, l);
833                                         if (db_insert_name(id, appid, (char *)i18n->lang, (char *)i18n->name) < 0) {
834                                                 ErrPrint("Failed to add i18n name: %s(%s)\n", i18n->name, i18n->lang);
835                                         }
836                                         xmlFree(i18n->lang);
837                                         xmlFree(i18n->name);
838                                         free(i18n);
839                                 }
840                                 commit_transaction();
841                         }
842                 }
843
844                 xmlFree(key);
845                 xmlFree(data);
846                 xmlFree(icon);
847                 xmlFree(name);
848                 xmlFree(shortcut_appid);
849         }
850
851         return 0;
852 }
853
854 int PKGMGR_PARSER_PLUGIN_PRE_UNINSTALL(const char *appid)
855 {
856         if (!s_info.handle) {
857                 if (db_init() < 0) {
858                         return -EIO;
859                 }
860         }
861
862         do_upgrade_db_schema();
863         return 0;
864 }
865
866 int PKGMGR_PARSER_PLUGIN_POST_UNINSTALL(const char *appid)
867 {
868         int ret;
869
870         begin_transaction();
871         ret = do_uninstall(appid);
872         if (ret < 0) {
873                 rollback_transaction();
874                 return ret;
875         }
876         commit_transaction();
877
878         db_fini();
879         return 0;
880 }
881
882 int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char *_appid)
883 {
884         xmlNodePtr node = NULL;
885         xmlChar *key;
886         xmlChar *data;
887         xmlChar *appid;
888         xmlNodePtr root;
889         int id;
890
891         root = xmlDocGetRootElement(docPtr);
892         if (!root) {
893                 ErrPrint("Invalid node ptr\n");
894                 return -EINVAL;
895         }
896
897         for (root = root->children; root; root = root->next) {
898                 if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list")) {
899                         break;
900                 }
901         }
902
903         if (!root) {
904                 ErrPrint("Root has no shortcut-list\n");
905                 return -EINVAL;
906         }
907
908         DbgPrint("AppID: %s\n", _appid);
909         root = root->children;
910         for (node = root; node; node = node->next) {
911                 if (node->type == XML_ELEMENT_NODE) {
912                         DbgPrint("Element %s\n", node->name);
913                 }
914
915                 if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut")) {
916                         continue;
917                 }
918
919                 if (!xmlHasProp(node, (xmlChar *)"extra_data")
920                                 || !xmlHasProp(node, (xmlChar *)"extra_key")
921                                 || !xmlHasProp(node, (xmlChar *)"appid"))
922                 {
923                         DbgPrint("Invalid element %s\n", node->name);
924                         continue;
925                 }
926
927                 appid = xmlGetProp(node, (xmlChar *)"appid");
928                 key = xmlGetProp(node, (xmlChar *)"extra_key");
929                 data = xmlGetProp(node, (xmlChar *)"extra_data");
930
931                 DbgPrint("appid: %s\n", appid);
932                 DbgPrint("key: %s\n", key);
933                 DbgPrint("data: %s\n", data);
934
935                 id = db_get_id("", (char *)appid, (char *)key, (char *)data);
936                 if (id < 0) {
937                         ErrPrint("No records found\n");
938                         xmlFree(appid);
939                         xmlFree(key);
940                         xmlFree(data);
941                         continue;
942                 }
943
944                 begin_transaction();
945                 if (db_remove_record("", (char *)appid, (char *)key, (char *)data) < 0) {
946                         ErrPrint("Failed to remove a record\n");
947                         rollback_transaction();
948                         xmlFree(appid);
949                         xmlFree(key);
950                         xmlFree(data);
951                         continue;
952                 }
953
954                 if (db_remove_name(id) < 0) {
955                         ErrPrint("Failed to remove name records\n");
956                         rollback_transaction();
957                         xmlFree(appid);
958                         xmlFree(key);
959                         xmlFree(data);
960                         continue;
961                 }
962                 commit_transaction();
963
964                 xmlFree(appid);
965                 xmlFree(key);
966                 xmlFree(data);
967
968                 /*!
969                  * \note
970                  * if (node->children)
971                  * DbgPrint("Skip this node's children\n");
972                  */
973         }
974
975         return 0;
976 }
977
978 int PKGMGR_PARSER_PLUGIN_PRE_INSTALL(const char *appid)
979 {
980         int ret;
981
982         if (!s_info.handle) {
983                 if (db_init() < 0) {
984                         return -EIO;
985                 }
986         }
987
988         do_upgrade_db_schema();
989
990         begin_transaction();
991         ret = do_uninstall(appid);
992         if (ret < 0) {
993                 ErrPrint("Failed to remove record: %s\n", appid);
994                 rollback_transaction();
995                 return ret;
996         }
997         commit_transaction();
998         return  0;
999 }
1000
1001 int PKGMGR_PARSER_PLUGIN_POST_INSTALL(const char *appid)
1002 {
1003         db_fini();
1004         return 0;
1005 }
1006
1007 int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char *appid)
1008 {
1009         return do_install(docPtr, appid);
1010 }
1011
1012 int PKGMGR_PARSER_PLUGIN_PRE_UPGRADE(const char *appid)
1013 {
1014         int ret;
1015
1016         if (!s_info.handle) {
1017                 if (db_init() < 0) {
1018                         return -EIO;
1019                 }
1020         }
1021
1022         do_upgrade_db_schema();
1023
1024         begin_transaction();
1025         ret = do_uninstall(appid);
1026         if (ret < 0) {
1027                 ErrPrint("Failed to remove a record: %s\n", appid);
1028                 rollback_transaction();
1029                 return ret;
1030         }
1031         commit_transaction();
1032         return 0;
1033 }
1034
1035 int PKGMGR_PARSER_PLUGIN_POST_UPGRADE(const char *appid)
1036 {
1037         db_fini();
1038         return 0;
1039 }
1040
1041 int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char *appid)
1042 {
1043         /* So... ugly */
1044         return do_install(docPtr, appid);
1045 }
1046
1047 /*
1048 int main(int argc, char *argv[])
1049 {
1050         xmlDoc *doc;
1051         xmlNode *root;
1052
1053         if (argc != 2) {
1054                 ErrPRint("Invalid argument: %s XML_FILENAME\n", argv[0]);
1055                 return -EINVAL;
1056         }
1057
1058         doc = xmlReadFile(argv[1], NULL, 0);
1059         if (!doc) {
1060                 ErrPrint("Failed to parse %s\n", argv[1]);
1061                 return -EIO;
1062         }
1063
1064         root = xmlDocGetRootElement(doc);
1065
1066         db_init();
1067         install_shortcut("", root);
1068         db_fini();
1069
1070         xmlFreeDoc(doc);
1071         xmlCleanupParser();
1072         return 0;
1073 }
1074 */
1075
1076 /* End of a file */