Fix use of undefined value
[clawsker.git] / clawsker
index 6a03c5da465c63d53904bb1403f5d0b5f21eb02e..497b42aed8277b3de5b3fee6c9db7c93de865cf3 100755 (executable)
--- a/clawsker
+++ b/clawsker
 #!/usr/bin/perl -w
 #
-# $Id$
+# Clawsker :: A Claws Mail Tweaker
+# Copyright 2007-2016 Ricardo Mones <ricardo@mones.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# See COPYING file for license details.
+# See AUTHORS file for a complete list of contributors.
 #
 
-=pod
-
-=head1 NAME
-
-Clawsker - A Claws Mail Tweaker
-
-=head1 SYNOPSIS
-
-clawsker [options]
-
-=head1 DESCRIPTION
-
-Clawsker is an applet to edit the so called Claws Mail hidden preferences.
-
-Claws Mail is a fast, lightweight and feature-rich MUA with a high number 
-of configurable options. To keep the binary small and fast some of these 
-preferences which not widely used are not provided with a graphical interface 
-for inspection and/or modification.
-
-Users wanting to edit such preferences had to face raw edition of their 
-configuration files, now you can do it with a convenient GTK2 interface
-using Clawsker.
-
-=head1 OPTIONS
-
-No options are currently available.
-
-=head1 LIMITATIONS
-
-Alternate configuration directories are not (yet) supported.
-
-=head1 AUTHOR
-
-Ricardo Mones E<lt>ricardo@mones.orgE<gt>
-
-=head1 LICENSE
-
-Copyright (c) 2007 by Ricardo Mones
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see E<lt>http://www.gnu.org/licenses/E<gt>.
-
-=cut
+binmode STDOUT, ":encoding(utf8)";
 
+use 5.010_000;
 use strict;
+use utf8;
+use Glib qw(TRUE FALSE);
+use Gtk2;
 use POSIX qw(setlocale);
 use Locale::gettext;
-use Glib qw(TRUE FALSE);
-use Gtk2 -init;
+use Encode;
+use Digest::MD5 qw(md5_hex);
+use Getopt::Long;
 
 my $NAME = 'clawsker';
 my $PREFIX = '@PREFIX@';
 my $LIBDIR = '@LIBDIR@';
+my $DATADIR = '@DATADIR@';
 my $VERSION = '@VERSION@';
+my $VERBOSE = FALSE;
+my $CLAWSV = undef;
+my $main_window = undef;
 
 my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
-setlocale(LC_ALL, $locale);
-bindtextdomain(lc($NAME), sprintf('%s/share/locale', $PREFIX));
-textdomain(lc($NAME));
+$locale = "C" unless defined($locale);
+setlocale (LC_ALL, $locale);
+bindtextdomain ($NAME, sprintf ('%s/share/locale', $PREFIX));
+textdomain ($NAME);
+
+my $SHOWHINTS = FALSE;
+$SHOWHINTS = TRUE if ($Gtk2::VERSION >= 1.040 and Gtk2->CHECK_VERSION (2, 12, 0));
 
 sub _ {
     my $str = shift;
     my %par = @_;
-    my $xla = gettext($str);
+    my $xla = gettext ($str);
     if (scalar(keys(%par)) > 0) {
         foreach my $key (keys %par) {
             $xla =~ s/\{$key\}/$par{$key}/g;
         }
     }
-    return $xla;
+    return decode_utf8($xla);
 }
 
 # default messages
 %xl::s = (
     win_title => _('Claws Mail Hidden Preferences'),
     about => _('About...'),
-    about_title => _('Clawsker ~ A Claws Mail Tweaker'),
+    about_title => _('Clawsker :: A Claws Mail Tweaker'),
     about_license => _('License:'),
+    about_version => _('Version:'),
 
     tab_colours => _('Colours'),
     tab_behaviour => _('Behaviour'),
     tab_gui => _('GUI'),
     tab_other => _('Other'),
+    tab_winpos => _('Windows'),
 
     ab_frame => _('Addressbook'),
     mem_frame => _('Memory'),
-    msgview_frame => _('Message view'),
+    msgview_frame => _('Message View'),
     log_frame => _('Log window'),
-
-    l_oth_use_dlg => _('Use address book dialog'),
-    h_oth_use_dlg => _('If true use a separate dialogue to edit a person\'s details. Otherwise will use a form embedded in the addressbook\'s main window.'),
-    l_oth_max_use => _('Maximum memory for message cache (Kb)'),
-    h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kB.'),
+    dnd_frame => _('Drag \'n\' drop'),
+    ssl_frame => _('Secure Sockets Layer'),
+    msgs_frame => _('Messages'),
+    swc_frame => _('Completion'),
+    stripes_frame => _('Coloured stripes'),
+    sbar_frame => _('Scroll bars'),
+    mlist_frame => _('Message List'),
+    mview_frame => _('Message View'),
+    compo_frame => _('Compose window'),
+    netm_frame => _('NetworkManager'),
+    diff_frame => _('Viewing patches'),
+    mpass_frame => _('Master passphrase'),
+
+    l_oth_use_dlg => _('Use detached address book edit dialogue'),
+    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.'),
+    l_oth_max_use => _('Maximum memory for message cache (kB)'),
+    h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kilobytes.'),
     l_oth_min_time => _('Minimun time for cache elements (minutes)'),
     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.'),
+    l_oth_use_netm => _('Use NetworkManager'),
+    h_oth_use_netm => _('Use NetworkManager to switch offline automatically.'),
+    l_oth_mp_rounds => _('Rounds for PBKDF2 function'),
+    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.'),
     
     l_gui_b_unread => _('Show unread messages with bold font'),
     h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
-    l_gui_no_markup => _('Don\'t use markup in compose window'),
+    l_gui_no_markup => _('Don\'t use markup'),
     h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
-    l_gui_dot_lines => _('Use dotted lines in tree views'),
-    h_gui_dot_lines => _('Use the old dotted line look in the main window tree views (folder and message lists) instead of the modern lineless look.'),
+    l_gui_dot_lines => _('Use dotted lines in tree view components'),
+    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.'),
     l_gui_h_scroll => _('Enable horizontal scrollbar'),
     h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
-    l_gui_swp_from => _('Swap From field in Sent folder'),
-    h_gui_swp_from => _('Display the sender\'s email address in the To column of the Sent folder instead of the recipient\'s.'),
-    l_gui_v_scroll => _('Folder list scrollbar behaviour'),
+    l_gui_swp_from => _('Display To column instead From column in Sent folder'),
+    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.'),
+    l_gui_v_scroll => _('Folder List scrollbar behaviour'),
     h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
     l_gui_v_scroll_show => _('Show always'),
     l_gui_v_scroll_auto => _('Automatic'),
     l_gui_v_scroll_hide => _('Hide always'),
-    l_gui_strip_off => _('Striped lines contrast'),
+    l_gui_from_show => _('From column displays'),
+    h_gui_from_show => _('Selects the data displayed in the From column of the Message List: name, address or both.'),
+    l_gui_from_show_name => _('Name only'),
+    l_gui_from_show_addr => _('Address only'),
+    l_gui_from_show_both => _('Both name and address'),
+    l_gui_strip_off => _('Coloured lines contrast'),
     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.'),
-    l_gui_cursor_v => _('Cursor visible in message view'),
-    h_gui_cursor_v => _('Display the cursor in the message view.'),
+    l_gui_cursor_v => _('Show cursor'),
+    h_gui_cursor_v => _('Display the cursor in the Message View.'),
     l_gui_toolbar_d => _('Detachable toolbars'),
     h_gui_toolbar_d => _('Show handles in the toolbars.'),
-    l_gui_strip_all => _('Use stripes in tree view components'),
+    l_gui_strip_all => _('Use stripes in all tree view components'),
     h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
-    l_gui_strip_sum => _('Use stripes in summary view'),
-    h_gui_strip_sum => _('Enable alternately coloured lines in summary view and folder list'),
-
-    l_beh_hover_t => _('Drag and drop hover timeout (ms)'),
+    l_gui_strip_sum => _('Use stripes in Folder List and Message List'),
+    h_gui_strip_sum => _('Enable alternately coloured lines in Message List and Folder List.'),
+    l_gui_two_line_v => _('2 lines per Message List item in 3-column layout'),
+    h_gui_two_line_v => _('Spread Message List information over two lines when using the three column mode.'),
+    l_gui_margin_co => _('Show margin'),
+    h_gui_margin_co => _('Shows a small margin in the Compose View.'),
+    l_gui_mview_date => _('Don\'t display localized date'),
+    h_gui_mview_date => _('Toggles localization of date format in Message View.'),
+    l_gui_zero_char => _('Zero replacement character'),
+    h_gui_zero_char => _('Replaces \'0\' with the given character in Folder List.'),
+    l_gui_type_any => _('Editable headers'),
+    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.'),
+    l_gui_next_del => _('Select next message on delete'),
+    h_gui_next_del => _('When deleting a message, toggles between selecting the next one (newer message) or the previous one (older message).'),
+
+    l_beh_hover_t => _('Drag \'n\' drop hover timeout (ms)'),
     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.'),
-    l_beh_dangerous => _('Don\'t confirm deletions'),
+    l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
     h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
-    l_beh_flowed => _('Respect flowed format in messages'),
+    l_beh_flowed => _('Respect format=flowed in messages'),
     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.'),
     l_beh_parts_rw => _('Allow writable temporary files'),
     h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
     l_beh_skip_ssl => _('Don\'t check SSL certificates'),
     h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
-    l_beh_up_step => _('Progress update step (items)'),
+    l_beh_up_step => _('Progress bar update step (items)'),
     h_beh_up_step => _('Update stepping in progress bars.'),
-    l_beh_thread_a => _('Maximum age in threading by subject (days)'),
+    l_beh_thread_a => _('Maximum age when threading by subject (days)'),
     h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
     l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
     h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
-    l_beh_use_utf8 => _('Use UTF-8 in broken mails'),
+    l_beh_use_utf8 => _('Force UTF-8 for broken mails'),
     h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
-    l_beh_warn_dnd => _('Warning on drag and drop'),
+    l_beh_warn_dnd => _('Warn on drag \'n\' drop'),
     h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
-
-    l_col_emphasis => _('Emphasised X-Mailer colour'),
+    l_beh_out_ascii => _('Outgoing messages fallback to ASCII'),
+    h_beh_out_ascii => _('If content allows, ASCII will be used to encode outgoing messages, otherwise the user-defined encoding is enforced always.'),
+    l_beh_pp_unsel => _('Primary paste unselects selection'),
+    h_beh_pp_unsel => _('Controls how pasting using middle-click changes the selected text and insertion point.'),
+    l_beh_inline_at => _('Show inline attachments'),
+    h_beh_inline_at => _('Allows hiding inline attachments already shown in mail structure view.'),
+    l_beh_addr_swc => _('Address search in compose window matches any'),
+    h_beh_addr_swc => _('On Tab-key completion, address text will match any part of the string or only from the start.'),
+    l_beh_fold_swc => _('Folder search in folder selector matches any'),
+    h_beh_fold_swc => _('On folder name completion text will match any part of the string or only from the start.'),
+
+    l_col_emphasis => _('X-Mailer header'),
     h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
-    l_col_log_err => _('Errors colour'),
+    l_col_log_err => _('Error messages'),
     h_col_log_err => _('Colour for error messages in log window.'),
-    l_col_log_in => _('Input colour'),
-    h_col_log_in => _('Colour for input messages in log window.'),
-    l_col_log_msg => _('Messages colour'),
+    l_col_log_in => _('Server messages'),
+    h_col_log_in => _('Colour for messages received from servers in log window.'),
+    l_col_log_msg => _('Standard messages'),
     h_col_log_msg => _('Colour for messages in log window.'),
-    l_col_log_out => _('Output colour'),
-    h_col_log_out => _('Colour for output messages in log window.'),
-    l_col_log_warn => _('Warnings colour'),
+    l_col_log_out => _('Client messages'),
+    h_col_log_out => _('Colour for messages sent to servers in log window.'),
+    l_col_log_warn => _('Warnings'),
     h_col_log_warn => _('Colour for warning messages in log window.'),
 
+    l_col_diff_add => _('Added lines'),
+    h_col_diff_add => _('Colour for added lines in patches.'),
+    l_col_diff_del => _('Deleted lines'),
+    h_col_diff_del => _('Colour for deleted lines in patches.'),
+    l_col_diff_hunk => _('Hunk lines'),
+    h_col_diff_hunk => _('Color for hunk headers in patches.'),
+
+    l_win_x => _('X position'),
+    h_win_x => _('X coordinate for window\'s top-left corner.'),
+    l_win_y => _('Y position'),
+    h_win_y => _('Y coordinate for window\'s top-left corner.'),
+    l_win_w => _('Width'),
+    h_win_w => _('Window\'s width in pixels.'),
+    l_win_h => _('Height'),
+    h_win_h => _('Window\'s height in pixels.'),
+
+    l_win_main_mx => _('Maximized'),
+    h_win_main_mx => _('Changes window maximized status.'),
+    l_win_main_fs => _('Full-screen'),
+    h_win_main_fs => _('Changes full screen status.'),
+
     e_error => _('Error: '),
-    e_noclawsrc => _('no $HOME/.claws-mail/clawsrc file found.'),
+    e_noclawsrc => _('resource file for Claws Mail was not found.'),
     e_running => _('seems Claws Mail is currently running, close it first.'),
 );
 
