Use bold label for default account tab
[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     foreach (keys %ACPREFS) {
1858         my $name = $ACPREFS{$_}{'account_name'};
1859         my $isdef = ($ACPREFS{$_}{'is_default'} eq '1');
1860         my $page = new_account_subpage ($_);
1861         $accbook->append_page ($page, $isdef? '<b>' . $name . '</b>': $name);
1862         if ($isdef) {
1863             my $label = $accbook->get_tab_label ($page);
1864             $label->set_use_markup (TRUE);
1865         }
1866     }
1867     return $accbook;
1868 }
1869
1870 %pr::plu = ( # plugins hidden preferences
1871     # att_remover
1872     arm_winw => [
1873         'win_width',
1874         $xl::s{l_win_w},
1875         $xl::s{h_win_w},
1876         'int,0,3000', # 0 pixels - 3000 pixels
1877         '3.9.0.74',
1878         '-1',
1879         'AttRemover',
1880     ],
1881     arm_winh => [
1882         'win_height',
1883         $xl::s{l_win_h},
1884         $xl::s{h_win_h},
1885         'int,0,3000', # 0 pixels - 3000 pixels
1886         '3.9.0.74',
1887         '-1',
1888         'AttRemover',
1889     ],
1890     # GPG
1891     gpg_alimit => [
1892         'autocompletion_limit',
1893         $xl::s{l_plu_gpg_alimit},
1894         $xl::s{h_plu_gpg_alimit},
1895         'int,0,100',
1896         '3.12.0.75',
1897         '0',
1898         'GPG',
1899     ],
1900     # managesieve
1901     msv_winw => [
1902         'manager_win_width',
1903         $xl::s{l_win_w},
1904         $xl::s{h_win_w},
1905         'int,0,3000', # 0 pixels - 3000 pixels
1906         '3.11.1.210',
1907         '-1',
1908         'ManageSieve',
1909     ],
1910     msv_winh => [
1911         'manager_win_height',
1912         $xl::s{l_win_h},
1913         $xl::s{h_win_h},
1914         'int,0,3000', # 0 pixels - 3000 pixels
1915         '3.11.1.210',
1916         '-1',
1917         'ManageSieve',
1918     ],
1919     # libravatar
1920     lav_burl => [
1921         'base_url',
1922         $xl::s{l_plu_lav_burl},
1923         $xl::s{h_plu_lav_burl},
1924         'char,0,1024,32',
1925         '3.9.3.32',
1926         'http://cdn.libravatar.org/avatar',
1927         'Libravatar',
1928     ],
1929     # perl
1930     prl_flvb => [
1931         'filter_log_verbosity',
1932         $xl::s{l_plu_prl_flvb},
1933         $xl::s{h_plu_prl_flvb},
1934         '0=l_plu_prl_none;1=l_plu_prl_manual;2=l_plu_prl_action;3=l_plu_prl_match',
1935         '3.9.0.75',
1936         '2',
1937         'PerlPlugin',
1938     ],
1939 );
1940
1941 sub new_plugins_page() {
1942     my %frame = ();
1943     $frame{'AttRemover'} =
1944                 new_subpage_frame (
1945                      new_hbox_pack (
1946                           new_text_box_for_int (\%pr::plu, 'arm_winw', $PLHPVALUE{'AttRemover'}),
1947                           new_text_box_for_int (\%pr::plu, 'arm_winh', $PLHPVALUE{'AttRemover'})),
1948                      _('Attachment remover'), 'not-packed');
1949     $frame{'GPG'} =
1950                 new_subpage_frame (
1951                      new_hbox_pack (
1952                           new_text_box_for_int (\%pr::plu, 'gpg_alimit', $PLHPVALUE{'GPG'})),
1953                      _('GPG'), 'not-packed');
1954     $frame{'ManageSieve'} =
1955                 new_subpage_frame (
1956                      new_hbox_pack (
1957                           new_text_box_for_int (\%pr::plu, 'msv_winw', $PLHPVALUE{'ManageSieve'}),
1958                           new_text_box_for_int (\%pr::plu, 'msv_winh', $PLHPVALUE{'ManageSieve'})),
1959                      _('Sieve manager'), 'not-packed');
1960     $frame{'Libravatar'} =
1961                 new_subpage_frame (
1962                      new_hbox_pack (
1963                           new_text_box_for_nchar (\%pr::plu, 'lav_burl', $PLHPVALUE{'Libravatar'})),
1964                      _('Libravatar'), 'not-packed');
1965     $frame{'PerlPlugin'} =
1966                 new_subpage_frame (
1967                      new_hbox_pack (
1968                           new_selection_box_for (\%pr::plu, 'prl_flvb', $PLHPVALUE{'PerlPlugin'})),
1969                      _('Perl'), 'not-packed');
1970     foreach (@PLUGINS) {
1971         $frame{$_}->set_sensitive (defined $PLHPVALUE{$_});
1972     }
1973     return new_vbox_pack (
1974                 $frame{'AttRemover'},
1975                 $frame{'GPG'},
1976                 $frame{'ManageSieve'},
1977                 $frame{'Libravatar'},
1978                 $frame{'PerlPlugin'});
1979 }
1980
1981 # version info
1982 sub get_toolkit_versions {
1983     my %versions = ();
1984     $versions{'glib'} = $Glib::VERSION;
1985     # version info stuff appeared in 1.040
1986     if ($Glib::VERSION >= 1.040) {
1987         $versions{'glib-b'} = join('.', Glib->GET_VERSION_INFO);
1988         $versions{'glib-r'} = join('.',
1989             &Glib::major_version, &Glib::minor_version, &Glib::micro_version);
1990     }
1991     $versions{'gtk2'} = $Gtk2::VERSION;
1992     if ($Gtk2::VERSION >= 1.040) {
1993         $versions{'gtk2-b'} = join('.', Gtk2->GET_VERSION_INFO);
1994         $versions{'gtk2-r'} = join('.',
1995             &Gtk2::major_version, &Gtk2::minor_version, &Gtk2::micro_version);
1996     }
1997     return \%versions;
1998 }
1999
2000 sub print_version() {
2001     print $xl::s{about_title} . "\n";
2002     print $xl::s{about_version} . " $VERSION\n";
2003     my $v = get_toolkit_versions ();
2004     print "Perl-GLib " . $v->{'glib'};
2005     print _(", built for ") . $v->{'glib-b'}
2006         . _(", running with ") . $v->{'glib-r'} if $v->{'glib-b'};
2007     print "\n";
2008     print "Perl-GTK2 " . $v->{'gtk2'};
2009     print _(", built for ") . $v->{'gtk2-b'}
2010         . _(", running with ") . $v->{'gtk2-r'} if $v->{'gtk2-b'};
2011     print "\n";
2012     my $clawsver = ($CLAWSV eq "") ?
2013                 _("was not found!") :
2014                 (_("returned version ") . $CLAWSV);
2015     print "Claws Mail " . $clawsver . "\n";
2016 }
2017
2018 # the command line help
2019 sub print_help() {
2020     my $line = '-' x length ($xl::s{about_title}) . "\n";
2021     print $line;
2022     print $xl::s{about_title} . "\n";
2023     print $line;
2024     print _("Syntax:\n");
2025     print _("  clawsker [options]\n");
2026     print _("Options:\n");
2027     print _("  -a|--alternate-config-dir <dir>  Uses <dir> as Claws Mail config dir.\n");
2028     print _("  -b|--verbose                     More messages on standard output.\n");
2029     print _("  -c|--clawsrc <file>              Uses <file> as full resource name.\n");
2030     print _("  -h|--help                        Prints this help screen.\n");
2031     print _("  -r|--read-only                   Disables writing changes to disk.\n");
2032     print _("  -v|--version                     Prints version infos.\n");
2033 }
2034
2035 sub parse_command_line {
2036     my $cont = TRUE;
2037     $CLAWSV = get_claws_version ();
2038     eval {
2039         GetOptions('h|help' => sub { print_help (); $cont = FALSE },
2040             'v|version' => sub { print_version (); $cont = FALSE },
2041             'b|verbose' => sub { $VERBOSE = TRUE },
2042             'r|read-only' => sub { $READONLY = TRUE },
2043             'u|use-claws-version=s' => \&opt_use_claws_version,
2044             'a|alternate-config-dir=s' => \&opt_alternate_config_dir,
2045             'c|clawsrc=s' => \&opt_clawsrc)
2046         or die _("try -h or --help for syntax.\n");
2047     };
2048     if ($@) {
2049         my $msg = _("Error in options: {msg}\n", msg => $@);
2050         if (defined $ENV{'DISPLAY'} and $ENV{'DISPLAY'} ne '') {
2051             eval { Gtk2->init };
2052             error_dialog ($msg) unless $@;
2053         }
2054         die $msg;
2055     }
2056     return $cont;
2057 }
2058
2059 sub opt_use_claws_version {
2060     my ($name, $value) = @_;
2061     die _("Error: {opt} requires a dotted numeric value argument\n", opt => $name)
2062         unless ($value =~ /^[\d\.]+$/);
2063     $CLAWSV = $value;
2064 }
2065
2066 sub opt_alternate_config_dir {
2067     my ($name, $value) = @_;
2068     die _("Error: '{dir}' is not a directory or does not exist\n", dir => $value)
2069         unless -d $value;
2070     $CONFIGDIR = $value;
2071     $CONFIGDIR .= "/" unless ($CONFIGDIR =~ /.*\/$/);
2072     $ALTCONFIGDIR = TRUE;
2073 }
2074
2075 sub opt_clawsrc {
2076     my ($name, $value) = @_;
2077     die _("Error: '{value}' is not a file or does not exist\n", value => $value)
2078         unless -f $value;
2079     set_rc_filename ($value);
2080 }
2081
2082 # update the hidden preferences status from loaded values
2083 sub init_hidden_preferences {
2084     foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth, \%pr::win) {
2085         foreach my $key (keys %$hash) {
2086             $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
2087         }
2088     }
2089     return TRUE;
2090 }
2091
2092 sub init_ac_hidden_preferences {
2093     foreach my $akey (keys %ACPREFS) {
2094         foreach my $key (keys %pr::acc) {
2095             my $pname = $pr::acc{$key}[NAME];
2096             $ACHPVALUE{$akey}{$pname} = $ACPREFS{$akey}{$pname};
2097         }
2098     }
2099     return TRUE;
2100 }
2101
2102 sub init_plu_hidden_preferences {
2103     foreach my $key (keys %pr::plu) {
2104         my $plugin = $pr::plu{$key}[PLUGIN];
2105         my $pname = $pr::plu{$key}[NAME];
2106         if (defined $PLPREFS{$plugin}) {
2107             $PLHPVALUE{$plugin}{$pname} = $PLPREFS{$plugin}{$pname};
2108         }
2109     }
2110     return TRUE;
2111 }
2112
2113 # generic load/save resource files
2114 sub load_resource {
2115     my $rc = shift;
2116     my %data = ();
2117     my %meta = ();
2118     my $line = 0;
2119     open (RCF, '<:encoding(utf8)', $rc)
2120         or die _("Error: opening '{file}' for reading", file => $rc) . ": $!";
2121     my $section = '_'; # default unnamed section
2122     while (<RCF>) {
2123         chomp;
2124         ++$line;
2125         next if (/^\s*$/);
2126         if (/^\[([^\]]+)\]$/) { # new section
2127             $section = $1;
2128             die _("Error: duplicate section '{sect}' in resource file '{file}'\n",
2129                 sect => $section, file => $rc) if ($data{$section});
2130             $data{$section} = {};
2131             $meta{$section}{'#'} = $line;
2132         }
2133         elsif (/^([0-9a-z_]+)=(.*)$/) { # key=value
2134             $data{$section}{$1} = $2;
2135             $meta{$section}{$1} = $line;
2136         }
2137         elsif (/^(.*)$/) { # lone value
2138             push (@{$data{$section}{'_'}}, $1);
2139         }
2140     }
2141     close (RCF);
2142     return (\%data, \%meta);
2143 }
2144
2145 sub save_resource {
2146     my ($rc, $data, $meta) = @_;
2147     open (RCF, '>:utf8', $rc)
2148         or die _("Error: opening '{file}' for writing", file => $rc) . ": $!";
2149     my @sections = keys %$data;
2150     if (defined $meta) {
2151         @sections = sort {
2152             $meta->{$a}{'#'} <=> $meta->{$b}{'#'}
2153         } @sections
2154     }
2155     foreach my $section (@sections) {
2156         say RCF "[$section]";
2157         if (ref ($data->{$section}{'_'}) eq 'ARRAY') {
2158             foreach my $val (@{$data->{$section}{'_'}}) {
2159                 say RCF $val;
2160             }
2161         } else {
2162             my @keys = keys %{$data->{$section}};
2163             if (defined $meta) {
2164                 @keys = sort {
2165                     $meta->{$section}{$a} <=> $meta->{$section}{$b}
2166                 } @keys
2167             }
2168             foreach my $key (@keys) {
2169                 my $val = $data->{$section}{$key};
2170                 say RCF "$key=$val";
2171             }
2172         }
2173         say RCF "";
2174     }
2175     close (RCF);
2176 }
2177
2178 # load current status from disc
2179 sub load_preferences {
2180     my $rc = get_rc_filename ();
2181     log_message ("Loading preferences from $rc\n");
2182     return FALSE unless check_rc_file ($rc);
2183     return FALSE unless check_claws_not_running ();
2184     ($CONFIGDATA, $CONFIGMETA) = load_resource ($rc);
2185     foreach (keys %{$CONFIGDATA->{'Common'}}) {
2186         $PREFS{$_} = $CONFIGDATA->{'Common'}{$_};
2187     }
2188     foreach my $plugin (@PLUGINS) {
2189         if (defined $CONFIGDATA->{$plugin}) {
2190             push (@AVPLUGINS, $plugin);
2191             foreach (keys %{$CONFIGDATA->{$plugin}}) {
2192                 $PLPREFS{$plugin}{$_} = $CONFIGDATA->{$plugin}{$_};
2193             }
2194         }
2195     }
2196     return TRUE;
2197 }
2198
2199 sub load_ac_preferences {
2200     my $rc = get_ac_rc_filename ();
2201     log_message ("Loading account preferences from $rc\n");
2202     return FALSE unless check_rc_file ($rc);
2203     return FALSE unless check_claws_not_running ();
2204     ($ACCOUNTDATA, $ACCOUNTMETA) = load_resource ($rc);
2205     foreach my $asect (keys %$ACCOUNTDATA) {
2206         if ($asect =~ /^Account: (\d+)$/) {
2207             foreach (keys %{$ACCOUNTDATA->{$asect}}) {
2208                 $ACPREFS{$1}{$_} = $ACCOUNTDATA->{$asect}{$_};
2209             }
2210         }
2211     }
2212     return TRUE;
2213 }
2214
2215 # save current preferences to disc
2216 sub save_preferences {
2217     my $rc = get_rc_filename ();
2218     log_message ("Saving preferences to $rc\n");
2219     return FALSE unless check_rc_file ($rc);
2220     return FALSE unless check_claws_not_running ();
2221     my $rcbak = "$rc.backup";
2222     rename ($rc, $rcbak);
2223     foreach (keys %PREFS) {
2224         if (defined $HPVALUE{$_}) {
2225             $CONFIGDATA->{'Common'}{$_} = $HPVALUE{$_};
2226         }
2227     }
2228     foreach my $plugin (@AVPLUGINS) {
2229         foreach (keys %{$CONFIGDATA->{$plugin}}) {
2230             if (defined $PLHPVALUE{$plugin}{$_}) {
2231                 $CONFIGDATA->{$plugin}{$_} = $PLHPVALUE{$plugin}{$_};
2232             }
2233         }
2234     }
2235     save_resource ($rc, $CONFIGDATA, $CONFIGMETA);
2236     return TRUE;
2237 }
2238
2239 sub save_ac_preferences {
2240     my $rc = get_ac_rc_filename ();
2241     log_message ("Saving account preferences to $rc\n");
2242     return FALSE unless check_rc_file ($rc);
2243     return FALSE unless check_claws_not_running ();
2244     my $rcbak = "$rc.backup";
2245     rename ($rc, $rcbak);
2246     foreach my $asect (keys %$ACCOUNTDATA) {
2247         if ($asect =~ /^Account: (\d+)$/) {
2248             foreach (keys %{$ACCOUNTDATA->{$asect}}) {
2249                 if (defined $ACHPVALUE{$1}{$_}) {
2250                     $ACCOUNTDATA->{$asect}{$_} = $ACHPVALUE{$1}{$_};
2251                 }
2252             }
2253         }
2254     }
2255     save_resource ($rc, $ACCOUNTDATA, $ACCOUNTMETA);
2256     return TRUE;
2257 }
2258
2259 # create notebook
2260 sub new_notebook {
2261     my $nb = Gtk2::Notebook->new;
2262     #
2263     $nb->append_page (new_behaviour_page (), $xl::s{tab_behaviour});
2264     $nb->append_page (new_colours_page (), $xl::s{tab_colours});
2265     $nb->append_page (new_gui_page (), $xl::s{tab_gui});
2266     $nb->append_page (new_other_page (), $xl::s{tab_other});
2267     $nb->append_page (new_winpos_page (), $xl::s{tab_winpos});
2268     $nb->append_page (new_accounts_page (), $xl::s{tab_accounts});
2269     $nb->append_page (new_plugins_page (), $xl::s{tab_plugins});
2270
2271     return $nb;
2272 }
2273
2274 # create an about dialog
2275 sub new_about_dialog {
2276     my ($parent) = @_;
2277     my $title = $xl::s{about_title};
2278     my $lic = $xl::s{about_license};
2279     my $vers = $xl::s{about_version} . " $VERSION";
2280     my $license =
2281 "This program is free software: you can redistribute it and/or modify
2282 it under the terms of the GNU General Public License as published by
2283 the Free Software Foundation, either version 3 of the License, or
2284 (at your option) any later version.
2285
2286 This program is distributed in the hope that it will be useful,
2287 but WITHOUT ANY WARRANTY; without even the implied warranty of
2288 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2289 GNU General Public License for more details.
2290
2291 You should have received a copy of the GNU General Public License
2292 along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.";
2293     my $year = "2007-2016";
2294     my $holder = "Ricardo Mones &lt;ricardo\@mones.org&gt;";
2295     my $url = "http://www.claws-mail.org/clawsker.php";
2296
2297     my $dialog = Gtk2::MessageDialog->new_with_markup ($parent,
2298                     [qw/modal destroy-with-parent/],
2299                     'info', 'close',
2300                     "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
2301                     . "<span size=\"large\">$vers</span>\n\n"
2302                     . "<span color=\"blue\" size=\"large\">$url</span>\n\n"
2303                     . "<span>Copyright $year by $holder</span>\n\n"
2304                     . "<span size=\"large\">$lic</span>\n\n"
2305                     . "<span size=\"small\">$license</span>");
2306     $dialog->set_title ($xl::s{about});
2307     #
2308     return $dialog;
2309 }
2310
2311 # create buttons box
2312 sub new_button_box {
2313     my ($parent, $adlg) = @_;
2314     my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
2315     my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
2316     my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
2317     # disable button until is really implemented
2318     # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
2319     my $hbox = Gtk2::HBox->new (FALSE, 5);
2320     # signal handlers
2321     $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
2322     $b_apply->set_sensitive (not $READONLY);
2323     $b_apply->signal_connect (clicked => sub {
2324         save_preferences ($parent);
2325         save_ac_preferences ($parent);
2326     });
2327     # $b_undo->signal_connect (clicked => sub { undo_current_changes });
2328     $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
2329     # package them
2330     $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
2331     $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
2332     # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
2333     $hbox->pack_start ($b_about, FALSE, FALSE, 0);
2334     #
2335     return $hbox;
2336 }
2337
2338 sub get_app_icons {
2339     my $dir = $DATADIR . '/icons/hicolor';
2340     my @names = map {
2341       join ('/', ($dir, , $_ . 'x' . $_, 'apps', $NAME . '.png'))
2342     } (64, 128);
2343     my @icons = ();
2344     foreach (@names) {
2345         my $icon = undef;
2346         $icon = Gtk2::Gdk::Pixbuf->new_from_file($_) if (-f $_);
2347         push @icons, $icon if ($icon);
2348     }
2349     return @icons;
2350 }
2351
2352 # initialise
2353 exit unless parse_command_line ();
2354 Gtk2->init;
2355 $main_window = Gtk2::Window->new ('toplevel');
2356 exit unless load_preferences ();
2357 exit unless load_ac_preferences ();
2358 exit unless init_hidden_preferences ();
2359 exit unless init_ac_hidden_preferences ();
2360 exit unless init_plu_hidden_preferences ();
2361 # create main GUI
2362 my $box = Gtk2::VBox->new (FALSE, 5);
2363 $box->set_border_width(3);
2364 my $about = new_about_dialog ();
2365 $box->pack_start (new_notebook (), FALSE, FALSE, 0);
2366 $box->pack_end (new_button_box ($main_window, $about), FALSE, FALSE, 0);
2367 $main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
2368 $main_window->set_title ($xl::s{win_title});
2369 $main_window->set_icon_list (get_app_icons ());
2370 $main_window->add ($box);
2371 $main_window->show_all;
2372 Gtk2->main;
2373