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