#-*- perl -*-
#
# Copyright (C) 2002,2003,2004,2005 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: Digest.pm,v 1.22 2005/08/11 04:11:26 fukachan Exp $
#
package FML::Digest;
use strict;
use vars qw(@ISA @EXPORT @EXPORT_OK $AUTOLOAD);
use Carp;
#
# XXX-TODO: Currently, fml 8 digest has no granuality like fml 4.
#
=head1 NAME
FML::Digest - create digest, a subset of articles.
=head1 SYNOPSIS
=head1 DESCRIPTION
=head1 METHODS
=head2 new()
constructor.
=cut
# Descriptions: constructor.
# Arguments: OBJ($self) OBJ($curproc)
# Side Effects: $self->{ _curproc } = $curproc;
# Return Value: OBJ
sub new
{
my ($self, $curproc) = @_;
my ($type) = ref($self) || $self;
my $me = { _curproc => $curproc };
return bless $me, $type;
}
# Descriptions: get lock channel name.
# Arguments: OBJ($self)
# Side Effects: none
# Return Value: STR
sub get_lock_channel_name
{
my ($self) = @_;
# XXX_LOCK_CHANNEL: digest_sequence
return 'digest_sequence';
}
=head1 GIANT LOCK VERSION of DIGEST
=head2 id()
same as get_digest_id().
=head2 get_digest_id()
return the last article id sent back as digest.
=head2 set_digest_id()
set the last article id sent back as digest.
=cut
# Descriptions: return the last article id sent back as digest.
# Arguments: OBJ($self)
# Side Effects: none
# Return Value: NUM
sub id
{
my ($self) = @_;
$self->get_digest_id();
}
# Descriptions: return the last article id sent back as digest.
# Arguments: OBJ($self)
# Side Effects: none
# Return Value: NUM
sub get_digest_id
{
my ($self) = @_;
my $curproc = $self->{ _curproc };
my $config = $curproc->config();
my $seq_file = $config->{ digest_sequence_file };
return $self->_get_id($seq_file);
}
# Descriptions: return the last article id sent back as digest
# Arguments: OBJ($self)
# Side Effects: none
# Return Value: NUM
sub get_article_id
{
my ($self) = @_;
my $curproc = $self->{ _curproc };
return $curproc->article_get_max_id();
}
# Descriptions: return the last sequence id sent back as digest.
# Arguments: OBJ($self) STR($seq_file)
# Side Effects: none
# Return Value: NUM
sub _get_id
{
my ($self, $seq_file) = @_;
my $curproc = $self->{ _curproc };
my $channel = $self->get_lock_channel_name();
my $id = 1; # XXX return default value if something fails.
$curproc->lock($channel);
if (-f $seq_file) {
my $map = sprintf("file:%s", $seq_file);
use FML::Article::Sequence;
my $seq = new FML::Article::Sequence $curproc;
$id = $seq->get_number_from_map($map) || 0;
}
$curproc->unlock($channel);
# XXX return default value if something fails.
return $id;
}
# Descriptions: set digest id.
# Arguments: OBJ($self) NUM($id)
# Side Effects: none
# Return Value: NUM
sub set_digest_id
{
my ($self, $id) = @_;
my $curproc = $self->{ _curproc };
my $config = $curproc->config();
my $seq_file = $config->{ digest_sequence_file };
my $map = sprintf("file:%s", $seq_file);
my $channel = $self->get_lock_channel_name();
$curproc->lock($channel);
use IO::Adapter;
my $io = new IO::Adapter $map;
$io->sequence_replace($id);
if ($io->error()) {
$curproc->logerror( $io->error() );
}
$curproc->unlock($channel);
return $id;
}
# Descriptions: insert articles sent as digest into reply message queue.
# Arguments: OBJ($self) HASH_REF($optargs)
# Side Effects: update reply messages chain on memory
# Return Value: none
sub create_multipart_message
{
my ($self, $optargs) = @_;
my $range = $optargs->{ range };
my $curproc = $self->{ _curproc };
my $config = $curproc->config();
my $ml_name = $config->{ ml_name };
my $ml_addr = $config->{ article_post_address };
my $seq_file = $config->{ digest_sequence_file };
my $rcptmaps = $config->get_as_array_ref('digest_recipient_maps');
my $count_ok = 0;
my $count_err = 0;
# XXX-TODO: subject should be configurable.
my $msgopts = {
recipient_maps => $rcptmaps,
header => {
'subject' => "$ml_name ML digest $range",
'to' => $ml_addr,
'reply-to' => $ml_addr,
}
};
$curproc->log("send back articles range=$range");
my $filelist = $self->_expand_range($range);
for my $filename (@$filelist) {
use FML::Article;
my $article = new FML::Article $curproc;
my $filepath = $article->filepath($filename);
if (-f $filepath) {
# XXX-TODO: disposition should be configurable.
$curproc->reply_message( {
type => "message/rfc822",
path => $filepath,
filename => $filename,
disposition => "$ml_name ML article $filename",
}, $msgopts);
$count_ok++;
}
else {
$curproc->logerror("no such file: $filepath");
$count_err++;
}
}
$curproc->log("eat articles ok=$count_ok error=$count_err");
}
# Descriptions: eat "10-20", return file list as \( 10 11 ... 20 ).
# Arguments: OBJ($self) STR($fn)
# Side Effects: none
# Return Value: ARRAY_REF
sub _expand_range
{
my ($self, $fn) = @_;
use Mail::Message::MH;
my $mh = new Mail::Message::MH;
if ($fn =~ /(\d+)\-(\d+)/) {
return $mh->expand($fn, 1, $2);
}
else {
return [];
}
}
#
# debug
#
if ($0 eq __FILE__) {
my $obj = new FML::Digest;
for (@ARGV) {
my $ra = $obj->_expand_range($_);
print join(" ", @$ra), "\n";
}
}
=head1 CODING STYLE
See C on fml coding style guide.
=head1 AUTHOR
Ken'ichi Fukamachi
=head1 COPYRIGHT
Copyright (C) 2002,2003,2004,2005 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::Digest appeared in fml8 mailing list driver package.
See C for more details.
=cut
1;