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