/[suikacvs]/messaging/bunshin/Bunshin.pm
Suika

Contents of /messaging/bunshin/Bunshin.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (show annotations) (download)
Thu Aug 29 12:10:59 2002 UTC (22 years, 2 months ago) by wakaba
Branch: MAIN
Changes since 1.4: +18 -9 lines
2002-08-29  Wakaba <w@suika.fam.cx>

	* Bunshin.pm:
	- (make_msgs): Prepend '#' to misc_.*color.* property
	value if desirable.  (There are HTML documents with
	color name of 'HHHHHH' without '#':-<)
	- Update Message::Field::Date interface with its latest
	revision.

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

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24