#!/usr/bin/perl -w
use Net::IRC;
use DB_File;
use Fcntl;

$server = 'irc.openprojects.net';
$cr_nick=''; $cr_pass = 'DGlC2nzrP1zyc'; $ID=0;
%dbases=('opt','options.db','dict','dict.db','seen','seen.db','msgs','msgs.db');
for (keys %dbases){tie %{$_}, DB_File, $dbases{$_}, O_RDWR, 0600, $DB_HASH}
open(LOGFILE,'>>logfile') || die "Cant write to logfile: $!";
$irc = new Net::IRC;
$conn=$irc->newconn(Server,$server,Port,6667,Nick,$opt{nick},Maxlinelen,400) or die "Error: $!";

$conn->add_global_handler(376, \&on_connect);
$conn->add_global_handler('join', \&on_join);
$conn->add_global_handler('part', \&on_part);
$conn->add_global_handler('nick', \&on_nick);
$conn->add_global_handler('notice', \&on_notice);
$conn->add_global_handler(433, \&on_nick_taken);
$conn->add_global_handler('msg', \&on_msg);
$conn->add_global_handler('public', \&on_public);
$conn->add_global_handler('caction', \&on_action);
$conn->add_global_handler('kick', \&on_kick);
$conn->add_global_handler('quit', \&on_quit);
$conn->add_global_handler('disconnect', \&on_disconnect);
$irc->start;

sub on_kick {
	sleep 5;
	$_[0]->join(($_[1]->to)[0]);
}

sub on_connect {
	my $self=shift;
	print "connected!\n";
	$self->privmsg('nickserv',"identify foo");
	for (split / /,$opt{chans}){$self->join($_)}
}

sub on_disconnect {
	sleep 5;
	$_[0]->connect();
}

sub on_action {
	my ($self,$event)=@_;
	my ($nick)=$event->nick;
	$_=$a=join ' ',$event->args;
	s/$opt{nick}/$nick/ig;
	$self->me(($event->to)[0],$_) if($a=~/$opt{nick}/i);
}

sub on_join {
	my ($self,$event) = @_;
	seen(@_,'join');
	if(exists $msgs{lc $event->nick}) {for (split(/\n/,$msgs{lc $event->nick})) {$self->privmsg($event->nick,$_)}$msgs{lc $event->nick}=''}
	if($event->userhost=~/^root\@/i){$self->privmsg(($event->to)[0],"r000000000000000000000000000t!")}
}

sub on_part {
	if(lc $_[1]->nick eq lc $cr_nick){$ID=0}
	$nick=lc $_[1]->nick; @ops = grep !/^$nick$/, @ops;
	seen(@_,'leave');
}

sub on_notice {
	($self,$event)=@_;
	if(lc $event->nick eq 'nickserv'){
		($nick,$num)=(($_=join ' ',$event->args)=~/^STATUS (.*?) (.*)$/) or return;
		push @ops,$nick if($num == 3);
	} else {&parse_msg(@_,$event->nick)}
}
sub on_msg {&parse_msg(@_,$_[1]->nick)}
sub on_public {&parse_msg(@_,($_[1]->to)[0])}
sub on_nick_taken {$_[0]->nick($opt{nick}.='_')}
sub on_nick {on_part(@_)}
sub on_quit {on_part(@_)}
sub seen {$seen{lc $_[1]->nick}="$_[2],".gmtime}
sub op {$_[0]->privmsg('chanserv',"op ".$_[1].' '.$opt{nick});sleep 1}
sub deop {$_[0]->privmsg('chanserv',"deop ".$_[1].' '.$_[2])}

