| 1 |
|
| 2 |
=head1 NAME
|
| 3 |
|
| 4 |
Bunshin
|
| 5 |
|
| 6 |
=cut
|
| 7 |
|
| 8 |
package Bunshin;
|
| 9 |
use strict;
|
| 10 |
use vars qw($DEBUG $MYNAME $VERSION);
|
| 11 |
$VERSION=do{my @r=(q$Revision: 1.1 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
|
| 12 |
$MYNAME = 'Bunshin';
|
| 13 |
$DEBUG = 0;
|
| 14 |
use Time::Local;
|
| 15 |
use FileHandle;
|
| 16 |
require Message::Entity;
|
| 17 |
require Message::Util;
|
| 18 |
require Message::Field::Date;
|
| 19 |
|
| 20 |
sub new ($;%) {
|
| 21 |
my $class = shift;
|
| 22 |
my $self = bless {}, $class;
|
| 23 |
$self->{fmt2str} = Message::Util::make_clone
|
| 24 |
($Message::Field::Date::DEFAULT{-fmt2str});
|
| 25 |
$self;
|
| 26 |
}
|
| 27 |
|
| 28 |
=item $b->msg_regex ($regex)
|
| 29 |
|
| 30 |
Set regex used to cut a message.
|
| 31 |
|
| 32 |
=cut
|
| 33 |
|
| 34 |
sub set_regex ($$$) {
|
| 35 |
my $self = shift;
|
| 36 |
my $name = shift;
|
| 37 |
my $regex = shift;
|
| 38 |
$regex =~ s/\x20/\\x20/g;
|
| 39 |
$regex =~ s/\x09/\\x09/g;
|
| 40 |
$regex =~ s/\x0D(?!\x0A)/\x0D\x0A/g;
|
| 41 |
$regex =~ s/(?<!\x0D)\x0A/\x0D\x0A/g;
|
| 42 |
$regex =~ s/\x0D/\\x0D/g;
|
| 43 |
$regex =~ s/\x0A/\\x0A/g;
|
| 44 |
$regex =~ s/\x23/\\x23/g;
|
| 45 |
$self->{'regex_'.$name} = $regex;
|
| 46 |
}
|
| 47 |
|
| 48 |
sub set_hook_function ($$\&) {
|
| 49 |
my $self = shift;
|
| 50 |
my $name = shift;
|
| 51 |
my $function = shift;
|
| 52 |
$self->{'hook_'.$name} = $function;
|
| 53 |
}
|
| 54 |
|
| 55 |
sub set_format ($$\&) {
|
| 56 |
my $self = shift;
|
| 57 |
my $name = shift;
|
| 58 |
my $function = shift;
|
| 59 |
$self->{fmt2str}->{$name} = $function;
|
| 60 |
}
|
| 61 |
|
| 62 |
sub set_elements ($$@) {
|
| 63 |
my $self = shift;
|
| 64 |
my $name = shift;
|
| 65 |
$self->{'elements_'.$name} = \@_;
|
| 66 |
}
|
| 67 |
|
| 68 |
sub set_source ($%) {
|
| 69 |
my $self = shift;
|
| 70 |
my %option = @_;
|
| 71 |
if (defined $option{value}) {
|
| 72 |
$self->{source} = $option{value};
|
| 73 |
} elsif ($option{uri}) {
|
| 74 |
require Message::Field::UA;
|
| 75 |
require LWP::UserAgent;
|
| 76 |
my $ua = Message::Field::UA->new;
|
| 77 |
$ua->add_our_name;
|
| 78 |
$ua->add ('libwww-perl' => $LWP::VERSION);
|
| 79 |
my $lwp = LWP::UserAgent->new;
|
| 80 |
$lwp->agent ($ua->stringify);
|
| 81 |
my $req = HTTP::Request->new (GET => $option{uri});
|
| 82 |
my $res = $lwp->request ($req);
|
| 83 |
my $c = $self->{hook_code_conversion} || \&_code_conversion;
|
| 84 |
$self->{source} = &$c ($self, $res->content, \%option);
|
| 85 |
$self->default_parameter (base_uri => $option{uri});
|
| 86 |
} elsif ($option{file}) {
|
| 87 |
my $f = new FileHandle $option{file} => 'r';
|
| 88 |
Carp::croak "set_source: $option{file}: $!" unless defined $f;
|
| 89 |
my $c = $self->{hook_code_conversion} || \&_code_conversion;
|
| 90 |
local $/ = undef;
|
| 91 |
$self->{source} = &$c ($self, $f->getline, \%option);
|
| 92 |
close SRC;
|
| 93 |
} else {
|
| 94 |
Carp::croak "set_source: $_[0]: Unsupported data source type";
|
| 95 |
}
|
| 96 |
$self->{source} =~ s/\x0D(?!\x0A)/\x0D\x0A/g;
|
| 97 |
$self->{source} =~ s/(?<!\x0D)\x0A/\x0D\x0A/g;
|
| 98 |
$self;
|
| 99 |
}
|
| 100 |
|
| 101 |
## $self->_code_conversion ($string, \%option)
|
| 102 |
sub _code_conversion ($$\%) {
|
| 103 |
$_[1];
|
| 104 |
}
|
| 105 |
|
| 106 |
sub make_msgs ($) {
|
| 107 |
my $self = shift;
|
| 108 |
my $s = $self->{source};
|
| 109 |
my $f = $self->{hook_make_msg} || \&_make_a_msg;
|
| 110 |
my @msg;
|
| 111 |
my %param = %{$self->{default_parameter}};
|
| 112 |
if ($self->{regex_metainfo} && ref $self->{elements_metainfo}) {
|
| 113 |
$s =~ s{ $self->{regex_metainfo} }{
|
| 114 |
no strict 'refs';
|
| 115 |
for my $i (0..$#{$self->{elements_metainfo}}) {
|
| 116 |
$param{$self->{elements_metainfo}->[$i]} = ${$i+1};
|
| 117 |
}
|
| 118 |
$&;
|
| 119 |
}esx;
|
| 120 |
}
|
| 121 |
$s =~ s{ $self->{regex_message} }{
|
| 122 |
no strict 'refs';
|
| 123 |
my %p = %param;
|
| 124 |
for my $i (0..$#{$self->{elements_message}}) {
|
| 125 |
$p{$self->{elements_message}->[$i]} = ${$i+1};
|
| 126 |
}
|
| 127 |
my $msg = &$f ($self, %p);
|
| 128 |
push @msg, $msg;
|
| 129 |
}gesx;
|
| 130 |
@msg;
|
| 131 |
}
|
| 132 |
|
| 133 |
## Default function for "make_msg"
|
| 134 |
sub _make_a_msg ($@) {
|
| 135 |
my $self = shift;
|
| 136 |
my %p = @_;
|
| 137 |
my $msg = new Message::Entity
|
| 138 |
-fill_date => 0,
|
| 139 |
-fill_msgid => 0,
|
| 140 |
-fill_ua_name => 'x-shimbun-agent',
|
| 141 |
-parse_all => 1,
|
| 142 |
;
|
| 143 |
my $hdr = $msg->header;
|
| 144 |
## Originator and date
|
| 145 |
my $from = $hdr->field ('from')->add ($p{from_mail});
|
| 146 |
$from->display_name ($p{from_name}) if length $p{from_name};
|
| 147 |
my $date = $hdr->field ('date');
|
| 148 |
$p{date_year} ||= (gmtime)[5];
|
| 149 |
$date->set_datetime (@p{qw/date_year date_month
|
| 150 |
date_day date_hour date_minute date_second/},
|
| 151 |
zone => $p{date_zone});
|
| 152 |
$hdr->add ('x-uri' => $p{from_uri}) if $p{from_uri};
|
| 153 |
if ($p{from_face}) {
|
| 154 |
$msg->header->field ('x-face')->value ($p{from_face});
|
| 155 |
} elsif ($p{faces}->{$p{from_mail}}) {
|
| 156 |
$msg->header->field ('x-face')->value ($p{faces}->{$p{from_mail}});
|
| 157 |
} elsif ($p{list_face}) {
|
| 158 |
$msg->header->field ('x-face')->value ($p{list_face});
|
| 159 |
}
|
| 160 |
## Message attribute
|
| 161 |
if (length $p{msg_id}) {
|
| 162 |
$hdr->add ('message-id' => $p{msg_id});
|
| 163 |
} else {
|
| 164 |
my $id_right = $p{msg_id_right} || $p{list_id};
|
| 165 |
my $c = $p{msg_count};
|
| 166 |
$c = '.d'.(0+$date) unless defined $p{msg_count};
|
| 167 |
my $mid = sprintf '<msg%s.BS%%list@%s>', $c, $id_right;
|
| 168 |
$mid = sprintf '<msg%s.BS%%%s>', $c, $p{msg_id_from} if $p{msg_id_from};
|
| 169 |
$hdr->add (($DEBUG?'x-':'').'message-id' => $mid);
|
| 170 |
}
|
| 171 |
$hdr->add (subject => $p{subject}) if length $p{subject};
|
| 172 |
my $a;
|
| 173 |
for (grep {/^misc_/} keys %p) {
|
| 174 |
$a = $hdr->field ('content-x-properties') unless ref $a;
|
| 175 |
my $name = substr ($_, 5);
|
| 176 |
$name =~ tr/_/-/;
|
| 177 |
if ($p{base_uri} && /uri/ && length $p{$_}) {
|
| 178 |
require URI::WithBase;
|
| 179 |
$a->add ($name => URI::WithBase->new ($_, $p{base_uri})->abs);
|
| 180 |
} else {
|
| 181 |
$a->add ($name => $p{$_}) if length $p{$_};
|
| 182 |
}
|
| 183 |
}
|
| 184 |
## Body and body information
|
| 185 |
my $b = $self->{hook_msg_body} || \&_make_a_msg_body;
|
| 186 |
&$b ($self, $msg, $p{body}, \%p);
|
| 187 |
## List information
|
| 188 |
if (length $p{list_id}) {
|
| 189 |
my $lid = $hdr->field ('list-id');
|
| 190 |
$lid->value ($p{list_id});
|
| 191 |
$lid->display_name ($p{list_name}) if length $p{list_name};
|
| 192 |
}
|
| 193 |
$hdr->add ('x-mail-count' => $p{msg_count}) if defined $p{msg_count};
|
| 194 |
$hdr->add ('x-ml-info' => $p{list_info}) if defined $p{list_info};
|
| 195 |
if ($p{base_uri}) {
|
| 196 |
my $uri = $hdr->add (x_uri => '');
|
| 197 |
$uri->value ($p{base_uri});
|
| 198 |
$uri->display_name ($p{list_name}) if length $p{list_name};
|
| 199 |
}
|
| 200 |
if ($p{urn_template}) {
|
| 201 |
my $urn = $self->Message::Field::Date::_date2str ({
|
| 202 |
format_template => $p{urn_template},
|
| 203 |
date_time => $date->unix_time,
|
| 204 |
zone => $date->zone,
|
| 205 |
fmt2str => $self->{fmt2str},
|
| 206 |
});
|
| 207 |
$hdr->add ('x-uri')->value ($urn);
|
| 208 |
}
|
| 209 |
## Additional information
|
| 210 |
my $u = $self->{hook_msg_header_add};
|
| 211 |
&$u ($self, $msg, \%p) if ref $u;
|
| 212 |
$hdr->field ('x-shimbun-agent')->add ($MYNAME => $VERSION);
|
| 213 |
$msg;
|
| 214 |
}
|
| 215 |
|
| 216 |
sub _make_a_msg_body ($$$\%) {
|
| 217 |
my $self = shift;
|
| 218 |
my ($msg, $body, $param) = @_;
|
| 219 |
if (length $body) {
|
| 220 |
$body =~ s/(?<!\x0D\x0A)\z/\x0D\x0A/s;
|
| 221 |
$msg->body ($body);
|
| 222 |
}
|
| 223 |
}
|
| 224 |
|
| 225 |
sub default_parameter ($@) {
|
| 226 |
my $self = shift;
|
| 227 |
if (@_ == 1) {
|
| 228 |
return $self->{default_parameter}->{ $_[0] };
|
| 229 |
}
|
| 230 |
while (my ($name, $value) = splice (@_, 0, 2)) {
|
| 231 |
$self->{default_parameter}->{$name} = $value;
|
| 232 |
}
|
| 233 |
$self;
|
| 234 |
}
|
| 235 |
|
| 236 |
=head1 LICENSE
|
| 237 |
|
| 238 |
Copyright 2002 wakaba E<lt>w@suika.fam.cxE<gt>.
|
| 239 |
|
| 240 |
This program is free software; you can redistribute it and/or modify
|
| 241 |
it under the terms of the GNU General Public License as published by
|
| 242 |
the Free Software Foundation; either version 2 of the License, or
|
| 243 |
(at your option) any later version.
|
| 244 |
|
| 245 |
This program is distributed in the hope that it will be useful,
|
| 246 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 247 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 248 |
GNU General Public License for more details.
|
| 249 |
|
| 250 |
You should have received a copy of the GNU General Public License
|
| 251 |
along with this program; see the file COPYING. If not, write to
|
| 252 |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
| 253 |
Boston, MA 02111-1307, USA.
|
| 254 |
|
| 255 |
=head1 CHANGE
|
| 256 |
|
| 257 |
See F<ChangeLog>.
|
| 258 |
$Date: 2002/03/21 04:33:44 $
|
| 259 |
|
| 260 |
=cut
|
| 261 |
|
| 262 |
1;
|