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