#!/usr/bin/perl -w
#
# Clawsker :: A Claws Mail Tweaker
#
use strict;
use encoding 'utf8';
use Glib qw(TRUE FALSE);
use Gtk2 -init;
use POSIX qw(setlocale);
use Locale::gettext;
use Encode;

my $NAME = 'clawsker';
my $PREFIX = '@PREFIX@';
my $LIBDIR = '@LIBDIR@';
my $VERSION = '@VERSION@';
my $VERBOSE = FALSE;
my $CLAWSV = undef;
my $main_window = undef;

my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
$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);
    if (scalar(keys(%par)) > 0) {
        foreach my $key (keys %par) {
            $xla =~ s/\{$key\}/$par{$key}/g;
        }
    }
    return decode_utf8($xla);
}

# default messages
%xl::s = (
    win_title => _('Claws Mail Hidden Preferences'),
    about => _('About...'),
    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'),
    log_frame => _('Log window'),
    dnd_frame => _('Drag \'n\' drop'),
    ssl_frame => _('Secure Sockets Layer'),
    msgs_frame => _('Messages'),
    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'),

    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_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'),
    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 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 => _('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_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 => _('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 all tree view components'),
    h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
    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 compose 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_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 (dangerous!)'),
    h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
    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 bar update step (items)'),
    h_beh_up_step => _('Update stepping in progress bars.'),
    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 => _('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 => _('Warn on drag \'n\' drop'),
    h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
    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_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 => _('Error messages'),
    h_col_log_err => _('Colour for error messages in log window.'),
    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 => _('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 => _('resource file for Claws Mail was not found.'),
    e_running => _('seems Claws Mail is currently running, close it first.'),
    e_requireddir => _('option requires a directory name.'),
    e_requiredfile => _('option requires a file name.'),
    e_notadir => _('specified name is not a directory or does not exist.'),
    e_notafile => _('specified name is not a file or does not exist.'),
);

# 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 CMVER => 4; # lowest Claws Mail version 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+)cvs(\d+)/) {
        $res .= "$1.$2";
    }
    else {
        $res .= "$ver[2].0";
    }
    return $res;
}

# data handlers and auxiliar functions

sub handle_bool_value {
    my ($widget, $event, $dataref) = @_;
    $$dataref = ($widget->get_active ())? '1': '0';
}

sub handle_int_value {
    my ($widget, $event, $dataref) = @_;
    $_ = $widget->get_text ();
    s/^\s+//;
    s/\s+$//;
    if (/^[0-9]+$/) {
        $$dataref = $_;
        $widget->set_text ($_);
    }
    else {
        $widget->set_text ($$dataref);
    }
}

sub handle_string_value {
    my ($widget, $event, $dataref) = @_;
    $$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);
    $_ = uc ($str);
    if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
        $rr = hex($1) * 256;
        $gg = hex($2) * 256; 
        $bb = hex($3) * 256;
    }
    my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
    return $color;
}

sub str_from_gdk_color {
    my ($color) = @_;
    my $rr = $color->red / 256;
    my $gg = $color->green / 256;
    my $bb = $color->blue / 256;
    my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
    return $str;
}

sub handle_color_value {
    my ($widget, $event, $dataref) = @_;
    my $newcol = $widget->get_color;
    $$dataref = &str_from_gdk_color ($newcol);
}

sub handle_selection_value {
    my ($widget, $event, $dataref) = @_;
    $$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 (_('Error message'));
    $errordlg->run;
    $errordlg->destroy;
}

sub check_claws_not_running() {
    my $socket = (not $ALTCONFIGDIR)? "/tmp/": $CONFIGDIR;
    $socket .= "claws-mail-$<";
    -S $socket and do {
        my $emsg = "$xl::s{e_error}$xl::s{e_running}";
        log_message ($emsg);
        error_dialog ($emsg);
        return FALSE;
     };
     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, $minver) = @_;
    $wdgt->set_sensitive (&version_greater_or_equal ($CLAWSV, $minver));
}

# graphic element creation 

sub new_check_button_for {
    my ($hash, $key) = @_;
    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;
    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});
        });
    &set_widget_hint ($cb, $$hash{$key}[DESC]);
    &set_widget_sens ($cb, $$hash{$key}[CMVER]);
    $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
    #
    return $hbox;
}

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 $pagei = int (($type[2] - $type[1]) / 10);
    my $gentry = Gtk2::SpinButton->new_with_range ($type[1], $type[2], $pagei);
    $gentry->set_numeric (TRUE);
    $gentry->set_value ($HPVALUE{$name});
    $$hash{$key}[GUI] = $gentry;
    $gentry->signal_connect('value-changed' => sub {
            my ($w, $e) = @_;
            &handle_int_value($w, $e, \$HPVALUE{$name});
        });
    &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;
}

