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'),
134 l_oth_use_dlg => _('Use detached address book edit dialogue'),
135 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.'),
136 l_oth_max_use => _('Maximum memory for message cache (Kb)'),
137 h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kB.'),
138 l_oth_min_time => _('Minimun time for cache elements (minutes)'),
139 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_gui_b_unread => _('Show unread messages with bold font'),
142 h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
143 l_gui_no_markup => _('Don\'t use markup in compose window'),
144 h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
145 l_gui_dot_lines => _('Use dotted lines in tree views'),
146 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.'),
147 l_gui_h_scroll => _('Enable horizontal scrollbar'),
148 h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
149 l_gui_swp_from => _('Dislay To header in From field in Sent folder'),
150 h_gui_swp_from => _('Display the sender\'s email address in the To column of the Sent folder instead of the recipient\'s.'),
151 l_gui_v_scroll => _('Folder list scrollbar behaviour'),
152 h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
153 l_gui_v_scroll_show => _('Show always'),
154 l_gui_v_scroll_auto => _('Automatic'),
155 l_gui_v_scroll_hide => _('Hide always'),
156 l_gui_strip_off => _('Striped lines contrast'),
157 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.'),
158 l_gui_cursor_v => _('Show Cursor in message view'),
159 h_gui_cursor_v => _('Display the cursor in the message view.'),
160 l_gui_toolbar_d => _('Detachable toolbars'),
161 h_gui_toolbar_d => _('Show handles in the toolbars.'),
162 l_gui_strip_all => _('Use stripes in all tree view components'),
163 h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
164 l_gui_strip_sum => _('Use stripes in Folder List and Message List'),
165 h_gui_strip_sum => _('Enable alternately coloured lines in message list and folder list'),
167 l_beh_hover_t => _('Drag \'n\' drop hover timeout (ms)'),
168 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.'),
169 l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
170 h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
171 l_beh_flowed => _('Respect format=flowed in messages'),
172 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.'),
173 l_beh_parts_rw => _('Allow writable temporary files'),
174 h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
175 l_beh_skip_ssl => _('Don\'t check SSL certificates'),
176 h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
177 l_beh_up_step => _('Progress bar update step (items)'),
178 h_beh_up_step => _('Update stepping in progress bars.'),
179 l_beh_thread_a => _('Maximum age when threading by subject (days)'),
180 h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
181 l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
182 h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
183 l_beh_use_utf8 => _('Force UTF-8 for broken mails'),
184 h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
185 l_beh_warn_dnd => _('Warn on drag \'n\' drop'),
186 h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
188 l_col_emphasis => _('X-Mailer header'),
189 h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
190 l_col_log_err => _('Error messages'),
191 h_col_log_err => _('Colour for error messages in log window.'),
192 l_col_log_in => _('Server messages'),
193 h_col_log_in => _('Colour for input messages in log window.'),
194 l_col_log_msg => _('Standard messages'),
195 h_col_log_msg => _('Colour for messages in log window.'),
196 l_col_log_out => _('Client messages'),
197 h_col_log_out => _('Colour for output messages in log window.'),
198 l_col_log_warn => _('Warnings'),
199 h_col_log_warn => _('Colour for warning messages in log window.'),
201 e_error => _('Error: '),
202 e_noclawsrc => _('resource file for Claws Mail was not found.'),
203 e_running => _('seems Claws Mail is currently running, close it first.'),
204 e_requireddir => _('option requires a directory name.'),
205 e_requiredfile => _('option requires a file name.'),
206 e_notadir => _('specified name is not a directory or does not exist.'),
207 e_notafile => _('specified name is not a file or does not exist.'),
210 # all preferences read by load_preferences
212 # values of all preferences handled by clawsker
214 # default config dir and file name
215 my $ALTCONFIGDIR = FALSE;
216 my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
217 my $CONFIGRC = 'clawsrc';
219 # index constants for preference arrays
220 use constant NAME => 0; # the name on the rc file
221 use constant LABEL => 1; # the label on the GUI
222 use constant DESC => 2; # the description for the hint/help
223 use constant TYPE => 3; # data type: bool, int, float, string, color
224 use constant CMVER => 4; # lowest Claws Mail version the feature exists
225 use constant CMDEF => 5; # default value for the preference in Claws Mail
226 use constant GUI => 6; # GUI element
228 # constants for GUI spacing
229 use constant HBOX_SPC => 5;
230 use constant FRAME_SPC => 2;
231 use constant PAGE_SPC => 5;
233 # data handlers and auxiliar functions
235 sub handle_bool_value {
236 my ($widget, $event, $dataref) = @_;
237 $$dataref = ($widget->get_active ())? '1': '0';
240 sub handle_int_value {
241 my ($widget, $event, $dataref) = @_;
242 $_ = $widget->get_text ();
247 $widget->set_text ($_);
250 $widget->set_text ($$dataref);
254 sub handle_string_value {
255 my ($widget, $event, $dataref) = @_;
256 $$dataref = $widget->get_text ();
259 sub gdk_color_from_str {
261 my ($rr, $gg, $bb) = (0, 0 ,0);
263 if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
268 my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
272 sub str_from_gdk_color {
274 my $rr = $color->red / 256;
275 my $gg = $color->green / 256;
276 my $bb = $color->blue / 256;
277 my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
281 sub handle_color_value {
282 my ($widget, $event, $dataref) = @_;
283 my $newcol = $widget->get_color;
284 $$dataref = &str_from_gdk_color ($newcol);
287 sub handle_selection_value {
288 my ($widget, $event, $dataref) = @_;
289 $$dataref = $widget->get_active;
292 sub get_rc_filename {
293 return $CONFIGDIR . $CONFIGRC;
296 sub set_rc_filename {
298 my @parts = split ('/', $fullname);
299 $CONFIGRC = $parts[$#parts];
300 $parts[$#parts] = '';
301 $CONFIGDIR = join ('/', @parts);
305 my ($mesg, $fatal) = @_;
306 if (defined($fatal) && $fatal eq 'die') {
307 die "$NAME: $mesg\n";
310 print "$NAME: $mesg\n";
316 my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
317 my $errordlg = Gtk2::MessageDialog->new_with_markup ($main_window, 'modal', 'error', 'cancel', $markup);
318 $errordlg->set_title (_('Error message'));
323 sub check_claws_not_running() {
324 my $socket = (not $ALTCONFIGDIR)? "/tmp/": $CONFIGDIR;
325 $socket .= "claws-mail-$<";
327 my $emsg = "$xl::s{e_error}$xl::s{e_running}";
329 error_dialog ($emsg);
336 sub check_rc_file() {
338 (defined($rcfile) && -f $rcfile) or do {
339 my $emsg = "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
341 error_dialog ($emsg);
348 sub set_widget_hint() {
350 my ($wdgt, $hint) = @_;
351 $wdgt->set_tooltip_text ($hint);
352 $wdgt->set_has_tooltip (TRUE);
356 # graphic element creation
358 sub new_check_button_for {
359 my ($hash, $key) = @_;
360 my $name = $$hash{$key}[NAME];
361 my $label = $$hash{$key}[LABEL];
363 my $hbox = Gtk2::HBox->new (FALSE, 5);
364 my $cb = Gtk2::CheckButton->new ($label);
365 $$hash{$key}[GUI] = $cb;
366 $cb->set_active ($HPVALUE{$name} eq '1');
367 $cb->signal_connect (clicked => sub {
369 &handle_bool_value($w, $e, \$HPVALUE{$name});
371 &set_widget_hint ($cb, $$hash{$key}[DESC]);
372 $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
377 sub new_text_box_for {
378 my ($hash, $key) = @_;
379 my $name = $$hash{$key}[NAME];
380 my $label = $$hash{$key}[LABEL];
382 my $hbox = Gtk2::HBox->new (FALSE, 5);
383 my $glabel = Gtk2::Label->new ($label);
384 my $gentry = Gtk2::Entry->new;
385 $gentry->set_width_chars (8);
386 $$hash{$key}[GUI] = $gentry;
387 $gentry->set_text($HPVALUE{$name});
388 $gentry->signal_connect(changed => sub {
390 &handle_int_value($w, $e, \$HPVALUE{$name}); # FIXME int only
392 &set_widget_hint ($gentry, $$hash{$key}[DESC]);
393 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
394 $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
399 sub new_color_button_for {
400 my ($hash, $key) = @_;
401 my $name = $$hash{$key}[NAME];
402 my $label = $$hash{$key}[LABEL];
404 my $col = &gdk_color_from_str ($HPVALUE{$name});
405 my $hbox = Gtk2::HBox->new (FALSE, 5);
406 my $glabel = Gtk2::Label->new ($label);
407 my $button = Gtk2::ColorButton->new_with_color ($col);
408 $$hash{$key}[GUI] = $button;
409 $button->set_title ($label);
410 $button->set_relief ('none');
411 $button->signal_connect ('color-set' => sub {
413 &handle_color_value($w, $e, \$HPVALUE{$name});
415 &set_widget_hint ($button, $$hash{$key}[DESC]);
416 $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
417 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
422 sub new_selection_box_for {
423 my ($hash, $key) = @_;
424 my $name = $$hash{$key}[NAME];
425 my $label = $$hash{$key}[LABEL];
427 my $hbox = Gtk2::HBox->new (FALSE, 5);
428 my $glabel = Gtk2::Label->new ($label);
429 my $combo = Gtk2::ComboBox->new_text;
430 $$hash{$key}[GUI] = $combo;
431 my @options = split (';', $$hash{$key}[TYPE]);
432 foreach my $opt (@options) {
433 my ($index, $textkey) = split ('=', $opt);
434 $combo->insert_text ($index, $xl::s{$textkey});
436 $combo->signal_connect ('changed' => sub {
438 &handle_selection_value($w, $e, \$HPVALUE{$name});
440 $combo->set_active ($HPVALUE{$name});
441 &set_widget_hint ($combo, $$hash{$key}[DESC]);
442 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
443 $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
448 # preference maps and corresponding page creation subs
450 %pr::oth = ( # other preferences
452 'addressbook_use_editaddress_dialog',
453 $xl::s{l_oth_use_dlg},
454 $xl::s{h_oth_use_dlg},
461 'cache_max_mem_usage',
462 $xl::s{l_oth_max_use},
463 $xl::s{h_oth_max_use},
470 'cache_min_keep_time',
471 $xl::s{l_oth_min_time},
472 $xl::s{h_oth_min_time},
480 sub new_other_page() {
481 my $of = Gtk2::VBox->new (FALSE, 5);
482 $of->set_border_width (PAGE_SPC);
484 my $ab_frame = Gtk2::Frame->new ($xl::s{ab_frame});
485 my $cb_use_dlg = &new_check_button_for(\%pr::oth, 'use_dlg');
486 my $vb1 = Gtk2::VBox->new (FALSE, 5);
487 $vb1->set_border_width (PAGE_SPC);
488 $vb1->pack_start ($cb_use_dlg, FALSE, FALSE, 0);
489 $ab_frame->add ($vb1);
491 my $mem_frame = Gtk2::Frame->new ($xl::s{mem_frame});
492 my $tb_max_use = &new_text_box_for(\%pr::oth, 'max_use');
493 my $tb_min_time = &new_text_box_for(\%pr::oth, 'min_time');
494 my $vb2 = Gtk2::VBox->new (FALSE, 5);
495 $vb2->set_border_width (PAGE_SPC);
496 $vb2->pack_start ($tb_max_use, FALSE, FALSE, 0);
497 $vb2->pack_start ($tb_min_time, FALSE, FALSE, 0);
498 $mem_frame->add ($vb2);
500 $of->pack_start ($ab_frame, FALSE, FALSE, FRAME_SPC);
501 $of->pack_start ($mem_frame, FALSE, FALSE, FRAME_SPC);
506 %pr::gui = ( # gui bells and whistles
509 $xl::s{l_gui_b_unread},
510 $xl::s{h_gui_b_unread},
518 $xl::s{l_gui_no_markup},
519 $xl::s{h_gui_no_markup},
526 'enable_dotted_lines',
527 $xl::s{l_gui_dot_lines},
528 $xl::s{h_gui_dot_lines},
536 $xl::s{l_gui_h_scroll},
537 $xl::s{h_gui_h_scroll},
545 $xl::s{l_gui_swp_from},
546 $xl::s{h_gui_swp_from},
553 'folderview_vscrollbar_policy',
554 $xl::s{l_gui_v_scroll},
555 $xl::s{h_gui_v_scroll},
556 '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
562 'stripes_color_offset',
563 $xl::s{l_gui_strip_off},
564 $xl::s{h_gui_strip_off},
571 'textview_cursor_visible',
572 $xl::s{l_gui_cursor_v},
573 $xl::s{h_gui_cursor_v},
580 'toolbar_detachable',
581 $xl::s{l_gui_toolbar_d},
582 $xl::s{h_gui_toolbar_d},
589 'use_stripes_everywhere',
590 $xl::s{l_gui_strip_all},
591 $xl::s{h_gui_strip_all},
598 'use_stripes_in_summaries',
599 $xl::s{l_gui_strip_sum},
600 $xl::s{h_gui_strip_sum},
609 my $gf = Gtk2::VBox->new (FALSE, 5);
610 $gf->set_border_width (PAGE_SPC);
612 my $stripes_frame = Gtk2::Frame->new ($xl::s{stripes_frame});
613 my $cb_strip_all = &new_check_button_for (\%pr::gui, 'strip_all');
614 my $cb_strip_sum = &new_check_button_for (\%pr::gui, 'strip_sum');
615 my $tb_strip_off = &new_text_box_for (\%pr::gui, 'strip_off');
616 my $vb1 = Gtk2::VBox->new (FALSE, 5);
617 $vb1->set_border_width (PAGE_SPC);
618 $vb1->pack_start ($cb_strip_all, FALSE, FALSE, 0);
619 $vb1->pack_start ($cb_strip_sum, FALSE, FALSE, 0);
620 $vb1->pack_start ($tb_strip_off, FALSE, FALSE, 0);
621 $stripes_frame->add ($vb1);
623 my $mlist_frame = Gtk2::Frame->new ($xl::s{mlist_frame});
624 my $cb_b_unread = &new_check_button_for (\%pr::gui, 'b_unread');
625 my $cb_swp_from = &new_check_button_for (\%pr::gui, 'swp_from');
626 my $vb3 = Gtk2::VBox->new (FALSE, 5);
627 $vb3->set_border_width (PAGE_SPC);
628 $vb3->pack_start ($cb_b_unread, FALSE, FALSE, 0);
629 $vb3->pack_start ($cb_swp_from, FALSE, FALSE, 0);
630 $mlist_frame->add ($vb3);
632 my $sbar_frame = Gtk2::Frame->new ($xl::s{sbar_frame});
633 my $cb_h_scroll = &new_check_button_for (\%pr::gui, 'h_scroll');
634 my $sb_v_scroll = &new_selection_box_for (\%pr::gui, 'v_scroll');
635 my $vb2 = Gtk2::VBox->new (FALSE, 5);
636 $vb2->set_border_width (PAGE_SPC);
637 $vb2->pack_start ($cb_h_scroll, FALSE, FALSE, 0);
638 $vb2->pack_start ($sb_v_scroll, FALSE, FALSE, 0);
639 $sbar_frame->add ($vb2);
641 my $cb_no_markup = &new_check_button_for (\%pr::gui, 'no_markup');
642 my $cb_dot_lines = &new_check_button_for (\%pr::gui, 'dot_lines');
643 my $cb_cursor_v = &new_check_button_for (\%pr::gui, 'cursor_v');
644 my $cb_toolbar_d = &new_check_button_for (\%pr::gui, 'toolbar_d');
646 $gf->pack_start ($stripes_frame, FALSE, FALSE, FRAME_SPC);
647 $gf->pack_start ($mlist_frame, FALSE, FALSE, FRAME_SPC);
648 $gf->pack_start ($cb_no_markup, FALSE, FALSE, 0);
649 $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
650 $gf->pack_start ($cb_cursor_v, FALSE, FALSE, 0);
651 $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
652 $gf->pack_start ($sbar_frame, FALSE, FALSE, FRAME_SPC);
657 %pr::beh = ( # tweak some behaviour
660 $xl::s{l_beh_hover_t},
661 $xl::s{h_beh_hover_t},
669 $xl::s{l_beh_dangerous},
670 $xl::s{h_beh_dangerous},
677 'respect_flowed_format',
678 $xl::s{l_beh_flowed},
679 $xl::s{h_beh_flowed},
686 'save_parts_readwrite',
687 $xl::s{l_beh_parts_rw},
688 $xl::s{h_beh_parts_rw},
695 'skip_ssl_cert_check',
696 $xl::s{l_beh_skip_ssl},
697 $xl::s{h_beh_skip_ssl},
704 'statusbar_update_step',
705 $xl::s{l_beh_up_step},
706 $xl::s{h_beh_up_step},
713 'thread_by_subject_max_age',
714 $xl::s{l_beh_thread_a},
715 $xl::s{h_beh_thread_a},
723 $xl::s{l_beh_unsafe_ssl},
724 $xl::s{h_beh_unsafe_ssl},
731 'utf8_instead_of_locale_for_broken_mail',
732 $xl::s{l_beh_use_utf8},
733 $xl::s{h_beh_use_utf8},
741 $xl::s{l_beh_warn_dnd},
742 $xl::s{h_beh_warn_dnd},
750 sub new_behaviour_page() {
751 my $bf = Gtk2::VBox->new (FALSE, 5);
752 $bf->set_border_width (PAGE_SPC);
754 my $dnd_frame = Gtk2::Frame->new ($xl::s{dnd_frame});
755 my $tb_hoover_t = &new_text_box_for (\%pr::beh, 'hover_t');
756 my $cb_warn_dnd = &new_check_button_for (\%pr::beh, 'warn_dnd');
757 my $vb1 = Gtk2::VBox->new (FALSE, 5);
758 $vb1->set_border_width (PAGE_SPC);
759 $vb1->pack_start ($cb_warn_dnd, FALSE, FALSE, 0);
760 $vb1->pack_start ($tb_hoover_t, FALSE, FALSE, 0);
761 $dnd_frame->add ($vb1);
763 my $ssl_frame = Gtk2::Frame->new ($xl::s{ssl_frame});
764 my $cb_skip_ssl = &new_check_button_for (\%pr::beh, 'skip_ssl');
765 my $cb_unsafe_ssl = &new_check_button_for (\%pr::beh, 'unsafe_ssl');
766 my $hb1 = Gtk2::HBox->new (FALSE, 5);
767 $hb1->set_border_width (PAGE_SPC);
768 $hb1->pack_start ($cb_skip_ssl, FALSE, FALSE, 0);
769 $hb1->pack_start ($cb_unsafe_ssl, FALSE, FALSE, 0);
770 $ssl_frame->add ($hb1);
772 my $tb_up_step = &new_text_box_for (\%pr::beh, 'up_step');
773 my $tb_thread_a = &new_text_box_for (\%pr::beh, 'thread_a');
775 my $msgs_frame = Gtk2::Frame->new ($xl::s{msgs_frame});
776 my $cb_flowed = &new_check_button_for (\%pr::beh, 'flowed');
777 my $cb_parts_rw = &new_check_button_for (\%pr::beh, 'parts_rw');
778 my $cb_use_utf8 = &new_check_button_for (\%pr::beh, 'use_utf8');
779 my $cb_dangerous = &new_check_button_for (\%pr::beh, 'dangerous');
780 my $vb2 = Gtk2::VBox->new (FALSE, 5);
781 $vb2->set_border_width (PAGE_SPC);
782 $vb2->pack_start ($cb_flowed, FALSE, FALSE, 0);
783 $vb2->pack_start ($cb_parts_rw, FALSE, FALSE, 0);
784 $vb2->pack_start ($cb_use_utf8, FALSE, FALSE, 0);
785 $vb2->pack_start ($cb_dangerous, FALSE, FALSE, 0);
786 $msgs_frame->add ($vb2);
788 $bf->pack_start ($dnd_frame, FALSE, FALSE, FRAME_SPC);
789 $bf->pack_start ($ssl_frame, FALSE, FALSE, FRAME_SPC);
790 $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
791 $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
792 $bf->pack_start ($msgs_frame, FALSE, FALSE, FRAME_SPC);
797 %pr::col = ( # a variety of colours
800 $xl::s{l_col_emphasis},
801 $xl::s{h_col_emphasis},
809 $xl::s{l_col_log_err},
810 $xl::s{h_col_log_err},
818 $xl::s{l_col_log_in},
819 $xl::s{h_col_log_in},
827 $xl::s{l_col_log_msg},
828 $xl::s{h_col_log_msg},
836 $xl::s{l_col_log_out},
837 $xl::s{h_col_log_out},
845 $xl::s{l_col_log_warn},
846 $xl::s{h_col_log_warn},
854 sub new_colours_page() {
855 my $cf = Gtk2::VBox->new (FALSE, 5);
856 $cf->set_border_width (PAGE_SPC);
858 my $msgview_frame = Gtk2::Frame->new ($xl::s{msgview_frame});
859 my $cb_emphasis = &new_color_button_for (\%pr::col, 'emphasis');
860 my $vb1 = Gtk2::VBox->new (FALSE, 5);
861 $vb1->set_border_width (PAGE_SPC);
862 $vb1->pack_start ($cb_emphasis, FALSE, FALSE, 0);
863 $msgview_frame->add ($vb1);
865 my $log_frame = Gtk2::Frame->new ($xl::s{log_frame});
866 my $cb_log_err = &new_color_button_for (\%pr::col, 'log_err');
867 my $cb_log_in = &new_color_button_for (\%pr::col, 'log_in');
868 my $cb_log_msg = &new_color_button_for (\%pr::col, 'log_msg');
869 my $cb_log_out = &new_color_button_for (\%pr::col, 'log_out');
870 my $cb_log_warn = &new_color_button_for (\%pr::col, 'log_warn');
871 my $vb2 = Gtk2::VBox->new (FALSE, 5);
872 $vb2->set_border_width (PAGE_SPC);
873 $vb2->pack_start ($cb_log_err, FALSE, FALSE, 0);
874 $vb2->pack_start ($cb_log_in, FALSE, FALSE, 0);
875 $vb2->pack_start ($cb_log_msg, FALSE, FALSE, 0);
876 $vb2->pack_start ($cb_log_out, FALSE, FALSE, 0);
877 $vb2->pack_start ($cb_log_warn, FALSE, FALSE, 0);
878 $log_frame->add ($vb2);
880 $cf->pack_start ($msgview_frame, FALSE, FALSE, 0);
881 $cf->pack_start ($log_frame, FALSE, FALSE, 0);
886 # the command line help
888 my $line = '-' x length ($xl::s{about_title}) . "\n";
890 print $xl::s{about_title} . "\n";
891 print $xl::s{about_version} . " $VERSION\n";
892 print "Perl-GLib " . $Glib::VERSION;
893 # version info stuff appeared in 1.040
894 if ($Glib::VERSION >= 1.040) {
895 print _(", built for ") . join(".", Glib->GET_VERSION_INFO)
896 . _(", running with ") . join(".", &Glib::major_version,
897 &Glib::minor_version, &Glib::micro_version);
900 print "Perl-GTK2 " . $Gtk2::VERSION;
901 if ($Gtk2::VERSION >= 1.040) {
902 print _(", built for ") . join(".", Gtk2->GET_VERSION_INFO)
903 . _(", running with ") . join(".", &Gtk2::major_version,
904 &Gtk2::minor_version, &Gtk2::micro_version);
908 print _("Syntax:\n");
909 print _(" clawsker [options]\n");
910 print _("Options:\n");
911 print _(" --help Prints this help screen.\n");
912 print _(" --verbose More messages on standard output.\n");
913 print _(" --alternate-config-dir <dir> Uses <dir> as Claws Mail config dir.\n");
914 print _(" --clawsrc <file> Uses <file> as full resource name.\n");
917 # handle errors which don't allow to run
918 sub command_line_fatal() {
920 my $emsg = $xl::s{e_error} . $reason;
921 error_dialog ($emsg);
922 log_message ("$emsg", 'die');
925 # parse the command line
926 sub parse_command_line() {
928 while (defined($ARGV[$arg])) {
938 /--alternate-config-dir/ && do {
940 &command_line_fatal ($xl::s{e_requireddir})
941 unless defined($ARGV[$arg]);
942 &command_line_fatal ($xl::s{e_notadir})
943 unless -d $ARGV[$arg];
944 $CONFIGDIR = $ARGV[$arg];
945 $ALTCONFIGDIR = TRUE;
950 &command_line_fatal($xl::s{e_requiredfile})
951 unless defined($ARGV[$arg]);
952 &command_line_fatal($xl::s{e_notafile})
953 unless -f $ARGV[$arg];
954 &set_rc_filename ($ARGV[$arg]);
957 /.*/ && &command_line_fatal (
958 _("unknown option '{opt}'.\n", opt => $ARGV[$arg]));
962 # eveything continues...
966 # update the hidden preferences status from loaded values
967 sub init_hidden_preferences() {
968 foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth) {
969 foreach my $key (keys %$hash) {
970 $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
976 # load current status from disc
977 sub load_preferences() {
978 my $rc = &get_rc_filename;
979 &log_message ("Loading preferences from $rc\n");
980 return FALSE unless &check_rc_file ($rc);
981 return FALSE unless &check_claws_not_running;
985 if (/^([8a-z_]+)=(.*)$/) {
993 # save current preferences to disc
994 sub save_preferences() {
995 my $rc = &get_rc_filename;
996 &log_message ("Saving preferences to $rc\n");
997 return FALSE unless &check_rc_file ($rc);
998 return FALSE unless &check_claws_not_running;
999 my $rcbak = "$rc.backup";
1000 rename ($rc, $rcbak);
1002 open (RCB, "<$rcbak");
1005 if (/^([8a-z_]+)=(.*)$/) {
1006 if (defined($HPVALUE{$1})) {
1007 print RCF $1 . "=" . $HPVALUE{$1} . "\n";
1010 print RCF $_ . "\n";
1014 print RCF $_ . "\n";
1023 sub new_notebook() {
1024 my $nb = Gtk2::Notebook->new;
1026 $nb->append_page (&new_behaviour_page, $xl::s{tab_behaviour});
1027 $nb->append_page (&new_colours_page, $xl::s{tab_colours});
1028 $nb->append_page (&new_gui_page, $xl::s{tab_gui});
1029 $nb->append_page (&new_other_page, $xl::s{tab_other});
1034 # create an about dialog
1035 sub new_about_dialog() {
1037 my $title = $xl::s{about_title};
1038 my $lic = $xl::s{about_license};
1039 my $vers = $xl::s{about_version} . " $VERSION";
1041 "This program is free software: you can redistribute it and/or modify
1042 it under the terms of the GNU General Public License as published by
1043 the Free Software Foundation, either version 3 of the License, or
1044 (at your option) any later version.
1046 This program is distributed in the hope that it will be useful,
1047 but WITHOUT ANY WARRANTY; without even the implied warranty of
1048 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1049 GNU General Public License for more details.
1051 You should have received a copy of the GNU General Public License
1052 along with this program. If not, see <http://www.gnu.org/licenses/>.";
1054 my $holder = "Ricardo Mones <ricardo\@mones.org>";
1056 my $dialog = Gtk2::MessageDialog->new_with_markup ($parent,
1057 [qw/modal destroy-with-parent/],
1059 "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
1060 . "<span size=\"large\">$vers</span>\n"
1061 . "<span>Copyright $year by $holder</span>\n\n"
1062 . "<span size=\"large\">$lic</span>\n\n"
1063 . "<span size=\"small\">$license</span>");
1064 $dialog->set_title ($xl::s{about});
1069 # create buttons box
1070 sub new_button_box() {
1071 my ($parent, $adlg) = @_;
1072 my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
1073 my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
1074 my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
1075 # disable button until is really implemented
1076 # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
1077 my $hbox = Gtk2::HBox->new (FALSE, 5);
1079 $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
1080 $b_apply->signal_connect (clicked => sub { &save_preferences ($parent) });
1081 # $b_undo->signal_connect (clicked => sub { &undo_current_changes });
1082 $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
1084 $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
1085 $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
1086 # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
1087 $hbox->pack_start ($b_about, FALSE, FALSE, 0);
1093 $main_window = Gtk2::Window->new ('toplevel');
1094 exit unless &parse_command_line;
1095 exit unless &load_preferences;
1096 exit unless &init_hidden_preferences;
1098 my $box = Gtk2::VBox->new (FALSE, 5);
1099 $box->set_border_width(3);
1100 my $about = &new_about_dialog;
1101 $box->pack_start (&new_notebook, FALSE, FALSE, 0);
1102 $box->pack_end (&new_button_box ($main_window, $about), FALSE, FALSE, 0);
1103 $main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
1104 $main_window->set_title ($xl::s{win_title});
1105 $main_window->add ($box);
1106 $main_window->show_all;