#-*- perl -*- # # Copyright (C) 2001,2002,2003,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: Subject.pm,v 1.42 2004/01/02 14:50:32 fukachan Exp $ # package FML::Header::Subject; use strict; use vars qw(@ISA @EXPORT @EXPORT_OK); use Carp; use FML::Log qw(Log LogWarn LogError); =head1 NAME FML::Header::Subject - manipulate the mail header subject =head1 SYNOPSIS use FML::Header::Subject; FML::Header::Subject->rewrite_article_subject_tag($header, $config, $args); =head1 DESCRIPTION collection of functions to manipulate the header subject. =head1 METHODS =head2 new() constructor. =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; } =head2 rewrite_article_subject_tag($header, $config, $args) add or rewrite the subject tag for C<$header>. This mothod cuts off Re: (reply identifier) in subject: and replace the subject with the newer content e.g. including the ML tag. =cut # Descriptions: add or rewrite the subject tag. # Arguments: OBJ($self) OBJ($header) OBJ($config) HASH_REF($rw_args) # Side Effects: the header subject is rewritten # Return Value: none sub rewrite_article_subject_tag { my ($self, $header, $config, $rw_args) = @_; my ($in_code, $out_code); # XXX-TODO: need $article_subject_tag expaned already e.g. "\Lmlname\E" # XXX-TODO: we should include this exapansion method within this module? my $tag = $config->{ article_subject_tag }; my $subject = $header->get('subject'); # decode MIME encoded string and get charset info if could. ($subject, $tag, $in_code, $out_code) = $self->decode($subject, $tag); # cut off Re: Re: Re: ... $self->_cut_off_reply(\$subject); # XXX-TODO: method-ify _delete_subject_tag() ? # de-tag $subject = _delete_subject_tag( $subject, $tag ); # cut off Re: Re: Re: ... $self->_cut_off_reply(\$subject); use Mail::Message::Encode; my $obj = new Mail::Message::Encode; # add(prepend) the rewrited tag with mime encoding. $tag = sprintf($tag, $rw_args->{ id }); my $new_subject = $tag." ".$subject; $new_subject = $obj->encode_mime_string($new_subject, 'base64', $in_code); $header->replace('Subject', $new_subject); } # Descriptions: delete subject tag. # Arguments: OBJ($self) STR($subject) STR($tag) # Side Effects: none # Return Value: STR sub clean_up { my ($self, $subject, $tag) = @_; my ($s, $in_code, $out_code) = $self->decode($subject, $tag); return $self->delete_subject_tag($s, $tag); } # Descriptions: exapnd special regexp(s) and mime-decode subject. # Arguments: OBJ($self) STR($subject) STR($tag) # Side Effects: none # Return Value: ARRAY(STR, STR, STR, STR) sub decode { my ($self, $subject, $tag) = @_; my ($in_code, $out_code) = (); # for example, ml_name = elena # if $tag has special regexp such as \U$ml_name\E or \L$ml_name\E if (defined $tag) { if ($tag =~ /\\E/o && $tag =~ /\\U|\\L/o) { eval qq{ \$tag = "$tag";}; Log($@) if $@; } } # XXX-TODO: care for not Japanese ! if ($subject =~ /=\?iso-2022-jp\?/i) { $in_code = 'jis-jp'; $out_code = 'euc-jp'; } else { $in_code = $out_code = ''; } # decode mime use Mail::Message::Encode; my $obj = new Mail::Message::Encode; $subject = $obj->decode_mime_string($subject , $out_code); return ($subject, $tag, $in_code, $out_code); } # Descriptions: delete subject tag # Arguments: OBJ($self) STR($subject) STR($tag) # Side Effects: none # Return Value: STR sub delete_subject_tag { my ($self, $subject, $tag) = @_; # XXX-TODO: method-fy ? return _delete_subject_tag($subject, $tag); } # Descriptions: remove tag-like string # Arguments: STR($subject) STR($tag) # XXX non OO type function # Side Effects: none # Return Value: STR(subject string) sub _delete_subject_tag { my ($subject, $tag) = @_; my $retag = _regexp_compile($tag); $subject =~ s/$retag//g; $subject =~ s/^\s*//; return $subject; } =head2 regexp_compile($string) build a regular expression to trap C<$string>. =cut # Descriptions: wrapper for _regexp_compile # Arguments: OBJ($self) STR($string) # Side Effects: none # Return Value: STR(regular expression) sub regexp_compile { my ($self, $string) = @_; _regexp_compile($string); } # Descriptions: create regexp for a subject tag, for example # "[%s %05d]" => "\[\S+ \d+\]" # not OO style. # Arguments: STR($s) # $s == a subject tag string # Side Effects: none # Return Value: STR(a regexp for the given tag) sub _regexp_compile { my ($s) = @_; if (defined $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; } else { return ''; } } =head2 is_reply($subject_string) speculate C<$subject_string> looks a reply message or not? It depends on each language specific representations. Now we can trap Japanese specific keywords. =cut # Descriptions: speculate $subject looks a reply message or not? # Arguments: OBJ($self) STR($subject) # Side Effects: none # Return Value: 1 (looks reply message) or 0 sub is_reply { my ($self, $subject) = @_; return 1 if $subject =~ /^\s*Re:/i; # XXX-TODO: care for not Japanese string! # XXX-TODO: method-ify ? my $pkg = 'Mail::Message::Language::Japanese::Subject'; eval qq{ require $pkg; $pkg->import();}; unless ($@) { return 1 if &Mail::Message::Language::Japanese::Subject::is_reply($subject); }; return 0; } # Descriptions: cut off reply keywords like "Re:". # Arguments: OBJ($self) STR_REF($r_subject) # $r_subject is SCALAR REREFENCE to the subject string # Side Effects: $r_subject is rewritten # Return Value: none sub _cut_off_reply { my ($self, $r_subject) = @_; # XXX-TODO: care for not Japanese string! my $pkg = 'Mail::Message::Language::Japanese::Subject'; eval qq{ require $pkg; $pkg->import();}; unless ($@) { my $obj = new Mail::Message::Language::Japanese::Subject; $$r_subject = $obj->cut_off_reply_tag($$r_subject); } else { Log($@); } } =head1 CODING STYLE See C on fml coding style guide. =head1 AUTHOR Ken'ichi Fukamachi =head1 COPYRIGHT Copyright (C) 2001,2002,2003,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 FML::Header::Subject first appeared in fml8 mailing list driver package. See C for more details. =cut 1;