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