#! /usr/bin/perl

# $Id: PerlBot,v 1.7 2003/09/21 07:56:12 blusseau Exp $

# use lib "/usr/libexec/dchub/extprog"; # Put here the path to the DcHub.pm perl module

use 5.008; # 5.8 required for stable threading
use lib "/usr/libexec/dchub/extprog"; # Put here the path to the DcHub.pm perl module
use DcHub;
use strict;
# use Symbol;
use POSIX;
use threads;
use threads::shared;

# use vars qw($server);

our $hub;
our $client;

our $me : shared;
our %LAST_LIST_DL : shared;
our %SHARE_SIZE : shared;
our %IP_TO_NICK : shared;
our %NICK_TO_IP : shared;
our @OP_LIST : shared;

$|=1; # Autoflush

sub verif_share($) {
	my $user=shift;
	my $total=0;
	my $total_divx=0;
	my $total_gamez=0;
	if (exists($SHARE_SIZE{$user})) {
		my $ucl_file="/tmp/".$user.".ucl";
		my $dclst_file;
		($dclst_file=$ucl_file)=~s/\.ucl$/.DcLst/;
		return unless open (SHARE,"</tmp/".$user.".ucl");
		while (<SHARE>) {
			chomp;
			next unless /\s+(.+)\|(\d+)/;
			my $file=$1;
			my $size=$2;
			# print "$file => $size\n";
			$total+=$size;
			if ($file=~/\.(avi|rmvb|mpe?g|wma|mov)$/i && $size > 409600000) {
				$total_divx+=$size;
			} elsif ($file=~/\.(bin|iso)$/i && $size > 409600000) {
				$total_gamez+=$size;
			}
		}
		# DivX et GameZ en Go
		$total_divx=int($total_divx/102400000)/10;
		$total_gamez=int($total_gamez/102400000)/10;
		# if ($user eq '[Cb@ll]JrCs') { # Pour les Tests
		# 	$total_divx=1;
		# 	$total_gamez=2;
		# }
		# print "Total:$total <=> $SHARE_SIZE{$user}\n";
		if ($total != $SHARE_SIZE{$user}) {
			$hub->send_private_chat_message("Hub-Security","-tbanip $user 5"); # Ban for 5 Min
			$hub->send_private_chat_message("Hub-Security","-kick $user \"Fake Share !\"");
			print "*** Fake Share for:$user Myinfo:$SHARE_SIZE{$user} <=> Total:$total\n";
		}
		# Check min DivX File
	    # print "*** Divx: $total_divx Gamez:$total_gamez\n";
		# 10 Go de DivX Mini
		if ($total_divx < 10 && $total_gamez < 10) {
			my $msg;
			if ($total_divx < 10) {
				$msg="10Go de DivX Minimum !";
			} else {
				$msg="10Go de Gamez ou Appz Minimum (.bin, .iso, etc...) !";
			}
			$hub->send_private_chat_message($user,"Kick because: $msg");
			$hub->send_private_chat_message("Hub-Security","-tbanip $user 15"); # Ban for 5 Min
			$hub->send_private_chat_message("Hub-Security","-kick $user \"$msg\"");
			unlink($dclst_file);
			$LAST_LIST_DL{$user}=0; # Force reload
		}
	}
}

sub is_op($) {
	my $nick=shift;
	return grep { $_ eq $nick } @OP_LIST;
}

sub hello_process($) {
	my $user=shift;
	$hub->send_private_chat_message("Hub-Security","-getip $user");
	$LAST_LIST_DL{$user}=0 unless $LAST_LIST_DL{$user};
	# $hub->unisearch($user,".mp3",1024);
}

sub oplist_process(\@) {
	my $ref_array=shift;
	@OP_LIST=@$ref_array;
}

sub quit_process($) {
	my $user=shift;
	if (exists($NICK_TO_IP{$user})) {
		my $ip=$NICK_TO_IP{$user};
		delete $NICK_TO_IP{$user};
		delete $IP_TO_NICK{$ip};
	}
	@OP_LIST=grep { $_ ne $user } @OP_LIST;
}

