Mercurial > pidgin.yaz
comparison src/prefs.c @ 10443:b6ca0e1b19d0
[gaim-migrate @ 11703]
Shuffle some things around in prefs.c and use xmlnode/the util function
for saving prefs. Now all our xml files are written to disk at once,
with gobs of error detection. If anyone complains about losing their
config file with 2.x, send them to me. Muwha ha ha ha ha. Ha. Heh. Sigh.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 28 Dec 2004 19:11:15 +0000 |
parents | 3232e1a33899 |
children | fa06fda62868 |
comparison
equal
deleted
inserted
replaced
10442:937697da5233 | 10443:b6ca0e1b19d0 |
---|---|
45 gpointer data; | 45 gpointer data; |
46 guint id; | 46 guint id; |
47 void *handle; | 47 void *handle; |
48 }; | 48 }; |
49 | 49 |
50 /* TODO: This should use GaimValues? */ | |
50 struct gaim_pref { | 51 struct gaim_pref { |
51 GaimPrefType type; | 52 GaimPrefType type; |
52 char *name; | 53 char *name; |
53 union { | 54 union { |
54 gpointer generic; | 55 gpointer generic; |
61 struct gaim_pref *parent; | 62 struct gaim_pref *parent; |
62 struct gaim_pref *sibling; | 63 struct gaim_pref *sibling; |
63 struct gaim_pref *first_child; | 64 struct gaim_pref *first_child; |
64 }; | 65 }; |
65 | 66 |
67 | |
68 static struct gaim_pref prefs = { | |
69 GAIM_PREF_NONE, | |
70 NULL, | |
71 { NULL }, | |
72 NULL, | |
73 NULL, | |
74 NULL, | |
75 NULL | |
76 }; | |
77 | |
66 static GHashTable *prefs_hash = NULL; | 78 static GHashTable *prefs_hash = NULL; |
67 | 79 static guint save_timer = 0; |
68 static struct gaim_pref prefs = { GAIM_PREF_NONE, NULL, {NULL}, NULL, | 80 static gboolean prefs_loaded = FALSE; |
69 NULL, NULL, NULL }; | 81 |
70 | 82 |
71 static guint prefs_save_timer = 0; | 83 /********************************************************************* |
72 static gboolean prefs_is_loaded = FALSE; | 84 * Private utility functions * |
73 | 85 *********************************************************************/ |
74 | 86 |
75 static gboolean prefs_save_callback(gpointer who_cares) { | 87 static struct |
76 gaim_prefs_sync(); | 88 gaim_pref *find_pref(const char *name) |
77 prefs_save_timer = 0; | 89 { |
90 if (!name || name[0] != '/') | |
91 return NULL; | |
92 else if (name[1] == '\0') | |
93 return &prefs; | |
94 else | |
95 return g_hash_table_lookup(prefs_hash, name); | |
96 } | |
97 | |
98 | |
99 /********************************************************************* | |
100 * Writing to disk * | |
101 *********************************************************************/ | |
102 | |
103 /* | |
104 * This function recursively creates the xmlnode tree from the prefs | |
105 * tree structure. Yay recursion! | |
106 */ | |
107 void | |
108 pref_to_xmlnode(xmlnode *parent, struct gaim_pref *pref) | |
109 { | |
110 xmlnode *node, *childnode; | |
111 struct gaim_pref *child; | |
112 char buf[20]; | |
113 GList *cur; | |
114 | |
115 /* Create a new node */ | |
116 node = xmlnode_new_child(parent, "pref"); | |
117 xmlnode_set_attrib(node, "name", pref->name); | |
118 | |
119 /* Set the type of this node (if type == GAIM_PREF_NONE then do nothing) */ | |
120 if (pref->type == GAIM_PREF_INT) { | |
121 xmlnode_set_attrib(node, "type", "int"); | |
122 snprintf(buf, sizeof(buf), "%d", pref->value.integer); | |
123 xmlnode_set_attrib(node, "value", buf); | |
124 } | |
125 else if (pref->type == GAIM_PREF_STRING) { | |
126 xmlnode_set_attrib(node, "type", "string"); | |
127 xmlnode_set_attrib(node, "value", pref->value.string); | |
128 } | |
129 else if (pref->type == GAIM_PREF_STRING_LIST) { | |
130 xmlnode_set_attrib(node, "type", "stringlist"); | |
131 for (cur = pref->value.stringlist; cur != NULL; cur = cur->next) | |
132 { | |
133 childnode = xmlnode_new_child(node, "item"); | |
134 xmlnode_set_attrib(childnode, "value", cur->data); | |
135 } | |
136 } | |
137 else if (pref->type == GAIM_PREF_BOOLEAN) { | |
138 xmlnode_set_attrib(node, "type", "bool"); | |
139 snprintf(buf, sizeof(buf), "%d", pref->value.boolean); | |
140 xmlnode_set_attrib(node, "value", buf); | |
141 } | |
142 | |
143 /* All My Children */ | |
144 for (child = pref->first_child; child != NULL; child = child->sibling) | |
145 pref_to_xmlnode(node, child); | |
146 } | |
147 | |
148 static xmlnode * | |
149 prefs_to_xmlnode(void) | |
150 { | |
151 xmlnode *node; | |
152 struct gaim_pref *pref, *child; | |
153 | |
154 pref = &prefs; | |
155 | |
156 /* Create the root preference node */ | |
157 node = xmlnode_new("pref"); | |
158 xmlnode_set_attrib(node, "version", "1"); | |
159 xmlnode_set_attrib(node, "name", "/"); | |
160 | |
161 /* All My Children */ | |
162 for (child = pref->first_child; child != NULL; child = child->sibling) | |
163 pref_to_xmlnode(node, child); | |
164 | |
165 return node; | |
166 } | |
167 | |
168 static void | |
169 sync_prefs(void) | |
170 { | |
171 xmlnode *node; | |
172 char *data; | |
173 | |
174 if (!prefs_loaded) | |
175 { | |
176 /* | |
177 * TODO: Call schedule_prefs_save()? Ideally we wouldn't need to. | |
178 * (prefs.xml should be loaded when gaim_prefs_init is called) | |
179 */ | |
180 gaim_debug_error("prefs", "Attempted to save prefs before " | |
181 "they were read!\n"); | |
182 return; | |
183 } | |
184 | |
185 node = prefs_to_xmlnode(); | |
186 data = xmlnode_to_formatted_str(node, NULL); | |
187 gaim_util_write_data_to_file("prefs.xml", data, -1); | |
188 g_free(data); | |
189 xmlnode_free(node); | |
190 } | |
191 | |
192 static gboolean | |
193 save_cb(gpointer data) | |
194 { | |
195 sync_prefs(); | |
196 save_timer = 0; | |
78 return FALSE; | 197 return FALSE; |
79 } | 198 } |
80 | 199 |
81 static void schedule_prefs_save() { | 200 static void |
82 if(!prefs_save_timer) | 201 schedule_prefs_save(void) |
83 prefs_save_timer = gaim_timeout_add(5000, prefs_save_callback, NULL); | 202 { |
84 } | 203 if (save_timer == 0) |
85 | 204 save_timer = gaim_timeout_add(5000, save_cb, NULL); |
86 static void prefs_save_cb(const char *name, GaimPrefType type, gpointer val, | 205 } |
87 gpointer user_data) { | 206 |
88 | 207 |
89 if(!prefs_is_loaded) | 208 /********************************************************************* |
90 return; | 209 * Reading from disk * |
91 | 210 *********************************************************************/ |
92 gaim_debug(GAIM_DEBUG_MISC, "prefs", "%s changed, scheduling save.\n", name); | 211 |
212 static GList *prefs_stack = NULL; | |
213 | |
214 static void | |
215 prefs_start_element_handler (GMarkupParseContext *context, | |
216 const gchar *element_name, | |
217 const gchar **attribute_names, | |
218 const gchar **attribute_values, | |
219 gpointer user_data, | |
220 GError **error) | |
221 { | |
222 GaimPrefType pref_type = GAIM_PREF_NONE; | |
223 int i; | |
224 const char *pref_name = NULL, *pref_value = NULL; | |
225 GString *pref_name_full; | |
226 GList *tmp; | |
227 | |
228 if(strcmp(element_name, "pref") && strcmp(element_name, "item")) | |
229 return; | |
230 | |
231 for(i = 0; attribute_names[i]; i++) { | |
232 if(!strcmp(attribute_names[i], "name")) { | |
233 pref_name = attribute_values[i]; | |
234 } else if(!strcmp(attribute_names[i], "type")) { | |
235 if(!strcmp(attribute_values[i], "bool")) | |
236 pref_type = GAIM_PREF_BOOLEAN; | |
237 else if(!strcmp(attribute_values[i], "int")) | |
238 pref_type = GAIM_PREF_INT; | |
239 else if(!strcmp(attribute_values[i], "string")) | |
240 pref_type = GAIM_PREF_STRING; | |
241 else if(!strcmp(attribute_values[i], "stringlist")) | |
242 pref_type = GAIM_PREF_STRING_LIST; | |
243 else | |
244 return; | |
245 } else if(!strcmp(attribute_names[i], "value")) { | |
246 pref_value = attribute_values[i]; | |
247 } | |
248 } | |
249 | |
250 if(!strcmp(element_name, "item")) { | |
251 struct gaim_pref *pref; | |
252 | |
253 pref_name_full = g_string_new(""); | |
254 | |
255 for(tmp = prefs_stack; tmp; tmp = tmp->next) { | |
256 pref_name_full = g_string_prepend(pref_name_full, tmp->data); | |
257 pref_name_full = g_string_prepend_c(pref_name_full, '/'); | |
258 } | |
259 | |
260 pref = find_pref(pref_name_full->str); | |
261 | |
262 if(pref) { | |
263 pref->value.stringlist = g_list_append(pref->value.stringlist, | |
264 g_strdup(pref_value)); | |
265 } | |
266 } else { | |
267 if(!pref_name || !strcmp(pref_name, "/")) | |
268 return; | |
269 | |
270 pref_name_full = g_string_new(pref_name); | |
271 | |
272 for(tmp = prefs_stack; tmp; tmp = tmp->next) { | |
273 pref_name_full = g_string_prepend_c(pref_name_full, '/'); | |
274 pref_name_full = g_string_prepend(pref_name_full, tmp->data); | |
275 } | |
276 | |
277 pref_name_full = g_string_prepend_c(pref_name_full, '/'); | |
278 | |
279 switch(pref_type) { | |
280 case GAIM_PREF_NONE: | |
281 gaim_prefs_add_none(pref_name_full->str); | |
282 break; | |
283 case GAIM_PREF_BOOLEAN: | |
284 gaim_prefs_set_bool(pref_name_full->str, atoi(pref_value)); | |
285 break; | |
286 case GAIM_PREF_INT: | |
287 gaim_prefs_set_int(pref_name_full->str, atoi(pref_value)); | |
288 break; | |
289 case GAIM_PREF_STRING: | |
290 gaim_prefs_set_string(pref_name_full->str, pref_value); | |
291 break; | |
292 case GAIM_PREF_STRING_LIST: | |
293 gaim_prefs_set_string_list(pref_name_full->str, NULL); | |
294 break; | |
295 } | |
296 prefs_stack = g_list_prepend(prefs_stack, g_strdup(pref_name)); | |
297 g_string_free(pref_name_full, TRUE); | |
298 } | |
299 } | |
300 | |
301 static void | |
302 prefs_end_element_handler(GMarkupParseContext *context, | |
303 const gchar *element_name, | |
304 gpointer user_data, GError **error) | |
305 { | |
306 if(prefs_stack && !strcmp(element_name, "pref")) { | |
307 g_free(prefs_stack->data); | |
308 prefs_stack = g_list_delete_link(prefs_stack, prefs_stack); | |
309 } | |
310 } | |
311 | |
312 static GMarkupParser prefs_parser = { | |
313 prefs_start_element_handler, | |
314 prefs_end_element_handler, | |
315 NULL, | |
316 NULL, | |
317 NULL | |
318 }; | |
319 | |
320 gboolean | |
321 gaim_prefs_load() | |
322 { | |
323 gchar *filename = g_build_filename(gaim_user_dir(), "prefs.xml", NULL); | |
324 gchar *contents = NULL; | |
325 gsize length; | |
326 GMarkupParseContext *context; | |
327 GError *error = NULL; | |
328 | |
329 if (!filename) { | |
330 prefs_loaded = TRUE; | |
331 return FALSE; | |
332 } | |
333 | |
334 gaim_debug_info("prefs", "Reading %s\n", filename); | |
335 | |
336 if(!g_file_get_contents(filename, &contents, &length, &error)) { | |
337 #ifndef _WIN32 | |
338 g_free(filename); | |
339 g_error_free(error); | |
340 | |
341 error = NULL; | |
342 | |
343 filename = g_build_filename(SYSCONFDIR, "gaim", "prefs.xml", NULL); | |
344 | |
345 gaim_debug_info("prefs", "Reading %s\n", filename); | |
346 | |
347 if (!g_file_get_contents(filename, &contents, &length, &error)) { | |
348 gaim_debug_error("prefs", "Error reading prefs: %s\n", | |
349 error->message); | |
350 g_error_free(error); | |
351 g_free(filename); | |
352 prefs_loaded = TRUE; | |
353 | |
354 return FALSE; | |
355 } | |
356 #else /* _WIN32 */ | |
357 gaim_debug_error("prefs", "Error reading prefs: %s\n", | |
358 error->message); | |
359 g_error_free(error); | |
360 g_free(filename); | |
361 prefs_loaded = TRUE; | |
362 | |
363 return FALSE; | |
364 #endif /* _WIN32 */ | |
365 } | |
366 | |
367 context = g_markup_parse_context_new(&prefs_parser, 0, NULL, NULL); | |
368 | |
369 if(!g_markup_parse_context_parse(context, contents, length, NULL)) { | |
370 g_markup_parse_context_free(context); | |
371 g_free(contents); | |
372 g_free(filename); | |
373 prefs_loaded = TRUE; | |
374 | |
375 return FALSE; | |
376 } | |
377 | |
378 if(!g_markup_parse_context_end_parse(context, NULL)) { | |
379 gaim_debug_error("prefs", "Error parsing %s\n", filename); | |
380 g_markup_parse_context_free(context); | |
381 g_free(contents); | |
382 g_free(filename); | |
383 prefs_loaded = TRUE; | |
384 | |
385 return FALSE; | |
386 } | |
387 | |
388 gaim_debug_info("prefs", "Finished reading %s\n", filename); | |
389 g_markup_parse_context_free(context); | |
390 g_free(contents); | |
391 g_free(filename); | |
392 prefs_loaded = TRUE; | |
393 | |
394 return TRUE; | |
395 } | |
396 | |
397 | |
398 | |
399 static void | |
400 prefs_save_cb(const char *name, GaimPrefType type, gpointer val, | |
401 gpointer user_data) | |
402 { | |
403 | |
404 if(!prefs_loaded) | |
405 return; | |
406 | |
407 gaim_debug_misc("prefs", "%s changed, scheduling save.\n", name); | |
93 | 408 |
94 schedule_prefs_save(); | 409 schedule_prefs_save(); |
95 } | |
96 | |
97 void gaim_prefs_init() { | |
98 prefs_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); | |
99 | |
100 gaim_prefs_connect_callback(NULL, "/", prefs_save_cb, NULL); | |
101 | |
102 gaim_prefs_add_none("/core"); | |
103 gaim_prefs_add_none("/plugins"); | |
104 gaim_prefs_add_none("/plugins/core"); | |
105 gaim_prefs_add_none("/plugins/lopl"); | |
106 gaim_prefs_add_none("/plugins/prpl"); | |
107 | |
108 /* Away */ | |
109 gaim_prefs_add_none("/core/away"); | |
110 gaim_prefs_add_bool("/core/away/away_when_idle", TRUE); | |
111 gaim_prefs_add_int("/core/away/mins_before_away", 5); | |
112 /* XXX: internationalized string in prefs...evil */ | |
113 gaim_prefs_add_string("/core/away/default_message", | |
114 _("Slightly less boring default")); | |
115 | |
116 /* Away -> Auto-Reply */ | |
117 if (!gaim_prefs_exists("/core/away/auto_response/enabled") || | |
118 !gaim_prefs_exists("/core/away/auto_response/idle_only")) { | |
119 gaim_prefs_add_string("/core/away/auto_reply", "awayidle"); | |
120 } else { | |
121 if (!gaim_prefs_get_bool("/core/away/auto_response/enabled")) { | |
122 gaim_prefs_add_string("/core/away/auto_reply", "never"); | |
123 } else { | |
124 if (gaim_prefs_get_bool("/core/away/auto_response/idle_only")) { | |
125 gaim_prefs_add_string("/core/away/auto_reply", "awayidle"); | |
126 } else { | |
127 gaim_prefs_add_string("/core/away/auto_reply", "away"); | |
128 } | |
129 } | |
130 } | |
131 | |
132 /* Buddies */ | |
133 gaim_prefs_add_none("/core/buddies"); | |
134 | |
135 /* Contact Priority Settings */ | |
136 gaim_prefs_add_none("/core/contact"); | |
137 gaim_prefs_add_bool("/core/contact/last_match", FALSE); | |
138 gaim_prefs_add_int("/core/contact/offline_score", 4); | |
139 gaim_prefs_add_int("/core/contact/away_score", 2); | |
140 gaim_prefs_add_int("/core/contact/idle_score", 1); | |
141 } | |
142 | |
143 void | |
144 gaim_prefs_uninit() | |
145 { | |
146 if (prefs_save_timer != 0) { | |
147 gaim_timeout_remove(prefs_save_timer); | |
148 prefs_save_timer = 0; | |
149 gaim_prefs_sync(); | |
150 } | |
151 } | 410 } |
152 | 411 |
153 static char * | 412 static char * |
154 get_path_dirname(const char *name) | 413 get_path_dirname(const char *name) |
155 { | 414 { |
184 return g_strdup(c + 1); | 443 return g_strdup(c + 1); |
185 | 444 |
186 return g_strdup(name); | 445 return g_strdup(name); |
187 } | 446 } |
188 | 447 |
189 static char *pref_full_name(struct gaim_pref *pref) { | 448 static char * |
449 pref_full_name(struct gaim_pref *pref) | |
450 { | |
190 GString *name; | 451 GString *name; |
191 struct gaim_pref *parent; | 452 struct gaim_pref *parent; |
192 char *ret; | 453 char *ret; |
193 | 454 |
194 if(!pref) | 455 if(!pref) |
207 ret = name->str; | 468 ret = name->str; |
208 g_string_free(name, FALSE); | 469 g_string_free(name, FALSE); |
209 return ret; | 470 return ret; |
210 } | 471 } |
211 | 472 |
212 static struct gaim_pref *find_pref(const char *name) | 473 static struct gaim_pref * |
213 { | 474 find_pref_parent(const char *name) |
214 if(!name || name[0] != '/') { | |
215 return NULL; | |
216 } else if(name[1] == '\0') { | |
217 return &prefs; | |
218 } else { | |
219 return g_hash_table_lookup(prefs_hash, name); | |
220 } | |
221 } | |
222 | |
223 static struct gaim_pref *find_pref_parent(const char *name) | |
224 { | 475 { |
225 char *parent_name = get_path_dirname(name); | 476 char *parent_name = get_path_dirname(name); |
226 struct gaim_pref *ret = &prefs; | 477 struct gaim_pref *ret = &prefs; |
227 | 478 |
228 if(strcmp(parent_name, "/")) { | 479 if(strcmp(parent_name, "/")) { |
231 | 482 |
232 g_free(parent_name); | 483 g_free(parent_name); |
233 return ret; | 484 return ret; |
234 } | 485 } |
235 | 486 |
236 static void free_pref_value(struct gaim_pref *pref) { | 487 static void |
488 free_pref_value(struct gaim_pref *pref) | |
489 { | |
237 switch(pref->type) { | 490 switch(pref->type) { |
238 case GAIM_PREF_BOOLEAN: | 491 case GAIM_PREF_BOOLEAN: |
239 pref->value.boolean = FALSE; | 492 pref->value.boolean = FALSE; |
240 break; | 493 break; |
241 case GAIM_PREF_INT: | 494 case GAIM_PREF_INT: |
256 case GAIM_PREF_NONE: | 509 case GAIM_PREF_NONE: |
257 break; | 510 break; |
258 } | 511 } |
259 } | 512 } |
260 | 513 |
261 static struct gaim_pref *add_pref(GaimPrefType type, const char *name) { | 514 static struct gaim_pref * |
515 add_pref(GaimPrefType type, const char *name) | |
516 { | |
262 struct gaim_pref *parent; | 517 struct gaim_pref *parent; |
263 struct gaim_pref *me; | 518 struct gaim_pref *me; |
264 struct gaim_pref *sibling; | 519 struct gaim_pref *sibling; |
265 char *my_name; | 520 char *my_name; |
266 | 521 |
295 g_hash_table_insert(prefs_hash, g_strdup(name), (gpointer)me); | 550 g_hash_table_insert(prefs_hash, g_strdup(name), (gpointer)me); |
296 | 551 |
297 return me; | 552 return me; |
298 } | 553 } |
299 | 554 |
300 void gaim_prefs_add_none(const char *name) { | 555 void |
556 gaim_prefs_add_none(const char *name) | |
557 { | |
301 add_pref(GAIM_PREF_NONE, name); | 558 add_pref(GAIM_PREF_NONE, name); |
302 } | 559 } |
303 | 560 |
304 void gaim_prefs_add_bool(const char *name, gboolean value) { | 561 void |
562 gaim_prefs_add_bool(const char *name, gboolean value) | |
563 { | |
305 struct gaim_pref *pref = add_pref(GAIM_PREF_BOOLEAN, name); | 564 struct gaim_pref *pref = add_pref(GAIM_PREF_BOOLEAN, name); |
306 | 565 |
307 if(!pref) | 566 if(!pref) |
308 return; | 567 return; |
309 | 568 |
310 pref->value.boolean = value; | 569 pref->value.boolean = value; |
311 } | 570 } |
312 | 571 |
313 void gaim_prefs_add_int(const char *name, int value) { | 572 void |
573 gaim_prefs_add_int(const char *name, int value) | |
574 { | |
314 struct gaim_pref *pref = add_pref(GAIM_PREF_INT, name); | 575 struct gaim_pref *pref = add_pref(GAIM_PREF_INT, name); |
315 | 576 |
316 if(!pref) | 577 if(!pref) |
317 return; | 578 return; |
318 | 579 |
319 pref->value.integer = value; | 580 pref->value.integer = value; |
320 } | 581 } |
321 | 582 |
322 void gaim_prefs_add_string(const char *name, const char *value) { | 583 void |
584 gaim_prefs_add_string(const char *name, const char *value) | |
585 { | |
323 struct gaim_pref *pref = add_pref(GAIM_PREF_STRING, name); | 586 struct gaim_pref *pref = add_pref(GAIM_PREF_STRING, name); |
324 | 587 |
325 if(!pref) | 588 if(!pref) |
326 return; | 589 return; |
327 | 590 |
328 pref->value.string = g_strdup(value); | 591 pref->value.string = g_strdup(value); |
329 } | 592 } |
330 | 593 |
331 void gaim_prefs_add_string_list(const char *name, GList *value) { | 594 void |
595 gaim_prefs_add_string_list(const char *name, GList *value) | |
596 { | |
332 struct gaim_pref *pref = add_pref(GAIM_PREF_STRING_LIST, name); | 597 struct gaim_pref *pref = add_pref(GAIM_PREF_STRING_LIST, name); |
333 GList *tmp; | 598 GList *tmp; |
334 | 599 |
335 if(!pref) | 600 if(!pref) |
336 return; | 601 return; |
338 for(tmp = value; tmp; tmp = tmp->next) | 603 for(tmp = value; tmp; tmp = tmp->next) |
339 pref->value.stringlist = g_list_append(pref->value.stringlist, | 604 pref->value.stringlist = g_list_append(pref->value.stringlist, |
340 g_strdup(tmp->data)); | 605 g_strdup(tmp->data)); |
341 } | 606 } |
342 | 607 |
343 void remove_pref(struct gaim_pref *pref) { | 608 void |
609 remove_pref(struct gaim_pref *pref) | |
610 { | |
344 char *name; | 611 char *name; |
345 | 612 |
346 if(!pref || pref == &prefs) | 613 if(!pref || pref == &prefs) |
347 return; | 614 return; |
348 | 615 |
358 sib->sibling = pref->sibling; | 625 sib->sibling = pref->sibling; |
359 } | 626 } |
360 | 627 |
361 name = pref_full_name(pref); | 628 name = pref_full_name(pref); |
362 | 629 |
363 gaim_debug(GAIM_DEBUG_INFO, "prefs", "removing pref /%s\n", name); | 630 gaim_debug_info("prefs", "removing pref /%s\n", name); |
364 | 631 |
365 g_hash_table_remove(prefs_hash, name); | 632 g_hash_table_remove(prefs_hash, name); |
366 g_free(name); | 633 g_free(name); |
367 | 634 |
368 free_pref_value(pref); | 635 free_pref_value(pref); |
370 g_slist_free(pref->callbacks); | 637 g_slist_free(pref->callbacks); |
371 g_free(pref->name); | 638 g_free(pref->name); |
372 g_free(pref); | 639 g_free(pref); |
373 } | 640 } |
374 | 641 |
375 void gaim_prefs_remove(const char *name) { | 642 void |
643 gaim_prefs_remove(const char *name) | |
644 { | |
376 struct gaim_pref *pref = find_pref(name); | 645 struct gaim_pref *pref = find_pref(name); |
377 | 646 |
378 if(!pref) | 647 if(!pref) |
379 return; | 648 return; |
380 | 649 |
381 remove_pref(pref); | 650 remove_pref(pref); |
382 } | 651 } |
383 | 652 |
384 void gaim_prefs_destroy() { | 653 void |
654 gaim_prefs_destroy() | |
655 { | |
385 gaim_prefs_remove("/"); | 656 gaim_prefs_remove("/"); |
386 } | 657 } |
387 | 658 |
388 static void do_callbacks(const char* name, struct gaim_pref *pref) { | 659 static void |
660 do_callbacks(const char* name, struct gaim_pref *pref) | |
661 { | |
389 GSList *cbs; | 662 GSList *cbs; |
390 struct gaim_pref *cb_pref; | 663 struct gaim_pref *cb_pref; |
391 for(cb_pref = pref; cb_pref; cb_pref = cb_pref->parent) { | 664 for(cb_pref = pref; cb_pref; cb_pref = cb_pref->parent) { |
392 for(cbs = cb_pref->callbacks; cbs; cbs = cbs->next) { | 665 for(cbs = cb_pref->callbacks; cbs; cbs = cbs->next) { |
393 struct pref_cb *cb = cbs->data; | 666 struct pref_cb *cb = cbs->data; |
394 cb->func(name, pref->type, pref->value.generic, cb->data); | 667 cb->func(name, pref->type, pref->value.generic, cb->data); |
395 } | 668 } |
396 } | 669 } |
397 } | 670 } |
398 | 671 |
399 void gaim_prefs_trigger_callback(const char *name) { | 672 void |
673 gaim_prefs_trigger_callback(const char *name) | |
674 { | |
400 struct gaim_pref *pref = find_pref(name); | 675 struct gaim_pref *pref = find_pref(name); |
401 | 676 |
402 if(!pref) { | 677 if(!pref) { |
403 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 678 gaim_debug_error("prefs", |
404 "gaim_prefs_trigger_callback: Unknown pref %s\n", name); | 679 "gaim_prefs_trigger_callback: Unknown pref %s\n", name); |
405 return; | 680 return; |
406 } | 681 } |
407 | 682 |
408 do_callbacks(name, pref); | 683 do_callbacks(name, pref); |
409 } | 684 } |
410 | 685 |
411 void gaim_prefs_set_generic(const char *name, gpointer value) { | 686 void |
687 gaim_prefs_set_generic(const char *name, gpointer value) | |
688 { | |
412 struct gaim_pref *pref = find_pref(name); | 689 struct gaim_pref *pref = find_pref(name); |
413 | 690 |
414 if(!pref) { | 691 if(!pref) { |
415 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 692 gaim_debug_error("prefs", |
416 "gaim_prefs_set_generic: Unknown pref %s\n", name); | 693 "gaim_prefs_set_generic: Unknown pref %s\n", name); |
417 return; | 694 return; |
418 } | 695 } |
419 | 696 |
420 pref->value.generic = value; | 697 pref->value.generic = value; |
421 do_callbacks(name, pref); | 698 do_callbacks(name, pref); |
422 } | 699 } |
423 | 700 |
424 void gaim_prefs_set_bool(const char *name, gboolean value) { | 701 void |
702 gaim_prefs_set_bool(const char *name, gboolean value) | |
703 { | |
425 struct gaim_pref *pref = find_pref(name); | 704 struct gaim_pref *pref = find_pref(name); |
426 | 705 |
427 if(pref) { | 706 if(pref) { |
428 if(pref->type != GAIM_PREF_BOOLEAN) { | 707 if(pref->type != GAIM_PREF_BOOLEAN) { |
429 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 708 gaim_debug_error("prefs", |
430 "gaim_prefs_set_bool: %s not a boolean pref\n", name); | 709 "gaim_prefs_set_bool: %s not a boolean pref\n", name); |
431 return; | 710 return; |
432 } | 711 } |
433 | 712 |
434 if(pref->value.boolean != value) { | 713 if(pref->value.boolean != value) { |
438 } else { | 717 } else { |
439 gaim_prefs_add_bool(name, value); | 718 gaim_prefs_add_bool(name, value); |
440 } | 719 } |
441 } | 720 } |
442 | 721 |
443 void gaim_prefs_set_int(const char *name, int value) { | 722 void |
723 gaim_prefs_set_int(const char *name, int value) | |
724 { | |
444 struct gaim_pref *pref = find_pref(name); | 725 struct gaim_pref *pref = find_pref(name); |
445 | 726 |
446 if(pref) { | 727 if(pref) { |
447 if(pref->type != GAIM_PREF_INT) { | 728 if(pref->type != GAIM_PREF_INT) { |
448 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 729 gaim_debug_error("prefs", |
449 "gaim_prefs_set_int: %s not an integer pref\n", name); | 730 "gaim_prefs_set_int: %s not an integer pref\n", name); |
450 return; | 731 return; |
451 } | 732 } |
452 | 733 |
453 if(pref->value.integer != value) { | 734 if(pref->value.integer != value) { |
457 } else { | 738 } else { |
458 gaim_prefs_add_int(name, value); | 739 gaim_prefs_add_int(name, value); |
459 } | 740 } |
460 } | 741 } |
461 | 742 |
462 void gaim_prefs_set_string(const char *name, const char *value) { | 743 void |
744 gaim_prefs_set_string(const char *name, const char *value) | |
745 { | |
463 struct gaim_pref *pref = find_pref(name); | 746 struct gaim_pref *pref = find_pref(name); |
464 | 747 |
465 if(pref) { | 748 if(pref) { |
466 if(pref->type != GAIM_PREF_STRING) { | 749 if(pref->type != GAIM_PREF_STRING) { |
467 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 750 gaim_debug_error("prefs", |
468 "gaim_prefs_set_string: %s not a string pref\n", name); | 751 "gaim_prefs_set_string: %s not a string pref\n", name); |
469 return; | 752 return; |
470 } | 753 } |
471 | 754 |
472 if((value && !pref->value.string) || | 755 if((value && !pref->value.string) || |
479 } else { | 762 } else { |
480 gaim_prefs_add_string(name, value); | 763 gaim_prefs_add_string(name, value); |
481 } | 764 } |
482 } | 765 } |
483 | 766 |
484 void gaim_prefs_set_string_list(const char *name, GList *value) { | 767 void |
768 gaim_prefs_set_string_list(const char *name, GList *value) | |
769 { | |
485 struct gaim_pref *pref = find_pref(name); | 770 struct gaim_pref *pref = find_pref(name); |
486 if(pref) { | 771 if(pref) { |
487 GList *tmp; | 772 GList *tmp; |
488 | 773 |
489 if(pref->type != GAIM_PREF_STRING_LIST) { | 774 if(pref->type != GAIM_PREF_STRING_LIST) { |
490 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 775 gaim_debug_error("prefs", |
491 "gaim_prefs_set_string_list: %s not a string list pref\n", | 776 "gaim_prefs_set_string_list: %s not a string list pref\n", |
492 name); | 777 name); |
493 return; | 778 return; |
494 } | 779 } |
495 | 780 |
508 } else { | 793 } else { |
509 gaim_prefs_add_string_list(name, value); | 794 gaim_prefs_add_string_list(name, value); |
510 } | 795 } |
511 } | 796 } |
512 | 797 |
513 gboolean gaim_prefs_exists(const char *name) { | 798 gboolean |
799 gaim_prefs_exists(const char *name) | |
800 { | |
514 struct gaim_pref *pref = find_pref(name); | 801 struct gaim_pref *pref = find_pref(name); |
515 | 802 |
516 if (pref != NULL) | 803 if (pref != NULL) |
517 return TRUE; | 804 return TRUE; |
518 | 805 |
519 return FALSE; | 806 return FALSE; |
520 } | 807 } |
521 | 808 |
522 GaimPrefType gaim_prefs_get_type(const char *name) { | 809 GaimPrefType |
810 gaim_prefs_get_type(const char *name) | |
811 { | |
523 struct gaim_pref *pref = find_pref(name); | 812 struct gaim_pref *pref = find_pref(name); |
524 | 813 |
525 if (pref == NULL) | 814 if (pref == NULL) |
526 return GAIM_PREF_NONE; | 815 return GAIM_PREF_NONE; |
527 | 816 |
528 return (pref->type); | 817 return (pref->type); |
529 } | 818 } |
530 | 819 |
531 gboolean gaim_prefs_get_bool(const char *name) { | 820 gboolean |
821 gaim_prefs_get_bool(const char *name) | |
822 { | |
532 struct gaim_pref *pref = find_pref(name); | 823 struct gaim_pref *pref = find_pref(name); |
533 | 824 |
534 if(!pref) { | 825 if(!pref) { |
535 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 826 gaim_debug_error("prefs", |
536 "gaim_prefs_get_bool: Unknown pref %s\n", name); | 827 "gaim_prefs_get_bool: Unknown pref %s\n", name); |
537 return FALSE; | 828 return FALSE; |
538 } else if(pref->type != GAIM_PREF_BOOLEAN) { | 829 } else if(pref->type != GAIM_PREF_BOOLEAN) { |
539 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 830 gaim_debug_error("prefs", |
540 "gaim_prefs_get_bool: %s not a boolean pref\n", name); | 831 "gaim_prefs_get_bool: %s not a boolean pref\n", name); |
541 return FALSE; | 832 return FALSE; |
542 } | 833 } |
543 | 834 |
544 return pref->value.boolean; | 835 return pref->value.boolean; |
545 } | 836 } |
546 | 837 |
547 int gaim_prefs_get_int(const char *name) { | 838 int |
839 gaim_prefs_get_int(const char *name) | |
840 { | |
548 struct gaim_pref *pref = find_pref(name); | 841 struct gaim_pref *pref = find_pref(name); |
549 | 842 |
550 if(!pref) { | 843 if(!pref) { |
551 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 844 gaim_debug_error("prefs", |
552 "gaim_prefs_get_int: Unknown pref %s\n", name); | 845 "gaim_prefs_get_int: Unknown pref %s\n", name); |
553 return 0; | 846 return 0; |
554 } else if(pref->type != GAIM_PREF_INT) { | 847 } else if(pref->type != GAIM_PREF_INT) { |
555 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 848 gaim_debug_error("prefs", |
556 "gaim_prefs_get_int: %s not an integer pref\n", name); | 849 "gaim_prefs_get_int: %s not an integer pref\n", name); |
557 return 0; | 850 return 0; |
558 } | 851 } |
559 | 852 |
560 return pref->value.integer; | 853 return pref->value.integer; |
561 } | 854 } |
562 | 855 |
563 const char *gaim_prefs_get_string(const char *name) { | 856 const char * |
857 gaim_prefs_get_string(const char *name) | |
858 { | |
564 struct gaim_pref *pref = find_pref(name); | 859 struct gaim_pref *pref = find_pref(name); |
565 | 860 |
566 if(!pref) { | 861 if(!pref) { |
567 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 862 gaim_debug_error("prefs", |
568 "gaim_prefs_get_string: Unknown pref %s\n", name); | 863 "gaim_prefs_get_string: Unknown pref %s\n", name); |
569 return NULL; | 864 return NULL; |
570 } else if(pref->type != GAIM_PREF_STRING) { | 865 } else if(pref->type != GAIM_PREF_STRING) { |
571 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 866 gaim_debug_error("prefs", |
572 "gaim_prefs_get_string: %s not a string pref\n", name); | 867 "gaim_prefs_get_string: %s not a string pref\n", name); |
573 return NULL; | 868 return NULL; |
574 } | 869 } |
575 | 870 |
576 return pref->value.string; | 871 return pref->value.string; |
577 } | 872 } |
578 | 873 |
579 GList *gaim_prefs_get_string_list(const char *name) { | 874 GList * |
875 gaim_prefs_get_string_list(const char *name) | |
876 { | |
580 struct gaim_pref *pref = find_pref(name); | 877 struct gaim_pref *pref = find_pref(name); |
581 GList *ret = NULL, *tmp; | 878 GList *ret = NULL, *tmp; |
582 | 879 |
583 if(!pref) { | 880 if(!pref) { |
584 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 881 gaim_debug_error("prefs", |
585 "gaim_prefs_get_string_list: Unknown pref %s\n", name); | 882 "gaim_prefs_get_string_list: Unknown pref %s\n", name); |
586 return NULL; | 883 return NULL; |
587 } else if(pref->type != GAIM_PREF_STRING_LIST) { | 884 } else if(pref->type != GAIM_PREF_STRING_LIST) { |
588 gaim_debug(GAIM_DEBUG_ERROR, "prefs", | 885 gaim_debug_error("prefs", |
589 "gaim_prefs_get_string_list: %s not a string list pref\n", name); | 886 "gaim_prefs_get_string_list: %s not a string list pref\n", name); |
590 return NULL; | 887 return NULL; |
591 } | 888 } |
592 | 889 |
593 for(tmp = pref->value.stringlist; tmp; tmp = tmp->next) | 890 for(tmp = pref->value.stringlist; tmp; tmp = tmp->next) |
594 ret = g_list_append(ret, g_strdup(tmp->data)); | 891 ret = g_list_append(ret, g_strdup(tmp->data)); |
595 | 892 |
596 return ret; | 893 return ret; |
597 } | 894 } |
598 | 895 |
599 void gaim_prefs_rename(const char *oldname, const char *newname) { | 896 void |
897 gaim_prefs_rename(const char *oldname, const char *newname) | |
898 { | |
600 struct gaim_pref *oldpref, *newpref; | 899 struct gaim_pref *oldpref, *newpref; |
601 | 900 |
602 oldpref = find_pref(oldname); | 901 oldpref = find_pref(oldname); |
603 newpref = find_pref(newname); | 902 newpref = find_pref(newname); |
604 | 903 |
630 } | 929 } |
631 | 930 |
632 remove_pref(oldpref); | 931 remove_pref(oldpref); |
633 } | 932 } |
634 | 933 |
635 void gaim_prefs_rename_boolean_toggle(const char *oldname, const char *newname) { | 934 void |
935 gaim_prefs_rename_boolean_toggle(const char *oldname, const char *newname) | |
936 { | |
636 struct gaim_pref *oldpref, *newpref; | 937 struct gaim_pref *oldpref, *newpref; |
637 | 938 |
638 gaim_debug_info("prefs", "Attempting to rename and toggle %s to %s\n", oldname, newname); | 939 gaim_debug_info("prefs", "Attempting to rename and toggle %s to %s\n", oldname, newname); |
639 | 940 |
640 oldpref = find_pref(oldname); | 941 oldpref = find_pref(oldname); |
653 | 954 |
654 remove_pref(oldpref); | 955 remove_pref(oldpref); |
655 | 956 |
656 } | 957 } |
657 | 958 |
658 guint gaim_prefs_connect_callback(void *handle, const char *name, GaimPrefCallback func, gpointer data) | 959 guint |
960 gaim_prefs_connect_callback(void *handle, const char *name, GaimPrefCallback func, gpointer data) | |
659 { | 961 { |
660 struct gaim_pref *pref; | 962 struct gaim_pref *pref; |
661 struct pref_cb *cb; | 963 struct pref_cb *cb; |
662 static guint cb_id = 0; | 964 static guint cb_id = 0; |
663 | 965 |
675 pref->callbacks = g_slist_append(pref->callbacks, cb); | 977 pref->callbacks = g_slist_append(pref->callbacks, cb); |
676 | 978 |
677 return cb->id; | 979 return cb->id; |
678 } | 980 } |
679 | 981 |
680 static gboolean disco_callback_helper(struct gaim_pref *pref, guint callback_id) { | 982 static gboolean |
983 disco_callback_helper(struct gaim_pref *pref, guint callback_id) | |
984 { | |
681 GSList *cbs; | 985 GSList *cbs; |
682 struct gaim_pref *child; | 986 struct gaim_pref *child; |
683 | 987 |
684 if(!pref) | 988 if(!pref) |
685 return FALSE; | 989 return FALSE; |
699 } | 1003 } |
700 | 1004 |
701 return FALSE; | 1005 return FALSE; |
702 } | 1006 } |
703 | 1007 |
704 void gaim_prefs_disconnect_callback(guint callback_id) { | 1008 void |
1009 gaim_prefs_disconnect_callback(guint callback_id) | |
1010 { | |
705 disco_callback_helper(&prefs, callback_id); | 1011 disco_callback_helper(&prefs, callback_id); |
706 } | 1012 } |
707 | 1013 |
708 static void disco_callback_helper_handle(struct gaim_pref *pref, void *handle) { | 1014 static void |
1015 disco_callback_helper_handle(struct gaim_pref *pref, void *handle) | |
1016 { | |
709 GSList *cbs; | 1017 GSList *cbs; |
710 struct gaim_pref *child; | 1018 struct gaim_pref *child; |
711 | 1019 |
712 if(!pref) | 1020 if(!pref) |
713 return; | 1021 return; |
725 | 1033 |
726 for(child = pref->first_child; child; child = child->sibling) | 1034 for(child = pref->first_child; child; child = child->sibling) |
727 disco_callback_helper_handle(child, handle); | 1035 disco_callback_helper_handle(child, handle); |
728 } | 1036 } |
729 | 1037 |
730 void gaim_prefs_disconnect_by_handle(void *handle) { | 1038 void |
1039 gaim_prefs_disconnect_by_handle(void *handle) | |
1040 { | |
731 g_return_if_fail(handle != NULL); | 1041 g_return_if_fail(handle != NULL); |
1042 | |
732 disco_callback_helper_handle(&prefs, handle); | 1043 disco_callback_helper_handle(&prefs, handle); |
733 } | 1044 } |
734 | 1045 |
735 static void gaim_prefs_write(FILE *f, struct gaim_pref *pref, int depth) { | 1046 void |
736 struct gaim_pref *tmp; | 1047 gaim_prefs_update_old() |
737 char *esc; | 1048 { |
738 int i; | |
739 | |
740 if(!pref) { | |
741 pref = &prefs; | |
742 | |
743 fprintf(f, "<?xml version='1.0' encoding='UTF-8' ?>\n\n"); | |
744 fprintf(f, "<pref version='1.0' name='/'"); | |
745 } else { | |
746 for(i=0; i<depth; i++) | |
747 fprintf(f, "\t"); | |
748 esc = g_markup_escape_text(pref->name, -1); | |
749 fprintf(f, "<pref name='%s'", esc); | |
750 g_free(esc); | |
751 } | |
752 | |
753 switch(pref->type) { | |
754 case GAIM_PREF_NONE: | |
755 break; | |
756 case GAIM_PREF_BOOLEAN: | |
757 fprintf(f, " type='bool' value='%d'", pref->value.boolean); | |
758 break; | |
759 case GAIM_PREF_INT: | |
760 fprintf(f, " type='int' value='%d'", pref->value.integer); | |
761 break; | |
762 case GAIM_PREF_STRING: | |
763 esc = g_markup_escape_text(pref->value.string, -1); | |
764 fprintf(f, " type='string' value='%s'", esc); | |
765 g_free(esc); | |
766 break; | |
767 case GAIM_PREF_STRING_LIST: | |
768 fprintf(f, " type='stringlist'"); | |
769 break; | |
770 } | |
771 | |
772 if(pref->first_child || pref->type == GAIM_PREF_STRING_LIST) { | |
773 fprintf(f, ">\n"); | |
774 | |
775 for(tmp = pref->first_child; tmp; tmp = tmp->sibling) | |
776 gaim_prefs_write(f, tmp, depth+1); | |
777 | |
778 if(pref->type == GAIM_PREF_STRING_LIST) { | |
779 GList *tmp2; | |
780 for(tmp2 = pref->value.stringlist; tmp2; tmp2 = tmp2->next) { | |
781 for(i=0; i<depth+1; i++) | |
782 fprintf(f, "\t"); | |
783 esc = g_markup_escape_text(tmp2->data, -1); | |
784 fprintf(f, "<item value='%s' />\n", esc); | |
785 g_free(esc); | |
786 } | |
787 } | |
788 | |
789 for(i=0; i<depth; i++) | |
790 fprintf(f, "\t"); | |
791 fprintf(f, "</pref>\n"); | |
792 } else { | |
793 fprintf(f, " />\n"); | |
794 } | |
795 } | |
796 | |
797 void gaim_prefs_sync() { | |
798 FILE *file; | |
799 struct stat st; | |
800 const char *user_dir = gaim_user_dir(); | |
801 char *filename; | |
802 char *filename_real; | |
803 | |
804 if(!prefs_is_loaded) { | |
805 gaim_debug(GAIM_DEBUG_WARNING, "prefs", "prefs saved before loading! scheduling save.\n"); | |
806 schedule_prefs_save(); /* schedule a save for after we read in */ | |
807 return; | |
808 } | |
809 | |
810 if(!user_dir) | |
811 return; | |
812 | |
813 gaim_debug(GAIM_DEBUG_INFO, "prefs", "writing prefs out to disk.\n"); | |
814 | |
815 file = fopen(user_dir, "r"); | |
816 if(!file) | |
817 mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR); | |
818 else | |
819 fclose(file); | |
820 | |
821 filename = g_build_filename(user_dir, "prefs.xml.save", NULL); | |
822 | |
823 if((file = fopen(filename, "w"))) { | |
824 gaim_prefs_write(file, NULL, 0); | |
825 fclose(file); | |
826 chmod(filename, S_IRUSR | S_IWUSR); | |
827 } else { | |
828 gaim_debug(GAIM_DEBUG_ERROR, "prefs", "Unable to write %s\n", | |
829 filename); | |
830 g_free(filename); | |
831 return; | |
832 } | |
833 | |
834 if (stat(filename, &st) || (st.st_size == 0)) { | |
835 gaim_debug_error("prefs", "Failed to save prefs\n"); | |
836 unlink(filename); | |
837 g_free(filename); | |
838 return; | |
839 } | |
840 | |
841 filename_real = g_build_filename(user_dir, "prefs.xml", NULL); | |
842 if(rename(filename, filename_real) < 0) | |
843 gaim_debug(GAIM_DEBUG_ERROR, "prefs", "Error renaming %s to %s\n", | |
844 filename, filename_real); | |
845 | |
846 g_free(filename); | |
847 g_free(filename_real); | |
848 } | |
849 | |
850 static GList *prefs_stack = NULL; | |
851 | |
852 static void prefs_start_element_handler (GMarkupParseContext *context, | |
853 const gchar *element_name, | |
854 const gchar **attribute_names, | |
855 const gchar **attribute_values, | |
856 gpointer user_data, | |
857 GError **error) { | |
858 GaimPrefType pref_type = GAIM_PREF_NONE; | |
859 int i; | |
860 const char *pref_name = NULL, *pref_value = NULL; | |
861 GString *pref_name_full; | |
862 GList *tmp; | |
863 | |
864 if(strcmp(element_name, "pref") && strcmp(element_name, "item")) | |
865 return; | |
866 | |
867 for(i = 0; attribute_names[i]; i++) { | |
868 if(!strcmp(attribute_names[i], "name")) { | |
869 pref_name = attribute_values[i]; | |
870 } else if(!strcmp(attribute_names[i], "type")) { | |
871 if(!strcmp(attribute_values[i], "bool")) | |
872 pref_type = GAIM_PREF_BOOLEAN; | |
873 else if(!strcmp(attribute_values[i], "int")) | |
874 pref_type = GAIM_PREF_INT; | |
875 else if(!strcmp(attribute_values[i], "string")) | |
876 pref_type = GAIM_PREF_STRING; | |
877 else if(!strcmp(attribute_values[i], "stringlist")) | |
878 pref_type = GAIM_PREF_STRING_LIST; | |
879 else | |
880 return; | |
881 } else if(!strcmp(attribute_names[i], "value")) { | |
882 pref_value = attribute_values[i]; | |
883 } | |
884 } | |
885 | |
886 if(!strcmp(element_name, "item")) { | |
887 struct gaim_pref *pref; | |
888 | |
889 pref_name_full = g_string_new(""); | |
890 | |
891 for(tmp = prefs_stack; tmp; tmp = tmp->next) { | |
892 pref_name_full = g_string_prepend(pref_name_full, tmp->data); | |
893 pref_name_full = g_string_prepend_c(pref_name_full, '/'); | |
894 } | |
895 | |
896 pref = find_pref(pref_name_full->str); | |
897 | |
898 if(pref) { | |
899 pref->value.stringlist = g_list_append(pref->value.stringlist, | |
900 g_strdup(pref_value)); | |
901 } | |
902 } else { | |
903 if(!pref_name || !strcmp(pref_name, "/")) | |
904 return; | |
905 | |
906 pref_name_full = g_string_new(pref_name); | |
907 | |
908 for(tmp = prefs_stack; tmp; tmp = tmp->next) { | |
909 pref_name_full = g_string_prepend_c(pref_name_full, '/'); | |
910 pref_name_full = g_string_prepend(pref_name_full, tmp->data); | |
911 } | |
912 | |
913 pref_name_full = g_string_prepend_c(pref_name_full, '/'); | |
914 | |
915 switch(pref_type) { | |
916 case GAIM_PREF_NONE: | |
917 gaim_prefs_add_none(pref_name_full->str); | |
918 break; | |
919 case GAIM_PREF_BOOLEAN: | |
920 gaim_prefs_set_bool(pref_name_full->str, atoi(pref_value)); | |
921 break; | |
922 case GAIM_PREF_INT: | |
923 gaim_prefs_set_int(pref_name_full->str, atoi(pref_value)); | |
924 break; | |
925 case GAIM_PREF_STRING: | |
926 gaim_prefs_set_string(pref_name_full->str, pref_value); | |
927 break; | |
928 case GAIM_PREF_STRING_LIST: | |
929 gaim_prefs_set_string_list(pref_name_full->str, NULL); | |
930 break; | |
931 } | |
932 prefs_stack = g_list_prepend(prefs_stack, g_strdup(pref_name)); | |
933 g_string_free(pref_name_full, TRUE); | |
934 } | |
935 } | |
936 | |
937 static void prefs_end_element_handler(GMarkupParseContext *context, | |
938 const gchar *element_name, gpointer user_data, GError **error) { | |
939 if(prefs_stack && !strcmp(element_name, "pref")) { | |
940 g_free(prefs_stack->data); | |
941 prefs_stack = g_list_delete_link(prefs_stack, prefs_stack); | |
942 } | |
943 } | |
944 | |
945 static GMarkupParser prefs_parser = { | |
946 prefs_start_element_handler, | |
947 prefs_end_element_handler, | |
948 NULL, | |
949 NULL, | |
950 NULL | |
951 }; | |
952 | |
953 gboolean gaim_prefs_load() { | |
954 gchar *filename = g_build_filename(gaim_user_dir(), "prefs.xml", NULL); | |
955 gchar *contents = NULL; | |
956 gsize length; | |
957 GMarkupParseContext *context; | |
958 GError *error = NULL; | |
959 | |
960 if (!filename) { | |
961 prefs_is_loaded = TRUE; | |
962 return FALSE; | |
963 } | |
964 | |
965 gaim_debug(GAIM_DEBUG_INFO, "prefs", "Reading %s\n", filename); | |
966 | |
967 if(!g_file_get_contents(filename, &contents, &length, &error)) { | |
968 #ifndef _WIN32 | |
969 g_free(filename); | |
970 g_error_free(error); | |
971 | |
972 error = NULL; | |
973 | |
974 filename = g_build_filename(SYSCONFDIR, "gaim", "prefs.xml", NULL); | |
975 | |
976 gaim_debug(GAIM_DEBUG_INFO, "prefs", "Reading %s\n", filename); | |
977 | |
978 if (!g_file_get_contents(filename, &contents, &length, &error)) { | |
979 gaim_debug(GAIM_DEBUG_ERROR, "prefs", "Error reading prefs: %s\n", | |
980 error->message); | |
981 g_error_free(error); | |
982 g_free(filename); | |
983 prefs_is_loaded = TRUE; | |
984 | |
985 return FALSE; | |
986 } | |
987 #else /* _WIN32 */ | |
988 gaim_debug(GAIM_DEBUG_ERROR, "prefs", "Error reading prefs: %s\n", | |
989 error->message); | |
990 g_error_free(error); | |
991 g_free(filename); | |
992 prefs_is_loaded = TRUE; | |
993 | |
994 return FALSE; | |
995 #endif /* _WIN32 */ | |
996 } | |
997 | |
998 context = g_markup_parse_context_new(&prefs_parser, 0, NULL, NULL); | |
999 | |
1000 if(!g_markup_parse_context_parse(context, contents, length, NULL)) { | |
1001 g_markup_parse_context_free(context); | |
1002 g_free(contents); | |
1003 g_free(filename); | |
1004 prefs_is_loaded = TRUE; | |
1005 | |
1006 return FALSE; | |
1007 } | |
1008 | |
1009 if(!g_markup_parse_context_end_parse(context, NULL)) { | |
1010 gaim_debug(GAIM_DEBUG_ERROR, "prefs", "Error parsing %s\n", filename); | |
1011 g_markup_parse_context_free(context); | |
1012 g_free(contents); | |
1013 g_free(filename); | |
1014 prefs_is_loaded = TRUE; | |
1015 | |
1016 return FALSE; | |
1017 } | |
1018 | |
1019 gaim_debug(GAIM_DEBUG_INFO, "prefs", "Finished reading %s\n", filename); | |
1020 g_markup_parse_context_free(context); | |
1021 g_free(contents); | |
1022 g_free(filename); | |
1023 prefs_is_loaded = TRUE; | |
1024 | |
1025 return TRUE; | |
1026 } | |
1027 | |
1028 void gaim_prefs_update_old() { | |
1029 /* Remove some no-longer-used prefs */ | 1049 /* Remove some no-longer-used prefs */ |
1030 gaim_prefs_remove("/core/away/auto_response/enabled"); | 1050 gaim_prefs_remove("/core/away/auto_response/enabled"); |
1031 gaim_prefs_remove("/core/away/auto_response/idle_only"); | 1051 gaim_prefs_remove("/core/away/auto_response/idle_only"); |
1032 gaim_prefs_remove("/core/away/auto_response/in_active_conv"); | 1052 gaim_prefs_remove("/core/away/auto_response/in_active_conv"); |
1033 gaim_prefs_remove("/core/away/auto_response/sec_before_resend"); | 1053 gaim_prefs_remove("/core/away/auto_response/sec_before_resend"); |
1039 gaim_prefs_remove("/core/conversations/chat/show_join"); | 1059 gaim_prefs_remove("/core/conversations/chat/show_join"); |
1040 gaim_prefs_remove("/core/conversations/chat/show_leave"); | 1060 gaim_prefs_remove("/core/conversations/chat/show_leave"); |
1041 gaim_prefs_remove("/core/conversations/combine_chat_im"); | 1061 gaim_prefs_remove("/core/conversations/combine_chat_im"); |
1042 gaim_prefs_remove("/core/conversations/use_alias_for_title"); | 1062 gaim_prefs_remove("/core/conversations/use_alias_for_title"); |
1043 } | 1063 } |
1064 | |
1065 void * | |
1066 gaim_prefs_get_handle(void) | |
1067 { | |
1068 static int handle; | |
1069 | |
1070 return &handle; | |
1071 } | |
1072 | |
1073 void | |
1074 gaim_prefs_init(void) | |
1075 { | |
1076 void *handle = gaim_prefs_get_handle(); | |
1077 | |
1078 prefs_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); | |
1079 | |
1080 gaim_prefs_connect_callback(handle, "/", prefs_save_cb, NULL); | |
1081 | |
1082 gaim_prefs_add_none("/core"); | |
1083 gaim_prefs_add_none("/plugins"); | |
1084 gaim_prefs_add_none("/plugins/core"); | |
1085 gaim_prefs_add_none("/plugins/lopl"); | |
1086 gaim_prefs_add_none("/plugins/prpl"); | |
1087 | |
1088 /* Away */ | |
1089 gaim_prefs_add_none("/core/away"); | |
1090 gaim_prefs_add_bool("/core/away/away_when_idle", TRUE); | |
1091 gaim_prefs_add_int("/core/away/mins_before_away", 5); | |
1092 /* XXX: internationalized string in prefs...evil */ | |
1093 gaim_prefs_add_string("/core/away/default_message", | |
1094 _("Slightly less boring default")); | |
1095 | |
1096 /* Away -> Auto-Reply */ | |
1097 if (!gaim_prefs_exists("/core/away/auto_response/enabled") || | |
1098 !gaim_prefs_exists("/core/away/auto_response/idle_only")) { | |
1099 gaim_prefs_add_string("/core/away/auto_reply", "awayidle"); | |
1100 } else { | |
1101 if (!gaim_prefs_get_bool("/core/away/auto_response/enabled")) { | |
1102 gaim_prefs_add_string("/core/away/auto_reply", "never"); | |
1103 } else { | |
1104 if (gaim_prefs_get_bool("/core/away/auto_response/idle_only")) { | |
1105 gaim_prefs_add_string("/core/away/auto_reply", "awayidle"); | |
1106 } else { | |
1107 gaim_prefs_add_string("/core/away/auto_reply", "away"); | |
1108 } | |
1109 } | |
1110 } | |
1111 | |
1112 /* Buddies */ | |
1113 gaim_prefs_add_none("/core/buddies"); | |
1114 | |
1115 /* Contact Priority Settings */ | |
1116 gaim_prefs_add_none("/core/contact"); | |
1117 gaim_prefs_add_bool("/core/contact/last_match", FALSE); | |
1118 gaim_prefs_add_int("/core/contact/offline_score", 4); | |
1119 gaim_prefs_add_int("/core/contact/away_score", 2); | |
1120 gaim_prefs_add_int("/core/contact/idle_score", 1); | |
1121 } | |
1122 | |
1123 void | |
1124 gaim_prefs_uninit() | |
1125 { | |
1126 if (save_timer != 0) | |
1127 { | |
1128 gaim_timeout_remove(save_timer); | |
1129 save_timer = 0; | |
1130 sync_prefs(); | |
1131 } | |
1132 | |
1133 gaim_prefs_disconnect_by_handle(gaim_prefs_get_handle()); | |
1134 } |