1 /*
2 |  Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net>
3 |  Copyright (C) 2006 James Liggett <jrliggett at cox.net>
4 |  Part of the gtkpod project.
5 |
6 |  URL: http://www.gtkpod.org/
7 |  URL: http://gtkpod.sourceforge.net/
8 |
9 |  This program is free software; you can redistribute it and/or modify
10 |  it under the terms of the GNU General Public License as published by
11 |  the Free Software Foundation; either version 2 of the License, or
12 |  (at your option) any later version.
13 |
14 |  This program is distributed in the hope that it will be useful,
15 |  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 |  GNU General Public License for more details.
18 |
19 |  You should have received a copy of the GNU General Public License
20 |  along with this program; if not, write to the Free Software
21 |  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 |
23 |  iTunes and iPod are trademarks of Apple
24 |
25 |  This product is not supported/written/published by Apple!
26 |
27 |  $Id$
28 */
29 
30 /* -------------------------------------------------------------------
31  *
32  * HOWTO add a new_option to the prefs dialog
33  *
34  * - add the desired option to the prefs window using glade-2
35  *
36  * - set the default value of new_option in set_default_preferences() in prefs.c
37  *
38  * - add a callback on_new_option_*() to prefs_windows.c to set the
39  *   new value.
40  *   The value is applied to the actual prefs when pressing the "OK"
41  *   or "Apply" button in the prefs window.
42  *
43  * - add code to prefs_window_create() in prefs_window.c to set the
44  *   correct state of the option in the prefs window.
45  *
46  * - if you want new_option to be a command line option as well, add
47  *   code to usage() and read_commandline().
48  *
49  * - for environment variables, add code to read_environment().
50  *
51  * ---------------------------------------------------------------- */
52 
53 /* ----------------------------------------------------------------
54  *
55  * The prefs module should be thread safe. The hash table is locked
56  * before each read or write access.
57  *
58  * The temp_prefs module is not thread-safe. If necessary a locking
59  * mechanism can be implemented.
60  *
61  * ---------------------------------------------------------------- */
62 
63 
64 
65 
66 /* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
67    Ditto for AIX 3.2 and <stdlib.h>.  */
68 #ifndef _NO_PROTO
69 # define _NO_PROTO
70 #endif
71 
72 #ifdef HAVE_CONFIG_H
73 #  include <config.h>
74 #endif
75 
76 #include <stdio.h>
77 #include <string.h>
78 #include <glib/gstdio.h>
79 #ifdef HAVE_GETOPT_LONG_ONLY
80 #  include <getopt.h>
81 #else
82 #  include "getopt.h"
83 #endif
84 
85 #include "clientserver.h"
86 #include "misc.h"
87 #include "prefs.h"
88 
89 /*
90  * Data global to this module only
91  */
92 
93 /* End-of-list marker for variable-length lists */
94 #define LIST_END_MARKER "----++++----"
95 
96 struct temp_prefs_save
97 {
98     GIOChannel *gio;
99     GError **error;
100     gboolean success;
101 };
102 
103 struct sub_data
104 {
105     TempPrefs *temp_prefs;
106     TempPrefs *temp_prefs_orig;
107     const gchar *subkey;
108     const gchar *subkey2;
109     gboolean exists;
110 };
111 
112 /* Pointer to preferences hash table */
113 static GHashTable *prefs_table = NULL;
114 static GMutex *prefs_table_mutex = NULL;
115 
116 /*
117  * Functions used by this module only
118  */
119 void discard_prefs (void);
120 
121 /* Different paths that can be set in the prefs window */
122 typedef enum
123 {
124     PATH_PLAY_NOW = 0,
125     PATH_PLAY_ENQUEUE,
126     PATH_MP3GAIN,
127     PATH_SYNC_CONTACTS,
128     PATH_SYNC_CALENDAR,
129     PATH_MSERV_MUSIC_ROOT,
130     PATH_MSERV_TRACKINFO_ROOT,
131     PATH_SYNC_NOTES,
132     PATH_AACGAIN,
133     PATH_NUM
134 } PathType;
135 
136 /* enum for reading of options */
137 enum {
138   GP_HELP,
139   GP_PLAYCOUNT,
140   GP_MOUNT,
141   GP_PRINT_HASH,
142 };
143 
144 
145 /* Lock the prefs table. If the table is already locked the calling
146  * thread will remain blocked until the lock is released by the other thread. */
lock_prefs_table()147 static void lock_prefs_table ()
148 {
149     g_return_if_fail (prefs_table_mutex);
150     g_mutex_lock (prefs_table_mutex);
151 }
152 
153 /* Unlock the prefs table again. */
unlock_prefs_table()154 static void unlock_prefs_table ()
155 {
156     g_return_if_fail (prefs_table_mutex);
157     g_mutex_unlock (prefs_table_mutex);
158 }
159 
160 
161 /* Set default preferences */
set_default_preferences()162 static void set_default_preferences()
163 {
164     int i;
165     gchar *str;
166 
167     prefs_set_int("update_existing", FALSE);
168     prefs_set_int("id3_write", FALSE);
169     prefs_set_int("id3_write_id3v24", FALSE);
170     prefs_set_int(KEY_SYNC_DELETE_TRACKS, TRUE);
171     prefs_set_int(KEY_SYNC_CONFIRM_DELETE, TRUE);
172     prefs_set_int(KEY_SYNC_SHOW_SUMMARY, TRUE);
173     prefs_set_int("show_duplicates", TRUE);
174     prefs_set_int("show_non_updated", TRUE);
175     prefs_set_int("show_updated", TRUE);
176     prefs_set_int("photo_library_confirm_delete", TRUE);
177     prefs_set_int("mserv_report_probs", TRUE);
178     prefs_set_int("delete_ipod", TRUE);
179     prefs_set_int("delete_file", TRUE);
180     prefs_set_int("delete_local_file", TRUE);
181     prefs_set_int("delete_database", TRUE);
182     prefs_set_string("initial_mountpoint", "/mnt/ipod");
183     prefs_set_string ("path_play_now", "xmms %s");
184     prefs_set_string ("path_play_enqueue", "xmms -e %s");
185     prefs_set_string ("path_mserv_trackinfo_root", "/var/lib/mserv/trackinfo/");
186     prefs_set_string ("coverart_display_bg_color", "#000000");
187     prefs_set_string ("coverart_display_fg_color", "#FFFFFF");
188 
189     str = g_build_filename (SCRIPTDIR, "convert-ogg2mp3.sh", NULL);
190     prefs_set_string ("path_conv_ogg", str);
191     g_free (str);
192     prefs_set_int ("convert_ogg", TRUE);
193 
194     str = g_build_filename (SCRIPTDIR, "convert-flac2mp3.sh", NULL);
195     prefs_set_string ("path_conv_flac", str);
196     g_free (str);
197     prefs_set_int ("convert_flac", TRUE);
198 
199     str = g_build_filename (SCRIPTDIR, "convert-wav2mp3.sh", NULL);
200     prefs_set_string ("path_conv_wav", str);
201     g_free (str);
202     prefs_set_int ("convert_wav", FALSE);
203 
204 
205     /* Set sorting tab defaults */
206     for (i = 0; i < SORT_TAB_MAX; i++)
207     {
208 	prefs_set_int_index("st_autoselect", i, TRUE);
209 	prefs_set_int_index("st_category", i, (i < ST_CAT_NUM ? i : 0));
210 	prefs_set_int_index("sp_or", i, FALSE);
211 	prefs_set_int_index("sp_rating_cond", i, FALSE);
212 	prefs_set_int_index("sp_playcount_cond", i, FALSE);
213 	prefs_set_int_index("sp_played_cond", i, FALSE);
214 	prefs_set_int_index("sp_modified_cond", i, FALSE);
215 	prefs_set_int_index("sp_added_cond", i, FALSE);
216 	prefs_set_int_index("sp_rating_state", i, 0);
217 	prefs_set_string_index("sp_played_state", i, ">4w");
218 	prefs_set_string_index("sp_modified_state", i, "<1d");
219 	prefs_set_string_index("sp_added_state", i, "<1d");
220 	prefs_set_int_index("sp_playcount_low", i, 0);
221 	prefs_set_int_index("sp_playcount_high", i, -1);
222 	prefs_set_int_index("sp_autodisplay", i, FALSE);
223     }
224 
225     prefs_set_int("sort_tab_num", 2);
226 
227     /* Set colum preferences */
228     for (i = 0; i < TM_NUM_COLUMNS; i++)
229     {
230 	prefs_set_int_index("col_order", i, i);
231     }
232 
233     prefs_set_int_index("col_visible", TM_COLUMN_ARTIST, TRUE);
234     prefs_set_int_index("col_visible", TM_COLUMN_ALBUM, TRUE);
235     prefs_set_int_index("col_visible", TM_COLUMN_TITLE, TRUE);
236     prefs_set_int_index("col_visible", TM_COLUMN_TRACKLEN, TRUE);
237     prefs_set_int_index("col_visible", TM_COLUMN_RATING, TRUE);
238 
239     for (i = 0; i < TM_NUM_TAGS_PREFS; i++)
240     {
241 	prefs_set_int_index("tag_autoset", i, FALSE);
242     }
243 
244     prefs_set_int_index("tag_autoset", TM_COLUMN_TITLE, TRUE);
245 
246     prefs_set_int("horizontal_scrollbar", TRUE);
247     prefs_set_int("filter_tabs_top", FALSE);
248 
249     /* Set pane positions--Let gtk worry about position */
250     for (i = 0; i < PANED_NUM; i++)
251 	prefs_set_int_index("paned_pos_", i, -1);
252 
253     prefs_set_int("mpl_autoselect", TRUE);
254 
255     /* Set window sizes */
256     prefs_set_int("size_gtkpod.x", 780);
257     prefs_set_int("size_gtkpod.y", 580);
258     prefs_set_int("size_cal.x", 500);
259     prefs_set_int("size_cal.y", 300);
260     prefs_set_int("size_conf_sw.x", 300);
261     prefs_set_int("size_conf_sw.y", 300);
262     prefs_set_int("size_conf.x", 300);
263     prefs_set_int("size_conf.y", -1);
264     prefs_set_int("size_dirbr.x", 300);
265     prefs_set_int("size_dirbr.y", 400);
266     prefs_set_int("size_prefs.x", -1);
267     prefs_set_int("size_prefs.y", 480);
268     prefs_set_int("size_info.x", 510);
269     prefs_set_int("size_info.y", 300);
270 
271     /* size of file dialog if there is not a details textview */
272     prefs_set_int("size_file_dialog.x", 320);
273     prefs_set_int("size_file_dialog.y", 140);
274 
275     /* size of file dialog if there is a details textview */
276     prefs_set_int("size_file_dialog_details.x", 320);
277     prefs_set_int("size_file_dialog_details.y", 140);
278 
279     prefs_set_int("readtags", TRUE);
280     prefs_set_int("parsetags", FALSE);
281     prefs_set_int("parsetags_overwrite", FALSE);
282     prefs_set_string("parsetags_template", "%a - %A/%T %t.mp3;%t.wav");
283     prefs_set_int("coverart_apic", TRUE);
284     prefs_set_int("coverart_file", TRUE);
285     prefs_set_string("coverart_template", "%A;folder.jpg");
286     prefs_set_string("video_thumbnailer_prog", "totem-video-thumbnailer %f %o");
287     prefs_set_int("mserv_use", FALSE);
288     prefs_set_string("mserv_username", "");
289     prefs_set_int("startup_messages", TRUE);
290     prefs_set_int("add_recursively", TRUE);
291     prefs_set_int("info_window", FALSE);
292     prefs_set_int("last_prefs_page", 0);
293     prefs_set_int("multi_edit_title", TRUE);
294     prefs_set_int("multi_edit", FALSE);
295     prefs_set_int("not_played_track", TRUE);
296     prefs_set_int("misc_track_nr", 25);
297     prefs_set_int("update_charset", FALSE);
298     prefs_set_int("display_tooltips_main", TRUE);
299     prefs_set_int("display_tooltips_prefs", TRUE);
300     prefs_set_int("display_toolbar", TRUE);
301     prefs_set_int("toolbar_style", GTK_TOOLBAR_BOTH);
302     prefs_set_int("sha1", TRUE);
303     prefs_set_int("file_dialog_details_expanded", FALSE);
304 
305     /* Set last browsed directory */
306     str = g_get_current_dir();
307 
308     if (str)
309     {
310 	prefs_set_string("last_dir_browsed", str);
311 	g_free(str);
312     }
313     else
314 	prefs_set_string("last_dir_browsed", g_get_home_dir());
315 
316     /* Set sorting prefs */
317     prefs_set_int("case_sensitive", FALSE);
318     prefs_set_int("tm_autostore", FALSE);
319     prefs_set_int("st_sort", SORT_NONE);
320     prefs_set_int("pm_sort", SORT_NONE);
321     prefs_set_int("tm_sortcol", TM_COLUMN_TITLE);
322     prefs_set_int("tm_sort", SORT_NONE);
323 
324     /* New conversion preferences */
325     prefs_set_int("conversion_target_format", TARGET_FORMAT_MP3);
326 
327     /* ReplayGain prefs */
328     prefs_set_int("replaygain_offset", 0);
329     prefs_set_int("replaygain_mode_album_priority", TRUE);
330 }
331 
332 /* Initialize default variable-length list entries */
set_default_list_entries()333 static void set_default_list_entries()
334 {
335     if (!prefs_get_string_value_index("sort_ign_string_", 0, NULL))
336     {
337 	prefs_set_string_index("sort_ign_string_", 0, "a ");
338 	prefs_set_string_index("sort_ign_string_", 1, "an ");
339 	prefs_set_string_index("sort_ign_string_", 2, LIST_END_MARKER);
340     }
341 }
342 
343 /* A printf-like function that outputs in the system locale */
locale_fprintf(FILE * fp,const gchar * format,...)344 static void locale_fprintf(FILE *fp, const gchar *format, ...)
345 {
346     gchar *utf8_string; /* Raw UTF-8 string */
347     gchar *locale_string;  /* String in system locale format */
348     va_list format_list;  /* Printf-like formatting arguments */
349 
350     /* Create the locale format string based on the given format */
351     va_start(format_list, format);
352     utf8_string = g_strdup_vprintf(format, format_list);
353     va_end(format_list);
354 
355     locale_string = g_locale_from_utf8 (utf8_string, -1, NULL, NULL, NULL);
356 
357     if (fp)
358 	fprintf(fp, "%s", locale_string);
359 
360     g_free(utf8_string);
361     g_free(locale_string);
362 }
363 
364 /* Print commandline usage information */
usage(FILE * fp)365 static void usage(FILE *fp)
366 {
367   locale_fprintf(fp, _("gtkpod version %s usage:\n"), VERSION);
368   locale_fprintf(fp, _("  -h, --help:   display this message\n"));
369   locale_fprintf(fp, _("  -p <file>:    increment playcount for file by one\n"));
370   locale_fprintf(fp, _("  --hash <file>:print gtkpod hash for file\n"));
371   locale_fprintf(fp, _("  -m path:      define the mountpoint of your iPod\n"));
372   locale_fprintf(fp, _("  --mountpoint: same as '-m'.\n"));
373 }
374 
375 /* Parse commandline based options */
read_commandline(int argc,char * argv[])376 static void read_commandline(int argc, char *argv[])
377 {
378     int option; /* Code returned by getopt */
379 
380     /* The options data structure. The format is standard getopt. */
381     struct option const options[] =
382 	{
383 	    { "h",           no_argument,	NULL, GP_HELP },
384 	    { "help",        no_argument,	NULL, GP_HELP },
385 	    { "p",           required_argument, NULL, GP_PLAYCOUNT },
386 	    { "hash",        required_argument, NULL, GP_PRINT_HASH },
387 	    { "m",           required_argument,	NULL, GP_MOUNT },
388 	    { "mountpoint",  required_argument,	NULL, GP_MOUNT },
389 	    { 0, 0, 0, 0 }
390 	};
391 
392     /* Handle commandline options */
393     while ((option = getopt_long_only(argc, argv, "", options, NULL)) != -1)
394     {
395 	switch (option)
396 	{
397 	case GP_HELP:
398 	    usage(stdout);
399 	    exit(0);
400 	    break;
401 	case GP_PLAYCOUNT:
402 	    client_playcount(optarg);
403 	    exit(0);
404 	    break;
405 	case GP_PRINT_HASH:
406 	    print_sha1_hash (optarg);
407 	    exit(0);
408 	    break;
409 	case GP_MOUNT:
410 	    prefs_set_string("initial_mountpoint", optarg);
411 	    break;
412 	default:
413 	    locale_fprintf(stderr, "Unknown option: %s\n", argv[optind]);
414 	    usage(stderr);
415 	    exit(1);
416 	    break;
417 	};
418     }
419 }
420 
421 /* Read options from environment variables */
read_environment()422 static void read_environment()
423 {
424     gchar *buf;
425 
426     buf = convert_filename(getenv("IPOD_MOUNTPOINT"));
427     if (buf)
428 	prefs_set_string("initial_mountpoint", buf);
429     g_free(buf);
430 }
431 
432 /* Create a full numbered key from a base key string and a number.
433  * Free returned string. */
create_full_key(const gchar * base_key,gint index)434 static gchar *create_full_key(const gchar *base_key, gint index)
435 {
436     if (base_key)
437 	return g_strdup_printf("%s%i", base_key, index);
438     else
439 	return NULL;
440 }
441 
442 /* Remove key present in the temp prefs tree from the hash table */
flush_key(gpointer key,gpointer value,gpointer user_data)443 static gboolean flush_key (gpointer key, gpointer value, gpointer user_data)
444 {
445     g_return_val_if_fail (prefs_table, FALSE);
446 
447     g_hash_table_remove (prefs_table, key);
448 
449     return FALSE;
450 }
451 
452 
453 /* Copy key data from the temp prefs tree to the hash table (or to
454  * sub_data->temp_prefs_orig if non-NULL). The old key is removed. */
subst_key(gpointer key,gpointer value,gpointer user_data)455 static gboolean subst_key (gpointer key, gpointer value, gpointer user_data)
456 {
457     struct sub_data *sub_data = user_data;
458     gint len;
459 
460     g_return_val_if_fail (key && value && user_data, FALSE);
461     g_return_val_if_fail (sub_data->subkey && sub_data->subkey2, FALSE);
462     if (!sub_data->temp_prefs_orig)
463 	g_return_val_if_fail (prefs_table, FALSE);
464     if (sub_data->temp_prefs_orig)
465 	g_return_val_if_fail (sub_data->temp_prefs_orig->tree, FALSE);
466 
467     len = strlen (sub_data->subkey);
468 
469     if (strncmp (key, sub_data->subkey, len) == 0)
470     {
471 	gchar *new_key = g_strdup_printf ("%s%s",
472 					  sub_data->subkey2,
473 					  ((gchar *)key)+len);
474 	if (sub_data->temp_prefs_orig)
475 	{
476 	    g_tree_remove (sub_data->temp_prefs_orig->tree, key);
477 	    g_tree_insert (sub_data->temp_prefs_orig->tree,
478 			   new_key, g_strdup(value));
479 	}
480 	else
481 	{
482 	    g_hash_table_remove (prefs_table, key);
483 	    g_hash_table_insert (prefs_table, new_key, g_strdup(value));
484 	}
485     }
486     return FALSE;
487 }
488 
489 /* return TRUE if @key starts with @subkey */
match_subkey(gpointer key,gpointer value,gpointer subkey)490 static gboolean match_subkey (gpointer key, gpointer value, gpointer subkey)
491 {
492     g_return_val_if_fail (key && subkey, FALSE);
493 
494     if (strncmp (key, subkey, strlen (subkey)) == 0)  return TRUE;
495     return FALSE;
496 }
497 
498 
499 /* return TRUE and set sub_data->exists to TRUE if @key starts with
500  * @subkey */
check_subkey(gpointer key,gpointer value,gpointer user_data)501 static gboolean check_subkey (gpointer key, gpointer value, gpointer user_data)
502 {
503     struct sub_data *sub_data = user_data;
504 
505     g_return_val_if_fail (key && user_data, TRUE);
506     g_return_val_if_fail (sub_data->subkey, TRUE);
507 
508     if (strncmp (key, sub_data->subkey, strlen (sub_data->subkey)) == 0)
509     {
510 	sub_data->exists = TRUE;
511 	return TRUE;
512     }
513     return FALSE;
514 }
515 
516 
517 
518 /* Add key/value to temp_prefs if it matches subkey -- called by
519  * prefs_create_subset() and temp_prefs_create_subset() */
get_subset(gpointer key,gpointer value,gpointer user_data)520 static gboolean get_subset (gpointer key, gpointer value, gpointer user_data)
521 {
522     struct sub_data *sub_data = user_data;
523 
524     g_return_val_if_fail (key && value && user_data, TRUE);
525     g_return_val_if_fail (sub_data->subkey && sub_data->temp_prefs, TRUE);
526 
527     if (strncmp (key, sub_data->subkey,
528 		 strlen (sub_data->subkey)) == 0)
529     {  /* match */
530 	temp_prefs_set_string (sub_data->temp_prefs, key, value);
531     }
532     return FALSE; /* continue traversal (g_tree), ignored for g_hash */
533 }
534 
535 
536 /* Copy a variable-length list to the prefs table */
copy_list(gpointer key,gpointer value,gpointer user_data)537 static gboolean copy_list(gpointer key, gpointer value, gpointer user_data)
538 {
539 	prefs_apply_list((gchar*)key, (GList*)value);
540 	return FALSE;
541 }
542 
543 /* Callback that writes pref table data to a file */
write_key(gpointer key,gpointer value,gpointer user_data)544 static void write_key(gpointer key, gpointer value, gpointer user_data)
545 {
546     FILE *fp;  /* file pointer passed in through user_data */
547 
548     /* Write out each key and value to the given file */
549     fp = (FILE*)user_data;
550 
551     if (fp)
552 	fprintf(fp, "%s=%s\n", (gchar*)key, (gchar*)value);
553 }
554 
555 /* Gets a string that contains ~/.gtkpod/ If the folder doesn't exist,
556  * create it. Free the string when you are done with it.
557  * If the folder wasn't found, and couldn't be created, return NULL */
prefs_get_cfgdir()558 gchar *prefs_get_cfgdir()
559 {
560     gchar *folder;  /* Folder path */
561 
562     /* Create the folder path. If the folder doesn't exist, create it. */
563     folder = g_build_filename(g_get_home_dir(), ".gtkpod", NULL);
564 
565     if (!g_file_test(folder, G_FILE_TEST_IS_DIR))
566     {
567 	if ((g_mkdir(folder, 0777)) == -1)
568 	{
569 	    printf(_("Couldn't create '%s'\n"), folder);
570 	    g_free (folder);
571 	    return NULL;
572 	}
573     }
574     return folder;
575 }
576 
577 
578 /* get @key and @value from a string like "key=value" */
579 /* you must g_free (*key) and (*value) after use */
read_prefs_get_key_value(const gchar * buf,gchar ** key,gchar ** value)580 static gboolean read_prefs_get_key_value (const gchar *buf,
581 					  gchar **key, gchar **value)
582 {
583     size_t len;  /* string length */
584     const gchar *buf_start; /* Pointer to where actual useful data starts in line */
585 
586     g_return_val_if_fail (buf && key && value, FALSE);
587 
588     /* Strip out any comments (lines that begin with ; or #) */
589     if ((buf[0] == ';') || (buf[0] == '#'))
590 	return FALSE;
591 
592     /* Find the key and value, and look for malformed lines */
593     buf_start = strchr (buf, '=');
594 
595     if ((!buf_start) || (buf_start == buf))
596     {
597 	printf("Parse error reading prefs: %s", buf);
598 	return FALSE;
599     }
600 
601     /* Find the key name */
602     *key = g_strndup (buf, (buf_start - buf));
603 
604     /* Strip whitespace */
605     g_strstrip (*key);
606 
607     /* Find the value string */
608     *value = strdup (buf_start+1);
609 
610     /* remove newline */
611     len = strlen (*value);
612     if ((len > 0) && ((*value)[len - 1] == 0x0a))
613 	(*value)[len - 1] = 0;
614 
615     /* Don't strip whitespace! If there is any, there's a reason for it. */
616     /* g_strstrip (*value); */
617 
618     return TRUE;
619 }
620 
621 
622 /* Read preferences from a file */
read_prefs_from_file(FILE * fp)623 static void read_prefs_from_file(FILE *fp)
624 {
625     gchar buf[PATH_MAX];  /* Buffer that contains one line */
626     gchar *key;  /* Pref value key */
627     gchar *value; /* Pref value */
628 
629 
630     g_return_if_fail (prefs_table && fp);
631 
632     while (fgets(buf, PATH_MAX, fp))
633     {
634 	if (read_prefs_get_key_value (buf, &key, &value))
635 	{
636 	    g_hash_table_insert (prefs_table, key, value);
637 	}
638     }
639 }
640 
641 /* Write prefs to file */
write_prefs_to_file(FILE * fp)642 static void write_prefs_to_file(FILE *fp)
643 {
644     lock_prefs_table ();
645 
646     if (!prefs_table)
647     {
648 	unlock_prefs_table ();
649 	g_return_if_reached ();
650     }
651 
652     g_hash_table_foreach(prefs_table, write_key, (gpointer)fp);
653 
654     unlock_prefs_table ();
655 }
656 
657 /* Load preferences, first loading the defaults, and then overwrite that with
658  * preferences in the user home folder. */
load_prefs()659 static void load_prefs()
660 {
661     gchar *filename; /* Config path to open */
662     gchar *config_dir;  /* Directory where config is (usually ~/.gtkpod) */
663     FILE *fp;
664 
665     /* Start by initializing the prefs to their default values */
666     set_default_preferences();
667 
668     /* and then override those values with those found in the home folder. */
669     config_dir = prefs_get_cfgdir();
670 
671     if (config_dir)
672     {
673 	filename = g_build_filename(config_dir, "prefs", NULL);
674 
675 	if (filename)
676 	{
677 	    fp = fopen(filename, "r");
678 
679 	    if (fp)
680 	    {
681 		read_prefs_from_file(fp);
682 		fclose(fp);
683 	    }
684 
685 	    g_free(filename);
686 	}
687 
688 	g_free(config_dir);
689     }
690 
691     /* Finally, initialize variable-length lists. Do this after everything else
692      * so that list defaults don't hang out in the table after prefs have been
693      * read from the file. */
694     set_default_list_entries();
695 }
696 
697 /* Save preferences to user home folder (~/.gtkpod/prefs) */
prefs_save()698 void prefs_save ()
699 {
700     gchar *filename;  /* Path of file to write to */
701     gchar *config_dir;   /* Folder where prefs file is */
702     FILE *fp;  /* File pointer */
703 
704     /* Open $HOME/.gtkpod/prefs, and write prefs */
705     config_dir = prefs_get_cfgdir();
706 
707     if (config_dir)
708     {
709 	filename = g_build_filename(config_dir, "prefs", NULL);
710 
711 	if (filename)
712 	{
713 	    fp = fopen(filename, "w");
714 
715 	    if (fp)
716 	    {
717 		write_prefs_to_file(fp);
718 		fclose(fp);
719 	    }
720 
721 	    g_free(filename);
722 	}
723 
724 	g_free(config_dir);
725     }
726 }
727 
728 
temp_prefs_save_fe(gchar * key,gchar * value,struct temp_prefs_save * tps)729 static gboolean temp_prefs_save_fe (gchar *key, gchar *value,
730 				    struct temp_prefs_save *tps)
731 {
732     gchar *buf;
733     GIOStatus status;
734 
735     buf=g_strdup_printf ("%s=%s\n", key, value);
736     status = g_io_channel_write_chars (tps->gio, buf, -1, NULL, tps->error);
737     g_free (buf);
738     if (status != G_IO_STATUS_NORMAL)
739     {
740 	tps->success = FALSE;
741 	return TRUE;  /* stop traversal */
742     }
743     return FALSE;
744 }
745 
746 
747 /* Save @temp_prefs to @filename in the same manner as prefs_save is
748  * saving to ~/.gtkpod/prefs. @error: location where to store
749  * information about errors or NULL.
750  *
751  * Return value: TRUE on success, FALSE if an error occured, in which
752  * case @error will be set accordingly.
753  */
temp_prefs_save(TempPrefs * temp_prefs,const gchar * filename,GError ** error)754 gboolean temp_prefs_save (TempPrefs *temp_prefs,
755 			  const gchar *filename,
756 			  GError **error)
757 {
758     GIOChannel *gio;
759     struct temp_prefs_save tps;
760 
761     g_return_val_if_fail (temp_prefs && filename, FALSE);
762 
763     gio = g_io_channel_new_file (filename, "w", error);
764     tps.gio = gio;
765     tps.error = error;
766     tps.success = TRUE;
767     if (gio)
768     {
769 	g_tree_foreach (temp_prefs->tree, (GTraverseFunc)temp_prefs_save_fe, &tps);
770 	g_io_channel_unref (gio);
771     }
772 
773     return tps.success;
774 }
775 
776 
temp_prefs_load(const gchar * filename,GError ** error)777 TempPrefs *temp_prefs_load (const gchar *filename, GError **error)
778 {
779     GIOChannel *gio;
780     TempPrefs *temp_prefs = NULL;
781 
782     g_return_val_if_fail (filename, NULL);
783 
784     gio = g_io_channel_new_file (filename, "r", error);
785     if (gio)
786     {
787 	GIOStatus status;
788 
789 	temp_prefs = temp_prefs_create ();
790 
791 	do
792 	{
793 	    gchar *line = NULL;
794 
795 	    status = g_io_channel_read_line (gio, &line, NULL, NULL, error);
796 	    if (status == G_IO_STATUS_NORMAL)
797 	    {
798 		gchar *key, *value;
799 		if (read_prefs_get_key_value (line, &key, &value))
800 		{
801 		    temp_prefs_set_string (temp_prefs, key, value);
802 		    g_free (key);
803 		    g_free (value);
804 		}
805 	    }
806 	    g_free (line);
807 	} while (status == G_IO_STATUS_NORMAL);
808 
809 	g_io_channel_unref (gio);
810 
811 	if (status != G_IO_STATUS_EOF)
812 	{
813 	    temp_prefs_destroy (temp_prefs);
814 	    temp_prefs = NULL;
815 	}
816     }
817 
818     return temp_prefs;
819 }
820 
821 
822 /* Removes already existing list keys from the prefs table */
wipe_list(const gchar * key)823 static void wipe_list(const gchar *key)
824 {
825     gchar *full_key; /* Complete key, with its number suffix */
826     guint i;  /* Loop counter */
827 
828     /* Go through the prefs table, starting at key<number>, delete it and go
829      * through key<number+1>... until there are no keys left */
830 
831     for (i = 0;;i++)
832     {
833 	full_key = create_full_key(key, i);
834 
835 	if (g_hash_table_remove(prefs_table, full_key))
836 	{
837 	    g_free(full_key);
838 	    continue;
839 	}
840 	else /* We got all the unneeded keys, leave the loop... */
841 	{
842 	    g_free(full_key);
843 	    break;
844 	}
845     }
846 }
847 
848 /* Delete and rename keys */
cleanup_keys()849 static void cleanup_keys()
850 {
851     gchar *buf;
852     gint int_buf;
853     gint i;
854     gint x, y, p;  /* Window position */
855     float version=0;
856 
857     /* Get version */
858     version = prefs_get_double("version");
859 
860     /* rename mountpoint to initial_mountpoint */
861     if (prefs_get_string_value(KEY_MOUNTPOINT, &buf))
862     {
863 	prefs_set_string("initial_mountpoint", buf);
864 	g_free(buf);
865 	prefs_set_string(KEY_MOUNTPOINT, NULL);
866     }
867 
868     /* rename coverart to coverart_file */
869     if (prefs_get_string_value("coverart", &buf))
870     {
871 	prefs_set_string("coverart_file", buf);
872 	g_free(buf);
873 	prefs_set_string("coverart", NULL);
874     }
875 
876     /* rename tm_sort_ to tm_sort */
877     if (prefs_get_string_value("tm_sort_", &buf))
878     {
879 	prefs_set_string("tm_sort", buf);
880 	g_free(buf);
881 	prefs_set_string("tm_sort_", NULL);
882     }
883 
884     /* rename md5 to sha1 */
885     if (prefs_get_string_value("md5", &buf))
886     {
887 	prefs_set_string("sha1", buf);
888 	g_free(buf);
889 	prefs_set_string("md5", NULL);
890     }
891 
892     /* Convert old path numbered keys to named ones */
893 
894     /* Play Now */
895     if (prefs_get_string_value_index("path", PATH_PLAY_NOW, &buf))
896     {
897 	prefs_set_string("path_play_now", buf);
898 	prefs_set_string_index("path", PATH_PLAY_NOW, NULL);
899 	if (version < 0.87)
900 	{  /* default changed from "xmms -p %s" to "xmms
901 	      %s" which avoids xmms from hanging --
902 	      thanks to Chris Vine */
903 	    if (strcmp (buf, "xmms -p %s") == 0)
904 	    {
905 		prefs_set_string ("path_play_now", "xmms %s");
906 	    }
907 	}
908 	g_free(buf);
909     }
910 
911     if (prefs_get_string_value_index("toolpath", PATH_PLAY_NOW, &buf))
912     {
913 	prefs_set_string("path_play_now", buf);
914 	g_free(buf);
915 	prefs_set_string_index("toolpath", PATH_PLAY_NOW, NULL);
916     }
917 
918     /* Enqueue */
919     if (prefs_get_string_value_index("path", PATH_PLAY_ENQUEUE, &buf))
920     {
921 	prefs_set_string("path_play_enqueue", buf);
922 	g_free(buf);
923 	prefs_set_string_index("path", PATH_PLAY_ENQUEUE, NULL);
924     }
925 
926     if (prefs_get_string_value_index("toolpath", PATH_PLAY_ENQUEUE, &buf))
927     {
928 	prefs_set_string("path_play_enqueue", buf);
929 	g_free(buf);
930 	prefs_set_string_index("toolpath", PATH_PLAY_ENQUEUE, NULL);
931     }
932 
933     /* MP3 Gain */
934     if (prefs_get_string_value_index("path", PATH_MP3GAIN, &buf))
935     {
936 	prefs_set_string("path_mp3gain", buf);
937 	g_free(buf);
938 	prefs_set_string_index("path", PATH_MP3GAIN, NULL);
939     }
940 
941     if (prefs_get_string_value_index("toolpath", PATH_MP3GAIN, &buf))
942     {
943 	prefs_set_string("path_mp3gain", buf);
944 	g_free(buf);
945 	prefs_set_string_index("toolpath", PATH_MP3GAIN, NULL);
946     }
947 
948     /* Sync contacts */
949     if (prefs_get_string_value_index("path", PATH_SYNC_CONTACTS, &buf))
950     {
951 	prefs_set_string("itdb_0_path_sync_contacts", buf);
952 	g_free(buf);
953 	prefs_set_string_index("path", PATH_SYNC_CONTACTS, NULL);
954     }
955 
956     if (prefs_get_string_value_index("toolpath", PATH_SYNC_CONTACTS, &buf))
957     {
958 	prefs_set_string("itdb_0_path_sync_contacts", buf);
959 	g_free(buf);
960 	prefs_set_string_index("toolpath", PATH_SYNC_CONTACTS, NULL);
961     }
962 
963     /* Sync calendar */
964     if (prefs_get_string_value_index("path", PATH_SYNC_CALENDAR, &buf))
965     {
966 	prefs_set_string("itdb_0_path_sync_calendar", buf);
967 	g_free(buf);
968 	prefs_set_string_index("path", PATH_SYNC_CALENDAR, NULL);
969     }
970 
971     if (prefs_get_string_value_index("toolpath", PATH_SYNC_CALENDAR, &buf))
972     {
973 	prefs_set_string("itdb_0_path_sync_calendar", buf);
974 	g_free(buf);
975 	prefs_set_string_index("toolpath", PATH_SYNC_CALENDAR, NULL);
976     }
977 
978     /* Sync notes */
979     if (prefs_get_string_value_index("path", PATH_SYNC_NOTES, &buf))
980     {
981 	prefs_set_string("itdb_0_path_sync_notes", buf);
982 	g_free(buf);
983 	prefs_set_string_index("path", PATH_SYNC_NOTES, NULL);
984     }
985 
986     if (prefs_get_string_value_index("toolpath", PATH_SYNC_NOTES, &buf))
987     {
988 	prefs_set_string("itdb_0_path_sync_notes", buf);
989 	g_free(buf);
990 	prefs_set_string_index("toolpath", PATH_SYNC_NOTES, NULL);
991     }
992 
993     /* MSERV music root */
994     if (prefs_get_string_value_index("path", PATH_MSERV_MUSIC_ROOT, &buf))
995     {
996 	prefs_set_string("path_mserv_music_root", buf);
997 	g_free(buf);
998 	prefs_set_string_index("path", PATH_MSERV_MUSIC_ROOT, NULL);
999     }
1000 
1001     if (prefs_get_string_value_index("toolpath", PATH_MSERV_MUSIC_ROOT, &buf))
1002     {
1003 	prefs_set_string("path_mserv_music_root", buf);
1004 	g_free(buf);
1005 	prefs_set_string_index("toolpath", PATH_MSERV_MUSIC_ROOT, NULL);
1006     }
1007 
1008     /* MSERV track info root */
1009     if (prefs_get_string_value_index("path", PATH_MSERV_TRACKINFO_ROOT, &buf))
1010     {
1011 	prefs_set_string("path_mserv_trackinfo_root", buf);
1012 	g_free(buf);
1013 	prefs_set_string_index("path", PATH_MSERV_TRACKINFO_ROOT, NULL);
1014     }
1015 
1016     if (prefs_get_string_value_index("toolpath", PATH_MSERV_TRACKINFO_ROOT, &buf))
1017     {
1018 	prefs_set_string("path_mserv_trackinfo_root", buf);
1019 	g_free(buf);
1020 	prefs_set_string_index("toolpath", PATH_MSERV_TRACKINFO_ROOT, NULL);
1021     }
1022 
1023     /* If there's an extra (PATH_NUM) key, delete it */
1024     prefs_set_string_index("path", PATH_NUM, NULL);
1025     prefs_set_string_index("toolpath", PATH_NUM, NULL);
1026 
1027     /* Ignore/remove some keys */
1028     prefs_set_string("play_now_path", NULL);
1029     prefs_set_string("sync_remove", NULL);
1030     prefs_set_string("sync_remove_confirm", NULL);
1031     prefs_set_string("show_sync_dirs", NULL);
1032     prefs_set_string("play_enqueue_path", NULL);
1033     prefs_set_string("mp3gain_path", NULL);
1034     prefs_set_string("statusbar_timeout", NULL);
1035     prefs_set_string("offline", NULL);
1036     prefs_set_string("time_format", NULL);
1037     prefs_set_string("id3_all", NULL);
1038     prefs_set_string("pm_autostore", NULL);
1039     prefs_set_string("backups", NULL);
1040     prefs_set_string("save_sorted_order", NULL);
1041     prefs_set_string("fix_path", NULL);
1042     prefs_set_string("write_gaintag", NULL);
1043     prefs_set_string("automount", NULL);
1044     prefs_set_string("display_artcovers", NULL);
1045     prefs_set_string("block_display", NULL);
1046     prefs_set_string("tmp_disable_sort", NULL);
1047     prefs_set_string("size_file_dialog.x", NULL);
1048     prefs_set_string("size_file_dialog.y", NULL);
1049     prefs_set_string("size_file_dialog_details.x", NULL);
1050     prefs_set_string("size_file_dialog_details.y", NULL);
1051     prefs_set_string("autoimport", NULL);
1052     prefs_set_string("auto_import", NULL);
1053     prefs_set_string("conversion_enable", NULL);
1054     prefs_set_string("export_template", NULL);
1055     prefs_set_string("filename_format", NULL);
1056     prefs_set_string("write_extended_info", NULL);
1057 
1058     /* sp_created_cond renamed to sp_added_cond */
1059     for (i = 0; i < SORT_TAB_MAX; i++)
1060     {
1061 	if (prefs_get_int_value_index("sp_created_cond", i, &int_buf))
1062 	{
1063 	    prefs_set_int_index("sp_added_cond", i, int_buf);
1064 	    prefs_set_string("sp_created_cond", NULL);
1065 	}
1066     }
1067 
1068     /* sp_created_state renamed to sp_added_state */
1069     for (i = 0; i < SORT_TAB_MAX; i++)
1070     {
1071 	if (prefs_get_int_value_index("sp_created_state", i, &int_buf))
1072 	{
1073 	    prefs_set_int_index("sp_added_state", i, int_buf);
1074 	    prefs_set_string("sp_created_state", NULL);
1075 	}
1076     }
1077 
1078     /* sm_col_width renamed to tm_col_width */
1079     for (i = 0; i < TM_NUM_COLUMNS; i++)
1080     {
1081 	if (prefs_get_int_value_index("sm_col_width", i, &int_buf))
1082 	{
1083 	    prefs_set_int_index("tm_col_width", i, int_buf);
1084 	    prefs_set_string_index("sm_col_width", i, NULL);
1085 	}
1086     }
1087 
1088     /* handle version changes in prefs */
1089     if (version == 0.0)
1090     {
1091 	/* most likely prefs file written by V0.50 */
1092 	/* I added two new PANED elements since V0.50 --> shift */
1093 	for (i=PANED_NUM_ST-1; i>=0; --i)
1094 	{
1095 	    prefs_set_int_index("paned_pos_", PANED_NUM_GLADE + i,
1096 				prefs_get_int_index("paned_pos_", PANED_NUM_GLADE + i - 2));
1097 	}
1098 	prefs_set_int_index("paned_pos_", PANED_STATUS1, -1);
1099 	prefs_set_int_index("paned_pos_", PANED_STATUS2, -1);
1100     }
1101 
1102     /* set statusbar paned to a decent value if unset */
1103     if (prefs_get_int_index("paned_pos_", PANED_STATUS1) == -1)
1104     {
1105 	x = prefs_get_int("size_gtkpod.x");
1106 	/* set to about 2/3 of the window width */
1107 	if (x>0)
1108 	    prefs_set_int_index("paned_pos_", PANED_STATUS1, 20*x/30);
1109     }
1110 
1111     if (prefs_get_int_index("paned_pos_", PANED_STATUS2) == -1)
1112     {
1113 	x = prefs_get_int("size_gtkpod.x");
1114 	y = prefs_get_int("size_gtkpod.y");
1115 	p = prefs_get_int_index("paned_pos_", PANED_STATUS1);
1116 	/* set to about half of the remaining window */
1117 	if (x>0)
1118 	    prefs_set_int_index("paned_pos_", PANED_STATUS2, (x-p)/2 );
1119     }
1120 
1121     /* Changed layout of info window between 0.72 and 0.73 */
1122     if (version < 0.73)
1123     {
1124 	prefs_set_string("size_info.x", NULL);
1125 	prefs_set_string("size_info.y", NULL);
1126     }
1127 
1128     /* not_played_song renamed to not_played_track */
1129     if (prefs_get_int_value("not_played_song", &int_buf))
1130     {
1131 	prefs_set_int("not_played_track", int_buf);
1132 	prefs_set_string("not_played_song", NULL);
1133     }
1134 
1135     /* misc_song_nr renamed to misc_track_nr */
1136     if (prefs_get_int_value("misc_song_nr", &int_buf))
1137     {
1138 	prefs_set_int("misc_track_nr", int_buf);
1139 	prefs_set_string("misc_song_nr", NULL);
1140     }
1141 
1142     /* sm_autostore renamed to tm_autostore */
1143     if (prefs_get_int_value("sm_autostore", &int_buf))
1144     {
1145 	prefs_set_int("tm_autostore", int_buf);
1146 	prefs_set_string("sm_autostore", NULL);
1147     }
1148 
1149     /* sm_sortcol renamed to tm_sortcol */
1150     if (prefs_get_int_value("sm_sortcol", &int_buf))
1151     {
1152 	prefs_set_int("tm_sortcol", int_buf);
1153 	prefs_set_string("sm_sortcol", NULL);
1154     }
1155 
1156     /* sm_sort_ renamed to tm_sort */
1157     if (prefs_get_int_value("sm_sort_", &int_buf))
1158     {
1159 	prefs_set_int("tm_sort", int_buf);
1160 	prefs_set_string("sm_sort_", NULL);
1161     }
1162 
1163     /* For versions < 0.91, remove all itdb keys */
1164     if (version < 0.91)
1165 	prefs_flush_subkey("itdb_");
1166 
1167     /* rename convert scripts */
1168     if (version <= 0.99001)
1169     {
1170 
1171 	const gchar **keyp;
1172 	const gchar *keys[] =
1173 	    {"path_conv_m4a", "path_conv_wav", "path_conv_mp3",
1174 	     "path_conv_ogg", "path_conv_flac", NULL};
1175 
1176 	for (keyp=keys; *keyp; ++keyp)
1177 	{
1178 	    buf = prefs_get_string (*keyp);
1179 	    if (buf)
1180 	    {
1181 		const gchar *needles[] =
1182 		    { "convert-flac2mp3.sh", "convert-m4a2mp3.sh",
1183 		      "convert-ogg2mp3.sh", "convert-wav2mp3.sh",
1184 		      "convert-flac2m4a.sh", "convert-m4a2m4a.sh",
1185 		      "convert-ogg2m4a.sh", "convert-wav2m4a.sh", NULL };
1186 		const gchar *replacements[] =
1187 		    { "convert-2mp3.sh    ", "convert-2mp3.sh   ",
1188 		      "convert-2mp3.sh   ", "convert-2mp3.sh   " ,
1189 		      "convert-2m4a.sh    ", "convert-2m4a.sh   ",
1190 		      "convert-2m4a.sh   ", "convert-2m4a.sh   " };
1191 		const gchar **needlep;
1192 		const gchar **replp;
1193 		replp = replacements;
1194 		for (needlep=needles; *needlep; ++needlep, ++replp)
1195 		{
1196 		    gchar *bufp = strstr (buf, *needlep);
1197 		    if (bufp)
1198 		    {
1199 			g_memmove (bufp, *replp, strlen (*replp));
1200 			prefs_set_string (*keyp, buf);
1201 			break;
1202 		    }
1203 		}
1204 		g_free (buf);
1205 	    }
1206 	}
1207     }
1208 
1209     prefs_set_string ("version", VERSION);
1210 }
1211 
1212 /* Initialize the prefs table and read configuration */
prefs_init(int argc,char * argv[])1213 void prefs_init (int argc, char *argv[])
1214 {
1215     if (!prefs_table_mutex)
1216 	prefs_table_mutex = g_mutex_new ();
1217 
1218     lock_prefs_table ();
1219 
1220     /* Create the prefs hash table */
1221     prefs_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
1222 					g_free);
1223 
1224     unlock_prefs_table ();
1225 
1226     /* Load preferences */
1227     load_prefs();
1228 
1229     /* Clean up old prefs keys */
1230     cleanup_keys();
1231 
1232     /* Read environment variables */
1233     read_environment();
1234 
1235     /* Read commandline arguments */
1236     read_commandline(argc, argv);
1237 }
1238 
1239 /* Delete the hash table */
prefs_shutdown()1240 void prefs_shutdown ()
1241 {
1242     lock_prefs_table ();
1243 
1244     if (!prefs_table)
1245     {
1246 	unlock_prefs_table ();
1247 	g_return_if_reached ();
1248     }
1249 
1250     /* Delete the prefs hash table */
1251     g_hash_table_destroy(prefs_table);
1252     prefs_table = NULL;
1253 
1254     unlock_prefs_table ();
1255 
1256     /* We can't free the prefs_table_mutex in a thread-safe way */
1257 }
1258 
1259 /* Create the temp prefs tree */
1260 /* Free the returned structure with delete_temp_prefs() */
temp_prefs_create()1261 TempPrefs *temp_prefs_create ()
1262 {
1263     TempPrefs *temp_prefs;  /* Returned temp prefs structure */
1264 
1265     temp_prefs = (TempPrefs*)g_malloc(sizeof(TempPrefs));
1266 
1267     temp_prefs->tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL,
1268 				       g_free, g_free);
1269 
1270     return temp_prefs;
1271 }
1272 
copy_key_to_temp_prefs(gpointer key,gpointer value,gpointer user_data)1273 static void copy_key_to_temp_prefs (gpointer key, gpointer value, gpointer user_data)
1274 {
1275     temp_prefs_set_string ((TempPrefs *)user_data, key, value);
1276 }
1277 
temp_prefs_copy_prefs(TempPrefs * temp_prefs)1278 void temp_prefs_copy_prefs (TempPrefs *temp_prefs)
1279 {
1280     g_return_if_fail (prefs_table);
1281     g_return_if_fail (temp_prefs);
1282     g_return_if_fail (temp_prefs->tree);
1283 
1284 	lock_prefs_table ();
1285     g_hash_table_foreach (prefs_table, copy_key_to_temp_prefs, temp_prefs);
1286 	unlock_prefs_table ();
1287 }
1288 
1289 /* Delete temp prefs */
temp_prefs_destroy(TempPrefs * temp_prefs)1290 void temp_prefs_destroy (TempPrefs *temp_prefs)
1291 {
1292     g_return_if_fail (temp_prefs);
1293     g_return_if_fail (temp_prefs->tree);
1294 
1295     g_tree_destroy(temp_prefs->tree);
1296     g_free(temp_prefs);
1297 }
1298 
1299 /* Copy key data from the temp prefs tree to the hash table */
copy_key(gpointer key,gpointer value,gpointer user_data)1300 static gboolean copy_key (gpointer key, gpointer value, gpointer user_data)
1301 {
1302     prefs_set_string(key, value);
1303 
1304     return FALSE;
1305 }
1306 
1307 /* Copy the data from the temp prefs tree to the permanent prefs table */
temp_prefs_apply(TempPrefs * temp_prefs)1308 void temp_prefs_apply (TempPrefs *temp_prefs)
1309 {
1310     g_return_if_fail (temp_prefs);
1311     g_return_if_fail (temp_prefs->tree);
1312 
1313     g_tree_foreach (temp_prefs->tree, copy_key, NULL);
1314 }
1315 
1316 
1317 /* Create a temp_prefs tree containing a subset of keys in the
1318    permanent prefs table (those starting with @subkey */
prefs_create_subset_unlocked(const gchar * subkey)1319 static TempPrefs *prefs_create_subset_unlocked (const gchar *subkey)
1320 {
1321     struct sub_data sub_data;
1322 
1323     g_return_val_if_fail (prefs_table, NULL);
1324 
1325     sub_data.temp_prefs = temp_prefs_create ();
1326     sub_data.subkey = subkey;
1327 
1328     g_hash_table_foreach (prefs_table, (GHFunc)get_subset, &sub_data);
1329 
1330     return sub_data.temp_prefs;
1331 }
1332 
1333 /* Create a temp_prefs tree containing a subset of keys in the
1334    permanent prefs table (those starting with @subkey */
prefs_create_subset(const gchar * subkey)1335 TempPrefs *prefs_create_subset (const gchar *subkey)
1336 {
1337     TempPrefs *temp_prefs;
1338 
1339     lock_prefs_table ();
1340 
1341     temp_prefs = prefs_create_subset_unlocked (subkey);
1342 
1343     unlock_prefs_table ();
1344 
1345     return temp_prefs;
1346 }
1347 
1348 
1349 /* Create a temp_prefs tree containing a subset of keys in the
1350    permanent prefs table (those starting with @subkey */
temp_prefs_create_subset(TempPrefs * temp_prefs,const gchar * subkey)1351 TempPrefs *temp_prefs_create_subset (TempPrefs *temp_prefs,
1352 				     const gchar *subkey)
1353 {
1354     struct sub_data sub_data;
1355 
1356     g_return_val_if_fail (temp_prefs, NULL);
1357     g_return_val_if_fail (temp_prefs->tree, NULL);
1358 
1359     sub_data.temp_prefs = temp_prefs_create ();
1360     sub_data.subkey = subkey;
1361 
1362     g_tree_foreach (temp_prefs->tree, get_subset, &sub_data);
1363 
1364     return sub_data.temp_prefs;
1365 }
1366 
1367 
1368 /* Remove all keys in the temp prefs tree from the permanent prefs
1369    table */
temp_prefs_flush(TempPrefs * temp_prefs)1370 void temp_prefs_flush (TempPrefs *temp_prefs)
1371 {
1372     g_return_if_fail (temp_prefs);
1373     g_return_if_fail (temp_prefs->tree);
1374 
1375     lock_prefs_table ();
1376 
1377     g_tree_foreach (temp_prefs->tree, flush_key, NULL);
1378 
1379     unlock_prefs_table ();
1380 }
1381 
1382 /* Return the number of keys stored in @temp_prefs */
temp_prefs_size(TempPrefs * temp_prefs)1383 gint temp_prefs_size (TempPrefs *temp_prefs)
1384 {
1385     g_return_val_if_fail (temp_prefs, 0);
1386     g_return_val_if_fail (temp_prefs->tree, 0);
1387 
1388     return g_tree_nnodes (temp_prefs->tree);
1389 }
1390 
1391 
1392 /* Returns TRUE if at least one key starting with @subkey exists */
temp_prefs_subkey_exists(TempPrefs * temp_prefs,const gchar * subkey)1393 gboolean temp_prefs_subkey_exists (TempPrefs *temp_prefs,
1394 				   const gchar *subkey)
1395 {
1396     struct sub_data sub_data;
1397 
1398     g_return_val_if_fail (temp_prefs && subkey, FALSE);
1399 
1400     sub_data.temp_prefs = NULL;
1401     sub_data.subkey = subkey;
1402     sub_data.exists = FALSE;
1403 
1404     g_tree_foreach (temp_prefs->tree, check_subkey, &sub_data);
1405 
1406     return sub_data.exists;
1407 }
1408 
1409 
1410 /* Special functions */
1411 
1412 /* Remove all keys that start with @subkey */
prefs_flush_subkey(const gchar * subkey)1413 void prefs_flush_subkey (const gchar *subkey)
1414 {
1415     lock_prefs_table ();
1416 
1417     if (!prefs_table)
1418     {
1419 	unlock_prefs_table ();
1420 	g_return_if_reached ();
1421     }
1422 
1423     g_hash_table_foreach_remove (prefs_table, match_subkey, (gchar *)subkey);
1424 
1425     unlock_prefs_table ();
1426 }
1427 
1428 
1429 /* Rename all keys that start with @subkey_old in such a way that they
1430    start with @subkey_new */
prefs_rename_subkey(const gchar * subkey_old,const gchar * subkey_new)1431 void prefs_rename_subkey (const gchar *subkey_old, const gchar *subkey_new){
1432     struct sub_data sub_data;
1433 
1434     g_return_if_fail (subkey_old);
1435     g_return_if_fail (subkey_new);
1436 
1437     lock_prefs_table ();
1438 
1439     if (!prefs_table)
1440     {
1441 	unlock_prefs_table ();
1442 	g_return_if_reached ();
1443     }
1444 
1445     sub_data.temp_prefs = prefs_create_subset_unlocked (subkey_old);
1446     sub_data.temp_prefs_orig = NULL;
1447 
1448     if (temp_prefs_size (sub_data.temp_prefs) > 0)
1449     {
1450 	sub_data.subkey = subkey_old;
1451 	sub_data.subkey2 = subkey_new;
1452 	g_tree_foreach (sub_data.temp_prefs->tree, subst_key, &sub_data);
1453     }
1454 
1455     temp_prefs_destroy (sub_data.temp_prefs);
1456 
1457     unlock_prefs_table ();
1458 }
1459 
1460 
1461 /* Rename all keys that start with @subkey_old in such a way that they
1462    start with @subkey_new */
temp_prefs_rename_subkey(TempPrefs * temp_prefs,const gchar * subkey_old,const gchar * subkey_new)1463 void temp_prefs_rename_subkey (TempPrefs *temp_prefs,
1464 			       const gchar *subkey_old,
1465 			       const gchar *subkey_new)
1466 {
1467     struct sub_data sub_data;
1468 
1469     g_return_if_fail (temp_prefs);
1470     g_return_if_fail (subkey_old);
1471     g_return_if_fail (subkey_new);
1472 
1473     sub_data.temp_prefs_orig = temp_prefs;
1474     sub_data.temp_prefs = temp_prefs_create_subset (temp_prefs,
1475 						    subkey_old);
1476 
1477     if (temp_prefs_size (sub_data.temp_prefs) > 0)
1478     {
1479 	sub_data.subkey = subkey_old;
1480 	sub_data.subkey2 = subkey_new;
1481 	g_tree_foreach (sub_data.temp_prefs->tree, subst_key, &sub_data);
1482     }
1483 
1484     temp_prefs_destroy (sub_data.temp_prefs);
1485 }
1486 
1487 /* Functions for non-numbered pref keys */
1488 
1489 /* Set a string value with the given key, or remove key if @value is
1490    NULL */
prefs_set_string(const gchar * key,const gchar * value)1491 void prefs_set_string(const gchar *key, const gchar *value)
1492 {
1493     g_return_if_fail (key);
1494 
1495     lock_prefs_table ();
1496 
1497     if (!prefs_table)
1498     {
1499 	unlock_prefs_table ();
1500 	g_return_if_reached ();
1501     }
1502 
1503     if (value)
1504 	g_hash_table_insert (prefs_table,
1505 			     g_strdup(key), g_strdup(value));
1506     else
1507 	g_hash_table_remove (prefs_table, key);
1508 
1509     unlock_prefs_table ();
1510 }
1511 
1512 /* Set a key value to a given integer */
prefs_set_int(const gchar * key,const gint value)1513 void prefs_set_int(const gchar *key, const gint value)
1514 {
1515     gchar *strvalue; /* String value converted from integer */
1516 
1517     lock_prefs_table ();
1518 
1519     if (!prefs_table)
1520     {
1521 	unlock_prefs_table ();
1522 	g_return_if_reached ();
1523     }
1524 
1525     strvalue = g_strdup_printf("%i", value);
1526     g_hash_table_insert(prefs_table, g_strdup(key), strvalue);
1527 
1528     unlock_prefs_table ();
1529 }
1530 
1531 /* Set a key to an int64 value */
prefs_set_int64(const gchar * key,const gint64 value)1532 void prefs_set_int64(const gchar *key, const gint64 value)
1533 {
1534     gchar *strvalue; /* String value converted from int64 */
1535 
1536     lock_prefs_table ();
1537 
1538     if (!prefs_table)
1539     {
1540 	unlock_prefs_table ();
1541 	g_return_if_reached ();
1542     }
1543 
1544     strvalue = g_strdup_printf("%" G_GINT64_FORMAT, value);
1545     g_hash_table_insert(prefs_table, g_strdup(key), strvalue);
1546 
1547     unlock_prefs_table ();
1548 }
1549 
prefs_set_double(const gchar * key,gdouble value)1550 void prefs_set_double(const gchar *key, gdouble value)
1551 {
1552     gchar *strvalue; /* String value converted from integer */
1553 
1554     lock_prefs_table ();
1555 
1556     if (!prefs_table)
1557     {
1558 	unlock_prefs_table ();
1559 	g_return_if_reached ();
1560     }
1561 
1562     strvalue = g_strdup_printf("%f", value);
1563     g_hash_table_insert(prefs_table, g_strdup(key), strvalue);
1564 
1565     unlock_prefs_table ();
1566 }
1567 
1568 /* Get a string value associated with a key. Free returned string. */
prefs_get_string(const gchar * key)1569 gchar *prefs_get_string(const gchar *key)
1570 {
1571     gchar *string = NULL;
1572 
1573     lock_prefs_table ();
1574 
1575     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), NULL));
1576 
1577     string = g_strdup(g_hash_table_lookup(prefs_table, key));
1578 
1579     unlock_prefs_table ();
1580 
1581     return string;
1582 }
1583 
1584 /* Use this if you need to know if the given key actually exists */
1585 /* The value parameter can be NULL if you don't need the value itself. */
prefs_get_string_value(const gchar * key,gchar ** value)1586 gboolean prefs_get_string_value(const gchar *key, gchar **value)
1587 {
1588     const gchar *string;  /* String value from prefs table */
1589     gboolean valid = FALSE;
1590 
1591     lock_prefs_table ();
1592 
1593     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
1594 
1595     string = g_hash_table_lookup(prefs_table, key);
1596 
1597     if (value)
1598 	*value = g_strdup (string);
1599     if (string)
1600 	valid = TRUE;
1601 
1602     unlock_prefs_table ();
1603 
1604     return valid;
1605 }
1606 
1607 /* Get an integer value from a key */
prefs_get_int(const gchar * key)1608 gint prefs_get_int(const gchar *key)
1609 {
1610     gchar *string; /* Hash value string */
1611     gint value;  /* Returned value */
1612 
1613     value = 0;
1614 
1615     lock_prefs_table ();
1616 
1617     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
1618 
1619     string = g_hash_table_lookup(prefs_table, key);
1620 
1621     if (string)
1622 	value = atoi(string);
1623 
1624     unlock_prefs_table ();
1625 
1626     return value;
1627 }
1628 
1629 /* Use this if you need to know if the given key actually exists */
1630 /* The value parameter can be NULL if you don't need the value itself. */
prefs_get_int_value(const gchar * key,gint * value)1631 gboolean prefs_get_int_value(const gchar *key, gint *value)
1632 {
1633     gchar *string;  /* String value from prefs table */
1634     gboolean valid = FALSE;
1635 
1636     lock_prefs_table ();
1637 
1638     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
1639 
1640     string = g_hash_table_lookup(prefs_table, key);
1641 
1642     if (value)
1643     {
1644 	if (string)
1645 	    *value = atoi(string);
1646 	else
1647 	    *value = 0;
1648     }
1649 
1650     if (string)
1651 	valid = TRUE;
1652 
1653     unlock_prefs_table ();
1654 
1655     return valid;
1656 }
1657 
1658 /* Get a 64 bit integer value from a key */
prefs_get_int64(const gchar * key)1659 gint64 prefs_get_int64(const gchar *key)
1660 {
1661     gchar *string;  /* Key value string */
1662     gint64 value;  /* Returned value */
1663 
1664     value = 0;
1665 
1666     lock_prefs_table ();
1667 
1668     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
1669 
1670     string = g_hash_table_lookup(prefs_table, key);
1671 
1672     if (string)
1673 	value = g_ascii_strtoull(string, NULL, 10);
1674 
1675     unlock_prefs_table ();
1676 
1677     return value;
1678 }
1679 
1680 /* Get a 64 bit integer value from a key */
1681 /* Use this if you need to know if the given key actually exists */
1682 /* The value parameter can be NULL if you don't need the value itself. */
prefs_get_int64_value(const gchar * key,gint64 * value)1683 gboolean prefs_get_int64_value(const gchar *key, gint64 *value)
1684 {
1685     gchar *string;  /* String value from prefs table */
1686     gboolean valid = FALSE;
1687 
1688     lock_prefs_table ();
1689 
1690     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
1691 
1692     string = g_hash_table_lookup(prefs_table, key);
1693 
1694     if (value)
1695     {
1696 	if (string)
1697 	    *value = g_ascii_strtoull(string, NULL, 10);
1698 	else
1699 	    *value = 0;
1700     }
1701 
1702     if (string)
1703 	valid = TRUE;
1704 
1705     unlock_prefs_table ();
1706 
1707     return valid;
1708 }
1709 
prefs_get_double(const gchar * key)1710 gdouble prefs_get_double(const gchar *key)
1711 {
1712     gchar *string;  /* Key value string */
1713     gdouble value;  /* Returned value */
1714 
1715     value = 0;
1716 
1717     lock_prefs_table ();
1718 
1719     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), value));
1720 
1721     string = g_hash_table_lookup(prefs_table, key);
1722 
1723     if (string)
1724 	value = g_ascii_strtod(string, NULL);
1725 
1726     unlock_prefs_table ();
1727 
1728     return value;
1729 }
1730 
prefs_get_double_value(const gchar * key,gdouble * value)1731 gboolean prefs_get_double_value(const gchar *key, gdouble *value)
1732 {
1733     gchar *string;  /* String value from prefs table */
1734     gboolean valid = FALSE;
1735 
1736     lock_prefs_table ();
1737 
1738     g_return_val_if_fail (prefs_table, (unlock_prefs_table(), FALSE));
1739 
1740     string = g_hash_table_lookup(prefs_table, key);
1741 
1742     if (value)
1743     {
1744 	if (string)
1745 	    *value = g_ascii_strtod(string, NULL);
1746 	else
1747 	    *value = 0;
1748     }
1749 
1750     if (string)
1751 	valid = TRUE;
1752 
1753     unlock_prefs_table ();
1754 
1755     return valid;
1756 }
1757 
1758 /* Functions for numbered pref keys */
1759 
1760 /* Set a string value with the given key */
prefs_set_string_index(const gchar * key,const guint index,const gchar * value)1761 void prefs_set_string_index(const gchar *key, const guint index,
1762 			    const gchar *value)
1763 {
1764     gchar *full_key; /* Complete numbered key */
1765 
1766     full_key = create_full_key(key, index);
1767     prefs_set_string(full_key, value);
1768 
1769     g_free(full_key);
1770 }
1771 
1772 /* Set a key value to a given integer */
prefs_set_int_index(const gchar * key,const guint index,const gint value)1773 void prefs_set_int_index(const gchar *key, const guint index,
1774 			 const gint value)
1775 {
1776     gchar *full_key; /* Complete numbered key */
1777 
1778     full_key = create_full_key(key, index);
1779     prefs_set_int(full_key, value);
1780 
1781     g_free(full_key);
1782 }
1783 
1784 /* Set a key to an int64 value */
prefs_set_int64_index(const gchar * key,const guint index,const gint64 value)1785 void prefs_set_int64_index(const gchar *key, const guint index,
1786 			   const gint64 value)
1787 {
1788     gchar *full_key; /* Complete numbered key */
1789 
1790     full_key = create_full_key(key, index);
1791     prefs_set_int64(full_key, value);
1792 
1793     g_free(full_key);
1794 }
1795 
1796 /* Set a key to a gdouble value */
prefs_set_double_index(const gchar * key,guint index,gdouble value)1797 void prefs_set_double_index(const gchar *key, guint index,
1798 			     gdouble value)
1799 {
1800     gchar *full_key; /* Complete numbered key */
1801 
1802     full_key = create_full_key(key, index);
1803     prefs_set_double(full_key, value);
1804 
1805     g_free(full_key);
1806 }
1807 
1808 /* Get a string value associated with a key. Free returned string. */
prefs_get_string_index(const gchar * key,const guint index)1809 gchar *prefs_get_string_index(const gchar *key, const guint index)
1810 {
1811     gchar *full_key; /* Complete numbered key */
1812     gchar *string;  /* Return string */
1813 
1814     full_key = create_full_key(key, index);
1815     string = prefs_get_string(full_key);
1816 
1817     g_free(full_key);
1818     return string;
1819 }
1820 
1821 /* Get a string value associated with a key. Free returned string. */
1822 /* Use this if you need to know if the given key actually exists */
prefs_get_string_value_index(const gchar * key,const guint index,gchar ** value)1823 gboolean prefs_get_string_value_index(const gchar *key, const guint index,
1824 				      gchar **value)
1825 {
1826     gchar *full_key; /* Complete numbered key */
1827     gboolean ret; /* Return value */
1828 
1829     full_key = create_full_key(key, index);
1830     ret = prefs_get_string_value(full_key, value);
1831 
1832     g_free(full_key);
1833     return ret;
1834 }
1835 
1836 /* Get an integer value from a key */
prefs_get_int_index(const gchar * key,const guint index)1837 gint prefs_get_int_index(const gchar *key, const guint index)
1838 {
1839     gchar *full_key; /* Complete numbered key */
1840     gint value;  /* Returned integer value */
1841 
1842     full_key = create_full_key(key, index);
1843     value = prefs_get_int(full_key);
1844 
1845     g_free(full_key);
1846     return value;
1847 }
1848 
1849 /* Get an integer value from a key */
1850 /* Use this if you need to know if the given key actually exists */
prefs_get_int_value_index(const gchar * key,const guint index,gint * value)1851 gboolean prefs_get_int_value_index(const gchar *key, const guint index,
1852 				   gint *value)
1853 {
1854     gchar *full_key; /* Complete numbered key */
1855     gboolean ret; /* Return value */
1856 
1857     full_key = create_full_key(key, index);
1858     ret = prefs_get_int_value(full_key, value);
1859 
1860     g_free(full_key);
1861     return ret;
1862 }
1863 
1864 /* Get a 64 bit integer value from a key */
prefs_get_int64_index(const gchar * key,const guint index)1865 gint64 prefs_get_int64_index(const gchar *key, const guint index)
1866 {
1867     gchar *full_key; /* Complete numbered key */
1868     gint64 value; /* Return value */
1869 
1870     full_key = create_full_key(key, index);
1871     value = prefs_get_int64(full_key);
1872 
1873     g_free(full_key);
1874     return value;
1875 }
1876 
1877 /* Get a 64 bit integer value from a key */
1878 /* Use this if you need to know if the given key actually exists */
prefs_get_int64_value_index(const gchar * key,const guint index,gint64 * value)1879 gboolean prefs_get_int64_value_index(const gchar *key, const guint index,
1880 				     gint64 *value)
1881 {
1882     gchar *full_key; /* Complete numbered key */
1883     gboolean ret; /* Return value */
1884 
1885     full_key = create_full_key(key, index);
1886     ret = prefs_get_int64_value(full_key, value);
1887 
1888     g_free(full_key);
1889     return ret;
1890 }
1891 
prefs_get_double_index(const gchar * key,guint index)1892 gdouble prefs_get_double_index(const gchar *key, guint index)
1893 {
1894     gchar *full_key; /* Complete numbered key */
1895     gdouble value; /* Return value */
1896 
1897     full_key = create_full_key(key, index);
1898     value = prefs_get_double(full_key);
1899 
1900     g_free(full_key);
1901     return value;
1902 }
1903 
prefs_get_double_value_index(const gchar * key,guint index,gdouble * value)1904 gboolean prefs_get_double_value_index(const gchar *key, guint index,
1905 				      gdouble *value)
1906 {
1907     gchar *full_key; /* Complete numbered key */
1908     gboolean ret; /* Return value */
1909 
1910     full_key = create_full_key(key, index);
1911     ret = prefs_get_double_value(full_key, value);
1912 
1913     g_free(full_key);
1914     return ret;
1915 }
1916 
1917 /* Add string value with the given key to temp prefs. Note: use
1918  * temp_prefs_remove_key() to remove key from the temp prefs. Setting
1919  * it to NULL will not remove the key. It will instead remove the key
1920  * in the main prefs table when you call temp_prefs_apply(). */
temp_prefs_set_string(TempPrefs * temp_prefs,const gchar * key,const gchar * value)1921 void temp_prefs_set_string (TempPrefs *temp_prefs, const gchar *key,
1922 			   const gchar *value)
1923 {
1924     g_return_if_fail (temp_prefs && temp_prefs->tree);
1925     g_return_if_fail (key);
1926 
1927     g_tree_insert (temp_prefs->tree, g_strdup(key), g_strdup(value));
1928 }
1929 
1930 /* Add string value with the given key to temp prefs. Remove the key
1931  * if @value is NULL. */
temp_prefs_remove_key(TempPrefs * temp_prefs,const gchar * key)1932 void temp_prefs_remove_key (TempPrefs *temp_prefs, const gchar *key)
1933 {
1934     g_return_if_fail (temp_prefs && temp_prefs->tree);
1935     g_return_if_fail (key);
1936 
1937     g_tree_remove (temp_prefs->tree, key);
1938 }
1939 
1940 /* Add an integer value to temp prefs */
temp_prefs_set_int(TempPrefs * temp_prefs,const gchar * key,const gint value)1941 void temp_prefs_set_int(TempPrefs *temp_prefs, const gchar *key,
1942 			const gint value)
1943 {
1944     gchar *strvalue; /* String value converted from integer */
1945 
1946     g_return_if_fail (temp_prefs && temp_prefs->tree);
1947     g_return_if_fail (key);
1948 
1949     strvalue = g_strdup_printf("%i", value);
1950     g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
1951 }
1952 
1953 /* Add an int64 to temp prefs */
temp_prefs_set_int64(TempPrefs * temp_prefs,const gchar * key,const gint64 value)1954 void temp_prefs_set_int64(TempPrefs *temp_prefs, const gchar *key,
1955 			  const gint64 value)
1956 {
1957     gchar *strvalue; /* String value converted from int64 */
1958 
1959     g_return_if_fail (temp_prefs && temp_prefs->tree);
1960     g_return_if_fail (key);
1961 
1962     strvalue = g_strdup_printf("%" G_GINT64_FORMAT, value);
1963     g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
1964 }
1965 
temp_prefs_set_double(TempPrefs * temp_prefs,const gchar * key,gdouble value)1966 void temp_prefs_set_double(TempPrefs *temp_prefs, const gchar *key,
1967 			   gdouble value)
1968 {
1969     gchar *strvalue; /* String value converted from int64 */
1970 
1971     g_return_if_fail (temp_prefs && temp_prefs->tree);
1972     g_return_if_fail (key);
1973 
1974     strvalue = g_strdup_printf("%fu", value);
1975     g_tree_insert(temp_prefs->tree, g_strdup(key), strvalue);
1976 }
1977 
1978 /* Get a string value associated with a key. Free returned string. */
temp_prefs_get_string(TempPrefs * temp_prefs,const gchar * key)1979 gchar *temp_prefs_get_string(TempPrefs *temp_prefs, const gchar *key)
1980 {
1981     g_return_val_if_fail (temp_prefs && temp_prefs->tree, NULL);
1982     g_return_val_if_fail (key, NULL);
1983 
1984     return g_strdup (g_tree_lookup (temp_prefs->tree, key));
1985 }
1986 
1987 /* Use this if you need to know if the given key actually exists */
1988 /* The value parameter can be NULL if you don't need the value itself. */
temp_prefs_get_string_value(TempPrefs * temp_prefs,const gchar * key,gchar ** value)1989 gboolean temp_prefs_get_string_value(TempPrefs *temp_prefs,
1990 				     const gchar *key, gchar **value)
1991 {
1992     gchar *string;  /* String value from prefs table */
1993 
1994     g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
1995     g_return_val_if_fail (key, FALSE);
1996 
1997     string = g_tree_lookup (temp_prefs->tree, key);
1998 
1999     if (value)
2000 	*value = g_strdup (string);
2001 
2002     if (string)
2003 	return TRUE;
2004     else
2005 	return FALSE;
2006 }
2007 
2008 /* Get an integer value from a key */
temp_prefs_get_int(TempPrefs * temp_prefs,const gchar * key)2009 gint temp_prefs_get_int(TempPrefs *temp_prefs, const gchar *key)
2010 {
2011     gchar *string; /* Hash value string */
2012     gint value;  /* Returned value */
2013 
2014     g_return_val_if_fail (temp_prefs && temp_prefs->tree, 0);
2015     g_return_val_if_fail (key, 0);
2016 
2017     value = 0;
2018 
2019     string = g_tree_lookup (temp_prefs->tree, key);
2020 
2021     if (string)
2022 	value = atoi(string);
2023 
2024     return value;
2025 }
2026 
2027 /* Use this if you need to know if the given key actually exists */
2028 /* The value parameter can be NULL if you don't need the value itself. */
temp_prefs_get_int_value(TempPrefs * temp_prefs,const gchar * key,gint * value)2029 gboolean temp_prefs_get_int_value(TempPrefs *temp_prefs,
2030 				  const gchar *key, gint *value)
2031 {
2032     gchar *string;  /* String value from prefs table */
2033 
2034     g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
2035     g_return_val_if_fail (key, FALSE);
2036 
2037     string = g_tree_lookup (temp_prefs->tree, key);
2038 
2039     if (value)
2040     {
2041 	if (string)
2042 	    *value = atoi(string);
2043 	else
2044 	    *value = 0;
2045     }
2046 
2047     if (string)
2048 	return TRUE;
2049     else
2050 	return FALSE;
2051 }
2052 
temp_prefs_get_double(TempPrefs * temp_prefs,const gchar * key)2053 gdouble temp_prefs_get_double(TempPrefs *temp_prefs,
2054 			      const gchar *key)
2055 {
2056     gchar *string; /* Hash value string */
2057     gdouble value;  /* Returned value */
2058 
2059     g_return_val_if_fail (temp_prefs && temp_prefs->tree, 0);
2060     g_return_val_if_fail (key, 0);
2061 
2062     value = 0.0f;
2063 
2064     string = g_tree_lookup (temp_prefs->tree, key);
2065 
2066     if (string)
2067 	value = g_ascii_strtod(string, NULL);
2068 
2069     return value;
2070 }
2071 
temp_prefs_get_double_value(TempPrefs * temp_prefs,const gchar * key,gdouble * value)2072 gboolean temp_prefs_get_double_value(TempPrefs *temp_prefs,
2073 				    const gchar *key, gdouble *value)
2074 {
2075     gchar *string;  /* String value from prefs table */
2076 
2077     g_return_val_if_fail (temp_prefs && temp_prefs->tree, FALSE);
2078     g_return_val_if_fail (key, FALSE);
2079 
2080     string = g_tree_lookup (temp_prefs->tree, key);
2081 
2082     if (value)
2083     {
2084 	if (string)
2085 	    *value = g_ascii_strtod(string, NULL);
2086 	else
2087 	    *value = 0;
2088     }
2089 
2090     if (string)
2091 	return TRUE;
2092     else
2093 	return FALSE;
2094 }
2095 
2096 /* Functions for numbered pref keys */
2097 
2098 /* Set a string value with the given key */
temp_prefs_set_string_index(TempPrefs * temp_prefs,const gchar * key,const guint index,const gchar * value)2099 void temp_prefs_set_string_index(TempPrefs *temp_prefs, const gchar *key,
2100 				 const guint index, const gchar *value)
2101 {
2102     gchar *full_key; /* Complete numbered key */
2103 
2104     g_return_if_fail (temp_prefs && temp_prefs->tree);
2105     g_return_if_fail (key);
2106 
2107     full_key = create_full_key(key, index);
2108     temp_prefs_set_string(temp_prefs, full_key, value);
2109 
2110     g_free(full_key);
2111 }
2112 
2113 /* Set a key value to a given integer */
temp_prefs_set_int_index(TempPrefs * temp_prefs,const gchar * key,const guint index,const gint value)2114 void temp_prefs_set_int_index(TempPrefs *temp_prefs, const gchar *key,
2115 			      const guint index, const gint value)
2116 {
2117     gchar *full_key; /* Complete numbered key */
2118 
2119     g_return_if_fail (temp_prefs && temp_prefs->tree);
2120     g_return_if_fail (key);
2121 
2122     full_key = create_full_key(key, index);
2123     temp_prefs_set_int(temp_prefs, full_key, value);
2124 
2125     g_free(full_key);
2126 }
2127 
2128 /* Set a key to an int64 value */
temp_prefs_set_int64_index(TempPrefs * temp_prefs,const gchar * key,const guint index,const gint64 value)2129 void temp_prefs_set_int64_index(TempPrefs *temp_prefs, const gchar *key,
2130 				const guint index, const gint64 value)
2131 {
2132     gchar *full_key; /* Complete numbered key */
2133 
2134     g_return_if_fail (temp_prefs && temp_prefs->tree);
2135     g_return_if_fail (key);
2136 
2137     full_key = create_full_key(key, index);
2138     temp_prefs_set_int64(temp_prefs, full_key, value);
2139 
2140     g_free(full_key);
2141 }
2142 
2143 /* Functions for variable-length lists */
2144 
2145 /* Create a tree that contains lists that need to be rebuilt */
2146 /* Free the returned structure with destroy_temp_lists */
temp_lists_create()2147 TempLists *temp_lists_create()
2148 {
2149     TempLists *temp_lists;  /* Allocated temp list structure */
2150 
2151     temp_lists = (TempLists*)g_malloc(sizeof(TempLists));
2152 
2153 
2154     temp_lists->tree = g_tree_new_full((GCompareDataFunc)strcmp, NULL,
2155 				       g_free,
2156 				       (GDestroyNotify)prefs_free_list);
2157     return temp_lists;
2158 }
2159 
2160 /* Destroys the list tree */
temp_lists_destroy(TempLists * temp_lists)2161 void temp_lists_destroy(TempLists *temp_lists)
2162 {
2163     if (temp_lists)
2164     {
2165 	if (temp_lists->tree)
2166 	    g_tree_destroy(temp_lists->tree);
2167 
2168 	g_free(temp_lists);
2169     }
2170 }
2171 
2172 /* Add a list with the given key prefix to a temp list tree */
temp_list_add(TempLists * temp_lists,const gchar * key,GList * list)2173 void temp_list_add(TempLists *temp_lists, const gchar *key, GList *list)
2174 {
2175     if (temp_lists)
2176     {
2177 	if (temp_lists->tree)
2178 	    g_tree_insert(temp_lists->tree, g_strdup(key), list);
2179     }
2180 }
2181 
2182 /* Copy the items of the lists in the given tree to the prefs table */
temp_lists_apply(TempLists * temp_lists)2183 void temp_lists_apply(TempLists *temp_lists)
2184 {
2185     if (temp_lists)
2186     {
2187 	if (temp_lists->tree)
2188 	    g_tree_foreach(temp_lists->tree, copy_list, NULL);
2189     }
2190 }
2191 
2192 /* Copy one list to the prefs table. Useful for lists not changed by a window */
prefs_apply_list(gchar * key,GList * list)2193 void prefs_apply_list(gchar *key, GList *list)
2194 {
2195     GList *node;  /* Current list node */
2196     guint i;  /* Counter */
2197 
2198     i = 0;
2199 
2200     if (prefs_table)
2201     {
2202 	/* Clean the existing list */
2203 	wipe_list(key);
2204 
2205 	node = list;
2206 
2207 	/* Add the new list items to the table */
2208 	while (node)
2209 	{
2210 	    g_hash_table_insert(prefs_table, create_full_key(key, i),
2211 				g_strdup(node->data));
2212 
2213 	    node = g_list_next(node);
2214 	    i++;
2215 	}
2216 
2217 	/* Add the end marker */
2218 	g_hash_table_insert(prefs_table, create_full_key(key, i),
2219 			    g_strdup(LIST_END_MARKER));
2220     }
2221 }
2222 
2223 /* Get the items in a variable-length list from the prefs table */
prefs_get_list(const gchar * key)2224 GList *prefs_get_list(const gchar *key)
2225 {
2226     guint end_marker_hash;  /* Hash value of the list end marker */
2227     guint item_hash;  /* Hash value of current list string */
2228     gchar *item_string;  /* List item string */
2229     guint i;  /* Counter */
2230     GList *list;  /* List that contains items */
2231 
2232     /* Go through each key in the table until we find the end marker */
2233     end_marker_hash = g_str_hash(LIST_END_MARKER);
2234     list = NULL;
2235 
2236     for (i = 0;;i++)
2237     {
2238 	item_string = prefs_get_string_index(key, i);
2239 
2240 	if (item_string)
2241 	{
2242 	    item_hash = g_str_hash(item_string);
2243 
2244 	    if (item_hash != end_marker_hash)
2245 	    {
2246 		list = g_list_append(list, item_string);
2247 		continue;
2248 	    }
2249 	    else
2250 	    {
2251 		g_free(item_string);
2252 		break;
2253 	    }
2254 	}
2255     }
2256 
2257     return list;
2258 }
2259 
2260 /* Free a list and its strings */
prefs_free_list(GList * list)2261 void prefs_free_list(GList *list)
2262 {
2263     GList *node;  /* Current list node */
2264 
2265     node = list;
2266 
2267     /* Go through the list, freeing the strings */
2268 
2269     while (node)
2270     {
2271 	if (node->data)
2272 	    g_free(node->data);
2273 
2274 	node = g_list_next(node);
2275     }
2276 
2277     g_list_free(list);
2278 }
2279 
2280 /* Creates a list from lines in a GtkTextBuffer. Free the list when done. */
get_list_from_buffer(GtkTextBuffer * buffer)2281 GList *get_list_from_buffer(GtkTextBuffer *buffer)
2282 {
2283     GtkTextIter start_iter; /* Start of buffer text */
2284     GtkTextIter end_iter; /* End of buffer text */
2285     gchar *text_buffer; /* Raw text buffer */
2286     gchar **string_array; /* Contains each line of the buffer */
2287     gchar **string_iter;  /* Pointer for iterating through the string vector */
2288     GList *list; /* List that contains each string */
2289 
2290     list = NULL;
2291 
2292     /* Grab the text from the buffer, and then split it up by lines */
2293     gtk_text_buffer_get_start_iter(buffer, &start_iter);
2294     gtk_text_buffer_get_end_iter(buffer, &end_iter);
2295 
2296     text_buffer = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, FALSE);
2297     string_array = g_strsplit(text_buffer, "\n", -1);
2298     string_iter = string_array;
2299 
2300     /* Go through each string and put it in the list */
2301     while (*string_iter)
2302     {
2303 	if (strlen(*string_iter) != 0)
2304 	    list = g_list_append(list, g_strdup(*string_iter));
2305 
2306 	string_iter++;
2307     }
2308 
2309     g_free (text_buffer);
2310     g_strfreev (string_array);
2311 
2312     return list;
2313 }
2314