#-*- perl -*- # # Copyright (C) 2001,2002,2004 Ken'ichi Fukamachi # All rights reserved. This program is free software; you can # redistribute it and/or modify it under the same terms as Perl itself. # # $FML: Print.pm,v 1.27 2002/12/22 03:21:33 fukachan Exp $ # package Mail::ThreadTrack::Print; use strict; use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); use Carp; use Mail::ThreadTrack::Print::Utils qw(decode_mime_string STR2EUC); =head1 NAME Mail::ThreadTrack::Print - dispatcher to print out thread =head1 SYNOPSIS =head1 DESCRIPTION =head1 METHODS =head2 list([ @opts ]) show todo list without article summary. =cut # Descriptions: show todo list without article summary. # Arguments: OBJ($self) VARARGS(@opts) # Side Effects: none # Return Value: none sub list { my ($self, @opts) = @_; $self->_load_library(); $self->db_open(); $self->_do_list(@opts); $self->db_close(); } =head2 summary([ @opts ]) show the thread summary, which is todo list C article summary. Each row that C returns has a set of C, C, C, C and C, which is a list of articles with the thread-id. list() shows entries by the thread_id order. For example, date age status thread id articles ------------------------------------------------------------ 2001/02/07 3.6 going elena_#00000450 807 808 809 2001/02/07 3.1 open elena_#00000451 810 2001/02/07 3.0 open elena_#00000452 812 2001/02/07 3.0 open elena_#00000453 813 2001/02/07 3.0 going elena_#00000454 814 815 2001/02/10 0.1 open elena_#00000456 821 summary() shows the todo list above and article summaries. =cut # Descriptions: show todo list with article summary. # Arguments: OBJ($self) VARARGS(@opts) # Side Effects: none # Return Value: none sub summary { my ($self, @opts) = @_; $self->_load_library(); $self->db_open(); $self->_do_summary(@opts); $self->db_close(); } =head2 review([ @opts ]) show a chain of a few lines summary for articles in each thread. This summary is a collection of short summary of articles in one thread. =cut # Descriptions: show a chain of summaries for each thread. # Arguments: OBJ($self) VARARGS(@opts) # Side Effects: none # Return Value: none sub review { my ($self, @opts) = @_; $self->_load_library(); $self->db_open(); $self->_do_review(@opts); $self->db_close(); } # Descriptions: load subclasses, change @INC. # Arguments: OBJ($self) # Side Effects: @INC modified # Return Value: none sub _load_library { my ($self) = @_; my $mode = $self->get_mode || 'text'; require Mail::ThreadTrack::Print::Message; require Mail::ThreadTrack::Print::Sort; my @list = qw(Mail::ThreadTrack::Print::Message Mail::ThreadTrack::Print::Sort); if ($mode eq 'text') { require Mail::ThreadTrack::Print::Text; push(@list, 'Mail::ThreadTrack::Print::Text'); } elsif ($mode eq 'html') { require Mail::ThreadTrack::Print::HTML; push(@list, 'Mail::ThreadTrack::Print::HTML'); } unshift(@ISA, @list); } # # SUMMARY MODE # # Descriptions: dispatcher to show todo list with article summary. # Arguments: OBJ($self) # Side Effects: none # Return Value: none sub _do_summary { my ($self) = @_; $self->__do_summary( { mode => 'summary' }); } # Descriptions: dispatcher to show todo list without article summary. # Arguments: OBJ($self) # Side Effects: none # Return Value: none sub _do_list { my ($self) = @_; $self->__do_summary( { mode => 'list' }); } # Descriptions: get thread id list with status != 'close' and # show summary for the list if needed. # Arguments: OBJ($thread) HASH_REF($option) # Side Effects: none # Return Value: none sub __do_summary { my ($thread, $option) = @_; my $mode = $thread->get_mode || 'text'; my $config = $thread->{ _config }; # rh: thread id list picked from status.db my $thread_id_list = $thread->list_up_thread_id(); # 1. sort the thread output order by cost # 2. print the thread brief summary in that order. # 3. show short summary for each message if needed (mode dependent) if (@$thread_id_list) { # XXX-TODO: $thread->sort() method should accept the order ? $thread->sort_thread_id($thread_id_list); # reverse order (first thread is the latest one) if reverse mode if ($config->{ reverse_order }) { @$thread_id_list = reverse @$thread_id_list; } # XXX thread summary == todo list $thread->_print_thread_summary($thread_id_list); # XXX message summary == brief summary of articles. if ($option->{ mode } eq 'summary') { $thread->_print_message_summary($thread_id_list); } } } # Descriptions: show thread summary (without article summary). # Arguments: OBJ($self) ARRAY_REF($thread_id_list) # Side Effects: none # Return Value: none sub _print_thread_summary { my ($self, $thread_id_list) = @_; my $mode = $self->get_mode || 'text'; my $db = $self->{ _hash_table }; # guide of presentation $self->__start_thread_summary(); # XXX dynamic binding # show brief summary along thread_id list my ($thread_id, @article_id, $article_id, $date, $age, $status) = (); my $date_h = new Mail::Message::Date; for $thread_id (@$thread_id_list) { next unless defined $db->{ _articles }->{ $thread_id }; # get the first $article_id from the article_id list (@article_id) = split(/\s+/, $db->{ _articles }->{ $thread_id }); $article_id = $article_id[0]; # format $date for the $article_id $date = $date_h->YYYYxMMxDD( $db->{ _date }->{ $article_id } , '/'); $age = $self->{ _age }->{ $thread_id }; $status = $db->{ _status }->{ $thread_id }; # XXX-TODO: who care for output mode ? (e.g. against CSS). $self->__print_thread_summary( { date => $date, age => $age, status => $status, thread_id => $thread_id, articles => $db->{ _articles }->{ $thread_id }, }); # XXX dynamic binding } $self->__end_thread_summary(); # XXX dynamic binding } # Descriptions: show the first few lines of the first message in the thread # Arguments: OBJ($self) STR($thread_id) # Side Effects: none # Return Value: none sub _print_message_summary { my ($self, $thread_id) = @_; $self->__print_message_summary($thread_id); } # # REVIEW MODE # # Descriptions: show brief summary chain of messages in the thread. # Arguments: OBJ($self) STR($str) NUM($min) NUM($max) # Side Effects: none # Return Value: none sub _do_review { my ($self, $str, $min, $max) = @_; my $config = $self->{ _config }; my $spool_dir = $config->{ spool_dir }; my $fd = $self->{ _fd } || \*STDOUT; my $db = $self->{ _hash_table }; my %uniq = (); my $is_first = 0; # translate the given parameter (MH style) # get ARRAY_REF of specified range use Mail::Message::MH; my $range = Mail::Message::MH->expand($str, $min, $max); # reverse order (first thread is the latest one) if reverse mode if ($config->{ reverse_order }) { @$range = reverse @$range;} ID_LIST: for my $id (@$range) { next ID_LIST unless defined $id; if ($id =~ /^\d+$/) { # create thread identifier string: e.g. 100 -> elena/100 my $tid = $self->_create_thread_id_strings($id); # check thread id $tid exists really ? if (defined $db->{ _articles }->{ $tid }) { # XXX-TODO: validate $tid. printf $fd "\n>Thread-Id: %-10s %s\n", $tid; # different treatment for the fisrt article in this thread $is_first = 1; # show all articles in this thread ARTICLE: for my $aid (split(/\s+/, $db->{ _articles }->{ $tid })) { # ensure uniquness next ARTICLE if $uniq{ $aid }; $uniq{ $aid } = 1; # show header only for the first message in this thread if ($is_first) { undef $self->{ _no_header_summary }; $is_first = 0; } else { $self->{ _no_header_summary } = 1; } my $file = $self->filepath({ base_dir => $spool_dir, id => $aid, }); if (-f $file) { $self->print( $self->message_summary($file) ); print $fd "\n"; } } } } } } =head2 show($tid) show all articles in specified thread. =cut # Descriptions: show all articles in specified thread. # Arguments: OBJ($self) STR($tid) # Side Effects: none # Return Value: none sub show { my ($self, $tid) = @_; $self->_load_library(); $self->db_open(); $self->show_articles_in_thread($tid); $self->db_close(); } =head2 print(str) print str with special effect e.g. quoting if needed. The function depends the mode, 'text' or 'html'. =cut # Descriptions: wrapper of print() # Arguments: OBJ($self) STR($str) # Side Effects: quote if needed # Return Value: none sub print { my ($self, $str) = @_; my $mode = $self->get_mode || 'text'; my $fd = $self->{ _fd } || \*STDOUT; if ($mode eq 'text') { print $fd $str; } elsif ($mode eq 'html') { $str = &_quote($str); $str =~ s/\n/
\n/g; print $fd $str; } } # Descriptions: quote for html metachars # Arguments: STR($str) # Side Effects: none # Return Value: STR sub _quote { my ($str) = @_; $str =~ s/&/&/g; $str =~ s//>/g; $str =~ s/\"/"/g; return $str; } =head1 CODING STYLE See C on fml coding style guide. =head1 AUTHOR Ken'ichi Fukamachi =head1 COPYRIGHT Copyright (C) 2001,2002,2004 Ken'ichi Fukamachi All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 HISTORY Mail::ThreadTrack::Print first appeared in fml8 mailing list driver package. See C for more details. =cut 1;