4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
32 #include <sys/types.h>
44 PurplePrefCallback func
;
50 /* TODO: This should use PurpleValues? */
62 struct purple_pref
*parent
;
63 struct purple_pref
*sibling
;
64 struct purple_pref
*first_child
;
68 static struct purple_pref prefs
= {
78 static GHashTable
*prefs_hash
= NULL
;
79 static guint save_timer
= 0;
80 static gboolean prefs_loaded
= FALSE
;
83 /*********************************************************************
84 * Private utility functions *
85 *********************************************************************/
88 purple_pref
*find_pref(const char *name
)
90 g_return_val_if_fail(name
!= NULL
&& name
[0] == '/', NULL
);
96 /* When we're initializing, the debug system is
97 * initialized before the prefs system, but debug
98 * calls will end up calling prefs functions, so we
99 * need to deal cleanly here. */
101 return g_hash_table_lookup(prefs_hash
, name
);
108 /*********************************************************************
110 *********************************************************************/
113 * This function recursively creates the xmlnode tree from the prefs
114 * tree structure. Yay recursion!
117 pref_to_xmlnode(xmlnode
*parent
, struct purple_pref
*pref
)
119 xmlnode
*node
, *childnode
;
120 struct purple_pref
*child
;
124 /* Create a new node */
125 node
= xmlnode_new_child(parent
, "pref");
126 xmlnode_set_attrib(node
, "name", pref
->name
);
128 /* Set the type of this node (if type == PURPLE_PREF_NONE then do nothing) */
129 if (pref
->type
== PURPLE_PREF_INT
) {
130 xmlnode_set_attrib(node
, "type", "int");
131 g_snprintf(buf
, sizeof(buf
), "%d", pref
->value
.integer
);
132 xmlnode_set_attrib(node
, "value", buf
);
134 else if (pref
->type
== PURPLE_PREF_STRING
) {
135 xmlnode_set_attrib(node
, "type", "string");
136 xmlnode_set_attrib(node
, "value", pref
->value
.string
? pref
->value
.string
: "");
138 else if (pref
->type
== PURPLE_PREF_STRING_LIST
) {
139 xmlnode_set_attrib(node
, "type", "stringlist");
140 for (cur
= pref
->value
.stringlist
; cur
!= NULL
; cur
= cur
->next
)
142 childnode
= xmlnode_new_child(node
, "item");
143 xmlnode_set_attrib(childnode
, "value", cur
->data
? cur
->data
: "");
146 else if (pref
->type
== PURPLE_PREF_PATH
) {
147 char *encoded
= g_filename_to_utf8(pref
->value
.string
? pref
->value
.string
: "", -1, NULL
, NULL
, NULL
);
148 xmlnode_set_attrib(node
, "type", "path");
149 xmlnode_set_attrib(node
, "value", encoded
);
152 else if (pref
->type
== PURPLE_PREF_PATH_LIST
) {
153 xmlnode_set_attrib(node
, "type", "pathlist");
154 for (cur
= pref
->value
.stringlist
; cur
!= NULL
; cur
= cur
->next
)
156 char *encoded
= g_filename_to_utf8(cur
->data
? cur
->data
: "", -1, NULL
, NULL
, NULL
);
157 childnode
= xmlnode_new_child(node
, "item");
158 xmlnode_set_attrib(childnode
, "value", encoded
);
162 else if (pref
->type
== PURPLE_PREF_BOOLEAN
) {
163 xmlnode_set_attrib(node
, "type", "bool");
164 g_snprintf(buf
, sizeof(buf
), "%d", pref
->value
.boolean
);
165 xmlnode_set_attrib(node
, "value", buf
);
168 /* All My Children */
169 for (child
= pref
->first_child
; child
!= NULL
; child
= child
->sibling
)
170 pref_to_xmlnode(node
, child
);
174 prefs_to_xmlnode(void)
177 struct purple_pref
*pref
, *child
;
181 /* Create the root preference node */
182 node
= xmlnode_new("pref");
183 xmlnode_set_attrib(node
, "version", "1");
184 xmlnode_set_attrib(node
, "name", "/");
186 /* All My Children */
187 for (child
= pref
->first_child
; child
!= NULL
; child
= child
->sibling
)
188 pref_to_xmlnode(node
, child
);
202 * TODO: Call schedule_prefs_save()? Ideally we wouldn't need to.
203 * (prefs.xml should be loaded when purple_prefs_init is called)
205 purple_debug_error("prefs", "Attempted to save prefs before "
206 "they were read!\n");
210 node
= prefs_to_xmlnode();
211 data
= xmlnode_to_formatted_str(node
, NULL
);
212 purple_util_write_data_to_file("prefs.xml", data
, -1);
218 save_cb(gpointer data
)
226 schedule_prefs_save(void)
229 save_timer
= purple_timeout_add_seconds(5, save_cb
, NULL
);
233 /*********************************************************************
234 * Reading from disk *
235 *********************************************************************/
237 static GList
*prefs_stack
= NULL
;
240 prefs_start_element_handler (GMarkupParseContext
*context
,
241 const gchar
*element_name
,
242 const gchar
**attribute_names
,
243 const gchar
**attribute_values
,
247 PurplePrefType pref_type
= PURPLE_PREF_NONE
;
249 const char *pref_name
= NULL
, *pref_value
= NULL
;
250 GString
*pref_name_full
;
253 if(!purple_strequal(element_name
, "pref") &&
254 !purple_strequal(element_name
, "item"))
257 for(i
= 0; attribute_names
[i
]; i
++) {
258 if(purple_strequal(attribute_names
[i
], "name")) {
259 pref_name
= attribute_values
[i
];
260 } else if(purple_strequal(attribute_names
[i
], "type")) {
261 if(purple_strequal(attribute_values
[i
], "bool"))
262 pref_type
= PURPLE_PREF_BOOLEAN
;
263 else if(purple_strequal(attribute_values
[i
], "int"))
264 pref_type
= PURPLE_PREF_INT
;
265 else if(purple_strequal(attribute_values
[i
], "string"))
266 pref_type
= PURPLE_PREF_STRING
;
267 else if(purple_strequal(attribute_values
[i
], "stringlist"))
268 pref_type
= PURPLE_PREF_STRING_LIST
;
269 else if(purple_strequal(attribute_values
[i
], "path"))
270 pref_type
= PURPLE_PREF_PATH
;
271 else if(purple_strequal(attribute_values
[i
], "pathlist"))
272 pref_type
= PURPLE_PREF_PATH_LIST
;
275 } else if(purple_strequal(attribute_names
[i
], "value")) {
276 pref_value
= attribute_values
[i
];
280 if(purple_strequal(element_name
, "item")) {
281 struct purple_pref
*pref
;
283 pref_name_full
= g_string_new("");
285 for(tmp
= prefs_stack
; tmp
; tmp
= tmp
->next
) {
286 pref_name_full
= g_string_prepend(pref_name_full
, tmp
->data
);
287 pref_name_full
= g_string_prepend_c(pref_name_full
, '/');
290 pref
= find_pref(pref_name_full
->str
);
293 if(pref
->type
== PURPLE_PREF_STRING_LIST
) {
294 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
295 g_strdup(pref_value
));
296 } else if(pref
->type
== PURPLE_PREF_PATH_LIST
) {
297 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
298 g_filename_from_utf8(pref_value
, -1, NULL
, NULL
, NULL
));
301 g_string_free(pref_name_full
, TRUE
);
305 if(!pref_name
|| purple_strequal(pref_name
, "/"))
308 pref_name_full
= g_string_new(pref_name
);
310 for(tmp
= prefs_stack
; tmp
; tmp
= tmp
->next
) {
311 pref_name_full
= g_string_prepend_c(pref_name_full
, '/');
312 pref_name_full
= g_string_prepend(pref_name_full
, tmp
->data
);
315 pref_name_full
= g_string_prepend_c(pref_name_full
, '/');
318 case PURPLE_PREF_NONE
:
319 purple_prefs_add_none(pref_name_full
->str
);
321 case PURPLE_PREF_BOOLEAN
:
322 purple_prefs_set_bool(pref_name_full
->str
, atoi(pref_value
));
324 case PURPLE_PREF_INT
:
325 purple_prefs_set_int(pref_name_full
->str
, atoi(pref_value
));
327 case PURPLE_PREF_STRING
:
328 purple_prefs_set_string(pref_name_full
->str
, pref_value
);
330 case PURPLE_PREF_STRING_LIST
:
331 purple_prefs_set_string_list(pref_name_full
->str
, NULL
);
333 case PURPLE_PREF_PATH
:
335 decoded
= g_filename_from_utf8(pref_value
, -1, NULL
, NULL
, NULL
);
336 purple_prefs_set_path(pref_name_full
->str
, decoded
);
339 purple_prefs_set_path(pref_name_full
->str
, NULL
);
342 case PURPLE_PREF_PATH_LIST
:
343 purple_prefs_set_path_list(pref_name_full
->str
, NULL
);
346 prefs_stack
= g_list_prepend(prefs_stack
, g_strdup(pref_name
));
347 g_string_free(pref_name_full
, TRUE
);
352 prefs_end_element_handler(GMarkupParseContext
*context
,
353 const gchar
*element_name
,
354 gpointer user_data
, GError
**error
)
356 if(prefs_stack
&& purple_strequal(element_name
, "pref")) {
357 g_free(prefs_stack
->data
);
358 prefs_stack
= g_list_delete_link(prefs_stack
, prefs_stack
);
362 static GMarkupParser prefs_parser
= {
363 prefs_start_element_handler
,
364 prefs_end_element_handler
,
373 gchar
*filename
= g_build_filename(purple_user_dir(), "prefs.xml", NULL
);
374 gchar
*contents
= NULL
;
376 GMarkupParseContext
*context
;
377 GError
*error
= NULL
;
384 purple_debug_info("prefs", "Reading %s\n", filename
);
386 if(!g_file_get_contents(filename
, &contents
, &length
, &error
)) {
388 gchar
*common_appdata
= wpurple_get_special_folder(CSIDL_COMMON_APPDATA
);
396 filename
= g_build_filename(common_appdata
? common_appdata
: "", "purple", "prefs.xml", NULL
);
397 g_free(common_appdata
);
399 filename
= g_build_filename(SYSCONFDIR
, "purple", "prefs.xml", NULL
);
402 purple_debug_info("prefs", "Reading %s\n", filename
);
404 if (!g_file_get_contents(filename
, &contents
, &length
, &error
)) {
405 purple_debug_error("prefs", "Error reading prefs: %s\n",
415 context
= g_markup_parse_context_new(&prefs_parser
, 0, NULL
, NULL
);
417 if(!g_markup_parse_context_parse(context
, contents
, length
, NULL
)) {
418 g_markup_parse_context_free(context
);
426 if(!g_markup_parse_context_end_parse(context
, NULL
)) {
427 purple_debug_error("prefs", "Error parsing %s\n", filename
);
428 g_markup_parse_context_free(context
);
436 purple_debug_info("prefs", "Finished reading %s\n", filename
);
437 g_markup_parse_context_free(context
);
448 prefs_save_cb(const char *name
, PurplePrefType type
, gconstpointer val
,
455 purple_debug_misc("prefs", "%s changed, scheduling save.\n", name
);
457 schedule_prefs_save();
461 get_path_dirname(const char *name
)
465 str
= g_strdup(name
);
467 if ((c
= strrchr(str
, '/')) != NULL
) {
486 get_path_basename(const char *name
)
490 if ((c
= strrchr(name
, '/')) != NULL
)
491 return g_strdup(c
+ 1);
493 return g_strdup(name
);
497 pref_full_name(struct purple_pref
*pref
)
500 struct purple_pref
*parent
;
506 return g_strdup("/");
508 name
= g_string_new(pref
->name
);
510 for(parent
= pref
->parent
; parent
&& parent
->name
; parent
= parent
->parent
) {
511 name
= g_string_prepend_c(name
, '/');
512 name
= g_string_prepend(name
, parent
->name
);
514 name
= g_string_prepend_c(name
, '/');
515 return g_string_free(name
, FALSE
);
518 static struct purple_pref
*
519 find_pref_parent(const char *name
)
521 char *parent_name
= get_path_dirname(name
);
522 struct purple_pref
*ret
= &prefs
;
524 if(!purple_strequal(parent_name
, "/")) {
525 ret
= find_pref(parent_name
);
533 free_pref_value(struct purple_pref
*pref
)
536 case PURPLE_PREF_BOOLEAN
:
537 pref
->value
.boolean
= FALSE
;
539 case PURPLE_PREF_INT
:
540 pref
->value
.integer
= 0;
542 case PURPLE_PREF_STRING
:
543 case PURPLE_PREF_PATH
:
544 g_free(pref
->value
.string
);
545 pref
->value
.string
= NULL
;
547 case PURPLE_PREF_STRING_LIST
:
548 case PURPLE_PREF_PATH_LIST
:
550 g_list_foreach(pref
->value
.stringlist
, (GFunc
)g_free
, NULL
);
551 g_list_free(pref
->value
.stringlist
);
553 case PURPLE_PREF_NONE
:
558 static struct purple_pref
*
559 add_pref(PurplePrefType type
, const char *name
)
561 struct purple_pref
*parent
;
562 struct purple_pref
*me
;
563 struct purple_pref
*sibling
;
566 parent
= find_pref_parent(name
);
571 my_name
= get_path_basename(name
);
573 for(sibling
= parent
->first_child
; sibling
; sibling
= sibling
->sibling
) {
574 if(purple_strequal(sibling
->name
, my_name
)) {
580 me
= g_new0(struct purple_pref
, 1);
585 if(parent
->first_child
) {
586 /* blatant abuse of a for loop */
587 for(sibling
= parent
->first_child
; sibling
->sibling
;
588 sibling
= sibling
->sibling
);
589 sibling
->sibling
= me
;
591 parent
->first_child
= me
;
594 g_hash_table_insert(prefs_hash
, g_strdup(name
), (gpointer
)me
);
600 purple_prefs_add_none(const char *name
)
602 add_pref(PURPLE_PREF_NONE
, name
);
606 purple_prefs_add_bool(const char *name
, gboolean value
)
608 struct purple_pref
*pref
= add_pref(PURPLE_PREF_BOOLEAN
, name
);
613 pref
->value
.boolean
= value
;
617 purple_prefs_add_int(const char *name
, int value
)
619 struct purple_pref
*pref
= add_pref(PURPLE_PREF_INT
, name
);
624 pref
->value
.integer
= value
;
628 purple_prefs_add_string(const char *name
, const char *value
)
630 struct purple_pref
*pref
;
632 if(value
!= NULL
&& !g_utf8_validate(value
, -1, NULL
)) {
633 purple_debug_error("prefs", "purple_prefs_add_string: Cannot store invalid UTF8 for string pref %s\n", name
);
637 pref
= add_pref(PURPLE_PREF_STRING
, name
);
642 pref
->value
.string
= g_strdup(value
);
646 purple_prefs_add_string_list(const char *name
, GList
*value
)
648 struct purple_pref
*pref
= add_pref(PURPLE_PREF_STRING_LIST
, name
);
654 for(tmp
= value
; tmp
; tmp
= tmp
->next
) {
655 if(tmp
->data
!= NULL
&& !g_utf8_validate(tmp
->data
, -1, NULL
)) {
656 purple_debug_error("prefs", "purple_prefs_add_string_list: Skipping invalid UTF8 for string list pref %s\n", name
);
659 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
660 g_strdup(tmp
->data
));
665 purple_prefs_add_path(const char *name
, const char *value
)
667 struct purple_pref
*pref
= add_pref(PURPLE_PREF_PATH
, name
);
672 pref
->value
.string
= g_strdup(value
);
676 purple_prefs_add_path_list(const char *name
, GList
*value
)
678 struct purple_pref
*pref
= add_pref(PURPLE_PREF_PATH_LIST
, name
);
684 for(tmp
= value
; tmp
; tmp
= tmp
->next
)
685 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
686 g_strdup(tmp
->data
));
691 remove_pref(struct purple_pref
*pref
)
699 while(pref
->first_child
)
700 remove_pref(pref
->first_child
);
705 if(pref
->parent
->first_child
== pref
) {
706 pref
->parent
->first_child
= pref
->sibling
;
708 struct purple_pref
*sib
= pref
->parent
->first_child
;
709 while(sib
&& sib
->sibling
!= pref
)
712 sib
->sibling
= pref
->sibling
;
715 name
= pref_full_name(pref
);
718 purple_debug_info("prefs", "removing pref %s\n", name
);
720 g_hash_table_remove(prefs_hash
, name
);
723 free_pref_value(pref
);
725 while((l
= pref
->callbacks
) != NULL
) {
726 pref
->callbacks
= pref
->callbacks
->next
;
735 purple_prefs_remove(const char *name
)
737 struct purple_pref
*pref
= find_pref(name
);
746 purple_prefs_destroy()
748 purple_prefs_remove("/");
752 do_callbacks(const char* name
, struct purple_pref
*pref
)
755 struct purple_pref
*cb_pref
;
756 for(cb_pref
= pref
; cb_pref
; cb_pref
= cb_pref
->parent
) {
757 for(cbs
= cb_pref
->callbacks
; cbs
; cbs
= cbs
->next
) {
758 struct pref_cb
*cb
= cbs
->data
;
759 cb
->func(name
, pref
->type
, pref
->value
.generic
, cb
->data
);
765 purple_prefs_trigger_callback(const char *name
)
767 struct purple_pref
*pref
= find_pref(name
);
770 purple_debug_error("prefs",
771 "purple_prefs_trigger_callback: Unknown pref %s\n", name
);
775 do_callbacks(name
, pref
);
779 purple_prefs_set_generic(const char *name
, gpointer value
)
781 struct purple_pref
*pref
= find_pref(name
);
784 purple_debug_error("prefs",
785 "purple_prefs_set_generic: Unknown pref %s\n", name
);
789 pref
->value
.generic
= value
;
790 do_callbacks(name
, pref
);
794 purple_prefs_set_bool(const char *name
, gboolean value
)
796 struct purple_pref
*pref
= find_pref(name
);
799 if(pref
->type
!= PURPLE_PREF_BOOLEAN
) {
800 purple_debug_error("prefs",
801 "purple_prefs_set_bool: %s not a boolean pref\n", name
);
805 if(pref
->value
.boolean
!= value
) {
806 pref
->value
.boolean
= value
;
807 do_callbacks(name
, pref
);
810 purple_prefs_add_bool(name
, value
);
815 purple_prefs_set_int(const char *name
, int value
)
817 struct purple_pref
*pref
= find_pref(name
);
820 if(pref
->type
!= PURPLE_PREF_INT
) {
821 purple_debug_error("prefs",
822 "purple_prefs_set_int: %s not an integer pref\n", name
);
826 if(pref
->value
.integer
!= value
) {
827 pref
->value
.integer
= value
;
828 do_callbacks(name
, pref
);
831 purple_prefs_add_int(name
, value
);
836 purple_prefs_set_string(const char *name
, const char *value
)
838 struct purple_pref
*pref
= find_pref(name
);
840 if(value
!= NULL
&& !g_utf8_validate(value
, -1, NULL
)) {
841 purple_debug_error("prefs", "purple_prefs_set_string: Cannot store invalid UTF8 for string pref %s\n", name
);
846 if(pref
->type
!= PURPLE_PREF_STRING
&& pref
->type
!= PURPLE_PREF_PATH
) {
847 purple_debug_error("prefs",
848 "purple_prefs_set_string: %s not a string pref\n", name
);
852 if (!purple_strequal(pref
->value
.string
, value
)) {
853 g_free(pref
->value
.string
);
854 pref
->value
.string
= g_strdup(value
);
855 do_callbacks(name
, pref
);
858 purple_prefs_add_string(name
, value
);
863 purple_prefs_set_string_list(const char *name
, GList
*value
)
865 struct purple_pref
*pref
= find_pref(name
);
869 if(pref
->type
!= PURPLE_PREF_STRING_LIST
) {
870 purple_debug_error("prefs",
871 "purple_prefs_set_string_list: %s not a string list pref\n",
876 g_list_foreach(pref
->value
.stringlist
, (GFunc
)g_free
, NULL
);
877 g_list_free(pref
->value
.stringlist
);
878 pref
->value
.stringlist
= NULL
;
880 for(tmp
= value
; tmp
; tmp
= tmp
->next
) {
881 if(tmp
->data
!= NULL
&& !g_utf8_validate(tmp
->data
, -1, NULL
)) {
882 purple_debug_error("prefs", "purple_prefs_set_string_list: Skipping invalid UTF8 for string list pref %s\n", name
);
885 pref
->value
.stringlist
= g_list_prepend(pref
->value
.stringlist
,
886 g_strdup(tmp
->data
));
888 pref
->value
.stringlist
= g_list_reverse(pref
->value
.stringlist
);
890 do_callbacks(name
, pref
);
893 purple_prefs_add_string_list(name
, value
);
898 purple_prefs_set_path(const char *name
, const char *value
)
900 struct purple_pref
*pref
= find_pref(name
);
903 if(pref
->type
!= PURPLE_PREF_PATH
) {
904 purple_debug_error("prefs",
905 "purple_prefs_set_path: %s not a path pref\n", name
);
909 if (!purple_strequal(pref
->value
.string
, value
)) {
910 g_free(pref
->value
.string
);
911 pref
->value
.string
= g_strdup(value
);
912 do_callbacks(name
, pref
);
915 purple_prefs_add_path(name
, value
);
920 purple_prefs_set_path_list(const char *name
, GList
*value
)
922 struct purple_pref
*pref
= find_pref(name
);
926 if(pref
->type
!= PURPLE_PREF_PATH_LIST
) {
927 purple_debug_error("prefs",
928 "purple_prefs_set_path_list: %s not a path list pref\n",
933 g_list_foreach(pref
->value
.stringlist
, (GFunc
)g_free
, NULL
);
934 g_list_free(pref
->value
.stringlist
);
935 pref
->value
.stringlist
= NULL
;
937 for(tmp
= value
; tmp
; tmp
= tmp
->next
)
938 pref
->value
.stringlist
= g_list_prepend(pref
->value
.stringlist
,
939 g_strdup(tmp
->data
));
940 pref
->value
.stringlist
= g_list_reverse(pref
->value
.stringlist
);
942 do_callbacks(name
, pref
);
945 purple_prefs_add_path_list(name
, value
);
951 purple_prefs_exists(const char *name
)
953 struct purple_pref
*pref
= find_pref(name
);
962 purple_prefs_get_type(const char *name
)
964 struct purple_pref
*pref
= find_pref(name
);
967 return PURPLE_PREF_NONE
;
973 purple_prefs_get_bool(const char *name
)
975 struct purple_pref
*pref
= find_pref(name
);
978 purple_debug_error("prefs",
979 "purple_prefs_get_bool: Unknown pref %s\n", name
);
981 } else if(pref
->type
!= PURPLE_PREF_BOOLEAN
) {
982 purple_debug_error("prefs",
983 "purple_prefs_get_bool: %s not a boolean pref\n", name
);
987 return pref
->value
.boolean
;
991 purple_prefs_get_int(const char *name
)
993 struct purple_pref
*pref
= find_pref(name
);
996 purple_debug_error("prefs",
997 "purple_prefs_get_int: Unknown pref %s\n", name
);
999 } else if(pref
->type
!= PURPLE_PREF_INT
) {
1000 purple_debug_error("prefs",
1001 "purple_prefs_get_int: %s not an integer pref\n", name
);
1005 return pref
->value
.integer
;
1009 purple_prefs_get_string(const char *name
)
1011 struct purple_pref
*pref
= find_pref(name
);
1014 purple_debug_error("prefs",
1015 "purple_prefs_get_string: Unknown pref %s\n", name
);
1017 } else if(pref
->type
!= PURPLE_PREF_STRING
) {
1018 purple_debug_error("prefs",
1019 "purple_prefs_get_string: %s not a string pref\n", name
);
1023 return pref
->value
.string
;
1027 purple_prefs_get_string_list(const char *name
)
1029 struct purple_pref
*pref
= find_pref(name
);
1030 GList
*ret
= NULL
, *tmp
;
1033 purple_debug_error("prefs",
1034 "purple_prefs_get_string_list: Unknown pref %s\n", name
);
1036 } else if(pref
->type
!= PURPLE_PREF_STRING_LIST
) {
1037 purple_debug_error("prefs",
1038 "purple_prefs_get_string_list: %s not a string list pref\n", name
);
1042 for(tmp
= pref
->value
.stringlist
; tmp
; tmp
= tmp
->next
)
1043 ret
= g_list_prepend(ret
, g_strdup(tmp
->data
));
1044 ret
= g_list_reverse(ret
);
1050 purple_prefs_get_path(const char *name
)
1052 struct purple_pref
*pref
= find_pref(name
);
1055 purple_debug_error("prefs",
1056 "purple_prefs_get_path: Unknown pref %s\n", name
);
1058 } else if(pref
->type
!= PURPLE_PREF_PATH
) {
1059 purple_debug_error("prefs",
1060 "purple_prefs_get_path: %s not a path pref\n", name
);
1064 return pref
->value
.string
;
1068 purple_prefs_get_path_list(const char *name
)
1070 struct purple_pref
*pref
= find_pref(name
);
1071 GList
*ret
= NULL
, *tmp
;
1074 purple_debug_error("prefs",
1075 "purple_prefs_get_path_list: Unknown pref %s\n", name
);
1077 } else if(pref
->type
!= PURPLE_PREF_PATH_LIST
) {
1078 purple_debug_error("prefs",
1079 "purple_prefs_get_path_list: %s not a path list pref\n", name
);
1083 for(tmp
= pref
->value
.stringlist
; tmp
; tmp
= tmp
->next
)
1084 ret
= g_list_prepend(ret
, g_strdup(tmp
->data
));
1085 ret
= g_list_reverse(ret
);
1091 purple_prefs_rename_node(struct purple_pref
*oldpref
, struct purple_pref
*newpref
)
1093 struct purple_pref
*child
, *next
;
1094 char *oldname
, *newname
;
1096 /* if we're a parent, rename the kids first */
1097 for(child
= oldpref
->first_child
; child
!= NULL
; child
= next
)
1099 struct purple_pref
*newchild
;
1100 next
= child
->sibling
;
1101 for(newchild
= newpref
->first_child
; newchild
!= NULL
; newchild
= newchild
->sibling
)
1103 if(purple_strequal(child
->name
, newchild
->name
))
1105 purple_prefs_rename_node(child
, newchild
);
1109 if(newchild
== NULL
) {
1110 /* no rename happened, we weren't able to find the new pref */
1111 char *tmpname
= pref_full_name(child
);
1112 purple_debug_error("prefs", "Unable to find rename pref for %s\n", tmpname
);
1117 oldname
= pref_full_name(oldpref
);
1118 newname
= pref_full_name(newpref
);
1120 if (oldpref
->type
!= newpref
->type
)
1122 purple_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname
, newname
);
1128 purple_debug_info("prefs", "Renaming %s to %s\n", oldname
, newname
);
1131 switch(oldpref
->type
) {
1132 case PURPLE_PREF_NONE
:
1134 case PURPLE_PREF_BOOLEAN
:
1135 purple_prefs_set_bool(newname
, oldpref
->value
.boolean
);
1137 case PURPLE_PREF_INT
:
1138 purple_prefs_set_int(newname
, oldpref
->value
.integer
);
1140 case PURPLE_PREF_STRING
:
1141 purple_prefs_set_string(newname
, oldpref
->value
.string
);
1143 case PURPLE_PREF_STRING_LIST
:
1144 purple_prefs_set_string_list(newname
, oldpref
->value
.stringlist
);
1146 case PURPLE_PREF_PATH
:
1147 purple_prefs_set_path(newname
, oldpref
->value
.string
);
1149 case PURPLE_PREF_PATH_LIST
:
1150 purple_prefs_set_path_list(newname
, oldpref
->value
.stringlist
);
1155 remove_pref(oldpref
);
1159 purple_prefs_rename(const char *oldname
, const char *newname
)
1161 struct purple_pref
*oldpref
, *newpref
;
1163 oldpref
= find_pref(oldname
);
1165 /* it's already been renamed, call off the dogs */
1169 newpref
= find_pref(newname
);
1171 if (newpref
== NULL
)
1173 purple_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname
, newname
);
1177 purple_prefs_rename_node(oldpref
, newpref
);
1181 purple_prefs_rename_boolean_toggle(const char *oldname
, const char *newname
)
1183 struct purple_pref
*oldpref
, *newpref
;
1185 oldpref
= find_pref(oldname
);
1187 /* it's already been renamed, call off the cats */
1191 if (oldpref
->type
!= PURPLE_PREF_BOOLEAN
)
1193 purple_debug_error("prefs", "Unable to rename %s to %s: old pref not a boolean\n", oldname
, newname
);
1197 if (oldpref
->first_child
!= NULL
) /* can't rename parents */
1199 purple_debug_error("prefs", "Unable to rename %s to %s: can't rename parents\n", oldname
, newname
);
1204 newpref
= find_pref(newname
);
1206 if (newpref
== NULL
)
1208 purple_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname
, newname
);
1212 if (oldpref
->type
!= newpref
->type
)
1214 purple_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname
, newname
);
1218 purple_debug_info("prefs", "Renaming and toggling %s to %s\n", oldname
, newname
);
1219 purple_prefs_set_bool(newname
, !(oldpref
->value
.boolean
));
1221 remove_pref(oldpref
);
1225 purple_prefs_connect_callback(void *handle
, const char *name
, PurplePrefCallback func
, gpointer data
)
1227 struct purple_pref
*pref
;
1229 static guint cb_id
= 0;
1231 g_return_val_if_fail(name
!= NULL
, 0);
1232 g_return_val_if_fail(func
!= NULL
, 0);
1234 pref
= find_pref(name
);
1236 purple_debug_error("prefs", "purple_prefs_connect_callback: Unknown pref %s\n", name
);
1240 cb
= g_new0(struct pref_cb
, 1);
1245 cb
->handle
= handle
;
1247 pref
->callbacks
= g_slist_append(pref
->callbacks
, cb
);
1253 disco_callback_helper(struct purple_pref
*pref
, guint callback_id
)
1256 struct purple_pref
*child
;
1261 for(cbs
= pref
->callbacks
; cbs
; cbs
= cbs
->next
) {
1262 struct pref_cb
*cb
= cbs
->data
;
1263 if(cb
->id
== callback_id
) {
1264 pref
->callbacks
= g_slist_delete_link(pref
->callbacks
, cbs
);
1270 for(child
= pref
->first_child
; child
; child
= child
->sibling
) {
1271 if(disco_callback_helper(child
, callback_id
))
1279 purple_prefs_disconnect_callback(guint callback_id
)
1281 disco_callback_helper(&prefs
, callback_id
);
1285 disco_callback_helper_handle(struct purple_pref
*pref
, void *handle
)
1288 struct purple_pref
*child
;
1293 cbs
= pref
->callbacks
;
1294 while (cbs
!= NULL
) {
1295 struct pref_cb
*cb
= cbs
->data
;
1296 if(cb
->handle
== handle
) {
1297 pref
->callbacks
= g_slist_delete_link(pref
->callbacks
, cbs
);
1299 cbs
= pref
->callbacks
;
1304 for(child
= pref
->first_child
; child
; child
= child
->sibling
)
1305 disco_callback_helper_handle(child
, handle
);
1309 purple_prefs_disconnect_by_handle(void *handle
)
1311 g_return_if_fail(handle
!= NULL
);
1313 disco_callback_helper_handle(&prefs
, handle
);
1317 purple_prefs_get_children_names(const char *name
)
1319 GList
* list
= NULL
;
1320 struct purple_pref
*pref
= find_pref(name
), *child
;
1321 char sep
[2] = "\0\0";;
1326 if (name
[strlen(name
) - 1] != '/')
1328 for (child
= pref
->first_child
; child
; child
= child
->sibling
) {
1329 list
= g_list_append(list
, g_strdup_printf("%s%s%s", name
, sep
, child
->name
));
1335 purple_prefs_update_old()
1337 purple_prefs_rename("/core", "/purple");
1339 /* Remove some no-longer-used prefs */
1340 purple_prefs_remove("/purple/away/auto_response/enabled");
1341 purple_prefs_remove("/purple/away/auto_response/idle_only");
1342 purple_prefs_remove("/purple/away/auto_response/in_active_conv");
1343 purple_prefs_remove("/purple/away/auto_response/sec_before_resend");
1344 purple_prefs_remove("/purple/away/auto_response");
1345 purple_prefs_remove("/purple/away/default_message");
1346 purple_prefs_remove("/purple/buddies/use_server_alias");
1347 purple_prefs_remove("/purple/conversations/away_back_on_send");
1348 purple_prefs_remove("/purple/conversations/send_urls_as_links");
1349 purple_prefs_remove("/purple/conversations/im/show_login");
1350 purple_prefs_remove("/purple/conversations/chat/show_join");
1351 purple_prefs_remove("/purple/conversations/chat/show_leave");
1352 purple_prefs_remove("/purple/conversations/combine_chat_im");
1353 purple_prefs_remove("/purple/conversations/use_alias_for_title");
1354 purple_prefs_remove("/purple/logging/log_signon_signoff");
1355 purple_prefs_remove("/purple/logging/log_idle_state");
1356 purple_prefs_remove("/purple/logging/log_away_state");
1357 purple_prefs_remove("/purple/logging/log_own_states");
1358 purple_prefs_remove("/purple/status/scores/hidden");
1359 purple_prefs_remove("/plugins/core/autorecon/hide_connected_error");
1360 purple_prefs_remove("/plugins/core/autorecon/hide_connecting_error");
1361 purple_prefs_remove("/plugins/core/autorecon/hide_reconnecting_dialog");
1362 purple_prefs_remove("/plugins/core/autorecon/restore_state");
1363 purple_prefs_remove("/plugins/core/autorecon");
1365 /* Convert old sounds while_away pref to new 3-way pref. */
1366 if (purple_prefs_exists("/purple/sound/while_away") &&
1367 purple_prefs_get_bool("/purple/sound/while_away"))
1369 purple_prefs_set_int("/purple/sound/while_status", 3);
1371 purple_prefs_remove("/purple/sound/while_away");
1375 purple_prefs_get_handle(void)
1383 purple_prefs_init(void)
1385 void *handle
= purple_prefs_get_handle();
1387 prefs_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
1389 purple_prefs_connect_callback(handle
, "/", prefs_save_cb
, NULL
);
1391 purple_prefs_add_none("/purple");
1392 purple_prefs_add_none("/plugins");
1393 purple_prefs_add_none("/plugins/core");
1394 purple_prefs_add_none("/plugins/lopl");
1395 purple_prefs_add_none("/plugins/prpl");
1398 purple_prefs_add_none("/purple/away");
1399 purple_prefs_add_string("/purple/away/idle_reporting", "system");
1400 purple_prefs_add_bool("/purple/away/away_when_idle", TRUE
);
1401 purple_prefs_add_int("/purple/away/mins_before_away", 5);
1403 /* Away -> Auto-Reply */
1404 if (!purple_prefs_exists("/purple/away/auto_response/enabled") ||
1405 !purple_prefs_exists("/purple/away/auto_response/idle_only"))
1407 purple_prefs_add_string("/purple/away/auto_reply", "awayidle");
1411 if (!purple_prefs_get_bool("/purple/away/auto_response/enabled"))
1413 purple_prefs_add_string("/purple/away/auto_reply", "never");
1417 if (purple_prefs_get_bool("/purple/away/auto_response/idle_only"))
1419 purple_prefs_add_string("/purple/away/auto_reply", "awayidle");
1423 purple_prefs_add_string("/purple/away/auto_reply", "away");
1429 purple_prefs_add_none("/purple/buddies");
1431 /* Contact Priority Settings */
1432 purple_prefs_add_none("/purple/contact");
1433 purple_prefs_add_bool("/purple/contact/last_match", FALSE
);
1434 purple_prefs_remove("/purple/contact/offline_score");
1435 purple_prefs_remove("/purple/contact/away_score");
1436 purple_prefs_remove("/purple/contact/idle_score");
1438 purple_prefs_load();
1439 purple_prefs_update_old();
1443 purple_prefs_uninit()
1445 if (save_timer
!= 0)
1447 purple_timeout_remove(save_timer
);
1452 purple_prefs_disconnect_by_handle(purple_prefs_get_handle());
1454 prefs_loaded
= FALSE
;
1455 purple_prefs_destroy();
1456 g_hash_table_destroy(prefs_hash
);