253c6c37d03fa2608bbd303577bed23c1eff8ab3
[platform/core/appfw/shortcut.git] / lib / src / main.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 <stdlib.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #include <sys/socket.h>
24 #include <sys/ioctl.h>
25 #include <libgen.h>
26
27 #include <dlog.h>
28 #include <glib.h>
29 #include <db-util.h>
30 #include <vconf.h>
31 #include <vconf-keys.h>
32
33 #include <packet.h>
34 #include <com-core.h>
35 #include <com-core_packet.h>
36
37 #include "shortcut.h"
38 #include "shortcut_internal.h"
39
40 int errno;
41
42 static struct info {
43         const char *dbfile;
44         sqlite3 *handle;
45         int server_fd;
46         int client_fd;
47         const char *socket_file;
48         struct {
49                 int (*request_cb)(const char *appid, const char *name, int type, const char *content, const char *icon, pid_t pid, double period, int allow_duplicate, void *data);
50                 void *data;
51         } server_cb;
52         int initialized;
53         int db_opened;
54         guint timer_id;
55 } s_info = {
56         .server_fd = -1,
57         .client_fd = -1,
58         .socket_file = "/tmp/.shortcut.service",
59         .dbfile = "/opt/dbspace/.shortcut_service.db",
60         .handle = NULL,
61         .initialized = 0,
62         .db_opened = 0,
63         .timer_id = 0,
64 };
65
66
67 static inline int make_connection(void);
68
69
70 static struct packet *remove_shortcut_handler(pid_t pid, int handle, const struct packet *packet)
71 {
72         const char *appid;
73         const char *name;
74         const char *content_info;
75         int ret;
76         int sender_pid;
77
78         if (!packet) {
79                 ErrPrint("Packet is NIL, maybe disconnected?\n");
80                 return NULL;
81         }
82
83         if (packet_get(packet, "isss", &sender_pid, &appid, &name, &content_info) != 4) {
84                 ErrPrint("Invalid apcket\n");
85                 return NULL;
86         }
87
88         DbgPrint("appid[%s], name[%s], content_info[%s]\n", appid, name, content_info);
89
90         if (s_info.server_cb.request_cb) {
91                 ret = s_info.server_cb.request_cb(appid, name, SHORTCUT_REMOVE, content_info, NULL, sender_pid, -1.0f, 0, s_info.server_cb.data);
92         } else {
93                 ret = SHORTCUT_ERROR_UNSUPPORTED;
94         }
95
96         return packet_create_reply(packet, "i", ret);
97 }
98
99
100
101 static struct packet *remove_livebox_handler(pid_t pid, int handle, const struct packet *packet)
102 {
103         const char *appid;
104         const char *name;
105         int ret;
106         int sender_pid;
107
108         if (!packet) {
109                 ErrPrint("PAcket is NIL, maybe disconnected?\n");
110                 return NULL;
111         }
112
113         if (packet_get(packet, "iss", &sender_pid, &appid, &name) != 3) {
114                 ErrPrint("Invalid packet\n");
115                 return NULL;
116         }
117
118         DbgPrint("appid[%s], name[%s]\n", appid, name);
119
120         if (s_info.server_cb.request_cb) {
121                 ret = s_info.server_cb.request_cb(appid, name, LIVEBOX_REMOVE, NULL, NULL, sender_pid, -1.0f, 0, s_info.server_cb.data);
122         } else {
123                 ret = SHORTCUT_ERROR_UNSUPPORTED;
124         }
125
126         return packet_create_reply(packet, "i", ret);
127 }
128
129
130
131 static struct packet *add_shortcut_handler(pid_t pid, int handle, const struct packet *packet)
132 {
133         const char *appid;
134         const char *name;
135         int type;
136         const char *content;
137         const char *icon;
138         int allow_duplicate;
139         int ret;
140         int sender_pid;
141
142         if (!packet) {
143                 return NULL;
144         }
145
146         if (packet_get(packet, "ississi", &sender_pid, &appid, &name, &type, &content, &icon, &allow_duplicate) != 7) {
147                 ErrPrint("Invalid packet\n");
148                 return NULL;
149         }
150
151         DbgPrint("appid[%s], name[%s], type[0x%x], content[%s], icon[%s] allow_duplicate[%d]\n", appid, name, type, content, icon, allow_duplicate);
152
153         if (s_info.server_cb.request_cb) {
154                 ret = s_info.server_cb.request_cb(appid, name, type, content, icon, sender_pid, -1.0f, allow_duplicate, s_info.server_cb.data);
155         } else {
156                 ret = SHORTCUT_ERROR_UNSUPPORTED;
157         }
158
159         return packet_create_reply(packet, "i", ret);
160 }
161
162
163
164 static struct packet *add_livebox_handler(pid_t pid, int handle, const struct packet *packet)
165 {
166         const char *appid;
167         const char *name;
168         int type;
169         const char *content;
170         const char *icon;
171         double period;
172         int allow_duplicate;
173         int ret;
174         int sender_pid;
175
176         if (!packet) {
177                 return NULL;
178         }
179
180         if (packet_get(packet, "ississdi", &sender_pid, &appid, &name, &type, &content, &icon, &period, &allow_duplicate) != 8) {
181                 ErrPrint("Invalid packet\n");
182                 return NULL;
183         }
184
185         DbgPrint("appid[%s], name[%s], type[0x%x], content[%s], icon[%s], period[%lf], allow_duplicate[%d]\n", appid, name, type, content, icon, period, allow_duplicate);
186
187         if (s_info.server_cb.request_cb) {
188                 ret = s_info.server_cb.request_cb(appid, name, type, content, icon, sender_pid, period, allow_duplicate, s_info.server_cb.data);
189         } else {
190                 ret = 0;
191         }
192
193         return packet_create_reply(packet, "i", ret);
194 }
195
196
197
198 static void master_started_cb(keynode_t *node, void *user_data)
199 {
200         int state = 0;
201
202         if (vconf_get_bool(VCONFKEY_MASTER_STARTED, &state) < 0) {
203                 ErrPrint("Unable to get \"%s\"\n", VCONFKEY_MASTER_STARTED);
204         }
205
206         if (state == 1 && make_connection() == SHORTCUT_SUCCESS) {
207                 int ret;
208                 ret = vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb);
209                 DbgPrint("Ignore VCONF [%d]\n", ret);
210         }
211 }
212
213
214
215 static gboolean timeout_cb(void *data)
216 {
217         int ret;
218
219         ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
220         if (ret < 0) {
221                 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
222         } else {
223                 DbgPrint("vconf is registered\n");
224         }
225
226         master_started_cb(NULL, NULL);
227
228         s_info.timer_id = 0;
229         return FALSE;
230 }
231
232
233
234 static int disconnected_cb(int handle, void *data)
235 {
236         if (s_info.client_fd == handle) {
237                 s_info.client_fd = SHORTCUT_ERROR_INVALID;
238                 return 0;
239         }
240
241         if (s_info.server_fd == handle) {
242                 if (!s_info.timer_id) {
243                         s_info.server_fd = SHORTCUT_ERROR_INVALID;
244                         s_info.timer_id = g_timeout_add(1000, timeout_cb, NULL);
245                         if (!s_info.timer_id) {
246                                 ErrPrint("Unable to add timer\n");
247                         }
248                 }
249                 return 0;
250         }
251
252         return 0;
253 }
254
255
256
257 static inline int make_connection(void)
258 {
259         int ret;
260         struct packet *packet;
261         static struct method service_table[] = {
262                 {
263                         .cmd = "add_shortcut",
264                         .handler = add_shortcut_handler,
265                 },
266                 {
267                         .cmd = "add_livebox",
268                         .handler = add_livebox_handler,
269                 },
270                 {
271                         .cmd = "rm_shortcut",
272                         .handler = remove_shortcut_handler,
273                 },
274                 {
275                         .cmd = "rm_livebox",
276                         .handler = remove_livebox_handler,
277                 },
278                 {
279                         .cmd = NULL,
280                         .handler = NULL,
281                 },
282         };
283
284         if (s_info.initialized == 0) {
285                 s_info.initialized = 1;
286                 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
287         }
288
289         s_info.server_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
290         if (s_info.server_fd < 0) {
291                 ErrPrint("Failed to make a connection to the master\n");
292                 return SHORTCUT_ERROR_COMM;
293         }
294
295         packet = packet_create_noack("service_register", "");
296         if (!packet) {
297                 ErrPrint("Failed to build a packet\n");
298                 return SHORTCUT_ERROR_FAULT;
299         }
300
301         ret = com_core_packet_send_only(s_info.server_fd, packet);
302         DbgPrint("Service register sent: %d\n", ret);
303         packet_destroy(packet);
304         if (ret != 0) {
305                 com_core_packet_client_fini(s_info.server_fd);
306                 s_info.server_fd = -1;
307                 ret = SHORTCUT_ERROR_COMM;
308         } else {
309                 ret = SHORTCUT_SUCCESS;
310         }
311
312         DbgPrint("Server FD: %d\n", s_info.server_fd);
313         return ret;
314 }
315
316
317
318 EAPI int shortcut_set_request_cb(request_cb_t request_cb, void *data)
319 {
320         s_info.server_cb.request_cb = request_cb;
321         s_info.server_cb.data = data;
322
323         if (s_info.server_fd < 0) {
324                 int ret;
325
326                 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
327                 if (ret < 0) {
328                         ErrPrint("Failed to add vconf for service state [%d]\n", ret);
329                 } else {
330                         DbgPrint("vconf is registered\n");
331                 }
332
333                 master_started_cb(NULL, NULL);
334         }
335
336         return SHORTCUT_SUCCESS;
337 }
338
339
340
341 struct result_cb_item {
342         result_cb_t result_cb;
343         void *data;
344 };
345
346
347
348 static int shortcut_send_cb(pid_t pid, int handle, const struct packet *packet, void *data)
349 {
350         struct result_cb_item *item = data;
351         int ret;
352
353         if (!packet) {
354                 ErrPrint("Packet is not valid\n");
355                 ret = SHORTCUT_ERROR_FAULT;
356         } else if (packet_get(packet, "i", &ret) != 1) {
357                 ErrPrint("Packet is not valid\n");
358                 ret = SHORTCUT_ERROR_INVALID;
359         }
360
361         if (item->result_cb) {
362                 ret = item->result_cb(ret, pid, item->data);
363         } else {
364                 ret = SHORTCUT_SUCCESS;
365         }
366         free(item);
367         return ret;
368 }
369
370
371
372 EAPI int add_to_home_remove_shortcut(const char *appid, const char *name, const char *content_info, result_cb_t result_cb, void *data)
373 {
374         struct packet *packet;
375         struct result_cb_item *item;
376         int ret;
377
378         if (!appid || !name) {
379                 ErrPrint("Invalid argument\n");
380                 return SHORTCUT_ERROR_INVALID;
381         }
382
383         if (!s_info.initialized) {
384                 s_info.initialized = 1;
385                 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
386         }
387
388         if (s_info.client_fd < 0) {
389                 static struct method service_table[] = {
390                         {
391                                 .cmd = NULL,
392                                 .handler = NULL,
393                         },
394                 };
395
396                 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
397                 if (s_info.client_fd < 0) {
398                         ErrPrint("Failed to make connection\n");
399                         return SHORTCUT_ERROR_COMM;
400                 }
401         }
402
403         item = malloc(sizeof(*item));
404         if (!item) {
405                 ErrPrint("Heap: %s\n", strerror(errno));
406                 return SHORTCUT_ERROR_MEMORY;
407         }
408
409         item->result_cb = result_cb;
410         item->data = data;
411
412         packet = packet_create("rm_shortcut", "isss", getpid(), appid, name, content_info);
413         if (!packet) {
414                 ErrPrint("Failed to build a packet\n");
415                 free(item);
416                 return SHORTCUT_ERROR_FAULT;
417         }
418
419         ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
420         if (ret < 0) {
421                 packet_destroy(packet);
422                 free(item);
423                 com_core_packet_client_fini(s_info.client_fd);
424                 s_info.client_fd = SHORTCUT_ERROR_INVALID;
425                 return SHORTCUT_ERROR_COMM;
426         }
427
428         return SHORTCUT_SUCCESS;
429 }
430
431
432
433 EAPI int add_to_home_remove_livebox(const char *appid, const char *name, result_cb_t result_cb, void *data)
434 {
435         struct packet *packet;
436         struct result_cb_item *item;
437         int ret;
438
439         if (!appid || !name) {
440                 ErrPrint("Invalid argument\n");
441                 return SHORTCUT_ERROR_INVALID;
442         }
443
444         if (!s_info.initialized) {
445                 s_info.initialized = 1;
446                 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
447         }
448
449         if (s_info.client_fd < 0) {
450                 static struct method service_table[] = {
451                         {
452                                 .cmd = NULL,
453                                 .handler = NULL,
454                         },
455                 };
456
457
458                 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
459                 if (s_info.client_fd < 0) {
460                         ErrPrint("Failed to make connection\n");
461                         return SHORTCUT_ERROR_COMM;
462                 }
463         }
464
465         item = malloc(sizeof(*item));
466         if (!item) {
467                 ErrPrint("Heap: %s\n", strerror(errno));
468                 return SHORTCUT_ERROR_MEMORY;
469         }
470
471         item->result_cb = result_cb;
472         item->data = data;
473
474         packet = packet_create("rm_livebox", "iss", getpid(), appid, name);
475         if (!packet) {
476                 ErrPrint("Failed to build a packet\n");
477                 free(item);
478                 return SHORTCUT_ERROR_FAULT;
479         }
480
481         ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
482         if (ret < 0) {
483                 packet_destroy(packet);
484                 free(item);
485                 com_core_packet_client_fini(s_info.client_fd);
486                 s_info.client_fd = SHORTCUT_ERROR_INVALID;
487                 return SHORTCUT_ERROR_COMM;
488         }
489
490         return SHORTCUT_SUCCESS;
491 }
492
493
494
495 EAPI int add_to_home_shortcut(const char *appid, const char *name, int type, const char *content, const char *icon, int allow_duplicate, result_cb_t result_cb, void *data)
496 {
497         struct packet *packet;
498         struct result_cb_item *item;
499         int ret;
500
501         if (ADD_TO_HOME_IS_LIVEBOX(type)) {
502                 ErrPrint("Invalid type used for adding a shortcut\n");
503         }
504
505         if (!s_info.initialized) {
506                 s_info.initialized = 1;
507                 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
508         }
509
510         if (s_info.client_fd < 0) {
511                 static struct method service_table[] = {
512                         {
513                                 .cmd = NULL,
514                                 .handler = NULL,
515                         },
516                 };
517
518                 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
519                 if (s_info.client_fd < 0) {
520                         ErrPrint("Failed to make connection\n");
521                         return SHORTCUT_ERROR_COMM;
522                 }
523         }
524
525         item = malloc(sizeof(*item));
526         if (!item) {
527                 ErrPrint("Heap: %s\n", strerror(errno));
528                 return SHORTCUT_ERROR_MEMORY;
529         }
530
531         item->result_cb = result_cb;
532         item->data = data;
533
534         if (!appid) {
535                 appid = "";
536         }
537
538         if (!name) {
539                 name = "";
540         }
541
542         if (!content) {
543                 content = "";
544         }
545
546         if (!icon) {
547                 icon = "";
548         }
549
550         packet = packet_create("add_shortcut", "ississi", getpid(), appid, name, type, content, icon, allow_duplicate);
551         if (!packet) {
552                 ErrPrint("Failed to build a packet\n");
553                 free(item);
554                 return SHORTCUT_ERROR_FAULT;
555         }
556
557         ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
558         if (ret < 0) {
559                 packet_destroy(packet);
560                 free(item);
561                 com_core_packet_client_fini(s_info.client_fd);
562                 s_info.client_fd = SHORTCUT_ERROR_INVALID;
563                 return SHORTCUT_ERROR_COMM;
564         }
565
566         return SHORTCUT_SUCCESS;
567 }
568
569
570
571 EAPI int add_to_home_livebox(const char *appid, const char *name, int type, const char *content, const char *icon, double period, int allow_duplicate, result_cb_t result_cb, void *data)
572 {
573         struct packet *packet;
574         struct result_cb_item *item;
575         int ret;
576
577         if (!ADD_TO_HOME_IS_LIVEBOX(type)) {
578                 ErrPrint("Invalid type is used for adding a livebox\n");
579         }
580
581         if (!s_info.initialized) {
582                 s_info.initialized = 1;
583                 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
584         }
585
586         if (s_info.client_fd < 0) {
587                 static struct method service_table[] = {
588                         {
589                                 .cmd = NULL,
590                                 .handler = NULL,
591                         },
592                 };
593
594                 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
595                 if (s_info.client_fd < 0) {
596                         return SHORTCUT_ERROR_COMM;
597                 }
598         }
599
600         item = malloc(sizeof(*item));
601         if (!item) {
602                 ErrPrint("Heap: %s\n", strerror(errno));
603                 return SHORTCUT_ERROR_MEMORY;
604         }
605
606         item->result_cb = result_cb;
607         item->data = data;
608
609         packet = packet_create("add_livebox", "ississdi", getpid(), appid, name, type, content, icon, period, allow_duplicate);
610         if (!packet) {
611                 ErrPrint("Failed to build a packet\n");
612                 free(item);
613                 return SHORTCUT_ERROR_FAULT;
614         }
615
616         ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
617         if (ret < 0) {
618                 packet_destroy(packet);
619                 free(item);
620                 com_core_packet_client_fini(s_info.client_fd);
621                 s_info.client_fd = SHORTCUT_ERROR_INVALID;
622                 return SHORTCUT_ERROR_COMM;
623         }
624
625         return SHORTCUT_SUCCESS;
626 }
627
628
629 static inline int open_db(void)
630 {
631         int ret;
632
633         ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
634         if (ret != SQLITE_OK) {
635                 DbgPrint("Failed to open a %s\n", s_info.dbfile);
636                 return SHORTCUT_ERROR_IO;
637         }
638
639         return SHORTCUT_SUCCESS;
640 }
641
642
643
644 /*!
645  * \note this function will returns allocated(heap) string
646  */
647 static inline int get_i18n_name(const char *lang, int id, char **name, char **icon)
648 {
649         sqlite3_stmt *stmt;
650         static const char *query = "SELECT name, icon FROM shortcut_name WHERE id = ? AND lang = ? COLLATE NOCASE";
651         const unsigned char *_name;
652         const unsigned char *_icon;
653         int ret = 0;
654         int status;
655
656         status = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
657         if (status != SQLITE_OK) {
658                 ErrPrint("Failed to prepare stmt: %s\n", sqlite3_errmsg(s_info.handle));
659                 return -EFAULT;
660         }
661
662         status = sqlite3_bind_int(stmt, 1, id);
663         if (status != SQLITE_OK) {
664                 ErrPrint("Failed to bind id: %s\n", sqlite3_errmsg(s_info.handle));
665                 ret = -EFAULT;
666                 goto out;
667         }
668
669         status = sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT);
670         if (status != SQLITE_OK) {
671                 ErrPrint("Failed to bind lang: %s\n", sqlite3_errmsg(s_info.handle));
672                 ret = -EFAULT;
673                 goto out;
674         }
675
676         DbgPrint("id: %d, lang: %s\n", id, lang);
677         if (SQLITE_ROW != sqlite3_step(stmt)) {
678                 ErrPrint("Failed to do step: %s\n", sqlite3_errmsg(s_info.handle));
679                 ret = -ENOENT;
680                 goto out;
681         }
682
683         _name = sqlite3_column_text(stmt, 0);
684         if (name) {
685                 if (_name && strlen((const char *)_name)) {
686                         *name = strdup((const char *)_name);
687                         if (!*name) {
688                                 ErrPrint("strdup: %s\n", strerror(errno));
689                                 ret = -ENOMEM;
690                                 goto out;
691                         }
692                 } else {
693                         *name = NULL;
694                 }
695         }
696
697         _icon = sqlite3_column_text(stmt, 1);
698         if (icon) {
699                 if (_icon && strlen((const char *)_icon)) {
700                         *icon = strdup((const char *)_icon);
701                         if (!*icon) {
702                                 ErrPrint("strdup: %s\n", strerror(errno));
703                                 ret = -ENOMEM;
704                                 if (name && *name) {
705                                         free(*name);
706                                 }
707                                 goto out;
708                         }
709                 } else {
710                         *icon = NULL;
711                 }
712         }
713
714 out:
715         sqlite3_reset(stmt);
716         sqlite3_clear_bindings(stmt);
717         sqlite3_finalize(stmt);
718         return ret;
719 }
720
721
722
723 static inline char *cur_locale(void)
724 {
725         char *language;
726         language = vconf_get_str(VCONFKEY_LANGSET);
727         if (language) {
728                 char *ptr;
729
730                 ptr = language;
731                 while (*ptr) {
732                         if (*ptr == '.') {
733                                 *ptr = '\0';
734                                 break;
735                         }
736
737                         if (*ptr == '_') {
738                                 *ptr = '-';
739                         }
740
741                         ptr++;
742                 }
743         } else {
744                 language = strdup("en-us");
745                 if (!language) {
746                         ErrPrint("Heap: %s\n", strerror(errno));
747                 }
748         }
749
750         return language;
751 }
752
753
754
755 /*!
756  * \note READ ONLY DB
757  */
758 EAPI int shortcut_get_list(const char *appid, int (*cb)(const char *appid, const char *icon, const char *name, const char *extra_key, const char *extra_data, void *data), void *data)
759 {
760         sqlite3_stmt *stmt;
761         const char *query;
762         const unsigned char *name;
763         char *i18n_name = NULL;
764         char *i18n_icon = NULL;
765         const unsigned char *extra_data;
766         const unsigned char *extra_key;
767         const unsigned char *icon;
768         int id;
769         int ret;
770         int cnt;
771         char *language;
772
773         if (!s_info.db_opened) {
774                 s_info.db_opened = (open_db() == 0);
775         }
776
777         if (!s_info.db_opened) {
778                 ErrPrint("Failed to open a DB\n");
779                 return SHORTCUT_ERROR_IO;
780         }
781
782         language = cur_locale();
783         if (!language) {
784                 ErrPrint("Locale is not valid\n");
785                 return SHORTCUT_ERROR_FAULT;
786         }
787
788         if (appid) {
789                 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service WHERE appid = ?";
790                 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
791                 if (ret != SQLITE_OK) {
792                         ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
793                         free(language);
794                         return SHORTCUT_ERROR_IO;
795                 }
796
797                 ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT);
798                 if (ret != SQLITE_OK) {
799                         ErrPrint("bind text: %s\n", sqlite3_errmsg(s_info.handle));
800                         sqlite3_finalize(stmt);
801                         free(language);
802                         return SHORTCUT_ERROR_IO;
803                 }
804         } else {
805                 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service";
806                 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
807                 if (ret != SQLITE_OK) {
808                         ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
809                         free(language);
810                         return SHORTCUT_ERROR_IO;
811                 }
812         }
813
814         cnt = 0;
815         while (SQLITE_ROW == sqlite3_step(stmt)) {
816                 id = sqlite3_column_int(stmt, 0);
817
818                 appid = (const char *)sqlite3_column_text(stmt, 1);
819                 if (!appid) {
820                         LOGE("Failed to get package name\n");
821                         continue;
822                 }
823
824                 name = sqlite3_column_text(stmt, 2);
825                 if (!name) {
826                         LOGE("Failed to get name\n");
827                         continue;
828                 }
829
830                 extra_key = sqlite3_column_text(stmt, 3);
831                 if (!extra_key) {
832                         LOGE("Failed to get service\n");
833                         continue;
834                 }
835
836                 extra_data = sqlite3_column_text(stmt, 4);
837                 if (!extra_data) {
838                         LOGE("Failed to get service\n");
839                         continue;
840                 }
841
842                 icon = sqlite3_column_text(stmt, 5);
843                 if (!icon) {
844                         LOGE("Failed to get icon\n");
845                         continue;
846                 }
847
848                 /*!
849                  * \todo
850                  * Implement the "GET LOCALE" code
851                  */
852                 if (get_i18n_name(language, id, &i18n_name, &i18n_icon) < 0) {
853                         /* Okay, we can't manage this. just use the fallback string */
854                 }
855
856                 cnt++;
857                 if (cb(appid, (i18n_icon != NULL ? i18n_icon : (char *)icon), (i18n_name != NULL ? i18n_name : (char *)name), (char *)extra_key, (char *)extra_data, data) < 0) {
858                         free(i18n_name);
859                         break;
860                 }
861
862                 free(i18n_name);
863                 free(i18n_icon);
864         }
865
866         sqlite3_reset(stmt);
867         sqlite3_clear_bindings(stmt);
868         sqlite3_finalize(stmt);
869         free(language);
870         return cnt;
871 }
872
873 /* End of a file */