Support “rewrite_first_from”
[clawsker.git] / clawsker
index e0741b41d8371e3e727bde3d3feb9a5d8ab356f3..f4167c390d12802a1b8f929fde912ffdd398db09 100755 (executable)
--- a/clawsker
+++ b/clawsker
@@ -31,6 +31,7 @@ my $LIBDIR = '@LIBDIR@';
 my $DATADIR = '@DATADIR@';
 my $VERSION = '@VERSION@';
 my $VERBOSE = FALSE;
+my $READONLY = FALSE;
 my $CLAWSV = undef;
 my $main_window = undef;
 
@@ -69,6 +70,8 @@ sub _ {
     tab_other => _('Other'),
     tab_winpos => _('Windows'),
     tab_accounts => _('Accounts'),
+    tab_plugins => _('Plugins'),
+    tab_info => _('Info'),
 
     ab_frame => _('Addressbook'),
     mem_frame => _('Memory'),
@@ -97,7 +100,7 @@ sub _ {
     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'),
@@ -171,6 +174,8 @@ sub _ {
     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_beh_rewrite_ff => _('Rewrite first \'From\' using QP encoding'),
+    h_beh_rewrite_ff => _('Workaround some servers which convert first \'From\' to \'>From\' by using Quoted-Printable transfer encoding instead of 7bit/8bit encoding.'),
 
     l_col_emphasis => _('X-Mailer header'),
     h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
@@ -211,22 +216,45 @@ sub _ {
     l_acc_gtls_pri => _('GnuTLS priority'),
     h_acc_gtls_pri => _('Value to use as GnuTLS priority string if custom priority check is enabled. Otherwise this value is ignored.'),
 
+    l_plu_gpg_alimit => _('Autocompletion limit'),
+    h_plu_gpg_alimit => _('Limits the number of addresses obtained from keyring through autocompletion. Use 0 to get all matches.'),
+    l_plu_lav_burl => _('Base URL'),
+    h_plu_lav_burl => _('This is the URL where avatar requests are sent. You can use the one of your own libravatar server, if available.'),
+    l_plu_prl_flvb => _('Log level'),
+    h_plu_prl_flvb => _('Verbosity level of log, acumulative.'),
+    l_plu_prl_none => _('None'),
+    l_plu_prl_manual => _('Manual'),
+    l_plu_prl_action => _('Actions'),
+    l_plu_prl_match => _('Matches'),
+
     e_error => _('Error: '),
     e_noclawsrc => _('resource file for Claws Mail was not found.'),
     e_running => _('seems Claws Mail is currently running, close it first.'),
 );
 
+# data and metadata of resource files
+my $CONFIGDATA;
+my $CONFIGMETA;
+my $ACCOUNTDATA;
+my $ACCOUNTMETA;
 # all preferences read by load_preferences
 my %PREFS = ();
 my %ACPREFS = ();
+my %PLPREFS = ();
 # values of all preferences handled by clawsker
 my %HPVALUE = ();
 my %ACHPVALUE = ();
+my %PLHPVALUE = ();
 # default config dir and file name
 my $ALTCONFIGDIR = FALSE;
 my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
 my $CONFIGRC = 'clawsrc';
 my $ACCOUNTRC = 'accountrc';
+# supported and available plugins lists
+my @PLUGINS = qw(AttRemover GPG ManageSieve Libravatar PerlPlugin);
+my @AVPLUGINS = ();
+# loaded icons
+my @APPICONS = ();
 
 # index constants for preference arrays
 use constant NAME  => 0; # the name on the rc file
@@ -235,7 +263,7 @@ 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[,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
+use constant PLUGIN => 6; # plugin section (only in plugin preferences)
 
 # constants for GUI spacing
 use constant HBOX_SPC => 5;
@@ -252,7 +280,7 @@ sub version_greater_or_equal {
         push (@version, '0');
     }
     my $idx = 0;
-    while (($idx <= $#refvers) 
+    while (($idx <= $#refvers)
             and (int ($version[$idx]) == int ($refvers[$idx]))) {
         ++$idx;
     }
@@ -309,8 +337,8 @@ sub handle_string_value {
 }
 
 sub handle_nchar_value {
-    my ($widget, $event, $dataref, $minlen) = @_;
-    $_ = substr ($widget->get_text (), 0, $minlen);
+    my ($widget, $event, $dataref, $minlen, $maxlen) = @_;
+    $_ = substr ($widget->get_text (), 0, $maxlen);
     $widget->set_text ($_);
     $$dataref = $_;
 }
@@ -321,7 +349,7 @@ sub gdk_color_from_str {
     $_ = 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; 
+        $gg = hex($2) * 256;
         $bb = hex($3) * 256;
     }
     my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
@@ -391,10 +419,11 @@ sub claws_is_running {
 }
 
 sub check_claws_not_running {
+    return TRUE if $READONLY;
     my $tmpdir = (defined $ENV{TMPDIR})? $ENV{TMPDIR}: '/tmp';
     $tmpdir = '/tmp' if ($tmpdir eq '');
     my $lockdir = "$tmpdir/claws-mail-$<";
-    -d $lockdir and do { 
+    -d $lockdir and do {
         $_ = $CONFIGDIR;
         s/\/$//;
         my $socket = "$lockdir/" . md5_hex ($_);
@@ -416,7 +445,7 @@ sub check_rc_file {
 
 sub set_widget_hint {
     if ($SHOWHINTS) {
-        my ($wdgt, $hint) = @_;    
+        my ($wdgt, $hint) = @_;
         $wdgt->set_tooltip_text ($hint);
         $wdgt->set_has_tooltip (TRUE);
     }
@@ -435,7 +464,7 @@ sub set_widget_sens {
     }
 }
 
-# graphic element creation 
+# graphic element creation
 
 sub new_check_button_for($$$) {
     my ($hash, $key, $vhash) = @_;
@@ -463,7 +492,7 @@ sub new_text_box_for_int($$$) {
     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); 
+    push (@type, 0), push (@type, 10000) unless ($#type > 0);
     #
     my $hbox = Gtk2::HBox->new (FALSE, 5);
     my $glabel = Gtk2::Label->new ($label);
@@ -490,18 +519,20 @@ sub new_text_box_for_nchar($$$) {
     my ($hash, $key, $vhash) = @_;
     my $name = $$hash{$key}[NAME];
     my $label = $$hash{$key}[LABEL];
-    my @type = split (/,/, $$hash{$key}[TYPE]); # char,minlen,maxlen
+    my @type = split (/,/, $$hash{$key}[TYPE]); # char,minlen,maxlen,width
     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]);
+    my $width = $type[3];
+    $width //= $type[2];
+    $gentry->set_width_chars(int ($width) + 2) if defined ($width);
     my $value = $$vhash{$name};
     $value //= $$hash{$key}[CMDEF];
     $gentry->set_text ($value);
     $gentry->signal_connect('key-release-event' => sub {
             my ($w, $e) = @_;
-            handle_nchar_value ($w, $e, \$$vhash{$name}, $type[1]);
+            handle_nchar_value ($w, $e, \$$vhash{$name}, $type[1], $type[2]);
         });
     set_widget_hint ($gentry, $$hash{$key}[DESC]);
     set_widget_sens ($gentry, $$hash{$key}[CMVER]);
@@ -576,7 +607,7 @@ sub new_hbox_pack {
         $hbox->pack_start ($item, FALSE, FALSE, 0);
     }
     return $hbox;
-}    
+}
 
 sub new_vbox_pack {
     my $vbox = Gtk2::VBox->new (FALSE, 5);
@@ -585,7 +616,7 @@ sub new_vbox_pack {
         $vbox->pack_start ($item, FALSE, FALSE, 0);
     }
     return $vbox;
-}    
+}
 
 sub new_vbox_pack_compact {
     my $vbox = Gtk2::VBox->new (FALSE, 0);
@@ -594,12 +625,12 @@ sub new_vbox_pack_compact {
         $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);    
+    $frame->add ($box);
     return new_vbox_pack ($frame) unless defined ($notpacked);
     return $frame;
 }
@@ -607,14 +638,13 @@ sub new_subpage_frame {
 # preference maps and corresponding page creation subs
 
 %pr::oth = ( # other preferences
-    use_dlg => [ 
+    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',
@@ -623,7 +653,6 @@ sub new_subpage_frame {
         'int,0,262144', # 0 Kb - 256 Mb
         '0.0.0',
         '4096',
-        undef,
     ],
     min_time => [
         'cache_min_keep_time',
@@ -632,7 +661,6 @@ sub new_subpage_frame {
         'int,0,120', # 0 minutes - 2 hours
         '0.0.0',
         '15',
-        undef,
     ],
     use_netm => [
         'use_networkmanager',
@@ -641,7 +669,6 @@ sub new_subpage_frame {
         'bool',
         '3.3.1',
         '1',
-        undef,
     ],
     mp_rounds => [
         'master_passphrase_pbkdf2_rounds',
@@ -650,7 +677,6 @@ sub new_subpage_frame {
         'int,50000,1000000',
         '3.13.2.110',
         '50000',
-        undef,
     ],
 );
 
@@ -677,14 +703,13 @@ sub new_other_page() {
 }
 
 %pr::gui = ( # gui bells and whistles
-    b_unread => [ 
+    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',
@@ -693,7 +718,6 @@ sub new_other_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     dot_lines => [
         'enable_dotted_lines',
@@ -702,7 +726,6 @@ sub new_other_page() {
         'bool',
         '0.0.0,3.7.10.44',
         '0',
-        undef,
     ],
     h_scroll => [
         'enable_hscrollbar',
@@ -711,7 +734,6 @@ sub new_other_page() {
         'bool',
         '0.0.0',
         '1',
-        undef,
     ],
     swp_from => [
         'enable_swap_from',
@@ -720,7 +742,6 @@ sub new_other_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     v_scroll => [
         'folderview_vscrollbar_policy',
@@ -729,7 +750,6 @@ sub new_other_page() {
         '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',
@@ -738,7 +758,6 @@ sub new_other_page() {
         '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',
@@ -747,7 +766,6 @@ sub new_other_page() {
         'int,0,40000', # no idea what this number means
         '0.0.0',
         '4000',
-        undef,
     ],
     cursor_v => [
         'textview_cursor_visible',
@@ -756,7 +774,6 @@ sub new_other_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     toolbar_d => [
         'toolbar_detachable',
@@ -765,7 +782,6 @@ sub new_other_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     strip_all => [
         'use_stripes_everywhere',
@@ -774,7 +790,6 @@ sub new_other_page() {
         'bool',
         '0.0.0',
         '1',
-        undef,
     ],
     strip_sum => [
         'use_stripes_in_summaries',
@@ -783,7 +798,6 @@ sub new_other_page() {
         'bool',
         '0.0.0',
         '1',
-        undef,
     ],
     two_linev => [
         'two_line_vertical',
@@ -792,7 +806,6 @@ sub new_other_page() {
         'bool',
         '3.4.0.7',
         '0',
-        undef,
     ],
     margin_co => [
         'show_compose_margin',
@@ -801,7 +814,6 @@ sub new_other_page() {
         'bool',
         '3.7.6.7',
         '0',
-        undef,
     ],
     mview_date => [
         'msgview_date_format',
@@ -810,7 +822,6 @@ sub new_other_page() {
         'bool',
         '3.7.8.42',
         '0',
-        undef,
     ],
     zero_char => [
         'zero_replacement_char',
@@ -819,7 +830,6 @@ sub new_other_page() {
         'char,1,1',
         '2.8.1.77',
         '0',
-        undef,
     ],
     type_any => [
         'type_any_header',
@@ -828,7 +838,6 @@ sub new_other_page() {
         'bool',
         '3.12.0.44',
         '0',
-        undef,
     ],
     next_del => [
         'next_on_delete',
@@ -837,7 +846,6 @@ sub new_other_page() {
         'bool',
         '3.13.0.5',
         '0',
-        undef,
     ],
 );
 
@@ -863,20 +871,20 @@ sub new_gui_page() {
                              new_check_button_for (\%pr::gui, 'two_linev', \%HPVALUE),
                              new_check_button_for (\%pr::gui, 'next_del', \%HPVALUE),
                              new_selection_box_for (\%pr::gui, 'from_show', \%HPVALUE)),
-                         $xl::s{mlist_frame}, 'not-packed'), 
+                         $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', \%HPVALUE),
                              new_check_button_for (\%pr::gui, 'mview_date', \%HPVALUE)),
-                         $xl::s{mview_frame}, 'not-packed'), 
+                         $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', \%HPVALUE),
                              new_check_button_for (\%pr::gui, 'margin_co', \%HPVALUE),
                              new_check_button_for (\%pr::gui, 'type_any', \%HPVALUE)),
-                         $xl::s{compo_frame}, 'not-packed'), 
+                         $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);
@@ -899,7 +907,6 @@ sub new_gui_page() {
         'int,100,3000', # 0.1 seconds - 3 seconds
         '0.0.0',
         '500',
-        undef,
     ],
     dangerous => [
         'live_dangerously',
@@ -908,7 +915,6 @@ sub new_gui_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     flowed => [
         'respect_flowed_format',
@@ -917,7 +923,6 @@ sub new_gui_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     parts_rw => [
         'save_parts_readwrite',
@@ -926,7 +931,6 @@ sub new_gui_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     skip_ssl => [
         'skip_ssl_cert_check',
@@ -935,7 +939,6 @@ sub new_gui_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     up_step => [
         'statusbar_update_step',
@@ -944,7 +947,6 @@ sub new_gui_page() {
         'int,1,200', # 1 item - 200 items
         '0.0.0',
         '10',
-        undef,
     ],
     thread_a => [
         'thread_by_subject_max_age',
@@ -953,7 +955,6 @@ sub new_gui_page() {
         'int,1,30', # 1 day - 30 days
         '0.0.0',
         '10',
-        undef,
     ],
     unsafe_ssl => [
         'unsafe_ssl_certs',
@@ -962,7 +963,6 @@ sub new_gui_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     use_utf8 => [
         'utf8_instead_of_locale_for_broken_mail',
@@ -971,7 +971,6 @@ sub new_gui_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     warn_dnd => [
         'warn_dnd',
@@ -980,7 +979,6 @@ sub new_gui_page() {
         'bool',
         '0.0.0',
         '1',
-        undef,
     ],
     out_ascii => [
         'outgoing_fallback_to_ascii',
@@ -989,7 +987,6 @@ sub new_gui_page() {
         'bool',
         '3.4.0.37',
         '1',
-        undef,
     ],
     pp_unsel => [
         'primary_paste_unselects',
@@ -998,7 +995,6 @@ sub new_gui_page() {
         'bool',
         '3.6.1.35',
         '0',
-        undef,
     ],
     inline_at => [
         'show_inline_attachments',
@@ -1007,7 +1003,6 @@ sub new_gui_page() {
         'bool',
         '3.7.8.48',
         '1',
-        undef,
     ],
     addr_swc => [
         'address_search_wildcard',
@@ -1016,7 +1011,6 @@ sub new_gui_page() {
         'bool',
         '3.9.3.18',
         '0',
-        undef,
     ],
     fold_swc => [
         'folder_search_wildcard',
@@ -1025,7 +1019,14 @@ sub new_gui_page() {
         'bool',
         '3.9.3.18',
         '0',
-        undef,
+    ],
+    rewrite_ff => [
+        'rewrite_first_from',
+        $xl::s{l_beh_rewrite_ff},
+        $xl::s{h_beh_rewrite_ff},
+        'bool',
+        '3.14.0.94',
+        '0',
     ],
 );
 
@@ -1040,7 +1041,7 @@ sub new_behaviour_page() {
                          new_vbox_pack (
                              new_text_box_for_int (\%pr::beh, 'hover_t', \%HPVALUE),
                              new_check_button_for (\%pr::beh, 'warn_dnd', \%HPVALUE)),
-                         $xl::s{dnd_frame}, 'not-packed'), 
+                         $xl::s{dnd_frame}, 'not-packed'),
                      FALSE, FALSE, FRAME_SPC);
     $bf->pack_start (new_subpage_frame (
                          new_hbox_pack (
@@ -1058,7 +1059,8 @@ sub new_behaviour_page() {
                              new_check_button_for (\%pr::beh, 'dangerous', \%HPVALUE),
                              new_check_button_for (\%pr::beh, 'out_ascii', \%HPVALUE),
                              new_check_button_for (\%pr::beh, 'pp_unsel', \%HPVALUE),
-                             new_check_button_for (\%pr::beh, 'inline_at', \%HPVALUE)),
+                             new_check_button_for (\%pr::beh, 'inline_at', \%HPVALUE),
+                             new_check_button_for (\%pr::beh, 'rewrite_ff', \%HPVALUE)),
                          $xl::s{msgs_frame}, 'not-packed'),
                      FALSE, FALSE, FRAME_SPC);
     $bf->pack_start (new_subpage_frame (
@@ -1078,7 +1080,6 @@ sub new_behaviour_page() {
         'color',
         '0.0.0',
         '#0000cf',
-        undef,
     ],
     log_err => [
         'log_error_color',
@@ -1087,7 +1088,6 @@ sub new_behaviour_page() {
         'color',
         '0.0.0',
         '#af0000',
-        undef,
     ],
     log_in => [
         'log_in_color',
@@ -1096,7 +1096,6 @@ sub new_behaviour_page() {
         'color',
         '0.0.0',
         '#000000',
-        undef,
     ],
     log_msg => [
         'log_msg_color',
@@ -1105,7 +1104,6 @@ sub new_behaviour_page() {
         'color',
         '0.0.0',
         '#00af00',
-        undef,
     ],
     log_out => [
         'log_out_color',
@@ -1114,7 +1112,6 @@ sub new_behaviour_page() {
         'color',
         '0.0.0',
         '#0000ef',
-        undef,
     ],
     log_warn => [
         'log_warn_color',
@@ -1123,7 +1120,6 @@ sub new_behaviour_page() {
         'color',
         '0.0.0',
         '#af0000',
-        undef,
     ],
     diff_add => [
         'diff_added_color',
@@ -1132,7 +1128,6 @@ sub new_behaviour_page() {
         'color',
         '3.8.0.54',
         '#008b8b',
-        undef,
     ],
     diff_del => [
         'diff_deleted_color',
@@ -1141,7 +1136,6 @@ sub new_behaviour_page() {
         'color',
         '3.8.0.54',
         '#6a5acd',
-        undef,
     ],
     diff_hunk => [
         'diff_hunk_color',
@@ -1150,7 +1144,6 @@ sub new_behaviour_page() {
         'color',
         '3.8.0.54',
         '#a52a2a',
-        undef,
     ],
 );
 
@@ -1185,7 +1178,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '16',
-        undef,
     ],
     main_y => [
         'mainwin_y',
@@ -1194,7 +1186,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '16',
-        undef,
     ],
     main_w => [
         'mainwin_width',
@@ -1203,7 +1194,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '779',
-        undef,
     ],
     main_h => [
         'mainwin_height',
@@ -1212,7 +1202,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '568',
-        undef,
     ],
     main_mx => [
         'mainwin_maximised',
@@ -1221,7 +1210,6 @@ sub new_colours_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     main_fs => [
         'mainwin_fullscreen',
@@ -1230,7 +1218,6 @@ sub new_colours_page() {
         'bool',
         '0.0.0',
         '0',
-        undef,
     ],
     msgs_x => [
         'main_messagewin_x',
@@ -1239,7 +1226,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '256',
-        undef,
     ],
     msgs_y => [
         'main_messagewin_y',
@@ -1248,7 +1234,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '210',
-        undef,
     ],
     msgs_w => [
         'messagewin_width',
@@ -1257,7 +1242,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '600',
-        undef,
     ],
     msgs_h => [
         'messagewin_height',
@@ -1266,7 +1250,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '540',
-        undef,
     ],
     send_w => [
         'sendwin_width',
@@ -1275,7 +1258,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '460',
-        undef,
     ],
     send_h => [
         'sendwin_height',
@@ -1284,7 +1266,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     recv_w => [
         'receivewin_width',
@@ -1293,7 +1274,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '460',
-        undef,
     ],
     recv_h => [
         'receivewin_height',
@@ -1302,7 +1282,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     fold_x => [
         'folderwin_x',
@@ -1311,7 +1290,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '16',
-        undef,
     ],
     fold_y => [
         'folderwin_y',
@@ -1320,7 +1298,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '16',
-        undef,
     ],
     fold_w => [
         'folderitemwin_width',
@@ -1329,7 +1306,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '500',
-        undef,
     ],
     fold_h => [
         'folderitemwin_height',
@@ -1338,7 +1314,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     fsel_w => [
         'folderselwin_width',
@@ -1347,7 +1322,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '300',
-        undef,
     ],
     fsel_h => [
         'folderselwin_height',
@@ -1356,7 +1330,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     sour_w => [
         'sourcewin_width',
@@ -1365,7 +1338,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '600',
-        undef,
     ],
     sour_h => [
         'sourcewin_height',
@@ -1374,7 +1346,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '500',
-        undef,
     ],
     addr_w => [
         'addressbookwin_width',
@@ -1383,7 +1354,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '520',
-        undef,
     ],
     addr_h => [
         'addressbookwin_height',
@@ -1392,7 +1362,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     adep_w => [
         'addressbookeditpersonwin_width',
@@ -1401,7 +1370,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '640',
-        undef,
     ],
     adep_h => [
         'addressbookeditpersonwin_height',
@@ -1410,7 +1378,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '320',
-        undef,
     ],
     adeg_w => [
         'addressbookeditgroupwin_width',
@@ -1419,7 +1386,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '580',
-        undef,
     ],
     adeg_h => [
         'addressbookeditgroupwin_height',
@@ -1428,7 +1394,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '340',
-        undef,
     ],
     adda_w => [
         'addressaddwin_width',
@@ -1437,7 +1402,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '300',
-        undef,
     ],
     adda_h => [
         'addressaddwin_height',
@@ -1446,7 +1410,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     addf_w => [
         'addressbook_folderselwin_width',
@@ -1455,7 +1418,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '300',
-        undef,
     ],
     addf_h => [
         'addressbook_folderselwin_height',
@@ -1464,7 +1426,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     acce_w => [
         'editaccountwin_width',
@@ -1473,7 +1434,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '500',
-        undef,
     ],
     acce_h => [
         'editaccountwin_height',
@@ -1482,7 +1442,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     acco_w => [
         'accountswin_width',
@@ -1491,7 +1450,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '500',
-        undef,
     ],
     acco_h => [
         'accountswin_height',
@@ -1500,7 +1458,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     filt_w => [
         'filteringwin_width',
@@ -1509,7 +1466,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '500',
-        undef,
     ],
     filt_h => [
         'filteringwin_height',
@@ -1518,7 +1474,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     fila_w => [
         'filteringactionwin_width',
@@ -1527,7 +1482,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '490',
-        undef,
     ],
     fila_h => [
         'filteringactionwin_height',
@@ -1536,7 +1490,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     fild_w => [
         'filtering_debugwin_width',
@@ -1545,7 +1498,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '600',
-        undef,
     ],
     fild_h => [
         'filtering_debugwin_height',
@@ -1554,7 +1506,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     matc_w => [
         'matcherwin_width',
@@ -1563,7 +1514,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '520',
-        undef,
     ],
     matc_h => [
         'matcherwin_height',
@@ -1572,7 +1522,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     pref_w => [
         'prefswin_width',
@@ -1581,7 +1530,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '600',
-        undef,
     ],
     pref_h => [
         'prefswin_height',
@@ -1590,7 +1538,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     temp_w => [
         'templateswin_width',
@@ -1599,7 +1546,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '480',
-        undef,
     ],
     temp_h => [
         'templateswin_height',
@@ -1608,7 +1554,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     acti_w => [
         'actionswin_width',
@@ -1617,7 +1562,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '486',
-        undef,
     ],
     acti_h => [
         'actionswin_height',
@@ -1626,7 +1570,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     tags_w => [
         'tagswin_width',
@@ -1635,7 +1578,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '486',
-        undef,
     ],
     tags_h => [
         'tagswin_height',
@@ -1644,7 +1586,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     plug_w => [
         'pluginswin_width',
@@ -1653,7 +1594,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     plug_h => [
         'pluginswin_height',
@@ -1662,7 +1602,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     logw_w => [
         'logwin_width',
@@ -1671,7 +1610,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '520',
-        undef,
     ],
     logw_h => [
         'logwin_height',
@@ -1680,7 +1618,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
     prin_w => [
         'print_previewwin_width',
@@ -1689,7 +1626,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '600',
-        undef,
     ],
     prin_h => [
         'print_previewwin_height',
@@ -1698,7 +1634,6 @@ sub new_colours_page() {
         'int,0,3000', # 0 pixels - 3000 pixels
         '0.0.0',
         '-1',
-        undef,
     ],
 );
 
@@ -1908,16 +1843,14 @@ sub new_winpos_page() {
         'bool',
         '3.9.0.181',
         '0',
-        undef,
     ],
     tls_pri => [
         'gnutls_priority',
         $xl::s{l_acc_gtls_pri},
         $xl::s{h_acc_gtls_pri},
-        'char,32,32',
+        'char,0,256,32',
         '3.9.0.181',
         '0',
-        undef,
     ],
 );
 
@@ -1935,34 +1868,210 @@ sub new_account_subpage($) {
 sub new_accounts_page() {
     my $accbook = Gtk2::Notebook->new;
     $accbook->set_tab_pos ('right');
-    foreach (keys %ACPREFS) {
+    my @akeys = sort {
+        $ACPREFS{$a}{'account_name'} cmp $ACPREFS{$b}{'account_name'}
+    } keys %ACPREFS;
+    foreach (@akeys) {
         my $name = $ACPREFS{$_}{'account_name'};
-        $accbook->append_page (new_account_subpage ($_), $name);
+        my $isdef = ($ACPREFS{$_}{'is_default'} eq '1');
+        my $page = new_account_subpage ($_);
+        $accbook->append_page ($page, $isdef? '<b>' . $name . '</b>': $name);
+        if ($isdef) {
+            my $label = $accbook->get_tab_label ($page);
+            $label->set_use_markup (TRUE);
+        }
     }
     return $accbook;
 }
 
+%pr::plu = ( # plugins hidden preferences
+    # att_remover
+    arm_winw => [
+        'win_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '3.9.0.74',
+        '-1',
+        'AttRemover',
+    ],
+    arm_winh => [
+        'win_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '3.9.0.74',
+        '-1',
+        'AttRemover',
+    ],
+    # GPG
+    gpg_alimit => [
+        'autocompletion_limit',
+        $xl::s{l_plu_gpg_alimit},
+        $xl::s{h_plu_gpg_alimit},
+        'int,0,100',
+        '3.12.0.75',
+        '0',
+        'GPG',
+    ],
+    # managesieve
+    msv_winw => [
+        'manager_win_width',
+        $xl::s{l_win_w},
+        $xl::s{h_win_w},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '3.11.1.210',
+        '-1',
+        'ManageSieve',
+    ],
+    msv_winh => [
+        'manager_win_height',
+        $xl::s{l_win_h},
+        $xl::s{h_win_h},
+        'int,0,3000', # 0 pixels - 3000 pixels
+        '3.11.1.210',
+        '-1',
+        'ManageSieve',
+    ],
+    # libravatar
+    lav_burl => [
+        'base_url',
+        $xl::s{l_plu_lav_burl},
+        $xl::s{h_plu_lav_burl},
+        'char,0,1024,32',
+        '3.9.3.32',
+        'http://cdn.libravatar.org/avatar',
+        'Libravatar',
+    ],
+    # perl
+    prl_flvb => [
+        'filter_log_verbosity',
+        $xl::s{l_plu_prl_flvb},
+        $xl::s{h_plu_prl_flvb},
+        '0=l_plu_prl_none;1=l_plu_prl_manual;2=l_plu_prl_action;3=l_plu_prl_match',
+        '3.9.0.75',
+        '2',
+        'PerlPlugin',
+    ],
+);
+
+sub new_plugins_page() {
+    my %frame = ();
+    $frame{'AttRemover'} =
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::plu, 'arm_winw', $PLHPVALUE{'AttRemover'}),
+                          new_text_box_for_int (\%pr::plu, 'arm_winh', $PLHPVALUE{'AttRemover'})),
+                     _('Attachment remover'), 'not-packed');
+    $frame{'GPG'} =
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::plu, 'gpg_alimit', $PLHPVALUE{'GPG'})),
+                     _('GPG'), 'not-packed');
+    $frame{'ManageSieve'} =
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_int (\%pr::plu, 'msv_winw', $PLHPVALUE{'ManageSieve'}),
+                          new_text_box_for_int (\%pr::plu, 'msv_winh', $PLHPVALUE{'ManageSieve'})),
+                     _('Sieve manager'), 'not-packed');
+    $frame{'Libravatar'} =
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_text_box_for_nchar (\%pr::plu, 'lav_burl', $PLHPVALUE{'Libravatar'})),
+                     _('Libravatar'), 'not-packed');
+    $frame{'PerlPlugin'} =
+                new_subpage_frame (
+                     new_hbox_pack (
+                          new_selection_box_for (\%pr::plu, 'prl_flvb', $PLHPVALUE{'PerlPlugin'})),
+                     _('Perl'), 'not-packed');
+    foreach (@PLUGINS) {
+        $frame{$_}->set_sensitive (defined $PLHPVALUE{$_});
+    }
+    return new_vbox_pack (
+                $frame{'AttRemover'},
+                $frame{'GPG'},
+                $frame{'ManageSieve'},
+                $frame{'Libravatar'},
+                $frame{'PerlPlugin'});
+}
+
+sub new_info_page() {
+    my $t0 = Gtk2::Table->new (7, 2, FALSE);
+    my $v = get_toolkit_versions ();
+    my %labels = (
+        'glib' => 'Perl-GLib',
+        'glib-r' => _('GLib runtime'),
+        'glib-b' => _('GLib built'),
+        'gtk2' => 'Perl-GTK2',
+        'gtk2-r' => _('GTK2 runtime'),
+        'gtk2-b' => _('GTK2 built'),
+    );
+    my $row = 0;
+    foreach (sort keys %$v) {
+        if (defined $v->{$_}) {
+            my $label = Gtk2::Label->new ($labels{$_});
+            my $value = Gtk2::Label->new ('<b>' . $v->{$_} . '</b>');
+            $label->set_alignment (0, 0.5);
+            $value->set_alignment (0, 0.5);
+            $value->set_use_markup (TRUE);
+            $t0->attach ($label, 0, 1, $row, $row + 1, 'fill', 'shrink', 8, 6);
+            $t0->attach ($value, 1, 2, $row, $row + 1, 'fill', 'shrink', 8, 6);
+            ++$row;
+        }
+    }
+    my $t1 = Gtk2::Table->new (2, 2, FALSE);
+    my @lbl = map { $_->set_alignment (0, 0.5); $_ } (
+        Gtk2::Label->new (_('Binary')),
+        Gtk2::Label->new (_('Configuration'))
+    );
+    my $cfgv = $CONFIGDATA->{'Common'}{'config_version'};
+    $cfgv //= '';
+    my @val = map { $_->set_alignment (0, 0.5); $_->set_use_markup (TRUE); $_ } (
+        Gtk2::Label->new ('<b>' . $CLAWSV . '</b>'),
+        Gtk2::Label->new ('<b>' . $cfgv . '</b>')
+    );
+    for (my $i = 0; $i <= $#lbl; ++$i) {
+        $t1->attach ($lbl[$i], 0, 1, $i, $i + 1, 'fill', 'shrink', 8, 6);
+        $t1->attach ($val[$i], 1, 2, $i, $i + 1, 'fill', 'shrink', 8, 6);
+    }
+    return new_vbox_pack (
+                new_subpage_frame ($t0, _('Library versions'), 'not-packed'),
+                new_subpage_frame ($t1, _('Claws Mail versions'), 'not-packed'));
+}
+
 # version info
-sub print_version() {
-    print $xl::s{about_title} . "\n";
-    print $xl::s{about_version} . " $VERSION\n";
-    print "Perl-GLib " . $Glib::VERSION;
+sub get_toolkit_versions {
+    my %versions = ();
+    $versions{'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);
+        $versions{'glib-b'} = join('.', Glib->GET_VERSION_INFO);
+        $versions{'glib-r'} = join('.',
+            &Glib::major_version, &Glib::minor_version, &Glib::micro_version);
     }
-    print "\n";
-    print "Perl-GTK2 " . $Gtk2::VERSION;
+    $versions{'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);
+        $versions{'gtk2-b'} = join('.', Gtk2->GET_VERSION_INFO);
+        $versions{'gtk2-r'} = join('.',
+            &Gtk2::major_version, &Gtk2::minor_version, &Gtk2::micro_version);
     }
+    return \%versions;
+}
+
+sub print_version() {
+    print $xl::s{about_title} . "\n";
+    print $xl::s{about_version} . " $VERSION\n";
+    my $v = get_toolkit_versions ();
+    print "Perl-GLib " . $v->{'glib'};
+    print _(", built for ") . $v->{'glib-b'}
+        . _(", running with ") . $v->{'glib-r'} if $v->{'glib-b'};
+    print "\n";
+    print "Perl-GTK2 " . $v->{'gtk2'};
+    print _(", built for ") . $v->{'gtk2-b'}
+        . _(", running with ") . $v->{'gtk2-r'} if $v->{'gtk2-b'};
     print "\n";
-    my $clawsver = ($CLAWSV eq "") ? 
-                _("was not found!") : 
+    my $clawsver = ($CLAWSV eq "") ?
+                _("was not found!") :
                 (_("returned version ") . $CLAWSV);
     print "Claws Mail " . $clawsver . "\n";
 }
@@ -1976,11 +2085,12 @@ sub print_help() {
     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 _("  -b|--verbose                     More messages on standard output.\n");
     print _("  -c|--clawsrc <file>              Uses <file> as full resource name.\n");
+    print _("  -h|--help                        Prints this help screen.\n");
+    print _("  -r|--read-only                   Disables writing changes to disk.\n");
+    print _("  -v|--version                     Prints version infos.\n");
 }
 
 sub parse_command_line {
@@ -1990,9 +2100,10 @@ sub parse_command_line {
         GetOptions('h|help' => sub { print_help (); $cont = FALSE },
             'v|version' => sub { print_version (); $cont = FALSE },
             'b|verbose' => sub { $VERBOSE = TRUE },
+            'r|read-only' => sub { $READONLY = TRUE },
             'u|use-claws-version=s' => \&opt_use_claws_version,
             'a|alternate-config-dir=s' => \&opt_alternate_config_dir,
-            'r|clawsrc=s' => \&opt_clawsrc)
+            'c|clawsrc=s' => \&opt_clawsrc)
         or die _("try -h or --help for syntax.\n");
     };
     if ($@) {
@@ -2032,7 +2143,7 @@ sub opt_clawsrc {
 # 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) { 
+        foreach my $key (keys %$hash) {
             $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
         }
     }
@@ -2049,20 +2160,100 @@ sub init_ac_hidden_preferences {
     return TRUE;
 }
 
+sub init_plu_hidden_preferences {
+    foreach my $key (keys %pr::plu) {
+        my $plugin = $pr::plu{$key}[PLUGIN];
+        my $pname = $pr::plu{$key}[NAME];
+        if (defined $PLPREFS{$plugin}) {
+            $PLHPVALUE{$plugin}{$pname} = $PLPREFS{$plugin}{$pname};
+        }
+    }
+    return TRUE;
+}
+
+# generic load/save resource files
+sub load_resource {
+    my $rc = shift;
+    my %data = ();
+    my %meta = ();
+    my $line = 0;
+    open (RCF, '<:encoding(utf8)', $rc)
+        or die _("Error: opening '{file}' for reading", file => $rc) . ": $!\n";
+    my $section = '_'; # default unnamed section
+    while (<RCF>) {
+        chomp;
+        ++$line;
+        next if (/^\s*$/);
+        if (/^\[([^\]]+)\]$/) { # new section
+            $section = $1;
+            die _("Error: duplicate section '{sect}' in resource file '{file}'\n",
+                sect => $section, file => $rc) if ($data{$section});
+            $data{$section} = {};
+            $meta{$section}{'#'} = $line;
+        }
+        elsif (/^([0-9a-z_]+)=(.*)$/) { # key=value
+            $data{$section}{$1} = $2;
+            $meta{$section}{$1} = $line;
+        }
+        elsif (/^(.*)$/) { # lone value
+            push (@{$data{$section}{'_'}}, $1);
+        }
+    }
+    close (RCF);
+    return (\%data, \%meta);
+}
+
+sub save_resource {
+    my ($rc, $data, $meta) = @_;
+    open (RCF, '>:utf8', $rc)
+        or die _("Error: opening '{file}' for writing", file => $rc) . ": $!\n";
+    my @sections = keys %$data;
+    if (defined $meta) {
+        @sections = sort {
+            $meta->{$a}{'#'} <=> $meta->{$b}{'#'}
+        } @sections
+    }
+    foreach my $section (@sections) {
+        say RCF "[$section]";
+        if (ref ($data->{$section}{'_'}) eq 'ARRAY') {
+            foreach my $val (@{$data->{$section}{'_'}}) {
+                say RCF $val;
+            }
+        } else {
+            my @keys = keys %{$data->{$section}};
+            if (defined $meta) {
+                @keys = sort {
+                    $meta->{$section}{$a} <=> $meta->{$section}{$b}
+                } @keys
+            }
+            foreach my $key (@keys) {
+                my $val = $data->{$section}{$key};
+                say RCF "$key=$val";
+            }
+        }
+        say RCF "";
+    }
+    close (RCF);
+}
+
 # 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} = decode('UTF-8', $2);
+    ($CONFIGDATA, $CONFIGMETA) = load_resource ($rc);
+    foreach (keys %{$CONFIGDATA->{'Common'}}) {
+        $PREFS{$_} = $CONFIGDATA->{'Common'}{$_};
+    }
+    foreach my $plugin (@PLUGINS) {
+        if (defined $CONFIGDATA->{$plugin}) {
+            push (@AVPLUGINS, $plugin);
+            foreach (keys %{$CONFIGDATA->{$plugin}}) {
+                $PLPREFS{$plugin}{$_} = $CONFIGDATA->{$plugin}{$_};
+            }
         }
     }
-    close (RCF);
     return TRUE;
 }
 
@@ -2071,19 +2262,14 @@ sub load_ac_preferences {
     log_message ("Loading account preferences from $rc\n");
     return FALSE unless check_rc_file ($rc);
     return FALSE unless check_claws_not_running ();
-    open (RCF, "<$rc");
-    my $akey;
-    while (<RCF>) {
-        chomp;
-        if (/^\[Account: (\d+)\]$/) {
-          $akey = $1;
-          next;
-        }
-        if (/^([8a-z_]+)=(.*)$/) {
-            $ACPREFS{$akey}{$1} = decode('UTF-8', $2);
+    ($ACCOUNTDATA, $ACCOUNTMETA) = load_resource ($rc);
+    foreach my $asect (keys %$ACCOUNTDATA) {
+        if ($asect =~ /^Account: (\d+)$/) {
+            foreach (keys %{$ACCOUNTDATA->{$asect}}) {
+                $ACPREFS{$1}{$_} = $ACCOUNTDATA->{$asect}{$_};
+            }
         }
     }
-    close (RCF);
     return TRUE;
 }
 
@@ -2095,24 +2281,19 @@ sub save_preferences {
     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";
-            }
+    foreach (keys %PREFS) {
+        if (defined $HPVALUE{$_}) {
+            $CONFIGDATA->{'Common'}{$_} = $HPVALUE{$_};
         }
-        else {
-            print RCF $_ . "\n";
+    }
+    foreach my $plugin (@AVPLUGINS) {
+        foreach (keys %{$CONFIGDATA->{$plugin}}) {
+            if (defined $PLHPVALUE{$plugin}{$_}) {
+                $CONFIGDATA->{$plugin}{$_} = $PLHPVALUE{$plugin}{$_};
+            }
         }
     }
-    close (RCB);
-    close (RCF);
+    save_resource ($rc, $CONFIGDATA, $CONFIGMETA);
     return TRUE;
 }
 
@@ -2123,43 +2304,31 @@ sub save_ac_preferences {
     return FALSE unless check_claws_not_running ();
     my $rcbak = "$rc.backup";
     rename ($rc, $rcbak);
-    open (RCF, ">$rc");
-    open (RCB, "<$rcbak");
-    my $akey;
-    while (<RCB>) {
-        chomp;
-        if (/^\[Account: (\d+)\]$/) {
-          $akey = $1;
-          print RCF $_ . "\n";
-          next;
-        }
-        if (/^([8a-z_]+)=(.*)$/) {
-            if (defined($ACHPVALUE{$akey}{$1})) {
-                print RCF $1 . "=" . $ACHPVALUE{$akey}{$1} . "\n";
-            }
-            else {
-                print RCF $_ . "\n";
+    foreach my $asect (keys %$ACCOUNTDATA) {
+        if ($asect =~ /^Account: (\d+)$/) {
+            foreach (keys %{$ACCOUNTDATA->{$asect}}) {
+                if (defined $ACHPVALUE{$1}{$_}) {
+                    $ACCOUNTDATA->{$asect}{$_} = $ACHPVALUE{$1}{$_};
+                }
             }
         }
-        else {
-            print RCF $_ . "\n";
-        }
     }
-    close (RCB);
-    close (RCF);
+    save_resource ($rc, $ACCOUNTDATA, $ACCOUNTMETA);
     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});
     $nb->append_page (new_accounts_page (), $xl::s{tab_accounts});
+    $nb->append_page (new_plugins_page (), $xl::s{tab_plugins});
+    $nb->append_page (new_info_page (), $xl::s{tab_info});
 
     return $nb;
 }
@@ -2170,7 +2339,7 @@ sub new_about_dialog {
     my $title = $xl::s{about_title};
     my $lic = $xl::s{about_license};
     my $vers = $xl::s{about_version} . " $VERSION";
-    my $license = 
+    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
@@ -2187,9 +2356,9 @@ along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
     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', 
+    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"
@@ -2197,6 +2366,13 @@ along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
                     . "<span size=\"large\">$lic</span>\n\n"
                     . "<span size=\"small\">$license</span>");
     $dialog->set_title ($xl::s{about});
+    if (Gtk2->CHECK_VERSION (2, 10, 0)) {
+        my @icons = get_app_icons ();
+        my $image = Gtk2::Image->new_from_pixbuf ($icons[1]);
+        $image->show ();
+        $image->set_alignment (0, 0);
+        $dialog->set_image ($image);
+    }
     #
     return $dialog;
 }
@@ -2210,8 +2386,9 @@ sub new_button_box {
     # 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 
+    # signal handlers
     $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
+    $b_apply->set_sensitive (not $READONLY);
     $b_apply->signal_connect (clicked => sub {
         save_preferences ($parent);
         save_ac_preferences ($parent);
@@ -2228,17 +2405,24 @@ sub new_button_box {
 }
 
 sub get_app_icons {
-    my $dir = $DATADIR . '/icons/hicolor';
-    my @names = map {
-      join ('/', ($dir, , $_ . 'x' . $_, 'apps', $NAME . '.png'))
-    } (64, 128);
-    my @icons = ();
+    return @APPICONS if (@APPICONS);
+    my @names;
+    if (-d $DATADIR) { # installed
+        my $dir = $DATADIR . '/icons/hicolor';
+        @names = map {
+            join ('/', ($dir, $_ . 'x' . $_, 'apps', $NAME . '.png'))
+        } (64, 128);
+    } else { # unpacked tarball or git clone
+        @names = map {
+            join ('/', ('./icons', $NAME . '-' . $_ . '.png'));
+        } (64, 128);
+    }
     foreach (@names) {
         my $icon = undef;
         $icon = Gtk2::Gdk::Pixbuf->new_from_file($_) if (-f $_);
-        push @icons, $icon if ($icon);
+        push @APPICONS, $icon if ($icon);
     }
-    return @icons;
+    return @APPICONS;
 }
 
 # initialise
@@ -2249,6 +2433,7 @@ exit unless load_preferences ();
 exit unless load_ac_preferences ();
 exit unless init_hidden_preferences ();
 exit unless init_ac_hidden_preferences ();
+exit unless init_plu_hidden_preferences ();
 # create main GUI
 my $box = Gtk2::VBox->new (FALSE, 5);
 $box->set_border_width(3);