Adding missing header files
[platform/core/appfw/vconf-buxton.git] / src / vconf-buxton.c
1 /*
2  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
3  * Copyright (C) 2014 Intel Corporation
4  *
5  * Author: José Bollo <jose.bollo@open.eurogiciel.org>
6  * Author: Hakjoo Ko <hakjoo.ko@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 /*
23  * Note on conditionnal compilation: The following defines are controlling the compilation.
24  *
25  * NO_MULTITHREADING
26  *     Defining NO_MULTITHREADING removes multithreading support.
27  *     Defining it is not a good idea.
28  *
29  * NO_GLIB
30  *     Defining NO_GLIB removes support of GLIB main loop used for notification
31  *     Defining it implies to dig code to find some replacement (new API verbs to create).
32  *
33  * REMOVE_PREFIXES
34  *     Removes the prefixe of the keys depending (depends on the layer).
35  *     Defining it is not a good idea.
36  *
37  * The best is to not define any of the conditional value and let use the default.
38  */
39
40 #define _GNU_SOURCE
41
42 #include <stdlib.h>
43 #include <limits.h>
44 #include <string.h>
45 #include <assert.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <poll.h>
49 #include <buxton.h>
50 #if !defined(NO_GLIB)
51 #include <glib.h>
52 #endif
53 #if !defined(NO_MULTITHREADING)
54 #include <pthread.h>
55 #endif
56
57 #include "vconf-buxton.h"
58 #include "log.h"
59
60 #define VCONF_OK      0
61 #define VCONF_ERROR  -1
62
63 /*================= SECTION definition of types =============*/
64
65 /*
66  * internal types for keys 
67  */
68 enum keytype
69 {
70   type_unset,                   /* type unset or unknown */
71   type_directory,               /* a directory, not a real key */
72   type_delete,                  /* key to be deleted */
73   type_string,                  /* key of type string */
74   type_int,                     /* key of type integer */
75   type_double,                  /* key of type double */
76   type_bool                     /* key of type boolean */
77 };
78
79 /*
80  * union for storing values 
81  */
82 union keyvalue
83 {
84   int i;                        /* storage of integers */
85   int b;                        /* storage of booleans */
86   double d;                     /* storage of doubles */
87   char *s;                      /* storage of strings */
88 };
89
90 /*
91  * structure for keys 
92  */
93 struct _keynode_t
94 {
95   enum keytype type;            /* type of the key */
96   union keyvalue value;         /* value of the key */
97   keynode_t *next;              /* linking to the next key */
98   keylist_t *list;              /* the containing list */
99   const char *keyname;          /* name of the key */
100 };
101
102 /*
103  * structure for list of keys 
104  */
105 struct _keylist_t
106 {
107   int num;                      /* count of keys in the list */
108   keynode_t *head;              /* first key of the list */
109   keynode_t *cursor;            /* iterator on keys for clients */
110   int cb_active;                /* callback global activity */
111   int cb_status;                /* callback global status */
112   unsigned cb_sent;             /* callback global count of sent queries */
113   unsigned cb_received;         /* callback global count of
114                                  * received responses */
115 };
116
117 /*
118  * data for the callback of scanning 
119  */
120 struct scanning_data
121 {
122   int pending;                  /* is the scan pending? */
123   int cb_status;                /* status of the call back */
124   int want_directories;         /* is scanning directories? */
125   int want_keys;                /* is scanning keys? */
126   int is_recursive;             /* is scanning recursively? */
127   size_t dirlen;                /* length of the directory */
128   keylist_t *keylist;           /* keylist to fill */
129   const char *prefix;           /* prefix to add in front of names */
130   const char *directory;        /* scanned directory */
131 };
132
133 /*
134  * data when translating vconf names to buxton names. ** the rule is that
135  * name == prefix/key 
136  */
137 struct layer_key
138 {
139   const char *layer;            /* identified layer-name */
140   const char *prefix;           /* vconf prefix of the name (without
141                                  * trailing /) */
142   const char *key;              /* buxton key-name (without leading /) */
143 };
144
145 /*
146  * singleton data for facilities 
147  */
148 struct singleton
149 {
150   keylist_t list;               /* the list */
151   keynode_t node;               /* its single node */
152 };
153
154 /*
155  * structure for notifications 
156  */
157 struct notify
158 {
159   int status;                   /* callback status */
160   vconf_callback_fn callback;   /* the user callback */
161   void *userdata;               /* the user data */
162   keynode_t *keynode;           /* the recorded key node */
163   struct notify *next;          /* tink to the next notification */
164 };
165
166 /*================= SECTION local variables =============*/
167
168 /*
169  * maximum length of key-names 
170  */
171 static size_t keyname_maximum_length = 2030;
172
173 /*
174  * maximum length of group-names 
175  */
176 static size_t keygroup_maximum_length = 1010;
177
178 /*
179  * association from prefixes to layers 
180  */
181 static const char *assoc_prefix_layer[][2] = {
182   {"db", "base"},
183   {"file", "base"},
184   {"memory", "temp"},
185   {"memory_init", "base"},
186   {"user", "user"},
187   {NULL, NULL}
188 };
189
190 /*
191  * default timeout in scanning responses 
192  */
193 static int default_timeout = 5000;      /* in milliseconds */
194
195 /*
196  * instance of the buxton client 
197  */
198 static BuxtonClient the_buxton_client = 0;
199
200 /*
201  * the file handle number for polling buxton events 
202  */
203 static int the_buxton_client_fd = 0;
204
205 /*
206  * flag indacating if the buxton client is set or not 
207  */
208 static char the_buxton_client_is_set = 0;
209
210 /*
211  * the group to use if default group is unset 
212  */
213 static const char initial_default_group[] = "vconf";
214
215 /*
216  * the default group to use 
217  */
218 static char *default_group = NULL;
219
220 /*
221  * the notify keylist 
222  */
223 static keylist_t *notify_keylist = NULL;
224
225 /*
226  * the notify entries 
227  */
228 static struct notify *notify_entries = NULL;
229
230 /*
231  * the count of lists
232  */
233 static int internal_list_count = 0;
234
235 #if !defined(NO_GLIB)
236 /*
237  * link to the glib main loop 
238  */
239 static GSource *glib_source = NULL;
240 #endif
241
242 #if !defined(NO_MULTITHREADING)
243 /*
244  * multithreaded protection
245  * CAUTION: always use the given order!
246  */
247 static pthread_mutex_t mutex_notify = PTHREAD_MUTEX_INITIALIZER;
248 static pthread_mutex_t mutex_counter = PTHREAD_MUTEX_INITIALIZER;
249 static pthread_mutex_t mutex_buxton = PTHREAD_MUTEX_INITIALIZER;
250 static pthread_mutex_t mutex_group = PTHREAD_MUTEX_INITIALIZER;
251 #define LOCK(x) pthread_mutex_lock(&mutex_##x)
252 #define UNLOCK(x) pthread_mutex_unlock(&mutex_##x)
253 #else
254 #define LOCK(x)
255 #define UNLOCK(x)
256 #endif
257
258 /*================= SECTION utils =============*/
259
260 /*
261  * duplication of a string with validation of the length 
262  */
263 static inline char *
264 _dup_ (const char *source, size_t maxlen, const char *tag)
265 {
266   size_t length;
267   char *result;
268
269   assert (source != NULL);
270   length = strlen (source);
271   if (length >= maxlen)
272     {
273       ERR ("Invalid argument: %s is too long", tag);
274       return NULL;
275     }
276   result = malloc (++length);
277   if (result == NULL)
278     {
279       ERR ("Can't allocate memory for %s", tag);
280       return NULL;
281     }
282   memcpy (result, source, length);
283   return result;
284 }
285
286 /*================= SECTION groupname utils =============*/
287
288 static inline char *
289 _dup_groupname_ (const char *groupname)
290 {
291   return _dup_ (groupname, keygroup_maximum_length, "group-name");
292 }
293
294 static inline int
295 _ensure_default_group_ ()
296 {
297   int result = VCONF_OK;
298
299   LOCK (group);
300   if (default_group == NULL)
301     {
302       default_group = _dup_groupname_ (initial_default_group);
303       if (default_group == NULL)
304         result = VCONF_ERROR;
305     }
306   UNLOCK (group);
307
308   return result;
309 }
310
311 /*================= SECTION key utils =============*/
312
313 static inline void
314 _keynode_free_ (keynode_t * keynode)
315 {
316   assert (keynode != NULL);
317   if (keynode->type == type_string)
318     free (keynode->value.s);
319   free (keynode);
320 }
321
322 static inline size_t
323 _check_keyname_ (const char *keyname)
324 {
325   size_t result;
326
327   assert (keyname != NULL);
328
329   if (*keyname == '/')
330     {
331       return 0;
332     }
333
334   for (result = 0; keyname[result]; result++)
335     {
336       if (keyname[result] == '/' && keyname[result + 1] == '/')
337         {
338           return 0;
339         }
340     }
341
342   return result;
343 }
344
345 /*================= SECTION list utils =============*/
346
347 /*
348  * search in 'keylist' an entry of 'keyname' and return it if found or
349  * NULL if not found. 'previous' if not NULL and if the entry is found
350  * will recieve the address of the pointer referencing the returned node. 
351  */
352 static inline keynode_t *
353 _keylist_lookup_ (keylist_t * keylist,
354                   const char *keyname, keynode_t *** previous)
355 {
356   keynode_t *node, **prev;
357   size_t length = 1 + strlen (keyname);
358
359   prev = &keylist->head;
360   node = keylist->head;
361   while (node)
362     {
363       assert (node->keyname != NULL);
364       if (!memcmp (keyname, node->keyname, length))
365         {
366           if (previous)
367             *previous = prev;
368           return node;
369         }
370
371       prev = &node->next;
372       node = node->next;
373     }
374   return NULL;
375 }
376
377 static inline keynode_t *
378 _keylist_add_ (keylist_t * keylist, const char *keyname, enum keytype type)
379 {
380   keynode_t *result;
381   char *name;
382   size_t length;
383
384   /*
385    * not found, create it 
386    */
387   length = _check_keyname_ (keyname);
388   retvm_if (!length, NULL, "invalid keyname");
389   retvm_if (length > keyname_maximum_length, NULL, "keyname too long");
390   result = malloc (1 + length + sizeof *result);
391   retvm_if (result == NULL, NULL, "allocation of keynode failed");
392   result->type = type;
393   result->value.s = NULL;
394
395   result->list = keylist;
396   name = (char *) (result + 1);
397   result->keyname = name;
398   memcpy (name, keyname, length + 1);
399
400   result->next = keylist->head;
401   keylist->head = result;
402   keylist->num++;
403
404   return result;
405 }
406
407 static inline keynode_t *
408 _keylist_getadd_ (keylist_t * keylist, const char *keyname, enum keytype type)
409 {
410   keynode_t *result;
411
412   /*
413    * search keynode of keyname 
414    */
415   result = _keylist_lookup_ (keylist, keyname, NULL);
416   if (result == NULL)
417     {
418       /*
419        * not found, create it 
420        */
421       result = _keylist_add_ (keylist, keyname, type);
422     }
423   else if (result->type != type)
424     {
425       if (result->type == type_string)
426         free (result->value.s);
427       result->type = type;
428       result->value.s = NULL;
429     }
430   return result;
431 }
432
433 static inline int
434 _keylist_init_singleton_ (struct singleton *singleton, const char *keyname,
435                           enum keytype type)
436 {
437   int status;
438
439   if (!_check_keyname_ (keyname))
440     {
441       ERR ("Invalid key name(%s)", keyname);
442       return VCONF_ERROR;
443     }
444   status = _ensure_default_group_ ();
445   if (status != VCONF_OK)
446     return status;
447
448   memset (singleton, 0, sizeof *singleton);
449   singleton->list.num = 1;
450   singleton->list.head = &singleton->node;
451   singleton->node.keyname = keyname;
452   singleton->node.type = type;
453   singleton->node.list = &singleton->list;
454
455   return VCONF_OK;
456 }
457
458
459 /*================= SECTION buxton =============*/
460
461 static void
462 _check_close_buxton_ ()
463 {
464   BuxtonClient bc;
465
466   LOCK (notify);
467   LOCK (counter);
468   if (internal_list_count == 0 && notify_entries == NULL)
469     if (internal_list_count == 0 && notify_entries == NULL)
470       {
471         LOCK (buxton);
472         bc = the_buxton_client;
473         the_buxton_client_is_set = 0;
474         the_buxton_client = NULL;
475         the_buxton_client_fd = -1;
476         UNLOCK (buxton);
477         if (bc)
478           buxton_close (bc);
479       }
480   UNLOCK (counter);
481   UNLOCK (notify);
482 }
483
484 static void
485 _try_to_open_buxton_ ()
486 {
487   the_buxton_client_fd = buxton_open (&the_buxton_client);
488   if (the_buxton_client_fd < 0)
489     {
490       ERR ("can't connect to buxton server: %m");
491       errno = ENOTCONN;
492       the_buxton_client = NULL;
493     }
494 }
495
496 static inline int
497 _open_buxton_ ()
498 {
499   LOCK (buxton);
500   if (!the_buxton_client_is_set)
501     {
502       /*
503        * first time, try to connect to buxton 
504        */
505       the_buxton_client_is_set = 1;
506       _try_to_open_buxton_ ();
507     }
508   UNLOCK (buxton);
509   return the_buxton_client != NULL;
510 }
511
512
513 static inline BuxtonClient
514 _buxton_ ()
515 {
516   BuxtonClient result = the_buxton_client;
517   assert (result != NULL);
518   return result;
519 }
520
521 static inline int
522 _handle_buxton_response_ (int lock)
523 {
524   int result;
525
526   if (lock)
527     LOCK (buxton);
528   result = buxton_client_handle_response (_buxton_ ());
529   if (result < 0)
530     ERR ("Error in buxton_client_handle_response: %m");
531   if (lock)
532     UNLOCK (buxton);
533   return result;
534 }
535
536 static inline int
537 _dispatch_buxton_ (int writing, int lock)
538 {
539   int status;
540   struct pollfd pfd;
541
542   assert (_buxton_ () != NULL);
543
544   pfd.fd = the_buxton_client_fd;
545   pfd.events = writing ? POLLIN | POLLOUT : POLLIN;
546   for (;;)
547     {
548       pfd.revents = 0;
549       status = poll (&pfd, 1, default_timeout);
550       if (status == -1)
551         {
552           if (errno != EINTR)
553             {
554               return VCONF_ERROR;
555             }
556         }
557       else if (status == 1)
558         {
559           if (pfd.revents & POLLIN)
560             {
561               status = _handle_buxton_response_ (lock);
562               if (status < 0)
563                 {
564                   return VCONF_ERROR;
565                 }
566               if (!writing)
567                 {
568                   return VCONF_OK;
569                 }
570             }
571           if (pfd.revents & POLLOUT)
572             {
573               return VCONF_OK;
574             }
575           else
576             {
577               return VCONF_ERROR;
578             }
579         }
580     }
581 }
582
583 static inline int
584 _wait_buxton_response_ (int *pending)
585 {
586   int result;
587
588   do
589     {
590       result = _dispatch_buxton_ (0, 1);
591     }
592   while (result == VCONF_OK && *pending);
593   return result;
594 }
595
596 static inline int
597 _get_layer_key_ (const char *keyname, struct layer_key *laykey)
598 {
599   int i, j;
600   const char *prefix;
601
602   /*
603    * get the names 
604    */
605   i = 0;
606   prefix = assoc_prefix_layer[i][0];
607   while (prefix != NULL)
608     {
609       for (j = 0; prefix[j] && prefix[j] == keyname[j]; j++);
610       if (!prefix[j] && (!keyname[j] || keyname[j] == '/'))
611         {
612           laykey->prefix = prefix;
613           laykey->layer = assoc_prefix_layer[i][1];
614 #if defined(REMOVE_PREFIXES)
615           laykey->key = keyname + j + (keyname[j] == '/');
616 #else
617           laykey->key = keyname;
618 #endif
619           return VCONF_OK;
620         }
621       i++;
622       prefix = assoc_prefix_layer[i][0];
623     }
624   ERR ("Invalid argument: wrong prefix of key(%s)", keyname);
625   return VCONF_ERROR;
626 }
627
628 static inline BuxtonKey
629 _get_buxton_key_ (keynode_t * node)
630 {
631   BuxtonDataType type;
632   struct layer_key laykey;
633
634   /*
635    * get layer and key 
636    */
637   if (_get_layer_key_ (node->keyname, &laykey) != VCONF_OK)
638     {
639       return NULL;
640     }
641
642   /*
643    * get type 
644    */
645   switch (node->type)
646     {
647     case type_string:
648       type = BUXTON_TYPE_STRING;
649       break;
650     case type_int:
651       type = BUXTON_TYPE_INT32;
652       break;
653     case type_double:
654       type = BUXTON_TYPE_DOUBLE;
655       break;
656     case type_bool:
657       type = BUXTON_TYPE_BOOLEAN;
658       break;
659     default:
660       type = BUXTON_TYPE_UNSET;
661     }
662
663   return buxton_key_create (default_group, laykey.key, laykey.layer, type);
664 }
665
666 /*================= SECTION set/unset/refresh =============*/
667
668 static void
669 _cb_inc_received_ (BuxtonResponse resp, keynode_t * keynode)
670 {
671   keylist_t *list;
672
673   assert (keynode != NULL);
674   assert (keynode->list != NULL);
675
676   list = keynode->list;
677   list->cb_received++;
678   if (buxton_response_status (resp) != 0)
679     {
680       ERR ("Buxton returned error %d for key %s",
681            buxton_response_status (resp), keynode->keyname);
682       list->cb_status = VCONF_ERROR;
683     }
684 }
685
686 static int
687 _set_response_to_keynode_ (BuxtonResponse resp, keynode_t * keynode,
688                            int force)
689 {
690   enum keytype type;
691   BuxtonDataType buxtyp;
692   void *buxval;
693
694   assert (keynode != NULL);
695   assert (buxton_response_status (resp) == 0);
696
697   buxtyp = buxton_response_value_type (resp);
698   switch (buxtyp)
699     {
700     case BUXTON_TYPE_STRING:
701       type = type_string;
702       break;
703     case BUXTON_TYPE_INT32:
704       type = type_int;
705       break;
706     case BUXTON_TYPE_DOUBLE:
707       type = type_double;
708       break;
709     case BUXTON_TYPE_BOOLEAN:
710       type = type_bool;
711       break;
712     default:
713       return VCONF_ERROR;
714     }
715
716   if (force && type != keynode->type && keynode->type != type_unset)
717     return VCONF_ERROR;
718
719   buxval = buxton_response_value (resp);
720   if (buxval == NULL)
721     return VCONF_ERROR;
722
723   if (keynode->type == type_string)
724     free (keynode->value.s);
725
726   keynode->type = type;
727   switch (type)
728     {
729     case type_string:
730       keynode->value.s = buxval;
731       return VCONF_OK;
732     case type_int:
733       keynode->value.i = (int) *(int32_t *) buxval;
734       break;
735     case type_double:
736       keynode->value.d = *(double *) buxval;
737       break;
738     case type_bool:
739       keynode->value.b = *(bool *) buxval;
740       break;
741     default:
742       assert (0);
743       break;
744     }
745   free (buxval);
746   return VCONF_OK;
747 }
748
749 static void
750 _cb_refresh_ (BuxtonResponse resp, keynode_t * keynode)
751 {
752   keylist_t *list;
753
754   assert (keynode != NULL);
755   assert (keynode->list != NULL);
756   assert (buxton_response_type (resp) == BUXTON_CONTROL_GET);
757
758   list = keynode->list;
759   list->cb_received++;
760   if (buxton_response_status (resp) != 0)
761     {
762       ERR ("Error %d while getting buxton key %s",
763            buxton_response_status (resp), keynode->keyname);
764       list->cb_status = VCONF_ERROR;
765     }
766   else if (_set_response_to_keynode_ (resp, keynode, 0) != VCONF_OK)
767     {
768       list->cb_status = VCONF_ERROR;
769     }
770 }
771
772 static void
773 _cb_scan_ (BuxtonResponse resp, struct scanning_data *data)
774 {
775   char *buxname;
776   char *name;
777   char *term;
778   uint32_t count;
779   uint32_t index;
780   keylist_t *keylist;
781   keynode_t *keynode;
782   int length;
783
784   data->pending = 0;
785
786   /*
787    * check the response status 
788    */
789   if (buxton_response_status (resp) != 0)
790     {
791       ERR ("Error while getting list of names from buxton");
792       data->cb_status = VCONF_ERROR;
793       return;
794     }
795
796   /*
797    * iterate on the list of names 
798    */
799   assert (data->directory[data->dirlen - 1] == '/');
800   keylist = data->keylist;
801   count = buxton_response_list_names_count (resp);
802   index = 0;
803   while (index < count)
804     {
805       /*
806        * get the name 
807        */
808       buxname = buxton_response_list_names_item (resp, index++);
809       if (buxname == NULL)
810         {
811           ERR ("Unexpected NULL name returned by buxton");
812           data->cb_status = VCONF_ERROR;
813           return;
814         }
815
816       /*
817        * normalise the name 
818        */
819 #if defined(REMOVE_PREFIXES)
820       length = asprintf (&name, "%s/%s", data->prefix, buxname);
821 #else
822       length = asprintf (&name, "%s", buxname);
823 #endif
824       free (buxname);
825       if (length < 0)
826         {
827           ERR ("Memory allocation error");
828           data->cb_status = VCONF_ERROR;
829           return;
830         }
831       assert (_check_keyname_ (name));
832       assert (!memcmp (data->directory, name, data->dirlen));
833
834       /*
835        * add key if requested 
836        */
837       term = strchr (name + data->dirlen, '/');
838       if (data->want_keys && (data->is_recursive || term == NULL))
839         {
840           keynode = _keylist_getadd_ (keylist, name, type_unset);
841           if (keynode == NULL)
842             {
843               free (name);
844               data->cb_status = VCONF_ERROR;
845               return;
846             }
847         }
848
849       /*
850        * add directories if requested 
851        */
852       if (data->want_directories)
853         {
854           while (term != NULL)
855             {
856               *term = 0;
857               keynode = _keylist_getadd_ (keylist, name, type_directory);
858               if (keynode == NULL)
859                 {
860                   free (name);
861                   data->cb_status = VCONF_ERROR;
862                   return;
863                 }
864               if (!data->is_recursive)
865                 {
866                   break;
867                 }
868               *term = '/';
869               term = strchr (term + 1, '/');
870             }
871         }
872
873       free (name);
874     }
875   data->cb_status = VCONF_OK;
876 }
877
878
879 static inline int
880 _async_set_ (keynode_t * keynode)
881 {
882   void *data;
883   int status;
884   BuxtonKey key;
885
886   assert (keynode != NULL);
887
888   switch (keynode->type)
889     {
890     case type_string:
891       data = keynode->value.s;
892       break;
893     case type_int:
894     case type_double:
895     case type_bool:
896       data = &keynode->value;
897       break;
898     default:
899       return 0;
900     }
901
902   key = _get_buxton_key_ (keynode);
903   if (key == NULL)
904     {
905       return -1;
906     }
907
908   status = buxton_set_value (_buxton_ (), key,
909                              data,
910                              (BuxtonCallback) _cb_inc_received_, keynode,
911                              false);
912   buxton_key_free (key);
913
914   if (status == 0)
915     {
916       return 1;
917     }
918
919   ERR ("Error while calling buxton_set_value: %m");
920   return -1;
921 }
922
923 static inline int
924 _async_unset_ (keynode_t * keynode)
925 {
926   int status;
927   BuxtonKey key;
928
929   assert (keynode != NULL);
930
931   if (keynode->type != type_delete)
932     {
933       return 0;
934     }
935
936   key = _get_buxton_key_ (keynode);
937   if (key == NULL)
938     {
939       return -1;
940     }
941
942   status = buxton_unset_value (_buxton_ (), key,
943                                (BuxtonCallback) _cb_inc_received_,
944                                keynode, false);
945   buxton_key_free (key);
946
947   if (status == 0)
948     {
949       return 1;
950     }
951
952   ERR ("Error while calling buxton_unset_value: %m");
953   return -1;
954 }
955
956 static inline int
957 _async_set_or_unset_ (keynode_t * keynode, const char *unused)
958 {
959   assert (keynode != NULL);
960
961   switch (keynode->type)
962     {
963     case type_unset:
964     case type_directory:
965       return 0;
966     case type_delete:
967       return _async_unset_ (keynode);
968     default:
969       return _async_set_ (keynode);
970     }
971 }
972
973 static inline int
974 _async_refresh_ (keynode_t * keynode, const char *unused)
975 {
976   int status;
977   BuxtonKey key;
978
979   assert (keynode != NULL);
980
981   switch (keynode->type)
982     {
983     case type_unset:
984     case type_string:
985     case type_int:
986     case type_double:
987     case type_bool:
988       break;
989     default:
990       return 0;
991     }
992
993   key = _get_buxton_key_ (keynode);
994   if (key == NULL)
995     {
996       return -1;
997     }
998
999   status = buxton_get_value (_buxton_ (), key,
1000                              (BuxtonCallback) _cb_refresh_, keynode, false);
1001   buxton_key_free (key);
1002
1003   if (status == 0)
1004     {
1005       return 1;
1006     }
1007
1008   ERR ("Error while calling buxton_get_value: %m");
1009   return -1;
1010 }
1011
1012 static inline int
1013 _async_set_label_ (keynode_t * keynode, const char *label)
1014 {
1015   int status;
1016   BuxtonKey key;
1017
1018   assert (keynode != NULL);
1019
1020   key = _get_buxton_key_ (keynode);
1021   if (key == NULL)
1022     {
1023       return -1;
1024     }
1025
1026   status = buxton_set_label (_buxton_ (), key, label,
1027                              (BuxtonCallback) _cb_inc_received_,
1028                              keynode, false);
1029   buxton_key_free (key);
1030
1031   if (status == 0)
1032     {
1033       return 1;
1034     }
1035
1036   ERR ("Error while calling buxton_set_label: %m");
1037   return -1;
1038 }
1039
1040
1041 static int
1042 _apply_buxton_on_list_ (keylist_t * keylist,
1043                         int (*async) (keynode_t *, const char *),
1044                         const char *data)
1045 {
1046   keynode_t *keynode;
1047   int status;
1048   int sent;
1049
1050   assert (keylist != NULL);
1051
1052   status = _open_buxton_ ();
1053   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1054   assert (_buxton_ () != NULL);
1055
1056   retvm_if (keylist->cb_active != 0, VCONF_ERROR,
1057             "Already active in vconf-buxton");
1058
1059   LOCK(buxton);
1060
1061   keylist->cb_active = 1;
1062   keylist->cb_status = VCONF_OK;
1063   keylist->cb_sent = 0;
1064   keylist->cb_received = 0;
1065
1066   keynode = keylist->head;
1067   status = _dispatch_buxton_ (1, 0);
1068   while (keynode != NULL && status == VCONF_OK)
1069     {
1070       sent = async (keynode, data);
1071       keynode = keynode->next;
1072       if (sent < 0)
1073         {
1074           status = VCONF_ERROR;
1075         }
1076       else if (sent > 0)
1077         {
1078           keylist->cb_sent += sent;
1079           status = _dispatch_buxton_ (1, 0);
1080         }
1081     }
1082
1083   /*
1084    * get the responses 
1085    */
1086   while (status == VCONF_OK && keylist->cb_sent != keylist->cb_received)
1087     {
1088       status = _dispatch_buxton_ (0, 0);
1089     }
1090
1091   if (status == VCONF_OK && keylist->cb_status != VCONF_OK)
1092     status = keylist->cb_status;
1093   keylist->cb_active = 0;
1094
1095   UNLOCK(buxton);
1096
1097   _check_close_buxton_ ();
1098
1099   return status;
1100 }
1101
1102 /*================= SECTION notification =============*/
1103
1104 static void
1105 _cb_notify_ (BuxtonResponse resp, struct notify *notif)
1106 {
1107   switch (buxton_response_type (resp))
1108     {
1109     case BUXTON_CONTROL_NOTIFY:
1110     case BUXTON_CONTROL_UNNOTIFY:
1111       notif->status =
1112         buxton_response_status (resp) == 0 ? VCONF_OK : VCONF_ERROR;
1113       break;
1114     case BUXTON_CONTROL_CHANGED:
1115       if (_set_response_to_keynode_ (resp, notif->keynode, 1) == VCONF_OK)
1116         {
1117           UNLOCK (buxton);
1118           notif->callback (notif->keynode, notif->userdata);
1119           LOCK (buxton);
1120         }
1121       break;
1122     default:
1123       break;
1124     }
1125 }
1126
1127 static int
1128 _notify_reg_unreg_ (struct notify *notif, bool reg)
1129 {
1130   int status;
1131   BuxtonKey key;
1132
1133   status = _open_buxton_ ();
1134   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1135
1136   LOCK(buxton);
1137   key = _get_buxton_key_ (notif->keynode);
1138   retvm_if (key == NULL, VCONF_ERROR, "Can't create buxton key");
1139   notif->status = VCONF_OK;     /* on success calback isn't called! */
1140   status =
1141     (reg ? buxton_register_notification :
1142      buxton_unregister_notification) (_buxton_ (), key,
1143                                       (BuxtonCallback) _cb_notify_,
1144                                       notif, false);
1145   buxton_key_free (key);
1146   UNLOCK(buxton);
1147   return status == 0 && notif->status == VCONF_OK ? VCONF_OK : VCONF_ERROR;
1148 }
1149
1150 #if !defined(NO_GLIB)
1151 /*================= SECTION glib =============*/
1152
1153 static gboolean
1154 _cb_glib_ (GIOChannel * src, GIOCondition cond, gpointer data)
1155 {
1156   _handle_buxton_response_ (1);
1157   return G_SOURCE_CONTINUE;
1158 }
1159
1160 static int
1161 _glib_start_watch_ ()
1162 {
1163   GIOChannel *gio;
1164
1165   if (glib_source != NULL)
1166     return VCONF_OK;
1167
1168   gio = g_io_channel_unix_new (the_buxton_client_fd);
1169   retvm_if (gio == NULL, VCONF_ERROR, "Error: create a new GIOChannel");
1170
1171   g_io_channel_set_flags (gio, G_IO_FLAG_NONBLOCK, NULL);
1172
1173   glib_source = g_io_create_watch (gio, G_IO_IN);
1174   if (glib_source == NULL)
1175     {
1176       ERR ("Error: create a new GSource");
1177       g_io_channel_unref (gio);
1178       return VCONF_ERROR;
1179     }
1180
1181   g_source_set_callback (glib_source, (GSourceFunc) _cb_glib_, NULL, NULL);
1182   g_source_attach (glib_source, NULL);
1183   g_io_channel_unref (gio);
1184   g_source_unref (glib_source);
1185
1186   return VCONF_OK;
1187 }
1188
1189 static void
1190 _glib_stop_watch_ ()
1191 {
1192   if (glib_source != NULL)
1193     {
1194       g_source_destroy (glib_source);
1195       glib_source = NULL;
1196     }
1197 }
1198 #endif
1199
1200 /*================= SECTION VCONF API =============*/
1201
1202 const char *
1203 vconf_keynode_get_name (keynode_t * keynode)
1204 {
1205   retvm_if (keynode == NULL, NULL, "Invalid argument: keynode is NULL");
1206   retvm_if (keynode->keyname == NULL, NULL, "The name of keynode is NULL");
1207
1208   return keynode->keyname;
1209 }
1210
1211 int
1212 vconf_keynode_get_type (keynode_t * keynode)
1213 {
1214   retvm_if (keynode == NULL,
1215             VCONF_ERROR, "Invalid argument: keynode is NULL");
1216
1217   switch (keynode->type)
1218     {
1219     case type_directory:
1220       return VCONF_TYPE_DIR;
1221     case type_string:
1222       return VCONF_TYPE_STRING;
1223     case type_int:
1224       return VCONF_TYPE_INT;
1225     case type_double:
1226       return VCONF_TYPE_DOUBLE;
1227     case type_bool:
1228       return VCONF_TYPE_BOOL;
1229     default:
1230       return VCONF_TYPE_NONE;
1231     }
1232 }
1233
1234 int
1235 vconf_keynode_get_int (keynode_t * keynode)
1236 {
1237   retvm_if (keynode == NULL,
1238             VCONF_ERROR, "Invalid argument: keynode is NULL");
1239   retvm_if (keynode->type != type_int, VCONF_ERROR,
1240             "The type of keynode(%s) is not INT", keynode->keyname);
1241
1242   return keynode->value.i;
1243 }
1244
1245 double
1246 vconf_keynode_get_dbl (keynode_t * keynode)
1247 {
1248   retvm_if (keynode == NULL, -1.0, "Invalid argument: keynode is NULL");
1249   retvm_if (keynode->type != type_double, -1.0,
1250             "The type of keynode(%s) is not DBL", keynode->keyname);
1251
1252   return keynode->value.d;
1253 }
1254
1255 int
1256 vconf_keynode_get_bool (keynode_t * keynode)
1257 {
1258   retvm_if (keynode == NULL,
1259             VCONF_ERROR, "Invalid argument: keynode is NULL");
1260   retvm_if (keynode->type != type_bool, VCONF_ERROR,
1261             "The type of keynode(%s) is not BOOL", keynode->keyname);
1262
1263   return !!(keynode->value.b);
1264 }
1265
1266 char *
1267 vconf_keynode_get_str (keynode_t * keynode)
1268 {
1269   retvm_if (keynode == NULL, NULL, "Invalid argument: keynode is NULL");
1270   retvm_if (keynode->type != type_string, NULL,
1271             "The type of keynode(%s) is not STR", keynode->keyname);
1272
1273   return keynode->value.s;
1274 }
1275
1276 int
1277 vconf_set_default_group (const char *groupname)
1278 {
1279   char *copy;
1280
1281   copy = _dup_groupname_ (groupname);
1282   if (copy == NULL)
1283     return VCONF_ERROR;
1284   free (default_group);
1285   default_group = copy;
1286   return VCONF_OK;
1287 }
1288
1289 keylist_t *
1290 vconf_keylist_new ()
1291 {
1292   keylist_t *result;
1293   if (_ensure_default_group_ () != VCONF_OK)
1294     return NULL;
1295   result = calloc (1, sizeof (keylist_t));
1296   LOCK (counter);
1297   internal_list_count += (result != NULL);
1298   UNLOCK (counter);
1299   return result;
1300 }
1301
1302 int
1303 vconf_keylist_free (keylist_t * keylist)
1304 {
1305   keynode_t *keynode, *temp;
1306
1307   retvm_if (keylist == NULL,
1308             VCONF_ERROR, "Invalid argument: keylist is NULL");
1309
1310   keynode = keylist->head;
1311   free (keylist);
1312   while (keynode)
1313     {
1314       temp = keynode->next;
1315       _keynode_free_ (keynode);
1316       keynode = temp;
1317     }
1318
1319   LOCK (counter);
1320   internal_list_count -= (internal_list_count > 0);
1321   UNLOCK (counter);
1322   _check_close_buxton_ ();
1323   return 0;
1324 }
1325
1326 int
1327 vconf_keylist_rewind (keylist_t * keylist)
1328 {
1329   retvm_if (keylist == NULL,
1330             VCONF_ERROR, "Invalid argument: keylist is NULL");
1331
1332   keylist->cursor = NULL;
1333
1334   return 0;
1335 }
1336
1337 keynode_t *
1338 vconf_keylist_nextnode (keylist_t * keylist)
1339 {
1340   keynode_t *result;
1341
1342   retvm_if (keylist == NULL, NULL, "Invalid argument: keylist is NULL");
1343
1344   result = keylist->cursor;
1345   result = result == NULL ? keylist->head : result->next;
1346   keylist->cursor = result;
1347
1348   return result;
1349 }
1350
1351 int
1352 vconf_keylist_lookup (keylist_t * keylist,
1353                       const char *keyname, keynode_t ** return_node)
1354 {
1355   keynode_t *keynode;
1356
1357   retvm_if (keylist == NULL,
1358             VCONF_ERROR, "Invalid argument: keylist is NULL");
1359   retvm_if (keyname == NULL,
1360             VCONF_ERROR, "Invalid argument: keyname is NULL");
1361   retvm_if (return_node == NULL,
1362             VCONF_ERROR, "Invalid argument: return_node is NULL");
1363
1364   keynode = _keylist_lookup_ (keylist, keyname, NULL);
1365   if (NULL == keynode)
1366     return 0;
1367
1368   if (return_node)
1369     *return_node = keynode;
1370   return keynode->type;
1371 }
1372
1373 static int
1374 _cb_sort_keynodes (const void *a, const void *b)
1375 {
1376   register const keynode_t *kna = *(const keynode_t **) a;
1377   register const keynode_t *knb = *(const keynode_t **) b;
1378   return strcmp (kna->keyname, knb->keyname);
1379 }
1380
1381 int
1382 vconf_keylist_sort (keylist_t * keylist)
1383 {
1384   int index;
1385   keynode_t **nodes, *keynode;
1386
1387   retvm_if (keylist == NULL,
1388             VCONF_ERROR, "Invalid argument: keylist is NULL");
1389
1390   if (keylist->num <= 1)
1391     return VCONF_OK;
1392
1393   nodes = malloc (keylist->num * sizeof *nodes);
1394   retvm_if (nodes == NULL, VCONF_ERROR, "can't allocate memory for sorting");
1395
1396   index = 0;
1397   keynode = keylist->head;
1398   while (keynode != NULL)
1399     {
1400       assert (index < keylist->num);
1401       nodes[index++] = keynode;
1402       keynode = keynode->next;
1403     }
1404   assert (index == keylist->num);
1405
1406   qsort (nodes, index, sizeof *nodes, _cb_sort_keynodes);
1407
1408   while (index)
1409     {
1410       nodes[--index]->next = keynode;
1411       keynode = nodes[index];
1412     }
1413   keylist->head = keynode;
1414   free (nodes);
1415   return VCONF_OK;
1416 }
1417
1418 int
1419 vconf_keylist_add_int (keylist_t * keylist, const char *keyname,
1420                        const int value)
1421 {
1422   keynode_t *keynode;
1423
1424   retvm_if (keylist == NULL,
1425             VCONF_ERROR, "Invalid argument: keylist is NULL");
1426   retvm_if (keyname == NULL,
1427             VCONF_ERROR, "Invalid argument: keyname is NULL");
1428
1429   keynode = _keylist_getadd_ (keylist, keyname, type_int);
1430   if (keynode == NULL)
1431     return VCONF_ERROR;
1432
1433   keynode->value.i = value;
1434   return keylist->num;
1435 }
1436
1437 int
1438 vconf_keylist_add_bool (keylist_t * keylist, const char *keyname,
1439                         const int value)
1440 {
1441   keynode_t *keynode;
1442
1443   retvm_if (keylist == NULL,
1444             VCONF_ERROR, "Invalid argument: keylist is NULL");
1445   retvm_if (keyname == NULL,
1446             VCONF_ERROR, "Invalid argument: keyname is NULL");
1447
1448   keynode = _keylist_getadd_ (keylist, keyname, type_bool);
1449   if (keynode == NULL)
1450     return VCONF_ERROR;
1451
1452   keynode->value.b = !!value;
1453   return keylist->num;
1454 }
1455
1456 int
1457 vconf_keylist_add_dbl (keylist_t * keylist,
1458                        const char *keyname, const double value)
1459 {
1460   keynode_t *keynode;
1461
1462   retvm_if (keylist == NULL, VCONF_ERROR,
1463             "Invalid argument: keylist is NULL");
1464   retvm_if (keyname == NULL, VCONF_ERROR,
1465             "Invalid argument: keyname is NULL");
1466
1467   keynode = _keylist_getadd_ (keylist, keyname, type_double);
1468   if (keynode == NULL)
1469     return VCONF_ERROR;
1470
1471   keynode->value.d = value;
1472   return keylist->num;
1473 }
1474
1475 int
1476 vconf_keylist_add_str (keylist_t * keylist,
1477                        const char *keyname, const char *value)
1478 {
1479   keynode_t *keynode;
1480   char *copy;
1481
1482   retvm_if (keylist == NULL, VCONF_ERROR,
1483             "Invalid argument: keylist is NULL");
1484   retvm_if (keyname == NULL, VCONF_ERROR,
1485             "Invalid argument: keyname is NULL");
1486
1487   copy = strdup (value == NULL ? "" : value);
1488   retvm_if (copy == NULL, VCONF_ERROR, "Allocation of memory failed");
1489
1490   keynode = _keylist_getadd_ (keylist, keyname, type_string);
1491   if (keynode == NULL)
1492     {
1493       free (copy);
1494       return VCONF_ERROR;
1495     }
1496
1497   free (keynode->value.s);
1498   keynode->value.s = copy;
1499   return keylist->num;
1500 }
1501
1502 int
1503 vconf_keylist_add_null (keylist_t * keylist, const char *keyname)
1504 {
1505   keynode_t *keynode;
1506
1507   retvm_if (keylist == NULL, VCONF_ERROR,
1508             "Invalid argument: keylist is NULL");
1509   retvm_if (keyname == NULL, VCONF_ERROR,
1510             "Invalid argument: keyname is NULL");
1511
1512   keynode = _keylist_getadd_ (keylist, keyname, type_unset);
1513   if (keynode == NULL)
1514     return VCONF_ERROR;
1515
1516   return keylist->num;
1517 }
1518
1519 int
1520 vconf_keylist_del (keylist_t * keylist, const char *keyname)
1521 {
1522   keynode_t *keynode, **previous = NULL;
1523
1524   retvm_if (keylist == NULL, VCONF_ERROR,
1525             "Invalid argument: keylist is NULL");
1526   retvm_if (keyname == NULL, VCONF_ERROR,
1527             "Invalid argument: keyname is NULL");
1528
1529   keynode = _keylist_lookup_ (keylist, keyname, &previous);
1530   if (keynode == NULL)
1531     return VCONF_ERROR;
1532
1533   *previous = keynode->next;
1534   keylist->num--;
1535   _keynode_free_ (keynode);
1536
1537   return VCONF_OK;
1538 }
1539
1540 int
1541 vconf_set (keylist_t * keylist)
1542 {
1543   retvm_if (keylist == NULL, VCONF_ERROR,
1544             "Invalid argument: keylist is NULL");
1545
1546   return _apply_buxton_on_list_ (keylist, _async_set_or_unset_, NULL);
1547 }
1548
1549 int
1550 vconf_set_labels (keylist_t * keylist, const char *label)
1551 {
1552   retvm_if (keylist == NULL, VCONF_ERROR,
1553             "Invalid argument: keylist is NULL");
1554
1555   retvm_if (label == NULL, VCONF_ERROR, "Invalid argument: name is NULL");
1556
1557   return _apply_buxton_on_list_ (keylist, _async_set_label_, label);
1558 }
1559
1560 int
1561 vconf_sync_key (const char *keyname)
1562 {
1563   /*
1564    * does nothing succefully 
1565    */
1566   return 0;
1567 }
1568
1569 int
1570 vconf_refresh (keylist_t * keylist)
1571 {
1572   retvm_if (keylist == NULL, VCONF_ERROR,
1573             "Invalid argument: keylist is NULL");
1574
1575   return _apply_buxton_on_list_ (keylist, _async_refresh_, NULL);
1576 }
1577
1578 int
1579 vconf_scan (keylist_t * keylist, const char *dirpath, get_option_t option)
1580 {
1581   char *dircopy;
1582   struct layer_key laykey;
1583   struct scanning_data data;
1584   int status;
1585
1586   retvm_if (keylist == NULL, VCONF_ERROR,
1587             "Invalid argument: keylist is null");
1588   retvm_if (keylist->num != 0, VCONF_ERROR,
1589             "Invalid argument: keylist not empty");
1590   retvm_if (dirpath == NULL, VCONF_ERROR,
1591             "Invalid argument: dirpath is null");
1592   retvm_if (_check_keyname_ (dirpath) == 0, VCONF_ERROR,
1593             "Invalid argument: dirpath is not valid");
1594
1595   status = _open_buxton_ ();
1596   if (!status)
1597     {
1598       ERR ("Can't connect to buxton");
1599       return VCONF_ERROR;
1600     }
1601
1602   data.keylist = keylist;
1603
1604   switch (option)
1605     {
1606     case VCONF_GET_KEY:
1607       data.want_directories = 0;
1608       data.want_keys = 1;
1609       data.is_recursive = 0;
1610       break;
1611     case VCONF_GET_ALL:
1612       data.want_directories = 1;
1613       data.want_keys = 1;
1614       data.is_recursive = 0;
1615       break;
1616     case VCONF_GET_DIR:
1617       data.want_directories = 1;
1618       data.want_keys = 0;
1619       data.is_recursive = 0;
1620       break;
1621     case VCONF_GET_KEY_REC:
1622       data.want_directories = 0;
1623       data.want_keys = 1;
1624       data.is_recursive = 1;
1625       break;
1626     case VCONF_GET_ALL_REC:
1627       data.want_directories = 1;
1628       data.want_keys = 1;
1629       data.is_recursive = 1;
1630       break;
1631     case VCONF_GET_DIR_REC:
1632       data.want_directories = 0;
1633       data.want_keys = 1;
1634       data.is_recursive = 1;
1635       break;
1636     default:
1637       ERR ("Invalid argument: Bad option value");
1638       return VCONF_ERROR;
1639     }
1640
1641   data.dirlen = strlen (dirpath);
1642   assert (data.dirlen);
1643   if (dirpath[data.dirlen - 1] == '/')
1644     {
1645       data.directory = dirpath;
1646       dircopy = NULL;
1647     }
1648   else
1649     {
1650       status = asprintf (&dircopy, "%s/", dirpath);
1651       retvm_if (status < 0, VCONF_ERROR,
1652                 "No more memory for copying dirpath");
1653       data.directory = dircopy;
1654       data.dirlen++;
1655     }
1656
1657   status = _get_layer_key_ (data.directory, &laykey);
1658   if (status != VCONF_OK)
1659     {
1660       return status;
1661     }
1662
1663   data.prefix = laykey.prefix;
1664   if (!laykey.key[0])
1665     {
1666       laykey.key = NULL;
1667     }
1668
1669   data.pending = 1;
1670   assert (_buxton_ () != NULL);
1671   status = buxton_list_names (_buxton_ (), laykey.layer, default_group,
1672                               laykey.key, (BuxtonCallback) _cb_scan_,
1673                               &data, false);
1674   if (!status)
1675     status = _wait_buxton_response_ (&data.pending);
1676
1677   free (dircopy);
1678
1679   retvm_if (status, VCONF_ERROR, "Error while calling buxton_list_names: %m");
1680   if (data.cb_status != VCONF_OK)
1681     {
1682       return VCONF_ERROR;
1683     }
1684
1685   return vconf_refresh (keylist);
1686 }
1687
1688 int
1689 vconf_get (keylist_t * keylist, const char *dirpath, get_option_t option)
1690 {
1691   if (option == VCONF_REFRESH_ONLY
1692       || (option == VCONF_GET_KEY && keylist->num != 0))
1693     {
1694       return vconf_refresh (keylist);
1695     }
1696   else
1697     {
1698       return vconf_scan (keylist, dirpath, option);
1699     }
1700 }
1701
1702 int
1703 vconf_unset (const char *keyname)
1704 {
1705   struct singleton single;
1706   int status;
1707
1708   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1709
1710   status = _keylist_init_singleton_ (&single, keyname, type_delete);
1711   if (status == VCONF_OK)
1712     {
1713       status = vconf_set (&single.list);
1714     }
1715   return status;
1716
1717 }
1718
1719 int
1720 vconf_exists (const char *keyname)
1721 {
1722   struct singleton single;
1723   int status;
1724
1725   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1726
1727   status = _keylist_init_singleton_ (&single, keyname, type_unset);
1728   if (status == VCONF_OK)
1729     {
1730       status = vconf_refresh (&single.list);
1731       if (status == VCONF_OK && single.node.type == type_string)
1732         free (single.node.value.s);
1733     }
1734   return status;
1735
1736 }
1737
1738 int
1739 vconf_unset_recursive (const char *in_dir)
1740 {
1741   struct _keylist_t *keylist;
1742   struct _keynode_t *keynode;
1743   int status;
1744
1745   retvm_if (in_dir == NULL, VCONF_ERROR, "Invalid argument: dir is null");
1746
1747   keylist = vconf_keylist_new ();
1748   if (keylist == NULL)
1749     return VCONF_ERROR;
1750
1751   status = vconf_scan (keylist, in_dir, VCONF_GET_KEY_REC);
1752   if (status == VCONF_OK)
1753     {
1754       for (keynode = keylist->head; keynode; keynode = keynode->next)
1755         keynode->type = type_delete;
1756       status = vconf_set (keylist);
1757     }
1758   vconf_keylist_free (keylist);
1759   return status;
1760 }
1761
1762 int
1763 vconf_notify_key_changed (const char *keyname, vconf_callback_fn cb,
1764                           void *user_data)
1765 {
1766   int status;
1767   struct notify *notif;
1768   keynode_t *keynode, *aknode;
1769   keylist_t *alist;
1770
1771   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is null");
1772   retvm_if (cb == NULL, VCONF_ERROR, "Invalid argument: cb(%p)", cb);
1773   status = _open_buxton_ ();
1774   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1775   status = vconf_exists (keyname);
1776   retvm_if (status != VCONF_OK, VCONF_ERROR, "key %s doesn't exist", keyname);
1777
1778
1779   /*
1780    * create the notification 
1781    */
1782   notif = malloc (sizeof *notif);
1783   retvm_if (notif == NULL, VCONF_ERROR,
1784             "Allocation of notify structure failed");
1785
1786   /*
1787    * ensure existing list 
1788    */
1789   LOCK (notify);
1790   if (notify_keylist == NULL)
1791     {
1792       notify_keylist = vconf_keylist_new ();
1793       if (notify_keylist == NULL)
1794         {
1795           UNLOCK (notify);
1796           free (notif);
1797           return VCONF_ERROR;
1798         }
1799     }
1800
1801   /*
1802    * search keynode of keyname 
1803    */
1804   keynode = _keylist_lookup_ (notify_keylist, keyname, NULL);
1805   if (keynode == NULL)
1806     {
1807       /*
1808        * not found, create it with type unset 
1809        */
1810       keynode = _keylist_add_ (notify_keylist, keyname, type_unset);
1811       if (keynode == NULL)
1812         {
1813           UNLOCK (notify);
1814           free (notif);
1815           return VCONF_ERROR;
1816         }
1817     }
1818
1819   /*
1820    * init the notification 
1821    */
1822   notif->callback = cb;
1823   notif->userdata = user_data;
1824   notif->keynode = keynode;
1825   notif->next = notify_entries;
1826   notify_entries = notif;
1827   UNLOCK (notify);
1828
1829   /*
1830    * record the notification 
1831    */
1832   status = _notify_reg_unreg_ (notif, true);
1833   if (status != VCONF_OK)
1834     {
1835       vconf_ignore_key_changed (keyname, cb);
1836       return VCONF_ERROR;
1837     }
1838
1839 #if !defined(NO_GLIB)
1840   return _glib_start_watch_ ();
1841 #else
1842   return VCONF_OK;
1843 #endif
1844 }
1845
1846 int
1847 vconf_ignore_key_changed (const char *keyname, vconf_callback_fn cb)
1848 {
1849   struct notify *entry, **prevent, *delent, **prevdelent;
1850   keynode_t *keynode, **prevnod;
1851   int fcount;
1852   int status;
1853
1854   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is null");
1855   retvm_if (cb == NULL, VCONF_ERROR, "Invalid argument: cb(%p)", cb);
1856   status = _open_buxton_ ();
1857   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1858
1859   fcount = 0;
1860   status = VCONF_ERROR;
1861   delent = NULL;
1862
1863   LOCK (notify);
1864   if (notify_keylist != NULL)
1865     {
1866       keynode = _keylist_lookup_ (notify_keylist, keyname, &prevnod);
1867       if (keynode != NULL)
1868         {
1869           prevdelent = &delent;
1870           prevent = &notify_entries;
1871           entry = notify_entries;
1872           while (entry != NULL)
1873             {
1874               if (entry->keynode == keynode)
1875                 {
1876                   if (entry->callback == cb)
1877                     {
1878                       *prevdelent = entry;
1879                       prevdelent = &entry->next;
1880                       entry = entry->next;
1881                       continue;
1882                     }
1883                   fcount++;
1884                 }
1885               *prevent = entry;
1886               prevent = &entry->next;
1887               entry = entry->next;
1888             }
1889           *prevent = NULL;
1890           *prevdelent = NULL;
1891           if (fcount == 0)
1892             *prevnod = keynode->next;
1893 #if !defined(NO_GLIB)
1894           if (notify_entries == NULL)
1895             _glib_stop_watch_ ();
1896 #endif
1897           if (delent != NULL)
1898             {
1899               UNLOCK (notify);
1900               while (delent != NULL)
1901                 {
1902                   entry = delent;
1903                   delent = entry->next;
1904                   _notify_reg_unreg_ (entry, false);
1905                   free (entry);
1906                 }
1907               if (fcount == 0)
1908                 _keynode_free_ (keynode);
1909               return VCONF_OK;
1910             }
1911         }
1912     }
1913   UNLOCK (notify);
1914   ERR ("Not found: can't remove notification for key(%s)", keyname);
1915
1916   return VCONF_ERROR;
1917 }
1918
1919 int
1920 vconf_set_int (const char *keyname, const int intval)
1921 {
1922   struct singleton single;
1923   int status;
1924
1925   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1926
1927   status = _keylist_init_singleton_ (&single, keyname, type_int);
1928   if (status == VCONF_OK)
1929     {
1930       single.node.value.i = intval;
1931       status = vconf_set (&single.list);
1932     }
1933   return status;
1934 }
1935
1936 int
1937 vconf_set_bool (const char *keyname, const int boolval)
1938 {
1939   struct singleton single;
1940   int status;
1941
1942   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1943
1944   status = _keylist_init_singleton_ (&single, keyname, type_bool);
1945   if (status == VCONF_OK)
1946     {
1947       single.node.value.b = (bool) boolval;
1948       status = vconf_set (&single.list);
1949     }
1950   return status;
1951 }
1952
1953 int
1954 vconf_set_dbl (const char *keyname, const double dblval)
1955 {
1956   struct singleton single;
1957   int status;
1958
1959   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1960
1961   status = _keylist_init_singleton_ (&single, keyname, type_double);
1962   if (status == VCONF_OK)
1963     {
1964       single.node.value.d = dblval;
1965       status = vconf_set (&single.list);
1966     }
1967   return status;
1968 }
1969
1970 int
1971 vconf_set_str (const char *keyname, const char *strval)
1972 {
1973   struct singleton single;
1974   int status;
1975
1976   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1977
1978   status = _keylist_init_singleton_ (&single, keyname, type_string);
1979   if (status == VCONF_OK)
1980     {
1981       single.node.value.s = (char *) strval;
1982       status = vconf_set (&single.list);
1983     }
1984   return status;
1985 }
1986
1987 int
1988 vconf_get_int (const char *keyname, int *intval)
1989 {
1990   struct singleton single;
1991   int status;
1992
1993   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1994
1995   status = _keylist_init_singleton_ (&single, keyname, type_int);
1996   if (status == VCONF_OK)
1997     {
1998       status = vconf_refresh (&single.list);
1999       if (status == VCONF_OK)
2000         *intval = single.node.value.i;
2001     }
2002   return status;
2003 }
2004
2005 int
2006 vconf_set_label (const char *keyname, const char *label)
2007 {
2008   struct singleton single;
2009   int status;
2010
2011   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
2012
2013   retvm_if (label == NULL, VCONF_ERROR, "Invalid argument: name is NULL");
2014
2015   status = _keylist_init_singleton_ (&single, keyname, type_unset);
2016   if (status == VCONF_OK)
2017     {
2018       status = vconf_set_labels (&single.list, label);
2019     }
2020   return status;
2021 }
2022
2023 int
2024 vconf_get_bool (const char *keyname, int *boolval)
2025 {
2026   struct singleton single;
2027   int status;
2028
2029   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
2030
2031   status = _keylist_init_singleton_ (&single, keyname, type_bool);
2032   if (status == VCONF_OK)
2033     {
2034       status = vconf_refresh (&single.list);
2035       if (status == VCONF_OK)
2036         *boolval = (int) single.node.value.b;
2037     }
2038   return status;
2039 }
2040
2041 int
2042 vconf_get_dbl (const char *keyname, double *dblval)
2043 {
2044   struct singleton single;
2045   int status;
2046
2047   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
2048
2049   status = _keylist_init_singleton_ (&single, keyname, type_double);
2050   if (status == VCONF_OK)
2051     {
2052       status = vconf_refresh (&single.list);
2053       if (status == VCONF_OK)
2054         *dblval = single.node.value.d;
2055     }
2056   return status;
2057 }
2058
2059 char *
2060 vconf_get_str (const char *keyname)
2061 {
2062   struct singleton single;
2063   int status;
2064
2065   retvm_if (keyname == NULL, NULL, "Invalid argument: key is NULL");
2066
2067   status = _keylist_init_singleton_ (&single, keyname, type_string);
2068   if (status != VCONF_OK)
2069     return NULL;
2070
2071   single.node.value.s = NULL;
2072   status = vconf_refresh (&single.list);
2073   if (status != VCONF_OK)
2074     return NULL;
2075
2076   return single.node.value.s;
2077 }