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