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