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) {
207 (void)vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb);
213 static gboolean timeout_cb(void *data)
217 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
219 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
221 DbgPrint("vconf is registered\n");
224 master_started_cb(NULL, NULL);
232 static int disconnected_cb(int handle, void *data)
234 if (s_info.client_fd == handle) {
235 s_info.client_fd = SHORTCUT_ERROR_INVALID;
239 if (s_info.server_fd == handle) {
240 if (!s_info.timer_id) {
241 s_info.server_fd = SHORTCUT_ERROR_INVALID;
242 s_info.timer_id = g_timeout_add(1000, timeout_cb, NULL);
243 if (!s_info.timer_id) {
244 ErrPrint("Unable to add timer\n");
255 static inline int make_connection(void)
258 struct packet *packet;
259 static struct method service_table[] = {
261 .cmd = "add_shortcut",
262 .handler = add_shortcut_handler,
265 .cmd = "add_livebox",
266 .handler = add_livebox_handler,
269 .cmd = "rm_shortcut",
270 .handler = remove_shortcut_handler,
274 .handler = remove_livebox_handler,
282 if (s_info.initialized == 0) {
283 s_info.initialized = 1;
284 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
287 s_info.server_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
288 if (s_info.server_fd < 0) {
289 ErrPrint("Failed to make a connection to the master\n");
290 return SHORTCUT_ERROR_COMM;
293 packet = packet_create_noack("service_register", "");
295 ErrPrint("Failed to build a packet\n");
296 return SHORTCUT_ERROR_FAULT;
299 ret = com_core_packet_send_only(s_info.server_fd, packet);
300 DbgPrint("Service register sent: %d\n", ret);
301 packet_destroy(packet);
303 com_core_packet_client_fini(s_info.server_fd);
304 s_info.server_fd = -1;
305 ret = SHORTCUT_ERROR_COMM;
307 ret = SHORTCUT_SUCCESS;
310 DbgPrint("Server FD: %d\n", s_info.server_fd);
316 EAPI int shortcut_set_request_cb(request_cb_t request_cb, void *data)
318 s_info.server_cb.request_cb = request_cb;
319 s_info.server_cb.data = data;
321 if (s_info.server_fd < 0) {
324 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
326 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
328 DbgPrint("vconf is registered\n");
331 master_started_cb(NULL, NULL);
334 return SHORTCUT_SUCCESS;
339 struct result_cb_item {
340 result_cb_t result_cb;
346 static int shortcut_send_cb(pid_t pid, int handle, const struct packet *packet, void *data)
348 struct result_cb_item *item = data;
352 ErrPrint("Packet is not valid\n");
353 ret = SHORTCUT_ERROR_FAULT;
354 } else if (packet_get(packet, "i", &ret) != 1) {
355 ErrPrint("Packet is not valid\n");
356 ret = SHORTCUT_ERROR_INVALID;
359 if (item->result_cb) {
360 ret = item->result_cb(ret, pid, item->data);
362 ret = SHORTCUT_SUCCESS;
370 EAPI int add_to_home_remove_shortcut(const char *appid, const char *name, const char *content_info, result_cb_t result_cb, void *data)
372 struct packet *packet;
373 struct result_cb_item *item;
376 if (!appid || !name) {
377 ErrPrint("Invalid argument\n");
378 return SHORTCUT_ERROR_INVALID;
381 if (!s_info.initialized) {
382 s_info.initialized = 1;
383 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
386 if (s_info.client_fd < 0) {
387 static struct method service_table[] = {
394 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
395 if (s_info.client_fd < 0) {
396 ErrPrint("Failed to make connection\n");
397 return SHORTCUT_ERROR_COMM;
401 item = malloc(sizeof(*item));
403 ErrPrint("Heap: %s\n", strerror(errno));
404 return SHORTCUT_ERROR_MEMORY;
407 item->result_cb = result_cb;
410 packet = packet_create("rm_shortcut", "isss", getpid(), appid, name, content_info);
412 ErrPrint("Failed to build a packet\n");
414 return SHORTCUT_ERROR_FAULT;
417 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
419 packet_destroy(packet);
421 com_core_packet_client_fini(s_info.client_fd);
422 s_info.client_fd = SHORTCUT_ERROR_INVALID;
423 return SHORTCUT_ERROR_COMM;
426 return SHORTCUT_SUCCESS;
431 EAPI int add_to_home_remove_livebox(const char *appid, const char *name, result_cb_t result_cb, void *data)
433 struct packet *packet;
434 struct result_cb_item *item;
437 if (!appid || !name) {
438 ErrPrint("Invalid argument\n");
439 return SHORTCUT_ERROR_INVALID;
442 if (!s_info.initialized) {
443 s_info.initialized = 1;
444 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
447 if (s_info.client_fd < 0) {
448 static struct method service_table[] = {
456 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
457 if (s_info.client_fd < 0) {
458 ErrPrint("Failed to make connection\n");
459 return SHORTCUT_ERROR_COMM;
463 item = malloc(sizeof(*item));
465 ErrPrint("Heap: %s\n", strerror(errno));
466 return SHORTCUT_ERROR_MEMORY;
469 item->result_cb = result_cb;
472 packet = packet_create("rm_livebox", "iss", getpid(), appid, name);
474 ErrPrint("Failed to build a packet\n");
476 return SHORTCUT_ERROR_FAULT;
479 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
481 packet_destroy(packet);
483 com_core_packet_client_fini(s_info.client_fd);
484 s_info.client_fd = SHORTCUT_ERROR_INVALID;
485 return SHORTCUT_ERROR_COMM;
488 return SHORTCUT_SUCCESS;
493 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)
495 struct packet *packet;
496 struct result_cb_item *item;
499 if (ADD_TO_HOME_IS_LIVEBOX(type)) {
500 ErrPrint("Invalid type used for adding a shortcut\n");
503 if (!s_info.initialized) {
504 s_info.initialized = 1;
505 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
508 if (s_info.client_fd < 0) {
509 static struct method service_table[] = {
516 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
517 if (s_info.client_fd < 0) {
518 ErrPrint("Failed to make connection\n");
519 return SHORTCUT_ERROR_COMM;
523 item = malloc(sizeof(*item));
525 ErrPrint("Heap: %s\n", strerror(errno));
526 return SHORTCUT_ERROR_MEMORY;
529 item->result_cb = result_cb;
548 packet = packet_create("add_shortcut", "ississi", getpid(), appid, name, type, content, icon, allow_duplicate);
550 ErrPrint("Failed to build a packet\n");
552 return SHORTCUT_ERROR_FAULT;
555 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
557 packet_destroy(packet);
559 com_core_packet_client_fini(s_info.client_fd);
560 s_info.client_fd = SHORTCUT_ERROR_INVALID;
561 return SHORTCUT_ERROR_COMM;
564 return SHORTCUT_SUCCESS;
569 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)
571 struct packet *packet;
572 struct result_cb_item *item;
575 if (!ADD_TO_HOME_IS_LIVEBOX(type)) {
576 ErrPrint("Invalid type is used for adding a livebox\n");
579 if (!s_info.initialized) {
580 s_info.initialized = 1;
581 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
584 if (s_info.client_fd < 0) {
585 static struct method service_table[] = {
592 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
593 if (s_info.client_fd < 0) {
594 return SHORTCUT_ERROR_COMM;
598 item = malloc(sizeof(*item));
600 ErrPrint("Heap: %s\n", strerror(errno));
601 return SHORTCUT_ERROR_MEMORY;
604 item->result_cb = result_cb;
607 packet = packet_create("add_livebox", "ississdi", getpid(), appid, name, type, content, icon, period, allow_duplicate);
609 ErrPrint("Failed to build a packet\n");
611 return SHORTCUT_ERROR_FAULT;
614 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
616 packet_destroy(packet);
618 com_core_packet_client_fini(s_info.client_fd);
619 s_info.client_fd = SHORTCUT_ERROR_INVALID;
620 return SHORTCUT_ERROR_COMM;
623 return SHORTCUT_SUCCESS;
627 static inline int open_db(void)
631 ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
632 if (ret != SQLITE_OK) {
633 DbgPrint("Failed to open a %s\n", s_info.dbfile);
634 return SHORTCUT_ERROR_IO;
637 return SHORTCUT_SUCCESS;
643 * \note this function will returns allocated(heap) string
645 static inline int get_i18n_name(const char *lang, int id, char **name, char **icon)
648 static const char *query = "SELECT name, icon FROM shortcut_name WHERE id = ? AND lang = ? COLLATE NOCASE";
649 const unsigned char *_name;
650 const unsigned char *_icon;
654 status = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
655 if (status != SQLITE_OK) {
656 ErrPrint("Failed to prepare stmt: %s\n", sqlite3_errmsg(s_info.handle));
660 status = sqlite3_bind_int(stmt, 1, id);
661 if (status != SQLITE_OK) {
662 ErrPrint("Failed to bind id: %s\n", sqlite3_errmsg(s_info.handle));
667 status = sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT);
668 if (status != SQLITE_OK) {
669 ErrPrint("Failed to bind lang: %s\n", sqlite3_errmsg(s_info.handle));
674 DbgPrint("id: %d, lang: %s\n", id, lang);
675 if (SQLITE_ROW != sqlite3_step(stmt)) {
676 ErrPrint("Failed to do step: %s\n", sqlite3_errmsg(s_info.handle));
681 _name = sqlite3_column_text(stmt, 0);
683 if (_name && strlen((const char *)_name)) {
684 *name = strdup((const char *)_name);
686 ErrPrint("strdup: %s\n", strerror(errno));
695 _icon = sqlite3_column_text(stmt, 1);
697 if (_icon && strlen((const char *)_icon)) {
698 *icon = strdup((const char *)_icon);
700 ErrPrint("strdup: %s\n", strerror(errno));
714 sqlite3_clear_bindings(stmt);
715 sqlite3_finalize(stmt);
721 static inline char *cur_locale(void)
724 language = vconf_get_str(VCONFKEY_LANGSET);
742 language = strdup("en-us");
744 ErrPrint("Heap: %s\n", strerror(errno));
756 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)
760 const unsigned char *name;
761 char *i18n_name = NULL;
762 char *i18n_icon = NULL;
763 const unsigned char *extra_data;
764 const unsigned char *extra_key;
765 const unsigned char *icon;
771 if (!s_info.db_opened) {
772 s_info.db_opened = (open_db() == 0);
775 if (!s_info.db_opened) {
776 ErrPrint("Failed to open a DB\n");
777 return SHORTCUT_ERROR_IO;
780 language = cur_locale();
782 ErrPrint("Locale is not valid\n");
783 return SHORTCUT_ERROR_FAULT;
787 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service WHERE appid = ?";
788 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
789 if (ret != SQLITE_OK) {
790 ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
792 return SHORTCUT_ERROR_IO;
795 ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT);
796 if (ret != SQLITE_OK) {
797 ErrPrint("bind text: %s\n", sqlite3_errmsg(s_info.handle));
798 sqlite3_finalize(stmt);
800 return SHORTCUT_ERROR_IO;
803 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service";
804 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
805 if (ret != SQLITE_OK) {
806 ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
808 return SHORTCUT_ERROR_IO;
813 while (SQLITE_ROW == sqlite3_step(stmt)) {
814 id = sqlite3_column_int(stmt, 0);
816 appid = (const char *)sqlite3_column_text(stmt, 1);
818 LOGE("Failed to get package name\n");
822 name = sqlite3_column_text(stmt, 2);
824 LOGE("Failed to get name\n");
828 extra_key = sqlite3_column_text(stmt, 3);
830 LOGE("Failed to get service\n");
834 extra_data = sqlite3_column_text(stmt, 4);
836 LOGE("Failed to get service\n");
840 icon = sqlite3_column_text(stmt, 5);
842 LOGE("Failed to get icon\n");
848 * Implement the "GET LOCALE" code
850 if (get_i18n_name(language, id, &i18n_name, &i18n_icon) < 0) {
851 /* Okay, we can't manage this. just use the fallback string */
855 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) {
865 sqlite3_clear_bindings(stmt);
866 sqlite3_finalize(stmt);