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