2 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <sys/socket.h>
24 #include <sys/ioctl.h>
31 #include <vconf-keys.h>
35 #include <com-core_packet.h>
38 #include "shortcut_internal.h"
47 const char *socket_file;
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);
58 .socket_file = "/tmp/.shortcut.service",
59 .dbfile = "/opt/dbspace/.shortcut_service.db",
67 static inline int make_connection(void);
70 static struct packet *remove_shortcut_handler(pid_t pid, int handle, const struct packet *packet)
74 const char *content_info;
79 ErrPrint("Packet is NIL, maybe disconnected?\n");
83 if (packet_get(packet, "isss", &sender_pid, &appid, &name, &content_info) != 4) {
84 ErrPrint("Invalid apcket\n");
88 DbgPrint("appid[%s], name[%s], content_info[%s]\n", appid, name, content_info);
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);
93 ret = SHORTCUT_ERROR_UNSUPPORTED;
96 return packet_create_reply(packet, "i", ret);
101 static struct packet *remove_livebox_handler(pid_t pid, int handle, const struct packet *packet)
109 ErrPrint("PAcket is NIL, maybe disconnected?\n");
113 if (packet_get(packet, "iss", &sender_pid, &appid, &name) != 3) {
114 ErrPrint("Invalid packet\n");
118 DbgPrint("appid[%s], name[%s]\n", appid, name);
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);
123 ret = SHORTCUT_ERROR_UNSUPPORTED;
126 return packet_create_reply(packet, "i", ret);
131 static struct packet *add_shortcut_handler(pid_t pid, int handle, const struct packet *packet)
146 if (packet_get(packet, "ississi", &sender_pid, &appid, &name, &type, &content, &icon, &allow_duplicate) != 7) {
147 ErrPrint("Invalid packet\n");
151 DbgPrint("appid[%s], name[%s], type[0x%x], content[%s], icon[%s] allow_duplicate[%d]\n", appid, name, type, content, icon, allow_duplicate);
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);
156 ret = SHORTCUT_ERROR_UNSUPPORTED;
159 return packet_create_reply(packet, "i", ret);
164 static struct packet *add_livebox_handler(pid_t pid, int handle, const struct packet *packet)
180 if (packet_get(packet, "ississdi", &sender_pid, &appid, &name, &type, &content, &icon, &period, &allow_duplicate) != 8) {
181 ErrPrint("Invalid packet\n");
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);
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);
193 return packet_create_reply(packet, "i", ret);
198 static void master_started_cb(keynode_t *node, void *user_data)
202 if (vconf_get_bool(VCONFKEY_MASTER_STARTED, &state) < 0) {
203 ErrPrint("Unable to get \"%s\"\n", VCONFKEY_MASTER_STARTED);
206 if (state == 1 && make_connection() == SHORTCUT_SUCCESS) {
208 ret = vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb);
209 DbgPrint("Ignore VCONF [%d]\n", ret);
215 static gboolean timeout_cb(void *data)
219 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
221 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
223 DbgPrint("vconf is registered\n");
226 master_started_cb(NULL, NULL);
234 static int disconnected_cb(int handle, void *data)
236 if (s_info.client_fd == handle) {
237 s_info.client_fd = SHORTCUT_ERROR_INVALID;
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");
257 static inline int make_connection(void)
260 struct packet *packet;
261 static struct method service_table[] = {
263 .cmd = "add_shortcut",
264 .handler = add_shortcut_handler,
267 .cmd = "add_livebox",
268 .handler = add_livebox_handler,
271 .cmd = "rm_shortcut",
272 .handler = remove_shortcut_handler,
276 .handler = remove_livebox_handler,
284 if (s_info.initialized == 0) {
285 s_info.initialized = 1;
286 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
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;
295 packet = packet_create_noack("service_register", "");
297 ErrPrint("Failed to build a packet\n");
298 return SHORTCUT_ERROR_FAULT;
301 ret = com_core_packet_send_only(s_info.server_fd, packet);
302 DbgPrint("Service register sent: %d\n", ret);
303 packet_destroy(packet);
305 com_core_packet_client_fini(s_info.server_fd);
306 s_info.server_fd = -1;
307 ret = SHORTCUT_ERROR_COMM;
309 ret = SHORTCUT_SUCCESS;
312 DbgPrint("Server FD: %d\n", s_info.server_fd);
318 EAPI int shortcut_set_request_cb(request_cb_t request_cb, void *data)
320 s_info.server_cb.request_cb = request_cb;
321 s_info.server_cb.data = data;
323 if (s_info.server_fd < 0) {
326 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
328 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
330 DbgPrint("vconf is registered\n");
333 master_started_cb(NULL, NULL);
336 return SHORTCUT_SUCCESS;
341 struct result_cb_item {
342 result_cb_t result_cb;
348 static int shortcut_send_cb(pid_t pid, int handle, const struct packet *packet, void *data)
350 struct result_cb_item *item = data;
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;
361 if (item->result_cb) {
362 ret = item->result_cb(ret, pid, item->data);
364 ret = SHORTCUT_SUCCESS;
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)
374 struct packet *packet;
375 struct result_cb_item *item;
378 if (!appid || !name) {
379 ErrPrint("Invalid argument\n");
380 return SHORTCUT_ERROR_INVALID;
383 if (!s_info.initialized) {
384 s_info.initialized = 1;
385 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
388 if (s_info.client_fd < 0) {
389 static struct method service_table[] = {
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;
403 item = malloc(sizeof(*item));
405 ErrPrint("Heap: %s\n", strerror(errno));
406 return SHORTCUT_ERROR_MEMORY;
409 item->result_cb = result_cb;
412 packet = packet_create("rm_shortcut", "isss", getpid(), appid, name, content_info);
414 ErrPrint("Failed to build a packet\n");
416 return SHORTCUT_ERROR_FAULT;
419 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
421 packet_destroy(packet);
423 com_core_packet_client_fini(s_info.client_fd);
424 s_info.client_fd = SHORTCUT_ERROR_INVALID;
425 return SHORTCUT_ERROR_COMM;
428 return SHORTCUT_SUCCESS;
433 EAPI int add_to_home_remove_livebox(const char *appid, const char *name, result_cb_t result_cb, void *data)
435 struct packet *packet;
436 struct result_cb_item *item;
439 if (!appid || !name) {
440 ErrPrint("Invalid argument\n");
441 return SHORTCUT_ERROR_INVALID;
444 if (!s_info.initialized) {
445 s_info.initialized = 1;
446 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
449 if (s_info.client_fd < 0) {
450 static struct method service_table[] = {
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;
465 item = malloc(sizeof(*item));
467 ErrPrint("Heap: %s\n", strerror(errno));
468 return SHORTCUT_ERROR_MEMORY;
471 item->result_cb = result_cb;
474 packet = packet_create("rm_livebox", "iss", getpid(), appid, name);
476 ErrPrint("Failed to build a packet\n");
478 return SHORTCUT_ERROR_FAULT;
481 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
483 packet_destroy(packet);
485 com_core_packet_client_fini(s_info.client_fd);
486 s_info.client_fd = SHORTCUT_ERROR_INVALID;
487 return SHORTCUT_ERROR_COMM;
490 return SHORTCUT_SUCCESS;
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)
497 struct packet *packet;
498 struct result_cb_item *item;
501 if (ADD_TO_HOME_IS_LIVEBOX(type)) {
502 ErrPrint("Invalid type used for adding a shortcut\n");
505 if (!s_info.initialized) {
506 s_info.initialized = 1;
507 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
510 if (s_info.client_fd < 0) {
511 static struct method service_table[] = {
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;
525 item = malloc(sizeof(*item));
527 ErrPrint("Heap: %s\n", strerror(errno));
528 return SHORTCUT_ERROR_MEMORY;
531 item->result_cb = result_cb;
550 packet = packet_create("add_shortcut", "ississi", getpid(), appid, name, type, content, icon, allow_duplicate);
552 ErrPrint("Failed to build a packet\n");
554 return SHORTCUT_ERROR_FAULT;
557 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
559 packet_destroy(packet);
561 com_core_packet_client_fini(s_info.client_fd);
562 s_info.client_fd = SHORTCUT_ERROR_INVALID;
563 return SHORTCUT_ERROR_COMM;
566 return SHORTCUT_SUCCESS;
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)
573 struct packet *packet;
574 struct result_cb_item *item;
577 if (!ADD_TO_HOME_IS_LIVEBOX(type)) {
578 ErrPrint("Invalid type is used for adding a livebox\n");
581 if (!s_info.initialized) {
582 s_info.initialized = 1;
583 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
586 if (s_info.client_fd < 0) {
587 static struct method service_table[] = {
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;
600 item = malloc(sizeof(*item));
602 ErrPrint("Heap: %s\n", strerror(errno));
603 return SHORTCUT_ERROR_MEMORY;
606 item->result_cb = result_cb;
609 packet = packet_create("add_livebox", "ississdi", getpid(), appid, name, type, content, icon, period, allow_duplicate);
611 ErrPrint("Failed to build a packet\n");
613 return SHORTCUT_ERROR_FAULT;
616 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
618 packet_destroy(packet);
620 com_core_packet_client_fini(s_info.client_fd);
621 s_info.client_fd = SHORTCUT_ERROR_INVALID;
622 return SHORTCUT_ERROR_COMM;
625 return SHORTCUT_SUCCESS;
629 static inline int open_db(void)
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;
639 return SHORTCUT_SUCCESS;
645 * \note this function will returns allocated(heap) string
647 static inline int get_i18n_name(const char *lang, int id, char **name, char **icon)
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;
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));
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));
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));
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));
683 _name = sqlite3_column_text(stmt, 0);
685 if (_name && strlen((const char *)_name)) {
686 *name = strdup((const char *)_name);
688 ErrPrint("strdup: %s\n", strerror(errno));
697 _icon = sqlite3_column_text(stmt, 1);
699 if (_icon && strlen((const char *)_icon)) {
700 *icon = strdup((const char *)_icon);
702 ErrPrint("strdup: %s\n", strerror(errno));
716 sqlite3_clear_bindings(stmt);
717 sqlite3_finalize(stmt);
723 static inline char *cur_locale(void)
726 language = vconf_get_str(VCONFKEY_LANGSET);
744 language = strdup("en-us");
746 ErrPrint("Heap: %s\n", strerror(errno));
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)
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;
773 if (!s_info.db_opened) {
774 s_info.db_opened = (open_db() == 0);
777 if (!s_info.db_opened) {
778 ErrPrint("Failed to open a DB\n");
779 return SHORTCUT_ERROR_IO;
782 language = cur_locale();
784 ErrPrint("Locale is not valid\n");
785 return SHORTCUT_ERROR_FAULT;
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));
794 return SHORTCUT_ERROR_IO;
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);
802 return SHORTCUT_ERROR_IO;
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));
810 return SHORTCUT_ERROR_IO;
815 while (SQLITE_ROW == sqlite3_step(stmt)) {
816 id = sqlite3_column_int(stmt, 0);
818 appid = (const char *)sqlite3_column_text(stmt, 1);
820 LOGE("Failed to get package name\n");
824 name = sqlite3_column_text(stmt, 2);
826 LOGE("Failed to get name\n");
830 extra_key = sqlite3_column_text(stmt, 3);
832 LOGE("Failed to get service\n");
836 extra_data = sqlite3_column_text(stmt, 4);
838 LOGE("Failed to get service\n");
842 icon = sqlite3_column_text(stmt, 5);
844 LOGE("Failed to get icon\n");
850 * Implement the "GET LOCALE" code
852 if (get_i18n_name(language, id, &i18n_name, &i18n_icon) < 0) {
853 /* Okay, we can't manage this. just use the fallback string */
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) {
867 sqlite3_clear_bindings(stmt);
868 sqlite3_finalize(stmt);