Add multi-user support
[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 /* For multi-user support */
33 #include <tzplatform_config.h>
34
35 #include "dlist.h"
36
37 #if !defined(SECURE_LOGD)
38 #define SECURE_LOGD LOGD
39 #endif
40
41 #if !defined(SECURE_LOGE)
42 #define SECURE_LOGE LOGE
43 #endif
44
45 #if !defined(SECURE_LOGW)
46 #define SECURE_LOGW LOGW
47 #endif
48
49 #if !defined(FLOG)
50 #define DbgPrint(format, arg...)        SECURE_LOGD("[\e[32m%s/%s\e[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
51 #define ErrPrint(format, arg...)        SECURE_LOGE("[\e[32m%s/%s\e[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
52 #endif
53 /* End of a file */
54
55 /*!
56  * DB Table schema
57  *
58  * +----+-------+-------+------+---------+-----------+------------+
59  * | id | pkgid | appid | Icon |  Name   | extra_key | extra_data |
60  * +----+-------+-------+------+---------+-----------+------------+
61  * | id |   -   |   -   |   -  |    -    |     -     |     -      |
62  * +----+-------+-------+------+---------+-----------+------------+
63  *
64  * +----+-------+------+------+------+
65  * | fk | pkgid | lang | name | icon |
66  * +----+-------+------+------+------+
67  * | id |   -   |   -  |      |   -  |
68  * +----+-------+------+------+------+
69  */
70
71 #if !defined(LIBXML_TREE_ENABLED)
72         #error "LIBXML is not supporting the tree"
73 #endif
74
75 int errno;
76
77 struct i18n_name {
78         xmlChar *icon;
79         xmlChar *name;
80         xmlChar *lang;
81 };
82
83 static struct {
84         const char *dbfile;
85         sqlite3 *handle;
86 } s_info = {
87         .dbfile = "",
88         .handle = NULL,
89 };
90
91 static inline int begin_transaction(void)
92 {
93         sqlite3_stmt *stmt;
94         int ret;
95
96         ret = sqlite3_prepare_v2(s_info.handle, "BEGIN TRANSACTION", -1, &stmt, NULL);
97         if (ret != SQLITE_OK) {
98                 DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
99                 return EXIT_FAILURE;
100         }
101
102         if (sqlite3_step(stmt) != SQLITE_DONE) {
103                 DbgPrint("Failed to do update (%s)\n",
104                                         sqlite3_errmsg(s_info.handle));
105                 sqlite3_finalize(stmt);
106                 return EXIT_FAILURE;
107         }
108
109         sqlite3_finalize(stmt);
110         return EXIT_SUCCESS;
111 }
112
113 static inline int rollback_transaction(void)
114 {
115         int ret;
116         sqlite3_stmt *stmt;
117
118         ret = sqlite3_prepare_v2(s_info.handle, "ROLLBACK TRANSACTION", -1, &stmt, NULL);
119         if (ret != SQLITE_OK) {
120                 DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
121                 return EXIT_FAILURE;
122         }
123
124         if (sqlite3_step(stmt) != SQLITE_DONE) {
125                 DbgPrint("Failed to do update (%s)\n",
126                                 sqlite3_errmsg(s_info.handle));
127                 sqlite3_finalize(stmt);
128                 return EXIT_FAILURE;
129         }
130
131         sqlite3_finalize(stmt);
132         return EXIT_SUCCESS;
133 }
134
135 static inline int commit_transaction(void)
136 {
137         sqlite3_stmt *stmt;
138         int ret;
139
140         ret = sqlite3_prepare_v2(s_info.handle, "COMMIT TRANSACTION", -1, &stmt, NULL);
141         if (ret != SQLITE_OK) {
142                 DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
143                 return EXIT_FAILURE;
144         }
145
146         if (sqlite3_step(stmt) != SQLITE_DONE) {
147                 DbgPrint("Failed to do update (%s)\n",
148                                         sqlite3_errmsg(s_info.handle));
149                 sqlite3_finalize(stmt);
150                 return EXIT_FAILURE;
151         }
152
153         sqlite3_finalize(stmt);
154         return EXIT_SUCCESS;
155 }
156
157 static void db_create_version(void)
158 {
159         static const char *ddl = "CREATE TABLE version (version INTEGER)";
160         char *err;
161
162         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
163                 ErrPrint("Failed to execute the DDL (%s)\n", err);
164                 return;
165         }
166
167         if (sqlite3_changes(s_info.handle) == 0) {
168                 ErrPrint("No changes to DB\n");
169         }
170 }
171
172 static int set_version(int version)
173 {
174         static const char *dml = "INSERT INTO version (version) VALUES (?)";
175         sqlite3_stmt *stmt;
176         int ret;
177
178         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
179         if (ret != SQLITE_OK) {
180                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
181                 return -EIO;
182         }
183
184         if (sqlite3_bind_int(stmt, 1, version) != SQLITE_OK) {
185                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
186                 ret = -EIO;
187                 goto out;
188         }
189
190         ret = sqlite3_step(stmt);
191         if (ret != SQLITE_DONE) {
192                 ErrPrint("Failed to execute the DML for version: %d\n", ret);
193                 ret = -EIO;
194         } else {
195                 ret = 0;
196         }
197
198 out:
199         sqlite3_reset(stmt);
200         sqlite3_clear_bindings(stmt);
201         sqlite3_finalize(stmt);
202         return ret;
203 }
204
205 static int update_version(int version)
206 {
207         static const char *dml = "UPDATE version SET version = ?";
208         sqlite3_stmt *stmt;
209         int ret;
210
211         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
212         if (ret != SQLITE_OK) {
213                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
214                 return -EIO;
215         }
216
217         if (sqlite3_bind_int(stmt, 1, version) != SQLITE_OK) {
218                 ErrPrint("Failed to bind a version: %s\n", sqlite3_errmsg(s_info.handle));
219                 ret = -EIO;
220                 goto out;
221         }
222
223         ret = sqlite3_step(stmt);
224         if (ret != SQLITE_DONE) {
225                 ErrPrint("Failed to execute DML: %d\n", ret);
226                 ret = -EIO;
227         } else {
228                 ret = 0;
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 get_version(void)
239 {
240         static const char *dml = "SELECT version FROM version";
241         sqlite3_stmt *stmt;
242         int ret;
243
244         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
245         if (ret != SQLITE_OK) {
246                 return -ENOSYS;
247         }
248
249         if (sqlite3_step(stmt) != SQLITE_ROW) {
250                 ret = -ENOENT;
251         } else {
252                 ret = sqlite3_column_int(stmt, 0);
253         }
254
255         sqlite3_reset(stmt);
256         sqlite3_clear_bindings(stmt);
257         sqlite3_finalize(stmt);
258         return ret;
259 }
260
261 static void db_create_table(void)
262 {
263         char *err;
264         static const char *ddl =
265                 "CREATE TABLE shortcut_service ("
266                 "id INTEGER PRIMARY KEY AUTOINCREMENT, "
267                 "pkgid TEXT, "
268                 "appid TEXT, "
269                 "icon TEXT, "
270                 "name TEXT, "
271                 "extra_key TEXT, "
272                 "extra_data TEXT)";
273
274         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
275                 ErrPrint("Failed to execute the DDL (%s)\n", err);
276                 return;
277         }
278
279         if (sqlite3_changes(s_info.handle) == 0) {
280                 ErrPrint("No changes to DB\n");
281         }
282
283         ddl = "CREATE TABLE shortcut_name (id INTEGER, pkgid TEXT, lang TEXT, name TEXT, icon TEXT)";
284         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
285                 ErrPrint("Failed to execute the DDL (%s)\n", err);
286                 return;
287         }
288
289         if (sqlite3_changes(s_info.handle) == 0) {
290                 ErrPrint("No changes to DB\n");
291         }
292
293         db_create_version();
294 }
295
296 static void alter_shortcut_icon(void)
297 {
298         char *err;
299         static const char *ddl = "ALTER TABLE shortcut_name ADD icon TEXT";
300
301         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
302                 ErrPrint("Failed to execute the DDL (%s)\n", err);
303                 return;
304         }
305
306         if (sqlite3_changes(s_info.handle) == 0) {
307                 ErrPrint("No changes to DB\n");
308         }
309 }
310
311 static void alter_shortcut_name(void)
312 {
313         char *err;
314         static const char *ddl = "ALTER TABLE shortcut_name ADD pkgid TEXT";
315
316         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
317                 ErrPrint("Failed to execute the DDL (%s)\n", err);
318                 return;
319         }
320
321         if (sqlite3_changes(s_info.handle) == 0) {
322                 ErrPrint("No changes to DB\n");
323         }
324 }
325
326 static void alter_shortcut_service(void)
327 {
328         char *err;
329         static const char *ddl = "ALTER TABLE shortcut_service ADD pkgid TEXT";
330
331         if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
332                 ErrPrint("Failed to execute the DDL (%s)\n", err);
333                 return;
334         }
335
336         if (sqlite3_changes(s_info.handle) == 0) {
337                 ErrPrint("No changes to DB\n");
338         }
339 }
340
341 static int db_remove_by_pkgid(const char *pkgid)
342 {
343         static const char *dml = "DELETE FROM shortcut_service WHERE pkgid = ?";
344         sqlite3_stmt *stmt;
345         int ret;
346
347         if (!pkgid) {
348                 ErrPrint("Invalid argument\n");
349                 return -EINVAL;
350         }
351
352         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
353         if (ret != SQLITE_OK) {
354                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
355                 return -EIO;
356         }
357
358         ret = -EIO;
359         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
360                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
361                 goto out;
362         }
363
364         ret = 0;
365         if (sqlite3_step(stmt) != SQLITE_DONE) {
366                 ret = -EIO;
367                 ErrPrint("Failed to execute the DML for %s\n", pkgid);
368         } else {
369                 if (sqlite3_changes(s_info.handle) == 0) {
370                         DbgPrint("No changed\n");
371                 }
372         }
373
374 out:
375         sqlite3_reset(stmt);
376         sqlite3_clear_bindings(stmt);
377         sqlite3_finalize(stmt);
378         return ret;
379 }
380
381 static void do_upgrade_db_schema(void)
382 {
383         int version;
384
385         version = get_version();
386
387         switch (version) {
388         case -ENOSYS:
389                 db_create_version();
390                 /* Need to create version table */
391         case -ENOENT:
392                 if (set_version(1) < 0) {
393                         ErrPrint("Failed to set version\n");
394                 }
395                 /* Need to set version */
396                 alter_shortcut_name();
397                 alter_shortcut_service();
398         case 1:
399                 alter_shortcut_icon();
400                 if (update_version(2) < 0) {
401                         ErrPrint("Failed to update version\n");
402                 }
403         case 2:
404                 break;
405         default:
406                 /* Need to update version */
407                 DbgPrint("Old version: %d\n", version);
408                 if (update_version(2) < 0) {
409                         ErrPrint("Failed to update version\n");
410                 }
411
412                 alter_shortcut_name();
413                 alter_shortcut_service();
414                 /* 2 */
415                 alter_shortcut_icon();
416                 break;
417         }
418 }
419
420 static int db_remove_record(const char *pkgid, const char *appid, const char *key, const char *data)
421 {
422         static const char *dml = "DELETE FROM shortcut_service WHERE appid = ? AND extra_key = ? AND extra_data = ? AND pkgid = ?";
423         sqlite3_stmt *stmt;
424         int ret;
425
426         if (!appid || !key || !data) {
427                 ErrPrint("Invalid argument\n");
428                 return -EINVAL;
429         }
430
431         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
432         if (ret != SQLITE_OK) {
433                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
434                 return -EIO;
435         }
436
437         ret = -EIO;
438         if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
439                 ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle));
440                 goto out;
441         }
442
443         if (sqlite3_bind_text(stmt, 2, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
444                 ErrPrint("Failed to bind a key(%s)\n", sqlite3_errmsg(s_info.handle));
445                 goto out;
446         }
447
448         if (sqlite3_bind_text(stmt, 3, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
449                 ErrPrint("Failed to bind a data(%s)\n", sqlite3_errmsg(s_info.handle));
450                 goto out;
451         }
452
453         if (sqlite3_bind_text(stmt, 4, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
454                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
455                 goto out;
456         }
457
458         ret = 0;
459         if (sqlite3_step(stmt) != SQLITE_DONE) {
460                 ret = -EIO;
461                 ErrPrint("Failed to execute the DML for %s - %s(%s)\n", appid, key, data);
462         }
463
464         if (sqlite3_changes(s_info.handle) == 0) {
465                 DbgPrint("No changes\n");
466         }
467
468 out:
469         sqlite3_reset(stmt);
470         sqlite3_clear_bindings(stmt);
471         sqlite3_finalize(stmt);
472         return ret;
473 }
474
475 static int db_remove_name_by_pkgid(const char *pkgid)
476 {
477         static const char *dml = "DELETE FROM shortcut_name WHERE pkgid = ?";
478         sqlite3_stmt *stmt;
479         int ret;
480
481         if (!pkgid) {
482                 ErrPrint("Invalid id\n");
483                 return -EINVAL;
484         }
485
486         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
487         if (ret != SQLITE_OK) {
488                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
489                 return -EIO;
490         }
491
492         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
493                 ErrPrint("Failed to bind pkgid(%s)\n", pkgid);
494                 return -EIO;
495         }
496
497         ret = 0;
498         if (sqlite3_step(stmt) != SQLITE_DONE) {
499                 ret = -EIO;
500                 ErrPrint("Failed to execute the DML for %s\n", pkgid);
501                 goto out;
502         }
503
504         if (sqlite3_changes(s_info.handle) == 0) {
505                 DbgPrint("No chnages\n");
506         }
507
508 out:
509         sqlite3_reset(stmt);
510         sqlite3_clear_bindings(stmt);
511         sqlite3_finalize(stmt);
512         return ret;
513 }
514
515 static int db_remove_name(int id)
516 {
517         static const char *dml = "DELETE FROM shortcut_name WHERE id = ?";
518         sqlite3_stmt *stmt;
519         int ret;
520
521         if (id < 0) {
522                 ErrPrint("Inavlid id\n");
523                 return -EINVAL;
524         }
525
526         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
527         if (ret != SQLITE_OK) {
528                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
529                 return -EIO;
530         }
531
532         if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
533                 ErrPrint("Failed to bind id(%d)\n", id);
534                 ret = -EIO;
535                 goto out;
536         }
537
538         ret = 0;
539         if (sqlite3_step(stmt) != SQLITE_DONE) {
540                 ret = -EIO;
541                 ErrPrint("Failed to execute the DML for %d\n", id);
542                 goto out;
543         }
544
545         if (sqlite3_changes(s_info.handle) == 0) {
546                 DbgPrint("No changes\n");
547         }
548
549 out:
550         sqlite3_reset(stmt);
551         sqlite3_clear_bindings(stmt);
552         sqlite3_finalize(stmt);
553         return ret;
554 }
555
556 static int db_insert_record(const char *pkgid, const char *appid, const char *icon, const char *name, const char *key, const char *data)
557 {
558         static const char *dml = "INSERT INTO shortcut_service (pkgid, appid, icon, name, extra_key, extra_data) VALUES (?, ?, ?, ?, ?, ?)";
559         sqlite3_stmt *stmt;
560         int ret;
561
562         if (!pkgid) {
563                 ErrPrint("Failed to get pkgid\n");
564                 return -EINVAL;
565         }
566
567         if (!appid) {
568                 ErrPrint("Failed to get appid\n");
569                 return -EINVAL;
570         }
571
572         if (!name) {
573                 ErrPrint("Failed to get name\n");
574                 return -EINVAL;
575         }
576
577         if (!key) {
578                 ErrPrint("Failed to get key\n");
579                 return -EINVAL;
580         }
581
582         if (!data) {
583                 ErrPrint("Faield to get key\n");
584                 return -EINVAL;
585         }
586
587         icon = icon ? icon : "";
588
589         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
590         if (ret != SQLITE_OK) {
591                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
592                 return -EIO;
593         }
594
595         ret = -EIO;
596         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
597                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
598                 goto out;
599         }
600
601         if (sqlite3_bind_text(stmt, 2, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
602                 ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle));
603                 goto out;
604         }
605
606         if (sqlite3_bind_text(stmt, 3, icon, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
607                 ErrPrint("Failed to bind a icon(%s)\n", sqlite3_errmsg(s_info.handle));
608                 goto out;
609         }
610
611         if (sqlite3_bind_text(stmt, 4, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
612                 ErrPrint("Failed to bind a name(%s)\n", sqlite3_errmsg(s_info.handle));
613                 goto out;
614         }
615
616         if (sqlite3_bind_text(stmt, 5, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
617                 ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle));
618                 goto out;
619         }
620
621         if (sqlite3_bind_text(stmt, 6, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
622                 ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle));
623                 goto out;
624         }
625
626         ret = 0;
627         if (sqlite3_step(stmt) != SQLITE_DONE) {
628                 ErrPrint("Failed to execute the DML for %s - %s\n", appid, name);
629                 ret = -EIO;
630         }
631
632 out:
633         sqlite3_reset(stmt);
634         sqlite3_clear_bindings(stmt);
635         sqlite3_finalize(stmt);
636         return ret;
637 }
638
639 static int db_insert_name(int id, const char *pkgid, const char *lang, const char *name, const char *icon)
640 {
641         static const char *dml = "INSERT INTO shortcut_name (id, pkgid, lang, name, icon) VALUES (?, ?, ?, ?, ?)";
642         sqlite3_stmt *stmt;
643         int ret;
644
645         if (id < 0 || !lang) {
646                 ErrPrint("Invalid parameters\n");
647                 return -EINVAL;
648         }
649
650         if (!name) {
651                 name = "";
652         }
653
654         if (!icon) {
655                 icon = "";
656         }
657
658         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
659         if (ret != SQLITE_OK) {
660                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
661                 return -EIO;
662         }
663
664         if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) {
665                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
666                 ret = -EIO;
667                 goto out;
668         }
669
670         if (sqlite3_bind_text(stmt, 2, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
671                 ErrPrint("Failed to bind a pkgid(%s)\n", sqlite3_errmsg(s_info.handle));
672                 ret = -EIO;
673                 goto out;
674         }
675
676         if (sqlite3_bind_text(stmt, 3, lang, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
677                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
678                 ret = -EIO;
679                 goto out;
680         }
681
682         if (sqlite3_bind_text(stmt, 4, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
683                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
684                 ret = -EIO;
685                 goto out;
686         }
687
688         if (sqlite3_bind_text(stmt, 5, icon, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
689                 ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
690                 ret = -EIO;
691                 goto out;
692         }
693
694         ret = 0;
695         if (sqlite3_step(stmt) != SQLITE_DONE) {
696                 ErrPrint("Failed to execute the DML for %d %s %s\n", id, lang, name);
697                 ret = -EIO;
698         }
699
700 out:
701         sqlite3_reset(stmt);
702         sqlite3_clear_bindings(stmt);
703         sqlite3_finalize(stmt);
704         return ret;
705 }
706
707 static int db_get_id(const char *pkgid, const char *appid, const char *key, const char *data)
708 {
709         static const char *dml = "SELECT id FROM shortcut_service WHERE pkgid = ? AND appid = ? AND extra_key = ? AND extra_data = ?";
710         sqlite3_stmt *stmt;
711         int ret;
712
713         if (!appid || !key || !data) {
714                 ErrPrint("Invalid argument\n");
715                 return -EINVAL;
716         }
717
718         ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
719         if (ret != SQLITE_OK) {
720                 ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
721                 return -EIO;
722         }
723
724         ret = -EIO;
725         if (sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
726                 ErrPrint("Failed to bind a pkgid(%s) - %s\n", pkgid, sqlite3_errmsg(s_info.handle));
727                 goto out;
728         }
729
730         if (sqlite3_bind_text(stmt, 2, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
731                 ErrPrint("Failed to bind a appid(%s) - %s\n", appid, sqlite3_errmsg(s_info.handle));
732                 goto out;
733         }
734
735         if (sqlite3_bind_text(stmt, 3, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
736                 ErrPrint("Failed to bind a key(%s) - %s\n", key, sqlite3_errmsg(s_info.handle));
737                 goto out;
738         }
739
740         if (sqlite3_bind_text(stmt, 4, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
741                 ErrPrint("Failed to bind a data(%s) - %s\n", data, sqlite3_errmsg(s_info.handle));
742                 goto out;
743         }
744
745         if (sqlite3_step(stmt) != SQLITE_ROW) {
746                 ErrPrint("Failed to execute the DML for %s - %s, %s\n", appid, key, data);
747                 ret = -EIO;
748                 goto out;
749         }
750
751         ret = sqlite3_column_int(stmt, 0);
752
753 out:
754         sqlite3_reset(stmt);
755         sqlite3_clear_bindings(stmt);
756         sqlite3_finalize(stmt);
757         return ret;
758 }
759
760 static int db_init(void)
761 {
762         int ret;
763         struct stat stat;
764
765         s_info.dbfile = tzplatform_mkpath(TZ_SYS_DB, ".shortcut_service.db");
766         ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
767         if (ret != SQLITE_OK) {
768                 ErrPrint("Failed to open a DB\n");
769                 return -EIO;
770         }
771
772         if (lstat(s_info.dbfile, &stat) < 0) {
773                 ErrPrint("%s\n", strerror(errno));
774                 db_util_close(s_info.handle);
775                 s_info.handle = NULL;
776                 return -EIO;
777         }
778
779         if (!S_ISREG(stat.st_mode)) {
780                 ErrPrint("Invalid file\n");
781                 db_util_close(s_info.handle);
782                 s_info.handle = NULL;
783                 return -EINVAL;
784         }
785
786         if (!stat.st_size) {
787                 db_create_table();
788         }
789
790         return 0;
791 }
792
793 static int db_fini(void)
794 {
795         if (!s_info.handle) {
796                 return 0;
797         }
798
799         db_util_close(s_info.handle);
800         s_info.handle = NULL;
801
802         return 0;
803 }
804
805 static int do_uninstall(const char *appid)
806 {
807         int ret;
808
809         ret = db_remove_by_pkgid(appid); 
810         if (ret < 0) {
811                 ErrPrint("Failed to remove a record: %s\n", appid);
812                 return ret;
813         }
814
815         ret = db_remove_name_by_pkgid(appid);
816         if (ret < 0) {
817                 ErrPrint("Failed to remove name records: %s\n", appid);
818                 return ret;
819         }
820
821         return 0;
822 }
823
824 static inline struct i18n_name *find_i18n_name(struct dlist *i18n_list, xmlChar *lang)
825 {
826         struct dlist *l;
827         struct i18n_name *i18n;
828
829         dlist_foreach(i18n_list, l, i18n) {
830                 if (!xmlStrcasecmp(i18n->lang, lang)) {
831                         return i18n;
832                 }
833         }
834
835         return NULL;
836 }
837
838 static inline struct i18n_name *create_i18n_name(xmlChar *lang, xmlChar *name, xmlChar *icon)
839 {
840         struct i18n_name *i18n;
841
842         i18n = malloc(sizeof(*i18n));
843         if (!i18n) {
844                 ErrPrint("Heap: %s\n", strerror(errno));
845                 return NULL;
846         }
847
848         i18n->lang = lang;
849         i18n->name = name;
850         i18n->icon = icon;
851
852         return i18n;
853 }
854
855 static inline void destroy_i18n_name(struct i18n_name *i18n)
856 {
857         xmlFree(i18n->lang);
858         xmlFree(i18n->name);
859         xmlFree(i18n->icon);
860         free(i18n);
861 }
862
863 static int do_install(xmlDocPtr docPtr, const char *appid)
864 {
865         xmlNodePtr node = NULL;
866         xmlNodePtr child = NULL;
867         xmlChar *key;
868         xmlChar *data;
869         xmlChar *name;
870         xmlChar *icon;
871         xmlChar *lang;
872         xmlChar *shortcut_appid;
873         xmlNodePtr root;
874         struct i18n_name *i18n;
875         struct dlist *i18n_list = NULL;
876         struct dlist *l;
877         struct dlist *n;
878         int id;
879
880         root = xmlDocGetRootElement(docPtr);
881         if (!root) {
882                 ErrPrint("Invalid node ptr\n");
883                 return -EINVAL;
884         }
885
886         for (root = root->children; root; root = root->next) {
887                 if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list")) {
888                         break;
889                 }
890         }
891
892         if (!root) {
893                 ErrPrint("Root has no children\n");
894                 return -EINVAL;
895         }
896
897         DbgPrint("AppID: %s\n", appid);
898
899         root = root->children; /* Jump to children node */
900         for (node = root; node; node = node->next) {
901                 if (node->type == XML_ELEMENT_NODE) {
902                         DbgPrint("Element %s\n", node->name);
903                 }
904
905                 if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut")) {
906                         continue;
907                 }
908
909                 if (!xmlHasProp(node, (xmlChar *)"extra_key") || !xmlHasProp(node, (xmlChar *)"extra_data")) {
910                         DbgPrint("Invalid element %s\n", node->name);
911                         continue;
912                 }
913
914                 key = xmlGetProp(node, (xmlChar *)"extra_key");
915                 data = xmlGetProp(node, (xmlChar *)"extra_data");
916                 shortcut_appid = xmlGetProp(node, (xmlChar *)"appid");
917
918                 icon = NULL;
919                 name = NULL;
920                 for (child = node->children; child; child = child->next) {
921                         if (!xmlStrcasecmp(child->name, (const xmlChar *)"icon")) {
922                                 lang = xmlNodeGetLang(child);
923                                 if (!lang) {
924                                         if (icon) {
925                                                 DbgPrint("Default icon is duplicated\n");
926                                         } else {
927                                                 icon = xmlNodeGetContent(child);
928                                                 DbgPrint("Default icon is %s\n", icon);
929                                         }
930
931                                         continue;
932                                 }
933
934                                 i18n = find_i18n_name(i18n_list, lang);
935                                 if (i18n) {
936                                         xmlFree(lang);
937
938                                         if (i18n->icon) {
939                                                 DbgPrint("%s is duplicated\n", i18n->icon);
940                                                 continue;
941                                         }
942
943                                         i18n->icon = xmlNodeGetContent(child);
944                                 } else {
945                                         i18n = create_i18n_name(lang, NULL, xmlNodeGetContent(child));
946                                         if (!i18n) {
947                                                 ErrPrint("Failed to create a new i18n_name\n");
948                                                 continue;
949                                         }
950                                         i18n_list = dlist_append(i18n_list, i18n);
951                                 }
952
953                                 continue;
954                         }
955
956                         if (!xmlStrcasecmp(child->name, (const xmlChar *)"label")) {
957                                 lang = xmlNodeGetLang(child);
958                                 if (!lang) {
959                                         if (name) {
960                                                 DbgPrint("Default name is duplicated\n");
961                                         } else {
962                                                 name = xmlNodeGetContent(child);
963                                                 DbgPrint("Default name is %s\n", name);
964                                         }
965
966                                         continue;
967                                 }
968
969                                 i18n = find_i18n_name(i18n_list, lang);
970                                 if (i18n) {
971                                         xmlFree(lang);
972
973                                         if (i18n->name) {
974                                                 DbgPrint("%s is duplicated\n", i18n->name);
975                                                 continue;
976                                         }
977
978                                         i18n->name = xmlNodeGetContent(child);
979                                 } else {
980                                         i18n = create_i18n_name(lang, xmlNodeGetContent(child), NULL);
981                                         if (!i18n) {
982                                                 ErrPrint("Failed to create a new i18n_name\n");
983                                                 continue;
984                                         }
985                                         i18n_list = dlist_append(i18n_list, i18n);
986                                 }
987
988                                 continue;
989                         }
990                 }
991
992                 DbgPrint("appid: %s\n", appid);
993                 DbgPrint("shortcut appid: %s\n", shortcut_appid);
994                 DbgPrint("key: %s\n", key);
995                 DbgPrint("data: %s\n", data);
996                 DbgPrint("icon: %s\n", icon);
997                 DbgPrint("Default name: %s\n", name);
998
999                 if (!shortcut_appid) {
1000                         shortcut_appid = xmlStrdup((xmlChar *)appid);
1001                         DbgPrint("Use the default appid\n");
1002                 }
1003
1004                 begin_transaction();
1005                 if (db_insert_record(appid, (char *)shortcut_appid, (char *)icon, (char *)name, (char *)key, (char *)data) < 0) {
1006                         ErrPrint("Failed to insert a new record\n");
1007                         rollback_transaction();
1008
1009                         dlist_foreach_safe(i18n_list, l, n, i18n) {
1010                                 i18n_list = dlist_remove(i18n_list, l);
1011                                 destroy_i18n_name(i18n);
1012                         }
1013                 } else {
1014                         id = db_get_id((char *)appid, (char *)shortcut_appid, (char *)key, (char *)data);
1015                         if (id < 0) {
1016                                 ErrPrint("Failed to insert a new record\n");
1017                                 rollback_transaction();
1018
1019                                 dlist_foreach_safe(i18n_list, l, n, i18n) {
1020                                         i18n_list = dlist_remove(i18n_list, l);
1021                                         destroy_i18n_name(i18n);
1022                                 }
1023                         } else {
1024                                 dlist_foreach_safe(i18n_list, l, n, i18n) {
1025                                         i18n_list = dlist_remove(i18n_list, l);
1026                                         if (db_insert_name(id, appid, (char *)i18n->lang, (char *)i18n->name, (char *)i18n->icon) < 0) {
1027                                                 ErrPrint("Failed to add i18n name: %s(%s)\n", i18n->name, i18n->lang);
1028                                         }
1029                                         destroy_i18n_name(i18n);
1030                                 }
1031                                 commit_transaction();
1032                         }
1033                 }
1034
1035                 xmlFree(key);
1036                 xmlFree(data);
1037                 xmlFree(icon);
1038                 xmlFree(name);
1039                 xmlFree(shortcut_appid);
1040         }
1041
1042         return 0;
1043 }
1044
1045 int PKGMGR_PARSER_PLUGIN_PRE_UNINSTALL(const char *appid)
1046 {
1047         if (!s_info.handle) {
1048                 if (db_init() < 0) {
1049                         return -EIO;
1050                 }
1051         }
1052
1053         do_upgrade_db_schema();
1054         return 0;
1055 }
1056
1057 int PKGMGR_PARSER_PLUGIN_POST_UNINSTALL(const char *appid)
1058 {
1059         int ret;
1060
1061         begin_transaction();
1062         ret = do_uninstall(appid);
1063         if (ret < 0) {
1064                 rollback_transaction();
1065                 return ret;
1066         }
1067         commit_transaction();
1068
1069         db_fini();
1070         return 0;
1071 }
1072
1073 int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char *_appid)
1074 {
1075         xmlNodePtr node = NULL;
1076         xmlChar *key;
1077         xmlChar *data;
1078         xmlChar *appid;
1079         xmlNodePtr root;
1080         int id;
1081
1082         if (!docPtr) {
1083                 DbgPrint("Package manager doesn't support the docPtr (%s)\n", _appid);
1084                 return 0;
1085         }
1086
1087         root = xmlDocGetRootElement(docPtr);
1088         if (!root) {
1089                 ErrPrint("Invalid node ptr\n");
1090                 return -EINVAL;
1091         }
1092
1093         for (root = root->children; root; root = root->next) {
1094                 if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list")) {
1095                         break;
1096                 }
1097         }
1098
1099         if (!root) {
1100                 ErrPrint("Root has no shortcut-list\n");
1101                 return -EINVAL;
1102         }
1103
1104         DbgPrint("AppID: %s\n", _appid);
1105         root = root->children;
1106         for (node = root; node; node = node->next) {
1107                 if (node->type == XML_ELEMENT_NODE) {
1108                         DbgPrint("Element %s\n", node->name);
1109                 }
1110
1111                 if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut")) {
1112                         continue;
1113                 }
1114
1115                 if (!xmlHasProp(node, (xmlChar *)"extra_data")
1116                                 || !xmlHasProp(node, (xmlChar *)"extra_key")
1117                                 || !xmlHasProp(node, (xmlChar *)"appid"))
1118                 {
1119                         DbgPrint("Invalid element %s\n", node->name);
1120                         continue;
1121                 }
1122
1123                 appid = xmlGetProp(node, (xmlChar *)"appid");
1124                 key = xmlGetProp(node, (xmlChar *)"extra_key");
1125                 data = xmlGetProp(node, (xmlChar *)"extra_data");
1126
1127                 DbgPrint("appid: %s\n", appid);
1128                 DbgPrint("key: %s\n", key);
1129                 DbgPrint("data: %s\n", data);
1130
1131                 id = db_get_id("", (char *)appid, (char *)key, (char *)data);
1132                 if (id < 0) {
1133                         ErrPrint("No records found\n");
1134                         xmlFree(appid);
1135                         xmlFree(key);
1136                         xmlFree(data);
1137                         continue;
1138                 }
1139
1140                 begin_transaction();
1141                 if (db_remove_record("", (char *)appid, (char *)key, (char *)data) < 0) {
1142                         ErrPrint("Failed to remove a record\n");
1143                         rollback_transaction();
1144                         xmlFree(appid);
1145                         xmlFree(key);
1146                         xmlFree(data);
1147                         continue;
1148                 }
1149
1150                 if (db_remove_name(id) < 0) {
1151                         ErrPrint("Failed to remove name records\n");
1152                         rollback_transaction();
1153                         xmlFree(appid);
1154                         xmlFree(key);
1155                         xmlFree(data);
1156                         continue;
1157                 }
1158                 commit_transaction();
1159
1160                 xmlFree(appid);
1161                 xmlFree(key);
1162                 xmlFree(data);
1163
1164                 /*!
1165                  * \note
1166                  * if (node->children)
1167                  * DbgPrint("Skip this node's children\n");
1168                  */
1169         }
1170
1171         return 0;
1172 }
1173
1174 int PKGMGR_PARSER_PLUGIN_PRE_INSTALL(const char *appid)
1175 {
1176         int ret;
1177
1178         if (!s_info.handle) {
1179                 if (db_init() < 0) {
1180                         return -EIO;
1181                 }
1182         }
1183
1184         do_upgrade_db_schema();
1185
1186         begin_transaction();
1187         ret = do_uninstall(appid);
1188         if (ret < 0) {
1189                 ErrPrint("Failed to remove record: %s\n", appid);
1190                 /* Keep going */
1191         }
1192         commit_transaction();
1193         return  0;
1194 }
1195
1196 int PKGMGR_PARSER_PLUGIN_POST_INSTALL(const char *appid)
1197 {
1198         db_fini();
1199         return 0;
1200 }
1201
1202 int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char *appid)
1203 {
1204         return do_install(docPtr, appid);
1205 }
1206
1207 int PKGMGR_PARSER_PLUGIN_PRE_UPGRADE(const char *appid)
1208 {
1209         int ret;
1210
1211         if (!s_info.handle) {
1212                 if (db_init() < 0) {
1213                         return -EIO;
1214                 }
1215         }
1216
1217         do_upgrade_db_schema();
1218
1219         begin_transaction();
1220         ret = do_uninstall(appid);
1221         if (ret < 0) {
1222                 ErrPrint("Failed to remove a record: %s\n", appid);
1223                 /* Keep going */
1224         }
1225         commit_transaction();
1226         return 0;
1227 }
1228
1229 int PKGMGR_PARSER_PLUGIN_POST_UPGRADE(const char *appid)
1230 {
1231         db_fini();
1232         return 0;
1233 }
1234
1235 int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char *appid)
1236 {
1237         /* So... ugly */
1238         return do_install(docPtr, appid);
1239 }
1240
1241 /*
1242 int main(int argc, char *argv[])
1243 {
1244         xmlDoc *doc;
1245         xmlNode *root;
1246
1247         if (argc != 2) {
1248                 ErrPRint("Invalid argument: %s XML_FILENAME\n", argv[0]);
1249                 return -EINVAL;
1250         }
1251
1252         doc = xmlReadFile(argv[1], NULL, 0);
1253         if (!doc) {
1254                 ErrPrint("Failed to parse %s\n", argv[1]);
1255                 return -EIO;
1256         }
1257
1258         root = xmlDocGetRootElement(doc);
1259
1260         db_init();
1261         install_shortcut("", root);
1262         db_fini();
1263
1264         xmlFreeDoc(doc);
1265         xmlCleanupParser();
1266         return 0;
1267 }
1268 */
1269
1270 /* End of a file */