#!%PERL%

use IO::Socket;

$|=1;

$path = "%PATH%";

$timeout = "300";
$botpass = $ARGV[0];
$srcaddr = $ARGV[1];
$srcport = $ARGV[2];
$logfile = $ARGV[3];
$file    = "$path/var/dcc";

if ( $logfile ) {
	open(FILE,"$logfile");
	while(<FILE>) {
		chop;
		push(@LOG,$_);
	}
}

if ( $srcport eq 0 ) { undef $srcport; }

$server = IO::Socket::INET->new(
	Proto     => 'tcp',
	LocalAddr => $srcaddr,
	LocalPort => $srcport,
	Listen    => 1,
	Timeout   => 15,
	Reuse     => 1 );

if ( $server ) {
	print $server->sockport() . "\n";
} else {
	print "Cannot bind $srcaddr:$srcport\n";
	exit;
}

daemonize();

if ($client = $server->accept()) {
	# stop listening
	$server = IO::Socket::INET->new(
		Proto     => 'tcp',
		LocalAddr => $srcaddr,
		LocalPort => $srcport,
		Listen    => 0,
		Reuse     => 1);

	$client->autoflush(1);
	vec($wdata,fileno($client),1) = 1;

	client("Password?");

	$lastmsg = time;

	while(1) {
		$xdata = $wdata;
		if ( select($xdata, undef, undef, 0.2) ) {
			if (vec($xdata, fileno($client), 1)) {
				$line = <$client>;
				if ( !$auth ) {
					if ( $line =~ /^$botpass/ ) { $auth=1; }
					else { exit; }
				}
				$line =~ s/(\r|\n)+$//;
				$line =~ s/\[/\#\#20/g;
				$line =~ s/\]/\#\#21/g;
				$line =~ s/\|/\#\#22/g;
				$line =~ s/\^/\#\#23/g;
				$line =~ s/\`/\#\#24/g;
				$line =~ s/\'/\#\#25/g;
				$line =~ s/\~/\#\#26/g;
				$line =~ s/\\/\#\#27/g;
				$line =~ s/\{/\#\#28/g;
				$line =~ s/\}/\#\#29/g;

			} else {
				undef $line;
			}
		} else {
			undef $line;
		}

		if ( $auth && $logfile ) {
			client("LAST 300 CLIENTS CONNECT/DISCONNECT LOG");
			$lines = 300;
			foreach(@LOG) {
				$ts = $_;
				$ts =~ s/ .*//;
				s/^$ts //;
				if ( $lastts eq $ts ) { $pts = "      "; }
				else { $pts = sprintf("%6s",easytime(time-$ts)); }
				$lines = sprintf("%03d",$lines);
				client("[$lines] - $pts - $_");
				$lines--;
				$lastts = $ts;
			}
			client("End-of-Log");
			client("Resuming normal DCC opterations");
			undef $logfile;
		} elsif ( $auth && !$welcome ) {
			client("Welcome to GenEthic DCC Interface, type 'help' for commands list.");
			client("TIMEZONE is set as default to UTC, use the 'tz' command to set your offset");
			$welcome=1;
		}


		if ( $line )  {
			$lastmsg = time;
			undef $warned;

			if ( $line =~ /^(quit|exit)/i ) {
				client("Preparing to close the connection...");
				sleep 1;
				client("Ready to close the link...");
				sleep 1;
				client("Have a nice day!");
				client("Closing link...");
				exit;
			} elsif ( $line =~ /^hack *(.*)/i ) {
				if ( $1 ) {
					$match = $1;
				} else {
					$match = "*";
				}

				client("HACK4 messages log (matching $match).");
				client("TIME is given in UTC $tz");

				$match =~ s/\?/./g;
				$match =~ s/\*/.*/g;
				open(HACK,"$path/var/hack4.log");
				while(<HACK>) {
					chop;
					if ( /$match/i ) {
						$ts1 = $ts2 = $_;
						$ts1 =~ s/ .*//;
						$ts2 =~ s/.* //g;
						s/^$ts1 //;
						s/ $ts2//;

						$ts2 =~ s/^##20(.*)##21$/$1/;
						$ts1 += ( $tz * 3600 );
						$ts1= unix2date($ts1);
						$ts2 += ( $tz * 3600 );
						$ts2= unix2date($ts2);
						client("$ts1 $_ ##20$ts2##21");
					}
				} close(HACK);
				client("EOF");
			} elsif ( $line =~ /^gline *(.*)/i ) {
				if ( $1 ) {
					$match = $1;
				} else {
					$match = "*";
				}

				client("GLINE messages log (matching $match).");
				client("TIME is given in UTC $tz");

				$match =~ s/\?/./g;
				$match =~ s/\*/.*/g;
				client("STATUS MODE   SET_TIME            DURATION  UNTIL               SET_BY     GLINE          :REASON");
				open(HACK,"$path/var/gline.log");
				while(<HACK>) {
					chop;
					if ( /$match/i ) {
						($tset,$nick,$mode,$who,$until,$reason)=split(/	/);
						if ( time > $until ) { $status = "over  "; }
						else                 { $status = "active"; }

						$nick  =~ s/^(.{9}).*/$1\*/;
						$nick  = sprintf("%-10s",$nick);
						$gtime = easytime($until-$tset);
						$tset  = unix2date($tset  + ( $tz * 3600 ));
						$until = unix2date($until + ( $tz * 3600 ));
						$mode = sprintf("%-6s",$mode);
						$gtime = sprintf("%-9s",$gtime);
						$who   = sprintf("%-30s",$who);
						
						client("$status $mode $tset $gtime $until $nick $who :$reason");
					}
				} close(HACK);
				client("EOF");
			} elsif ( $line =~ /^tz *((\+|\-)([0-9]+))/i ) {
				$tz = $1;
				$ltime = unix2date(time + ( $tz * 3600 ));
				client("Your local time should be: $ltime");
			} else {
				client("Available Commands are:");
				client("hack  <match>     HACK(4) log search, ? and * allowed. empty match, will show everything");
				client("gline <match>     GLINE   log search, ? and * allowed. empty match, will show everything");
				client("tz    <+/-hours>  set your UTC timezone offset in hours");
				client("quit              end the dcc session");
				client("exit              end the dcc session");
			}

		} elsif ( time-$lastmsg >= $timeout ) {
			client("$timeout seconds without activity, quitting.");
			exit;
		} elsif ( time-$lastmsg+30 >= $timeout && !$warned ) {
			$warned=1;
			client("warning, the session will timeout in 30 seconds!");
		}
			
	}
}

sub client {
	$toclient = (shift);
        $toclient =~ s/\#\#20/\[/g;
        $toclient =~ s/\#\#21/\]/g;
        $toclient =~ s/\#\#22/\|/g;
        $toclient =~ s/\#\#23/\^/g;
        $toclient =~ s/\#\#24/\`/g;
        $toclient =~ s/\#\#25/\'/g;
        $toclient =~ s/\#\#26/\~/g;
        $toclient =~ s/\#\#27/\\/g;
        $toclient =~ s/\#\#28/\{/g;
        $toclient =~ s/\#\#29/\}/g;
	print $client $toclient . "\n";
}

sub debug {
	open(LOG,">>$path/tmp/dcc.log");
	print LOG (shift) . "\n";
	close(LOG);
}

sub daemonize {
	chdir "$path"              or print "Can't chdir to /: $!";
	open STDIN, '/dev/null'    or print "Can't read /dev/null: $!";
	open STDOUT, '>>/dev/null' or print "Can't write to /dev/null: $!";
	open STDERR, '>>/dev/null' or print "Can't write to /dev/null: $!";
	defined(my $pid = fork)    or print "Can't fork: $!";
	exit if $pid;
	setsid                     or print "Can't start a new session: $!";
	umask 0;
}

sub unix2date {
	($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(shift);
	$mon++;
	$year += 1900;
	foreach ( split(/ /,'sec min hour mon mday') ) {
		$$_ = sprintf("%02d",$$_);
	}
	return "$year-$mon-$mday $hour:$min:$sec";
}

sub easytime {
        $in = (shift);
 
        $S = $in % 60;
        $in -= $S;
        $in = $in / 60;   
        
        $M = $in % 60;   
        $in -= $M;   
        $in = $in / 60;

        $H = $in % 24;
        $in -= $H;
        $in = $in / 24;
                        
        $D = $in % 7;
        $in -= $D;
        $in = $in / 7;
        
        $W = $in;           

        foreach(split//,'WDHMS') { if ( !$$_ ) { $$_ = '0'; } }
        
        if ( $W )    { return $W . 'w' . $D . 'd' . $H . 'h'; }
        elsif ( $D ) { return $D . 'd' . $H . 'h' . $M . 'm'; }
        elsif ( $H ) { return $H . 'h' . $M . 'm' . $S . 's'; }
        elsif ( $M ) { return $M . 'm' . $S . 's'; }
        else         { return $S . 's'; }
}
