0cee33eb0c208983e3c7698f5c6a5a875e10c55b
[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         gtkut_button_set_create(&confirm_area,
473                                 &ok_btn,        _("OK"),
474                                 &cancel_btn,    _("Cancel"),
475                                 &apply_btn,     _("Apply"));
476         gtk_widget_show(confirm_area);
477         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
478         gtk_widget_grab_default(ok_btn);
479
480         dialog->window     = window;
481         dialog->notebook   = notebook;
482         dialog->ok_btn     = ok_btn;
483         dialog->cancel_btn = cancel_btn;
484         dialog->apply_btn  = apply_btn;
485 }
486
487 void prefs_button_toggled(GtkToggleButton *toggle_btn, GtkWidget *widget)
488 {
489         gboolean is_active;
490
491         is_active = gtk_toggle_button_get_active(toggle_btn);
492         gtk_widget_set_sensitive(widget, is_active);
493 }
494
495 void prefs_set_dialog(PrefParam *param)
496 {
497         gint i;
498
499         for (i = 0; param[i].name != NULL; i++) {
500                 if (param[i].widget_set_func)
501                         param[i].widget_set_func(&param[i]);
502         }
503 }
504
505 void prefs_set_data_from_dialog(PrefParam *param)
506 {
507         gint i;
508
509         for (i = 0; param[i].name != NULL; i++) {
510                 if (param[i].data_set_func)
511                         param[i].data_set_func(&param[i]);
512         }
513 }
514
515 void prefs_set_dialog_to_default(PrefParam *param)
516 {
517         gint       i;
518         PrefParam  tmpparam;
519         gchar     *str_data = NULL;
520         gint       int_data;
521         gushort    ushort_data;
522         gboolean   bool_data;
523         DummyEnum  enum_data;
524
525         for (i = 0; param[i].name != NULL; i++) {
526                 if (!param[i].widget_set_func) continue;
527
528                 tmpparam = param[i];
529
530                 switch (tmpparam.type) {
531                 case P_STRING:
532                         if (tmpparam.defval) {
533                                 if (!strncasecmp(tmpparam.defval, "ENV_", 4)) {
534                                         str_data = g_strdup(g_getenv(param[i].defval + 4));
535                                         tmpparam.data = &str_data;
536                                         break;
537                                 } else if (tmpparam.defval[0] == '~') {
538                                         str_data =
539                                                 g_strconcat(get_home_dir(),
540                                                             param[i].defval + 1,
541                                                             NULL);
542                                         tmpparam.data = &str_data;
543                                         break;
544                                 }
545                         }
546                         tmpparam.data = &tmpparam.defval;
547                         break;
548                 case P_INT:
549                         if (tmpparam.defval)
550                                 int_data = atoi(tmpparam.defval);
551                         else
552                                 int_data = 0;
553                         tmpparam.data = &int_data;
554                         break;
555                 case P_USHORT:
556                         if (tmpparam.defval)
557                                 ushort_data = atoi(tmpparam.defval);
558                         else
559                                 ushort_data = 0;
560                         tmpparam.data = &ushort_data;
561                         break;
562                 case P_BOOL:
563                         if (tmpparam.defval) {
564                                 if (!strcasecmp(tmpparam.defval, "TRUE"))
565                                         bool_data = TRUE;
566                                 else
567                                         bool_data = atoi(tmpparam.defval)
568                                                 ? TRUE : FALSE;
569                         } else
570                                 bool_data = FALSE;
571                         tmpparam.data = &bool_data;
572                         break;
573                 case P_ENUM:
574                         if (tmpparam.defval)
575                                 enum_data = (DummyEnum)atoi(tmpparam.defval);
576                         else
577                                 enum_data = 0;
578                         tmpparam.data = &enum_data;
579                         break;
580                 case P_OTHER:
581                         break;
582                 }
583                 tmpparam.widget_set_func(&tmpparam);
584                 g_free(str_data);
585                 str_data = NULL;
586         }
587 }
588
589 void prefs_set_data_from_entry(PrefParam *pparam)
590 {
591         gchar **str, *entry_str;
592
593         g_return_if_fail(*pparam->widget != NULL);
594
595         entry_str = gtk_entry_get_text(GTK_ENTRY(*pparam->widget));
596
597         switch (pparam->type) {
598         case P_STRING:
599                 str = (gchar **)pparam->data;
600                 g_free(*str);
601                 *str = entry_str[0] ? g_strdup(entry_str) : NULL;
602                 break;
603         case P_USHORT:
604                 *((gushort *)pparam->data) = atoi(entry_str);
605                 break;
606         case P_INT:
607                 *((gint *)pparam->data) = atoi(entry_str);
608                 break;
609         default:
610                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
611                           pparam->type);
612         }
613 }
614
615 void prefs_set_entry(PrefParam *pparam)
616 {
617         gchar **str;
618
619         g_return_if_fail(*pparam->widget != NULL);
620
621         switch (pparam->type) {
622         case P_STRING:
623                 str = (gchar **)pparam->data;
624                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
625                                    *str ? *str : "");
626                 break;
627         case P_INT:
628                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
629                                    itos(*((gint *)pparam->data)));
630                 break;
631         case P_USHORT:
632                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
633                                    itos(*((gushort *)pparam->data)));
634                 break;
635         default:
636                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
637                           pparam->type);
638         }
639 }
640
641 void prefs_set_data_from_text(PrefParam *pparam)
642 {
643         gchar **str;
644         gchar *text, *tp;
645         gchar *tmp, *tmpp;
646
647         g_return_if_fail(*pparam->widget != NULL);
648
649         switch (pparam->type) {
650         case P_STRING:
651                 str = (gchar **)pparam->data;
652                 g_free(*str);
653                 tp = text = gtk_editable_get_chars
654                         (GTK_EDITABLE(*pparam->widget), 0, -1);
655                 if (text[0] == '\0') {
656                         *str = NULL;
657                         g_free(text);
658                         break;
659                 }
660
661                 Xalloca(tmpp = tmp, strlen(text) * 2 + 1,
662                         { *str = NULL; break; });
663                 while (*tp) {
664                         if (*tp == '\n') {
665                                 *tmpp++ = '\\';
666                                 *tmpp++ = 'n';
667                                 tp++;
668                         } else
669                                 *tmpp++ = *tp++;
670                 }
671                 *tmpp = '\0';
672                 *str = g_strdup(tmp);
673                 g_free(text);
674                 break;
675         default:
676                 g_warning("Invalid PrefType for GtkText widget: %d\n",
677                           pparam->type);
678         }
679 }
680
681 void prefs_set_text(PrefParam *pparam)
682 {
683         gchar *buf, *sp, *bufp;
684         gchar **str;
685         GtkText *text;
686
687         g_return_if_fail(*pparam->widget != NULL);
688
689         switch (pparam->type) {
690         case P_STRING:
691                 str = (gchar **)pparam->data;
692                 if (*str) {
693                         bufp = buf = alloca(strlen(*str) + 1);
694                         if (!buf) buf = "";
695                         else {
696                                 sp = *str;
697                                 while (*sp) {
698                                         if (*sp == '\\' && *(sp + 1) == 'n') {
699                                                 *bufp++ = '\n';
700                                                 sp += 2;
701                                         } else
702                                                 *bufp++ = *sp++;
703                                 }
704                                 *bufp = '\0';
705                         }
706                 } else
707                         buf = "";
708
709                 text = GTK_TEXT(*pparam->widget);
710                 gtk_text_set_point(text, 0);
711                 gtk_text_forward_delete(text, gtk_text_get_length(text));
712                 gtk_text_set_point(text, 0);
713                 gtk_text_insert(text, NULL, NULL, NULL, buf, -1);
714                 break;
715         default:
716                 g_warning("Invalid PrefType for GtkText widget: %d\n",
717                           pparam->type);
718         }
719 }
720
721 void prefs_set_data_from_toggle(PrefParam *pparam)
722 {
723         g_return_if_fail(pparam->type == P_BOOL);
724         g_return_if_fail(*pparam->widget != NULL);
725         
726         *((gboolean *)pparam->data) =
727                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(*pparam->widget));
728 }
729
730 void prefs_set_toggle(PrefParam *pparam)
731 {
732         g_return_if_fail(pparam->type == P_BOOL);
733         g_return_if_fail(*pparam->widget != NULL);
734
735         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(*pparam->widget),
736                                      *((gboolean *)pparam->data));
737 }
738
739 void prefs_set_data_from_spinbtn(PrefParam *pparam)
740 {
741         g_return_if_fail(*pparam->widget != NULL);
742
743         switch (pparam->type) {
744         case P_INT:
745                 *((gint *)pparam->data) =
746                         gtk_spin_button_get_value_as_int
747                         (GTK_SPIN_BUTTON(*pparam->widget));
748                 break;
749         case P_USHORT:
750                 *((gushort *)pparam->data) =
751                         (gushort)gtk_spin_button_get_value_as_int
752                         (GTK_SPIN_BUTTON(*pparam->widget));
753                 break;
754         default:
755                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
756                           pparam->type);
757         }
758 }
759
760 void prefs_set_spinbtn(PrefParam *pparam)
761 {
762         g_return_if_fail(*pparam->widget != NULL);
763
764         switch (pparam->type) {
765         case P_INT:
766                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
767                                           (gfloat)*((gint *)pparam->data));
768                 break;
769         case P_USHORT:
770                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
771                                           (gfloat)*((gushort *)pparam->data));
772                 break;
773         default:
774                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
775                           pparam->type);
776         }
777 }
778
779 gboolean prefs_is_readonly(const gchar * path)
780 {
781         if (path == NULL)
782                 return TRUE;
783
784         return (access(path, W_OK) != 0 && access(path, F_OK) == 0);
785 }
786
787 gboolean prefs_rc_is_readonly(const gchar * rcfile)
788 {
789         gboolean result;
790         gchar * rcpath;
791
792         if (rcfile == NULL)
793                 return TRUE;
794
795         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
796         result = prefs_is_readonly(rcpath);
797         g_free(rcpath);
798
799         return result;
800 }