diff options
| author | fukachan <fukachan> | 2003-03-16 04:53:32 +0000 |
|---|---|---|
| committer | fukachan <fukachan> | 2003-03-16 04:53:32 +0000 |
| commit | 379d3a44e1e9722b5d7e86d58740d862383c0cbf (patch) | |
| tree | 8beb66ae0fe375eef71b89148a1dde81f2ef8052 /fml/lib | |
| parent | e15109eaacd3d712f20421eabd6c6452828e4494 (diff) | |
| download | fml8-379d3a44e1e9722b5d7e86d58740d862383c0cbf.tar.gz fml8-379d3a44e1e9722b5d7e86d58740d862383c0cbf.tar.bz2 fml8-379d3a44e1e9722b5d7e86d58740d862383c0cbf.zip | |
remove fmlthread.
"fmlthread ..." -> "fml $ml thread ..."
Diffstat (limited to 'fml/lib')
| -rw-r--r-- | fml/lib/FML/Article/Thread.pm | 352 | ||||
| -rw-r--r-- | fml/lib/FML/Command/Admin/thread.pm | 188 | ||||
| -rw-r--r-- | fml/lib/FML/Process/ThreadTrack.pm | 562 |
3 files changed, 540 insertions, 562 deletions
diff --git a/fml/lib/FML/Article/Thread.pm b/fml/lib/FML/Article/Thread.pm new file mode 100644 index 00000000..a9f7202f --- /dev/null +++ b/fml/lib/FML/Article/Thread.pm @@ -0,0 +1,352 @@ +#-*- perl -*- +# +# Copyright (C) 2003 Ken'ichi Fukamachi +# All rights reserved. +# +# $FML$ +# + +package FML::Article::Thread; + +use vars qw($debug @ISA @EXPORT @EXPORT_OK); +use strict; +use Carp; + +use FML::Log qw(Log LogWarn LogError); +use FML::Config; +use FML::Process::Kernel; +@ISA = qw(FML::Process::Kernel); + + +=head1 NAME + +FML::Article::Thread -- primitive thread tracking system + +=head1 SYNOPSIS + +See C<Mail::ThreadTrack> module. + +=head1 DESCRIPTION + +This class drives thread tracking system in the top level. + +=head1 METHOD + +=head2 new($curproc) + +create a C<FML::Process::Kernel> object and return it. + +=cut + + +# Descriptions: standard constructor +# Arguments: OBJ($self) OBJ($curproc) +# Side Effects: none +# Return Value: OBJ +sub new +{ + my ($self, $curproc) = @_; + my $type = ref($self) || $self; + my $me = { _curproc => $curproc }; + return bless $me, $type; +} + + +# Descriptions: return the last modified time. +# Arguments: OBJ($self) STR($seq_file) +# Side Effects: none +# Return Value: NUM +sub _last_modified_time +{ + my ($self, $seq_file) = @_; + my $sf_last_modified = 0; + + if (-f $seq_file) { + use File::stat; + my $st = stat($seq_file); + $sf_last_modified = + ($sf_last_modified > $st->mtime ? $sf_last_modified : $st->mtime); + } + + return $sf_last_modified; +} + + +# Descriptions: speculate the last id our thread system processed. +# Arguments: OBJ($curproc) OBJ($thread) +# Side Effects: none +# Return Value: NUM +sub speculate_last_id +{ + my ($self, $curproc, $thread) = @_; + my $config = $curproc->config(); + my $seq_file = $config->{ sequence_file }; + my $db_last_modified = $thread->db_last_modified(); + my $sf_last_modified = $self->_last_modified_time($seq_file); + + # The condition "$sf_last_modified < $db_last_modified" is always + # true since FML::Process::Distribute updates the thread db after + # updating $seq_file. + # XXX 3600 is the magic number. How long time is appropriate ? + if (-f $seq_file && + ($sf_last_modified + 3600 > $db_last_modified)) { + return $curproc->article_id_max(); + } + else { + my $last_id = 0; + + $thread->db_open(); + + my $rh = $thread->db_hash( 'date' ); + if (defined $rh) { + use File::Sequence; + my $obj = new File::Sequence; + $last_id = $obj->search_max_id( { hash => $rh } ); + } + + $thread->db_close(); + + return $last_id; + } +} + + +# Descriptions: speculate the maximum sequence number for ML articles. +# Arguments: OBJ($curproc) STR($spool_dir) +# Side Effects: none +# Return Value: NUM +sub speculate_max_id +{ + my ($self, $curproc, $spool_dir) = @_; + + eval q{ + use FML::Article; + push(@ISA, 'FML::Article'); + }; + my $max_id = $curproc->speculate_max_id(); + + # XXX check whether $max_id > 1 or not since + # XXX speculate_max_id() returns 1 by default + if ($max_id > 1) { + return $max_id; + } + else { + eval q{ + use FML::Article; + push(@ISA, 'FML::Article'); + $max_id = $curproc->speculate_max_id($spool_dir); + }; + warn($@) if $@; + } + + if ($max_id > 0) { + return $max_id; + } + + warn("cannot determine max_id"); + return undef; +} + + +# Descriptions: read filter list +# Arguments: OBJ($thread) STR($file) +# Side Effects: none +# Return Value: none +sub _read_filter_list +{ + my ($thread, $file) = @_; + + if (-f $file) { + use FileHandle; + my $fh = new FileHandle $file; + if (defined $fh) { + my ($key, $value, $buf); + while ($buf = <$fh>) { + chomp $buf; + ($key, $value) = split(/\s+/, $buf, 2); + if ($key) { + $thread->add_filter( { $key => $value }); + } + } + $fh->close(); + } + } +} + + +# Descriptions: change status to "closed". +# $thread_id accepts MH style format. +# MH style is expanded by C<Mail::Messsage::MH>. +# Arguments: OBJ($thread) STR($thread_id) NUM($min) NUM($max) +# Side Effects: update thread status database +# Return Value: none +sub close +{ + my ($self, $thread, $thread_id, $min, $max) = @_; + + # expand MH style variable: e.g. last:100 -> [ 100 .. 200 ] + use Mail::Message::MH; + my $ra = Mail::Message::MH->expand($thread_id, $min, $max); + $ra = [ $thread_id ] unless defined $ra; + + for my $id (@$ra) { + # e.g. 100 -> elena/100 + if ($id =~ /^\d+$/) { + $id = $thread->_create_thread_id_strings($id); + } + + # check "elena/100" exists ? + if ($thread->exist($id)) { + Log("close thread_id=$id"); + $thread->close($id); + } + else { + Log("thread_id=$id not exists") if $debug; + } + } +} + + +package FML::Article::Thread::CUI; + +use vars qw($debug @ISA @EXPORT @EXPORT_OK); +use strict; +use Carp; + + +# Descriptions: top level interface for CUI. +# This routine is in loop. +# Arguments: OBJ($curproc) HASH_REF($args) OBJ($thread) HASH_REF($ttargs) +# Side Effects: none +# Return Value: none +sub interactive +{ + my ($self, $curproc, $thread, $ttargs) = @_; + + eval q{ + use Term::ReadLine; + my $term = new Term::ReadLine "fmlthread"; + my $ml_name = $ttargs->{ ml_name }; + my $prompt = "$ml_name thread> "; + my $OUT = $term->OUT || \*STDOUT; + my $res = ''; + my $buf = ''; + + # main loop; + no strict; + while ( defined ($buf = $term->readline($prompt)) ) { + _exec($curproc, $thread, $ttargs, $buf); + warn $@ if $@; + $term->addhistory($buf) if $buf =~ /\S/o; + } + }; + carp($@) if $@; +} + + +# Descriptions: CUI command switch +# Arguments: OBJ($curproc) HASH_REF($args) +# OBJ($xthread) HASH_REF($ttargs) +# STR($buf) +# Side Effects: exit for some type of input. +# Return Value: none +sub _exec +{ + my ($self, $curproc, $xthread, $ttargs, $buf) = @_; + my ($command, @argv) = (); + + use Mail::ThreadTrack; + my $thread = new Mail::ThreadTrack $ttargs; + $thread->set_mode('text'); + + # clean up + if (defined $buf && $buf) { + $buf =~ s/^\s*//; + $buf =~ s/\s*$//; + ($command, @argv) = split(/\s+/, $buf); + } + + if ($command eq '') { + help(); + } + elsif ($command eq 'quit' || $command eq 'exit' || $command eq 'end') { + exit(0); + } + elsif ($command eq 'list') { + $thread->list(); + } + elsif ($command eq 'show') { + for my $id (@argv) { + if ($id =~ /^\d+$/) { + my $xid = $thread->_create_thread_id_strings($id); + use FileHandle; + my $wh = new FileHandle "| less"; + my $saved_fd = $thread->get_fd( $wh ); + $thread->set_fd( $wh ); + $thread->show($xid); + $thread->set_fd( $saved_fd ); + } + else { + print "sorry, cannot show $id\n"; + } + } + } + elsif ($command eq 'close') { + my $max_id = $ttargs->{ max_id }; + for my $id (@argv) { + print "close $id\n"; + &FML::Article::Thread::_close($thread, $id, 1, $max_id); + } + } + else { + help(); + } +} + + +# Descriptions: show CUI help +# Arguments: none +# Side Effects: none +# Return Value: none +sub help +{ + print "Usage: $0\n\n"; + + print "list show thread summary (without article summary)\n"; + print "show id(s) show articles in thread_id\n"; + print "close id(s) close thread specified by thread_id\n"; + print "quit to end\n"; + print "Ctl-D to end\n"; + print "\n"; + print "Typical Usage:\n"; + print " > list\n ... \n"; + print " > show 100\n"; + print " > close 100\n"; + print "\n"; +} + + +=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) 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 + +FML::Process::Kernel first appeared in fml8 mailing list driver package. +See C<http://www.fml.org/> for more details. + +=cut + + +1; diff --git a/fml/lib/FML/Command/Admin/thread.pm b/fml/lib/FML/Command/Admin/thread.pm new file mode 100644 index 00000000..27735e0d --- /dev/null +++ b/fml/lib/FML/Command/Admin/thread.pm @@ -0,0 +1,188 @@ +#-*- perl -*- +# +# Copyright (C) 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: thread.pm,v 1.2 2003/03/14 06:53:22 fukachan Exp $ +# + +package FML::Command::Admin::thread; +use strict; +use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD); +use Carp; +use FML::Log qw(Log LogWarn LogError); + + +=head1 NAME + +FML::Command::Admin::thread - show article thread or update its status. + +=head1 SYNOPSIS + +See C<FML::Command> for more details. + +=head1 DESCRIPTION + +show status article thread or manipulate it. + +=head1 METHODS + +=head2 C<process($curproc, $command_args)> + +=cut + + +# Descriptions: constructor. +# Arguments: OBJ($self) +# Side Effects: none +# Return Value: OBJ +sub new +{ + my ($self) = @_; + my ($type) = ref($self) || $self; + my $me = {}; + return bless $me, $type; +} + + +# Descriptions: need lock or not +# Arguments: none +# Side Effects: none +# Return Value: NUM( 1 or 0) +sub need_lock { 1;} + + +# Descriptions: change delivery mode from real time to digest. +# Arguments: OBJ($self) OBJ($curproc) HASH_REF($command_args) +# Side Effects: update $recipient_map +# Return Value: none +sub process +{ + my ($self, $curproc, $command_args) = @_; + my $config = $curproc->config(); + my $myname = $curproc->myname(); + + # prepare argumente for thread track module (Mail::ThreadTrack). + my $ml_name = $config->{ ml_name }; + my $thread_db_dir = $config->{ thread_db_dir }; + my $spool_dir = $config->{ spool_dir }; + my $max_id = $curproc->article_id_max(); + my $ttargs = { + myname => $myname, + logfp => \&Log, + fd => \*STDOUT, + db_base_dir => $thread_db_dir, + ml_name => $ml_name, + spool_dir => $spool_dir, + max_id => $max_id, + reverse_order => 1, + }; + + # if (defined $options->{ f }) { + # _read_filter_list($thread, $options->{ f }); + # } + + $self->_switch($curproc, $command_args, $ttargs); +} + + +# Descriptions: switch thread library command +# Arguments: OBJ($self) OBJ($curproc) HASH_REF($command_args) +# HASH_REF($ttargs) +# Side Effects: thread db may be updated +# Return Value: none +sub _switch +{ + my ($self, $curproc, $command_args, $ttargs) = @_; + my $options = $command_args->{ options }; + my $command = $options->[ 0 ] || 'list'; + my $max_id = $ttargs->{ max_id }; + + # utility functions for spool in fml side. + use FML::Article::Thread; + my $a_thread = new FML::Article::Thread $curproc; + + # functions to manipulate thread db. + use Mail::ThreadTrack; + my $thread = new Mail::ThreadTrack $ttargs; + $thread->set_mode('text'); + + if ($command eq 'list' || $command eq 'summary') { + $thread->$command(); + } + elsif ($command eq 'review') { + my $str = $options->[ 1 ] || 'last:100'; + $thread->review( $str , 1, $max_id ); + } + elsif ($command eq 'db_dump') { + my $type = $options->[ 1 ] || 'status'; + $thread->db_open(); + $thread->db_dump( $type ); + $thread->db_close(); + } + elsif ($command eq 'db_update') { + my $last_id = $a_thread->speculate_last_id($curproc, $thread); + print STDERR "db_update: $last_id -> $max_id\n"; + $thread->db_mkdb($last_id, $max_id); + } + elsif ($command eq 'db_rebuild') { + print STDERR "\$thread->db_mkdb(1, $max_id);\n"; + $thread->db_mkdb(1, $max_id); + } + elsif ($command eq 'db_clear') { + $thread->db_open(); + $thread->db_clear(); + $thread->db_close(); + } + elsif ($command eq 'close') { + my $thread_id = $options->[ 1 ]; + if (defined $thread_id) { + $a_thread->close($thread, $thread_id, 1, $max_id); + } + else { + croak("specify \$thread_id"); + } + } + elsif ($command eq 'cui') { + # XXX-TODO: hmm, run interactive session unless @ARGV ? + # XXX-TODO: showing help is appropriate ? + if ($options->[ 1 ]) { + push(@ISA, 'FML::Article::Thread::CUI'); + # $ttargs->{ ml_name } = $argv->[ 0 ]; + $a_thread->interactive($thread, $ttargs); + } + else { + help(); + } + } + else { + croak("subcommand not specified"); + } +} + + +=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) 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 + +FML::Command::Admin::thread first appeared in fml8 mailing list driver package. +See C<http://www.fml.org/> for more details. + +=cut + + +1; diff --git a/fml/lib/FML/Process/ThreadTrack.pm b/fml/lib/FML/Process/ThreadTrack.pm deleted file mode 100644 index f5be1888..00000000 --- a/fml/lib/FML/Process/ThreadTrack.pm +++ /dev/null @@ -1,562 +0,0 @@ -#-*- perl -*- -# -# Copyright (C) 2001,2002,2003 Ken'ichi Fukamachi -# All rights reserved. -# -# $FML: ThreadTrack.pm,v 1.39 2003/02/01 08:51:41 fukachan Exp $ -# - -package FML::Process::ThreadTrack; - -use vars qw($debug @ISA @EXPORT @EXPORT_OK); -use strict; -use Carp; - -use FML::Log qw(Log LogWarn LogError); -use FML::Config; -use FML::Process::Kernel; -@ISA = qw(FML::Process::Kernel); - - -=head1 NAME - -FML::Process::ThreadTrack -- primitive thread tracking system - -=head1 SYNOPSIS - -See C<Mail::ThreadTrack> module. - -=head1 DESCRIPTION - -This class drives thread tracking system in the top level. - -=head1 METHOD - -=head2 C<new($args)> - -create a C<FML::Process::Kernel> object and return it. - -=head2 C<prepare()> - -adjust ml_*, load configuration files and fix @INC. - -=cut - - -# Descriptions: standard constructor -# Arguments: OBJ($self) HASH_REF($args) -# Side Effects: none -# Return Value: OBJ -sub new -{ - my ($self, $args) = @_; - my $type = ref($self) || $self; - my $curproc = new FML::Process::Kernel $args; - return bless $curproc, $type; -} - - -# Descriptions: adjust ml_*, load configuration files and fix @INC. -# Arguments: OBJ($curproc) HASH_REF($args) -# Side Effects: none -# Return Value: none -sub prepare -{ - my ($curproc, $args) = @_; - my $config = $curproc->{ config }; - - my $eval = $config->get_hook( 'fmlthread_prepare_start_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } - - $curproc->resolve_ml_specific_variables( $args ); - $curproc->load_config_files( $args->{ cf_list } ); - $curproc->fix_perl_include_path(); - - $eval = $config->get_hook( 'fmlthread_prepare_end_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } -} - - -# Descriptions: dummy. -# Arguments: OBJ($curproc) HASH_REF($args) -# Side Effects: none. -# Return Value: none -sub verify_request -{ - my ($curproc, $args) = @_; - my $argv = $curproc->command_line_argv(); - my $config = $curproc->{ config }; - - my $eval = $config->get_hook( 'fmlthread_verify_request_start_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } - - $eval = $config->get_hook( 'fmlthread_verify_request_end_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } -} - - -=head2 C<run($args)> - -call the actual thread tracking system. - -=cut - - -# Descriptions: switch to Mail::ThreadTrack module -# Arguments: OBJ($curproc) HASH_REF($args) -# Side Effects: load module if needed -# Return Value: none -sub run -{ - my ($curproc, $args) = @_; - my $config = $curproc->{ config }; - my $myname = $curproc->myname(); - my $argv = $curproc->command_line_argv(); - my $options = $curproc->command_line_options(); - my $mydir = defined $options->{spool_dir} ? $options->{spool_dir} : ''; - my $command = $argv->[ 0 ] || ''; - - # argumente for thread track module - my $ml_name = $config->{ ml_name }; - my $thread_db_dir = $config->{ thread_db_dir }; - my $spool_dir = $mydir || $config->{ spool_dir }; - my $max_id = $curproc->_speculate_max_id($spool_dir); - my $ttargs = { - myname => $myname, - logfp => \&Log, - fd => \*STDOUT, - db_base_dir => $thread_db_dir, - ml_name => $ml_name, - spool_dir => $spool_dir, - max_id => $max_id, - reverse_order => (defined $options->{ reverse } ? 1 : 0), - }; - - my $eval = $config->get_hook( 'fmlthread_run_start_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } - - use Mail::ThreadTrack; - my $thread = new Mail::ThreadTrack $ttargs; - $thread->set_mode('text'); - - if (defined $options->{ f }) { - _read_filter_list($thread, $options->{ f }); - } - - $curproc->lock(); - - if ($command eq 'list') { - $thread->list(); - } - elsif ($command eq 'summary') { - $thread->summary(); - } - elsif ($command eq 'review') { - my $str = defined $argv->[2] ? $argv->[ 2 ] : 'last:100'; - $thread->review( $str , 1, $max_id ); - } - elsif ($command eq 'db_dump') { - my $type = defined $argv->[ 2 ] ? $argv->[ 2 ] : 'status'; - $thread->db_open(); - $thread->db_dump( $type ); - $thread->db_close(); - } - elsif ($command eq 'db_update') { - my $last_id = $curproc->_speculate_last_id($thread); - print STDERR "db_update: $last_id -> $max_id\n"; - $thread->db_mkdb($last_id, $max_id); - } - elsif ($command eq 'db_rebuild') { - print STDERR "\$thread->db_mkdb(1, $max_id);\n" if $debug; - $thread->db_mkdb(1, $max_id); - } - elsif ($command eq 'db_clear') { - $thread->db_open(); - $thread->db_clear(); - $thread->db_close(); - } - elsif ($command eq 'close') { - my $thread_id = $argv->[ 2 ]; - if (defined $thread_id) { - # XXX-TODO: method-ify. - _close($thread, $thread_id, 1, $max_id); - } - else { - croak("specify \$thread_id"); - } - } - else { - # XXX-TODO: hmm, run interactive session unless @ARGV ? - # XXX-TODO: showing help is appropriate ? - if ($argv->[ 0 ] ne '') { - push(@ISA, 'FML::Process::ThreadTrack::CUI'); - $ttargs->{ ml_name } = $argv->[ 0 ]; - $curproc->interactive($args, $thread, $ttargs); - } - else { - help(); - } - } - - $curproc->unlock(); - - $eval = $config->get_hook( 'fmlthread_run_end_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } -} - - -# Descriptions: speculate the last id our thread system processed. -# Arguments: OBJ($curproc) OBJ($thread) -# Side Effects: none -# Return Value: NUM -sub _speculate_last_id -{ - my ($curproc, $thread) = @_; - my $config = $curproc->{ config }; - my $seq_file = $config->{ sequence_file }; - my $db_last_modified = $thread->db_last_modified(); - my $sf_last_modified = 0; - - if (-f $seq_file) { - my $st = undef; - eval q{ - use File::stat; - my $st = stat($seq_file); - $sf_last_modified = - $sf_last_modified > $st->mtime ? - $sf_last_modified : - $st->mtime; - }; - } - - # The condition "$sf_last_modified < $db_last_modified" is always - # true since FML::Process::Distribute updates the thread db after - # updating $seq_file. - # XXX 3600 is the magic number. How long time is appropriate ? - if (-f $seq_file && - ($sf_last_modified + 3600 > $db_last_modified)) { - print STDERR "read seqfile\n"; sleep 3; - my $last_id = 0; - eval q{ - use File::Sequence; - my $sfh = new File::Sequence { sequence_file => $seq_file }; - $last_id = $sfh->get_id(); - }; - warn($@) if $@; - return $last_id; - } - else { - my $last_id = 0; - - $thread->db_open(); - - my $rh = $thread->db_hash( 'date' ); - if (defined $rh) { - eval q{ - use File::Sequence; - my $obj = new File::Sequence { sequence_file => $seq_file }; - $last_id = $obj->search_max_id( { hash => $rh } ); - }; - warn($@) if $@; - } - - $thread->db_close(); - - return $last_id; - } -} - - -# Descriptions: speculate the maximum sequence number for ML articles. -# Arguments: OBJ($curproc) STR($spool_dir) -# Side Effects: none -# Return Value: NUM -sub _speculate_max_id -{ - my ($curproc, $spool_dir) = @_; - my $options = $curproc->command_line_options(); - - if (defined $options->{ article_id_max }) { - return $options->{ article_id_max }; - } - else { - eval q{ - use FML::Article; - push(@ISA, 'FML::Article'); - }; - my $max_id = $curproc->speculate_max_id(); - - # XXX check whether $max_id > 1 or not since - # XXX speculate_max_id() returns 1 by default - if ($max_id > 1) { - return $max_id; - } - else { - eval q{ - use FML::Article; - push(@ISA, 'FML::Article'); - $max_id = $curproc->speculate_max_id($spool_dir); - }; - warn($@) if $@; - } - - if ($max_id > 0) { - return $max_id; - } - } - - warn("cannot determine max_id"); - return undef; -} - - -# Descriptions: read filter list -# Arguments: OBJ($thread) STR($file) -# Side Effects: none -# Return Value: none -sub _read_filter_list -{ - my ($thread, $file) = @_; - - if (-f $file) { - use FileHandle; - my $fh = new FileHandle $file; - if (defined $fh) { - my ($key, $value, $buf); - while ($buf = <$fh>) { - chomp $buf; - ($key, $value) = split(/\s+/, $buf, 2); - if ($key) { - $thread->add_filter( { $key => $value }); - } - } - $fh->close(); - } - } -} - - -# Descriptions: change status to "closed". -# $thread_id accepts MH style format. -# MH style is expanded by C<Mail::Messsage::MH>. -# Arguments: OBJ($thread) STR($thread_id) NUM($min) NUM($max) -# Side Effects: update thread status database -# Return Value: none -sub _close -{ - my ($thread, $thread_id, $min, $max) = @_; - - # expand MH style variable: e.g. last:100 -> [ 100 .. 200 ] - use Mail::Message::MH; - my $ra = Mail::Message::MH->expand($thread_id, $min, $max); - $ra = [ $thread_id ] unless defined $ra; - - for my $id (@$ra) { - # e.g. 100 -> elena/100 - if ($id =~ /^\d+$/) { - $id = $thread->_create_thread_id_strings($id); - } - - # check "elena/100" exists ? - if ($thread->exist($id)) { - Log("close thread_id=$id"); - $thread->close($id); - } - else { - Log("thread_id=$id not exists") if $debug; - } - } -} - - -# Descriptions: show help -# Arguments: none -# Side Effects: none -# Return Value: none -sub help -{ - use File::Basename; - my $name = basename($0); - -print <<"_EOF_"; - -Usage: $name \$command \$ml_name [options] - -$name list \$ml_name list up summary -$name summary \$ml_name list up summary -$name close \$ml_name id close ticket specified by id (MH style) -$name db_update \$ml_name rebuild database for latest articles -$name db_rebuild \$ml_name rebuild database for whole of ML -$name db_clear \$ml_name clear thread database for \$ml_name ML - -_EOF_ -} - - -# Descriptions: dummy. -# Arguments: OBJ($curproc) HASH_REF($args) -# Side Effects: queue flush -# Return Value: none -sub finish -{ - my ($curproc, $args) = @_; - my $config = $curproc->{ config }; - - my $eval = $config->get_hook( 'fmlthread_finish_start_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } - - $eval = $config->get_hook( 'fmlthread_finish_end_hook' ); - if ($eval) { eval qq{ $eval; }; LogWarn($@) if $@; } -} - - -# Descriptions: dummy -# Arguments: OBJ($self) HASH_REF($args) -# Side Effects: none -# Return Value: none -sub DESTROY {} - - -package FML::Process::ThreadTrack::CUI; - -use vars qw($debug @ISA @EXPORT @EXPORT_OK); -use strict; -use Carp; - - -# Descriptions: top level interface for CUI. -# This routine is in loop. -# Arguments: OBJ($curproc) HASH_REF($args) OBJ($thread) HASH_REF($ttargs) -# Side Effects: none -# Return Value: none -sub interactive -{ - my ($curproc, $args, $thread, $ttargs) = @_; - - eval q{ - use Term::ReadLine; - my $term = new Term::ReadLine "fmlthread"; - my $ml_name = $ttargs->{ ml_name }; - my $prompt = "$ml_name thread> "; - my $OUT = $term->OUT || \*STDOUT; - my $res = ''; - my $buf = ''; - - # main loop; - no strict; - while ( defined ($buf = $term->readline($prompt)) ) { - _exec($curproc, $args, $thread, $ttargs, $buf); - warn $@ if $@; - $term->addhistory($buf) if $buf =~ /\S/o; - } - }; - carp($@) if $@; -} - - -# Descriptions: CUI command switch -# Arguments: OBJ($curproc) HASH_REF($args) -# OBJ($xthread) HASH_REF($ttargs) -# STR($buf) -# Side Effects: exit for some type of input. -# Return Value: none -sub _exec -{ - my ($curproc, $args, $xthread, $ttargs, $buf) = @_; - my ($command, @argv) = (); - - use Mail::ThreadTrack; - my $thread = new Mail::ThreadTrack $ttargs; - $thread->set_mode('text'); - - # clean up - if (defined $buf && $buf) { - $buf =~ s/^\s*//; - $buf =~ s/\s*$//; - ($command, @argv) = split(/\s+/, $buf); - } - - if ($command eq '') { - help(); - } - elsif ($command eq 'quit' || $command eq 'exit' || $command eq 'end') { - exit(0); - } - elsif ($command eq 'list') { - $thread->list(); - } - elsif ($command eq 'show') { - for my $id (@argv) { - if ($id =~ /^\d+$/) { - my $xid = $thread->_create_thread_id_strings($id); - use FileHandle; - my $wh = new FileHandle "| less"; - my $saved_fd = $thread->get_fd( $wh ); - $thread->set_fd( $wh ); - $thread->show($xid); - $thread->set_fd( $saved_fd ); - } - else { - print "sorry, cannot show $id\n"; - } - } - } - elsif ($command eq 'close') { - my $max_id = $ttargs->{ max_id }; - for my $id (@argv) { - print "close $id\n"; - &FML::Process::ThreadTrack::_close($thread, $id, 1, $max_id); - } - } - else { - help(); - } -} - - -# Descriptions: show CUI help -# Arguments: none -# Side Effects: none -# Return Value: none -sub help -{ - print "Usage: $0\n\n"; - - print "list show thread summary (without article summary)\n"; - print "show id(s) show articles in thread_id\n"; - print "close id(s) close thread specified by thread_id\n"; - print "quit to end\n"; - print "Ctl-D to end\n"; - print "\n"; - print "Typical Usage:\n"; - print " > list\n ... \n"; - print " > show 100\n"; - print " > close 100\n"; - print "\n"; -} - - -=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 - -FML::Process::Kernel first appeared in fml8 mailing list driver package. -See C<http://www.fml.org/> for more details. - -=cut - - -1; |
