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