10 Clawsker - A Claws Mail Tweaker
18 Clawsker is an applet to edit the so called Claws Mail hidden preferences.
20 Claws Mail is a fast, lightweight and feature-rich MUA with a high number
21 of configurable options. To keep the binary small and fast some of these
22 preferences which are not widely used are not provided with a graphical
23 interface for inspection and/or modification.
25 Users wanting to edit such preferences had to face raw editing of their
26 configuration files, now you can do it with a convenient GTK2 interface
32 Shows a brief help screen.
35 Tell more on the standard output.
37 --alternate-config-dir <dir>
38 Uses <dir> as Claws Mail configuration dir.
41 Uses <file> as Claws Mail resource configuration file. This sets
42 the full file name overriding any previous setting.
44 Multiple options are allowed, although only the last one has effect. Weird
45 option specifications may produce weird results (but otherwise correct).
49 A running Claws Mail cannot be detected if using the --clawsrc option because
50 the directory is not assumed to be a Claws Mail configuration dir. If that is
51 the case use the --alternate-config-dir option instead.
55 Ricardo Mones E<lt>ricardo@mones.orgE<gt>
59 Copyright (c) 2007-2008 by Ricardo Mones Lastra
61 This program is free software: you can redistribute it and/or modify
62 it under the terms of the GNU General Public License as published by
63 the Free Software Foundation, either version 3 of the License, or
64 (at your option) any later version.
66 This program is distributed in the hope that it will be useful,
67 but WITHOUT ANY WARRANTY; without even the implied warranty of
68 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
69 GNU General Public License for more details.
71 You should have received a copy of the GNU General Public License
72 along with this program. If not, see E<lt>http://www.gnu.org/licenses/E<gt>.
77 use POSIX qw(setlocale);
79 use Glib qw(TRUE FALSE);
82 my $NAME = 'clawsker';
83 my $PREFIX = '@PREFIX@';
84 my $LIBDIR = '@LIBDIR@';
85 my $VERSION = '@VERSION@';
87 my $main_window = undef;
89 my $locale = (defined($ENV{LC_MESSAGES}) ? $ENV{LC_MESSAGES} : $ENV{LANG});
90 $locale = "C" unless defined($locale);
91 setlocale (LC_ALL, $locale);
92 bindtextdomain ($NAME, sprintf ('%s/share/locale', $PREFIX));
95 my $SHOWHINTS = FALSE;
96 $SHOWHINTS = TRUE if ($Gtk2::VERSION >= 1.040 and Gtk2->CHECK_VERSION (2, 12, 0));
101 my $xla = gettext ($str);
102 if (scalar(keys(%par)) > 0) {
103 foreach my $key (keys %par) {
104 $xla =~ s/\{$key\}/$par{$key}/g;
112 win_title => _('Claws Mail Hidden Preferences'),
113 about => _('About...'),
114 about_title => _('Clawsker :: A Claws Mail Tweaker'),
115 about_license => _('License:'),
116 about_version => _('Version:'),
118 tab_colours => _('Colours'),
119 tab_behaviour => _('Behaviour'),
121 tab_other => _('Other'),
123 ab_frame => _('Addressbook'),
124 mem_frame => _('Memory'),
125 msgview_frame => _('Message view'),
126 log_frame => _('Log window'),
127 dnd_frame => _('Drag \'n\' drop'),
128 ssl_frame => _('Secure Sockets Layer'),
129 msgs_frame => _('Messages'),
130 stripes_frame => _('Coloured stripes'),
131 sbar_frame => _('Scroll bars'),
132 mlist_frame => _('Message list'),
133 netm_frame => _('NetworkManager'),
135 l_oth_use_dlg => _('Use detached address book edit dialogue'),
136 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.'),
137 l_oth_max_use => _('Maximum memory for message cache (Kb)'),
138 h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kB.'),
139 l_oth_min_time => _('Minimun time for cache elements (minutes)'),
140 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.'),
141 l_oth_use_netm => _('Use NetworkManager'),
142 h_oth_use_netm => _('Use NetworkManager to switch offline automatically.'),
144 l_gui_b_unread => _('Show unread messages with bold font'),
145 h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
146 l_gui_no_markup => _('Don\'t use markup in compose window'),
147 h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
148 l_gui_dot_lines => _('Use dotted lines in tree views'),
149 h_gui_dot_lines => _('Use the old dotted line look in the main window tree views (folder and message lists) instead of the modern lineless look.'),
150 l_gui_h_scroll => _('Enable horizontal scrollbar'),
151 h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
152 l_gui_swp_from => _('Dislay To header in From field in Sent folder'),
153 h_gui_swp_from => _('Display the sender\'s email address in the To column of the Sent folder instead of the recipient\'s.'),
154 l_gui_v_scroll => _('Folder list scrollbar behaviour'),
155 h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
156 l_gui_v_scroll_show => _('Show always'),
157 l_gui_v_scroll_auto => _('Automatic'),
158 l_gui_v_scroll_hide => _('Hide always'),
159 l_gui_strip_off => _('Striped lines contrast'),
160 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.'),
161 l_gui_cursor_v => _('Show Cursor in message view'),
162 h_gui_cursor_v => _('Display the cursor in the message view.'),
163 l_gui_toolbar_d => _('Detachable toolbars'),
164 h_gui_toolbar_d => _('Show handles in the toolbars.'),
165 l_gui_strip_all => _('Use stripes in all tree view components'),
166 h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
167 l_gui_strip_sum => _('Use stripes in Folder List and Message List'),
168 h_gui_strip_sum => _('Enable alternately coloured lines in message list and folder list'),
170 l_beh_hover_t => _('Drag \'n\' drop hover timeout (ms)'),
171 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.'),
172 l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
173 h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
174 l_beh_flowed => _('Respect format=flowed in messages'),
175 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.'),
176 l_beh_parts_rw => _('Allow writable temporary files'),
177 h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
178 l_beh_skip_ssl => _('Don\'t check SSL certificates'),
179 h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
180 l_beh_up_step => _('Progress bar update step (items)'),
181 h_beh_up_step => _('Update stepping in progress bars.'),
182 l_beh_thread_a => _('Maximum age when threading by subject (days)'),
183 h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
184 l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
185 h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
186 l_beh_use_utf8 => _('Force UTF-8 for broken mails'),
187 h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
188 l_beh_warn_dnd => _('Warn on drag \'n\' drop'),
189 h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
191 l_col_emphasis => _('X-Mailer header'),
192 h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
193 l_col_log_err => _('Error messages'),
194 h_col_log_err => _('Colour for error messages in log window.'),
195 l_col_log_in => _('Server messages'),
196 h_col_log_in => _('Colour for input messages in log window.'),
197 l_col_log_msg => _('Standard messages'),
198 h_col_log_msg => _('Colour for messages in log window.'),
199 l_col_log_out => _('Client messages'),
200 h_col_log_out => _('Colour for output messages in log window.'),
201 l_col_log_warn => _('Warnings'),
202 h_col_log_warn => _('Colour for warning messages in log window.'),
204 e_error => _('Error: '),
205 e_noclawsrc => _('resource file for Claws Mail was not found.'),
206 e_running => _('seems Claws Mail is currently running, close it first.'),
207 e_requireddir => _('option requires a directory name.'),
208 e_requiredfile => _('option requires a file name.'),
209 e_notadir => _('specified name is not a directory or does not exist.'),
210 e_notafile => _('specified name is not a file or does not exist.'),
213 # all preferences read by load_preferences
215 # values of all preferences handled by clawsker
217 # default config dir and file name
218 my $ALTCONFIGDIR = FALSE;
219 my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
220 my $CONFIGRC = 'clawsrc';
222 # index constants for preference arrays
223 use constant NAME => 0; # the name on the rc file
224 use constant LABEL => 1; # the label on the GUI
225 use constant DESC => 2; # the description for the hint/help
226 use constant TYPE => 3; # data type: bool, int, float, string, color
227 use constant CMVER => 4; # lowest Claws Mail version the feature exists
228 use constant CMDEF => 5; # default value for the preference in Claws Mail
229 use constant GUI => 6; # GUI element
231 # constants for GUI spacing
232 use constant HBOX_SPC => 5;
233 use constant FRAME_SPC => 2;
234 use constant PAGE_SPC => 5;
236 # data handlers and auxiliar functions
238 sub handle_bool_value {
239 my ($widget, $event, $dataref) = @_;
240 $$dataref = ($widget->get_active ())? '1': '0';
243 sub handle_int_value {
244 my ($widget, $event, $dataref) = @_;
245 $_ = $widget->get_text ();
250 $widget->set_text ($_);
253 $widget->set_text ($$dataref);
257 sub handle_string_value {
258 my ($widget, $event, $dataref) = @_;
259 $$dataref = $widget->get_text ();
262 sub gdk_color_from_str {
264 my ($rr, $gg, $bb) = (0, 0 ,0);
266 if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
271 my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
275 sub str_from_gdk_color {
277 my $rr = $color->red / 256;
278 my $gg = $color->green / 256;
279 my $bb = $color->blue / 256;
280 my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
284 sub handle_color_value {
285 my ($widget, $event, $dataref) = @_;
286 my $newcol = $widget->get_color;
287 $$dataref = &str_from_gdk_color ($newcol);
290 sub handle_selection_value {
291 my ($widget, $event, $dataref) = @_;
292 $$dataref = $widget->get_active;
295 sub get_rc_filename {
296 return $CONFIGDIR . $CONFIGRC;
299 sub set_rc_filename {
301 my @parts = split ('/', $fullname);
302 $CONFIGRC = $parts[$#parts];
303 $parts[$#parts] = '';
304 $CONFIGDIR = join ('/', @parts);
308 my ($mesg, $fatal) = @_;
309 if (defined($fatal) && $fatal eq 'die') {
310 die "$NAME: $mesg\n";
313 print "$NAME: $mesg\n";
319 my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
320 my $errordlg = Gtk2::MessageDialog->new_with_markup ($main_window, 'modal', 'error', 'cancel', $markup);
321 $errordlg->set_title (_('Error message'));
326 sub check_claws_not_running() {
327 my $socket = (not $ALTCONFIGDIR)? "/tmp/": $CONFIGDIR;
328 $socket .= "claws-mail-$<";
330 my $emsg = "$xl::s{e_error}$xl::s{e_running}";
332 error_dialog ($emsg);
339 sub check_rc_file() {
341 (defined($rcfile) && -f $rcfile) or do {
342 my $emsg = "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
344 error_dialog ($emsg);
351 sub set_widget_hint() {
353 my ($wdgt, $hint) = @_;
354 $wdgt->set_tooltip_text ($hint);
355 $wdgt->set_has_tooltip (TRUE);
359 # graphic element creation
361 sub new_check_button_for {
362 my ($hash, $key) = @_;
363 my $name = $$hash{$key}[NAME];
364 my $label = $$hash{$key}[LABEL];
366 my $hbox = Gtk2::HBox->new (FALSE, 5);
367 my $cb = Gtk2::CheckButton->new ($label);
368 $$hash{$key}[GUI] = $cb;
369 $cb->set_active ($HPVALUE{$name} eq '1');
370 $cb->signal_connect (clicked => sub {
372 &handle_bool_value($w, $e, \$HPVALUE{$name});
374 &set_widget_hint ($cb, $$hash{$key}[DESC]);
375 $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
380 sub new_text_box_for {
381 my ($hash, $key) = @_;
382 my $name = $$hash{$key}[NAME];
383 my $label = $$hash{$key}[LABEL];
385 my $hbox = Gtk2::HBox->new (FALSE, 5);
386 my $glabel = Gtk2::Label->new ($label);
387 my $gentry = Gtk2::Entry->new;
388 $gentry->set_width_chars (8);
389 $$hash{$key}[GUI] = $gentry;
390 $gentry->set_text($HPVALUE{$name});
391 $gentry->signal_connect(changed => sub {
393 &handle_int_value($w, $e, \$HPVALUE{$name}); # FIXME int only
395 &set_widget_hint ($gentry, $$hash{$key}[DESC]);
396 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
397 $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
402 sub new_color_button_for {
403 my ($hash, $key) = @_;
404 my $name = $$hash{$key}[NAME];
405 my $label = $$hash{$key}[LABEL];
407 my $col = &gdk_color_from_str ($HPVALUE{$name});
408 my $hbox = Gtk2::HBox->new (FALSE, 5);
409 my $glabel = Gtk2::Label->new ($label);
410 my $button = Gtk2::ColorButton->new_with_color ($col);
411 $$hash{$key}[GUI] = $button;
412 $button->set_title ($label);
413 $button->set_relief ('none');
414 $button->signal_connect ('color-set' => sub {
416 &handle_color_value($w, $e, \$HPVALUE{$name});
418 &set_widget_hint ($button, $$hash{$key}[DESC]);
419 $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
420 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
425 sub new_selection_box_for {
426 my ($hash, $key) = @_;
427 my $name = $$hash{$key}[NAME];
428 my $label = $$hash{$key}[LABEL];
430 my $hbox = Gtk2::HBox->new (FALSE, 5);
431 my $glabel = Gtk2::Label->new ($label);
432 my $combo = Gtk2::ComboBox->new_text;
433 $$hash{$key}[GUI] = $combo;
434 my @options = split (';', $$hash{$key}[TYPE]);
435 foreach my $opt (@options) {
436 my ($index, $textkey) = split ('=', $opt);
437 $combo->insert_text ($index, $xl::s{$textkey});
439 $combo->signal_connect ('changed' => sub {
441 &handle_selection_value($w, $e, \$HPVALUE{$name});
443 $combo->set_active ($HPVALUE{$name});
444 &set_widget_hint ($combo, $$hash{$key}[DESC]);
445 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
446 $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
451 # preference maps and corresponding page creation subs
453 %pr::oth = ( # other preferences
455 'addressbook_use_editaddress_dialog',
456 $xl::s{l_oth_use_dlg},
457 $xl::s{h_oth_use_dlg},
464 'cache_max_mem_usage',
465 $xl::s{l_oth_max_use},
466 $xl::s{h_oth_max_use},
473 'cache_min_keep_time',
474 $xl::s{l_oth_min_time},
475 $xl::s{h_oth_min_time},
482 'use_networkmanager',
483 $xl::s{l_oth_use_netm},
484 $xl::s{h_oth_use_netm},
492 sub new_other_page() {
493 my $of = Gtk2::VBox->new (FALSE, 5);
494 $of->set_border_width (PAGE_SPC);
496 my $ab_frame = Gtk2::Frame->new ($xl::s{ab_frame});
497 my $cb_use_dlg = &new_check_button_for(\%pr::oth, 'use_dlg');
498 my $vb1 = Gtk2::VBox->new (FALSE, 5);
499 $vb1->set_border_width (PAGE_SPC);
500 $vb1->pack_start ($cb_use_dlg, FALSE, FALSE, 0);
501 $ab_frame->add ($vb1);
503 my $mem_frame = Gtk2::Frame->new ($xl::s{mem_frame});
504 my $tb_max_use = &new_text_box_for(\%pr::oth, 'max_use');
505 my $tb_min_time = &new_text_box_for(\%pr::oth, 'min_time');
506 my $vb2 = Gtk2::VBox->new (FALSE, 5);
507 $vb2->set_border_width (PAGE_SPC);
508 $vb2->pack_start ($tb_max_use, FALSE, FALSE, 0);
509 $vb2->pack_start ($tb_min_time, FALSE, FALSE, 0);
510 $mem_frame->add ($vb2);
512 my $netm_frame = Gtk2::Frame->new ($xl::s{netm_frame});
513 my $cb_use_netm = &new_check_button_for(\%pr::oth, 'use_netm');
514 my $vb3 = Gtk2::VBox->new (FALSE, 5);
515 $vb3->set_border_width (PAGE_SPC);
516 $vb3->pack_start ($cb_use_netm, FALSE, FALSE, 0);
517 $netm_frame->add ($vb3);
519 $of->pack_start ($ab_frame, FALSE, FALSE, FRAME_SPC);
520 $of->pack_start ($mem_frame, FALSE, FALSE, FRAME_SPC);
521 $of->pack_start ($netm_frame, FALSE, FALSE, FRAME_SPC);
526 %pr::gui = ( # gui bells and whistles
529 $xl::s{l_gui_b_unread},
530 $xl::s{h_gui_b_unread},
538 $xl::s{l_gui_no_markup},
539 $xl::s{h_gui_no_markup},
546 'enable_dotted_lines',
547 $xl::s{l_gui_dot_lines},
548 $xl::s{h_gui_dot_lines},
556 $xl::s{l_gui_h_scroll},
557 $xl::s{h_gui_h_scroll},
565 $xl::s{l_gui_swp_from},
566 $xl::s{h_gui_swp_from},
573 'folderview_vscrollbar_policy',
574 $xl::s{l_gui_v_scroll},
575 $xl::s{h_gui_v_scroll},
576 '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
582 'stripes_color_offset',
583 $xl::s{l_gui_strip_off},
584 $xl::s{h_gui_strip_off},
591 'textview_cursor_visible',
592 $xl::s{l_gui_cursor_v},
593 $xl::s{h_gui_cursor_v},
600 'toolbar_detachable',
601 $xl::s{l_gui_toolbar_d},
602 $xl::s{h_gui_toolbar_d},
609 'use_stripes_everywhere',
610 $xl::s{l_gui_strip_all},
611 $xl::s{h_gui_strip_all},
618 'use_stripes_in_summaries',
619 $xl::s{l_gui_strip_sum},
620 $xl::s{h_gui_strip_sum},
629 my $gf = Gtk2::VBox->new (FALSE, 5);
630 $gf->set_border_width (PAGE_SPC);
632 my $stripes_frame = Gtk2::Frame->new ($xl::s{stripes_frame});
633 my $cb_strip_all = &new_check_button_for (\%pr::gui, 'strip_all');
634 my $cb_strip_sum = &new_check_button_for (\%pr::gui, 'strip_sum');
635 my $tb_strip_off = &new_text_box_for (\%pr::gui, 'strip_off');
636 my $vb1 = Gtk2::VBox->new (FALSE, 5);
637 $vb1->set_border_width (PAGE_SPC);
638 $vb1->pack_start ($cb_strip_all, FALSE, FALSE, 0);
639 $vb1->pack_start ($cb_strip_sum, FALSE, FALSE, 0);
640 $vb1->pack_start ($tb_strip_off, FALSE, FALSE, 0);
641 $stripes_frame->add ($vb1);
643 my $mlist_frame = Gtk2::Frame->new ($xl::s{mlist_frame});
644 my $cb_b_unread = &new_check_button_for (\%pr::gui, 'b_unread');
645 my $cb_swp_from = &new_check_button_for (\%pr::gui, 'swp_from');
646 my $vb3 = Gtk2::VBox->new (FALSE, 5);
647 $vb3->set_border_width (PAGE_SPC);
648 $vb3->pack_start ($cb_b_unread, FALSE, FALSE, 0);
649 $vb3->pack_start ($cb_swp_from, FALSE, FALSE, 0);
650 $mlist_frame->add ($vb3);
652 my $sbar_frame = Gtk2::Frame->new ($xl::s{sbar_frame});
653 my $cb_h_scroll = &new_check_button_for (\%pr::gui, 'h_scroll');
654 my $sb_v_scroll = &new_selection_box_for (\%pr::gui, 'v_scroll');
655 my $vb2 = Gtk2::VBox->new (FALSE, 5);
656 $vb2->set_border_width (PAGE_SPC);
657 $vb2->pack_start ($cb_h_scroll, FALSE, FALSE, 0);
658 $vb2->pack_start ($sb_v_scroll, FALSE, FALSE, 0);
659 $sbar_frame->add ($vb2);
661 my $cb_no_markup = &new_check_button_for (\%pr::gui, 'no_markup');
662 my $cb_dot_lines = &new_check_button_for (\%pr::gui, 'dot_lines');
663 my $cb_cursor_v = &new_check_button_for (\%pr::gui, 'cursor_v');
664 my $cb_toolbar_d = &new_check_button_for (\%pr::gui, 'toolbar_d');
666 $gf->pack_start ($stripes_frame, FALSE, FALSE, FRAME_SPC);
667 $gf->pack_start ($mlist_frame, FALSE, FALSE, FRAME_SPC);
668 $gf->pack_start ($cb_no_markup, FALSE, FALSE, 0);
669 $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
670 $gf->pack_start ($cb_cursor_v, FALSE, FALSE, 0);
671 $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
672 $gf->pack_start ($sbar_frame, FALSE, FALSE, FRAME_SPC);
677 %pr::beh = ( # tweak some behaviour
680 $xl::s{l_beh_hover_t},
681 $xl::s{h_beh_hover_t},
689 $xl::s{l_beh_dangerous},
690 $xl::s{h_beh_dangerous},
697 'respect_flowed_format',
698 $xl::s{l_beh_flowed},
699 $xl::s{h_beh_flowed},
706 'save_parts_readwrite',
707 $xl::s{l_beh_parts_rw},
708 $xl::s{h_beh_parts_rw},
715 'skip_ssl_cert_check',
716 $xl::s{l_beh_skip_ssl},
717 $xl::s{h_beh_skip_ssl},
724 'statusbar_update_step',
725 $xl::s{l_beh_up_step},
726 $xl::s{h_beh_up_step},
733 'thread_by_subject_max_age',
734 $xl::s{l_beh_thread_a},
735 $xl::s{h_beh_thread_a},
743 $xl::s{l_beh_unsafe_ssl},
744 $xl::s{h_beh_unsafe_ssl},
751 'utf8_instead_of_locale_for_broken_mail',
752 $xl::s{l_beh_use_utf8},
753 $xl::s{h_beh_use_utf8},
761 $xl::s{l_beh_warn_dnd},
762 $xl::s{h_beh_warn_dnd},
770 sub new_behaviour_page() {
771 my $bf = Gtk2::VBox->new (FALSE, 5);
772 $bf->set_border_width (PAGE_SPC);
774 my $dnd_frame = Gtk2::Frame->new ($xl::s{dnd_frame});
775 my $tb_hoover_t = &new_text_box_for (\%pr::beh, 'hover_t');
776 my $cb_warn_dnd = &new_check_button_for (\%pr::beh, 'warn_dnd');
777 my $vb1 = Gtk2::VBox->new (FALSE, 5);
778 $vb1->set_border_width (PAGE_SPC);
779 $vb1->pack_start ($cb_warn_dnd, FALSE, FALSE, 0);
780 $vb1->pack_start ($tb_hoover_t, FALSE, FALSE, 0);
781 $dnd_frame->add ($vb1);
783 my $ssl_frame = Gtk2::Frame->new ($xl::s{ssl_frame});
784 my $cb_skip_ssl = &new_check_button_for (\%pr::beh, 'skip_ssl');
785 my $cb_unsafe_ssl = &new_check_button_for (\%pr::beh, 'unsafe_ssl');
786 my $hb1 = Gtk2::HBox->new (FALSE, 5);
787 $hb1->set_border_width (PAGE_SPC);
788 $hb1->pack_start ($cb_skip_ssl, FALSE, FALSE, 0);
789 $hb1->pack_start ($cb_unsafe_ssl, FALSE, FALSE, 0);
790 $ssl_frame->add ($hb1);
792 my $tb_up_step = &new_text_box_for (\%pr::beh, 'up_step');
793 my $tb_thread_a = &new_text_box_for (\%pr::beh, 'thread_a');
795 my $msgs_frame = Gtk2::Frame->new ($xl::s{msgs_frame});
796 my $cb_flowed = &new_check_button_for (\%pr::beh, 'flowed');
797 my $cb_parts_rw = &new_check_button_for (\%pr::beh, 'parts_rw');
798 my $cb_use_utf8 = &new_check_button_for (\%pr::beh, 'use_utf8');
799 my $cb_dangerous = &new_check_button_for (\%pr::beh, 'dangerous');
800 my $vb2 = Gtk2::VBox->new (FALSE, 5);
801 $vb2->set_border_width (PAGE_SPC);
802 $vb2->pack_start ($cb_flowed, FALSE, FALSE, 0);
803 $vb2->pack_start ($cb_parts_rw, FALSE, FALSE, 0);
804 $vb2->pack_start ($cb_use_utf8, FALSE, FALSE, 0);
805 $vb2->pack_start ($cb_dangerous, FALSE, FALSE, 0);
806 $msgs_frame->add ($vb2);
808 $bf->pack_start ($dnd_frame, FALSE, FALSE, FRAME_SPC);
809 $bf->pack_start ($ssl_frame, FALSE, FALSE, FRAME_SPC);
810 $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
811 $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
812 $bf->pack_start ($msgs_frame, FALSE, FALSE, FRAME_SPC);
817 %pr::col = ( # a variety of colours
820 $xl::s{l_col_emphasis},
821 $xl::s{h_col_emphasis},
829 $xl::s{l_col_log_err},
830 $xl::s{h_col_log_err},
838 $xl::s{l_col_log_in},
839 $xl::s{h_col_log_in},
847 $xl::s{l_col_log_msg},
848 $xl::s{h_col_log_msg},
856 $xl::s{l_col_log_out},
857 $xl::s{h_col_log_out},
865 $xl::s{l_col_log_warn},
866 $xl::s{h_col_log_warn},
874 sub new_colours_page() {
875 my $cf = Gtk2::VBox->new (FALSE, 5);
876 $cf->set_border_width (PAGE_SPC);
878 my $msgview_frame = Gtk2::Frame->new ($xl::s{msgview_frame});
879 my $cb_emphasis = &new_color_button_for (\%pr::col, 'emphasis');
880 my $vb1 = Gtk2::VBox->new (FALSE, 5);
881 $vb1->set_border_width (PAGE_SPC);
882 $vb1->pack_start ($cb_emphasis, FALSE, FALSE, 0);
883 $msgview_frame->add ($vb1);
885 my $log_frame = Gtk2::Frame->new ($xl::s{log_frame});
886 my $cb_log_err = &new_color_button_for (\%pr::col, 'log_err');
887 my $cb_log_in = &new_color_button_for (\%pr::col, 'log_in');
888 my $cb_log_msg = &new_color_button_for (\%pr::col, 'log_msg');
889 my $cb_log_out = &new_color_button_for (\%pr::col, 'log_out');
890 my $cb_log_warn = &new_color_button_for (\%pr::col, 'log_warn');
891 my $vb2 = Gtk2::VBox->new (FALSE, 5);
892 $vb2->set_border_width (PAGE_SPC);
893 $vb2->pack_start ($cb_log_err, FALSE, FALSE, 0);
894 $vb2->pack_start ($cb_log_in, FALSE, FALSE, 0);
895 $vb2->pack_start ($cb_log_msg, FALSE, FALSE, 0);
896 $vb2->pack_start ($cb_log_out, FALSE, FALSE, 0);
897 $vb2->pack_start ($cb_log_warn, FALSE, FALSE, 0);
898 $log_frame->add ($vb2);
900 $cf->pack_start ($msgview_frame, FALSE, FALSE, 0);
901 $cf->pack_start ($log_frame, FALSE, FALSE, 0);
906 # the command line help
908 my $line = '-' x length ($xl::s{about_title}) . "\n";
910 print $xl::s{about_title} . "\n";
911 print $xl::s{about_version} . " $VERSION\n";
912 print "Perl-GLib " . $Glib::VERSION;
913 # version info stuff appeared in 1.040
914 if ($Glib::VERSION >= 1.040) {
915 print _(", built for ") . join(".", Glib->GET_VERSION_INFO)
916 . _(", running with ") . join(".", &Glib::major_version,
917 &Glib::minor_version, &Glib::micro_version);
920 print "Perl-GTK2 " . $Gtk2::VERSION;
921 if ($Gtk2::VERSION >= 1.040) {
922 print _(", built for ") . join(".", Gtk2->GET_VERSION_INFO)
923 . _(", running with ") . join(".", &Gtk2::major_version,
924 &Gtk2::minor_version, &Gtk2::micro_version);
928 print _("Syntax:\n");
929 print _(" clawsker [options]\n");
930 print _("Options:\n");
931 print _(" --help Prints this help screen.\n");
932 print _(" --verbose More messages on standard output.\n");
933 print _(" --alternate-config-dir <dir> Uses <dir> as Claws Mail config dir.\n");
934 print _(" --clawsrc <file> Uses <file> as full resource name.\n");
937 # handle errors which don't allow to run
938 sub command_line_fatal() {
940 my $emsg = $xl::s{e_error} . $reason;
941 error_dialog ($emsg);
942 log_message ("$emsg", 'die');
945 # parse the command line
946 sub parse_command_line() {
948 while (defined($ARGV[$arg])) {
958 /--alternate-config-dir/ && do {
960 &command_line_fatal ($xl::s{e_requireddir})
961 unless defined($ARGV[$arg]);
962 &command_line_fatal ($xl::s{e_notadir})
963 unless -d $ARGV[$arg];
964 $CONFIGDIR = $ARGV[$arg];
965 $ALTCONFIGDIR = TRUE;
970 &command_line_fatal($xl::s{e_requiredfile})
971 unless defined($ARGV[$arg]);
972 &command_line_fatal($xl::s{e_notafile})
973 unless -f $ARGV[$arg];
974 &set_rc_filename ($ARGV[$arg]);
977 /.*/ && &command_line_fatal (
978 _("unknown option '{opt}'.\n", opt => $ARGV[$arg]));
982 # eveything continues...
986 # update the hidden preferences status from loaded values
987 sub init_hidden_preferences() {
988 foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth) {
989 foreach my $key (keys %$hash) {
990 $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
996 # load current status from disc
997 sub load_preferences() {
998 my $rc = &get_rc_filename;
999 &log_message ("Loading preferences from $rc\n");
1000 return FALSE unless &check_rc_file ($rc);
1001 return FALSE unless &check_claws_not_running;
1005 if (/^([8a-z_]+)=(.*)$/) {
1013 # save current preferences to disc
1014 sub save_preferences() {
1015 my $rc = &get_rc_filename;
1016 &log_message ("Saving preferences to $rc\n");
1017 return FALSE unless &check_rc_file ($rc);
1018 return FALSE unless &check_claws_not_running;
1019 my $rcbak = "$rc.backup";
1020 rename ($rc, $rcbak);
1022 open (RCB, "<$rcbak");
1025 if (/^([8a-z_]+)=(.*)$/) {
1026 if (defined($HPVALUE{$1})) {
1027 print RCF $1 . "=" . $HPVALUE{$1} . "\n";
1030 print RCF $_ . "\n";
1034 print RCF $_ . "\n";
1043 sub new_notebook() {
1044 my $nb = Gtk2::Notebook->new;
1046 $nb->append_page (&new_behaviour_page, $xl::s{tab_behaviour});
1047 $nb->append_page (&new_colours_page, $xl::s{tab_colours});
1048 $nb->append_page (&new_gui_page, $xl::s{tab_gui});
1049 $nb->append_page (&new_other_page, $xl::s{tab_other});
1054 # create an about dialog
1055 sub new_about_dialog() {
1057 my $title = $xl::s{about_title};
1058 my $lic = $xl::s{about_license};
1059 my $vers = $xl::s{about_version} . " $VERSION";
1061 "This program is free software: you can redistribute it and/or modify
1062 it under the terms of the GNU General Public License as published by
1063 the Free Software Foundation, either version 3 of the License, or
1064 (at your option) any later version.
1066 This program is distributed in the hope that it will be useful,
1067 but WITHOUT ANY WARRANTY; without even the implied warranty of
1068 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1069 GNU General Public License for more details.
1071 You should have received a copy of the GNU General Public License
1072 along with this program. If not, see <http://www.gnu.org/licenses/>.";
1074 my $holder = "Ricardo Mones <ricardo\@mones.org>";
1076 my $dialog = Gtk2::MessageDialog->new_with_markup ($parent,
1077 [qw/modal destroy-with-parent/],
1079 "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
1080 . "<span size=\"large\">$vers</span>\n"
1081 . "<span>Copyright $year by $holder</span>\n\n"
1082 . "<span size=\"large\">$lic</span>\n\n"
1083 . "<span size=\"small\">$license</span>");
1084 $dialog->set_title ($xl::s{about});
1089 # create buttons box
1090 sub new_button_box() {
1091 my ($parent, $adlg) = @_;
1092 my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
1093 my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
1094 my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
1095 # disable button until is really implemented
1096 # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
1097 my $hbox = Gtk2::HBox->new (FALSE, 5);
1099 $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
1100 $b_apply->signal_connect (clicked => sub { &save_preferences ($parent) });
1101 # $b_undo->signal_connect (clicked => sub { &undo_current_changes });
1102 $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
1104 $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
1105 $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
1106 # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
1107 $hbox->pack_start ($b_about, FALSE, FALSE, 0);
1113 $main_window = Gtk2::Window->new ('toplevel');
1114 exit unless &parse_command_line;
1115 exit unless &load_preferences;
1116 exit unless &init_hidden_preferences;
1118 my $box = Gtk2::VBox->new (FALSE, 5);
1119 $box->set_border_width(3);
1120 my $about = &new_about_dialog;
1121 $box->pack_start (&new_notebook, FALSE, FALSE, 0);
1122 $box->pack_end (&new_button_box ($main_window, $about), FALSE, FALSE, 0);
1123 $main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
1124 $main_window->set_title ($xl::s{win_title});
1125 $main_window->add ($box);
1126 $main_window->show_all;