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