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