sync with sylpheed 0.5.0pre1
[claws.git] / src / prefs.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999,2000 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <gtk/gtk.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include "intl.h"
32 #include "main.h"
33 #include "prefs.h"
34 #include "utils.h"
35 #include "gtkutils.h"
36
37 typedef enum
38 {
39         DUMMY_PARAM
40 } DummyEnum;
41
42 #define PREFSBUFSIZE    1024
43
44 void prefs_read_config(PrefParam *param, const gchar *label,
45                        const gchar *rcfile)
46 {
47         FILE *fp;
48         gchar buf[PREFSBUFSIZE];
49         gchar *rcpath;
50         gchar *block_label;
51
52         g_return_if_fail(param != NULL);
53         g_return_if_fail(label != NULL);
54         g_return_if_fail(rcfile != NULL);
55
56         debug_print(_("Reading configuration...\n"));
57
58         prefs_set_default(param);
59
60         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
61         if ((fp = fopen(rcpath, "r")) == NULL) {
62                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
63                 g_free(rcpath);
64                 return;
65         }
66         g_free(rcpath);
67
68         block_label = g_strdup_printf("[%s]", label);
69
70         /* search aiming block */
71         while (fgets(buf, sizeof(buf), fp) != NULL) {
72                 gint val;
73
74                 val = strncmp(buf, block_label, strlen(block_label));
75                 if (val == 0) {
76                         debug_print(_("Found %s\n"), block_label);
77                         break;
78                 }
79         }
80         g_free(block_label);
81
82         while (fgets(buf, sizeof(buf), fp) != NULL) {
83                 strretchomp(buf);
84                 /* reached next block */
85                 if (buf[0] == '[') break;
86
87                 prefs_config_parse_one_line(param, buf);
88         }
89
90         debug_print(_("Finished reading configuration.\n"));
91         fclose(fp);
92 }
93
94 void prefs_config_parse_one_line(PrefParam *param, const gchar *buf)
95 {
96         gint i;
97         gint name_len;
98         const gchar *value;
99
100         for (i = 0; param[i].name != NULL; i++) {
101                 name_len = strlen(param[i].name);
102                 if (strncasecmp(buf, param[i].name, name_len))
103                         continue;
104                 if (buf[name_len] != '=')
105                         continue;
106                 value = buf + name_len + 1;
107                 debug_print("%s = %s\n", param[i].name, value);
108
109                 switch (param[i].type) {
110                 case P_STRING:
111                         g_free(*((gchar **)param[i].data));
112                         *((gchar **)param[i].data) =
113                                 *value ? g_strdup(value) : NULL;
114                         break;
115                 case P_INT:
116                         *((gint *)param[i].data) =
117                                 (gint)atoi(value);
118                         break;
119                 case P_BOOL:
120                         *((gboolean *)param[i].data) =
121                                 (*value == '0' || *value == '\0')
122                                         ? FALSE : TRUE;
123                         break;
124                 case P_ENUM:
125                         *((DummyEnum *)param[i].data) =
126                                 (DummyEnum)atoi(value);
127                         break;
128                 case P_USHORT:
129                         *((gushort *)param[i].data) =
130                                 (gushort)atoi(value);
131                         break;
132                 default:
133                 }
134         }
135 }
136
137 #define TRY(func) \
138 if (!(func)) \
139 { \
140         g_warning(_("failed to write configuration to file\n")); \
141         if (orig_fp) fclose(orig_fp); \
142         prefs_write_close_revert(pfile); \
143         g_free(rcpath); \
144         g_free(block_label); \
145         return; \
146 } \
147
148 void prefs_save_config(PrefParam *param, const gchar *label,
149                        const gchar *rcfile)
150 {
151         FILE *orig_fp;
152         PrefFile *pfile;
153         gchar *rcpath;
154         gchar buf[PREFSBUFSIZE];
155         gchar *block_label = NULL;
156         gboolean block_matched = FALSE;
157
158         g_return_if_fail(param != NULL);
159         g_return_if_fail(label != NULL);
160         g_return_if_fail(rcfile != NULL);
161
162         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
163         if ((orig_fp = fopen(rcpath, "r")) == NULL) {
164                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
165         }
166
167         if ((pfile = prefs_write_open(rcpath)) == NULL) {
168                 g_warning(_("failed to write configuration to file\n"));
169                 if (orig_fp) fclose(orig_fp);
170                 g_free(rcpath);
171                 return;
172         }
173
174         block_label = g_strdup_printf("[%s]", label);
175
176         /* search aiming block */
177         if (orig_fp) {
178                 while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
179                         gint val;
180
181                         val = strncmp(buf, block_label, strlen(block_label));
182                         if (val == 0) {
183                                 debug_print(_("Found %s\n"), block_label);
184                                 block_matched = TRUE;
185                                 break;
186                         } else
187                                 TRY(fputs(buf, pfile->fp) != EOF);
188                 }
189         }
190
191         TRY(fprintf(pfile->fp, "%s\n", block_label) > 0);
192         g_free(block_label);
193         block_label = NULL;
194
195         /* write all param data to file */
196         TRY(prefs_write_param(param, pfile->fp) == 0);
197
198         if (block_matched) {
199                 while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
200                         /* next block */
201                         if (buf[0] == '[') {
202                                 TRY(fputc('\n', pfile->fp) != EOF &&
203                                     fputs(buf, pfile->fp)  != EOF);
204                                 break;
205                         }
206                 }
207                 while (fgets(buf, sizeof(buf), orig_fp) != NULL)
208                         TRY(fputs(buf, pfile->fp) != EOF);
209         }
210
211         if (orig_fp) fclose(orig_fp);
212         if (prefs_write_close(pfile) < 0)
213                 g_warning(_("failed to write configuration to file\n"));
214         g_free(rcpath);
215
216         debug_print(_("Configuration is saved.\n"));
217 }
218
219 gint prefs_write_param(PrefParam *param, FILE *fp)
220 {
221         gint i;
222         gchar buf[PREFSBUFSIZE];
223
224         for (i = 0; param[i].name != NULL; i++) {
225                 switch (param[i].type) {
226                 case P_STRING:
227                         g_snprintf(buf, sizeof(buf), "%s=%s\n", param[i].name,
228                                    *((gchar **)param[i].data) ?
229                                    *((gchar **)param[i].data) : "");
230                         break;
231                 case P_INT:
232                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
233                                    *((gint *)param[i].data));
234                         break;
235                 case P_BOOL:
236                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
237                                    *((gboolean *)param[i].data));
238                         break;
239                 case P_ENUM:
240                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
241                                    *((DummyEnum *)param[i].data));
242                         break;
243                 case P_USHORT:
244                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
245                                    *((gushort *)param[i].data));
246                         break;
247                 default:
248                         buf[0] = '\0';
249                 }
250
251                 if (buf[0] != '\0') {
252                         if (fputs(buf, fp) == EOF) {
253                                 perror("fputs");
254                                 return -1;
255                         }
256                 }
257         }
258
259         return 0;
260 }
261
262 PrefFile *prefs_write_open(const gchar *path)
263 {
264         PrefFile *pfile;
265         gchar *tmppath;
266         FILE *fp;
267
268         g_return_val_if_fail(path != NULL, NULL);
269
270         if (prefs_is_readonly(path)) {
271                 g_warning(_("no permission - %s\n"), path);
272                 return NULL;
273         }
274
275         tmppath = g_strconcat(path, ".tmp", NULL);
276         if ((fp = fopen(tmppath, "w")) == NULL) {
277                 FILE_OP_ERROR(tmppath, "fopen");
278                 g_free(tmppath);
279                 return NULL;
280         }
281
282         if (change_file_mode_rw(fp, tmppath) < 0)
283                 FILE_OP_ERROR(tmppath, "chmod");
284
285         g_free(tmppath);
286
287         pfile = g_new(PrefFile, 1);
288         pfile->fp = fp;
289         pfile->path = g_strdup(path);
290
291         return pfile;
292 }
293
294 gint prefs_write_close(PrefFile *pfile)
295 {
296         FILE *fp;
297         gchar *path;
298         gchar *tmppath;
299         gchar *bakpath = NULL;
300
301         g_return_val_if_fail(pfile != NULL, -1);
302
303         fp = pfile->fp;
304         path = pfile->path;
305         g_free(pfile);
306
307         tmppath = g_strconcat(path, ".tmp", NULL);
308         if (fclose(fp) == EOF) {
309                 FILE_OP_ERROR(tmppath, "fclose");
310                 unlink(tmppath);
311                 g_free(path);
312                 g_free(tmppath);
313                 return -1;
314         }
315
316         if (is_file_exist(path)) {
317                 bakpath = g_strconcat(path, ".bak", NULL);
318                 if (rename(path, bakpath) < 0) {
319                         FILE_OP_ERROR(path, "rename");
320                         unlink(tmppath);
321                         g_free(path);
322                         g_free(tmppath);
323                         g_free(bakpath);
324                         return -1;
325                 }
326         }
327
328         if (rename(tmppath, path) < 0) {
329                 FILE_OP_ERROR(tmppath, "rename");
330                 unlink(tmppath);
331                 g_free(path);
332                 g_free(tmppath);
333                 g_free(bakpath);
334                 return -1;
335         }
336
337         g_free(path);
338         g_free(tmppath);
339         g_free(bakpath);
340         return 0;
341 }
342
343 gint prefs_write_close_revert(PrefFile *pfile)
344 {
345         gchar *tmppath;
346
347         g_return_val_if_fail(pfile != NULL, -1);
348
349         tmppath = g_strconcat(pfile->path, ".tmp", NULL);
350         fclose(pfile->fp);
351         if (unlink(tmppath) < 0) FILE_OP_ERROR(tmppath, "unlink");
352         g_free(tmppath);
353         g_free(pfile->path);
354         g_free(pfile);
355
356         return 0;
357 }
358
359 void prefs_set_default(PrefParam *param)
360 {
361         gint i;
362
363         g_return_if_fail(param != NULL);
364
365         for (i = 0; param[i].name != NULL; i++) {
366                 if (!param[i].data) continue;
367
368                 switch (param[i].type) {
369                 case P_STRING:
370                         if (param[i].defval != NULL) {
371                                 if (!strncasecmp(param[i].defval, "ENV_", 4))
372                                         *((gchar **)param[i].data) =
373                                                 g_strdup(g_getenv(param[i].defval + 4));
374                                 else if (param[i].defval[0] == '~')
375                                         *((gchar **)param[i].data) =
376                                                 g_strconcat(get_home_dir(),
377                                                             param[i].defval + 1,
378                                                             NULL);
379                                 else if (param[i].defval[0] != '\0')
380                                         *((gchar **)param[i].data) =
381                                                 g_strdup(param[i].defval);
382                                 else
383                                         *((gchar **)param[i].data) = NULL;
384                         } else
385                                 *((gchar **)param[i].data) = NULL;
386                         break;
387                 case P_INT:
388                         if (param[i].defval != NULL)
389                                 *((gint *)param[i].data) =
390                                         (gint)atoi(param[i].defval);
391                         else
392                                 *((gint *)param[i].data) = 0;
393                         break;
394                 case P_BOOL:
395                         if (param[i].defval != NULL) {
396                                 if (!strcasecmp(param[i].defval, "TRUE"))
397                                         *((gboolean *)param[i].data) = TRUE;
398                                 else
399                                         *((gboolean *)param[i].data) =
400                                                 atoi(param[i].defval) ? TRUE : FALSE;
401                         } else
402                                 *((gboolean *)param[i].data) = FALSE;
403                         break;
404                 case P_ENUM:
405                         if (param[i].defval != NULL)
406                                 *((DummyEnum*)param[i].data) =
407                                         (DummyEnum)atoi(param[i].defval);
408                         else
409                                 *((DummyEnum *)param[i].data) = 0;
410                         break;
411                 case P_USHORT:
412                         if (param[i].defval != NULL)
413                                 *((gushort *)param[i].data) =
414                                         (gushort)atoi(param[i].defval);
415                         else
416                                 *((gushort *)param[i].data) = 0;
417                         break;
418                 default:
419                 }
420         }
421 }
422
423 void prefs_free(PrefParam *param)
424 {
425         gint i;
426
427         g_return_if_fail(param != NULL);
428
429         for (i = 0; param[i].name != NULL; i++) {
430                 if (!param[i].data) continue;
431
432                 switch (param[i].type) {
433                 case P_STRING:
434                         g_free(*((gchar **)param[i].data));
435                         break;
436                 default:
437                 }
438         }
439 }
440
441 void prefs_dialog_create(PrefsDialog *dialog)
442 {
443         GtkWidget *window;
444         GtkWidget *vbox;
445         GtkWidget *notebook;
446
447         GtkWidget *confirm_area;
448         GtkWidget *ok_btn;
449         GtkWidget *cancel_btn;
450         GtkWidget *apply_btn;
451
452         g_return_if_fail(dialog != NULL);
453
454         window = gtk_window_new (GTK_WINDOW_DIALOG);
455         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
456         gtk_window_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
457         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
458         gtk_window_set_policy (GTK_WINDOW(window), FALSE, TRUE, FALSE);
459
460         vbox = gtk_vbox_new (FALSE, 6);
461         gtk_widget_show(vbox);
462         gtk_container_add (GTK_CONTAINER (window), vbox);
463
464         notebook = gtk_notebook_new ();
465         gtk_widget_show(notebook);
466         gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
467         gtk_container_set_border_width (GTK_CONTAINER (notebook), 2);
468         /* GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS); */
469         gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
470
471         gtkut_button_set_create(&confirm_area,
472                                 &ok_btn,        _("OK"),
473                                 &cancel_btn,    _("Cancel"),
474                                 &apply_btn,     _("Apply"));
475         gtk_widget_show(confirm_area);
476         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
477         gtk_widget_grab_default(ok_btn);
478
479         dialog->window     = window;
480         dialog->notebook   = notebook;
481         dialog->ok_btn     = ok_btn;
482         dialog->cancel_btn = cancel_btn;
483         dialog->apply_btn  = apply_btn;
484 }
485
486 void prefs_button_toggled(GtkToggleButton *toggle_btn, GtkWidget *widget)
487 {
488         gboolean is_active;
489
490         is_active = gtk_toggle_button_get_active(toggle_btn);
491         gtk_widget_set_sensitive(widget, is_active);
492 }
493
494 void prefs_set_dialog(PrefParam *param)
495 {
496         gint i;
497
498         for (i = 0; param[i].name != NULL; i++) {
499                 if (param[i].widget_set_func)
500                         param[i].widget_set_func(&param[i]);
501         }
502 }
503
504 void prefs_set_data_from_dialog(PrefParam *param)
505 {
506         gint i;
507
508         for (i = 0; param[i].name != NULL; i++) {
509                 if (param[i].data_set_func)
510                         param[i].data_set_func(&param[i]);
511         }
512 }
513
514 void prefs_set_dialog_to_default(PrefParam *param)
515 {
516         gint       i;
517         PrefParam  tmpparam;
518         gchar     *str_data = NULL;
519         gint       int_data;
520         gushort    ushort_data;
521         gboolean   bool_data;
522         DummyEnum  enum_data;
523
524         for (i = 0; param[i].name != NULL; i++) {
525                 if (!param[i].widget_set_func) continue;
526
527                 tmpparam = param[i];
528
529                 switch (tmpparam.type) {
530                 case P_STRING:
531                         if (tmpparam.defval) {
532                                 if (!strncasecmp(tmpparam.defval, "ENV_", 4)) {
533                                         str_data = g_strdup(g_getenv(param[i].defval + 4));
534                                         tmpparam.data = &str_data;
535                                         break;
536                                 } else if (tmpparam.defval[0] == '~') {
537                                         str_data =
538                                                 g_strconcat(get_home_dir(),
539                                                             param[i].defval + 1,
540                                                             NULL);
541                                         tmpparam.data = &str_data;
542                                         break;
543                                 }
544                         }
545                         tmpparam.data = &tmpparam.defval;
546                         break;
547                 case P_INT:
548                         if (tmpparam.defval)
549                                 int_data = atoi(tmpparam.defval);
550                         else
551                                 int_data = 0;
552                         tmpparam.data = &int_data;
553                         break;
554                 case P_USHORT:
555                         if (tmpparam.defval)
556                                 ushort_data = atoi(tmpparam.defval);
557                         else
558                                 ushort_data = 0;
559                         tmpparam.data = &ushort_data;
560                         break;
561                 case P_BOOL:
562                         if (tmpparam.defval) {
563                                 if (!strcasecmp(tmpparam.defval, "TRUE"))
564                                         bool_data = TRUE;
565                                 else
566                                         bool_data = atoi(tmpparam.defval)
567                                                 ? TRUE : FALSE;
568                         } else
569                                 bool_data = FALSE;
570                         tmpparam.data = &bool_data;
571                         break;
572                 case P_ENUM:
573                         if (tmpparam.defval)
574                                 enum_data = (DummyEnum)atoi(tmpparam.defval);
575                         else
576                                 enum_data = 0;
577                         tmpparam.data = &enum_data;
578                         break;
579                 case P_OTHER:
580                 }
581                 tmpparam.widget_set_func(&tmpparam);
582                 g_free(str_data);
583                 str_data = NULL;
584         }
585 }
586
587 void prefs_set_data_from_entry(PrefParam *pparam)
588 {
589         gchar **str, *entry_str;
590
591         g_return_if_fail(*pparam->widget != NULL);
592
593         entry_str = gtk_entry_get_text(GTK_ENTRY(*pparam->widget));
594
595         switch (pparam->type) {
596         case P_STRING:
597                 str = (gchar **)pparam->data;
598                 g_free(*str);
599                 *str = entry_str[0] ? g_strdup(entry_str) : NULL;
600                 break;
601         case P_USHORT:
602                 *((gushort *)pparam->data) = atoi(entry_str);
603                 break;
604         case P_INT:
605                 *((gint *)pparam->data) = atoi(entry_str);
606                 break;
607         default:
608                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
609                           pparam->type);
610         }
611 }
612
613 void prefs_set_entry(PrefParam *pparam)
614 {
615         gchar **str;
616
617         g_return_if_fail(*pparam->widget != NULL);
618
619         switch (pparam->type) {
620         case P_STRING:
621                 str = (gchar **)pparam->data;
622                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
623                                    *str ? *str : "");
624                 break;
625         case P_INT:
626                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
627                                    itos(*((gint *)pparam->data)));
628                 break;
629         case P_USHORT:
630                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
631                                    itos(*((gushort *)pparam->data)));
632                 break;
633         default:
634                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
635                           pparam->type);
636         }
637 }
638
639 void prefs_set_data_from_text(PrefParam *pparam)
640 {
641         gchar **str;
642         gchar *text, *tp;
643         gchar *tmp, *tmpp;
644
645         g_return_if_fail(*pparam->widget != NULL);
646
647         switch (pparam->type) {
648         case P_STRING:
649                 str = (gchar **)pparam->data;
650                 g_free(*str);
651                 tp = text = gtk_editable_get_chars
652                         (GTK_EDITABLE(*pparam->widget), 0, -1);
653                 if (text[0] == '\0') {
654                         *str = NULL;
655                         g_free(text);
656                         break;
657                 }
658
659                 Xalloca(tmpp = tmp, strlen(text) * 2 + 1,
660                         { *str = NULL; break; });
661                 while (*tp) {
662                         if (*tp == '\n') {
663                                 *tmpp++ = '\\';
664                                 *tmpp++ = 'n';
665                                 tp++;
666                         } else
667                                 *tmpp++ = *tp++;
668                 }
669                 *tmpp = '\0';
670                 *str = g_strdup(tmp);
671                 g_free(text);
672                 break;
673         default:
674                 g_warning("Invalid PrefType for GtkText widget: %d\n",
675                           pparam->type);
676         }
677 }
678
679 void prefs_set_text(PrefParam *pparam)
680 {
681         gchar *buf, *sp, *bufp;
682         gchar **str;
683         GtkText *text;
684
685         g_return_if_fail(*pparam->widget != NULL);
686
687         switch (pparam->type) {
688         case P_STRING:
689                 str = (gchar **)pparam->data;
690                 if (*str) {
691                         bufp = buf = alloca(strlen(*str) + 1);
692                         if (!buf) buf = "";
693                         else {
694                                 sp = *str;
695                                 while (*sp) {
696                                         if (*sp == '\\' && *(sp + 1) == 'n') {
697                                                 *bufp++ = '\n';
698                                                 sp += 2;
699                                         } else
700                                                 *bufp++ = *sp++;
701                                 }
702                                 *bufp = '\0';
703                         }
704                 } else
705                         buf = "";
706
707                 text = GTK_TEXT(*pparam->widget);
708                 gtk_text_set_point(text, 0);
709                 gtk_text_forward_delete(text, gtk_text_get_length(text));
710                 gtk_text_set_point(text, 0);
711                 gtk_text_insert(text, NULL, NULL, NULL, buf, -1);
712                 break;
713         default:
714                 g_warning("Invalid PrefType for GtkText widget: %d\n",
715                           pparam->type);
716         }
717 }
718
719 void prefs_set_data_from_toggle(PrefParam *pparam)
720 {
721         g_return_if_fail(pparam->type == P_BOOL);
722         g_return_if_fail(*pparam->widget != NULL);
723         
724         *((gboolean *)pparam->data) =
725                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(*pparam->widget));
726 }
727
728 void prefs_set_toggle(PrefParam *pparam)
729 {
730         g_return_if_fail(pparam->type == P_BOOL);
731         g_return_if_fail(*pparam->widget != NULL);
732
733         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(*pparam->widget),
734                                      *((gboolean *)pparam->data));
735 }
736
737 void prefs_set_data_from_spinbtn(PrefParam *pparam)
738 {
739         g_return_if_fail(*pparam->widget != NULL);
740
741         switch (pparam->type) {
742         case P_INT:
743                 *((gint *)pparam->data) =
744                         gtk_spin_button_get_value_as_int
745                         (GTK_SPIN_BUTTON(*pparam->widget));
746                 break;
747         case P_USHORT:
748                 *((gushort *)pparam->data) =
749                         (gushort)gtk_spin_button_get_value_as_int
750                         (GTK_SPIN_BUTTON(*pparam->widget));
751                 break;
752         default:
753                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
754                           pparam->type);
755         }
756 }
757
758 void prefs_set_spinbtn(PrefParam *pparam)
759 {
760         g_return_if_fail(*pparam->widget != NULL);
761
762         switch (pparam->type) {
763         case P_INT:
764                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
765                                           (gfloat)*((gint *)pparam->data));
766                 break;
767         case P_USHORT:
768                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
769                                           (gfloat)*((gushort *)pparam->data));
770                 break;
771         default:
772                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
773                           pparam->type);
774         }
775 }
776
777 gboolean prefs_is_readonly(const gchar * path)
778 {
779         if (path == NULL)
780                 return TRUE;
781
782         return (access(path, W_OK) != 0 && access(path, F_OK) == 0);
783 }
784
785 gboolean prefs_rc_is_readonly(const gchar * rcfile)
786 {
787         gboolean result;
788         gchar * rcpath;
789
790         if (rcfile == NULL)
791                 return TRUE;
792
793         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
794         result = prefs_is_readonly(rcpath);
795         g_free(rcpath);
796
797         return result;
798 }