sub myinfo_process($$$$$$) {
	my ($nick,$desc,$cnx_type,$flag,$email,$share_size)=@_;
	my $dcpp_version;
	my $dcpp_slots;
	# print "Myinfo: Nick:$nick, Desc:$desc, Email:$email, Share:$share_size\n";

	if ($desc=~/.*<\+\+ V:(\d+\.\d+),M:.+,S:(\d+).*>$/) {
		$dcpp_version=$1;
		$dcpp_slots=$2;
		# print "Version:$dcpp_version Slots:$dcpp_slots\n";
	}
	if ((not defined $dcpp_version) && ($desc=~/V:(\d+\.\d+)/)) {
		# Not a true DC++
		$hub->send_private_chat_message($nick,"Votre version de DC++ est vieille.");
		$hub->send_private_chat_message($nick,"Installer une nouvelle version:");
		$hub->send_private_chat_message($nick,"http://dcplusplus.sourceforge.net/index.php?page=download");
		$hub->send_private_chat_message("Hub-Security","-ban 1 $nick \"Version DC++ non compatible\"");
		sleep(1);
		$hub->send_private_chat_message("Hub-Security","-skick $nick \"\"");
	} else {
		# Reload if ShareSize changed or LAST_LIST_DL = 0 (Force reload).
		if ($SHARE_SIZE{$nick} != $share_size || $LAST_LIST_DL{$nick} == 0) {
			my $now=time();
			my $diff=$now-$LAST_LIST_DL{$nick};
			# print "DIFF pour $nick:$diff [".$LAST_LIST_DL{$nick}."]\n";
			if ($diff > 900) {
				$hub->get_file("$nick","MyList.DcLst","/tmp/$nick.DcLst");
				$SHARE_SIZE{$nick}=$share_size;
			}
		}
	}
}

sub global_chat_process($$) {
	my ($nick,$msg)=@_;
	# print "Global chat message from $nick:$msg\n";
	exit if ($msg=~/^!die/);
	if ($msg=~s/^!info //i) {
		my $user=$msg;
		my %uinfo=$hub->get_user_info($user);
		if (%uinfo) {
			$hub->send_private_gchat_message($nick,"-------------------------------------");
			foreach (keys(%uinfo)) {
				$hub->send_private_gchat_message($nick,"$_ -> $uinfo{$_}");
			}
			$hub->send_private_gchat_message($nick,"-------------------------------------");
		} else {
			$hub->send_private_gchat_message($nick,"user $user unknown !");
		}
	} elsif ($msg=~/^!restart/) {
		print "OK SENDING RESTART\n";
		$hub->send_private_chat_message("Hub-Security","-startprg minibot");
		$hub->send_private_chat_message($nick,"-startprg minibot");
	}
}

sub priv_chat_process($$) {
	my ($nick,$msg)=@_;
	# print "Private message from $nick:$msg\n";
	exit if ($msg=~/^!die/);
	if ($msg=~/^!queue/) {
		my %queue=$hub->get_dl_queue();
		if (%queue) {
			$hub->send_private_chat_message($nick,"Current Download Queue is:");
			foreach my $rmnick (keys(%queue)) {
				$hub->send_private_chat_message($nick,"For $rmnick:".join(',',@{$queue{$rmnick}}));
			}
		}
   	} elsif ($msg=~s/^!list\s+//) {
		$hub->send_private_chat_message($nick,"Try to List $msg");
		$hub->get_file($msg,"MyList.DcLst","/tmp/$msg.DcLst");	
   	} elsif ($msg=~s/^!send\s+//) {
		$hub->send_private_chat_message($nick,"Try to send $msg");
		$hub->send_dc_line("\$".$msg);	
   	} elsif ($msg=~s/^!verif\s+//) {
		$hub->send_private_chat_message($nick,"Try to verify $msg");
		$hub->unisearch($msg,".mp3",1024);
   	} elsif ($nick eq 'Hub-Security' && $msg=~m/^rev:(\d+\.\d+\.\d+\.\d+)\s+(.+)\r/) { # Result from -revip command
		$IP_TO_NICK{$1}=$2;
		$NICK_TO_IP{$2}=$1;
   	} elsif ($nick eq 'Hub-Security' && $msg=~m/^ip:(.+)\s+(\d+\.\d+\.\d+\.\d+).*/) { # Result from -getip command
		$IP_TO_NICK{$2}=$1;
		$NICK_TO_IP{$1}=$2;
	}
}