sub parse_msg {
	local ($self,$event,$addy) = @_;
	local $nick = lc $event->nick;
	local @args = split(' ',join(' ',$event->args));
	local $respond=0;
	print LOGFILE "$nick/$addy @args\n";
	if($args[0] =~ /$opt{nick}/i) {$_=shift @args}
	elsif($args[$#args] =~ /$opt{nick}/i) {$_=pop @args}
	elsif(!(($addy !~ /^#/)||(($args[$#args] =~ /\?/)&&($opt{auto} eq 'ques'))||($opt{auto} eq 'on'))){$respond=1}
	$args1 = join(' ',@args);
	($command=lc shift @args) =~ s/[,!?]//g;
	local $args=join(' ',@args);

	if(($nick eq lc $cr_nick)&&($ID==1)) {
		if($command eq 'set') {
			@_ = ($args =~ /^(.*?) to (.*)$/i) or return;
			$opt{lc $_[0]}=$_[1]
		} elsif($command eq 'nick') {
			$self->nick($args);
			$opt{nick}=$args;
		} elsif($command eq 'quit') {irc_quit($self,$args)}
	}
	if(grep /^$nick$/, @ops) {
		if($command eq 'join') {
			$opt{chans}.=" $args";
			$self->join($args);
		} elsif($command eq 'part') {
			$opt{chans}=~s/ $args//g;
			$self->part($args);
		} elsif($command =~ /^kick/) {
			local $chan=($args[0]=~/^#/)?shift @args:$event->to;
			&op($self,$chan);
			$self->kick($chan,$args[0],join(' ',@args[1..$#args]));
			$self->mode($chan,'+b',$args[0]) if($command =~ /ban$/);
		} elsif($command eq 'topic') {
			&op($self,$args[0]);
			$self->topic($args[0],join(' ',@args[1..$#args]));
		} elsif($command eq 'op') {
			&op($self,($args[0]=~/^#/)?$args[0]:$event->to);
			$self->mode(($args[0]=~/^#/)?shift @args:$event->to,'+o',($args[0] eq '')?$opt{nick}:$args[0]);
		} elsif($command eq 'deop') {
			&deop($self,($args[0] =~ /^#/)?shift @args:$event->to,($args[0] eq '')?$opt{nick}:$args[0]);
		} elsif($command eq 'say') {
			out($self,$args[0],join(' ',@args[1..$#args]),$event->nick) if($args[0] !~ /^(.{4}serv|$opt{nick})$/i);
		} elsif(($command eq 'messages')&&(exists $msgs{lc $args})) {
			 for (split(/\n/,$msgs{lc $args})) {$self->privmsg($addy,$_) if($args ne 'JALH')}
		}
	}
	if(($command eq 'respond')&&(lc $args[0] eq 'to')) {
		$args = join(' ',@args[1..$#args]);
		@_=($args =~ /^\{?(.*?)\}? with (.*)$/i) or return;
		$_[0] =~ s/[,!?]//g;
		$dict{lc $_[0]}="$nick,$_[1]" if(!exists $dict{lc $_[0]});
	} elsif($command eq 'forget') {
		$args =~ s/[?!,]//g;
		delete $dict{lc $args} if((exists $dict{lc $args})&&(($dict{lc $args} =~ /^$nick,/i)||(grep /^$nick$/, @ops)));
	} elsif($command eq 'append') {
		@_ = ($args =~ /^(.*) to \{?(.*?)\}?$/i) or return;
		$_[1] =~ s/[,!?]//g;
		$dict{lc $_[1]}.=$_[0] if((exists $dict{lc $_[1]})&&(($dict{lc $_[1]} =~ /^$nick,/i)||(grep /^$nick$/, @ops)));
	} elsif(($command eq 'who')&&(lc join(' ',@args[0,1]) eq 'taught you')){
		($args=join(' ',@args[2..$#args]))=~s/[!?]//g;
		$self->privmsg($addy,(split(/,/,$dict{lc $args},2))[0]." taught me $args") if(exists $dict{lc $args});
	} elsif($command eq 'remind') {
		$msgs{lc $args[0]}.="$nick says ".join(' ',@args[1..$#args])."\n";
	} elsif($command eq 'value') {
		out($self,$addy,"$args = $opt{lc $args}",$event->nick) if(exists $opt{$args})
	} elsif($command eq 'calc') {
		out($self,$addy,eval $args) if($args=~/^[0-9+\-*\\.\/%()e ]*$/i)
	} elsif($command eq 'date') {out($self,$addy,(gmtime),$event->nick)
	} elsif(($command eq 'identify') && ($opt{ops} =~ /,$nick,/i)) {
		if((defined $args)&&(crypt($args,$cr_pass) eq $cr_pass)){$ID=1;$cr_nick=$event->nick}
		$self->privmsg('nickserv',"status $nick");
	} elsif($command eq 'seen') {
		$args=~s/[,!?]//g;
		if(exists $seen{lc $args}) {
			($seen,$date)=split(/,/,$seen{lc $args},2);
			if($seen eq 'join'){$self->privmsg($addy,"$args is still here!")
			}else{$self->privmsg($addy,"$args left on $date")}
		}
	} elsif(($command eq 'slashdot')&&($respond == 0)) {
		$str="Latest /. headlines: ";@_=`lynx --source www.slashdot.com/slashdot.xml`; for(@_){if(/\<title\>/){$str.=($_=~ /\<title\>(.*)\<\/title\>/)[0]." | "}} chop $str;chop $str;$self->privmsg($addy,$str)
	} elsif($command eq 'tell') {@_=($args =~ /\{?(.*?)\}? about (.*)/i);
		dict_ref($_[1],$self,$_[0]) if($_[0]!~/(.{4}serv|$opt{nick})/i)
	} elsif($respond==0) {dict_ref($args1,$self,$addy)
	} elsif($args1 =~ /^.* (is|are|==|=) .*$/i) {
		@_ = ($args1 =~ /^\{?(.*?)\}? (is|are|==|=) (.*)$/i);
		$_[0] =~ s/[,!?]//g;
		$dict{lc $_[0]}="$nick,$args1" if(!exists $dict{lc $_[0]});
	}
}

sub dict_ref {
	local ($args,$self,$addy)=@_;
	$args=~s/[!?,]//g;
	out($self,$addy,(split(/,/,$dict{lc $args},2))[1],$event->nick) if(exists $dict{lc $args});
}

sub out {
	local ($self,$addy,$_,$nick) = @_;
	s/\$dict_count/scalar keys %dict/eg;
	s/\$(\w+){(.+)}/${$1}{$2}/g;
	s/\$(\w+)/${$1}/g;
	if(/^\/me /i) {s/^\/me //i;$self->me($addy,$_)}
	else {$self->privmsg($addy,$_)}
}

sub irc_quit {
	$_[0]->quit($_[1]);
	close LOGFILE;
	for (keys %dbases){untie %{$_}}
	exit;
}
