diff options
| author | fukachan <fukachan> | 2004-03-31 12:53:50 +0000 |
|---|---|---|
| committer | fukachan <fukachan> | 2004-03-31 12:53:50 +0000 |
| commit | 5432a7011fcb4386b56fc044a54ec4c4dd2da0e5 (patch) | |
| tree | 0d73b11db0e7a903d7b020323b97f6aaaa8cd10d /fml/lib/Mail/ThreadTrack | |
| parent | 408f950159c3aae27154eaaceb15d6d91095d9d9 (diff) | |
| download | fml8-5432a7011fcb4386b56fc044a54ec4c4dd2da0e5.tar.gz fml8-5432a7011fcb4386b56fc044a54ec4c4dd2da0e5.tar.bz2 fml8-5432a7011fcb4386b56fc044a54ec4c4dd2da0e5.zip | |
Mail::ThreadTrack is obsoleted. remove related codes.
Diffstat (limited to 'fml/lib/Mail/ThreadTrack')
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/Analyze.pm | 663 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/DB.pm | 321 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/HeaderRewrite.pm | 133 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/Print.pm | 419 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/Print/HTML.pm | 291 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/Print/Message.pm | 253 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/Print/Sort.pm | 124 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/Print/Text.pm | 247 | ||||
| -rw-r--r-- | fml/lib/Mail/ThreadTrack/Print/Utils.pm | 115 |
9 files changed, 0 insertions, 2566 deletions
diff --git a/fml/lib/Mail/ThreadTrack/Analyze.pm b/fml/lib/Mail/ThreadTrack/Analyze.pm deleted file mode 100644 index 96b01a6b..00000000 --- a/fml/lib/Mail/ThreadTrack/Analyze.pm +++ /dev/null @@ -1,663 +0,0 @@ -#-*- perl -*- -# -# Copyright (C) 2001,2002,2003 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: Analyze.pm,v 1.32 2003/07/21 11:29:15 fukachan Exp $ -# - -package Mail::ThreadTrack::Analyze; -use strict; -use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); -use Carp; - -# XXX-TODO: we should remove not used function ? - -my $debug = 0; - -=head1 NAME - -Mail::ThreadTrack::Analyze - analyze mail thread relation - -=head1 SYNOPSIS - -See C<Mail::ThreadTrack> perl module for more detail. - -=head1 DESCRIPTION - -=head1 METHODS - -=head2 analyze($mesg) - -C<$mesg> is Mail::Message object. - -This is top level entrance for - -1) assign a new thread or extract the existing thread-id from the subject. - -2) update thread status if needed. - -3) update database. - -=cut - - -# Descriptions: top level entrance -# Arguments: OBJ($self) OBJ($msg) -# $msg = "Mail::Messge object" -# Side Effects: none -# Return Value: none -sub analyze -{ - my ($self, $msg) = @_; - - $self->assign($msg); - $self->rewrite_header($msg) if $self->{ _is_rewrite_header }; - $self->update_thread_status($msg); - $self->update_db($msg); -} - - -=head2 assign($msg) - -analyze message given by $msg and assign thread id if needed. - -=cut - - -# Descriptions: given string looks like subject or not -# Arguments: STR($subject) -# Side Effects: none -# Return Value: 1 or 0 -sub _is_reply -{ - my ($subject) = @_; - - use Mail::Message::Language::Japanese::Subject; - return Mail::Message::Language::Japanese::Subject::is_reply($subject); -} - - -# Descriptions: assign a new thread id or -# extract the existing thread-id from the subject -# Arguments: OBJ($self) OBJ($msg) -# $msg = Mail::Message object -# Side Effects: a new thread_id may be assigned -# Return Value: none -sub assign -{ - my ($self, $msg) = @_; - my $header = $msg->whole_message_header(); - my $subject = $header->get('subject'); - my $is_reply = _is_reply($subject); - - # XXX-TODO: who validate $thread_id regexp - # XXX-TODO: since $thread_id is given from outside. - # 1. try to extract $thread_id from header - my $thread_id = $self->_extract_thread_id_in_subject($header); - unless ($thread_id) { - # If we fail to pick up thread id from subject, - # we try to speculate id from other fields in header. - $thread_id = $self->_speculate_thread_id_from_header($header); - if ($thread_id) { - $is_reply = 1; # message already have thread_id, so replied one? - $self->set_thread_id($thread_id); - $self->log("speculated id=$thread_id"); - } - else { - $self->log("(debug) fail to spelucate thread_id") if $debug; - } - } - - # 2. check "X-Thread-Pragma:" field, - # we ignore this mail if the pragma is specified as "ignore". - if (defined $header->get('x-thread-pragma')) { - my $pragma = $header->get('x-thread-pragma') || ''; - if ($pragma =~ /ignore/io) { - $self->{ _pragma } = 'ignore'; - $self->_append_thread_status_info("ignored"); - return undef; - } - } - - # 3. if the header has some thread_id, - # we do not rewrite the subject but save the extracted $thread_id. - if ($is_reply && $thread_id) { - $self->log("reply message with thread_id=$thread_id"); - $self->set_thread_id($thread_id); - $self->set_thread_status('analyzed'); - $self->_append_thread_status_info('analyzed'); - } - elsif ($thread_id) { - $self->log("message with thread_id=$thread_id but not reply"); - $self->set_thread_id($thread_id); - $self->_append_thread_status_info("found"); - } - else { - $self->log("message without thread_id") if $debug; - - my $id = $self->_assign_new_thread_id_number(); - - # side effect: - # define $self->{ _thread_subject_tag } and $self->{ _thread_id } - my $thread_id = $self->_create_thread_id_strings($id); - $self->set_thread_id($thread_id); - $self->_append_thread_status_info("newly assigned"); - } -} - - -# Descriptions: assign new thread_id -# Arguments: OBJ($self) -# Side Effects: increment id -# Return Value: NUM -sub _assign_new_thread_id_number -{ - my ($self) = @_; - my $id = 0; - - # assign a new thread number for a new message - if (1) { - # unique but non sequential number - $id = $self->{ _config }->{ article_id }; - } - else { - # incremental number - $id = $self->increment_id(); - } - - $self->log("assign thread_id=$id") if $debug; - return $id; -} - - -# Descriptions: update $self->{ _status_info } -# Arguments: OBJ($self) STR($s) -# Side Effects: update $self->{ _status_info } -# Return Value: STR -sub _append_thread_status_info -{ - my ($self, $s) = @_; - $self->{ _status_info } .= $self->{ _status_info } ? " -> ".$s : $s; -} - - -=head2 get_thread_status() - -get thread status. - -=head2 set_thread_status($status) - -set thread status. - -=cut - - -# Descriptions: get thread status -# Arguments: OBJ($self) -# Side Effects: none -# Return Value: STR -sub get_thread_status -{ - my ($self) = @_; - return(defined $self->{ _status } ? $self->{ _status } : undef); -} - - -# Descriptions: set thread status -# Arguments: OBJ($self) STR($thread_status) -# Side Effects: none -# Return Value: STR -sub set_thread_status -{ - my ($self, $thread_status) = @_; - $self->{ _status } = $thread_status; - return $thread_status; -} - - -=head2 update_thread_status($msg) - -ignore this procedure if "ignore" pragma is specified. - -update status to "close" if "close" pragma or "close" commmand in the -message is found. - -=cut - - -# Descriptions: update thread status -# Arguments: OBJ($self) OBJ($msg) -# Side Effects: update database -# Return Value: none -sub update_thread_status -{ - my ($self, $msg) = @_; - my $content = ''; - my $subject = ''; - my $pragma = ''; - - if (defined $self->{ _pragma }) { - return if $self->{ _pragma } eq 'ignore'; - } - - unless (ref($msg) eq 'Mail::Message') { - croak("invalid object"); - } - - # filter messages of some class - if (defined $self->{ _filterlist }) { - if ($self->_is_ignore($msg)) { - $self->log("this thread should be ignored"); - $pragma = "close"; - } - } - - my $header = $msg->whole_message_header(); - my $textmsg = $msg->find_first_plaintext_message(); - $content = $textmsg->message_text() if defined $textmsg; - $subject = $header->get('subject') || ''; - $pragma = $header->get('x-thread-pragma') || $pragma || ''; - - if ($pragma =~ /close/ || - $content =~ /^\s*close/ || - $subject =~ /^\s*close/) { - $self->set_thread_status("close"); - $self->_append_thread_status_info("closed"); - $self->log("thread is closed"); - } - else { - $self->log("thread status not changed"); - } -} - - -# Descriptions: check filter whether this $msg should be ignored or not. -# Arguments: OBJ($self) OBJ($msg) -# Side Effects: none -# Return Value: 1 or 0 -sub _is_ignore -{ - my ($self, $msg) = @_; - my ($header, $textmsg, $content); - my ($field, $rule); - my $filterlist = $self->{ _filterlist }; - - $header = $msg->whole_message_header(); - $textmsg = $msg->find_first_plaintext_message(); - $content = $textmsg->message_text() if defined $textmsg; - - # check header - while (($field, $rule) = each %$filterlist) { - if (defined $header->get($field)) { - my $value = $header->get($field); - if ($debug) { - print STDERR "ignore $field: $value\n" if $value =~ /$rule/m; - } - return 1 if $value =~ /$rule/; - } - } - - return 0; -} - - -=head2 get_thread_id() - -get thread_id in object ($self->{ _thread_id }). - -=head2 set_thread_id($thread_id) - -set thread_id in object ($self->{ _thread_id }). - -=cut - - -# Descriptions: get thread_id in object ($self->{ _thread_id }). -# Arguments: OBJ($self) -# Side Effects: none. -# Return Value: STR or UNDEF -sub get_thread_id -{ - my ($self) = @_; - return(defined $self->{ _thread_id } ? $self->{ _thread_id } : undef); -} - - -# Descriptions: set thread_id -# Arguments: OBJ($self) STR($thread_id) -# Side Effects: update $self->{ _thread_id }. -# Return Value: STR -sub set_thread_id -{ - my ($self, $thread_id) = @_; - $self->{ _thread_id } = $thread_id; - return $thread_id; -} - - -# Descriptions: create regexp for a subject tag, for example -# "[%s %05d]" => "\[\S+ \d+\]" -# Arguments: STR($s) -# XXX non OO type function -# Side Effects: none -# Return Value: STR(a regexp for the given tag) -sub _regexp_compile -{ - my ($s) = @_; - - $s = quotemeta( $s ); - $s =~ s@\\\%@\%@g; - $s =~ s@\%s@\\S+@g; - $s =~ s@\%d@\\d+@g; - $s =~ s@\%0\d+d@\\d+@g; - $s =~ s@\%\d+d@\\d+@g; - $s =~ s@\%\-\d+d@\\d+@g; - - # quote for regexp substitute: [ something ] -> \[ something \] - # $s =~ s/^(.)/quotemeta($1)/e; - # $s =~ s/(.)$/quotemeta($1)/e; - - return $s; -} - - -# Descriptions: extract message-id list and return it. -# Arguments: OBJ($header) -# function not OO -# Side Effects: none -# Return Value: ARRAY_HASH -sub _extract_message_id_references -{ - my ($header) = @_; - my (@addrs, @r, %uniq) = (); - - # XXX-TODO: Mail::Message should provide this function ? - - use Mail::Address; - - if (defined $header->get('in-reply-to')) { - my $buf = $header->get('in-reply-to'); - push(@addrs, Mail::Address->parse($buf)); - } - - if (defined $header->get('references')) { - my $buf = $header->get('references'); - push(@addrs, Mail::Address->parse($buf)); - } - - for my $addr (@addrs) { - my $a = $addr->address; - unless (defined $uniq{ $a } && $uniq{ $a }) { - # RFC822 says msg-id = "<" addr-spec ">" ; Unique message id - push(@r, "<".$addr->address.">"); - $uniq{ $a } = 1; - } - } - - return \@r; -} - - -# Descriptions: extract thread_id in Subject: -# Arguments: OBJ($self) OBJ($header) -# Side Effects: none -# Return Value: STR or 0 -sub _extract_thread_id_in_subject -{ - my ($self, $header) = @_; - my $config = $self->{ _config }; - my $tag = $config->{ thread_subject_tag } || ''; - my $loctype = $config->{ thread_subject_tag_location } || 'appended'; - my $subject = $header->get('subject') || ''; - my $regexp = _regexp_compile($tag); - - # Subject: ... [thread_id] - if (($loctype eq 'appended') && ($subject =~ /($regexp)\s*$/)) { - my $id = $1; - $id =~ s/^(\[|\(|\{)//; - $id =~ s/(\]|\)|\})$//; - return $id; - } - # XXX incomplete, we check subject after cutting off "Re:" et. al. - # Subject: [thread_id] ... - # Subject: Re: [thread_id] ... - elsif (($loctype eq 'prepended') && ($subject =~ /^\s*($regexp)/)) { - my $id = $1; - $id =~ s/^(\[|\(|\{)//; - $id =~ s/(\]|\)|\})$//; - return $id; - } - else { - $self->log("no thread id /$regexp/ in subject") if $debug; - return 0; - } -} - - -# Descriptions: -# For example, consider a posting to both elena ML and -# rudo (DM) from kenken. -# -# From: kenken -# To: elena-ml -# Cc: rudo -# -# The reply to this DM (direct message) from rudo is -# -# From: rudo -# To: elena-ml -# -# This reply message has no thread_id since the -# message from kenken to rudo comes directly from -# kenken not through fml driver. In this case, we -# try to speculdate the reply relation and the -# thread_id of this thread by using _ -# speculate_thread_id_from_header(). -# -# Arguments: OBJ($self) OBJ($header) -# Side Effects: none -# Return Value: STR(message id) -sub _speculate_thread_id_from_header -{ - my ($self, $header) = @_; - my $midlist = _extract_message_id_references( $header ); - my $result = ''; - - if (defined $midlist) { - $self->db_open(); - - # prepare hash table tied to db_dir/*db's - my $rh = $self->{ _hash_table }; - - MSGID_LIST: - for my $mid (@$midlist) { - $result = $rh->{ _message_id }->{ $mid }; - last MSGID_LIST if $result; - } - - $self->db_close(); - } - - if ($debug) { - $self->log("(debug) not speculated") unless $result; - } - $result; -} - - -# Descriptions: create thread_id -# Arguments: OBJ($self) STR($id) -# Side Effects: update $self->{ _thread_subject_tag } -# Return Value: STR(thread_id string) -sub _create_thread_id_strings -{ - my ($self, $id) = @_; - my $config = $self->{ _config }; - - # thread_id appeared in subject: field - my $subject_tag = $config->{ thread_subject_tag }; - $self->{ _thread_subject_tag } = sprintf($subject_tag, $id); - - # thread_id used as primary key - my $id_syntax = $config->{ thread_id_syntax }; - return sprintf($id_syntax, $id); -} - - -=head2 update_db($msg) - -update database. - -=cut - - -# Descriptions: top level dispatcher to drive database update -# Arguments: OBJ($self) OBJ($msg) -# Side Effects: update databases -# Return Value: none -sub update_db -{ - my ($self, $msg) = @_; - my $config = $self->{ _config }; - my $ml_name = $config->{ ml_name }; - - if (defined $self->{ _pragma }) { - return if $self->{ _pragma } eq 'ignore'; - } - - $self->db_open(); - - # save $ticke_id et.al. in db_dir/$ml_name - $self->_update_db($msg); - - $self->prepare_history_info($msg) if $self->{ _is_rewrite_header }; - - # save cross reference pointers among $ml_name - $self->_update_index_db(); - - $self->db_close(); -} - - -# Descriptions: speculate unixtime from header -# Arguments: OBJ($msg) -# Side Effects: none -# Return Value: NUM(unix time) -sub _speculate_time -{ - my ($msg) = @_; - my $header = $msg->whole_message_header; - - if (defined $header->get('date')) { - use Mail::Message::Date; - my $obj = new Mail::Message::Date; - return $obj->date_to_unixtime($header->get('date')); - } - else { - return time; - } -} - - -# Descriptions: update database -# Arguments: OBJ($self) OBJ($msg) -# Side Effects: update database -# Return Value: STR -sub _update_db -{ - my ($self, $msg) = @_; - my $config = $self->{ _config }; - my $article_id = $config->{ article_id }; - my $thread_id = $self->get_thread_id(); - - # 0. logging - $self->log("article_id=$article_id thread_id=$thread_id") if $debug; - - # prepare hash table tied to db_dir/*db's - my $rh = $self->{ _hash_table }; - - # check - if (defined $rh->{ _thread_id }->{ $article_id }) { - print STDERR "_update_db.ignore id=$article_id\n" if $debug; - return; - } - - # 1. - $rh->{ _thread_id }->{ $article_id } = $thread_id; - $rh->{ _date }->{ $article_id } = _speculate_time($msg); - $rh->{ _articles }->{ $thread_id } .= $article_id . " "; - - # 2. record the sender information - my $header = $msg->whole_message_header; - $rh->{ _sender }->{ $article_id } = $header->get('from'); - - # 3. update status information - if (defined $self->get_thread_status()) { - my $status = $self->get_thread_status(); - $self->_set_status($thread_id, $status); - } - else { - # set the default status value for the first time. - unless (defined $rh->{ _status }->{ $thread_id }) { - $self->_set_status($thread_id, 'open'); - } - } - - # 4. save optional/additional information - # message_id hash is { message_id => thread_id }; - # RFC822 says msg-id = "<" addr-spec ">" ; Unique message id - my $mid = $header->get('message-id'); $mid =~ s/[\n\s]*$//; - if ($mid eq "") { - print STDERR "missing message-id $thread_id\n" if $debug; - return; - } - $rh->{ _message_id }->{ $mid } = $thread_id; -} - - -# Descriptions: register myself to index_db for further reference -# among mailing lists -# Arguments: OBJ($self) -# Side Effects: update object -# Return Value: STR -sub _update_index_db -{ - my ($self) = @_; - my $config = $self->{ _config }; - my $thread_id = $self->get_thread_id(); - my $rh = $self->{ _hash_table }; - my $ml_name = $config->{ ml_name }; - - my $ref = $rh->{ _index }->{ $thread_id } || ''; - if ($ref !~ /^$ml_name|\s$ml_name\s|$ml_name$/) { - $rh->{ _index }->{ $thread_id } .= $ml_name." "; - } -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> on fml coding style guide. - -=head1 AUTHOR - -Ken'ichi Fukamachi - -=head1 COPYRIGHT - -Copyright (C) 2001,2002,2003 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::Analyze first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/DB.pm b/fml/lib/Mail/ThreadTrack/DB.pm deleted file mode 100644 index a7831861..00000000 --- a/fml/lib/Mail/ThreadTrack/DB.pm +++ /dev/null @@ -1,321 +0,0 @@ -#-*- perl -*- -# -# Copyright (C) 2001,2002,2003 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: DB.pm,v 1.33 2003/08/23 04:35:49 fukachan Exp $ -# - -package Mail::ThreadTrack::DB; -use strict; -use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); -use Carp; - -my $debug = 0; - -=head1 NAME - -Mail::ThreadTrack::DB - database access. - -=head1 SYNOPSIS - -=head1 DESCRIPTION - -=head1 METHODS - -=cut - -=head2 db_open() - -open database. -It uses tie() to bind a hash to a DB file. -Our thread model uses several DB files such as -C<%thread_id>, -C<%date>, -C<%status>, -C<%sender>, -C<%articles>, -C<%message_id> -and -C<%index>. - -=head2 db_close() - -untie() the corresponding hashes opened by C<db_open()>. - -=cut - -my @kind_of_databases = qw(thread_id date status sender articles - message_id); - - -# Descriptions: open database by tie() -# Arguments: OBJ($self) -# Side Effects: $self->{ _hash_table } initialized. -# Return Value: none -sub db_open -{ - my ($self) = @_; - my $db_type = $self->{ config }->{ db_type } || 'AnyDBM_File'; - my $db_dir = $self->{ _db_dir }; - my $file_mode = $self->{ _file_mode } || 0644; - - use File::Spec; - eval qq{ use $db_type; use Fcntl;}; - unless ($@) { - for my $db (@kind_of_databases) { - my $file = File::Spec->catfile($db_dir, $db); - my $str = qq{ - my \%$db = (); - tie \%$db, \$db_type, \$file, O_RDWR|O_CREAT, $file_mode; - \$self->{ _hash_table }->{ _$db } = \\\%$db; - }; - eval $str; - croak($@) if $@; - } - - my %index = (); - my $index_file = $self->{ _index_db }; - eval q{ - tie %index, $db_type, $index_file, O_RDWR|O_CREAT, $file_mode; - $self->{ _hash_table }->{ _index } = \%index; - }; - croak($@) if $@; - } - else { - croak("failed to \"use $db_type\""); - } - - 1; -} - - -# Descriptions: clear database -# Arguments: OBJ($self) -# Side Effects: update database -# Return Value: none -sub db_clear -{ - my ($self) = @_; - my $db_dir = ''; - - $db_dir = $self->{ _db_dir }; - _db_clear($db_dir) if -d $db_dir; - - $db_dir = $self->{ _db_base_dir }; - _db_clear($db_dir) if -d $db_dir; -} - - -# Descriptions: clear database -# Arguments: STR($db_dir) -# Side Effects: clear database, remove file if needed -# Return Value: none -sub _db_clear -{ - my ($db_dir) = @_; - - eval q{ - use DirHandle; - use File::Spec; - my $dh = new DirHandle $db_dir; - - if (defined $dh) { - my $f = ''; - while (defined($f = $dh->read)) { - next if $f =~ /^\./; - my $file = File::Spec->catfile($db_dir, $f); - if (-f $file) { - unlink $file; - print STDERR "removed $file\n" unless -f $file; - } - } - $dh->close; - } - }; - croak($@) if $@; -} - - -# Descriptions: close database by untie() -# Arguments: OBJ($self) -# Side Effects: none -# Return Value: none -sub db_close -{ - my ($self) = @_; - - for my $db (@kind_of_databases) { - my $str = qq{ - my \$${db} = \$self->{ _hash_table }->{ _$db }; - untie \%\$${db}; - }; - eval $str; - croak($@) if $@; - } - - my $index = $self->{ _hash_table }->{ _index }; - untie %$index; -} - - -=head2 db_mkdb($min, $max) - -remake database. - -=cut - - -# Descriptions: remake database for messages from $min_id to $max_id -# Arguments: OBJ($self) NUM($min_id) NUM($max_id) -# Side Effects: remake database -# Return Value: none -sub db_mkdb -{ - my ($self, $min_id, $max_id) = @_; - my $config = $self->{ _config }; - my $spool_dir = $config->{ spool_dir }; - my $saved_args = $self->{ _saved_args }; # original $args - - return undef unless (defined $min_id && defined $max_id); - - use Mail::Message; - use File::Spec; - - my $count = 0; - my ($fh, $file, $msg); - print STDERR "db_mkdb: $min_id -> $max_id\n" if $debug; - - ID: - for my $id ( $min_id .. $max_id ) { - print STDERR "." if $count++ % 10 == 0; - print STDERR "process $id\n" if $debug; - - # XXX-TODO: this code is workaround, we should create more clever way. - # XXX-TODO: overwrite (tricky) - $self->{ _config }->{ article_id } = $id; - - # parse article and analyze it. - $file = $self->filepath({ - base_dir => $spool_dir, - id => $id, - }); - - $fh = new FileHandle $file; - if (defined $fh) { - my $msg = Mail::Message->parse({ fd => $fh }); - $self->analyze($msg); - - # XXX-TODO: workaround, we should create more clever way. - # XXX-TODO: remove current status (tricky ;) - delete $self->{ _status }; - } - } - print STDERR "\n" if $count > 0; -} - - -=head2 db_dump([$type]) - -dump hash as text. -dump status database if $type is not specified. - -=cut - - -# Descriptions: dump data for database $type -# Arguments: OBJ($self) STR($type) -# Side Effects: none -# Return Value: none -sub db_dump -{ - my ($self, $type) = @_; - my $db_type = "_" . ( defined $type ? $type : 'status' ); - my $rh = $self->{ _hash_table }->{ $db_type }; - - my ($k, $v); - while (($k, $v) = each %$rh) { - printf "%-20s %s\n", $k, $v; - } -} - - -=head2 db_hash( $type ) - -return HASH REFERENCE for specified database $type. - -=cut - - -# Descriptions: get HASH REFERENCE for specified $type. -# Arguments: OBJ($self) STR($db_type) -# Side Effects: none -# Return Value: HASH_REF or UNDEF -sub db_hash -{ - my ($self, $db_type) = @_; - my $type = "_" . $db_type; - - if (defined $self->{ _hash_table }->{ $type }) { - return $self->{ _hash_table }->{ $type }; - } - else { - return undef; - } -} - - -=head2 db_last_modified() - -return the last modified time of our dateabase as unix time. -This time is the latest modified time among all database files. - -=cut - - -# Descriptions: return the last modified time (unix time) of database -# Arguments: OBJ($self) STR($db_type) -# Side Effects: none -# Return Value: STR or UNDEF -sub db_last_modified -{ - my ($self, $db_type) = @_; - my $db_dir = $self->{ _db_dir }; - my $last_modified = 0; - - # XXX-TODO: we supporse Berkeley DB. fix it. - use File::Spec; - my $file = File::Spec->catfile($db_dir, "date.db"); - if (-f $file) { - $last_modified = (stat($file))[8]; - } - - return $last_modified; -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> on fml coding style guide. - -=head1 AUTHOR - -Ken'ichi Fukamachi - -=head1 COPYRIGHT - -Copyright (C) 2001,2002,2003 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::DB first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/HeaderRewrite.pm b/fml/lib/Mail/ThreadTrack/HeaderRewrite.pm deleted file mode 100644 index 5b47445c..00000000 --- a/fml/lib/Mail/ThreadTrack/HeaderRewrite.pm +++ /dev/null @@ -1,133 +0,0 @@ -#-*- perl -*- -# -# Copyright (C) 2001,2002,2003 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: HeaderRewrite.pm,v 1.14 2003/08/23 04:35:49 fukachan Exp $ -# - -package Mail::ThreadTrack::HeaderRewrite; -use strict; -use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); -use Carp; - -=head1 NAME - -Mail::ThreadTrack::HeaderRewrite - header manipulation - -=head1 SYNOPSIS - -=head1 DESCRIPTION - -=head1 METHODS - -=head2 rewrite_header($msg) - -C<$msg> is Mail::Message object. - -=cut - - -# Descriptions: add thread track info into $msg where -# $msg is Mail::Message object. -# Arguments: OBJ($self) OBJ($msg) -# Side Effects: modify $msg header -# Return Value: none -sub rewrite_header -{ - my ($self, $msg) = @_; - my $config = $self->{ _config }; - my $loctype = $config->{ thread_subject_tag_location } || 'appended'; - my $header = $msg->whole_message_header(); - my $tag = $self->{ _thread_subject_tag } || ''; - - # append the thread tag to the subject - if (defined $header->get('subject')) { - my $subject = $header->get('subject'); - - if ($loctype eq 'appended' && $tag) { - $header->replace('subject', $subject ." ". $tag); - } - elsif ($loctype eq 'prepended' && $tag) { - $header->replace('subject', $tag ." ". $subject); - } - else { - $self->log("unknown thread_subject_tag_location type"); - } - - if (defined $self->{ _status_info }) { - $header->add('X-Thread-Status', $self->{ _status_info }); - } - - if (defined $self->{ _thread_id }) { - $header->add('X-Thread-ID', $self->{ _thread_id }); - } - - if (defined $self->{ _status_history }) { - $header->add('X-Thread-History', $self->{ _status_history }); - } - } -} - - -# Descriptions: prepare history infomation for further header rewriting. -# Arguments: OBJ($self) OBJ($msg) -# Side Effects: update $self->{ _status_history } -# Return Value: none -sub prepare_history_info -{ - my ($self, $msg) = @_; - my $thread_id = $self->get_thread_id(); - - # prepare hash table tied to db_dir/*db's - my $rh = $self->{ _hash_table }; - - if (defined $rh->{ _articles }->{ $thread_id }) { - my $buf = ''; - my (@aid) = split(/\s+/, $rh->{ _articles }->{ $thread_id }); - my $sender = $rh->{ _sender }->{ $aid[0] }; - my $when = $rh->{ _date }->{ $aid[0] }; - - # clean up - $sender =~ s/[\s\n]*$//; - $when =~ s/[\s\n]*$//; - - use Mail::Message::Date; - $when = Mail::Message::Date->new($when)->mail_header_style(); - - # XXX-TODO: validate $aid[0], $sender, $when, @aid. - $buf .= "\t\n"; - $buf .= "\tthis thread is opended at article $aid[0]\n"; - $buf .= "\tby $sender\n"; - $buf .= "\ton $when\n"; - $buf .= "\tarticle references: @aid\n"; - $self->{ _status_history } = $buf; - } -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> on fml coding style guide. - -=head1 AUTHOR - -Ken'ichi Fukamachi - -=head1 COPYRIGHT - -Copyright (C) 2001,2002,2003 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::HeaderRewrite first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/Print.pm b/fml/lib/Mail/ThreadTrack/Print.pm deleted file mode 100644 index c8b08bfc..00000000 --- a/fml/lib/Mail/ThreadTrack/Print.pm +++ /dev/null @@ -1,419 +0,0 @@ -#-*- 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<with> article summary. - -Each row that C<show_summary()> returns has a set of -C<date>, C<age>, C<status>, C<thread-id> and -C<articles>, 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/<BR>\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; - $str =~ s/\"/"/g; - - return $str; -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> 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<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/Print/HTML.pm b/fml/lib/Mail/ThreadTrack/Print/HTML.pm deleted file mode 100644 index 220c6e09..00000000 --- a/fml/lib/Mail/ThreadTrack/Print/HTML.pm +++ /dev/null @@ -1,291 +0,0 @@ -#-*- perl -*- -# -# Copyright (C) 2001,2002,2003 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: HTML.pm,v 1.17 2003/02/11 11:22:56 fukachan Exp $ -# - -package Mail::ThreadTrack::Print::HTML; - -use strict; -use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); -use Carp; - - -=head1 NAME - -Mail::ThreadTrack::Print::HTML - print thread summary as HTML - -=head1 SYNOPSIS - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 DESCRIPTION - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 METHODS - -=head2 show_articles_in_thread(thread_id) - -show articles as HTML in this thread. - -=cut - - -use CGI qw/:standard/; -use Mail::ThreadTrack::Print::Utils qw(decode_mime_string STR2EUC); - - -# Descriptions: show articles as HTML in this thread -# Arguments: OBJ($self) STR($thread_id) -# Side Effects: none -# Return Value: none -sub show_articles_in_thread -{ - my ($self, $thread_id) = @_; - my $mode = $self->get_mode || 'text'; - my $config = $self->{ _config }; - my $spool_dir = $config->{ spool_dir }; - - my $articles = $self->{ _hash_table }->{ _articles }->{ $thread_id }; - - # XXX-TODO: who validates $thread_id ? - print "<B>"; - print "show contents related with thread_id=$thread_id\n"; - print "</B>"; - print "<HR>"; - print "<PRE>\n"; - - if (defined($articles) && defined($spool_dir) && -d $spool_dir) { - use FileHandle; - - my $s = ''; - for my $article (split(/\s+/, $articles)) { - my $file = $self->filepath({ - base_dir => $spool_dir, - id => $article, - }); - - # XXX-TODO: care for non Japanese char(s). - # XXX-TODO: to avoid CSS bug, convert all special char(s). - # XXX-TODO: create method safe_html_string() in Mail::Message ? - if (-f $file) { - my $fh = new FileHandle $file; - - if (defined $fh) { - my $buf; - - while (defined($buf = $fh->getline())) { - # ignore header part. - next if 1 .. $buf =~ /^$/o; - - $s = STR2EUC($buf); - $s =~ s/&/&/g; - $s =~ s/</</g; - $s =~ s/>/>/g; - $s =~ s/\"/"/g; - print $s; - } - $fh->close; - } - } - } - } - - print "</PRE>"; -} - - -# Descriptions: show guide -# Arguments: OBJ($self) HASH_REF($args) -# Side Effects: none -# Return Value: none -sub __start_thread_summary -{ - my ($self, $args) = @_; - my $config = $self->{ _config }; - my $ml_name = $config->{ ml_name }; - my $fd = $self->{ _fd } || \*STDOUT; - my $action = $curproc->safe_cgi_action_name(); - my $target = '_top'; - - # statistics - if (defined $self->{ _ticket_id_stat }) { - my $stat = $self->{ _ticket_id_stat }; - for my $key ('open', 'analyzed', 'closed') { - print $fd "$key: "; - print $fd defined $stat->{ $key } ? $stat->{ $key } : 0; - print $fd ", "; - } - print $fd br, "\n"; - } - - # XXX-TODO: validate $action ? - print $fd start_form(-action=>$action, -target=>$target); - print $fd submit(-name => 'submit'); - print $fd reset(-name => 'reset'); - print $fd "\n"; - - # XXX-TODO: validate $ml_name ? - print $fd hidden(-name => 'ml_name', - -default => [ $ml_name ], - ), "\n"; - - param('action', 'change_status'); # we need to override - print $fd hidden(-name => 'action', - -default => [ 'change_status ' ], - ), "\n"; - - print $fd "<TABLE BORDER=4>\n"; - print $fd "<TD>id\n"; - print $fd "<TD>change\n"; - print $fd "<TD>summary\n"; - print $fd "<TD>age\n"; - print $fd "<TD>status\n"; -} - - -# Descriptions: finalize thread list. -# close TABLE tag. -# Arguments: OBJ($self) HASH_REF($args) -# Side Effects: none -# Return Value: none -sub __end_thread_summary -{ - my ($self, $args) = @_; - my $fd = $self->{ _fd } || \*STDOUT; - - print $fd "</TABLE>\n"; - - print submit(-name => 'submit'); - print reset(-name => 'reset'); - print $fd end_form; -} - - -# Descriptions: This shows summary on C<$thread_id> in HTML language. -# It is used in C<FML::CGI::ThreadSystem>. -# Arguments: OBJ($self) HASH_REF($optargs) -# Side Effects: none -# Return Value: none -sub __print_thread_summary -{ - my ($self, $optargs) = @_; - my $config = $self->{ _config }; - my $ml_name = $config->{ ml_name }; - my $spool_dir = $config->{ spool_dir }; - my $action = $curproc->safe_cgi_action_name(); - my $target = $config->{ thread_cgi_target_window } || '_top'; - - my $date = $optargs->{ date }; - my $age = $optargs->{ age }; - my $status = $optargs->{ status }; - my $tid = $optargs->{ thread_id }; - my $articles = $optargs->{ articles }; - my $aid = (split(/\s+/, $articles))[0]; - - # do nothing if the $thread_id is unknown. - return unless $tid; - - # XXX-TODO: validate $action, $ml_name, $aid ... - # <FORM ACTION=> ..> - my $xtid = CGI::escape($tid); - $action = "${action}?ml_name=${ml_name}&article_id=$aid"; - - $self->{ _table_count } = 1 unless defined $self->{ _table_count }; - if (($self->{ _table_count }++ % 5) == 0) { - print "<TR>\n<TD>\n"; - print submit(-name => 'submit'); - print reset(-name => 'reset'); - } - - print "<TR>\n"; - - # XXX-TODO: validate $msg_base_url ? - # show articles in this thread id - print "<TD>"; - if (defined $config->{ msg_base_url }) { - my $msg_base_url = $config->{ msg_base_url }; - my $url = "$msg_base_url/msg$aid.html"; - print "<A HREF=\"$url\" TARGET=\"article\">\n"; - print $tid; - print "\n</A>\n"; - } - else { - # XXX-TODO: validate $action ? - print "<A HREF=\"$action&action=show\" TARGET=\"article\">\n"; - print $tid; - print "\n</A>\n"; - } - - # action - print "<TD>"; - my $name = "change_status.$tid"; - my $values = ["open", "analyzed", "closed"]; - my $default = $status; - print radio_group(-name => $name, - -values => $values, - -default => $default, - -linebreak => 'true', - ); - - # message (article) brief summary - print "<TD>"; - if (defined $articles) { - $aid = (split(/\s+/, $articles))[0]; - my $f = $self->filepath({ - base_dir => $spool_dir, - id => $aid, - }); - if (-f $f) { - # XXX-TODO: care for non Japanese. - my $buf = $self->message_summary($f); - $self->print( STR2EUC($buf) ); - } - } - - # addional information: age, status - print "<TD>$age\n"; - print "<TD>$status\n"; - - print "\n\n"; -} - - -# Descriptions: dummy, defined for symmetry -# Arguments: none -# Side Effects: none -# Return Value: none -sub __print_message_summary -{ - ; -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> on fml coding style guide. - -=head1 AUTHOR - -Ken'ichi Fukamachi - -=head1 COPYRIGHT - -Copyright (C) 2001,2002,2003 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::HTML first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/Print/Message.pm b/fml/lib/Mail/ThreadTrack/Print/Message.pm deleted file mode 100644 index 7c61a63a..00000000 --- a/fml/lib/Mail/ThreadTrack/Print/Message.pm +++ /dev/null @@ -1,253 +0,0 @@ -#-*- perl -*- -# -# Copyright (C) 2001,2002,2003 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: Message.pm,v 1.9 2002/12/22 03:19:15 fukachan Exp $ -# - -package Mail::ThreadTrack::Print::Message; -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::Message - summarize message et.al. - -=head1 SYNOPSIS - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 DESCRIPTION - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 METHODS - -=head2 message_summary($file) - -make message summary for specified $file (article). - -=cut - - -# Descriptions: make summary of the specified $file (article). -# Arguments: OBJ($self) STR($file) -# Side Effects: none -# Return Value: STR -sub message_summary -{ - my ($self, $file) = @_; - my (@header) = (); - my $msgbuf = ''; - my $line = $self->{ _article_summary_lines } || 3; - my $mode = $self->get_mode || 'text'; - my $padding = $mode eq 'text' ? ' ' : ''; - - use FileHandle; - my $fh = new FileHandle $file; - - if (defined $fh) { - my $buf; - - LINE: - while ($buf = <$fh>) { - # remove useless lines - next LINE if $buf =~ /^\>/o; - next LINE if $buf =~ /^\-/o; - - # header part - if (1 .. $buf =~ /^$/o) { - push(@header, $buf); - } - # body part - else { - next LINE if $buf =~ /^\s*$/o; - - # ignore mail header like patterns. - next LINE if $buf =~ /^X-[-A-Za-z0-9]+:/io; - next LINE if $buf =~ /^Return-[-A-Za-z0-9]+:/io; - next LINE if $buf =~ /^Mime-[-A-Za-z0-9]+:/io; - next LINE if $buf =~ /^Content-[-A-Za-z0-9]+:/io; - next LINE if $buf =~ /^(To|From|Subject|Reply-To|Received):/io; - next LINE if $buf =~ /^(Message-ID|Date):/io; - - # pick up effetive the first $line lines - if (_is_valid_buf($buf)) { - $line--; - $msgbuf .= $padding . $buf; - } - - last LINE if $line < 0; - } - } - - $fh->close(); - - # XXX-TODO: WHO CARE FOR CSS ? return raw messages from here. - # XXX-TODO: care for non Japanese. - if (defined $self->{ _no_header_summary }) { - return STR2EUC( $msgbuf ); - } - else { - use Mail::Header; - my $header = new Mail::Header \@header; - my $header_info = $self->header_summary({ - header => $header, - padding => $padding, - }); - return STR2EUC( $header_info ."\n". $msgbuf ); - } - } - else { - return undef; - } -} - - -# Descriptions: check if $str looks effective, not quotation et.al. ? -# Arguments: STR($str) -# Side Effects: none -# Return Value: 1 or 0 -sub _is_valid_buf -{ - my ($str) = @_; - $str = STR2EUC( $str ); - - if ($str =~ /^[\>\#\|\*\:\;\=]/o) { - return 0; - } - elsif ($str =~ /^in /o) { # quotation ? - return 0; - } - elsif ($str =~ /\w+\@\w+/o) { # mail address ? - return 0; - } - elsif ($str =~ /^\S+\>/o) { # quotation ? - return 0; - } - - return 1; -} - - -# Descriptions: remove subject tag like string in $str e.g. [elena 100]. -# Arguments: STR($str) -# Side Effects: none -# Return Value: STR -sub _delete_subject_tag_like_string -{ - my ($str) = @_; - - if (defined $str) { - # XXX-TODO: hmm, method-ify Mail::Message::Utils ? - use Mail::Message::Utils; - return Mail::Message::Utils::remove_subject_tag_like_string($str); - } - else { - return undef; - } -} - - -# Descriptions: make summary of header $args->{ header }. -# Arguments: OBJ($self) HASH_REF($args) -# Side Effects: none -# Return Value: STR -sub header_summary -{ - my ($self, $args) = @_; - my $date = $args->{ header }->get('date'); - my $from = $args->{ header }->get('from'); - my $subject = $args->{ header }->get('subject'); - my $padding = $args->{ padding } || ' '; - - # XXX-TODO: care for non Japanese. - if (defined $subject) { - $subject = decode_mime_string($subject, { charset => 'euc-japan' }); - $subject =~ s/\n/ /g; - $subject = _delete_subject_tag_like_string($subject); - $subject =~ s/[\s\n]*$//g; - } - - if (defined $from) { - $from = $self->_who_of_address( $from ); - $from =~ s/\n/ /g; - $from =~ s/[\s\n]*$//g; - } - - # XXX-TODO: WHO CARE FOR CSS ? return raw messages from here. - # XXX-TODO: care for non Japanese. - # return buffer - my $r = $padding. $date; - $r .= $padding. "$subject, $from\n"; - return STR2EUC( $r ); -} - - -# Descriptions: get gecos field in $address. -# return $address itself if the extraction failed. -# Arguments: OBJ($self) STR($address) -# Side Effects: none -# Return Value: STR -sub _who_of_address -{ - my ($self, $address) = @_; - my ($user); - - use Mail::Address; - my (@addrs) = Mail::Address->parse($address); - - for my $addr (@addrs) { - if (defined( $addr->phrase() )) { - # XXX-TODO: care for non Japanese. - my $phrase = decode_mime_string( $addr->phrase(), { - charset => 'euc-japan', - }); - - if ($phrase) { - return($phrase); - } - } - - $user = $addr->user(); - } - - # XXX-TODO: hmm, CROSS SITE SCRIPTING may cause ? - if ($self->get_mode() eq 'html') { - return( $user ? "$user\@xxx.xxx.xxx.xxx" : $address ); - } - else { - return $address; - } -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> on fml coding style guide. - -=head1 AUTHOR - -Ken'ichi Fukamachi - -=head1 COPYRIGHT - -Copyright (C) 2001,2002,2003 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::Message first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/Print/Sort.pm b/fml/lib/Mail/ThreadTrack/Print/Sort.pm deleted file mode 100644 index 6b0fa5bf..00000000 --- a/fml/lib/Mail/ThreadTrack/Print/Sort.pm +++ /dev/null @@ -1,124 +0,0 @@ -#-*- 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: Sort.pm,v 1.9 2002/12/22 03:21:33 fukachan Exp $ -# - -package Mail::ThreadTrack::Print::Sort; -use strict; -use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); -use Carp; - - -=head1 NAME - -Mail::ThreadTrack::Print::Sort - sort function for printing - -=head1 SYNOPSIS - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 DESCRIPTION - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 METHODS - -=head2 sort_thread_id($thread_id_list) - -=cut - - -# Descriptions: sort ARRAY REFERENCE $thread_id_list -# Arguments: OBJ($self) ARRAY_REF($thread_id_list) -# Side Effects: initialize $self->{ _age } and $self->{ _cost } -# Return Value: ARRAY_REF -sub sort_thread_id -{ - my ($self, $thread_id_list) = @_; - - # get age HASH TABLE - my ($age, $cost) = $self->_calculate_age($thread_id_list); - $self->{ _age } = $age; - $self->{ _cost } = $cost; - - @$thread_id_list = sort { - $cost->{$b} <=> $cost->{$a} - } @$thread_id_list; - - return $thread_id_list; -} - - -my $status_cost = { - open => ( 1 << 10 ), - analyzed => ( 1 << 9 ), -}; - - -# Descriptions: evaluate how old and status each thread is -# Arguments: OBJ($self) ARRAY_REF($thread_id_list) -# Side Effects: none -# Return Value: ARRAY( HASH_REF, HASH_REF ) -sub _calculate_age -{ - my ($self, $thread_id_list) = @_; - my (%age, %cost) = (); - my $now = time; # save the current UTC for convenience - my $rh = $self->{ _hash_table } || {}; - my $day = 24*3600; - - # $age hash referehence = { $thread_id => $age }; - my (@aid, $last, $age, $date, $status, $tid) = (); - for $tid (sort @$thread_id_list) { - next unless defined $rh->{ _articles }->{ $tid }; - - # $last: get the latest one of article_id's - (@aid) = split(/\s+/, $rh->{ _articles }->{ $tid }); - $last = $aid[ $#aid ] || 0; - - # how long this thread is not concerned ? - $age = sprintf("%2.1f%s", ($now - $rh->{ _date }->{ $last })/$day); - $age{ $tid } = $age; - - # evaluate cost hash table which is { $thread_id => $cost } - my $status = $rh->{ _status }->{ $tid }; - $cost{ $tid } = $status_cost->{ $status } + $age; - } - - return (\%age, \%cost); -} - - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> on fml coding style guide. - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> 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::Sort first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/Print/Text.pm b/fml/lib/Mail/ThreadTrack/Print/Text.pm deleted file mode 100644 index c6d5a6a1..00000000 --- a/fml/lib/Mail/ThreadTrack/Print/Text.pm +++ /dev/null @@ -1,247 +0,0 @@ -#-*- perl -*- -# -# Copyright (C) 2001,2002,2003 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: Text.pm,v 1.14 2003/01/11 15:16:37 fukachan Exp $ -# - -package Mail::ThreadTrack::Print::Text; -use strict; -use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); -use Carp; -use Mail::ThreadTrack::Print::Utils qw(decode_mime_string STR2EUC); - -# -# XXX-TODO: insert more examples on format in each function. -# - -=head1 NAME - -Mail::ThreadTrack::Print::Text - printing suitable for text - -=head1 SYNOPSIS - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 DESCRIPTION - -See C<Mail::ThreadTrack::Print> for usage of this subclass. - -=head1 METHODS - -=head2 show_articles_in_thread(thread_id) - -show articles as text in this thread. - -=cut - -# XXX-TODO: $is_show_cost_indicate hard-coded. -my $is_show_cost_indicate = 0; - -# XXX-TODO: $format hard-coded. -my $format = "%-20s %10s %5s %8s %s\n"; - - -# Descriptions: show articles as text in this thread -# Arguments: OBJ($self) STR($thread_id) -# Side Effects: none -# Return Value: none -sub show_articles_in_thread -{ - my ($self, $thread_id) = @_; - my $mode = $self->get_mode || 'text'; - my $config = $self->{ _config }; - my $spool_dir = $config->{ spool_dir }; - my $articles = $self->{ _hash_table }->{ _articles }->{ $thread_id }; - my $wh = $self->{ _fd } || \*STDOUT; - - use FileHandle; - if (defined($articles) && defined($spool_dir) && -d $spool_dir) { - my $s = ''; - # $articles = "1 2 3 4 5"; - for my $id (split(/\s+/, $articles)) { - my $file = $self->filepath({ - base_dir => $spool_dir, - id => $id, - }); - - my $fh = new FileHandle $file; - if (defined $fh) { - my $buf; - - LINE: - while (defined($buf = $fh->getline())) { - next LINE if 1 .. $buf =~ /^$/o; - - # XXX-TODO: we suppose Japanese only here. - $s = STR2EUC($buf); - print $wh $s; - } - $fh->close; - } - } - } -} - - -# Descriptions: show guide line -# Arguments: OBJ($self) HASH_REF($args) -# Side Effects: none -# Return Value: none -sub __start_thread_summary -{ - my ($self, $args) = @_; - my $fd = $self->{ _fd } || \*STDOUT; - - # XXX-TODO: guide line is hard-coded. o.k.? - printf($fd $format, 'id', 'date', 'age', 'status', 'articles'); - print $fd "-" x60; - print $fd "\n"; -} - - -# Descriptions: print formatted brief summary -# Arguments: OBJ($self) HASH_REF($optargs) -# Side Effects: none -# Return Value: none -sub __print_thread_summary -{ - my ($self, $optargs) = @_; - my $fd = $self->{ _fd } || \*STDOUT; - my $date = $optargs->{ date }; - my $age = $optargs->{ age }; - my $status = $optargs->{ status }; - my $thread_id = $optargs->{ thread_id }; - my $articles = $optargs->{ articles }; - my $aid = (split(/\s+/, $articles))[0]; # the head of this thread - - printf($fd $format, $thread_id, $date, $age, $status, - _format_list(25, $articles)); -} - - -# Descriptions: print closing string, empty now (dummy). -# Arguments: OBJ($self) HASH_REF($args) -# Side Effects: none -# Return Value: none -sub __end_thread_summary -{ - my ($self, $args) = @_; - my $fd = $self->{ _fd } || \*STDOUT; -} - - -# Descriptions: create a string of "a b c .." style up to $num bytes -# Arguments: NUM($max) STR($str) -# Side Effects: none -# Return Value: STR -sub _format_list -{ - my ($max, $str) = @_; - my (@idlist) = split(/\s+/, $str); - my $r = ''; - - ID: - for my $id (@idlist) { - $r .= $id . " "; - if (length($r) > $max) { - $r .= "..."; - last ID; - } - } - - return $r; -} - - -# Descriptions: print message summary -# Arguments: OBJ($self) STR($thread_id) -# Side Effects: none -# Return Value: none -sub __print_message_summary -{ - my ($self, $thread_id) = @_; - my $config = $self->{ _config }; - my $age = $self->{ _age } || {}; - my $cost = $self->{ _cost } || {}; - my $fd = $self->{ _fd } || \*STDOUT; - my $rh = $self->{ _hash_table }; - - if (defined $config->{ spool_dir }) { - my ($aid, @aid, $file); - my $spool_dir = $config->{ spool_dir }; - - THREAD_ID_LIST: - for my $thread_id (@$thread_id) { - if ($is_show_cost_indicate) { - my $how_bad = _cost_to_indicator( $cost->{ $thread_id } ); - printf $fd "\n%6s %-10s %s\n", $how_bad, $thread_id; - } - else { - printf $fd "\n>Thread-Id: %-10s %s\n", $thread_id; - } - - # show only the first article of this thread $thread_id - if (defined $rh->{ _articles }->{ $thread_id }) { - (@aid) = split(/\s+/, $rh->{ _articles }->{ $thread_id }); - $aid = $aid[0]; - $file = $self->filepath({ - base_dir => $spool_dir, - id => $aid, - }); - if (-f $file) { - $self->print( $self->message_summary($file) ); - } - } - } - } -} - - -# Descriptions: for example, cost -> '!!!' -# broken now ;-) -# Arguments: STR($cost) -# Side Effects: none -# Return Value: STR -sub _cost_to_indicator -{ - my ($cost) = @_; - my $how_bad = 0; - - # XXX-TODO: cost indicator is broken ? - if ($cost =~ /(\w+)\-(\d+)/) { - $how_bad += $2; - $how_bad += 2 if $1 =~ /open/; - $how_bad = "!" x ($how_bad > 6 ? 6 : $how_bad); - } - - $how_bad; -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> on fml coding style guide. - -=head1 AUTHOR - -Ken'ichi Fukamachi - -=head1 COPYRIGHT - -Copyright (C) 2001,2002,2003 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::Text first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; diff --git a/fml/lib/Mail/ThreadTrack/Print/Utils.pm b/fml/lib/Mail/ThreadTrack/Print/Utils.pm deleted file mode 100644 index 45bfcbcf..00000000 --- a/fml/lib/Mail/ThreadTrack/Print/Utils.pm +++ /dev/null @@ -1,115 +0,0 @@ -#-*- 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: Utils.pm,v 1.6 2002/12/22 03:21:33 fukachan Exp $ -# - -package Mail::ThreadTrack::Print::Utils; -use strict; -use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); -use Carp; - -require Exporter; -@ISA = qw(Exporter); -@EXPORT_OK = qw(decode_mime_string STR2EUC); - - -=head1 NAME - -Mail::ThreadTrack::Print::Utils - utility functions - -=head1 SYNOPSIS - - use Mail::ThreadTrack::Print::Utils qw(decode_mime_string STR2EUC); - -=head1 DESCRIPTION - -utility functions to manipulate Japanese string. - -=head1 METHODS - -=head2 decode_mime_string(string, [$options]) - -decode a base64/quoted-printable encoded string to a plain message. -The encoding method is automatically detected. - -C<$options> is a HASH REFERENCE. -You can specify the charset of the string to return -by $options->{ charset }. - -=head2 STR2EUC(str) - -convert str to Japanese EUC. - -=cut - - -# Descriptions: decode $str -# Arguments: STR($str) HASH_REF($options) -# Side Effects: none -# Return Value: STR -sub decode_mime_string -{ - my ($str, $options) = @_; - my $charset = $options->{ 'charset' } || 'euc-japan'; - - # XXX-TODO: care for non Japanese. - if ($charset eq 'euc-japan') { - if ($str =~ /=\?ISO\-2022\-JP\?B\?(\S+\=*)\?=/i) { - eval q{ use MIME::Base64; }; - $str =~ s/=\?ISO\-2022\-JP\?B\?(\S+\=*)\?=/decode_base64($1)/gie; - } - - if ($str =~ /=\?ISO\-2022\-JP\?Q\?(\S+\=*)\?=/i) { - eval q{ use MIME::QuotedPrint;}; - $str =~ s/=\?ISO\-2022\-JP\?Q\?(\S+\=*)\?=/decode_qp($1)/gie; - } - } - - use Jcode; - &Jcode::convert(\$str, 'euc'); - $str; -} - - -# Descriptions: convert $str to Japanese EUC -# Arguments: STR($str) -# Side Effects: none -# Return Value: STR -sub STR2EUC -{ - my ($str) = @_; - - use Jcode; - &Jcode::convert(\$str, 'euc'); - return $str; -} - - -=head1 CODING STYLE - -See C<http://www.fml.org/software/FNF/> 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::Utils first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; |