sub search_process($$$$$$) {
	my ($user,$passive_mode,$size_matter,$size_at_most,$type,$pattern)=@_;
	print "Search message User:$user Pasv:$passive_mode SM:$size_matter SAM:$size_at_most Type:$type Pattern:$pattern\n";
}

sub sr_process($$$$$$) {
	my ($user,$filename,$filesize,$free_slot,$max_slot,$hub)=@_;
	print "Find User:$user,Filename:$filename,Size:$filesize,FS:$free_slot,MS:$max_slot,HUB:$hub\n";
}

sub connecttome_process($$$) {
	my ($dest_nick,$remote_ip,$remote_port)=@_;
	if (exists($IP_TO_NICK{$remote_ip})) {
		my $nicktokick=$IP_TO_NICK{$remote_ip};
		$hub->send_private_chat_message($nicktokick,"N'essayez pas de downloader chez moi !");
		$hub->send_private_chat_message($nicktokick,"Je n'ai rien en partage: je suis un BOT !");
		$hub->send_private_chat_message($nicktokick,"Au revoir !");
		sleep(1);
		$hub->send_private_chat_message("Hub-Security","-skick $nicktokick \"\"");
		$hub->send_private_chat_message("Hub-Security","-unban $remote_ip");
	} else {
		$hub->send_private_chat_message("Hub-Security","-revip $remote_ip");
	}
}

sub file_downloaded($$$$$) {
	my ($remotenick,$remotefile,$localfile,$filesize,$reallydownloaded)=@_;
	# print "FileSize:$filesize Really:$reallydownloaded\n";
	if ($remotefile eq "MyList.DcLst") {
		$LAST_LIST_DL{$remotenick}=time();
		# print "OK pour $remotenick [".$LAST_LIST_DL{$remotenick}."]\n";
		# Try to decompress the file
		my $new_filename;
		($new_filename=$localfile)=~s/\.DcLst/.ucl/;
		if (! -f $new_filename || $reallydownloaded) {
			my $command="he3 -o $new_filename $localfile";
			my $errcheck = system("$command");
			my $exit_value  = $errcheck >> 8;
			if ($exit_value != 0) {
				print "*** Erreur lors de la decompression !\n";
				return -1;
			}
			unless (is_op($remotenick)) {
				my $verif_thread=threads->create(\&verif_share,$remotenick);
				$verif_thread->detach();
			}
		}
	}
}

sub start_hub_thread() {
	my $recu;
	do {
		$recu=$hub->get_a_dc_line;
		# print "*** [RECU:$recu]\n";
		my $result=$hub->generic_decoder($recu);
		if ($result < 0) {
			print "BAD RESULT for $recu\n";
		}
	} while ($recu);
}

$hub=DcHub->new(@ARGV,2401,2401); # Create and initialize
$me=$ARGV[0];
# $hub->send_public_chat_message("Public Message");
# $hub->send_private_gchat_message("MASTER","Private global chat Message with |");
# $hub->send_private_chat_message("MASTER","Private only message with |");
$hub->define_callback("hello",\&hello_process);
$hub->define_callback("oplist",\&oplist_process);
$hub->define_callback("quit",\&quit_process);
$hub->define_callback("myinfo",\&myinfo_process);
$hub->define_callback("global_chat",\&global_chat_process);
$hub->define_callback("priv_chat",\&priv_chat_process);
# $hub->define_callback("search",\&search_process);
# $hub->define_callback("sr",\&sr_process);
$hub->define_callback("connecttome",\&connecttome_process);
$hub->define_callback("filedownloaded",\&file_downloaded);
# $hub->send_dc_line("\$GetNickList");
# $hub->send_dc_line("\$Search 10.10.10.22:4689 F?F?0?1?.avi");
# $hub->search(".avi",1024,0);
# $hub->unisearch("MASTER","metal unfor .mp3",2048);
# $hub->unisearch("MASTER",".mp3",2000048,1);
# $hub->get_file("MASTER","-= movies =-\-= DivX Seen =-\Trois Zero.avi","/tmp/toto.avi");

$hub->start_server();
my $hub_thread=threads->create(\&start_hub_thread);					

$hub_thread->join();

print "FIN :-(\n";
