2 * Copyright (c) 2011 - 2015 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>
32 #include <vconf-keys.h>
36 #include <com-core_packet.h>
39 #include "shortcut_private.h"
40 #include "shortcut_manager.h"
42 #define SHORTCUT_PKGNAME_LEN 512
44 #define SHORTCUT_IS_WIDGET_SIZE(size) (!!((size) & WIDGET_SIZE_DEFAULT))
45 #define SHORTCUT_IS_EASY_MODE_WIDGET_SIZE(size) (!!((size) & WIDGET_SIZE_EASY_DEFAULT))
49 static inline int make_connection(void);
56 const char *socket_file;
58 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);
67 .socket_file = "/tmp/.shortcut.service",
75 static struct packet *add_shortcut_handler(pid_t pid, int handle, const struct packet *packet)
83 int ret = SHORTCUT_ERROR_NONE;
89 if (packet_get(packet, "ississi", &sender_pid, &appid, &name, &type, &content, &icon, &allow_duplicate) != 7) {
90 ErrPrint("Invalid packet\n");
94 DbgPrint("appid[%s], name[%s], type[0x%x], content[%s], icon[%s] allow_duplicate[%d]\n", appid, name, type, content, icon, allow_duplicate);
96 if (s_info.server_cb.request_cb)
97 ret = s_info.server_cb.request_cb(appid, name, type, content, icon, sender_pid, -1.0f, allow_duplicate, s_info.server_cb.data);
99 ret = SHORTCUT_ERROR_NOT_SUPPORTED;
101 if (ret != SHORTCUT_ERROR_NONE)
102 ErrPrint("ret [%d]\n", ret);
104 return packet_create_reply(packet, "i", ret);
109 static struct packet *add_shortcut_widget_handler(pid_t pid, int handle, const struct packet *packet)
111 const char *widget_id;
118 int ret = SHORTCUT_ERROR_NONE;
124 if (packet_get(packet, "ississdi", &sender_pid, &widget_id, &name, &type, &content, &icon, &period, &allow_duplicate) != 8) {
125 ErrPrint("Invalid packet\n");
129 DbgPrint("widget_id[%s], name[%s], type[0x%x], content[%s], icon[%s], period[%lf], allow_duplicate[%d]\n", widget_id, name, type, content, icon, period, allow_duplicate);
131 if (s_info.server_cb.request_cb)
132 ret = s_info.server_cb.request_cb(widget_id, name, type, content, icon, sender_pid, period, allow_duplicate, s_info.server_cb.data);
136 if (ret != SHORTCUT_ERROR_NONE)
137 ErrPrint("ret [%d]\n", ret);
139 return packet_create_reply(packet, "i", ret);
142 int shortcut_is_master_ready(void)
144 int ret = -1, is_master_started = 0;
146 ret = vconf_get_bool(VCONFKEY_MASTER_STARTED, &is_master_started);
147 if (ret == 0 && is_master_started == 1) {
148 ErrPrint("the master has been started");
150 is_master_started = 0;
151 ErrPrint("the master has been stopped");
154 return is_master_started;
157 static void master_started_cb(keynode_t *node, void *user_data)
161 if (vconf_get_bool(VCONFKEY_MASTER_STARTED, &state) < 0)
162 ErrPrint("Unable to get \"%s\"\n", VCONFKEY_MASTER_STARTED);
164 if (state == 1 && make_connection() == SHORTCUT_ERROR_NONE)
165 (void)vconf_ignore_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb);
168 static gboolean timeout_cb(void *data)
172 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
174 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
176 DbgPrint("vconf is registered\n");
178 master_started_cb(NULL, NULL);
186 static int disconnected_cb(int handle, void *data)
188 if (s_info.client_fd == handle) {
189 s_info.client_fd = SHORTCUT_ERROR_INVALID_PARAMETER;
193 if (s_info.server_fd == handle) {
194 if (!s_info.timer_id) {
195 s_info.server_fd = SHORTCUT_ERROR_INVALID_PARAMETER;
196 s_info.timer_id = g_timeout_add(1000, timeout_cb, NULL);
197 if (!s_info.timer_id)
198 ErrPrint("Unable to add timer\n");
206 static inline int make_connection(void)
209 struct packet *packet;
210 static struct method service_table[] = {
212 .cmd = "add_shortcut",
213 .handler = add_shortcut_handler,
216 .cmd = "add_shortcut_widget",
217 .handler = add_shortcut_widget_handler,
221 if (s_info.initialized == 0) {
222 s_info.initialized = 1;
223 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
226 s_info.server_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
227 if (s_info.server_fd < 0) {
228 ErrPrint("Failed to make a connection to the master\n");
229 return SHORTCUT_ERROR_COMM;
232 packet = packet_create_noack("service_register", "");
234 ErrPrint("Failed to build a packet\n");
235 return SHORTCUT_ERROR_FAULT;
238 ret = com_core_packet_send_only(s_info.server_fd, packet);
239 DbgPrint("Service register sent: %d\n", ret);
240 packet_destroy(packet);
242 com_core_packet_client_fini(s_info.server_fd);
243 s_info.server_fd = -1;
244 ret = SHORTCUT_ERROR_COMM;
246 ret = SHORTCUT_ERROR_NONE;
249 DbgPrint("Server FD: %d\n", s_info.server_fd);
255 static char *_shortcut_get_pkgname_by_pid(void)
257 char pkgname[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
258 int pid = 0, ret = 0;
264 ret = aul_app_get_pkgname_bypid(pid, pkgname, sizeof(pkgname));
266 char buf[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
268 snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
270 fd = open(buf, O_RDONLY);
274 ret = read(fd, pkgname, sizeof(pkgname) - 1);
283 * "ret" is not able to be larger than "sizeof(pkgname) - 1",
284 * if the system is not going wrong.
287 if (strlen(pkgname) <= 0)
291 dup_pkgname = strdup(pkgname);
293 ErrPrint("Heap: %d\n", errno);
300 EAPI int shortcut_set_request_cb(shortcut_request_cb request_cb, void *data)
302 if (request_cb == NULL)
303 return SHORTCUT_ERROR_INVALID_PARAMETER;
305 s_info.server_cb.request_cb = request_cb;
306 s_info.server_cb.data = data;
308 if (s_info.server_fd < 0) {
311 ret = vconf_notify_key_changed(VCONFKEY_MASTER_STARTED, master_started_cb, NULL);
313 ErrPrint("Failed to add vconf for service state [%d]\n", ret);
314 return SHORTCUT_ERROR_COMM;
316 DbgPrint("vconf is registered\n");
319 master_started_cb(NULL, NULL);
322 return SHORTCUT_ERROR_NONE;
326 struct result_cb_item {
327 result_internal_cb_t result_internal_cb;
328 result_cb_t result_cb;
332 static int shortcut_send_cb(pid_t pid, int handle, const struct packet *packet, void *data)
334 struct result_cb_item *item = data;
338 ErrPrint("Packet is not valid\n");
339 ret = SHORTCUT_ERROR_FAULT;
340 } else if (packet_get(packet, "i", &ret) != 1) {
341 ErrPrint("Packet is not valid\n");
342 ret = SHORTCUT_ERROR_INVALID_PARAMETER;
345 if (ret != SHORTCUT_ERROR_NONE) {
346 DbgPrint("Packet reply [%d]\n", ret);
347 if (ret == SHORTCUT_ERROR_PERMISSION_DENIED)
348 ret = SHORTCUT_ERROR_NONE;
351 if (item->result_internal_cb)
352 ret = item->result_internal_cb(ret, pid, item->data);
353 else if (item->result_cb)
354 ret = item->result_cb(ret, item->data);
356 ret = SHORTCUT_ERROR_NONE;
363 EAPI int add_to_home_shortcut(const char *appid, const char *name, int type, const char *content, const char *icon, int allow_duplicate, result_internal_cb_t result_cb, void *data)
366 return SHORTCUT_ERROR_NONE;
369 EAPI int add_to_home_dynamicbox(const char *appid, const char *name, int type, const char *content, const char *icon, double period, int allow_duplicate, result_internal_cb_t result_cb, void *data)
372 return SHORTCUT_ERROR_NONE;
377 EAPI int shortcut_add_to_home(const char *name, shortcut_type type, const char *uri, const char *icon, int allow_duplicate, result_cb_t result_cb, void *data)
379 struct packet *packet;
380 struct result_cb_item *item;
383 static struct method service_table[] = {
390 if (ADD_TO_HOME_IS_DYNAMICBOX(type)) {
391 ErrPrint("Invalid type used for adding a shortcut\n");
392 return SHORTCUT_ERROR_INVALID_PARAMETER;
395 appid = _shortcut_get_pkgname_by_pid();
397 if (!s_info.initialized) {
398 s_info.initialized = 1;
399 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
402 if (s_info.client_fd < 0) {
403 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
404 if (s_info.client_fd < 0) {
408 if (shortcut_is_master_ready() == 1)
409 return SHORTCUT_ERROR_PERMISSION_DENIED;
411 return SHORTCUT_ERROR_COMM;
415 item = malloc(sizeof(*item));
420 ErrPrint("Heap: %d\n", errno);
421 return SHORTCUT_ERROR_OUT_OF_MEMORY;
424 item->result_cb = result_cb;
425 item->result_internal_cb = NULL;
438 packet = packet_create("add_shortcut", "ississi", getpid(), appid, name, type, uri, icon, allow_duplicate);
440 ErrPrint("Failed to build a packet\n");
447 return SHORTCUT_ERROR_FAULT;
450 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
451 packet_destroy(packet);
456 com_core_packet_client_fini(s_info.client_fd);
457 s_info.client_fd = SHORTCUT_ERROR_INVALID_PARAMETER;
458 return SHORTCUT_ERROR_COMM;
461 return SHORTCUT_ERROR_NONE;
465 EAPI int shortcut_add_to_home_widget(const char *name, shortcut_widget_size_e size, const char *widget_id, const char *icon, double period, int allow_duplicate, result_cb_t result_cb, void *data)
467 struct packet *packet;
468 struct result_cb_item *item;
471 int err = SHORTCUT_ERROR_NONE;
472 static struct method service_table[] = {
480 ErrPrint("AppID is null\n");
481 err = SHORTCUT_ERROR_INVALID_PARAMETER;
485 if (!SHORTCUT_IS_WIDGET_SIZE(size)) {
486 ErrPrint("Invalid type used for adding a widget\n");
487 err = SHORTCUT_ERROR_INVALID_PARAMETER;
491 appid = _shortcut_get_pkgname_by_pid();
493 if (!s_info.initialized) {
494 s_info.initialized = 1;
495 com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL);
498 if (s_info.client_fd < 0) {
499 s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table);
500 if (s_info.client_fd < 0) {
501 err = SHORTCUT_ERROR_COMM;
506 item = malloc(sizeof(*item));
508 ErrPrint("Heap: %d\n", errno);
509 err = SHORTCUT_ERROR_OUT_OF_MEMORY;
513 item->result_internal_cb = NULL;
514 item->result_cb = result_cb;
517 packet = packet_create("add_shortcut_widget", "ississdi", getpid(), widget_id, name, size, NULL, icon, period, allow_duplicate);
519 ErrPrint("Failed to build a packet\n");
521 err = SHORTCUT_ERROR_FAULT;
525 ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item);
527 packet_destroy(packet);
529 com_core_packet_client_fini(s_info.client_fd);
530 s_info.client_fd = SHORTCUT_ERROR_INVALID_PARAMETER;
531 err = SHORTCUT_ERROR_COMM;
541 static inline int open_db(void)
545 ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD);
546 if (ret != SQLITE_OK) {
547 DbgPrint("Failed to open a %s\n", s_info.dbfile);
548 return SHORTCUT_ERROR_IO_ERROR;
551 return SHORTCUT_ERROR_NONE;
555 * \note this function will returns allocated(heap) string
557 static inline int get_i18n_name(const char *lang, int id, char **name, char **icon)
560 static const char *query = "SELECT name, icon FROM shortcut_name WHERE id = ? AND lang = ? COLLATE NOCASE";
561 const unsigned char *_name;
562 const unsigned char *_icon;
566 status = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
567 if (status != SQLITE_OK) {
568 ErrPrint("Failed to prepare stmt: %s\n", sqlite3_errmsg(s_info.handle));
572 status = sqlite3_bind_int(stmt, 1, id);
573 if (status != SQLITE_OK) {
574 ErrPrint("Failed to bind id: %s\n", sqlite3_errmsg(s_info.handle));
579 status = sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT);
580 if (status != SQLITE_OK) {
581 ErrPrint("Failed to bind lang: %s\n", sqlite3_errmsg(s_info.handle));
586 DbgPrint("id: %d, lang: %s\n", id, lang);
587 if (SQLITE_ROW != sqlite3_step(stmt)) {
588 ErrPrint("Failed to do step: %s\n", sqlite3_errmsg(s_info.handle));
593 _name = sqlite3_column_text(stmt, 0);
595 if (_name && strlen((const char *)_name)) {
596 *name = strdup((const char *)_name);
598 ErrPrint("strdup: %d\n", errno);
607 _icon = sqlite3_column_text(stmt, 1);
609 if (_icon && strlen((const char *)_icon)) {
610 *icon = strdup((const char *)_icon);
612 ErrPrint("strdup: %d\n", errno);
626 sqlite3_clear_bindings(stmt);
627 sqlite3_finalize(stmt);
631 static inline char *cur_locale(void)
636 language = vconf_get_str(VCONFKEY_LANGSET);
651 language = strdup("en-us");
653 ErrPrint("Heap: %d\n", errno);
659 EAPI int shortcut_get_list(const char *package_name, shortcut_list_cb list_cb, void *data)
663 const unsigned char *name;
664 char *i18n_name = NULL;
665 char *i18n_icon = NULL;
666 const unsigned char *extra_data;
667 const unsigned char *extra_key;
668 const unsigned char *icon;
675 return SHORTCUT_ERROR_INVALID_PARAMETER;
677 if (!s_info.db_opened)
678 s_info.db_opened = (open_db() == 0);
680 if (!s_info.db_opened) {
681 ErrPrint("Failed to open a DB\n");
682 return SHORTCUT_ERROR_IO_ERROR;
685 language = cur_locale();
687 ErrPrint("Locale is not valid\n");
688 return SHORTCUT_ERROR_FAULT;
692 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service WHERE appid = ?";
693 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
694 if (ret != SQLITE_OK) {
695 ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
697 return SHORTCUT_ERROR_IO_ERROR;
700 ret = sqlite3_bind_text(stmt, 1, package_name, -1, SQLITE_TRANSIENT);
701 if (ret != SQLITE_OK) {
702 ErrPrint("bind text: %s\n", sqlite3_errmsg(s_info.handle));
703 sqlite3_finalize(stmt);
705 return SHORTCUT_ERROR_IO_ERROR;
708 query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service";
709 ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL);
710 if (ret != SQLITE_OK) {
711 ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle));
713 return SHORTCUT_ERROR_IO_ERROR;
718 while (SQLITE_ROW == sqlite3_step(stmt)) {
719 id = sqlite3_column_int(stmt, 0);
721 package_name = (const char *)sqlite3_column_text(stmt, 1);
723 LOGE("Failed to get package name\n");
727 name = sqlite3_column_text(stmt, 2);
729 LOGE("Failed to get name\n");
733 extra_key = sqlite3_column_text(stmt, 3);
735 LOGE("Failed to get service\n");
739 extra_data = sqlite3_column_text(stmt, 4);
741 LOGE("Failed to get service\n");
745 icon = sqlite3_column_text(stmt, 5);
747 LOGE("Failed to get icon\n");
753 * Implement the "GET LOCALE" code
755 /* if (get_i18n_name(language, id, &i18n_name, &i18n_icon) < 0) { */
756 /* Okay, we can't manage this. just use the fallback string */
758 get_i18n_name(language, id, &i18n_name, &i18n_icon);
761 if (list_cb(package_name, (i18n_icon != NULL ? i18n_icon : (char *)icon), (i18n_name != NULL ? i18n_name : (char *)name), (char *)extra_key, (char *)extra_data, data) < 0) {
774 sqlite3_clear_bindings(stmt);
775 sqlite3_finalize(stmt);