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 setlocale (LC_ALL, $locale);
91 bindtextdomain ($NAME, sprintf ('%s/share/locale', $PREFIX));
94 my $SHOWHINTS = FALSE;
95 $SHOWHINTS = TRUE if ($Gtk2::VERSION >= 1.040 and Gtk2->CHECK_VERSION (2, 12, 0));
100 my $xla = gettext ($str);
101 if (scalar(keys(%par)) > 0) {
102 foreach my $key (keys %par) {
103 $xla =~ s/\{$key\}/$par{$key}/g;
111 win_title => _('Claws Mail Hidden Preferences'),
112 about => _('About...'),
113 about_title => _('Clawsker :: A Claws Mail Tweaker'),
114 about_license => _('License:'),
115 about_version => _('Version:'),
117 tab_colours => _('Colours'),
118 tab_behaviour => _('Behaviour'),
120 tab_other => _('Other'),
122 ab_frame => _('Addressbook'),
123 mem_frame => _('Memory'),
124 msgview_frame => _('Message view'),
125 log_frame => _('Log window'),
126 dnd_frame => _('Drag \'n\' drop'),
127 ssl_frame => _('Secure Sockets Layer'),
128 msgs_frame => _('Messages'),
129 stripes_frame => _('Coloured stripes'),
130 sbar_frame => _('Scroll bars'),
131 mlist_frame => _('Message list'),
133 l_oth_use_dlg => _('Use detached address book edit dialogue'),
134 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.'),
135 l_oth_max_use => _('Maximum memory for message cache (Kb)'),
136 h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kB.'),
137 l_oth_min_time => _('Minimun time for cache elements (minutes)'),
138 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.'),
140 l_gui_b_unread => _('Show unread messages with bold font'),
141 h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
142 l_gui_no_markup => _('Don\'t use markup in compose window'),
143 h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
144 l_gui_dot_lines => _('Use dotted lines in tree views'),
145 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.'),
146 l_gui_h_scroll => _('Enable horizontal scrollbar'),
147 h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
148 l_gui_swp_from => _('Dislay To header in From field in Sent folder'),
149 h_gui_swp_from => _('Display the sender\'s email address in the To column of the Sent folder instead of the recipient\'s.'),
150 l_gui_v_scroll => _('Folder list scrollbar behaviour'),
151 h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
152 l_gui_v_scroll_show => _('Show always'),
153 l_gui_v_scroll_auto => _('Automatic'),
154 l_gui_v_scroll_hide => _('Hide always'),
155 l_gui_strip_off => _('Striped lines contrast'),
156 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.'),
157 l_gui_cursor_v => _('Show Cursor in message view'),
158 h_gui_cursor_v => _('Display the cursor in the message view.'),
159 l_gui_toolbar_d => _('Detachable toolbars'),
160 h_gui_toolbar_d => _('Show handles in the toolbars.'),
161 l_gui_strip_all => _('Use stripes in all tree view components'),
162 h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
163 l_gui_strip_sum => _('Use stripes in Folder List and Message List'),
164 h_gui_strip_sum => _('Enable alternately coloured lines in message list and folder list'),
166 l_beh_hover_t => _('Drag \'n\' drop hover timeout (ms)'),
167 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.'),
168 l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
169 h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
170 l_beh_flowed => _('Respect format=flowed in messages'),
171 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.'),
172 l_beh_parts_rw => _('Allow writable temporary files'),
173 h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
174 l_beh_skip_ssl => _('Don\'t check SSL certificates'),
175 h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
176 l_beh_up_step => _('Progress bar update step (items)'),
177 h_beh_up_step => _('Update stepping in progress bars.'),
178 l_beh_thread_a => _('Maximum age when threading by subject (days)'),
179 h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
180 l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
181 h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
182 l_beh_use_utf8 => _('Force UTF-8 for broken mails'),
183 h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
184 l_beh_warn_dnd => _('Warn on drag \'n\' drop'),
185 h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
187 l_col_emphasis => _('X-Mailer header'),
188 h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
189 l_col_log_err => _('Error messages'),
190 h_col_log_err => _('Colour for error messages in log window.'),
191 l_col_log_in => _('Server messages'),
192 h_col_log_in => _('Colour for input messages in log window.'),
193 l_col_log_msg => _('Standard messages'),
194 h_col_log_msg => _('Colour for messages in log window.'),
195 l_col_log_out => _('Client messages'),
196 h_col_log_out => _('Colour for output messages in log window.'),
197 l_col_log_warn => _('Warnings'),
198 h_col_log_warn => _('Colour for warning messages in log window.'),
200 e_error => _('Error: '),
201 e_noclawsrc => _('resource file for Claws Mail was not found.'),
202 e_running => _('seems Claws Mail is currently running, close it first.'),
203 e_requireddir => _('option requires a directory name.'),
204 e_requiredfile => _('option requires a file name.'),
205 e_notadir => _('specified name is not a directory or does not exist.'),
206 e_notafile => _('specified name is not a file or does not exist.'),
209 # all preferences read by load_preferences
211 # values of all preferences handled by clawsker
213 # default config dir and file name
214 my $ALTCONFIGDIR = FALSE;
215 my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
216 my $CONFIGRC = 'clawsrc';
218 # index constants for preference arrays
219 use constant NAME => 0; # the name on the rc file
220 use constant LABEL => 1; # the label on the GUI
221 use constant DESC => 2; # the description for the hint/help
222 use constant TYPE => 3; # data type: bool, int, float, string, color
223 use constant GUI => 4; # GUI element
225 # constants for GUI spacing
226 use constant HBOX_SPC => 5;
227 use constant FRAME_SPC => 2;
228 use constant PAGE_SPC => 5;
230 # data handlers and auxiliar functions
232 sub handle_bool_value {
233 my ($widget, $event, $dataref) = @_;
234 $$dataref = ($widget->get_active ())? '1': '0';
237 sub handle_int_value {
238 my ($widget, $event, $dataref) = @_;
239 $_ = $widget->get_text ();
244 $widget->set_text ($_);
247 $widget->set_text ($$dataref);
251 sub handle_string_value {
252 my ($widget, $event, $dataref) = @_;
253 $$dataref = $widget->get_text ();
256 sub gdk_color_from_str {
258 my ($rr, $gg, $bb) = (0, 0 ,0);
260 if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
265 my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
269 sub str_from_gdk_color {
271 my $rr = $color->red / 256;
272 my $gg = $color->green / 256;
273 my $bb = $color->blue / 256;
274 my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
278 sub handle_color_value {
279 my ($widget, $event, $dataref) = @_;
280 my $newcol = $widget->get_color;
281 $$dataref = &str_from_gdk_color ($newcol);
284 sub handle_selection_value {
285 my ($widget, $event, $dataref) = @_;
286 $$dataref = $widget->get_active;
289 sub get_rc_filename {
290 return $CONFIGDIR . $CONFIGRC;
293 sub set_rc_filename {
295 my @parts = split ('/', $fullname);
296 $CONFIGRC = $parts[$#parts];
297 $parts[$#parts] = '';
298 $CONFIGDIR = join ('/', @parts);
302 my ($mesg, $fatal) = @_;
303 if (defined($fatal) && $fatal eq 'die') {
304 die "$NAME: $mesg\n";
307 print "$NAME: $mesg\n";
313 my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
314 my $errordlg = Gtk2::MessageDialog->new_with_markup ($main_window, 'modal', 'error', 'cancel', $markup);
315 $errordlg->set_title (_('Error message'));
320 sub check_claws_not_running() {
321 my $socket = (not $ALTCONFIGDIR)? "/tmp/": $CONFIGDIR;
322 $socket .= "claws-mail-$<";
324 my $emsg = "$xl::s{e_error}$xl::s{e_running}";
326 error_dialog ($emsg);
333 sub check_rc_file() {
335 (defined($rcfile) && -f $rcfile) or do {
336 my $emsg = "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
338 error_dialog ($emsg);
345 sub set_widget_hint() {
347 my ($wdgt, $hint) = @_;
348 $wdgt->set_tooltip_text ($hint);
349 $wdgt->set_has_tooltip (TRUE);
353 # graphic element creation
355 sub new_check_button_for {
356 my ($hash, $key) = @_;
357 my $name = $$hash{$key}[NAME];
358 my $label = $$hash{$key}[LABEL];
360 my $hbox = Gtk2::HBox->new (FALSE, 5);
361 my $cb = Gtk2::CheckButton->new ($label);
362 $$hash{$key}[GUI] = $cb;
363 $cb->set_active ($HPVALUE{$name} eq '1');
364 $cb->signal_connect (clicked => sub {
366 &handle_bool_value($w, $e, \$HPVALUE{$name});
368 &set_widget_hint ($cb, $$hash{$key}[DESC]);
369 $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
374 sub new_text_box_for {
375 my ($hash, $key) = @_;
376 my $name = $$hash{$key}[NAME];
377 my $label = $$hash{$key}[LABEL];
379 my $hbox = Gtk2::HBox->new (FALSE, 5);
380 my $glabel = Gtk2::Label->new ($label);
381 my $gentry = Gtk2::Entry->new;
382 $gentry->set_width_chars (8);
383 $$hash{$key}[GUI] = $gentry;
384 $gentry->set_text($HPVALUE{$name});
385 $gentry->signal_connect(changed => sub {
387 &handle_int_value($w, $e, \$HPVALUE{$name}); # FIXME int only
389 &set_widget_hint ($gentry, $$hash{$key}[DESC]);
390 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
391 $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
396 sub new_color_button_for {
397 my ($hash, $key) = @_;
398 my $name = $$hash{$key}[NAME];
399 my $label = $$hash{$key}[LABEL];
401 my $col = &gdk_color_from_str ($HPVALUE{$name});
402 my $hbox = Gtk2::HBox->new (FALSE, 5);
403 my $glabel = Gtk2::Label->new ($label);
404 my $button = Gtk2::ColorButton->new_with_color ($col);
405 $$hash{$key}[GUI] = $button;
406 $button->set_title ($label);
407 $button->set_relief ('none');
408 $button->signal_connect ('color-set' => sub {
410 &handle_color_value($w, $e, \$HPVALUE{$name});
412 &set_widget_hint ($button, $$hash{$key}[DESC]);
413 $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
414 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
419 sub new_selection_box_for {
420 my ($hash, $key) = @_;
421 my $name = $$hash{$key}[NAME];
422 my $label = $$hash{$key}[LABEL];
424 my $hbox = Gtk2::HBox->new (FALSE, 5);
425 my $glabel = Gtk2::Label->new ($label);
426 my $combo = Gtk2::ComboBox->new_text;
427 $$hash{$key}[GUI] = $combo;
428 my @options = split (';', $$hash{$key}[TYPE]);
429 foreach my $opt (@options) {
430 my ($index, $textkey) = split ('=', $opt);
431 $combo->insert_text ($index, $xl::s{$textkey});
433 $combo->signal_connect ('changed' => sub {
435 &handle_selection_value($w, $e, \$HPVALUE{$name});
437 $combo->set_active ($HPVALUE{$name});
438 &set_widget_hint ($combo, $$hash{$key}[DESC]);
439 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
440 $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
445 # preference maps and corresponding page creation subs
447 %pr::oth = ( # other preferences
449 'addressbook_use_editaddress_dialog',
450 $xl::s{l_oth_use_dlg},
451 $xl::s{h_oth_use_dlg},
456 'cache_max_mem_usage',
457 $xl::s{l_oth_max_use},
458 $xl::s{h_oth_max_use},
463 'cache_min_keep_time',
464 $xl::s{l_oth_min_time},
465 $xl::s{h_oth_min_time},
471 sub new_other_page() {
472 my $of = Gtk2::VBox->new (FALSE, 5);
473 $of->set_border_width (PAGE_SPC);
475 my $ab_frame = Gtk2::Frame->new ($xl::s{ab_frame});
476 my $cb_use_dlg = &new_check_button_for(\%pr::oth, 'use_dlg');
477 my $vb1 = Gtk2::VBox->new (FALSE, 5);
478 $vb1->set_border_width (PAGE_SPC);
479 $vb1->pack_start ($cb_use_dlg, FALSE, FALSE, 0);
480 $ab_frame->add ($vb1);
482 my $mem_frame = Gtk2::Frame->new ($xl::s{mem_frame});
483 my $tb_max_use = &new_text_box_for(\%pr::oth, 'max_use');
484 my $tb_min_time = &new_text_box_for(\%pr::oth, 'min_time');
485 my $vb2 = Gtk2::VBox->new (FALSE, 5);
486 $vb2->set_border_width (PAGE_SPC);
487 $vb2->pack_start ($tb_max_use, FALSE, FALSE, 0);
488 $vb2->pack_start ($tb_min_time, FALSE, FALSE, 0);
489 $mem_frame->add ($vb2);
491 $of->pack_start ($ab_frame, FALSE, FALSE, FRAME_SPC);
492 $of->pack_start ($mem_frame, FALSE, FALSE, FRAME_SPC);
497 %pr::gui = ( # gui bells and whistles
500 $xl::s{l_gui_b_unread},
501 $xl::s{h_gui_b_unread},
507 $xl::s{l_gui_no_markup},
508 $xl::s{h_gui_no_markup},
513 'enable_dotted_lines',
514 $xl::s{l_gui_dot_lines},
515 $xl::s{h_gui_dot_lines},
521 $xl::s{l_gui_h_scroll},
522 $xl::s{h_gui_h_scroll},
528 $xl::s{l_gui_swp_from},
529 $xl::s{h_gui_swp_from},
534 'folderview_vscrollbar_policy',
535 $xl::s{l_gui_v_scroll},
536 $xl::s{h_gui_v_scroll},
537 '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
541 'stripes_color_offset',
542 $xl::s{l_gui_strip_off},
543 $xl::s{h_gui_strip_off},
548 'textview_cursor_visible',
549 $xl::s{l_gui_cursor_v},
550 $xl::s{h_gui_cursor_v},
555 'toolbar_detachable',
556 $xl::s{l_gui_toolbar_d},
557 $xl::s{h_gui_toolbar_d},
562 'use_stripes_everywhere',
563 $xl::s{l_gui_strip_all},
564 $xl::s{h_gui_strip_all},
569 'use_stripes_in_summaries',
570 $xl::s{l_gui_strip_sum},
571 $xl::s{h_gui_strip_sum},
578 my $gf = Gtk2::VBox->new (FALSE, 5);
579 $gf->set_border_width (PAGE_SPC);
581 my $stripes_frame = Gtk2::Frame->new ($xl::s{stripes_frame});
582 my $cb_strip_all = &new_check_button_for (\%pr::gui, 'strip_all');
583 my $cb_strip_sum = &new_check_button_for (\%pr::gui, 'strip_sum');
584 my $tb_strip_off = &new_text_box_for (\%pr::gui, 'strip_off');
585 my $vb1 = Gtk2::VBox->new (FALSE, 5);
586 $vb1->set_border_width (PAGE_SPC);
587 $vb1->pack_start ($cb_strip_all, FALSE, FALSE, 0);
588 $vb1->pack_start ($cb_strip_sum, FALSE, FALSE, 0);
589 $vb1->pack_start ($tb_strip_off, FALSE, FALSE, 0);
590 $stripes_frame->add ($vb1);
592 my $mlist_frame = Gtk2::Frame->new ($xl::s{mlist_frame});
593 my $cb_b_unread = &new_check_button_for (\%pr::gui, 'b_unread');
594 my $cb_swp_from = &new_check_button_for (\%pr::gui, 'swp_from');
595 my $vb3 = Gtk2::VBox->new (FALSE, 5);
596 $vb3->set_border_width (PAGE_SPC);
597 $vb3->pack_start ($cb_b_unread, FALSE, FALSE, 0);
598 $vb3->pack_start ($cb_swp_from, FALSE, FALSE, 0);
599 $mlist_frame->add ($vb3);
601 my $sbar_frame = Gtk2::Frame->new ($xl::s{sbar_frame});
602 my $cb_h_scroll = &new_check_button_for (\%pr::gui, 'h_scroll');
603 my $sb_v_scroll = &new_selection_box_for (\%pr::gui, 'v_scroll');
604 my $vb2 = Gtk2::VBox->new (FALSE, 5);
605 $vb2->set_border_width (PAGE_SPC);
606 $vb2->pack_start ($cb_h_scroll, FALSE, FALSE, 0);
607 $vb2->pack_start ($sb_v_scroll, FALSE, FALSE, 0);
608 $sbar_frame->add ($vb2);
610 my $cb_no_markup = &new_check_button_for (\%pr::gui, 'no_markup');
611 my $cb_dot_lines = &new_check_button_for (\%pr::gui, 'dot_lines');
612 my $cb_cursor_v = &new_check_button_for (\%pr::gui, 'cursor_v');
613 my $cb_toolbar_d = &new_check_button_for (\%pr::gui, 'toolbar_d');
615 $gf->pack_start ($stripes_frame, FALSE, FALSE, FRAME_SPC);
616 $gf->pack_start ($mlist_frame, FALSE, FALSE, FRAME_SPC);
617 $gf->pack_start ($cb_no_markup, FALSE, FALSE, 0);
618 $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
619 $gf->pack_start ($cb_cursor_v, FALSE, FALSE, 0);
620 $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
621 $gf->pack_start ($sbar_frame, FALSE, FALSE, FRAME_SPC);
626 %pr::beh = ( # tweak some behaviour
629 $xl::s{l_beh_hover_t},
630 $xl::s{h_beh_hover_t},
636 $xl::s{l_beh_dangerous},
637 $xl::s{h_beh_dangerous},
642 'respect_flowed_format',
643 $xl::s{l_beh_flowed},
644 $xl::s{h_beh_flowed},
649 'save_parts_readwrite',
650 $xl::s{l_beh_parts_rw},
651 $xl::s{h_beh_parts_rw},
656 'skip_ssl_cert_check',
657 $xl::s{l_beh_skip_ssl},
658 $xl::s{h_beh_skip_ssl},
663 'statusbar_update_step',
664 $xl::s{l_beh_up_step},
665 $xl::s{h_beh_up_step},
670 'thread_by_subject_max_age',
671 $xl::s{l_beh_thread_a},
672 $xl::s{h_beh_thread_a},
678 $xl::s{l_beh_unsafe_ssl},
679 $xl::s{h_beh_unsafe_ssl},
684 'utf8_instead_of_locale_for_broken_mail',
685 $xl::s{l_beh_use_utf8},
686 $xl::s{h_beh_use_utf8},
692 $xl::s{l_beh_warn_dnd},
693 $xl::s{h_beh_warn_dnd},
699 sub new_behaviour_page() {
700 my $bf = Gtk2::VBox->new (FALSE, 5);
701 $bf->set_border_width (PAGE_SPC);
703 my $dnd_frame = Gtk2::Frame->new ($xl::s{dnd_frame});
704 my $tb_hoover_t = &new_text_box_for (\%pr::beh, 'hover_t');
705 my $cb_warn_dnd = &new_check_button_for (\%pr::beh, 'warn_dnd');
706 my $vb1 = Gtk2::VBox->new (FALSE, 5);
707 $vb1->set_border_width (PAGE_SPC);
708 $vb1->pack_start ($cb_warn_dnd, FALSE, FALSE, 0);
709 $vb1->pack_start ($tb_hoover_t, FALSE, FALSE, 0);
710 $dnd_frame->add ($vb1);
712 my $ssl_frame = Gtk2::Frame->new ($xl::s{ssl_frame});
713 my $cb_skip_ssl = &new_check_button_for (\%pr::beh, 'skip_ssl');
714 my $cb_unsafe_ssl = &new_check_button_for (\%pr::beh, 'unsafe_ssl');
715 my $hb1 = Gtk2::HBox->new (FALSE, 5);
716 $hb1->set_border_width (PAGE_SPC);
717 $hb1->pack_start ($cb_skip_ssl, FALSE, FALSE, 0);
718 $hb1->pack_start ($cb_unsafe_ssl, FALSE, FALSE, 0);
719 $ssl_frame->add ($hb1);
721 my $tb_up_step = &new_text_box_for (\%pr::beh, 'up_step');
722 my $tb_thread_a = &new_text_box_for (\%pr::beh, 'thread_a');
724 my $msgs_frame = Gtk2::Frame->new ($xl::s{msgs_frame});
725 my $cb_flowed = &new_check_button_for (\%pr::beh, 'flowed');
726 my $cb_parts_rw = &new_check_button_for (\%pr::beh, 'parts_rw');
727 my $cb_use_utf8 = &new_check_button_for (\%pr::beh, 'use_utf8');
728 my $cb_dangerous = &new_check_button_for (\%pr::beh, 'dangerous');
729 my $vb2 = Gtk2::VBox->new (FALSE, 5);
730 $vb2->set_border_width (PAGE_SPC);
731 $vb2->pack_start ($cb_flowed, FALSE, FALSE, 0);
732 $vb2->pack_start ($cb_parts_rw, FALSE, FALSE, 0);
733 $vb2->pack_start ($cb_use_utf8, FALSE, FALSE, 0);
734 $vb2->pack_start ($cb_dangerous, FALSE, FALSE, 0);
735 $msgs_frame->add ($vb2);
737 $bf->pack_start ($dnd_frame, FALSE, FALSE, FRAME_SPC);
738 $bf->pack_start ($ssl_frame, FALSE, FALSE, FRAME_SPC);
739 $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
740 $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
741 $bf->pack_start ($msgs_frame, FALSE, FALSE, FRAME_SPC);
746 %pr::col = ( # a variety of colours
749 $xl::s{l_col_emphasis},
750 $xl::s{h_col_emphasis},
756 $xl::s{l_col_log_err},
757 $xl::s{h_col_log_err},
763 $xl::s{l_col_log_in},
764 $xl::s{h_col_log_in},
770 $xl::s{l_col_log_msg},
771 $xl::s{h_col_log_msg},
777 $xl::s{l_col_log_out},
778 $xl::s{h_col_log_out},
784 $xl::s{l_col_log_warn},
785 $xl::s{h_col_log_warn},
791 sub new_colours_page() {
792 my $cf = Gtk2::VBox->new (FALSE, 5);
793 $cf->set_border_width (PAGE_SPC);
795 my $msgview_frame = Gtk2::Frame->new ($xl::s{msgview_frame});
796 my $cb_emphasis = &new_color_button_for (\%pr::col, 'emphasis');
797 my $vb1 = Gtk2::VBox->new (FALSE, 5);
798 $vb1->set_border_width (PAGE_SPC);
799 $vb1->pack_start ($cb_emphasis, FALSE, FALSE, 0);
800 $msgview_frame->add ($vb1);
802 my $log_frame = Gtk2::Frame->new ($xl::s{log_frame});
803 my $cb_log_err = &new_color_button_for (\%pr::col, 'log_err');
804 my $cb_log_in = &new_color_button_for (\%pr::col, 'log_in');
805 my $cb_log_msg = &new_color_button_for (\%pr::col, 'log_msg');
806 my $cb_log_out = &new_color_button_for (\%pr::col, 'log_out');
807 my $cb_log_warn = &new_color_button_for (\%pr::col, 'log_warn');
808 my $vb2 = Gtk2::VBox->new (FALSE, 5);
809 $vb2->set_border_width (PAGE_SPC);
810 $vb2->pack_start ($cb_log_err, FALSE, FALSE, 0);
811 $vb2->pack_start ($cb_log_in, FALSE, FALSE, 0);
812 $vb2->pack_start ($cb_log_msg, FALSE, FALSE, 0);
813 $vb2->pack_start ($cb_log_out, FALSE, FALSE, 0);
814 $vb2->pack_start ($cb_log_warn, FALSE, FALSE, 0);
815 $log_frame->add ($vb2);
817 $cf->pack_start ($msgview_frame, FALSE, FALSE, 0);
818 $cf->pack_start ($log_frame, FALSE, FALSE, 0);
823 # the command line help
825 my $line = '-' x length ($xl::s{about_title}) . "\n";
827 print $xl::s{about_title} . "\n";
828 print $xl::s{about_version} . " $VERSION\n";
829 print "Perl-GLib " . $Glib::VERSION;
830 # version info stuff appeared in 1.040
831 if ($Glib::VERSION >= 1.040) {
832 print _(", built for ") . join(".", Glib->GET_VERSION_INFO)
833 . _(", running with ") . join(".", &Glib::major_version,
834 &Glib::minor_version, &Glib::micro_version);
837 print "Perl-GTK2 " . $Gtk2::VERSION;
838 if ($Gtk2::VERSION >= 1.040) {
839 print _(", built for ") . join(".", Gtk2->GET_VERSION_INFO)
840 . _(", running with ") . join(".", &Gtk2::major_version,
841 &Gtk2::minor_version, &Gtk2::micro_version);
845 print _("Syntax:\n");
846 print _(" clawsker [options]\n");
847 print _("Options:\n");
848 print _(" --help Prints this help screen.\n");
849 print _(" --verbose More messages on standard output.\n");
850 print _(" --alternate-config-dir <dir> Uses <dir> as Claws Mail config dir.\n");
851 print _(" --clawsrc <file> Uses <file> as full resource name.\n");
854 # handle errors which don't allow to run
855 sub command_line_fatal() {
857 my $emsg = $xl::s{e_error} . $reason;
858 error_dialog ($emsg);
859 log_message ("$emsg", 'die');
862 # parse the command line
863 sub parse_command_line() {
865 while (defined($ARGV[$arg])) {
875 /--alternate-config-dir/ && do {
877 &command_line_fatal ($xl::s{e_requireddir})
878 unless defined($ARGV[$arg]);
879 &command_line_fatal ($xl::s{e_notadir})
880 unless -d $ARGV[$arg];
881 $CONFIGDIR = $ARGV[$arg];
882 $ALTCONFIGDIR = TRUE;
887 &command_line_fatal($xl::s{e_requiredfile})
888 unless defined($ARGV[$arg]);
889 &command_line_fatal($xl::s{e_notafile})
890 unless -f $ARGV[$arg];
891 &set_rc_filename ($ARGV[$arg]);
894 /.*/ && &command_line_fatal (
895 _("unknown option '{opt}'.\n", opt => $ARGV[$arg]));
899 # eveything continues...
903 # update the hidden preferences status from loaded values
904 sub init_hidden_preferences() {
905 foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth) {
906 foreach my $key (keys %$hash) {
907 $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
913 # load current status from disc
914 sub load_preferences() {
915 my $rc = &get_rc_filename;
916 &log_message ("Loading preferences from $rc\n");
917 return FALSE unless &check_rc_file ($rc);
918 return FALSE unless &check_claws_not_running;
922 if (/^([8a-z_]+)=(.*)$/) {
930 # save current preferences to disc
931 sub save_preferences() {
932 my $rc = &get_rc_filename;
933 &log_message ("Saving preferences to $rc\n");
934 return FALSE unless &check_rc_file ($rc);
935 return FALSE unless &check_claws_not_running;
936 my $rcbak = "$rc.backup";
937 rename ($rc, $rcbak);
939 open (RCB, "<$rcbak");
942 if (/^([8a-z_]+)=(.*)$/) {
943 if (defined($HPVALUE{$1})) {
944 print RCF $1 . "=" . $HPVALUE{$1} . "\n";
961 my $nb = Gtk2::Notebook->new;
963 $nb->append_page (&new_behaviour_page, $xl::s{tab_behaviour});
964 $nb->append_page (&new_colours_page, $xl::s{tab_colours});
965 $nb->append_page (&new_gui_page, $xl::s{tab_gui});
966 $nb->append_page (&new_other_page, $xl::s{tab_other});
971 # create an about dialog
972 sub new_about_dialog() {
974 my $title = $xl::s{about_title};
975 my $lic = $xl::s{about_license};
976 my $vers = $xl::s{about_version} . " $VERSION";
978 "This program is free software: you can redistribute it and/or modify
979 it under the terms of the GNU General Public License as published by
980 the Free Software Foundation, either version 3 of the License, or
981 (at your option) any later version.
983 This program is distributed in the hope that it will be useful,
984 but WITHOUT ANY WARRANTY; without even the implied warranty of
985 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
986 GNU General Public License for more details.
988 You should have received a copy of the GNU General Public License
989 along with this program. If not, see <http://www.gnu.org/licenses/>.";
991 my $holder = "Ricardo Mones <ricardo\@mones.org>";
993 my $dialog = Gtk2::MessageDialog->new_with_markup ($parent,
994 [qw/modal destroy-with-parent/],
996 "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
997 . "<span size=\"large\">$vers</span>\n"
998 . "<span>Copyright $year by $holder</span>\n\n"
999 . "<span size=\"large\">$lic</span>\n\n"
1000 . "<span size=\"small\">$license</span>");
1001 $dialog->set_title ($xl::s{about});
1006 # create buttons box
1007 sub new_button_box() {
1008 my ($parent, $adlg) = @_;
1009 my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
1010 my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
1011 my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
1012 # disable button until is really implemented
1013 # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
1014 my $hbox = Gtk2::HBox->new (FALSE, 5);
1016 $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
1017 $b_apply->signal_connect (clicked => sub { &save_preferences ($parent) });
1018 # $b_undo->signal_connect (clicked => sub { &undo_current_changes });
1019 $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
1021 $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
1022 $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
1023 # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
1024 $hbox->pack_start ($b_about, FALSE, FALSE, 0);
1030 $main_window = Gtk2::Window->new ('toplevel');
1031 exit unless &parse_command_line;
1032 exit unless &load_preferences;
1033 exit unless &init_hidden_preferences;
1035 my $box = Gtk2::VBox->new (FALSE, 5);
1036 $box->set_border_width(3);
1037 my $about = &new_about_dialog;
1038 $box->pack_start (&new_notebook, FALSE, FALSE, 0);
1039 $box->pack_end (&new_button_box ($main_window, $about), FALSE, FALSE, 0);
1040 $main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
1041 $main_window->set_title ($xl::s{win_title});
1042 $main_window->add ($box);
1043 $main_window->show_all;