Fix #13 - support “master_passphrase_pbkdf2_rounds”
[clawsker.git] / clawsker
1 #!/usr/bin/perl -w
2 #
3 # Clawsker :: A Claws Mail Tweaker
4 # Copyright 2007-2015 Ricardo Mones <ricardo@mones.org>
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # See COPYING file for license details.
12 # See AUTHORS file for a complete list of contributors.
13 #
14
15 binmode STDOUT, ":encoding(utf8)";
16
17 use strict;
18 use utf8;
19 use Glib qw(TRUE FALSE);
20 use Gtk2;
21 use POSIX qw(setlocale);
22 use Locale::gettext;
23 use Encode;
24 use Digest::MD5 qw(md5_hex);
25 use Getopt::Long;
26
27 my $NAME = 'clawsker';
28 my $PREFIX = '@PREFIX@';
29 my $LIBDIR = '@LIBDIR@';
30 my $VERSION = '@VERSION@';
31 my $VERBOSE = FALSE;
32 my $CLAWSV = undef;
33 my $main_window = undef;
34
35 my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
36 $locale = "C" unless defined($locale);
37 setlocale (LC_ALL, $locale);
38 bindtextdomain ($NAME, sprintf ('%s/share/locale', $PREFIX));
39 textdomain ($NAME);
40
41 my $SHOWHINTS = FALSE;
42 $SHOWHINTS = TRUE if ($Gtk2::VERSION >= 1.040 and Gtk2->CHECK_VERSION (2, 12, 0));
43
44 sub _ {
45     my $str = shift;
46     my %par = @_;
47     my $xla = gettext ($str);
48     if (scalar(keys(%par)) > 0) {
49         foreach my $key (keys %par) {
50             $xla =~ s/\{$key\}/$par{$key}/g;
51         }
52     }
53     return decode_utf8($xla);
54 }
55
56 # default messages
57 %xl::s = (
58     win_title => _('Claws Mail Hidden Preferences'),
59     about => _('About...'),
60     about_title => _('Clawsker :: A Claws Mail Tweaker'),
61     about_license => _('License:'),
62     about_version => _('Version:'),
63
64     tab_colours => _('Colours'),
65     tab_behaviour => _('Behaviour'),
66     tab_gui => _('GUI'),
67     tab_other => _('Other'),
68     tab_winpos => _('Windows'),
69
70     ab_frame => _('Addressbook'),
71     mem_frame => _('Memory'),
72     msgview_frame => _('Message View'),
73     log_frame => _('Log window'),
74     dnd_frame => _('Drag \'n\' drop'),
75     ssl_frame => _('Secure Sockets Layer'),
76     msgs_frame => _('Messages'),
77     swc_frame => _('Completion'),
78     stripes_frame => _('Coloured stripes'),
79     sbar_frame => _('Scroll bars'),
80     mlist_frame => _('Message List'),
81     mview_frame => _('Message View'),
82     compo_frame => _('Compose window'),
83     netm_frame => _('NetworkManager'),
84     diff_frame => _('Viewing patches'),
85     mpass_frame => _('Master passphrase'),
86
87     l_oth_use_dlg => _('Use detached address book edit dialogue'),
88     h_oth_use_dlg => _('If true use a separate dialogue to edit a person\'s details. Otherwise will use a form embedded in the address book\'s main window.'),
89     l_oth_max_use => _('Maximum memory for message cache (kB)'),
90     h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kilobytes.'),
91     l_oth_min_time => _('Minimun time for cache elements (minutes)'),
92     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.'),
93     l_oth_use_netm => _('Use NetworkManager'),
94     h_oth_use_netm => _('Use NetworkManager to switch offline automatically.'),
95     l_oth_mp_rounds => _('Rounds for PBKDF2 function'),
96     h_oth_mp_rounds => _('Specify the number of iterations the key derivation function will be applied on master passphrase computation. Does not modify currently stored passphrase, only master passphrases computed after changing this value are affected.'),
97     
98     l_gui_b_unread => _('Show unread messages with bold font'),
99     h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
100     l_gui_no_markup => _('Don\'t use markup'),
101     h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
102     l_gui_dot_lines => _('Use dotted lines in tree view components'),
103     h_gui_dot_lines => _('Use the old dotted line look in the main window tree views (Folder, Message and other lists) instead of the modern lineless look.'),
104     l_gui_h_scroll => _('Enable horizontal scrollbar'),
105     h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
106     l_gui_swp_from => _('Display To column instead From column in Sent folder'),
107     h_gui_swp_from => _('Display the recipient\'s email address in a To column of the Sent folder instead of the originator\'s one in a From column.'),
108     l_gui_v_scroll => _('Folder List scrollbar behaviour'),
109     h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
110     l_gui_v_scroll_show => _('Show always'),
111     l_gui_v_scroll_auto => _('Automatic'),
112     l_gui_v_scroll_hide => _('Hide always'),
113     l_gui_from_show => _('From column displays'),
114     h_gui_from_show => _('Selects the data displayed in the From column of the Message List: name, address or both.'),
115     l_gui_from_show_name => _('Name only'),
116     l_gui_from_show_addr => _('Address only'),
117     l_gui_from_show_both => _('Both name and address'),
118     l_gui_strip_off => _('Coloured lines contrast'),
119     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.'),
120     l_gui_cursor_v => _('Show cursor'),
121     h_gui_cursor_v => _('Display the cursor in the Message View.'),
122     l_gui_toolbar_d => _('Detachable toolbars'),
123     h_gui_toolbar_d => _('Show handles in the toolbars.'),
124     l_gui_strip_all => _('Use stripes in all tree view components'),
125     h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
126     l_gui_strip_sum => _('Use stripes in Folder List and Message List'),
127     h_gui_strip_sum => _('Enable alternately coloured lines in Message List and Folder List.'),
128     l_gui_two_line_v => _('2 lines per Message List item in 3-column layout'),
129     h_gui_two_line_v => _('Spread Message List information over two lines when using the three column mode.'),
130     l_gui_margin_co => _('Show margin'),
131     h_gui_margin_co => _('Shows a small margin in the Compose View.'),
132     l_gui_mview_date => _('Don\'t display localized date'),
133     h_gui_mview_date => _('Toggles localization of date format in Message View.'),
134     l_gui_zero_char => _('Zero replacement character'),
135     h_gui_zero_char => _('Replaces \'0\' with the given character in Folder List.'),
136     l_gui_type_any => _('Editable headers'),
137     h_gui_type_any => _('Allows to manually type any value in Compose Window header entries or just select from the available choices in the associated dropdown list.'),
138     l_gui_next_del => _('Select next message on delete'),
139     h_gui_next_del => _('When deleting a message, toggles between selecting the next one (newer message) or the previous one (older message).'),
140
141     l_beh_hover_t => _('Drag \'n\' drop hover timeout (ms)'),
142     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.'),
143     l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
144     h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
145     l_beh_flowed => _('Respect format=flowed in messages'),
146     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.'),
147     l_beh_parts_rw => _('Allow writable temporary files'),
148     h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
149     l_beh_skip_ssl => _('Don\'t check SSL certificates'),
150     h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
151     l_beh_up_step => _('Progress bar update step (items)'),
152     h_beh_up_step => _('Update stepping in progress bars.'),
153     l_beh_thread_a => _('Maximum age when threading by subject (days)'),
154     h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
155     l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
156     h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
157     l_beh_use_utf8 => _('Force UTF-8 for broken mails'),
158     h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
159     l_beh_warn_dnd => _('Warn on drag \'n\' drop'),
160     h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
161     l_beh_out_ascii => _('Outgoing messages fallback to ASCII'),
162     h_beh_out_ascii => _('If content allows, ASCII will be used to encode outgoing messages, otherwise the user-defined encoding is enforced always.'),
163     l_beh_pp_unsel => _('Primary paste unselects selection'),
164     h_beh_pp_unsel => _('Controls how pasting using middle-click changes the selected text and insertion point.'),
165     l_beh_inline_at => _('Show inline attachments'),
166     h_beh_inline_at => _('Allows hiding inline attachments already shown in mail structure view.'),
167     l_beh_addr_swc => _('Address search in compose window matches any'),
168     h_beh_addr_swc => _('On Tab-key completion, address text will match any part of the string or only the from the start.'),
169     l_beh_fold_swc => _('Folder search in folder selector matches any'),
170     h_beh_fold_swc => _('On folder name completion text will match any part of the string or only from the start.'),
171
172     l_col_emphasis => _('X-Mailer header'),
173     h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
174     l_col_log_err => _('Error messages'),
175     h_col_log_err => _('Colour for error messages in log window.'),
176     l_col_log_in => _('Server messages'),
177     h_col_log_in => _('Colour for messages received from servers in log window.'),
178     l_col_log_msg => _('Standard messages'),
179     h_col_log_msg => _('Colour for messages in log window.'),
180     l_col_log_out => _('Client messages'),
181     h_col_log_out => _('Colour for messages sent to servers in log window.'),
182     l_col_log_warn => _('Warnings'),
183     h_col_log_warn => _('Colour for warning messages in log window.'),
184
185     l_col_diff_add => _('Added lines'),
186     h_col_diff_add => _('Colour for added lines in patches.'),
187     l_col_diff_del => _('Deleted lines'),
188     h_col_diff_del => _('Colour for deleted lines in patches.'),
189     l_col_diff_hunk => _('Hunk lines'),
190     h_col_diff_hunk => _('Color for hunk headers in patches.'),
191
192     l_win_x => _('X position'),
193     h_win_x => _('X coordinate for window\'s top-left corner.'),
194     l_win_y => _('Y position'),
195     h_win_y => _('Y coordinate for window\'s top-left corner.'),
196     l_win_w => _('Width'),
197     h_win_w => _('Window\'s width in pixels.'),
198     l_win_h => _('Height'),
199     h_win_h => _('Window\'s height in pixels.'),
200
201     l_win_main_mx => _('Maximized'),
202     h_win_main_mx => _('Changes window maximized status.'),
203     l_win_main_fs => _('Full-screen'),
204     h_win_main_fs => _('Changes full screen status.'),
205
206     e_error => _('Error: '),
207     e_noclawsrc => _('resource file for Claws Mail was not found.'),
208     e_running => _('seems Claws Mail is currently running, close it first.'),
209 );
210
211 # all preferences read by load_preferences
212 my %PREFS = ();
213 # values of all preferences handled by clawsker
214 my %HPVALUE = ();
215 # default config dir and file name
216 my $ALTCONFIGDIR = FALSE;
217 my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
218 my $CONFIGRC = 'clawsrc';
219
220 # index constants for preference arrays
221 use constant NAME  => 0; # the name on the rc file
222 use constant LABEL => 1; # the label on the GUI
223 use constant DESC  => 2; # the description for the hint/help
224 use constant TYPE  => 3; # data type: bool, int, float, string, color
225 use constant CMVER => 4; # lowest[,highest] Claws Mail version(s) the feature exists
226 use constant CMDEF => 5; # default value for the preference in Claws Mail
227 use constant GUI   => 6; # GUI element
228
229 # constants for GUI spacing
230 use constant HBOX_SPC => 5;
231 use constant FRAME_SPC => 2;
232 use constant PAGE_SPC => 5;
233
234 # version functions
235
236 sub version_greater_or_equal {
237     my ($version, $refvers) = @_;
238     my @version = split (/\./, $version);
239     my @refvers = split (/\./, $refvers);
240     while ($#version < $#refvers) {
241         push (@version, '0');
242     }
243     my $idx = 0;
244     while (($idx <= $#refvers) 
245             and (int ($version[$idx]) == int ($refvers[$idx]))) {
246         ++$idx;
247     }
248     return TRUE if (($idx > $#refvers)
249         or (int ($version[$idx]) >= int ($refvers[$idx])));
250     return FALSE;
251 }
252
253 sub get_claws_version {
254     my @cmbin = (
255         'claws-mail',
256     );
257     my $res = "";
258     foreach my $bin (@cmbin) {
259         $_ = qx/which $bin/;
260         chomp;
261         last if ($_ ne "");
262     }
263     return "" unless ($_); # not installed
264     $_ = qx/$_ -v/;
265     chomp;
266     my @fver = split (/ /);
267     die "Invalid version string" unless ($fver[2] eq "version");
268     my @ver = split (/\./, $fver[3]);
269     $res .= "$ver[0].";
270     $res .= "$ver[1].";
271     if ($ver[2] =~ /(\d+)cvs(\d+)/) {
272         $res .= "$1.$2";
273     }
274     else {
275         $res .= "$ver[2].0";
276     }
277     return $res;
278 }
279
280 # data handlers and auxiliar functions
281
282 sub handle_bool_value {
283     my ($widget, $event, $dataref) = @_;
284     $$dataref = ($widget->get_active ())? '1': '0';
285 }
286
287 sub handle_int_value {
288     my ($widget, $event, $dataref) = @_;
289     $_ = $widget->get_text ();
290     s/^\s+//;
291     s/\s+$//;
292     if (/^[0-9]+$/) {
293         $$dataref = $_;
294         $widget->set_text ($_);
295     }
296     else {
297         $widget->set_text ($$dataref);
298     }
299 }
300
301 sub handle_string_value {
302     my ($widget, $event, $dataref) = @_;
303     $$dataref = $widget->get_text ();
304 }
305
306 sub handle_nchar_value {
307     my ($widget, $event, $dataref, $minlen) = @_;
308     $_ = substr ($widget->get_text (), 0, $minlen);
309     $widget->set_text ($_);
310     $$dataref = $_;
311 }
312
313 sub gdk_color_from_str {
314     my ($str) = @_;
315     my ($rr, $gg, $bb) = (0, 0 ,0);
316     $_ = uc ($str);
317     if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
318         $rr = hex($1) * 256;
319         $gg = hex($2) * 256; 
320         $bb = hex($3) * 256;
321     }
322     my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
323     return $color;
324 }
325
326 sub str_from_gdk_color {
327     my ($color) = @_;
328     my $rr = $color->red / 256;
329     my $gg = $color->green / 256;
330     my $bb = $color->blue / 256;
331     my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
332     return $str;
333 }
334
335 sub handle_color_value {
336     my ($widget, $event, $dataref) = @_;
337     my $newcol = $widget->get_color;
338     $$dataref = str_from_gdk_color ($newcol);
339 }
340
341 sub handle_selection_value {
342     my ($widget, $event, $dataref) = @_;
343     $$dataref = $widget->get_active;
344 }
345
346 sub get_rc_filename {
347     return $CONFIGDIR . $CONFIGRC;
348 }
349
350 sub set_rc_filename {
351     my ($fullname) = @_;
352     my @parts = split ('/', $fullname);
353     $CONFIGRC = $parts[$#parts];
354     $parts[$#parts] = '';
355     $CONFIGDIR = join ('/', @parts);
356 }
357
358 sub log_message {
359     my ($mesg, $fatal) = @_;
360     if (defined($fatal) && $fatal eq 'die') {
361         die "$NAME: $mesg\n";
362     }
363     if ($VERBOSE) {
364         print "$NAME: $mesg\n";
365     }
366 }
367
368 sub error_dialog {
369     my ($emsg) = @_;
370     my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
371     my $errordlg = Gtk2::MessageDialog->new_with_markup ($main_window, 'modal', 'error', 'cancel', $markup);
372     $errordlg->set_title (_('Clawsker error'));
373     $errordlg->run;
374     $errordlg->destroy;
375 }
376
377 sub claws_is_running {
378     my $emsg = "$xl::s{e_error}$xl::s{e_running}";
379     log_message ($emsg);
380     error_dialog ($emsg);
381     return FALSE;
382 }
383
384 sub check_claws_not_running {
385     my $tmpdir = (defined $ENV{TMPDIR})? $ENV{TMPDIR}: '/tmp';
386     $tmpdir = '/tmp' if ($tmpdir eq '');
387     my $socket = (not $ALTCONFIGDIR)? $tmpdir: $CONFIGDIR;
388     $socket .= "/claws-mail-$<";
389     -S $socket and return claws_is_running ();
390     # since 3.9.0cvs36
391     my $lockdir = "$tmpdir/claws-mail-$<";
392     -d $lockdir and do { 
393         $_ = $CONFIGDIR;
394         s/\/$//;
395         $socket = "$lockdir/" . md5_hex ($_);
396         -S $socket and return claws_is_running ();
397     };
398     return TRUE;
399 }
400
401 sub check_rc_file {
402     my ($rcfile) = @_;
403     (defined($rcfile) && -f $rcfile) or do {
404         my $emsg = "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
405         log_message ($emsg);
406         error_dialog ($emsg);
407         return FALSE;
408     };
409     return TRUE;
410 }
411
412 sub set_widget_hint {
413     if ($SHOWHINTS) {
414         my ($wdgt, $hint) = @_;    
415         $wdgt->set_tooltip_text ($hint);
416         $wdgt->set_has_tooltip (TRUE);
417     }
418 }
419
420 sub set_widget_sens {
421     my ($wdgt, $versions) = @_;
422     my @ver = split(/,/, $versions);
423     if ($#ver == 1) {
424       $wdgt->set_sensitive (
425         version_greater_or_equal ($CLAWSV, $ver[0])
426         and version_greater_or_equal ($ver[1], $CLAWSV)
427       );
428     } else {
429         $wdgt->set_sensitive (version_greater_or_equal ($CLAWSV, $ver[0]));
430     }
431 }
432
433 # graphic element creation 
434
435 sub new_check_button_for {
436     my ($hash, $key) = @_;
437     my $name = $$hash{$key}[NAME];
438     my $label = $$hash{$key}[LABEL];
439     #
440     my $hbox = Gtk2::HBox->new (FALSE, 5);
441     my $cb = Gtk2::CheckButton->new ($label);
442     $$hash{$key}[GUI] = $cb;
443     if (defined ($HPVALUE{$name})) {
444         $cb->set_active ($HPVALUE{$name} eq '1');
445     }
446     $cb->signal_connect (clicked => sub {
447             my ($w, $e) = @_;
448             handle_bool_value ($w, $e, \$HPVALUE{$name});
449         });
450     set_widget_hint ($cb, $$hash{$key}[DESC]);
451     set_widget_sens ($cb, $$hash{$key}[CMVER]);
452     $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
453     #
454     return $hbox;
455 }
456
457 sub new_text_box_for_int {
458     my ($hash, $key) = @_;
459     my $name = $$hash{$key}[NAME];
460     my $label = $$hash{$key}[LABEL];
461     my @type = split (/,/, $$hash{$key}[TYPE]);
462     push (@type, 0), push (@type, 10000) unless ($#type > 0); 
463     #
464     my $hbox = Gtk2::HBox->new (FALSE, 5);
465     my $glabel = Gtk2::Label->new ($label);
466     my $pagei = int (($type[2] - $type[1]) / 10);
467     my $gentry = Gtk2::SpinButton->new_with_range ($type[1], $type[2], $pagei);
468     $gentry->set_numeric (TRUE);
469     $gentry->set_value ($HPVALUE{$name});
470     $$hash{$key}[GUI] = $gentry;
471     $gentry->signal_connect('value-changed' => sub {
472             my ($w, $e) = @_;
473             handle_int_value ($w, $e, \$HPVALUE{$name});
474         });
475     set_widget_hint ($gentry, $$hash{$key}[DESC]);
476     set_widget_sens ($gentry, $$hash{$key}[CMVER]);
477     $glabel->set_sensitive ($gentry->sensitive);
478     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
479     $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
480     #
481     return $hbox;
482 }
483
484 sub new_text_box_for_nchar {
485     my ($hash, $key) = @_;
486     my $name = $$hash{$key}[NAME];
487     my $label = $$hash{$key}[LABEL];
488     my @type = split (/,/, $$hash{$key}[TYPE]); # char,minlen,maxlen
489     my $hbox = Gtk2::HBox->new (FALSE, 5);
490     my $glabel = Gtk2::Label->new ($label);
491     my $gentry = Gtk2::Entry->new ();
492     $gentry->set_max_length($type[2]) if defined ($type[2]);
493     $gentry->set_width_chars(int ($type[2]) + 2) if defined ($type[2]);
494     $gentry->set_text ($HPVALUE{$name});
495     $$hash{$key}[GUI] = $gentry;
496     $gentry->signal_connect('key-release-event' => sub {
497             my ($w, $e) = @_;
498             handle_nchar_value ($w, $e, \$HPVALUE{$name}, $type[1]);
499         });
500     set_widget_hint ($gentry, $$hash{$key}[DESC]);
501     set_widget_sens ($gentry, $$hash{$key}[CMVER]);
502     $glabel->set_sensitive ($gentry->sensitive);
503     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
504     $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
505     #
506     return $hbox;
507 }
508
509 sub new_color_button_for {
510     my ($hash, $key) = @_;
511     my $name = $$hash{$key}[NAME];
512     my $label = $$hash{$key}[LABEL];
513     #
514     my $col = gdk_color_from_str ($HPVALUE{$name});
515     my $hbox = Gtk2::HBox->new (FALSE, 5);
516     my $glabel = Gtk2::Label->new ($label);
517     my $button = Gtk2::ColorButton->new_with_color ($col);
518     $$hash{$key}[GUI] = $button;
519     $button->set_title ($label);
520     $button->set_relief ('none');
521     $button->signal_connect ('color-set' => sub {
522             my ($w, $e) = @_;
523             handle_color_value ($w, $e, \$HPVALUE{$name});
524         });
525     set_widget_hint ($button, $$hash{$key}[DESC]);
526     set_widget_sens ($button, $$hash{$key}[CMVER]);
527     $glabel->set_sensitive ($button->sensitive);
528     $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
529     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
530     #
531     return $hbox;
532 }
533
534 sub new_selection_box_for {
535     my ($hash, $key) = @_;
536     my $name = $$hash{$key}[NAME];
537     my $label = $$hash{$key}[LABEL];
538     #
539     my $hbox = Gtk2::HBox->new (FALSE, 5);
540     my $glabel = Gtk2::Label->new ($label);
541     my $combo = Gtk2::ComboBox->new_text;
542     $$hash{$key}[GUI] = $combo;
543     my @options = split (';', $$hash{$key}[TYPE]);
544     foreach my $opt (@options) {
545         my ($index, $textkey) = split ('=', $opt);
546         $combo->insert_text ($index, $xl::s{$textkey});
547     }
548     $combo->signal_connect ('changed' => sub {
549             my ($w, $e) = @_;
550             handle_selection_value ($w, $e, \$HPVALUE{$name});
551         });
552     $combo->set_active ($HPVALUE{$name});
553     set_widget_hint ($combo, $$hash{$key}[DESC]);
554     set_widget_sens ($combo, $$hash{$key}[CMVER]);
555     $glabel->set_sensitive ($combo->sensitive);
556     $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
557     $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
558     #
559     return $hbox;
560 }
561
562 # more graphic helpers
563
564 sub new_hbox_pack {
565     my $hbox = Gtk2::HBox->new (FALSE, 5);
566     $hbox->set_border_width (PAGE_SPC);
567     foreach my $item (@_) {
568         $hbox->pack_start ($item, FALSE, FALSE, 0);
569     }
570     return $hbox;
571 }    
572
573 sub new_vbox_pack {
574     my $vbox = Gtk2::VBox->new (FALSE, 5);
575     $vbox->set_border_width (PAGE_SPC);
576     foreach my $item (@_) {
577         $vbox->pack_start ($item, FALSE, FALSE, 0);
578     }
579     return $vbox;
580 }    
581
582 sub new_vbox_pack_compact {
583     my $vbox = Gtk2::VBox->new (FALSE, 0);
584     $vbox->set_border_width (0);
585     foreach my $item (@_) {
586         $vbox->pack_start ($item, FALSE, FALSE, 0);
587     }
588     return $vbox;
589 }    
590
591 sub new_subpage_frame {
592     my ($box, $title, $notpacked) = @_;
593     my $frame = Gtk2::Frame->new ($title);
594     $frame->add ($box);    
595     return new_vbox_pack ($frame) unless defined ($notpacked);
596     return $frame;
597 }
598
599 # preference maps and corresponding page creation subs
600
601 %pr::oth = ( # other preferences
602     use_dlg => [ 
603         'addressbook_use_editaddress_dialog',
604         $xl::s{l_oth_use_dlg},
605         $xl::s{h_oth_use_dlg},
606         'bool',
607         '2.7.0',
608         '0',
609         undef,
610     ],
611     max_use => [
612         'cache_max_mem_usage',
613         $xl::s{l_oth_max_use},
614         $xl::s{h_oth_max_use},
615         'int,0,262144', # 0 Kb - 256 Mb
616         '0.0.0',
617         '4096',
618         undef,
619     ],
620     min_time => [
621         'cache_min_keep_time',
622         $xl::s{l_oth_min_time},
623         $xl::s{h_oth_min_time},
624         'int,0,120', # 0 minutes - 2 hours
625         '0.0.0',
626         '15',
627         undef,
628     ],
629     use_netm => [
630         'use_networkmanager',
631         $xl::s{l_oth_use_netm},
632         $xl::s{h_oth_use_netm},
633         'bool',
634         '3.3.1',
635         '1',
636         undef,
637     ],
638     mp_rounds => [
639         'master_passphrase_pbkdf2_rounds',
640         $xl::s{l_oth_mp_rounds},
641         $xl::s{h_oth_mp_rounds},
642         'int,50000,1000000',
643         '3.13.2.110',
644         '50000',
645         undef,
646     ],
647 );
648
649 sub new_other_page() {
650     return new_vbox_pack (
651                new_subpage_frame (
652                    new_vbox_pack (
653                        new_check_button_for(\%pr::oth, 'use_dlg')),
654                    $xl::s{ab_frame}, 'not-packed'),
655                new_subpage_frame (
656                    new_vbox_pack (
657                        new_text_box_for_int(\%pr::oth, 'max_use'),
658                        new_text_box_for_int(\%pr::oth, 'min_time')),
659                    $xl::s{mem_frame}, 'not-packed'),
660                new_subpage_frame (
661                    new_vbox_pack (
662                        new_check_button_for(\%pr::oth, 'use_netm')),
663                    $xl::s{netm_frame}, 'not-packed'),
664                new_subpage_frame (
665                    new_vbox_pack (
666                        new_text_box_for_int(\%pr::oth, 'mp_rounds')),
667                    $xl::s{mpass_frame}, 'not-packed')
668            );
669 }
670
671 %pr::gui = ( # gui bells and whistles
672     b_unread => [ 
673         'bold_unread',
674         $xl::s{l_gui_b_unread},
675         $xl::s{h_gui_b_unread},
676         'bool',
677         '0.0.0',
678         '1',
679         undef,
680     ],
681     no_markup => [
682         'compose_no_markup',
683         $xl::s{l_gui_no_markup},
684         $xl::s{h_gui_no_markup},
685         'bool',
686         '0.0.0',
687         '0',
688         undef,
689     ],
690     dot_lines => [
691         'enable_dotted_lines',
692         $xl::s{l_gui_dot_lines},
693         $xl::s{h_gui_dot_lines},
694         'bool',
695         '0.0.0,3.7.10.44',
696         '0',
697         undef,
698     ],
699     h_scroll => [
700         'enable_hscrollbar',
701         $xl::s{l_gui_h_scroll},
702         $xl::s{h_gui_h_scroll},
703         'bool',
704         '0.0.0',
705         '1',
706         undef,
707     ],
708     swp_from => [
709         'enable_swap_from',
710         $xl::s{l_gui_swp_from},
711         $xl::s{h_gui_swp_from},
712         'bool',
713         '0.0.0',
714         '0',
715         undef,
716     ],
717     v_scroll => [
718         'folderview_vscrollbar_policy',
719         $xl::s{l_gui_v_scroll},
720         $xl::s{h_gui_v_scroll},
721         '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
722         '0.0.0',
723         '0',
724         undef,
725     ],
726     from_show => [
727         'summary_from_show',
728         $xl::s{l_gui_from_show},
729         $xl::s{h_gui_from_show},
730         '0=l_gui_from_show_name;1=l_gui_from_show_addr;2=l_gui_from_show_both',
731         '3.7.10',
732         '0',
733         undef,
734     ],
735     strip_off => [
736         'stripes_color_offset',
737         $xl::s{l_gui_strip_off},
738         $xl::s{h_gui_strip_off},
739         'int,0,40000', # no idea what this number means
740         '0.0.0',
741         '4000',
742         undef,
743     ],
744     cursor_v => [
745         'textview_cursor_visible',
746         $xl::s{l_gui_cursor_v},
747         $xl::s{h_gui_cursor_v},
748         'bool',
749         '0.0.0',
750         '0',
751         undef,
752     ],
753     toolbar_d => [
754         'toolbar_detachable',
755         $xl::s{l_gui_toolbar_d},
756         $xl::s{h_gui_toolbar_d},
757         'bool',
758         '0.0.0',
759         '0',
760         undef,
761     ],
762     strip_all => [
763         'use_stripes_everywhere',
764         $xl::s{l_gui_strip_all},
765         $xl::s{h_gui_strip_all},
766         'bool',
767         '0.0.0',
768         '1',
769         undef,
770     ],
771     strip_sum => [
772         'use_stripes_in_summaries',
773         $xl::s{l_gui_strip_sum},
774         $xl::s{h_gui_strip_sum},
775         'bool',
776         '0.0.0',
777         '1',
778         undef,
779     ],
780     two_linev => [
781         'two_line_vertical',
782         $xl::s{l_gui_two_line_v},
783         $xl::s{h_gui_two_line_v},
784         'bool',
785         '3.4.0.7',
786         '0',
787         undef,
788     ],
789     margin_co => [
790         'show_compose_margin',
791         $xl::s{l_gui_margin_co},
792         $xl::s{h_gui_margin_co},
793         'bool',
794         '3.7.6.7',
795         '0',
796         undef,
797     ],
798     mview_date => [
799         'msgview_date_format',
800         $xl::s{l_gui_mview_date},
801         $xl::s{h_gui_mview_date},
802         'bool',
803         '3.7.8.42',
804         '0',
805         undef,
806     ],
807     zero_char => [
808         'zero_replacement_char',
809         $xl::s{l_gui_zero_char},
810         $xl::s{h_gui_zero_char},
811         'char,1,1',
812         '2.8.1.77',
813         '0',
814         undef,
815     ],
816     type_any => [
817         'type_any_header',
818         $xl::s{l_gui_type_any},
819         $xl::s{h_gui_type_any},
820         'bool',
821         '3.12.0.44',
822         '0',
823         undef,
824     ],
825     next_del => [
826         'next_on_delete',
827         $xl::s{l_gui_next_del},
828         $xl::s{h_gui_next_del},
829         'bool',
830         '3.13.0.5',
831         '0',
832         undef,
833     ],
834 );
835
836 sub new_gui_page() {
837     my $gf = Gtk2::VBox->new (FALSE, 5);
838     $gf->set_border_width (PAGE_SPC);
839
840     my $cb_dot_lines = new_check_button_for (\%pr::gui, 'dot_lines');
841     my $cb_toolbar_d = new_check_button_for (\%pr::gui, 'toolbar_d');
842     my $tb_zero_char = new_text_box_for_nchar (\%pr::gui, 'zero_char');
843
844     $gf->pack_start (new_subpage_frame (
845                          new_vbox_pack (
846                              new_check_button_for (\%pr::gui, 'strip_all'),
847                              new_check_button_for (\%pr::gui, 'strip_sum'),
848                              new_text_box_for_int (\%pr::gui, 'strip_off')),
849                          $xl::s{stripes_frame}, 'not-packed'),
850                      FALSE, FALSE, FRAME_SPC);
851     $gf->pack_start (new_subpage_frame (
852                          new_vbox_pack (
853                              new_check_button_for (\%pr::gui, 'b_unread'),
854                              new_check_button_for (\%pr::gui, 'swp_from'),
855                              new_check_button_for (\%pr::gui, 'two_linev'),
856                              new_check_button_for (\%pr::gui, 'next_del'),
857                              new_selection_box_for (\%pr::gui, 'from_show')),
858                          $xl::s{mlist_frame}, 'not-packed'), 
859                      FALSE, FALSE, FRAME_SPC);
860     $gf->pack_start (new_subpage_frame (
861                          new_hbox_pack (
862                              new_check_button_for (\%pr::gui, 'cursor_v'),
863                              new_check_button_for (\%pr::gui, 'mview_date')),
864                          $xl::s{mview_frame}, 'not-packed'), 
865                      FALSE, FALSE, FRAME_SPC);
866     $gf->pack_start (new_subpage_frame (
867                          new_hbox_pack (
868                              new_check_button_for (\%pr::gui, 'no_markup'),
869                              new_check_button_for (\%pr::gui, 'margin_co'),
870                              new_check_button_for (\%pr::gui, 'type_any')),
871                          $xl::s{compo_frame}, 'not-packed'), 
872                      FALSE, FALSE, FRAME_SPC);
873     $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
874     $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
875     $gf->pack_start (new_subpage_frame (
876                          new_vbox_pack (
877                              new_check_button_for (\%pr::gui, 'h_scroll'),
878                              new_selection_box_for (\%pr::gui, 'v_scroll')),
879                          $xl::s{sbar_frame}, 'not-packed'),
880                      FALSE, FALSE, FRAME_SPC);
881     $gf->pack_start ($tb_zero_char, FALSE, FALSE, 0);
882
883     return $gf;
884 }
885
886 %pr::beh = ( # tweak some behaviour
887     hover_t => [
888         'hover_timeout',
889         $xl::s{l_beh_hover_t},
890         $xl::s{h_beh_hover_t},
891         'int,100,3000', # 0.1 seconds - 3 seconds
892         '0.0.0',
893         '500',
894         undef,
895     ],
896     dangerous => [
897         'live_dangerously',
898         $xl::s{l_beh_dangerous},
899         $xl::s{h_beh_dangerous},
900         'bool',
901         '0.0.0',
902         '0',
903         undef,
904     ],
905     flowed => [
906         'respect_flowed_format',
907         $xl::s{l_beh_flowed},
908         $xl::s{h_beh_flowed},
909         'bool',
910         '0.0.0',
911         '0',
912         undef,
913     ],
914     parts_rw => [
915         'save_parts_readwrite',
916         $xl::s{l_beh_parts_rw},
917         $xl::s{h_beh_parts_rw},
918         'bool',
919         '0.0.0',
920         '0',
921         undef,
922     ],
923     skip_ssl => [
924         'skip_ssl_cert_check',
925         $xl::s{l_beh_skip_ssl},
926         $xl::s{h_beh_skip_ssl},
927         'bool',
928         '0.0.0',
929         '0',
930         undef,
931     ],
932     up_step => [
933         'statusbar_update_step',
934         $xl::s{l_beh_up_step},
935         $xl::s{h_beh_up_step},
936         'int,1,200', # 1 item - 200 items
937         '0.0.0',
938         '10',
939         undef,
940     ],
941     thread_a => [
942         'thread_by_subject_max_age',
943         $xl::s{l_beh_thread_a},
944         $xl::s{h_beh_thread_a},
945         'int,1,30', # 1 day - 30 days
946         '0.0.0',
947         '10',
948         undef,
949     ],
950     unsafe_ssl => [
951         'unsafe_ssl_certs',
952         $xl::s{l_beh_unsafe_ssl},
953         $xl::s{h_beh_unsafe_ssl},
954         'bool',
955         '0.0.0',
956         '0',
957         undef,
958     ],
959     use_utf8 => [
960         'utf8_instead_of_locale_for_broken_mail',
961         $xl::s{l_beh_use_utf8},
962         $xl::s{h_beh_use_utf8},
963         'bool',
964         '0.0.0',
965         '0',
966         undef,
967     ],
968     warn_dnd => [
969         'warn_dnd',
970         $xl::s{l_beh_warn_dnd},
971         $xl::s{h_beh_warn_dnd},
972         'bool',
973         '0.0.0',
974         '1',
975         undef,
976     ],
977     out_ascii => [
978         'outgoing_fallback_to_ascii',
979         $xl::s{l_beh_out_ascii},
980         $xl::s{h_beh_out_ascii},
981         'bool',
982         '3.4.0.37',
983         '1',
984         undef,
985     ],
986     pp_unsel => [
987         'primary_paste_unselects',
988         $xl::s{l_beh_pp_unsel},
989         $xl::s{h_beh_pp_unsel},
990         'bool',
991         '3.6.1.35',
992         '0',
993         undef,
994     ],
995     inline_at => [
996         'show_inline_attachments',
997         $xl::s{l_beh_inline_at},
998         $xl::s{h_beh_inline_at},
999         'bool',
1000         '3.7.8.48',
1001         '1',
1002         undef,
1003     ],
1004     addr_swc => [
1005         'address_search_wildcard',
1006         $xl::s{l_beh_addr_swc},
1007         $xl::s{h_beh_addr_sw1},
1008         'bool',
1009         '3.9.3.18',
1010         '0',
1011         undef,
1012     ],
1013     fold_swc => [
1014         'folder_search_wildcard',
1015         $xl::s{l_beh_fold_swc},
1016         $xl::s{h_beh_fold_sw1},
1017         'bool',
1018         '3.9.3.18',
1019         '0',
1020         undef,
1021     ],
1022 );
1023
1024 sub new_behaviour_page() {
1025     my $bf = Gtk2::VBox->new (FALSE, 5);
1026     $bf->set_border_width (PAGE_SPC);
1027
1028     my $tb_up_step = new_text_box_for_int (\%pr::beh, 'up_step');
1029     my $tb_thread_a = new_text_box_for_int (\%pr::beh, 'thread_a');
1030
1031     $bf->pack_start (new_subpage_frame (
1032                          new_vbox_pack (
1033                              new_text_box_for_int (\%pr::beh, 'hover_t'),
1034                              new_check_button_for (\%pr::beh, 'warn_dnd')),
1035                          $xl::s{dnd_frame}, 'not-packed'), 
1036                      FALSE, FALSE, FRAME_SPC);
1037     $bf->pack_start (new_subpage_frame (
1038                          new_hbox_pack (
1039                              new_check_button_for (\%pr::beh, 'skip_ssl'),
1040                              new_check_button_for (\%pr::beh, 'unsafe_ssl')),
1041                          $xl::s{ssl_frame}, 'not-packed'),
1042                      FALSE, FALSE, FRAME_SPC);
1043     $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
1044     $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
1045     $bf->pack_start (new_subpage_frame (
1046                          new_vbox_pack (
1047                              new_check_button_for (\%pr::beh, 'flowed'),
1048                              new_check_button_for (\%pr::beh, 'parts_rw'),
1049                              new_check_button_for (\%pr::beh, 'use_utf8'),
1050                              new_check_button_for (\%pr::beh, 'dangerous'),
1051                              new_check_button_for (\%pr::beh, 'out_ascii'),
1052                              new_check_button_for (\%pr::beh, 'pp_unsel'),
1053                              new_check_button_for (\%pr::beh, 'inline_at')),
1054                          $xl::s{msgs_frame}, 'not-packed'),
1055                      FALSE, FALSE, FRAME_SPC);
1056     $bf->pack_start (new_subpage_frame (
1057                          new_vbox_pack (
1058                              new_check_button_for (\%pr::beh, 'addr_swc'),
1059                              new_check_button_for (\%pr::beh, 'fold_swc')),
1060                          $xl::s{swc_frame}, 'not-packed'),
1061                      FALSE, FALSE, FRAME_SPC);
1062     return $bf;
1063 }
1064
1065 %pr::col = ( # a variety of colours
1066     emphasis => [
1067         'emphasis_color',
1068         $xl::s{l_col_emphasis},
1069         $xl::s{h_col_emphasis},
1070         'color',
1071         '0.0.0',
1072         '#0000cf',
1073         undef,
1074     ],
1075     log_err => [
1076         'log_error_color',
1077         $xl::s{l_col_log_err},
1078         $xl::s{h_col_log_err},
1079         'color',
1080         '0.0.0',
1081         '#af0000',
1082         undef,
1083     ],
1084     log_in => [
1085         'log_in_color',
1086         $xl::s{l_col_log_in},
1087         $xl::s{h_col_log_in},
1088         'color',
1089         '0.0.0',
1090         '#000000',
1091         undef,
1092     ],
1093     log_msg => [
1094         'log_msg_color',
1095         $xl::s{l_col_log_msg},
1096         $xl::s{h_col_log_msg},
1097         'color',
1098         '0.0.0',
1099         '#00af00',
1100         undef,
1101     ],
1102     log_out => [
1103         'log_out_color',
1104         $xl::s{l_col_log_out},
1105         $xl::s{h_col_log_out},
1106         'color',
1107         '0.0.0',
1108         '#0000ef',
1109         undef,
1110     ],
1111     log_warn => [
1112         'log_warn_color',
1113         $xl::s{l_col_log_warn},
1114         $xl::s{h_col_log_warn},
1115         'color',
1116         '0.0.0',
1117         '#af0000',
1118         undef,
1119     ],
1120     diff_add => [
1121         'diff_added_color',
1122         $xl::s{l_col_diff_add},
1123         $xl::s{h_col_diff_add},
1124         'color',
1125         '3.8.0.54',
1126         '#008b8b',
1127         undef,
1128     ],
1129     diff_del => [
1130         'diff_deleted_color',
1131         $xl::s{l_col_diff_del},
1132         $xl::s{h_col_diff_del},
1133         'color',
1134         '3.8.0.54',
1135         '#6a5acd',
1136         undef,
1137     ],
1138     diff_hunk => [
1139         'diff_hunk_color',
1140         $xl::s{l_col_diff_hunk},
1141         $xl::s{h_col_diff_hunk},
1142         'color',
1143         '3.8.0.54',
1144         '#a52a2a',
1145         undef,
1146     ],
1147 );
1148
1149 sub new_colours_page() {
1150     return new_vbox_pack (
1151                new_subpage_frame (
1152                    new_vbox_pack (
1153                        new_color_button_for (\%pr::col, 'emphasis')),
1154                    $xl::s{msgview_frame}, 'not-packed'),
1155                new_subpage_frame (
1156                    new_vbox_pack (
1157                        new_color_button_for (\%pr::col, 'log_err'),
1158                        new_color_button_for (\%pr::col, 'log_in'),
1159                        new_color_button_for (\%pr::col, 'log_msg'),
1160                        new_color_button_for (\%pr::col, 'log_out'),
1161                        new_color_button_for (\%pr::col, 'log_warn')),
1162                    $xl::s{log_frame}, 'not-packed'),
1163                new_subpage_frame (
1164                    new_vbox_pack (
1165                        new_color_button_for (\%pr::col, 'diff_add'),
1166                        new_color_button_for (\%pr::col, 'diff_del'),
1167                        new_color_button_for (\%pr::col, 'diff_hunk')),
1168                    $xl::s{diff_frame}, 'not-packed')
1169            );
1170 }
1171
1172 %pr::win = ( # tweak window positions and/or sizes
1173     main_x => [
1174         'mainwin_x',
1175         $xl::s{l_win_x},
1176         $xl::s{h_win_x},
1177         'int,0,3000', # 0 pixels - 3000 pixels
1178         '0.0.0',
1179         '16',
1180         undef,
1181     ],
1182     main_y => [
1183         'mainwin_y',
1184         $xl::s{l_win_y},
1185         $xl::s{h_win_y},
1186         'int,0,3000', # 0 pixels - 3000 pixels
1187         '0.0.0',
1188         '16',
1189         undef,
1190     ],
1191     main_w => [
1192         'mainwin_width',
1193         $xl::s{l_win_w},
1194         $xl::s{h_win_w},
1195         'int,0,3000', # 0 pixels - 3000 pixels
1196         '0.0.0',
1197         '779',
1198         undef,
1199     ],
1200     main_h => [
1201         'mainwin_height',
1202         $xl::s{l_win_h},
1203         $xl::s{h_win_h},
1204         'int,0,3000', # 0 pixels - 3000 pixels
1205         '0.0.0',
1206         '568',
1207         undef,
1208     ],
1209     main_mx => [
1210         'mainwin_maximised',
1211         $xl::s{l_win_main_mx},
1212         $xl::s{h_win_main_mx},
1213         'bool',
1214         '0.0.0',
1215         '0',
1216         undef,
1217     ],
1218     main_fs => [
1219         'mainwin_fullscreen',
1220         $xl::s{l_win_main_fs},
1221         $xl::s{h_win_main_fs},
1222         'bool',
1223         '0.0.0',
1224         '0',
1225         undef,
1226     ],
1227     msgs_x => [
1228         'main_messagewin_x',
1229         $xl::s{l_win_x},
1230         $xl::s{h_win_x},
1231         'int,0,3000', # 0 pixels - 3000 pixels
1232         '0.0.0',
1233         '256',
1234         undef,
1235     ],
1236     msgs_y => [
1237         'main_messagewin_y',
1238         $xl::s{l_win_y},
1239         $xl::s{h_win_y},
1240         'int,0,3000', # 0 pixels - 3000 pixels
1241         '0.0.0',
1242         '210',
1243         undef,
1244     ],
1245     msgs_w => [
1246         'messagewin_width',
1247         $xl::s{l_win_w},
1248         $xl::s{h_win_w},
1249         'int,0,3000', # 0 pixels - 3000 pixels
1250         '0.0.0',
1251         '600',
1252         undef,
1253     ],
1254     msgs_h => [
1255         'messagewin_height',
1256         $xl::s{l_win_h},
1257         $xl::s{h_win_h},
1258         'int,0,3000', # 0 pixels - 3000 pixels
1259         '0.0.0',
1260         '540',
1261         undef,
1262     ],
1263     send_w => [
1264         'sendwin_width',
1265         $xl::s{l_win_w},
1266         $xl::s{h_win_w},
1267         'int,0,3000', # 0 pixels - 3000 pixels
1268         '0.0.0',
1269         '460',
1270         undef,
1271     ],
1272     send_h => [
1273         'sendwin_height',
1274         $xl::s{l_win_h},
1275         $xl::s{h_win_h},
1276         'int,0,3000', # 0 pixels - 3000 pixels
1277         '0.0.0',
1278         '-1',
1279         undef,
1280     ],
1281     recv_w => [
1282         'receivewin_width',
1283         $xl::s{l_win_w},
1284         $xl::s{h_win_w},
1285         'int,0,3000', # 0 pixels - 3000 pixels
1286         '0.0.0',
1287         '460',
1288         undef,
1289     ],
1290     recv_h => [
1291         'receivewin_height',
1292         $xl::s{l_win_h},
1293         $xl::s{h_win_h},
1294         'int,0,3000', # 0 pixels - 3000 pixels
1295         '0.0.0',
1296         '-1',
1297         undef,
1298     ],
1299     fold_x => [
1300         'folderwin_x',
1301         $xl::s{l_win_x},
1302         $xl::s{h_win_x},
1303         'int,0,3000', # 0 pixels - 3000 pixels
1304         '0.0.0',
1305         '16',
1306         undef,
1307     ],
1308     fold_y => [
1309         'folderwin_y',
1310         $xl::s{l_win_y},
1311         $xl::s{h_win_y},
1312         'int,0,3000', # 0 pixels - 3000 pixels
1313         '0.0.0',
1314         '16',
1315         undef,
1316     ],
1317     fold_w => [
1318         'folderitemwin_width',
1319         $xl::s{l_win_w},
1320         $xl::s{h_win_w},
1321         'int,0,3000', # 0 pixels - 3000 pixels
1322         '0.0.0',
1323         '500',
1324         undef,
1325     ],
1326     fold_h => [
1327         'folderitemwin_height',
1328         $xl::s{l_win_h},
1329         $xl::s{h_win_h},
1330         'int,0,3000', # 0 pixels - 3000 pixels
1331         '0.0.0',
1332         '-1',
1333         undef,
1334     ],
1335     fsel_w => [
1336         'folderselwin_width',
1337         $xl::s{l_win_w},
1338         $xl::s{h_win_w},
1339         'int,0,3000', # 0 pixels - 3000 pixels
1340         '0.0.0',
1341         '300',
1342         undef,
1343     ],
1344     fsel_h => [
1345         'folderselwin_height',
1346         $xl::s{l_win_h},
1347         $xl::s{h_win_h},
1348         'int,0,3000', # 0 pixels - 3000 pixels
1349         '0.0.0',
1350         '-1',
1351         undef,
1352     ],
1353     sour_w => [
1354         'sourcewin_width',
1355         $xl::s{l_win_w},
1356         $xl::s{h_win_w},
1357         'int,0,3000', # 0 pixels - 3000 pixels
1358         '0.0.0',
1359         '600',
1360         undef,
1361     ],
1362     sour_h => [
1363         'sourcewin_height',
1364         $xl::s{l_win_h},
1365         $xl::s{h_win_h},
1366         'int,0,3000', # 0 pixels - 3000 pixels
1367         '0.0.0',
1368         '500',
1369         undef,
1370     ],
1371     addr_w => [
1372         'addressbookwin_width',
1373         $xl::s{l_win_w},
1374         $xl::s{h_win_w},
1375         'int,0,3000', # 0 pixels - 3000 pixels
1376         '0.0.0',
1377         '520',
1378         undef,
1379     ],
1380     addr_h => [
1381         'addressbookwin_height',
1382         $xl::s{l_win_h},
1383         $xl::s{h_win_h},
1384         'int,0,3000', # 0 pixels - 3000 pixels
1385         '0.0.0',
1386         '-1',
1387         undef,
1388     ],
1389     adep_w => [
1390         'addressbookeditpersonwin_width',
1391         $xl::s{l_win_w},
1392         $xl::s{h_win_w},
1393         'int,0,3000', # 0 pixels - 3000 pixels
1394         '0.0.0',
1395         '640',
1396         undef,
1397     ],
1398     adep_h => [
1399         'addressbookeditpersonwin_height',
1400         $xl::s{l_win_h},
1401         $xl::s{h_win_h},
1402         'int,0,3000', # 0 pixels - 3000 pixels
1403         '0.0.0',
1404         '320',
1405         undef,
1406     ],
1407     adeg_w => [
1408         'addressbookeditgroupwin_width',
1409         $xl::s{l_win_w},
1410         $xl::s{h_win_w},
1411         'int,0,3000', # 0 pixels - 3000 pixels
1412         '0.0.0',
1413         '580',
1414         undef,
1415     ],
1416     adeg_h => [
1417         'addressbookeditgroupwin_height',
1418         $xl::s{l_win_h},
1419         $xl::s{h_win_h},
1420         'int,0,3000', # 0 pixels - 3000 pixels
1421         '0.0.0',
1422         '340',
1423         undef,
1424     ],
1425     adda_w => [
1426         'addressaddwin_width',
1427         $xl::s{l_win_w},
1428         $xl::s{h_win_w},
1429         'int,0,3000', # 0 pixels - 3000 pixels
1430         '0.0.0',
1431         '300',
1432         undef,
1433     ],
1434     adda_h => [
1435         'addressaddwin_height',
1436         $xl::s{l_win_h},
1437         $xl::s{h_win_h},
1438         'int,0,3000', # 0 pixels - 3000 pixels
1439         '0.0.0',
1440         '-1',
1441         undef,
1442     ],
1443     addf_w => [
1444         'addressbook_folderselwin_width',
1445         $xl::s{l_win_w},
1446         $xl::s{h_win_w},
1447         'int,0,3000', # 0 pixels - 3000 pixels
1448         '0.0.0',
1449         '300',
1450         undef,
1451     ],
1452     addf_h => [
1453         'addressbook_folderselwin_height',
1454         $xl::s{l_win_h},
1455         $xl::s{h_win_h},
1456         'int,0,3000', # 0 pixels - 3000 pixels
1457         '0.0.0',
1458         '-1',
1459         undef,
1460     ],
1461     acce_w => [
1462         'editaccountwin_width',
1463         $xl::s{l_win_w},
1464         $xl::s{h_win_w},
1465         'int,0,3000', # 0 pixels - 3000 pixels
1466         '0.0.0',
1467         '500',
1468         undef,
1469     ],
1470     acce_h => [
1471         'editaccountwin_height',
1472         $xl::s{l_win_h},
1473         $xl::s{h_win_h},
1474         'int,0,3000', # 0 pixels - 3000 pixels
1475         '0.0.0',
1476         '-1',
1477         undef,
1478     ],
1479     acco_w => [
1480         'accountswin_width',
1481         $xl::s{l_win_w},
1482         $xl::s{h_win_w},
1483         'int,0,3000', # 0 pixels - 3000 pixels
1484         '0.0.0',
1485         '500',
1486         undef,
1487     ],
1488     acco_h => [
1489         'accountswin_height',
1490         $xl::s{l_win_h},
1491         $xl::s{h_win_h},
1492         'int,0,3000', # 0 pixels - 3000 pixels
1493         '0.0.0',
1494         '-1',
1495         undef,
1496     ],
1497     filt_w => [
1498         'filteringwin_width',
1499         $xl::s{l_win_w},
1500         $xl::s{h_win_w},
1501         'int,0,3000', # 0 pixels - 3000 pixels
1502         '0.0.0',
1503         '500',
1504         undef,
1505     ],
1506     filt_h => [
1507         'filteringwin_height',
1508         $xl::s{l_win_h},
1509         $xl::s{h_win_h},
1510         'int,0,3000', # 0 pixels - 3000 pixels
1511         '0.0.0',
1512         '-1',
1513         undef,
1514     ],
1515     fila_w => [
1516         'filteringactionwin_width',
1517         $xl::s{l_win_w},
1518         $xl::s{h_win_w},
1519         'int,0,3000', # 0 pixels - 3000 pixels
1520         '0.0.0',
1521         '490',
1522         undef,
1523     ],
1524     fila_h => [
1525         'filteringactionwin_height',
1526         $xl::s{l_win_h},
1527         $xl::s{h_win_h},
1528         'int,0,3000', # 0 pixels - 3000 pixels
1529         '0.0.0',
1530         '-1',
1531         undef,
1532     ],
1533     fild_w => [
1534         'filtering_debugwin_width',
1535         $xl::s{l_win_w},
1536         $xl::s{h_win_w},
1537         'int,0,3000', # 0 pixels - 3000 pixels
1538         '0.0.0',
1539         '600',
1540         undef,
1541     ],
1542     fild_h => [
1543         'filtering_debugwin_height',
1544         $xl::s{l_win_h},
1545         $xl::s{h_win_h},
1546         'int,0,3000', # 0 pixels - 3000 pixels
1547         '0.0.0',
1548         '-1',
1549         undef,
1550     ],
1551     matc_w => [
1552         'matcherwin_width',
1553         $xl::s{l_win_w},
1554         $xl::s{h_win_w},
1555         'int,0,3000', # 0 pixels - 3000 pixels
1556         '0.0.0',
1557         '520',
1558         undef,
1559     ],
1560     matc_h => [
1561         'matcherwin_height',
1562         $xl::s{l_win_h},
1563         $xl::s{h_win_h},
1564         'int,0,3000', # 0 pixels - 3000 pixels
1565         '0.0.0',
1566         '-1',
1567         undef,
1568     ],
1569     pref_w => [
1570         'prefswin_width',
1571         $xl::s{l_win_w},
1572         $xl::s{h_win_w},
1573         'int,0,3000', # 0 pixels - 3000 pixels
1574         '0.0.0',
1575         '600',
1576         undef,
1577     ],
1578     pref_h => [
1579         'prefswin_height',
1580         $xl::s{l_win_h},
1581         $xl::s{h_win_h},
1582         'int,0,3000', # 0 pixels - 3000 pixels
1583         '0.0.0',
1584         '-1',
1585         undef,
1586     ],
1587     temp_w => [
1588         'templateswin_width',
1589         $xl::s{l_win_w},
1590         $xl::s{h_win_w},
1591         'int,0,3000', # 0 pixels - 3000 pixels
1592         '0.0.0',
1593         '480',
1594         undef,
1595     ],
1596     temp_h => [
1597         'templateswin_height',
1598         $xl::s{l_win_h},
1599         $xl::s{h_win_h},
1600         'int,0,3000', # 0 pixels - 3000 pixels
1601         '0.0.0',
1602         '-1',
1603         undef,
1604     ],
1605     acti_w => [
1606         'actionswin_width',
1607         $xl::s{l_win_w},
1608         $xl::s{h_win_w},
1609         'int,0,3000', # 0 pixels - 3000 pixels
1610         '0.0.0',
1611         '486',
1612         undef,
1613     ],
1614     acti_h => [
1615         'actionswin_height',
1616         $xl::s{l_win_h},
1617         $xl::s{h_win_h},
1618         'int,0,3000', # 0 pixels - 3000 pixels
1619         '0.0.0',
1620         '-1',
1621         undef,
1622     ],
1623     tags_w => [
1624         'tagswin_width',
1625         $xl::s{l_win_w},
1626         $xl::s{h_win_w},
1627         'int,0,3000', # 0 pixels - 3000 pixels
1628         '0.0.0',
1629         '486',
1630         undef,
1631     ],
1632     tags_h => [
1633         'tagswin_height',
1634         $xl::s{l_win_h},
1635         $xl::s{h_win_h},
1636         'int,0,3000', # 0 pixels - 3000 pixels
1637         '0.0.0',
1638         '-1',
1639         undef,
1640     ],
1641     plug_w => [
1642         'pluginswin_width',
1643         $xl::s{l_win_w},
1644         $xl::s{h_win_w},
1645         'int,0,3000', # 0 pixels - 3000 pixels
1646         '0.0.0',
1647         '-1',
1648         undef,
1649     ],
1650     plug_h => [
1651         'pluginswin_height',
1652         $xl::s{l_win_h},
1653         $xl::s{h_win_h},
1654         'int,0,3000', # 0 pixels - 3000 pixels
1655         '0.0.0',
1656         '-1',
1657         undef,
1658     ],
1659     logw_w => [
1660         'logwin_width',
1661         $xl::s{l_win_w},
1662         $xl::s{h_win_w},
1663         'int,0,3000', # 0 pixels - 3000 pixels
1664         '0.0.0',
1665         '520',
1666         undef,
1667     ],
1668     logw_h => [
1669         'logwin_height',
1670         $xl::s{l_win_h},
1671         $xl::s{h_win_h},
1672         'int,0,3000', # 0 pixels - 3000 pixels
1673         '0.0.0',
1674         '-1',
1675         undef,
1676     ],
1677     prin_w => [
1678         'print_previewwin_width',
1679         $xl::s{l_win_w},
1680         $xl::s{h_win_w},
1681         'int,0,3000', # 0 pixels - 3000 pixels
1682         '0.0.0',
1683         '600',
1684         undef,
1685     ],
1686     prin_h => [
1687         'print_previewwin_height',
1688         $xl::s{l_win_h},
1689         $xl::s{h_win_h},
1690         'int,0,3000', # 0 pixels - 3000 pixels
1691         '0.0.0',
1692         '-1',
1693         undef,
1694     ],
1695 );
1696
1697 sub new_winpos_subpage_main() {
1698     return new_subpage_frame (
1699                new_vbox_pack_compact (
1700                    new_vbox_pack (
1701                        new_text_box_for_int (\%pr::win, 'main_x'),
1702                        new_text_box_for_int (\%pr::win, 'main_y')),
1703                    new_hbox_pack (
1704                        new_text_box_for_int (\%pr::win, 'main_w'),
1705                        new_text_box_for_int (\%pr::win, 'main_h')),
1706                    new_vbox_pack (
1707                        new_check_button_for (\%pr::win, 'main_fs'),
1708                        new_check_button_for (\%pr::win, 'main_mx'))),
1709                _('Main window')
1710            );
1711 }
1712
1713 sub new_winpos_subpage_msgs() {
1714     return new_subpage_frame (
1715                new_vbox_pack_compact (
1716                    new_vbox_pack (
1717                        new_text_box_for_int (\%pr::win, 'msgs_x'),
1718                        new_text_box_for_int (\%pr::win, 'msgs_y')),
1719                    new_hbox_pack (
1720                        new_text_box_for_int (\%pr::win, 'msgs_w'),
1721                        new_text_box_for_int (\%pr::win, 'msgs_h'))),
1722                _('Message window')
1723            );
1724 }
1725
1726 sub new_winpos_subpage_sendrecv() {
1727     return new_vbox_pack (
1728                new_subpage_frame (
1729                    new_hbox_pack (
1730                        new_text_box_for_int (\%pr::win, 'send_w'),
1731                        new_text_box_for_int (\%pr::win, 'send_h')),
1732                    _('Send window'), 'not-packed'),
1733                new_subpage_frame (
1734                    new_hbox_pack (
1735                        new_text_box_for_int (\%pr::win, 'recv_w'),
1736                        new_text_box_for_int (\%pr::win, 'recv_h')),
1737                    _('Receive window'), 'not-packed')
1738            );
1739 }
1740
1741 sub new_winpos_subpage_fold() {
1742     return new_vbox_pack (
1743                new_subpage_frame (
1744                    new_vbox_pack_compact (
1745                        new_vbox_pack (
1746                             new_text_box_for_int (\%pr::win, 'fold_x'),
1747                             new_text_box_for_int (\%pr::win, 'fold_y')),
1748                        new_hbox_pack (
1749                            new_text_box_for_int (\%pr::win, 'fold_w'),
1750                            new_text_box_for_int (\%pr::win, 'fold_h'))),
1751                    _('Folder window'), 'not-packed'),
1752                new_subpage_frame (
1753                    new_hbox_pack (
1754                        new_text_box_for_int (\%pr::win, 'fsel_w'),
1755                        new_text_box_for_int (\%pr::win, 'fsel_h')),
1756                    _('Folder selection window'), 'not-packed')
1757            );
1758 }
1759
1760 sub new_winpos_subpage_addrbook() {
1761     return new_vbox_pack (
1762                 new_subpage_frame (
1763                      new_hbox_pack (
1764                           new_text_box_for_int (\%pr::win, 'addr_w'),
1765                           new_text_box_for_int (\%pr::win, 'addr_h')),
1766                      _('Addressbook main window'), 'not-packed'),
1767                 new_subpage_frame (
1768                      new_hbox_pack (
1769                           new_text_box_for_int (\%pr::win, 'adep_w'),
1770                           new_text_box_for_int (\%pr::win, 'adep_h')),
1771                      _('Edit person window'), 'not-packed'),
1772                 new_subpage_frame (
1773                      new_hbox_pack (
1774                           new_text_box_for_int (\%pr::win, 'adeg_w'),
1775                           new_text_box_for_int (\%pr::win, 'adeg_h')),
1776                      _('Edit group window'), 'not-packed'),
1777                 new_subpage_frame (
1778                      new_hbox_pack (
1779                           new_text_box_for_int (\%pr::win, 'adda_w'),
1780                           new_text_box_for_int (\%pr::win, 'adda_h')),
1781                      _('Add address window'), 'not-packed'),
1782                 new_subpage_frame (
1783                      new_hbox_pack (
1784                           new_text_box_for_int (\%pr::win, 'addf_w'),
1785                           new_text_box_for_int (\%pr::win, 'addf_h')),
1786                      _('Folder select window'), 'not-packed')
1787            );
1788 }
1789
1790 sub new_winpos_subpage_accounts() {
1791     return new_vbox_pack (
1792                 new_subpage_frame (
1793                      new_hbox_pack (
1794                           new_text_box_for_int (\%pr::win, 'acco_w'),
1795                           new_text_box_for_int (\%pr::win, 'acco_h')),
1796                      _('Accounts window'), 'not-packed'),
1797                 new_subpage_frame (
1798                      new_hbox_pack (
1799                           new_text_box_for_int (\%pr::win, 'acce_w'),
1800                           new_text_box_for_int (\%pr::win, 'acce_h')),
1801                      _('Edit account window'), 'not-packed')
1802            );
1803 }
1804
1805 sub new_winpos_subpage_filtering() {
1806     return new_vbox_pack (
1807                 new_subpage_frame (
1808                      new_hbox_pack (
1809                           new_text_box_for_int (\%pr::win, 'filt_w'),
1810                           new_text_box_for_int (\%pr::win, 'filt_h')),
1811                      _('Filtering window'), 'not-packed'),
1812                 new_subpage_frame (
1813                      new_hbox_pack (
1814                           new_text_box_for_int (\%pr::win, 'fila_w'),
1815                           new_text_box_for_int (\%pr::win, 'fila_h')),
1816                      _('Filtering actions window'), 'not-packed'),
1817                 new_subpage_frame (
1818                      new_hbox_pack (
1819                           new_text_box_for_int (\%pr::win, 'fild_w'),
1820                           new_text_box_for_int (\%pr::win, 'fild_h')),
1821                      _('Filtering debug window'), 'not-packed'),
1822                 new_subpage_frame (
1823                      new_hbox_pack (
1824                           new_text_box_for_int (\%pr::win, 'matc_w'),
1825                           new_text_box_for_int (\%pr::win, 'matc_h')),
1826                      _('Matcher window'), 'not-packed')
1827            );
1828 }
1829
1830 sub new_winpos_subpage_prefs() {
1831     return new_vbox_pack (
1832                 new_subpage_frame (
1833                      new_hbox_pack (
1834                           new_text_box_for_int (\%pr::win, 'pref_w'),
1835                           new_text_box_for_int (\%pr::win, 'pref_h')),
1836                      _('Preferences window'), 'not-packed'),
1837                 new_subpage_frame (
1838                      new_hbox_pack (
1839                           new_text_box_for_int (\%pr::win, 'temp_w'),
1840                           new_text_box_for_int (\%pr::win, 'temp_h')),
1841                      _('Templates window'), 'not-packed'),
1842                 new_subpage_frame (
1843                      new_hbox_pack (
1844                           new_text_box_for_int (\%pr::win, 'acti_w'),
1845                           new_text_box_for_int (\%pr::win, 'acti_h')),
1846                      _('Actions window'), 'not-packed'),
1847                 new_subpage_frame (
1848                      new_hbox_pack (
1849                           new_text_box_for_int (\%pr::win, 'tags_w'),
1850                           new_text_box_for_int (\%pr::win, 'tags_h')),
1851                      _('Tags window'), 'not-packed'),
1852                 new_subpage_frame (
1853                      new_hbox_pack (
1854                           new_text_box_for_int (\%pr::win, 'plug_w'),
1855                           new_text_box_for_int (\%pr::win, 'plug_h')),
1856                      _('Plugins window'), 'not-packed')
1857            );
1858 }
1859
1860 sub new_winpos_subpage_misc() {
1861     return new_vbox_pack (
1862                 new_subpage_frame (
1863                      new_hbox_pack (
1864                           new_text_box_for_int (\%pr::win, 'logw_w'),
1865                           new_text_box_for_int (\%pr::win, 'logw_h')),
1866                      _('Log window'), 'not-packed'),
1867                 new_subpage_frame (
1868                      new_hbox_pack (
1869                           new_text_box_for_int (\%pr::win, 'prin_w'),
1870                           new_text_box_for_int (\%pr::win, 'prin_h')),
1871                      _('Print preview window'), 'not-packed'),
1872                 new_subpage_frame (
1873                      new_hbox_pack (
1874                           new_text_box_for_int (\%pr::win, 'sour_w'),
1875                           new_text_box_for_int (\%pr::win, 'sour_h')),
1876                      _('View source window'), 'not-packed')
1877            );
1878 }
1879
1880 sub new_winpos_page() {
1881     my $winbook = Gtk2::Notebook->new;
1882     $winbook->set_tab_pos ('right');
1883     $winbook->append_page (new_winpos_subpage_main, _('Main'));
1884     $winbook->append_page (new_winpos_subpage_msgs, _('Message'));
1885     $winbook->append_page (new_winpos_subpage_sendrecv, _('Send/Receive'));
1886     $winbook->append_page (new_winpos_subpage_fold, _('Folder'));
1887     $winbook->append_page (new_winpos_subpage_addrbook, _('Addressbook'));
1888     $winbook->append_page (new_winpos_subpage_accounts, _('Accounts'));
1889     $winbook->append_page (new_winpos_subpage_filtering, _('Filtering'));
1890     $winbook->append_page (new_winpos_subpage_prefs, _('Preferences'));
1891     $winbook->append_page (new_winpos_subpage_misc, _('Other'));
1892     return $winbook;
1893 }
1894
1895 # version info
1896 sub print_version() {
1897     print $xl::s{about_title} . "\n";
1898     print $xl::s{about_version} . " $VERSION\n";
1899     print "Perl-GLib " . $Glib::VERSION;
1900     # version info stuff appeared in 1.040
1901     if ($Glib::VERSION >= 1.040) {
1902         print _(", built for ") . join(".", Glib->GET_VERSION_INFO) 
1903               . _(", running with ") . join(".", &Glib::major_version, 
1904               &Glib::minor_version, &Glib::micro_version);
1905     }
1906     print "\n";
1907     print "Perl-GTK2 " . $Gtk2::VERSION;
1908     if ($Gtk2::VERSION >= 1.040) {
1909         print _(", built for ") . join(".", Gtk2->GET_VERSION_INFO)
1910               . _(", running with ") . join(".", &Gtk2::major_version, 
1911               &Gtk2::minor_version, &Gtk2::micro_version);
1912     }
1913     print "\n";
1914     my $clawsver = ($CLAWSV eq "") ? 
1915                 _("was not found!") : 
1916                 (_("returned version ") . $CLAWSV);
1917     print "Claws Mail " . $clawsver . "\n";
1918 }
1919
1920 # the command line help
1921 sub print_help() {
1922     my $line = '-' x length ($xl::s{about_title}) . "\n";
1923     print $line;
1924     print $xl::s{about_title} . "\n";
1925     print $line;
1926     print _("Syntax:\n");
1927     print _("  clawsker [options]\n");
1928     print _("Options:\n");
1929     print _("  -h|--help                        Prints this help screen.\n");
1930     print _("  -v|--version                     Prints version infos.\n");
1931     print _("  -b|--verbose                     More messages on standard output.\n");
1932     print _("  -a|--alternate-config-dir <dir>  Uses <dir> as Claws Mail config dir.\n");
1933     print _("  -c|--clawsrc <file>              Uses <file> as full resource name.\n");
1934 }
1935
1936 sub parse_command_line {
1937     my $cont = TRUE;
1938     $CLAWSV = get_claws_version ();
1939     eval {
1940         GetOptions('h|help' => sub { print_help (); $cont = FALSE },
1941             'v|version' => sub { print_version (); $cont = FALSE },
1942             'b|verbose' => sub { $VERBOSE = TRUE },
1943             'u|use-claws-version=s' => \&opt_use_claws_version,
1944             'a|alternate-config-dir=s' => \&opt_alternate_config_dir,
1945             'r|clawsrc=s' => \&opt_clawsrc)
1946         or die _("try -h or --help for syntax.\n");
1947     };
1948     if ($@) {
1949         my $msg = _("Error in options: {msg}\n", msg => $@);
1950         if (defined $ENV{'DISPLAY'} and $ENV{'DISPLAY'} ne '') {
1951             eval { Gtk2->init };
1952             error_dialog ($msg) unless $@;
1953         }
1954         die $msg;
1955     }
1956     return $cont;
1957 }
1958
1959 sub opt_use_claws_version {
1960     my ($name, $value) = @_;
1961     die _("Error: {opt} requires a dotted numeric value argument\n", opt => $name)
1962         unless ($value =~ /^[\d\.]+$/);
1963     $CLAWSV = $value;
1964 }
1965
1966 sub opt_alternate_config_dir {
1967     my ($name, $value) = @_;
1968     die _("Error: '{dir}' is not a directory or does not exist\n", dir => $value)
1969         unless -d $value;
1970     $CONFIGDIR = $value;
1971     $CONFIGDIR .= "/" unless ($CONFIGDIR =~ /.*\/$/);
1972     $ALTCONFIGDIR = TRUE;
1973 }
1974
1975 sub opt_clawsrc {
1976     my ($name, $value) = @_;
1977     die _("Error: '{value}' is not a file or does not exist\n", value => $value)
1978         unless -f $value;
1979     set_rc_filename ($value);
1980 }
1981
1982 # update the hidden preferences status from loaded values
1983 sub init_hidden_preferences {
1984     foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth, \%pr::win) {
1985         foreach my $key (keys %$hash) { 
1986             $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
1987         }
1988     }
1989     return TRUE;
1990 }
1991
1992 # load current status from disc
1993 sub load_preferences {
1994     my $rc = get_rc_filename ();
1995     log_message ("Loading preferences from $rc\n");
1996     return FALSE unless check_rc_file ($rc);
1997     return FALSE unless check_claws_not_running ();
1998     open (RCF, "<$rc");
1999     while (<RCF>) {
2000         chomp;
2001         if (/^([8a-z_]+)=(.*)$/) {
2002             $PREFS{$1} = decode('UTF-8', $2);
2003         }
2004     }
2005     close (RCF);
2006     return TRUE;
2007 }
2008
2009 # save current preferences to disc
2010 sub save_preferences {
2011     my $rc = get_rc_filename ();
2012     log_message ("Saving preferences to $rc\n");
2013     return FALSE unless check_rc_file ($rc);
2014     return FALSE unless check_claws_not_running ();
2015     my $rcbak = "$rc.backup";
2016     rename ($rc, $rcbak);
2017     open (RCF, ">$rc");
2018     open (RCB, "<$rcbak");
2019     while (<RCB>) {
2020         chomp;
2021         if (/^([8a-z_]+)=(.*)$/) {
2022             if (defined($HPVALUE{$1})) {
2023                 print RCF $1 . "=" . $HPVALUE{$1} . "\n";
2024             }
2025             else {
2026                 print RCF $_ . "\n";
2027             }
2028         }
2029         else {
2030             print RCF $_ . "\n";
2031         }
2032     }
2033     close (RCB);
2034     close (RCF);
2035     return TRUE;
2036 }
2037
2038 # create notebook
2039 sub new_notebook {
2040     my $nb = Gtk2::Notebook->new;
2041     # 
2042     $nb->append_page (new_behaviour_page (), $xl::s{tab_behaviour});
2043     $nb->append_page (new_colours_page (), $xl::s{tab_colours});
2044     $nb->append_page (new_gui_page (), $xl::s{tab_gui});
2045     $nb->append_page (new_other_page (), $xl::s{tab_other});
2046     $nb->append_page (new_winpos_page (), $xl::s{tab_winpos});
2047
2048     return $nb;
2049 }
2050
2051 # create an about dialog
2052 sub new_about_dialog {
2053     my ($parent) = @_;
2054     my $title = $xl::s{about_title};
2055     my $lic = $xl::s{about_license};
2056     my $vers = $xl::s{about_version} . " $VERSION";
2057     my $license = 
2058 "This program is free software: you can redistribute it and/or modify
2059 it under the terms of the GNU General Public License as published by
2060 the Free Software Foundation, either version 3 of the License, or
2061 (at your option) any later version.
2062
2063 This program is distributed in the hope that it will be useful,
2064 but WITHOUT ANY WARRANTY; without even the implied warranty of
2065 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2066 GNU General Public License for more details.
2067
2068 You should have received a copy of the GNU General Public License
2069 along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
2070     my $year = "2007-2015";
2071     my $holder = "Ricardo Mones &lt;ricardo\@mones.org&gt;";
2072     my $url = "http://www.claws-mail.org/clawsker.php";
2073
2074     my $dialog = Gtk2::MessageDialog->new_with_markup ($parent, 
2075                     [qw/modal destroy-with-parent/], 
2076                     'info', 'close', 
2077                     "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
2078                     . "<span size=\"large\">$vers</span>\n\n"
2079                     . "<span color=\"blue\" size=\"large\">$url</span>\n\n"
2080                     . "<span>Copyright $year by $holder</span>\n\n"
2081                     . "<span size=\"large\">$lic</span>\n\n"
2082                     . "<span size=\"small\">$license</span>");
2083     $dialog->set_title ($xl::s{about});
2084     #
2085     return $dialog;
2086 }
2087
2088 # create buttons box
2089 sub new_button_box {
2090     my ($parent, $adlg) = @_;
2091     my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
2092     my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
2093     my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
2094     # disable button until is really implemented
2095     # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
2096     my $hbox = Gtk2::HBox->new (FALSE, 5);
2097     # signal handlers 
2098     $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
2099     $b_apply->signal_connect (clicked => sub { save_preferences ($parent) });
2100     # $b_undo->signal_connect (clicked => sub { undo_current_changes });
2101     $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
2102     # package them
2103     $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
2104     $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
2105     # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
2106     $hbox->pack_start ($b_about, FALSE, FALSE, 0);
2107     #
2108     return $hbox;
2109 }
2110
2111 # initialise
2112 exit unless parse_command_line ();
2113 Gtk2->init;
2114 $main_window = Gtk2::Window->new ('toplevel');
2115 exit unless load_preferences ();
2116 exit unless init_hidden_preferences ();
2117 # create main GUI
2118 my $box = Gtk2::VBox->new (FALSE, 5);
2119 $box->set_border_width(3);
2120 my $about = new_about_dialog ();
2121 $box->pack_start (new_notebook (), FALSE, FALSE, 0);
2122 $box->pack_end (new_button_box ($main_window, $about), FALSE, FALSE, 0);
2123 $main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
2124 $main_window->set_title ($xl::s{win_title});
2125 $main_window->add ($box);
2126 $main_window->show_all;
2127 Gtk2->main;
2128