#!/usr/bin/perl -w # # this little bot will watch some chans and speak in only one # at somewhat-random intervals by taking what it's learned # from everything said in all the chans so far # # this is a very ugly and basic and badly coded version # please don't judge my code on this :) # (more code at http://code.lucidx.com) # # -Samy Kamkar + code from mark_v_shaney_bigram.pl by Rosie Jones # http://www-2.cs.cmu.edu/~rosie/yapc/src/ use Socket; use Storable; use strict; my $server = "irc.openprojects.net"; # server to connect to my $nnick = "radagast"; # nickname my $name = "radagast"; # real name my $mainchan = "#killallhumans"; # chan to talk in my @chans = ( "#wireless", "#slackware", "#perl" ); # other chans to JUST watch my $password = "morrisminor"; # you can /msg bot password (join|part|quit|mode) ... my $ratio = 0; # 1:$ratio - normal message to /me ratio (random) my $fewest = 2; # wait for $fewest messages to talk (fewest) my $rrand = 2; # also wait for rand($rrand) messages to talk (rand) my $datafile = "$nnick.dat"; # data file. my $cp_freq = 100; # how often to save to the data file. #### subs sub checkpoint { my $seen = shift; my $pid = fork; if (defined($pid) and not $pid) { store $seen => $datafile; exit; } } sub process { my ($seen, $data) = @_; $data =~ s/\b\W+\B//g; $data = lc($data); $data =~ s/://; my $lastword = "BEGIN_FILE"; my @words = split(/\s+/, $data); for my $word (@words, "END_FILE") { $seen->{$lastword}{$word}++; $seen->{$lastword}{WORD_COUNT}++; $lastword = $word; } return @words; } sub generate_next_word { my ( $seen, $lastword ) = @_; return "END_FILE" unless exists $seen->{$lastword}; my $rand = rand($seen->{$lastword}{WORD_COUNT}); my $probability_mass = 0; my $candidate; for $candidate ( keys %{$seen->{$lastword}} ) { next if $candidate eq "WORD_COUNT" or $candidate eq "BEGIN_FILE"; $probability_mass += $seen->{$lastword}{$candidate}; return $candidate if ($probability_mass > $rand); } return $candidate; } ##### main my $iteration = int(rand($rrand)) + $fewest; my $myit = 0; my $last_cp = $cp_freq; my $seen; if (-r $datafile) { $seen = retrieve $datafile; } else { $seen = {} } if (@ARGV) { process( $seen => $_ ) while <>; checkpoint $seen; exit; } defined(my $fork = fork()) || die "Can't fork, sorry\n"; ($fork) && die "Bot active on process $fork.\n"; while (1) { my $iaddr = inet_aton($server); my $paddr = sockaddr_in(6667, $iaddr); my $proto = getprotobyname('tcp'); socket(SOCK, PF_INET, SOCK_STREAM, $proto) || die "Cannot create socket\n"; connect(SOCK, $paddr) || die "Unable to connect\n"; select(SOCK); $| = 1; select('stdout'); print SOCK "USER $nnick $nnick $nnick :$name\n"; print SOCK "NICK $nnick\n"; while () { my ($fulladd, $what, $where, $data) = $_ =~ /^(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/; my ($nick) = (/^:(.+)!.+\@\S+\s/); if ($what =~ /002/) { print SOCK "JOIN $mainchan\n" if $mainchan; foreach (@chans) { print SOCK "JOIN $_\n"; } } elsif (/^PING(.*)$/) { print SOCK "PONG$1\n"; } elsif ($what =~ /PRIVMSG/) { if ($where !~ /^#/) { if ($data =~ /:\caVERSION/) { print SOCK "NOTICE $nick :\caVERSION mIRC32 v5.91 K.Mardam-Bey\ca\n"; } elsif ($data =~ /:$password JOIN (.*)$/) { foreach (split(/\s+/, $1)) { print SOCK "JOIN $_\n"; } } elsif ($data =~ /:$password PART (.*)$/) { foreach (split(/\s+/, $1)) { print SOCK "PART $_\n"; } } elsif ($data =~ /:$password QUIT (.*)$/) { my $why = $1; print SOCK "QUIT :$1\n"; checkpoint($seen); die $why; } elsif ($data =~ /:$password MODE (.*)$/) { print SOCK "MODE $1\n"; } elsif ($data =~ /:$password CHECKPOINT/) { checkpoint($seen); } } else { unless ( --$last_cp ) { checkpoint($seen); $last_cp = $cp_freq; } if ($data =~ /$nnick/ && $myit) { $myit += int(rand(($iteration/10)*9)); } my @words = process( $seen => $data ); if ($mainchan and $iteration <= $myit++) { my $type; $iteration = int(rand($rrand)) + $fewest; $myit = 0; if ($ratio and int(rand($ratio)) == 0) { $type = 0 } else { $type = 1 } my $message = ""; my $nextword; while ($nextword = splice( @words, int rand @words, 1 )) { last if exists $seen->{$nextword}; $nextword = ""; } $nextword ||= "BEGIN_FILE"; while ($nextword ne "END_FILE") { $nextword = generate_next_word( $seen => $nextword ); $message .= "$nextword " unless ($nextword eq "END_FILE"); } chop($message); $message .= (".","?","!")[int rand 3]; $type = not ( $message =~ s/^\W*action\s+//gios ); if ($type) { print SOCK "PRIVMSG $mainchan :$message\n"; } else { print SOCK "PRIVMSG $mainchan :\cAACTION $message\cA\n"; } } } } } }