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