#!/usr/bin/perl

#     jsRSS++  jsRSS.cgi 1.0
#
#  Copyright(C) 2004 by 大黒屋
#   http://www.daikoku-ya.org/
#    webmaster@daikoku-ya.org

use CGI::Carp qw(fatalsToBrowser);
use Socket;

# Jcode.pm がサーバにインストースされている場合は use Jcode; を使用
# インストールされていない場合(あとからpmファイルを置いた場合など)は require ' パス /Jcode.pm'; を使用
use Jcode;
# require './lib/Jcode.pm';

my $dir   = 'rssdata'; # RSSデータを保存するディレクトリ
my $check = 5;     # 更新間隔(分)
my $acchk = '';    # 外部サーバからのアクセスを許可する場合は空欄に

my $time_format = "[ y/m/d H:M:S ]"; # 日時の表示形式

my $class_site   = 'RSSsite';     # リスト表示時のサイト名のclass
my $class_line   = 'RSSline';     # リスト表示時の１エントリーのブロックのclass (div)
my $class_title  = 'RSStitle';    # リスト表示時のエントリー名のclass (span)
my $class_dsc    = 'RSSdescript'; # リスト表示時の概要のclass (span)
my $class_time   = 'RSStime';     # リスト表示時の日時のclass (span)
my $class_select = 'RSSselect';   # ポップアップ表示時のclass (select)
my $class_option = 'RSSoption';   # ポップアップ表示時のclass (option)

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 

my %enc = (
'jis'  => 'ISO-2022-JP',
'sjis' => 'Shift_JIS',
'euc'  => 'EUC-JP',
'utf8' => 'UTF-8'
);

my $REFF = $ENV{HTTP_REFERER};
my $ROOT = $ENV{DOCUMENT_ROOT};
my $SERVER = $ENV{SERVER_NAME};
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;
  $$nam = $val;
  }

$mode ||= 'list';
$line ||= 5;
$enc  ||= 'euc';
$dsc  ||= 'off';

if(length($acchk) == 1 && $REFF !~ /$SERVER/)
  { $RSS = qq(<div class="$class_site">Bad Call!!</div>) }
elsif(length($url) == 0)
  { $RSS = qq(<div class="$class_site">urlを指定してください</div>) }
else
  {
  my @RDF = &read_rdf($url);
  &parse_rdf(\@RDF);
  &set_mode;
  $RSS = $head . $list;
  $RSS .= "</select>\n</form>\n" if($mode eq 'popup');
  }

&Jcode::convert(\$RSS,$enc);
@RSS = split(/\n/,$RSS);
for(@RSS) { $_ = "'$_',\n" }
$RSS = join("",@RSS);

print <<_SRC;
Content-Type: text/html

document.write(
$RSS''
);
_SRC

exit;

sub read_rdf
{
my $file = my $url = shift;
$file =~ s|http://||;
$file =~ s|\.||g;
$file =~ s|/||g;
$file = "$dir/$file";

my $now = (time);
my $checktime = 60 * $check;
my $last_mod = (stat $file)[9] + $check;

if($url =~ /$SERVER/)
  {
  $url =~ s|http://$SERVER||;
  open(IN,"$ROOT$url") or die "$!";
  @RDF = <IN>;
  close(IN);
  }
elsif(-e $file && ($last_mod + $check) > $now) 
  {
  open(IN,$file) or die "$!";
  @RDF = <IN>;
  close(IN);
  }
else
  {
  @RDF = &sock($url);
  open(OUT,">$file") or die "$!";
  print OUT @RDF;
  close(OUT);  
  }
return @RDF;
}

