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