sub new_color_button_for {
    my ($hash, $key) = @_;
    my $name = $$hash{$key}[NAME];
    my $label = $$hash{$key}[LABEL];
    #
    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}); 
        });
    &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;
}

sub new_selection_box_for {
    my ($hash, $key) = @_;
    my $name = $$hash{$key}[NAME];
    my $label = $$hash{$key}[LABEL];
    #
    my $hbox = Gtk2::HBox->new (FALSE, 5);
    my $glabel = Gtk2::Label->new ($label);
    my $combo = Gtk2::ComboBox->new_text;
    $$hash{$key}[GUI] = $combo;
    my @options = split (';', $$hash{$key}[TYPE]);
    foreach my $opt (@options) {
        my ($index, $textkey) = split ('=', $opt);
        $combo->insert_text ($index, $xl::s{$textkey});
    }
    $combo->signal_connect ('changed' => sub {
            my ($w, $e) = @_;
            &handle_selection_value($w, $e, \$HPVALUE{$name});
        });
    $combo->set_active ($HPVALUE{$name});
    &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{h_oth_use_dlg},
        '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,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,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,
    ],
);

sub new_other_page() {
    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')
           );
}

%pr::gui = ( # gui bells and whistles
    b_unread => [ 
        'bold_unread',
        $xl::s{l_gui_b_unread},
        $xl::s{h_gui_b_unread},
        'bool',
        '0.0.0',
        '1',
        undef,
    ],
    no_markup => [
        'compose_no_markup',
        $xl::s{l_gui_no_markup},
        $xl::s{h_gui_no_markup},
        'bool',
        '0.0.0',
        '0',
        undef,
    ],
    dot_lines => [
        'enable_dotted_lines',
        $xl::s{l_gui_dot_lines},
        $xl::s{h_gui_dot_lines},
        'bool',
        '0.0.0',
        '0',
        undef,
    ],
    h_scroll => [
        'enable_hscrollbar',
        $xl::s{l_gui_h_scroll},
        $xl::s{h_gui_h_scroll},
        'bool',
        '0.0.0',
        '1',
        undef,
    ],
    swp_from => [
        'enable_swap_from',
        $xl::s{l_gui_swp_from},
        $xl::s{h_gui_swp_from},
        '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',
        '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,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',
        '0.0.0',
        '0',
        undef,
    ],
    toolbar_d => [
        'toolbar_detachable',
        $xl::s{l_gui_toolbar_d},
        $xl::s{h_gui_toolbar_d},
        'bool',
        '0.0.0',
        '0',
        undef,
    ],
    strip_all => [
        'use_stripes_everywhere',
        $xl::s{l_gui_strip_all},
        $xl::s{h_gui_strip_all},
        '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',
        '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,
    ],
);

sub new_gui_page() {
    my $gf = Gtk2::VBox->new (FALSE, 5);
    $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_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')),
                         $xl::s{compo_frame}, 'not-packed'), 
                     FALSE, FALSE, FRAME_SPC);
    $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
    $gf->pack_start ($cb_toolbar_d, 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;
}

%pr::beh = ( # tweak some behaviour
    hover_t => [
        'hover_timeout',
        $xl::s{l_beh_hover_t},
        $xl::s{h_beh_hover_t},
        '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',
        '0.0.0',
        '0',
        undef,
    ],
    flowed => [
        'respect_flowed_format',
        $xl::s{l_beh_flowed},
        $xl::s{h_beh_flowed},
        'bool',
        '0.0.0',
        '0',
        undef,
    ],
    parts_rw => [
        'save_parts_readwrite',
        $xl::s{l_beh_parts_rw},
        $xl::s{h_beh_parts_rw},
        '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',
        '0.0.0',
        '0',
        undef,
    ],
    up_step => [
        'statusbar_update_step',
        $xl::s{l_beh_up_step},
        $xl::s{h_beh_up_step},
        '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,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',
        '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',
        '0.0.0',
        '0',
        undef,
    ],
    warn_dnd => [
        'warn_dnd',
        $xl::s{l_beh_warn_dnd},
        $xl::s{h_beh_warn_dnd},
        '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,
    ],
);