sub parse_rdf
{
my $rdf = shift;
my @RDF = @{$rdf};
my $cnt  = 1;
my $site_flag = my $articl = 0;
for(@RDF)
  {
  if   ($_ =~ /<channel/i) { $site_flag = 1 }
  elsif($_ =~ /<feed/i)    { $site_flag = 1 }
  if($_ =~ /<\/channel>/i) { $site_flag = 0 ; $site_num += 1; }
  if($_ =~ /<item/i)       { $site_flag = 0 ; $site_num += 1; }
  if($site_flag == 1 && $articl == 0)
    {
    if($_ =~ /<title>(.*)<\/title>/is)        { $site{title} = $1 }
    if($_ =~ /<link>(.*)<\/link>/is)          { $site{link} = $1  }
    elsif($_ =~ /<link(.*)href="(.*)"(.*)>/i) { $site{link} = $2  }
    }

  if   ($_ =~ /<item/i && $_ !~ /<items/i)    { $articl = 1 }
  elsif($_ =~ /<entry/i)                      { $articl = 1 }

  if   ($_ =~ /<\/item>/i)    { $articl = 0 ; $cnt += 1; }
  elsif($_ =~ /<\/entry>/i)   { $articl = 0 ; $cnt += 1; }

  next if($line < $cnt);
  if($articl == 1)
    {
    if($_ =~ /<title>(.*)<\/title>/i)                   { $site[$cnt]{title} = $1 }
    if   ($_ =~ /<link>(.*)<\/link>/i)                  { $site[$cnt]{link} = $1  }
    elsif($_ =~ /<link(.*)href="(.*)"(.*)>/i)           { $site[$cnt]{link} = $2  }

    if   ($_ =~ /<description>(.*)<\/description>/i)    { $site[$cnt]{description} = $1 }
    elsif($_ =~ /<summary(.*)>(.*)<\/summary>/i) { $site[$cnt]{description} = $2 }
    elsif($_ =~ /<description>(.*)/)                    { $site[$cnt]{description} = $1; $dsc = 1; }
    elsif($_ =~ /(.*)<\/description>/i)                 { $site[$cnt]{description} = $1; $dsc = 0; }
    elsif($dsc == 1)                                    { $site[$cnt]{description} = $_ }

    $site[$cnt]{description} =~ s/<\!\[CDATA\[(.*)/$1/i;
    $site[$cnt]{description} =~ s/(.*)\]\]>/$1/i;

    if($_ =~ /<(.*)subject>(.*)<\/dc:subject>/i)    { $site[$cnt]{subject} = $2 }
    if($_ =~ /<(.*)creator>(.*)<\/dc:creator>/i)    { $site[$cnt]{creator} = $2 }
    if   ($_ =~ /<(.*)date>(.*)<\/dc:date>/i)       { $site[$cnt]{date} = $date = $2 }
    elsif($_ =~ /<issued>(.*)<\/issued>/i)          { $site[$cnt]{date} = $date = $1 }
    }
  }
@{$rdf} = @RDF;
}

sub set_mode
{
&$mode;

for(1..$line)
  {
  last unless($site[$_]{link} && $site[$_]{title});
  $site{link} =~ s/'/&rsquo;/g;
  $site{link} =~ s/"/&quot;/g;
  $site{title} =~ s/'/&rsquo;/g;
  $site{title} =~ s/"/&quot;/g; #"

  my $ts = '';
  if($site[$_]{date} ne '')
    {
    my $ymd = substr($site[$_]{date},0,10); 
    my $hms = substr($site[$_]{date},11,8);
    my($yyyy,$mm,$dd) = split(/-/,$ymd);
    my($HH,$MM,$SS) = split(/:/,$hms);

    $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/;
    }

  if($mode eq 'popup')
    {
    $list .= qq(<option value="$site[$_]{link}" class="$class_option">);
    $list .= $ts if($dt eq 'f');
    $list .= $site[$_]{title};
    $list .= $ts if($dt eq 'b');
    $list .= qq(</option>\n);
    }
  else
    {
    $list .= qq(<div class="$class_line">\n);
    $list .= qq(<span class="$class_time">$ts</span>\n) if($dt eq 'f');
    $list .= qq(<span class="$class_title"><a href="$site[$_]{link}" target="_blank">$site[$_]{title}</a></span>\n);
    $list .= qq(<br /><span class="$class_time">$ts</span>\n) if($dt eq 'b');
    $list .= qq(<div class="$class_dsc">$site[$_]{description}</div>\n) if($dsc eq 'on');
    $list .= qq(</div>\n);
    }
  }
}

sub popup
{
$site{link} =~ s/'/&#39;/g;
$site{link} =~ s/"/&quot;/g;
$site{title} =~ s/'/&#39;/g;
$site{title} =~ s/"/&quot;/g; #"

$head = <<_SRC;
<form name="rsspopup">
<select name="rsspopup" class="$class_select" onChange="popup(this)">
<option class="$class_select">$site{title}</option>
_SRC
}

sub list
{
$site{link} =~ s/'/&#39;/g;
$site{link} =~ s/"/&quot;/g;
$site{title} =~ s/'/&#39;/g;
$site{title} =~ s/"/&quot;/g; #"

$head = <<_SRC;
<div class="$class_site">
<a href="$site{link}" target="_blank">$site{title}</a>
</div>
_SRC
}

sub sock
{
my $url = shift;
undef(@tmp);
$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 = "GET $path HTTP/1.0\r\n";
$request .= "Host: $host\r\n";
$request .= "\r\n";

print SOCK $request;
while(<SOCK>) { push @tmp,$_; }
close(SOCK);
return @tmp;
}
