Workaround for infinite loop issue
[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 (result == 0) {
532     ERR ("Connection closed");
533     result = -1;
534   }
535   if (lock)
536     UNLOCK (buxton);
537   return result;
538 }
539
540 static inline int
541 _dispatch_buxton_ (int writing, int lock)
542 {
543   int status;
544   struct pollfd pfd;
545
546   assert (_buxton_ () != NULL);
547
548   pfd.fd = the_buxton_client_fd;
549   pfd.events = writing ? POLLIN | POLLOUT : POLLIN;
550   for (;;)
551     {
552       pfd.revents = 0;
553       status = poll (&pfd, 1, default_timeout);
554       if (status == -1)
555         {
556           if (errno != EINTR)
557             {
558               return VCONF_ERROR;
559             }
560         }
561       else if (status == 1)
562         {
563           if (pfd.revents & POLLIN)
564             {
565               status = _handle_buxton_response_ (lock);
566               if (status < 0)
567                 {
568                   return VCONF_ERROR;
569                 }
570               if (!writing)
571                 {
572                   return VCONF_OK;
573                 }
574             }
575           if (pfd.revents & POLLOUT)
576             {
577               return VCONF_OK;
578             }
579           else
580             {
581               return VCONF_ERROR;
582             }
583         }
584     }
585 }
586
587 static inline int
588 _wait_buxton_response_ (int *pending)
589 {
590   int result;
591
592   do
593     {
594       result = _dispatch_buxton_ (0, 1);
595     }
596   while (result == VCONF_OK && *pending);
597   return result;
598 }
599
600 static inline int
601 _get_layer_key_ (const char *keyname, struct layer_key *laykey)
602 {
603   int i, j;
604   const char *prefix;
605
606   /*
607    * get the names 
608    */
609   i = 0;
610   prefix = assoc_prefix_layer[i][0];
611   while (prefix != NULL)
612     {
613       for (j = 0; prefix[j] && prefix[j] == keyname[j]; j++);
614       if (!prefix[j] && (!keyname[j] || keyname[j] == '/'))
615         {
616           laykey->prefix = prefix;
617           laykey->layer = assoc_prefix_layer[i][1];
618 #if defined(REMOVE_PREFIXES)
619           laykey->key = keyname + j + (keyname[j] == '/');
620 #else
621           laykey->key = keyname;
622 #endif
623           return VCONF_OK;
624         }
625       i++;
626       prefix = assoc_prefix_layer[i][0];
627     }
628   ERR ("Invalid argument: wrong prefix of key(%s)", keyname);
629   return VCONF_ERROR;
630 }
631
632 static inline BuxtonKey
633 _get_buxton_key_ (keynode_t * node)
634 {
635   BuxtonDataType type;
636   struct layer_key laykey;
637
638   /*
639    * get layer and key 
640    */
641   if (_get_layer_key_ (node->keyname, &laykey) != VCONF_OK)
642     {
643       return NULL;
644     }
645
646   /*
647    * get type 
648    */
649   switch (node->type)
650     {
651     case type_string:
652       type = BUXTON_TYPE_STRING;
653       break;
654     case type_int:
655       type = BUXTON_TYPE_INT32;
656       break;
657     case type_double:
658       type = BUXTON_TYPE_DOUBLE;
659       break;
660     case type_bool:
661       type = BUXTON_TYPE_BOOLEAN;
662       break;
663     default:
664       type = BUXTON_TYPE_UNSET;
665     }
666
667   return buxton_key_create (default_group, laykey.key, laykey.layer, type);
668 }
669
670 /*================= SECTION set/unset/refresh =============*/
671
672 static void
673 _cb_inc_received_ (BuxtonResponse resp, keynode_t * keynode)
674 {
675   keylist_t *list;
676
677   assert (keynode != NULL);
678   assert (keynode->list != NULL);
679
680   list = keynode->list;
681   list->cb_received++;
682   if (buxton_response_status (resp) != 0)
683     {
684       ERR ("Buxton returned error %d for key %s",
685            buxton_response_status (resp), keynode->keyname);
686       list->cb_status = VCONF_ERROR;
687     }
688 }
689
690 static int
691 _set_response_to_keynode_ (BuxtonResponse resp, keynode_t * keynode,
692                            int force)
693 {
694   enum keytype type;
695   BuxtonDataType buxtyp;
696   void *buxval;
697
698   assert (keynode != NULL);
699   assert (buxton_response_status (resp) == 0);
700
701   buxtyp = buxton_response_value_type (resp);
702   switch (buxtyp)
703     {
704     case BUXTON_TYPE_STRING:
705       type = type_string;
706       break;
707     case BUXTON_TYPE_INT32:
708       type = type_int;
709       break;
710     case BUXTON_TYPE_DOUBLE:
711       type = type_double;
712       break;
713     case BUXTON_TYPE_BOOLEAN:
714       type = type_bool;
715       break;
716     default:
717       return VCONF_ERROR;
718     }
719
720   if (force && type != keynode->type && keynode->type != type_unset)
721     return VCONF_ERROR;
722
723   buxval = buxton_response_value (resp);
724   if (buxval == NULL)
725     return VCONF_ERROR;
726
727   if (keynode->type == type_string)
728     free (keynode->value.s);
729
730   keynode->type = type;
731   switch (type)
732     {
733     case type_string:
734       keynode->value.s = buxval;
735       return VCONF_OK;
736     case type_int:
737       keynode->value.i = (int) *(int32_t *) buxval;
738       break;
739     case type_double:
740       keynode->value.d = *(double *) buxval;
741       break;
742     case type_bool:
743       keynode->value.b = *(bool *) buxval;
744       break;
745     default:
746       assert (0);
747       break;
748     }
749   free (buxval);
750   return VCONF_OK;
751 }
752
753 static void
754 _cb_refresh_ (BuxtonResponse resp, keynode_t * keynode)
755 {
756   keylist_t *list;
757
758   assert (keynode != NULL);
759   assert (keynode->list != NULL);
760   assert (buxton_response_type (resp) == BUXTON_CONTROL_GET);
761
762   list = keynode->list;
763   list->cb_received++;
764   if (buxton_response_status (resp) != 0)
765     {
766       ERR ("Error %d while getting buxton key %s",
767            buxton_response_status (resp), keynode->keyname);
768       list->cb_status = VCONF_ERROR;
769     }
770   else if (_set_response_to_keynode_ (resp, keynode, 0) != VCONF_OK)
771     {
772       list->cb_status = VCONF_ERROR;
773     }
774 }
775
776 static void
777 _cb_scan_ (BuxtonResponse resp, struct scanning_data *data)
778 {
779   char *buxname;
780   char *name;
781   char *term;
782   uint32_t count;
783   uint32_t index;
784   keylist_t *keylist;
785   keynode_t *keynode;
786   int length;
787
788   data->pending = 0;
789
790   /*
791    * check the response status 
792    */
793   if (buxton_response_status (resp) != 0)
794     {
795       ERR ("Error while getting list of names from buxton");
796       data->cb_status = VCONF_ERROR;
797       return;
798     }
799
800   /*
801    * iterate on the list of names 
802    */
803   assert (data->directory[data->dirlen - 1] == '/');
804   keylist = data->keylist;
805   count = buxton_response_list_names_count (resp);
806   index = 0;
807   while (index < count)
808     {
809       /*
810        * get the name 
811        */
812       buxname = buxton_response_list_names_item (resp, index++);
813       if (buxname == NULL)
814         {
815           ERR ("Unexpected NULL name returned by buxton");
816           data->cb_status = VCONF_ERROR;
817           return;
818         }
819
820       /*
821        * normalise the name 
822        */
823 #if defined(REMOVE_PREFIXES)
824       length = asprintf (&name, "%s/%s", data->prefix, buxname);
825 #else
826       length = asprintf (&name, "%s", buxname);
827 #endif
828       free (buxname);
829       if (length < 0)
830         {
831           ERR ("Memory allocation error");
832           data->cb_status = VCONF_ERROR;
833           return;
834         }
835       assert (_check_keyname_ (name));
836       assert (!memcmp (data->directory, name, data->dirlen));
837
838       /*
839        * add key if requested 
840        */
841       term = strchr (name + data->dirlen, '/');
842       if (data->want_keys && (data->is_recursive || term == NULL))
843         {
844           keynode = _keylist_getadd_ (keylist, name, type_unset);
845           if (keynode == NULL)
846             {
847               free (name);
848               data->cb_status = VCONF_ERROR;
849               return;
850             }
851         }
852
853       /*
854        * add directories if requested 
855        */
856       if (data->want_directories)
857         {
858           while (term != NULL)
859             {
860               *term = 0;
861               keynode = _keylist_getadd_ (keylist, name, type_directory);
862               if (keynode == NULL)
863                 {
864                   free (name);
865                   data->cb_status = VCONF_ERROR;
866                   return;
867                 }
868               if (!data->is_recursive)
869                 {
870                   break;
871                 }
872               *term = '/';
873               term = strchr (term + 1, '/');
874             }
875         }
876
877       free (name);
878     }
879   data->cb_status = VCONF_OK;
880 }
881
882
883 static inline int
884 _async_set_ (keynode_t * keynode)
885 {
886   void *data;
887   int status;
888   BuxtonKey key;
889
890   assert (keynode != NULL);
891
892   switch (keynode->type)
893     {
894     case type_string:
895       data = keynode->value.s;
896       break;
897     case type_int:
898     case type_double:
899     case type_bool:
900       data = &keynode->value;
901       break;
902     default:
903       return 0;
904     }
905
906   key = _get_buxton_key_ (keynode);
907   if (key == NULL)
908     {
909       return -1;
910     }
911
912   status = buxton_set_value (_buxton_ (), key,
913                              data,
914                              (BuxtonCallback) _cb_inc_received_, keynode,
915                              false);
916   buxton_key_free (key);
917
918   if (status == 0)
919     {
920       return 1;
921     }
922
923   ERR ("Error while calling buxton_set_value: %m");
924   return -1;
925 }
926
927 static inline int
928 _async_unset_ (keynode_t * keynode)
929 {
930   int status;
931   BuxtonKey key;
932
933   assert (keynode != NULL);
934
935   if (keynode->type != type_delete)
936     {
937       return 0;
938     }
939
940   key = _get_buxton_key_ (keynode);
941   if (key == NULL)
942     {
943       return -1;
944     }
945
946   status = buxton_unset_value (_buxton_ (), key,
947                                (BuxtonCallback) _cb_inc_received_,
948                                keynode, false);
949   buxton_key_free (key);
950
951   if (status == 0)
952     {
953       return 1;
954     }
955
956   ERR ("Error while calling buxton_unset_value: %m");
957   return -1;
958 }
959
960 static inline int
961 _async_set_or_unset_ (keynode_t * keynode, const char *unused)
962 {
963   assert (keynode != NULL);
964
965   switch (keynode->type)
966     {
967     case type_unset:
968     case type_directory:
969       return 0;
970     case type_delete:
971       return _async_unset_ (keynode);
972     default:
973       return _async_set_ (keynode);
974     }
975 }
976
977 static inline int
978 _async_refresh_ (keynode_t * keynode, const char *unused)
979 {
980   int status;
981   BuxtonKey key;
982
983   assert (keynode != NULL);
984
985   switch (keynode->type)
986     {
987     case type_unset:
988     case type_string:
989     case type_int:
990     case type_double:
991     case type_bool:
992       break;
993     default:
994       return 0;
995     }
996
997   key = _get_buxton_key_ (keynode);
998   if (key == NULL)
999     {
1000       return -1;
1001     }
1002
1003   status = buxton_get_value (_buxton_ (), key,
1004                              (BuxtonCallback) _cb_refresh_, keynode, false);
1005   buxton_key_free (key);
1006
1007   if (status == 0)
1008     {
1009       return 1;
1010     }
1011
1012   ERR ("Error while calling buxton_get_value: %m");
1013   return -1;
1014 }
1015
1016 static inline int
1017 _async_set_label_ (keynode_t * keynode, const char *label)
1018 {
1019   int status;
1020   BuxtonKey key;
1021
1022   assert (keynode != NULL);
1023
1024   key = _get_buxton_key_ (keynode);
1025   if (key == NULL)
1026     {
1027       return -1;
1028     }
1029
1030   status = buxton_set_label (_buxton_ (), key, label,
1031                              (BuxtonCallback) _cb_inc_received_,
1032                              keynode, false);
1033   buxton_key_free (key);
1034
1035   if (status == 0)
1036     {
1037       return 1;
1038     }
1039
1040   ERR ("Error while calling buxton_set_label: %m");
1041   return -1;
1042 }
1043
1044
1045 static int
1046 _apply_buxton_on_list_ (keylist_t * keylist,
1047                         int (*async) (keynode_t *, const char *),
1048                         const char *data)
1049 {
1050   keynode_t *keynode;
1051   int status;
1052   int sent;
1053
1054   assert (keylist != NULL);
1055
1056   status = _open_buxton_ ();
1057   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1058   assert (_buxton_ () != NULL);
1059
1060   retvm_if (keylist->cb_active != 0, VCONF_ERROR,
1061             "Already active in vconf-buxton");
1062
1063   LOCK(buxton);
1064
1065   keylist->cb_active = 1;
1066   keylist->cb_status = VCONF_OK;
1067   keylist->cb_sent = 0;
1068   keylist->cb_received = 0;
1069
1070   keynode = keylist->head;
1071   status = _dispatch_buxton_ (1, 0);
1072   while (keynode != NULL && status == VCONF_OK)
1073     {
1074       sent = async (keynode, data);
1075       keynode = keynode->next;
1076       if (sent < 0)
1077         {
1078           status = VCONF_ERROR;
1079         }
1080       else if (sent > 0)
1081         {
1082           keylist->cb_sent += sent;
1083           status = _dispatch_buxton_ (1, 0);
1084         }
1085     }
1086
1087   /*
1088    * get the responses 
1089    */
1090   while (status == VCONF_OK && keylist->cb_sent != keylist->cb_received)
1091     {
1092       status = _dispatch_buxton_ (0, 0);
1093     }
1094
1095   if (status == VCONF_OK && keylist->cb_status != VCONF_OK)
1096     status = keylist->cb_status;
1097   keylist->cb_active = 0;
1098
1099   UNLOCK(buxton);
1100
1101   _check_close_buxton_ ();
1102
1103   return status;
1104 }
1105
1106 /*================= SECTION notification =============*/
1107
1108 static void
1109 _cb_notify_ (BuxtonResponse resp, struct notify *notif)
1110 {
1111   switch (buxton_response_type (resp))
1112     {
1113     case BUXTON_CONTROL_NOTIFY:
1114     case BUXTON_CONTROL_UNNOTIFY:
1115       notif->status =
1116         buxton_response_status (resp) == 0 ? VCONF_OK : VCONF_ERROR;
1117       break;
1118     case BUXTON_CONTROL_CHANGED:
1119       if (_set_response_to_keynode_ (resp, notif->keynode, 1) == VCONF_OK)
1120         {
1121           UNLOCK (buxton);
1122           notif->callback (notif->keynode, notif->userdata);
1123           LOCK (buxton);
1124         }
1125       break;
1126     default:
1127       break;
1128     }
1129 }
1130
1131 static int
1132 _notify_reg_unreg_ (struct notify *notif, bool reg)
1133 {
1134   int status;
1135   BuxtonKey key;
1136
1137   status = _open_buxton_ ();
1138   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1139
1140   LOCK(buxton);
1141   key = _get_buxton_key_ (notif->keynode);
1142   retvm_if (key == NULL, VCONF_ERROR, "Can't create buxton key");
1143   notif->status = VCONF_OK;     /* on success calback isn't called! */
1144   status =
1145     (reg ? buxton_register_notification :
1146      buxton_unregister_notification) (_buxton_ (), key,
1147                                       (BuxtonCallback) _cb_notify_,
1148                                       notif, false);
1149   buxton_key_free (key);
1150   UNLOCK(buxton);
1151   return status == 0 && notif->status == VCONF_OK ? VCONF_OK : VCONF_ERROR;
1152 }
1153
1154 #if !defined(NO_GLIB)
1155 /*================= SECTION glib =============*/
1156
1157 static gboolean
1158 _cb_glib_ (GIOChannel * src, GIOCondition cond, gpointer data)
1159 {
1160   int status;
1161
1162   status = _handle_buxton_response_ (1);
1163   if (status < 0) {
1164     glib_source = NULL;
1165     return G_SOURCE_REMOVE;
1166   }
1167   return G_SOURCE_CONTINUE;
1168 }
1169
1170 static int
1171 _glib_start_watch_ ()
1172 {
1173   GIOChannel *gio;
1174
1175   if (glib_source != NULL)
1176     return VCONF_OK;
1177
1178   gio = g_io_channel_unix_new (the_buxton_client_fd);
1179   retvm_if (gio == NULL, VCONF_ERROR, "Error: create a new GIOChannel");
1180
1181   g_io_channel_set_flags (gio, G_IO_FLAG_NONBLOCK, NULL);
1182
1183   glib_source = g_io_create_watch (gio, G_IO_IN);
1184   if (glib_source == NULL)
1185     {
1186       ERR ("Error: create a new GSource");
1187       g_io_channel_unref (gio);
1188       return VCONF_ERROR;
1189     }
1190
1191   g_source_set_callback (glib_source, (GSourceFunc) _cb_glib_, NULL, NULL);
1192   g_source_attach (glib_source, NULL);
1193   g_io_channel_unref (gio);
1194   g_source_unref (glib_source);
1195
1196   return VCONF_OK;
1197 }
1198
1199 static void
1200 _glib_stop_watch_ ()
1201 {
1202   if (glib_source != NULL)
1203     {
1204       g_source_destroy (glib_source);
1205       glib_source = NULL;
1206     }
1207 }
1208 #endif
1209
1210 /*================= SECTION VCONF API =============*/
1211
1212 const char *
1213 vconf_keynode_get_name (keynode_t * keynode)
1214 {
1215   retvm_if (keynode == NULL, NULL, "Invalid argument: keynode is NULL");
1216   retvm_if (keynode->keyname == NULL, NULL, "The name of keynode is NULL");
1217
1218   return keynode->keyname;
1219 }
1220
1221 int
1222 vconf_keynode_get_type (keynode_t * keynode)
1223 {
1224   retvm_if (keynode == NULL,
1225             VCONF_ERROR, "Invalid argument: keynode is NULL");
1226
1227   switch (keynode->type)
1228     {
1229     case type_directory:
1230       return VCONF_TYPE_DIR;
1231     case type_string:
1232       return VCONF_TYPE_STRING;
1233     case type_int:
1234       return VCONF_TYPE_INT;
1235     case type_double:
1236       return VCONF_TYPE_DOUBLE;
1237     case type_bool:
1238       return VCONF_TYPE_BOOL;
1239     default:
1240       return VCONF_TYPE_NONE;
1241     }
1242 }
1243
1244 int
1245 vconf_keynode_get_int (keynode_t * keynode)
1246 {
1247   retvm_if (keynode == NULL,
1248             VCONF_ERROR, "Invalid argument: keynode is NULL");
1249   retvm_if (keynode->type != type_int, VCONF_ERROR,
1250             "The type of keynode(%s) is not INT", keynode->keyname);
1251
1252   return keynode->value.i;
1253 }
1254
1255 double
1256 vconf_keynode_get_dbl (keynode_t * keynode)
1257 {
1258   retvm_if (keynode == NULL, -1.0, "Invalid argument: keynode is NULL");
1259   retvm_if (keynode->type != type_double, -1.0,
1260             "The type of keynode(%s) is not DBL", keynode->keyname);
1261
1262   return keynode->value.d;
1263 }
1264
1265 int
1266 vconf_keynode_get_bool (keynode_t * keynode)
1267 {
1268   retvm_if (keynode == NULL,
1269             VCONF_ERROR, "Invalid argument: keynode is NULL");
1270   retvm_if (keynode->type != type_bool, VCONF_ERROR,
1271             "The type of keynode(%s) is not BOOL", keynode->keyname);
1272
1273   return !!(keynode->value.b);
1274 }
1275
1276 char *
1277 vconf_keynode_get_str (keynode_t * keynode)
1278 {
1279   retvm_if (keynode == NULL, NULL, "Invalid argument: keynode is NULL");
1280   retvm_if (keynode->type != type_string, NULL,
1281             "The type of keynode(%s) is not STR", keynode->keyname);
1282
1283   return keynode->value.s;
1284 }
1285
1286 int
1287 vconf_set_default_group (const char *groupname)
1288 {
1289   char *copy;
1290
1291   copy = _dup_groupname_ (groupname);
1292   if (copy == NULL)
1293     return VCONF_ERROR;
1294   free (default_group);
1295   default_group = copy;
1296   return VCONF_OK;
1297 }
1298
1299 keylist_t *
1300 vconf_keylist_new ()
1301 {
1302   keylist_t *result;
1303   if (_ensure_default_group_ () != VCONF_OK)
1304     return NULL;
1305   result = calloc (1, sizeof (keylist_t));
1306   LOCK (counter);
1307   internal_list_count += (result != NULL);
1308   UNLOCK (counter);
1309   return result;
1310 }
1311
1312 int
1313 vconf_keylist_free (keylist_t * keylist)
1314 {
1315   keynode_t *keynode, *temp;
1316
1317   retvm_if (keylist == NULL,
1318             VCONF_ERROR, "Invalid argument: keylist is NULL");
1319
1320   keynode = keylist->head;
1321   free (keylist);
1322   while (keynode)
1323     {
1324       temp = keynode->next;
1325       _keynode_free_ (keynode);
1326       keynode = temp;
1327     }
1328
1329   LOCK (counter);
1330   internal_list_count -= (internal_list_count > 0);
1331   UNLOCK (counter);
1332   _check_close_buxton_ ();
1333   return 0;
1334 }
1335
1336 int
1337 vconf_keylist_rewind (keylist_t * keylist)
1338 {
1339   retvm_if (keylist == NULL,
1340             VCONF_ERROR, "Invalid argument: keylist is NULL");
1341
1342   keylist->cursor = NULL;
1343
1344   return 0;
1345 }
1346
1347 keynode_t *
1348 vconf_keylist_nextnode (keylist_t * keylist)
1349 {
1350   keynode_t *result;
1351
1352   retvm_if (keylist == NULL, NULL, "Invalid argument: keylist is NULL");
1353
1354   result = keylist->cursor;
1355   result = result == NULL ? keylist->head : result->next;
1356   keylist->cursor = result;
1357
1358   return result;
1359 }
1360
1361 int
1362 vconf_keylist_lookup (keylist_t * keylist,
1363                       const char *keyname, keynode_t ** return_node)
1364 {
1365   keynode_t *keynode;
1366
1367   retvm_if (keylist == NULL,
1368             VCONF_ERROR, "Invalid argument: keylist is NULL");
1369   retvm_if (keyname == NULL,
1370             VCONF_ERROR, "Invalid argument: keyname is NULL");
1371   retvm_if (return_node == NULL,
1372             VCONF_ERROR, "Invalid argument: return_node is NULL");
1373
1374   keynode = _keylist_lookup_ (keylist, keyname, NULL);
1375   if (NULL == keynode)
1376     return 0;
1377
1378   if (return_node)
1379     *return_node = keynode;
1380   return keynode->type;
1381 }
1382
1383 static int
1384 _cb_sort_keynodes (const void *a, const void *b)
1385 {
1386   register const keynode_t *kna = *(const keynode_t **) a;
1387   register const keynode_t *knb = *(const keynode_t **) b;
1388   return strcmp (kna->keyname, knb->keyname);
1389 }
1390
1391 int
1392 vconf_keylist_sort (keylist_t * keylist)
1393 {
1394   int index;
1395   keynode_t **nodes, *keynode;
1396
1397   retvm_if (keylist == NULL,
1398             VCONF_ERROR, "Invalid argument: keylist is NULL");
1399
1400   if (keylist->num <= 1)
1401     return VCONF_OK;
1402
1403   nodes = malloc (keylist->num * sizeof *nodes);
1404   retvm_if (nodes == NULL, VCONF_ERROR, "can't allocate memory for sorting");
1405
1406   index = 0;
1407   keynode = keylist->head;
1408   while (keynode != NULL)
1409     {
1410       assert (index < keylist->num);
1411       nodes[index++] = keynode;
1412       keynode = keynode->next;
1413     }
1414   assert (index == keylist->num);
1415
1416   qsort (nodes, index, sizeof *nodes, _cb_sort_keynodes);
1417
1418   while (index)
1419     {
1420       nodes[--index]->next = keynode;
1421       keynode = nodes[index];
1422     }
1423   keylist->head = keynode;
1424   free (nodes);
1425   return VCONF_OK;
1426 }
1427
1428 int
1429 vconf_keylist_add_int (keylist_t * keylist, const char *keyname,
1430                        const int value)
1431 {
1432   keynode_t *keynode;
1433
1434   retvm_if (keylist == NULL,
1435             VCONF_ERROR, "Invalid argument: keylist is NULL");
1436   retvm_if (keyname == NULL,
1437             VCONF_ERROR, "Invalid argument: keyname is NULL");
1438
1439   keynode = _keylist_getadd_ (keylist, keyname, type_int);
1440   if (keynode == NULL)
1441     return VCONF_ERROR;
1442
1443   keynode->value.i = value;
1444   return keylist->num;
1445 }
1446
1447 int
1448 vconf_keylist_add_bool (keylist_t * keylist, const char *keyname,
1449                         const int value)
1450 {
1451   keynode_t *keynode;
1452
1453   retvm_if (keylist == NULL,
1454             VCONF_ERROR, "Invalid argument: keylist is NULL");
1455   retvm_if (keyname == NULL,
1456             VCONF_ERROR, "Invalid argument: keyname is NULL");
1457
1458   keynode = _keylist_getadd_ (keylist, keyname, type_bool);
1459   if (keynode == NULL)
1460     return VCONF_ERROR;
1461
1462   keynode->value.b = !!value;
1463   return keylist->num;
1464 }
1465
1466 int
1467 vconf_keylist_add_dbl (keylist_t * keylist,
1468                        const char *keyname, const double value)
1469 {
1470   keynode_t *keynode;
1471
1472   retvm_if (keylist == NULL, VCONF_ERROR,
1473             "Invalid argument: keylist is NULL");
1474   retvm_if (keyname == NULL, VCONF_ERROR,
1475             "Invalid argument: keyname is NULL");
1476
1477   keynode = _keylist_getadd_ (keylist, keyname, type_double);
1478   if (keynode == NULL)
1479     return VCONF_ERROR;
1480
1481   keynode->value.d = value;
1482   return keylist->num;
1483 }
1484
1485 int
1486 vconf_keylist_add_str (keylist_t * keylist,
1487                        const char *keyname, const char *value)
1488 {
1489   keynode_t *keynode;
1490   char *copy;
1491
1492   retvm_if (keylist == NULL, VCONF_ERROR,
1493             "Invalid argument: keylist is NULL");
1494   retvm_if (keyname == NULL, VCONF_ERROR,
1495             "Invalid argument: keyname is NULL");
1496
1497   copy = strdup (value == NULL ? "" : value);
1498   retvm_if (copy == NULL, VCONF_ERROR, "Allocation of memory failed");
1499
1500   keynode = _keylist_getadd_ (keylist, keyname, type_string);
1501   if (keynode == NULL)
1502     {
1503       free (copy);
1504       return VCONF_ERROR;
1505     }
1506
1507   free (keynode->value.s);
1508   keynode->value.s = copy;
1509   return keylist->num;
1510 }
1511
1512 int
1513 vconf_keylist_add_null (keylist_t * keylist, const char *keyname)
1514 {
1515   keynode_t *keynode;
1516
1517   retvm_if (keylist == NULL, VCONF_ERROR,
1518             "Invalid argument: keylist is NULL");
1519   retvm_if (keyname == NULL, VCONF_ERROR,
1520             "Invalid argument: keyname is NULL");
1521
1522   keynode = _keylist_getadd_ (keylist, keyname, type_unset);
1523   if (keynode == NULL)
1524     return VCONF_ERROR;
1525
1526   return keylist->num;
1527 }
1528
1529 int
1530 vconf_keylist_del (keylist_t * keylist, const char *keyname)
1531 {
1532   keynode_t *keynode, **previous = NULL;
1533
1534   retvm_if (keylist == NULL, VCONF_ERROR,
1535             "Invalid argument: keylist is NULL");
1536   retvm_if (keyname == NULL, VCONF_ERROR,
1537             "Invalid argument: keyname is NULL");
1538
1539   keynode = _keylist_lookup_ (keylist, keyname, &previous);
1540   if (keynode == NULL)
1541     return VCONF_ERROR;
1542
1543   *previous = keynode->next;
1544   keylist->num--;
1545   _keynode_free_ (keynode);
1546
1547   return VCONF_OK;
1548 }
1549
1550 int
1551 vconf_set (keylist_t * keylist)
1552 {
1553   retvm_if (keylist == NULL, VCONF_ERROR,
1554             "Invalid argument: keylist is NULL");
1555
1556   return _apply_buxton_on_list_ (keylist, _async_set_or_unset_, NULL);
1557 }
1558
1559 int
1560 vconf_set_labels (keylist_t * keylist, const char *label)
1561 {
1562   retvm_if (keylist == NULL, VCONF_ERROR,
1563             "Invalid argument: keylist is NULL");
1564
1565   retvm_if (label == NULL, VCONF_ERROR, "Invalid argument: name is NULL");
1566
1567   return _apply_buxton_on_list_ (keylist, _async_set_label_, label);
1568 }
1569
1570 int
1571 vconf_sync_key (const char *keyname)
1572 {
1573   /*
1574    * does nothing succefully 
1575    */
1576   return 0;
1577 }
1578
1579 int
1580 vconf_refresh (keylist_t * keylist)
1581 {
1582   retvm_if (keylist == NULL, VCONF_ERROR,
1583             "Invalid argument: keylist is NULL");
1584
1585   return _apply_buxton_on_list_ (keylist, _async_refresh_, NULL);
1586 }
1587
1588 int
1589 vconf_scan (keylist_t * keylist, const char *dirpath, get_option_t option)
1590 {
1591   char *dircopy;
1592   struct layer_key laykey;
1593   struct scanning_data data;
1594   int status;
1595
1596   retvm_if (keylist == NULL, VCONF_ERROR,
1597             "Invalid argument: keylist is null");
1598   retvm_if (keylist->num != 0, VCONF_ERROR,
1599             "Invalid argument: keylist not empty");
1600   retvm_if (dirpath == NULL, VCONF_ERROR,
1601             "Invalid argument: dirpath is null");
1602   retvm_if (_check_keyname_ (dirpath) == 0, VCONF_ERROR,
1603             "Invalid argument: dirpath is not valid");
1604
1605   status = _open_buxton_ ();
1606   if (!status)
1607     {
1608       ERR ("Can't connect to buxton");
1609       return VCONF_ERROR;
1610     }
1611
1612   data.keylist = keylist;
1613
1614   switch (option)
1615     {
1616     case VCONF_GET_KEY:
1617       data.want_directories = 0;
1618       data.want_keys = 1;
1619       data.is_recursive = 0;
1620       break;
1621     case VCONF_GET_ALL:
1622       data.want_directories = 1;
1623       data.want_keys = 1;
1624       data.is_recursive = 0;
1625       break;
1626     case VCONF_GET_DIR:
1627       data.want_directories = 1;
1628       data.want_keys = 0;
1629       data.is_recursive = 0;
1630       break;
1631     case VCONF_GET_KEY_REC:
1632       data.want_directories = 0;
1633       data.want_keys = 1;
1634       data.is_recursive = 1;
1635       break;
1636     case VCONF_GET_ALL_REC:
1637       data.want_directories = 1;
1638       data.want_keys = 1;
1639       data.is_recursive = 1;
1640       break;
1641     case VCONF_GET_DIR_REC:
1642       data.want_directories = 0;
1643       data.want_keys = 1;
1644       data.is_recursive = 1;
1645       break;
1646     default:
1647       ERR ("Invalid argument: Bad option value");
1648       return VCONF_ERROR;
1649     }
1650
1651   data.dirlen = strlen (dirpath);
1652   assert (data.dirlen);
1653   if (dirpath[data.dirlen - 1] == '/')
1654     {
1655       data.directory = dirpath;
1656       dircopy = NULL;
1657     }
1658   else
1659     {
1660       status = asprintf (&dircopy, "%s/", dirpath);
1661       retvm_if (status < 0, VCONF_ERROR,
1662                 "No more memory for copying dirpath");
1663       data.directory = dircopy;
1664       data.dirlen++;
1665     }
1666
1667   status = _get_layer_key_ (data.directory, &laykey);
1668   if (status != VCONF_OK)
1669     {
1670       return status;
1671     }
1672
1673   data.prefix = laykey.prefix;
1674   if (!laykey.key[0])
1675     {
1676       laykey.key = NULL;
1677     }
1678
1679   data.pending = 1;
1680   assert (_buxton_ () != NULL);
1681   status = buxton_list_names (_buxton_ (), laykey.layer, default_group,
1682                               laykey.key, (BuxtonCallback) _cb_scan_,
1683                               &data, false);
1684   if (!status)
1685     status = _wait_buxton_response_ (&data.pending);
1686
1687   free (dircopy);
1688
1689   retvm_if (status, VCONF_ERROR, "Error while calling buxton_list_names: %m");
1690   if (data.cb_status != VCONF_OK)
1691     {
1692       return VCONF_ERROR;
1693     }
1694
1695   return vconf_refresh (keylist);
1696 }
1697
1698 int
1699 vconf_get (keylist_t * keylist, const char *dirpath, get_option_t option)
1700 {
1701   if (option == VCONF_REFRESH_ONLY
1702       || (option == VCONF_GET_KEY && keylist->num != 0))
1703     {
1704       return vconf_refresh (keylist);
1705     }
1706   else
1707     {
1708       return vconf_scan (keylist, dirpath, option);
1709     }
1710 }
1711
1712 int
1713 vconf_unset (const char *keyname)
1714 {
1715   struct singleton single;
1716   int status;
1717
1718   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1719
1720   status = _keylist_init_singleton_ (&single, keyname, type_delete);
1721   if (status == VCONF_OK)
1722     {
1723       status = vconf_set (&single.list);
1724     }
1725   return status;
1726
1727 }
1728
1729 int
1730 vconf_exists (const char *keyname)
1731 {
1732   struct singleton single;
1733   int status;
1734
1735   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1736
1737   status = _keylist_init_singleton_ (&single, keyname, type_unset);
1738   if (status == VCONF_OK)
1739     {
1740       status = vconf_refresh (&single.list);
1741       if (status == VCONF_OK && single.node.type == type_string)
1742         free (single.node.value.s);
1743     }
1744   return status;
1745
1746 }
1747
1748 int
1749 vconf_unset_recursive (const char *in_dir)
1750 {
1751   struct _keylist_t *keylist;
1752   struct _keynode_t *keynode;
1753   int status;
1754
1755   retvm_if (in_dir == NULL, VCONF_ERROR, "Invalid argument: dir is null");
1756
1757   keylist = vconf_keylist_new ();
1758   if (keylist == NULL)
1759     return VCONF_ERROR;
1760
1761   status = vconf_scan (keylist, in_dir, VCONF_GET_KEY_REC);
1762   if (status == VCONF_OK)
1763     {
1764       for (keynode = keylist->head; keynode; keynode = keynode->next)
1765         keynode->type = type_delete;
1766       status = vconf_set (keylist);
1767     }
1768   vconf_keylist_free (keylist);
1769   return status;
1770 }
1771
1772 int
1773 vconf_notify_key_changed (const char *keyname, vconf_callback_fn cb,
1774                           void *user_data)
1775 {
1776   int status;
1777   struct notify *notif;
1778   keynode_t *keynode, *aknode;
1779   keylist_t *alist;
1780
1781   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is null");
1782   retvm_if (cb == NULL, VCONF_ERROR, "Invalid argument: cb(%p)", cb);
1783   status = _open_buxton_ ();
1784   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1785   status = vconf_exists (keyname);
1786   retvm_if (status != VCONF_OK, VCONF_ERROR, "key %s doesn't exist", keyname);
1787
1788
1789   /*
1790    * create the notification 
1791    */
1792   notif = malloc (sizeof *notif);
1793   retvm_if (notif == NULL, VCONF_ERROR,
1794             "Allocation of notify structure failed");
1795
1796   /*
1797    * ensure existing list 
1798    */
1799   LOCK (notify);
1800   if (notify_keylist == NULL)
1801     {
1802       notify_keylist = vconf_keylist_new ();
1803       if (notify_keylist == NULL)
1804         {
1805           UNLOCK (notify);
1806           free (notif);
1807           return VCONF_ERROR;
1808         }
1809     }
1810
1811   /*
1812    * search keynode of keyname 
1813    */
1814   keynode = _keylist_lookup_ (notify_keylist, keyname, NULL);
1815   if (keynode == NULL)
1816     {
1817       /*
1818        * not found, create it with type unset 
1819        */
1820       keynode = _keylist_add_ (notify_keylist, keyname, type_unset);
1821       if (keynode == NULL)
1822         {
1823           UNLOCK (notify);
1824           free (notif);
1825           return VCONF_ERROR;
1826         }
1827     }
1828
1829   /*
1830    * init the notification 
1831    */
1832   notif->callback = cb;
1833   notif->userdata = user_data;
1834   notif->keynode = keynode;
1835   notif->next = notify_entries;
1836   notify_entries = notif;
1837   UNLOCK (notify);
1838
1839   /*
1840    * record the notification 
1841    */
1842   status = _notify_reg_unreg_ (notif, true);
1843   if (status != VCONF_OK)
1844     {
1845       vconf_ignore_key_changed (keyname, cb);
1846       return VCONF_ERROR;
1847     }
1848
1849 #if !defined(NO_GLIB)
1850   return _glib_start_watch_ ();
1851 #else
1852   return VCONF_OK;
1853 #endif
1854 }
1855
1856 int
1857 vconf_ignore_key_changed (const char *keyname, vconf_callback_fn cb)
1858 {
1859   struct notify *entry, **prevent, *delent, **prevdelent;
1860   keynode_t *keynode, **prevnod;
1861   int fcount;
1862   int status;
1863
1864   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is null");
1865   retvm_if (cb == NULL, VCONF_ERROR, "Invalid argument: cb(%p)", cb);
1866   status = _open_buxton_ ();
1867   retvm_if (!status, VCONF_ERROR, "Can't connect to buxton");
1868
1869   fcount = 0;
1870   status = VCONF_ERROR;
1871   delent = NULL;
1872
1873   LOCK (notify);
1874   if (notify_keylist != NULL)
1875     {
1876       keynode = _keylist_lookup_ (notify_keylist, keyname, &prevnod);
1877       if (keynode != NULL)
1878         {
1879           prevdelent = &delent;
1880           prevent = &notify_entries;
1881           entry = notify_entries;
1882           while (entry != NULL)
1883             {
1884               if (entry->keynode == keynode)
1885                 {
1886                   if (entry->callback == cb)
1887                     {
1888                       *prevdelent = entry;
1889                       prevdelent = &entry->next;
1890                       entry = entry->next;
1891                       continue;
1892                     }
1893                   fcount++;
1894                 }
1895               *prevent = entry;
1896               prevent = &entry->next;
1897               entry = entry->next;
1898             }
1899           *prevent = NULL;
1900           *prevdelent = NULL;
1901           if (fcount == 0)
1902             *prevnod = keynode->next;
1903 #if !defined(NO_GLIB)
1904           if (notify_entries == NULL)
1905             _glib_stop_watch_ ();
1906 #endif
1907           if (delent != NULL)
1908             {
1909               UNLOCK (notify);
1910               while (delent != NULL)
1911                 {
1912                   entry = delent;
1913                   delent = entry->next;
1914                   _notify_reg_unreg_ (entry, false);
1915                   free (entry);
1916                 }
1917               if (fcount == 0)
1918                 _keynode_free_ (keynode);
1919               return VCONF_OK;
1920             }
1921         }
1922     }
1923   UNLOCK (notify);
1924   ERR ("Not found: can't remove notification for key(%s)", keyname);
1925
1926   return VCONF_ERROR;
1927 }
1928
1929 int
1930 vconf_set_int (const char *keyname, const int intval)
1931 {
1932   struct singleton single;
1933   int status;
1934
1935   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1936
1937   status = _keylist_init_singleton_ (&single, keyname, type_int);
1938   if (status == VCONF_OK)
1939     {
1940       single.node.value.i = intval;
1941       status = vconf_set (&single.list);
1942     }
1943   return status;
1944 }
1945
1946 int
1947 vconf_set_bool (const char *keyname, const int boolval)
1948 {
1949   struct singleton single;
1950   int status;
1951
1952   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1953
1954   status = _keylist_init_singleton_ (&single, keyname, type_bool);
1955   if (status == VCONF_OK)
1956     {
1957       single.node.value.b = (bool) boolval;
1958       status = vconf_set (&single.list);
1959     }
1960   return status;
1961 }
1962
1963 int
1964 vconf_set_dbl (const char *keyname, const double dblval)
1965 {
1966   struct singleton single;
1967   int status;
1968
1969   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1970
1971   status = _keylist_init_singleton_ (&single, keyname, type_double);
1972   if (status == VCONF_OK)
1973     {
1974       single.node.value.d = dblval;
1975       status = vconf_set (&single.list);
1976     }
1977   return status;
1978 }
1979
1980 int
1981 vconf_set_str (const char *keyname, const char *strval)
1982 {
1983   struct singleton single;
1984   int status;
1985
1986   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
1987
1988   status = _keylist_init_singleton_ (&single, keyname, type_string);
1989   if (status == VCONF_OK)
1990     {
1991       single.node.value.s = (char *) strval;
1992       status = vconf_set (&single.list);
1993     }
1994   return status;
1995 }
1996
1997 int
1998 vconf_get_int (const char *keyname, int *intval)
1999 {
2000   struct singleton single;
2001   int status;
2002
2003   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
2004
2005   status = _keylist_init_singleton_ (&single, keyname, type_int);
2006   if (status == VCONF_OK)
2007     {
2008       status = vconf_refresh (&single.list);
2009       if (status == VCONF_OK)
2010         *intval = single.node.value.i;
2011     }
2012   return status;
2013 }
2014
2015 int
2016 vconf_set_label (const char *keyname, const char *label)
2017 {
2018   struct singleton single;
2019   int status;
2020
2021   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
2022
2023   retvm_if (label == NULL, VCONF_ERROR, "Invalid argument: name is NULL");
2024
2025   status = _keylist_init_singleton_ (&single, keyname, type_unset);
2026   if (status == VCONF_OK)
2027     {
2028       status = vconf_set_labels (&single.list, label);
2029     }
2030   return status;
2031 }
2032
2033 int
2034 vconf_get_bool (const char *keyname, int *boolval)
2035 {
2036   struct singleton single;
2037   int status;
2038
2039   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
2040
2041   status = _keylist_init_singleton_ (&single, keyname, type_bool);
2042   if (status == VCONF_OK)
2043     {
2044       status = vconf_refresh (&single.list);
2045       if (status == VCONF_OK)
2046         *boolval = (int) single.node.value.b;
2047     }
2048   return status;
2049 }
2050
2051 int
2052 vconf_get_dbl (const char *keyname, double *dblval)
2053 {
2054   struct singleton single;
2055   int status;
2056
2057   retvm_if (keyname == NULL, VCONF_ERROR, "Invalid argument: key is NULL");
2058
2059   status = _keylist_init_singleton_ (&single, keyname, type_double);
2060   if (status == VCONF_OK)
2061     {
2062       status = vconf_refresh (&single.list);
2063       if (status == VCONF_OK)
2064         *dblval = single.node.value.d;
2065     }
2066   return status;
2067 }
2068
2069 char *
2070 vconf_get_str (const char *keyname)
2071 {
2072   struct singleton single;
2073   int status;
2074
2075   retvm_if (keyname == NULL, NULL, "Invalid argument: key is NULL");
2076
2077   status = _keylist_init_singleton_ (&single, keyname, type_string);
2078   if (status != VCONF_OK)
2079     return NULL;
2080
2081   single.node.value.s = NULL;
2082   status = vconf_refresh (&single.list);
2083   if (status != VCONF_OK)
2084     return NULL;
2085
2086   return single.node.value.s;
2087 }