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