2006-04-05 [colin] 2.1.0cvs4
[claws.git] / src / prefs_gtk.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <glib/gi18n.h>
26 #include <gtk/gtk.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32
33 #include "main.h"
34 #include "prefs.h"
35 #include "prefs_gtk.h"
36 #include "prefs_common.h"
37 #include "utils.h"
38 #include "gtkutils.h"
39 #include "passcrypt.h"
40 #include "base64.h"
41 #include "codeconv.h"
42
43 #define CL(x)   (((gulong) (x) >> (gulong) 8) & 0xFFUL)
44 #define RGB_FROM_GDK_COLOR(c) \
45         ((CL(c.red)   << (gulong) 16) | \
46          (CL(c.green) << (gulong)  8) | \
47          (CL(c.blue)))
48
49 typedef enum
50 {
51         DUMMY_PARAM
52 } DummyEnum;
53
54 void prefs_read_config(PrefParam *param, const gchar *label,
55                        const gchar *rcfile, const gchar *encoding)
56 {
57         FILE *fp;
58         gchar buf[PREFSBUFSIZE];
59         gchar *block_label;
60
61         g_return_if_fail(param != NULL);
62         g_return_if_fail(label != NULL);
63         g_return_if_fail(rcfile != NULL);
64
65         debug_print("Reading configuration...\n");
66
67         prefs_set_default(param);
68
69         if ((fp = g_fopen(rcfile, "rb")) == NULL) {
70                 if (ENOENT != errno) FILE_OP_ERROR(rcfile, "fopen");
71                 return;
72         }
73
74         block_label = g_strdup_printf("[%s]", label);
75
76         /* search aiming block */
77         while (fgets(buf, sizeof(buf), fp) != NULL) {
78                 gint val;
79
80                 if (encoding) {
81                         gchar *conv_str;
82
83                         conv_str = conv_codeset_strdup
84                                 (buf, encoding, CS_INTERNAL);
85                         if (!conv_str)
86                                 conv_str = g_strdup(buf);
87                         val = strncmp
88                                 (conv_str, block_label, strlen(block_label));
89                         g_free(conv_str);
90                 } else
91                         val = strncmp(buf, block_label, strlen(block_label));
92                 if (val == 0) {
93                         debug_print("Found %s\n", block_label);
94                         break;
95                 }
96         }
97         g_free(block_label);
98
99         while (fgets(buf, sizeof(buf), fp) != NULL) {
100                 strretchomp(buf);
101                 /* reached next block */
102                 if (buf[0] == '[') break;
103                 if (buf[0] == '#') continue;
104
105                 if (encoding) {
106                         gchar *conv_str;
107
108                         conv_str = conv_codeset_strdup
109                                 (buf, encoding, CS_INTERNAL);
110                         if (!conv_str)
111                                 conv_str = g_strdup(buf);
112                         prefs_config_parse_one_line(param, conv_str);
113                         g_free(conv_str);
114                 } else
115                         prefs_config_parse_one_line(param, buf);
116         }
117
118         debug_print("Finished reading configuration.\n");
119         fclose(fp);
120 }
121
122 void prefs_config_parse_one_line(PrefParam *param, const gchar *buf)
123 {
124         gint i;
125         gint name_len;
126         const gchar *value;
127         GdkColor color;
128
129         for (i = 0; param[i].name != NULL; i++) {
130                 name_len = strlen(param[i].name);
131                 if (g_ascii_strncasecmp(buf, param[i].name, name_len))
132                         continue;
133                 if (buf[name_len] != '=')
134                         continue;
135                 value = buf + name_len + 1;
136                 /* debug_print("%s = %s\n", param[i].name, value); */
137
138                 switch (param[i].type) {
139                 case P_STRING:
140                 {
141                         gchar *tmp;
142
143                         tmp = *value ?
144                                 conv_codeset_strdup(value,
145                                                     conv_get_locale_charset_str(),
146                                                     CS_UTF_8)
147                                 : g_strdup("");
148                         if (!tmp) {
149                                 g_warning("failed to convert character set.");
150                                 tmp = g_strdup(value);
151                         }
152                         g_free(*((gchar **)param[i].data));
153                         *((gchar **)param[i].data) = tmp;
154                         break;
155                 }
156                 case P_INT:
157                         *((gint *)param[i].data) =
158                                 (gint)atoi(value);
159                         break;
160                 case P_BOOL:
161                         *((gboolean *)param[i].data) =
162                                 (*value == '0' || *value == '\0')
163                                         ? FALSE : TRUE;
164                         break;
165                 case P_ENUM:
166                         *((DummyEnum *)param[i].data) =
167                                 (DummyEnum)atoi(value);
168                         break;
169                 case P_USHORT:
170                         *((gushort *)param[i].data) =
171                                 (gushort)atoi(value);
172                         break;
173                 case P_COLOR:
174                         if (gdk_color_parse(value, &color)) 
175                                 *((gulong *)param[i].data) = RGB_FROM_GDK_COLOR(color); 
176                         else 
177                                 /* be compatible and accept ints */
178                                 *((gulong *)param[i].data) = strtoul(value, 0, 10); 
179                         break;
180                 case P_PASSWORD:
181                         g_free(*((gchar **)param[i].data));
182                         if (value[0] == '!') {
183                                 gchar tmp[1024];
184                                 gint len;
185
186                                 len = base64_decode(tmp, &value[1], strlen(value) - 1);
187                                 passcrypt_decrypt(tmp, len);
188                                 tmp[len] = '\0';
189                                 *((gchar **)param[i].data) =
190                                         *tmp ? g_strdup(tmp) : NULL;
191                         } else {
192                                 *((gchar **)param[i].data) =
193                                         *value ? g_strdup(value) : NULL;
194                         }
195                         break;
196                 default:
197                         break;
198                 }
199         }
200 }
201
202 #define TRY(func) \
203 if (!(func)) \
204 { \
205         g_warning("failed to write configuration to file\n"); \
206         if (orig_fp) fclose(orig_fp); \
207         prefs_file_close_revert(pfile); \
208         g_free(rcpath); \
209         g_free(block_label); \
210         return; \
211 } \
212
213 void prefs_write_config(PrefParam *param, const gchar *label,
214                         const gchar *rcfile)
215 {
216         FILE *orig_fp;
217         PrefFile *pfile;
218         gchar *rcpath;
219         gchar buf[PREFSBUFSIZE];
220         gchar *block_label = NULL;
221         gboolean block_matched = FALSE;
222
223         g_return_if_fail(param != NULL);
224         g_return_if_fail(label != NULL);
225         g_return_if_fail(rcfile != NULL);
226
227         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, rcfile, NULL);
228         if ((orig_fp = g_fopen(rcpath, "rb")) == NULL) {
229                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
230         }
231
232         if ((pfile = prefs_write_open(rcpath)) == NULL) {
233                 g_warning("failed to write configuration to file\n");
234                 if (orig_fp) fclose(orig_fp);
235                 g_free(rcpath);
236                 return;
237         }
238
239         block_label = g_strdup_printf("[%s]", label);
240
241         /* search aiming block */
242         if (orig_fp) {
243                 while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
244                         gint val;
245
246                         val = strncmp(buf, block_label, strlen(block_label));
247                         if (val == 0) {
248                                 debug_print("Found %s\n", block_label);
249                                 block_matched = TRUE;
250                                 break;
251                         } else
252                                 TRY(fputs(buf, pfile->fp) != EOF);
253                 }
254         }
255
256         TRY(fprintf(pfile->fp, "%s\n", block_label) > 0);
257         g_free(block_label);
258         block_label = NULL;
259
260         /* write all param data to file */
261         TRY(prefs_write_param(param, pfile->fp) == 0);
262
263         if (block_matched) {
264                 while (fgets(buf, sizeof(buf), orig_fp) != NULL) {
265                         /* next block */
266                         if (buf[0] == '[') {
267                                 TRY(fputc('\n', pfile->fp) != EOF &&
268                                     fputs(buf, pfile->fp)  != EOF);
269                                 break;
270                         }
271                 }
272                 while (fgets(buf, sizeof(buf), orig_fp) != NULL)
273                         TRY(fputs(buf, pfile->fp) != EOF);
274         }
275
276         if (orig_fp) fclose(orig_fp);
277         if (prefs_file_close(pfile) < 0)
278                 g_warning("failed to write configuration to file\n");
279         g_free(rcpath);
280
281         debug_print("Configuration is saved.\n");
282 }
283
284 gint prefs_write_param(PrefParam *param, FILE *fp)
285 {
286         gint i;
287         gchar buf[PREFSBUFSIZE];
288
289         for (i = 0; param[i].name != NULL; i++) {
290                 switch (param[i].type) {
291                 case P_STRING:
292                 {
293                         gchar *tmp = NULL;
294
295                         if (*((gchar **)param[i].data)) {
296                                 tmp = conv_codeset_strdup(*((gchar **)param[i].data),
297                                                           CS_UTF_8,
298                                                           conv_get_locale_charset_str());
299                                 if (!tmp)
300                                         tmp = g_strdup(*((gchar **)param[i].data));
301                         }
302
303                         g_snprintf(buf, sizeof(buf), "%s=%s\n", param[i].name,
304                                    tmp ? tmp : "");
305
306                         g_free(tmp);
307                         break;
308                 }
309                 case P_INT:
310                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
311                                    *((gint *)param[i].data));
312                         break;
313                 case P_BOOL:
314                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
315                                    *((gboolean *)param[i].data));
316                         break;
317                 case P_ENUM:
318                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
319                                    *((DummyEnum *)param[i].data));
320                         break;
321                 case P_USHORT:
322                         g_snprintf(buf, sizeof(buf), "%s=%d\n", param[i].name,
323                                    *((gushort *)param[i].data));
324                         break;
325                 case P_COLOR:
326                         g_snprintf(buf, sizeof buf,  "%s=#%6.6lx\n", param[i].name,
327                                    *((gulong *) param[i].data));
328                         break;
329                 case P_PASSWORD:
330                         {
331                                 gchar *tmp = NULL, tmp2[1024] = {0};
332
333                                 tmp = *((gchar **)param[i].data);
334                                 if (tmp) {
335                                         gint len;
336
337                                         tmp = g_strdup(tmp);
338                                         len = strlen(tmp);
339                                         passcrypt_encrypt(tmp, len);
340                                         base64_encode(tmp2, tmp, len);
341                                         g_free(tmp);
342                                         tmp = tmp2;
343                                 }
344                                 g_snprintf(buf, sizeof(buf), "%s=!%s\n", param[i].name,
345                                            tmp ?
346                                            tmp : "");
347                         }
348                         break;
349                 default:
350                         /* unrecognized, fail */
351                         debug_print("Unrecognized parameter type\n");
352                         return -1;
353                 }
354
355                 if (buf[0] != '\0') {
356                         if (fputs(buf, fp) == EOF) {
357                                 perror("fputs");
358                                 return -1;
359                         }
360                 }
361         }
362
363         return 0;
364 }
365
366 void prefs_set_default(PrefParam *param)
367 {
368         gint i;
369         GdkColor color;
370
371         g_return_if_fail(param != NULL);
372
373         for (i = 0; param[i].name != NULL; i++) {
374                 if (!param[i].data) continue;
375
376                 switch (param[i].type) {
377                 case P_STRING:
378                 case P_PASSWORD:
379                         g_free(*((gchar **)param[i].data));
380                         if (param[i].defval != NULL) {
381                                 if (!strncasecmp(param[i].defval, "ENV_", 4)) {
382                                         const gchar *envstr;
383                                         gchar *tmp;
384
385                                         envstr = g_getenv(param[i].defval + 4);
386                                         tmp = envstr && *envstr ?
387                                                 conv_codeset_strdup(envstr,
388                                                                     conv_get_locale_charset_str(),
389                                                                     CS_UTF_8)
390                                                 : g_strdup("");
391                                         if (!tmp) {
392                                                 g_warning("faild to convert character set.");
393                                                 tmp = g_strdup(envstr);
394                                         }
395                                         *((gchar **)param[i].data) = tmp;
396                                 } else if (param[i].defval[0] == '~')
397                                         *((gchar **)param[i].data) =
398                                                 g_strconcat(get_home_dir(),
399                                                             param[i].defval + 1,
400                                                             NULL);
401                                 else if (param[i].defval[0] != '\0')
402                                         *((gchar **)param[i].data) =
403                                                 g_strdup(param[i].defval);
404                                 else
405                                         *((gchar **)param[i].data) = NULL;
406                         } else
407                                 *((gchar **)param[i].data) = NULL;
408                         break;
409                 case P_INT:
410                         if (param[i].defval != NULL)
411                                 *((gint *)param[i].data) =
412                                         (gint)atoi(param[i].defval);
413                         else
414                                 *((gint *)param[i].data) = 0;
415                         break;
416                 case P_BOOL:
417                         if (param[i].defval != NULL) {
418                                 if (!g_ascii_strcasecmp(param[i].defval, "TRUE"))
419                                         *((gboolean *)param[i].data) = TRUE;
420                                 else
421                                         *((gboolean *)param[i].data) =
422                                                 atoi(param[i].defval) ? TRUE : FALSE;
423                         } else
424                                 *((gboolean *)param[i].data) = FALSE;
425                         break;
426                 case P_ENUM:
427                         if (param[i].defval != NULL)
428                                 *((DummyEnum*)param[i].data) =
429                                         (DummyEnum)atoi(param[i].defval);
430                         else
431                                 *((DummyEnum *)param[i].data) = 0;
432                         break;
433                 case P_USHORT:
434                         if (param[i].defval != NULL)
435                                 *((gushort *)param[i].data) =
436                                         (gushort)atoi(param[i].defval);
437                         else
438                                 *((gushort *)param[i].data) = 0;
439                         break;
440                 case P_COLOR:
441                         if (param[i].defval != NULL && gdk_color_parse(param[i].defval, &color))
442                                 *((gulong *)param[i].data) =
443                                         RGB_FROM_GDK_COLOR(color);
444                         else if (param[i].defval)
445                                 /* be compatible and accept ints */
446                                 *((gulong *)param[i].data) = strtoul(param[i].defval, 0, 10); 
447                         else
448                                 *((gulong *)param[i].data) = 0; 
449                         break;
450                 default:
451                         break;
452                 }
453         }
454 }
455
456 void prefs_free(PrefParam *param)
457 {
458         gint i;
459
460         g_return_if_fail(param != NULL);
461
462         for (i = 0; param[i].name != NULL; i++) {
463                 if (!param[i].data) continue;
464
465                 switch (param[i].type) {
466                 case P_STRING:
467                 case P_PASSWORD:
468                         g_free(*((gchar **)param[i].data));
469                         break;
470                 default:
471                         break;
472                 }
473         }
474 }
475
476 void prefs_dialog_create(PrefsDialog *dialog)
477 {
478         GtkWidget *window;
479         GtkWidget *vbox;
480         GtkWidget *notebook;
481
482         GtkWidget *confirm_area;
483         GtkWidget *ok_btn;
484         GtkWidget *cancel_btn;
485         GtkWidget *apply_btn;
486
487         g_return_if_fail(dialog != NULL);
488
489         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
490         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
491         gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
492         gtk_window_set_modal (GTK_WINDOW (window), TRUE);
493         gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
494
495         vbox = gtk_vbox_new (FALSE, 6);
496         gtk_widget_show(vbox);
497         gtk_container_add (GTK_CONTAINER (window), vbox);
498
499         notebook = gtk_notebook_new ();
500         gtk_widget_show(notebook);
501         gtk_box_pack_start (GTK_BOX (vbox), notebook, TRUE, TRUE, 0);
502         gtk_container_set_border_width (GTK_CONTAINER (notebook), 2);
503         /* GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS); */
504         gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook), TRUE);
505         
506         gtk_notebook_popup_enable (GTK_NOTEBOOK (notebook));
507
508         gtkut_stock_button_set_create(&confirm_area,
509                                       &ok_btn, GTK_STOCK_OK,
510                                       &cancel_btn, GTK_STOCK_CANCEL,
511                                       &apply_btn, GTK_STOCK_APPLY);
512         gtk_widget_show(confirm_area);
513         gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
514         gtk_widget_grab_default(ok_btn);
515
516         dialog->window     = window;
517         dialog->notebook   = notebook;
518         dialog->ok_btn     = ok_btn;
519         dialog->cancel_btn = cancel_btn;
520         dialog->apply_btn  = apply_btn;
521 }
522
523 void prefs_dialog_destroy(PrefsDialog *dialog)
524 {
525         gtk_widget_destroy(dialog->window);
526         dialog->window     = NULL;
527         dialog->notebook   = NULL;
528         dialog->ok_btn     = NULL;
529         dialog->cancel_btn = NULL;
530         dialog->apply_btn  = NULL;
531 }
532
533 void prefs_button_toggled(GtkToggleButton *toggle_btn, GtkWidget *widget)
534 {
535         gboolean is_active;
536
537         is_active = gtk_toggle_button_get_active(toggle_btn);
538         gtk_widget_set_sensitive(widget, is_active);
539 }
540
541 void prefs_button_toggled_reverse(GtkToggleButton *toggle_btn, GtkWidget *widget)
542 {
543         gboolean is_active;
544
545         is_active = gtk_toggle_button_get_active(toggle_btn);
546         gtk_widget_set_sensitive(widget, !is_active);
547 }
548
549 void prefs_set_dialog(PrefParam *param)
550 {
551         gint i;
552
553         for (i = 0; param[i].name != NULL; i++) {
554                 if (param[i].widget_set_func)
555                         param[i].widget_set_func(&param[i]);
556         }
557 }
558
559 void prefs_set_data_from_dialog(PrefParam *param)
560 {
561         gint i;
562
563         for (i = 0; param[i].name != NULL; i++) {
564                 if (param[i].data_set_func)
565                         param[i].data_set_func(&param[i]);
566         }
567 }
568
569 void prefs_set_dialog_to_default(PrefParam *param)
570 {
571         gint       i;
572         PrefParam  tmpparam;
573         gchar     *str_data = NULL;
574         gint       int_data;
575         gushort    ushort_data;
576         gboolean   bool_data;
577         DummyEnum  enum_data;
578
579         for (i = 0; param[i].name != NULL; i++) {
580                 if (!param[i].widget_set_func) continue;
581
582                 tmpparam = param[i];
583
584                 switch (tmpparam.type) {
585                 case P_STRING:
586                 case P_PASSWORD:
587                         if (tmpparam.defval) {
588                                 if (!g_ascii_strncasecmp(tmpparam.defval, "ENV_", 4)) {
589                                         str_data = g_strdup(g_getenv(param[i].defval + 4));
590                                         tmpparam.data = &str_data;
591                                         break;
592                                 } else if (tmpparam.defval[0] == '~') {
593                                         str_data =
594                                                 g_strconcat(get_home_dir(),
595                                                             param[i].defval + 1,
596                                                             NULL);
597                                         tmpparam.data = &str_data;
598                                         break;
599                                 }
600                         }
601                         tmpparam.data = &tmpparam.defval;
602                         break;
603                 case P_INT:
604                         if (tmpparam.defval)
605                                 int_data = atoi(tmpparam.defval);
606                         else
607                                 int_data = 0;
608                         tmpparam.data = &int_data;
609                         break;
610                 case P_USHORT:
611                         if (tmpparam.defval)
612                                 ushort_data = atoi(tmpparam.defval);
613                         else
614                                 ushort_data = 0;
615                         tmpparam.data = &ushort_data;
616                         break;
617                 case P_BOOL:
618                         if (tmpparam.defval) {
619                                 if (!g_ascii_strcasecmp(tmpparam.defval, "TRUE"))
620                                         bool_data = TRUE;
621                                 else
622                                         bool_data = atoi(tmpparam.defval)
623                                                 ? TRUE : FALSE;
624                         } else
625                                 bool_data = FALSE;
626                         tmpparam.data = &bool_data;
627                         break;
628                 case P_ENUM:
629                         if (tmpparam.defval)
630                                 enum_data = (DummyEnum)atoi(tmpparam.defval);
631                         else
632                                 enum_data = 0;
633                         tmpparam.data = &enum_data;
634                         break;
635                 case P_OTHER:
636                 default:
637                         break;
638                 }
639                 tmpparam.widget_set_func(&tmpparam);
640                 g_free(str_data);
641                 str_data = NULL;
642         }
643 }
644
645 void prefs_set_data_from_entry(PrefParam *pparam)
646 {
647         gchar **str;
648         const gchar *entry_str;
649
650         g_return_if_fail(*pparam->widget != NULL);
651
652         entry_str = gtk_entry_get_text(GTK_ENTRY(*pparam->widget));
653
654         switch (pparam->type) {
655         case P_STRING:
656         case P_PASSWORD:
657                 str = (gchar **)pparam->data;
658                 g_free(*str);
659                 *str = entry_str[0] ? g_strdup(entry_str) : NULL;
660                 break;
661         case P_USHORT:
662                 *((gushort *)pparam->data) = atoi(entry_str);
663                 break;
664         case P_INT:
665                 *((gint *)pparam->data) = atoi(entry_str);
666                 break;
667         default:
668                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
669                           pparam->type);
670         }
671 }
672
673 void prefs_set_entry(PrefParam *pparam)
674 {
675         gchar **str;
676
677         g_return_if_fail(*pparam->widget != NULL);
678
679         switch (pparam->type) {
680         case P_STRING:
681         case P_PASSWORD:
682                 str = (gchar **)pparam->data;
683                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
684                                    *str ? *str : "");
685                 break;
686         case P_INT:
687                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
688                                    itos(*((gint *)pparam->data)));
689                 break;
690         case P_USHORT:
691                 gtk_entry_set_text(GTK_ENTRY(*pparam->widget),
692                                    itos(*((gushort *)pparam->data)));
693                 break;
694         default:
695                 g_warning("Invalid PrefType for GtkEntry widget: %d\n",
696                           pparam->type);
697         }
698 }
699
700 void prefs_set_data_from_text(PrefParam *pparam)
701 {
702         gchar **str;
703         gchar *text = NULL, *tp = NULL;
704         gchar *tmp, *tmpp;
705
706         g_return_if_fail(*pparam->widget != NULL);
707
708         switch (pparam->type) {
709         case P_STRING:
710         case P_PASSWORD:
711                 str = (gchar **)pparam->data;
712                 g_free(*str);
713                 if (GTK_IS_EDITABLE(*pparam->widget)) {   /* need? */
714                         tp = text = gtk_editable_get_chars
715                                         (GTK_EDITABLE(*pparam->widget), 0, -1);
716                 } else if (GTK_IS_TEXT_VIEW(*pparam->widget)) {
717                         GtkTextView *textview = GTK_TEXT_VIEW(*pparam->widget);
718                         GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview);
719                         GtkTextIter start, end;
720                         gtk_text_buffer_get_start_iter(buffer, &start);
721                         gtk_text_buffer_get_iter_at_offset(buffer, &end, -1);
722                         tp = text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
723                 }
724
725                 g_return_if_fail (tp && text);
726
727                 if (text[0] == '\0') {
728                         *str = NULL;
729                         g_free(text);
730                         break;
731                 }
732
733                 Xalloca(tmpp = tmp, strlen(text) * 2 + 1,
734                         { *str = NULL; break; });
735                 while (*tp) {
736                         if (*tp == '\n') {
737                                 *tmpp++ = '\\';
738                                 *tmpp++ = 'n';
739                                 tp++;
740                         } else
741                                 *tmpp++ = *tp++;
742                 }
743                 *tmpp = '\0';
744                 *str = g_strdup(tmp);
745                 g_free(text);
746                 break;
747         default:
748                 g_warning("Invalid PrefType for GtkText widget: %d\n",
749                           pparam->type);
750         }
751 }
752
753 void prefs_set_text(PrefParam *pparam)
754 {
755         gchar *buf, *sp, *bufp;
756         gchar **str;
757         GtkTextView *text;
758         GtkTextBuffer *buffer;
759         GtkTextIter iter;
760
761         g_return_if_fail(*pparam->widget != NULL);
762
763         switch (pparam->type) {
764         case P_STRING:
765         case P_PASSWORD:
766                 str = (gchar **)pparam->data;
767                 if (*str) {
768                         bufp = buf = alloca(strlen(*str) + 1);
769                         if (!buf) buf = "";
770                         else {
771                                 sp = *str;
772                                 while (*sp) {
773                                         if (*sp == '\\' && *(sp + 1) == 'n') {
774                                                 *bufp++ = '\n';
775                                                 sp += 2;
776                                         } else
777                                                 *bufp++ = *sp++;
778                                 }
779                                 *bufp = '\0';
780                         }
781                 } else
782                         buf = "";
783
784                 text = GTK_TEXT_VIEW(*pparam->widget);
785                 buffer = gtk_text_view_get_buffer(text);
786                 gtk_text_buffer_set_text(buffer, "", -1);
787                 gtk_text_buffer_get_start_iter(buffer, &iter);
788                 gtk_text_buffer_insert(buffer, &iter, buf, -1);
789                 break;
790         default:
791                 g_warning("Invalid PrefType for GtkTextView widget: %d\n",
792                           pparam->type);
793         }
794 }
795
796 void prefs_set_data_from_toggle(PrefParam *pparam)
797 {
798         g_return_if_fail(pparam->type == P_BOOL);
799         g_return_if_fail(*pparam->widget != NULL);
800         
801         *((gboolean *)pparam->data) =
802                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(*pparam->widget));
803 }
804
805 void prefs_set_toggle(PrefParam *pparam)
806 {
807         g_return_if_fail(pparam->type == P_BOOL);
808         g_return_if_fail(*pparam->widget != NULL);
809
810         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(*pparam->widget),
811                                      *((gboolean *)pparam->data));
812 }
813
814 void prefs_set_data_from_spinbtn(PrefParam *pparam)
815 {
816         g_return_if_fail(*pparam->widget != NULL);
817
818         switch (pparam->type) {
819         case P_INT:
820                 *((gint *)pparam->data) =
821                         gtk_spin_button_get_value_as_int
822                         (GTK_SPIN_BUTTON(*pparam->widget));
823                 break;
824         case P_USHORT:
825                 *((gushort *)pparam->data) =
826                         (gushort)gtk_spin_button_get_value_as_int
827                         (GTK_SPIN_BUTTON(*pparam->widget));
828                 break;
829         default:
830                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
831                           pparam->type);
832         }
833 }
834
835 void prefs_set_spinbtn(PrefParam *pparam)
836 {
837         g_return_if_fail(*pparam->widget != NULL);
838
839         switch (pparam->type) {
840         case P_INT:
841                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
842                                           (gfloat)*((gint *)pparam->data));
843                 break;
844         case P_USHORT:
845                 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*pparam->widget),
846                                           (gfloat)*((gushort *)pparam->data));
847                 break;
848         default:
849                 g_warning("Invalid PrefType for GtkSpinButton widget: %d\n",
850                           pparam->type);
851         }
852 }
853
854 static GSList *prefs_pages = NULL;
855
856 void prefs_gtk_open(void)
857 {
858         prefswindow_open(_("Preferences"), prefs_pages, NULL,
859                         &prefs_common.prefswin_width, &prefs_common.prefswin_height);
860 }
861
862 void prefs_gtk_register_page(PrefsPage *page)
863 {
864         prefs_pages = g_slist_append(prefs_pages, page);
865 }
866
867 void prefs_gtk_unregister_page(PrefsPage *page)
868 {
869         prefs_pages = g_slist_remove(prefs_pages, page);
870 }