#!/usr/bin/perl require 5.004; use strict; use lib '../../adiary/lib'; use Satsuki::Base; #------------------------------------------------------------------------------ use Socket; use Fcntl; use IO::File; # for File Handle Object use Time::Local; my $do_download = 1; my $check_css_update = 1; my $host = 'd.hatena.ne.jp'; my $port = 80; my $basepath = '/theme/'; my $check_dir = 'hatena/'; my $css_ref = 'http://d.hatena.ne.jp/themesample?hatena'; #------------------------------------------------------------------------------ my $r = Satsuki::Base->new(); my $themes = $r->search_files($check_dir, undef, 1); my $last_modified_tm; #--------------------------------------------------- # IPとポートを変換 #--------------------------------------------------- my $ip_bin = inet_aton($host); # IP 情報に変換 if ($ip_bin eq '') { die("$host が見つかりません"); return ; } my $sockaddr = pack_sockaddr_in($port, $ip_bin); #------------------------------------------------------------------------------ # 確認作業 #------------------------------------------------------------------------------ my @themes = sort @$themes; foreach my $theme (@themes) { my $dir = $check_dir . $theme . '/'; if (!-d $dir) { next; } my $css_file = $dir . $theme . '.css'; # CSSのアップデート判別 if ($check_css_update) { my $css_tm = $r->get_file_lastmodified($css_file); my $path = "$basepath$theme/$theme.css"; my $sockaddr = pack_sockaddr_in($port, inet_aton($host)); my $sh = &connect_host($sockaddr); my $add_header = "If-Modified-Since: " . $r->rfc_date($css_tm) . "\n"; my $data = &get_file($sh, $host, $path, $css_ref, $add_header); sleep(1); # 更新されている if ($data != 304 && $css_tm < $last_modified_tm && ref($data)) { print "save new css file ($css_tm < $last_modified_tm)\n\n"; $data = join('', @$data); $data =~ s/\r\n|\r/\n/g; # \n に統一 $data =~ s/\n/\n\x01/g; # \n のうしろに \1 $data = [ split("\x01", $data) ]; $r->fwrite_lines($css_file, $data); } } # CSS読み出し print "Read $css_file\n"; my $lines = $r->fread_lines($css_file); my $rewrite = 0; foreach(@$lines) { if ($_ =~ /url\(\s*(.+?)\s*\)/i) { my $file = $1; if ($file =~ /(["'])(.*)\1/) { $file = $2; } $file =~ s|^http:\s*//|http://|; if ($file =~ /^http:\/\/d\.hatena\.ne\.jp/) { $rewrite = 1; $file = substr($file, rindex($file, '/')+1); $_ =~ s/url\(\s*(.+?)\s*\)/url("$file")/g; } if ($file ne '' && !-e "$dir$file") { # download に挑戦 if ($do_download && $file =~ /http:\/\/([\w\.\-]+?)\//) { # 外部サイト $file = substr($file, rindex($file, '/')+1); # if (-e "$dir$file") { next; } my $ref = "http://$host$basepath$theme/$theme.css"; my $host = $1; my $path = '/' . $'; my $sockaddr = pack_sockaddr_in($port, inet_aton($host)); my $sh = &connect_host($sockaddr); my $data = &get_file($sh, $host, $path, $ref); if (ref $data) { print "download from http://$host$path\n"; $rewrite = 1; $_ =~ s/url\(\s*(.+?)\s*\)/url("$file")/g; $r->fwrite_lines("$dir/$file", $data); sleep(1); next; } } elsif ($do_download) { # はてな内 my $ref = "http://$host$basepath$theme/$theme.css"; if ($file eq 'README') { undef $ref; } my $sh = &connect_host($sockaddr); my $data = &get_file($sh, $host, "$basepath$theme/$file", $ref); if (ref $data) { print "download from $basepath$theme/$file\n"; $r->fwrite_lines("$dir/$file", $data); sleep(1); next; } } print "\tFile not found $file\n"; undef $_; # その行を削除 $rewrite = 1; } } } if ($rewrite) { print "\t-->Rewrite to $css_file\n"; rename("$css_file", "$css_file.orig"); $r->fwrite_lines($css_file, $lines); } } ############################################################################### # ■トラックバック送信のための HTTP クライアント関連ルーチン ############################################################################### #------------------------------------------------------------------------------ # ●指定ホストに接続する #------------------------------------------------------------------------------ sub connect_host { my ($sockaddr) = @_; my $sh = IO::File->new; if (! socket($sh, Socket::PF_INET(), Socket::SOCK_STREAM(), 0)) { die("socket が開けません"); return ; } if (! connect($sh, $sockaddr)) { die("$host に接続できません"); return ; } autoflush $sh (1); return $sh; } #------------------------------------------------------------------------------ # ●GET, POST, HEAD などを送り、データを受信する #------------------------------------------------------------------------------ sub get_file { my ($socket, $host, $filepath, $referer, $add_header) = @_; print "Update check $filepath\n"; print $socket <; my $len; $last_modified_tm = 0; local($_); while(<$socket>) { if($_ =~ /^Last-Modified: (.*)/) { my $year = substr($1, 12, 4) - 1900; my $mon = substr($1, 8, 3); $mon = int(index('JanFebMarAprMayJunJulAugSepOctNovDec', $mon)/3); my $day = substr($1, 5, 2); my $hour = substr($1, 17, 2); my $min = substr($1, 20, 2); my $sec = substr($1, 23, 2); $last_modified_tm = Time::Local::timegm($sec,$min,$hour,$day,$mon,$year); } if($_ =~ /^\r?\n$/) { last; } } @response = <$socket>; close($socket); $status = (split(' ', $status))[1] +0; if ($status == 404) { print ("ファイルが見つかりません\n"); return ; } if ($status == 304) { return 304; } if ($status != 200) { print ("$host がエラーを返しました (Status : $status)\n"); return ; } return \@response; } #------------------------------------------------------------------------------ # ●URIエンコード #------------------------------------------------------------------------------ sub uri_encode { foreach(@_) { $_ =~ s/([^\.\*\-_a-zA-Z0-9 ])/'%' . unpack("H2",$1)/eg; $_ =~ s/ /+/g; } }