[ACR-1827] Modify SYSTEM_SETTINGS_KEY_AUTOMATIC_TIME_UPDATE
[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 <glib.h>
22 #include <vconf.h>
23
24 #include "sst.h"
25 #include "sst_misc.h"
26 #include "sst_interface.h"
27
28 static GHashTable *sst_vconf_map_old = NULL;
29 static GHashTable *sst_vconf_map = NULL;
30 static GHashTable *sst_vconf_map_new = NULL;
31
32 static pthread_mutex_t sst_vconf_map_lock = PTHREAD_MUTEX_INITIALIZER;
33 static pthread_mutex_t sst_vconf_map_new_lock = PTHREAD_MUTEX_INITIALIZER;
34
35 struct sst_vconf_info_s {
36         system_settings_key_e key;
37         system_settings_changed_cb cb;
38         void *cb_data;
39 };
40
41 int sst_vconf_set_int(sst_interface *iface, int val)
42 {
43         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
44         RETV_IF(NULL == iface->vconf_key, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
45
46         if (VCONF_OK != vconf_set_int(iface->vconf_key, val)) {
47                 ERR("vconf_set_int(%s, %d) Fail", iface->vconf_key, val);
48                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
49         }
50
51         return SYSTEM_SETTINGS_ERROR_NONE;
52 }
53
54 int sst_vconf_set_bool(sst_interface *iface, bool val)
55 {
56         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
57         RETV_IF(NULL == iface->vconf_key, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
58
59         if (VCONF_OK != vconf_set_bool(iface->vconf_key, val)) {
60                 ERR("vconf_set_bool(%s, %d) Fail", iface->vconf_key, val);
61                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
62         }
63
64         return SYSTEM_SETTINGS_ERROR_NONE;
65 }
66
67 int sst_vconf_set_str(sst_interface *iface, const char *val)
68 {
69         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
70         RETV_IF(NULL == iface->vconf_key, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
71
72         if (VCONF_OK != vconf_set_str(iface->vconf_key, val)) {
73                 ERR("vconf_set_str(%s, %s) Fail", iface->vconf_key, val);
74                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
75         }
76
77         return SYSTEM_SETTINGS_ERROR_NONE;
78 }
79
80 int sst_vconf_get_int(sst_interface *iface, int *val)
81 {
82         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
83         RETV_IF(NULL == iface->vconf_key, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
84
85         int result = 0;
86         if (VCONF_OK != vconf_get_int(iface->vconf_key, &result)) {
87                 ERR("vconf_get_int(%s) Fail", iface->vconf_key);
88                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
89         }
90
91         *val = result;
92
93         return SYSTEM_SETTINGS_ERROR_NONE;
94 }
95
96 int sst_vconf_get_bool(sst_interface *iface, bool *val)
97 {
98         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
99         RETV_IF(NULL == iface->vconf_key, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
100
101         int result = 0;
102         if (VCONF_OK != vconf_get_bool(iface->vconf_key, &result)) {
103                 ERR("vconf_get_bool(%s) Fail", iface->vconf_key);
104                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
105         }
106
107         *val = result ? true : false;
108
109         return SYSTEM_SETTINGS_ERROR_NONE;
110 }
111
112 int sst_vconf_get_str(sst_interface *iface, char **val)
113 {
114         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
115         RETV_IF(NULL == iface->vconf_key, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
116
117         char *result = vconf_get_str(iface->vconf_key);
118         if (NULL == result) {
119                 ERR("vconf_get_str(%s) Fail(NULL)", iface->vconf_key);
120                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
121         }
122
123         *val = result;
124         return SYSTEM_SETTINGS_ERROR_NONE;
125 }
126
127 int sst_vconf_get_str_ally(const char *vconf_key, char **value)
128 {
129         char *str_value = vconf_get_str(vconf_key);
130         if (NULL == str_value) {
131                 ERR("vconf_get_str(%s) Fail(NULL)", vconf_key);
132                 return SYSTEM_SETTINGS_ERROR_IO_ERROR;
133         }
134
135         *value = str_value;
136         return SYSTEM_SETTINGS_ERROR_NONE;
137 }
138
139 //Because of a lot of parameters, it is an inline function
140 static inline int _subscribe(sst_interface *iface, system_settings_changed_cb cb, void *user_data, GHashTable **vconf_map, GList *list, vconf_callback_fn vconf_cb, system_settings_cb_id *id)
141 {
142         GHashTable *map = *vconf_map;
143         struct sst_vconf_info_s *info = malloc(sizeof(struct sst_vconf_info_s));
144         if (NULL == info) {
145                 ERR("malloc() Fail(%d)", errno);
146                 return SYSTEM_SETTINGS_ERROR_OUT_OF_MEMORY;
147         }
148         info->key = iface->key;
149         info->cb = cb;
150         info->cb_data = user_data;
151
152         GList *new_list = g_list_append(list, info);
153         g_hash_table_replace(map, (char*)iface->vconf_key, new_list);
154
155         if (NULL == list) {
156                 int ret = vconf_notify_key_changed(iface->vconf_key, vconf_cb, NULL);
157                 if (VCONF_OK != ret) {
158                         ERR("vconf_notify_key_changed(%s) Fail", iface->vconf_key);
159                         new_list = g_list_remove(new_list, info);
160                         if (NULL == new_list) {
161                                 g_hash_table_remove(map, iface->vconf_key);
162                                 if (0 == g_hash_table_size(map)) {
163                                         g_hash_table_unref(map);
164                                         *vconf_map = NULL;
165                                 }
166                         }
167                         free(info);
168                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
169                 }
170         }
171
172         if (id)
173                 *id = info;
174
175         return SYSTEM_SETTINGS_ERROR_NONE;
176 }
177
178 static int _unsubscribe(const char *vconf_key, GList *found, GHashTable **vconf_map, vconf_callback_fn cb)
179 {
180         GHashTable *map = *vconf_map;
181         GList *list = g_list_first(found);
182
183         if (1 == g_list_length(list)) {
184                 int ret = vconf_ignore_key_changed(vconf_key, cb);
185                 if (VCONF_OK != ret) {
186                         ERR("vconf_ignore_key_changed(%s) Fail", vconf_key);
187                         return SYSTEM_SETTINGS_ERROR_IO_ERROR;
188                 }
189         }
190
191         list = g_list_remove_link(list, found);
192         if (list) {
193                 g_hash_table_replace(map, (char*)vconf_key, list);
194         } else {
195                 g_hash_table_remove(map, vconf_key);
196                 if (0 == g_hash_table_size(map)) {
197                         g_hash_table_unref(map);
198                         *vconf_map = NULL;
199                 }
200         }
201
202         free(found->data);
203         g_list_free(found);
204
205         return SYSTEM_SETTINGS_ERROR_NONE;
206 }
207
208 static void _callback_fn_old(keynode_t *node, void *user_data)
209 {
210         RET_IF(NULL == sst_vconf_map_old);
211
212         GList *list = g_hash_table_lookup(sst_vconf_map_old, node->keyname);
213         GList *it;
214         for (it = list; it; it = it->next) {
215                 struct sst_vconf_info_s *info = it->data;
216                 if (info && info->cb)
217                         info->cb(info->key, info->cb_data);
218         }
219 }
220
221 static gint _compare_key(gconstpointer a, gconstpointer b)
222 {
223         const struct sst_vconf_info_s *info = a;
224
225         RETV_IF(NULL == a, 1);
226
227         if (info->key == GPOINTER_TO_INT(b))
228                 return 0;
229         else
230                 return 1;
231 }
232
233 int sst_vconf_set_cb(sst_interface *iface, system_settings_changed_cb cb, void *user_data)
234 {
235         GList *list = NULL;
236
237         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
238         RETV_IF(NULL == cb, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
239
240         if (sst_vconf_map_old) {
241                 list = g_hash_table_lookup(sst_vconf_map_old, iface->vconf_key);
242                 GList *found = g_list_find_custom(list, GINT_TO_POINTER(iface->key), _compare_key);
243                 if (found) {
244                         ERR("callback Already Exist");
245                         return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
246                 }
247         } else {
248                 sst_vconf_map_old = g_hash_table_new(g_str_hash, g_str_equal);
249         }
250
251         return _subscribe(iface, cb, user_data, &sst_vconf_map_old, list, _callback_fn_old, NULL);
252 }
253
254 int sst_vconf_unset_cb(sst_interface *iface)
255 {
256         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
257         RETV_IF(NULL == sst_vconf_map_old, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
258
259         GList *list = g_hash_table_lookup(sst_vconf_map_old, iface->vconf_key);
260         GList *found = g_list_find_custom(list, GINT_TO_POINTER(iface->key), _compare_key);
261         if (NULL == found) {
262                 ERR("No callback");
263                 return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
264         }
265
266         return _unsubscribe(iface->vconf_key, found, &sst_vconf_map_old, _callback_fn_old);
267 }
268
269 static void _callback_fn(keynode_t *node, void *user_data)
270 {
271         RET_IF(NULL == sst_vconf_map);
272
273         GList *list = g_hash_table_lookup(sst_vconf_map, node->keyname);
274         GList *it;
275         for (it = list; it; it = it->next) {
276                 struct sst_vconf_info_s *info = it->data;
277                 if (info && info->cb)
278                         info->cb(info->key, info->cb_data);
279         }
280 }
281
282 static gint _compare_cb(gconstpointer a, gconstpointer b)
283 {
284         const struct sst_vconf_info_s *info = a;
285
286         RETV_IF(NULL == a, 1);
287         RETV_IF(NULL == b, 1);
288
289         if (info->cb == b)
290                 return 0;
291         else
292                 return 1;
293 }
294
295 int sst_vconf_add_multi_cb(sst_interface *iface, system_settings_changed_cb cb, void *user_data)
296 {
297         GList *list = NULL;
298         int ret;
299
300         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
301         RETV_IF(NULL == cb, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
302
303         pthread_mutex_lock(&sst_vconf_map_lock);
304         if (sst_vconf_map) {
305                 list = g_hash_table_lookup(sst_vconf_map, iface->vconf_key);
306                 GList *found = g_list_find_custom(list, cb, _compare_cb);
307                 if (found) {
308                         ERR("callback Already Exist");
309                         pthread_mutex_unlock(&sst_vconf_map_lock);
310                         return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
311                 }
312         } else {
313                 sst_vconf_map = g_hash_table_new(g_str_hash, g_str_equal);
314         }
315
316         ret = _subscribe(iface, cb, user_data, &sst_vconf_map, list, _callback_fn, NULL);
317         pthread_mutex_unlock(&sst_vconf_map_lock);
318         return ret;
319 }
320
321 int sst_vconf_del_multi_cb(sst_interface *iface, system_settings_changed_cb cb)
322 {
323         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
324         RETV_IF(NULL == cb, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
325         RETV_IF(NULL == sst_vconf_map, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
326
327         pthread_mutex_lock(&sst_vconf_map_lock);
328         GList *list = g_hash_table_lookup(sst_vconf_map, iface->vconf_key);
329         GList *found = g_list_find_custom(list, cb, _compare_cb);
330         int ret;
331         if (NULL == found) {
332                 ERR("No callback");
333                 pthread_mutex_unlock(&sst_vconf_map_lock);
334                 return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
335         }
336
337         ret = _unsubscribe(iface->vconf_key, found, &sst_vconf_map, _callback_fn);
338         pthread_mutex_unlock(&sst_vconf_map_lock);
339         return ret;
340 }
341
342 static void _callback_fn_new(keynode_t *node, void *user_data)
343 {
344         RET_IF(NULL == sst_vconf_map_new);
345
346         GList *list = g_hash_table_lookup(sst_vconf_map_new, node->keyname);
347         GList *it;
348         for (it = list; it; it = it->next) {
349                 struct sst_vconf_info_s *info = it->data;
350                 if (info && info->cb)
351                         info->cb(info->key, info->cb_data);
352         }
353 }
354
355 int sst_vconf_subscribe(sst_interface *iface, system_settings_changed_cb cb, void *user_data, system_settings_cb_id *id)
356 {
357         GList *list = NULL;
358         int ret;
359
360         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
361         RETV_IF(NULL == cb, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
362
363         pthread_mutex_lock(&sst_vconf_map_new_lock);
364         if (sst_vconf_map_new) {
365                 list = g_hash_table_lookup(sst_vconf_map_new, iface->vconf_key);
366         } else {
367                 sst_vconf_map_new = g_hash_table_new(g_str_hash, g_str_equal);
368         }
369
370         ret = _subscribe(iface, cb, user_data, &sst_vconf_map_new, list, _callback_fn_new, id);
371         pthread_mutex_unlock(&sst_vconf_map_new_lock);
372         return ret;
373 }
374
375 int sst_vconf_unsubscribe(sst_interface *iface, system_settings_cb_id id)
376 {
377         RETV_IF(NULL == iface, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
378         RETV_IF(NULL == id, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
379         RETV_IF(NULL == sst_vconf_map_new, SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER);
380
381         pthread_mutex_lock(&sst_vconf_map_new_lock);
382         GList *list = g_hash_table_lookup(sst_vconf_map_new, iface->vconf_key);
383         GList *found = g_list_find(list, id);
384         int ret;
385         if (NULL == found) {
386                 ERR("No callback");
387                 pthread_mutex_unlock(&sst_vconf_map_new_lock);
388                 return SYSTEM_SETTINGS_ERROR_INVALID_PARAMETER;
389         }
390
391         ret = _unsubscribe(iface->vconf_key, found, &sst_vconf_map_new, _callback_fn_new);
392         pthread_mutex_unlock(&sst_vconf_map_new_lock);
393         return ret;
394 }