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 ((pref_type
== PURPLE_PREF_BOOLEAN
|| pref_type
== PURPLE_PREF_INT
) &&
281 pref_value
== NULL
) {
282 /* Missing a value attribute */
286 if(purple_strequal(element_name
, "item")) {
287 struct purple_pref
*pref
;
289 pref_name_full
= g_string_new("");
291 for(tmp
= prefs_stack
; tmp
; tmp
= tmp
->next
) {
292 pref_name_full
= g_string_prepend(pref_name_full
, tmp
->data
);
293 pref_name_full
= g_string_prepend_c(pref_name_full
, '/');
296 pref
= find_pref(pref_name_full
->str
);
299 if(pref
->type
== PURPLE_PREF_STRING_LIST
) {
300 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
301 g_strdup(pref_value
));
302 } else if(pref
->type
== PURPLE_PREF_PATH_LIST
) {
303 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
304 g_filename_from_utf8(pref_value
, -1, NULL
, NULL
, NULL
));
307 g_string_free(pref_name_full
, TRUE
);
311 if(!pref_name
|| purple_strequal(pref_name
, "/"))
314 pref_name_full
= g_string_new(pref_name
);
316 for(tmp
= prefs_stack
; tmp
; tmp
= tmp
->next
) {
317 pref_name_full
= g_string_prepend_c(pref_name_full
, '/');
318 pref_name_full
= g_string_prepend(pref_name_full
, tmp
->data
);
321 pref_name_full
= g_string_prepend_c(pref_name_full
, '/');
324 case PURPLE_PREF_NONE
:
325 purple_prefs_add_none(pref_name_full
->str
);
327 case PURPLE_PREF_BOOLEAN
:
328 purple_prefs_set_bool(pref_name_full
->str
, atoi(pref_value
));
330 case PURPLE_PREF_INT
:
331 purple_prefs_set_int(pref_name_full
->str
, atoi(pref_value
));
333 case PURPLE_PREF_STRING
:
334 purple_prefs_set_string(pref_name_full
->str
, pref_value
);
336 case PURPLE_PREF_STRING_LIST
:
337 purple_prefs_set_string_list(pref_name_full
->str
, NULL
);
339 case PURPLE_PREF_PATH
:
341 decoded
= g_filename_from_utf8(pref_value
, -1, NULL
, NULL
, NULL
);
342 purple_prefs_set_path(pref_name_full
->str
, decoded
);
345 purple_prefs_set_path(pref_name_full
->str
, NULL
);
348 case PURPLE_PREF_PATH_LIST
:
349 purple_prefs_set_path_list(pref_name_full
->str
, NULL
);
352 prefs_stack
= g_list_prepend(prefs_stack
, g_strdup(pref_name
));
353 g_string_free(pref_name_full
, TRUE
);
358 prefs_end_element_handler(GMarkupParseContext
*context
,
359 const gchar
*element_name
,
360 gpointer user_data
, GError
**error
)
362 if(prefs_stack
&& purple_strequal(element_name
, "pref")) {
363 g_free(prefs_stack
->data
);
364 prefs_stack
= g_list_delete_link(prefs_stack
, prefs_stack
);
368 static GMarkupParser prefs_parser
= {
369 prefs_start_element_handler
,
370 prefs_end_element_handler
,
379 gchar
*filename
= g_build_filename(purple_user_dir(), "prefs.xml", NULL
);
380 gchar
*contents
= NULL
;
382 GMarkupParseContext
*context
;
383 GError
*error
= NULL
;
390 purple_debug_info("prefs", "Reading %s\n", filename
);
392 if(!g_file_get_contents(filename
, &contents
, &length
, &error
)) {
394 gchar
*common_appdata
= wpurple_get_special_folder(CSIDL_COMMON_APPDATA
);
402 filename
= g_build_filename(common_appdata
? common_appdata
: "", "purple", "prefs.xml", NULL
);
403 g_free(common_appdata
);
405 filename
= g_build_filename(SYSCONFDIR
, "purple", "prefs.xml", NULL
);
408 purple_debug_info("prefs", "Reading %s\n", filename
);
410 if (!g_file_get_contents(filename
, &contents
, &length
, &error
)) {
411 purple_debug_error("prefs", "Error reading prefs: %s\n",
421 context
= g_markup_parse_context_new(&prefs_parser
, 0, NULL
, NULL
);
423 if(!g_markup_parse_context_parse(context
, contents
, length
, NULL
)) {
424 g_markup_parse_context_free(context
);
432 if(!g_markup_parse_context_end_parse(context
, NULL
)) {
433 purple_debug_error("prefs", "Error parsing %s\n", filename
);
434 g_markup_parse_context_free(context
);
442 purple_debug_info("prefs", "Finished reading %s\n", filename
);
443 g_markup_parse_context_free(context
);
454 prefs_save_cb(const char *name
, PurplePrefType type
, gconstpointer val
,
461 purple_debug_misc("prefs", "%s changed, scheduling save.\n", name
);
463 schedule_prefs_save();
467 get_path_dirname(const char *name
)
471 str
= g_strdup(name
);
473 if ((c
= strrchr(str
, '/')) != NULL
) {
492 get_path_basename(const char *name
)
496 if ((c
= strrchr(name
, '/')) != NULL
)
497 return g_strdup(c
+ 1);
499 return g_strdup(name
);
503 pref_full_name(struct purple_pref
*pref
)
506 struct purple_pref
*parent
;
512 return g_strdup("/");
514 name
= g_string_new(pref
->name
);
516 for(parent
= pref
->parent
; parent
&& parent
->name
; parent
= parent
->parent
) {
517 name
= g_string_prepend_c(name
, '/');
518 name
= g_string_prepend(name
, parent
->name
);
520 name
= g_string_prepend_c(name
, '/');
521 return g_string_free(name
, FALSE
);
524 static struct purple_pref
*
525 find_pref_parent(const char *name
)
527 char *parent_name
= get_path_dirname(name
);
528 struct purple_pref
*ret
= &prefs
;
530 if(!purple_strequal(parent_name
, "/")) {
531 ret
= find_pref(parent_name
);
539 free_pref_value(struct purple_pref
*pref
)
542 case PURPLE_PREF_BOOLEAN
:
543 pref
->value
.boolean
= FALSE
;
545 case PURPLE_PREF_INT
:
546 pref
->value
.integer
= 0;
548 case PURPLE_PREF_STRING
:
549 case PURPLE_PREF_PATH
:
550 g_free(pref
->value
.string
);
551 pref
->value
.string
= NULL
;
553 case PURPLE_PREF_STRING_LIST
:
554 case PURPLE_PREF_PATH_LIST
:
556 g_list_foreach(pref
->value
.stringlist
, (GFunc
)g_free
, NULL
);
557 g_list_free(pref
->value
.stringlist
);
559 case PURPLE_PREF_NONE
:
564 static struct purple_pref
*
565 add_pref(PurplePrefType type
, const char *name
)
567 struct purple_pref
*parent
;
568 struct purple_pref
*me
;
569 struct purple_pref
*sibling
;
572 parent
= find_pref_parent(name
);
577 my_name
= get_path_basename(name
);
579 for(sibling
= parent
->first_child
; sibling
; sibling
= sibling
->sibling
) {
580 if(purple_strequal(sibling
->name
, my_name
)) {
586 me
= g_new0(struct purple_pref
, 1);
591 if(parent
->first_child
) {
592 /* blatant abuse of a for loop */
593 for(sibling
= parent
->first_child
; sibling
->sibling
;
594 sibling
= sibling
->sibling
);
595 sibling
->sibling
= me
;
597 parent
->first_child
= me
;
600 g_hash_table_insert(prefs_hash
, g_strdup(name
), (gpointer
)me
);
606 purple_prefs_add_none(const char *name
)
608 add_pref(PURPLE_PREF_NONE
, name
);
612 purple_prefs_add_bool(const char *name
, gboolean value
)
614 struct purple_pref
*pref
= add_pref(PURPLE_PREF_BOOLEAN
, name
);
619 pref
->value
.boolean
= value
;
623 purple_prefs_add_int(const char *name
, int value
)
625 struct purple_pref
*pref
= add_pref(PURPLE_PREF_INT
, name
);
630 pref
->value
.integer
= value
;
634 purple_prefs_add_string(const char *name
, const char *value
)
636 struct purple_pref
*pref
;
638 if(value
!= NULL
&& !g_utf8_validate(value
, -1, NULL
)) {
639 purple_debug_error("prefs", "purple_prefs_add_string: Cannot store invalid UTF8 for string pref %s\n", name
);
643 pref
= add_pref(PURPLE_PREF_STRING
, name
);
648 pref
->value
.string
= g_strdup(value
);
652 purple_prefs_add_string_list(const char *name
, GList
*value
)
654 struct purple_pref
*pref
= add_pref(PURPLE_PREF_STRING_LIST
, name
);
660 for(tmp
= value
; tmp
; tmp
= tmp
->next
) {
661 if(tmp
->data
!= NULL
&& !g_utf8_validate(tmp
->data
, -1, NULL
)) {
662 purple_debug_error("prefs", "purple_prefs_add_string_list: Skipping invalid UTF8 for string list pref %s\n", name
);
665 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
666 g_strdup(tmp
->data
));
671 purple_prefs_add_path(const char *name
, const char *value
)
673 struct purple_pref
*pref
= add_pref(PURPLE_PREF_PATH
, name
);
678 pref
->value
.string
= g_strdup(value
);
682 purple_prefs_add_path_list(const char *name
, GList
*value
)
684 struct purple_pref
*pref
= add_pref(PURPLE_PREF_PATH_LIST
, name
);
690 for(tmp
= value
; tmp
; tmp
= tmp
->next
)
691 pref
->value
.stringlist
= g_list_append(pref
->value
.stringlist
,
692 g_strdup(tmp
->data
));
697 remove_pref(struct purple_pref
*pref
)
705 while(pref
->first_child
)
706 remove_pref(pref
->first_child
);
711 if(pref
->parent
->first_child
== pref
) {
712 pref
->parent
->first_child
= pref
->sibling
;
714 struct purple_pref
*sib
= pref
->parent
->first_child
;
715 while(sib
&& sib
->sibling
!= pref
)
718 sib
->sibling
= pref
->sibling
;
721 name
= pref_full_name(pref
);
724 purple_debug_info("prefs", "removing pref %s\n", name
);
726 g_hash_table_remove(prefs_hash
, name
);
729 free_pref_value(pref
);
731 while((l
= pref
->callbacks
) != NULL
) {
732 pref
->callbacks
= pref
->callbacks
->next
;
741 purple_prefs_remove(const char *name
)
743 struct purple_pref
*pref
= find_pref(name
);
752 purple_prefs_destroy()
754 purple_prefs_remove("/");
758 do_callbacks(const char* name
, struct purple_pref
*pref
)
761 struct purple_pref
*cb_pref
;
762 for(cb_pref
= pref
; cb_pref
; cb_pref
= cb_pref
->parent
) {
763 for(cbs
= cb_pref
->callbacks
; cbs
; cbs
= cbs
->next
) {
764 struct pref_cb
*cb
= cbs
->data
;
765 cb
->func(name
, pref
->type
, pref
->value
.generic
, cb
->data
);
771 purple_prefs_trigger_callback(const char *name
)
773 struct purple_pref
*pref
= find_pref(name
);
776 purple_debug_error("prefs",
777 "purple_prefs_trigger_callback: Unknown pref %s\n", name
);
781 do_callbacks(name
, pref
);
785 purple_prefs_set_generic(const char *name
, gpointer value
)
787 struct purple_pref
*pref
= find_pref(name
);
790 purple_debug_error("prefs",
791 "purple_prefs_set_generic: Unknown pref %s\n", name
);
795 pref
->value
.generic
= value
;
796 do_callbacks(name
, pref
);
800 purple_prefs_set_bool(const char *name
, gboolean value
)
802 struct purple_pref
*pref
= find_pref(name
);
805 if(pref
->type
!= PURPLE_PREF_BOOLEAN
) {
806 purple_debug_error("prefs",
807 "purple_prefs_set_bool: %s not a boolean pref\n", name
);
811 if(pref
->value
.boolean
!= value
) {
812 pref
->value
.boolean
= value
;
813 do_callbacks(name
, pref
);
816 purple_prefs_add_bool(name
, value
);
821 purple_prefs_set_int(const char *name
, int value
)
823 struct purple_pref
*pref
= find_pref(name
);
826 if(pref
->type
!= PURPLE_PREF_INT
) {
827 purple_debug_error("prefs",
828 "purple_prefs_set_int: %s not an integer pref\n", name
);
832 if(pref
->value
.integer
!= value
) {
833 pref
->value
.integer
= value
;
834 do_callbacks(name
, pref
);
837 purple_prefs_add_int(name
, value
);
842 purple_prefs_set_string(const char *name
, const char *value
)
844 struct purple_pref
*pref
= find_pref(name
);
846 if(value
!= NULL
&& !g_utf8_validate(value
, -1, NULL
)) {
847 purple_debug_error("prefs", "purple_prefs_set_string: Cannot store invalid UTF8 for string pref %s\n", name
);
852 if(pref
->type
!= PURPLE_PREF_STRING
&& pref
->type
!= PURPLE_PREF_PATH
) {
853 purple_debug_error("prefs",
854 "purple_prefs_set_string: %s not a string pref\n", name
);
858 if (!purple_strequal(pref
->value
.string
, value
)) {
859 g_free(pref
->value
.string
);
860 pref
->value
.string
= g_strdup(value
);
861 do_callbacks(name
, pref
);
864 purple_prefs_add_string(name
, value
);
869 purple_prefs_set_string_list(const char *name
, GList
*value
)
871 struct purple_pref
*pref
= find_pref(name
);
875 if(pref
->type
!= PURPLE_PREF_STRING_LIST
) {
876 purple_debug_error("prefs",
877 "purple_prefs_set_string_list: %s not a string list pref\n",
882 g_list_foreach(pref
->value
.stringlist
, (GFunc
)g_free
, NULL
);
883 g_list_free(pref
->value
.stringlist
);
884 pref
->value
.stringlist
= NULL
;
886 for(tmp
= value
; tmp
; tmp
= tmp
->next
) {
887 if(tmp
->data
!= NULL
&& !g_utf8_validate(tmp
->data
, -1, NULL
)) {
888 purple_debug_error("prefs", "purple_prefs_set_string_list: Skipping invalid UTF8 for string list pref %s\n", name
);
891 pref
->value
.stringlist
= g_list_prepend(pref
->value
.stringlist
,
892 g_strdup(tmp
->data
));
894 pref
->value
.stringlist
= g_list_reverse(pref
->value
.stringlist
);
896 do_callbacks(name
, pref
);
899 purple_prefs_add_string_list(name
, value
);
904 purple_prefs_set_path(const char *name
, const char *value
)
906 struct purple_pref
*pref
= find_pref(name
);
909 if(pref
->type
!= PURPLE_PREF_PATH
) {
910 purple_debug_error("prefs",
911 "purple_prefs_set_path: %s not a path pref\n", name
);
915 if (!purple_strequal(pref
->value
.string
, value
)) {
916 g_free(pref
->value
.string
);
917 pref
->value
.string
= g_strdup(value
);
918 do_callbacks(name
, pref
);
921 purple_prefs_add_path(name
, value
);
926 purple_prefs_set_path_list(const char *name
, GList
*value
)
928 struct purple_pref
*pref
= find_pref(name
);
932 if(pref
->type
!= PURPLE_PREF_PATH_LIST
) {
933 purple_debug_error("prefs",
934 "purple_prefs_set_path_list: %s not a path list pref\n",
939 g_list_foreach(pref
->value
.stringlist
, (GFunc
)g_free
, NULL
);
940 g_list_free(pref
->value
.stringlist
);
941 pref
->value
.stringlist
= NULL
;
943 for(tmp
= value
; tmp
; tmp
= tmp
->next
)
944 pref
->value
.stringlist
= g_list_prepend(pref
->value
.stringlist
,
945 g_strdup(tmp
->data
));
946 pref
->value
.stringlist
= g_list_reverse(pref
->value
.stringlist
);
948 do_callbacks(name
, pref
);
951 purple_prefs_add_path_list(name
, value
);
957 purple_prefs_exists(const char *name
)
959 struct purple_pref
*pref
= find_pref(name
);
968 purple_prefs_get_type(const char *name
)
970 struct purple_pref
*pref
= find_pref(name
);
973 return PURPLE_PREF_NONE
;
979 purple_prefs_get_bool(const char *name
)
981 struct purple_pref
*pref
= find_pref(name
);
984 purple_debug_error("prefs",
985 "purple_prefs_get_bool: Unknown pref %s\n", name
);
987 } else if(pref
->type
!= PURPLE_PREF_BOOLEAN
) {
988 purple_debug_error("prefs",
989 "purple_prefs_get_bool: %s not a boolean pref\n", name
);
993 return pref
->value
.boolean
;
997 purple_prefs_get_int(const char *name
)
999 struct purple_pref
*pref
= find_pref(name
);
1002 purple_debug_error("prefs",
1003 "purple_prefs_get_int: Unknown pref %s\n", name
);
1005 } else if(pref
->type
!= PURPLE_PREF_INT
) {
1006 purple_debug_error("prefs",
1007 "purple_prefs_get_int: %s not an integer pref\n", name
);
1011 return pref
->value
.integer
;
1015 purple_prefs_get_string(const char *name
)
1017 struct purple_pref
*pref
= find_pref(name
);
1020 purple_debug_error("prefs",
1021 "purple_prefs_get_string: Unknown pref %s\n", name
);
1023 } else if(pref
->type
!= PURPLE_PREF_STRING
) {
1024 purple_debug_error("prefs",
1025 "purple_prefs_get_string: %s not a string pref\n", name
);
1029 return pref
->value
.string
;
1033 purple_prefs_get_string_list(const char *name
)
1035 struct purple_pref
*pref
= find_pref(name
);
1036 GList
*ret
= NULL
, *tmp
;
1039 purple_debug_error("prefs",
1040 "purple_prefs_get_string_list: Unknown pref %s\n", name
);
1042 } else if(pref
->type
!= PURPLE_PREF_STRING_LIST
) {
1043 purple_debug_error("prefs",
1044 "purple_prefs_get_string_list: %s not a string list pref\n", name
);
1048 for(tmp
= pref
->value
.stringlist
; tmp
; tmp
= tmp
->next
)
1049 ret
= g_list_prepend(ret
, g_strdup(tmp
->data
));
1050 ret
= g_list_reverse(ret
);
1056 purple_prefs_get_path(const char *name
)
1058 struct purple_pref
*pref
= find_pref(name
);
1061 purple_debug_error("prefs",
1062 "purple_prefs_get_path: Unknown pref %s\n", name
);
1064 } else if(pref
->type
!= PURPLE_PREF_PATH
) {
1065 purple_debug_error("prefs",
1066 "purple_prefs_get_path: %s not a path pref\n", name
);
1070 return pref
->value
.string
;
1074 purple_prefs_get_path_list(const char *name
)
1076 struct purple_pref
*pref
= find_pref(name
);
1077 GList
*ret
= NULL
, *tmp
;
1080 purple_debug_error("prefs",
1081 "purple_prefs_get_path_list: Unknown pref %s\n", name
);
1083 } else if(pref
->type
!= PURPLE_PREF_PATH_LIST
) {
1084 purple_debug_error("prefs",
1085 "purple_prefs_get_path_list: %s not a path list pref\n", name
);
1089 for(tmp
= pref
->value
.stringlist
; tmp
; tmp
= tmp
->next
)
1090 ret
= g_list_prepend(ret
, g_strdup(tmp
->data
));
1091 ret
= g_list_reverse(ret
);
1097 purple_prefs_rename_node(struct purple_pref
*oldpref
, struct purple_pref
*newpref
)
1099 struct purple_pref
*child
, *next
;
1100 char *oldname
, *newname
;
1102 /* if we're a parent, rename the kids first */
1103 for(child
= oldpref
->first_child
; child
!= NULL
; child
= next
)
1105 struct purple_pref
*newchild
;
1106 next
= child
->sibling
;
1107 for(newchild
= newpref
->first_child
; newchild
!= NULL
; newchild
= newchild
->sibling
)
1109 if(purple_strequal(child
->name
, newchild
->name
))
1111 purple_prefs_rename_node(child
, newchild
);
1115 if(newchild
== NULL
) {
1116 /* no rename happened, we weren't able to find the new pref */
1117 char *tmpname
= pref_full_name(child
);
1118 purple_debug_error("prefs", "Unable to find rename pref for %s\n", tmpname
);
1123 oldname
= pref_full_name(oldpref
);
1124 newname
= pref_full_name(newpref
);
1126 if (oldpref
->type
!= newpref
->type
)
1128 purple_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname
, newname
);
1134 purple_debug_info("prefs", "Renaming %s to %s\n", oldname
, newname
);
1137 switch(oldpref
->type
) {
1138 case PURPLE_PREF_NONE
:
1140 case PURPLE_PREF_BOOLEAN
:
1141 purple_prefs_set_bool(newname
, oldpref
->value
.boolean
);
1143 case PURPLE_PREF_INT
:
1144 purple_prefs_set_int(newname
, oldpref
->value
.integer
);
1146 case PURPLE_PREF_STRING
:
1147 purple_prefs_set_string(newname
, oldpref
->value
.string
);
1149 case PURPLE_PREF_STRING_LIST
:
1150 purple_prefs_set_string_list(newname
, oldpref
->value
.stringlist
);
1152 case PURPLE_PREF_PATH
:
1153 purple_prefs_set_path(newname
, oldpref
->value
.string
);
1155 case PURPLE_PREF_PATH_LIST
:
1156 purple_prefs_set_path_list(newname
, oldpref
->value
.stringlist
);
1161 remove_pref(oldpref
);
1165 purple_prefs_rename(const char *oldname
, const char *newname
)
1167 struct purple_pref
*oldpref
, *newpref
;
1169 oldpref
= find_pref(oldname
);
1171 /* it's already been renamed, call off the dogs */
1175 newpref
= find_pref(newname
);
1177 if (newpref
== NULL
)
1179 purple_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname
, newname
);
1183 purple_prefs_rename_node(oldpref
, newpref
);
1187 purple_prefs_rename_boolean_toggle(const char *oldname
, const char *newname
)
1189 struct purple_pref
*oldpref
, *newpref
;
1191 oldpref
= find_pref(oldname
);
1193 /* it's already been renamed, call off the cats */
1197 if (oldpref
->type
!= PURPLE_PREF_BOOLEAN
)
1199 purple_debug_error("prefs", "Unable to rename %s to %s: old pref not a boolean\n", oldname
, newname
);
1203 if (oldpref
->first_child
!= NULL
) /* can't rename parents */
1205 purple_debug_error("prefs", "Unable to rename %s to %s: can't rename parents\n", oldname
, newname
);
1210 newpref
= find_pref(newname
);
1212 if (newpref
== NULL
)
1214 purple_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname
, newname
);
1218 if (oldpref
->type
!= newpref
->type
)
1220 purple_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname
, newname
);
1224 purple_debug_info("prefs", "Renaming and toggling %s to %s\n", oldname
, newname
);
1225 purple_prefs_set_bool(newname
, !(oldpref
->value
.boolean
));
1227 remove_pref(oldpref
);
1231 purple_prefs_connect_callback(void *handle
, const char *name
, PurplePrefCallback func
, gpointer data
)
1233 struct purple_pref
*pref
;
1235 static guint cb_id
= 0;
1237 g_return_val_if_fail(name
!= NULL
, 0);
1238 g_return_val_if_fail(func
!= NULL
, 0);
1240 pref
= find_pref(name
);
1242 purple_debug_error("prefs", "purple_prefs_connect_callback: Unknown pref %s\n", name
);
1246 cb
= g_new0(struct pref_cb
, 1);
1251 cb
->handle
= handle
;
1253 pref
->callbacks
= g_slist_append(pref
->callbacks
, cb
);
1259 disco_callback_helper(struct purple_pref
*pref
, guint callback_id
)
1262 struct purple_pref
*child
;
1267 for(cbs
= pref
->callbacks
; cbs
; cbs
= cbs
->next
) {
1268 struct pref_cb
*cb
= cbs
->data
;
1269 if(cb
->id
== callback_id
) {
1270 pref
->callbacks
= g_slist_delete_link(pref
->callbacks
, cbs
);
1276 for(child
= pref
->first_child
; child
; child
= child
->sibling
) {
1277 if(disco_callback_helper(child
, callback_id
))
1285 purple_prefs_disconnect_callback(guint callback_id
)
1287 disco_callback_helper(&prefs
, callback_id
);
1291 disco_callback_helper_handle(struct purple_pref
*pref
, void *handle
)
1294 struct purple_pref
*child
;
1299 cbs
= pref
->callbacks
;
1300 while (cbs
!= NULL
) {
1301 struct pref_cb
*cb
= cbs
->data
;
1302 if(cb
->handle
== handle
) {
1303 pref
->callbacks
= g_slist_delete_link(pref
->callbacks
, cbs
);
1305 cbs
= pref
->callbacks
;
1310 for(child
= pref
->first_child
; child
; child
= child
->sibling
)
1311 disco_callback_helper_handle(child
, handle
);
1315 purple_prefs_disconnect_by_handle(void *handle
)
1317 g_return_if_fail(handle
!= NULL
);
1319 disco_callback_helper_handle(&prefs
, handle
);
1323 purple_prefs_get_children_names(const char *name
)
1325 GList
* list
= NULL
;
1326 struct purple_pref
*pref
= find_pref(name
), *child
;
1327 char sep
[2] = "\0\0";;
1332 if (name
[strlen(name
) - 1] != '/')
1334 for (child
= pref
->first_child
; child
; child
= child
->sibling
) {
1335 list
= g_list_append(list
, g_strdup_printf("%s%s%s", name
, sep
, child
->name
));
1341 purple_prefs_update_old()
1343 purple_prefs_rename("/core", "/purple");
1345 /* Remove some no-longer-used prefs */
1346 purple_prefs_remove("/purple/away/auto_response/enabled");
1347 purple_prefs_remove("/purple/away/auto_response/idle_only");
1348 purple_prefs_remove("/purple/away/auto_response/in_active_conv");
1349 purple_prefs_remove("/purple/away/auto_response/sec_before_resend");
1350 purple_prefs_remove("/purple/away/auto_response");
1351 purple_prefs_remove("/purple/away/default_message");
1352 purple_prefs_remove("/purple/buddies/use_server_alias");
1353 purple_prefs_remove("/purple/conversations/away_back_on_send");
1354 purple_prefs_remove("/purple/conversations/send_urls_as_links");
1355 purple_prefs_remove("/purple/conversations/im/show_login");
1356 purple_prefs_remove("/purple/conversations/chat/show_join");
1357 purple_prefs_remove("/purple/conversations/chat/show_leave");
1358 purple_prefs_remove("/purple/conversations/combine_chat_im");
1359 purple_prefs_remove("/purple/conversations/use_alias_for_title");
1360 purple_prefs_remove("/purple/logging/log_signon_signoff");
1361 purple_prefs_remove("/purple/logging/log_idle_state");
1362 purple_prefs_remove("/purple/logging/log_away_state");
1363 purple_prefs_remove("/purple/logging/log_own_states");
1364 purple_prefs_remove("/purple/status/scores/hidden");
1365 purple_prefs_remove("/plugins/core/autorecon/hide_connected_error");
1366 purple_prefs_remove("/plugins/core/autorecon/hide_connecting_error");
1367 purple_prefs_remove("/plugins/core/autorecon/hide_reconnecting_dialog");
1368 purple_prefs_remove("/plugins/core/autorecon/restore_state");
1369 purple_prefs_remove("/plugins/core/autorecon");
1371 /* Convert old sounds while_away pref to new 3-way pref. */
1372 if (purple_prefs_exists("/purple/sound/while_away") &&
1373 purple_prefs_get_bool("/purple/sound/while_away"))
1375 purple_prefs_set_int("/purple/sound/while_status", 3);
1377 purple_prefs_remove("/purple/sound/while_away");
1381 purple_prefs_get_handle(void)
1389 purple_prefs_init(void)
1391 void *handle
= purple_prefs_get_handle();
1393 prefs_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
1395 purple_prefs_connect_callback(handle
, "/", prefs_save_cb
, NULL
);
1397 purple_prefs_add_none("/purple");
1398 purple_prefs_add_none("/plugins");
1399 purple_prefs_add_none("/plugins/core");
1400 purple_prefs_add_none("/plugins/lopl");
1401 purple_prefs_add_none("/plugins/prpl");
1404 purple_prefs_add_none("/purple/away");
1405 purple_prefs_add_string("/purple/away/idle_reporting", "system");
1406 purple_prefs_add_bool("/purple/away/away_when_idle", TRUE
);
1407 purple_prefs_add_int("/purple/away/mins_before_away", 5);
1409 /* Away -> Auto-Reply */
1410 if (!purple_prefs_exists("/purple/away/auto_response/enabled") ||
1411 !purple_prefs_exists("/purple/away/auto_response/idle_only"))
1413 purple_prefs_add_string("/purple/away/auto_reply", "awayidle");
1417 if (!purple_prefs_get_bool("/purple/away/auto_response/enabled"))
1419 purple_prefs_add_string("/purple/away/auto_reply", "never");
1423 if (purple_prefs_get_bool("/purple/away/auto_response/idle_only"))
1425 purple_prefs_add_string("/purple/away/auto_reply", "awayidle");
1429 purple_prefs_add_string("/purple/away/auto_reply", "away");
1435 purple_prefs_add_none("/purple/buddies");
1437 /* Contact Priority Settings */
1438 purple_prefs_add_none("/purple/contact");
1439 purple_prefs_add_bool("/purple/contact/last_match", FALSE
);
1440 purple_prefs_remove("/purple/contact/offline_score");
1441 purple_prefs_remove("/purple/contact/away_score");
1442 purple_prefs_remove("/purple/contact/idle_score");
1444 purple_prefs_load();
1445 purple_prefs_update_old();
1449 purple_prefs_uninit()
1451 if (save_timer
!= 0)
1453 purple_timeout_remove(save_timer
);
1458 purple_prefs_disconnect_by_handle(purple_prefs_get_handle());
1460 prefs_loaded
= FALSE
;
1461 purple_prefs_destroy();
1462 g_hash_table_destroy(prefs_hash
);