Mercurial > pidgin.yaz
annotate libgaim/prefs.c @ 15068:d08d7b7375c7
[gaim-migrate @ 17851]
Remember the positions of the windows depending on the titles. Moving all the
chat windows to places was getting really really annoying.
If you don't want it, turn it off by setting "remember_position" to 0 in .gntrc
committer: Tailor Script <tailor@pidgin.im>
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Thu, 30 Nov 2006 05:52:21 +0000 |
parents | dd4160b36f80 |
children | 40746bedd9a8 |
rev | line source |
---|---|
14192 | 1 /* |
2 * gaim | |
3 * | |
4 * Gaim 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 | |
6 * source distribution. | |
7 * | |
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. | |
12 * | |
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. | |
17 * | |
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 | |
24 #ifdef HAVE_CONFIG_H | |
25 #include <config.h> | |
26 #endif | |
27 | |
28 #include <string.h> | |
29 #include <stdio.h> | |
30 #include <stdlib.h> | |
31 #include <sys/stat.h> | |
32 #include <sys/types.h> | |
33 #include <glib.h> | |
34 #include "internal.h" | |
35 #include "prefs.h" | |
36 #include "debug.h" | |
37 #include "util.h" | |
38 | |
39 #ifdef _WIN32 | |
40 #include "win32dep.h" | |
41 #endif | |
42 | |
43 struct pref_cb { | |
44 GaimPrefCallback func; | |
45 gpointer data; | |
46 guint id; | |
47 void *handle; | |
48 }; | |
49 | |
50 /* TODO: This should use GaimValues? */ | |
51 struct gaim_pref { | |
52 GaimPrefType type; | |
53 char *name; | |
54 union { | |
55 gpointer generic; | |
56 gboolean boolean; | |
57 int integer; | |
58 char *string; | |
59 GList *stringlist; | |
60 } value; | |
61 GSList *callbacks; | |
62 struct gaim_pref *parent; | |
63 struct gaim_pref *sibling; | |
64 struct gaim_pref *first_child; | |
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 | |
78 static GHashTable *prefs_hash = NULL; | |
79 static guint save_timer = 0; | |
80 static gboolean prefs_loaded = FALSE; | |
81 | |
82 | |
83 /********************************************************************* | |
84 * Private utility functions * | |
85 *********************************************************************/ | |
86 | |
87 static struct | |
88 gaim_pref *find_pref(const char *name) | |
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 static 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 ? 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 ? 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; | |
197 return FALSE; | |
198 } | |
199 | |
200 static void | |
201 schedule_prefs_save(void) | |
202 { | |
203 if (save_timer == 0) | |
204 save_timer = gaim_timeout_add(5000, save_cb, NULL); | |
205 } | |
206 | |
207 | |
208 /********************************************************************* | |
209 * Reading from disk * | |
210 *********************************************************************/ | |
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 /* I introduced a bug in 2.0.0beta2. This fixes the broken | |
395 * scores on upgrade. This can be removed sometime shortly | |
396 * after 2.0.0 final is released. -- rlaager */ | |
397 if (gaim_prefs_get_int("/core/status/scores/offline") == -500 && | |
398 gaim_prefs_get_int("/core/status/scores/available") == 100 && | |
399 gaim_prefs_get_int("/core/status/scores/invisible") == -50 && | |
400 gaim_prefs_get_int("/core/status/scores/away") == -100 && | |
401 gaim_prefs_get_int("/core/status/scores/extended_away") == -200 && | |
402 gaim_prefs_get_int("/core/status/scores/idle") == -400) | |
403 { | |
404 gaim_prefs_set_int("/core/status/scores/idle", -10); | |
405 } | |
406 | |
407 return TRUE; | |
408 } | |
409 | |
410 | |
411 | |
412 static void | |
413 prefs_save_cb(const char *name, GaimPrefType type, gconstpointer val, | |
414 gpointer user_data) | |
415 { | |
416 | |
417 if(!prefs_loaded) | |
418 return; | |
419 | |
420 gaim_debug_misc("prefs", "%s changed, scheduling save.\n", name); | |
421 | |
422 schedule_prefs_save(); | |
423 } | |
424 | |
425 static char * | |
426 get_path_dirname(const char *name) | |
427 { | |
428 char *c, *str; | |
429 | |
430 str = g_strdup(name); | |
431 | |
432 if ((c = strrchr(str, '/')) != NULL) { | |
433 *c = '\0'; | |
434 | |
435 if (*str == '\0') { | |
436 g_free(str); | |
437 | |
438 str = g_strdup("/"); | |
439 } | |
440 } | |
441 else { | |
442 g_free(str); | |
443 | |
444 str = g_strdup("."); | |
445 } | |
446 | |
447 return str; | |
448 } | |
449 | |
450 static char * | |
451 get_path_basename(const char *name) | |
452 { | |
453 const char *c; | |
454 | |
455 if ((c = strrchr(name, '/')) != NULL) | |
456 return g_strdup(c + 1); | |
457 | |
458 return g_strdup(name); | |
459 } | |
460 | |
461 static char * | |
462 pref_full_name(struct gaim_pref *pref) | |
463 { | |
464 GString *name; | |
465 struct gaim_pref *parent; | |
466 | |
467 if(!pref) | |
468 return NULL; | |
469 | |
470 if(pref == &prefs) | |
471 return g_strdup("/"); | |
472 | |
473 name = g_string_new(pref->name); | |
474 parent = pref->parent; | |
475 | |
476 for(parent = pref->parent; parent && parent->name; parent = parent->parent) { | |
477 name = g_string_prepend_c(name, '/'); | |
478 name = g_string_prepend(name, parent->name); | |
479 } | |
480 name = g_string_prepend_c(name, '/'); | |
481 return g_string_free(name, FALSE); | |
482 } | |
483 | |
484 static struct gaim_pref * | |
485 find_pref_parent(const char *name) | |
486 { | |
487 char *parent_name = get_path_dirname(name); | |
488 struct gaim_pref *ret = &prefs; | |
489 | |
490 if(strcmp(parent_name, "/")) { | |
491 ret = find_pref(parent_name); | |
492 } | |
493 | |
494 g_free(parent_name); | |
495 return ret; | |
496 } | |
497 | |
498 static void | |
499 free_pref_value(struct gaim_pref *pref) | |
500 { | |
501 switch(pref->type) { | |
502 case GAIM_PREF_BOOLEAN: | |
503 pref->value.boolean = FALSE; | |
504 break; | |
505 case GAIM_PREF_INT: | |
506 pref->value.integer = 0; | |
507 break; | |
508 case GAIM_PREF_STRING: | |
509 g_free(pref->value.string); | |
510 pref->value.string = NULL; | |
511 break; | |
512 case GAIM_PREF_STRING_LIST: | |
513 { | |
514 g_list_foreach(pref->value.stringlist, (GFunc)g_free, NULL); | |
515 g_list_free(pref->value.stringlist); | |
516 } break; | |
517 case GAIM_PREF_NONE: | |
518 break; | |
519 } | |
520 } | |
521 | |
522 static struct gaim_pref * | |
523 add_pref(GaimPrefType type, const char *name) | |
524 { | |
525 struct gaim_pref *parent; | |
526 struct gaim_pref *me; | |
527 struct gaim_pref *sibling; | |
528 char *my_name; | |
529 | |
530 parent = find_pref_parent(name); | |
531 | |
532 if(!parent) | |
533 return NULL; | |
534 | |
535 my_name = get_path_basename(name); | |
536 | |
537 for(sibling = parent->first_child; sibling; sibling = sibling->sibling) { | |
538 if(!strcmp(sibling->name, my_name)) { | |
539 g_free(my_name); | |
540 return NULL; | |
541 } | |
542 } | |
543 | |
544 me = g_new0(struct gaim_pref, 1); | |
545 me->type = type; | |
546 me->name = my_name; | |
547 | |
548 me->parent = parent; | |
549 if(parent->first_child) { | |
550 /* blatant abuse of a for loop */ | |
551 for(sibling = parent->first_child; sibling->sibling; | |
552 sibling = sibling->sibling); | |
553 sibling->sibling = me; | |
554 } else { | |
555 parent->first_child = me; | |
556 } | |
557 | |
558 g_hash_table_insert(prefs_hash, g_strdup(name), (gpointer)me); | |
559 | |
560 return me; | |
561 } | |
562 | |
563 void | |
564 gaim_prefs_add_none(const char *name) | |
565 { | |
566 add_pref(GAIM_PREF_NONE, name); | |
567 } | |
568 | |
569 void | |
570 gaim_prefs_add_bool(const char *name, gboolean value) | |
571 { | |
572 struct gaim_pref *pref = add_pref(GAIM_PREF_BOOLEAN, name); | |
573 | |
574 if(!pref) | |
575 return; | |
576 | |
577 pref->value.boolean = value; | |
578 } | |
579 | |
580 void | |
581 gaim_prefs_add_int(const char *name, int value) | |
582 { | |
583 struct gaim_pref *pref = add_pref(GAIM_PREF_INT, name); | |
584 | |
585 if(!pref) | |
586 return; | |
587 | |
588 pref->value.integer = value; | |
589 } | |
590 | |
591 void | |
592 gaim_prefs_add_string(const char *name, const char *value) | |
593 { | |
594 struct gaim_pref *pref = add_pref(GAIM_PREF_STRING, name); | |
595 | |
596 if(!pref) | |
597 return; | |
598 | |
599 pref->value.string = g_strdup(value); | |
600 } | |
601 | |
602 void | |
603 gaim_prefs_add_string_list(const char *name, GList *value) | |
604 { | |
605 struct gaim_pref *pref = add_pref(GAIM_PREF_STRING_LIST, name); | |
606 GList *tmp; | |
607 | |
608 if(!pref) | |
609 return; | |
610 | |
611 for(tmp = value; tmp; tmp = tmp->next) | |
612 pref->value.stringlist = g_list_append(pref->value.stringlist, | |
613 g_strdup(tmp->data)); | |
614 } | |
615 | |
616 static void | |
617 remove_pref(struct gaim_pref *pref) | |
618 { | |
619 char *name; | |
15024
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
620 GSList *l; |
14192 | 621 |
622 if(!pref || pref == &prefs) | |
623 return; | |
624 | |
625 while(pref->first_child) | |
626 remove_pref(pref->first_child); | |
627 | |
628 if(pref->parent->first_child == pref) { | |
629 pref->parent->first_child = pref->sibling; | |
630 } else { | |
631 struct gaim_pref *sib = pref->parent->first_child; | |
632 while(sib && sib->sibling != pref) | |
633 sib = sib->sibling; | |
634 if(sib) | |
635 sib->sibling = pref->sibling; | |
636 } | |
637 | |
638 name = pref_full_name(pref); | |
639 | |
640 gaim_debug_info("prefs", "removing pref %s\n", name); | |
641 | |
642 g_hash_table_remove(prefs_hash, name); | |
643 g_free(name); | |
644 | |
645 free_pref_value(pref); | |
646 | |
15024
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
647 while((l = pref->callbacks) != NULL) { |
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
648 pref->callbacks = pref->callbacks->next; |
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
649 g_free(l->data); |
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
650 g_slist_free_1(l); |
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
651 } |
14192 | 652 g_free(pref->name); |
653 g_free(pref); | |
654 } | |
655 | |
656 void | |
657 gaim_prefs_remove(const char *name) | |
658 { | |
659 struct gaim_pref *pref = find_pref(name); | |
660 | |
661 if(!pref) | |
662 return; | |
663 | |
664 remove_pref(pref); | |
665 } | |
666 | |
667 void | |
668 gaim_prefs_destroy() | |
669 { | |
670 gaim_prefs_remove("/"); | |
671 } | |
672 | |
673 static void | |
674 do_callbacks(const char* name, struct gaim_pref *pref) | |
675 { | |
676 GSList *cbs; | |
677 struct gaim_pref *cb_pref; | |
678 for(cb_pref = pref; cb_pref; cb_pref = cb_pref->parent) { | |
679 for(cbs = cb_pref->callbacks; cbs; cbs = cbs->next) { | |
680 struct pref_cb *cb = cbs->data; | |
681 cb->func(name, pref->type, pref->value.generic, cb->data); | |
682 } | |
683 } | |
684 } | |
685 | |
686 void | |
687 gaim_prefs_trigger_callback(const char *name) | |
688 { | |
689 struct gaim_pref *pref = find_pref(name); | |
690 | |
691 if(!pref) { | |
692 gaim_debug_error("prefs", | |
693 "gaim_prefs_trigger_callback: Unknown pref %s\n", name); | |
694 return; | |
695 } | |
696 | |
697 do_callbacks(name, pref); | |
698 } | |
699 | |
700 void | |
701 gaim_prefs_set_generic(const char *name, gpointer value) | |
702 { | |
703 struct gaim_pref *pref = find_pref(name); | |
704 | |
705 if(!pref) { | |
706 gaim_debug_error("prefs", | |
707 "gaim_prefs_set_generic: Unknown pref %s\n", name); | |
708 return; | |
709 } | |
710 | |
711 pref->value.generic = value; | |
712 do_callbacks(name, pref); | |
713 } | |
714 | |
715 void | |
716 gaim_prefs_set_bool(const char *name, gboolean value) | |
717 { | |
718 struct gaim_pref *pref = find_pref(name); | |
719 | |
720 if(pref) { | |
721 if(pref->type != GAIM_PREF_BOOLEAN) { | |
722 gaim_debug_error("prefs", | |
723 "gaim_prefs_set_bool: %s not a boolean pref\n", name); | |
724 return; | |
725 } | |
726 | |
727 if(pref->value.boolean != value) { | |
728 pref->value.boolean = value; | |
729 do_callbacks(name, pref); | |
730 } | |
731 } else { | |
732 gaim_prefs_add_bool(name, value); | |
733 } | |
734 } | |
735 | |
736 void | |
737 gaim_prefs_set_int(const char *name, int value) | |
738 { | |
739 struct gaim_pref *pref = find_pref(name); | |
740 | |
741 if(pref) { | |
742 if(pref->type != GAIM_PREF_INT) { | |
743 gaim_debug_error("prefs", | |
744 "gaim_prefs_set_int: %s not an integer pref\n", name); | |
745 return; | |
746 } | |
747 | |
748 if(pref->value.integer != value) { | |
749 pref->value.integer = value; | |
750 do_callbacks(name, pref); | |
751 } | |
752 } else { | |
753 gaim_prefs_add_int(name, value); | |
754 } | |
755 } | |
756 | |
757 void | |
758 gaim_prefs_set_string(const char *name, const char *value) | |
759 { | |
760 struct gaim_pref *pref = find_pref(name); | |
761 | |
762 if(pref) { | |
763 if(pref->type != GAIM_PREF_STRING) { | |
764 gaim_debug_error("prefs", | |
765 "gaim_prefs_set_string: %s not a string pref\n", name); | |
766 return; | |
767 } | |
768 | |
769 if((value && !pref->value.string) || | |
770 (!value && pref->value.string) || | |
771 (value && pref->value.string && | |
772 strcmp(pref->value.string, value))) { | |
773 g_free(pref->value.string); | |
774 pref->value.string = g_strdup(value); | |
775 do_callbacks(name, pref); | |
776 } | |
777 } else { | |
778 gaim_prefs_add_string(name, value); | |
779 } | |
780 } | |
781 | |
782 void | |
783 gaim_prefs_set_string_list(const char *name, GList *value) | |
784 { | |
785 struct gaim_pref *pref = find_pref(name); | |
786 if(pref) { | |
787 GList *tmp; | |
788 | |
789 if(pref->type != GAIM_PREF_STRING_LIST) { | |
790 gaim_debug_error("prefs", | |
791 "gaim_prefs_set_string_list: %s not a string list pref\n", | |
792 name); | |
793 return; | |
794 } | |
795 | |
796 g_list_foreach(pref->value.stringlist, (GFunc)g_free, NULL); | |
797 g_list_free(pref->value.stringlist); | |
798 pref->value.stringlist = NULL; | |
799 | |
800 for(tmp = value; tmp; tmp = tmp->next) | |
801 pref->value.stringlist = g_list_prepend(pref->value.stringlist, | |
802 g_strdup(tmp->data)); | |
803 pref->value.stringlist = g_list_reverse(pref->value.stringlist); | |
804 | |
805 do_callbacks(name, pref); | |
806 | |
807 } else { | |
808 gaim_prefs_add_string_list(name, value); | |
809 } | |
810 } | |
811 | |
812 gboolean | |
813 gaim_prefs_exists(const char *name) | |
814 { | |
815 struct gaim_pref *pref = find_pref(name); | |
816 | |
817 if (pref != NULL) | |
818 return TRUE; | |
819 | |
820 return FALSE; | |
821 } | |
822 | |
823 GaimPrefType | |
824 gaim_prefs_get_type(const char *name) | |
825 { | |
826 struct gaim_pref *pref = find_pref(name); | |
827 | |
828 if (pref == NULL) | |
829 return GAIM_PREF_NONE; | |
830 | |
831 return (pref->type); | |
832 } | |
833 | |
834 gboolean | |
835 gaim_prefs_get_bool(const char *name) | |
836 { | |
837 struct gaim_pref *pref = find_pref(name); | |
838 | |
839 if(!pref) { | |
840 gaim_debug_error("prefs", | |
841 "gaim_prefs_get_bool: Unknown pref %s\n", name); | |
842 return FALSE; | |
843 } else if(pref->type != GAIM_PREF_BOOLEAN) { | |
844 gaim_debug_error("prefs", | |
845 "gaim_prefs_get_bool: %s not a boolean pref\n", name); | |
846 return FALSE; | |
847 } | |
848 | |
849 return pref->value.boolean; | |
850 } | |
851 | |
852 int | |
853 gaim_prefs_get_int(const char *name) | |
854 { | |
855 struct gaim_pref *pref = find_pref(name); | |
856 | |
857 if(!pref) { | |
858 gaim_debug_error("prefs", | |
859 "gaim_prefs_get_int: Unknown pref %s\n", name); | |
860 return 0; | |
861 } else if(pref->type != GAIM_PREF_INT) { | |
862 gaim_debug_error("prefs", | |
863 "gaim_prefs_get_int: %s not an integer pref\n", name); | |
864 return 0; | |
865 } | |
866 | |
867 return pref->value.integer; | |
868 } | |
869 | |
870 const char * | |
871 gaim_prefs_get_string(const char *name) | |
872 { | |
873 struct gaim_pref *pref = find_pref(name); | |
874 | |
875 if(!pref) { | |
876 gaim_debug_error("prefs", | |
877 "gaim_prefs_get_string: Unknown pref %s\n", name); | |
878 return NULL; | |
879 } else if(pref->type != GAIM_PREF_STRING) { | |
880 gaim_debug_error("prefs", | |
881 "gaim_prefs_get_string: %s not a string pref\n", name); | |
882 return NULL; | |
883 } | |
884 | |
885 return pref->value.string; | |
886 } | |
887 | |
888 GList * | |
889 gaim_prefs_get_string_list(const char *name) | |
890 { | |
891 struct gaim_pref *pref = find_pref(name); | |
892 GList *ret = NULL, *tmp; | |
893 | |
894 if(!pref) { | |
895 gaim_debug_error("prefs", | |
896 "gaim_prefs_get_string_list: Unknown pref %s\n", name); | |
897 return NULL; | |
898 } else if(pref->type != GAIM_PREF_STRING_LIST) { | |
899 gaim_debug_error("prefs", | |
900 "gaim_prefs_get_string_list: %s not a string list pref\n", name); | |
901 return NULL; | |
902 } | |
903 | |
904 for(tmp = pref->value.stringlist; tmp; tmp = tmp->next) | |
905 ret = g_list_prepend(ret, g_strdup(tmp->data)); | |
906 ret = g_list_reverse(ret); | |
907 | |
908 return ret; | |
909 } | |
910 | |
911 void | |
912 gaim_prefs_rename(const char *oldname, const char *newname) | |
913 { | |
914 struct gaim_pref *oldpref, *newpref; | |
915 | |
916 oldpref = find_pref(oldname); | |
917 | |
918 /* it's already been renamed, call off the dogs */ | |
919 if(!oldpref) | |
920 return; | |
921 | |
922 if (oldpref->first_child != NULL) /* can't rename parents */ | |
923 { | |
924 gaim_debug_error("prefs", "Unable to rename %s to %s: can't rename parents\n", oldname, newname); | |
925 return; | |
926 } | |
927 | |
928 | |
929 newpref = find_pref(newname); | |
930 | |
931 if (newpref == NULL) | |
932 { | |
933 gaim_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname, newname); | |
934 return; | |
935 } | |
936 | |
937 if (oldpref->type != newpref->type) | |
938 { | |
939 gaim_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname, newname); | |
940 return; | |
941 } | |
942 | |
943 gaim_debug_info("prefs", "Renaming %s to %s\n", oldname, newname); | |
944 | |
945 switch(oldpref->type) { | |
946 case GAIM_PREF_NONE: | |
947 break; | |
948 case GAIM_PREF_BOOLEAN: | |
949 gaim_prefs_set_bool(newname, oldpref->value.boolean); | |
950 break; | |
951 case GAIM_PREF_INT: | |
952 gaim_prefs_set_int(newname, oldpref->value.integer); | |
953 break; | |
954 case GAIM_PREF_STRING: | |
955 gaim_prefs_set_string(newname, oldpref->value.string); | |
956 break; | |
957 case GAIM_PREF_STRING_LIST: | |
958 gaim_prefs_set_string_list(newname, oldpref->value.stringlist); | |
959 break; | |
960 } | |
961 | |
962 remove_pref(oldpref); | |
963 } | |
964 | |
965 void | |
966 gaim_prefs_rename_boolean_toggle(const char *oldname, const char *newname) | |
967 { | |
968 struct gaim_pref *oldpref, *newpref; | |
969 | |
970 oldpref = find_pref(oldname); | |
971 | |
972 /* it's already been renamed, call off the cats */ | |
973 if(!oldpref) | |
974 return; | |
975 | |
976 if (oldpref->type != GAIM_PREF_BOOLEAN) | |
977 { | |
978 gaim_debug_error("prefs", "Unable to rename %s to %s: old pref not a boolean\n", oldname, newname); | |
979 return; | |
980 } | |
981 | |
982 if (oldpref->first_child != NULL) /* can't rename parents */ | |
983 { | |
984 gaim_debug_error("prefs", "Unable to rename %s to %s: can't rename parents\n", oldname, newname); | |
985 return; | |
986 } | |
987 | |
988 | |
989 newpref = find_pref(newname); | |
990 | |
991 if (newpref == NULL) | |
992 { | |
993 gaim_debug_error("prefs", "Unable to rename %s to %s: new pref not created\n", oldname, newname); | |
994 return; | |
995 } | |
996 | |
997 if (oldpref->type != newpref->type) | |
998 { | |
999 gaim_debug_error("prefs", "Unable to rename %s to %s: differing types\n", oldname, newname); | |
1000 return; | |
1001 } | |
1002 | |
1003 gaim_debug_info("prefs", "Renaming and toggling %s to %s\n", oldname, newname); | |
1004 gaim_prefs_set_bool(newname, !(oldpref->value.boolean)); | |
1005 | |
1006 remove_pref(oldpref); | |
1007 } | |
1008 | |
1009 guint | |
1010 gaim_prefs_connect_callback(void *handle, const char *name, GaimPrefCallback func, gpointer data) | |
1011 { | |
1012 struct gaim_pref *pref; | |
1013 struct pref_cb *cb; | |
1014 static guint cb_id = 0; | |
1015 | |
15024
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
1016 g_return_val_if_fail(name != NULL, 0); |
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
1017 g_return_val_if_fail(func != NULL, 0); |
dd4160b36f80
[gaim-migrate @ 17805]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14874
diff
changeset
|
1018 |
14192 | 1019 pref = find_pref(name); |
1020 if (pref == NULL) | |
1021 return 0; | |
1022 | |
1023 cb = g_new0(struct pref_cb, 1); | |
1024 | |
1025 cb->func = func; | |
1026 cb->data = data; | |
1027 cb->id = ++cb_id; | |
1028 cb->handle = handle; | |
1029 | |
1030 pref->callbacks = g_slist_append(pref->callbacks, cb); | |
1031 | |
1032 return cb->id; | |
1033 } | |
1034 | |
1035 static gboolean | |
1036 disco_callback_helper(struct gaim_pref *pref, guint callback_id) | |
1037 { | |
1038 GSList *cbs; | |
1039 struct gaim_pref *child; | |
1040 | |
1041 if(!pref) | |
1042 return FALSE; | |
1043 | |
1044 for(cbs = pref->callbacks; cbs; cbs = cbs->next) { | |
1045 struct pref_cb *cb = cbs->data; | |
1046 if(cb->id == callback_id) { | |
1047 pref->callbacks = g_slist_delete_link(pref->callbacks, cbs); | |
1048 g_free(cb); | |
1049 return TRUE; | |
1050 } | |
1051 } | |
1052 | |
1053 for(child = pref->first_child; child; child = child->sibling) { | |
1054 if(disco_callback_helper(child, callback_id)) | |
1055 return TRUE; | |
1056 } | |
1057 | |
1058 return FALSE; | |
1059 } | |
1060 | |
1061 void | |
1062 gaim_prefs_disconnect_callback(guint callback_id) | |
1063 { | |
1064 disco_callback_helper(&prefs, callback_id); | |
1065 } | |
1066 | |
1067 static void | |
1068 disco_callback_helper_handle(struct gaim_pref *pref, void *handle) | |
1069 { | |
1070 GSList *cbs; | |
1071 struct gaim_pref *child; | |
1072 | |
1073 if(!pref) | |
1074 return; | |
1075 | |
1076 cbs = pref->callbacks; | |
1077 while (cbs != NULL) { | |
1078 struct pref_cb *cb = cbs->data; | |
1079 if(cb->handle == handle) { | |
1080 pref->callbacks = g_slist_delete_link(pref->callbacks, cbs); | |
1081 g_free(cb); | |
1082 cbs = pref->callbacks; | |
1083 } else | |
1084 cbs = cbs->next; | |
1085 } | |
1086 | |
1087 for(child = pref->first_child; child; child = child->sibling) | |
1088 disco_callback_helper_handle(child, handle); | |
1089 } | |
1090 | |
1091 void | |
1092 gaim_prefs_disconnect_by_handle(void *handle) | |
1093 { | |
1094 g_return_if_fail(handle != NULL); | |
1095 | |
1096 disco_callback_helper_handle(&prefs, handle); | |
1097 } | |
1098 | |
1099 void | |
1100 gaim_prefs_update_old() | |
1101 { | |
1102 /* Remove some no-longer-used prefs */ | |
1103 gaim_prefs_remove("/core/away/auto_response/enabled"); | |
1104 gaim_prefs_remove("/core/away/auto_response/idle_only"); | |
1105 gaim_prefs_remove("/core/away/auto_response/in_active_conv"); | |
1106 gaim_prefs_remove("/core/away/auto_response/sec_before_resend"); | |
1107 gaim_prefs_remove("/core/away/auto_response"); | |
1108 gaim_prefs_remove("/core/away/default_message"); | |
1109 gaim_prefs_remove("/core/buddies/use_server_alias"); | |
1110 gaim_prefs_remove("/core/conversations/away_back_on_send"); | |
1111 gaim_prefs_remove("/core/conversations/send_urls_as_links"); | |
1112 gaim_prefs_remove("/core/conversations/im/show_login"); | |
1113 gaim_prefs_remove("/core/conversations/chat/show_join"); | |
1114 gaim_prefs_remove("/core/conversations/chat/show_leave"); | |
1115 gaim_prefs_remove("/core/conversations/combine_chat_im"); | |
1116 gaim_prefs_remove("/core/conversations/use_alias_for_title"); | |
1117 gaim_prefs_remove("/core/logging/log_signon_signoff"); | |
1118 gaim_prefs_remove("/core/logging/log_idle_state"); | |
1119 gaim_prefs_remove("/core/logging/log_away_state"); | |
1120 gaim_prefs_remove("/core/logging/log_own_states"); | |
1121 gaim_prefs_remove("/core/status/scores/hidden"); | |
1122 gaim_prefs_remove("/plugins/core/autorecon/hide_connected_error"); | |
1123 gaim_prefs_remove("/plugins/core/autorecon/hide_connecting_error"); | |
1124 gaim_prefs_remove("/plugins/core/autorecon/hide_reconnecting_dialog"); | |
1125 gaim_prefs_remove("/plugins/core/autorecon/restore_state"); | |
1126 gaim_prefs_remove("/plugins/core/autorecon"); | |
14874
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1127 |
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1128 /* Convert old sounds while_away pref to new 3-way pref. */ |
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1129 if (gaim_prefs_exists("/core/sound/while_away") && |
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1130 gaim_prefs_get_bool("/core/sound/while_away")) |
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1131 { |
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1132 gaim_prefs_set_int("/core/sound/while_status", 3); |
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1133 } |
71149a751439
[gaim-migrate @ 17643]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
1134 gaim_prefs_remove("/core/sound/while_away"); |
14192 | 1135 } |
1136 | |
1137 void * | |
1138 gaim_prefs_get_handle(void) | |
1139 { | |
1140 static int handle; | |
1141 | |
1142 return &handle; | |
1143 } | |
1144 | |
1145 void | |
1146 gaim_prefs_init(void) | |
1147 { | |
1148 void *handle = gaim_prefs_get_handle(); | |
1149 | |
1150 prefs_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); | |
1151 | |
1152 gaim_prefs_connect_callback(handle, "/", prefs_save_cb, NULL); | |
1153 | |
1154 gaim_prefs_add_none("/core"); | |
1155 gaim_prefs_add_none("/plugins"); | |
1156 gaim_prefs_add_none("/plugins/core"); | |
1157 gaim_prefs_add_none("/plugins/lopl"); | |
1158 gaim_prefs_add_none("/plugins/prpl"); | |
1159 | |
1160 /* Away */ | |
1161 gaim_prefs_add_none("/core/away"); | |
1162 gaim_prefs_add_string("/core/away/idle_reporting", "system"); | |
1163 gaim_prefs_add_bool("/core/away/away_when_idle", TRUE); | |
1164 gaim_prefs_add_int("/core/away/mins_before_away", 5); | |
1165 | |
1166 /* Away -> Auto-Reply */ | |
1167 if (!gaim_prefs_exists("/core/away/auto_response/enabled") || | |
1168 !gaim_prefs_exists("/core/away/auto_response/idle_only")) | |
1169 { | |
1170 gaim_prefs_add_string("/core/away/auto_reply", "awayidle"); | |
1171 } | |
1172 else | |
1173 { | |
1174 if (!gaim_prefs_get_bool("/core/away/auto_response/enabled")) | |
1175 { | |
1176 gaim_prefs_add_string("/core/away/auto_reply", "never"); | |
1177 } | |
1178 else | |
1179 { | |
1180 if (gaim_prefs_get_bool("/core/away/auto_response/idle_only")) | |
1181 { | |
1182 gaim_prefs_add_string("/core/away/auto_reply", "awayidle"); | |
1183 } | |
1184 else | |
1185 { | |
1186 gaim_prefs_add_string("/core/away/auto_reply", "away"); | |
1187 } | |
1188 } | |
1189 } | |
1190 | |
1191 /* Buddies */ | |
1192 gaim_prefs_add_none("/core/buddies"); | |
1193 | |
1194 /* Contact Priority Settings */ | |
1195 gaim_prefs_add_none("/core/contact"); | |
1196 gaim_prefs_add_bool("/core/contact/last_match", FALSE); | |
1197 gaim_prefs_remove("/core/contact/offline_score"); | |
1198 gaim_prefs_remove("/core/contact/away_score"); | |
1199 gaim_prefs_remove("/core/contact/idle_score"); | |
1200 } | |
1201 | |
1202 void | |
1203 gaim_prefs_uninit() | |
1204 { | |
1205 if (save_timer != 0) | |
1206 { | |
1207 gaim_timeout_remove(save_timer); | |
1208 save_timer = 0; | |
1209 sync_prefs(); | |
1210 } | |
1211 | |
1212 gaim_prefs_disconnect_by_handle(gaim_prefs_get_handle()); | |
1213 } |