gui improvements, make on po dir too, updated strings and translation
[clawsker.git] / clawsker
1 #!/usr/bin/perl -w
2 #
3 # $Id$
4 #
5
6 =pod
7
8 =head1 NAME
9
10 Clawsker - A Claws Mail Tweaker
11
12 =head1 SYNOPSIS
13
14 clawsker [options]
15
16 =head1 DESCRIPTION
17
18 Clawsker is an applet to edit the so called Claws Mail hidden preferences.
19
20 Claws Mail is a fast, lightweight and feature-rich MUA with a high number 
21 of configurable options. To keep the binary small and fast some of these 
22 preferences which not widely used are not provided with a graphical interface 
23 for inspection and/or modification.
24
25 Users wanting to edit such preferences had to face raw edition of their 
26 configuration files, now you can do it with a convenient GTK2 interface
27 using Clawsker.
28
29 =head1 OPTIONS
30
31 No options are currently available.
32
33 =head1 LIMITATIONS
34
35 Alternate configuration directories are not (yet) supported.
36
37 =head1 AUTHOR
38
39 Ricardo Mones E<lt>ricardo@mones.orgE<gt>
40
41 =head1 LICENSE
42
43 Copyright (c) 2007 by Ricardo Mones
44
45 This program is free software: you can redistribute it and/or modify
46 it under the terms of the GNU General Public License as published by
47 the Free Software Foundation, either version 3 of the License, or
48 (at your option) any later version.
49
50 This program is distributed in the hope that it will be useful,
51 but WITHOUT ANY WARRANTY; without even the implied warranty of
52 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
53 GNU General Public License for more details.
54
55 You should have received a copy of the GNU General Public License
56 along with this program.  If not, see E<lt>http://www.gnu.org/licenses/E<gt>.
57
58 =cut
59
60 use strict;
61 use POSIX qw(setlocale);
62 use Locale::gettext;
63 use Glib qw(TRUE FALSE);
64 use Gtk2 -init;
65
66 my $NAME = 'clawsker';
67 my $PREFIX = '@PREFIX@';
68 my $LIBDIR = '@LIBDIR@';
69 my $VERSION = '@VERSION@';
70
71 my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
72 setlocale(LC_ALL, $locale);
73 bindtextdomain(lc($NAME), sprintf('%s/share/locale', $PREFIX));
74 textdomain(lc($NAME));
75
76 sub _ {
77     my $str = shift;
78     my %par = @_;
79     my $xla = gettext($str);
80     if (scalar(keys(%par)) > 0) {
81         foreach my $key (keys %par) {
82             $xla =~ s/\{$key\}/$par{$key}/g;
83         }
84     }
85     return $xla;
86 }
87
88 # default messages
89 %xl::s = (
90     win_title => _('Claws Mail Hidden Preferences'),
91     about => _('About...'),
92     about_title => _('Clawsker ~ A Claws Mail Tweaker'),
93     about_license => _('License:'),
94     about_version => _('Version:'),
95
96     tab_colours => _('Colours'),
97     tab_behaviour => _('Behaviour'),
98     tab_gui => _('GUI'),
99     tab_other => _('Other'),
100
101     ab_frame => _('Addressbook'),
102     mem_frame => _('Memory'),
103     msgview_frame => _('Message view'),
104     log_frame => _('Log window'),
105     dnd_frame => _('Drag and drop'),
106     ssl_frame => _('Secure Sockets Layer'),
107     msgs_frame => _('Messages'),
108     stripes_frame => _('Stripes'),
109     sbar_frame => _('Scroll bars'),
110
111     l_oth_use_dlg => _('Use address book dialog'),
112     h_oth_use_dlg => _('If true use a separate dialogue to edit a person\'s details. Otherwise will use a form embedded in the addressbook\'s main window.'),
113     l_oth_max_use => _('Maximum memory for message cache (Kb)'),
114     h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kB.'),
115     l_oth_min_time => _('Minimun time for cache elements (minutes)'),
116     h_oth_min_time => _('The minimum time in minutes to keep a cache in memory. Caches more recent than this time will not be freed, even if the memory usage is too high.'),
117     
118     l_gui_b_unread => _('Show unread messages with bold font'),
119     h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
120     l_gui_no_markup => _('Don\'t use markup in compose window'),
121     h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
122     l_gui_dot_lines => _('Use dotted lines in tree views'),
123     h_gui_dot_lines => _('Use the old dotted line look in the main window tree views (folder and message lists) instead of the modern lineless look.'),
124     l_gui_h_scroll => _('Enable horizontal scrollbar'),
125     h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
126     l_gui_swp_from => _('Swap From field in Sent folder'),
127     h_gui_swp_from => _('Display the sender\'s email address in the To column of the Sent folder instead of the recipient\'s.'),
128     l_gui_v_scroll => _('Folder list scrollbar behaviour'),
129     h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
130     l_gui_v_scroll_show => _('Show always'),
131     l_gui_v_scroll_auto => _('Automatic'),
132     l_gui_v_scroll_hide => _('Hide always'),
133     l_gui_strip_off => _('Striped lines contrast'),
134     h_gui_strip_off => _('Specify the value to use when creating alternately coloured lines in tree view components. The smaller the value, the less visible the difference in the alternating colours of the lines.'),
135     l_gui_cursor_v => _('Cursor visible in message view'),
136     h_gui_cursor_v => _('Display the cursor in the message view.'),
137     l_gui_toolbar_d => _('Detachable toolbars'),
138     h_gui_toolbar_d => _('Show handles in the toolbars.'),
139     l_gui_strip_all => _('Use stripes in tree view components'),
140     h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
141     l_gui_strip_sum => _('Use stripes in summary view'),
142     h_gui_strip_sum => _('Enable alternately coloured lines in summary view and folder list'),
143
144     l_beh_hover_t => _('Drag and drop hover timeout (ms)'),
145     h_beh_hover_t => _('Time in milliseconds that will cause a folder tree to expand when the mouse cursor is held over it during drag and drop.'),
146     l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
147     h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
148     l_beh_flowed => _('Respect flowed format in messages'),
149     h_beh_flowed => _('Respect format=flowed on text/plain message parts. This will cause some mails to have long lines, but will fix some URLs that would otherwise be wrapped.'),
150     l_beh_parts_rw => _('Allow writable temporary files'),
151     h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
152     l_beh_skip_ssl => _('Don\'t check SSL certificates'),
153     h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
154     l_beh_up_step => _('Progress update step (items)'),
155     h_beh_up_step => _('Update stepping in progress bars.'),
156     l_beh_thread_a => _('Maximum age in threading by subject (days)'),
157     h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
158     l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
159     h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
160     l_beh_use_utf8 => _('Use UTF-8 in broken mails'),
161     h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
162     l_beh_warn_dnd => _('Warning on drag and drop'),
163     h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
164
165     l_col_emphasis => _('Emphasised X-Mailer colour'),
166     h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
167     l_col_log_err => _('Errors colour'),
168     h_col_log_err => _('Colour for error messages in log window.'),
169     l_col_log_in => _('Input colour'),
170     h_col_log_in => _('Colour for input messages in log window.'),
171     l_col_log_msg => _('Messages colour'),
172     h_col_log_msg => _('Colour for messages in log window.'),
173     l_col_log_out => _('Output colour'),
174     h_col_log_out => _('Colour for output messages in log window.'),
175     l_col_log_warn => _('Warnings colour'),
176     h_col_log_warn => _('Colour for warning messages in log window.'),
177
178     e_error => _('Error: '),
179     e_noclawsrc => _('no $HOME/.claws-mail/clawsrc file found.'),
180     e_running => _('seems Claws Mail is currently running, close it first.'),
181 );
182
183 # check if claws is running
184 my $socket = "/tmp/claws-mail-$<";
185 -S $socket and die "$xl::s{e_error}$xl::s{e_running}\n";
186
187 # all preferences read by load_preferences
188 my %PREFS = ();
189 # values of all preferences handled by clawsker
190 my %HPVALUE = ();
191
192 # index constants for preference arrays
193 use constant NAME  => 0; # the name on the rc file
194 use constant LABEL => 1; # the label on the GUI
195 use constant DESC  => 2; # the description for the hint/help
196 use constant TYPE  => 3; # data type: bool, int, float, string, color
197 use constant GUI   => 4; # GUI element
198
199 # constants for GUI spacing
200 use constant HBOX_SPC => 5;
201 use constant FRAME_SPC => 2;
202
203 # data handlers and auxiliar functions
204
205 sub handle_bool_value {
206     my ($widget, $event, $dataref) = @_;
207     $$dataref = ($widget->get_active ())? '1': '0';
208 }
209
210 sub handle_int_value {
211     my ($widget, $event, $dataref) = @_;
212     $_ = $widget->get_text ();
213     s/^\s+//;
214     s/\s+$//;
215     if (/^[0-9]+$/) {
216         $$dataref = $_;
217         $widget->set_text ($_);
218     }
219     else {
220         $widget->set_text ($$dataref);
221     }
222 }
223
224 sub handle_string_value {
225     my ($widget, $event, $dataref) = @_;
226     $$dataref = $widget->get_text ();
227 }
228
229 sub gdk_color_from_str {
230     my ($str) = @_;
231     my ($rr, $gg, $bb) = (0, 0 ,0);
232     $_ = uc ($str);
233     if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
234         $rr = hex($1) * 256;
235         $gg = hex($2) * 256; 
236         $bb = hex($3) * 256;
237     }
238     my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
239     return $color;
240 }
241
242 sub str_from_gdk_color {
243     my ($color) = @_;
244     my $rr = $color->red / 256;
245     my $gg = $color->green / 256;
246     my $bb = $color->blue / 256;
247     my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
248     return $str;
249 }
250
251 sub handle_color_value {
252     my ($widget, $event, $dataref) = @_;
253     my $newcol = $widget->get_color;
254     $$dataref = &str_from_gdk_color ($newcol);
255 }
256
257 sub handle_selection_value {
258     my ($widget, $event, $dataref) = @_;
259     $$dataref = $widget->get_active;
260 }
261
262 # graphic element creation 
263
264 sub new_check_button_for {
265     my ($hash, $key) = @_;
266     my $name = $$hash{$key}[NAME];
267     my $label = $$hash{$key}[LABEL];
268     #
269     my $hbox = Gtk2::HBox->new (FALSE, 5);
270     my $cb = Gtk2::CheckButton->new ($label);
271     $$hash{$key}[GUI] = $cb;
272     $cb->set_active ($HPVALUE{$name} eq '1');
273     $cb->signal_connect (clicked => sub {
274             my ($w, $e) = @_;
275             &handle_bool_value($w, $e, \$HPVALUE{$name});
276         });
277     $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
278     #
279     return $hbox;
280 }
281
282 sub new_text_box_for {
283     my ($hash, $key) = @_;
284     my $name = $$hash{$key}[NAME];
285     my $label = $$hash{$key}[LABEL];
286     #
287     my $hbox = Gtk2::HBox->new (FALSE, 5);
288     my $glabel = Gtk2::Label->new ($label);
289     my $gentry = Gtk2::Entry->new;
290     $$hash{$key}[GUI] = $gentry;
291     $gentry->set_text($HPVALUE{$name});
292     $gentry->signal_connect(changed => sub {
293             my ($w, $e) = @_;
294             &handle_int_value($w, $e, \$HPVALUE{$name}); # FIXME int only
295         });
296     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
297     $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
298     #
299     return $hbox;
300 }
301
302 sub new_color_button_for {
303     my ($hash, $key) = @_;
304     my $name = $$hash{$key}[NAME];
305     my $label = $$hash{$key}[LABEL];
306     #
307     my $col = &gdk_color_from_str ($HPVALUE{$name});
308     my $hbox = Gtk2::HBox->new (FALSE, 5);
309     my $glabel = Gtk2::Label->new ($label);
310     my $button = Gtk2::ColorButton->new_with_color ($col);
311     $$hash{$key}[GUI] = $button;
312     $button->set_title ($label);
313     $button->signal_connect ('color-set' => sub {
314             my ($w, $e) = @_;
315             &handle_color_value($w, $e, \$HPVALUE{$name}); 
316         });
317     $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
318     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
319     #
320     return $hbox;
321 }
322
323 sub new_selection_box_for {
324     my ($hash, $key) = @_;
325     my $name = $$hash{$key}[NAME];
326     my $label = $$hash{$key}[LABEL];
327     #
328     my $hbox = Gtk2::HBox->new (FALSE, 5);
329     my $glabel = Gtk2::Label->new ($label);
330     my $combo = Gtk2::ComboBox->new_text;
331     $$hash{$key}[GUI] = $combo;
332     my @options = split (';', $$hash{$key}[TYPE]);
333     foreach my $opt (@options) {
334         my ($index, $textkey) = split ('=', $opt);
335         $combo->insert_text ($index, $xl::s{$textkey});
336     }
337     $combo->signal_connect ('changed' => sub {
338             my ($w, $e) = @_;
339             &handle_selection_value($w, $e, \$HPVALUE{$name});
340         });
341     $combo->set_active ($HPVALUE{$name});
342     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
343     $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
344     #
345     return $hbox;
346 }
347
348 # preference maps and corresponding page creation subs
349
350 %pr::oth = ( # other preferences
351     use_dlg => [ 
352         'addressbook_use_editaddress_dialog',
353         $xl::s{l_oth_use_dlg},
354         $xl::s{h_oth_use_dlg},
355         'bool',
356         undef,
357     ],
358     max_use => [
359         'cache_max_mem_usage',
360         $xl::s{l_oth_max_use},
361         $xl::s{h_oth_max_use},
362         'int',
363         undef,
364     ],
365     min_time => [
366         'cache_min_keep_time',
367         $xl::s{l_oth_min_time},
368         $xl::s{h_oth_min_time},
369         'int',
370         undef,
371     ],
372 );
373
374 sub new_other_page() {
375     my $of = Gtk2::VBox->new (FALSE, 5);
376
377     my $ab_frame = Gtk2::Frame->new ($xl::s{ab_frame}); 
378     my $cb_use_dlg = &new_check_button_for(\%pr::oth, 'use_dlg');
379     my $vb1 = Gtk2::VBox->new (FALSE, 5);
380     $vb1->pack_start ($cb_use_dlg, FALSE, FALSE, 0);
381     $ab_frame->add ($vb1);
382
383     my $mem_frame = Gtk2::Frame->new ($xl::s{mem_frame}); 
384     my $tb_max_use = &new_text_box_for(\%pr::oth, 'max_use');
385     my $tb_min_time = &new_text_box_for(\%pr::oth, 'min_time');
386     my $vb2 = Gtk2::VBox->new (FALSE, 5);
387     $vb2->pack_start ($tb_max_use, FALSE, FALSE, 0);
388     $vb2->pack_start ($tb_min_time, FALSE, FALSE, 0);
389     $mem_frame->add ($vb2);
390
391     $of->pack_start ($ab_frame, FALSE, FALSE, FRAME_SPC);
392     $of->pack_start ($mem_frame, FALSE, FALSE, FRAME_SPC);
393
394     return $of;
395 }
396
397 %pr::gui = ( # gui bells and whistles
398     b_unread => [ 
399         'bold_unread',
400         $xl::s{l_gui_b_unread},
401         $xl::s{h_gui_b_unread},
402         'bool',
403         undef,
404     ],
405     no_markup => [
406         'compose_no_markup',
407         $xl::s{l_gui_no_markup},
408         $xl::s{h_gui_no_markup},
409         'bool',
410         undef,
411     ],
412     dot_lines => [
413         'enable_dotted_lines',
414         $xl::s{l_gui_dot_lines},
415         $xl::s{h_gui_dot_lines},
416         'bool',
417         undef,
418     ],
419     h_scroll => [
420         'enable_hscrollbar',
421         $xl::s{l_gui_h_scroll},
422         $xl::s{h_gui_h_scroll},
423         'bool',
424         undef,
425     ],
426     swp_from => [
427         'enable_swap_from',
428         $xl::s{l_gui_swp_from},
429         $xl::s{h_gui_swp_from},
430         'bool',
431         undef,
432     ],
433     v_scroll => [
434         'folderview_vscrollbar_policy',
435         $xl::s{l_gui_v_scroll},
436         $xl::s{h_gui_v_scroll},
437         '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
438         undef,
439     ],
440     strip_off => [
441         'stripes_color_offset',
442         $xl::s{l_gui_strip_off},
443         $xl::s{h_gui_strip_off},
444         'int',
445         undef,
446     ],
447     cursor_v => [
448         'textview_cursor_visible',
449         $xl::s{l_gui_cursor_v},
450         $xl::s{h_gui_cursor_v},
451         'bool',
452         undef,
453     ],
454     toolbar_d => [
455         'toolbar_detachable',
456         $xl::s{l_gui_toolbar_d},
457         $xl::s{h_gui_toolbar_d},
458         'bool',
459         undef,
460     ],
461     strip_all => [
462         'use_stripes_everywhere',
463         $xl::s{l_gui_strip_all},
464         $xl::s{h_gui_strip_all},
465         'bool',
466         undef,
467     ],
468     strip_sum => [
469         'use_stripes_in_summaries',
470         $xl::s{l_gui_strip_sum},
471         $xl::s{h_gui_strip_sum},
472         'bool',
473         undef,
474     ],
475 );
476
477 sub new_gui_page() {
478     my $gf = Gtk2::VBox->new (FALSE, 5);
479
480     my $stripes_frame = Gtk2::Frame->new ($xl::s{stripes_frame});
481     my $cb_strip_all = &new_check_button_for (\%pr::gui, 'strip_all');
482     my $cb_strip_sum = &new_check_button_for (\%pr::gui, 'strip_sum');
483     my $tb_strip_off = &new_text_box_for (\%pr::gui, 'strip_off');
484     my $vb1 = Gtk2::VBox->new (FALSE, 5);
485     $vb1->pack_start ($cb_strip_all, FALSE, FALSE, 0);
486     $vb1->pack_start ($cb_strip_sum, FALSE, FALSE, 0);
487     $vb1->pack_start ($tb_strip_off, FALSE, FALSE, 0);
488     $stripes_frame->add ($vb1);
489
490     my $sbar_frame = Gtk2::Frame->new ($xl::s{sbar_frame});
491     my $cb_h_scroll = &new_check_button_for (\%pr::gui, 'h_scroll');
492     my $sb_v_scroll = &new_selection_box_for (\%pr::gui, 'v_scroll');
493     my $vb2 = Gtk2::VBox->new (FALSE, 5);
494     $vb2->pack_start ($cb_h_scroll, FALSE, FALSE, 0);
495     $vb2->pack_start ($sb_v_scroll, FALSE, FALSE, 0);
496     $sbar_frame->add ($vb2);
497
498     my $cb_b_unread = &new_check_button_for (\%pr::gui, 'b_unread');
499     my $cb_no_markup = &new_check_button_for (\%pr::gui, 'no_markup'); 
500     my $cb_dot_lines = &new_check_button_for (\%pr::gui, 'dot_lines'); 
501     my $cb_swp_from = &new_check_button_for (\%pr::gui, 'swp_from');
502     my $cb_cursor_v = &new_check_button_for (\%pr::gui, 'cursor_v');
503     my $cb_toolbar_d = &new_check_button_for (\%pr::gui, 'toolbar_d');
504
505     $gf->pack_start ($stripes_frame, FALSE, FALSE, FRAME_SPC);
506     $gf->pack_start ($cb_b_unread, FALSE, FALSE, 0);
507     $gf->pack_start ($cb_no_markup, FALSE, FALSE, 0);
508     $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
509     $gf->pack_start ($cb_swp_from, FALSE, FALSE, 0);
510     $gf->pack_start ($cb_cursor_v, FALSE, FALSE, 0);
511     $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
512     $gf->pack_start ($sbar_frame, FALSE, FALSE, FRAME_SPC);
513
514     return $gf;
515 }
516
517 %pr::beh = ( # tweak some behaviour
518     hover_t => [
519         'hover_timeout',
520         $xl::s{l_beh_hover_t},
521         $xl::s{h_beh_hover_t},
522         'int',
523         undef,
524     ],
525     dangerous => [
526         'live_dangerously',
527         $xl::s{l_beh_dangerous},
528         $xl::s{h_beh_dangerous},
529         'bool',
530         undef,
531     ],
532     flowed => [
533         'respect_flowed_format',
534         $xl::s{l_beh_flowed},
535         $xl::s{h_beh_flowed},
536         'bool',
537         undef,
538     ],
539     parts_rw => [
540         'save_parts_readwrite',
541         $xl::s{l_beh_parts_rw},
542         $xl::s{h_beh_parts_rw},
543         'bool',
544         undef,
545     ],
546     skip_ssl => [
547         'skip_ssl_cert_check',
548         $xl::s{l_beh_skip_ssl},
549         $xl::s{h_beh_skip_ssl},
550         'bool',
551         undef,
552     ],
553     up_step => [
554         'statusbar_update_step',
555         $xl::s{l_beh_up_step},
556         $xl::s{h_beh_up_step},
557         'int',
558         undef,
559     ],
560     thread_a => [
561         'thread_by_subject_max_age',
562         $xl::s{l_beh_thread_a},
563         $xl::s{h_beh_thread_a},
564         'int',
565         undef,
566     ],
567     unsafe_ssl => [
568         'unsafe_ssl_certs',
569         $xl::s{l_beh_unsafe_ssl},
570         $xl::s{h_beh_unsafe_ssl},
571         'bool',
572         undef,
573     ],
574     use_utf8 => [
575         'utf8_instead_of_locale_for_broken_mail',
576         $xl::s{l_beh_use_utf8},
577         $xl::s{h_beh_use_utf8},
578         'bool',
579         undef,
580     ],
581     warn_dnd => [
582         'warn_dnd',
583         $xl::s{l_beh_warn_dnd},
584         $xl::s{h_beh_warn_dnd},
585         'bool',
586         undef,
587     ],
588 );
589
590 sub new_behaviour_page() {
591     my $bf = Gtk2::VBox->new (FALSE, 5);
592
593     my $dnd_frame = Gtk2::Frame->new ($xl::s{dnd_frame});
594     my $tb_hoover_t = &new_text_box_for (\%pr::beh, 'hover_t');
595     my $cb_warn_dnd = &new_check_button_for (\%pr::beh, 'warn_dnd');
596     my $vb1 = Gtk2::VBox->new (FALSE, 5);
597     $vb1->pack_start ($cb_warn_dnd, FALSE, FALSE, 0);
598     $vb1->pack_start ($tb_hoover_t, FALSE, FALSE, 0);
599     $dnd_frame->add ($vb1);
600
601     my $ssl_frame = Gtk2::Frame->new ($xl::s{ssl_frame});
602     my $cb_skip_ssl = &new_check_button_for (\%pr::beh, 'skip_ssl');
603     my $cb_unsafe_ssl = &new_check_button_for (\%pr::beh, 'unsafe_ssl');
604     my $hb1 = Gtk2::HBox->new (FALSE, 5);
605     $hb1->pack_start ($cb_skip_ssl, FALSE, FALSE, 0);
606     $hb1->pack_start ($cb_unsafe_ssl, FALSE, FALSE, 0);
607     $ssl_frame->add ($hb1);
608
609     my $tb_up_step = &new_text_box_for (\%pr::beh, 'up_step');
610     my $tb_thread_a = &new_text_box_for (\%pr::beh, 'thread_a');
611
612     my $msgs_frame = Gtk2::Frame->new ($xl::s{msgs_frame});
613     my $cb_flowed = &new_check_button_for (\%pr::beh, 'flowed');
614     my $cb_parts_rw = &new_check_button_for (\%pr::beh, 'parts_rw');
615     my $cb_use_utf8 = &new_check_button_for (\%pr::beh, 'use_utf8');
616     my $cb_dangerous = &new_check_button_for (\%pr::beh, 'dangerous');
617     my $vb2 = Gtk2::VBox->new (FALSE, 5);    
618     $vb2->pack_start ($cb_flowed, FALSE, FALSE, 0);
619     $vb2->pack_start ($cb_parts_rw, FALSE, FALSE, 0);
620     $vb2->pack_start ($cb_use_utf8, FALSE, FALSE, 0);
621     $vb2->pack_start ($cb_dangerous, FALSE, FALSE, 0);
622     $msgs_frame->add ($vb2);
623
624     $bf->pack_start ($dnd_frame, FALSE, FALSE, FRAME_SPC);
625     $bf->pack_start ($ssl_frame, FALSE, FALSE, FRAME_SPC);
626     $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
627     $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
628     $bf->pack_start ($msgs_frame, FALSE, FALSE, FRAME_SPC);
629
630     return $bf;
631 }
632
633 %pr::col = ( # a variety of colours
634     emphasis => [
635         'emphasis_color',
636         $xl::s{l_col_emphasis},
637         $xl::s{h_col_emphasis},
638         'color',
639         undef,
640     ],
641     log_err => [
642         'log_error_color',
643         $xl::s{l_col_log_err},
644         $xl::s{h_col_log_err},
645         'color',
646         undef,
647     ],
648     log_in => [
649         'log_in_color',
650         $xl::s{l_col_log_in},
651         $xl::s{h_col_log_in},
652         'color',
653         undef,
654     ],
655     log_msg => [
656         'log_msg_color',
657         $xl::s{l_col_log_msg},
658         $xl::s{h_col_log_msg},
659         'color',
660         undef,
661     ],
662     log_out => [
663         'log_out_color',
664         $xl::s{l_col_log_out},
665         $xl::s{h_col_log_out},
666         'color',
667         undef,
668     ],
669     log_warn => [
670         'log_warn_color',
671         $xl::s{l_col_log_warn},
672         $xl::s{h_col_log_warn},
673         'color',
674         undef,
675     ],
676 );
677
678 sub new_colours_page() {
679     my $cf = Gtk2::VBox->new (FALSE, 5);
680
681     my $msgview_frame = Gtk2::Frame->new ($xl::s{msgview_frame}); 
682     my $cb_emphasis = &new_color_button_for (\%pr::col, 'emphasis');
683     my $vb1 = Gtk2::VBox->new (FALSE, 5);
684     $vb1->pack_start ($cb_emphasis, FALSE, FALSE, 0);
685     $msgview_frame->add ($vb1);
686     
687     my $log_frame = Gtk2::Frame->new ($xl::s{log_frame}); 
688     my $cb_log_err = &new_color_button_for (\%pr::col, 'log_err');
689     my $cb_log_in = &new_color_button_for (\%pr::col, 'log_in');
690     my $cb_log_msg = &new_color_button_for (\%pr::col, 'log_msg');
691     my $cb_log_out = &new_color_button_for (\%pr::col, 'log_out');
692     my $cb_log_warn = &new_color_button_for (\%pr::col, 'log_warn');
693     my $vb2 = Gtk2::VBox->new (FALSE, 5);
694     $vb2->pack_start ($cb_log_err, FALSE, FALSE, 0);
695     $vb2->pack_start ($cb_log_in, FALSE, FALSE, 0);
696     $vb2->pack_start ($cb_log_msg, FALSE, FALSE, 0);
697     $vb2->pack_start ($cb_log_out, FALSE, FALSE, 0);
698     $vb2->pack_start ($cb_log_warn, FALSE, FALSE, 0);
699     $log_frame->add ($vb2);
700
701     $cf->pack_start ($msgview_frame, FALSE, FALSE, 0);
702     $cf->pack_start ($log_frame, FALSE, FALSE, 0);
703     return $cf;
704 }
705
706 # update the hidden preferences status from loaded values
707 sub init_hidden_preferences() {
708     foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth) {
709         foreach my $key (keys %$hash) { 
710             $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
711         }
712     }
713 }
714
715 # load current status from disc
716 sub load_preferences() {
717     my $rc = $ENV{HOME} . '/.claws-mail/clawsrc';
718     -f $rc or die "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
719     open (RCF, "<$rc");
720     while (<RCF>) {
721         chomp;
722         if (/^([8a-z_]+)=(.*)$/) {
723             $PREFS{$1} = "$2";
724         }
725     }
726     close (RCF);
727 }
728
729 # save current preferences to disc
730 sub save_preferences() {
731     my $rc = $ENV{HOME} . '/.claws-mail/clawsrc';
732     my $rcbak = "$rc.backup";
733     rename ($rc, $rcbak);
734     open (RCF, ">$rc");
735     open (RCB, "<$rcbak");
736     while (<RCB>) {
737         chomp;
738         if (/^([8a-z_]+)=(.*)$/) {
739             if (defined($HPVALUE{$1})) {
740                 print RCF $1 . "=" . $HPVALUE{$1} . "\n";
741             }
742             else {
743                 print RCF $_ . "\n";
744             }
745         }
746         else {
747             print RCF $_ . "\n";
748         }
749     }
750     close (RCB);
751     close (RCF);
752 }
753
754 # create notebook
755 sub new_notebook() {
756     my $nb = Gtk2::Notebook->new;
757     # 
758     $nb->append_page (&new_behaviour_page, $xl::s{tab_behaviour});
759     $nb->append_page (&new_colours_page, $xl::s{tab_colours});
760     $nb->append_page (&new_gui_page, $xl::s{tab_gui});
761     $nb->append_page (&new_other_page, $xl::s{tab_other});
762
763     return $nb;
764 }
765
766 # create an about dialog
767 sub new_about_dialog() {
768     my ($parent) = @_;
769     my $title = $xl::s{about_title};
770     my $lic = $xl::s{about_license};
771     my $vers = $xl::s{about_version} . " $VERSION";
772     my $license = 
773 "This program is free software: you can redistribute it and/or modify
774 it under the terms of the GNU General Public License as published by
775 the Free Software Foundation, either version 3 of the License, or
776 (at your option) any later version.
777
778 This program is distributed in the hope that it will be useful,
779 but WITHOUT ANY WARRANTY; without even the implied warranty of
780 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
781 GNU General Public License for more details.
782
783 You should have received a copy of the GNU General Public License
784 along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
785     my $year = "2007";
786     my $holder = "Ricardo Mones &lt;ricardo\@mones.org&gt;";
787
788     my $dialog = Gtk2::MessageDialog->new_with_markup ($parent, 
789                     [qw/modal destroy-with-parent/], 
790                     'info', 'close', 
791                     "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
792                     . "<span size=\"large\">$vers</span>\n"
793                     . "<span>Copyright $year by $holder</span>\n\n"
794                     . "<span size=\"large\">$lic</span>\n\n"
795                     . "<span size=\"small\">$license</span>");
796     $dialog->set_title ($xl::s{about});
797     #
798     return $dialog;
799 }
800
801 # create buttons box
802 sub new_button_box() {
803     my ($adlg) = @_;
804     my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
805     my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
806     my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
807     # disable button until is really implemented
808     # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
809     my $hbox = Gtk2::HBox->new (FALSE, 5);
810     # signal handlers 
811     $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
812     $b_apply->signal_connect (clicked => sub { &save_preferences });
813     # $b_undo->signal_connect (clicked => sub { &undo_current_changes });
814     $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
815     # package them
816     $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
817     $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
818     # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
819     $hbox->pack_start ($b_about, FALSE, FALSE, 0);
820     #
821     return $hbox;
822 }
823
824 # initialise values
825 &load_preferences;
826 &init_hidden_preferences;
827 # create main GUI
828 my $window = Gtk2::Window->new ('toplevel');
829 my $box = Gtk2::VBox->new (FALSE, 5);
830 my $about = &new_about_dialog;
831 $box->pack_start (&new_notebook, FALSE, FALSE, 0);
832 $box->pack_end (&new_button_box ($about), FALSE, FALSE, 0);
833
834 $window->set_title ($xl::s{win_title});
835 $window->add ($box);
836 $window->show_all;
837 Gtk2->main;
838