#!/usr/local/bin/perl
#
#     diffdir.pl    
#                                   ver.0.92
#                                   April 18 1998 
#                Copyright (c) 1998 Tomonori NOMOTO
#
# Math::BigInt,Net::FTP,Net::Telnet を使用しています。

## Net::FTP,Net::Telnet　モジュールがPerl5標準の位置にない
## 場合のみ"#"を取って、ディレクトリを指定してください。

#use lib "/home/someone/lib/perl5/Net"

# 転送元設定
$workdir = "/home/ntomo/test/";	# 作業用tarファイルを置くディレクトリ
$logfile = $workdir . "test.log"; # ログファイルの位置
$tarfile = "sendtar.tar";	# 送信用tarファイルの名前
$from_dir = "/home/someone/send/"; # 転送元ディレクトリー

$tar = $workdir . $tarfile;	# 送信tarファイル名(変えない)

# 転送先設定
$hostname = 'hostname.somewhere.org';    # 転送先アドレス
$to_dir = "/home/guest/place/";   # 転送先ディレクトリ名
$login = "guest";           # ログイン名
$passwd = "password";        # パスワード

######################################################################
use Net::FTP;
use Net::Telnet;
use Math::BigInt;

# 転送元ファイル情報を調べる
%local_file = &search_dir($from_dir,$from_dir);

# ログファイルの準備
$date = `date`;
open (STDERR, ">>$logfile");
print STDERR "$date";

# 転送先に接続
$ftp = Net::FTP->new($hostname)||die "Could't connect host.\n"; # ホストに接続
$ftp->login($login,$passwd)||die "Could't log in.\n";	# ホストにログイン

# 転送先ファイル情報を取得
%ftp_file = &search_ftp($to_dir,$to_dir);	# 転送先ディレクトリ内を調べる
## Only for debug.
#foreach(keys(%local_file)){print "$_  $local_file{$_}\n"} # 転送元ファイル
#print "\n\n";
#foreach(keys(%ftp_file)){print "$_  $ftp_file{$_}\n"} # 転送先ファイル

# 転送元、転送先を比較
&compare;

## Only for debug.
#foreach(@receive_file){print "$_\n"} # 受け取るファイル
#print "\n\n\n";
#foreach(@send_file){print "$_\n"} # 送るファイル
#print "\n\n\n";
#foreach(@lmkdir){print "$_\n"}	# ローカルに作るディレクトリ
#print "\n\n\n";
#foreach(@fmkdir){print "$_\n"}	# 相手先に作るディレクトリ

# 転送
$ftp->binary||&exit("Couldn't change to bin mode.\n");

foreach $send_file (@send_file){ # 送るファイルをtarファイルにする
    if(defined $tf){
#	print "cd $from_dir;tar -rf $tar ./$send_file\n";
	system("cd $from_dir;tar -rf $tar ./$send_file"); #||&exit("Couldn't run tar command.\n");
    }else{
#	print "cd $from_dir;tar -cf $tar ./$send_file\n";
	system("cd $from_dir;tar -cf $tar ./$send_file"); #||&exit("Couldn't run tar command.\n");
	$tf = "tar is already created";
    }
}
$from_path = $tar ;
$to_path = "$to_dir$tarfile";
$ftp->put($from_path,$to_path)||&exit("Couldn't put file '$fullpath'\n");

# tarファイルの展開
$telnet = new Net::Telnet (Host => "$hostname",
			   Timeout => 10,
			   Prompt => '/[$%#>] $/')||&exit("Couldn't make telnet connection.");
$telnet->login($login, $passwd)||&exit("Couldn't login to $hostname");
$telnet->cmd("cd $to_dir;tar --extract --atime-preserve --file $tar")||&exit("Command failed");
$telnet->close;


# 終了処理
$ftp->quit;			# 転送先との接続を切断
close STDERR;			# ログファイルを閉じる

### 以下サブルーチン ##################################################


# &search_dir($target_dir,$realtop_dir)
# localhostで、あるディレクトリからそのディレクトリ以下の
# ファイル、更新日時を調べ %local_file に入れる。
sub search_dir{
    local($target_dir,$real_top) = @_;
    unless($target_dir =~ /\/$/){$target_dir = $target_dir . "/";}
    unless($real_top =~ /\/$/){$real_top = $real_top . "/";}
    opendir(FROM,$target_dir);
    local(@dir_info) = readdir(FROM);
    foreach $file (@dir_info){ 
	if($file eq ".."){	# .  を抜かす
	}elsif($file eq "."){	# .. を抜かす
	}elsif(-d "$target_dir$file"){ 
	    &search_dir("$target_dir$file/",$real_top);
	    &format;
	    $local_file{"$relational_dir$file/"} = "$year$mon$mday$hour$min$sec";
	}else{
	    &format;
	    if($relational_dir eq ""){
		$local_file{"$file"} = "$year$mon$mday$hour$min$sec";
	    }else{
		$local_file{"$relational_dir$file"} = "$year$mon$mday$hour$min$sec";
	    }
	    closedir(FROM);
	}
    }
    return %local_file;
}

