#!/usr/bin/perl -w use Net::IRC; use LWP::Simple; use URI::Escape; use IO::Handle; use Data::Dumper; ### Init my $irc = new Net::IRC; my $conn = $irc->newconn(Server => 'irc.freenode.net', Port => 6667, Nick => ($ARGV[0] || 'hamlin'), Ircname => 'hamlin, second incarnation', Username => 'hamlin') or die "Can't connect to IRC server.\n"; open LOG, ">>hamlin.log"; LOG->autoflush(1); ### The body of the bot. my %Factoids; my @Todos; # [idx] = { id => ID, name => name of person doing it, priority => priority, desc => description } my($TodoLastID) = 0; my %Karma; my %Countdowns; my %CountdownHelpers; my %NicksHere; my(@GoodNicks) = (); # canuckid canuckid_ chacha2006 Stern ichaelmay8 my(%IdNicks); my($ReverseMode) = 0; sub handle_line($$$$;$); sub excellent($) { my($nick) = shift or die; $Karma{$nick} = 0 unless exists $Karma{$nick}; $Karma{$nick} += 3; } sub good($) { my($nick) = shift or die; $Karma{$nick} = 0 unless exists $Karma{$nick}; $Karma{$nick}++; } sub bad($) { my($nick) = shift or die; $Karma{$nick} = 0 unless exists $Karma{$nick}; $Karma{$nick}--; } sub terrible($) { my($nick) = shift or die; $Karma{$nick} = 0 unless exists $Karma{$nick}; $Karma{$nick} -= 3; } sub trivial_get($$$) { my($host, $port, $path) = @_; #print "HOST=$host, PORT=$port, PATH=$path\n"; require IO::Socket; local($^W) = 0; my $sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, Proto => 'tcp', Timeout => 60) || return undef; $sock->autoflush; my $netloc = $host; $netloc .= ":$port" if $port != 80; print $sock join("\015\012" => "GET $path HTTP/1.0", "Host: $netloc", "User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.7.6) Gecko/20050411 Firefox/1.0.2", "", ""); my $buf = ""; my $n; 1 while $n = sysread($sock, $buf, 8*1024, length($buf)); return undef unless defined($n); if ($buf =~ m,^HTTP/\d+\.\d+\s+(\d+)[^\012]*\012,) { my $code = $1; if ($code =~ /^30[1237]/ && $buf =~ /\012Location:\s*(\S+)/i) { # redirect # my $url = $1; return undef;# if $loop_check{$url}++; # return trivial_get($url, $host, $port, $path); } if ($code !~ /^2/) { print STDERR "Error $code\n"; } return undef unless $code =~ /^2/; $buf =~ s/.+?\015?\012\015?\012//s; # zap header } return $buf; } our($depth) = 0; our($np) = qr{ \[ (?: (?> [^][]+ ) | (??{ $np }) )* \] }x; sub send_line($$$$;$) { my($self,$line,$nick,$dest) = @_; unless ($IdNicks{$nick} > 0) { return; } $self->privmsg($dest, &handle_line||""); } ## ## # Arg 1: $self (object) # # Arg 2: the incoming line (string) # # Arg 3: nick who sent it (string) # # Arg 4: where to send response # ## ## sub handle_line($$$$;$) { my($self,$line,$nick,$dest,$prefix) = @_; my($wordy) = ($nick eq $dest); $prefix = "" unless defined($prefix); if ($line =~ /^\[.*\]$/) { $line =~ s/^\[//; $line =~ s/\]$//; } if ($depth >= 20) { return "... no, I'm not going to crash."; } if ($nick ne "hamlin") { $depth++; $line =~ s/[~`]($np)/handle_line($self,$1,$nick,$dest)||""/egx; #`]//;# to appease xemacs $depth--; } my(@words) = split/\s+/, $line; my($rest) = join " ", @words[1..$#words]; my($nickok) = 0; if (grep { /^\Q$nick\E$/i } (@GoodNicks)) { $nickok = 1; unless (exists $IdNicks{$nick} and $IdNicks{$nick}>0) { $IdNicks{$nick} = 0; $self->privmsg("NickServ", "list $nick"); $self->privmsg($nick, "You must be identified to use the privileged parts of the bot."); $self->schedule(2, \&send_line, $line, $nick, $dest); $self->privmsg($nick, "If you are, wait a few seconds."); return; } } if ($nick eq "hamlin") { $nickok = 1; } $words[0] = lc $words[0]; if ($words[0] eq "literal") { if (exists $Factoids{$rest}) { my($reply) = $Factoids{$rest}; $reply =~ s/^is\s+//; return "$reply"; } return "I literally don't know what you're talking about."; } if ($words[0] eq "setkarma") { if ($nick ne "hamlin") { bad $nick; return "Loophole closed. :-)"; } $Karma{$words[1]} = int($words[2]); return; } if ($words[0] eq "braindump") { $self->privmsg($nick, "I know about ".join(", ", keys(%Factoids))."."); return; } if ($words[0] eq "say") { return "$rest"; } if ($words[0] eq "latest") { my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time()); $year += 1900; $month = sprintf "%02d", $mon+1; $day = sprintf "%02d", $mday; return "Kernel: http://izilla.elwiki.com/builds/$year-$month-$day-kernel.bin.gz || Podzilla: http://izilla.elwiki.com/builds/$year-$month-$day-podzilla.gz || Remember to gunzip the files. If podzilla looks corrupted, check if the first four letters are 'bFLT'; if so, it's not compressed."; } if ($words[0] eq "wiki" or $words[0] eq "wikisearch") { SEARCH: { if (!$rest) { return "Use the WIKI. http://izilla.elwiki.com/"; } else { if ($words[0] ne "wikisearch") { $content = get("http://izilla.elwiki.com/".uri_escape($rest)); if (defined($content) && $content !~ /currently no text in this page/) { $retstr = "$rest (http://izilla.elwiki.com/".uri_escape($rest).") [".length($content)." bytes]"; $self->privmsg($dest, $retstr); return ""; } } $content = get("http://izilla.elwiki.com/Special:Search?search=". uri_escape($rest)."&fulltext=Search"); if (!defined($content)) { return "Error fetching "; } if ($content =~ /unsuccessful search/) { return "No matches. (By the way, words <= 3 letters aren't indexed.)"; } my($firstmatch) = 1; my($infosent) = 0; my($result) = 1; my($results) = 5; while ($content =~ m[
  • (.*?) \((\d+) bytes\)]g) { $retstr = "$2 (http://izilla.elwiki.com$1) [$3 bytes]"; if ($dest eq $nick and $words[0] eq "wikisearch") { $retstr = "$result. ".$retstr; } if ($firstmatch) { $self->privmsg($dest, $retstr); $firstmatch = 0; } else { if (!$infosent and $dest ne $nick) { $self->privmsg($dest, "I'll /msg you the next @{[$results-1]} results."); $infosent = 1; } $self->privmsg($nick, $retstr); } last if $result >= $results or $words[0] ne "wikisearch"; $result++; } if ($firstmatch) { return "No match, apparently (bug in hamlin)." } return ""; } }} if ($words[0] eq "google") { $dst = ""; $longlist = 0; $summfirst = 0; if ($nick eq $dest) { $dst = $nick; $longlist = 1; $summfirst = 0; } elsif ($rest =~ /for me/) { $rest =~ s/\s*for me//; $dst = $nick; $longlist = 1; $summfirst = 1; } elsif ($rest =~ /for (\S+)/) { $dst = $1; $rest =~ s/\s*for (\S+)//; $longlist = 1; $summfirst = 1; } else { $dst = $dest; $longlist = 0; $summfirst = 1; } $content = trivial_get("www.google.com", 80, "/search?hl=en&q=".uri_escape($rest)."&btnG=Google+Search"); if (!defined($content)) { return "Error fetching "; } if ($content =~ /did not match any documents/) { return "No match."; } $content =~ s/&#(\d+);/chr($1)/eg; my($firstmatch) = 1; my($infosent) = 0; my($result) = 1; my($results) = 5; while ($content =~ m[

    .*?(.*?).*?(.*?)
    ]sg) { $retstr = "$2 ($1): $3"; $retstr =~ s|||g; if (length $retstr > 200) { $retstr = substr($retstr,0,197)."..."; } if ($firstmatch and $summfirst) { $self->privmsg($dest, $retstr); $firstmatch = 0; } if ($longlist) { $retstr = "$result. ".$retstr; } if (!$infosent and $longlist and $summfirst) { $self->privmsg($dest, "I'll /msg you the next @{[$results-1]} results."); $infosent = 1; } if ($longlist) { $self->privmsg($dst, $retstr); } last if $result >= $results or !$longlist; $result++; } if ($firstmatch and $summfirst) { return "No match, apparently (bug)." } return ""; } # if ($words[0] eq "countdown") { # my($thing) = $words[1]; # if ($line =~ /.*in\s+(.+)/) { # my($offset) = $1; # $offset =~ s/(\d+)/+$1/g; # $offset =~ s/days?/*86400/g; # $offset =~ s/weeks?/*86400*7/g; # $offset =~ s/months?/*86400*30/g; # $offset =~ s/years?/*86400*365/g; # $offset =~ s/(\s+|[a-zA-Z`$()]+)//g; # $Countdowns{$words[1]} = time() + eval($offset); # $CountdownHelpers{$words[1]} = []; # } elsif ($line =~ /.*at\s+(\d+)/) { # $Countdowns{$words[1]} = $1; # $CountdownHelpers{$words[1]} = []; # } elsif (!exists $Countdowns{$words[1]}) { # return "I don't know anything about a countdown to $words[1]."; # } # return "Tentative release date for $thing: ".localtime($Countdowns{$words[1]}); # } # if ($words[0] eq "when") { # $Countdowns{$words[1]} += 86400*30; # my($asker) = $dest; # if ($asker =~ /^#/) { # $asker = $words[2]; # } # push @{$CountdownHelpers{$words[1]}}, $asker; # if (defined($prefix) and $prefix =~ /^#/) { # $dest = $prefix; # } # $self->privmsg($dest, "Tentative release date for $words[1]: ".localtime($Countdowns{$words[1]})); # $self->privmsg($dest, "Some of those responsible for the delay: ".join(', ', @{$CountdownHelpers{$words[1]}})); # return ""; # } # if ($words[0] eq "blame") { # push @{$CountdownHelpers{$words[3]}}, $words[1]; # $self->privmsg($dest, "Tentative release date for $words[3]: ".localtime($Countdowns{$words[3]})); # $self->privmsg($dest, "Some of those responsible for the delay: ".join(', ', @{$CountdownHelpers{$words[3]}})); # return ""; # } # # if ($words[0] eq "nocountdown") { # delete $Countdowns{$words[1]}; # delete $CountdownHelpers{$words[1]}; # return "Countdown $words[1] deleted."; # } if ($words[0] eq "karma") { if (exists $Karma{$words[1]}) { if ($Karma{$words[1]} >= 1000000) { return "$words[1]'s karma is infinitely good."; } elsif ($Karma{$words[1]} <= -1000000) { return "$words[1]'s karma is infinitely bad."; } return "$words[1]'s karma is $Karma{$words[1]}."; } return "$words[1] has no karma."; } if ($words[0] eq "extol") { if (!$nickok) { return; } $Karma{$words[1]} = 10000000; return; } if ($words[0] eq "abhor") { if (!$nickok) { return; } $Karma{$words[1]} = -10000000; return; } if ($words[0] eq "excellent") { if (!$nickok) { return; } if ($words[1] eq $nick) { $self->privmsg($nick, "You can't change your own karma."); return; } $Karma{$words[1]} = 0 unless exists $Karma{$words[1]}; $Karma{$words[1]} += 3; return ($wordy?"$words[1]'s karma is now $Karma{$words[1]}.":""); } if ($words[0] =~ /\+\+$/) { $words[0] =~ s/\+\+$//; ($words[1],$words[0]) = ($words[0],"good"); } if ($words[0] =~ /--$/) { $words[0] =~ s/--$//; ($words[1],$words[0]) = ($words[0],"bad"); } if ($words[0] eq "good") { if ($words[1] eq $nick) { $self->privmsg($nick, "You can't change your own karma."); return; } $Karma{$words[1]} = 0 unless exists $Karma{$words[1]}; $Karma{$words[1]}++; return ($wordy?"$words[1]'s karma is now $Karma{$words[1]}.":""); } if ($words[0] eq "bad") { if ($words[1] eq $nick) { $self->privmsg($nick, "You can't change your own karma."); return; } $Karma{$words[1]} = 0 unless exists $Karma{$words[1]}; $Karma{$words[1]}--; return ($wordy?"$words[1]'s karma is now $Karma{$words[1]}.":""); } if ($words[0] eq "terrible") { if (!$nickok) { return; } if ($words[1] eq $nick) { $self->privmsg($nick, "You can't change your own karma."); return; } $Karma{$words[1]} = 0 unless exists $Karma{$words[1]}; $Karma{$words[1]} -= 3; return ($wordy?"$words[1]'s karma is now $Karma{$words[1]}.":""); } if ($words[0] eq "voices") { return "Listening to: < @GoodNicks >"; } if ($words[0] eq "listen") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } push @GoodNicks, $words[1]||""; return ($wordy?"Now listening to $words[1]. Listening to: < @GoodNicks >":""); } if ($words[0] eq "ignore") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } my($badnick) = $words[1]||""; @GoodNicks = grep { !m/^\Q$badnick\E$/ } (@GoodNicks); if (!scalar @GoodNicks) { @GoodNicks = ( $nick ); } return ($wordy?"Now ignoring $badnick. Listening to: < @GoodNicks >":""); } if ($words[0] eq "forget") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } if (exists $Factoids{$rest}) { delete $Factoids{$rest}; return ($wordy?"I forgot about $rest, $nick.":""); } return ($wordy?"I didn't know anything about $rest, $nick.":""); } if ($words[0] eq "todo") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } push @Todos, { id => ++$TodoLastID, name => $words[1], priority => $words[2], desc => join(" ", @words[3..$#words]) }; my($ret) = $TodoLastID.". @".$words[2]." <".$words[1]."> ".$Todos[$#Todos]{desc}; @Todos = sort { $b->{priority} <=> $a->{priority} } @Todos; return $ret; } if ($words[0] eq "todump") { my($dumpy) = Data::Dumper::Dumper(\@Todos); $dumpy =~ s/\n/ \\ /g; return $dumpy; } if ($words[0] eq "todone") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } my($oldnum) = scalar @Todos; @Todos = grep { $_->{id} != $words[1] } @Todos; return ($oldnum - scalar @Todos )." todos killed off."; } if ($words[0] eq "todos") { if ($rest =~ /^\s*$/ || $rest =~ /for (me|\w+)/) { my($target) = $1; $target = "" unless defined($target); $target = $nick if $target eq "me"; if (scalar(@Todos) > 0) { my($ret); if ($target eq $nick) { $ret = "Your issues"; } elsif ($target) { $ret = "${target}'s issues"; } else { $ret = "Most pressing issues"; } my($maxnr) = 5; my($comma) = 0; foreach (@Todos) { last if !$maxnr; next if $target && $target !~ /$_->{name}_*/; $ret .= ($comma++? ", " : ": "); if (!$target) { $ret .= "<03".$_->{name}."> "; } $ret .= "(#".$_->{id}.") ".$_->{desc}; $maxnr--; } $ret .= ", ..." unless $maxnr; if ($maxnr == 5) { return "Nothing todo for $target."; } return $ret; } return "Nothing todo."; } elsif ($words[1] =~ /#(\d+)/) { my($id) = $1; foreach (@Todos) { if ($_->{id} == $id) { return "<03".$_->{name}."> ".$_->{desc}; } } return "Couldn't find it."; } return "Huh?"; } if ($words[0] eq "part") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } $self->part ($words[1], $nick); return; } if ($words[0] eq "join") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } $self->join ($words[1], $words[2]); return ($wordy?"Joined $words[1].":""); } if ($words[0] eq "write") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } open FACTOIDS, ">factoids.txt"; my($nfac,$nkar,$nblame) = (0,0,0); foreach (keys %Factoids) { print FACTOIDS "$_ $Factoids{$_}\n"; $nfac++; } foreach (keys %Karma) { print FACTOIDS "setkarma $_ $Karma{$_}\n"; $nkar++; } foreach (@GoodNicks) { print FACTOIDS "listen $_\n"; } foreach (@Todos) { print FACTOIDS "todo ".$_->{name}." ".$_->{priority}." ".$_->{desc}."\n"; } # foreach (keys %Countdowns) { # print FACTOIDS "countdown $_ at $Countdowns{$_}\n"; # } # foreach (keys %CountdownHelpers) { # my($ctdn) = $_; # for (@{$CountdownHelpers{$_}}) { # print FACTOIDS "blame $_ for $ctdn\n"; # $nblame++; # } # } close FACTOIDS; return "Wrote $nfac factoids".($nkar?" and $nkar karma data":"")."."; } if ($words[0] eq "mode") { if (!$nickok) { terrible $nick; return; } if (substr($words[1],0,1) eq "#") { $dest = $words[1]; $rest = join " ", @words[2..$#words]; } $self->mode ($dest, $rest); return; } if ($words[0] eq "kick") { my($whom); if (!$nickok) { terrible $nick; return; } if (substr($words[1],0,1) eq "#") { $dest = $words[1]; $whom = $words[2]; $rest = join " ", @words[3..$#words]; } else { $whom = $words[1]; $rest = join " ", @words[2..$#words]; } $self->kick ($dest, $whom, $rest); return; } if ($words[0] eq "leave") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } $self->quit ($nick); sleep(2); open FACTOIDS, ">factoids.txt"; foreach (keys %Factoids) { print FACTOIDS "$_ $Factoids{$_}\n"; } foreach (keys %Karma) { print FACTOIDS "setkarma $_ $Karma{$_}\n"; } foreach (@GoodNicks) { print FACTOIDS "listen $_\n"; } foreach (@Todos) { print FACTOIDS "todo ".$_->{name}." ".$_->{priority}." ".$_->{desc}."\n"; } # foreach (keys %Countdowns) { # print FACTOIDS "countdown $_ at $Countdowns{$_}\n"; # } # foreach (keys %CountdownHelpers) { # my($ctdn) = $_; # for (@{$CountdownHelpers{$_}}) { # print FACTOIDS "blame $_ for $ctdn\n"; # } # } close FACTOIDS; close LOG; exit(0); } if ($words[0] eq "nick") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } $self->nick ($words[1]); return; } if ($words[0] eq "qquit") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } $self->quit ("$nick"); close LOG; exit 0; } if ($words[0] eq "qupdate") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } $self->quit ("Restarted by $nick"); close LOG; sleep 2; exec "./$0"; } if ($words[0] eq "update") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } open FACTOIDS, ">factoids.txt"; foreach (keys %Factoids) { print FACTOIDS "$_ $Factoids{$_}\n"; } foreach (keys %Karma) { print FACTOIDS "setkarma $_ $Karma{$_}\n"; } foreach (@GoodNicks) { print FACTOIDS "listen $_\n"; } foreach (@Todos) { print FACTOIDS "todo ".$_->{name}." ".$_->{priority}." ".$_->{desc}."\n"; } # foreach (keys %Countdowns) { # print FACTOIDS "countdown $_ at $Countdowns{$_}\n"; # } # foreach (keys %CountdownHelpers) { # my($ctdn) = $_; # for (@{$CountdownHelpers{$_}}) { # print FACTOIDS "blame $_ for $ctdn\n"; # } # } close FACTOIDS; $self->quit ("Restarted by $nick"); close LOG; exec "./$0"; } if ($words[0] eq "tell") { if (!$nickok) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } if ($line =~ /tell\s+(\S+)\s+(?:about\s+)?(.*)/) { $self->privmsg ($1, handle_line($self,$2,$nick,$1)||""); return; } } if ($words[0] eq "inform") { if (!$nickok && $words[1] =~ /^#/) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } if ($line =~ /inform\s+(\S+)\s+(?:about\s+)?(.*)/) { my($res) = (handle_line($self,$2,$nick,$1,$dest)||""); if ($res ne "") { return "$1, ".$res; } return ""; } } if ($line =~ /(.+?)\s+(is.+|means.+|are.+)/) { my($word,$factoid) = ($1,$2); $word =~ s/^fact\s+//; if (!$nickok and $nick ne "hamlin" and $word ne $nick) { $self->privmsg($nick, "You aren't allowed to do that."); bad $nick; return; } $Factoids{$word} = $factoid; return ($wordy?"OK, $nick.":""); } keys %Factoids; # resets `each' iterator # Iterate through the whole factoid list. while (($k, $v) = each %Factoids) { my($key) = $k; $key =~ s/([][.^\$+*?])/\\$1/g if $key =~ /[][.^\$+*?]/; $key =~ s/\\\$\d+/(.*?)/g; # fix arg specifier my($input) = $line; $input=~s/(^\s+|\s+$)//; # strip whitespace if ($input =~ /^$key$/i) { my($fact) = $v; my($one,$two,$three,$four,$five) = ($1,$2,$3,$4,$5); $fact =~ s/\$1/$one/g if $one; $fact =~ s/\$2/$two/g if $two; $fact =~ s/\$3/$three/g if $three; $fact =~ s/\$4/$four/g if $four; $fact =~ s/\$5/$five/g if $five; $fact =~ s/^\s+//; $fact =~ s/\$who/$nick/gi; my(@factoids) = split /\s \\ \s/x, $fact; if (scalar @factoids > 1) { my($prefix) = "$key "; if ($fact =~ //) { $prefix = ""; $fact =~ s/\s*//; $fact =~ s/(is|means|are)\s+//; } @factoids = split /\s \\ \s/x, $fact; foreach (@factoids) { my($factoid) = $_; my($suffix) = (($factoid eq $factoids[$#factoids])? " [from $nick]" : ""); sleep(1); $self->privmsg($dest, $prefix.$factoid.($wordy? "" : $suffix)); $prefix = ""; } return ""; } else { if ($fact =~ //) { $fact =~ s/\s*//; $fact =~ s/(is|means|are)\s+//; return "$fact ".($wordy?"":"[from $nick]"); } elsif ($fact =~ //) { $fact =~ s/\s*//; $fact =~ s/(is|means|are)\s+//; $self->ctcp('action',$dest,$fact); return; } else { return "$key $fact ".($wordy?"":"[from $nick]"); } } } } my(@goodwords) = split/\s+/, $line; my($bestfact,$bestnum) = ("",0); my($num); keys %Factoids; while (($k, $v) = each %Factoids) { $num = 0; for (@goodwords) { my($word) = $_; my($kk) = $k; $num += ($kk =~ s/\Q$word\E//g); } if ($num > $bestnum) { $bestnum = $num; $bestfact = $k; } } if ($bestnum) { return "I assume you meant $bestfact. ".handle_line($self,$bestfact,$nick,$dest)||""; } if ($wordy) { return "Sorry, $nick, I don't know anything about $line."; } return; } ### The handlers sub on_connect { my $self = shift; $self->join("#izilla.bot"); $self->join("#izilla"); # Ha! You thought you'd actually get the password! :-) $self->privmsg("nickserv", "identify izilla"); print "Joined #izilla and #izilla.bot.\n"; print "Loading factoids... "; if (-e "factoids.txt") { open FACTOIDS, "factoids.txt"; while () { chomp; handle_line($self, $_, "hamlin", "nonexistent"); } close FACTOIDS; } print "Ready.\n"; } sub on_init { my ($self, $event) = @_; my (@args) = ($event->args); shift(@args); print "*** @args\n"; } sub on_join { my ($self, $event) = @_; my (@args) = ($event->args); my (@to) = ($event->to); print LOG "-!- join ".$event->nick."\n"; $NicksHere{$to[0]} = {} unless exists $NicksHere{$to[0]}; $NicksHere{$to[0]}{$event->nick} = 1; my($nick) = $event->nick; if (grep { /\Q$nick\E/ } (@GoodNicks)) { $self->privmsg("NickServ", "list ".$event->nick); $IdNicks{$event->nick} = 0; } } sub on_nick { my ($self, $event) = @_; my (@args) = ($event->args); my (@to) = ($event->to); $NicksHere{$to[0]}{$event->nick} = 0; $NicksHere{$to[0]}{$args[0]} = 1; print LOG "-!- ".$event->nick." is now known as ".$args[0]."\n"; $IdNicks{$event->nick} = 0; } sub on_part { my ($self, $event) = @_; my (@args) = ($event->args); my (@to) = ($event->to); $NicksHere{$to[0]}{$event->nick} = 0; print LOG "-!- part ".$event->nick." (@args)\n"; $IdNicks{$event->nick} = 0; } sub on_notice { my($self,$event) = @_; my($nick) = $event->nick; my($arg) = $event->args; if (lc $nick eq "nickserv" and $arg =~ /^(\S+).*ONLINE/) { $IdNicks{$1} = 1; print LOG "-!- $1 is identified.\n"; } } sub on_msg { my($self,$event) = @_; my ($nick) = ($event->nick); my ($arg) = ($event->args); return if $nick =~ /hamlin/; print LOG "[$nick] $arg\n"; $arg =~ s/^[~`]+//; $self->privmsg($nick, handle_line($self, $arg, $nick, $nick)||""); } my(%Warned); my($thisnick,$lastnick) = ('',''); sub on_public { my($self,$event) = @_; my @to = $event->to; my ($nick) = ($event->nick); my ($arg) = ($event->args); if ($nick ne $thisnick) { $lastnick = $thisnick; $thisnick = $nick; } return if $nick =~ /hamlin/; print LOG "<$nick> $arg\n"; if ($arg =~ /(^|\W)(thx|thks|tks|tnx|thanks|thank\s*you)(\W|$)/) { my($found) = 0; for (keys %Karma) { if ($arg =~ /(^|\W)($_)(\W|$)/) { good $2; $found = 1; last; } } good $lastnick unless $found; } if ($arg =~ /(\S+)[:,] /) { my($x) = $1; if (exists $NicksHere{$to[0]} and exists $NicksHere{$to[0]}{$x} and ($NicksHere{$to[0]}{$x} == 0)) { $self->privmsg($to[0], "I think he left."); $NicksHere{$to[0]}{$x} = 1; # don't say it again } } if ($arg =~ /[Ii].*(working\s+on|writing)/) { excellent $nick; } if ($arg =~ /[Ii].*releas(e|ing)/) { if ($arg =~ /4g/) { bad $nick; } else { excellent $nick; } } if ($arg =~ /(when|how\s+close|how\+long).*(4[Gg]|fourth[- ]gen(eration)?|photo|ipod.*color|color.*ipod).*support(ed)?/i) { bad $nick; } $ReverseMode = 1 if $arg =~ /esrever\s*([~`]|[:,]toblpi)$/ or $arg =~ /^([~`]|hamlin[,:])\s*reverse/; $ReverseMode = 0 if $arg =~ /drawrof\s*([~`]|[:,]toblpi)$/ or $arg =~ /^([~`]|hamlin[,:])\s*forward/; $arg = reverse $arg if $ReverseMode; if ($arg =~ /^([~`]|hamlin[,:])/) { $arg =~ s/^([~`]+|hamlin[,:]\s*)//; my($dest) = $to[0]; if (!grep { /^\Q$nick\E$/ } (@GoodNicks)) { $dest = $nick; } if ($ReverseMode) { $self->privmsg($dest, scalar reverse(handle_line($self, $arg, $nick, $dest)||"")); } else { $self->privmsg($dest, handle_line($self, $arg, $nick, $dest)||""); } } elsif ($arg =~ /~\[.*\]/) { if (!grep { /^\Q$nick\E$/ } (@GoodNicks)) { return; } $max = 3; while ($arg =~ /~($np)/g) { if (!$max) { $self->privmsg($nick, "Only up to 3 offhand substitutions per line, please."); last; } if ($ReverseMode) { $self->privmsg($to[0], scalar reverse(handle_line($self, $1, $nick, $to[0])||"")); } else { $self->privmsg($to[0], handle_line($self, $1, $nick, $to[0])||""); } $max--; } } } sub on_ping { my($self,$event) = @_; $self->ctcp_reply($event->nick, join(' ', $event->args)); } ### Set up handlers $conn->add_handler('cping', \&on_ping); $conn->add_handler('msg', \&on_msg); $conn->add_handler('public',\&on_public); $conn->add_handler('umode', \&on_umode); $conn->add_handler('notice',\&on_notice); $conn->add_handler('names', \&on_names); $conn->add_handler('nick', \&on_nick); $conn->add_handler('join', \&on_join); $conn->add_handler('part', \&on_part); $conn->add_global_handler([ 251,252,253,254,302,255 ], \&on_init); $conn->add_global_handler(376, \&on_connect); $conn->add_global_handler(433, \&on_nick_taken); print "Starting...\n"; $irc->start;