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