-# check if claws is running
-my $socket = "/tmp/claws-mail-$<";
--S $socket and die "$xl::s{e_error}$xl::s{e_running}\n";
-
 # all preferences read by load_preferences
 my %PREFS = ();
 # values of all preferences handled by clawsker
 my %HPVALUE = ();
+# default config dir and file name
+my $ALTCONFIGDIR = FALSE;
+my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
+my $CONFIGRC = 'clawsrc';
 
 # index constants for preference arrays
 use constant NAME  => 0; # the name on the rc file
 use constant LABEL => 1; # the label on the GUI
 use constant DESC  => 2; # the description for the hint/help
 use constant TYPE  => 3; # data type: bool, int, float, string, color
-use constant GUI   => 4; # GUI element
+use constant CMVER => 4; # lowest[,highest] Claws Mail version(s) the feature exists
+use constant CMDEF => 5; # default value for the preference in Claws Mail
+use constant GUI   => 6; # GUI element
+
+# constants for GUI spacing
+use constant HBOX_SPC => 5;
+use constant FRAME_SPC => 2;
+use constant PAGE_SPC => 5;
+
+# version functions
+
+sub version_greater_or_equal {
+    my ($version, $refvers) = @_;
+    my @version = split (/\./, $version);
+    my @refvers = split (/\./, $refvers);
+    while ($#version < $#refvers) {
+        push (@version, '0');
+    }
+    my $idx = 0;
+    while (($idx <= $#refvers) 
+            and (int ($version[$idx]) == int ($refvers[$idx]))) {
+        ++$idx;
+    }
+    return TRUE if (($idx > $#refvers)
+        or (int ($version[$idx]) >= int ($refvers[$idx])));
+    return FALSE;
+}
+
+sub get_claws_version {
+    my @cmbin = (
+        'claws-mail',
+    );
+    my $res = "";
+    foreach my $bin (@cmbin) {
+        $_ = qx/which $bin/;
+        chomp;
+        last if ($_ ne "");
+    }
+    return "" unless ($_); # not installed
+    $_ = qx/$_ -v/;
+    chomp;
+    my @fver = split (/ /);
+    die "Invalid version string" unless ($fver[2] eq "version");
+    my @ver = split (/\./, $fver[3]);
+    $res .= "$ver[0].";
+    $res .= "$ver[1].";
+    if ($ver[2] =~ /(\d+)git(\d+)/) {
+        $res .= "$1.$2";
+    }
+    else {
+        $res .= "$ver[2].0";
+    }
+    return $res;
+}
 
 # data handlers and auxiliar functions
 
@@ -204,7 +293,7 @@ sub handle_int_value {
     s/\s+$//;
     if (/^[0-9]+$/) {
         $$dataref = $_;
-       $widget->set_text ($_);
+        $widget->set_text ($_);
     }
     else {
         $widget->set_text ($$dataref);
@@ -216,6 +305,13 @@ sub handle_string_value {
     $$dataref = $widget->get_text ();
 }
 
+sub handle_nchar_value {
+    my ($widget, $event, $dataref, $minlen) = @_;
+    $_ = substr ($widget->get_text (), 0, $minlen);
+    $widget->set_text ($_);
+    $$dataref = $_;
+}
+
 sub gdk_color_from_str {
     my ($str) = @_;
     my ($rr, $gg, $bb) = (0, 0 ,0);
@@ -241,7 +337,7 @@ sub str_from_gdk_color {
 sub handle_color_value {
     my ($widget, $event, $dataref) = @_;
     my $newcol = $widget->get_color;
-    $$dataref = &str_from_gdk_color ($newcol);
+    $$dataref = str_from_gdk_color ($newcol);
 }
 
 sub handle_selection_value {
@@ -249,6 +345,93 @@ sub handle_selection_value {
     $$dataref = $widget->get_active;
 }
 
+sub get_rc_filename {
+    return $CONFIGDIR . $CONFIGRC;
+}
+
+sub set_rc_filename {
+    my ($fullname) = @_;
+    my @parts = split ('/', $fullname);
+    $CONFIGRC = $parts[$#parts];
+    $parts[$#parts] = '';
+    $CONFIGDIR = join ('/', @parts);
+}
+
+sub log_message {
+    my ($mesg, $fatal) = @_;
+    if (defined($fatal) && $fatal eq 'die') {
+        die "$NAME: $mesg\n";
+    }
+    if ($VERBOSE) {
+        print "$NAME: $mesg\n";
+    }
+}
+
+sub error_dialog {
+    my ($emsg) = @_;
+    my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
+    my $errordlg = Gtk2::MessageDialog->new_with_markup ($main_window, 'modal', 'error', 'cancel', $markup);
+    $errordlg->set_title (_('Clawsker error'));
+    $errordlg->run;
+    $errordlg->destroy;
+}
+
+sub claws_is_running {
+    my $emsg = "$xl::s{e_error}$xl::s{e_running}";
+    log_message ($emsg);
+    error_dialog ($emsg);
+    return FALSE;
+}
+
+sub check_claws_not_running {
+    my $tmpdir = (defined $ENV{TMPDIR})? $ENV{TMPDIR}: '/tmp';
+    $tmpdir = '/tmp' if ($tmpdir eq '');
+    my $socket = (not $ALTCONFIGDIR)? $tmpdir: $CONFIGDIR;
+    $socket .= "/claws-mail-$<";
+    -S $socket and return claws_is_running ();
+    # since 3.9.0cvs36
+    my $lockdir = "$tmpdir/claws-mail-$<";
+    -d $lockdir and do { 
+       $_ = $CONFIGDIR;
+       s/\/$//;
+        $socket = "$lockdir/" . md5_hex ($_);
+       -S $socket and return claws_is_running ();
+    };
+    return TRUE;
+}
+
+sub check_rc_file {
+    my ($rcfile) = @_;
+    (defined($rcfile) && -f $rcfile) or do {
+        my $emsg = "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
+        log_message ($emsg);
+        error_dialog ($emsg);
+        return FALSE;
+    };
+    return TRUE;
+}
+
+sub set_widget_hint {
+    if ($SHOWHINTS) {
+        my ($wdgt, $hint) = @_;    
+        $wdgt->set_tooltip_text ($hint);
+        $wdgt->set_has_tooltip (TRUE);
+    }
+}
+
+sub set_widget_sens {
+    my ($wdgt, $versions) = @_;
+    my @ver = split(/,/, $versions);
+    if ($#ver == 1) {
+      $wdgt->set_sensitive (
+        version_greater_or_equal ($CLAWSV, $ver[0])
+        and version_greater_or_equal ($ver[1], $CLAWSV)
+      );
+    } else {
+        $wdgt->set_sensitive (version_greater_or_equal ($CLAWSV, $ver[0]));
+    }
+}
+
 # graphic element creation 
 
 sub new_check_button_for {
@@ -256,33 +439,73 @@ sub new_check_button_for {
     my $name = $$hash{$key}[NAME];
     my $label = $$hash{$key}[LABEL];
     #
+    my $hbox = Gtk2::HBox->new (FALSE, 5);
     my $cb = Gtk2::CheckButton->new ($label);
     $$hash{$key}[GUI] = $cb;
-    $cb->set_active ($HPVALUE{$name} eq '1');
+    if (defined ($HPVALUE{$name})) {
+        $cb->set_active ($HPVALUE{$name} eq '1');
+    }
     $cb->signal_connect (clicked => sub {
             my ($w, $e) = @_;
-           &handle_bool_value($w, $e, \$HPVALUE{$name});
+            handle_bool_value ($w, $e, \$HPVALUE{$name});
         });
+    set_widget_hint ($cb, $$hash{$key}[DESC]);
+    set_widget_sens ($cb, $$hash{$key}[CMVER]);
+    $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
     #
-    return $cb;
+    return $hbox;
 }
 
-sub new_text_box_for {
+sub new_text_box_for_int {
     my ($hash, $key) = @_;
     my $name = $$hash{$key}[NAME];
     my $label = $$hash{$key}[LABEL];
+    my @type = split (/,/, $$hash{$key}[TYPE]);
+    push (@type, 0), push (@type, 10000) unless ($#type > 0); 
     #
     my $hbox = Gtk2::HBox->new (FALSE, 5);
     my $glabel = Gtk2::Label->new ($label);
-    my $gentry = Gtk2::Entry->new;
+    my $pagei = int (($type[2] - $type[1]) / 10);
+    my $gentry = Gtk2::SpinButton->new_with_range ($type[1], $type[2], $pagei);
+    my $value = $HPVALUE{$name};
+    $value //= $type[1];
+    $gentry->set_numeric (TRUE);
+    $gentry->set_value ($value);
     $$hash{$key}[GUI] = $gentry;
-    $gentry->set_text($HPVALUE{$name});
-    $gentry->signal_connect(changed => sub {
+    $gentry->signal_connect('value-changed' => sub {
             my ($w, $e) = @_;
-           &handle_int_value($w, $e, \$HPVALUE{$name}); # FIXME int only
+            handle_int_value ($w, $e, \$HPVALUE{$name});
         });
-    $hbox->pack_start ($glabel, FALSE, FALSE, 0);
-    $hbox->pack_start ($gentry, FALSE, FALSE, 0);
+    set_widget_hint ($gentry, $$hash{$key}[DESC]);
+    set_widget_sens ($gentry, $$hash{$key}[CMVER]);
+    $glabel->set_sensitive ($gentry->sensitive);
+    $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
+    $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
+    #
+    return $hbox;
+}
+
+sub new_text_box_for_nchar {
+    my ($hash, $key) = @_;
+    my $name = $$hash{$key}[NAME];
+    my $label = $$hash{$key}[LABEL];
+    my @type = split (/,/, $$hash{$key}[TYPE]); # char,minlen,maxlen
+    my $hbox = Gtk2::HBox->new (FALSE, 5);
+    my $glabel = Gtk2::Label->new ($label);
+    my $gentry = Gtk2::Entry->new ();
+    $gentry->set_max_length($type[2]) if defined ($type[2]);
+    $gentry->set_width_chars(int ($type[2]) + 2) if defined ($type[2]);
+    $gentry->set_text ($HPVALUE{$name});
+    $$hash{$key}[GUI] = $gentry;
+    $gentry->signal_connect('key-release-event' => sub {
+            my ($w, $e) = @_;
+            handle_nchar_value ($w, $e, \$HPVALUE{$name}, $type[1]);
+        });
+    set_widget_hint ($gentry, $$hash{$key}[DESC]);
+    set_widget_sens ($gentry, $$hash{$key}[CMVER]);
+    $glabel->set_sensitive ($gentry->sensitive);
+    $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
+    $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
     #
     return $hbox;
 }
@@ -292,18 +515,22 @@ sub new_color_button_for {
     my $name = $$hash{$key}[NAME];
     my $label = $$hash{$key}[LABEL];
     #
-    my $col = &gdk_color_from_str ($HPVALUE{$name});
+    my $col = gdk_color_from_str ($HPVALUE{$name});
     my $hbox = Gtk2::HBox->new (FALSE, 5);
     my $glabel = Gtk2::Label->new ($label);
     my $button = Gtk2::ColorButton->new_with_color ($col);
     $$hash{$key}[GUI] = $button;
     $button->set_title ($label);
+    $button->set_relief ('none');
     $button->signal_connect ('color-set' => sub {
             my ($w, $e) = @_;
-           &handle_color_value($w, $e, \$HPVALUE{$name}); 
+            handle_color_value ($w, $e, \$HPVALUE{$name});
         });
-    $hbox->pack_start ($button, FALSE, FALSE, 0);
-    $hbox->pack_start ($glabel, FALSE, FALSE, 0);
+    set_widget_hint ($button, $$hash{$key}[DESC]);
+    set_widget_sens ($button, $$hash{$key}[CMVER]);
+    $glabel->set_sensitive ($button->sensitive);
+    $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
+    $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
     #
     return $hbox;
 }
@@ -324,62 +551,125 @@ sub new_selection_box_for {
     }
     $combo->signal_connect ('changed' => sub {
             my ($w, $e) = @_;
-           &handle_selection_value($w, $e, \$HPVALUE{$name});
+            handle_selection_value ($w, $e, \$HPVALUE{$name});
         });
     $combo->set_active ($HPVALUE{$name});
-    $hbox->pack_start ($glabel, FALSE, FALSE, 0);
-    $hbox->pack_start ($combo, FALSE, FALSE, 0);
+    set_widget_hint ($combo, $$hash{$key}[DESC]);
+    set_widget_sens ($combo, $$hash{$key}[CMVER]);
+    $glabel->set_sensitive ($combo->sensitive);
+    $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
+    $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
     #
     return $hbox;
 }
 
+# more graphic helpers
+
+sub new_hbox_pack {
+    my $hbox = Gtk2::HBox->new (FALSE, 5);
+    $hbox->set_border_width (PAGE_SPC);
+    foreach my $item (@_) {
+        $hbox->pack_start ($item, FALSE, FALSE, 0);
+    }
+    return $hbox;
+}    
+
+sub new_vbox_pack {
+    my $vbox = Gtk2::VBox->new (FALSE, 5);
+    $vbox->set_border_width (PAGE_SPC);
+    foreach my $item (@_) {
+        $vbox->pack_start ($item, FALSE, FALSE, 0);
+    }
+    return $vbox;
+}    
+
+sub new_vbox_pack_compact {
+    my $vbox = Gtk2::VBox->new (FALSE, 0);
+    $vbox->set_border_width (0);
+    foreach my $item (@_) {
+        $vbox->pack_start ($item, FALSE, FALSE, 0);
+    }
+    return $vbox;
+}    
+
+sub new_subpage_frame {
+    my ($box, $title, $notpacked) = @_;
+    my $frame = Gtk2::Frame->new ($title);
+    $frame->add ($box);    
+    return new_vbox_pack ($frame) unless defined ($notpacked);
+    return $frame;
+}
+
 # preference maps and corresponding page creation subs
 
 %pr::oth = ( # other preferences
     use_dlg => [ 
         'addressbook_use_editaddress_dialog',
-       $xl::s{l_oth_use_dlg},
+        $xl::s{l_oth_use_dlg},
         $xl::s{h_oth_use_dlg},
-       'bool',
-       undef,
+        'bool',
+        '2.7.0',
+        '0',
+        undef,
     ],
     max_use => [
-       'cache_max_mem_usage',
-       $xl::s{l_oth_max_use},
-       $xl::s{h_oth_max_use},
-       'int',
-       undef,
+        'cache_max_mem_usage',
+        $xl::s{l_oth_max_use},
+        $xl::s{h_oth_max_use},
+        'int,0,262144', # 0 Kb - 256 Mb
+        '0.0.0',
+        '4096',
+        undef,
     ],
     min_time => [
         'cache_min_keep_time',
-       $xl::s{l_oth_min_time},
-       $xl::s{h_oth_min_time},
-       'int',
-       undef,
+        $xl::s{l_oth_min_time},
+        $xl::s{h_oth_min_time},
+        'int,0,120', # 0 minutes - 2 hours
+        '0.0.0',
+        '15',
+        undef,
+    ],
+    use_netm => [
+        'use_networkmanager',
+        $xl::s{l_oth_use_netm},
+        $xl::s{h_oth_use_netm},
+        'bool',
+        '3.3.1',
+        '1',
+        undef,
+    ],
+    mp_rounds => [
+        'master_passphrase_pbkdf2_rounds',
+        $xl::s{l_oth_mp_rounds},
+        $xl::s{h_oth_mp_rounds},
+        'int,50000,1000000',
+        '3.13.2.110',
+        '50000',
+        undef,
     ],
 );
 
 sub new_other_page() {
-    my $of = Gtk2::VBox->new (FALSE, 5);
-
-    my $ab_frame = Gtk2::Frame->new ($xl::s{ab_frame}); 
-    my $cb_use_dlg = &new_check_button_for(\%pr::oth, 'use_dlg');
-    my $vb1 = Gtk2::VBox->new (FALSE, 5);
-    $vb1->pack_start ($cb_use_dlg, FALSE, FALSE, 0);
-    $ab_frame->add ($vb1);
-
-    my $mem_frame = Gtk2::Frame->new ($xl::s{mem_frame}); 
-    my $tb_max_use = &new_text_box_for(\%pr::oth, 'max_use');
-    my $tb_min_time = &new_text_box_for(\%pr::oth, 'min_time');
-    my $vb2 = Gtk2::VBox->new (FALSE, 5);
-    $vb2->pack_start ($tb_max_use, FALSE, FALSE, 0);
-    $vb2->pack_start ($tb_min_time, FALSE, FALSE, 0);
-    $mem_frame->add ($vb2);
-
-    $of->pack_start ($ab_frame, FALSE, FALSE, 0);
-    $of->pack_start ($mem_frame, FALSE, FALSE, 0);
-
-    return $of;
+    return new_vbox_pack (
+               new_subpage_frame (
+                   new_vbox_pack (
+                       new_check_button_for(\%pr::oth, 'use_dlg')),
+                   $xl::s{ab_frame}, 'not-packed'),
+               new_subpage_frame (
+                   new_vbox_pack (
+                       new_text_box_for_int(\%pr::oth, 'max_use'),
+                       new_text_box_for_int(\%pr::oth, 'min_time')),
+                   $xl::s{mem_frame}, 'not-packed'),
+               new_subpage_frame (
+                   new_vbox_pack (
+                       new_check_button_for(\%pr::oth, 'use_netm')),
+                   $xl::s{netm_frame}, 'not-packed'),
+               new_subpage_frame (
+                   new_vbox_pack (
+                       new_text_box_for_int(\%pr::oth, 'mp_rounds')),
+                   $xl::s{mpass_frame}, 'not-packed')
+           );
 }
 
 %pr::gui = ( # gui bells and whistles
@@ -387,107 +677,213 @@ sub new_other_page() {
         'bold_unread',
         $xl::s{l_gui_b_unread},
         $xl::s{h_gui_b_unread},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '1',
+        undef,
     ],
     no_markup => [
         'compose_no_markup',
         $xl::s{l_gui_no_markup},
         $xl::s{h_gui_no_markup},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     dot_lines => [
         'enable_dotted_lines',
         $xl::s{l_gui_dot_lines},
         $xl::s{h_gui_dot_lines},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0,3.7.10.44',
+        '0',
+        undef,
     ],
     h_scroll => [
         'enable_hscrollbar',
         $xl::s{l_gui_h_scroll},
         $xl::s{h_gui_h_scroll},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '1',
+        undef,
     ],
     swp_from => [
         'enable_swap_from',
         $xl::s{l_gui_swp_from},
         $xl::s{h_gui_swp_from},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     v_scroll => [
         'folderview_vscrollbar_policy',
         $xl::s{l_gui_v_scroll},
         $xl::s{h_gui_v_scroll},
-       '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
-       undef,
+        '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
+        '0.0.0',
+        '0',
+        undef,
+    ],
+    from_show => [
+        'summary_from_show',
+        $xl::s{l_gui_from_show},
+        $xl::s{h_gui_from_show},
+        '0=l_gui_from_show_name;1=l_gui_from_show_addr;2=l_gui_from_show_both',
+        '3.7.10',
+        '0',
+        undef,
     ],
     strip_off => [
         'stripes_color_offset',
-       $xl::s{l_gui_strip_off},
-       $xl::s{h_gui_strip_off},
-       'int',
-       undef,
+        $xl::s{l_gui_strip_off},
+        $xl::s{h_gui_strip_off},
+        'int,0,40000', # no idea what this number means
+        '0.0.0',
+        '4000',
+        undef,
     ],
     cursor_v => [
         'textview_cursor_visible',
         $xl::s{l_gui_cursor_v},
         $xl::s{h_gui_cursor_v},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     toolbar_d => [
         'toolbar_detachable',
         $xl::s{l_gui_toolbar_d},
         $xl::s{h_gui_toolbar_d},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     strip_all => [
         'use_stripes_everywhere',
         $xl::s{l_gui_strip_all},
         $xl::s{h_gui_strip_all},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '1',
+        undef,
     ],
     strip_sum => [
         'use_stripes_in_summaries',
         $xl::s{l_gui_strip_sum},
         $xl::s{h_gui_strip_sum},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '1',
+        undef,
+    ],
+    two_linev => [
+        'two_line_vertical',
+        $xl::s{l_gui_two_line_v},
+        $xl::s{h_gui_two_line_v},
+        'bool',
+        '3.4.0.7',
+        '0',
+        undef,
+    ],
+    margin_co => [
+        'show_compose_margin',
+        $xl::s{l_gui_margin_co},
+        $xl::s{h_gui_margin_co},
+        'bool',
+        '3.7.6.7',
+        '0',
+        undef,
+    ],
+    mview_date => [
+        'msgview_date_format',
+        $xl::s{l_gui_mview_date},
+        $xl::s{h_gui_mview_date},
+        'bool',
+        '3.7.8.42',
+        '0',
+        undef,
+    ],
+    zero_char => [
+        'zero_replacement_char',
+        $xl::s{l_gui_zero_char},
+        $xl::s{h_gui_zero_char},
+        'char,1,1',
+        '2.8.1.77',
+        '0',
+        undef,
+    ],
+    type_any => [
+        'type_any_header',
+        $xl::s{l_gui_type_any},
+        $xl::s{h_gui_type_any},
+        'bool',
+        '3.12.0.44',
+        '0',
+        undef,
+    ],
+    next_del => [
+        'next_on_delete',
+        $xl::s{l_gui_next_del},
+        $xl::s{h_gui_next_del},
+        'bool',
+        '3.13.0.5',
+        '0',
+        undef,
     ],
 );
 
 sub new_gui_page() {
     my $gf = Gtk2::VBox->new (FALSE, 5);
-
-    my $cb_b_unread = &new_check_button_for (\%pr::gui, 'b_unread');
-    my $cb_no_markup = &new_check_button_for (\%pr::gui, 'no_markup'); 
-    my $cb_dot_lines = &new_check_button_for (\%pr::gui, 'dot_lines'); 
-    my $cb_h_scroll = &new_check_button_for (\%pr::gui, 'h_scroll');
-    my $cb_swp_from = &new_check_button_for (\%pr::gui, 'swp_from');
-    my $cb_cursor_v = &new_check_button_for (\%pr::gui, 'cursor_v');
-    my $cb_toolbar_d = &new_check_button_for (\%pr::gui, 'toolbar_d');
-    my $cb_strip_all = &new_check_button_for (\%pr::gui, 'strip_all');
-    my $cb_strip_sum = &new_check_button_for (\%pr::gui, 'strip_sum');
-    my $sb_v_scroll = &new_selection_box_for (\%pr::gui, 'v_scroll');
-    my $tb_strip_off = &new_text_box_for (\%pr::gui, 'strip_off');
-
-    $gf->pack_start ($cb_b_unread, FALSE, FALSE, 0);
-    $gf->pack_start ($cb_no_markup, FALSE, FALSE, 0);
+    $gf->set_border_width (PAGE_SPC);
+
+    my $cb_dot_lines = new_check_button_for (\%pr::gui, 'dot_lines');
+    my $cb_toolbar_d = new_check_button_for (\%pr::gui, 'toolbar_d');
+    my $tb_zero_char = new_text_box_for_nchar (\%pr::gui, 'zero_char');
+
+    $gf->pack_start (new_subpage_frame (
+                         new_vbox_pack (
+                             new_check_button_for (\%pr::gui, 'strip_all'),
+                             new_check_button_for (\%pr::gui, 'strip_sum'),
+                             new_text_box_for_int (\%pr::gui, 'strip_off')),
+                         $xl::s{stripes_frame}, 'not-packed'),
+                     FALSE, FALSE, FRAME_SPC);
+    $gf->pack_start (new_subpage_frame (
+                         new_vbox_pack (
+                             new_check_button_for (\%pr::gui, 'b_unread'),
+                             new_check_button_for (\%pr::gui, 'swp_from'),
+                             new_check_button_for (\%pr::gui, 'two_linev'),
+                             new_check_button_for (\%pr::gui, 'next_del'),
+                             new_selection_box_for (\%pr::gui, 'from_show')),
+                         $xl::s{mlist_frame}, 'not-packed'), 
+                     FALSE, FALSE, FRAME_SPC);
+    $gf->pack_start (new_subpage_frame (
+                         new_hbox_pack (
+                             new_check_button_for (\%pr::gui, 'cursor_v'),
+                             new_check_button_for (\%pr::gui, 'mview_date')),
+                         $xl::s{mview_frame}, 'not-packed'), 
+                     FALSE, FALSE, FRAME_SPC);
+    $gf->pack_start (new_subpage_frame (
+                         new_hbox_pack (
+                             new_check_button_for (\%pr::gui, 'no_markup'),
+                             new_check_button_for (\%pr::gui, 'margin_co'),
+                             new_check_button_for (\%pr::gui, 'type_any')),
+                         $xl::s{compo_frame}, 'not-packed'), 
+                     FALSE, FALSE, FRAME_SPC);
     $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
-    $gf->pack_start ($cb_h_scroll, FALSE, FALSE, 0);
-    $gf->pack_start ($cb_swp_from, FALSE, FALSE, 0);
-    $gf->pack_start ($cb_cursor_v, FALSE, FALSE, 0);
     $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
-    $gf->pack_start ($cb_strip_all, FALSE, FALSE, 0);
-    $gf->pack_start ($cb_strip_sum, FALSE, FALSE, 0);
-    $gf->pack_start ($sb_v_scroll, FALSE, FALSE, 0);
-    $gf->pack_start ($tb_strip_off, FALSE, FALSE, 0);
+    $gf->pack_start (new_subpage_frame (
+                         new_vbox_pack (
+                             new_check_button_for (\%pr::gui, 'h_scroll'),
+                             new_selection_box_for (\%pr::gui, 'v_scroll')),
+                         $xl::s{sbar_frame}, 'not-packed'),
+                     FALSE, FALSE, FRAME_SPC);
+    $gf->pack_start ($tb_zero_char, FALSE, FALSE, 0);
+
     return $gf;
 }
 
@@ -496,98 +892,177 @@ sub new_gui_page() {
         'hover_timeout',
         $xl::s{l_beh_hover_t},
         $xl::s{h_beh_hover_t},
-       'int',
-       undef,
+        'int,100,3000', # 0.1 seconds - 3 seconds
+        '0.0.0',
+        '500',
+        undef,
     ],
     dangerous => [
         'live_dangerously',
         $xl::s{l_beh_dangerous},
         $xl::s{h_beh_dangerous},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     flowed => [
         'respect_flowed_format',
         $xl::s{l_beh_flowed},
         $xl::s{h_beh_flowed},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     parts_rw => [
         'save_parts_readwrite',
         $xl::s{l_beh_parts_rw},
         $xl::s{h_beh_parts_rw},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     skip_ssl => [
         'skip_ssl_cert_check',
         $xl::s{l_beh_skip_ssl},
         $xl::s{h_beh_skip_ssl},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     up_step => [
         'statusbar_update_step',
         $xl::s{l_beh_up_step},
         $xl::s{h_beh_up_step},
-       'int',
-       undef,
+        'int,1,200', # 1 item - 200 items
+        '0.0.0',
+        '10',
+        undef,
     ],
     thread_a => [
         'thread_by_subject_max_age',
         $xl::s{l_beh_thread_a},
         $xl::s{h_beh_thread_a},
-       'int',
-       undef,
+        'int,1,30', # 1 day - 30 days
+        '0.0.0',
+        '10',
+        undef,
     ],
     unsafe_ssl => [
         'unsafe_ssl_certs',
         $xl::s{l_beh_unsafe_ssl},
         $xl::s{h_beh_unsafe_ssl},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     use_utf8 => [
         'utf8_instead_of_locale_for_broken_mail',
         $xl::s{l_beh_use_utf8},
         $xl::s{h_beh_use_utf8},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
     ],
     warn_dnd => [
         'warn_dnd',
         $xl::s{l_beh_warn_dnd},
         $xl::s{h_beh_warn_dnd},
-       'bool',
-       undef,
+        'bool',
+        '0.0.0',
+        '1',
+        undef,
+    ],
+    out_ascii => [
+        'outgoing_fallback_to_ascii',
+        $xl::s{l_beh_out_ascii},
+        $xl::s{h_beh_out_ascii},
+        'bool',
+        '3.4.0.37',
+        '1',
+        undef,
+    ],
+    pp_unsel => [
+        'primary_paste_unselects',
+        $xl::s{l_beh_pp_unsel},
+        $xl::s{h_beh_pp_unsel},
+        'bool',
+        '3.6.1.35',
+        '0',
+        undef,
+    ],
+    inline_at => [
+        'show_inline_attachments',
+        $xl::s{l_beh_inline_at},
+        $xl::s{h_beh_inline_at},
+        'bool',
+        '3.7.8.48',
+        '1',
+        undef,
+    ],
+    addr_swc => [
+        'address_search_wildcard',
+        $xl::s{l_beh_addr_swc},
+        $xl::s{h_beh_addr_swc},
+        'bool',
+        '3.9.3.18',
+        '0',
+        undef,
+    ],
+    fold_swc => [
+        'folder_search_wildcard',
+        $xl::s{l_beh_fold_swc},
+        $xl::s{h_beh_fold_swc},
+        'bool',
+        '3.9.3.18',
+        '0',
+        undef,
     ],
 );
 
 sub new_behaviour_page() {
     my $bf = Gtk2::VBox->new (FALSE, 5);
-  
-    my $tb_hoover_t = &new_text_box_for (\%pr::beh, 'hover_t');
-    my $tb_up_step = &new_text_box_for (\%pr::beh, 'up_step');
-    my $tb_thread_a = &new_text_box_for (\%pr::beh, 'thread_a');
-    my $cb_dangerous = &new_check_button_for (\%pr::beh, 'dangerous');
-    my $cb_flowed = &new_check_button_for (\%pr::beh, 'flowed');
-    my $cb_parts_rw = &new_check_button_for (\%pr::beh, 'parts_rw');
-    my $cb_skip_ssl = &new_check_button_for (\%pr::beh, 'skip_ssl');
-    my $cb_unsafe_ssl = &new_check_button_for (\%pr::beh, 'unsafe_ssl');
-    my $cb_use_utf8 = &new_check_button_for (\%pr::beh, 'use_utf8');
-    my $cb_warn_dnd = &new_check_button_for (\%pr::beh, 'warn_dnd');
-
-    $bf->pack_start ($tb_hoover_t, FALSE, FALSE, 0);
+    $bf->set_border_width (PAGE_SPC);
+
+    my $tb_up_step = new_text_box_for_int (\%pr::beh, 'up_step');
+    my $tb_thread_a = new_text_box_for_int (\%pr::beh, 'thread_a');
+
+    $bf->pack_start (new_subpage_frame (
+                         new_vbox_pack (
+                             new_text_box_for_int (\%pr::beh, 'hover_t'),
+                             new_check_button_for (\%pr::beh, 'warn_dnd')),
+                         $xl::s{dnd_frame}, 'not-packed'), 
+                     FALSE, FALSE, FRAME_SPC);
+    $bf->pack_start (new_subpage_frame (
+                         new_hbox_pack (
+                             new_check_button_for (\%pr::beh, 'skip_ssl'),
+                             new_check_button_for (\%pr::beh, 'unsafe_ssl')),
+                         $xl::s{ssl_frame}, 'not-packed'),
+                     FALSE, FALSE, FRAME_SPC);
     $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
     $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
-    $bf->pack_start ($cb_dangerous, FALSE, FALSE, 0);
-    $bf->pack_start ($cb_flowed, FALSE, FALSE, 0);
-    $bf->pack_start ($cb_parts_rw, FALSE, FALSE, 0);
-    $bf->pack_start ($cb_skip_ssl, FALSE, FALSE, 0);
-    $bf->pack_start ($cb_unsafe_ssl, FALSE, FALSE, 0);
-    $bf->pack_start ($cb_use_utf8, FALSE, FALSE, 0);
-    $bf->pack_start ($cb_warn_dnd, FALSE, FALSE, 0);
+    $bf->pack_start (new_subpage_frame (
+                         new_vbox_pack (
+                             new_check_button_for (\%pr::beh, 'flowed'),
+                             new_check_button_for (\%pr::beh, 'parts_rw'),
+                             new_check_button_for (\%pr::beh, 'use_utf8'),
+                             new_check_button_for (\%pr::beh, 'dangerous'),
+                             new_check_button_for (\%pr::beh, 'out_ascii'),
+                             new_check_button_for (\%pr::beh, 'pp_unsel'),
+                             new_check_button_for (\%pr::beh, 'inline_at')),
+                         $xl::s{msgs_frame}, 'not-packed'),
+                     FALSE, FALSE, FRAME_SPC);
+    $bf->pack_start (new_subpage_frame (
+                         new_vbox_pack (
+                             new_check_button_for (\%pr::beh, 'addr_swc'),
+                             new_check_button_for (\%pr::beh, 'fold_swc')),
+                         $xl::s{swc_frame}, 'not-packed'),
+                     FALSE, FALSE, FRAME_SPC);
     return $bf;
 }
 
@@ -596,14 +1071,18 @@ sub new_behaviour_page() {
         'emphasis_color',
         $xl::s{l_col_emphasis},
         $xl::s{h_col_emphasis},
-       'color',
-       undef,
+        'color',
+        '0.0.0',
+        '#0000cf',
+        undef,
     ],
     log_err => [
         'log_error_color',
         $xl::s{l_col_log_err},
         $xl::s{h_col_log_err},
         'color',
+        '0.0.0',
+        '#af0000',
         undef,
     ],
     log_in => [
@@ -611,6 +1090,8 @@ sub new_behaviour_page() {
         $xl::s{l_col_log_in},
         $xl::s{h_col_log_in},
         'color',
+        '0.0.0',
+        '#000000',
         undef,
     ],
     log_msg => [
@@ -618,6 +1099,8 @@ sub new_behaviour_page() {
         $xl::s{l_col_log_msg},
         $xl::s{h_col_log_msg},
         'color',
+        '0.0.0',
+        '#00af00',
         undef,
     ],
     log_out => [
@@ -625,6 +1108,8 @@ sub new_behaviour_page() {
         $xl::s{l_col_log_out},
         $xl::s{h_col_log_out},
         'color',
+        '0.0.0',
+        '#0000ef',
         undef,
     ],
     log_warn => [
@@ -632,103 +1117,947 @@ sub new_behaviour_page() {
         $xl::s{l_col_log_warn},
         $xl::s{h_col_log_warn},
         'color',
+        '0.0.0',
+        '#af0000',
+        undef,
+    ],
+    diff_add => [
+        'diff_added_color',
+        $xl::s{l_col_diff_add},
+        $xl::s{h_col_diff_add},
+        'color',
+        '3.8.0.54',
+        '#008b8b',
+        undef,
+    ],
+    diff_del => [
+        'diff_deleted_color',
+        $xl::s{l_col_diff_del},
+        $xl::s{h_col_diff_del},
+        'color',
+        '3.8.0.54',
+        '#6a5acd',
+        undef,
+    ],
+    diff_hunk => [
+        'diff_hunk_color',
+        $xl::s{l_col_diff_hunk},
+        $xl::s{h_col_diff_hunk},
+        'color',
+        '3.8.0.54',
+        '#a52a2a',
         undef,
     ],
 );
 
 sub new_colours_page() {
-    my $cf = Gtk2::VBox->new (FALSE, 5);
+    return new_vbox_pack (
+               new_subpage_frame (
+                   new_vbox_pack (
+                       new_color_button_for (\%pr::col, 'emphasis')),
+                   $xl::s{msgview_frame}, 'not-packed'),
+               new_subpage_frame (
+                   new_vbox_pack (
+                       new_color_button_for (\%pr::col, 'log_err'),
+                       new_color_button_for (\%pr::col, 'log_in'),
+                       new_color_button_for (\%pr::col, 'log_msg'),
+                       new_color_button_for (\%pr::col, 'log_out'),
+                       new_color_button_for (\%pr::col, 'log_warn')),
+                   $xl::s{log_frame}, 'not-packed'),
+               new_subpage_frame (
+                   new_vbox_pack (
+                       new_color_button_for (\%pr::col, 'diff_add'),
+                       new_color_button_for (\%pr::col, 'diff_del'),
+                       new_color_button_for (\%pr::col, 'diff_hunk')),
+                   $xl::s{diff_frame}, 'not-packed')
+           );
+}
 
-    my $msgview_frame = Gtk2::Frame->new ($xl::s{msgview_frame}); 
-    my $cb_emphasis = &new_color_button_for (\%pr::col, 'emphasis');
-    my $vb1 = Gtk2::VBox->new (FALSE, 5);
-    $vb1->pack_start ($cb_emphasis, FALSE, FALSE, 0);
-    $msgview_frame->add ($vb1);
-    
-    my $log_frame = Gtk2::Frame->new ($xl::s{log_frame}); 
-    my $cb_log_err = &new_color_button_for (\%pr::col, 'log_err');
-    my $cb_log_in = &new_color_button_for (\%pr::col, 'log_in');
-    my $cb_log_msg = &new_color_button_for (\%pr::col, 'log_msg');
-    my $cb_log_out = &new_color_button_for (\%pr::col, 'log_out');
-    my $cb_log_warn = &new_color_button_for (\%pr::col, 'log_warn');
-    my $vb2 = Gtk2::VBox->new (FALSE, 5);
-    $vb2->pack_start ($cb_log_err, FALSE, FALSE, 0);
-    $vb2->pack_start ($cb_log_in, FALSE, FALSE, 0);
-    $vb2->pack_start ($cb_log_msg, FALSE, FALSE, 0);
-    $vb2->pack_start ($cb_log_out, FALSE, FALSE, 0);
-    $vb2->pack_start ($cb_log_warn, FALSE, FALSE, 0);
-    $log_frame->add ($vb2);
-
-    $cf->pack_start ($msgview_frame, FALSE, FALSE, 0);
-    $cf->pack_start ($log_frame, FALSE, FALSE, 0);
-    return $cf;
+%pr::win = ( # tweak window positions and/or sizes
+    main_x => [
+        'mainwin_x',
+        $xl::s{l_win_x},
+        $xl::s{h_win_x},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '16',
+        undef,
+    ],
+    main_y => [
+        'mainwin_y',
+        $xl::s{l_win_y},
+        $xl::s{h_win_y},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '16',
+        undef,
+    ],
+    main_w => [
+        'mainwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '779',
+        undef,
+    ],
+    main_h => [
+        'mainwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '568',
+        undef,
+    ],
+    main_mx => [
+        'mainwin_maximised',
+        $xl::s{l_win_main_mx},
+        $xl::s{h_win_main_mx},
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
+    ],
+    main_fs => [
+        'mainwin_fullscreen',
+        $xl::s{l_win_main_fs},
+        $xl::s{h_win_main_fs},
+        'bool',
+        '0.0.0',
+        '0',
+        undef,
+    ],
+    msgs_x => [
+        'main_messagewin_x',
+        $xl::s{l_win_x},
+        $xl::s{h_win_x},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '256',
+        undef,
+    ],
+    msgs_y => [
+        'main_messagewin_y',
+        $xl::s{l_win_y},
+        $xl::s{h_win_y},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '210',
+        undef,
+    ],
+    msgs_w => [
+        'messagewin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '600',
+        undef,
+    ],
+    msgs_h => [
+        'messagewin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '540',
+        undef,
+    ],
+    send_w => [
+        'sendwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '460',
+        undef,
+    ],
+    send_h => [
+        'sendwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    recv_w => [
+        'receivewin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '460',
+        undef,
+    ],
+    recv_h => [
+        'receivewin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    fold_x => [
+        'folderwin_x',
+        $xl::s{l_win_x},
+        $xl::s{h_win_x},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '16',
+        undef,
+    ],
+    fold_y => [
+        'folderwin_y',
+        $xl::s{l_win_y},
+        $xl::s{h_win_y},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '16',
+        undef,
+    ],
+    fold_w => [
+        'folderitemwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '500',
+        undef,
+    ],
+    fold_h => [
+        'folderitemwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    fsel_w => [
+        'folderselwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '300',
+        undef,
+    ],
+    fsel_h => [
+        'folderselwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    sour_w => [
+        'sourcewin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '600',
+        undef,
+    ],
+    sour_h => [
+        'sourcewin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '500',
+        undef,
+    ],
+    addr_w => [
+        'addressbookwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '520',
+        undef,
+    ],
+    addr_h => [
+        'addressbookwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    adep_w => [
+        'addressbookeditpersonwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '640',
+        undef,
+    ],
+    adep_h => [
+        'addressbookeditpersonwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '320',
+        undef,
+    ],
+    adeg_w => [
+        'addressbookeditgroupwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '580',
+        undef,
+    ],
+    adeg_h => [
+        'addressbookeditgroupwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '340',
+        undef,
+    ],
+    adda_w => [
+        'addressaddwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '300',
+        undef,
+    ],
+    adda_h => [
+        'addressaddwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    addf_w => [
+        'addressbook_folderselwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '300',
+        undef,
+    ],
+    addf_h => [
+        'addressbook_folderselwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    acce_w => [
+        'editaccountwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '500',
+        undef,
+    ],
+    acce_h => [
+        'editaccountwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    acco_w => [
+        'accountswin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '500',
+        undef,
+    ],
+    acco_h => [
+        'accountswin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    filt_w => [
+        'filteringwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '500',
+        undef,
+    ],
+    filt_h => [
+        'filteringwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    fila_w => [
+        'filteringactionwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '490',
+        undef,
+    ],
+    fila_h => [
+        'filteringactionwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    fild_w => [
+        'filtering_debugwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '600',
+        undef,
+    ],
+    fild_h => [
+        'filtering_debugwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    matc_w => [
+        'matcherwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '520',
+        undef,
+    ],
+    matc_h => [
+        'matcherwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    pref_w => [
+        'prefswin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '600',
+        undef,
+    ],
+    pref_h => [
+        'prefswin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    temp_w => [
+        'templateswin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '480',
+        undef,
+    ],
+    temp_h => [
+        'templateswin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    acti_w => [
+        'actionswin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '486',
+        undef,
+    ],
+    acti_h => [
+        'actionswin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    tags_w => [
+        'tagswin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '486',
+        undef,
+    ],
+    tags_h => [
+        'tagswin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    plug_w => [
+        'pluginswin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    plug_h => [
+        'pluginswin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    logw_w => [
+        'logwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '520',
+        undef,
+    ],
+    logw_h => [
+        'logwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+    prin_w => [
+        'print_previewwin_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '600',
+        undef,
+    ],
+    prin_h => [
+        'print_previewwin_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '0.0.0',
+        '-1',
+        undef,
+    ],
+);
+
+sub new_winpos_subpage_main() {
+    return new_subpage_frame (
+               new_vbox_pack_compact (
+                   new_vbox_pack (
+                       new_text_box_for_int (\%pr::win, 'main_x'),
+                       new_text_box_for_int (\%pr::win, 'main_y')),
+                   new_hbox_pack (
+                       new_text_box_for_int (\%pr::win, 'main_w'),
+                       new_text_box_for_int (\%pr::win, 'main_h')),
+                   new_vbox_pack (
+                       new_check_button_for (\%pr::win, 'main_fs'),
+                       new_check_button_for (\%pr::win, 'main_mx'))),
+               _('Main window')
+           );
+}
+
+sub new_winpos_subpage_msgs() {
+    return new_subpage_frame (
+               new_vbox_pack_compact (
+                   new_vbox_pack (
+                       new_text_box_for_int (\%pr::win, 'msgs_x'),
+                       new_text_box_for_int (\%pr::win, 'msgs_y')),
+                   new_hbox_pack (
+                       new_text_box_for_int (\%pr::win, 'msgs_w'),
+                       new_text_box_for_int (\%pr::win, 'msgs_h'))),
+               _('Message window')
+           );
+}
+
+sub new_winpos_subpage_sendrecv() {
+    return new_vbox_pack (
+               new_subpage_frame (
+                   new_hbox_pack (
+                       new_text_box_for_int (\%pr::win, 'send_w'),
+                       new_text_box_for_int (\%pr::win, 'send_h')),
+                   _('Send window'), 'not-packed'),
+               new_subpage_frame (
+                   new_hbox_pack (
+                       new_text_box_for_int (\%pr::win, 'recv_w'),
+                       new_text_box_for_int (\%pr::win, 'recv_h')),
+                   _('Receive window'), 'not-packed')
+           );
+}
+
+sub new_winpos_subpage_fold() {
+    return new_vbox_pack (
+               new_subpage_frame (
+                   new_vbox_pack_compact (
+                       new_vbox_pack (
+                            new_text_box_for_int (\%pr::win, 'fold_x'),
+                            new_text_box_for_int (\%pr::win, 'fold_y')),
+                       new_hbox_pack (
+                           new_text_box_for_int (\%pr::win, 'fold_w'),
+                           new_text_box_for_int (\%pr::win, 'fold_h'))),
+                   _('Folder window'), 'not-packed'),
+               new_subpage_frame (
+                   new_hbox_pack (
+                       new_text_box_for_int (\%pr::win, 'fsel_w'),
+                       new_text_box_for_int (\%pr::win, 'fsel_h')),
+                   _('Folder selection window'), 'not-packed')
+           );
+}
+
+sub new_winpos_subpage_addrbook() {
+    return new_vbox_pack (
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'addr_w'),
+                          new_text_box_for_int (\%pr::win, 'addr_h')),
+                     _('Addressbook main window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'adep_w'),
+                          new_text_box_for_int (\%pr::win, 'adep_h')),
+                     _('Edit person window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'adeg_w'),
+                          new_text_box_for_int (\%pr::win, 'adeg_h')),
+                     _('Edit group window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'adda_w'),
+                          new_text_box_for_int (\%pr::win, 'adda_h')),
+                     _('Add address window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'addf_w'),
+                          new_text_box_for_int (\%pr::win, 'addf_h')),
+                     _('Folder select window'), 'not-packed')
+           );
+}
+
+sub new_winpos_subpage_accounts() {
+    return new_vbox_pack (
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'acco_w'),
+                          new_text_box_for_int (\%pr::win, 'acco_h')),
+                     _('Accounts window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'acce_w'),
+                          new_text_box_for_int (\%pr::win, 'acce_h')),
+                     _('Edit account window'), 'not-packed')
+           );
+}
+
+sub new_winpos_subpage_filtering() {
+    return new_vbox_pack (
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'filt_w'),
+                          new_text_box_for_int (\%pr::win, 'filt_h')),
+                     _('Filtering window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'fila_w'),
+                          new_text_box_for_int (\%pr::win, 'fila_h')),
+                     _('Filtering actions window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'fild_w'),
+                          new_text_box_for_int (\%pr::win, 'fild_h')),
+                     _('Filtering debug window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'matc_w'),
+                          new_text_box_for_int (\%pr::win, 'matc_h')),
+                     _('Matcher window'), 'not-packed')
+           );
+}
+
+sub new_winpos_subpage_prefs() {
+    return new_vbox_pack (
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'pref_w'),
+                          new_text_box_for_int (\%pr::win, 'pref_h')),
+                     _('Preferences window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'temp_w'),
+                          new_text_box_for_int (\%pr::win, 'temp_h')),
+                     _('Templates window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'acti_w'),
+                          new_text_box_for_int (\%pr::win, 'acti_h')),
+                     _('Actions window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'tags_w'),
+                          new_text_box_for_int (\%pr::win, 'tags_h')),
+                     _('Tags window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'plug_w'),
+                          new_text_box_for_int (\%pr::win, 'plug_h')),
+                     _('Plugins window'), 'not-packed')
+           );
+}
+
+sub new_winpos_subpage_misc() {
+    return new_vbox_pack (
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'logw_w'),
+                          new_text_box_for_int (\%pr::win, 'logw_h')),
+                     _('Log window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'prin_w'),
+                          new_text_box_for_int (\%pr::win, 'prin_h')),
+                     _('Print preview window'), 'not-packed'),
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::win, 'sour_w'),
+                          new_text_box_for_int (\%pr::win, 'sour_h')),
+                     _('View source window'), 'not-packed')
+           );
+}
+
+sub new_winpos_page() {
+    my $winbook = Gtk2::Notebook->new;
+    $winbook->set_tab_pos ('right');
+    $winbook->append_page (new_winpos_subpage_main, _('Main'));
+    $winbook->append_page (new_winpos_subpage_msgs, _('Message'));
+    $winbook->append_page (new_winpos_subpage_sendrecv, _('Send/Receive'));
+    $winbook->append_page (new_winpos_subpage_fold, _('Folder'));
+    $winbook->append_page (new_winpos_subpage_addrbook, _('Addressbook'));
+    $winbook->append_page (new_winpos_subpage_accounts, _('Accounts'));
+    $winbook->append_page (new_winpos_subpage_filtering, _('Filtering'));
+    $winbook->append_page (new_winpos_subpage_prefs, _('Preferences'));
+    $winbook->append_page (new_winpos_subpage_misc, _('Other'));
+    return $winbook;
+}
+
+# version info
+sub print_version() {
+    print $xl::s{about_title} . "\n";
+    print $xl::s{about_version} . " $VERSION\n";
+    print "Perl-GLib " . $Glib::VERSION;
+    # version info stuff appeared in 1.040
+    if ($Glib::VERSION >= 1.040) {
+        print _(", built for ") . join(".", Glib->GET_VERSION_INFO) 
+              . _(", running with ") . join(".", &Glib::major_version, 
+              &Glib::minor_version, &Glib::micro_version);
+    }
+    print "\n";
+    print "Perl-GTK2 " . $Gtk2::VERSION;
+    if ($Gtk2::VERSION >= 1.040) {
+        print _(", built for ") . join(".", Gtk2->GET_VERSION_INFO)
+              . _(", running with ") . join(".", &Gtk2::major_version, 
+              &Gtk2::minor_version, &Gtk2::micro_version);
+    }
+    print "\n";
+    my $clawsver = ($CLAWSV eq "") ? 
+                _("was not found!") : 
+                (_("returned version ") . $CLAWSV);
+    print "Claws Mail " . $clawsver . "\n";
+}
+
+# the command line help
+sub print_help() {
+    my $line = '-' x length ($xl::s{about_title}) . "\n";
+    print $line;
+    print $xl::s{about_title} . "\n";
+    print $line;
+    print _("Syntax:\n");
+    print _("  clawsker [options]\n");
+    print _("Options:\n");
+    print _("  -h|--help                        Prints this help screen.\n");
+    print _("  -v|--version                     Prints version infos.\n");
+    print _("  -b|--verbose                     More messages on standard output.\n");
+    print _("  -a|--alternate-config-dir <dir>  Uses <dir> as Claws Mail config dir.\n");
+    print _("  -c|--clawsrc <file>              Uses <file> as full resource name.\n");
+}
+
+sub parse_command_line {
+    my $cont = TRUE;
+    $CLAWSV = get_claws_version ();
+    eval {
+        GetOptions('h|help' => sub { print_help (); $cont = FALSE },
+            'v|version' => sub { print_version (); $cont = FALSE },
+            'b|verbose' => sub { $VERBOSE = TRUE },
+            'u|use-claws-version=s' => \&opt_use_claws_version,
+            'a|alternate-config-dir=s' => \&opt_alternate_config_dir,
+            'r|clawsrc=s' => \&opt_clawsrc)
+        or die _("try -h or --help for syntax.\n");
+    };
+    if ($@) {
+        my $msg = _("Error in options: {msg}\n", msg => $@);
+        if (defined $ENV{'DISPLAY'} and $ENV{'DISPLAY'} ne '') {
+            eval { Gtk2->init };
+            error_dialog ($msg) unless $@;
+        }
+        die $msg;
+    }
+    return $cont;
+}
+
+sub opt_use_claws_version {
+    my ($name, $value) = @_;
+    die _("Error: {opt} requires a dotted numeric value argument\n", opt => $name)
+        unless ($value =~ /^[\d\.]+$/);
+    $CLAWSV = $value;
+}
+
+sub opt_alternate_config_dir {
+    my ($name, $value) = @_;
+    die _("Error: '{dir}' is not a directory or does not exist\n", dir => $value)
+        unless -d $value;
+    $CONFIGDIR = $value;
+    $CONFIGDIR .= "/" unless ($CONFIGDIR =~ /.*\/$/);
+    $ALTCONFIGDIR = TRUE;
+}
+
+sub opt_clawsrc {
+    my ($name, $value) = @_;
+    die _("Error: '{value}' is not a file or does not exist\n", value => $value)
+        unless -f $value;
+    set_rc_filename ($value);
 }
 
 # update the hidden preferences status from loaded values
-sub init_hidden_preferences() {
-    foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth) {
+sub init_hidden_preferences {
+    foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth, \%pr::win) {
         foreach my $key (keys %$hash) { 
-           $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
+            $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
         }
     }
+    return TRUE;
 }
 
 # load current status from disc
-sub load_preferences() {
-    my $rc = $ENV{HOME} . '/.claws-mail/clawsrc';
-    -f $rc or die "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
+sub load_preferences {
+    my $rc = get_rc_filename ();
+    log_message ("Loading preferences from $rc\n");
+    return FALSE unless check_rc_file ($rc);
+    return FALSE unless check_claws_not_running ();
     open (RCF, "<$rc");
     while (<RCF>) {
-       chomp;
-       if (/^([8a-z_]+)=(.*)$/) {
-           $PREFS{$1} = "$2";
+        chomp;
+        if (/^([8a-z_]+)=(.*)$/) {
+            $PREFS{$1} = decode('UTF-8', $2);
         }
     }
     close (RCF);
+    return TRUE;
 }
 
 # save current preferences to disc
-sub save_preferences() {
-    my $rc = $ENV{HOME} . '/.claws-mail/clawsrc';
+sub save_preferences {
+    my $rc = get_rc_filename ();
+    log_message ("Saving preferences to $rc\n");
+    return FALSE unless check_rc_file ($rc);
+    return FALSE unless check_claws_not_running ();
     my $rcbak = "$rc.backup";
     rename ($rc, $rcbak);
     open (RCF, ">$rc");
     open (RCB, "<$rcbak");
     while (<RCB>) {
-       chomp;
-       if (/^([8a-z_]+)=(.*)$/) {
-           if (defined($HPVALUE{$1})) {
-               print RCF $1 . "=" . $HPVALUE{$1} . "\n";
-           }
-           else {
-               print RCF $_ . "\n";
-           }
+        chomp;
+        if (/^([8a-z_]+)=(.*)$/) {
+            if (defined($HPVALUE{$1})) {
+                print RCF $1 . "=" . $HPVALUE{$1} . "\n";
+            }
+            else {
+                print RCF $_ . "\n";
+            }
+        }
+        else {
+            print RCF $_ . "\n";
         }
-       else {
-           print RCF $_ . "\n";
-       }
     }
     close (RCB);
     close (RCF);
+    return TRUE;
 }
 
 # create notebook
-sub new_notebook() {
+sub new_notebook {
     my $nb = Gtk2::Notebook->new;
     # 
-    $nb->append_page (&new_behaviour_page, $xl::s{tab_behaviour});
-    $nb->append_page (&new_colours_page, $xl::s{tab_colours});
-    $nb->append_page (&new_gui_page, $xl::s{tab_gui});
-    $nb->append_page (&new_other_page, $xl::s{tab_other});
+    $nb->append_page (new_behaviour_page (), $xl::s{tab_behaviour});
+    $nb->append_page (new_colours_page (), $xl::s{tab_colours});
+    $nb->append_page (new_gui_page (), $xl::s{tab_gui});
+    $nb->append_page (new_other_page (), $xl::s{tab_other});
+    $nb->append_page (new_winpos_page (), $xl::s{tab_winpos});
 
     return $nb;
 }
 
 # create an about dialog
-sub new_about_dialog() {
+sub new_about_dialog {
     my ($parent) = @_;
     my $title = $xl::s{about_title};
     my $lic = $xl::s{about_license};
+    my $vers = $xl::s{about_version} . " $VERSION";
     my $license = 
 "This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -742,19 +2071,27 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
+    my $year = "2007-2016";
+    my $holder = "Ricardo Mones &lt;ricardo\@mones.org&gt;";
+    my $url = "http://www.claws-mail.org/clawsker.php";
 
     my $dialog = Gtk2::MessageDialog->new_with_markup ($parent, 
                     [qw/modal destroy-with-parent/], 
-                   'info', 'close', 
-                   "<span size=\"x-large\" weight=\"bold\">$title</span>\n<span>Copyright 2007 by Ricardo Mones &lt;ricardo\@mones.org&gt;</span>\n\n<span size=\"large\">$lic</span>\n\n<span size=\"small\">$license</span>");
+                    'info', 'close', 
+                    "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
+                    . "<span size=\"large\">$vers</span>\n\n"
+                    . "<span color=\"blue\" size=\"large\">$url</span>\n\n"
+                    . "<span>Copyright $year by $holder</span>\n\n"
+                    . "<span size=\"large\">$lic</span>\n\n"
+                    . "<span size=\"small\">$license</span>");
     $dialog->set_title ($xl::s{about});
     #
     return $dialog;
 }
 
 # create buttons box
-sub new_button_box() {
-    my ($adlg) = @_;
+sub new_button_box {
+    my ($parent, $adlg) = @_;
     my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
     my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
     my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
@@ -763,30 +2100,48 @@ sub new_button_box() {
     my $hbox = Gtk2::HBox->new (FALSE, 5);
     # signal handlers 
     $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
-    $b_apply->signal_connect (clicked => sub { &save_preferences });
-    # $b_undo->signal_connect (clicked => sub { &undo_current_changes });
+    $b_apply->signal_connect (clicked => sub { save_preferences ($parent) });
+    # $b_undo->signal_connect (clicked => sub { undo_current_changes });
     $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
     # package them
-    $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
     $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
+    $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
     # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
     $hbox->pack_start ($b_about, FALSE, FALSE, 0);
     #
     return $hbox;
 }
 
-# initialise values
-&load_preferences;
-&init_hidden_preferences;
+sub get_app_icons {
+    my $dir = $DATADIR . '/icons/hicolor';
+    my @names = map {
+      join ('/', ($dir, , $_ . 'x' . $_, 'apps', $NAME . '.png'))
+    } (64, 128);
+    my @icons = ();
+    foreach (@names) {
+        my $icon = undef;
+        $icon = Gtk2::Gdk::Pixbuf->new_from_file($_) if (-f $_);
+        push @icons, $icon if ($icon);
+    }
+    return @icons;
+}
+
+# initialise
+exit unless parse_command_line ();
+Gtk2->init;
+$main_window = Gtk2::Window->new ('toplevel');
+exit unless load_preferences ();
+exit unless init_hidden_preferences ();
 # create main GUI
-my $window = Gtk2::Window->new ('toplevel');
 my $box = Gtk2::VBox->new (FALSE, 5);
-my $about = &new_about_dialog;
-$box->pack_start (&new_notebook, FALSE, FALSE, 0);
-$box->pack_end (&new_button_box ($about), FALSE, FALSE, 0);
-
-$window->set_title ($xl::s{win_title});
-$window->add ($box);
-$window->show_all;
+$box->set_border_width(3);
+my $about = new_about_dialog ();
+$box->pack_start (new_notebook (), FALSE, FALSE, 0);
+$box->pack_end (new_button_box ($main_window, $about), FALSE, FALSE, 0);
+$main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
+$main_window->set_title ($xl::s{win_title});
+$main_window->set_icon_list (get_app_icons ());
+$main_window->add ($box);
+$main_window->show_all;
 Gtk2->main;