#!/usr/bin/perl
# jsRSS++ jsRSS.cgi 3.15
#
# Copyright(C) 2004-2005 by 大黒屋
# http://www.daikoku-ya.org/
# webmaster@daikoku-ya.org
# Jcode がサーバにインストールされている場合は use lib './'; をコメントアウト
# インストールされていない場合は Jcode.pm のあるディレクトリを use lib './lib'; で指定(ディレクトリ名は任意)
#use lib './lib';
use Jcode;
use Socket;
my $dir_feed = 'feed'; # RSSデータを保存するディレクトリ
my $check = 60; # 更新間隔(分)
my $TimeZone = +9; # 設置するサーバのタイムゾーン
my $dir_temp = 'temp'; # RSS表示用テンプレートのあるディレクトリ
my $def_temp = 'jsRSS.tmp'; # デフォルトのテンプテート
my $CDATA = 'cut'; # タグを削除する場合は 'cut'
my $HTMLTAG = 'cut'; # html のタグを削除する場合は 'cut'、無効化は 'off' に
my @callfrom = ( # 呼び出しを許可するサーバ名を '〜','〜',と列挙する
'http://www.daikoku-ya.org/',
'http://127.0.0.1/',
);
my $CR = 'no'; # 下部のスクリプト名(+リンク)の表示
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
my $VER = 3.15;
my %utf8 = (
'jis' => 'ISO-2022-JP',
'sjis' => 'Shift_JIS',
'euc' => 'EUC-JP',
'utf8' => 'UTF-8'
);
my $SCRIPT = $ENV{SCRIPT_NAME};
my $ROOT = $ENV{DOCUMENT_ROOT};
my $SERVER = $ENV{SERVER_NAME};
my %q = ();
my $str = $ENV{QUERY_STRING};
my @str = split(/::/,$str);
for(@str)
{
my($nam,$val) = split(/=/,$_,2);
$nam =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("H2",$1)/eg;
$val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("H2",$1)/eg;
$q{$nam} = $val;
}
my $line = $q{line} || 5;
my $enc = $q{enc} || 'euc';
my $temp = $q{temp} || $def_temp;
my $len = ($q{len} > 0) ? $q{len} * 2 : '';
my $tlen = ($q{tlen} > 0) ? $q{tlen} * 2 : '';
my $url = $q{url};
my %RSS = ();
my $RSS = '';
my @data = ();
my %site = ();
(my $cache = $url) =~ s|\?|_|;
$cache =~ s|http://||;
$cache =~ s|\.||g;
$cache =~ s|/||g;
$cache = "$dir_feed/$cache" . '.dat';
if((grep /$SERVER/,@callfrom) == 0)
{ $RSS = qq(
Bad Call!!
) }
elsif(length($url) == 0)
{ $RSS = qq(RSSのurlを指定してください
) }
elsif(!(-e "$dir_temp/$temp"))
{ $RSS = qq(テンプレートファイルがありません
) }
elsif(!(-e $cache))
{
my $tmp = &sock('GET','');
my $rdf = ${$tmp};
my $status = (split(/\r\n/,$rdf))[0];
if($status =~ /404/)
{ $RSS = qq(指定されたurlのファイルは存在しません
) }
elsif($status =~ /403/)
{ $RSS = qq(指定されたurlにはアクセス出来ません
) }
elsif($status =~ /401/)
{ $RSS = qq(指定されたurlにはアクセス認証が必要です
) }
elsif($status =~ /500/ || $status !~ /200/)
{ $RSS = qq(指定されたurlでサーバエラーが起きました
) }
else
{
my($site,$data) = &parse_rdf($rdf);
%site = %{$site};
@data = @{$data};
&save_cache(\@data);
}
}
else
{
my %mod_time = ();
my $now = (time);
my $checktime = 60 * $check;
$mod{cache} = (stat $cache)[9];
$mod{check} = $mod{cache} + $checktime;
$mod{jst} = localtime($mod{cache});
$mod{gmt} = gmtime($mod{cache});
$mod{check_gmt} = gmtime($mod{cache} - (60 * 60 * $TimeZone) + $checktime);
if($now > $mod{check})
{
my $tmp = &sock('HEAD',$mod{check_gmt});
my $head = ${$tmp};
my $status = (split(/\r\n/,$head))[0];
if($status !~ /304/)
{
my $tmp = &sock('GET','');
my $rdf = ${$tmp};
my($site,$data) = &parse_rdf(${$tmp});
%site = %{$site};
@data = @{$data};
&save_cache(\@data);
}
else
{
my $tmp = &read_cache;
@data = @{$tmp};
}
}
else
{
my $tmp = &read_cache;
@data = @{$tmp};$a += 4;
}
}
if($RSS eq '')
{
chomp @data;
local $/ = undef;
open(IN,"<$dir_temp/$temp") or die "$!";
my $TEMP = ;
close(IN);
$TEMP = Jcode -> new(\$TEMP) -> $enc if($enc ne 'euc');
$TEMP =~ s/\r\n/\n/g;
$TEMP =~ s/\r/\n/g;
eval($TEMP);
my($ver,$title,$link,$dsc,$cre,$day) = split(/\t/,$data[0]);
for('header','footer')
{
$RSS{$_} =~ s/#Version#/$ver/g;
$RSS{$_} =~ s/#SiteTitle#/$title/g;
$RSS{$_} =~ s/#SiteLink#/$link/g;
$RSS{$_} =~ s/#SiteDescription#/$dsc/g;
$RSS{$_} =~ s/#SiteCreator#/$cre/g;
$RSS{$_} =~ s/#SiteDate#/$day/g;
}
$RSS .= $RSS{header};
my($y,$m,$d,$H,$M,$S) = (localtime(time - 60 * 60 * $new_entry))[5,4,3,2,1,0];
my $new_check = sprintf("%04d%02d%02d%02d%02d%02d",$y +1900,$m +1,$d,$H,$M,$S);
for(1..$line)
{
last if(length($data[$_]) < 1);
my $repeat = $RSS{repeat};
my($dat,$ttl,$lnk,$sbj,$cre,$dsc) = split(/\t/,$data[$_]);
if($CDATA eq 'cut')
{
$dsc =~ s|<\!\[CDATA\[||gs;
$dsc =~ s|\]\]>||gs;
}
if($HTMLTAG eq 'cut')
{
$dsc =~ s/<[^>]*>//g;
$ttl =~ s/<[^>]*>//g;
}
elsif($HTMLTAG eq 'off')
{
$dsc =~ s/&/&/g ;
$dsc =~ s/</g ;
$dsc =~ s/>/>/g ;
$ttl =~ s/&/&/g ;
$ttl =~ s/</g ;
$ttl =~ s/>/>/g ;
}
if($len != 0)
{
my @dsc = jcode($dsc) -> jfold($len);
$dsc = $dsc[0];
}
if($tlen != 0)
{
my @ttl = jcode($ttl) -> jfold($tlen);
$ttl = $ttl[0];
}
my $ts = '';
if($dat ne '')
{
my $yyyy = substr($dat,0,4);
my $mm = substr($dat,4,2);
my $dd = substr($dat,6,2);
my $HH = substr($dat,8,2);
my $MM = substr($dat,10,2);
my $SS = substr($dat,12,2);
$ts = $time_format;
$ts =~ s/y/$yyyy/;
$ts =~ s/m/$mm/;
$ts =~ s/d/$dd/;
$ts =~ s/H/$HH/;
$ts =~ s/M/$MM/;
$ts =~ s/S/$SS/;
}
my $whatsnew = ($new_check <= $dat) ? $new_mark : '';
my $wnfront = ($new_check <= $dat) ? $whatsnew_front : '';
my $wnback = ($new_check <= $dat) ? $whatsnew_back : '';
$repeat =~ s/#TimeStamp#/$ts/g;
$repeat =~ s/#WhatsNew#/$whatsnew/g;
$repeat =~ s/#WhatsNewFront#/$wnfront/g;
$repeat =~ s/#WhatsNewBack#/$wnback/g;
$repeat =~ s/#Title#/$ttl/g;
$repeat =~ s/#Link#/$lnk/g;
$repeat =~ s/#Subject#/$sbj/g;
$repeat =~ s/#Creator#/$cre/g;
$repeat =~ s/#Description#/$dsc/g;
$RSS .= $repeat;
}
$RSS .= $RSS{footer};
$RSS .= qq(\n) if($CR ne 'no');
}
$RSS = Jcode -> new(\$RSS) -> $enc if($enc ne 'euc');
@RSS = split(/\n/,$RSS);
for(@RSS) { $_ = "'$_',\n" }
$RSS = join("",@RSS) . "''";
print <<_SRC;
Content-Type: text/html; charset=$enc{enc}
document.write($RSS);
_SRC
exit;
sub parse_rdf
{
my $rdf = shift;
my @data = ();
my %site = ();
$rdf = (getcode($rdf) eq 'euc') ? $rdf : Jcode -> new(\$rdf) -> euc;
$rdf =~ s|\t||g;
my $ent = 'item';
my $dsc = 'description';
my $cre = 'creator';
my $day = 'date';
if ($rdf =~ m|/atom/| && $rdf =~ m|(?:version="(.+?)".*>)|is) { $site{VER} = 'atom' . $1; $ent = 'entry'; }
elsif($rdf =~ m|<.*rss.*version="(.+?)"|is) { $site{VER} = 'rss' . $1; }
elsif($rdf =~ m|<.*feed.*version="(.+?)"|is) { $site{VER} = 'rss' . $1; }
elsif($rdf =~ m|xmlns.*?/purl.org/rss/(.*?)/|is) { $site{VER} = 'rss' . $1; }
if($rdf =~ m|encoding="(.+?)"|is) { $site{ENC} = $1; }
my($HEAD,$BODY) = split(/$ent/,$rdf,2);
$HEAD =~ s|\r\n|\n|g;
$HEAD =~ s|\r|\n|g;
$HEAD =~ s|\n||g;
$BODY = "<$ent" . $BODY;
if ($HEAD =~ m|(?:(.*?))|is) { $site{TITLE} = $1 }
if ($HEAD =~ m|(?:(.+?))|is) { $site{LINK} = $1 }
elsif($HEAD =~ m|(?:)|is) { $site{LINK} = $1 }
if ($HEAD =~ m|(?:(.+?))|is) { $site{DSC} = $1 }
elsif($HEAD =~ m|(?:(.+?))|is) { $site{DSC} = $1 }
if ($HEAD =~ m|(?:<.*?creator>(.+?))|is) { $site{CRE} = $1 }
elsif($HEAD =~ m|(?:<.*?webMaster>(.+?))|is) { $site{CRE} = $1 }
elsif($HEAD =~ m|(?:<.*?copyright>(.+?))|is) { $site{CRE} = $1 }
if ($HEAD =~ m|(?:<.*date>(.+?))|is) { $site{DAY} = $1 }
elsif($HEAD =~ m|(?:<.*modified>(.+?))|is) { $site{DAY} = $1 }
for(keys %site)
{
$site{$_} =~ s/'/'/g; #'
$site{$_} =~ s/"/"/g; #"
}
push @data,join("\t",$site{VER},$site{TITLE},$site{LINK},$site{DSC},$site{CRE},$site{DAY}) . "\n";
$BODY =~ s|.*||is;
my @ENTRY = ($BODY =~ m!<$ent.*?>(.*?)$ent>!isg);
for(@ENTRY)
{
my %entry = ();
$_ =~ s|\r\n|\n|g;
$_ =~ s|\r|\n|g;
$_ =~ s|\n|
|g;
if ($_ =~ m|(?:(.*?))|is) { $entry{title} = $1 }
if ($_ =~ m|(?:(.+?))|is) { $entry{link} = $1 }
elsif($_ =~ m|(?:.*?)|is) { $entry{link} = $1 }
if ($_ =~ m|(?:(.+?))|is) { $entry{description} = $1 }
elsif($_ =~ m|(?:(.+?))|is) { $entry{description} = $1 }
elsif($_ =~ m|(?:(.+?))|is){ $entry{description} = $1 }
if ($_ =~ m|(?:<.*subject.*?>(.+?))|is) { $entry{subject} = $1 }
if ($_ =~ m|(?:<.*creator.*?>(.+?))|is) { $entry{creator} = $1 }
elsif($_ =~ m|(?:.*(.+?).*)|is) { $entry{creator} = $1 }
if ($_ =~ m|(?:<.*date.*?>(.+?))|is) { $entry{date} = $date = $1 }
elsif($_ =~ m|(?:<.*issued.*?>(.+?))|is) { $entry{date} = $date = $1 }
if($entry{date} =~ m!(\d+).(\w+).(\d{4}).(\d+):(\d+):(\d+)!) #Y!
{
my %MON = ('Jan' => 1,'Feb' => 2,'Mar' => 3,'Apr' => 4,'May' => 5,'Jun' => 6,'Jul' => 7,'Aug' => 8,'Sep' => 9,'Oct' => 10,'Nov' => 11,'Dec' => 12);
$entry{date} = sprintf("%04d%02d%02d%02d%02d%02d",$3,$MON{$2},$1,$4,$5,$6);
}
else
{
$entry{date} =~ s![+|-]\d\d:\d\d!!;
$entry{date} =~ s![-|:|T]!!g;
}
while(length($entry{date}) < 14 && length($entry{date}) > 1) { $entry{date} .= '0' }
my $new_data = join("\t",$entry{date},$entry{title},$entry{link},$entry{subject},$entry{creator},$entry{description}) ."\n";
$new_data =~ s/'/'/g; #'
$new_data =~ s/"/"/g; #"
push @data,$new_data;
}
return \%site,\@data;
}
sub read_cache
{
open(IN,"<$cache") or die "$!";
my @data = ;
close(IN);
return \@data;
}
sub save_cache
{
my @data = @{$_[0]};
open(OUT,">$cache") or die "$! :: ";
print OUT @data;
close(OUT);
}
sub sock
{
my($method,$last_mod) = @_;
my $rss = '';
my $URL = $url;
$URL =~ m|http://([^:/]*)(:(\d+))?(/.*)?|;
$host = $1;
($port = $3) || ($port = 80);
($path = $4) || ($path = '/');
$ipaddr = inet_aton($host);
socket(SOCK,PF_INET,SOCK_STREAM,getprotobyname('tcp')) or die "$!";
connect(SOCK,sockaddr_in($port,$ipaddr)) or die "Cannot Connect to $host:\n$!";
select(SOCK); $| = 1;
select(STDOUT);
$request = "$method $path HTTP/1.0\r\n";
$request .= "Host: $host\r\n";
$request .= "User-Agent: jsRSS++/$VER (http://www.daikoku-ya.org/)\r\n";
$request .= "If-Modified-Since: $last_mod\r\n" if($method eq 'HEAD');
$request .= "\r\n";
print SOCK $request;
while() { $rss .= $_ }
close(SOCK);
return \$rss;
}