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 by Ricardo Mones
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));
97 my $xla = gettext ($str);
98 if (scalar(keys(%par)) > 0) {
99 foreach my $key (keys %par) {
100 $xla =~ s/\{$key\}/$par{$key}/g;
108 win_title => _('Claws Mail Hidden Preferences'),
109 about => _('About...'),
110 about_title => _('Clawsker :: A Claws Mail Tweaker'),
111 about_license => _('License:'),
112 about_version => _('Version:'),
114 tab_colours => _('Colours'),
115 tab_behaviour => _('Behaviour'),
117 tab_other => _('Other'),
119 ab_frame => _('Addressbook'),
120 mem_frame => _('Memory'),
121 msgview_frame => _('Message view'),
122 log_frame => _('Log window'),
123 dnd_frame => _('Drag \'n\' drop'),
124 ssl_frame => _('Secure Sockets Layer'),
125 msgs_frame => _('Messages'),
126 stripes_frame => _('Coloured stripes'),
127 sbar_frame => _('Scroll bars'),
128 mlist_frame => _('Message list'),
130 l_oth_use_dlg => _('Use detached address book edit dialogue'),
131 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.'),
132 l_oth_max_use => _('Maximum memory for message cache (Kb)'),
133 h_oth_max_use => _('The maximum amount of memory to use to cache messages, in kB.'),
134 l_oth_min_time => _('Minimun time for cache elements (minutes)'),
135 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.'),
137 l_gui_b_unread => _('Show unread messages with bold font'),
138 h_gui_b_unread => _('Show unread messages in the Message List using a bold font.'),
139 l_gui_no_markup => _('Don\'t use markup in compose window'),
140 h_gui_no_markup => _('Don\'t use bold and italic text in Compose dialogue\'s account selector.'),
141 l_gui_dot_lines => _('Use dotted lines in tree views'),
142 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.'),
143 l_gui_h_scroll => _('Enable horizontal scrollbar'),
144 h_gui_h_scroll => _('Enable the horizontal scrollbar in the Message List.'),
145 l_gui_swp_from => _('Dislay To header in From field in Sent folder'),
146 h_gui_swp_from => _('Display the sender\'s email address in the To column of the Sent folder instead of the recipient\'s.'),
147 l_gui_v_scroll => _('Folder list scrollbar behaviour'),
148 h_gui_v_scroll => _('Specify the policy of vertical scrollbar of Folder List: show always, automatic or hide always.'),
149 l_gui_v_scroll_show => _('Show always'),
150 l_gui_v_scroll_auto => _('Automatic'),
151 l_gui_v_scroll_hide => _('Hide always'),
152 l_gui_strip_off => _('Striped lines contrast'),
153 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.'),
154 l_gui_cursor_v => _('Show Cursor in message view'),
155 h_gui_cursor_v => _('Display the cursor in the message view.'),
156 l_gui_toolbar_d => _('Detachable toolbars'),
157 h_gui_toolbar_d => _('Show handles in the toolbars.'),
158 l_gui_strip_all => _('Use stripes in all tree view components'),
159 h_gui_strip_all => _('Enable alternately coloured lines in all tree view components.'),
160 l_gui_strip_sum => _('Use stripes in Folder List and Message List'),
161 h_gui_strip_sum => _('Enable alternately coloured lines in message list and folder list'),
163 l_beh_hover_t => _('Drag \'n\' drop hover timeout (ms)'),
164 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.'),
165 l_beh_dangerous => _('Don\'t confirm deletions (dangerous!)'),
166 h_beh_dangerous => _('Don\'t ask for confirmation before definitive deletion of emails.'),
167 l_beh_flowed => _('Respect format=flowed in messages'),
168 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.'),
169 l_beh_parts_rw => _('Allow writable temporary files'),
170 h_beh_parts_rw => _('Saves temporary files when opening attachment with write bit set.'),
171 l_beh_skip_ssl => _('Don\'t check SSL certificates'),
172 h_beh_skip_ssl => _('Disables the verification of SSL certificates.'),
173 l_beh_up_step => _('Progress bar update step (items)'),
174 h_beh_up_step => _('Update stepping in progress bars.'),
175 l_beh_thread_a => _('Maximum age when threading by subject (days)'),
176 h_beh_thread_a => _('Number of days to include a message in a thread when using "Thread using subject in addition to standard headers".'),
177 l_beh_unsafe_ssl => _('Allow unsafe SSL certificates'),
178 h_beh_unsafe_ssl => _('Allows Claws Mail to remember multiple SSL certificates for a given server/port.'),
179 l_beh_use_utf8 => _('Force UTF-8 for broken mails'),
180 h_beh_use_utf8 => _('Use UTF-8 encoding for broken mails instead of current locale.'),
181 l_beh_warn_dnd => _('Warn on drag \'n\' drop'),
182 h_beh_warn_dnd => _('Display a confirmation dialogue on drag \'n\' drop of folders.'),
184 l_col_emphasis => _('X-Mailer header'),
185 h_col_emphasis => _('The colour used for the X-Mailer line when its value is Claws Mail.'),
186 l_col_log_err => _('Error messages'),
187 h_col_log_err => _('Colour for error messages in log window.'),
188 l_col_log_in => _('Server messages'),
189 h_col_log_in => _('Colour for input messages in log window.'),
190 l_col_log_msg => _('Standard messages'),
191 h_col_log_msg => _('Colour for messages in log window.'),
192 l_col_log_out => _('Client messages'),
193 h_col_log_out => _('Colour for output messages in log window.'),
194 l_col_log_warn => _('Warnings'),
195 h_col_log_warn => _('Colour for warning messages in log window.'),
197 e_error => _('Error: '),
198 e_noclawsrc => _('resource file for Claws Mail was not found.'),
199 e_running => _('seems Claws Mail is currently running, close it first.'),
200 e_requireddir => _('option requires a directory name.'),
201 e_requiredfile => _('option requires a file name.'),
202 e_notadir => _('specified name is not a directory or does not exist.'),
203 e_notafile => _('specified name is not a file or does not exist.'),
206 # all preferences read by load_preferences
208 # values of all preferences handled by clawsker
210 # default config dir and file name
211 my $ALTCONFIGDIR = FALSE;
212 my $CONFIGDIR = $ENV{HOME} . '/.claws-mail/';
213 my $CONFIGRC = 'clawsrc';
215 # index constants for preference arrays
216 use constant NAME => 0; # the name on the rc file
217 use constant LABEL => 1; # the label on the GUI
218 use constant DESC => 2; # the description for the hint/help
219 use constant TYPE => 3; # data type: bool, int, float, string, color
220 use constant GUI => 4; # GUI element
222 # constants for GUI spacing
223 use constant HBOX_SPC => 5;
224 use constant FRAME_SPC => 2;
225 use constant PAGE_SPC => 5;
227 # data handlers and auxiliar functions
229 sub handle_bool_value {
230 my ($widget, $event, $dataref) = @_;
231 $$dataref = ($widget->get_active ())? '1': '0';
234 sub handle_int_value {
235 my ($widget, $event, $dataref) = @_;
236 $_ = $widget->get_text ();
241 $widget->set_text ($_);
244 $widget->set_text ($$dataref);
248 sub handle_string_value {
249 my ($widget, $event, $dataref) = @_;
250 $$dataref = $widget->get_text ();
253 sub gdk_color_from_str {
255 my ($rr, $gg, $bb) = (0, 0 ,0);
257 if (/\#([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])([A-F0-9][A-F0-9])/) {
262 my $color = Gtk2::Gdk::Color->new ($rr, $gg, $bb);
266 sub str_from_gdk_color {
268 my $rr = $color->red / 256;
269 my $gg = $color->green / 256;
270 my $bb = $color->blue / 256;
271 my $str = sprintf ("#%.2x%.2x%.2x", $rr, $gg, $bb);
275 sub handle_color_value {
276 my ($widget, $event, $dataref) = @_;
277 my $newcol = $widget->get_color;
278 $$dataref = &str_from_gdk_color ($newcol);
281 sub handle_selection_value {
282 my ($widget, $event, $dataref) = @_;
283 $$dataref = $widget->get_active;
286 sub get_rc_filename {
287 return $CONFIGDIR . $CONFIGRC;
290 sub set_rc_filename {
292 my @parts = split ('/', $fullname);
293 $CONFIGRC = $parts[$#parts];
294 $parts[$#parts] = '';
295 $CONFIGDIR = join ('/', @parts);
299 my ($mesg, $fatal) = @_;
301 if (defined($fatal) && $fatal eq 'die') {
302 die "$NAME: $mesg\n";
304 print "$NAME: $mesg\n";
310 my $markup = "<span weight=\"bold\" size=\"large\">" . $emsg . "</span>";
311 my $errordlg = Gtk2::MessageDialog->new_with_markup ($main_window, 'modal', 'error', 'cancel', $markup);
312 $errordlg->set_title (_('Error message'));
317 sub check_claws_not_running() {
318 my $socket = (not $ALTCONFIGDIR)? "/tmp/": $CONFIGDIR;
319 $socket .= "claws-mail-$<";
321 my $emsg = "$xl::s{e_error}$xl::s{e_running}";
323 error_dialog ($emsg);
330 sub check_rc_file() {
332 (defined($rcfile) && -f $rcfile) or do {
333 my $emsg = "$xl::s{e_error}$xl::s{e_noclawsrc}\n";
335 error_dialog ($emsg);
342 # graphic element creation
344 sub new_check_button_for {
345 my ($hash, $key) = @_;
346 my $name = $$hash{$key}[NAME];
347 my $label = $$hash{$key}[LABEL];
349 my $hbox = Gtk2::HBox->new (FALSE, 5);
350 my $cb = Gtk2::CheckButton->new ($label);
351 $$hash{$key}[GUI] = $cb;
352 $cb->set_active ($HPVALUE{$name} eq '1');
353 $cb->signal_connect (clicked => sub {
355 &handle_bool_value($w, $e, \$HPVALUE{$name});
357 $hbox->pack_start ($cb, FALSE, FALSE, HBOX_SPC);
362 sub new_text_box_for {
363 my ($hash, $key) = @_;
364 my $name = $$hash{$key}[NAME];
365 my $label = $$hash{$key}[LABEL];
367 my $hbox = Gtk2::HBox->new (FALSE, 5);
368 my $glabel = Gtk2::Label->new ($label);
369 my $gentry = Gtk2::Entry->new;
370 $gentry->set_width_chars (8);
371 $$hash{$key}[GUI] = $gentry;
372 $gentry->set_text($HPVALUE{$name});
373 $gentry->signal_connect(changed => sub {
375 &handle_int_value($w, $e, \$HPVALUE{$name}); # FIXME int only
377 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
378 $hbox->pack_start ($gentry, FALSE, FALSE, HBOX_SPC);
383 sub new_color_button_for {
384 my ($hash, $key) = @_;
385 my $name = $$hash{$key}[NAME];
386 my $label = $$hash{$key}[LABEL];
388 my $col = &gdk_color_from_str ($HPVALUE{$name});
389 my $hbox = Gtk2::HBox->new (FALSE, 5);
390 my $glabel = Gtk2::Label->new ($label);
391 my $button = Gtk2::ColorButton->new_with_color ($col);
392 $$hash{$key}[GUI] = $button;
393 $button->set_title ($label);
394 $button->set_relief ('none');
395 $button->signal_connect ('color-set' => sub {
397 &handle_color_value($w, $e, \$HPVALUE{$name});
399 $hbox->pack_start ($button, FALSE, FALSE, HBOX_SPC);
400 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
405 sub new_selection_box_for {
406 my ($hash, $key) = @_;
407 my $name = $$hash{$key}[NAME];
408 my $label = $$hash{$key}[LABEL];
410 my $hbox = Gtk2::HBox->new (FALSE, 5);
411 my $glabel = Gtk2::Label->new ($label);
412 my $combo = Gtk2::ComboBox->new_text;
413 $$hash{$key}[GUI] = $combo;
414 my @options = split (';', $$hash{$key}[TYPE]);
415 foreach my $opt (@options) {
416 my ($index, $textkey) = split ('=', $opt);
417 $combo->insert_text ($index, $xl::s{$textkey});
419 $combo->signal_connect ('changed' => sub {
421 &handle_selection_value($w, $e, \$HPVALUE{$name});
423 $combo->set_active ($HPVALUE{$name});
424 $hbox->pack_start ($glabel, FALSE, FALSE, HBOX_SPC);
425 $hbox->pack_start ($combo, FALSE, FALSE, HBOX_SPC);
430 # preference maps and corresponding page creation subs
432 %pr::oth = ( # other preferences
434 'addressbook_use_editaddress_dialog',
435 $xl::s{l_oth_use_dlg},
436 $xl::s{h_oth_use_dlg},
441 'cache_max_mem_usage',
442 $xl::s{l_oth_max_use},
443 $xl::s{h_oth_max_use},
448 'cache_min_keep_time',
449 $xl::s{l_oth_min_time},
450 $xl::s{h_oth_min_time},
456 sub new_other_page() {
457 my $of = Gtk2::VBox->new (FALSE, 5);
458 $of->set_border_width (PAGE_SPC);
460 my $ab_frame = Gtk2::Frame->new ($xl::s{ab_frame});
461 my $cb_use_dlg = &new_check_button_for(\%pr::oth, 'use_dlg');
462 my $vb1 = Gtk2::VBox->new (FALSE, 5);
463 $vb1->set_border_width (PAGE_SPC);
464 $vb1->pack_start ($cb_use_dlg, FALSE, FALSE, 0);
465 $ab_frame->add ($vb1);
467 my $mem_frame = Gtk2::Frame->new ($xl::s{mem_frame});
468 my $tb_max_use = &new_text_box_for(\%pr::oth, 'max_use');
469 my $tb_min_time = &new_text_box_for(\%pr::oth, 'min_time');
470 my $vb2 = Gtk2::VBox->new (FALSE, 5);
471 $vb2->set_border_width (PAGE_SPC);
472 $vb2->pack_start ($tb_max_use, FALSE, FALSE, 0);
473 $vb2->pack_start ($tb_min_time, FALSE, FALSE, 0);
474 $mem_frame->add ($vb2);
476 $of->pack_start ($ab_frame, FALSE, FALSE, FRAME_SPC);
477 $of->pack_start ($mem_frame, FALSE, FALSE, FRAME_SPC);
482 %pr::gui = ( # gui bells and whistles
485 $xl::s{l_gui_b_unread},
486 $xl::s{h_gui_b_unread},
492 $xl::s{l_gui_no_markup},
493 $xl::s{h_gui_no_markup},
498 'enable_dotted_lines',
499 $xl::s{l_gui_dot_lines},
500 $xl::s{h_gui_dot_lines},
506 $xl::s{l_gui_h_scroll},
507 $xl::s{h_gui_h_scroll},
513 $xl::s{l_gui_swp_from},
514 $xl::s{h_gui_swp_from},
519 'folderview_vscrollbar_policy',
520 $xl::s{l_gui_v_scroll},
521 $xl::s{h_gui_v_scroll},
522 '0=l_gui_v_scroll_show;1=l_gui_v_scroll_auto;2=l_gui_v_scroll_hide',
526 'stripes_color_offset',
527 $xl::s{l_gui_strip_off},
528 $xl::s{h_gui_strip_off},
533 'textview_cursor_visible',
534 $xl::s{l_gui_cursor_v},
535 $xl::s{h_gui_cursor_v},
540 'toolbar_detachable',
541 $xl::s{l_gui_toolbar_d},
542 $xl::s{h_gui_toolbar_d},
547 'use_stripes_everywhere',
548 $xl::s{l_gui_strip_all},
549 $xl::s{h_gui_strip_all},
554 'use_stripes_in_summaries',
555 $xl::s{l_gui_strip_sum},
556 $xl::s{h_gui_strip_sum},
563 my $gf = Gtk2::VBox->new (FALSE, 5);
564 $gf->set_border_width (PAGE_SPC);
566 my $stripes_frame = Gtk2::Frame->new ($xl::s{stripes_frame});
567 my $cb_strip_all = &new_check_button_for (\%pr::gui, 'strip_all');
568 my $cb_strip_sum = &new_check_button_for (\%pr::gui, 'strip_sum');
569 my $tb_strip_off = &new_text_box_for (\%pr::gui, 'strip_off');
570 my $vb1 = Gtk2::VBox->new (FALSE, 5);
571 $vb1->set_border_width (PAGE_SPC);
572 $vb1->pack_start ($cb_strip_all, FALSE, FALSE, 0);
573 $vb1->pack_start ($cb_strip_sum, FALSE, FALSE, 0);
574 $vb1->pack_start ($tb_strip_off, FALSE, FALSE, 0);
575 $stripes_frame->add ($vb1);
577 my $mlist_frame = Gtk2::Frame->new ($xl::s{mlist_frame});
578 my $cb_b_unread = &new_check_button_for (\%pr::gui, 'b_unread');
579 my $cb_swp_from = &new_check_button_for (\%pr::gui, 'swp_from');
580 my $vb3 = Gtk2::VBox->new (FALSE, 5);
581 $vb3->set_border_width (PAGE_SPC);
582 $vb3->pack_start ($cb_b_unread, FALSE, FALSE, 0);
583 $vb3->pack_start ($cb_swp_from, FALSE, FALSE, 0);
584 $mlist_frame->add ($vb3);
586 my $sbar_frame = Gtk2::Frame->new ($xl::s{sbar_frame});
587 my $cb_h_scroll = &new_check_button_for (\%pr::gui, 'h_scroll');
588 my $sb_v_scroll = &new_selection_box_for (\%pr::gui, 'v_scroll');
589 my $vb2 = Gtk2::VBox->new (FALSE, 5);
590 $vb2->set_border_width (PAGE_SPC);
591 $vb2->pack_start ($cb_h_scroll, FALSE, FALSE, 0);
592 $vb2->pack_start ($sb_v_scroll, FALSE, FALSE, 0);
593 $sbar_frame->add ($vb2);
595 my $cb_no_markup = &new_check_button_for (\%pr::gui, 'no_markup');
596 my $cb_dot_lines = &new_check_button_for (\%pr::gui, 'dot_lines');
597 my $cb_cursor_v = &new_check_button_for (\%pr::gui, 'cursor_v');
598 my $cb_toolbar_d = &new_check_button_for (\%pr::gui, 'toolbar_d');
600 $gf->pack_start ($stripes_frame, FALSE, FALSE, FRAME_SPC);
601 $gf->pack_start ($mlist_frame, FALSE, FALSE, FRAME_SPC);
602 $gf->pack_start ($cb_no_markup, FALSE, FALSE, 0);
603 $gf->pack_start ($cb_dot_lines, FALSE, FALSE, 0);
604 $gf->pack_start ($cb_cursor_v, FALSE, FALSE, 0);
605 $gf->pack_start ($cb_toolbar_d, FALSE, FALSE, 0);
606 $gf->pack_start ($sbar_frame, FALSE, FALSE, FRAME_SPC);
611 %pr::beh = ( # tweak some behaviour
614 $xl::s{l_beh_hover_t},
615 $xl::s{h_beh_hover_t},
621 $xl::s{l_beh_dangerous},
622 $xl::s{h_beh_dangerous},
627 'respect_flowed_format',
628 $xl::s{l_beh_flowed},
629 $xl::s{h_beh_flowed},
634 'save_parts_readwrite',
635 $xl::s{l_beh_parts_rw},
636 $xl::s{h_beh_parts_rw},
641 'skip_ssl_cert_check',
642 $xl::s{l_beh_skip_ssl},
643 $xl::s{h_beh_skip_ssl},
648 'statusbar_update_step',
649 $xl::s{l_beh_up_step},
650 $xl::s{h_beh_up_step},
655 'thread_by_subject_max_age',
656 $xl::s{l_beh_thread_a},
657 $xl::s{h_beh_thread_a},
663 $xl::s{l_beh_unsafe_ssl},
664 $xl::s{h_beh_unsafe_ssl},
669 'utf8_instead_of_locale_for_broken_mail',
670 $xl::s{l_beh_use_utf8},
671 $xl::s{h_beh_use_utf8},
677 $xl::s{l_beh_warn_dnd},
678 $xl::s{h_beh_warn_dnd},
684 sub new_behaviour_page() {
685 my $bf = Gtk2::VBox->new (FALSE, 5);
686 $bf->set_border_width (PAGE_SPC);
688 my $dnd_frame = Gtk2::Frame->new ($xl::s{dnd_frame});
689 my $tb_hoover_t = &new_text_box_for (\%pr::beh, 'hover_t');
690 my $cb_warn_dnd = &new_check_button_for (\%pr::beh, 'warn_dnd');
691 my $vb1 = Gtk2::VBox->new (FALSE, 5);
692 $vb1->set_border_width (PAGE_SPC);
693 $vb1->pack_start ($cb_warn_dnd, FALSE, FALSE, 0);
694 $vb1->pack_start ($tb_hoover_t, FALSE, FALSE, 0);
695 $dnd_frame->add ($vb1);
697 my $ssl_frame = Gtk2::Frame->new ($xl::s{ssl_frame});
698 my $cb_skip_ssl = &new_check_button_for (\%pr::beh, 'skip_ssl');
699 my $cb_unsafe_ssl = &new_check_button_for (\%pr::beh, 'unsafe_ssl');
700 my $hb1 = Gtk2::HBox->new (FALSE, 5);
701 $hb1->set_border_width (PAGE_SPC);
702 $hb1->pack_start ($cb_skip_ssl, FALSE, FALSE, 0);
703 $hb1->pack_start ($cb_unsafe_ssl, FALSE, FALSE, 0);
704 $ssl_frame->add ($hb1);
706 my $tb_up_step = &new_text_box_for (\%pr::beh, 'up_step');
707 my $tb_thread_a = &new_text_box_for (\%pr::beh, 'thread_a');
709 my $msgs_frame = Gtk2::Frame->new ($xl::s{msgs_frame});
710 my $cb_flowed = &new_check_button_for (\%pr::beh, 'flowed');
711 my $cb_parts_rw = &new_check_button_for (\%pr::beh, 'parts_rw');
712 my $cb_use_utf8 = &new_check_button_for (\%pr::beh, 'use_utf8');
713 my $cb_dangerous = &new_check_button_for (\%pr::beh, 'dangerous');
714 my $vb2 = Gtk2::VBox->new (FALSE, 5);
715 $vb2->set_border_width (PAGE_SPC);
716 $vb2->pack_start ($cb_flowed, FALSE, FALSE, 0);
717 $vb2->pack_start ($cb_parts_rw, FALSE, FALSE, 0);
718 $vb2->pack_start ($cb_use_utf8, FALSE, FALSE, 0);
719 $vb2->pack_start ($cb_dangerous, FALSE, FALSE, 0);
720 $msgs_frame->add ($vb2);
722 $bf->pack_start ($dnd_frame, FALSE, FALSE, FRAME_SPC);
723 $bf->pack_start ($ssl_frame, FALSE, FALSE, FRAME_SPC);
724 $bf->pack_start ($tb_up_step, FALSE, FALSE, 0);
725 $bf->pack_start ($tb_thread_a, FALSE, FALSE, 0);
726 $bf->pack_start ($msgs_frame, FALSE, FALSE, FRAME_SPC);
731 %pr::col = ( # a variety of colours
734 $xl::s{l_col_emphasis},
735 $xl::s{h_col_emphasis},
741 $xl::s{l_col_log_err},
742 $xl::s{h_col_log_err},
748 $xl::s{l_col_log_in},
749 $xl::s{h_col_log_in},
755 $xl::s{l_col_log_msg},
756 $xl::s{h_col_log_msg},
762 $xl::s{l_col_log_out},
763 $xl::s{h_col_log_out},
769 $xl::s{l_col_log_warn},
770 $xl::s{h_col_log_warn},
776 sub new_colours_page() {
777 my $cf = Gtk2::VBox->new (FALSE, 5);
778 $cf->set_border_width (PAGE_SPC);
780 my $msgview_frame = Gtk2::Frame->new ($xl::s{msgview_frame});
781 my $cb_emphasis = &new_color_button_for (\%pr::col, 'emphasis');
782 my $vb1 = Gtk2::VBox->new (FALSE, 5);
783 $vb1->set_border_width (PAGE_SPC);
784 $vb1->pack_start ($cb_emphasis, FALSE, FALSE, 0);
785 $msgview_frame->add ($vb1);
787 my $log_frame = Gtk2::Frame->new ($xl::s{log_frame});
788 my $cb_log_err = &new_color_button_for (\%pr::col, 'log_err');
789 my $cb_log_in = &new_color_button_for (\%pr::col, 'log_in');
790 my $cb_log_msg = &new_color_button_for (\%pr::col, 'log_msg');
791 my $cb_log_out = &new_color_button_for (\%pr::col, 'log_out');
792 my $cb_log_warn = &new_color_button_for (\%pr::col, 'log_warn');
793 my $vb2 = Gtk2::VBox->new (FALSE, 5);
794 $vb2->set_border_width (PAGE_SPC);
795 $vb2->pack_start ($cb_log_err, FALSE, FALSE, 0);
796 $vb2->pack_start ($cb_log_in, FALSE, FALSE, 0);
797 $vb2->pack_start ($cb_log_msg, FALSE, FALSE, 0);
798 $vb2->pack_start ($cb_log_out, FALSE, FALSE, 0);
799 $vb2->pack_start ($cb_log_warn, FALSE, FALSE, 0);
800 $log_frame->add ($vb2);
802 $cf->pack_start ($msgview_frame, FALSE, FALSE, 0);
803 $cf->pack_start ($log_frame, FALSE, FALSE, 0);
808 # the command line help
810 my $line = '-' x length ($xl::s{about_title}) . "\n";
812 print $xl::s{about_title} . "\n";
813 print $xl::s{about_version} . " $VERSION\n";
814 print "Perl-GLib " . $Glib::VERSION;
815 # The version info stuff appeared in 1.040
816 if ($Glib::VERSION >= 1.040) {
817 print _(", built for ") . join(".", Glib->GET_VERSION_INFO)
818 . _(", running with ") . join(".", &Glib::major_version,
819 &Glib::minor_version, &Glib::micro_version);
822 print "Perl-GTK2 " . $Gtk2::VERSION;
823 if ($Gtk2::VERSION >= 1.040) {
824 print _(", built for ") . join(".", Gtk2->GET_VERSION_INFO)
825 . _(", running with ") . join(".", &Gtk2::major_version,
826 &Gtk2::minor_version, &Gtk2::micro_version);
830 print _("Syntax:\n");
831 print _(" clawsker [options]\n");
832 print _("Options:\n");
833 print _(" --help Prints this help screen.\n");
834 print _(" --verbose More messages on standard output.\n");
835 print _(" --alternate-config-dir <dir> Uses <dir> as Claws Mail config dir.\n");
836 print _(" --clawsrc <file> Uses <file> as full resource name.\n");
839 # parse the command line
840 sub parse_command_line() {
842 while (defined($ARGV[$arg])) {
852 /--alternate-config-dir/ && do {
854 die "$xl::s{e_error}$xl::s{e_requireddir}\n"
855 unless defined($ARGV[$arg]);
856 die "$xl::s{e_error}$xl::s{e_notadir}\n"
857 unless -d $ARGV[$arg];
858 $CONFIGDIR = $ARGV[$arg];
859 $ALTCONFIGDIR = TRUE;
864 die "$xl::s{e_error}$xl::s{e_requiredfile}\n"
865 unless defined($ARGV[$arg]);
866 die "$xl::s{e_error}$xl::s{e_notafile}\n"
867 unless -f $ARGV[$arg];
868 &set_rc_filename ($ARGV[$arg]);
871 /.*/ && die $xl::s{e_error}
872 . _("unknown option '{opt}'.\n", opt => $ARGV[$arg]);
876 # eveything continues...
880 # update the hidden preferences status from loaded values
881 sub init_hidden_preferences() {
882 foreach my $hash (\%pr::beh, \%pr::col, \%pr::gui, \%pr::oth) {
883 foreach my $key (keys %$hash) {
884 $HPVALUE{${$hash}{$key}[NAME]} = $PREFS{${$hash}{$key}[NAME]};
890 # load current status from disc
891 sub load_preferences() {
892 my $rc = &get_rc_filename;
893 &log_message ("Loading preferences from $rc\n");
894 return FALSE unless &check_rc_file ($rc);
895 return FALSE unless &check_claws_not_running;
899 if (/^([8a-z_]+)=(.*)$/) {
907 # save current preferences to disc
908 sub save_preferences() {
909 my $rc = &get_rc_filename;
910 &log_message ("Saving preferences to $rc\n");
911 return FALSE unless &check_rc_file ($rc);
912 return FALSE unless &check_claws_not_running;
913 my $rcbak = "$rc.backup";
914 rename ($rc, $rcbak);
916 open (RCB, "<$rcbak");
919 if (/^([8a-z_]+)=(.*)$/) {
920 if (defined($HPVALUE{$1})) {
921 print RCF $1 . "=" . $HPVALUE{$1} . "\n";
938 my $nb = Gtk2::Notebook->new;
940 $nb->append_page (&new_behaviour_page, $xl::s{tab_behaviour});
941 $nb->append_page (&new_colours_page, $xl::s{tab_colours});
942 $nb->append_page (&new_gui_page, $xl::s{tab_gui});
943 $nb->append_page (&new_other_page, $xl::s{tab_other});
948 # create an about dialog
949 sub new_about_dialog() {
951 my $title = $xl::s{about_title};
952 my $lic = $xl::s{about_license};
953 my $vers = $xl::s{about_version} . " $VERSION";
955 "This program is free software: you can redistribute it and/or modify
956 it under the terms of the GNU General Public License as published by
957 the Free Software Foundation, either version 3 of the License, or
958 (at your option) any later version.
960 This program is distributed in the hope that it will be useful,
961 but WITHOUT ANY WARRANTY; without even the implied warranty of
962 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
963 GNU General Public License for more details.
965 You should have received a copy of the GNU General Public License
966 along with this program. If not, see <http://www.gnu.org/licenses/>.";
968 my $holder = "Ricardo Mones <ricardo\@mones.org>";
970 my $dialog = Gtk2::MessageDialog->new_with_markup ($parent,
971 [qw/modal destroy-with-parent/],
973 "<span size=\"x-large\" weight=\"bold\">$title</span>\n"
974 . "<span size=\"large\">$vers</span>\n"
975 . "<span>Copyright $year by $holder</span>\n\n"
976 . "<span size=\"large\">$lic</span>\n\n"
977 . "<span size=\"small\">$license</span>");
978 $dialog->set_title ($xl::s{about});
984 sub new_button_box() {
985 my ($parent, $adlg) = @_;
986 my $b_about = Gtk2::Button->new_from_stock ('gtk-about');
987 my $b_exit = Gtk2::Button->new_from_stock ('gtk-quit');
988 my $b_apply = Gtk2::Button->new_from_stock ('gtk-apply');
989 # disable button until is really implemented
990 # my $b_undo = Gtk2::Button->new_from_stock ('gtk-undo');
991 my $hbox = Gtk2::HBox->new (FALSE, 5);
993 $b_exit->signal_connect (clicked => sub { Gtk2->main_quit });
994 $b_apply->signal_connect (clicked => sub { &save_preferences ($parent) });
995 # $b_undo->signal_connect (clicked => sub { &undo_current_changes });
996 $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });
998 $hbox->pack_end ($b_apply, FALSE, FALSE, 0);
999 $hbox->pack_end ($b_exit, FALSE, FALSE, 0);
1000 # $hbox->pack_end ($b_undo, FALSE, FALSE, 0);
1001 $hbox->pack_start ($b_about, FALSE, FALSE, 0);
1007 $main_window = Gtk2::Window->new ('toplevel');
1008 exit unless &parse_command_line;
1009 exit unless &load_preferences;
1010 exit unless &init_hidden_preferences;
1012 my $box = Gtk2::VBox->new (FALSE, 5);
1013 $box->set_border_width(3);
1014 my $about = &new_about_dialog;
1015 $box->pack_start (&new_notebook, FALSE, FALSE, 0);
1016 $box->pack_end (&new_button_box ($main_window, $about), FALSE, FALSE, 0);
1017 $main_window->signal_connect (delete_event => sub { Gtk2->main_quit });
1018 $main_window->set_title ($xl::s{win_title});
1019 $main_window->add ($box);
1020 $main_window->show_all;