sub new_behaviour_page() {
    my $bf = Gtk2::VBox->new (FALSE, 5);
    $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 (&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);

    return $bf;
}

%pr::col = ( # a variety of colours
    emphasis => [
        'emphasis_color',
        $xl::s{l_col_emphasis},
        $xl::s{h_col_emphasis},
        '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 => [
        'log_in_color',
        $xl::s{l_col_log_in},
        $xl::s{h_col_log_in},
        'color',
        '0.0.0',
        '#000000',
        undef,
    ],
    log_msg => [
        'log_msg_color',
        $xl::s{l_col_log_msg},
        $xl::s{h_col_log_msg},
        'color',
        '0.0.0',
        '#00af00',
        undef,
    ],
    log_out => [
        'log_out_color',
        $xl::s{l_col_log_out},
        $xl::s{h_col_log_out},
        'color',
        '0.0.0',
        '#0000ef',
        undef,
    ],
    log_warn => [
        'log_warn_color',
        $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() {
    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')
           );
}

%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 _("    --help                         Prints this help screen.\n");
    print _("    --version                      Prints version infos.\n");
    print _("    --verbose                      More messages on standard output.\n");
    print _("    --alternate-config-dir <dir>   Uses <dir> as Claws Mail config dir.\n");
    print _("    --clawsrc <file>               Uses <file> as full resource name.\n");
}

# handle errors which don't allow to run
sub command_line_fatal() {
    my $reason = shift;
    my $emsg = $xl::s{e_error} . $reason;
    error_dialog ($emsg);
    log_message ("$emsg", 'die');
}

# parse the command line
sub parse_command_line() {
    $CLAWSV = &get_claws_version;
    my $arg = 0;
    while (defined($ARGV[$arg])) {
        for ($ARGV[$arg]) {
            /--help/ && do { 
                &print_help; 
                return FALSE;
            };
            /--version/ && do { 
                &print_version; 
                return FALSE;
            };
            /--verbose/ && do {
                $VERBOSE = TRUE;
                last;
            };
            /--use-claws-version/ && do {
                ++$arg;
                &command_line_fatal ("required version")
                    unless defined($ARGV[$arg]);
                &command_line_fatal ("required a dotted numeric value")
                    unless ($ARGV[$arg] =~ /[\d\.]+/);
                $CLAWSV = $ARGV[$arg];
                last;
            };
            /--alternate-config-dir/ && do {
                ++$arg;
                &command_line_fatal ($xl::s{e_requireddir})
                    unless defined($ARGV[$arg]);
                &command_line_fatal ($xl::s{e_notadir})
                    unless -d $ARGV[$arg];
                $CONFIGDIR = $ARGV[$arg];
                $CONFIGDIR .= "/" 
                    unless ($CONFIGDIR =~ /.*\/$/);
                $ALTCONFIGDIR = TRUE;
                last;
            };
            /--clawsrc/ && do {
                ++$arg;
                &command_line_fatal($xl::s{e_requiredfile}) 
                    unless defined($ARGV[$arg]);
                &command_line_fatal($xl::s{e_notafile}) 
                    unless -f $ARGV[$arg];
                &set_rc_filename ($ARGV[$arg]);
                last;
            };
            /.*/ && &command_line_fatal (
                _("unknown option '{opt}'.\n", opt => $ARGV[$arg]));
        }
        ++$arg;
    }
    # eveything continues...
    return TRUE;
}

# update the hidden preferences status from loaded values
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]};
        }
    }
    return TRUE;
}

# load current status from disc
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";
        }
    }
    close (RCF);
    return TRUE;
}

# save current preferences to disc
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";
            }
        }
        else {
            print RCF $_ . "\n";
        }
    }
    close (RCB);
    close (RCF);
    return TRUE;
}

# create 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_winpos_page, $xl::s{tab_winpos});

    return $nb;
}

# create an 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
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 &lt;http://www.gnu.org/licenses/&gt;.";
    my $year = "2007-2012";
    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 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 ($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');
    # disable button until is really implemented
    # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
    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 ($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_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
$main_window = Gtk2::Window->new ('toplevel');
exit unless &parse_command_line;
exit unless &load_preferences;
exit unless &init_hidden_preferences;
# create main GUI
my $box = Gtk2::VBox->new (FALSE, 5);
$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->add ($box);
$main_window->show_all;
Gtk2->main;

