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>
37 /* For multi-user support */
38 #include <tzplatform_config.h>
41 #include "shortcut_internal.h"
50 const char *socket_file;
52 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);
61 .socket_file = "/tmp/.shortcut.service",
70 static inline int make_connection(void);
73 static struct packet *remove_shortcut_handler(pid_t pid, int handle, const struct packet *packet)
77 const char *content_info;
82 ErrPrint("Packet is NIL, maybe disconnected?\n");
86 if (packet_get(packet, "isss", &sender_pid, &appid, &name, &content_info) != 4) {
87 ErrPrint("Invalid apcket\n");
91 DbgPrint("appid[%s], name[%s], content_info[%s]\n", appid, name, content_info);
93 if (s_info.server_cb.request_cb) {
94 ret = s_info.server_cb.request_cb(appid, name, SHORTCUT_REMOVE, content_info, NULL, sender_pid, -1.0f, 0, s_info.server_cb.data);
96 ret = SHORTCUT_ERROR_UNSUPPORTED;
99 return packet_create_reply(packet, "i", ret);
104 static struct packet *remove_livebox_handler(pid_t pid, int handle, const struct packet *packet)
112 ErrPrint("PAcket is NIL, maybe disconnected?\n");
116 if (packet_get(packet, "iss", &sender_pid, &appid, &name) != 3) {
117 ErrPrint("Invalid packet\n");
121 DbgPrint("appid[%s], name[%s]\n", appid, name);
123 if (s_info.server_cb.request_cb) {
124 ret = s_info.server_cb.request_cb(appid, name, LIVEBOX_REMOVE, NULL, NULL, sender_pid, -1.0f, 0, s_info.server_cb.data);
126 ret = SHORTCUT_ERROR_UNSUPPORTED;
129 return packet_create_reply(packet, "i", ret);
134 static struct packet *add_shortcut_handler(pid_t pid, int handle, const struct packet *packet)
149 if (packet_get(packet, "ississi", &sender_pid, &appid, &name, &type, &content, &icon, &allow_duplicate) != 7) {
150 ErrPrint("Invalid packet\n");
154 DbgPrint("appid[%s], name[%s], type[0x%x], content[%s], icon[%s] allow_duplicate[%d]\n", appid, name, type, content, icon, allow_duplicate);
156 if (s_info.server_cb.request_cb) {
157 ret = s_info.server_cb.request_cb(appid, name, type, content, icon, sender_pid, -1.0f, allow_duplicate, s_info.server_cb.data);
159 ret = SHORTCUT_ERROR_UNSUPPORTED;
162 return packet_create_reply(packet, "i", ret);
167 static struct packet *add_livebox_handler(pid_t pid, int handle, const struct packet *packet)
183 if (packet_get(packet, "ississdi", &sender_pid, &appid, &name, &type, &content, &icon, &period, &allow_duplicate) != 8) {
184 ErrPrint("Invalid packet\n");
188 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);
190 if (s_info.server_cb.request_cb) {
191 ret = s_info.server_cb.request_cb(appid, name, type, content, icon, sender_pid, period, allow_duplicate, s_info.server_cb.data);
196 return packet_create_reply(packet, "i", ret);
201 static void master_started_cb(keynode_t *node, void *user_data)
205 if (vconf_get_bool(VCONFKEY_MASTER_STARTED, &state) < 0) {
206 ErrPrint("Unable to get \"%s\"\n", VCONFKEY_MASTER_STARTED);
209 if (state == 1 && make_connection() == SHORTCUT_SUCCESS) {
211 ret = vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb);
212 DbgPrint("Ignore VCONF [%d]\n", ret);
218 static gboolean timeout_cb(void *data)
222 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
224 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
226 DbgPrint("vconf is registered\n");
229 master_started_cb(NULL, NULL);
237 static int disconnected_cb(int handle, void *data)
239 if (s_info.client_fd == handle) {
240 s_info.client_fd = SHORTCUT_ERROR_INVALID;
244 if (s_info.server_fd == handle) {
245 if (!s_info.timer_id) {
246 s_info.server_fd = SHORTCUT_ERROR_INVALID;
247 s_info.timer_id = g_timeout_add(1000, timeout_cb, NULL);
248 if (!s_info.timer_id) {
249 ErrPrint("Unable to add timer\n");
260 static inline int make_connection(void)
263 struct packet *packet;
264 static struct method service_table[] = {
266 .cmd = "add_shortcut",
267 .handler = add_shortcut_handler,
270 .cmd = "add_livebox",
271 .handler = add_livebox_handler,
274 .cmd = "rm_shortcut",
275 .handler = remove_shortcut_handler,
279 .handler = remove_livebox_handler,
287 if (s_info.initialized == 0) {
288 s_info.initialized = 1;
289 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
292 s_info.server_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
293 if (s_info.server_fd < 0) {
294 ErrPrint("Failed to make a connection to the master\n");
295 return SHORTCUT_ERROR_COMM;
298 packet = packet_create_noack("service_register", "");
300 ErrPrint("Failed to build a packet\n");
301 return SHORTCUT_ERROR_FAULT;
304 ret = com_core_packet_send_only(s_info.server_fd, packet);
305 DbgPrint("Service register sent: %d\n", ret);
306 packet_destroy(packet);
308 com_core_packet_client_fini(s_info.server_fd);
309 s_info.server_fd = -1;
310 ret = SHORTCUT_ERROR_COMM;
312 ret = SHORTCUT_SUCCESS;
315 DbgPrint("Server FD: %d\n", s_info.server_fd);
321 EAPI int shortcut_set_request_cb(request_cb_t request_cb, void *data)
323 s_info.server_cb.request_cb = request_cb;
324 s_info.server_cb.data = data;
326 if (s_info.server_fd < 0) {
329 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
331 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
333 DbgPrint("vconf is registered\n");
336 master_started_cb(NULL, NULL);
339 return SHORTCUT_SUCCESS;
344 struct result_cb_item {
345 result_cb_t result_cb;
351 static int shortcut_send_cb(pid_t pid, int handle, const struct packet *packet, void *data)
353 struct result_cb_item *item = data;
357 ErrPrint("Packet is not valid\n");
358 ret = SHORTCUT_ERROR_FAULT;
359 } else if (packet_get(packet, "i", &ret) != 1) {
360 ErrPrint("Packet is not valid\n");
361 ret = SHORTCUT_ERROR_INVALID;
364 if (item->result_cb) {
365 ret = item->result_cb(ret, pid, item->data);
367 ret = SHORTCUT_SUCCESS;
375 EAPI int add_to_home_remove_shortcut(const char *appid, const char *name, const char *content_info, result_cb_t result_cb, void *data)
377 struct packet *packet;
378 struct result_cb_item *item;
381 if (!appid || !name) {
382 ErrPrint("Invalid argument\n");
383 return SHORTCUT_ERROR_INVALID;
386 if (!s_info.initialized) {
387 s_info.initialized = 1;
388 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
391 if (s_info.client_fd < 0) {
392 static struct method service_table[] = {
399 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
400 if (s_info.client_fd < 0) {
401 ErrPrint("Failed to make connection\n");
402 return SHORTCUT_ERROR_COMM;
406 item = malloc(sizeof(*item));
408 ErrPrint("Heap: %s\n", strerror(errno));
409 return SHORTCUT_ERROR_MEMORY;
412 item->result_cb = result_cb;
415 packet = packet_create("rm_shortcut", "isss", getpid(), appid, name, content_info);
417 ErrPrint("Failed to build a packet\n");
419 return SHORTCUT_ERROR_FAULT;
422 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
424 packet_destroy(packet);
426 com_core_packet_client_fini(s_info.client_fd);
427 s_info.client_fd = SHORTCUT_ERROR_INVALID;
428 return SHORTCUT_ERROR_COMM;
431 return SHORTCUT_SUCCESS;
436 EAPI int add_to_home_remove_livebox(const char *appid, const char *name, result_cb_t result_cb, void *data)
438 struct packet *packet;
439 struct result_cb_item *item;
442 if (!appid || !name) {
443 ErrPrint("Invalid argument\n");
444 return SHORTCUT_ERROR_INVALID;
447 if (!s_info.initialized) {
448 s_info.initialized = 1;
449 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
452 if (s_info.client_fd < 0) {
453 static struct method service_table[] = {
461 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
462 if (s_info.client_fd < 0) {
463 ErrPrint("Failed to make connection\n");
464 return SHORTCUT_ERROR_COMM;
468 item = malloc(sizeof(*item));
470 ErrPrint("Heap: %s\n", strerror(errno));
471 return SHORTCUT_ERROR_MEMORY;
474 item->result_cb = result_cb;
477 packet = packet_create("rm_livebox", "iss", getpid(), appid, name);
479 ErrPrint("Failed to build a packet\n");
481 return SHORTCUT_ERROR_FAULT;
484 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
486 packet_destroy(packet);
488 com_core_packet_client_fini(s_info.client_fd);
489 s_info.client_fd = SHORTCUT_ERROR_INVALID;
490 return SHORTCUT_ERROR_COMM;
493 return SHORTCUT_SUCCESS;
498 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)
500 struct packet *packet;
501 struct result_cb_item *item;
504 if (ADD_TO_HOME_IS_LIVEBOX(type)) {
505 ErrPrint("Invalid type used for adding a shortcut\n");
508 if (!s_info.initialized) {
509 s_info.initialized = 1;
510 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
513 if (s_info.client_fd < 0) {
514 static struct method service_table[] = {
521 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
522 if (s_info.client_fd < 0) {
523 ErrPrint("Failed to make connection\n");
524 return SHORTCUT_ERROR_COMM;
528 item = malloc(sizeof(*item));
530 ErrPrint("Heap: %s\n", strerror(errno));
531 return SHORTCUT_ERROR_MEMORY;
534 item->result_cb = result_cb;
553 packet = packet_create("add_shortcut", "ississi", getpid(), appid, name, type, content, icon, allow_duplicate);
555 ErrPrint("Failed to build a packet\n");
557 return SHORTCUT_ERROR_FAULT;
560 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
562 packet_destroy(packet);
564 com_core_packet_client_fini(s_info.client_fd);
565 s_info.client_fd = SHORTCUT_ERROR_INVALID;
566 return SHORTCUT_ERROR_COMM;
569 return SHORTCUT_SUCCESS;
574 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)
576 struct packet *packet;
577 struct result_cb_item *item;
580 if (!ADD_TO_HOME_IS_LIVEBOX(type)) {
581 ErrPrint("Invalid type is used for adding a livebox\n");
584 if (!s_info.initialized) {
585 s_info.initialized = 1;
586 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
589 if (s_info.client_fd < 0) {
590 static struct method service_table[] = {
597 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
598 if (s_info.client_fd < 0) {
599 return SHORTCUT_ERROR_COMM;
603 item = malloc(sizeof(*item));
605 ErrPrint("Heap: %s\n", strerror(errno));
606 return SHORTCUT_ERROR_MEMORY;
609 item->result_cb = result_cb;
612 packet = packet_create("add_livebox", "ississdi", getpid(), appid, name, type, content, icon, period, allow_duplicate);
614 ErrPrint("Failed to build a packet\n");
616 return SHORTCUT_ERROR_FAULT;
619 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
621 packet_destroy(packet);
623 com_core_packet_client_fini(s_info.client_fd);
624 s_info.client_fd = SHORTCUT_ERROR_INVALID;
625 return SHORTCUT_ERROR_COMM;
628 return SHORTCUT_SUCCESS;
632 static inline int open_db(void)
636 s_info.dbfile = tzplatform_mkpath(TZ_SYS_DB, ".shortcut_service.db");
637 ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
638 if (ret != SQLITE_OK) {
639 DbgPrint("Failed to open a %s\n", s_info.dbfile);
640 return SHORTCUT_ERROR_IO;
643 return SHORTCUT_SUCCESS;
649 * \note this function will returns allocated(heap) string
651 static inline int get_i18n_name(const char *lang, int id, char **name, char **icon)
654 static const char *query = "SELECT name, icon FROM shortcut_name WHERE id = ? AND lang = ? COLLATE NOCASE";
655 const unsigned char *_name;
656 const unsigned char *_icon;
660 status = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
661 if (status != SQLITE_OK) {
662 ErrPrint("Failed to prepare stmt: %s\n", sqlite3_errmsg(s_info.handle));
666 status = sqlite3_bind_int(stmt, 1, id);
667 if (status != SQLITE_OK) {
668 ErrPrint("Failed to bind id: %s\n", sqlite3_errmsg(s_info.handle));
673 status = sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT);
674 if (status != SQLITE_OK) {
675 ErrPrint("Failed to bind lang: %s\n", sqlite3_errmsg(s_info.handle));
680 DbgPrint("id: %d, lang: %s\n", id, lang);
681 if (SQLITE_ROW != sqlite3_step(stmt)) {
682 ErrPrint("Failed to do step: %s\n", sqlite3_errmsg(s_info.handle));
687 _name = sqlite3_column_text(stmt, 0);
689 if (_name && strlen((const char *)_name)) {
690 *name = strdup((const char *)_name);
692 ErrPrint("strdup: %s\n", strerror(errno));
701 _icon = sqlite3_column_text(stmt, 1);
703 if (_icon && strlen((const char *)_icon)) {
704 *icon = strdup((const char *)_icon);
706 ErrPrint("strdup: %s\n", strerror(errno));
720 sqlite3_clear_bindings(stmt);
721 sqlite3_finalize(stmt);
727 static inline char *cur_locale(void)
730 language = vconf_get_str(VCONFKEY_LANGSET);
748 language = strdup("en-us");
750 ErrPrint("Heap: %s\n", strerror(errno));
762 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)
766 const unsigned char *name;
767 char *i18n_name = NULL;
768 char *i18n_icon = NULL;
769 const unsigned char *extra_data;
770 const unsigned char *extra_key;
771 const unsigned char *icon;
777 if (!s_info.db_opened) {
778 s_info.db_opened = (open_db() == 0);
781 if (!s_info.db_opened) {
782 ErrPrint("Failed to open a DB\n");
783 return SHORTCUT_ERROR_IO;
786 language = cur_locale();
788 ErrPrint("Locale is not valid\n");
789 return SHORTCUT_ERROR_FAULT;
793 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service WHERE appid = ?";
794 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
795 if (ret != SQLITE_OK) {
796 ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
798 return SHORTCUT_ERROR_IO;
801 ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT);
802 if (ret != SQLITE_OK) {
803 ErrPrint("bind text: %s\n", sqlite3_errmsg(s_info.handle));
804 sqlite3_finalize(stmt);
806 return SHORTCUT_ERROR_IO;
809 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service";
810 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
811 if (ret != SQLITE_OK) {
812 ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
814 return SHORTCUT_ERROR_IO;
819 while (SQLITE_ROW == sqlite3_step(stmt)) {
820 id = sqlite3_column_int(stmt, 0);
822 appid = (const char *)sqlite3_column_text(stmt, 1);
824 LOGE("Failed to get package name\n");
828 name = sqlite3_column_text(stmt, 2);
830 LOGE("Failed to get name\n");
834 extra_key = sqlite3_column_text(stmt, 3);
836 LOGE("Failed to get service\n");
840 extra_data = sqlite3_column_text(stmt, 4);
842 LOGE("Failed to get service\n");
846 icon = sqlite3_column_text(stmt, 5);
848 LOGE("Failed to get icon\n");
854 * Implement the "GET LOCALE" code
856 if (get_i18n_name(language, id, &i18n_name, &i18n_icon) < 0) {
857 /* Okay, we can't manage this. just use the fallback string */
861 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) {
871 sqlite3_clear_bindings(stmt);
872 sqlite3_finalize(stmt);