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