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