9597d2020f4f80a2f05a91ada4288250f7c63a65
[platform/core/api/system-settings.git] / src / sst_vconf.c
1 /*
2  * Copyright (c) 2011-2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "sst_vconf.h"
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <vconf.h>
22
23 #include "sst.h"
24 #include "sst_misc.h"
25 #include "sst_interface.h"
26
27 static GHashTable *sst_vconf_map_org = NULL;
28 static GHashTable *sst_vconf_map = NULL;
29
30 struct sst_vconf_info_s {
31         system_settings_key_e key;
32         system_settings_changed_cb cb;
33         void *cb_data;
34 };
35
36 int sst_vconf_set(sst_interface *iface, void *value)
37 {
38         char *vconf_char;
39         int vconf_int;
40         bool vconf_bool;
41
42         switch (iface->data_type) {
43         case SYSTEM_SETTING_DATA_TYPE_STRING:
44                 vconf_char = (char*)value;
45                 if (vconf_set_str(iface->vconf_key, vconf_char))
46                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
47                 break;
48         case SYSTEM_SETTING_DATA_TYPE_INT:
49                 //todo: change double pointer to valide data type
50                 vconf_int = **(int**)value;
51                 if (vconf_set_int(iface->vconf_key, vconf_int))
52                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
53                 break;
54         case SYSTEM_SETTING_DATA_TYPE_BOOL:
55                 vconf_bool = *(bool*)value;
56                 if (vconf_set_bool(iface->vconf_key, vconf_bool))
57                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
58                 break;
59         default:
60                 ERR("Unknown type(%d)", iface->data_type);
61                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
62         }
63
64         return SYSTEM_SETTINGS_ERROR_NONE;
65 }
66
67 int sst_vconf_get(sst_interface *iface, void **value)
68 {
69         char *vconf_char;
70         int vconf_int;
71         int **val = (int**)value;
72         bool vconf_bool;
73
74         switch (iface->data_type) {
75         case SYSTEM_SETTING_DATA_TYPE_STRING:
76                 if (sst_vconf_get_string(iface->vconf_key, &vconf_char))
77                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
78                 *value = vconf_char;
79                 break;
80         case SYSTEM_SETTING_DATA_TYPE_INT:
81                 if (vconf_get_int(iface->vconf_key, &vconf_int))
82                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
83                 **val = vconf_int;
84                 break;
85         case SYSTEM_SETTING_DATA_TYPE_BOOL:
86                 if (sst_vconf_get_real_bool(iface->vconf_key, &vconf_bool))
87                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
88                 *value = (void*)vconf_bool;
89                 break;
90         default:
91                 ERR("Unknown type(%d)", iface->data_type);
92                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
93         }
94
95         return SYSTEM_SETTINGS_ERROR_NONE;
96 }
97
98 int sst_vconf_get_real_bool(const char *vconf_key, bool *value)
99 {
100         int temp = 0;
101         int ret = vconf_get_bool(vconf_key, &temp);
102         if (VCONF_OK != ret) {
103                 ERR("vconf_get_bool(%s) Fail(%d)", vconf_key, ret);
104                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
105         }
106
107         *value = temp ? true : false;
108
109         return SYSTEM_SETTINGS_ERROR_NONE;
110 }
111
112 int sst_vconf_get_string(const char *vconf_key, char **value)
113 {
114         char *str_value = vconf_get_str(vconf_key);
115         if (NULL == str_value) {
116                 ERR("vconf_get_str(%s) Fail(NULL)", vconf_key);
117                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
118         }
119
120         *value = str_value;
121         return SYSTEM_SETTINGS_ERROR_NONE;
122 }
123
124 static inline GHashTable* _map_erase(GHashTable *hash_table, const char *key)
125 {
126         g_hash_table_remove(hash_table, key);
127         if (0 == g_hash_table_size(hash_table)) {
128                 g_hash_table_unref(hash_table);
129                 return NULL;
130         }
131         return hash_table;
132 }
133
134 static void _callback_fn_org(keynode_t *node, void *user_data)
135 {
136         RET_IF(NULL == sst_vconf_map_org);
137
138         GList *list = g_hash_table_lookup(sst_vconf_map_org, node->keyname);
139         GList *it;
140         for (it = list; it; it = it->next) {
141                 struct sst_vconf_info_s *info = it->data;
142                 if (info && info->cb)
143                         info->cb(info->key, info->cb_data);
144         }
145 }
146
147 static gint _compare_key(gconstpointer a, gconstpointer b)
148 {
149         const struct sst_vconf_info_s *info = a;
150
151         RETV_IF(NULL == a, 1);
152
153         if (info->key == GPOINTER_TO_INT(b))
154                 return 0;
155         else
156                 return 1;
157 }
158
159 int sst_vconf_set_cb(sst_interface *iface, system_settings_changed_cb cb, void *user_data)
160 {
161         GList *list = NULL;
162
163         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
164         RETV_IF(NULL == cb, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
165
166         if (sst_vconf_map_org) {
167                 list = g_hash_table_lookup(sst_vconf_map_org, iface->vconf_key);
168                 GList *found = g_list_find_custom(list, GINT_TO_POINTER(iface->key), _compare_key);
169                 if (found) {
170                         ERR("callback Already Exist");
171                         return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
172                 }
173         } else {
174                 sst_vconf_map_org = g_hash_table_new(g_str_hash, g_str_equal);
175         }
176
177         struct sst_vconf_info_s *info = malloc(sizeof(struct sst_vconf_info_s));
178         if (NULL == info) {
179                 ERR("malloc() Fail(%d)", errno);
180                 return SYSTEM_SETTINGS_ERROR_OUT_OF_MEMORY;
181         }
182         info->key = iface->key;
183         info->cb = cb;
184         info->cb_data = user_data;
185
186         GList *new_list = g_list_append(list, info);
187         g_hash_table_replace(sst_vconf_map_org, (char*)iface->vconf_key, new_list);
188
189         if (NULL == list) {
190                 int ret = vconf_notify_key_changed(iface->vconf_key, _callback_fn_org, NULL);
191                 if (VCONF_OK != ret) {
192                         ERR("vconf_notify_key_changed(%s) Fail", iface->vconf_key);
193                         new_list = g_list_remove(new_list, info);
194                         if (NULL == new_list)
195                                 sst_vconf_map_org = _map_erase(sst_vconf_map_org, iface->vconf_key);
196                         free(info);
197                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
198                 }
199         }
200
201         return SYSTEM_SETTINGS_ERROR_NONE;
202 }
203
204 int sst_vconf_unset_cb(sst_interface *iface)
205 {
206         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
207         RETV_IF(NULL == sst_vconf_map_org, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
208
209         GList *list = g_hash_table_lookup(sst_vconf_map_org, iface->vconf_key);
210         GList *found = g_list_find_custom(list, GINT_TO_POINTER(iface->key), _compare_key);
211         if (NULL == found) {
212                 ERR("No callback");
213                 return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
214         }
215
216         if (1 == g_list_length(list)) {
217                 int ret = vconf_ignore_key_changed(iface->vconf_key, _callback_fn_org);
218                 if (VCONF_OK != ret) {
219                         ERR("vconf_ignore_key_changed(%s) Fail", iface->vconf_key);
220                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
221                 }
222         }
223
224         list = g_list_remove_link(list, found);
225         if (list)
226                 g_hash_table_replace(sst_vconf_map_org, (char*)iface->vconf_key, list);
227         else
228                 sst_vconf_map_org = _map_erase(sst_vconf_map_org, iface->vconf_key);
229
230         free(found->data);
231         g_list_free(found);
232
233         return SYSTEM_SETTINGS_ERROR_NONE;
234 }
235
236 static void _callback_fn(keynode_t *node, void *user_data)
237 {
238         RET_IF(NULL == sst_vconf_map);
239
240         GList *list = g_hash_table_lookup(sst_vconf_map, node->keyname);
241         GList *it;
242         for (it = list; it; it = it->next) {
243                 struct sst_vconf_info_s *info = it->data;
244                 if (info && info->cb)
245                         info->cb(info->key, info->cb_data);
246         }
247 }
248
249 static gint _compare_cb(gconstpointer a, gconstpointer b)
250 {
251         const struct sst_vconf_info_s *info = a;
252
253         RETV_IF(NULL == a, 1);
254         RETV_IF(NULL == b, 1);
255
256         if (info->cb == b)
257                 return 0;
258         else
259                 return 1;
260 }
261
262 int sst_vconf_add_multi_cb(sst_interface *iface, system_settings_changed_cb cb, void *user_data)
263 {
264         GList *list = NULL;
265
266         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
267         RETV_IF(NULL == cb, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
268
269         if (sst_vconf_map) {
270                 list = g_hash_table_lookup(sst_vconf_map, iface->vconf_key);
271                 GList *found = g_list_find_custom(list, cb, _compare_cb);
272                 if (found) {
273                         ERR("callback Already Exist");
274                         return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
275                 }
276         } else {
277                 sst_vconf_map = g_hash_table_new(g_str_hash, g_str_equal);
278         }
279
280         struct sst_vconf_info_s *info = malloc(sizeof(struct sst_vconf_info_s));
281         if (NULL == info) {
282                 ERR("malloc() Fail(%d)", errno);
283                 return SYSTEM_SETTINGS_ERROR_OUT_OF_MEMORY;
284         }
285         info->key = iface->key;
286         info->cb = cb;
287         info->cb_data = user_data;
288
289         GList *new_list = g_list_append(list, info);
290         g_hash_table_replace(sst_vconf_map, (char*)iface->vconf_key, new_list);
291
292         if (NULL == list) {
293                 int ret = vconf_notify_key_changed(iface->vconf_key, _callback_fn, NULL);
294                 if (VCONF_OK != ret) {
295                         ERR("vconf_notify_key_changed(%s) Fail", iface->vconf_key);
296                         new_list = g_list_remove(new_list, info);
297                         if (NULL == new_list)
298                                 sst_vconf_map = _map_erase(sst_vconf_map, iface->vconf_key);
299                         free(info);
300                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
301                 }
302         }
303
304         return SYSTEM_SETTINGS_ERROR_NONE;
305 }
306
307 int sst_vconf_del_multi_cb(sst_interface *iface, system_settings_changed_cb cb)
308 {
309         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
310         RETV_IF(NULL == cb, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
311         RETV_IF(NULL == sst_vconf_map, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
312
313         GList *list = g_hash_table_lookup(sst_vconf_map, iface->vconf_key);
314         GList *found = g_list_find_custom(list, cb, _compare_cb);
315         if (NULL == found) {
316                 ERR("No callback");
317                 return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
318         }
319
320         if (1 == g_list_length(list)) {
321                 int ret = vconf_ignore_key_changed(iface->vconf_key, _callback_fn);
322                 if (VCONF_OK != ret) {
323                         ERR("vconf_ignore_key_changed(%s) Fail", iface->vconf_key);
324                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
325                 }
326         }
327
328         list = g_list_remove_link(list, found);
329         if (list)
330                 g_hash_table_replace(sst_vconf_map, (char*)iface->vconf_key, list);
331         else
332                 sst_vconf_map = _map_erase(sst_vconf_map, iface->vconf_key);
333
334         free(found->data);
335         g_list_free(found);
336
337         return SYSTEM_SETTINGS_ERROR_NONE;
338 }