diff options
Diffstat (limited to 'notification/src')
-rw-r--r-- | notification/src/notification.c | 2035 | ||||
-rw-r--r-- | notification/src/notification_db.c | 229 | ||||
-rw-r--r-- | notification/src/notification_db_query.h | 359 | ||||
-rw-r--r-- | notification/src/notification_error.c | 60 | ||||
-rw-r--r-- | notification/src/notification_group.c | 181 | ||||
-rw-r--r-- | notification/src/notification_init.c | 84 | ||||
-rw-r--r-- | notification/src/notification_internal.c | 2133 | ||||
-rw-r--r-- | notification/src/notification_ipc.c | 2726 | ||||
-rw-r--r-- | notification/src/notification_ipc_socket.c | 173 | ||||
-rw-r--r-- | notification/src/notification_list.c | 376 | ||||
-rw-r--r-- | notification/src/notification_noti.c | 2299 | ||||
-rw-r--r-- | notification/src/notification_ongoing.c | 273 | ||||
-rw-r--r-- | notification/src/notification_setting.c | 1125 | ||||
-rw-r--r-- | notification/src/notification_setting_service.c | 931 | ||||
-rw-r--r-- | notification/src/notification_shared_file.c | 1185 | ||||
-rw-r--r-- | notification/src/notification_status.c | 197 | ||||
-rw-r--r-- | notification/src/notification_viewer.c | 113 |
17 files changed, 14479 insertions, 0 deletions
diff --git a/notification/src/notification.c b/notification/src/notification.c new file mode 100644 index 0000000..698b150 --- /dev/null +++ b/notification/src/notification.c @@ -0,0 +1,2035 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <libintl.h> +#include <dbus/dbus.h> + +#include <app_control.h> +#include <app_control_internal.h> +#include <package_manager.h> +#include <aul.h> +#include <tizen.h> +#include <pkgmgr-info.h> +#include <pkgmgrinfo_type.h> + +#include <notification.h> +#include <notification_list.h> +#include <notification_debug.h> +#include <notification_private.h> +#include <notification_noti.h> +#include <notification_ongoing.h> +#include <notification_group.h> +#include <notification_ipc.h> +#include <notification_internal.h> +#include <notification_shared_file.h> + +static void (*posted_toast_message_cb)(void *data); + +#define NOTI_TEXT_RESULT_LEN 4096 +#define REGULAR_UID_MIN 5000 + +char *notification_get_app_id_by_pid(int pid) +{ +#define NOTI_APP_ID_LEN 512 + char app_id[NOTI_APP_ID_LEN + 1] = { 0, }; + int ret = AUL_R_OK; + int fd; + char *dup_app_id; + char buf[NOTI_APP_ID_LEN + 1] = { 0, }; + + ret = aul_app_get_appid_bypid(pid, app_id, sizeof(app_id)); + if (ret != AUL_R_OK) { + + snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid); + + fd = open(buf, O_RDONLY); + if (fd < 0) + return NULL; + + ret = read(fd, app_id, sizeof(app_id) - 1); + close(fd); + + if (ret <= 0) + return NULL; + + app_id[ret] = '\0'; + /*! + * \NOTE + * "ret" is not able to be larger than "sizeof(app_id) - 1", + * if the system is not going wrong. + */ + } else { + if (strlen(app_id) <= 0) + return NULL; + } + + dup_app_id = strdup(app_id); + if (!dup_app_id) + ERR("Failed to strdup, errno[%d]", errno); + + return dup_app_id; +} + +EXPORT_API int notification_set_image(notification_h noti, + notification_image_type_e type, + const char *image_path) +{ + bundle *b = NULL; + bundle *priv_b = NULL; + char buf_key[32] = { 0, }; + char *ret_val = NULL; + char *priv_path = NULL; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_IMAGE_TYPE_NONE + || type > NOTIFICATION_IMAGE_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->b_image_path) { + b = noti->b_image_path; + snprintf(buf_key, sizeof(buf_key), "%d", type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + if (image_path != NULL) + bundle_add_str(b, buf_key, image_path); + } else { + if (image_path == NULL) + return NOTIFICATION_ERROR_NONE; + + b = bundle_create(); + snprintf(buf_key, sizeof(buf_key), "%d", type); + bundle_add_str(b, buf_key, image_path); + noti->b_image_path = b; + } + + priv_path = notification_check_file_path_is_private(noti->pkg_id, image_path); + if (noti->b_priv_image_path) { + priv_b = noti->b_priv_image_path; + + ret_val = NULL; + bundle_get_str(priv_b, buf_key, &ret_val); + if (ret_val) + bundle_del(b, buf_key); + + if (priv_path != NULL) + bundle_add_str(priv_b, buf_key, priv_path); + } else if (priv_path != NULL) { + priv_b = bundle_create(); + bundle_add_str(priv_b, buf_key, priv_path); + noti->b_priv_image_path = priv_b; + } + + if (priv_path) + free(priv_path); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_image(notification_h noti, + notification_image_type_e type, + char **image_path) +{ + bundle *b = NULL; + char buf_key[32] = { 0, }; + char *ret_val = NULL; + + if (noti == NULL || image_path == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_IMAGE_TYPE_NONE + || type > NOTIFICATION_IMAGE_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->b_image_path) { + b = noti->b_image_path; + + snprintf(buf_key, sizeof(buf_key), "%d", type); + + bundle_get_str(b, buf_key, &ret_val); + + *image_path = ret_val; + } else { + /* If image path bundle does not exist, image path is NULL */ + *image_path = NULL; + } + + /* If image path is NULL and type is ICON, icon path set from AIL */ + /* order : user icon -> launch_app_id icon -> caller_app_id icon -> service app icon */ + if (*image_path == NULL && type == NOTIFICATION_IMAGE_TYPE_ICON) { + if (noti->app_icon_path != NULL) + *image_path = noti->app_icon_path; + else + *image_path = NULL; + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_time(notification_h noti, time_t input_time) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (input_time == 0) + noti->time = time(NULL); + else + noti->time = input_time; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_time(notification_h noti, time_t *ret_time) +{ + if (noti == NULL || ret_time == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *ret_time = noti->time; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_insert_time(notification_h noti, + time_t *ret_time) +{ + if (noti == NULL || ret_time == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *ret_time = noti->insert_time; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_text(notification_h noti, + notification_text_type_e type, const char *text, + const char *key, int args_type, ...) +{ + bundle *b = NULL; + char buf_key[32] = { 0, }; + char buf_val[NOTI_TEXT_RESULT_LEN] = { 0, }; + char *ret_val = NULL; + va_list var_args; + notification_variable_type_e var_type; + int num_args = 0; + int noti_err = NOTIFICATION_ERROR_NONE; + int var_value_int = 0; + double var_value_double = 0.0; + char *var_value_string = NULL; + notification_count_pos_type_e var_value_count = + NOTIFICATION_COUNT_POS_NONE; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_TEXT_TYPE_NONE + || type > NOTIFICATION_TEXT_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (text != NULL) { + if (noti->b_text != NULL) { + b = noti->b_text; + + snprintf(buf_key, sizeof(buf_key), "%d", type); + + bundle_get_str(b, buf_key, &ret_val); + + if (ret_val != NULL) + bundle_del(b, buf_key); + + snprintf(buf_val, sizeof(buf_val), "%s", text); + + bundle_add_str(b, buf_key, buf_val); + } else { + b = bundle_create(); + + snprintf(buf_key, sizeof(buf_key), "%d", type); + snprintf(buf_val, sizeof(buf_val), "%s", text); + + bundle_add_str(b, buf_key, buf_val); + + noti->b_text = b; + } + } else { + if (noti->b_text != NULL) { + b = noti->b_text; + + snprintf(buf_key, sizeof(buf_key), "%d", type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + } + } + + if (key != NULL) { + if (noti->b_key != NULL) { + b = noti->b_key; + + snprintf(buf_key, sizeof(buf_key), "%d", type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + snprintf(buf_val, sizeof(buf_val), "%s", key); + + bundle_add_str(b, buf_key, buf_val); + } else { + b = bundle_create(); + + snprintf(buf_key, sizeof(buf_key), "%d", type); + + snprintf(buf_val, sizeof(buf_val), "%s", key); + + bundle_add_str(b, buf_key, buf_val); + + noti->b_key = b; + } + } else { + if (noti->b_key != NULL) { + b = noti->b_key; + + snprintf(buf_key, sizeof(buf_key), "%d", type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + } + } + + if (noti->b_format_args != NULL) + b = noti->b_format_args; + else + b = bundle_create(); + + va_start(var_args, args_type); + + var_type = args_type; + num_args = 0; + + while (var_type != NOTIFICATION_VARIABLE_TYPE_NONE) { + /* Type */ + snprintf(buf_key, sizeof(buf_key), "%dtype%d", type, num_args); + snprintf(buf_val, sizeof(buf_val), "%d", var_type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, buf_val); + + switch (var_type) { + case NOTIFICATION_VARIABLE_TYPE_INT: + var_value_int = va_arg(var_args, int); + + /* Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", type, + num_args); + snprintf(buf_val, sizeof(buf_val), "%d", var_value_int); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, buf_val); + break; + + case NOTIFICATION_VARIABLE_TYPE_DOUBLE: + var_value_double = va_arg(var_args, double); + + /* Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", type, + num_args); + snprintf(buf_val, sizeof(buf_val), "%.2f", + var_value_double); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, buf_val); + break; + + case NOTIFICATION_VARIABLE_TYPE_STRING: + var_value_string = va_arg(var_args, char *); + + /* Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", type, + num_args); + snprintf(buf_val, sizeof(buf_val), "%s", + var_value_string); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, buf_val); + break; + + case NOTIFICATION_VARIABLE_TYPE_COUNT: + var_value_count = + va_arg(var_args, notification_count_pos_type_e); + + /* Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", type, + num_args); + snprintf(buf_val, sizeof(buf_val), "%d", + var_value_count); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, buf_val); + break; + + default: + ERR("Invalid variable type. : %d", var_type); + noti_err = NOTIFICATION_ERROR_INVALID_PARAMETER; + break; + } + + num_args++; + var_type = va_arg(var_args, notification_variable_type_e); + } + va_end(var_args); + + if (noti_err == NOTIFICATION_ERROR_NONE) + noti->num_format_args = num_args; + else + noti->num_format_args = 0; + + snprintf(buf_key, sizeof(buf_key), "num%d", type); + snprintf(buf_val, sizeof(buf_val), "%d", noti->num_format_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, buf_val); + + noti->b_format_args = b; + + return noti_err; +} + +EXPORT_API int notification_get_text(notification_h noti, + notification_text_type_e type, + char **text) +{ + char result_str[NOTI_TEXT_RESULT_LEN] = { 0, }; + char buf_str[NOTI_TEXT_RESULT_LEN] = { 0, }; + char buf_key[32] = { 0, }; + char *ret_val = NULL; + char *get_str = NULL; + char *temp_str = NULL; + char *translated_str = NULL; + bundle *b = NULL; + int num_args = 0; + int src_len = 0; + int max_len = 0; + int ret_variable_int = 0; + double ret_variable_double = 0.0; + notification_text_type_e text_type = NOTIFICATION_TEXT_TYPE_NONE; + notification_variable_type_e ret_var_type = 0; + + if (noti == NULL || text == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_TEXT_TYPE_NONE + || type > NOTIFICATION_TEXT_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + text_type = type; + + if (noti->b_key != NULL) { + b = noti->b_key; + + /* Get text domain and dir */ + /* _notification_get_text_domain(noti); */ + + snprintf(buf_key, sizeof(buf_key), "%d", type); + bundle_get_str(b, buf_key, &ret_val); + + if (noti->is_translation == false) { + if (ret_val != NULL && noti->domain != NULL + && noti->dir != NULL) { + /* Get application string */ + bindtextdomain(noti->domain, noti->dir); + + get_str = dgettext(noti->domain, ret_val); + if (get_str == ret_val) /* not found */ + get_str = NULL; + } else if (ret_val != NULL) { + /* Get system string */ + get_str = dgettext("sys_string", ret_val); + if (get_str == ret_val) /* not found */ + get_str = NULL; + } else { + get_str = NULL; + } + } + } + + if (get_str == NULL && noti->b_text != NULL) { + b = noti->b_text; + snprintf(buf_key, sizeof(buf_key), "%d", type); + bundle_get_str(b, buf_key, &get_str); + } + + if (get_str == NULL && ret_val != NULL) + get_str = ret_val; /* fallback for printing anything */ + + if (get_str == NULL) { + *text = NULL; + return NOTIFICATION_ERROR_NONE; + } + + /* Get number format args */ + noti->num_format_args = 0; + + b = noti->b_format_args; + if (b != NULL) { + snprintf(buf_key, sizeof(buf_key), "num%d", text_type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + noti->num_format_args = atoi(ret_val); + } + + if (noti->num_format_args == 0 || noti->is_translation == true) { + *text = (char *)get_str; + return NOTIFICATION_ERROR_NONE; + } + + /* Check first variable is count, LEFT pos */ + snprintf(buf_key, sizeof(buf_key), "%dtype%d", text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_var_type = atoi(ret_val); + + if (ret_var_type == NOTIFICATION_VARIABLE_TYPE_COUNT) { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", + text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_variable_int = atoi(ret_val); + + if (ret_variable_int == NOTIFICATION_COUNT_POS_LEFT) { + notification_get_count(noti->type, + noti->caller_app_id, + noti->group_id, + noti->priv_id, + &ret_variable_int); + snprintf(buf_str, sizeof(buf_str), + "%d ", ret_variable_int); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + num_args++; + } + } + + /* Check variable IN pos */ + for (temp_str = (char *)get_str; *temp_str != '\0'; temp_str++) { + if (*temp_str != '%') { + if (NOTI_TEXT_RESULT_LEN - 1 > strlen(result_str)) { + strncat(result_str, temp_str, 1); + } else { + WARN("The buffer is full"); + break; + } + } else { + if (*(temp_str + 1) == '%') { + if (NOTI_TEXT_RESULT_LEN - 1 > strlen(result_str)) { + strncat(result_str, temp_str, 1); + } else { + WARN("The buffer is full"); + break; + } + } else if (*(temp_str + 1) == 'd') { + /* Get var Type */ + ret_variable_int = 0; + + snprintf(buf_key, sizeof(buf_key), "%dtype%d", + text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_var_type = atoi(ret_val); + + if (ret_var_type == + NOTIFICATION_VARIABLE_TYPE_COUNT) { + /* Get notification count */ + notification_get_count(noti->type, + noti->caller_app_id, + noti->group_id, + noti->priv_id, + &ret_variable_int); + } else { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), + "%dvalue%d", text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_variable_int = atoi(ret_val); + } + + snprintf(buf_str, sizeof(buf_str), "%d", + ret_variable_int); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + + temp_str++; + num_args++; + } else if (*(temp_str + 1) == 's') { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", + text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + + if (ret_val != NULL && noti->domain != NULL + && noti->dir != NULL) { + /* Get application string */ + bindtextdomain(noti->domain, noti->dir); + translated_str = + dgettext(noti->domain, ret_val); + INFO("translated_str[%s]", translated_str); + } else if (ret_val != NULL) { + /* Get system string */ + translated_str = + dgettext("sys_string", ret_val); + INFO("translated_str[%s]", translated_str); + } else { + translated_str = NULL; + } + + if (translated_str != NULL) { + strncpy(buf_str, translated_str, + sizeof(buf_str) - 1); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + } + + temp_str++; + num_args++; + } else if (*(temp_str + 1) == 'f') { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", + text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_variable_double = atof(ret_val); + + snprintf(buf_str, sizeof(buf_str), "%.2f", + ret_variable_double); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + + temp_str++; + num_args++; + } else if (*(temp_str + 1) >= '1' && *(temp_str + 1) <= '9') { + if (*(temp_str + 3) == 'd') { + /* Get var Type */ + ret_variable_int = 0; + + snprintf(buf_key, sizeof(buf_key), + "%dtype%d", text_type, + num_args + *(temp_str + 1) - 49); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_var_type = atoi(ret_val); + + if (ret_var_type == + NOTIFICATION_VARIABLE_TYPE_COUNT) { + /* Get notification count */ + notification_get_count(noti->type, + noti->caller_app_id, + noti->group_id, + noti->priv_id, + &ret_variable_int); + } else { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), + "%dvalue%d", text_type, + num_args + *(temp_str + 1) - 49); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_variable_int = atoi(ret_val); + } + + snprintf(buf_str, sizeof(buf_str), "%d", + ret_variable_int); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + + temp_str += 3; + } else if (*(temp_str + 3) == 's') { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), + "%dvalue%d", text_type, + num_args + *(temp_str + 1) - 49); + + bundle_get_str(b, buf_key, &ret_val); + + snprintf(buf_str, sizeof(buf_str), "%s", + ret_val); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + + temp_str += 3; + } else if (*(temp_str + 3) == 'f') { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), + "%dvalue%d", text_type, + num_args + *(temp_str + 1) - 49); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_variable_double = atof(ret_val); + + snprintf(buf_str, sizeof(buf_str), + "%.2f", ret_variable_double); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + + temp_str += 3; + } else { + if (NOTI_TEXT_RESULT_LEN - 1 > strlen(result_str)) { + strncat(result_str, temp_str, 1); + } else { + WARN("The buffer is full"); + break; + } + } + } else { + if (NOTI_TEXT_RESULT_LEN - 1 > strlen(result_str)) { + strncat(result_str, temp_str, 1); + } else { + WARN("The buffer is full"); + break; + } + } + } + } + + /* Check last variable is count, LEFT pos */ + if (num_args < noti->num_format_args) { + snprintf(buf_key, sizeof(buf_key), "%dtype%d", + text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_var_type = atoi(ret_val); + + if (ret_var_type == NOTIFICATION_VARIABLE_TYPE_COUNT) { + /* Get var Value */ + snprintf(buf_key, sizeof(buf_key), "%dvalue%d", + text_type, num_args); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + ret_variable_int = atoi(ret_val); + + if (ret_variable_int == NOTIFICATION_COUNT_POS_RIGHT) { + notification_get_count(noti->type, + noti->caller_app_id, + noti->group_id, + noti->priv_id, + &ret_variable_int); + snprintf(buf_str, sizeof(buf_str), " %d", + ret_variable_int); + + src_len = strlen(result_str); + max_len = NOTI_TEXT_RESULT_LEN - src_len - 1; + strncat(result_str, buf_str, max_len); + + num_args++; + } + } + } + + switch (text_type) { + case NOTIFICATION_TEXT_TYPE_TITLE: + case NOTIFICATION_TEXT_TYPE_GROUP_TITLE: + if (noti->temp_title != NULL) + free(noti->temp_title); + + noti->temp_title = strdup(result_str); + + *text = noti->temp_title; + break; + case NOTIFICATION_TEXT_TYPE_CONTENT: + case NOTIFICATION_TEXT_TYPE_CONTENT_FOR_DISPLAY_OPTION_IS_OFF: + case NOTIFICATION_TEXT_TYPE_GROUP_CONTENT: + case NOTIFICATION_TEXT_TYPE_GROUP_CONTENT_FOR_DISPLAY_OPTION_IS_OFF: + if (noti->temp_content != + NULL) + free(noti->temp_content); + + noti->temp_content = strdup(result_str); + + *text = noti->temp_content; + break; + default: + break; + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_text_domain(notification_h noti, + const char *domain, + const char *dir) +{ + if (noti == NULL || domain == NULL || dir == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->domain) + free(noti->domain); + + noti->domain = strdup(domain); + + if (noti->dir) + free(noti->dir); + + noti->dir = strdup(dir); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_text_domain(notification_h noti, + char **domain, + char **dir) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (domain != NULL && noti->domain != NULL) + *domain = noti->domain; + + if (dir != NULL && noti->dir != NULL) + *dir = noti->dir; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_time_to_text(notification_h noti, notification_text_type_e type, + time_t time) +{ + int ret = NOTIFICATION_ERROR_NONE; + char buf[256] = { 0, }; + char buf_tag[512] = { 0, }; + + if (noti == NULL || time <= 0) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_TEXT_TYPE_NONE + || type > NOTIFICATION_TEXT_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + snprintf(buf, sizeof(buf), "%lu", time); + ret = notification_noti_set_tag(TAG_TIME, buf, buf_tag, sizeof(buf_tag)); + + if (ret != NOTIFICATION_ERROR_NONE) + return ret; + + return notification_set_text(noti, type, buf_tag, NULL, NOTIFICATION_VARIABLE_TYPE_NONE); +} + +EXPORT_API int notification_get_time_from_text(notification_h noti, notification_text_type_e type, + time_t *time) +{ + int ret = NOTIFICATION_ERROR_NONE; + char *ret_text = NULL; + char *tag_value; + + if (noti == NULL || time == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_TEXT_TYPE_NONE + || type > NOTIFICATION_TEXT_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_get_text(noti, type, &ret_text); + if (ret != NOTIFICATION_ERROR_NONE || ret_text == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (notification_noti_get_tag_type(ret_text) == TAG_TYPE_INVALID) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + tag_value = notification_noti_strip_tag(ret_text); + if (tag_value == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *time = atol(tag_value); + free(tag_value); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_sound(notification_h noti, + notification_sound_type_e type, + const char *path) +{ + char *priv_path = NULL; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type < NOTIFICATION_SOUND_TYPE_NONE + || type > NOTIFICATION_SOUND_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->sound_type = type; + + /* Save sound path if user data type */ + if (type == NOTIFICATION_SOUND_TYPE_USER_DATA && path != NULL) { + if (noti->sound_path != NULL) + free(noti->sound_path); + noti->sound_path = strdup(path); + + if (noti->priv_sound_path != NULL) + free(noti->priv_sound_path); + + priv_path = notification_check_file_path_is_private(noti->pkg_id, path); + if (priv_path) + noti->priv_sound_path = priv_path; + } else { + if (noti->sound_path != NULL) { + free(noti->sound_path); + noti->sound_path = NULL; + } + + if (noti->priv_sound_path != NULL) { + free(noti->priv_sound_path); + noti->priv_sound_path = NULL; + } + + if (type == NOTIFICATION_SOUND_TYPE_USER_DATA) { + noti->sound_type = NOTIFICATION_SOUND_TYPE_DEFAULT; + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_sound(notification_h noti, + notification_sound_type_e *type, + const char **path) +{ + if (noti == NULL || type == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *type = noti->sound_type; + + /* Set sound path if user data type */ + if (noti->sound_type == NOTIFICATION_SOUND_TYPE_USER_DATA + && path != NULL) + *path = noti->sound_path; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_vibration(notification_h noti, + notification_vibration_type_e type, + const char *path) +{ + char *priv_path = NULL; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type < NOTIFICATION_VIBRATION_TYPE_NONE + || type > NOTIFICATION_VIBRATION_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->vibration_type = type; + + /* Save sound path if user data type */ + if (type == NOTIFICATION_VIBRATION_TYPE_USER_DATA && path != NULL) { + if (noti->vibration_path != NULL) { + free(noti->vibration_path); + noti->vibration_path = NULL; + } + noti->vibration_path = strdup(path); + + if (noti->priv_vibration_path != NULL) { + free(noti->priv_vibration_path); + noti->priv_vibration_path = NULL; + } + priv_path = notification_check_file_path_is_private(noti->pkg_id, path); + if (priv_path) + noti->priv_vibration_path = priv_path; + } else { + if (noti->vibration_path != NULL) { + free(noti->vibration_path); + noti->vibration_path = NULL; + } + if (noti->priv_vibration_path != NULL) { + free(noti->priv_vibration_path); + noti->priv_vibration_path = NULL; + } + + if (type == NOTIFICATION_VIBRATION_TYPE_USER_DATA) { + noti->vibration_type = NOTIFICATION_VIBRATION_TYPE_DEFAULT; + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_vibration(notification_h noti, + notification_vibration_type_e *type, + const char **path) +{ + if (noti == NULL || type == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *type = noti->vibration_type; + /* Set sound path if user data type */ + if (noti->vibration_type == NOTIFICATION_VIBRATION_TYPE_USER_DATA + && path != NULL) + *path = noti->vibration_path; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_led(notification_h noti, + notification_led_op_e operation, + int led_argb) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (operation < NOTIFICATION_LED_OP_OFF + || operation > NOTIFICATION_LED_OP_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->led_operation = operation; + + /* Save led argb if operation is turning on LED with custom color */ + if (operation == NOTIFICATION_LED_OP_ON_CUSTOM_COLOR) + noti->led_argb = led_argb; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_led(notification_h noti, + notification_led_op_e *operation, + int *led_argb) +{ + if (noti == NULL || operation == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *operation = noti->led_operation; + + /* Save led argb if operation is turning on LED with custom color */ + if (noti->led_operation == NOTIFICATION_LED_OP_ON_CUSTOM_COLOR + && led_argb != NULL) + *led_argb = noti->led_argb; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_led_time_period(notification_h noti, + int on_ms, int off_ms) +{ + if (noti == NULL || on_ms < 0 || off_ms < 0) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->led_on_ms = on_ms; + noti->led_off_ms = off_ms; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_led_time_period(notification_h noti, + int *on_ms, int *off_ms) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (on_ms) + *(on_ms) = noti->led_on_ms; + if (off_ms) + *(off_ms) = noti->led_off_ms; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_launch_option(notification_h noti, + notification_launch_option_type type, void *option) +{ + int err = NOTIFICATION_ERROR_NONE; + int ret = 0; + bundle *b = NULL; + app_control_h app_control = option; + + if (noti == NULL || app_control == NULL || type != NOTIFICATION_LAUNCH_OPTION_APP_CONTROL) { + err = NOTIFICATION_ERROR_INVALID_PARAMETER; + goto out; + } + + ret = app_control_export_as_bundle(app_control, &b); + if (ret != APP_CONTROL_ERROR_NONE) { + ERR("Failed to convert appcontrol to bundle[%d]", ret); + err = NOTIFICATION_ERROR_INVALID_PARAMETER; + goto out; + } + + err = notification_set_execute_option(noti, NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, NULL, NULL, b); + +out: + if (b) + bundle_free(b); + + return err; +} + +EXPORT_API int notification_get_launch_option(notification_h noti, + notification_launch_option_type type, void *option) +{ + int ret = 0; + bundle *b = NULL; + app_control_h *app_control = (app_control_h *)option; + app_control_h app_control_new = NULL; + + if (noti == NULL || app_control == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type != NOTIFICATION_LAUNCH_OPTION_APP_CONTROL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_get_execute_option(noti, + NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, + NULL, + &b); + if (ret == NOTIFICATION_ERROR_NONE && b != NULL) { + ret = app_control_create(&app_control_new); + if (ret == APP_CONTROL_ERROR_NONE && app_control_new != NULL) { + ret = app_control_import_from_bundle(app_control_new, b); + if (ret == APP_CONTROL_ERROR_NONE) { + *app_control = app_control_new; + } else { + /* LCOV_EXCL_START */ + app_control_destroy(app_control_new); + ERR("Failed to import app control from bundle[%d]", ret); + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + } else { + /* LCOV_EXCL_START */ + ERR("Failed to create app control[%d]", ret); + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + } else { + /* LCOV_EXCL_START */ + ERR("Failed to get execute option[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_event_handler(notification_h noti, notification_event_type_e event_type, app_control_h event_handler) +{ + int err = NOTIFICATION_ERROR_NONE; + bundle *app_control_bundle = NULL; + + if (noti == NULL) { + err = NOTIFICATION_ERROR_INVALID_PARAMETER; + ERR("Invalid notification handle"); + goto out; + } + + if (event_type < NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_1 + || event_type > NOTIFICATION_EVENT_TYPE_MAX) { + ERR("Invalid event type"); + err = NOTIFICATION_ERROR_INVALID_PARAMETER; + goto out; + } + + err = app_control_export_as_bundle(event_handler, &app_control_bundle); + if (err != APP_CONTROL_ERROR_NONE) { + ERR("Failed to export app_control to bundle[%d]", err); + goto out; + } + + if (noti->b_event_handler[event_type] != NULL) + bundle_free(noti->b_event_handler[event_type]); + + noti->b_event_handler[event_type] = app_control_bundle; + +out: + return err; +} + +EXPORT_API int notification_get_event_handler(notification_h noti, notification_event_type_e event_type, app_control_h *event_handler) +{ + int err = NOTIFICATION_ERROR_NONE; + bundle *b = NULL; + app_control_h app_control_new = NULL; + + if (noti == NULL || event_handler == NULL) { + err = NOTIFICATION_ERROR_INVALID_PARAMETER; + ERR("Invalid handle"); + goto out; + } + + if (event_type < NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_1 + || event_type > NOTIFICATION_EVENT_TYPE_MAX) { + /* LCOV_EXCL_START */ + ERR("Invalid event type"); + err = NOTIFICATION_ERROR_INVALID_PARAMETER; + goto out; + /* LCOV_EXCL_STOP */ + } + + b = noti->b_event_handler[event_type]; + if (b == NULL) { + /* LCOV_EXCL_START */ + ERR("No event handler"); + err = NOTIFICATION_ERROR_NOT_EXIST_ID; + goto out; + /* LCOV_EXCL_STOP */ + } + + err = app_control_create(&app_control_new); + if (err != APP_CONTROL_ERROR_NONE || app_control_new == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to create app_control[%d]", err); + err = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + err = app_control_import_from_bundle(app_control_new, b); + if (err == APP_CONTROL_ERROR_NONE) { + *event_handler = app_control_new; + } else { + /* LCOV_EXCL_START */ + app_control_destroy(app_control_new); + app_control_new = NULL; + ERR("Failed to import app control from bundle[%d]", err); + err = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + +out: + if (event_handler) + *event_handler = app_control_new; + + return err; +} + +EXPORT_API int notification_set_property(notification_h noti, + int flags) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->flags_for_property = flags; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_property(notification_h noti, + int *flags) +{ + if (noti == NULL || flags == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *flags = noti->flags_for_property; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_display_applist(notification_h noti, + int applist) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (applist == 0xffffffff) /* 0xffffffff means old NOTIFICATION_DISPLAY_APP_ALL */ + applist = NOTIFICATION_DISPLAY_APP_ALL; + + noti->display_applist = applist; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_display_applist(notification_h noti, + int *applist) +{ + if (noti == NULL || applist == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *applist = noti->display_applist; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_size(notification_h noti, + double size) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->progress_size = size; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_size(notification_h noti, + double *size) +{ + if (noti == NULL || size == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *size = noti->progress_size; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_progress(notification_h noti, + double percentage) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->progress_percentage = percentage; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_progress(notification_h noti, + double *percentage) +{ + if (noti == NULL || percentage == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *percentage = noti->progress_percentage; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_pkgname(notification_h noti, + char **pkgname) +{ + if (noti == NULL || pkgname == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->caller_app_id) + *pkgname = noti->caller_app_id; + else + *pkgname = NULL; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_layout(notification_h noti, + notification_ly_type_e layout) +{ + if (noti == NULL || (layout < NOTIFICATION_LY_NONE || layout > NOTIFICATION_LY_MAX)) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->layout = layout; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_layout(notification_h noti, + notification_ly_type_e *layout) +{ + if (noti == NULL || layout == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *layout = noti->layout; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_type(notification_h noti, + notification_type_e *type) +{ + if (noti == NULL || type == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *type = noti->type; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_post(notification_h noti) +{ + return notification_post_for_uid(noti, getuid()); +} + +EXPORT_API int notification_update(notification_h noti) +{ + return notification_update_for_uid(noti, getuid()); +} + +EXPORT_API int notification_delete_all(notification_type_e type) +{ + return notification_delete_all_for_uid(type, getuid()); +} + +EXPORT_API int notification_delete(notification_h noti) +{ + return notification_delete_for_uid(noti, getuid()); +} + +static int _notification_get_domain_name(const char *app_id, char **name) +{ + char *name_token = NULL; + + if (app_id == NULL) + return -1; + + /* com.vendor.name -> name */ + name_token = strrchr(app_id, '.'); + if (name_token == NULL) + return -1; + + name_token++; + + *name = strdup(name_token); + if (*name == NULL) + return -1; + + return 0; +} + +static notification_h _notification_create(notification_type_e type) +{ +#define NOTI_PKG_ID_LEN 512 + notification_h noti = NULL; + package_info_h package_info = NULL; + pkgmgrinfo_appinfo_h appinfo = NULL; + char *domain_name = NULL; + char *app_root_path = NULL; + char *label = NULL; + char locale_directory[PATH_MAX] = { 0, }; /* PATH_MAX 4096 */ + char pkg_id[NOTI_PKG_ID_LEN + 1] = { 0, }; + int err = 0; + + if (type <= NOTIFICATION_TYPE_NONE || type > NOTIFICATION_TYPE_MAX) { + ERR("Invalid notification type[%d]", type); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + noti = (notification_h)calloc(1, sizeof(struct _notification)); + if (noti == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + return NULL; + /* LCOV_EXCL_STOP */ + } + + noti->type = type; + + if (type == NOTIFICATION_TYPE_NOTI) + noti->layout = NOTIFICATION_LY_NOTI_EVENT_SINGLE; + else if (type == NOTIFICATION_TYPE_ONGOING) + noti->layout = NOTIFICATION_LY_ONGOING_PROGRESS; + + noti->group_id = NOTIFICATION_GROUP_ID_NONE; + noti->sound_type = NOTIFICATION_SOUND_TYPE_NONE; + noti->vibration_type = NOTIFICATION_VIBRATION_TYPE_NONE; + noti->led_operation = NOTIFICATION_LED_OP_OFF; + noti->display_applist = NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY | + NOTIFICATION_DISPLAY_APP_LOCK | + NOTIFICATION_DISPLAY_APP_TICKER | + NOTIFICATION_DISPLAY_APP_INDICATOR; + noti->auto_remove = true; + noti->caller_app_id = notification_get_app_id_by_pid(getpid()); + if (noti->caller_app_id == NULL) { + ERR("Failed to get caller_app_id"); + err = -1; + goto out; + } + + if (getuid() < REGULAR_UID_MIN) { + noti->pkg_id = strdup(noti->caller_app_id); + if (noti->pkg_id == NULL) + err = -1; + } else { + err = aul_app_get_pkgid_bypid(getpid(), pkg_id, sizeof(pkg_id)); + if (err != AUL_R_OK) + noti->pkg_id = strdup(noti->caller_app_id); + else + noti->pkg_id = strdup(pkg_id); + + if (noti->pkg_id == NULL) { + err = -1; + goto out; + } + + err = _notification_get_domain_name(pkg_id, &domain_name); + if (err != 0 || domain_name == NULL) { + WARN("Failed to get domain_name"); + err = 0; + /* In the case of the web app, + the domain can not be obtained. */ + goto out; + } + + noti->domain = strdup(domain_name); + + err = package_info_create(pkg_id, &package_info); + if (err != PACKAGE_MANAGER_ERROR_NONE || package_info == NULL) { + /* LCOV_EXCL_START */ + WARN("Failed to create package_info err[%d] pkg_id[%s]", + err, pkg_id); + goto out; + /* LCOV_EXCL_STOP */ + } + + err = package_info_get_root_path(package_info, &app_root_path); + if (err != PACKAGE_MANAGER_ERROR_NONE || app_root_path == NULL) { + /* LCOV_EXCL_START */ + WARN("Failed to get root path err[%d] path[%p]", + err, app_root_path); + goto out; + /* LCOV_EXCL_STOP */ + } + + snprintf(locale_directory, PATH_MAX, "%s/res/locale", app_root_path); + noti->dir = strdup(locale_directory); + + err = pkgmgrinfo_appinfo_get_usr_appinfo(noti->caller_app_id, + getuid(), &appinfo); + if (err != PMINFO_R_OK || appinfo == NULL) { + WARN("Failed to get appinfo err[%d] caller_app_id[%s]", + err, noti->caller_app_id); + err = 0; + goto out; + } + + err = pkgmgrinfo_appinfo_get_label(appinfo, &label); + if (err != PMINFO_R_OK || label == NULL) { + WARN("Failed to get app_label err[%d]", err); + err = 0; + goto out; + } + + noti->app_label = strdup(label); + } + +out: + if (domain_name) + free(domain_name); + + if (app_root_path) + free(app_root_path); + + if (package_info) + package_info_destroy(package_info); + + if (appinfo) + pkgmgrinfo_appinfo_destroy_appinfo(appinfo); + + if (err != 0) { + notification_free(noti); + noti = NULL; + set_last_result(NOTIFICATION_ERROR_IO_ERROR); + } else { + set_last_result(NOTIFICATION_ERROR_NONE); + } + + /*! + * \NOTE + * Other fields are already initialized with ZERO. + */ + + return noti; +} + +EXPORT_API notification_h notification_create(notification_type_e type) +{ + return _notification_create(type); +} + +EXPORT_API notification_h notification_load_by_tag(const char *tag) +{ + return notification_load_by_tag_for_uid(tag, getuid()); +} + +EXPORT_API int notification_clone(notification_h noti, notification_h *clone) +{ + int i = 0; + notification_h new_noti = NULL; + + if (noti == NULL || clone == NULL) { + ERR("Invalid handle"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + new_noti = (notification_h) calloc(1, sizeof(struct _notification)); + if (new_noti == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + new_noti->type = noti->type; + new_noti->layout = noti->layout; + new_noti->group_id = noti->group_id; + new_noti->internal_group_id = noti->internal_group_id; + new_noti->priv_id = noti->priv_id; + + if (noti->pkg_id != NULL) + new_noti->pkg_id = strdup(noti->pkg_id); + + if (noti->caller_app_id != NULL) + new_noti->caller_app_id = strdup(noti->caller_app_id); + + if (noti->launch_app_id != NULL) + new_noti->launch_app_id = strdup(noti->launch_app_id); + + if (noti->args != NULL) + new_noti->args = bundle_dup(noti->args); + + if (noti->group_args != NULL) + new_noti->group_args = bundle_dup(noti->group_args); + + if (noti->b_execute_option != NULL) + new_noti->b_execute_option = bundle_dup(noti->b_execute_option); + + if (noti->b_service_responding != NULL) + new_noti->b_service_responding = bundle_dup(noti->b_service_responding); + + if (noti->b_service_single_launch != NULL) + new_noti->b_service_single_launch = bundle_dup(noti->b_service_single_launch); + + if (noti->b_service_multi_launch != NULL) + new_noti->b_service_multi_launch = bundle_dup(noti->b_service_multi_launch); + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) { + if (noti->b_event_handler[i] != NULL) + new_noti->b_event_handler[i] = bundle_dup(noti->b_event_handler[i]); + } + + if (noti->domain != NULL) + new_noti->domain = strdup(noti->domain); + + if (noti->dir != NULL) + new_noti->dir = strdup(noti->dir); + + if (noti->b_text != NULL) + new_noti->b_text = bundle_dup(noti->b_text); + + if (noti->b_key != NULL) + new_noti->b_key = bundle_dup(noti->b_key); + + if (noti->b_format_args != NULL) + new_noti->b_format_args = bundle_dup(noti->b_format_args); + + new_noti->num_format_args = noti->num_format_args; + + if (noti->b_image_path != NULL) + new_noti->b_image_path = bundle_dup(noti->b_image_path); + + if (noti->b_priv_image_path != NULL) + new_noti->b_priv_image_path = bundle_dup(noti->b_priv_image_path); + + new_noti->sound_type = noti->sound_type; + + if (noti->sound_path != NULL) + new_noti->sound_path = strdup(noti->sound_path); + + if (noti->priv_sound_path != NULL) + new_noti->priv_sound_path = strdup(noti->priv_sound_path); + + new_noti->vibration_type = noti->vibration_type; + + if (noti->vibration_path != NULL) + new_noti->vibration_path = strdup(noti->vibration_path); + + if (noti->priv_vibration_path != NULL) + new_noti->priv_vibration_path = strdup(noti->priv_vibration_path); + + new_noti->led_operation = noti->led_operation; + new_noti->led_argb = noti->led_argb; + new_noti->led_on_ms = noti->led_on_ms; + new_noti->led_off_ms = noti->led_off_ms; + new_noti->time = noti->time; + new_noti->insert_time = noti->insert_time; + new_noti->flags_for_property = noti->flags_for_property; + new_noti->display_applist = noti->display_applist; + new_noti->progress_size = noti->progress_size; + new_noti->progress_percentage = noti->progress_percentage; + + if (noti->tag != NULL) + new_noti->tag = strdup(noti->tag); + + new_noti->ongoing_flag = noti->ongoing_flag; + new_noti->ongoing_value_type = noti->ongoing_value_type; + new_noti->ongoing_current = noti->ongoing_current; + new_noti->ongoing_duration = noti->ongoing_duration; + new_noti->auto_remove = noti->auto_remove; + new_noti->default_button_index = noti->default_button_index; + new_noti->hide_timeout = noti->hide_timeout; + new_noti->delete_timeout = noti->delete_timeout; + new_noti->text_input_max_length = noti->text_input_max_length; + new_noti->event_flag = noti->event_flag; + new_noti->is_translation = noti->is_translation; + new_noti->extension_image_size = noti->extension_image_size; + + if (noti->app_label != NULL) + new_noti->app_label = strdup(noti->app_label); + + new_noti->uid = noti->uid; + + *clone = new_noti; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_free(notification_h noti) +{ + int i = 0; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->pkg_id) + free(noti->pkg_id); + + if (noti->caller_app_id) + free(noti->caller_app_id); + + if (noti->launch_app_id) + free(noti->launch_app_id); + + if (noti->args) + bundle_free(noti->args); + + if (noti->group_args) + bundle_free(noti->group_args); + + if (noti->b_execute_option) + bundle_free(noti->b_execute_option); + + if (noti->b_service_responding) + bundle_free(noti->b_service_responding); + + if (noti->b_service_single_launch) + bundle_free(noti->b_service_single_launch); + + if (noti->b_service_multi_launch) + bundle_free(noti->b_service_multi_launch); + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) { + if (noti->b_event_handler[i] != NULL) + bundle_free(noti->b_event_handler[i]); + } + + if (noti->b_image_path) + bundle_free(noti->b_image_path); + + if (noti->b_priv_image_path) + bundle_free(noti->b_priv_image_path); + + if (noti->sound_path) + free(noti->sound_path); + + if (noti->priv_sound_path) + free(noti->priv_sound_path); + + if (noti->vibration_path) + free(noti->vibration_path); + + if (noti->priv_vibration_path) + free(noti->priv_vibration_path); + + if (noti->domain) + free(noti->domain); + + if (noti->dir) + free(noti->dir); + + if (noti->b_text) + bundle_free(noti->b_text); + + if (noti->b_key) + bundle_free(noti->b_key); + + if (noti->b_format_args) + bundle_free(noti->b_format_args); + + if (noti->app_icon_path) + free(noti->app_icon_path); + + if (noti->app_label) + free(noti->app_label); + + if (noti->temp_title) + free(noti->temp_title); + + if (noti->temp_content) + free(noti->temp_content); + + if (noti->tag) + free(noti->tag); + + free(noti); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_tag(notification_h noti, const char *tag) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (tag != NULL) { + if (noti->tag != NULL) + free(noti->tag); + + noti->tag = strdup(tag); + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_tag(notification_h noti, const char **tag) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *tag = noti->tag; + return NOTIFICATION_ERROR_NONE; +} + +/* LCOV_EXCL_START */ +void notification_call_posted_toast_cb(const char *message) +{ + if (posted_toast_message_cb != NULL) + posted_toast_message_cb((void *)message); +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_set_ongoing_flag(notification_h noti, bool ongoing_flag) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->ongoing_flag = ongoing_flag; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_ongoing_flag(notification_h noti, bool *ongoing_flag) +{ + if (noti == NULL || ongoing_flag == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *ongoing_flag = noti->ongoing_flag; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_add_button(notification_h noti, notification_button_index_e button_index) +{ + if (noti == NULL || + !((button_index >= NOTIFICATION_BUTTON_1 && button_index <= NOTIFICATION_BUTTON_6) || + (button_index >= NOTIFICATION_BUTTON_7 && button_index <= NOTIFICATION_BUTTON_10))) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_remove_button(notification_h noti, notification_button_index_e button_index) +{ + if (noti == NULL || + !((button_index >= NOTIFICATION_BUTTON_1 && button_index <= NOTIFICATION_BUTTON_6) || + (button_index >= NOTIFICATION_BUTTON_7 && button_index <= NOTIFICATION_BUTTON_10))) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->b_event_handler[button_index - 1]) { + bundle_free(noti->b_event_handler[button_index - 1]); + noti->b_event_handler[button_index - 1] = NULL; + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_auto_remove(notification_h noti, bool auto_remove) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->auto_remove = auto_remove; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_auto_remove(notification_h noti, bool *auto_remove) +{ + if (noti == NULL || auto_remove == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *auto_remove = noti->auto_remove; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_save_as_template(notification_h noti, const char *template_name) +{ + if (noti == NULL || template_name == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return notification_ipc_request_save_as_template(noti, template_name); +} + +EXPORT_API notification_h notification_create_from_template(const char *template_name) +{ + int ret = 0; + notification_h noti = NULL; + + if (template_name == NULL) { + ERR("Invalid parameter"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + noti = (notification_h)calloc(1, sizeof(struct _notification)); + if (noti == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + return NULL; + /* LCOV_EXCL_STOP */ + } + + ret = notification_ipc_request_create_from_template(noti, template_name); + + set_last_result(ret); + if (ret != NOTIFICATION_ERROR_NONE) { + notification_free(noti); + return NULL; + } + + return noti; +} + +EXPORT_API int notification_get_noti_block_state(notification_block_state_e *state) +{ + int ret; + char *app_id; + int do_not_disturb; + int do_not_disturb_except; + int allow_to_notify; + + if (state == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + app_id = notification_get_app_id_by_pid(getpid()); + + ret = notification_ipc_get_noti_block_state(app_id, &do_not_disturb, &do_not_disturb_except, &allow_to_notify, getuid()); + + if (ret != NOTIFICATION_ERROR_NONE) { + if (app_id) + free(app_id); + return ret; + } + + if (allow_to_notify) { + *state = NOTIFICATION_BLOCK_STATE_ALLOWED; + if (do_not_disturb && !do_not_disturb_except) + *state = NOTIFICATION_BLOCK_STATE_DO_NOT_DISTURB; + } else { + *state = NOTIFICATION_BLOCK_STATE_BLOCKED; + } + + if (app_id) + free(app_id); + + return ret; +} + +EXPORT_API int notification_set_text_input(notification_h noti, int text_input_max_length) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->text_input_max_length = text_input_max_length; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_extension_image_size(notification_h noti, int height) +{ + if (noti == NULL || height <= 0) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->extension_image_size = height; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_extension_image_size(notification_h noti, int *height) +{ + if (noti == NULL || height == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *height = noti->extension_image_size; + + return NOTIFICATION_ERROR_NONE; +} diff --git a/notification/src/notification_db.c b/notification/src/notification_db.c new file mode 100644 index 0000000..485a207 --- /dev/null +++ b/notification/src/notification_db.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include <sqlite3.h> +#include <tizen.h> + +#include <notification_error.h> +#include <notification_debug.h> +#include <notification_db.h> +#include "notification_db_query.h" + +static bool is_db_corrupted = false; + +/* LCOV_EXCL_START */ +static int __check_integrity_cb(void *pid, int argc, char **argv, char **notUsed) +{ + char *check_str = "ok"; + + if (strncmp(argv[0], check_str, strlen(check_str))) { + ERR("db integrity result : %s", argv[0]); + is_db_corrupted = true; + return -1; + } + + INFO("db integrity result : %s", argv[0]); + return 0; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static int __recover_corrupted_db(sqlite3 *db) +{ + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + char *errmsg = NULL; + + INFO("DB is corrupted, start to recover corrupted db"); + if (db) + sqlite3_close(db); + unlink(DBPATH); + + sql_ret = sqlite3_open_v2(DBPATH, &db, + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, + NULL); + if (sql_ret != SQLITE_OK) { + ERR("Failed to open db[%d]", sql_ret); + unlink(DBPATH); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + } + + sql_ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, NULL, NULL, &errmsg); + if (sql_ret != SQLITE_OK) { + ERR("Failed to exec query[%d][%s]", sql_ret, errmsg); + ret = NOTIFICATION_ERROR_FROM_DB; + } + +out: + if (errmsg) + sqlite3_free(errmsg); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_db_init(void) +{ + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + sqlite3 *db = NULL; + char *errmsg = NULL; + + sql_ret = sqlite3_open_v2(DBPATH, &db, + SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, NULL); + if (sql_ret != SQLITE_OK) { + ERR("Failed to open db[%d]", ret); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + } + + sql_ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, NULL, NULL, &errmsg); + if (sql_ret != SQLITE_OK) { + ERR("Failed to exec sqlite[%d][%s]", ret, errmsg); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + } + + sql_ret = sqlite3_exec(db, "PRAGMA integrity_check", + __check_integrity_cb, NULL, &errmsg); + if (sql_ret != SQLITE_OK || is_db_corrupted) { + ERR("Failed to exec query[%d][%s]", sql_ret, errmsg); + ret = NOTIFICATION_ERROR_FROM_DB; + } + +out: + if (sql_ret == SQLITE_CORRUPT || sql_ret == SQLITE_NOTADB || is_db_corrupted) + ret = __recover_corrupted_db(db); + if (errmsg) + sqlite3_free(errmsg); + if (db) + sqlite3_close(db); + + return ret; +} +/* LCOV_EXCL_STOP */ + +sqlite3 *notification_db_open() +{ + int ret = 0; + sqlite3 *db = 0; + + ret = access(DBPATH, R_OK | W_OK); + if (ret != 0) { + /* LCOV_EXCL_START */ + set_last_result(NOTIFICATION_ERROR_FROM_DB); + return NULL; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READWRITE, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + if (ret == SQLITE_PERM) + set_last_result(NOTIFICATION_ERROR_PERMISSION_DENIED); + else + set_last_result(NOTIFICATION_ERROR_FROM_DB); + + return NULL; + /* LCOV_EXCL_STOP */ + } + + return db; +} + +int notification_db_close(sqlite3 **db) +{ + int ret = 0; + + if (db == NULL || *db == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = sqlite3_close(*db); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to close db[%d]", ret); + return NOTIFICATION_ERROR_FROM_DB; + /* LCOV_EXCL_STOP */ + } + + *db = NULL; + + return NOTIFICATION_ERROR_NONE; +} + +int notification_db_exec(sqlite3 *db, const char *query, int *num_changes) +{ + int ret = NOTIFICATION_ERROR_NONE; + sqlite3_stmt *stmt = NULL; + + if (db == NULL || query == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Sqlite3 err[%d][%s]", ret, sqlite3_errmsg(db)); + return NOTIFICATION_ERROR_FROM_DB; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_OK || ret == SQLITE_DONE) { + if (num_changes != NULL) + *num_changes = sqlite3_changes(db); + + ret = NOTIFICATION_ERROR_NONE; + } else { + /* LCOV_EXCL_START */ + ERR("Sqlite err[%d][%s]", ret, sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + /* LCOV_EXCL_STOP */ + } + + sqlite3_finalize(stmt); + + return ret; +} + +char *notification_db_column_text(sqlite3_stmt *stmt, int col) +{ + const unsigned char *col_text = NULL; + + col_text = sqlite3_column_text(stmt, col); + if (col_text == NULL || col_text[0] == '\0') + return NULL; + + return strdup((char *)col_text); +} + +bundle *notification_db_column_bundle(sqlite3_stmt *stmt, int col) +{ + const unsigned char *col_bundle = NULL; + + col_bundle = sqlite3_column_text(stmt, col); + if (col_bundle == NULL || col_bundle[0] == '\0') + return NULL; + + return bundle_decode(col_bundle, strlen((char *)col_bundle)); +} + diff --git a/notification/src/notification_db_query.h b/notification/src/notification_db_query.h new file mode 100644 index 0000000..dd6a65a --- /dev/null +++ b/notification/src/notification_db_query.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define NOTIFICATION_DB_TABLE "noti_list" +#define NOTIFICATION_SETTING_DB_TABLE "notification_setting" +#define NOTIFICATION_SYSTEM_SETTING_DB_TABLE "notification_system_setting" +#define NOTIFICATION_DND_ALLOW_EXCEPTION "dnd_allow_exception" + +#define CREATE_NOTIFICATION_TABLE \ + "PRAGMA journal_mode = PERSIST;\n" \ + "PRAGMA synchronous = FULL;\n" \ + "CREATE TABLE IF NOT EXISTS noti_list (\n" \ + " type INTEGER NOT NULL,\n" \ + " layout INTEGER NOT NULL DEFAULT 0,\n" \ + " pkg_id TEXT NOT NULL,\n" \ + " caller_app_id TEXT NOT NULL,\n" \ + " launch_app_id TEXT,\n" \ + " app_label TEXT,\n" \ + " image_path TEXT,\n" \ + " priv_image_path TEXT,\n" \ + " group_id INTEGER DEFAULT 0,\n" \ + " internal_group_id INTEGER DEFAULT 0,\n" \ + " priv_id INTEGER PRIMARY KEY AUTOINCREMENT,\n" \ + " title_key TEXT,\n" \ + " b_text TEXT,\n" \ + " b_key TEXT,\n" \ + " tag TEXT,\n" \ + " b_format_args TEXT,\n" \ + " num_format_args INTEGER DEFAULT 0,\n" \ + " text_domain TEXT,\n" \ + " text_dir TEXT,\n" \ + " time INTEGER DEFAULT 0,\n" \ + " insert_time INTEGER DEFAULT 0,\n" \ + " args TEXT,\n" \ + " group_args TEXT,\n" \ + " b_execute_option TEXT,\n" \ + " b_service_responding TEXT,\n" \ + " b_service_single_launch TEXT,\n" \ + " b_service_multi_launch TEXT,\n" \ + " b_event_handler_click_on_button_1 TEXT,\n" \ + " b_event_handler_click_on_button_2 TEXT,\n" \ + " b_event_handler_click_on_button_3 TEXT,\n" \ + " b_event_handler_click_on_button_4 TEXT,\n" \ + " b_event_handler_click_on_button_5 TEXT,\n" \ + " b_event_handler_click_on_button_6 TEXT,\n" \ + " b_event_handler_click_on_icon TEXT,\n" \ + " b_event_handler_click_on_thumbnail TEXT,\n" \ + " b_event_handler_click_on_text_input_button TEXT,\n" \ + " b_event_handler_click_on_button_7 TEXT,\n" \ + " b_event_handler_click_on_button_8 TEXT,\n" \ + " b_event_handler_click_on_button_9 TEXT,\n" \ + " b_event_handler_click_on_button_10 TEXT,\n" \ + " sound_type INTEGER DEFAULT 0,\n" \ + " sound_path TEXT,\n" \ + " priv_sound_path TEXT,\n" \ + " vibration_type INTEGER DEFAULT 0,\n" \ + " vibration_path TEXT,\n" \ + " priv_vibration_path TEXT,\n" \ + " led_operation INTEGER DEFAULT 0,\n" \ + " led_argb INTEGER DEFAULT 0,\n" \ + " led_on_ms INTEGER DEFAULT -1,\n" \ + " led_off_ms INTEGER DEFAULT -1,\n" \ + " flags_for_property INTEGER DEFAULT 0,\n" \ + " flag_simmode INTEGER DEFAULT 0,\n" \ + " display_applist INTEGER,\n" \ + " progress_size DOUBLE DEFAULT 0,\n" \ + " progress_percentage DOUBLE DEFAULT 0,\n" \ + " ongoing_flag INTEGER DEFAULT 0,\n" \ + " ongoing_value_type INTEGER DEFAULT 0,\n" \ + " ongoing_current INTEGER DEFAULT 0,\n" \ + " ongoing_duration INTEGER DEFAULT 0,\n" \ + " auto_remove INTEGER DEFAULT 1,\n" \ + " default_button_index INTEGER DEFAULT 0,\n" \ + " hide_timeout INTEGER DEFAULT 0,\n" \ + " delete_timeout INTEGER DEFAULT 0,\n" \ + " text_input_max_length INTEGER DEFAULT 0,\n" \ + " event_flag INTEGER DEFAULT 0,\n" \ + " extension_image_size INTEGER DEFAULT 0,\n" \ + " uid INTEGER );\n" \ + "CREATE TABLE IF NOT EXISTS noti_group_data (\n" \ + " caller_app_id TEXT NOT NULL,\n" \ + " group_id INTEGER DEFAULT 0,\n" \ + " badge INTEGER DEFAULT 0,\n" \ + " title TEXT,\n" \ + " content TEXT,\n" \ + " loc_title TEXT,\n" \ + " loc_content TEXT,\n" \ + " count_display_title INTEGER,\n" \ + " count_display_content INTEGER,\n" \ + " rowid INTEGER PRIMARY KEY AUTOINCREMENT,\n" \ + " UNIQUE (caller_app_id, group_id));\n" \ + "CREATE TABLE IF NOT EXISTS ongoing_list (\n" \ + " caller_app_id TEXT NOT NULL,\n" \ + " launch_app_id TEXT,\n" \ + " icon_path TEXT,\n" \ + " group_id INTEGER DEFAULT 0,\n" \ + " internal_group_id INTEGER DEFAULT 0,\n" \ + " priv_id INTERGER NOT NULL,\n" \ + " title TEXT,\n" \ + " content TEXT,\n" \ + " default_content TEXT,\n" \ + " loc_title TEXT,\n" \ + " loc_content TEXT,\n" \ + " loc_default_content TEXT,\n" \ + " text_domain TEXT,\n" \ + " text_dir TEXT,\n" \ + " args TEXT,\n" \ + " group_args TEXT,\n" \ + " flag INTEGER DEFAULT 0,\n" \ + " progress_size DOUBLE DEFAULT 0,\n" \ + " progress_percentage DOUBLE DEFAULT 0,\n" \ + " rowid INTEGER PRIMARY KEY AUTOINCREMENT,\n" \ + " UNIQUE (caller_app_id, priv_id));\n" \ + "CREATE TABLE IF NOT EXISTS notification_setting (\n" \ + " uid INTEGER,\n" \ + " package_name TEXT NOT NULL,\n" \ + " app_id TEXT NOT NULL,\n" \ + " allow_to_notify INTEGER DEFAULT 1,\n" \ + " do_not_disturb_except INTEGER DEFAULT 0,\n" \ + " visibility_class INTEGER DEFAULT 0,\n" \ + " pop_up_notification INTEGER DEFAULT 1,\n" \ + " lock_screen_content_level INTEGER DEFAULT 0,\n" \ + " app_disabled INTEGER DEFAULT 0,\n" \ + " UNIQUE (uid, package_name, app_id));\n" \ + "CREATE TABLE IF NOT EXISTS notification_system_setting (\n" \ + " uid INTEGER,\n" \ + " do_not_disturb INTEGER DEFAULT 0,\n" \ + " visibility_class INTEGER DEFAULT 0,\n" \ + " dnd_schedule_enabled INTEGER DEFAULT 0,\n" \ + " dnd_schedule_day INTEGER DEFAULT 62,\n" \ + " dnd_start_hour INTEGER DEFAULT 22,\n" \ + " dnd_start_min INTEGER DEFAULT 0,\n" \ + " dnd_end_hour INTEGER DEFAULT 8,\n" \ + " dnd_end_min INTEGER DEFAULT 0,\n" \ + " lock_screen_content_level INTEGER DEFAULT 0,\n" \ + " UNIQUE (uid));\n"\ + "CREATE TABLE IF NOT EXISTS dnd_allow_exception (\n" \ + " uid INTEGER,\n" \ + " type INTEGER DEFAULT 0,\n" \ + " value INTEGER DEFAULT 0,\n" \ + " UNIQUE (uid, type));\n" \ + "CREATE TABLE IF NOT EXISTS noti_template (\n" \ + " type INTEGER NOT NULL,\n" \ + " layout INTEGER NOT NULL DEFAULT 0,\n" \ + " pkg_id TEXT NOT NULL,\n" \ + " caller_app_id TEXT NOT NULL,\n" \ + " launch_app_id TEXT,\n" \ + " app_label TEXT,\n" \ + " image_path TEXT,\n" \ + " priv_image_path TEXT,\n" \ + " group_id INTEGER DEFAULT 0,\n" \ + " internal_group_id INTEGER DEFAULT 0,\n" \ + " priv_id INTEGER PRIMARY KEY AUTOINCREMENT,\n" \ + " title_key TEXT,\n" \ + " b_text TEXT,\n" \ + " b_key TEXT,\n" \ + " tag TEXT,\n" \ + " b_format_args TEXT,\n" \ + " num_format_args INTEGER DEFAULT 0,\n" \ + " text_domain TEXT,\n" \ + " text_dir TEXT,\n" \ + " time INTEGER DEFAULT 0,\n" \ + " insert_time INTEGER DEFAULT 0,\n" \ + " args TEXT,\n" \ + " group_args TEXT,\n" \ + " b_execute_option TEXT,\n" \ + " b_service_responding TEXT,\n" \ + " b_service_single_launch TEXT,\n" \ + " b_service_multi_launch TEXT,\n" \ + " b_event_handler_click_on_button_1 TEXT,\n" \ + " b_event_handler_click_on_button_2 TEXT,\n" \ + " b_event_handler_click_on_button_3 TEXT,\n" \ + " b_event_handler_click_on_button_4 TEXT,\n" \ + " b_event_handler_click_on_button_5 TEXT,\n" \ + " b_event_handler_click_on_button_6 TEXT,\n" \ + " b_event_handler_click_on_icon TEXT,\n" \ + " b_event_handler_click_on_thumbnail TEXT,\n" \ + " b_event_handler_click_on_text_input_button TEXT,\n" \ + " b_event_handler_click_on_button_7 TEXT,\n" \ + " b_event_handler_click_on_button_8 TEXT,\n" \ + " b_event_handler_click_on_button_9 TEXT,\n" \ + " b_event_handler_click_on_button_10 TEXT,\n" \ + " sound_type INTEGER DEFAULT 0,\n" \ + " sound_path TEXT,\n" \ + " priv_sound_path TEXT,\n" \ + " vibration_type INTEGER DEFAULT 0,\n" \ + " vibration_path TEXT,\n" \ + " priv_vibration_path TEXT,\n" \ + " led_operation INTEGER DEFAULT 0,\n" \ + " led_argb INTEGER DEFAULT 0,\n" \ + " led_on_ms INTEGER DEFAULT -1,\n" \ + " led_off_ms INTEGER DEFAULT -1,\n" \ + " flags_for_property INTEGER DEFAULT 0,\n" \ + " flag_simmode INTEGER DEFAULT 0,\n" \ + " display_applist INTEGER,\n" \ + " progress_size DOUBLE DEFAULT 0,\n" \ + " progress_percentage DOUBLE DEFAULT 0,\n" \ + " ongoing_flag INTEGER DEFAULT 0,\n" \ + " ongoing_value_type INTEGER DEFAULT 0,\n" \ + " ongoing_current INTEGER DEFAULT 0,\n" \ + " ongoing_duration INTEGER DEFAULT 0,\n" \ + " auto_remove INTEGER DEFAULT 1,\n" \ + " default_button_index INTEGER DEFAULT 0,\n" \ + " hide_timeout INTEGER DEFAULT 0,\n" \ + " delete_timeout INTEGER DEFAULT 0,\n" \ + " text_input_max_length INTEGER DEFAULT 0,\n" \ + " event_flag INTEGER DEFAULT 0,\n" \ + " extension_image_size INTEGER DEFAULT 0,\n" \ + " uid INTEGER,\n" \ + " template_name TEXT,\n" \ + " UNIQUE (caller_app_id, template_name));\n" + +#define NOTI_LIST_DB_ATTRIBUTES_SELECT \ + "type, layout, pkg_id, caller_app_id, launch_app_id, app_label, "\ + "image_path, priv_image_path, group_id, priv_id, b_text, b_key, " \ + "tag, b_format_args, num_format_args, text_domain, text_dir, " \ + "time, insert_time, args, group_args, b_execute_option, " \ + "b_service_responding, b_service_single_launch, b_service_multi_launch, " \ + "b_event_handler_click_on_button_1, b_event_handler_click_on_button_2, " \ + "b_event_handler_click_on_button_3, b_event_handler_click_on_button_4, " \ + "b_event_handler_click_on_button_5, b_event_handler_click_on_button_6, " \ + "b_event_handler_click_on_icon, b_event_handler_click_on_thumbnail, " \ + "b_event_handler_click_on_text_input_button, " \ + "b_event_handler_click_on_button_7, b_event_handler_click_on_button_8, " \ + "b_event_handler_click_on_button_9, b_event_handler_click_on_button_10, " \ + "sound_type, sound_path, priv_sound_path, " \ + "vibration_type, vibration_path, priv_vibration_path, " \ + "led_operation, led_argb, led_on_ms, led_off_ms, " \ + "flags_for_property, display_applist, " \ + "progress_size, progress_percentage, ongoing_flag, ongoing_value_type, " \ + "ongoing_current, ongoing_duration, auto_remove, default_button_index, " \ + "hide_timeout, delete_timeout, text_input_max_length, event_flag, "\ + "extension_image_size, uid" + +#define NOTI_LIST_DB_ATTRIBUTES_INSERT \ + "type, layout, pkg_id, caller_app_id, launch_app_id, app_label, " \ + "image_path, priv_image_path, group_id, internal_group_id, title_key, " \ + "b_text, b_key, tag, b_format_args, num_format_args, text_domain, " \ + "text_dir, time, insert_time, args, group_args, b_execute_option, " \ + "b_service_responding, b_service_single_launch, b_service_multi_launch, " \ + "b_event_handler_click_on_button_1, b_event_handler_click_on_button_2, " \ + "b_event_handler_click_on_button_3, b_event_handler_click_on_button_4, " \ + "b_event_handler_click_on_button_5, b_event_handler_click_on_button_6, " \ + "b_event_handler_click_on_icon, b_event_handler_click_on_thumbnail, " \ + "b_event_handler_click_on_text_input_button, " \ + "b_event_handler_click_on_button_7, b_event_handler_click_on_button_8, " \ + "b_event_handler_click_on_button_9, b_event_handler_click_on_button_10, " \ + "sound_type, sound_path, priv_sound_path, " \ + "vibration_type, vibration_path, priv_vibration_path, " \ + "led_operation, led_argb, led_on_ms, led_off_ms, " \ + "flags_for_property, flag_simmode, display_applist, " \ + "progress_size, progress_percentage, ongoing_flag, ongoing_value_type, " \ + "ongoing_current, ongoing_duration, auto_remove, default_button_index, " \ + "hide_timeout, delete_timeout, text_input_max_length, event_flag, " \ + "extension_image_size, uid" + +#define NOTI_LIST_INSERT_VALUES \ + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " \ + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " \ + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " \ + "?, ?, ?, ?, ?, ? " + +#define NOTI_LIST_DB_ATTRIBUTES_UPDATE \ + "type = ?, layout = ?, launch_app_id = ?, app_label = ?, " \ + "image_path = ?, priv_image_path = ?, b_text = ?, b_key = ?, tag = ?, " \ + "b_format_args = ?, num_format_args = ?, text_domain = ?, text_dir = ?, " \ + "time = ?, insert_time = ?, args = ?, group_args = ?, " \ + "b_execute_option = ?, b_service_responding = ?, " \ + "b_service_single_launch = ?, b_service_multi_launch = ?, " \ + "b_event_handler_click_on_button_1 = ?, " \ + "b_event_handler_click_on_button_2 = ?, " \ + "b_event_handler_click_on_button_3 = ?, " \ + "b_event_handler_click_on_button_4 = ?, " \ + "b_event_handler_click_on_button_5 = ?, " \ + "b_event_handler_click_on_button_6 = ?, " \ + "b_event_handler_click_on_icon = ?, " \ + "b_event_handler_click_on_thumbnail = ?, " \ + "b_event_handler_click_on_text_input_button = ?, " \ + "b_event_handler_click_on_button_7 = ?, " \ + "b_event_handler_click_on_button_8 = ?, " \ + "b_event_handler_click_on_button_9 = ?, " \ + "b_event_handler_click_on_button_10 = ?, " \ + "sound_type = ?, sound_path = ?, priv_sound_path = ?, " \ + "vibration_type = ?, vibration_path = ?, priv_vibration_path = ?, " \ + "led_operation = ?, led_argb = ?, led_on_ms = ?, led_off_ms = ?, " \ + "flags_for_property = ?, flag_simmode = ?, display_applist = ?, " \ + "progress_size = ?, progress_percentage = ?, " \ + "ongoing_flag = ?, ongoing_value_type = ?, " \ + "ongoing_current = ?, ongoing_duration = ?, " \ + "auto_remove = ?, default_button_index = ?, " \ + "hide_timeout = ?, delete_timeout = ?, " \ + "text_input_max_length = ?, event_flag = ?, extension_image_size = ? " + +#define NOTIFICATION_SETTING_DB_ATTRIBUTES \ + "package_name, app_id, allow_to_notify, do_not_disturb_except, "\ + "visibility_class, pop_up_notification, lock_screen_content_level, "\ + "app_disabled" + +#define NOTIFICATION_SYSTEM_SETTING_DB_ATTRIBUTES \ + "do_not_disturb, visibility_class, dnd_schedule_enabled, " \ + "dnd_schedule_day, dnd_start_hour, dnd_start_min, dnd_end_hour, " \ + "dnd_end_min, lock_screen_content_level" + +#define __BIND_TEXT(db, stmt, i, text, ret, label) \ +do { \ + ret = sqlite3_bind_text(stmt, i, text, -1, SQLITE_TRANSIENT); \ + if (ret != SQLITE_OK) { \ + ERR("bind error(index %d): [%d][%s]", i, ret, \ + sqlite3_errmsg(db)); \ + ret = NOTIFICATION_ERROR_FROM_DB; \ + goto label; \ + } \ +} while (0) + +#define __BIND_TEXT_STATIC(db, stmt, i, text, ret, label) \ +do { \ + ret = sqlite3_bind_text(stmt, i, text, -1, SQLITE_STATIC); \ + if (ret != SQLITE_OK) { \ + ERR("bind error(index %d): [%d][%s]", i, ret, \ + sqlite3_errmsg(db)); \ + ret = NOTIFICATION_ERROR_FROM_DB; \ + goto label; \ + } \ +} while (0) + +#define __BIND_INT(db, stmt, i, int, ret, label) \ +do { \ + ret = sqlite3_bind_int(stmt, i, int); \ + if (ret != SQLITE_OK) { \ + ERR("bind error(index %d): [%d][%s]", i, ret, \ + sqlite3_errmsg(db)); \ + ret = NOTIFICATION_ERROR_FROM_DB; \ + goto label; \ + } \ +} while (0) + +#define __BIND_DOUBLE(db, stmt, i, double, ret, label) \ +do { \ + ret = sqlite3_bind_double(stmt, i, double); \ + if (ret != SQLITE_OK) { \ + ERR("bind error(index %d): [%d][%s]", i, ret, \ + sqlite3_errmsg(db)); \ + ret = NOTIFICATION_ERROR_FROM_DB; \ + goto label; \ + } \ +} while (0) diff --git a/notification/src/notification_error.c b/notification/src/notification_error.c new file mode 100644 index 0000000..4e4c98b --- /dev/null +++ b/notification/src/notification_error.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string.h> +#include <gio/gio.h> +#include "notification_error.h" + +static const GDBusErrorEntry dbus_error_entries[] = { + {NOTIFICATION_ERROR_INVALID_PARAMETER, "org.freedesktop.Notification.Error.INVALID_PARAMETER"}, + {NOTIFICATION_ERROR_OUT_OF_MEMORY, "org.freedesktop.Notification.Error.OUT_OF_MEMORY"}, + {NOTIFICATION_ERROR_IO_ERROR, "org.freedesktop.Notification.Error.IO_ERROR"}, + {NOTIFICATION_ERROR_PERMISSION_DENIED, "org.freedesktop.Notification.Error.PERMISSION_DENIED"}, + {NOTIFICATION_ERROR_FROM_DB, "org.freedesktop.Notification.Error.FROM_DB"}, + {NOTIFICATION_ERROR_ALREADY_EXIST_ID, "org.freedesktop.Notification.Error.ALREADY_EXIST_ID"}, + {NOTIFICATION_ERROR_FROM_DBUS, "org.freedesktop.Notification.Error.FROM_DBUS"}, + {NOTIFICATION_ERROR_NOT_EXIST_ID, "org.freedesktop.Notification.Error.NOT_EXIST_ID"}, + {NOTIFICATION_ERROR_SERVICE_NOT_READY, "org.freedesktop.Notification.Error.SERVICE_NOT_READY"}, + {NOTIFICATION_ERROR_INVALID_OPERATION, "org.freedesktop.Notification.Error.INVALID_OPERATION"}, + {NOTIFICATION_ERROR_MAX_EXCEEDED, "org.freedesktop.Notification.Error.MAX_EXCEEDED"}, +}; + +#define NOTIFICATION_ERROR_QUARK "notification-error-quark" + +EXPORT_API GQuark notification_error_quark(void) +{ + static volatile gsize quark_volatile = 0; + static const char *domain_name = NULL; + + /* This is for preventing crash when notification api is used in ui-gadget */ + /* ui-gadget libraries can be unloaded when it is needed and the static string */ + /* parameter to g_dbus_error_register_error_domain may cause crash. */ + GQuark quark = g_quark_try_string(NOTIFICATION_ERROR_QUARK); + + if (quark == 0) { + if (domain_name == NULL) + domain_name = strdup(NOTIFICATION_ERROR_QUARK); + } else { + domain_name = NOTIFICATION_ERROR_QUARK; + } + + g_dbus_error_register_error_domain(domain_name, + &quark_volatile, + dbus_error_entries, + G_N_ELEMENTS(dbus_error_entries)); + return (GQuark)quark_volatile; +} + diff --git a/notification/src/notification_group.c b/notification/src/notification_group.c new file mode 100644 index 0000000..b03496a --- /dev/null +++ b/notification/src/notification_group.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <notification_debug.h> +#include <notification_group.h> +#include <notification_db.h> + +/* LCOV_EXCL_START */ +static int _notification_group_check_data_inserted(const char *app_id, + int group_id, sqlite3 *db) +{ + sqlite3_stmt *stmt = NULL; + char query[NOTIFICATION_QUERY_MAX] = { 0, }; + int ret; + int result; + + snprintf(query, sizeof(query), + "select count(*) from noti_group_data where caller_app_id = '%s' and group_id = %d", + app_id, group_id); + + ret = sqlite3_prepare(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + ERR("Get count DB err(%d) : %s", ret, sqlite3_errmsg(db)); + return NOTIFICATION_ERROR_FROM_DB; + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + result = sqlite3_column_int(stmt, 0); + else + result = 0; + + + sqlite3_finalize(stmt); + + if (result > 0) + return NOTIFICATION_ERROR_ALREADY_EXIST_ID; + + INFO("Check Data Inserted appid[%s] group_id[%d] result[%d]", + app_id, group_id, result); + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +int notification_group_set_badge(const char *app_id, + int group_id, int count) +{ + sqlite3 *db; + sqlite3_stmt *stmt = NULL; + char query[NOTIFICATION_QUERY_MAX] = { 0, }; + int ret; + int result; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + ret = _notification_group_check_data_inserted(app_id, group_id, db); + + if (ret == NOTIFICATION_ERROR_NONE) { + /* Insert if does not exist */ + snprintf(query, sizeof(query), "insert into noti_group_data (" + "caller_app_id, group_id, badge, content, loc_content) values (" + "'%s', %d, %d, '', '')", app_id, group_id, count); + + } else { + /* Update if exist */ + snprintf(query, sizeof(query), "update noti_group_data " + "set badge = %d " + "where caller_app_id = '%s' and group_id = %d", + count, app_id, group_id); + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ERR("Failed to insert data app_id[%s] err[%d][%s]", + app_id, ret, sqlite3_errmsg(db)); + if (stmt) + sqlite3_finalize(stmt); + + if (db) + notification_db_close(&db); + + return NOTIFICATION_ERROR_FROM_DB; + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_OK || ret == SQLITE_DONE) + result = NOTIFICATION_ERROR_NONE; + else + result = NOTIFICATION_ERROR_FROM_DB; + + sqlite3_finalize(stmt); + + if (db) + notification_db_close(&db); + + return result; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +int notification_group_get_badge(const char *app_id, + int group_id, int *count) +{ + sqlite3 *db; + sqlite3_stmt *stmt = NULL; + char query[NOTIFICATION_QUERY_MAX] = { 0, }; + int ret; + int col = 0; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + if (group_id == NOTIFICATION_GROUP_ID_NONE) { + ret = _notification_group_check_data_inserted(app_id, group_id, db); + if (ret == NOTIFICATION_ERROR_NONE) + /* Get all of app_id count if none group id is not exist */ + snprintf(query, sizeof(query), + "select sum(badge) " + "from noti_group_data " + "where caller_app_id = '%s'", app_id); + else + /* Get none group id count */ + snprintf(query, sizeof(query), + "select badge " + "from noti_group_data " + "where caller_app_id = '%s' and group_id = %d", + app_id, group_id); + } else { + snprintf(query, sizeof(query), + "select badge " + "from noti_group_data " + "where caller_app_id = '%s' and group_id = %d", + app_id, group_id); + } + + INFO("Get badge : query[%s]", query); + + ret = sqlite3_prepare(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + ERR("Failed to insert data app_id[%s] err[%d][%s]", + app_id, ret, sqlite3_errmsg(db)); + if (db) + notification_db_close(&db); + + return NOTIFICATION_ERROR_FROM_DB; + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + *count = sqlite3_column_int(stmt, col++); + + sqlite3_finalize(stmt); + + if (db) + notification_db_close(&db); + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ diff --git a/notification/src/notification_init.c b/notification/src/notification_init.c new file mode 100644 index 0000000..72d6cdc --- /dev/null +++ b/notification/src/notification_init.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#define _GNU_SOURCE + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> + +#include <notification_setting.h> + +/* For multi-user support */ +#include <tzplatform_config.h> + +#define OWNER_ROOT 0 + +#ifdef _E +#undef _E +#endif +#define _E(fmt, arg...) fprintf(stderr, "[NOTIFICATION_INIT][E][%s,%d] "fmt"\n", \ + __func__, __LINE__, ##arg) + +/* LCOV_EXCL_START */ +static int _is_authorized(void) +{ + /* pkg_init db should be called by as root privilege. */ + uid_t uid = getuid(); + + if ((uid_t) OWNER_ROOT == uid) + return 1; + else + return 0; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +int main(int argc, char *argv[]) +{ + int ret; + uid_t uid = 0; + + if (!_is_authorized()) { + _E("Not an authorized user"); + return -1; + } + + if (argc > 2) + uid = (uid_t)atoi(argv[2]); + + ret = notification_setting_refresh_setting_table(uid); + if (ret != NOTIFICATION_ERROR_NONE) { + _E("Failed to refresh setting table"); + return ret; + } + + ret = notification_system_setting_init_system_setting_table(uid); + if (ret != NOTIFICATION_ERROR_NONE) { + _E("Failed to init system setting table"); + return ret; + } + + return ret; +} +/* LCOV_EXCL_STOP */ diff --git a/notification/src/notification_internal.c b/notification/src/notification_internal.c new file mode 100644 index 0000000..bee6eb3 --- /dev/null +++ b/notification/src/notification_internal.c @@ -0,0 +1,2133 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <libintl.h> +#include <dbus/dbus.h> +#include <gio/gio.h> + +#include <aul.h> +#include <tizen.h> +#include <bundle.h> +#include <bundle_internal.h> +#include <app_control.h> +#include <app_control_internal.h> +#include <pkgmgr-info.h> + +#include <notification.h> +#include <notification_list.h> +#include <notification_debug.h> +#include <notification_private.h> +#include <notification_noti.h> +#include <notification_ongoing.h> +#include <notification_group.h> +#include <notification_ipc.h> +#include <notification_internal.h> +#include <notification_shared_file.h> + +#define REGULAR_UID_MIN 5000 + +typedef struct _notification_cb_info notification_cb_info_s; +typedef struct _notification_event_cb_info notification_event_cb_info_s; + +typedef enum __notification_cb_type { + NOTIFICATION_CB_NORMAL = 1, + NOTIFICATION_CB_DETAILED, +} _notification_cb_type_e; + +struct _notification_cb_info { + _notification_cb_type_e cb_type; + void (*changed_cb)(void *data, notification_type_e type); + void (*detailed_changed_cb)(void *data, notification_type_e type, notification_op *op_list, int num_op); + void *data; +}; + +struct _notification_event_cb_info { + int priv_id; + event_handler_cb cb; + void *userdata; +}; + +static GHashTable *_noti_cb_hash = NULL; +static GList *__noti_event_cb_list = NULL; + +void notification_reset_event_handler_list(void) +{ + GList *iter; + notification_event_cb_info_s *info; + + if (!__noti_event_cb_list) + return; + + iter = g_list_first(__noti_event_cb_list); + while (iter) { + info = g_list_nth_data(iter, 0); + if (info) + notification_ipc_reset_event_handler(info->priv_id); + iter = g_list_next(iter); + } +} + +/* LCOV_EXCL_START */ +static void __free_changed_cb_info(gpointer data) +{ + notification_cb_info_s *noti_cb_info = (notification_cb_info_s *)data; + + if (noti_cb_info) + free(noti_cb_info); +} +/* LCOV_EXCL_STOP */ + +void notification_call_changed_cb_for_uid(notification_op *op_list, int op_num, uid_t uid) +{ + notification_type_e type = NOTIFICATION_TYPE_NOTI; + GList *noti_cb_list; + notification_cb_info_s *noti_cb_info; + + if (_noti_cb_hash == NULL) + return; + + noti_cb_list = (GList *)g_hash_table_lookup(_noti_cb_hash, GUINT_TO_POINTER(uid)); + if (noti_cb_list == NULL) + return; + + if (op_list == NULL) { + ERR("Invalid parameter"); + return; + } + + noti_cb_list = g_list_first(noti_cb_list); + notification_get_type(op_list->noti, &type); + + for (; noti_cb_list != NULL; noti_cb_list = noti_cb_list->next) { + noti_cb_info = noti_cb_list->data; + + if (noti_cb_info->cb_type == NOTIFICATION_CB_NORMAL && noti_cb_info->changed_cb) + noti_cb_info->changed_cb(noti_cb_info->data, type); + + if (noti_cb_info->cb_type == NOTIFICATION_CB_DETAILED && noti_cb_info->detailed_changed_cb) { + noti_cb_info->detailed_changed_cb(noti_cb_info->data, + type, op_list, op_num); + } + } +} + +static gint __priv_id_compare(gconstpointer a, gconstpointer b) +{ + const notification_event_cb_info_s *info = NULL; + + if (!a) + return -1; + + info = (notification_event_cb_info_s *)a; + + if (info->priv_id == GPOINTER_TO_INT(b)) + return 0; + + return 1; +} + +void notification_call_event_handler_cb(notification_h noti, int event_type) +{ + int ret; + int priv_id; + GList *find_list; + notification_event_cb_info_s *info; + + if (__noti_event_cb_list == NULL) + return; + + ret = notification_get_id(noti, NULL, &priv_id); + if (ret != NOTIFICATION_ERROR_NONE) + return; + + __noti_event_cb_list = g_list_first(__noti_event_cb_list); + find_list = g_list_find_custom(__noti_event_cb_list, GINT_TO_POINTER(priv_id), + (GCompareFunc)__priv_id_compare); + if (find_list == NULL) + return; + + info = g_list_nth_data(find_list, 0); + info->cb(noti, event_type, info->userdata); +} + +/* LCOV_EXCL_START */ +void notification_delete_event_handler_cb(int priv_id) +{ + GList *delete_list; + notification_event_cb_info_s *info; + + if (__noti_event_cb_list == NULL) + return; + + __noti_event_cb_list = g_list_first(__noti_event_cb_list); + delete_list = g_list_find_custom(__noti_event_cb_list, GINT_TO_POINTER(priv_id), + (GCompareFunc)__priv_id_compare); + + if (delete_list == NULL) + return; + + info = g_list_nth_data(delete_list, 0); + __noti_event_cb_list = g_list_remove(g_list_first(__noti_event_cb_list), info); + + if (info) + free(info); + + if (__noti_event_cb_list == NULL) + notification_ipc_event_monitor_fini(); +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_add_deferred_task( + void (*deferred_task_cb)(void *data), void *user_data) +{ + if (deferred_task_cb == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + return notification_ipc_add_deffered_task(deferred_task_cb, user_data); +} + +EXPORT_API int notification_del_deferred_task( + void (*deferred_task_cb)(void *data)) +{ + if (deferred_task_cb == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + return notification_ipc_del_deffered_task(deferred_task_cb); +} + +EXPORT_API int notification_resister_changed_cb_for_uid( + void (*changed_cb)(void *data, notification_type_e type), + void *user_data, uid_t uid) +{ + GList *noti_cb_list; + notification_cb_info_s *noti_cb_info_new; + + if (changed_cb == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (_noti_cb_hash == NULL) + _noti_cb_hash = g_hash_table_new(g_direct_hash, g_direct_equal); + + noti_cb_info_new = (notification_cb_info_s *)malloc(sizeof(notification_cb_info_s)); + if (noti_cb_info_new == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + noti_cb_info_new->cb_type = NOTIFICATION_CB_NORMAL; + noti_cb_info_new->changed_cb = changed_cb; + noti_cb_info_new->detailed_changed_cb = NULL; + noti_cb_info_new->data = user_data; + + noti_cb_list = g_hash_table_lookup(_noti_cb_hash, GUINT_TO_POINTER(uid)); + + if (noti_cb_list == NULL) { + noti_cb_list = g_list_append(noti_cb_list, noti_cb_info_new); + g_hash_table_insert(_noti_cb_hash, GUINT_TO_POINTER(uid), noti_cb_list); + } else { + noti_cb_list = g_list_append(noti_cb_list, noti_cb_info_new); + } + + if (notification_ipc_monitor_init(uid) != NOTIFICATION_ERROR_NONE) { + notification_unresister_changed_cb_for_uid(changed_cb, uid); + return NOTIFICATION_ERROR_IO_ERROR; + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_resister_changed_cb( + void (*changed_cb)(void *data, notification_type_e type), + void *user_data) +{ + return notification_resister_changed_cb_for_uid(changed_cb, user_data, getuid()); +} + +static gint _noti_changed_compare(gconstpointer a, gconstpointer b) +{ + const struct _notification_cb_info *info = NULL; + + if (!a) + return -1; + info = (notification_cb_info_s *)a; + + if (info->changed_cb == b) + return 0; + + return 1; +} + +EXPORT_API int notification_unresister_changed_cb_for_uid( + void (*changed_cb)(void *data, notification_type_e type), uid_t uid) +{ + notification_cb_info_s *noti_cb_info; + GList *noti_cb_list; + GList *delete_cb_list; + + if (changed_cb == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (_noti_cb_hash == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti_cb_list = (GList *)g_hash_table_lookup(_noti_cb_hash, GUINT_TO_POINTER(uid)); + if (noti_cb_list == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti_cb_list = g_list_first(noti_cb_list); + delete_cb_list = g_list_find_custom(noti_cb_list, (gconstpointer)changed_cb, + (GCompareFunc)_noti_changed_compare); + if (delete_cb_list) { + noti_cb_info = g_list_nth_data(delete_cb_list, 0); + noti_cb_list = g_list_delete_link(noti_cb_list, delete_cb_list); + __free_changed_cb_info(noti_cb_info); + + if (noti_cb_list == NULL) { + g_hash_table_steal(_noti_cb_hash, GUINT_TO_POINTER(uid)); + } else { + noti_cb_list = g_list_first(noti_cb_list); + g_hash_table_replace(_noti_cb_hash, GUINT_TO_POINTER(uid), noti_cb_list); + } + + } else { + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (g_hash_table_size(_noti_cb_hash) == 0) + notification_ipc_monitor_fini(); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_unresister_changed_cb( + void (*changed_cb)(void *data, notification_type_e type)) +{ + return notification_unresister_changed_cb_for_uid(changed_cb, getuid()); +} + +EXPORT_API int notification_update_progress(notification_h noti, + int priv_id, + double progress) +{ + int ret; + int input_priv_id; + char *caller_app_id; + double input_progress; + + if (priv_id <= NOTIFICATION_PRIV_ID_NONE) { + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + input_priv_id = noti->priv_id; + } else { + input_priv_id = priv_id; + } + + if (noti == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(noti->caller_app_id); + + if (progress < 0.0) + input_progress = 0.0; + else if (progress > 1.0) + input_progress = 1.0; + else + input_progress = progress; + + ret = notification_ongoing_update_progress(caller_app_id, input_priv_id, + input_progress); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} + +EXPORT_API int notification_update_size(notification_h noti, + int priv_id, + double size) +{ + int ret; + int input_priv_id; + char *caller_app_id; + double input_size; + + if (priv_id <= NOTIFICATION_PRIV_ID_NONE) { + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + input_priv_id = noti->priv_id; + } else { + input_priv_id = priv_id; + } + + if (noti == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(noti->caller_app_id); + + if (size < 0.0) + input_size = 0.0; + else + input_size = size; + + ret = notification_ongoing_update_size(caller_app_id, input_priv_id, + input_size); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} + +EXPORT_API int notification_update_content(notification_h noti, + int priv_id, + const char *content) +{ + char *caller_app_id; + int input_priv_id; + int ret; + + if (priv_id <= NOTIFICATION_PRIV_ID_NONE) { + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + input_priv_id = noti->priv_id; + } else { + input_priv_id = priv_id; + } + + if (noti == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(noti->caller_app_id); + + ret = notification_ongoing_update_content(caller_app_id, input_priv_id, + content); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} + +/* notification_set_icon will be removed */ +/* LCOV_EXCL_START */ +EXPORT_API int notification_set_icon(notification_h noti, + const char *icon_path) +{ + return notification_set_image(noti, NOTIFICATION_IMAGE_TYPE_ICON, icon_path); +} +/* LCOV_EXCL_STOP */ + +/* notification_get_icon will be removed */ +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_icon(notification_h noti, + char **icon_path) +{ + int ret = NOTIFICATION_ERROR_NONE; + char *ret_image_path = NULL; + + ret = notification_get_image(noti, NOTIFICATION_IMAGE_TYPE_ICON, + &ret_image_path); + + if (ret == NOTIFICATION_ERROR_NONE && icon_path != NULL) + *icon_path = ret_image_path; + + return ret; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_translate_localized_text(notification_h noti) +{ + int ret = NOTIFICATION_ERROR_NONE; + char *ret_text = NULL; + char buf_key[32]; + char *bundle_val = NULL; + char *new_text; + bundle *b; + notification_text_type_e type = NOTIFICATION_TEXT_TYPE_TITLE; + + noti->is_translation = false; + + for (; type <= NOTIFICATION_TEXT_TYPE_MAX; type++) { + ret = notification_get_text(noti, type, &ret_text); + if (ret == NOTIFICATION_ERROR_NONE && ret_text) { + if (noti->b_text == NULL) { + noti->b_text = bundle_create(); + if (noti->b_text == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + + b = noti->b_text; + + new_text = strdup(ret_text); + + snprintf(buf_key, sizeof(buf_key), "%d", type); + bundle_get_str(b, buf_key, &bundle_val); + if (bundle_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, new_text); + free(new_text); + new_text = NULL; + + noti->num_format_args = 0; + bundle_val = NULL; + } + } + + noti->is_translation = true; + + return ret; +} + +/* LCOV_EXCL_START */ +EXPORT_API int notification_set_title(notification_h noti, + const char *title, + const char *loc_title) +{ + return notification_set_text(noti, NOTIFICATION_TEXT_TYPE_TITLE, + title, loc_title, + NOTIFICATION_VARIABLE_TYPE_NONE); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_title(notification_h noti, + char **title, + char **loc_title) +{ + int ret; + char *ret_text = NULL; + + ret = notification_get_text(noti, NOTIFICATION_TEXT_TYPE_TITLE, + &ret_text); + + if (title != NULL) + *title = ret_text; + + if (loc_title != NULL) + *loc_title = NULL; + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_set_content(notification_h noti, + const char *content, + const char *loc_content) +{ + return notification_set_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT, + content, loc_content, + NOTIFICATION_VARIABLE_TYPE_NONE); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_content(notification_h noti, + char **content, + char **loc_content) +{ + int ret; + char *ret_text = NULL; + + ret = notification_get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT, + &ret_text); + + if (content != NULL) + *content = ret_text; + + if (loc_content != NULL) + *loc_content = NULL; + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_set_application(notification_h noti, + const char *app_id) +{ + if (noti == NULL || app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->launch_app_id) + free(noti->launch_app_id); + + noti->launch_app_id = strdup(app_id); + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_application(notification_h noti, + char **app_id) +{ + if (noti == NULL || app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->launch_app_id) + *app_id = noti->launch_app_id; + else + *app_id = noti->caller_app_id; + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_set_args(notification_h noti, bundle *args, + bundle *group_args) +{ + if (noti == NULL || args == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->args) + bundle_free(noti->args); + + noti->args = bundle_dup(args); + + if (noti->group_args) { + bundle_free(noti->group_args); + noti->group_args = NULL; + } + + if (group_args != NULL) + noti->group_args = bundle_dup(group_args); + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_args(notification_h noti, + bundle **args, + bundle **group_args) +{ + if (noti == NULL || args == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->args) + *args = noti->args; + else + *args = NULL; + + if (group_args != NULL && noti->group_args) + *group_args = noti->group_args; + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +int notification_get_grouping_list_for_uid(notification_type_e type, int count, + notification_list_h *list, uid_t uid) +{ + notification_list_h get_list = NULL; + int ret = 0; + + if (list == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_noti_get_grouping_list(type, 1, count, &get_list, NULL, uid); + if (ret != NOTIFICATION_ERROR_NONE) + return ret; + + *list = get_list; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_grouping_list(notification_type_e type, int count, + notification_list_h *list) +{ + return notification_get_grouping_list_for_uid(type, count, list, getuid()); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_delete_group_by_group_id(const char *app_id, + notification_type_e type, + int group_id) +{ + int ret; + char *caller_app_id; + + if (app_id == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(app_id); + + ret = notification_ipc_request_delete_multiple(type, caller_app_id, getuid()); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +int notification_delete_group_by_priv_id_for_uid(const char *app_id, + notification_type_e type, + int priv_id, uid_t uid) +{ + int ret; + char *caller_app_id; + + if (app_id == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(app_id); + + ret = notification_ipc_request_delete_single(type, caller_app_id, priv_id, uid); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_delete_group_by_priv_id(const char *app_id, + notification_type_e type, + int priv_id) +{ + return notification_delete_group_by_priv_id_for_uid(app_id, type, priv_id, getuid()); +} + +int notification_get_count_for_uid(notification_type_e type, + const char *app_id, + int group_id, + int priv_id, int *count, + uid_t uid) +{ + int ret; + char *caller_app_id; + + if (count == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (app_id == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(app_id); + + ret = notification_ipc_request_get_count( + type, + caller_app_id, + group_id, + priv_id, + count, + uid); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_count(notification_type_e type, + const char *app_id, + int group_id, + int priv_id, int *count) +{ + return notification_get_count_for_uid(type, app_id, group_id, priv_id, count, getuid()); +} + +int notification_clear_for_uid(notification_type_e type, uid_t uid) +{ + if (type <= NOTIFICATION_TYPE_NONE || type > NOTIFICATION_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + return notification_ipc_request_delete_multiple(type, NULL, uid); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_clear(notification_type_e type) +{ + return notification_clear_for_uid(type, getuid()); +} + +EXPORT_API int notification_op_get_data(notification_op *noti_op, notification_op_data_type_e type, + void *data) +{ + if (noti_op == NULL || data == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + switch (type) { + case NOTIFICATION_OP_DATA_TYPE: + *((int *)data) = noti_op->type; + break; + case NOTIFICATION_OP_DATA_PRIV_ID: + *((int *)data) = noti_op->priv_id; + break; + case NOTIFICATION_OP_DATA_NOTI: + *((notification_h *)data) = noti_op->noti; + break; + case NOTIFICATION_OP_DATA_EXTRA_INFO_1: + *((int *)data) = noti_op->extra_info_1; + break; + case NOTIFICATION_OP_DATA_EXTRA_INFO_2: + *((int *)data) = noti_op->extra_info_2; + break; + default: + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_set_pkgname(notification_h noti, + const char *pkgname) +{ + return notification_set_app_id(noti, pkgname); +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_set_app_id(notification_h noti, + const char *app_id) +{ + if (noti == NULL || app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + /* Remove previous caller app_id */ + if (noti->caller_app_id) { + free(noti->caller_app_id); + noti->caller_app_id = NULL; + } + + noti->caller_app_id = strdup(app_id); + + return NOTIFICATION_ERROR_NONE; +} + +/* LCOV_EXCL_START */ +int notification_delete_all_by_type_for_uid(const char *app_id, + notification_type_e type, uid_t uid) +{ + int ret; + char *caller_app_id; + + if (type <= NOTIFICATION_TYPE_NONE || type > NOTIFICATION_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (app_id == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(app_id); + + ret = notification_ipc_request_delete_multiple(type, caller_app_id, uid); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_delete_all_by_type(const char *app_id, + notification_type_e type) +{ + return notification_delete_all_by_type_for_uid(app_id, type, getuid()); +} + +int notification_delete_by_priv_id_for_uid(const char *app_id, + notification_type_e type, + int priv_id, + uid_t uid) +{ + int ret; + char *caller_app_id; + + if (priv_id <= NOTIFICATION_PRIV_ID_NONE) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (app_id == NULL) + caller_app_id = notification_get_app_id_by_pid(getpid()); + else + caller_app_id = strdup(app_id); + + ret = notification_ipc_request_delete_single(type, caller_app_id, priv_id, uid); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_delete_by_priv_id(const char *app_id, + notification_type_e type, + int priv_id) +{ + return notification_delete_by_priv_id_for_uid(app_id, type, priv_id, getuid()); +} + +EXPORT_API int notification_set_execute_option(notification_h noti, + notification_execute_type_e type, + const char *text, + const char *key, + bundle *service_handle) +{ + char buf_key[32] = { 0, }; + char *ret_val = NULL; + bundle *b = NULL; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_EXECUTE_TYPE_NONE + || type > NOTIFICATION_EXECUTE_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->b_execute_option == NULL) + noti->b_execute_option = bundle_create(); + + b = noti->b_execute_option; + + if (text != NULL) { + snprintf(buf_key, sizeof(buf_key), "text%d", type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, text); + } + + if (key != NULL) { + snprintf(buf_key, sizeof(buf_key), "key%d", type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL) + bundle_del(b, buf_key); + + bundle_add_str(b, buf_key, key); + } + + switch ((int)type) { + case NOTIFICATION_EXECUTE_TYPE_RESPONDING: + if (noti->b_service_responding != NULL) { + bundle_free(noti->b_service_responding); + noti->b_service_responding = NULL; + } + + if (service_handle != NULL) + noti->b_service_responding = bundle_dup(service_handle); + + break; + case NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH: + if (noti->b_service_single_launch != NULL) { + bundle_free(noti->b_service_single_launch); + noti->b_service_single_launch = NULL; + } + + if (service_handle != NULL) + noti->b_service_single_launch = + bundle_dup(service_handle); + + break; + case NOTIFICATION_EXECUTE_TYPE_MULTI_LAUNCH: + if (noti->b_service_multi_launch != NULL) { + bundle_free(noti->b_service_multi_launch); + noti->b_service_multi_launch = NULL; + } + + if (service_handle != NULL) + noti->b_service_multi_launch = + bundle_dup(service_handle); + + break; + } + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_id(notification_h noti, + int *group_id, int *priv_id) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (group_id) { + if (noti->group_id < NOTIFICATION_GROUP_ID_NONE) + *group_id = NOTIFICATION_GROUP_ID_NONE; + else + *group_id = noti->group_id; + } + + if (priv_id) + *priv_id = noti->priv_id; + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_set_priv_id(notification_h noti, int priv_id) +{ + if (noti == NULL || priv_id <= 0) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->priv_id = priv_id; + + return NOTIFICATION_ERROR_NONE; +} + +/* LCOV_EXCL_START */ +notification_h notification_load_for_uid(char *app_id, + int priv_id, uid_t uid) +{ + int ret; + notification_h noti; + + noti = (notification_h)calloc(1, sizeof(struct _notification)); + if (noti == NULL) { + ERR("Failed to alloc memory"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + return NULL; + } + + ret = notification_ipc_request_load_noti_by_priv_id(noti, app_id, priv_id, uid); + if (ret != NOTIFICATION_ERROR_NONE) { + notification_free(noti); + set_last_result(ret); + return NULL; + } + + set_last_result(NOTIFICATION_ERROR_NONE); + + return noti; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API notification_h notification_load(char *app_id, + int priv_id) +{ + return notification_load_for_uid(app_id, priv_id, getuid()); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API notification_h notification_new(notification_type_e type, + int group_id, int priv_id) +{ + return notification_create(type); +} + +static void _notification_get_text_domain(notification_h noti) +{ +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_execute_option(notification_h noti, + notification_execute_type_e type, + const char **text, + bundle **service_handle) +{ + char buf_key[32] = { 0, }; + char *ret_val = NULL; + char *get_str = NULL; + bundle *b = NULL; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type <= NOTIFICATION_EXECUTE_TYPE_NONE + || type > NOTIFICATION_EXECUTE_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + switch (type) { + case NOTIFICATION_EXECUTE_TYPE_RESPONDING: + b = noti->b_service_responding; + break; + case NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH: + b = noti->b_service_single_launch; + break; + case NOTIFICATION_EXECUTE_TYPE_MULTI_LAUNCH: + b = noti->b_service_multi_launch; + break; + default: + break; + } + + if (b != NULL) { + if (text != NULL) { + if (noti->domain == NULL || noti->dir == NULL) + _notification_get_text_domain(noti); + + snprintf(buf_key, sizeof(buf_key), "key%d", type); + + bundle_get_str(b, buf_key, &ret_val); + if (ret_val != NULL && noti->domain != NULL + && noti->dir != NULL) { + bindtextdomain(noti->domain, noti->dir); + + get_str = dgettext(noti->domain, ret_val); + + *text = get_str; + } else if (ret_val != NULL) { + get_str = dgettext("sys_string", ret_val); + + *text = get_str; + } else { + snprintf(buf_key, sizeof(buf_key), "text%d", + type); + + bundle_get_str(b, buf_key, &ret_val); + + *text = ret_val; + } + } + } + + if (service_handle != NULL) + *service_handle = b; + + return NOTIFICATION_ERROR_NONE; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_insert_for_uid(notification_h noti, + int *priv_id, uid_t uid) +{ + int ret; + int id; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->type <= NOTIFICATION_TYPE_NONE + || noti->type > NOTIFICATION_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->uid = uid; + noti->insert_time = time(NULL); + + ret = notification_ipc_request_insert(noti, &id); + if (ret != NOTIFICATION_ERROR_NONE) + return ret; + + noti->priv_id = id; + + /* If priv_id is valid data, set priv_id */ + if (priv_id != NULL) + *priv_id = noti->priv_id; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_insert(notification_h noti, + int *priv_id) +{ + return notification_insert_for_uid(noti, priv_id, getuid()); +} + +EXPORT_API int notification_update_async_for_uid(notification_h noti, + void (*result_cb)(int priv_id, int result, void *data), void *user_data, uid_t uid) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->uid = uid; + /* Update insert time ? */ + noti->insert_time = time(NULL); + + return notification_ipc_request_update_async(noti, result_cb, user_data); +} + +EXPORT_API int notification_update_async(notification_h noti, + void (*result_cb)(int priv_id, int result, void *data), void *user_data) +{ + return notification_update_async_for_uid(noti, result_cb, user_data, getuid()); +} + +EXPORT_API int notification_register_detailed_changed_cb_for_uid( + void (*detailed_changed_cb)(void *data, notification_type_e type, notification_op *op_list, int num_op), + void *user_data, uid_t uid) +{ + GList *noti_cb_list = NULL; + notification_cb_info_s *noti_cb_info_new = NULL; + + if (detailed_changed_cb == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (_noti_cb_hash == NULL) + _noti_cb_hash = g_hash_table_new(g_direct_hash, g_direct_equal); + + noti_cb_info_new = (notification_cb_info_s *)malloc(sizeof(notification_cb_info_s)); + if (noti_cb_info_new == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + noti_cb_info_new->cb_type = NOTIFICATION_CB_DETAILED; + noti_cb_info_new->changed_cb = NULL; + noti_cb_info_new->detailed_changed_cb = detailed_changed_cb; + noti_cb_info_new->data = user_data; + + noti_cb_list = g_hash_table_lookup(_noti_cb_hash, GUINT_TO_POINTER(uid)); + + if (noti_cb_list == NULL) { + noti_cb_list = g_list_append(noti_cb_list, noti_cb_info_new); + g_hash_table_insert(_noti_cb_hash, GUINT_TO_POINTER(uid), noti_cb_list); + } else { + noti_cb_list = g_list_append(noti_cb_list, noti_cb_info_new); + } + + if (notification_ipc_monitor_init(uid) != NOTIFICATION_ERROR_NONE) { + notification_unregister_detailed_changed_cb_for_uid(detailed_changed_cb, user_data, uid); + return NOTIFICATION_ERROR_IO_ERROR; + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_register_detailed_changed_cb( + void (*detailed_changed_cb)(void *data, notification_type_e type, notification_op *op_list, int num_op), + void *user_data) +{ + return notification_register_detailed_changed_cb_for_uid(detailed_changed_cb, user_data, getuid()); +} + +static gint _noti_detailed_changed_compare(gconstpointer a, gconstpointer b) +{ + const struct _notification_cb_info *info = NULL; + + if (!a) + return -1; + info = (notification_cb_info_s *)a; + + if (info->detailed_changed_cb == b) + return 0; + + return 1; +} + +EXPORT_API int notification_unregister_detailed_changed_cb_for_uid( + void (*detailed_changed_cb)(void *data, notification_type_e type, notification_op *op_list, int num_op), + void *user_data, uid_t uid) +{ + notification_cb_info_s *noti_cb_info; + GList *noti_cb_list; + GList *delete_cb_list; + + if (detailed_changed_cb == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (_noti_cb_hash == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti_cb_list = (GList *)g_hash_table_lookup(_noti_cb_hash, GUINT_TO_POINTER(uid)); + + if (noti_cb_list == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti_cb_list = g_list_first(noti_cb_list); + delete_cb_list = g_list_find_custom(noti_cb_list, (gconstpointer)detailed_changed_cb, + (GCompareFunc)_noti_detailed_changed_compare); + + if (delete_cb_list) { + noti_cb_info = (notification_cb_info_s *)g_list_nth_data(delete_cb_list, 0); + noti_cb_list = g_list_delete_link(noti_cb_list, delete_cb_list); + __free_changed_cb_info(noti_cb_info); + if (noti_cb_list == NULL) { + g_hash_table_steal(_noti_cb_hash, GUINT_TO_POINTER(uid)); + } else { + noti_cb_list = g_list_first(noti_cb_list); + g_hash_table_replace(_noti_cb_hash, GUINT_TO_POINTER(uid), noti_cb_list); + } + + } else { + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (g_hash_table_size(_noti_cb_hash) == 0) + notification_ipc_monitor_fini(); + + return NOTIFICATION_ERROR_NONE; + +} + +EXPORT_API int notification_unregister_detailed_changed_cb( + void (*detailed_changed_cb)(void *data, notification_type_e type, notification_op *op_list, int num_op), + void *user_data) +{ + return notification_unregister_detailed_changed_cb_for_uid(detailed_changed_cb, user_data, getuid()); +} + +/* LCOV_EXCL_START */ +EXPORT_API int notification_is_service_ready(void) +{ + return notification_ipc_is_master_ready(); +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_set_uid(notification_h noti, + uid_t uid) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->uid = uid; + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_uid(notification_h noti, + uid_t *uid) +{ + if (noti == NULL || uid == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *uid = noti->uid; + return NOTIFICATION_ERROR_NONE; +} + +static GList *__copy_private_file(notification_h noti) +{ + bundle *dst_b; + bundle *src_b; + char buf_key[32]; + char *src_path; + char *dst_path; + int i; + GList *file_list = NULL; + int ret; + + if (noti->b_priv_image_path && noti->b_image_path) { + dst_b = noti->b_priv_image_path; + src_b = noti->b_image_path; + for (i = NOTIFICATION_IMAGE_TYPE_ICON; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) { + src_path = NULL; + dst_path = NULL; + + snprintf(buf_key, sizeof(buf_key), "%d", i); + + bundle_get_str(dst_b, buf_key, &dst_path); + if (dst_path == NULL) + continue; + + bundle_get_str(src_b, buf_key, &src_path); + if (src_path == NULL) + continue; + + ret = notification_copy_private_file(src_path, dst_path); + if (ret == NOTIFICATION_ERROR_NONE) + file_list = g_list_append(file_list, strdup(dst_path)); + } + } + if (noti->sound_path && noti->priv_sound_path) { + ret = notification_copy_private_file(noti->sound_path, + noti->priv_sound_path); + if (ret == NOTIFICATION_ERROR_NONE) + file_list = g_list_append(file_list, + strdup(noti->priv_sound_path)); + } + + if (noti->vibration_path && noti->priv_vibration_path) { + ret = notification_copy_private_file(noti->vibration_path, + noti->priv_vibration_path); + if (ret == NOTIFICATION_ERROR_NONE) + file_list = g_list_append(file_list, + strdup(noti->priv_vibration_path)); + } + + return file_list; +} + +/* LCOV_EXCL_START */ +static void __remove_private_file(gpointer data, gpointer user_data) +{ + GFile *src = NULL; + char *path = (char *)data; + + src = g_file_new_for_path(path); + if (src) { + g_file_delete(src, NULL, NULL); + g_object_unref(src); + } +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_post_for_uid(notification_h noti, uid_t uid) +{ + int ret = 0; + int id = 0; + GList *file_list; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->type <= NOTIFICATION_TYPE_NONE + || noti->type > NOTIFICATION_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + /* Save insert time */ + noti->insert_time = time(NULL); + noti->uid = uid; + + file_list = __copy_private_file(noti); + ret = notification_ipc_request_insert(noti, &id); + if (ret == NOTIFICATION_ERROR_NONE) { + noti->priv_id = id; + INFO("Posted notification id[%d]", id); + } else { + g_list_foreach(file_list, __remove_private_file, NULL); + } + + if (file_list) + g_list_free_full(file_list, free); + + return ret; +} + +EXPORT_API int notification_update_for_uid(notification_h noti, uid_t uid) +{ + if (noti == NULL) { + notification_ipc_request_refresh(uid); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + noti->uid = uid; + /* Update insert time ? */ + noti->insert_time = time(NULL); + + return notification_ipc_request_update(noti); +} + +EXPORT_API int notification_delete_for_uid(notification_h noti, uid_t uid) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + return notification_ipc_request_delete_single(NOTIFICATION_TYPE_NONE, + noti->caller_app_id, noti->priv_id, uid); +} + +EXPORT_API int notification_delete_all_for_uid(notification_type_e type, uid_t uid) +{ + int ret = 0; + char *caller_app_id = NULL; + + if (type <= NOTIFICATION_TYPE_NONE || type > NOTIFICATION_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + caller_app_id = notification_get_app_id_by_pid(getpid()); + + ret = notification_ipc_request_delete_multiple(type, caller_app_id, uid); + + if (caller_app_id) + free(caller_app_id); + + return ret; +} + +EXPORT_API notification_h notification_load_by_tag_for_uid(const char *tag, uid_t uid) +{ + int ret; + notification_h noti; + char *caller_app_id; + + if (tag == NULL) { + ERR("Invalid tag"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + caller_app_id = notification_get_app_id_by_pid(getpid()); + if (!caller_app_id) { + /* LCOV_EXCL_START */ + ERR("Failed to get a package name"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + return NULL; + /* LCOV_EXCL_STOP */ + } + + noti = (notification_h)calloc(1, sizeof(struct _notification)); + if (noti == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc a new notification"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + free(caller_app_id); + + return NULL; + /* LCOV_EXCL_STOP */ + } + + ret = notification_ipc_request_load_noti_by_tag(noti, caller_app_id, (char *)tag, uid); + free(caller_app_id); + + set_last_result(ret); + if (ret != NOTIFICATION_ERROR_NONE) { + notification_free(noti); + return NULL; + } + + return noti; +} + +EXPORT_API notification_h notification_create_from_package_template(const char *app_id, const char *template_name) +{ + int ret; + notification_h noti; + + if (app_id == NULL || template_name == NULL) { + ERR("Invalid parameter"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + noti = (notification_h)calloc(1, sizeof(struct _notification)); + if (noti == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + return NULL; + /* LCOV_EXCL_STOP */ + } + + ret = notification_ipc_request_create_from_package_template(noti, app_id, template_name); + set_last_result(ret); + if (ret != NOTIFICATION_ERROR_NONE) { + notification_free(noti); + return NULL; + } + + return noti; +} + +EXPORT_API int notification_set_default_button(notification_h noti, notification_button_index_e index) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (index < 0 || index > NOTIFICATION_BUTTON_6) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->default_button_index = index; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_default_button(notification_h noti, notification_button_index_e *index) +{ + if (noti == NULL || index == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *index = noti->default_button_index; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_ongoing_value_type(notification_h noti, notification_ongoing_value_type_e *type) +{ + if (noti == NULL || type == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *type = noti->ongoing_value_type; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_ongoing_value_type(notification_h noti, notification_ongoing_value_type_e type) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (type < NOTIFICATION_ONGOING_VALUE_TYPE_PERCENT || type > NOTIFICATION_ONGOING_VALUE_TYPE_TIME) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->ongoing_value_type = type; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_ongoing_time(notification_h noti, int *current, int *duration) +{ + if (noti == NULL || current == NULL || duration == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *current = noti->ongoing_current; + *duration = noti->ongoing_duration; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_ongoing_time(notification_h noti, int current, int duration) +{ + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (current < 0 || duration < 0 || current > duration) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->ongoing_current = current; + noti->ongoing_duration = duration; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_hide_timeout(notification_h noti, int *timeout) +{ + if (noti == NULL || timeout == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *timeout = noti->hide_timeout; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_hide_timeout(notification_h noti, int timeout) +{ + if (noti == NULL || timeout < 0) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->hide_timeout = timeout; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_delete_timeout(notification_h noti, int *timeout) +{ + if (noti == NULL || timeout == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *timeout = noti->delete_timeout; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_set_delete_timeout(notification_h noti, int timeout) +{ + if (noti == NULL || timeout < 0) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->delete_timeout = timeout; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_text_input_max_length(notification_h noti, int *text_input_max_length) +{ + if (noti == NULL || text_input_max_length == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *text_input_max_length = noti->text_input_max_length; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_post_with_event_cb_for_uid(notification_h noti, event_handler_cb cb, + void *userdata, uid_t uid) +{ + int ret; + int priv_id; + notification_event_cb_info_s *info = NULL; + GList *find_list; + + if (noti == NULL || cb == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->type <= NOTIFICATION_TYPE_NONE || noti->type > NOTIFICATION_TYPE_MAX) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti->insert_time = time(NULL); + noti->event_flag = true; + noti->uid = uid; + + ret = notification_ipc_request_insert(noti, &priv_id); + if (ret != NOTIFICATION_ERROR_NONE) + return ret; + + noti->priv_id = priv_id; + + __noti_event_cb_list = g_list_first(__noti_event_cb_list); + find_list = g_list_find_custom(__noti_event_cb_list, GINT_TO_POINTER(priv_id), + (GCompareFunc)__priv_id_compare); + + if (find_list) { + info = g_list_nth_data(find_list, 0); + info->cb = cb; + info->userdata = userdata; + } else { + info = (notification_event_cb_info_s *)malloc(sizeof(notification_event_cb_info_s)); + if (info == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + info->priv_id = priv_id; + info->cb = cb; + info->userdata = userdata; + __noti_event_cb_list = g_list_append(__noti_event_cb_list, info); + } + + return ret; +} + +EXPORT_API int notification_post_with_event_cb(notification_h noti, event_handler_cb cb, void *userdata) +{ + return notification_post_with_event_cb_for_uid(noti, cb, userdata, getuid()); +} + +EXPORT_API int notification_send_event(notification_h noti, int event_type) +{ + int ret; + bool event_flag; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (!((event_type >= NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_1 + && event_type <= NOTIFICATION_EVENT_TYPE_MAX) || + (event_type >= NOTIFICATION_EVENT_TYPE_HIDDEN_BY_USER + && event_type <= NOTIFICATION_EVENT_TYPE_HIDDEN_BY_EXTERNAL) || + (event_type >= NOTIFICATION_EVENT_TYPE_PRESSED + && event_type <= NOTIFICATION_EVENT_TYPE_DELETED))) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_get_event_flag(noti, &event_flag); + if (ret != NOTIFICATION_ERROR_NONE || event_flag == false) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_ipc_send_event(noti, event_type, -1); + + return ret; +} + +EXPORT_API int notification_send_event_by_priv_id(int priv_id, int event_type) +{ + int ret; + + if (priv_id <= 0) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (!((event_type >= NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_1 + && event_type <= NOTIFICATION_EVENT_TYPE_MAX) || + (event_type >= NOTIFICATION_EVENT_TYPE_HIDDEN_BY_USER + && event_type <= NOTIFICATION_EVENT_TYPE_HIDDEN_BY_EXTERNAL) || + (event_type >= NOTIFICATION_EVENT_TYPE_PRESSED + && event_type <= NOTIFICATION_EVENT_TYPE_DELETED))) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_ipc_send_event(NULL, event_type, priv_id); + return ret; +} + +EXPORT_API int notification_get_event_flag(notification_h noti, bool *flag) +{ + if (noti == NULL || flag == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *flag = noti->event_flag; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_check_event_receiver_available(notification_h noti, bool *available) +{ + int ret; + int priv_id; + + if (noti == NULL || available == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_get_id(noti, NULL, &priv_id); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get priv id"); + return ret; + } + + ret = notification_ipc_check_event_receiver(priv_id, available); + + return ret; +} + +static bundle *_create_bundle_from_bundle_raw(bundle_raw *string) +{ + if (string == NULL || string[0] == '\0') + return NULL; + + return bundle_decode(string, strlen((char *)string)); +} + +EXPORT_API int notification_set_extention_data(notification_h noti, const char *key, bundle *value) +{ + return notification_set_extension_data(noti, key, value); +} + +EXPORT_API int notification_set_extension_data(notification_h noti, const char *key, bundle *value) +{ + int ret; + int len = 0; + char *del = NULL; + bundle_raw *raw = NULL; + + if (noti == NULL || key == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->args == NULL) + noti->args = bundle_create(); + + if (value == NULL) { + ret = bundle_del(noti->args, key); + if (ret == BUNDLE_ERROR_NONE) + return NOTIFICATION_ERROR_NONE; + else + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + bundle_get_str(noti->args, key, &del); + if (del != NULL) { + bundle_del(noti->args, key); + del = NULL; + } + + bundle_encode(value, &raw, &len); + bundle_add_str(noti->args, key, (const char *)raw); + bundle_free_encoded_rawdata(&raw); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_extention_data(notification_h noti, const char *key, bundle **value) +{ + return notification_get_extension_data(noti, key, value); +} + +EXPORT_API int notification_get_extension_data(notification_h noti, const char *key, bundle **value) +{ + char *ret_str; + bundle *args; + + if (noti == NULL || key == NULL || value == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->args == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + args = noti->args; + + bundle_get_str(args, key, &ret_str); + if (ret_str == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + *value = _create_bundle_from_bundle_raw((bundle_raw *)ret_str); + if (*value == NULL) + return NOTIFICATION_ERROR_IO_ERROR; + + return NOTIFICATION_ERROR_NONE; +} + +#define KEY_LEN 40 +#define EXTENSION_EVENT_KEY "_NOTIFICATION_EXTENSION_EVENT_" +EXPORT_API int notification_set_extension_event_handler(notification_h noti, + notification_event_type_extension_e event, + app_control_h event_handler) +{ + int err; + int ret = NOTIFICATION_ERROR_NONE; + int len; + bundle *app_control_bundle = NULL; + bundle_raw *b_raw = NULL; + char key[KEY_LEN]; + char *del = NULL; + + if (noti == NULL || event_handler == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (event < NOTIFICATION_EVENT_TYPE_HIDDEN_BY_USER || + event > NOTIFICATION_EVENT_TYPE_HIDDEN_BY_EXTERNAL) { + ERR("Invalid event [%d]", event); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (noti->args == NULL) + noti->args = bundle_create(); + + snprintf(key, sizeof(key), "%s%d", EXTENSION_EVENT_KEY, event); + bundle_get_str(noti->args, key, &del); + if (del != NULL) { + bundle_del(noti->args, key); + del = NULL; + } + + err = app_control_export_as_bundle(event_handler, &app_control_bundle); + if (err != APP_CONTROL_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to export app_control to bundle [%d]", err); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + err = bundle_encode(app_control_bundle, &b_raw, &len); + if (err != BUNDLE_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to encode bundle [%d]", err); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + err = bundle_add_str(noti->args, key, (const char *)b_raw); + if (err != BUNDLE_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to add str to bundle [%d]", err); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + +out: + if (b_raw) + bundle_free_encoded_rawdata(&b_raw); + if (app_control_bundle) + bundle_free(app_control_bundle); + + return ret; +} + +EXPORT_API int notification_get_extension_event_handler(notification_h noti, + notification_event_type_extension_e event, + app_control_h *event_handler) +{ + int err; + int ret = NOTIFICATION_ERROR_NONE; + char *ret_str = NULL; + char key[KEY_LEN]; + bundle *app_control_bundle = NULL; + app_control_h ret_app_control = NULL; + + if (noti == NULL || event_handler == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (event < NOTIFICATION_EVENT_TYPE_HIDDEN_BY_USER || + event > NOTIFICATION_EVENT_TYPE_HIDDEN_BY_EXTERNAL) { + ERR("Invalid event [%d]", event); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + snprintf(key, sizeof(key), "%s%d", EXTENSION_EVENT_KEY, event); + + bundle_get_str(noti->args, key, &ret_str); + if (ret_str == NULL) { + ERR("No handler, Invalid event[%d]", event); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + app_control_bundle = _create_bundle_from_bundle_raw((bundle_raw *)ret_str); + if (app_control_bundle == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to create bundle"); + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + + err = app_control_create(&ret_app_control); + if (err != APP_CONTROL_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to create app control [%d]", err); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + err = app_control_import_from_bundle(ret_app_control, app_control_bundle); + if (err != APP_CONTROL_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to import app control from bundle [%d]", err); + app_control_destroy(ret_app_control); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + *event_handler = ret_app_control; + +out: + if (app_control_bundle) + bundle_free(app_control_bundle); + + return ret; +} + +EXPORT_API int notification_get_all_count_for_uid(notification_type_e type, int *count, uid_t uid) +{ + int ret; + + if (count == NULL) { + ERR("Invalid parameter - count is null"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (type < NOTIFICATION_TYPE_NONE || type > NOTIFICATION_TYPE_MAX) { + ERR("Invalid parameter - wrong type"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + ret = notification_ipc_request_get_all_count(type, count, uid); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get count [%d]", ret); + return ret; + } + + return ret; +} + +EXPORT_API int notification_get_all_count(notification_type_e type, int *count) +{ + return notification_get_all_count_for_uid(type, count, getuid()); +} + +EXPORT_API int notification_set_app_label(notification_h noti, char *label) +{ + if (noti == NULL || label == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->app_label) + free(noti->app_label); + + noti->app_label = strdup(label); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_app_label(notification_h noti, char **label) +{ + if (noti == NULL || label == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->app_label) + *label = noti->app_label; + + return NOTIFICATION_ERROR_NONE; +} + +static void __set_caller_info(bundle *b, const char *appid, uid_t uid) +{ + pkgmgrinfo_appinfo_h handle; + char buf[12]; + char *pkgid = NULL; + int r; + + snprintf(buf, sizeof(buf), "%u", uid); + bundle_del(b, AUL_K_ORG_CALLER_UID); + bundle_add(b, AUL_K_ORG_CALLER_UID, buf); + + bundle_del(b, AUL_K_ORG_CALLER_APPID); + bundle_add(b, AUL_K_ORG_CALLER_APPID, appid); + + r = pkgmgrinfo_appinfo_get_usr_appinfo(appid, uid, &handle); + if (r != PMINFO_R_OK) + return; + + pkgmgrinfo_appinfo_get_pkgid(handle, &pkgid); + if (pkgid) { + bundle_del(b, AUL_K_ORG_CALLER_PKGID); + bundle_add(b, AUL_K_ORG_CALLER_PKGID, pkgid); + } + pkgmgrinfo_appinfo_destroy_appinfo(handle); +} + +static void __set_indirect_request(bundle *b) +{ + bundle_del(b, AUL_K_REQUEST_TYPE); + bundle_add(b, AUL_K_REQUEST_TYPE, "indirect-request"); +} + +EXPORT_API int notification_set_indirect_request(notification_h noti, + pid_t pid, uid_t uid) +{ + char appid[256] = { 0, }; + int r; + int i; + + if (noti == NULL || pid <= 1 || uid < REGULAR_UID_MIN) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + r = aul_app_get_appid_bypid(pid, appid, sizeof(appid)); + if (r != AUL_R_OK) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->b_service_responding) { + __set_caller_info(noti->b_service_responding, appid, uid); + __set_indirect_request(noti->b_service_responding); + } + + if (noti->b_service_single_launch) { + __set_caller_info(noti->b_service_single_launch, appid, uid); + __set_indirect_request(noti->b_service_single_launch); + } + + if (noti->b_service_multi_launch) { + __set_caller_info(noti->b_service_multi_launch, appid, uid); + __set_indirect_request(noti->b_service_multi_launch); + } + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) { + if (noti->b_event_handler[i]) { + __set_caller_info(noti->b_event_handler[i], appid, uid); + __set_indirect_request(noti->b_event_handler[i]); + } + } + + return NOTIFICATION_ERROR_NONE; +} + + +int notification_delete_by_display_applist_for_uid(int display_applist, uid_t uid) +{ + if (display_applist < NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + return notification_ipc_request_delete_by_display_applist(display_applist, uid); +} + +EXPORT_API int notification_delete_by_display_applist(int display_applist) +{ + return notification_delete_by_display_applist_for_uid(display_applist, getuid()); +} diff --git a/notification/src/notification_ipc.c b/notification/src/notification_ipc.c new file mode 100644 index 0000000..c0446e9 --- /dev/null +++ b/notification/src/notification_ipc.c @@ -0,0 +1,2726 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <bundle_internal.h> + +#include <notification_ipc.h> +#include <notification_db.h> +#include <notification_type.h> +#include <notification_private.h> +#include <notification_debug.h> +#include <notification_setting.h> +#include <notification_setting_internal.h> +#include <notification_internal.h> + +#include <gio/gio.h> +#include <gio/gunixfdlist.h> + +#define PROVIDER_BUS_NAME "org.tizen.data_provider_service" +#define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service" +#define PROVIDER_NOTI_INTERFACE_NAME "org.tizen.data_provider_noti_service" +#define PROVIDER_NOTI_EVENT_INTERFACE_NAME "org.tizen.data_provider_noti_event_service" + +#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" +#define DBUS_PATH_DBUS "/org/freedesktop/DBus" +#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" +#define ERR_BUFFER_SIZE 1024 + +static const gchar *_bus_name = NULL; +static GDBusConnection *_gdbus_conn = NULL; +static guint provider_watcher_id = 0; +static int monitor_id = 0; +static int event_monitor_id = 0; +static int provider_monitor_id = 0; +static int is_master_started = 0; + +typedef struct _result_cb_item { + void (*result_cb)(int priv_id, int result, void *data); + void *data; +} result_cb_item; + +typedef struct _task_list task_list; +struct _task_list { + task_list *prev; + task_list *next; + + void (*task_cb)(void *data); + void *data; +}; + +static task_list *g_task_list; + +static int _ipc_monitor_register(uid_t uid); +static int _ipc_monitor_deregister(void); +static void _do_deffered_task(void); + +static void _print_noti(notification_h noti) +{ + char *app_id = NULL; + char *text = NULL; + char *content = NULL; + const char *tag = NULL; + + notification_get_pkgname(noti, &app_id); + notification_get_text(noti, NOTIFICATION_TEXT_TYPE_TITLE, &text); + notification_get_text(noti, NOTIFICATION_TEXT_TYPE_CONTENT, &content); + notification_get_tag(noti, &tag); + + DBG("Noti-info : app_id[%s] title[%s] content[%s] tag[%s] priv_id[%d]", + app_id, text, content, tag, noti->priv_id); +} + +static void __provider_appeared_cb(GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + INFO("name [%s] name_owner[%s]", name, name_owner); + notification_reset_event_handler_list(); +} + +/* LCOV_EXCL_START */ +static void __provider_vanished_cb(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + INFO("name [%s]", name); +} +/* LCOV_EXCL_STOP */ + +static int _dbus_init(void) +{ + GError *error = NULL; + + if (_gdbus_conn == NULL) { + _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + if (_gdbus_conn == NULL) { + /* LCOV_EXCL_START */ + if (error != NULL) { + ERR("Failed to get dbus[%s]", + error->message); + g_error_free(error); + } + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + _bus_name = g_dbus_connection_get_unique_name(_gdbus_conn); + INFO("Connected bus name[%s]", _bus_name); + + notification_error_quark(); + } + + if (provider_watcher_id == 0) { + provider_watcher_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM, + PROVIDER_BUS_NAME, + G_BUS_NAME_WATCHER_FLAGS_NONE, + __provider_appeared_cb, + __provider_vanished_cb, + NULL, + NULL); + DBG("Watching data-provider-master is [%s] watcher_id [%d]", + provider_watcher_id ? "success" : "fail", provider_watcher_id); + } + + return NOTIFICATION_ERROR_NONE; +} + +/* LCOV_EXCL_START */ +int notification_ipc_is_master_ready(void) +{ + GVariant *result; + GError *err = NULL; + gboolean name_exist; + int ret = NOTIFICATION_ERROR_NONE; + + ret = _dbus_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", ret); + is_master_started = 0; + return is_master_started; + } + + result = g_dbus_connection_call_sync( + _gdbus_conn, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "NameHasOwner", + g_variant_new("(s)", PROVIDER_BUS_NAME), + G_VARIANT_TYPE("(b)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &err); + + if (err || (result == NULL)) { + if (err) { + ERR("No reply[%s]", err->message); + g_error_free(err); + } + ERR("Failed to ready master"); + is_master_started = 0; + } else { + g_variant_get(result, "(b)", &name_exist); + + if (!name_exist) { + ERR("The master has been stopped, Not exsited name[%s]", PROVIDER_BUS_NAME); + is_master_started = 0; + } else { + DBG("The master has been started"); + is_master_started = 1; + } + } + + if (result) + g_variant_unref(result); + + return is_master_started; +} +/* LCOV_EXCL_STOP */ + +/* TODO: dbus activation isn't enough ? */ +/* + * store tasks when daemon stopped + */ +int notification_ipc_add_deffered_task( + void (*deferred_task_cb)(void *data), + void *user_data) +{ + task_list *list; + task_list *list_new; + + list_new = (task_list *) malloc(sizeof(task_list)); + if (list_new == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + + list_new->next = NULL; + list_new->prev = NULL; + + list_new->task_cb = deferred_task_cb; + list_new->data = user_data; + + if (g_task_list == NULL) { + g_task_list = list_new; + } else { + list = g_task_list; + + while (list->next != NULL) + list = list->next; + + list->next = list_new; + list_new->prev = list; + } + + return NOTIFICATION_ERROR_NONE; +} + +int notification_ipc_del_deffered_task( + void (*deferred_task_cb)(void *data)) +{ + task_list *list_del; + task_list *list_prev; + task_list *list_next; + + list_del = g_task_list; + + if (list_del == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + while (list_del->prev != NULL) + list_del = list_del->prev; + + do { + if (list_del->task_cb == deferred_task_cb) { + list_prev = list_del->prev; + list_next = list_del->next; + + if (list_prev == NULL) + g_task_list = list_next; + else + list_prev->next = list_next; + + if (list_next == NULL) { + if (list_prev != NULL) + list_prev->next = NULL; + } else { + list_next->prev = list_prev; + } + + free(list_del); + return NOTIFICATION_ERROR_NONE; + } + list_del = list_del->next; + } while (list_del != NULL); + + return NOTIFICATION_ERROR_INVALID_PARAMETER; +} + +/* LCOV_EXCL_START */ +static void _do_deffered_task(void) +{ + task_list *list_do; + task_list *list_temp; + + if (g_task_list == NULL) + return; + + list_do = g_task_list; + g_task_list = NULL; + + while (list_do->prev != NULL) + list_do = list_do->prev; + + while (list_do != NULL) { + if (list_do->task_cb != NULL) { + list_do->task_cb(list_do->data); + DBG("called:%p", list_do->task_cb); + } + list_temp = list_do->next; + free(list_do); + list_do = list_temp; + } +} +/* LCOV_EXCL_STOP */ + +/*! + * functions to create operation list + */ +static notification_op *_ipc_create_op(notification_op_type_e type, + int num_op, int *list_priv_id, int num_priv_id, notification_h *noti_list) +{ + int i; + notification_op *op_list; + + if (num_op <= 0) + return NULL; + + op_list = (notification_op *)malloc(sizeof(notification_op) * num_op); + if (op_list == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + return NULL; + /* LCOV_EXCL_STOP */ + } + + memset(op_list, 0x0, sizeof(notification_op) * num_op); + + for (i = 0; i < num_op; i++) { + (op_list + i)->type = type; + if (list_priv_id != NULL) + (op_list + i)->priv_id = *(list_priv_id + i); + if (noti_list != NULL) + (op_list + i)->noti = *(noti_list + i); + } + + return op_list; +} + +/*! + * utility functions creating notification packet + */ +static inline char *_dup_string(const char *string) +{ + char *ret; + char err_buf[ERR_BUFFER_SIZE]; + + if (string == NULL || string[0] == '\0') + return NULL; + + ret = strdup(string); + if (!ret) + ERR("Failed to strdup[%s]", + strerror_r(errno, err_buf, sizeof(err_buf))); + + return ret; +} + +static inline bundle *_create_bundle_from_bundle_raw(bundle_raw *string) +{ + if (string == NULL || string[0] == '\0') + return NULL; + + return bundle_decode(string, strlen((char *)string)); +} + +/* LCOV_EXCL_START */ +static void _add_noti_notify(GVariant *parameters) +{ + int ret; + notification_h noti; + notification_op *noti_op = NULL; + GVariant *body = NULL; + uid_t uid; + + DBG("add noti notify"); + noti = notification_create(NOTIFICATION_TYPE_NOTI); + if (!noti) { + ERR("Failed to create notification handle"); + return; + } + + g_variant_get(parameters, "(v)", &body); + notification_ipc_make_noti_from_gvariant(noti, body); + _print_noti(noti); + if (noti->flags_for_property & NOTIFICATION_PROP_DISABLE_UPDATE_ON_INSERT) { + ERR("Disable changed callback[%d]", noti->flags_for_property); + /* Disable changed cb */ + } else { + /* Enable changed cb */ + noti_op = _ipc_create_op(NOTIFICATION_OP_INSERT, 1, &(noti->priv_id), 1, ¬i); + ret = notification_get_uid(noti, &uid); + if (noti_op != NULL && ret == NOTIFICATION_ERROR_NONE) + notification_call_changed_cb_for_uid(noti_op, 1, uid); + } + g_variant_unref(body); + notification_free(noti); + if (noti_op) + free(noti_op); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static void _update_noti_notify(GVariant *parameters) +{ + int ret; + notification_h noti; + notification_op *noti_op = NULL; + GVariant *body = NULL; + uid_t uid; + + noti = notification_create(NOTIFICATION_TYPE_NOTI); + if (!noti) { + ERR("Failed to create notification handle"); + return; + } + + g_variant_get(parameters, "(v)", &body); + notification_ipc_make_noti_from_gvariant(noti, body); + _print_noti(noti); + + noti_op = _ipc_create_op(NOTIFICATION_OP_UPDATE, 1, &(noti->priv_id), 1, ¬i); + ret = notification_get_uid(noti, &uid); + if (noti_op != NULL && ret == NOTIFICATION_ERROR_NONE) + notification_call_changed_cb_for_uid(noti_op, 1, uid); + + g_variant_unref(body); + notification_free(noti); + if (noti_op) + free(noti_op); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static void _refresh_noti_notify(GVariant *parameters) +{ + uid_t uid; + notification_op *noti_op = _ipc_create_op(NOTIFICATION_OP_REFRESH, 1, NULL, 0, NULL); + + g_variant_get(parameters, "(i)", &uid); + + if (noti_op != NULL) { + notification_call_changed_cb_for_uid(noti_op, 1, uid); + free(noti_op); + } +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static void _delete_single_notify(GVariant *parameters) +{ + int num_deleted; + int priv_id; + notification_op *noti_op; + uid_t uid; + + /* num_deleted ?? */ + g_variant_get(parameters, "(iii)", &num_deleted, &priv_id, &uid); + + noti_op = _ipc_create_op(NOTIFICATION_OP_DELETE, 1, &priv_id, 1, NULL); + if (noti_op != NULL) { + notification_call_changed_cb_for_uid(noti_op, 1, uid); + free(noti_op); + } +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static void _delete_multiple_notify(GVariant *parameters) +{ + int *buf; + int idx = 0; + int num; + notification_op *noti_op; + GVariantIter *iter; + uid_t uid; + + g_variant_get(parameters, "(a(i)ii)", &iter, &num, &uid); + if (num <= 0) { + ERR("Invalid number to delete"); + return; + } + DBG("Deleted count[%d]", num); + + buf = (int *)malloc(sizeof(int) * num); + if (buf == NULL) { + ERR("Failed to alloc"); + return; + } + + while (idx < num && g_variant_iter_loop(iter, "(i)", &buf[idx])) { + DBG("priv id[%d]", buf[idx]); + idx++; + } + g_variant_iter_free(iter); + + noti_op = _ipc_create_op(NOTIFICATION_OP_DELETE, idx, buf, idx, NULL); + if (noti_op == NULL) { + ERR("Failed to create op"); + free(buf); + return; + } + + notification_call_changed_cb_for_uid(noti_op, idx, uid); + free(noti_op); + free(buf); +} +/* LCOV_EXCL_STOP */ + +static void _delete_by_display_applist_notify(GVariant *parameters) +{ + int *buf; + int idx = 0; + int num; + notification_op *noti_op; + GVariantIter *iter; + uid_t uid; + + g_variant_get(parameters, "(a(i)ii)", &iter, &num, &uid); + if (num <= 0) { + ERR("Invalid number to delete"); + return; + } + + DBG("Deleted count[%d]", num); + + buf = (int *)malloc(sizeof(int) * num); + if (buf == NULL) { + ERR("Failed to alloc"); + return; + } + + while (idx < num && g_variant_iter_loop(iter, "(i)", &buf[idx])) { + DBG("priv id[%d]", buf[idx]); + idx++; + } + g_variant_iter_free(iter); + + noti_op = _ipc_create_op(NOTIFICATION_OP_DELETE, idx, buf, idx, NULL); + if (noti_op == NULL) { + ERR("Failed to create op"); + free(buf); + return; + } + + notification_call_changed_cb_for_uid(noti_op, idx, uid); + free(noti_op); + free(buf); +} + +/* LCOV_EXCL_START */ +static void _change_dnd_notify(GVariant *parameters) +{ + int do_not_disturb; + uid_t uid; + + g_variant_get(parameters, "(ii)", &do_not_disturb, &uid); + DBG("do_not_disturb[%d], uid[%d]", do_not_disturb, uid); + + notification_call_dnd_changed_cb_for_uid(do_not_disturb, uid); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static void _handle_noti_notify(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + DBG("own_name : %s signal_name: %s", + g_dbus_connection_get_unique_name(connection), + signal_name); + + if (g_strcmp0(signal_name, "add_noti_notify") == 0) + _add_noti_notify(parameters); + else if (g_strcmp0(signal_name, "update_noti_notify") == 0) + _update_noti_notify(parameters); + else if (g_strcmp0(signal_name, "delete_single_notify") == 0) + _delete_single_notify(parameters); + else if (g_strcmp0(signal_name, "delete_multiple_notify") == 0) + _delete_multiple_notify(parameters); + else if (g_strcmp0(signal_name, "refresh_noti_notify") == 0) + _refresh_noti_notify(parameters); + else if (g_strcmp0(signal_name, "change_dnd_notify") == 0) + _change_dnd_notify(parameters); + else if (g_strcmp0(signal_name, "delete_by_display_applist_notify") == 0) + _delete_by_display_applist_notify(parameters); +} +/* LCOV_EXCL_STOP */ + +static void _send_event(GVariant *parameters) +{ + int ret; + int event_type; + notification_h noti; + GVariant *coupled_body; + GVariant *body; + + noti = notification_create(NOTIFICATION_TYPE_NOTI); + if (noti == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to create notification handle"); + return; + /* LCOV_EXCL_STOP */ + } + + g_variant_get(parameters, "(vi)", &coupled_body, &event_type); + g_variant_get(coupled_body, "(v)", &body); + + ret = notification_ipc_make_noti_from_gvariant(noti, body); + g_variant_unref(coupled_body); + g_variant_unref(body); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to make notification handle from gvariant"); + notification_free(noti); + return; + /* LCOV_EXCL_STOP */ + } + + notification_call_event_handler_cb(noti, event_type); + notification_free(noti); +} + +/* LCOV_EXCL_START */ +static void _delete_event(GVariant *parameters) +{ + int priv_id; + + g_variant_get(parameters, "(i)", &priv_id); + notification_delete_event_handler_cb(priv_id); +} +/* LCOV_EXCL_STOP */ + +static void _handle_noti_event_handler_notify(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + DBG("own_name : %s signal_name: %s", + g_dbus_connection_get_unique_name(connection), signal_name); + + if (g_strcmp0(signal_name, "send_event") == 0) + _send_event(parameters); + else if (g_strcmp0(signal_name, "delete_noti") == 0) + _delete_event(parameters); +} + +static int _dbus_event_handler_signal_init(void) +{ + int id; + int ret = NOTIFICATION_ERROR_NONE; + + if (event_monitor_id == 0) { + id = g_dbus_connection_signal_subscribe(_gdbus_conn, + PROVIDER_BUS_NAME, + PROVIDER_NOTI_EVENT_INTERFACE_NAME, /* interface */ + NULL, /* member */ + PROVIDER_OBJECT_PATH, /* path */ + NULL, /* arg0 */ + G_DBUS_SIGNAL_FLAGS_NONE, + _handle_noti_event_handler_notify, + NULL, + NULL); + + DBG("subscribe id[%d]", id); + if (id == 0) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR("Failed to subscribe connection signal"); + /* LCOV_EXCL_STOP */ + } else { + event_monitor_id = id; + } + } + + return ret; +} + +static int _dbus_signal_init(void) +{ + int id; + int ret = NOTIFICATION_ERROR_NONE; + + if (monitor_id == 0) { + id = g_dbus_connection_signal_subscribe(_gdbus_conn, + PROVIDER_BUS_NAME, + PROVIDER_NOTI_INTERFACE_NAME, /* interface */ + NULL, /* member */ + PROVIDER_OBJECT_PATH, /* path */ + NULL, /* arg0 */ + G_DBUS_SIGNAL_FLAGS_NONE, + _handle_noti_notify, + NULL, + NULL); + + DBG("subscribe id : %d", id); + if (id == 0) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR("Failed to register dbus_interface"); + /* LCOV_EXCL_STOP */ + } else { + monitor_id = id; + ret = NOTIFICATION_ERROR_NONE; + } + } + + return ret; +} + +static GDBusMessage *__get_new_msg(GVariant *body, const char *cmd) +{ + GDBusMessage *msg = NULL; + + msg = g_dbus_message_new_method_call( + PROVIDER_BUS_NAME, + PROVIDER_OBJECT_PATH, + PROVIDER_NOTI_INTERFACE_NAME, + cmd); + if (!msg) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc new method call"); + if (body) + g_variant_unref(body); + return NULL; + /* LCOV_EXCL_STOP */ + } + + if (body != NULL) + g_dbus_message_set_body(msg, body); + + return msg; +} + +static int __send_message(GDBusMessage *msg, GDBusMessage **reply, const char *cmd) +{ + int ret = NOTIFICATION_ERROR_NONE; + GError *g_err = NULL; + + *reply = g_dbus_connection_send_message_with_reply_sync( + _gdbus_conn, + msg, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + -1, + NULL, + NULL, + &g_err); + + if (!*reply) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_SERVICE_NOT_READY; + if (g_err != NULL) { + ERR("No reply. cmd[%s] err[%s]", cmd, g_err->message); + if (g_err->code == G_DBUS_ERROR_ACCESS_DENIED) + ret = NOTIFICATION_ERROR_PERMISSION_DENIED; + g_error_free(g_err); + } + return ret; + /* LCOV_EXCL_STOP */ + } + + if (g_dbus_message_to_gerror(*reply, &g_err)) { + if (g_err->code == G_DBUS_ERROR_ACCESS_DENIED) + ret = NOTIFICATION_ERROR_PERMISSION_DENIED; + else + ret = g_err->code; + g_error_free(g_err); + return ret; + } + + INFO("Success to send message[%s]", cmd); + return NOTIFICATION_ERROR_NONE; +} + +static int _send_sync_noti_with_fd(int fd, GVariant *body, GDBusMessage **reply, char *cmd) +{ + int ret = NOTIFICATION_ERROR_NONE; + GDBusMessage *msg = NULL; + GUnixFDList *fd_list = NULL; + GError *g_err = NULL; + + fd_list = g_unix_fd_list_new(); + g_unix_fd_list_append(fd_list, fd, &g_err); + if (g_err != NULL) { + /* LCOV_EXCL_START */ + ERR("g_unix_fd_list_append [%s]", g_err->message); + g_object_unref(fd_list); + g_error_free(g_err); + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + + msg = __get_new_msg(body, cmd); + if (msg == NULL) { + g_object_unref(fd_list); + return NOTIFICATION_ERROR_IO_ERROR; + } + + g_dbus_message_set_unix_fd_list(msg, fd_list); + + ret = __send_message(msg, reply, cmd); + + g_object_unref(msg); + g_object_unref(fd_list); + + INFO("Done - send sync message with fd list [%d]", ret); + return ret; +} + +static int _send_sync_noti(GVariant *body, GDBusMessage **reply, char *cmd) +{ + int ret = NOTIFICATION_ERROR_NONE; + GDBusMessage *msg = NULL; + + msg = __get_new_msg(body, cmd); + if (msg == NULL) + return NOTIFICATION_ERROR_IO_ERROR; + + ret = __send_message(msg, reply, cmd); + + if (msg) + g_object_unref(msg); + + INFO("Done - send sync message [%d]", ret); + return ret; +} + +static void _send_message_with_reply_async_cb(GDBusConnection *connection, + GAsyncResult *res, + gpointer user_data) +{ + GVariant *body; + int result = NOTIFICATION_ERROR_NONE; + int priv_id; + GDBusMessage *reply = NULL; + GError *err = NULL; + result_cb_item *cb_item = (result_cb_item *)user_data; + + if (cb_item == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to get a callback item"); + return; + /* LCOV_EXCL_START */ + } + + reply = g_dbus_connection_send_message_with_reply_finish( + connection, + res, + &err); + + if (!reply) { + /* LCOV_EXCL_START */ + if (err != NULL) { + ERR("No reply[%s]", err->message); + g_error_free(err); + } + result = NOTIFICATION_ERROR_SERVICE_NOT_READY; + /* LCOV_EXCL_STOP */ + + } else if (g_dbus_message_to_gerror(reply, &err)) { + /* LCOV_EXCL_START */ + if (err->code == G_DBUS_ERROR_ACCESS_DENIED) + result = NOTIFICATION_ERROR_PERMISSION_DENIED; + else + result = err->code; + + ERR("Failed to send message[%s]", err->message); + g_error_free(err); + /* LCOV_EXCL_STOP */ + } + + INFO("Async message callback result[%d]", result); + if (result == NOTIFICATION_ERROR_NONE) { + body = g_dbus_message_get_body(reply); + g_variant_get(body, "(i)", &priv_id); + + if (cb_item->result_cb) + cb_item->result_cb(priv_id, result, cb_item->data); + } else { + if (cb_item->result_cb) + cb_item->result_cb(NOTIFICATION_PRIV_ID_NONE, result, cb_item->data); + } + + if (reply) + g_object_unref(reply); + free(cb_item); +} + +static int _send_async_noti(GVariant *body, result_cb_item *cb_item, char *cmd) +{ + GDBusMessage *msg; + + msg = g_dbus_message_new_method_call( + PROVIDER_BUS_NAME, + PROVIDER_OBJECT_PATH, + PROVIDER_NOTI_INTERFACE_NAME, + cmd); + if (!msg) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc new method call"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + if (g_variant_is_floating(body)) + g_variant_ref(body); + + if (body != NULL) + g_dbus_message_set_body(msg, body); + + g_dbus_connection_send_message_with_reply( + _gdbus_conn, + msg, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + -1, + NULL, + NULL, + (GAsyncReadyCallback)_send_message_with_reply_async_cb, + cb_item); + + if (msg) + g_object_unref(msg); + + DBG("Success to send async message"); + return NOTIFICATION_ERROR_NONE; +} + +int notification_ipc_request_insert(notification_h noti, int *priv_id) +{ + int result; + int id = NOTIFICATION_PRIV_ID_NONE; + bool event_flag; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + result = notification_get_event_flag(noti, &event_flag); + if (result != NOTIFICATION_ERROR_NONE) + return result; + + if (event_flag == true && event_monitor_id == 0) { + result = _dbus_event_handler_signal_init(); + if (result != NOTIFICATION_ERROR_NONE) + return result; + } + + /* Initialize private ID */ + noti->group_id = NOTIFICATION_GROUP_ID_NONE; + noti->internal_group_id = NOTIFICATION_GROUP_ID_NONE; + + _print_noti(noti); + body = notification_ipc_make_gvariant_from_noti(noti, false); + if (body == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to make gvariant from notification handle"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + result = _send_sync_noti(body, &reply, "add_noti"); + DBG("_send_sync_noti %d", result); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &id); + + if (priv_id != NULL) + *priv_id = id; + } + + if (reply) + g_object_unref(reply); + + DBG("priv_id[%d] result[%d]", id, result); + return result; +} + +int notification_ipc_request_update(notification_h noti) +{ + int result; + int priv_id = NOTIFICATION_PRIV_ID_NONE; + + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = notification_ipc_make_gvariant_from_noti(noti, false); + if (body == NULL) { + /* LCOV_EXCL_START */ + ERR("cannot make gvariant"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + result = _send_sync_noti(body, &reply, "update_noti"); + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &priv_id); + } + + if (reply) + g_object_unref(reply); + + DBG("priv_id[%d] result[%d]", priv_id, result); + return result; +} + +int notification_ipc_request_update_async(notification_h noti, + void (*result_cb)(int priv_id, int result, void *data), void *user_data) +{ + int result; + result_cb_item *cb_item; + GVariant *body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + cb_item = calloc(1, sizeof(result_cb_item)); + if (cb_item == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + + cb_item->result_cb = result_cb; + cb_item->data = user_data; + + body = notification_ipc_make_gvariant_from_noti(noti, false); + if (body == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to make gvariant from notification handle"); + free(cb_item); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + result = _send_async_noti(body, cb_item, "update_noti"); + DBG("Update async result[%d]", result); + + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + free(cb_item); + cb_item = NULL; + /* LCOV_EXCL_STOP */ + } + + g_variant_unref(body); + + return result; +} + +int notification_ipc_request_refresh(uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(i)", uid); + result = _send_sync_noti(body, &reply, "refresh_noti"); + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_delete_single(notification_type_e type, char *app_id, int priv_id, uid_t uid) +{ + int result; + int id; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(sii)", app_id, priv_id, uid); + result = _send_sync_noti(body, &reply, "del_noti_single"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &id); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_delete_multiple(notification_type_e type, char *app_id, uid_t uid) +{ + int result; + int num_deleted; + GVariant *body; + GVariant *reply_body; + GDBusMessage *reply = NULL; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + if (!app_id) + app_id = ""; + + body = g_variant_new("(sii)", app_id, type, uid); + result = _send_sync_noti(body, &reply, "del_noti_multiple"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &num_deleted); + DBG("Deleted count[%d]", num_deleted); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_delete_by_display_applist(int display_applist, uid_t uid) +{ + int result; + int num_deleted; + GVariant *body; + GVariant *reply_body; + GDBusMessage *reply = NULL; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", result); + return result; + } + + body = g_variant_new("(ii)", display_applist, uid); + + result = _send_sync_noti(body, &reply, "del_noti_by_display_applist"); + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &num_deleted); + DBG("Deleted count[%d]", num_deleted); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_load_noti_by_tag(notification_h noti, const char *app_id, const char *tag, uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + GVariant *noti_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(ssi)", app_id, tag, uid); + result = _send_sync_noti(body, &reply, "load_noti_by_tag"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(v)", ¬i_body); + + notification_ipc_make_noti_from_gvariant(noti, noti_body); + g_variant_unref(noti_body); + _print_noti(noti); + + } + + if (reply) + g_object_unref(reply); + + DBG("tag[%s] result[%d]", tag, result); + return result; +} + +/* LCOV_EXCL_START */ +int notification_ipc_request_load_noti_by_priv_id(notification_h noti, const char *app_id, int priv_id, uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + GVariant *noti_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", result); + return result; + } + + if (!app_id) + app_id = ""; + + body = g_variant_new("(sii)", app_id, priv_id, uid); + result = _send_sync_noti(body, &reply, "load_noti_by_priv_id"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(v)", ¬i_body); + + notification_ipc_make_noti_from_gvariant(noti, noti_body); + g_variant_unref(noti_body); + _print_noti(noti); + } + + if (reply) + g_object_unref(reply); + + DBG("priv id[%d], result[%d]", priv_id, result); + return result; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +int notification_ipc_request_get_count(notification_type_e type, + const char *app_id, int group_id, int priv_id, int *count, uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + int re_count; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", result); + return result; + } + + body = g_variant_new("(isiii)", type, app_id, group_id, priv_id, uid); + result = _send_sync_noti(body, &reply, "get_noti_count"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &re_count); + + *count = re_count; + DBG("notification count[%d]", re_count); + } + + if (reply) + g_object_unref(reply); + + DBG("Count notification result[%d]", result); + return result; +} +/* LCOV_EXCL_STOP */ + +static int __receive_list_from_socket(int fd, notification_list_h *list, int list_count) +{ + int ret = NOTIFICATION_ERROR_NONE; + char *data = NULL; + unsigned int data_size = 0; + unsigned int buf_size = 0; + notification_h noti; + GVariant *noti_body; + GVariant *reply_body; + + ret = notification_ipc_socket_get_read_buf_size(fd, &buf_size); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("get read buf size"); + return NOTIFICATION_ERROR_IO_ERROR; + } + + data = (char *)calloc(buf_size, sizeof(char)); + if (data == NULL) { + ERR("OOM - socket buffer"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + + while (list_count > 0) { + ret = notification_ipc_socket_read(fd, (char *)&data_size, sizeof(data_size)); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("socket read buf [%d]", ret); + goto out; + } + + if (data_size > buf_size) { + buf_size = data_size; + if (data) + free(data); + data = (char *)calloc(data_size, sizeof(char)); + if (data == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + ERR("OOM - socket bulk buffer"); + goto out; + } + } + + ret = notification_ipc_socket_read(fd, data, data_size); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("socket read buf [%d]", ret); + goto out; + } + + noti = (notification_h)calloc(1, sizeof(struct _notification)); + if (noti == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + ERR("OOM - notification handle"); + goto out; + } + + reply_body = g_variant_new_from_data(G_VARIANT_TYPE("(v)"), + data, data_size, TRUE, NULL, NULL); + g_variant_get(reply_body, "(v)", ¬i_body); + notification_ipc_make_noti_from_gvariant(noti, noti_body); + *list = notification_list_append(*list, noti); + g_variant_unref(noti_body); + g_variant_unref(reply_body); + list_count--; + } + +out: + if (ret != NOTIFICATION_ERROR_NONE) + notification_free_list(*list); + if (data) + free(data); + + return ret; +} + +int notification_ipc_request_load_noti_grouping_list(notification_type_e type, + int count, int count_per_page, notification_list_h *list, uid_t uid) +{ +#define RCV_SOCK 0 +#define SND_SOCK 1 + int result; + int sockfd[2] = { 0, }; + int list_count; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + result = notification_ipc_socket_pair(sockfd); + if (result != NOTIFICATION_ERROR_NONE) + return result; + INFO("socket receive[%d] send[%d]", sockfd[RCV_SOCK], sockfd[SND_SOCK]); + + body = g_variant_new("(iiii)", type, count, count_per_page, uid); + result = _send_sync_noti_with_fd(sockfd[SND_SOCK], body, &reply, "load_noti_grouping_list"); + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &list_count); + result = __receive_list_from_socket(sockfd[RCV_SOCK], list, list_count); + } + + if (reply) + g_object_unref(reply); + if (sockfd[RCV_SOCK]) + close(sockfd[RCV_SOCK]); + if (sockfd[SND_SOCK]) + close(sockfd[SND_SOCK]); + + INFO("result [%d]", result); + return result; +} + +int notification_ipc_request_load_noti_detail_list(const char *app_id, + int group_id, + int priv_id, + int count, + notification_list_h *list, + uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + GVariant *iter_body; + GVariantIter *iter; + notification_h noti; + GVariant *noti_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", result); + return result; + } + + body = g_variant_new("(siiii)", app_id, group_id, priv_id, count, uid); + result = _send_sync_noti(body, &reply, "load_noti_detail_list"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(a(v))", &iter); + + while (g_variant_iter_loop(iter, "(v)", &iter_body)) { + noti = notification_create(NOTIFICATION_TYPE_NOTI); + if (!noti) { + result = NOTIFICATION_ERROR_OUT_OF_MEMORY; + ERR("failed to create a notification"); + notification_free_list(*list); + break; + } + g_variant_get(iter_body, "(v)", ¬i_body); + notification_ipc_make_noti_from_gvariant(noti, noti_body); + *list = notification_list_append(*list, noti); + g_variant_unref(noti_body); + } + g_variant_iter_free(iter); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_get_setting_array( + notification_setting_h *setting_array, + int *count, + uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *reply_body; + GVariant *iter_body; + GVariantIter *iter; + int setting_cnt; + notification_setting_h result_setting_array; + notification_setting_h temp; + int setting_idx; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + result = _send_sync_noti(g_variant_new("(i)", uid), &reply, "get_setting_array"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(ia(v))", &setting_cnt, &iter); + + DBG("get setting arr cnt: %d", setting_cnt); + result_setting_array = (struct notification_setting *)malloc(sizeof(struct notification_setting) * setting_cnt); + if (result_setting_array == NULL) { + /* LCOV_EXCL_START */ + ERR("malloc failed"); + g_object_unref(reply); + g_variant_iter_free(iter); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + + setting_idx = 0; + while (g_variant_iter_loop(iter, "(v)", &iter_body)) { + temp = result_setting_array + setting_idx; + notification_ipc_make_setting_from_gvariant(temp, iter_body); + setting_idx++; + } + + *count = setting_cnt; + *setting_array = result_setting_array; + g_variant_iter_free(iter); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_get_setting_by_app_id( + const char *app_id, notification_setting_h *setting, uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + GVariant *setting_body; + notification_setting_h result_setting; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", result); + return result; + } + + body = g_variant_new("(si)", app_id, uid); + result = _send_sync_noti(body, &reply, "get_setting_by_app_id"); + + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(v)", &setting_body); + + result_setting = (struct notification_setting *)malloc(sizeof(struct notification_setting)); + if (result_setting == NULL) { + /* LCOV_EXCL_START */ + ERR("malloc failed"); + g_object_unref(reply); + g_variant_unref(body); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ + } + notification_ipc_make_setting_from_gvariant(result_setting, setting_body); + + *setting = result_setting; + g_variant_unref(setting_body); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_load_system_setting(notification_system_setting_h *setting, uid_t uid) +{ + int result; + int count; + GDBusMessage *reply = NULL; + GVariant *setting_body = NULL; + GVariant *reply_body = NULL; + GVariant *iter_body = NULL; + GVariantIter *iter = NULL; + notification_system_setting_h result_setting = NULL; + dnd_allow_exception_h dnd_allow_exception; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + result = _send_sync_noti(g_variant_new("(i)", uid), &reply, "load_system_setting"); + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(v)", &setting_body); + + result_setting = (struct notification_system_setting *)calloc(1, sizeof(struct notification_system_setting)); + if (result_setting == NULL) { + /* LCOV_EXCL_START */ + ERR("malloc failed"); + result = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + notification_ipc_make_system_setting_from_gvariant(result_setting, setting_body); + + result = _send_sync_noti(g_variant_new("(i)", uid), &reply, "load_dnd_allow_exception"); + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(ia(v))", &count, &iter); + + while (g_variant_iter_loop(iter, "(v)", &iter_body)) { + dnd_allow_exception = (dnd_allow_exception_h)calloc(1, sizeof(struct notification_system_setting_dnd_allow_exception)); + if (dnd_allow_exception == NULL) { + /* LCOV_EXCL_START */ + result = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + notification_ipc_make_dnd_allow_exception_from_gvariant(dnd_allow_exception, iter_body); + result_setting->dnd_allow_exceptions = g_list_append(result_setting->dnd_allow_exceptions, dnd_allow_exception); + } + *setting = result_setting; + } + } + +out: + if (result != NOTIFICATION_ERROR_NONE && result_setting) + notification_system_setting_free_system_setting(result_setting); + if (iter) + g_variant_iter_free(iter); + if (setting_body) + g_variant_unref(setting_body); + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_update_setting(notification_setting_h setting, uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(ssiiiiii)", + setting->package_name, + setting->app_id, + (int)(setting->allow_to_notify), + (int)(setting->do_not_disturb_except), + (int)(setting->visibility_class), + (int)(setting->pop_up_notification), + (int)(setting->lock_screen_content_level), + uid); + + result = _send_sync_noti(body, &reply, "update_noti_setting"); + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_update_system_setting(notification_system_setting_h system_setting, uid_t uid) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GList *list; + dnd_allow_exception_h dnd_allow_exception; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(iiiiiiiiii)", + (int)(system_setting->do_not_disturb), + (int)(system_setting->visibility_class), + (int)(system_setting->dnd_schedule_enabled), + (int)(system_setting->dnd_schedule_day), + (int)(system_setting->dnd_start_hour), + (int)(system_setting->dnd_start_min), + (int)(system_setting->dnd_end_hour), + (int)(system_setting->dnd_end_min), + (int)(system_setting->lock_screen_content_level), + uid); + + result = _send_sync_noti(body, &reply, "update_noti_sys_setting"); + + /* update dnd_allow_exceptions */ + list = g_list_first(system_setting->dnd_allow_exceptions); + + for (; list != NULL; list = list->next) { + dnd_allow_exception = list->data; + + body = g_variant_new("(iii)", + (int)(dnd_allow_exception->type), + (int)(dnd_allow_exception->value), + uid); + result = _send_sync_noti(body, &reply, "update_dnd_allow_exception"); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_save_as_template(notification_h noti, const char *template_name) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = notification_ipc_make_gvariant_from_noti(noti, false); + if (body == NULL) { + ERR("Failed to make gvariant from notification handle"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + + result = _send_sync_noti(g_variant_new("(vs)", body, template_name), &reply, "save_as_template"); + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + return result; +} + +int notification_ipc_request_create_from_template(notification_h noti, const char *template_name) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + GVariant *noti_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(s)", template_name); + + result = _send_sync_noti(body, &reply, "create_from_template"); + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(v)", ¬i_body); + + notification_ipc_make_noti_from_gvariant(noti, noti_body); + g_variant_unref(noti_body); + _print_noti(noti); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + + return result; +} + +int notification_ipc_request_create_from_package_template(notification_h noti, const char *app_id, const char *template_name) +{ + int result; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + GVariant *noti_body; + + result = _dbus_init(); + if (result != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", result); + return result; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(ss)", app_id, template_name); + + result = _send_sync_noti(body, &reply, "create_from_package_template"); + if (result == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(v)", ¬i_body); + + notification_ipc_make_noti_from_gvariant(noti, noti_body); + g_variant_unref(noti_body); + _print_noti(noti); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", result); + + return result; +} + +int notification_ipc_get_noti_block_state(const char *app_id, int *do_not_disturb, + int *do_not_disturb_except, int *allow_to_notify, + uid_t uid) +{ + int ret; + int dnd; + int dnd_except; + int allow; + GDBusMessage *reply = NULL; + GVariant *body; + GVariant *reply_body; + GVariant *result_body; + + if (app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = _dbus_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + body = g_variant_new("(si)", app_id, uid); + + ret = _send_sync_noti(body, &reply, "get_noti_block_state"); + + if (ret == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(v)", &result_body); + g_variant_get(result_body, "(iii)", &dnd, &dnd_except, &allow); + *do_not_disturb = dnd; + *do_not_disturb_except = dnd_except; + *allow_to_notify = allow; + g_variant_unref(result_body); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", ret); + + return ret; +} + +int notification_ipc_request_get_all_count(notification_type_e type, int *count, uid_t uid) +{ + int ret; + int ret_count = -1; + GDBusMessage *reply = NULL; + GVariant *reply_body = NULL; + + ret = _dbus_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", ret); + return ret; + } + + ret = _send_sync_noti(g_variant_new("(ii)", type, uid), + &reply, "get_noti_all_count"); + if (ret == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &ret_count); + *count = ret_count; + } + + if (reply) + g_object_unref(reply); + + return ret; +} + +int notification_ipc_send_event(notification_h noti, int event_type, int priv_id) +{ + int ret; + GVariant *body = NULL; + GDBusMessage *reply = NULL; + + ret = _dbus_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + if (priv_id > 0) { + ret = _send_sync_noti(g_variant_new("(ii)", priv_id, event_type), &reply, "send_noti_event_by_priv_id"); + } else { + body = notification_ipc_make_gvariant_from_noti(noti, false); + if (body == NULL) { + ERR("Can't make gvariant to noti"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + + ret = _send_sync_noti(g_variant_new("(vi)", body, event_type), &reply, "send_noti_event"); + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", ret); + + return ret; +} + +int notification_ipc_check_event_receiver(int priv_id, bool *available) +{ + int ret; + int ret_available; + GVariant *reply_body = NULL; + GDBusMessage *reply = NULL; + + ret = _dbus_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + ret = _send_sync_noti(g_variant_new("(i)", priv_id), &reply, "check_event_receiver"); + if (ret == NOTIFICATION_ERROR_NONE) { + reply_body = g_dbus_message_get_body(reply); + g_variant_get(reply_body, "(i)", &ret_available); + *available = (bool)ret_available; + } + + if (reply) + g_object_unref(reply); + + DBG("result[%d]", ret); + return ret; +} + +/* LCOV_EXCL_START */ +void notification_ipc_reset_event_handler(int priv_id) +{ + int ret; + GDBusMessage *reply = NULL; + + ret = _dbus_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to init dbus connection[%d]", ret); + return; + } + + _send_sync_noti(g_variant_new("(i)", priv_id), &reply, "reset_event_handler"); + + if (reply) + g_object_unref(reply); +} +/* LCOV_EXCL_STOP */ + +EXPORT_API GVariant *notification_ipc_make_gvariant_from_noti(notification_h noti, bool translate) +{ + DBG("make gvariant from noti"); + int i = 0; + int b_encode_len = 0; + bundle_raw *args = NULL; + bundle_raw *group_args = NULL; + bundle_raw *b_image_path = NULL; + bundle_raw *b_priv_image_path = NULL; + bundle_raw *b_execute_option = NULL; + bundle_raw *b_service_responding = NULL; + bundle_raw *b_service_single_launch = NULL; + bundle_raw *b_service_multi_launch = NULL; + bundle_raw *b_event_handler[NOTIFICATION_EVENT_TYPE_MAX+1] = {NULL, }; + bundle_raw *b_text = NULL; + bundle_raw *b_key = NULL; + bundle_raw *b_format_args = NULL; + GVariant *body = NULL; + GVariant *result_body = NULL; + GVariantBuilder builder; + + if (translate) + notification_translate_localized_text(noti); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{iv}")); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_NOTI_TYPE, g_variant_new_int32(noti->type)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_LAYOUT, g_variant_new_int32(noti->layout)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_GROUP_ID, g_variant_new_int32(noti->group_id)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_INTERNAL_GROUP_ID, g_variant_new_int32(noti->internal_group_id)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_PRIV_ID, g_variant_new_int32(noti->priv_id)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_PKG_ID, g_variant_new_string((const gchar *)noti->pkg_id)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_CALLER_APP_ID, g_variant_new_string((const gchar *)noti->caller_app_id)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_DISPLAY_APPLIST, g_variant_new_int32(noti->display_applist)); + + if (noti->args) { + bundle_encode(noti->args, (bundle_raw **)&args, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_ARGS, g_variant_new_string((const gchar *)args)); + + if (args) + bundle_free_encoded_rawdata(&args); + } + + if (noti->group_args) { + bundle_encode(noti->group_args, (bundle_raw **)&group_args, + &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_GROUP_ARGS, g_variant_new_string((const gchar *)group_args)); + + if (group_args) + bundle_free_encoded_rawdata(&group_args); + } + + if (noti->b_execute_option) { + bundle_encode(noti->b_execute_option, + (bundle_raw **)&b_execute_option, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_EXECUTE_OPTION, g_variant_new_string((const gchar *)b_execute_option)); + + if (b_execute_option) + bundle_free_encoded_rawdata(&b_execute_option); + } + + if (noti->b_service_responding) { + bundle_encode(noti->b_service_responding, + (bundle_raw **)&b_service_responding, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_SERVICE_RESPONDING, g_variant_new_string((const gchar *)b_service_responding)); + + if (b_service_responding) + bundle_free_encoded_rawdata(&b_service_responding); + } + + if (noti->b_service_single_launch) { + bundle_encode(noti->b_service_single_launch, + (bundle_raw **)&b_service_single_launch, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_SERVICE_SINGLE_LAUNCH, g_variant_new_string((const gchar *)b_service_single_launch)); + + if (b_service_single_launch) + bundle_free_encoded_rawdata(&b_service_single_launch); + } + + if (noti->b_service_multi_launch) { + bundle_encode(noti->b_service_multi_launch, + (bundle_raw **)&b_service_multi_launch, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_SERVICE_MULTI_LAUNCH, g_variant_new_string((const gchar *)b_service_multi_launch)); + + if (b_service_multi_launch) + bundle_free_encoded_rawdata(&b_service_multi_launch); + } + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) { + if (noti->b_event_handler[i]) { + bundle_encode(noti->b_event_handler[i], + (bundle_raw **)&b_event_handler[i], &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_BUTTON1_EVENT + i, g_variant_new_string((const gchar *)b_event_handler[i])); + + if (b_event_handler[i]) + bundle_free_encoded_rawdata(&b_event_handler[i]); + } + } + + if (noti->launch_app_id) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_LAUNCH_APP_ID, g_variant_new_string((const gchar *)noti->launch_app_id)); + + if (noti->domain != NULL) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_DOMAIN, g_variant_new_string((const gchar *)noti->domain)); + + if (noti->dir != NULL) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_DIR, g_variant_new_string((const gchar *)noti->dir)); + + if (noti->b_text) { + bundle_encode(noti->b_text, (bundle_raw **)&b_text, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_TEXT, g_variant_new_string((const gchar *)b_text)); + + if (b_text) + bundle_free_encoded_rawdata(&b_text); + } + + if (noti->b_key) { + bundle_encode(noti->b_key, (bundle_raw **)&b_key, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_KEY, g_variant_new_string((const gchar *)b_key)); + + if (b_key) + bundle_free_encoded_rawdata(&b_key); + } + + if (noti->b_format_args) { + bundle_encode(noti->b_format_args, + (bundle_raw **)&b_format_args, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_FORMAT_ARGS, g_variant_new_string((const gchar *)b_format_args)); + + if (b_format_args) + bundle_free_encoded_rawdata(&b_format_args); + } + + if (noti->num_format_args != 0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_NUM_FORMAT_ARGS, g_variant_new_int32(noti->num_format_args)); + + if (noti->b_image_path) { + bundle_encode(noti->b_image_path, + (bundle_raw **)&b_image_path, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_IMAGE_PATH, g_variant_new_string((const gchar *)b_image_path)); + + if (b_image_path) + bundle_free_encoded_rawdata(&b_image_path); + } + + if (noti->b_priv_image_path) { + bundle_encode(noti->b_priv_image_path, + (bundle_raw **)&b_priv_image_path, &b_encode_len); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_PRIV_IMAGE_PATH, g_variant_new_string((const gchar *)b_priv_image_path)); + + if (b_priv_image_path) + bundle_free_encoded_rawdata(&b_priv_image_path); + } + + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_SOUND_TYPE, g_variant_new_int32(noti->sound_type)); + + if (noti->sound_path) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_SOUND_PATH, g_variant_new_string((const gchar *)noti->sound_path)); + + if (noti->priv_sound_path) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_PRIV_SOUND_PATH, g_variant_new_string((const gchar *)noti->priv_sound_path)); + + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_VIBRATION_TYPE, g_variant_new_int32(noti->vibration_type)); + + if (noti->vibration_path) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_VIBRATION_PATH, g_variant_new_string((const gchar *)noti->vibration_path)); + + if (noti->priv_vibration_path) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_PRIV_VIBRATION_PATH, g_variant_new_string((const gchar *)noti->priv_vibration_path)); + + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_LED_OPERATION, g_variant_new_int32(noti->led_operation)); + + if (noti->led_argb != 0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_LED_ARGB, g_variant_new_int32(noti->led_argb)); + + if (noti->led_on_ms != 0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_LED_ON_MS, g_variant_new_int32(noti->led_on_ms)); + + if (noti->led_off_ms != 0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_LED_OFF_MS, g_variant_new_int32(noti->led_off_ms)); + + if (noti->time != 0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_TIME, g_variant_new_int32(noti->time)); + + if (noti->insert_time != 0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_INSERT_TIME, g_variant_new_int32(noti->insert_time)); + + if (noti->flags_for_property != 0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_FLAGS_FOR_PROPERTY, g_variant_new_int32(noti->flags_for_property)); + + if (noti->progress_size != 0.0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_PROGRESS_SIZE, g_variant_new_double(noti->progress_size)); + + if (noti->progress_percentage != 0.0) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_PROGRESS_PERCENTAGE, g_variant_new_double(noti->progress_percentage)); + + if (noti->app_icon_path != NULL) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_APP_ICON_PATH, g_variant_new_string((const gchar *)noti->app_icon_path)); + if (noti->app_label != NULL) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_APP_LABEL, g_variant_new_string((const gchar *)noti->app_label)); + if (noti->temp_title != NULL) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_TEMP_TITLE, g_variant_new_string((const gchar *)noti->temp_title)); + if (noti->temp_content != NULL) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_TEMP_CONTENT, g_variant_new_string((const gchar *)noti->temp_content)); + if (noti->tag != NULL) + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_TAG, g_variant_new_string((const gchar *)noti->tag)); + + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_ONGOING_FLAG, g_variant_new_int32(noti->ongoing_flag)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_ONGOING_VALUE_TYPE, g_variant_new_int32(noti->ongoing_value_type)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_ONGOING_CURRENT, g_variant_new_int32(noti->ongoing_current)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_ONGOING_DURATION, g_variant_new_int32(noti->ongoing_duration)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_AUTO_REMOVE, g_variant_new_int32(noti->auto_remove)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_DEFAULT_BUTTON, g_variant_new_int32(noti->default_button_index)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_HIDE_TIMEOUT, g_variant_new_int32(noti->hide_timeout)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_DELETE_TIMEOUT, g_variant_new_int32(noti->delete_timeout)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_TEXT_INPUT_MAX_LENGTH, g_variant_new_int32(noti->text_input_max_length)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_EVENT_FLAG, g_variant_new_int32(noti->event_flag)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_TRANSLATION, g_variant_new_int32(noti->is_translation)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_EXTENSION_IMAGE_SIZE, g_variant_new_int32(noti->extension_image_size)); + g_variant_builder_add(&builder, "{iv}", NOTIFICATION_DATA_TYPE_UID, g_variant_new_int32(noti->uid)); + + result_body = g_variant_builder_end(&builder); + body = g_variant_new("(v)", result_body); + + return body; +} + +static gboolean _variant_to_int_dict(GHashTable **dict, GVariant *variant) +{ + GVariantIter iter; + int key; + int *hash_key; + GVariant *value; + + *dict = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, (GDestroyNotify)g_variant_unref); + if (*dict == NULL) + return FALSE; + + g_variant_iter_init(&iter, variant); + while (g_variant_iter_next(&iter, "{iv}", &key, &value)) { + hash_key = (int *)calloc(sizeof(int), 1); + if (hash_key == NULL) { + /* LCOV_EXCL_START */ + g_hash_table_unref(*dict); + return FALSE; + /* LCOV_EXCL_STOP */ + } + *hash_key = key; + g_hash_table_insert(*dict, (gpointer)hash_key, value); + } + return TRUE; +} + +static gboolean _variant_dict_lookup(GHashTable *dict, + int key, + const gchar *format_string, + ...) +{ + GVariant *value; + va_list ap; + + value = g_hash_table_lookup(dict, (gpointer)&key); + + if (value == NULL || !g_variant_check_format_string(value, format_string, FALSE)) + return FALSE; + + va_start(ap, format_string); + g_variant_get_va(value, format_string, NULL, &ap); + va_end(ap); + + return TRUE; +} + +/*! + * functions creating notification packet + */ +EXPORT_API int notification_ipc_make_noti_from_gvariant(notification_h noti, + GVariant *variant) { + + DBG("make noti from GVariant"); + GHashTable *dict; + + int i; + char *pkg_id = NULL; + char *caller_app_id = NULL; + char *launch_app_id = NULL; + bundle_raw *args = NULL; + bundle_raw *group_args = NULL; + bundle_raw *b_execute_option = NULL; + bundle_raw *b_service_responding = NULL; + bundle_raw *b_service_single_launch = NULL; + bundle_raw *b_service_multi_launch = NULL; + bundle_raw *b_event_handler[NOTIFICATION_EVENT_TYPE_MAX+1] = { NULL, }; + char *domain = NULL; + char *dir = NULL; + bundle_raw *b_text = NULL; + bundle_raw *b_key = NULL; + bundle_raw *b_format_args = NULL; + bundle_raw *b_image_path = NULL; + bundle_raw *b_priv_image_path = NULL; + char *sound_path = NULL; + char *priv_sound_path = NULL; + char *vibration_path = NULL; + char *priv_vibration_path = NULL; + char *app_icon_path = NULL; + char *app_label = NULL; + char *temp_title = NULL; + char *temp_content = NULL; + char *tag = NULL; + + if (noti == NULL) { + ERR("Invalid noti NULL"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (variant == NULL) { + ERR("Invalid variant NULL"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (!_variant_to_int_dict(&dict, variant)) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_NOTI_TYPE, "i", ¬i->type); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_LAYOUT, "i", ¬i->layout); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_GROUP_ID, "i", ¬i->group_id); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_INTERNAL_GROUP_ID, "i", ¬i->internal_group_id); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_PRIV_ID, "i", ¬i->priv_id); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_PKG_ID, "&s", &pkg_id); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_CALLER_APP_ID, "&s", &caller_app_id); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_LAUNCH_APP_ID, "&s", &launch_app_id); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_ARGS, "&s", &args); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_GROUP_ARGS, "&s", &group_args); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_EXECUTE_OPTION, "&s", &b_execute_option); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_SERVICE_RESPONDING, "&s", &b_service_responding); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_SERVICE_SINGLE_LAUNCH, "&s", &b_service_single_launch); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_SERVICE_MULTI_LAUNCH, "&s", &b_service_multi_launch); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON1_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_1]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON2_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_2]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON3_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_3]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON4_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_4]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON5_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_5]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON6_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_6]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_ICON_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_ICON]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_THUMBNAIL_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_THUMBNAIL]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TEXT_INPUT_BUTTON_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_TEXT_INPUT_BUTTON]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON7_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_7]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON8_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_8]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON9_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_9]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_BUTTON10_EVENT, "&s", &b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_10]); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_DOMAIN, "&s", &domain); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_DIR, "&s", &dir); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TEXT, "&s", &b_text); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_KEY, "&s", &b_key); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_FORMAT_ARGS, "&s", &b_format_args); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_NUM_FORMAT_ARGS, "i", ¬i->num_format_args); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_IMAGE_PATH, "&s", &b_image_path); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_PRIV_IMAGE_PATH, "&s", &b_priv_image_path); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_SOUND_TYPE, "i", ¬i->sound_type); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_SOUND_PATH, "&s", &sound_path); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_PRIV_SOUND_PATH, "&s", &priv_sound_path); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_VIBRATION_TYPE, "i", ¬i->vibration_type); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_VIBRATION_PATH, "&s", &vibration_path); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_PRIV_VIBRATION_PATH, "&s", &priv_vibration_path); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_LED_OPERATION, "i", ¬i->led_operation); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_LED_ARGB, "i", ¬i->led_argb); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_LED_ON_MS, "i", ¬i->led_on_ms); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_LED_OFF_MS, "i", ¬i->led_off_ms); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TIME, "i", ¬i->time); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_INSERT_TIME, "i", ¬i->insert_time); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_FLAGS_FOR_PROPERTY, "i", ¬i->flags_for_property); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_DISPLAY_APPLIST, "i", ¬i->display_applist); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_PROGRESS_SIZE, "d", ¬i->progress_size); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_PROGRESS_PERCENTAGE, "d", ¬i->progress_percentage); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_APP_ICON_PATH, "&s", &app_icon_path); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_APP_LABEL, "&s", &app_label); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TEMP_TITLE, "&s", &temp_title); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TEMP_CONTENT, "&s", &temp_content); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TAG, "&s", &tag); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_ONGOING_FLAG, "i", ¬i->ongoing_flag); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_ONGOING_VALUE_TYPE, "i", ¬i->ongoing_value_type); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_ONGOING_CURRENT, "i", ¬i->ongoing_current); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_ONGOING_DURATION, "i", ¬i->ongoing_duration); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_AUTO_REMOVE, "i", ¬i->auto_remove); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_DEFAULT_BUTTON, "i", ¬i->default_button_index); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_HIDE_TIMEOUT, "i", ¬i->hide_timeout); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_DELETE_TIMEOUT, "i", ¬i->delete_timeout); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TEXT_INPUT_MAX_LENGTH, "i", ¬i->text_input_max_length); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_EVENT_FLAG, "i", ¬i->event_flag); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_TRANSLATION, "i", ¬i->is_translation); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_EXTENSION_IMAGE_SIZE, "i", ¬i->extension_image_size); + _variant_dict_lookup(dict, NOTIFICATION_DATA_TYPE_UID, "i", ¬i->uid); + + if (noti->pkg_id) + free(noti->pkg_id); + noti->pkg_id = _dup_string(pkg_id); + + if (noti->caller_app_id) + free(noti->caller_app_id); + noti->caller_app_id = _dup_string(caller_app_id); + + noti->launch_app_id = _dup_string(launch_app_id); + + noti->args = _create_bundle_from_bundle_raw(args); + noti->group_args = _create_bundle_from_bundle_raw(group_args); + noti->b_execute_option = _create_bundle_from_bundle_raw(b_execute_option); + noti->b_service_responding = _create_bundle_from_bundle_raw( + b_service_responding); + noti->b_service_single_launch = _create_bundle_from_bundle_raw( + b_service_single_launch); + noti->b_service_multi_launch = _create_bundle_from_bundle_raw( + b_service_multi_launch); + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) { + noti->b_event_handler[i] = _create_bundle_from_bundle_raw( + b_event_handler[i]); + } + + if (noti->domain) + free(noti->domain); + noti->domain = _dup_string(domain); + + if (noti->dir) + free(noti->dir); + noti->dir = _dup_string(dir); + + noti->b_text = _create_bundle_from_bundle_raw(b_text); + noti->b_key = _create_bundle_from_bundle_raw(b_key); + noti->b_format_args = _create_bundle_from_bundle_raw(b_format_args); + noti->b_image_path = _create_bundle_from_bundle_raw(b_image_path); + noti->b_priv_image_path = _create_bundle_from_bundle_raw(b_priv_image_path); + noti->sound_path = _dup_string(sound_path); + noti->priv_sound_path = _dup_string(priv_sound_path); + noti->vibration_path = _dup_string(vibration_path); + noti->priv_vibration_path = _dup_string(priv_vibration_path); + noti->app_icon_path = _dup_string(app_icon_path); + noti->app_label = _dup_string(app_label); + noti->temp_title = _dup_string(temp_title); + noti->temp_content = _dup_string(temp_content); + noti->tag = _dup_string(tag); + + g_hash_table_unref(dict); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API GVariant *notification_ipc_make_gvariant_from_system_setting(struct notification_system_setting *noti_setting) +{ + GVariant *body = NULL; + + body = g_variant_new("(iiiiiiiii)", + noti_setting->do_not_disturb, + noti_setting->visibility_class, + noti_setting->dnd_schedule_enabled, + noti_setting->dnd_schedule_day, + noti_setting->dnd_start_hour, + noti_setting->dnd_start_min, + noti_setting->dnd_end_hour, + noti_setting->dnd_end_min, + noti_setting->lock_screen_content_level); + return body; +} + +EXPORT_API int notification_ipc_make_system_setting_from_gvariant(struct notification_system_setting *noti_setting, + GVariant *variant) +{ + int do_not_disturb; + int visibility_class; + int dnd_schedule_enabled; + int dnd_schedule_day; + int dnd_start_hour; + int dnd_start_min; + int dnd_end_hour; + int dnd_end_min; + int lock_screen_content_level; + + if (noti_setting == NULL) { + ERR("Invalid setting handle"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + g_variant_get(variant, + "(iiiiiiiii)", + &do_not_disturb, + &visibility_class, + &dnd_schedule_enabled, + &dnd_schedule_day, + &dnd_start_hour, + &dnd_start_min, + &dnd_end_hour, + &dnd_end_min, + &lock_screen_content_level); + + DBG("system setting %d, %d, %d, %d, [%d:%d] [%d:%d], %d", + do_not_disturb, visibility_class, dnd_schedule_enabled, + dnd_schedule_day, dnd_start_hour, dnd_start_min, + dnd_end_hour, dnd_end_min, lock_screen_content_level); + + noti_setting->do_not_disturb = do_not_disturb; + noti_setting->visibility_class = visibility_class; + noti_setting->dnd_schedule_enabled = dnd_schedule_enabled; + noti_setting->dnd_schedule_day = dnd_schedule_day; + noti_setting->dnd_start_hour = dnd_start_hour; + noti_setting->dnd_start_min = dnd_start_min; + noti_setting->dnd_end_hour = dnd_end_hour; + noti_setting->dnd_end_min = dnd_end_min; + noti_setting->lock_screen_content_level = lock_screen_content_level; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API GVariant *notification_ipc_make_gvariant_from_setting(struct notification_setting *noti_setting) +{ + GVariant *body = NULL; + + body = g_variant_new("(ssiiiiii)", + noti_setting->package_name, + noti_setting->app_id, + noti_setting->allow_to_notify, + noti_setting->do_not_disturb_except, + noti_setting->visibility_class, + noti_setting->pop_up_notification, + noti_setting->lock_screen_content_level, + noti_setting->app_disabled); + + return body; +} + +EXPORT_API int notification_ipc_make_setting_from_gvariant(struct notification_setting *noti_setting, + GVariant *variant) +{ + char *pkgname; + char *app_id; + int allow_to_notify; + int do_not_disturb_except; + int visibility_class; + int pop_up_notification; + int lock_screen_content_level; + int app_disabled; + + if (noti_setting == NULL || variant == NULL) { + ERR("invalid data"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + g_variant_get(variant, + "(&s&siiiiii)", + &pkgname, + &app_id, + &allow_to_notify, + &do_not_disturb_except, + &visibility_class, + &pop_up_notification, + &lock_screen_content_level, + &app_disabled); + + DBG("setting from variant %s !!", pkgname); + + noti_setting->package_name = _dup_string(pkgname); + noti_setting->app_id = _dup_string(app_id); + noti_setting->allow_to_notify = allow_to_notify; + noti_setting->do_not_disturb_except = do_not_disturb_except; + noti_setting->visibility_class = visibility_class; + noti_setting->pop_up_notification = pop_up_notification; + noti_setting->lock_screen_content_level = lock_screen_content_level; + noti_setting->app_disabled = app_disabled; + + DBG("setting->pkgname[%s] pkgname[%s]", + noti_setting->package_name, pkgname); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API GVariant *notification_ipc_make_gvariant_from_dnd_allow_exception(struct notification_system_setting_dnd_allow_exception *dnd_allow_exception) +{ + GVariant *body = NULL; + + body = g_variant_new("(ii)", + dnd_allow_exception->type, + dnd_allow_exception->value); + + return body; +} + +int notification_ipc_make_dnd_allow_exception_from_gvariant(struct notification_system_setting_dnd_allow_exception *dnd_allow_exception, GVariant *variant) +{ + int type; + int value; + + if (dnd_allow_exception == NULL) { + ERR("Invalid data"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + g_variant_get(variant, "(ii)", &type, &value); + + dnd_allow_exception->type = type; + dnd_allow_exception->value = value; + + return NOTIFICATION_ERROR_NONE; +} + +static int _send_service_register(uid_t uid) +{ + int result; + notification_op *noti_op = NULL; + GDBusMessage *reply = NULL; + + result = _send_sync_noti(g_variant_new("(i)", uid), &reply, "noti_service_register"); + if (reply) + g_object_unref(reply); + if (result != NOTIFICATION_ERROR_NONE) { + ERR("send sync noti [%d]", result); + return result; + } + + is_master_started = 1; + + noti_op = _ipc_create_op(NOTIFICATION_OP_SERVICE_READY, 1, NULL, 1, NULL); + if (noti_op != NULL) { + notification_call_changed_cb_for_uid(noti_op, 1, uid); + free(noti_op); + } else { + ERR("Failed to create op"); + } + + DBG("bus name[%s] result[%d]", _bus_name, result); + return result; +} + +static int _ipc_monitor_register(uid_t uid) +{ + return _send_service_register(uid); +} + +/* LCOV_EXCL_START */ +static void _on_name_appeared(GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + int uid = GPOINTER_TO_INT(user_data); + + DBG("uid[%d] name[%s]", uid, name); + + if (is_master_started == 0) + _ipc_monitor_register(uid); + + /* TODO: dbus activation isn't enough ? */ + _do_deffered_task(); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static void _on_name_vanished(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + int uid = GPOINTER_TO_INT(user_data); + + DBG("uid[%d] name[%s]", uid, name); + is_master_started = 0; +} +/* LCOV_EXCL_STOP */ + +int notification_ipc_monitor_init(uid_t uid) +{ + int ret; + + ret = _dbus_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init dbus connection[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + ret = _dbus_signal_init(); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init signal[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + ret = _ipc_monitor_register(uid); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to register service[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + if (provider_monitor_id == 0) { + provider_monitor_id = g_bus_watch_name_on_connection( + _gdbus_conn, + PROVIDER_BUS_NAME, + G_BUS_NAME_WATCHER_FLAGS_NONE, + _on_name_appeared, + _on_name_vanished, + GINT_TO_POINTER((int)uid), + NULL); + if (provider_monitor_id == 0) { + /* LCOV_EXCL_START */ + g_dbus_connection_signal_unsubscribe(_gdbus_conn, monitor_id); + monitor_id = 0; + ERR("Failed to watch name"); + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + } + + return NOTIFICATION_ERROR_NONE; +} + +static int _ipc_monitor_deregister(void) +{ + if (provider_monitor_id) { + g_bus_unwatch_name(provider_monitor_id); + provider_monitor_id = 0; + } + + if (monitor_id) { + g_dbus_connection_signal_unsubscribe(_gdbus_conn, monitor_id); + monitor_id = 0; + } + + return NOTIFICATION_ERROR_NONE; +} + +int notification_ipc_monitor_fini(void) +{ + return _ipc_monitor_deregister(); +} + +/* LCOV_EXCL_START */ +void notification_ipc_event_monitor_fini(void) +{ + if (event_monitor_id == 0) + return; + + g_dbus_connection_signal_unsubscribe(_gdbus_conn, event_monitor_id); + event_monitor_id = 0; +} +/* LCOV_EXCL_STOP */ diff --git a/notification/src/notification_ipc_socket.c b/notification/src/notification_ipc_socket.c new file mode 100644 index 0000000..54090ac --- /dev/null +++ b/notification/src/notification_ipc_socket.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include "notification_ipc.h" +#include "notification_debug.h" + +#define RCV_SOCK 0 +#define SND_SOCK 1 + +#define MAX_RETRY_CNT 10 +#define WRITE_TIMEOUT 20 /* milliseconds*/ + +EXPORT_API int notification_ipc_socket_pair(int *fd) +{ + int ret_fd[2]; + int err; + + if (fd == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + errno = 0; + err = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, ret_fd); + if (err < 0) { + ERR("socketpair [%d]", errno); + return NOTIFICATION_ERROR_IO_ERROR; + } + + fd[RCV_SOCK] = ret_fd[RCV_SOCK]; + fd[SND_SOCK] = ret_fd[SND_SOCK]; + + return NOTIFICATION_ERROR_NONE; +} + +static int __get_socket_buffer_size(int fd, unsigned int *size, int optname) +{ + unsigned int ret_size = 0; + socklen_t len = sizeof(ret_size); + + errno = 0; + if (getsockopt(fd, SOL_SOCKET, optname, &ret_size, &len) < 0) { + ERR("read socket size [%d]", errno); + return NOTIFICATION_ERROR_IO_ERROR; + } + + *size = ret_size; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_ipc_socket_get_read_buf_size(int fd, unsigned int *size) +{ + return __get_socket_buffer_size(fd, size, SO_RCVBUF); +} + +EXPORT_API int notification_ipc_socket_get_write_buf_size(int fd, unsigned int *size) +{ + return __get_socket_buffer_size(fd, size, SO_SNDBUF); +} + + +EXPORT_API int notification_ipc_socket_write(int fd, const char *buffer, unsigned int nbytes) +{ + int retry_cnt = 0; + unsigned int left = nbytes; + ssize_t nb; + const struct timespec SLEEP_TIME = { 0, 20 * 1000 * 1000 }; + + while (left && (retry_cnt < MAX_RETRY_CNT)) { + errno = 0; + nb = write(fd, buffer, left); + if (nb == -1) { + /* LCOV_EXCL_START */ + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { + ERR("continue.."); + retry_cnt++; + nanosleep(&SLEEP_TIME, 0); + continue; + } + ERR("error fd [%d] errno [%d]", fd, errno); + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + + left -= nb; + buffer += nb; + retry_cnt = 0; + } + + if (left != 0) { + ERR("error fd [%d], retry_cnt [%d]", fd, retry_cnt); + return NOTIFICATION_ERROR_IO_ERROR; + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_ipc_socket_write_string(int fd, const char *buffer, unsigned int string_len) +{ + int ret; + + ret = notification_ipc_socket_write(fd, (char *)&string_len, sizeof(string_len)); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("write string_len fail"); + return ret; + /* LCOV_EXCL_STOP */ + } + + if (string_len > 0) { + ret = notification_ipc_socket_write(fd, buffer, string_len); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("write string fail"); + return ret; + /* LCOV_EXCL_STOP */ + } + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_ipc_socket_read(int fd, char *buffer, unsigned int nbytes) +{ + unsigned int left = nbytes; + ssize_t nb; + int retry_cnt = 0; + const struct timespec SLEEP_TIME = { 0, 20 * 1000 * 1000 }; + + while (left && (retry_cnt < MAX_RETRY_CNT)) { + errno = 0; + nb = read(fd, buffer, left); + if (nb == 0) { + ERR("read socket - EOF, fd close [%d]", fd); + return NOTIFICATION_ERROR_IO_ERROR; + } else if (nb == -1) { + if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) { + ERR("errno [%d], sleep and retry", errno); + retry_cnt++; + nanosleep(&SLEEP_TIME, 0); + continue; + } + ERR("errno [%d] fd [%d]", errno, fd); + return NOTIFICATION_ERROR_IO_ERROR; + } + left -= nb; + buffer += nb; + retry_cnt = 0; + } + + if (left != 0) { + ERR("error fd [%d] retry_cnt [%d]", fd, retry_cnt); + return NOTIFICATION_ERROR_IO_ERROR; + } + + return NOTIFICATION_ERROR_NONE; +} diff --git a/notification/src/notification_list.c b/notification/src/notification_list.c new file mode 100644 index 0000000..18d14b2 --- /dev/null +++ b/notification/src/notification_list.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> + +#include <tizen.h> + +#include <notification.h> +#include <notification_list.h> +#include <notification_noti.h> +#include <notification_debug.h> +#include <notification_private.h> +#include <notification_ipc.h> + + +struct _notification_list { + notification_list_h prev; + notification_list_h next; + notification_h noti; +}; + +notification_list_h _notification_list_create(void) +{ + notification_list_h list = NULL; + + list = (notification_list_h)malloc(sizeof(struct _notification_list)); + if (list == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + return NULL; + /* LCOV_EXCL_STOP */ + } + + list->prev = NULL; + list->next = NULL; + + list->noti = NULL; + + return list; +} + +EXPORT_API notification_list_h notification_list_get_head(notification_list_h list) +{ + notification_list_h cur_list = NULL; + + if (list == NULL) { + ERR("Invalid parameter"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + cur_list = list; + + while (cur_list->prev != NULL) + cur_list = cur_list->prev; + + set_last_result(NOTIFICATION_ERROR_NONE); + return cur_list; +} + +EXPORT_API notification_list_h notification_list_get_tail(notification_list_h list) +{ + notification_list_h cur_list = NULL; + + if (list == NULL) { + ERR("INVALID DATA : list == NULL"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + cur_list = list; + + while (cur_list->next != NULL) + cur_list = cur_list->next; + + set_last_result(NOTIFICATION_ERROR_NONE); + return cur_list; +} + +EXPORT_API notification_list_h notification_list_get_prev(notification_list_h list) +{ + notification_list_h cur_list = NULL; + + if (list == NULL) { + ERR("INVALID DATA : list == NULL"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + cur_list = list; + + set_last_result(NOTIFICATION_ERROR_NONE); + return cur_list->prev; +} + +EXPORT_API notification_list_h notification_list_get_next(notification_list_h list) +{ + notification_list_h cur_list = NULL; + + if (list == NULL) { + ERR("INVALID DATA : list == NULL"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + cur_list = list; + + set_last_result(NOTIFICATION_ERROR_NONE); + return cur_list->next; +} + +EXPORT_API notification_h notification_list_get_data(notification_list_h list) +{ + notification_list_h cur_list = NULL; + + if (list == NULL) { + ERR("INVALID DATA : list == NULL"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + cur_list = list; + + set_last_result(NOTIFICATION_ERROR_NONE); + return cur_list->noti; +} + +EXPORT_API int notification_list_get_count(notification_list_h list) +{ + int count = 0; + notification_list_h cur_list = NULL; + + if (list == NULL) { + ERR("Invalid paramter"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return 0; + } + + cur_list = notification_list_get_head(list); + + while (cur_list != NULL) { + count++; + cur_list = cur_list->next; + } + + set_last_result(NOTIFICATION_ERROR_NONE); + return count; +} + +EXPORT_API notification_list_h notification_list_append(notification_list_h list, + notification_h noti) +{ + notification_list_h new_list = NULL; + notification_list_h cur_list = NULL; + + if (noti == NULL) { + ERR("Invalid parameter"); + set_last_result(NOTIFICATION_ERROR_INVALID_PARAMETER); + return NULL; + } + + if (list != NULL) { + cur_list = notification_list_get_tail(list); + + new_list = _notification_list_create(); + if (new_list == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + return NULL; + /* LCOV_EXCL_STOP */ + } + + cur_list->next = new_list; + new_list->prev = cur_list; + + new_list->noti = noti; + } else { + cur_list = _notification_list_create(); + if (cur_list == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + set_last_result(NOTIFICATION_ERROR_OUT_OF_MEMORY); + return NULL; + /* LCOV_EXCL_STOP */ + } + + new_list = cur_list; + new_list->noti = noti; + } + + set_last_result(NOTIFICATION_ERROR_NONE); + return new_list; +} + +EXPORT_API notification_list_h notification_list_remove(notification_list_h list, + notification_h noti) +{ + notification_list_h cur_list = NULL; + notification_list_h prev_list = NULL; + notification_list_h next_list = NULL; + + cur_list = notification_list_get_head(list); + while (cur_list != NULL) { + if (cur_list->noti == noti) { + /* remove */ + prev_list = cur_list->prev; + next_list = cur_list->next; + + if (next_list != NULL) { + if (prev_list != NULL) { + prev_list->next = next_list; + next_list->prev = prev_list; + } else { + next_list->prev = NULL; + } + } else { + if (prev_list != NULL) + prev_list->next = NULL; + } + + free(cur_list); + break; + } + + cur_list = cur_list->next; + } + + if (prev_list != NULL) + return notification_list_get_head(prev_list); + else if (next_list != NULL) + return next_list; + + return NULL; +} + +EXPORT_API int notification_get_list_for_uid(notification_type_e type, + int count, + notification_list_h *list, uid_t uid) +{ + notification_list_h get_list = NULL; + int ret = 0; + + if (list == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_ipc_request_load_noti_grouping_list(type, 1, count, &get_list, uid); + if (ret != NOTIFICATION_ERROR_NONE) + return ret; + + if (get_list != NULL) + *list = notification_list_get_head(get_list); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_list(notification_type_e type, + int count, + notification_list_h *list) +{ + return notification_get_list_for_uid(type, count, list, getuid()); +} + +EXPORT_API int notification_get_list_by_page_for_uid(notification_type_e type, + int page_number, + int count_per_page, + notification_list_h *list, + uid_t uid) +{ +#define COUNT_PER_PAGE_MAX 100 + + int ret; + notification_list_h get_list = NULL; + + if (list == NULL) { + ERR("Invalid parameter - list is null"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (page_number <= 0) { + ERR("Invalid parameter - page_number [%d]", page_number); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (count_per_page > COUNT_PER_PAGE_MAX) { + WARN("count_per_page exceeds max value, max must be set %d", + COUNT_PER_PAGE_MAX); + count_per_page = COUNT_PER_PAGE_MAX; + } + + ret = notification_ipc_request_load_noti_grouping_list(type, + page_number, count_per_page, &get_list, uid); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("fail request load noti grouping list"); + return ret; + } + + *list = notification_list_get_head(get_list); + + return ret; +} + +EXPORT_API int notification_get_list_by_page(notification_type_e type, + int page_number, int count_per_page, notification_list_h *list) +{ + return notification_get_list_by_page_for_uid(type, + page_number, count_per_page, list, getuid()); +} + +EXPORT_API int notification_get_detail_list_for_uid(const char *app_id, + int group_id, + int priv_id, + int count, + notification_list_h *list, + uid_t uid) +{ + int ret = 0; + notification_list_h get_list = NULL; + + if (list == NULL || app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + ret = notification_ipc_request_load_noti_detail_list(app_id, group_id, priv_id, count, + &get_list, uid); + if (ret != NOTIFICATION_ERROR_NONE) + return ret; + + if (get_list != NULL) + *list = notification_list_get_head(get_list); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_get_detail_list(const char *app_id, + int group_id, + int priv_id, + int count, + notification_list_h *list) +{ + return notification_get_detail_list_for_uid(app_id, group_id, + priv_id, count, list, getuid()); +} + +EXPORT_API int notification_free_list(notification_list_h list) +{ + notification_list_h cur_list = NULL; + notification_h noti = NULL; + + if (list == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + cur_list = notification_list_get_head(list); + + while (cur_list != NULL) { + noti = notification_list_get_data(cur_list); + cur_list = notification_list_remove(cur_list, noti); + + notification_free(noti); + } + + return NOTIFICATION_ERROR_NONE; +} + diff --git a/notification/src/notification_noti.c b/notification/src/notification_noti.c new file mode 100644 index 0000000..df0455e --- /dev/null +++ b/notification/src/notification_noti.c @@ -0,0 +1,2299 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <vconf.h> +#include <pkgmgr-info.h> +#include <package_manager.h> +#include <app_control_internal.h> +#include <bundle_internal.h> +#include <iniparser.h> + +#include <notification.h> +#include <notification_internal.h> +#include <notification_db.h> +#include <notification_list.h> +#include <notification_noti.h> +#include <notification_debug.h> +#include <notification_private.h> +#include <notification_setting.h> +#include <notification_setting_internal.h> +#include <notification_setting_service.h> +#include "notification_db_query.h" + +#define NOTI_BURST_DELETE_UNIT 10 +#define ERR_BUFFER_SIZE 1024 +#define NOTI_LIMIT 100 + +static void __free_and_set(void **target_ptr, void *new_ptr) +{ + if (target_ptr != NULL) { + if (*target_ptr != NULL) + free(*target_ptr); + + *target_ptr = new_ptr; + } +} + +static void __free_encoded_data(char *encoded_data) +{ + if (encoded_data) + bundle_free_encoded_rawdata((bundle_raw **)&encoded_data); +} + +static void __free_deleted_list(notification_deleted_list_info_s *info, int count) +{ + int i; + + for (i = 0; i < count; i++) { + if ((info + i)->app_id != NULL) + free((info + i)->app_id); + } + + free(info); +} + +static void __notification_noti_populate_from_stmt(sqlite3_stmt *stmt, notification_h noti) +{ + int col = 0; + int i = 0; + + if (stmt == NULL || noti == NULL) + return; + + noti->type = sqlite3_column_int(stmt, col++); + noti->layout = sqlite3_column_int(stmt, col++); + __free_and_set((void **)&(noti->pkg_id), notification_db_column_text(stmt, col++)); + __free_and_set((void **)&(noti->caller_app_id), notification_db_column_text(stmt, col++)); + __free_and_set((void **)&(noti->launch_app_id), notification_db_column_text(stmt, col++)); + __free_and_set((void **)&(noti->app_label), notification_db_column_text(stmt, col++)); + noti->b_image_path = notification_db_column_bundle(stmt, col++); + noti->b_priv_image_path = notification_db_column_bundle(stmt, col++); + noti->group_id = sqlite3_column_int(stmt, col++); + noti->internal_group_id = 0; + noti->priv_id = sqlite3_column_int(stmt, col++); + noti->b_text = notification_db_column_bundle(stmt, col++); + noti->b_key = notification_db_column_bundle(stmt, col++); + __free_and_set((void **)&(noti->tag), notification_db_column_text(stmt, col++)); + noti->b_format_args = notification_db_column_bundle(stmt, col++); + noti->num_format_args = sqlite3_column_int(stmt, col++); + + __free_and_set((void **)&(noti->domain), notification_db_column_text(stmt, col++)); + __free_and_set((void **)&(noti->dir), notification_db_column_text(stmt, col++)); + noti->time = sqlite3_column_int(stmt, col++); + noti->insert_time = sqlite3_column_int(stmt, col++); + noti->args = notification_db_column_bundle(stmt, col++); + noti->group_args = notification_db_column_bundle(stmt, col++); + + noti->b_execute_option = notification_db_column_bundle(stmt, col++); + noti->b_service_responding = notification_db_column_bundle(stmt, col++); + noti->b_service_single_launch = + notification_db_column_bundle(stmt, col++); + noti->b_service_multi_launch = + notification_db_column_bundle(stmt, col++); + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) + noti->b_event_handler[i] = notification_db_column_bundle(stmt, col++); + + noti->sound_type = sqlite3_column_int(stmt, col++); + __free_and_set((void **)&(noti->sound_path), notification_db_column_text(stmt, col++)); + __free_and_set((void **)&(noti->priv_sound_path), notification_db_column_text(stmt, col++)); + noti->vibration_type = sqlite3_column_int(stmt, col++); + __free_and_set((void **)&(noti->vibration_path), notification_db_column_text(stmt, col++)); + __free_and_set((void **)&(noti->priv_vibration_path), notification_db_column_text(stmt, col++)); + noti->led_operation = sqlite3_column_int(stmt, col++); + noti->led_argb = sqlite3_column_int(stmt, col++); + noti->led_on_ms = sqlite3_column_int(stmt, col++); + noti->led_off_ms = sqlite3_column_int(stmt, col++); + + noti->flags_for_property = sqlite3_column_int(stmt, col++); + noti->display_applist = sqlite3_column_int(stmt, col++); + noti->progress_size = sqlite3_column_double(stmt, col++); + noti->progress_percentage = sqlite3_column_double(stmt, col++); + + noti->ongoing_flag = sqlite3_column_int(stmt, col++); + noti->ongoing_value_type = sqlite3_column_int(stmt, col++); + noti->ongoing_current = sqlite3_column_int(stmt, col++); + noti->ongoing_duration = sqlite3_column_int(stmt, col++); + noti->auto_remove = sqlite3_column_int(stmt, col++); + noti->default_button_index = sqlite3_column_int(stmt, col++); + noti->hide_timeout = sqlite3_column_int(stmt, col++); + noti->delete_timeout = sqlite3_column_int(stmt, col++); + noti->text_input_max_length = sqlite3_column_int(stmt, col++); + noti->event_flag = sqlite3_column_int(stmt, col++); + noti->extension_image_size = sqlite3_column_int(stmt, col++); + noti->uid = sqlite3_column_int(stmt, col++); + + noti->app_icon_path = NULL; + noti->temp_title = NULL; + noti->temp_content = NULL; +} + +static int _notification_noti_check_priv_id(notification_h noti, sqlite3 *db) +{ + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int result = 0; + int ret = NOTIFICATION_ERROR_NONE; + + query = sqlite3_mprintf("SELECT count(*) FROM noti_list " + "WHERE caller_app_id = %Q AND priv_id = %d", + noti->caller_app_id, noti->priv_id); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc query"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to sqlite3_prepare_v2 Failed [%d][%s]", + ret, sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + result = sqlite3_column_int(stmt, 0); + else + result = 0; + + /* If result > 0, there is priv_id in DB */ + if (result > 0) + ret = NOTIFICATION_ERROR_ALREADY_EXIST_ID; + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + return ret; +} + +static int _notification_noti_get_internal_group_id_by_priv_id(const char *app_id, + int priv_id, + sqlite3 *db) +{ + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int result = 0; + + query = sqlite3_mprintf("SELECT internal_group_id FROM noti_list " + "WHERE caller_app_id = %Q AND priv_id = %d", + app_id, priv_id); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc query"); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 Failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + result = sqlite3_column_int(stmt, 0); + else + result = 0; + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (ret != NOTIFICATION_ERROR_NONE) + ERR("Failed to get internal group ID [%d]", ret); + + return result; +} + +static int _create_insertion_query(sqlite3 *db, notification_h noti, sqlite3_stmt *stmt, int *index) +{ + char buf_key[32] = { 0, }; + char *title_key = NULL; + char *b_text = NULL; + char *b_key = NULL; + char *b_format_args = NULL; + char *args = NULL; + char *group_args = NULL; + char *b_image_path = NULL; + char *b_priv_image_path = NULL; + char *b_execute_option = NULL; + char *b_service_responding = NULL; + char *b_service_single_launch = NULL; + char *b_service_multi_launch = NULL; + char *b_event_handler[NOTIFICATION_EVENT_TYPE_MAX+1] = { NULL, }; + int flag_simmode = 0; + int idx = 1; + int i = 0; + int b_encode_len = 0; + int ret = NOTIFICATION_ERROR_NONE; + + if (noti == NULL || stmt == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (noti->b_image_path) + bundle_encode(noti->b_image_path, (bundle_raw **)&b_image_path, + &b_encode_len); + + if (noti->b_priv_image_path) + bundle_encode(noti->b_priv_image_path, + (bundle_raw **)&b_priv_image_path, &b_encode_len); + + /* Get title key */ + if (noti->b_key != NULL) { + snprintf(buf_key, sizeof(buf_key), "%d", + NOTIFICATION_TEXT_TYPE_TITLE); + + bundle_get_str(noti->b_key, buf_key, &title_key); + } + + if (title_key == NULL && noti->b_text != NULL) { + snprintf(buf_key, sizeof(buf_key), "%d", + NOTIFICATION_TEXT_TYPE_TITLE); + + bundle_get_str(noti->b_text, buf_key, &title_key); + } + + if (title_key == NULL) + title_key = noti->caller_app_id; + + if (noti->b_text) + bundle_encode(noti->b_text, (bundle_raw **)&b_text, &b_encode_len); + + if (noti->b_key) + bundle_encode(noti->b_key, (bundle_raw **)&b_key, &b_encode_len); + + if (noti->b_format_args) + bundle_encode(noti->b_format_args, + (bundle_raw **)&b_format_args, &b_encode_len); + + if (noti->args) + bundle_encode(noti->args, (bundle_raw **)&args, &b_encode_len); + + if (noti->group_args) + bundle_encode(noti->group_args, (bundle_raw **)&group_args, + &b_encode_len); + + if (noti->b_execute_option) + bundle_encode(noti->b_execute_option, + (bundle_raw **)&b_execute_option, &b_encode_len); + + if (noti->b_service_responding) + bundle_encode(noti->b_service_responding, + (bundle_raw **)&b_service_responding, &b_encode_len); + + if (noti->b_service_single_launch) + bundle_encode(noti->b_service_single_launch, + (bundle_raw **)&b_service_single_launch, &b_encode_len); + + if (noti->b_service_multi_launch) + bundle_encode(noti->b_service_multi_launch, + (bundle_raw **)&b_service_multi_launch, &b_encode_len); + + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) { + if (noti->b_event_handler[i]) + bundle_encode(noti->b_event_handler[i], + (bundle_raw **)&b_event_handler[i], &b_encode_len); + } + + /* Check only simmode property is enable */ + if (noti->flags_for_property & NOTIFICATION_PROP_DISPLAY_ONLY_SIMMODE) + flag_simmode = 1; + + __BIND_INT(db, stmt, idx++, noti->type, ret, out); + __BIND_INT(db, stmt, idx++, noti->layout, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->pkg_id), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->caller_app_id), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->launch_app_id), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->app_label), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_image_path), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_priv_image_path), ret, out); + __BIND_INT(db, stmt, idx++, noti->group_id, ret, out); + __BIND_INT(db, stmt, idx++, noti->internal_group_id, ret, out); + __BIND_TEXT_STATIC(db, stmt, idx++, NOTIFICATION_CHECK_STR(title_key), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_text), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_key), ret, out); + __BIND_TEXT_STATIC(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->tag), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_format_args), ret, out); + __BIND_INT(db, stmt, idx++, noti->num_format_args, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->domain), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->dir), ret, out); + __BIND_INT(db, stmt, idx++, (int)noti->time, ret, out); + __BIND_INT(db, stmt, idx++, (int)noti->insert_time, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(args), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(group_args), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_execute_option), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_service_responding), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_service_single_launch), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_service_multi_launch), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_1]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_2]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_3]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_4]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_5]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_6]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_ICON]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_THUMBNAIL]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_TEXT_INPUT_BUTTON]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_7]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_8]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_9]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_10]), ret, out); + __BIND_INT(db, stmt, idx++, noti->sound_type, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->sound_path), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->priv_sound_path), ret, out); + __BIND_INT(db, stmt, idx++, noti->vibration_type, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->vibration_path), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->priv_vibration_path), ret, out); + __BIND_INT(db, stmt, idx++, noti->led_operation, ret, out); + __BIND_INT(db, stmt, idx++, noti->led_argb, ret, out); + __BIND_INT(db, stmt, idx++, noti->led_on_ms, ret, out); + __BIND_INT(db, stmt, idx++, noti->led_off_ms, ret, out); + __BIND_INT(db, stmt, idx++, noti->flags_for_property, ret, out); + __BIND_INT(db, stmt, idx++, flag_simmode, ret, out); + __BIND_INT(db, stmt, idx++, noti->display_applist, ret, out); + __BIND_DOUBLE(db, stmt, idx++, noti->progress_size, ret, out); + __BIND_DOUBLE(db, stmt, idx++, noti->progress_percentage, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_flag, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_value_type, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_current, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_duration, ret, out); + __BIND_INT(db, stmt, idx++, noti->auto_remove, ret, out); + __BIND_INT(db, stmt, idx++, noti->default_button_index, ret, out); + __BIND_INT(db, stmt, idx++, noti->hide_timeout, ret, out); + __BIND_INT(db, stmt, idx++, noti->delete_timeout, ret, out); + __BIND_INT(db, stmt, idx++, noti->text_input_max_length, ret, out); + __BIND_INT(db, stmt, idx++, noti->event_flag, ret, out); + __BIND_INT(db, stmt, idx++, noti->extension_image_size, ret, out); + __BIND_INT(db, stmt, idx++, noti->uid, ret, out); + +out: + __free_encoded_data(b_image_path); + __free_encoded_data(b_priv_image_path); + __free_encoded_data(b_text); + __free_encoded_data(b_key); + __free_encoded_data(b_format_args); + __free_encoded_data(args); + __free_encoded_data(group_args); + __free_encoded_data(b_execute_option); + __free_encoded_data(b_service_responding); + __free_encoded_data(b_service_single_launch); + __free_encoded_data(b_service_multi_launch); + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) + __free_encoded_data(b_event_handler[i]); + + if (index != NULL && ret == NOTIFICATION_ERROR_NONE) + *index = idx; + + return ret; +} + +static int _create_update_query(sqlite3 *db, notification_h noti, sqlite3_stmt *stmt) +{ + char *b_image_path = NULL; + char *b_priv_image_path = NULL; + char *b_text = NULL; + char *b_key = NULL; + char *b_format_args = NULL; + char *args = NULL; + char *group_args = NULL; + char *b_execute_option = NULL; + char *b_service_responding = NULL; + char *b_service_single_launch = NULL; + char *b_service_multi_launch = NULL; + char *b_event_handler[NOTIFICATION_EVENT_TYPE_MAX+1] = { NULL, }; + int flag_simmode = 0; + int idx = 1; + int i = 0; + int b_encode_len = 0; + int ret = NOTIFICATION_ERROR_NONE; + + if (noti == NULL || stmt == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + /* Decode bundle to update DB */ + if (noti->b_image_path) + bundle_encode(noti->b_image_path, + (bundle_raw **)&b_image_path, &b_encode_len); + + if (noti->b_priv_image_path) + bundle_encode(noti->b_priv_image_path, + (bundle_raw **)&b_priv_image_path, &b_encode_len); + + if (noti->b_text) + bundle_encode(noti->b_text, + (bundle_raw **)&b_text, &b_encode_len); + + if (noti->b_key) + bundle_encode(noti->b_key, + (bundle_raw **)&b_key, &b_encode_len); + + if (noti->b_format_args) + bundle_encode(noti->b_format_args, + (bundle_raw **)&b_format_args, &b_encode_len); + + if (noti->args) + bundle_encode(noti->args, (bundle_raw **)&args, &b_encode_len); + + if (noti->group_args) + bundle_encode(noti->group_args, (bundle_raw **)&group_args, + &b_encode_len); + + if (noti->b_execute_option) + bundle_encode(noti->b_execute_option, + (bundle_raw **)&b_execute_option, &b_encode_len); + + if (noti->b_service_responding) + bundle_encode(noti->b_service_responding, + (bundle_raw **)&b_service_responding, &b_encode_len); + + if (noti->b_service_single_launch) + bundle_encode(noti->b_service_single_launch, + (bundle_raw **)&b_service_single_launch, &b_encode_len); + + if (noti->b_service_multi_launch) + bundle_encode(noti->b_service_multi_launch, + (bundle_raw **)&b_service_multi_launch, &b_encode_len); + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) { + if (noti->b_event_handler[i]) + bundle_encode(noti->b_event_handler[i], + (bundle_raw **)&b_event_handler[i], &b_encode_len); + } + + /* Check only simmode property is enable */ + if (noti->flags_for_property & NOTIFICATION_PROP_DISPLAY_ONLY_SIMMODE) + flag_simmode = 1; + + __BIND_INT(db, stmt, idx++, noti->type, ret, out); + __BIND_INT(db, stmt, idx++, noti->layout, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->launch_app_id), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->app_label), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_image_path), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_priv_image_path), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_text), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_key), ret, out); + __BIND_TEXT_STATIC(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->tag), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_format_args), ret, out); + __BIND_INT(db, stmt, idx++, noti->num_format_args, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->domain), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->dir), ret, out); + __BIND_INT(db, stmt, idx++, (int)noti->time, ret, out); + __BIND_INT(db, stmt, idx++, (int)noti->insert_time, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(args), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(group_args), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_execute_option), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_service_responding), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_service_single_launch), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_service_multi_launch), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_1]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_2]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_3]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_4]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_5]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_6]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_ICON]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_THUMBNAIL]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_TEXT_INPUT_BUTTON]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_7]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_8]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_9]), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(b_event_handler[NOTIFICATION_EVENT_TYPE_CLICK_ON_BUTTON_10]), ret, out); + __BIND_INT(db, stmt, idx++, noti->sound_type, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->sound_path), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->priv_sound_path), ret, out); + __BIND_INT(db, stmt, idx++, noti->vibration_type, ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->vibration_path), ret, out); + __BIND_TEXT(db, stmt, idx++, NOTIFICATION_CHECK_STR(noti->priv_vibration_path), ret, out); + __BIND_INT(db, stmt, idx++, noti->led_operation, ret, out); + __BIND_INT(db, stmt, idx++, noti->led_argb, ret, out); + __BIND_INT(db, stmt, idx++, noti->led_on_ms, ret, out); + __BIND_INT(db, stmt, idx++, noti->led_off_ms, ret, out); + __BIND_INT(db, stmt, idx++, noti->flags_for_property, ret, out); + __BIND_INT(db, stmt, idx++, flag_simmode, ret, out); + __BIND_INT(db, stmt, idx++, noti->display_applist, ret, out); + __BIND_DOUBLE(db, stmt, idx++, noti->progress_size, ret, out); + __BIND_DOUBLE(db, stmt, idx++, noti->progress_percentage, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_flag, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_value_type, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_current, ret, out); + __BIND_INT(db, stmt, idx++, noti->ongoing_duration, ret, out); + __BIND_INT(db, stmt, idx++, noti->auto_remove, ret, out); + __BIND_INT(db, stmt, idx++, noti->default_button_index, ret, out); + __BIND_INT(db, stmt, idx++, noti->hide_timeout, ret, out); + __BIND_INT(db, stmt, idx++, noti->delete_timeout, ret, out); + __BIND_INT(db, stmt, idx++, noti->text_input_max_length, ret, out); + __BIND_INT(db, stmt, idx++, noti->event_flag, ret, out); + __BIND_INT(db, stmt, idx++, noti->extension_image_size, ret, out); + +out: + __free_encoded_data(b_image_path); + __free_encoded_data(b_priv_image_path); + __free_encoded_data(b_text); + __free_encoded_data(b_key); + __free_encoded_data(b_format_args); + __free_encoded_data(args); + __free_encoded_data(group_args); + __free_encoded_data(b_execute_option); + __free_encoded_data(b_service_responding); + __free_encoded_data(b_service_single_launch); + __free_encoded_data(b_service_multi_launch); + + for (i = 0; i <= NOTIFICATION_EVENT_TYPE_MAX; i++) + __free_encoded_data(b_event_handler[i]); + + return ret; +} + +static int _get_notification(char *query_where, notification_h noti) +{ + int ret; + char *query = NULL; + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + + if (query_where == NULL || noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT %s FROM %s", + NOTI_LIST_DB_ATTRIBUTES_SELECT, query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) { + __notification_noti_populate_from_stmt(stmt, noti); + ret = NOTIFICATION_ERROR_NONE; + } else { + if (ret == SQLITE_DONE) + DBG("No valid record found"); + else + ERR("sqlite3_step failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + } + +err: + if (query) + sqlite3_free(query); + + if (stmt) + sqlite3_finalize(stmt); + + if (db != NULL) + notification_db_close(&db); + + return ret; +} + +static int _get_notification_list(char *query_where, notification_list_h *list, int *list_count, int count) +{ + int ret; + int internal_count = 0; + char *query = NULL; + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + notification_list_h get_list = NULL; + notification_h noti = NULL; + + if (query_where == NULL || list == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT %s FROM %s", + NOTI_LIST_DB_ATTRIBUTES_SELECT, query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + while (sqlite3_step(stmt) == SQLITE_ROW) { + noti = (notification_h)calloc(1, sizeof(struct _notification)); + if (noti == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + if (get_list) { + get_list = notification_list_get_head(get_list); + notification_free_list(get_list); + } + goto err; + /* LCOV_EXCL_STOP */ + } + + __notification_noti_populate_from_stmt(stmt, noti); + if (noti != NULL) { + internal_count++; + get_list = notification_list_append(get_list, noti); + if (count != -1 && internal_count >= count) { + INFO("internal count[%d] count[%d]", + internal_count, count); + break; + } + } + } + + if (get_list != NULL) { + *list = notification_list_get_head(get_list); + if (list_count) + *list_count = internal_count; + } + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (db != NULL) + notification_db_close(&db); + + if (query) + sqlite3_free(query); + + return ret; +} +int notification_noti_set_tag(const char *tag, char *value, char *buf, int buf_len) +{ + int len_total = 0; + + len_total += (strlen(tag) * 2) + 5 + strlen(value) + 1; + + if (buf_len <= len_total) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + snprintf(buf, buf_len, "<%s>%s</%s>", tag, value, tag); + + return NOTIFICATION_ERROR_NONE; +} + +char *notification_noti_strip_tag(const char *tagged_str) +{ + if (tagged_str == NULL) + return NULL; + + int len_total = strlen(tagged_str); + + if (len_total == 0) + return NULL; + + char *b_f_e = strstr(tagged_str, ">"); + char *b_e_s = strstr(tagged_str, "</"); + + if (b_f_e == NULL || b_e_s == NULL || (b_e_s - b_f_e - 1) <= 0) + return NULL; + + return strndup(b_f_e + 1, b_e_s - b_f_e - 1); +} + +int notification_noti_get_tag_type(const char *tagged_str) +{ + if (tagged_str == NULL) + return TAG_TYPE_INVALID; + + if (strlen(tagged_str) == 0) + return TAG_TYPE_INVALID; + + char *b_f_s = strstr(tagged_str, "<"); + char *b_f_e = strstr(tagged_str, ">"); + + if (b_f_s == NULL || b_f_e == NULL || (b_f_e - b_f_s - 1) <= 0) + return TAG_TYPE_INVALID; + + char *start = b_f_s + 1; + int len_tag = b_f_e - b_f_s - 1; + + if (strncmp(start, TAG_TIME, len_tag) == 0) + return TAG_TYPE_TIME; + + return TAG_TYPE_INVALID; +} + +/* LCOV_EXCL_START */ +static int __get_setting_from_app_control(notification_h noti, notification_setting_h *setting) +{ + notification_setting_h setting_new = NULL; + app_control_h app_control = NULL; + bundle *b = NULL; + char *app_id = NULL; + int ret; + + ret = notification_get_execute_option(noti, + NOTIFICATION_EXECUTE_TYPE_SINGLE_LAUNCH, + NULL, + &b); + if (ret != NOTIFICATION_ERROR_NONE || b == NULL) { + WARN("Failed to get or no the excute option [%x]", ret); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + ret = app_control_create(&app_control); + if (ret != APP_CONTROL_ERROR_NONE) { + ERR("Failed to create app_control [%x]", ret); + goto out; + } + + ret = app_control_import_from_bundle(app_control, b); + if (ret != APP_CONTROL_ERROR_NONE) { + ERR("Failed to import from bundle to app_control [%x]", ret); + goto out; + } + + ret = app_control_get_app_id(app_control, &app_id); + if (ret != APP_CONTROL_ERROR_NONE || app_id == NULL) { + ERR("Failed to get app id from app_control [%x]", ret); + goto out; + } + + ret = noti_setting_service_get_setting_by_app_id(app_id, &setting_new, noti->uid); + if (ret != APP_CONTROL_ERROR_NONE || setting == NULL) { + ERR("Failed to get setting by app id[%s][%x]", + app_id, ret); + goto out; + } + + *setting = setting_new; + +out: + if (app_id) + free(app_id); + + if (app_control) + app_control_destroy(app_control); + + return ret; +} +/* LCOV_EXCL_STOP */ + +static bool _is_allowed_to_notify(notification_h noti) +{ + notification_setting_h setting = NULL; + bool allow_to_notify = true; + bool app_disabled = false; + bool ret = true; + int err; + + err = noti_setting_service_get_setting_by_app_id(noti->caller_app_id, + &setting, noti->uid); + if (err != NOTIFICATION_ERROR_NONE) { + err = __get_setting_from_app_control(noti, &setting); + if (err != NOTIFICATION_ERROR_NONE) + return ret; + } + + err = notification_setting_get_allow_to_notify(setting, &allow_to_notify); + if (err != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get allow_to_notify [%x]", err); + goto out; + } + + err = notification_setting_get_app_disabled(setting, &app_disabled); + if (err != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get app_disabled [%x]", err); + goto out; + } + + if (!allow_to_notify || app_disabled) + ret = false; + +out: + if (setting) + notification_setting_free_notification(setting); + + return ret; +} + +static int _handle_do_not_disturb_option(notification_h noti) +{ + int err = NOTIFICATION_ERROR_NONE; + bool do_not_disturb = false; + bool do_not_disturb_exception = false; + notification_setting_h setting = NULL; + notification_system_setting_h system_setting = NULL; + + if (noti == NULL) { + ERR("Invalid notification handle"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + /* Get system setting */ + err = noti_system_setting_load_system_setting(&system_setting, noti->uid); + if (err != NOTIFICATION_ERROR_NONE) { + ERR("Failed to load system setting [%d]", err); + goto out; + } + + err = notification_system_setting_get_do_not_disturb(system_setting, + &do_not_disturb); + if (err != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get do_not_disturb [%d]", err); + goto out; + } + + DBG("do_not_disturb [%d]", do_not_disturb); + + if (do_not_disturb) { + /* Check exception option of the caller app_id */ + err = noti_setting_service_get_setting_by_app_id(noti->caller_app_id, &setting, noti->uid); + if (err != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get setting by app_id [%d]", err); + goto out; + } + + err = notification_setting_get_do_not_disturb_except(setting, &do_not_disturb_exception); + if (err != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get do_not_disturb_exception [%d]", err); + goto out; + } + + if (do_not_disturb_exception == false) { + /* do_not_disturb is ON and do_not_disturb_exception is OFF */ + /* Then add this notification only on quick panel and indicator */ + noti->display_applist = noti->display_applist & + (NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY | + NOTIFICATION_DISPLAY_APP_INDICATOR); + /* and reset all sound and vibration and led options */ + noti->sound_type = NOTIFICATION_SOUND_TYPE_NONE; + SAFE_FREE(noti->sound_path); + SAFE_FREE(noti->priv_sound_path); + noti->vibration_type = NOTIFICATION_VIBRATION_TYPE_NONE; + SAFE_FREE(noti->vibration_path); + SAFE_FREE(noti->priv_vibration_path); + noti->led_operation = NOTIFICATION_LED_OP_OFF; + noti->led_argb = 0; + noti->led_on_ms = 0; + noti->led_off_ms = 0; + } + } + +out: + if (system_setting) + notification_system_setting_free_system_setting(system_setting); + + if (setting) + notification_setting_free_notification(setting); + + return err; +} + +static bool _is_pop_up_notification(const char *app_id, uid_t uid) +{ + int err; + bool ret = true; + notification_setting_h setting = NULL; + + err = noti_setting_service_get_setting_by_app_id(app_id, &setting, uid); + if (err != NOTIFICATION_ERROR_NONE) { + WARN("Failed get the setting for [%s] [%x]", app_id, err); + goto out; + } + + err = notification_setting_get_pop_up_notification(setting, &ret); + if (err != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get pop_up_notification [%d]", err); + goto out; + } + + if (ret != true) + DBG("[%s] is not allowed Pop-up notification", app_id); + +out: + if (setting) + notification_setting_free_notification(setting); + + return ret; +} + +static int _check_text_input(notification_h noti) +{ + int err; + int text_input_max_length; + app_control_h app_control = NULL; + + err = notification_get_text_input_max_length(noti, &text_input_max_length); + if (err == NOTIFICATION_ERROR_NONE && text_input_max_length != 0) { + err = notification_get_event_handler(noti, NOTIFICATION_EVENT_TYPE_CLICK_ON_TEXT_INPUT_BUTTON, &app_control); + if (err != NOTIFICATION_ERROR_NONE || app_control == NULL) { + ERR("Event handler for text_input is not set"); + return -1; + } + app_control_destroy(app_control); + } + + return NOTIFICATION_ERROR_NONE; +} + +static int _get_noti_count(sqlite3 *db, char *query_where, int *count) +{ + int ret; + char *query = NULL; + sqlite3_stmt *stmt = NULL; + + if (db == NULL || query_where == NULL || count == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + query = sqlite3_mprintf("SELECT COUNT(*) FROM noti_list %s", query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("sqlite3_mprintf Failed"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 Failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) { + *count = sqlite3_column_int(stmt, 0); + ret = NOTIFICATION_ERROR_NONE; + } else { + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + } + +err: + if (stmt) + sqlite3_finalize(stmt); + if (query) + sqlite3_free(query); + + return ret; +} + +EXPORT_API int notification_noti_insert(notification_h noti) +{ + int ret = 0; + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + + if (noti == NULL) { + ERR("Invalid notification handle"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (_is_allowed_to_notify(noti) == false) { + ERR("[%s] is not allowed to notify", noti->caller_app_id); + return NOTIFICATION_ERROR_PERMISSION_DENIED; + } + + if (_handle_do_not_disturb_option(noti) != NOTIFICATION_ERROR_NONE) + WARN("Failed to handle do_not_disturb"); + + if (_is_pop_up_notification((const char *)noti->caller_app_id, noti->uid) == false) { + noti->display_applist = (noti->display_applist & (~NOTIFICATION_DISPLAY_APP_ACTIVE)); + DBG("notification display applist - app_id [%s], applist [%d]", + noti->caller_app_id, noti->display_applist); + } + + if (_check_text_input(noti) != NOTIFICATION_ERROR_NONE) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + /* Initialize private ID */ + noti->group_id = NOTIFICATION_GROUP_ID_NONE; + noti->internal_group_id = NOTIFICATION_GROUP_ID_NONE; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("INSERT INTO noti_list (%s) VALUES (%s)", + NOTI_LIST_DB_ATTRIBUTES_INSERT, NOTI_LIST_INSERT_VALUES); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("sqlite3_mprintf Failed"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 Failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = _create_insertion_query(db, noti, stmt, NULL); + if (ret != NOTIFICATION_ERROR_NONE) + goto err; + + ret = sqlite3_step(stmt); + if (ret == SQLITE_OK || ret == SQLITE_DONE) { + noti->priv_id = (int)sqlite3_last_insert_rowid(db); + ret = NOTIFICATION_ERROR_NONE; + } else { + ret = NOTIFICATION_ERROR_FROM_DB; + } + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +/* LCOV_EXCL_START */ +EXPORT_API int notification_noti_get_by_priv_id(notification_h noti, int priv_id) +{ + int ret = NOTIFICATION_ERROR_NONE; + char *query_where = NULL; + + if (priv_id < 0 || noti == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + query_where = sqlite3_mprintf("noti_list WHERE priv_id = %d", priv_id); + if (query_where == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = _get_notification(query_where, noti); + +err: + if (query_where) + sqlite3_free(query_where); + + return ret; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_noti_get_by_tag(notification_h noti, char *app_id, char *tag, uid_t uid) +{ + int ret = NOTIFICATION_ERROR_NONE; + char *query_where; + + if (tag == NULL || noti == NULL) { + ERR("Invalid paramter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + query_where = sqlite3_mprintf("noti_list WHERE caller_app_id = %Q " + "AND tag = %Q AND uid = %d", app_id, tag, uid); + if (query_where == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = _get_notification(query_where, noti); + +err: + if (query_where) + sqlite3_free(query_where); + + return ret; +} + +EXPORT_API int notification_noti_update(notification_h noti) +{ + int ret = NOTIFICATION_ERROR_NONE; + sqlite3 *db; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + + if (noti == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (_is_allowed_to_notify(noti) == false) { + DBG("[%s] is not allowed to notify", noti->caller_app_id); + return NOTIFICATION_ERROR_PERMISSION_DENIED; + } + + if (_handle_do_not_disturb_option(noti) != NOTIFICATION_ERROR_NONE) + WARN("Failed to handle do_not_disturb"); + + if (_is_pop_up_notification((const char *)noti->caller_app_id, noti->uid) == false) { + noti->display_applist = (noti->display_applist & (~NOTIFICATION_DISPLAY_APP_ACTIVE)); + DBG("notification display applist - app_id [%s], applist [%d]", + noti->caller_app_id, noti->display_applist); + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + /* Check private ID is exist */ + ret = _notification_noti_check_priv_id(noti, db); + if (ret != NOTIFICATION_ERROR_ALREADY_EXIST_ID) { + ERR("The ID is not existed"); + ret = NOTIFICATION_ERROR_NOT_EXIST_ID; + goto err; + } + + query = sqlite3_mprintf("UPDATE noti_list SET %s WHERE priv_id = %d ", + NOTI_LIST_DB_ATTRIBUTES_UPDATE, noti->priv_id); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 Failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = _create_update_query(db, noti, stmt); + if (ret != NOTIFICATION_ERROR_NONE) + goto err; + + ret = sqlite3_step(stmt); + if (ret == SQLITE_OK || ret == SQLITE_DONE) + ret = NOTIFICATION_ERROR_NONE; + else + ret = NOTIFICATION_ERROR_FROM_DB; + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_noti_delete_all(notification_type_e type, + const char *app_id, int *deleted_num, + int **deleted_list, uid_t uid) +{ + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + char *query_where = NULL; + int *tmp = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int count = 0; + int i = 0; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + /* create query_where according to appid and type */ + if (app_id == NULL || strlen(app_id) == 0) { + if (type == NOTIFICATION_TYPE_NONE) + query_where = sqlite3_mprintf("WHERE uid = %d", uid); + else + query_where = sqlite3_mprintf("WHERE type = %d " + "AND uid = %d", type, uid); + if (query_where == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + } else { + if (type == NOTIFICATION_TYPE_NONE) + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND uid = %d", app_id, uid); + else + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND type = %d AND uid = %d", + app_id, type, uid); + + if (query_where == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + } + + /* check count to delete */ + ret = _get_noti_count(db, query_where, &count); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get count to delete %d", ret); + goto err; + } + + /* Get priv_id and add to list */ + if (count > 0 && deleted_list != NULL) { + query = sqlite3_mprintf("SELECT priv_id FROM noti_list %s", + query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to sqlite3_prepare_V2 [%d][%s]", + ret, sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + tmp = (int *)calloc(count, sizeof(int)); + if (tmp == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + while (sqlite3_step(stmt) == SQLITE_ROW) { + *(tmp + i) = sqlite3_column_int(stmt, 0); + i++; + } + + sqlite3_free(query); + query = NULL; + } + + /* execute main query */ + query = sqlite3_mprintf("DELETE FROM noti_list %s", query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, NULL); + if (ret != NOTIFICATION_ERROR_NONE) + goto err; + + if (deleted_list) + *deleted_list = tmp; + + if (deleted_num != NULL) + *deleted_num = count; + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (query_where) + sqlite3_free(query_where); + + if (db) + notification_db_close(&db); + + if (ret != NOTIFICATION_ERROR_NONE) { + if (tmp != NULL) + free(tmp); + } + + return ret; +} + +/* LCOV_EXCL_START */ +EXPORT_API int notification_noti_delete_by_priv_id(const char *app_id, int priv_id) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + + if (app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("DELETE FROM noti_list WHERE caller_app_id = %Q " + "AND priv_id = %d", app_id, priv_id); + if (query == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + } + + ret = notification_db_exec(db, query, NULL); + +err: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_noti_delete_by_priv_id_get_changes(const char *app_id, + int priv_id, + int *num_changes, + uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("DELETE FROM noti_list WHERE caller_app_id = %Q " + "AND priv_id = %d AND uid = %d", + app_id, priv_id, uid); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, num_changes); + +err: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_noti_delete_by_display_applist(int display_applist, + int *deleted_num, + notification_deleted_list_info_s **deleted_list, + uid_t uid) +{ + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + notification_deleted_list_info_s *info = NULL; + char *query = NULL; + char *query_where = NULL; + int count = 0; + int ret; + int i = 0; + + if (display_applist < NOTIFICATION_DISPLAY_APP_NOTIFICATION_TRAY) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query_where = sqlite3_mprintf("WHERE (display_applist & %d) = %d " + "AND uid = %d", display_applist, display_applist, + uid); + if (query_where == NULL) { + /* LCOV_EXCL_START */ + ERR("sqlite3_mprintf Failed"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + /* check count to delete */ + ret = _get_noti_count(db, query_where, &count); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get count to delete %d", ret); + goto err; + } + + /* get priv_id, app_id to add deleted_list */ + if (count > 0 && deleted_list != NULL) { + query = sqlite3_mprintf("SELECT priv_id, caller_app_id " + "FROM noti_list %s", query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to sqlite3_prepare [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + info = (notification_deleted_list_info_s *)calloc(count, + sizeof(notification_deleted_list_info_s)); + if (info == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + while (sqlite3_step(stmt) == SQLITE_ROW) { + (info + i)->priv_id = sqlite3_column_int(stmt, 0); + (info + i)->app_id = notification_db_column_text(stmt, 1); + i++; + } + + if (query) { + sqlite3_free(query); + query = NULL; + } + } + + /* execute main query */ + query = sqlite3_mprintf("DELETE FROM noti_list %s", query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("sqlite3_mprintf Failed"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, NULL); + if (ret != NOTIFICATION_ERROR_NONE) + goto err; + + + if (deleted_num != NULL) + *deleted_num = count; + + if (deleted_list != NULL) + *deleted_list = info; + +err: + if (stmt) + sqlite3_finalize(stmt); + if (query_where) + sqlite3_free(query_where); + if (query) + sqlite3_free(query); + if (db) + notification_db_close(&db); + + if (ret != NOTIFICATION_ERROR_NONE) { + if (info != NULL) + __free_deleted_list(info, count); + } + + return ret; +} + +/* todo refactoring */ +/* LCOV_EXCL_START */ +EXPORT_API int notification_noti_get_count(notification_type_e type, + const char *app_id, + int group_id, int priv_id, + int *count, uid_t uid) +{ + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + char *query_base = NULL; + char *query_where = NULL; + char *query_where_more = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int get_count = 0; + int internal_group_id = 0; + int status = VCONFKEY_TELEPHONY_SIM_UNKNOWN; + + /* Check current sim status */ + ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &status); + if (ret < 0) { + status = VCONFKEY_TELEPHONY_SIM_INSERTED; + WARN("vconf_get_int"); + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query_base = sqlite3_mprintf("SELECT count(*) FROM noti_list "); + if (query_base == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + } + + internal_group_id = + _notification_noti_get_internal_group_id_by_priv_id(app_id, priv_id, db); + + if (group_id == NOTIFICATION_GROUP_ID_NONE) { + if (priv_id == NOTIFICATION_PRIV_ID_NONE) + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND uid = %d ", app_id, uid); + else + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND internal_group_id = %d AND uid = %d ", + app_id, internal_group_id, uid); + } else { + if (priv_id == NOTIFICATION_PRIV_ID_NONE) + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND group_id = %d AND uid = %d ", + app_id, group_id, uid); + else + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND internal_group_id = %d AND uid = %d ", + app_id, internal_group_id, uid); + } + + if (query_where == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + } + + if (status == VCONFKEY_TELEPHONY_SIM_INSERTED) { + if (type != NOTIFICATION_TYPE_NONE) { + query_where_more = sqlite3_mprintf("type = %d ", type); + if (query_where_more == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + } + } + } else { + if (type != NOTIFICATION_TYPE_NONE) + query_where_more = sqlite3_mprintf("type = %d AND " + "flag_simmode = 0 ", type); + else + query_where_more = sqlite3_mprintf("flag_simmode = 0 "); + + if (query_where_more == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + } + } + + if (query_where_more) { + query = sqlite3_mprintf("%s %s AND %s", query_base, query_where, + query_where_more); + if (query == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + } + } else { + query = sqlite3_mprintf("%s %s", query_base, query_where); + if (query == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + } + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ERR("Failed to sqlite3_prepare_v2[%d][%s]", + ret, sqlite3_errmsg(db)); + + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + get_count = sqlite3_column_int(stmt, 0); + + ret = NOTIFICATION_ERROR_NONE; + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (query_base) + sqlite3_free(query_base); + + if (query_where) + sqlite3_free(query_where); + + if (query_where_more) + sqlite3_free(query_where_more); + + if (db) + notification_db_close(&db); + + *count = get_count; + + return ret; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_noti_get_all_count(notification_type_e type, int *count, uid_t uid) +{ + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + char *sql_buf = NULL; + + if (count == NULL) { + ERR("Invalid parameter - count is null"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + db = notification_db_open(); + if (db == NULL) { + /* LCOV_EXCL_START */ + ret = get_last_result(); + ERR("Failed to open db [%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + if (type != NOTIFICATION_TYPE_NONE) + sql_buf = sqlite3_mprintf("SELECT count(*) FROM %q " + "WHERE uid = %d AND type = %d", + NOTIFICATION_DB_TABLE, uid, type); + else + sql_buf = sqlite3_mprintf("SELECT count(*) FROM %q WHERE uid = %d", + NOTIFICATION_DB_TABLE, uid); + + if (sql_buf == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_FROM_DB; + ERR("OOM - sqlite3_mprintf"); + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_prepare_v2(db, sql_buf, -1, &stmt, NULL); + if (sql_ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_FROM_DB; + ERR("SQLITE3 Error - sqlite3_prepare_v2 [%d][%s]", + sql_ret, sqlite3_errmsg(db)); + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_step(stmt); + if (sql_ret == SQLITE_ROW) + *count = sqlite3_column_int(stmt, 0); + else + *count = 0; + + INFO("The numbers of all notification is [%d]", *count); + +out: + if (stmt) + sqlite3_finalize(stmt); + if (sql_buf) + sqlite3_free(sql_buf); + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_noti_get_grouping_list(notification_type_e type, + int page_number, + int count_per_page, + notification_list_h *list, + int *list_count, + uid_t uid) +{ + char *query = NULL; + char *query_uid = NULL; + char *query_where = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int status; + int start_index; + + /* Check current sim status */ + ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &status); + if (ret < 0) { + status = VCONFKEY_TELEPHONY_SIM_INSERTED; + WARN("vconf_get_int"); + } + + if (status == VCONFKEY_TELEPHONY_SIM_INSERTED) { + if (type != NOTIFICATION_TYPE_NONE) { + query_where = sqlite3_mprintf(" AND type = %d ", type); + if (query_where == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + } else { + if (type != NOTIFICATION_TYPE_NONE) + query_where = sqlite3_mprintf(" AND type = %d AND " + "flag_simmode = 0 ", type); + else + query_where = sqlite3_mprintf(" AND flag_simmode = 0 "); + + if (query_where == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + + if (uid != NOTIFICATION_GLOBAL_UID) { + query_uid = sqlite3_mprintf(" AND uid = %d ", uid); + if (query_uid == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + } + + if (count_per_page > 0) { + start_index = (page_number - 1) * count_per_page; + query = sqlite3_mprintf("noti_list WHERE 1 > 0 %s %s " + "ORDER BY rowid DESC, time DESC LIMIT %d,%d", + query_where, query_uid, start_index, count_per_page); + } else { + query = sqlite3_mprintf("noti_list WHERE 1 > 0 %s %s " + "ORDER BY rowid DESC, time DESC", + query_where, query_uid); + count_per_page = -1; + } + + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = _get_notification_list(query, list, list_count, count_per_page); + +err: + if (query_where) + sqlite3_free(query_where); + + if (query_uid) + sqlite3_free(query_uid); + + if (query) + sqlite3_free(query); + + return ret; +} + +EXPORT_API int notification_noti_get_detail_list(const char *app_id, + int group_id, + int priv_id, int count, + notification_list_h *list, + uid_t uid) +{ + char *query_where = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int internal_group_id = 0; + int status = 0; + sqlite3 *db = NULL; + + /* Check current sim status */ + ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &status); + if (ret < 0) { + status = VCONFKEY_TELEPHONY_SIM_INSERTED; + WARN("vconf_get_int"); + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + if (priv_id == NOTIFICATION_PRIV_ID_NONE && + group_id == NOTIFICATION_GROUP_ID_NONE) { + if (status == VCONFKEY_TELEPHONY_SIM_INSERTED) + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND uid = %d ", app_id, uid); + else + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND flag_simmode = 0 AND uid = %d ", app_id, uid); + + } else { + internal_group_id = + _notification_noti_get_internal_group_id_by_priv_id(app_id, + priv_id, db); + + if (status == VCONFKEY_TELEPHONY_SIM_INSERTED) + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND internal_group_id = %d AND uid = %d ", + app_id, internal_group_id, uid); + else + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q " + "AND internal_group_id = %d AND flag_simmode = 0 " + "AND uid = %d ", + app_id, internal_group_id, uid); + } + + if (query_where == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + query = sqlite3_mprintf("noti_list %s ORDER BY rowid DESC, time DESC", + query_where); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = _get_notification_list(query, list, NULL, count); + +err: + if (query_where) + sqlite3_free(query_where); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_noti_check_tag(notification_h noti) +{ + sqlite3 *db; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int result = 0; + + if (noti->tag == NULL) + return NOTIFICATION_ERROR_NOT_EXIST_ID; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT priv_id FROM noti_list " + "WHERE caller_app_id = %Q AND tag = %Q", + NOTIFICATION_CHECK_STR(noti->caller_app_id), + NOTIFICATION_CHECK_STR(noti->tag)); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to sqlite3_prepare_v2[%d][%s]", + ret, sqlite3_errmsg(db)); + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + result = sqlite3_column_int(stmt, 0); + else + result = 0; + + /* If result > 0, there is priv_id in DB */ + if (result > 0) { + noti->priv_id = result; + ret = NOTIFICATION_ERROR_ALREADY_EXIST_ID; + } else { + ret = NOTIFICATION_ERROR_NOT_EXIST_ID; + } + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_noti_check_count_for_template(notification_h noti, int *count) +{ + sqlite3 *db; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int result = 0; + + if (noti == NULL || count == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT COUNT(caller_app_id) FROM noti_template " + "WHERE caller_app_id = %Q", + NOTIFICATION_CHECK_STR(noti->caller_app_id)); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to sqlite3_prepare_v2[%d][%s]", + ret, sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_step(stmt); + if (ret == SQLITE_ROW) + result = sqlite3_column_int(stmt, 0); + else + result = 0; + + *count = result; + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_noti_add_template(notification_h noti, char *template_name) +{ + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int idx = 1; + int ret = NOTIFICATION_ERROR_NONE; + + if (noti == NULL || template_name == NULL) { + ERR("NOTIFICATION_ERROR_INVALID_PARAMETER"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + /* Initialize private ID */ + noti->group_id = NOTIFICATION_GROUP_ID_NONE; + noti->internal_group_id = NOTIFICATION_GROUP_ID_NONE; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("INSERT OR REPLACE INTO noti_template " + "(%s, template_name) VALUES (%s, %Q)", + NOTI_LIST_DB_ATTRIBUTES_INSERT, + NOTI_LIST_INSERT_VALUES, + template_name); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to sqlite3_prepare_v2[%d][%s]", + ret, sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = _create_insertion_query(db, noti, stmt, &idx); + if (ret != NOTIFICATION_ERROR_NONE) + goto err; + + ret = sqlite3_step(stmt); + if (ret == SQLITE_OK || ret == SQLITE_DONE) + ret = NOTIFICATION_ERROR_NONE; + else + ret = NOTIFICATION_ERROR_FROM_DB; + +err: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_noti_get_package_template(notification_h noti, char *app_id, char *template_name) +{ + int ret = NOTIFICATION_ERROR_NONE; + char *query_where = NULL; + + if (noti == NULL || app_id == NULL || template_name == NULL) { + ERR("NOTIFICATION_ERROR_INVALID_PARAMETER"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + query_where = sqlite3_mprintf("noti_template WHERE caller_app_id = %Q " + "AND template_name = %Q", app_id, template_name); + if (query_where == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + + ret = _get_notification(query_where, noti); + if (ret != NOTIFICATION_ERROR_NONE) + ERR("Failed to get notification [%d]", ret); + + if (query_where) + sqlite3_free(query_where); + + return ret; +} + +EXPORT_API int notification_noti_delete_template(const char *pkg_id) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + + if (pkg_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("DELETE FROM noti_template WHERE pkg_id = %Q", + NOTIFICATION_CHECK_STR(pkg_id)); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, NULL); + +err: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +/* LCOV_EXCL_START */ +EXPORT_API void notification_noti_init_data(void) +{ + int ret; + sqlite3 *db = NULL; + char *query = NULL; + + db = notification_db_open(); + if (!db) { + ERR("db open"); + return; + } + + query = sqlite3_mprintf("DELETE FROM noti_list WHERE type = %d OR flags_for_property & %d", + NOTIFICATION_TYPE_ONGOING, NOTIFICATION_PROP_VOLATILE_DISPLAY); + if (!query) { + ERR("OOM - sql query"); + notification_db_close(&db); + return; + } + + ret = notification_db_exec(db, query, NULL); + if (ret != NOTIFICATION_ERROR_NONE) + ERR("notification_db_exec"); + + sqlite3_free(query); + notification_db_close(&db); +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_noti_check_limit(notification_h noti, uid_t uid, GList **list) +{ + int ret; + int priv_id; + int count = 0; + char *query = NULL; + char *query_where = NULL; + sqlite3 *db = NULL; + sqlite3_stmt *stmt = NULL; + + if (noti == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query_where = sqlite3_mprintf("WHERE caller_app_id = %Q AND uid = %d ", + noti->caller_app_id, uid); + if (query_where == NULL) { + /* LCOV_EXCL_START */ + ERR("sqlite3_mprintf Failed"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + /* check count to delete */ + ret = _get_noti_count(db, query_where, &count); + if (ret != NOTIFICATION_ERROR_NONE) { + ERR("Failed to get count to delete %d", ret); + goto err; + } + + /* get priv_id to delete */ + if (count > NOTI_LIMIT) { + count -= NOTI_LIMIT; + + query = sqlite3_mprintf("SELECT priv_id FROM noti_list %s " + "AND type = %d ORDER BY insert_time ASC, priv_id ASC", + query_where, NOTIFICATION_TYPE_NOTI); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("sqlite3_mprintf Failed"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto err; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 Failed [%d][%s]", ret, + sqlite3_errmsg(db)); + ret = NOTIFICATION_ERROR_FROM_DB; + goto err; + /* LCOV_EXCL_STOP */ + } + + while (sqlite3_step(stmt) == SQLITE_ROW && count > 0) { + priv_id = sqlite3_column_int(stmt, 0); + *list = g_list_append(*list, GINT_TO_POINTER(priv_id)); + count--; + } + } + +err: + if (stmt) + sqlite3_finalize(stmt); + if (query) + sqlite3_free(query); + if (query_where) + sqlite3_free(query_where); + if (db) + notification_db_close(&db); + + return ret; +} diff --git a/notification/src/notification_ongoing.c b/notification/src/notification_ongoing.c new file mode 100644 index 0000000..89ee0c9 --- /dev/null +++ b/notification/src/notification_ongoing.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <glib.h> +#include <gio/gio.h> + +#include <notification_db.h> +#include <notification_debug.h> +#include <notification_ongoing.h> +#include <notification_private.h> + +#define PATH_NAME "/dbus/signal" +#define INTERFACE_NAME "notification.ongoing" +#define MEMBER_PROGRESS "update_progress" +#define MEMBER_SIZE "update_size" +#define MEMBER_CONTENT "update_content" + +struct _ongoing_update_cb_data { + notification_ongoing_update_cb callback; + void *data; + GDBusConnection *conn; + guint subscribe_id; +}; + +static struct _ongoing_update_cb_data od; + +static void __notification_ongoing_update_callback(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + struct ongoing_info_s *info; + char *app_id = NULL; + int priv_id = 0; + double progress = 0; + double size = 0; + char *content = NULL; + + info = calloc(1, sizeof(struct ongoing_info_s)); + if (info == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + return; + /* LCOV_EXCL_STOP */ + } + + if (g_strcmp0(signal_name, MEMBER_PROGRESS) == 0) { + g_variant_get(parameters, "(&sid)", &app_id, &priv_id, &progress); + info->type = ONGOING_TYPE_PROGRESS; + } else if (g_strcmp0(signal_name, MEMBER_SIZE) == 0) { + g_variant_get(parameters, "(&sid)", &app_id, &priv_id, &size); + info->type = ONGOING_TYPE_SIZE; + } else if (g_strcmp0(signal_name, MEMBER_CONTENT) == 0) { + g_variant_get(parameters, "(&si&s)", &app_id, &priv_id, &content); + info->type = ONGOING_TYPE_CONTENT; + } + + if (app_id == NULL) { + /* LCOV_EXCL_START */ + ERR("app_id is NULL"); + free(info); + return; + /* LCOV_EXCL_STOP */ + } + + info->pkgname = app_id; + info->priv_id = priv_id; + info->progress = progress; + info->size = size; + info->content = content; + + od.callback(info, od.data); + + free(info); +} + +static int __send_ongoing_update_signal(const char *signal_name, GVariant *param) +{ + GError *err = NULL; + GDBusConnection *conn; + int ret = NOTIFICATION_ERROR_NONE; + + if (signal_name == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (conn == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to connect to the D-BUS Daemon[%s]", + err->message); + ret = NOTIFICATION_ERROR_FROM_DBUS; + goto end; + /* LCOV_EXCL_STOP */ + } + + if (g_dbus_connection_emit_signal(conn, + NULL, + PATH_NAME, + INTERFACE_NAME, + signal_name, + param, + &err) == FALSE) { + /* LCOV_EXCL_START */ + ERR("Failed to emit gdbus signal[%s]", + err->message); + ret = NOTIFICATION_ERROR_FROM_DBUS; + goto end; + /* LCOV_EXCL_STOP */ + } + + if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) { + /* LCOV_EXCL_START */ + ERR("Failed to flush connection sync[%s]", + err->message); + ret = NOTIFICATION_ERROR_FROM_DBUS; + goto end; + /* LCOV_EXCL_STOP */ + } + + +end: + if (err) + g_error_free(err); + + if (conn) + g_object_unref(conn); + + + return ret; +} + +EXPORT_API +int notification_ongoing_update_cb_set(notification_ongoing_update_cb callback, + void *user_data) +{ + GError *error = NULL; + + if (!callback) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (od.conn == NULL) { + od.conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (od.conn == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to connect to the D-BUS Daemon: %s", + error->message); + g_error_free(error); + return NOTIFICATION_ERROR_FROM_DBUS; + /* LCOV_EXCL_STOP */ + } + } + + if (!od.subscribe_id) { + od.subscribe_id = g_dbus_connection_signal_subscribe(od.conn, + NULL, + INTERFACE_NAME, + NULL, + PATH_NAME, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + __notification_ongoing_update_callback, + NULL, + NULL); + if (od.subscribe_id == 0) { + /* LCOV_EXCL_START */ + ERR("Failed to subscribe signal"); + g_object_unref(od.conn); + return NOTIFICATION_ERROR_FROM_DBUS; + /* LCOV_EXCL_STOP */ + } + } + + od.callback = callback; + od.data = user_data; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API +int notification_ongoing_update_cb_unset(void) +{ + if (od.subscribe_id) { + g_dbus_connection_signal_unsubscribe(od.conn, od.subscribe_id); + od.subscribe_id = 0; + } + + if (od.conn) { + g_object_unref(od.conn); + od.conn = NULL; + } + + od.callback = NULL; + od.data = NULL; + + return NOTIFICATION_ERROR_NONE; +} + +int notification_ongoing_update_progress(const char *caller_app_id, + int priv_id, double progress) +{ + GVariant *param; + int ret; + + param = g_variant_new("(sid)", caller_app_id, priv_id, progress); + + ret = __send_ongoing_update_signal(MEMBER_PROGRESS, param); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to update progress[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + return NOTIFICATION_ERROR_NONE; +} + +int notification_ongoing_update_size(const char *caller_app_id, + int priv_id, double size) +{ + GVariant *param; + int ret; + + param = g_variant_new("(sid)", caller_app_id, priv_id, size); + + ret = __send_ongoing_update_signal(MEMBER_SIZE, param); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to update size[%d]", ret); + return ret; + /* LCOV_EXCL_STOP */ + } + + return NOTIFICATION_ERROR_NONE; +} + +int notification_ongoing_update_content(const char *caller_app_id, + int priv_id, const char *content) +{ + GVariant *param; + int ret; + + param = g_variant_new("(sis)", caller_app_id, priv_id, content); + + ret = __send_ongoing_update_signal(MEMBER_CONTENT, param); + if (ret != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to update content[%d]", + ret); + return ret; + /* LCOV_EXCL_STOP */ + } + return NOTIFICATION_ERROR_NONE; +} diff --git a/notification/src/notification_setting.c b/notification/src/notification_setting.c new file mode 100644 index 0000000..6be851f --- /dev/null +++ b/notification/src/notification_setting.c @@ -0,0 +1,1125 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <package_manager.h> +#include <pkgmgr-info.h> +#include <tizen_type.h> +#include <tzplatform_config.h> + +#include <notification.h> +#include <notification_db.h> +#include <notification_list.h> +#include <notification_noti.h> +#include <notification_debug.h> +#include <notification_ipc.h> +#include <notification_private.h> +#include <notification_setting.h> +#include <notification_setting_internal.h> +#include "notification_db_query.h" + +#define NOTIFICATION_PRIVILEGE "http://tizen.org/privilege/notification" + +typedef struct _noti_dnd_cb_info noti_dnd_cb_info_s; + +typedef struct { + uid_t uid; + sqlite3 *db; +} setting_local_info; + +struct _noti_dnd_cb_info { + dnd_changed_cb callback; + void *user_data; +}; + +static GHashTable *_noti_dnd_cb_hash = NULL; + +EXPORT_API int notification_setting_get_setting_array_for_uid(notification_setting_h *setting_array, int *count, uid_t uid) +{ + if (setting_array == NULL || count == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return notification_ipc_request_get_setting_array(setting_array, count, uid); +} + +EXPORT_API int notification_setting_get_setting_array(notification_setting_h *setting_array, int *count) +{ + return notification_setting_get_setting_array_for_uid(setting_array, count, getuid()); +} + +EXPORT_API int notification_setting_get_setting_by_appid_for_uid(const char *app_id, notification_setting_h *setting, uid_t uid) +{ + if (app_id == NULL || setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return notification_ipc_request_get_setting_by_app_id(app_id, setting, uid); +} + +/* LCOV_EXCL_START */ +EXPORT_API int notification_setting_get_setting_by_package_name(const char *package_name, notification_setting_h *setting) +{ + return notification_setting_get_setting_by_appid_for_uid(package_name, setting, getuid()); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_setting_get_setting(notification_setting_h *setting) +{ + int ret; + char *app_id = NULL; + + app_id = notification_get_app_id_by_pid(getpid()); + if (app_id == NULL) + return NOTIFICATION_ERROR_NOT_EXIST_ID; + + ret = notification_setting_get_setting_by_package_name(app_id, setting); + + free(app_id); + + return ret; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_setting_get_package_name(notification_setting_h setting, char **value) +{ + if (setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (setting->package_name == NULL) { + /* LCOV_EXCL_START */ + ERR("setting->package_name is null"); + return NOTIFICATION_ERROR_NOT_EXIST_ID; + /* LCOV_EXCL_STOP */ + } + + *value = SAFE_STRDUP(setting->package_name); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_get_appid(notification_setting_h setting, char **app_id) +{ + if (setting == NULL || app_id == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (setting->app_id == NULL) { + /* LCOV_EXCL_START */ + ERR("setting->app_id is null"); + return NOTIFICATION_ERROR_NOT_EXIST_ID; + /* LCOV_EXCL_STOP */ + } + + *app_id = SAFE_STRDUP(setting->app_id); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_get_allow_to_notify(notification_setting_h setting, bool *value) +{ + if (setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *value = setting->allow_to_notify; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_set_allow_to_notify(notification_setting_h setting, bool value) +{ + if (setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + setting->allow_to_notify = value; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_get_do_not_disturb_except(notification_setting_h setting, bool *value) +{ + if (setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *value = setting->do_not_disturb_except; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_set_do_not_disturb_except(notification_setting_h setting, bool value) +{ + if (setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + setting->do_not_disturb_except = value; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_get_visibility_class(notification_setting_h setting, int *value) +{ + if (setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *value = setting->visibility_class; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_set_visibility_class(notification_setting_h setting, int value) +{ + if (setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + setting->visibility_class = value; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_get_pop_up_notification(notification_setting_h setting, bool *value) +{ + if (setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *value = setting->pop_up_notification; + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_set_pop_up_notification(notification_setting_h setting, bool value) +{ + if (setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + setting->pop_up_notification = value; + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_get_lock_screen_content(notification_setting_h setting, lock_screen_content_level_e *level) +{ + if (setting == NULL || level == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *level = setting->lock_screen_content_level; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_set_lock_screen_content(notification_setting_h setting, lock_screen_content_level_e level) +{ + if (setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + setting->lock_screen_content_level = level; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_get_app_disabled(notification_setting_h setting, bool *value) +{ + if (setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *value = setting->app_disabled; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_setting_update_setting_for_uid(notification_setting_h setting, uid_t uid) +{ + if (setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return notification_ipc_update_setting(setting, uid); +} + +EXPORT_API int notification_setting_update_setting(notification_setting_h setting) +{ + return notification_setting_update_setting_for_uid(setting, getuid()); +} + +EXPORT_API int notification_setting_free_notification(notification_setting_h setting) +{ + if (setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + SAFE_FREE(setting->package_name); + SAFE_FREE(setting->app_id); + + /* add codes to free all properties */ + + SAFE_FREE(setting); + + return NOTIFICATION_ERROR_NONE; +} + +static bool _is_package_in_setting_table(sqlite3 *db, const char *package_name, + const char *app_id, uid_t uid) +{ + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int sql_ret; + bool err = true; + + if (app_id != NULL) + query = sqlite3_mprintf("SELECT app_id FROM %s WHERE uid = %d " + "AND package_name = %Q AND app_id = %Q", + NOTIFICATION_SETTING_DB_TABLE, + uid, package_name, app_id); + else + query = sqlite3_mprintf("SELECT package_name FROM %s " + "WHERE uid = %d AND package_name = %Q", + NOTIFICATION_SETTING_DB_TABLE, + uid, package_name); + + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("fail to alloc query"); + return false; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (sql_ret != SQLITE_OK) { + /* LCOV_EXCL_START */ + ERR("sqlite3_prepare_v2 failed [%d][%s]", sql_ret, + sqlite3_errmsg(db)); + err = false; + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_step(stmt); + if (sql_ret == SQLITE_DONE) { + INFO("No matched [%s] from package_name [%s], [%d]", + app_id, package_name, sql_ret); + err = false; + goto out; + } + + if (sql_ret != SQLITE_OK && sql_ret != SQLITE_ROW) { + /* LCOV_EXCL_START */ + ERR("sqlite3_step failed [%d][%s]", sql_ret, + sqlite3_errmsg(db)); + err = false; + goto out; + /* LCOV_EXCL_STOP */ + } + +out: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + return err; +} + +static int _foreach_app_info_callback(const pkgmgrinfo_appinfo_h handle, + void *user_data) +{ + setting_local_info *info = (setting_local_info *)user_data; + sqlite3 *db = info->db; + char *query = NULL; + int ret; + int err = true; + char *app_id = NULL; + char *package_name = NULL; + + ret = pkgmgrinfo_appinfo_get_appid(handle, &app_id); + if (ret != PACKAGE_MANAGER_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to get appid from pkgmgrinfo [%d]", + ret); + err = false; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = pkgmgrinfo_appinfo_get_pkgname(handle, &package_name); + if (ret != PACKAGE_MANAGER_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to get pkgname from pkgmgrinfo[%d]", + ret); + goto out; + /* LCOV_EXCL_STOP */ + } + + if (_is_package_in_setting_table(db, package_name, app_id, info->uid) == true) { + INFO("uid %d [%s] is exist", info->uid, app_id); + err = false; + goto out; + } + + query = sqlite3_mprintf("INSERT INTO %s (uid, package_name, app_id) " + "VALUES (%d, %Q, %Q) ", + NOTIFICATION_SETTING_DB_TABLE, + info->uid, package_name, app_id); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("fail to alloc query"); + err = false; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, NULL); + if (ret != NOTIFICATION_ERROR_NONE) + err = false; + else + INFO("uid [%d] package_name [%s] appid [%s] is inserted", + info->uid, package_name, app_id); + +out: + if (query) + sqlite3_free(query); + + return err; +} + +static int _install_and_update_package(const char *package_name, uid_t uid) +{ + sqlite3 *db; + int err = NOTIFICATION_ERROR_NONE; + int pkgmgr_ret; + setting_local_info info; + pkgmgrinfo_appinfo_filter_h handle = NULL; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + pkgmgr_ret = pkgmgrinfo_appinfo_filter_create(&handle); + if (pkgmgr_ret != PMINFO_R_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to create appinfo_filter[%d]", pkgmgr_ret); + err = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + pkgmgr_ret = pkgmgrinfo_appinfo_filter_add_string(handle, + PMINFO_APPINFO_PROP_PRIVILEGE, NOTIFICATION_PRIVILEGE); + if (pkgmgr_ret != PMINFO_R_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to add string to appinfo_filter[%d]", pkgmgr_ret); + err = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + pkgmgr_ret = pkgmgrinfo_appinfo_filter_add_string(handle, + PMINFO_APPINFO_PROP_APP_PACKAGE, package_name); + if (pkgmgr_ret != PMINFO_R_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to add string to appinfo_filter[%d]", pkgmgr_ret); + err = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + info.db = db; + info.uid = uid; + pkgmgr_ret = pkgmgrinfo_appinfo_usr_filter_foreach_appinfo(handle, + _foreach_app_info_callback, &info, uid); + if (pkgmgr_ret != PMINFO_R_OK) { + /* LCOV_EXCL_START */ + ERR("Failed to iterate appinfo[%d]", pkgmgr_ret); + err = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + +out: + if (handle) + pkgmgrinfo_appinfo_filter_destroy(handle); + + if (db) + notification_db_close(&db); + + return err; +} + +static int _delete_package_from_setting_db(const char *package_name, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int err = NOTIFICATION_ERROR_NONE; + bool is_package_in_setting_table = false; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + is_package_in_setting_table = _is_package_in_setting_table(db, + package_name, NULL, uid); + if (is_package_in_setting_table == false) { + INFO("[%s] is not exist", package_name); + goto out; + } + + query = sqlite3_mprintf("DELETE FROM %s WHERE uid = %d " + "AND package_name = %Q ", + NOTIFICATION_SETTING_DB_TABLE, uid, + package_name); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc query"); + err = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + err = notification_db_exec(db, query, NULL); + +out: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return err; +} + +/* LCOV_EXCL_START */ +EXPORT_API int notification_setting_refresh_setting_table(uid_t uid) +{ + int err = NOTIFICATION_ERROR_NONE; + sqlite3 *db = NULL; + int pkgmgr_ret; + pkgmgrinfo_appinfo_filter_h filter = NULL; + setting_local_info info; + + INFO("Refresh setting table [%d]", uid); + + db = notification_db_open(); + if (!db) + return get_last_result(); + + pkgmgr_ret = pkgmgrinfo_appinfo_filter_create(&filter); + if (pkgmgr_ret != PMINFO_R_OK) { + ERR("Failed to create appinfo_filter[%d]", pkgmgr_ret); + err = NOTIFICATION_ERROR_FROM_DB; + goto out; + } + + pkgmgr_ret = pkgmgrinfo_appinfo_filter_add_string(filter, + PMINFO_APPINFO_PROP_PRIVILEGE, NOTIFICATION_PRIVILEGE); + if (pkgmgr_ret != PMINFO_R_OK) { + ERR("Failed to add string to appinfo_filter[%d]", pkgmgr_ret); + err = NOTIFICATION_ERROR_FROM_DB; + goto out; + } + + info.db = db; + info.uid = uid; + pkgmgr_ret = pkgmgrinfo_appinfo_usr_filter_foreach_appinfo(filter, + _foreach_app_info_callback, &info, uid); + if (pkgmgr_ret != PMINFO_R_OK) { + ERR("Failed to foreach appinfo[%d]", pkgmgr_ret); + err = NOTIFICATION_ERROR_FROM_DB; + goto out; + } + +out: + if (filter) + pkgmgrinfo_appinfo_filter_destroy(filter); + + if (db) + notification_db_close(&db); + + return err; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_setting_insert_package_for_uid(const char *package_name, uid_t uid) +{ + return _install_and_update_package(package_name, uid); +} + +EXPORT_API int notification_setting_delete_package_for_uid(const char *package_name, uid_t uid) +{ + return _delete_package_from_setting_db(package_name, uid); +} + +EXPORT_API int notification_system_setting_load_system_setting_for_uid(notification_system_setting_h *system_setting, uid_t uid) +{ + if (system_setting == NULL) { + ERR("NOTIFICATION_ERROR_INVALID_PARAMETER"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return notification_ipc_request_load_system_setting(system_setting, uid); +} + +EXPORT_API int notification_system_setting_load_system_setting(notification_system_setting_h *system_setting) +{ + return notification_system_setting_load_system_setting_for_uid(system_setting, getuid()); +} + +EXPORT_API int notification_system_setting_update_system_setting_for_uid(notification_system_setting_h system_setting, uid_t uid) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return notification_ipc_update_system_setting(system_setting, uid); +} + +EXPORT_API int notification_system_setting_update_system_setting(notification_system_setting_h system_setting) +{ + return notification_system_setting_update_system_setting_for_uid(system_setting, getuid()); +} + +EXPORT_API int notification_system_setting_free_system_setting(notification_system_setting_h system_setting) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + /* add codes to free all properties */ + + if (system_setting->dnd_allow_exceptions != NULL) + g_list_free_full(system_setting->dnd_allow_exceptions, free); + + SAFE_FREE(system_setting); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_get_do_not_disturb(notification_system_setting_h system_setting, bool *value) +{ + if (system_setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *value = system_setting->do_not_disturb; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_set_do_not_disturb(notification_system_setting_h system_setting, bool value) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + system_setting->do_not_disturb = value; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_get_visibility_class(notification_system_setting_h system_setting, int *value) +{ + if (system_setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *value = system_setting->visibility_class; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_set_visibility_class(notification_system_setting_h system_setting, int value) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + system_setting->visibility_class = value; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_get_enabled(notification_system_setting_h system_setting, bool *enabled) +{ + if (system_setting == NULL || enabled == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *enabled = system_setting->dnd_schedule_enabled; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_set_enabled(notification_system_setting_h system_setting, bool enabled) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + system_setting->dnd_schedule_enabled = enabled; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_get_day(notification_system_setting_h system_setting, int *day) +{ + if (system_setting == NULL || day == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *day = system_setting->dnd_schedule_day; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_set_day(notification_system_setting_h system_setting, int day) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + system_setting->dnd_schedule_day = day; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_get_start_time(notification_system_setting_h system_setting, int *hour, int *min) +{ + if (system_setting == NULL || hour == NULL || min == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *hour = system_setting->dnd_start_hour; + *min = system_setting->dnd_start_min; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_set_start_time(notification_system_setting_h system_setting, int hour, int min) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + system_setting->dnd_start_hour = hour; + system_setting->dnd_start_min = min; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_get_end_time(notification_system_setting_h system_setting, int *hour, int *min) +{ + if (system_setting == NULL || hour == NULL || min == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *hour = system_setting->dnd_end_hour; + *min = system_setting->dnd_end_min; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_dnd_schedule_set_end_time(notification_system_setting_h system_setting, int hour, int min) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + system_setting->dnd_end_hour = hour; + system_setting->dnd_end_min = min; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_get_lock_screen_content(notification_system_setting_h system_setting, lock_screen_content_level_e *level) +{ + if (system_setting == NULL || level == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + *level = system_setting->lock_screen_content_level; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_set_lock_screen_content(notification_system_setting_h system_setting, lock_screen_content_level_e level) +{ + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + system_setting->lock_screen_content_level = level; + + return NOTIFICATION_ERROR_NONE; +} + +static gint _dnd_allow_exception_compare(gconstpointer a, gconstpointer b) +{ + dnd_allow_exception_h dnd_allow_exception_data_a; + + if (a == NULL) + return -1; + + dnd_allow_exception_data_a = (dnd_allow_exception_h)a; + + if (dnd_allow_exception_data_a->type == GPOINTER_TO_INT(b)) + return 0; + + return -1; +} + +EXPORT_API int notification_system_setting_get_dnd_allow_exceptions(notification_system_setting_h system_setting, dnd_allow_exception_type_e type, int *value) +{ + dnd_allow_exception_h dnd_allow_exception_data; + GList *list; + + if (system_setting == NULL || value == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + list = g_list_find_custom(system_setting->dnd_allow_exceptions, GINT_TO_POINTER(type), (GCompareFunc)_dnd_allow_exception_compare); + if (list) { + dnd_allow_exception_data = (dnd_allow_exception_h)list->data; + *value = dnd_allow_exception_data->value; + } else { + ERR("Invalid type"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_system_setting_set_dnd_allow_exceptions(notification_system_setting_h system_setting, dnd_allow_exception_type_e type, int value) +{ + dnd_allow_exception_h dnd_allow_exception_data; + GList *list = NULL; + + if (system_setting == NULL) { + ERR("Invalid parameter"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + list = g_list_first(system_setting->dnd_allow_exceptions); + list = g_list_find_custom(list, GINT_TO_POINTER(type), (GCompareFunc)_dnd_allow_exception_compare); + + if (list) { + dnd_allow_exception_data = (dnd_allow_exception_h)list->data; + dnd_allow_exception_data->value = value; + } else { + dnd_allow_exception_data = (dnd_allow_exception_h)malloc(sizeof(struct notification_system_setting_dnd_allow_exception)); + if (dnd_allow_exception_data == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + + dnd_allow_exception_data->type = type; + dnd_allow_exception_data->value = value; + system_setting->dnd_allow_exceptions = g_list_append(list, dnd_allow_exception_data); + } + + return NOTIFICATION_ERROR_NONE; +} + +static gint _noti_dnd_cb_compare(gconstpointer a, gconstpointer b) +{ + noti_dnd_cb_info_s *info = NULL; + + if (a == NULL) + return -1; + + info = (noti_dnd_cb_info_s *)a; + if (info->callback == b) + return 0; + + return 1; +} + +/* LCOV_EXCL_START */ +void notification_call_dnd_changed_cb_for_uid(int do_not_disturb, uid_t uid) +{ + GList *noti_dnd_cb_list = NULL; + noti_dnd_cb_info_s *dnd_data = NULL; + + if (_noti_dnd_cb_hash == NULL) + return; + + noti_dnd_cb_list = (GList *)g_hash_table_lookup(_noti_dnd_cb_hash, GUINT_TO_POINTER(uid)); + if (noti_dnd_cb_list == NULL) { + ERR("Invalid data"); + return; + } + + noti_dnd_cb_list = g_list_first(noti_dnd_cb_list); + + for (; noti_dnd_cb_list != NULL; noti_dnd_cb_list = noti_dnd_cb_list->next) { + dnd_data = noti_dnd_cb_list->data; + + if (dnd_data != NULL && dnd_data->callback != NULL) + dnd_data->callback(dnd_data->user_data, do_not_disturb); + } +} +/* LCOV_EXCL_STOP */ + +EXPORT_API int notification_register_system_setting_dnd_changed_cb_for_uid(dnd_changed_cb callback, void *user_data, uid_t uid) +{ + GList *noti_dnd_list = NULL; + GList *noti_dnd_found_list = NULL; + noti_dnd_cb_info_s *dnd_data = NULL; + + if (callback == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (notification_ipc_monitor_init(uid) != NOTIFICATION_ERROR_NONE) { + /* LCOV_EXCL_START */ + ERR("Failed to init monitor"); + return NOTIFICATION_ERROR_IO_ERROR; + /* LCOV_EXCL_STOP */ + } + + if (_noti_dnd_cb_hash == NULL) + _noti_dnd_cb_hash = g_hash_table_new(g_direct_hash, g_direct_equal); + + dnd_data = (noti_dnd_cb_info_s *)malloc(sizeof(noti_dnd_cb_info_s)); + if (dnd_data == NULL) + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + + dnd_data->callback = callback; + dnd_data->user_data = user_data; + + noti_dnd_list = (GList *)g_hash_table_lookup(_noti_dnd_cb_hash, GUINT_TO_POINTER(uid)); + + if (noti_dnd_list == NULL) { + noti_dnd_list = g_list_append(noti_dnd_list, dnd_data); + g_hash_table_insert(_noti_dnd_cb_hash, GUINT_TO_POINTER(uid), noti_dnd_list); + } else { + noti_dnd_found_list = g_list_find_custom(noti_dnd_list, (gconstpointer)callback, + (GCompareFunc)_noti_dnd_cb_compare); + if (noti_dnd_found_list) { + ERR("Already existing callback"); + free(dnd_data); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + noti_dnd_list = g_list_append(noti_dnd_list, dnd_data); + } + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_register_system_setting_dnd_changed_cb(dnd_changed_cb callback, void *user_data) +{ + return notification_register_system_setting_dnd_changed_cb_for_uid(callback, user_data, getuid()); +} + +EXPORT_API int notification_unregister_system_setting_dnd_changed_cb_for_uid(dnd_changed_cb callback, uid_t uid) +{ + GList *noti_dnd_cb_list = NULL; + GList *noti_dnd_del_list = NULL; + noti_dnd_cb_info_s *dnd_data = NULL; + + if (callback == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (_noti_dnd_cb_hash == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti_dnd_cb_list = (GList *)g_hash_table_lookup(_noti_dnd_cb_hash, GUINT_TO_POINTER(uid)); + + if (noti_dnd_cb_list == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + noti_dnd_del_list = g_list_find_custom(noti_dnd_cb_list, (gconstpointer)callback, + (GCompareFunc)_noti_dnd_cb_compare); + + if (noti_dnd_del_list) { + dnd_data = g_list_nth_data(noti_dnd_del_list, 0); + noti_dnd_cb_list = g_list_delete_link(noti_dnd_cb_list, noti_dnd_del_list); + free(dnd_data); + } else { + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + if (noti_dnd_cb_list == NULL) { + g_hash_table_steal(_noti_dnd_cb_hash, GUINT_TO_POINTER(uid)); + } else { + noti_dnd_cb_list = g_list_first(noti_dnd_cb_list); + g_hash_table_replace(_noti_dnd_cb_hash, GUINT_TO_POINTER(uid), noti_dnd_cb_list); + } + + if (g_hash_table_size(_noti_dnd_cb_hash) == 0) + notification_ipc_monitor_fini(); + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API int notification_unregister_system_setting_dnd_changed_cb(dnd_changed_cb callback) +{ + return notification_unregister_system_setting_dnd_changed_cb_for_uid(callback, getuid()); +} + +/* LCOV_EXCL_START */ +static bool _is_uid_in_system_setting_table(sqlite3 *db, uid_t uid) +{ + sqlite3_stmt *stmt = NULL; + char *query = NULL; + int sql_ret; + bool err = true; + + query = sqlite3_mprintf("SELECT uid FROM %s WHERE uid = %d", + NOTIFICATION_SYSTEM_SETTING_DB_TABLE, uid); + if (query == NULL) { + ERR("Failed to alloc query"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + + sql_ret = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + if (sql_ret != SQLITE_OK) { + ERR("sqlite3_prepare_v2 failed [%d][%s]", sql_ret, + sqlite3_errmsg(db)); + err = false; + goto out; + } + + sql_ret = sqlite3_step(stmt); + if (sql_ret == SQLITE_DONE) { + INFO("No matched uid[%d] err[%d]", uid, sql_ret); + err = false; + goto out; + } + + if (sql_ret != SQLITE_OK && sql_ret != SQLITE_ROW) { + ERR("sqlite3_step failed [%d][%s]", + sql_ret, sqlite3_errmsg(db)); + err = false; + } + +out: + if (stmt) + sqlite3_finalize(stmt); + + if (query) + sqlite3_free(query); + + return err; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_system_setting_init_system_setting_table(uid_t uid) +{ + sqlite3 *db = NULL; + char *query_system_setting = NULL; + char *query_dnd_allow_exception = NULL; + int ret = NOTIFICATION_ERROR_NONE; + + INFO("init system setting table [%d]", uid); + + db = notification_db_open(); + if (db == NULL) + return get_last_result(); + + if (_is_uid_in_system_setting_table(db, uid) == true) { + INFO("Setting table is already initialized."); + goto out; + } + + /* notification_system_setting */ + query_system_setting = sqlite3_mprintf("INSERT INTO %s (uid) " + "VALUES (%d) ", + NOTIFICATION_SYSTEM_SETTING_DB_TABLE, + uid); + if (query_system_setting == NULL) { + ERR("fail to alloc query"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = notification_db_exec(db, query_system_setting, NULL); + if (ret != NOTIFICATION_ERROR_NONE) + goto out; + + /* dnd_allow_exception */ + query_dnd_allow_exception = sqlite3_mprintf("INSERT INTO %s " + "(uid) VALUES (%d) ", + NOTIFICATION_DND_ALLOW_EXCEPTION, + uid); + if (query_dnd_allow_exception == NULL) { + ERR("Failed to alloc query"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = notification_db_exec(db, query_dnd_allow_exception, NULL); + if (ret != NOTIFICATION_ERROR_NONE) + goto out; + + DBG("Initialization is success."); + +out: + if (query_system_setting) + sqlite3_free(query_system_setting); + + if (query_dnd_allow_exception) + sqlite3_free(query_dnd_allow_exception); + + if (db) + notification_db_close(&db); + + return ret; +} +/* LCOV_EXCL_STOP */ diff --git a/notification/src/notification_setting_service.c b/notification/src/notification_setting_service.c new file mode 100644 index 0000000..7faee55 --- /dev/null +++ b/notification/src/notification_setting_service.c @@ -0,0 +1,931 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <sqlite3.h> +#include <tizen.h> + +#include <notification.h> +#include <notification_db.h> +#include <notification_error.h> +#include <notification_debug.h> +#include <notification_private.h> +#include <notification_setting.h> +#include <notification_setting_internal.h> +#include <notification_setting_service.h> +#include "notification_db_query.h" + +static int _get_table_field_data_int(char **table, int *buf, int index) +{ + if (table == NULL || buf == NULL || index < 0) { + /* LCOV_EXCL_START */ + ERR("table[%p], buf[%p], index[%d]", table, buf, index); + return false; + /* LCOV_EXCL_STOP */ + } + + if (table[index] != NULL) { + *buf = atoi(table[index]); + return true; + } + + /* LCOV_EXCL_START */ + *buf = 0; + return false; + /* LCOV_EXCL_STOP */ +} + +static int _get_table_field_data_string(char **table, char **buf, int ucs2, int index) +{ + int ret = false; + int sLen = 0; + char *pTemp; + + if (table == NULL || buf == NULL || index < 0) { + /* LCOV_EXCL_START */ + ERR("table[%p], buf[%p], index[%d]", table, buf, index); + return false; + /* LCOV_EXCL_STOP */ + } + + pTemp = table[index]; + + if (pTemp == NULL) { + *buf = NULL; /* LCOV_EXCL_LINE */ + } else { + sLen = strlen(pTemp); + if (sLen) { + *buf = (char *)malloc(sLen + 1); + if (*buf == NULL) { + ERR("Failed to alloc memory"); /* LCOV_EXCL_LINE */ + goto out; + } + memset(*buf, 0, sLen + 1); + strncpy(*buf, pTemp, sLen); + } else { + *buf = NULL; /* LCOV_EXCL_LINE */ + } + } + + ret = true; + +out: + return ret; +} + +EXPORT_API +int noti_setting_service_get_setting_by_app_id(const char *app_id, notification_setting_h *setting, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + char **query_result = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + int row_count = 0; + int column_count = 0; + int i = 0; + int col_index = 0; + notification_setting_h result_setting_array = NULL; + + if (app_id == NULL || setting == NULL) { + ERR("Invalid parameter"); /* LCOV_EXCL_LINE */ + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT %s FROM %s WHERE app_id = %Q AND uid = %d", + NOTIFICATION_SETTING_DB_ATTRIBUTES, NOTIFICATION_SETTING_DB_TABLE, + app_id, uid); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc query"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_get_table(db, query, &query_result, &row_count, &column_count, NULL); + if (sql_ret != SQLITE_OK && sql_ret != -1) { + /* LCOV_EXCL_START */ + ERR("sqlite3_get_table failed [%d][%s]", sql_ret, + query); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (!row_count) { + DBG("No setting found for [%s]", app_id); + ret = NOTIFICATION_ERROR_NOT_EXIST_ID; + goto out; + } + + DBG("row_count[%d] column_count[%d]", row_count, column_count); + + row_count = 1; + + result_setting_array = (struct notification_setting *)malloc(sizeof(struct notification_setting) * row_count); + if (result_setting_array == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + col_index = column_count; + + _get_table_field_data_string(query_result, &(result_setting_array[i].package_name), 1, col_index++); + _get_table_field_data_string(query_result, &(result_setting_array[i].app_id), 1, col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].allow_to_notify), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].do_not_disturb_except), col_index++); + _get_table_field_data_int(query_result, &(result_setting_array[i].visibility_class), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].pop_up_notification), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].lock_screen_content_level), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].app_disabled), col_index++); + + *setting = result_setting_array; + +out: + if (query_result) + sqlite3_free_table(query_result); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API +int noti_setting_get_setting_array(notification_setting_h *setting_array, int *count, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + char **query_result = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + int row_count = 0; + int column_count = 0; + int i = 0; + int col_index = 0; + notification_setting_h result_setting_array = NULL; + + if (setting_array == NULL || count == NULL) { + ERR("NOTIFICATION_ERROR_INVALID_PARAMETER"); /* LCOV_EXCL_LINE */ + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT %s FROM %s WHERE uid = %d " + "AND app_disabled = %d ORDER BY package_name, " + "app_id ", NOTIFICATION_SETTING_DB_ATTRIBUTES, + NOTIFICATION_SETTING_DB_TABLE, uid, 0); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc query"); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_get_table(db, query, &query_result, &row_count, &column_count, NULL); + if (sql_ret != SQLITE_OK && sql_ret != -1) { + /* LCOV_EXCL_START */ + ERR("Failed to get db table [%d][%s]", + sql_ret, query); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (!row_count) { + DBG("No setting found"); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_NOT_EXIST_ID; + goto out; + } + + DBG("row_count[%d] column_count[%d]", row_count, column_count); + + result_setting_array = (struct notification_setting *)malloc(sizeof(struct notification_setting) * row_count); + if (result_setting_array == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + col_index = column_count; + + for (i = 0; i < row_count; i++) { + _get_table_field_data_string(query_result, &(result_setting_array[i].package_name), 1, col_index++); + _get_table_field_data_string(query_result, &(result_setting_array[i].app_id), 1, col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].allow_to_notify), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].do_not_disturb_except), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].visibility_class), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].pop_up_notification), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].lock_screen_content_level), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_setting_array[i].app_disabled), col_index++); + } + + *setting_array = result_setting_array; + *count = row_count; + +out: + if (query_result) + sqlite3_free_table(query_result); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + + +EXPORT_API +int noti_system_setting_load_system_setting(notification_system_setting_h *system_setting, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + char **query_result = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + int row_count = 0; + int column_count = 0; + int col_index = 0; + notification_system_setting_h result_system_setting = NULL; + + if (system_setting == NULL) { + ERR("Invalid parameter"); /* LCOV_EXCL_LINE */ + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT %s FROM %s WHERE uid = %d", + NOTIFICATION_SYSTEM_SETTING_DB_ATTRIBUTES, + NOTIFICATION_SYSTEM_SETTING_DB_TABLE, uid); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc query"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_get_table(db, query, &query_result, &row_count, &column_count, NULL); + if (sql_ret != SQLITE_OK && sql_ret != -1) { + /* LCOV_EXCL_START */ + ERR("Failed to get db table [%d][%s]", sql_ret, query); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + DBG("row_count [%d] column_count [%d]", row_count, column_count); + + result_system_setting = (struct notification_system_setting *)malloc(sizeof(struct notification_system_setting)); + if (result_system_setting == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + /* no system setting record. allow everyting */ + if (!row_count) { + /* LCOV_EXCL_START */ + DBG("No setting found"); + result_system_setting->do_not_disturb = 0; + result_system_setting->visibility_class = 0; + result_system_setting->dnd_schedule_enabled = 0; + result_system_setting->dnd_schedule_day = 0; + result_system_setting->dnd_start_hour = 0; + result_system_setting->dnd_start_min = 0; + result_system_setting->dnd_end_hour = 0; + result_system_setting->dnd_end_min = 0; + result_system_setting->lock_screen_content_level = 0; + result_system_setting->dnd_allow_exceptions = NULL; + /* LCOV_EXCL_STOP */ + } else { + /* LCOV_EXCL_START */ + col_index = column_count; + _get_table_field_data_int(query_result, (int *)&(result_system_setting->do_not_disturb), col_index++); + _get_table_field_data_int(query_result, &(result_system_setting->visibility_class), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_system_setting->dnd_schedule_enabled), col_index++); + _get_table_field_data_int(query_result, &(result_system_setting->dnd_schedule_day), col_index++); + _get_table_field_data_int(query_result, &(result_system_setting->dnd_start_hour), col_index++); + _get_table_field_data_int(query_result, &(result_system_setting->dnd_start_min), col_index++); + _get_table_field_data_int(query_result, &(result_system_setting->dnd_end_hour), col_index++); + _get_table_field_data_int(query_result, &(result_system_setting->dnd_end_min), col_index++); + _get_table_field_data_int(query_result, (int *)&(result_system_setting->lock_screen_content_level), col_index++); + result_system_setting->dnd_allow_exceptions = NULL; + /* LCOV_EXCL_STOP */ + } + + *system_setting = result_system_setting; + +out: + if (query_result) + sqlite3_free_table(query_result); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API +int notification_setting_db_update(const char *package_name, const char *app_id, + int allow_to_notify, int do_not_disturb_except, + int visibility_class, int pop_up_notification, + int lock_screen_content_level, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + + if (package_name == NULL || app_id == NULL) { + ERR("Invalid paramter"); /* LCOV_EXCL_LINE */ + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("UPDATE %s SET allow_to_notify = %d, " + "do_not_disturb_except = %d, visibility_class = %d, " + "pop_up_notification = %d, lock_screen_content_level = %d " + "WHERE app_id = %Q AND package_name = %Q AND uid = %d ", + NOTIFICATION_SETTING_DB_TABLE, allow_to_notify, + do_not_disturb_except, visibility_class, + pop_up_notification, lock_screen_content_level, app_id, + package_name, uid); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, NULL); + +out: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API +int notification_setting_db_update_system_setting(int do_not_disturb, int visibility_class, + int dnd_schedule_enabled, int dnd_schedule_day, + int dnd_start_hour, int dnd_start_min, + int dnd_end_hour, int dnd_end_min, + int lock_screen_content_level, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int num_changes = 0; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("INSERT OR REPLACE INTO %s (uid, %s) " + "VALUES(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d) ", + NOTIFICATION_SYSTEM_SETTING_DB_TABLE, + NOTIFICATION_SYSTEM_SETTING_DB_ATTRIBUTES, + uid, do_not_disturb, visibility_class, + dnd_schedule_enabled, dnd_schedule_day, dnd_start_hour, + dnd_start_min, dnd_end_hour, dnd_end_min, + lock_screen_content_level); + if (query == NULL) { + /* LCOV_EXCL_START */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, &num_changes); + if (ret != NOTIFICATION_ERROR_NONE) + goto out; + + if (num_changes == 0) + WARN("No changes on DB"); + +out: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +/* LCOV_EXCL_START */ +EXPORT_API +int notification_setting_db_update_do_not_disturb(int do_not_disturb, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("UPDATE %s SET do_not_disturb = %d " + "WHERE uid = %d", + NOTIFICATION_SYSTEM_SETTING_DB_TABLE, + do_not_disturb, uid); + if (query == NULL) { + ERR("Failed to alloc query"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = notification_db_exec(db, query, NULL); + +out: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API +int notification_system_setting_get_dnd_schedule_enabled_uid(uid_t **uids, int *count) +{ + int ret = NOTIFICATION_ERROR_NONE; + int i; + int row_count = 0; + int column_count = 0; + int column_index = 0; + char *query = NULL; + char **query_result = NULL; + sqlite3 *db = NULL; + uid_t *result_uids; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT uid FROM %s " + "WHERE dnd_schedule_enabled = 1", + NOTIFICATION_SYSTEM_SETTING_DB_TABLE); + if (query == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = sqlite3_get_table(db, query, &query_result, &row_count, &column_count, NULL); + if (ret != SQLITE_OK && ret != -1) { + ERR("Failed to get DB table [%d][%s]", ret, query); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + } + + if (row_count == 0) { + DBG("No enabled do_not_disturb user"); + ret = NOTIFICATION_ERROR_NONE; + goto out; + } + + result_uids = (uid_t *)malloc(sizeof(int) * row_count); + if (result_uids == NULL) { + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + column_index = column_count; + for (i = 0; i < row_count; i++) + _get_table_field_data_int(query_result, (int *)&(result_uids[i]), column_index++); + + *uids = result_uids; + *count = row_count; + +out: + if (query) + sqlite3_free(query); + + if (query_result) + sqlite3_free_table(query_result); + + if (db) + notification_db_close(&db); + + return ret; +} +/* LCOV_EXCL_STOP */ + +EXPORT_API +int notification_get_dnd_and_allow_to_notify(const char *app_id, + int *do_not_disturb, + int *do_not_disturb_except, + int *allow_to_notify, + uid_t uid) +{ + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + int row_count; + int col_count; + int col_index; + sqlite3 *db; + char *query_setting = NULL; + char **query_setting_result = NULL; + char *query_system_setting = NULL; + char **query_system_setting_result = NULL; + + if (app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query_setting = sqlite3_mprintf("SELECT allow_to_notify, " + "do_not_disturb_except FROM %s WHERE app_id = %Q " + "AND (uid = %d OR uid = %d) ORDER BY uid DESC", + NOTIFICATION_SETTING_DB_TABLE, app_id, + uid, tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)); + if (query_setting == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + query_system_setting = sqlite3_mprintf("SELECT do_not_disturb FROM %s " + "WHERE uid = %d", + NOTIFICATION_SYSTEM_SETTING_DB_TABLE, uid); + if (query_system_setting == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_get_table(db, query_setting, &query_setting_result, &row_count, &col_count, NULL); + if (sql_ret != SQLITE_OK && sql_ret != -1) { + /* LCOV_EXCL_START */ + ERR("Failed to get DB table [%d][%s]", sql_ret, query_setting); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (row_count == 0) { + ERR("Invalid uid [%d] or app id [%s]", uid, app_id); + ret = NOTIFICATION_ERROR_INVALID_PARAMETER; + goto out; + } + + col_index = col_count; + _get_table_field_data_int(query_setting_result, (int *)allow_to_notify, col_index++); + _get_table_field_data_int(query_setting_result, (int *)do_not_disturb_except, col_index++); + + sql_ret = sqlite3_get_table(db, query_system_setting, &query_system_setting_result, &row_count, &col_count, NULL); + if (sql_ret != SQLITE_OK && sql_ret != -1) { + /* LCOV_EXCL_START */ + ERR("Failed to get DB table [%d][%s]", sql_ret, query_setting); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (row_count == 0) { + ERR("Invalid uid [%d]", uid); + ret = NOTIFICATION_ERROR_INVALID_PARAMETER; + goto out; + } + + col_index = col_count; + _get_table_field_data_int(query_system_setting_result, (int *)do_not_disturb, col_index++); + +out: + if (query_setting_result) + sqlite3_free_table(query_setting_result); + + if (query_system_setting_result) + sqlite3_free_table(query_system_setting_result); + + if (query_setting) + sqlite3_free(query_setting); + + if (query_system_setting) + sqlite3_free(query_system_setting); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API int notification_system_setting_load_dnd_allow_exception(dnd_allow_exception_h *dnd_allow_exception, int *count, uid_t uid) +{ + int ret = NOTIFICATION_ERROR_NONE; + int sql_ret; + int row_count = 0; + int column_count = 0; + int col_index = 0; + int i; + char *query = NULL; + char **query_result = NULL; + sqlite3 *db = NULL; + dnd_allow_exception_h dnd_allow_exception_data = NULL; + + if (dnd_allow_exception == NULL) { + ERR("Invalid paramter"); /* LCOV_EXCL_LINE */ + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT type, value FROM %s WHERE uid = %d", + NOTIFICATION_DND_ALLOW_EXCEPTION, uid); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + sql_ret = sqlite3_get_table(db, query, &query_result, &row_count, &column_count, NULL); + if (sql_ret != SQLITE_OK && sql_ret != -1) { + /* LCOV_EXCL_START */ + ERR("Failed to get DB table [%d][%s]", sql_ret, query); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (!row_count) { + DBG("No setting found"); /* LCOV_EXCL_LINE */ + goto out; + } else { + dnd_allow_exception_data = (dnd_allow_exception_h)malloc(sizeof(struct notification_system_setting_dnd_allow_exception) * row_count); + if (dnd_allow_exception_data == NULL) { + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + col_index = column_count; + + for (i = 0; i < row_count; i++) { + _get_table_field_data_int(query_result, (int *)&(dnd_allow_exception_data[i].type), col_index++); + _get_table_field_data_int(query_result, (int *)&(dnd_allow_exception_data[i].value), col_index++); + } + } + + *dnd_allow_exception = dnd_allow_exception_data; + *count = row_count; + +out: + if (query_result) + sqlite3_free_table(query_result); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API +int notification_system_setting_update_dnd_allow_exception(int type, int value, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int num_changes = 0; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("INSERT OR REPLACE INTO %s (uid, type, value) " + "VALUES(%d, %d, %d) ", + NOTIFICATION_DND_ALLOW_EXCEPTION, + uid, type, value); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = notification_db_exec(db, query, &num_changes); + if (ret != NOTIFICATION_ERROR_NONE) + goto out; + + if (num_changes == 0) + WARN("No changes on DB"); + +out: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +EXPORT_API +int noti_system_setting_get_do_not_disturb(int *do_not_disturb, uid_t uid) +{ + int ret = NOTIFICATION_ERROR_NONE; + int row_count = 0; + int col_count = 0; + int col_index = 0; + char *query = NULL; + char **query_result = NULL; + sqlite3 *db = NULL; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("SELECT do_not_disturb FROM %s WHERE uid = %d", + NOTIFICATION_SYSTEM_SETTING_DB_TABLE, uid); + if (query == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to alloc memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = sqlite3_get_table(db, query, &query_result, &row_count, &col_count, NULL); + if (ret != SQLITE_OK && ret != -1) { + /* LCOV_EXCL_START */ + ERR("Failed to get DB table [%d][%s]", ret, query); + ret = NOTIFICATION_ERROR_FROM_DB; + goto out; + /* LCOV_EXCL_STOP */ + } + + col_index = col_count; + if (row_count == 0) { + /* LCOV_EXCL_START */ + ERR("No system setting found"); + ret = NOTIFICATION_ERROR_INVALID_PARAMETER; + /* LCOV_EXCL_STOP */ + } else { + if (_get_table_field_data_int(query_result, (int *)do_not_disturb, col_index++) == false) + ret = NOTIFICATION_ERROR_FROM_DB; + } + +out: + if (query_result) + sqlite3_free_table(query_result); + + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} + +/* LCOV_EXCL_START */ +EXPORT_API +int notification_setting_db_update_app_disabled(const char *app_id, bool value, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int num_changes = 0; + + if (app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("UPDATE %s SET app_disabled= %d " \ + "WHERE app_id = %Q AND uid = %d", + NOTIFICATION_SETTING_DB_TABLE, value, + app_id, uid); + if (query == NULL) { + ERR("Failed to alloc memory"); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = notification_db_exec(db, query, &num_changes); + if (ret == NOTIFICATION_ERROR_NONE && num_changes <= 0) + ret = NOTIFICATION_ERROR_NOT_EXIST_ID; + +out: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API +int notification_setting_db_update_pkg_disabled(const char *pkg_id, bool value, uid_t uid) +{ + sqlite3 *db = NULL; + char *query = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int num_changes = 0; + + if (pkg_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + db = notification_db_open(DBPATH); + if (!db) + return get_last_result(); + + query = sqlite3_mprintf("UPDATE %s SET app_disabled= %d " \ + "WHERE package_name = %Q AND uid = %d", + NOTIFICATION_SETTING_DB_TABLE, value, + pkg_id, uid); + if (query == NULL) { + ERR("Failed to alloc memory"); /* LCOV_EXCL_LINE */ + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = notification_db_exec(db, query, &num_changes); + if (ret == NOTIFICATION_ERROR_NONE && num_changes <= 0) + ret = NOTIFICATION_ERROR_NOT_EXIST_ID; + +out: + if (query) + sqlite3_free(query); + + if (db) + notification_db_close(&db); + + return ret; +} +/* LCOV_EXCL_STOP */ + diff --git a/notification/src/notification_shared_file.c b/notification/src/notification_shared_file.c new file mode 100644 index 0000000..7ca23d9 --- /dev/null +++ b/notification/src/notification_shared_file.c @@ -0,0 +1,1185 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <gio/gio.h> +#include <glib/gstdio.h> + +#include <tzplatform_config.h> +#include <security-manager.h> +#include <sys/smack.h> +#include <sys/stat.h> +#include <linux/xattr.h> +#include <sys/types.h> +#include <utime.h> +#include <sys/time.h> +#include <package_manager.h> + +#include "notification.h" +#include "notification_debug.h" +#include "notification_shared_file.h" +#include <notification_private.h> + + +#define DUMMY_PARAM +#define __OOM_CHECK(value, ret_value, free_fun) \ +do { \ + if (value == NULL) { \ + ERR("out of memory"); \ + free_fun; \ + return ret_value; \ + } \ +} while (0) + +GList *__uid_list; +typedef struct uid_info { + uid_t uid; + GList *sharing_req_list; + GList *target_app_list; +} uid_info_s; + +typedef struct sharing_req_data { + char *app_id; + char *dir; + GList *priv_id_list; + GList *shared_file_list; + GList *target_app_table; +} sharing_req_data_s; + +typedef struct sharing_file_info { + char *src_path; + char *dst_path; + time_t modification_time; +} sharing_file_info_s; + +typedef struct target_app_info { + char *app_id; + char *dbus_sender_name; +} target_app_info_s; + +static bool __make_sharing_dir(const char *dir) +{ + GFile *noti_dir = NULL; + GError *g_err = NULL; + + if (access(dir, R_OK) != 0) { + noti_dir = g_file_new_for_path(dir); + if (g_file_make_directory(noti_dir, NULL, &g_err) == false) { + /* LCOV_EXCL_START */ + if (g_err) { + ERR("Failed to make sharing dir[%s]", + g_err->message); + g_error_free(g_err); + } + g_object_unref(noti_dir); + return false; + /* LCOV_EXCL_STOP */ + } + g_object_unref(noti_dir); + } + + return true; +} + +static char *__get_data_path_by_pkg_id(const char *pkg_id, + const char *file_name, uid_t uid) +{ +#define NOTI_PRIV_DATA_DIR "data/.notification" + + const char *path; + char dir[PATH_MAX]; + + tzplatform_set_user(uid); + path = tzplatform_getenv(TZ_USER_APP); + tzplatform_reset_user(); + + if (pkg_id == NULL || path == NULL) + return NULL; + + snprintf(dir, sizeof(dir), "%s/%s/%s", path, pkg_id, NOTI_PRIV_DATA_DIR); + + if (__make_sharing_dir(dir) == false) + return NULL; + + snprintf(dir, sizeof(dir), "%s/%s/%s/%s", path, pkg_id, + NOTI_PRIV_DATA_DIR, file_name); + + return strdup(dir); +} + +static const char *__last_index_of(const char *path, const char *search) +{ + int i; + int search_len; + const char *index; + + if (path == NULL || search == NULL) + return NULL; + + search_len = strlen(search); + index = path + strlen(path) - search_len; + + while (index >= path) { + for (i = 0; i < search_len; i++) + if (index[i] != search[i]) + break; + + if (i == search_len) + return index; + index--; + } + + return NULL; +} + +/* Check path that include res directory */ +/* LCOV_EXCL_START */ +static bool __is_private_file(const char *smack_label, const char *pkg_id) +{ + const char *smack_index; + bool ret = false; + + if (smack_label == NULL || pkg_id == NULL) + return ret; + + smack_index = __last_index_of(smack_label, pkg_id); + if (smack_index != NULL && (strlen(smack_index) == strlen(pkg_id))) + ret = true; + + return ret; +} +/* LCOV_EXCL_STOP */ + +static bool __is_RO_file(const char *smack_label) +{ +#define CHECK_LABEL "::RO" + + const char *smack_index; + bool ret = false; + + smack_index = __last_index_of(smack_label, CHECK_LABEL); + if (smack_index != NULL && (strlen(smack_index) == strlen(CHECK_LABEL))) + ret = true; + + return ret; +} + +/* file copy from /res to /data */ +int notification_copy_private_file(const char *src_path, + const char *dst_path) +{ + int ret = NOTIFICATION_ERROR_NONE; + GFile *src = NULL; + GFile *dst = NULL; + GError *g_err = NULL; + struct utimbuf ut = {0,}; + + dst = g_file_new_for_path(dst_path); + if (dst == NULL) { + /* LCOV_EXCL_START */ + ERR("dst path is wrong [%s]", dst_path); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (g_file_query_exists(dst, NULL) == true) { + ret = NOTIFICATION_ERROR_ALREADY_EXIST_ID; + INFO("dst path existed [%s]", dst_path); + goto out; + } + + src = g_file_new_for_path(src_path); + if (src == NULL) { + /* LCOV_EXCL_START */ + ERR("src path is wrong [%s]", src_path); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (!g_file_copy(src, dst, G_FILE_COPY_NOFOLLOW_SYMLINKS, + /* LCOV_EXCL_START */ + NULL, NULL, NULL, &g_err)) { + if (g_err) { + ERR( + "Copying file from [%s] to [%s] is failed [%s]", + src_path, dst_path, g_err->message); + g_error_free(g_err); + } + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + ut.modtime = time(NULL); + if (g_utime(dst_path, &ut) != 0) + DBG("Failed to set g_utime %d ", errno); + +out: + if (src) + g_object_unref(src); + if (dst) + g_object_unref(dst); + + return ret; +} + +static void __free_file_info(gpointer data) +{ + sharing_file_info_s *info = (sharing_file_info_s *)data; + + if (info != NULL) { + if (info->src_path) + free(info->src_path); + if (info->dst_path) + free(info->dst_path); + free(info); + } +} + +/* LCOV_EXCL_START */ +static void __free_req_info(gpointer data) +{ + sharing_req_data_s *info = (sharing_req_data_s *)data; + + if (info == NULL) + return; + if (info->app_id) + free(info->app_id); + if (info->dir) + free(info->dir); + if (info->shared_file_list) + g_list_free_full(info->shared_file_list, __free_file_info); + if (info->target_app_table) + g_list_free_full(info->target_app_table, free); + + free(info); +} +/* LCOV_EXCL_STOP */ + +static char **__convert_list_to_array(GList *list, int *length) +{ + int len, i; + char **array; + GList *iter; + + if (list == NULL) + return NULL; + + len = g_list_length(list); + if (len == 0) + return NULL; + + array = (char **)calloc(len + 1, sizeof(char *)); + __OOM_CHECK(array, NULL, DUMMY_PARAM); + + for (i = 0, iter = list; iter != NULL; i++, iter = g_list_next(iter)) + array[i] = ((sharing_file_info_s *)iter->data)->dst_path; + + *length = len; + + return array; +} + +static gint __comp_str(gconstpointer a, gconstpointer b) +{ + char *new_file = (char *)a; + char *file = (char *)b; + + if (new_file == NULL || file == NULL) + return -1; + + return strcmp(new_file, file); +} + +/* LCOV_EXCL_START */ +static gint __comp_file_info(gconstpointer a, gconstpointer b) +{ + sharing_file_info_s *file = (sharing_file_info_s *)a; + sharing_file_info_s *new_file = (sharing_file_info_s *)b; + + if (!file || !new_file || !new_file->dst_path || !file->dst_path) + return -1; + + return strcmp(new_file->dst_path, file->dst_path); +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +static gint __comp_dst_path(gconstpointer a, gconstpointer b) +{ + sharing_file_info_s *info = (sharing_file_info_s *)a; + char *path = (char *)b; + + if (!info || !path || !info->dst_path) + return -1; + + return strcmp(info->dst_path, path); +} +/* LCOV_EXCL_STOP */ + +static sharing_file_info_s *__dup_file_info(sharing_file_info_s *src) +{ + sharing_file_info_s *file_info; + + file_info = (sharing_file_info_s *)calloc(1, sizeof(sharing_file_info_s)); + __OOM_CHECK(file_info, NULL, DUMMY_PARAM); + + file_info->dst_path = strdup(src->dst_path); + __OOM_CHECK(file_info->dst_path, NULL, __free_file_info(file_info)); + + file_info->src_path = strdup(src->src_path); + __OOM_CHECK(file_info->src_path, NULL, __free_file_info(file_info)); + + file_info->modification_time = src->modification_time; + + return file_info; + +} + +static void __make_file_info(char *src_path, char *dst_path, + GList **new_file_list, GList *shared_file_list, bool *is_overlapping) +{ + int ret; + GList *tmp; + sharing_file_info_s *file_info; + sharing_file_info_s *dup_file_info; + struct stat stat_buf = {0,}; + + /* + * If the file copy is successful, + * ignore the shared_file_list check for private sharing + */ + ret = notification_copy_private_file(src_path, dst_path); + + if (ret == NOTIFICATION_ERROR_ALREADY_EXIST_ID) { + tmp = g_list_find_custom(shared_file_list, dst_path, + __comp_dst_path); + if (tmp == NULL) { + file_info = (sharing_file_info_s *)calloc(1, + sizeof(sharing_file_info_s)); + __OOM_CHECK(file_info, DUMMY_PARAM, DUMMY_PARAM); + + file_info->dst_path = strdup(dst_path); + __OOM_CHECK(file_info->dst_path, DUMMY_PARAM, + __free_file_info(file_info)); + + file_info->src_path = strdup(src_path); + __OOM_CHECK(file_info->src_path, DUMMY_PARAM, + __free_file_info(file_info)); + + if (stat(dst_path, &stat_buf) != 0) + ERR("Failed to get stat info"); + file_info->modification_time = stat_buf.st_mtime; + + *new_file_list = g_list_append(*new_file_list, file_info); + } else { + file_info = (sharing_file_info_s *)tmp->data; + + if (stat(file_info->dst_path, &stat_buf) != 0) + ERR("Failed to get stat info"); + + if (file_info->modification_time != stat_buf.st_mtime) { + dup_file_info = __dup_file_info(file_info); + __OOM_CHECK(dup_file_info, DUMMY_PARAM, DUMMY_PARAM); + + *new_file_list = g_list_append(*new_file_list, + dup_file_info); + *is_overlapping = true; + } + } + } else if (ret == NOTIFICATION_ERROR_NONE) { + *is_overlapping = true; + } + +} + +static GList *__get_new_file_list(notification_h noti, + GList *shared_file_list, + bool *is_overlapping) +{ + GList *new_file_list = NULL; + char *src_path, *dst_path, *dup_str; + char buf_key[32] = { 0, }; + int i = NOTIFICATION_IMAGE_TYPE_ICON; + + + if (noti->priv_sound_path != NULL && noti->sound_path != NULL) { + dst_path = noti->priv_sound_path; + src_path = noti->sound_path; + + dup_str = strdup(dst_path); + __OOM_CHECK(dup_str, NULL, DUMMY_PARAM); + + __make_file_info(src_path, dst_path, &new_file_list, + shared_file_list, is_overlapping); + + free(noti->sound_path); + noti->sound_path = dup_str; + } + + if (noti->priv_vibration_path != NULL && noti->vibration_path != NULL) { + dst_path = noti->priv_vibration_path; + src_path = noti->vibration_path; + + dup_str = strdup(dst_path); + __OOM_CHECK(dup_str, NULL, + g_list_free_full(new_file_list, __free_file_info)); + + __make_file_info(src_path, dst_path, &new_file_list, + shared_file_list, is_overlapping); + + free(noti->vibration_path); + noti->vibration_path = dup_str; + } + + if (noti->b_priv_image_path == NULL) + return new_file_list; + + for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) { + src_path = NULL; + dst_path = NULL; + snprintf(buf_key, sizeof(buf_key), "%d", i); + bundle_get_str(noti->b_priv_image_path, buf_key, &dst_path); + bundle_get_str(noti->b_image_path, buf_key, &src_path); + if (dst_path != NULL && src_path != NULL) { + __make_file_info(src_path, dst_path, &new_file_list, + shared_file_list, is_overlapping); + + bundle_del(noti->b_image_path, buf_key); + bundle_add_str(noti->b_image_path, buf_key, dst_path); + } + } + + return new_file_list; +} + +static char *__get_shared_dir(notification_h noti) +{ + char *path = NULL; + char *dir; + const char *index; + char buf_key[32] = { 0, }; + int i = NOTIFICATION_IMAGE_TYPE_ICON, dir_len; + + if (noti->b_priv_image_path != NULL) { + for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) { + snprintf(buf_key, sizeof(buf_key), "%d", i); + bundle_get_str(noti->b_priv_image_path, buf_key, &path); + if (path != NULL) + break; + } + } + + if (path == NULL && noti->priv_sound_path != NULL) + path = noti->priv_sound_path; + else if (path == NULL && noti->priv_vibration_path != NULL) + path = noti->priv_vibration_path; + + if (path == NULL) { + DBG("No private resource"); + return NULL; + } + + index = __last_index_of(path, "/"); + if (index == NULL) { + ERR("Failed to find directory separator"); + return NULL; + } + + dir_len = index - path + 1; + if (dir_len <= 0 || dir_len > PATH_MAX) + return NULL; + + dir = (char *)calloc(dir_len, sizeof(char)); + __OOM_CHECK(dir, NULL, DUMMY_PARAM); + + snprintf(dir, dir_len, "%s", path); + + return dir; +} + +static gint __comp_sharing_req_list(gconstpointer a, gconstpointer b) +{ + sharing_req_data_s *req_data = (sharing_req_data_s *)a; + char *app_id = (char *)b; + + if (!req_data || !app_id || !req_data->app_id) + return -1; + + if (!strcmp(app_id, req_data->app_id)) + return 0; + + return -1; +} + +static gint __comp_uid_info_list(gconstpointer a, gconstpointer b) +{ + uid_info_s *uid_info = (uid_info_s *)a; + + if (!a || !b) + return -1; + + if (uid_info->uid == GPOINTER_TO_INT(b)) + return 0; + + return -1; +} + +static gint __comp_priv_id(gconstpointer a, gconstpointer b) +{ + if (!a || !b) + return -1; + + if (GPOINTER_TO_INT(a) == GPOINTER_TO_INT(b)) + return 0; + + return 1; +} + +static gint __comp_target_app(gconstpointer a, gconstpointer b) +{ + target_app_info_s *target = (target_app_info_s *)a; + char *sender = (char *)b; + + if (!target || !sender || !target->dbus_sender_name) + return -1; + + return strcmp(sender, target->dbus_sender_name); +} + +EXPORT_API void notification_remove_private_sharing_target_id( + const char *sender, uid_t uid) +{ + target_app_info_s *target_info; + uid_info_s *uid_info; + GList *sharing_req_list, *target_app; + + sharing_req_list = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid), + __comp_uid_info_list); + if (sharing_req_list == NULL) + return; + + uid_info = sharing_req_list->data; + target_app = g_list_find_custom(uid_info->target_app_list, sender, + __comp_target_app); + + if (target_app != NULL) { + target_info = target_app->data; + if (target_info) { + uid_info->target_app_list = g_list_remove( + uid_info->target_app_list, target_info); + + free(target_info->app_id); + free(target_info->dbus_sender_name); + free(target_info); + target_info = NULL; + } + } +} + +EXPORT_API void notification_add_private_sharing_target_id(pid_t pid, + const char *sender, uid_t uid) +{ + char *app_id; + target_app_info_s *target_info; + uid_info_s *uid_info; + GList *sharing_req_list, *target_app; + + sharing_req_list = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid), + __comp_uid_info_list); + if (sharing_req_list == NULL) { + uid_info = (uid_info_s *)calloc(1, sizeof(uid_info_s)); + __OOM_CHECK(uid_info, DUMMY_PARAM, DUMMY_PARAM); + uid_info->uid = uid; + + __uid_list = g_list_append(__uid_list, uid_info); + } else { + uid_info = sharing_req_list->data; + } + + target_app = g_list_find_custom(uid_info->target_app_list, sender, + __comp_target_app); + if (target_app == NULL) { + app_id = notification_get_app_id_by_pid((int)pid); + if (app_id == NULL) { + ERR("Failed to get app id by pid"); + return; + } + + target_info = (target_app_info_s *)calloc(1, sizeof(target_app_info_s)); + if (target_info == NULL) { + ERR("Failed to alloc memory"); + free(app_id); + return; + } + + target_info->app_id = app_id; + target_info->dbus_sender_name = strdup(sender); + if (target_info->dbus_sender_name == NULL) { + ERR("Failed to alloc memory"); + free(target_info); + free(app_id); + return; + } + + uid_info->target_app_list = g_list_append( + uid_info->target_app_list, target_info); + } +} + +char *notification_check_file_path_is_private(const char *pkg_id, + const char *file_path) +{ + char *smack_label = NULL; + char *dst_path = NULL; + int size; + uid_t uid = getuid(); + + size = smack_new_label_from_path(file_path, XATTR_NAME_SMACK, + TRUE, &smack_label); + if (size <= 0) { + ERR("Failed to get smack info"); + return NULL; + } + + if (__is_RO_file(smack_label)) + dst_path = __get_data_path_by_pkg_id(pkg_id, + __last_index_of(file_path, "/") + 1, uid); + + if (dst_path == NULL && __is_private_file(smack_label, pkg_id)) { + dst_path = strdup(file_path); + if (dst_path == NULL) + ERR("Failed to strdup"); + } + + free(smack_label); + return dst_path; +} + +EXPORT_API bool notification_validate_private_sharing( + notification_h updated_noti) +{ + char *updated_path = NULL; + char *private_path; + char buf_key[32] = { 0, }; + int i = NOTIFICATION_IMAGE_TYPE_ICON; + + if (updated_noti->b_image_path && updated_noti->b_priv_image_path) { + for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) { + snprintf(buf_key, sizeof(buf_key), "%d", i); + + bundle_get_str(updated_noti->b_image_path, buf_key, + &updated_path); + if (updated_path == NULL) + continue; + + bundle_get_str(updated_noti->b_priv_image_path, + buf_key, &private_path); + if (private_path == NULL) + continue; + + if (strcmp(updated_path, private_path) == 0) + return false; + + updated_path = NULL; + } + } + + if (updated_noti->sound_path && updated_noti->priv_sound_path) { + if (strcmp(updated_noti->sound_path, + updated_noti->priv_sound_path) == 0) + return false; + } + + if (updated_noti->vibration_path && updated_noti->priv_vibration_path) { + if (strcmp(updated_noti->vibration_path, + updated_noti->priv_vibration_path) == 0) + return false; + } + + return true; +} + +EXPORT_API void notification_calibrate_private_sharing( + notification_h updated_noti, notification_h source_noti) +{ + char *updated_path = NULL; + char *source_path; + char *private_path; + char buf_key[32] = { 0, }; + int i = NOTIFICATION_IMAGE_TYPE_ICON; + + if (updated_noti->b_image_path && updated_noti->b_priv_image_path) { + for (; i <= NOTIFICATION_IMAGE_TYPE_MAX; i++) { + snprintf(buf_key, sizeof(buf_key), "%d", i); + bundle_get_str(updated_noti->b_image_path, buf_key, + &updated_path); + if (updated_path == NULL) + continue; + bundle_get_str(updated_noti->b_priv_image_path, + buf_key, &private_path); + if (private_path == NULL) + continue; + if (strcmp(updated_path, private_path) == 0) { + bundle_get_str(source_noti->b_image_path, + buf_key, &source_path); + bundle_del(updated_noti->b_image_path, buf_key); + bundle_add_str(updated_noti->b_image_path, + buf_key, source_path); + } + updated_path = NULL; + private_path = NULL; + } + } + + if (updated_noti->sound_path && updated_noti->priv_sound_path) { + if (strcmp(updated_noti->sound_path, + updated_noti->priv_sound_path) == 0) { + free(updated_noti->sound_path); + updated_noti->sound_path = strdup(source_noti->sound_path); + if (updated_noti->sound_path == NULL) + ERR("out of memory"); + } + } + + if (updated_noti->vibration_path && updated_noti->priv_vibration_path) { + if (strcmp(updated_noti->vibration_path, + updated_noti->priv_vibration_path) == 0) { + free(updated_noti->vibration_path); + updated_noti->vibration_path = + strdup(source_noti->priv_vibration_path); + if (updated_noti->vibration_path == NULL) + ERR("out of memory"); + } + } +} + + +int __set_sharing_for_new_target(sharing_req_data_s *req_data, + GList *target_app_list) +{ + char **path_array = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int len; + private_sharing_req *handle = NULL; + GList *iter, *tmp; + target_app_info_s *target_info; + char *app_info = NULL; + + iter = target_app_list; + for (; iter != NULL; iter = g_list_next(iter)) { + target_info = (target_app_info_s *)iter->data; + tmp = g_list_find_custom(req_data->target_app_table, + target_info->app_id, __comp_str); + if (tmp != NULL) + continue; + + app_info = strdup(target_info->app_id); + if (app_info == NULL) { + ERR("out of memory"); + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + if (handle == NULL) { + ret = security_manager_private_sharing_req_new(&handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR("Failed to create PS handle"); + goto out; + } + + ret = security_manager_private_sharing_req_set_owner_appid( + handle, req_data->app_id); + if (ret != SECURITY_MANAGER_SUCCESS) { + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR( + "Failed to set owner appid(%s) %d", + req_data->app_id, ret); + goto out; + } + path_array = __convert_list_to_array( + req_data->shared_file_list, &len); + if (path_array == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = security_manager_private_sharing_req_add_paths( + handle, (const char **)path_array, len); + if (ret != SECURITY_MANAGER_SUCCESS) { + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR("Failed to add paths %d", ret); + goto out; + } + } + + ret = security_manager_private_sharing_req_set_target_appid( + handle, target_info->app_id); + if (ret != SECURITY_MANAGER_SUCCESS) { + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR("Failed to set target appid(%s)", + (const char *)iter->data); + goto out; + } + + ret = security_manager_private_sharing_apply(handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR("Failed to apply PS %d", ret); + goto out; + } + + req_data->target_app_table = g_list_append( + req_data->target_app_table, + app_info); + } + +out: + if (ret != NOTIFICATION_ERROR_NONE && app_info) + free(app_info); + + if (handle != NULL) + security_manager_private_sharing_req_free(handle); + if (path_array != NULL) + free(path_array); + + return ret; +} + +int __set_sharing_for_new_file(sharing_req_data_s *req_data, + GList *new_file_list, bool is_overlapping) +{ + char **path_array = NULL; + int ret = NOTIFICATION_ERROR_NONE; + int len; + private_sharing_req *handle = NULL; + GList *iter; + + path_array = __convert_list_to_array(new_file_list, &len); + if (path_array == NULL) { + ret = NOTIFICATION_ERROR_OUT_OF_MEMORY; + goto out; + } + + ret = security_manager_private_sharing_req_new(&handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + ret = NOTIFICATION_ERROR_IO_ERROR; + ERR("Failed to create private sharing request handle[%d]", ret); + goto out; + } + + ret = security_manager_private_sharing_req_set_owner_appid(handle, + req_data->app_id); + if (ret != SECURITY_MANAGER_SUCCESS) { + /* LCOV_EXCL_START */ + ERR("Failed to set owner appid[%s][%d]", + req_data->app_id, ret); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = security_manager_private_sharing_req_add_paths(handle, + (const char **)path_array, len); + if (ret != SECURITY_MANAGER_SUCCESS) { + /* LCOV_EXCL_START */ + ERR("Failed to add paths [%d]", ret); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + if (is_overlapping == true) { + iter = req_data->target_app_table; + for (; iter != NULL; iter = g_list_next(iter)) { + ret = security_manager_private_sharing_req_set_target_appid( + handle, (const char *)iter->data); + if (ret != SECURITY_MANAGER_SUCCESS) { + /* LCOV_EXCL_START */ + ERR("Failed to set target appid [%s]", + (const char *)iter->data); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = security_manager_private_sharing_drop(handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + /* LCOV_EXCL_START */ + ERR("Failed to drop [%d]", ret); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + } + } + + iter = req_data->target_app_table; + for (; iter != NULL; iter = g_list_next(iter)) { + ret = security_manager_private_sharing_req_set_target_appid(handle, + (const char *)iter->data); + if (ret != SECURITY_MANAGER_SUCCESS) { + /* LCOV_EXCL_START */ + ERR("Failed to set target appid [%s]", + (const char *)iter->data); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + + ret = security_manager_private_sharing_apply(handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + /* LCOV_EXCL_START */ + ERR("Failed to apply PS [%d]", ret); + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + /* LCOV_EXCL_STOP */ + } + } + +out: + if (handle != NULL) + security_manager_private_sharing_req_free(handle); + if (path_array != NULL) + free(path_array); + + return ret; +} + +EXPORT_API int notification_set_private_sharing(notification_h noti, + uid_t uid) +{ + int ret = NOTIFICATION_ERROR_NONE; + bool is_overlapping = false; + sharing_req_data_s *req_data; + sharing_file_info_s *file_info, *dup_file_info; + uid_info_s *uid_info; + GList *req_list, *iter, *tmp; + GList *new_file_list = NULL; + + if (noti == NULL || noti->caller_app_id == NULL) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + tmp = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid), + __comp_uid_info_list); + if (tmp == NULL) { + uid_info = (uid_info_s *)calloc(1, sizeof(uid_info_s)); + __OOM_CHECK(uid_info, NOTIFICATION_ERROR_OUT_OF_MEMORY, DUMMY_PARAM); + + uid_info->uid = uid; + __uid_list = g_list_append(__uid_list, uid_info); + } else { + uid_info = tmp->data; + } + + req_list = g_list_find_custom(uid_info->sharing_req_list, + noti->caller_app_id, __comp_sharing_req_list); + if (req_list == NULL) { + req_data = (sharing_req_data_s *)calloc(1, sizeof(sharing_req_data_s)); + __OOM_CHECK(req_data, NOTIFICATION_ERROR_OUT_OF_MEMORY, DUMMY_PARAM); + + req_data->app_id = strdup(noti->caller_app_id); + __OOM_CHECK(req_data->app_id, NOTIFICATION_ERROR_OUT_OF_MEMORY, + __free_req_info(req_data)); + + req_data->dir = __get_shared_dir(noti); + if (req_data->dir == NULL) { + __free_req_info(req_data); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + uid_info->sharing_req_list = g_list_append( + uid_info->sharing_req_list, req_data); + } else { + req_data = (sharing_req_data_s *)req_list->data; + } + + __make_sharing_dir(req_data->dir); + + tmp = g_list_find_custom(req_data->priv_id_list, + GINT_TO_POINTER(noti->priv_id), __comp_priv_id); + if (tmp == NULL) + req_data->priv_id_list = g_list_append(req_data->priv_id_list, + GINT_TO_POINTER(noti->priv_id)); + + new_file_list = __get_new_file_list(noti, req_data->shared_file_list, + &is_overlapping); + if (new_file_list != NULL) { + if (__set_sharing_for_new_file(req_data, new_file_list, + is_overlapping) != NOTIFICATION_ERROR_NONE) { + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + } + } + + for (iter = new_file_list; iter != NULL; iter = g_list_next(iter)) { + tmp = NULL; + file_info = iter->data; + if (is_overlapping == true) + tmp = g_list_find_custom( + req_data->shared_file_list, file_info, + __comp_file_info); + + if (tmp == NULL) { + dup_file_info = __dup_file_info(file_info); + req_data->shared_file_list = g_list_append( + req_data->shared_file_list, dup_file_info); + } + } + + if (__set_sharing_for_new_target(req_data, uid_info->target_app_list) + != NOTIFICATION_ERROR_NONE) { + ret = NOTIFICATION_ERROR_IO_ERROR; + goto out; + } + INFO("PS success priv id[%d] shared file count[%d] target app count[%d]", + noti->priv_id, + g_list_length(req_data->shared_file_list), + g_list_length(req_data->target_app_table)); + +out: + if (new_file_list != NULL) + g_list_free_full(new_file_list, __free_file_info); + if (ret != NOTIFICATION_ERROR_NONE) + req_data->priv_id_list = g_list_remove(req_data->priv_id_list, + GINT_TO_POINTER(noti->priv_id)); + return ret; +} + +EXPORT_API void notification_remove_private_sharing( + const char *src_app_id, int priv_id, uid_t uid) +{ + char **path_array = NULL; + sharing_req_data_s *req_data; + private_sharing_req *handle = NULL; + uid_info_s *uid_info; + GList *req_list; + GList *iter; + GList *priv_id_info = NULL; + GList *tmp_list = NULL; + int len, ret; + + tmp_list = g_list_find_custom(__uid_list, GINT_TO_POINTER(uid), + __comp_uid_info_list); + if (tmp_list == NULL) + return; + + uid_info = tmp_list->data; + + req_list = g_list_find_custom(uid_info->sharing_req_list, src_app_id, + __comp_sharing_req_list); + if (req_list == NULL) + return; + + req_data = (sharing_req_data_s *)req_list->data; + + priv_id_info = g_list_find_custom(req_data->priv_id_list, + GINT_TO_POINTER(priv_id), __comp_priv_id); + if (priv_id_info == NULL) + return; + + len = g_list_length(req_data->priv_id_list); + if (len > 1) { + req_data->priv_id_list = g_list_remove(req_data->priv_id_list, + priv_id_info->data); + return; + } + + /* If there is no shared file, the private sharing is not dropped. */ + __make_sharing_dir(req_data->dir); + iter = req_data->shared_file_list; + for (; iter != NULL; iter = g_list_next(iter)) + notification_copy_private_file( + ((sharing_file_info_s *)(iter->data))->src_path, + ((sharing_file_info_s *)(iter->data))->dst_path); + + if (g_list_length(req_data->target_app_table) > 0) { + ret = security_manager_private_sharing_req_new(&handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + ERR("Failed to create PS request handle"); + goto out; + } + + ret = security_manager_private_sharing_req_set_owner_appid( + handle, src_app_id); + if (ret != SECURITY_MANAGER_SUCCESS) { + ERR("Failed to set owner appid(%s) %d", + req_data->app_id, ret); + goto out; + } + + path_array = __convert_list_to_array(req_data->shared_file_list, &len); + if (path_array == NULL) { + ERR("path_array is null %d", + g_list_length(req_data->shared_file_list)); + goto out; + } + + ret = security_manager_private_sharing_req_add_paths(handle, + (const char **)path_array, len); + if (ret != SECURITY_MANAGER_SUCCESS) { + ERR("Failed to add paths %d", ret); + goto out; + } + + iter = req_data->target_app_table; + for (; iter != NULL; iter = g_list_next(iter)) { + ret = security_manager_private_sharing_req_set_target_appid( + handle, (const char *)iter->data); + if (ret != SECURITY_MANAGER_SUCCESS) { + ERR("Failed to set target appid(%s)", + (const char *)iter->data); + goto out; + } + + ret = security_manager_private_sharing_drop(handle); + if (ret != SECURITY_MANAGER_SUCCESS) { + ERR("Failed to drop %d", ret); + goto out; + } + } + } + + iter = req_data->shared_file_list; + for (; iter != NULL; iter = g_list_next(iter)) { + if (g_remove(((sharing_file_info_s *)(iter->data))->dst_path) != 0) + ERR("Failed [%s] [%d]", + (const char *)iter->data, errno); + } + + g_rmdir(req_data->dir); + req_data->priv_id_list = g_list_remove(req_data->priv_id_list, + priv_id_info->data); + + uid_info->sharing_req_list = g_list_remove(uid_info->sharing_req_list, + req_data); + __free_req_info(req_data); + +out: + if (handle != NULL) + security_manager_private_sharing_req_free(handle); + + if (path_array) + free(path_array); +} + diff --git a/notification/src/notification_status.c b/notification/src/notification_status.c new file mode 100644 index 0000000..cb69bbc --- /dev/null +++ b/notification/src/notification_status.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <glib.h> +#include <gio/gio.h> + +#include <notification.h> +#include <notification_db.h> +#include <notification_list.h> +#include <notification_noti.h> +#include <notification_debug.h> +#include <notification_private.h> +#include <notification_status.h> +#include <notification_status_internal.h> + +#define PATH_NAME "/Org/Tizen/System/Notification/Status_message" +#define INTERFACE_NAME "org.tizen.system.notification.status_message" +#define MEMBER_NAME "status_message" + +struct _message_cb_data { + notification_status_message_cb callback; + void *data; + GDBusConnection *conn; + uint message_id; +}; + +static struct _message_cb_data md; + +static void __notification_status_message_dbus_callback(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + char *message = NULL; + + g_variant_get(parameters, "(&s)", &message); + if (strlen(message) <= 0) { + /* LCOV_EXCL_START */ + ERR("message is NULL"); + return; + /* LCOV_EXCL_STOP */ + } + + if (!md.callback) { + /* LCOV_EXCL_START */ + ERR("No callback"); + return; + /* LCOV_EXCL_STOP */ + } + + md.callback(message, md.data); +} + +EXPORT_API +int notification_status_monitor_message_cb_set(notification_status_message_cb callback, void *user_data) +{ + GError *error = NULL; + + if (!callback) + return NOTIFICATION_ERROR_INVALID_PARAMETER; + + if (md.conn == NULL) { + md.conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (md.conn == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to connect to the D-BUS Daemon[%s]", + error->message); + g_error_free(error); + return NOTIFICATION_ERROR_FROM_DBUS; + /* LCOV_EXCL_STOP */ + } + } + + if (!md.message_id) { + md.message_id = g_dbus_connection_signal_subscribe(md.conn, + NULL, + INTERFACE_NAME, + MEMBER_NAME, + PATH_NAME, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + __notification_status_message_dbus_callback, + NULL, + NULL); + if (md.message_id == 0) { + /* LCOV_EXCL_START */ + ERR("Failed to subscribe signal"); + g_object_unref(md.conn); + return NOTIFICATION_ERROR_FROM_DBUS; + /* LCOV_EXCL_STOP */ + } + } + + md.callback = callback; + md.data = user_data; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API +int notification_status_monitor_message_cb_unset(void) +{ + if (md.message_id) { + g_dbus_connection_signal_unsubscribe(md.conn, md.message_id); + md.message_id = 0; + } + + if (md.conn) { + g_object_unref(md.conn); + md.conn = NULL; + } + + md.callback = NULL; + md.data = NULL; + + return NOTIFICATION_ERROR_NONE; +} + +EXPORT_API +int notification_status_message_post(const char *message) +{ + GError *err = NULL; + GDBusConnection *conn; + GVariant *param; + int ret = NOTIFICATION_ERROR_NONE; + + if (!message) { + ERR("message is NULL"); + return NOTIFICATION_ERROR_INVALID_PARAMETER; + } + + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err); + if (conn == NULL) { + /* LCOV_EXCL_START */ + ERR("Failed to connect to the D-BUS Daemon[%s]", + err->message); + ret = NOTIFICATION_ERROR_FROM_DBUS; + goto end; + /* LCOV_EXCL_STOP */ + } + + param = g_variant_new("(s)", message); + + if (g_dbus_connection_emit_signal(conn, + NULL, + PATH_NAME, + INTERFACE_NAME, + MEMBER_NAME, + param, + &err) == FALSE) { + /* LCOV_EXCL_START */ + ERR("Failed to emit signal[%s]", + err->message); + ret = NOTIFICATION_ERROR_FROM_DBUS; + goto end; + /* LCOV_EXCL_STOP */ + } + + if (g_dbus_connection_flush_sync(conn, NULL, &err) == FALSE) { + /* LCOV_EXCL_START */ + ERR("Failed to flush connection sync[%s]", + err->message); + ret = NOTIFICATION_ERROR_FROM_DBUS; + goto end; + /* LCOV_EXCL_STOP */ + } + +end: + if (err) + g_error_free(err); /* LCOV_EXCL_LINE */ + + if (conn) + g_object_unref(conn); + + return ret; +} diff --git a/notification/src/notification_viewer.c b/notification/src/notification_viewer.c new file mode 100644 index 0000000..6200d6b --- /dev/null +++ b/notification/src/notification_viewer.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> + +#include <app_control_internal.h> +#include <iniparser.h> +#include <aul_svc.h> + +#include <notification.h> +#include <notification_debug.h> +#include <notification_viewer.h> + +/* LCOV_EXCL_START */ +EXPORT_API int notification_get_default_viewer(const char *path, char **default_viewer) +{ + char *viewer = NULL; + dictionary *dict = NULL; + + if (access(path, F_OK) != 0) { + ERR("can't access file_path(%s)", path); + return -1; + } + + dict = iniparser_load(path); + if (!dict) { + ERR("can't load file"); + return -1; + } + + viewer = iniparser_getstring(dict, "Notification:DefaultViewer", NULL); + if (viewer != NULL) + *default_viewer = strdup(viewer); + + iniparser_freedict(dict); + + return 0; +} +/* LCOV_EXCL_STOP */ + +/* LCOV_EXCL_START */ +EXPORT_API int notification_launch_default_viewer(const char *default_viewer, + int priv_id, notification_op_type_e status, uid_t uid) +{ + int ret; + char buf[32] = {0,}; + bundle *b = NULL; + + b = bundle_create(); + if (b == NULL) { + ERR("Failed to create bundle"); + return NOTIFICATION_ERROR_OUT_OF_MEMORY; + } + + ret = aul_svc_set_appid(b, default_viewer); + if (ret != AUL_SVC_RET_OK) { + ERR("Failed to set appid to bundle[%x]", ret); + goto out; + } + + snprintf(buf, sizeof(buf), "%d", priv_id); + + ret = aul_svc_add_data(b, "NOTIFICATION_PRIVATE_ID", buf); + if (ret != AUL_SVC_RET_OK) { + ERR("Failed to add extra_data[%x]", ret); + goto out; + } + + memset(buf, 0, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d", status); + + ret = aul_svc_add_data(b, "NOTIFICATION_OP_TYPE", buf); + if (ret != AUL_SVC_RET_OK) { + ERR("Failed to add extra_data[%x]", ret); + goto out; + } + + ret = aul_svc_run_service_async_for_uid(b, 0, NULL, NULL, uid); + if (ret < 0) { + ERR("Failed to request app launch[%d]", ret); + } else { + INFO("successed to request app launch[%d],[%d]", + ret, uid); + ret = APP_CONTROL_ERROR_NONE; + } + +out: + if (b) + bundle_free(b); + + if (ret == 0) + ret = NOTIFICATION_ERROR_NONE; + else + ret = NOTIFICATION_ERROR_IO_ERROR; + + return ret; +} +/* LCOV_EXCL_STOP */ |