sub format{
    ($tsec,$tmin,$thour,$tmday,$tmon,$tyear,$twday,$tyday,$tisdst) = localtime;
    if($tyear < 30){$tyear = "20$tyear"}else{$tyear = "19$tyear"}
    local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$target_dir$file");
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $mtime;
    $mon = $mon + 1;
    if($year < 30){$year = "20$year"}else{$year = "19$year"}
    if($mon < 10){$mon = "0$mon"}
    if($mday < 10){$mday = "0$mday"}
    if($hour < 10){$hour = "0$hour"}
    if($min < 10){$ min = "0$min"}
    if($sec < 10){$sec = "0$sec"}
    $sec = "00"; # 実際は $sec は使わず"00"とする。
    if($tyear ne $year){($hour,$min)=("00","00")} # 今年でなければ$hour,$minも"00"
    $relational_dir = $target_dir;
    $relational_dir =~ s/$real_top//;
}

# &search_ftp($top_dir,$realtop_dir)
# ftp上で、あるディレクトリからそのディレクトリ以下の
# ファイル、更新日時を調べる
sub search_ftp{
    local($target_dir,$real_top) = @_;
    unless($target_dir =~ /\/$/){$target_dir = $target_dir . "/";}
    unless($real_top =~ /\/$/){$real_top = $real_top . "/";}
    (local(@dir) = $ftp->dir($target_dir))||&exit("Couldn't run dir.\n");
#    foreach(@dir){print "$_\n";} # for debug
    foreach $line (@dir){
	@line = split(/[ \t\n]+/,$line);
	if($line[0] =~ /total/){
	}elsif($line[8] eq ""){	# total XXX を抜かす
	}elsif($line[8] eq "."){ # .を抜かす
	}elsif($line[8] eq ".."){ # ..を抜かす
	}elsif(@line[0] =~ /^d.........$/ && $line[8] ne ".." && $line[8] ne "."){
	    $relational_ftpdir = $target_dir;
	    $relational_ftpdir =~ s/$real_top//;
            &ftpformat;
	    $ftp_file{"$relational_ftpdir$line[8]/"} = "$year$mon$mday$hour$min$sec";
	    &search_ftp("$target_dir$line[8]/",$real_top);
	}else{
	    $relational_ftpdir = $target_dir;
	    $relational_ftpdir =~ s/$real_top//;
            &ftpformat;
	    if($relational_ftpdir eq ""){
		$ftp_file{"@line[8]"} = "$year$mon$mday$hour$min$sec";
	    }else{
		$ftp_file{"$relational_ftpdir@line[8]"} = "$year$mon$mday$hour$min$sec";
	    }
	} 
    }
    return %ftp_file;
}

sub ftpformat{
    if(@line[7] =~ /:/){
	($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
	$mon = $mon + 1;
	if($year < 30){$year = "20$year"}else{$year = "19$year"}
	($hour,$min) = split(/:/,@line[7]);
	$sec = "00";
    }else{$year = @line[7];($hour,$min,$sec) = ("00","00","00");    }
    $mday = @line[6];
    if($mday < 10){$mday = "0$mday"}
    %month = (Jan => "01", Feb => "02", Mar => "03", Apr => "04", May => "05", Jun => "06", Jul => "07", Aug => "08", Sep => "09", Oct => "10", Nov => "11", Dec => "12");
    $mon = $month{@line[5]};
}

# &compare
# 転送元、転送先を比較して転送が必要なものを選ぶ。
#
sub compare{
    foreach $lfile (keys(%local_file)){
	if(defined $ftp_file{$lfile}){
	    $i = Math::BigInt->new($local_file{$lfile});
	    if($lfile =~ /\/$/){
	    }elsif(($i->bcmp($ftp_file{$lfile})) == 1){
		push @send_file, $lfile;
	    }elsif($ftp_file{$lfile} eq $local_file{$lfile}){
	    }else{
		push @receive_file, $lfile;
	    }
	    delete $ftp_file{$lfile};
	}else{
	    if($lfile =~ /\/$/){
		push @fmkdir, $lfile;
	    }else{
		push @send_file, $lfile;
	    }
	}
    }
    foreach $ffile (keys(%ftp_file)){
	if(defined $local_file{$ffile}){
	    $j = Math::BigInt->new($local_file{$ffile});
	    if($ffile =~ /\/$/){
	    }elsif(($j->bcmp($ftp_file{$ffile})) == 1){
		push @send_file, $ffile;
	    }elsif($ftp_file{$ffile} eq $local_file{$ffile}){
	    }else{push @receive_file, $ffile;}
	}else{
	    if($ffile =~ /\/$/){
		push @lmkdir, $ffile;
	    }else{
		push @receive_file, $ffile;
	    }
	}
    }
}

# &exit("Error Message")
#
sub exit{
$ftp->quit;			# 転送先との接続を切断
die "$_[0]\n";
}














