User:XLinkBot/Code/LinkWatcher.pl

From Wikipedia, the free encyclopedia

#!/usr/bin/perl

use strict;
use POE qw(Component::IRC Component::IRC::Plugin::BotAddressed Component::Server::TCP);
use Socket;
use DBI;
use Data::Dumper;
use perlwikipedia;

my %settings;
my @editQueue;

my $username = "LinkWatcher";
my $editor=Perlwikipedia->new($username,$username);
my $counter=0;

my $editcounter=0;
my $watchedspacecounter=0;
my $totallinks=0;
my $whitelinks=0;
my $linkadditions=0;
my $blacklinks=0;
my $redlinks=0;
my $whiteuser=0;
my $ratio1=0;
my $ratio2=0;
my $ratio3=0;
my $ratio4=0;
my $ratio5=0;
my $ratio6=0;
my $ratio7=0;
my $ratio8=0;
my $ratio9=0;
my $ratio10=0;
my $starttime = time();

print "Reading config file...";
open (CONFIG,"<linkwatcher-config") or die "Can't open LinkWatcher config: $!";
foreach (<CONFIG>) {
    unless (/^#/) {
        if(/(.+?)=(.+)/) {
            $settings{$1}=$2;
        }
    }
}   
close (CONFIG); 

print "done\n";

print "Initializing IRC subsystem...";
my $ircsettings= {
        $settings{'rcserver'}  => { port => 6667, },
        $settings{'ircserver'} => { port => $settings{'ircport'}, channels=> [ $settings{'ircreportchannel'}, $settings{'ircbotchannel'} ], },
};

foreach my $server ( keys %{ $ircsettings } ) {
        POE::Component::IRC->spawn( 
                alias   => $server, 
                nick    => $settings{'ircnick'},
                ircname => $settings{'ircname'},  
        username=> $settings{'ircusername'},
        );
}
my @rcchannels = split( /\s,?/, $settings{'rcchannels'} );
print "RC channels are: " . join(' ',@rcchannels) . "\n";
print "done\n";

foreach my $parserNumber ( 1 .. $settings{'numberofparsers'} ) {

    print "Starting slave $parserNumber...";

    system("perl","LinkParser.pl",$settings{'serverport'});

    print "done\n";
}

print "Initializing LinkWatcher2 master server on port $settings{'serverport'}...";
POE::Component::Server::TCP->new(
    Port            => $settings{'serverport'},
    ClientInput         => \&slave_input,
    ClientDisconnected  => \&slave_disconnect,
);
print "done\n";

POE::Session->create(
        package_states => [
                'main' => [ qw(_start irc_registered irc_001 irc_public irc_bot_addressed irc_disconnected) ],
        ],
        heap => { config => $ircsettings },
);

print "Connecting to MySQL...";
my $mysql;
my $mysql=DBI->connect("dbi:mysql:$settings{'mysqldb'};$settings{'mysqlhost'}",$settings{'mysqluser'},$settings{'mysqlpassword'}) or die "Can't connect to MySQL: $DBI::errstr";
$mysql->{mysql_auto_reconnect} = 1;
print "done\n";

my $rulespage=$editor->get_text($settings{'blacklist'});
my @wikiblacklist = split(/\n/,$rulespage);

print "Starting LinkWatcher2...\n";

POE::Kernel->run();
exit 0;

sub _start {
        my ($kernel,$session) = @_[KERNEL,SESSION];
        # Send a POCOIRC_REGISTER signal to all poco-ircs
        $kernel->signal( $kernel, 'POCOIRC_REGISTER', $session->ID(), 'all' );
    undef;
}

sub irc_registered {
        my ($kernel,$heap,$sender,$irc_object) = @_[KERNEL,HEAP,SENDER,ARG0];

        my $alias = $irc_object->session_alias();

    $irc_object->plugin_add( 'BotAddressed', POE::Component::IRC::Plugin::BotAddressed->new( eat=> 1 ) );

        my %conn_hash = (
                server => $alias,
        port   => $heap->{config}->{ $alias }->{port},
        );

        # In any irc_* events SENDER will be the PoCo-IRC session
        $kernel->post( $sender, 'connect', \%conn_hash ); 

    undef;
}

sub irc_001 {
        my ($kernel,$heap,$sender) = @_[KERNEL,HEAP,SENDER];

        # Get the component's object at any time by accessing the heap of
        # the SENDER
        my $poco_object = $sender->get_heap();
        print "Connected to ", $poco_object->server_name(), "\n";

    if ($poco_object->server_name() eq $settings{'rcserver'}) {
        my $alias = $poco_object->session_alias();

        $kernel->post( $sender => join => $_ ) for @rcchannels;
    }

    elsif ($poco_object->server_name() eq $settings{'ircserver'}) {
        $kernel->post( $sender => privmsg => 'NickServ',"identify $settings{'ircpassword'}" );
        sleep 4;
        $kernel->post( $sender => join => $settings{'ircreportchannel'} ) if $settings{'ircreportchannel'};
        $kernel->post( $sender => join => $settings{'ircbotchannel'} ) if $settings{'ircbotchannel'};
    }
    undef;
}

sub irc_public {
    my ($kernel,$sender,$who,$where,$message) = @_[KERNEL,SENDER,ARG0,ARG1,ARG2];
    my $nick =  ( split /!/, $who )[0];
    my $cloak = ( split /@/, $who )[1];
    $message=~ s/\cC\d{1,2}(?:,\d{1,2})?|[\cC\cB\cI\cU\cR\cO]//g;
    my $page;
    my $lang;
    my $diffurl;
    my $user;
    my $size;
    my $space;
    my $domain1;
    my $domain;
    my $domainpage;
    my $garbage;
    $counter++;
    if ($settings{'source'} eq "Wiki") {
        if ($counter > $settings{'refreshevery'}) {
            my $rulespage=$editor->get_text($settings{'blacklist'});
            my @wikiblacklist = split(/\n/,$rulespage);
            $counter=0;
        }
        if (($message =~ m/$settings{'blacklist'}/) && ($nick eq "rc")) {
            my $rulespage=$editor->get_text($settings{'blacklist'});
            my @wikiblacklist = split(/\n/,$rulespage);
            $counter=0;
            $kernel->post( $settings{'ircserver'} => privmsg => $settings{'ircreportchannel'} => "[[$settings{'blacklist'}]] edited." );
        }
        if ( $message =~ m/^!refresh/) {
            my $rulespage=$editor->get_text($settings{'blacklist'});
            my @wikiblacklist = split(/\n/,$rulespage);
            $counter=0;
        }
    }
    if ( $message =~ m/!info/) {
        my $currenttime = time();
        my $timedifference = $currenttime - $starttime;
        $timedifference = $timedifference/60;
        my $printtimedifference = int($timedifference);
        my $ratio1 = int(10000 * $watchedspacecounter/$editcounter)/100 unless ($editcounter == 0);
        my $ratio2 = int(10000 * $whiteuser/$watchedspacecounter)/100 unless ($watchedspacecounter == 0);
        my $ratio3 = int(10000 * $linkadditions/$watchedspacecounter)/100 unless ($watchedspacecounter == 0);
        my $ratio4 = int(10000 * $whitelinks/$totallinks)/100 unless ($totallinks == 0);
        my $ratio5 = int(10000 * $redlinks/$totallinks)/100 unless ($totallinks == 0);
        my $ratio6 = int(10000 * $blacklinks/$totallinks)/100 unless ($totallinks == 0);
        my $editsperminute = int($editcounter/$timedifference) unless ($timedifference == 0);
        my $watchededitsperminute = int($watchedspacecounter/$timedifference) unless ($timedifference == 0);
        my $linksperminute = int($totallinks/$timedifference) unless ($timedifference == 0);
        my $blacklinksperminute = int($blacklinks/$timedifference) unless ($timedifference == 0);
        my $whitelinksperminute = int($whitelinks/$timedifference) unless ($timedifference == 0);
        my $redlinksperminute = int($redlinks/$timedifference) unless ($timedifference == 0);
        $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "LinkWatcher info: $printtimedifference minutes active: E(T): $editcounter ($editsperminute PM); E(W): $watchedspacecounter ($ratio1%; $watchededitsperminute PM); E(L): $linkadditions ($ratio3%); U(W): $whiteuser ($ratio2%); L(T) $totallinks ($linksperminute PM); L(W): $whitelinks ($ratio4%; $whitelinksperminute PM); L(R): $redlinks ($ratio5%; $redlinksperminute PM); L(B): $blacklinks ($ratio6%; $blacklinksperminute PM). Sourcing: $settings{'source'}" );
    }
    if ($message=~m/\[\[(.+?)\]\] M?\s*?http:\/\/(.+?)\.(.+?)\/(.+?) \* (.+?) \* \(([^)]+)\)/) {
        $editcounter++;
        $page = $1;
        $lang = $2;
        $domain1 = $3;
        $diffurl = "http://$lang.$domain1/$4";
        $user = $5;
        $size = $6;
        if ($domain1 eq "org") {
            $domain1 = "$lang.$domain";
            $lang = "";
        }
        ($space,$garbage) = split(/:/,$1,2);
        if ($garbage eq "") {
           $space = "";
        }
        $domain = "";
        if ($domain1 eq "wiktionary.org") {
            $domain = "wikt:";
        }
        if ($domain1 eq "wikibooks.org") {
            $domain = "b:";
        }
        if ($domain1 eq "wikinews.org") {
            $domain = "n:";
        }
        if ($domain1 eq "wikisource.org") {
            $domain = "s:";
        }
        if ($domain1 eq "wikiquote.org") {
            $domain = "q:";
        }
        if ($domain1 eq "wikimedia.org")  {
            if ($space eq "species") {
                $domain = "wikispecies:";
            } elsif ($space eq "") {
                $domain = "";
            }
        }
        print ("Read: $domain1 - $domain - $page - $lang - $space - $diffurl - $user - $size\n");
        $domainpage = "$domain$lang:$page";
        if ( ($space eq "") || ($space eq "Category") || ($space eq "Template") || ($space eq "Categorie") || ($space eq "Sjabloon") ) {
            $watchedspacecounter++;
            unshift(@editQueue,{pagename=>$page,domain=>$domain,lang=>$lang,diffurl=>$diffurl,user=>$user,size=>$size});
        }
    }
}

sub irc_bot_addressed {
    my ( $kernel, $sender, $who, $where, $message ) = @_[ KERNEL, SENDER, ARG0, ARG1, ARG2 ];
    my $nick = ( split /!/, $who)[0];
    my $cloak = ( split /@/, $who )[1];
    my $channels;
    my $channel;
    my $channel2;
    my $oldchannel;
    my $newchannel;    
    unless ( $where->[0] eq $settings{'ircreportchannel'} ) {
        return;
    }

    if ( $message =~m/link (.+?) (.{1,3}) (.+?) (.+)/ ) {
        my $list = $1;
        my $operation = $2;
        my $link = $mysql->quote($3);
        my $reason;
        my $link = $mysql->quote($4);
        my $query;
        if ( $operation eq 'add' ) {
            $query = "INSERT INTO ";
        }
        elsif ( $operation eq 'del' ) {
            $query = "DELETE FROM ";
        }
        if ( $list eq 'wl' ) {
            $query .= "$settings{'mysqltableprefix'}whitelist ";
        }
        elsif ( $list eq 'rl' ) {
            $query .= "$settings{'mysqltableprefix'}redlist ";
        }
        elsif ( $list eq 'bl' ) {
            $query .= "$settings{'mysqltableprefix'}blacklist ";
        }
        else {
            return;
        }
        if ( $operation eq 'add' ) {
            $query .= "(rule,cloak,reason) VALUES ($link,$cloak,$reason)";
        }
        elsif ( $operation eq 'del' ) {
            $query .= "WHERE rule=$link";
        }
        &query($query);

        if ( $operation eq 'add' ) {
            $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "Item $link added to $list" );
        }
        elsif ( $operation eq 'del' ) {
            $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "Item $link removed from $list" );
        }
    }   
    if ( $message =~m/user (.+?) (.+)/ ) {
        my $operation = $1;
        my $user;
        my $user = $mysql->quote($2);
        my $query;
        if ( $operation eq 'add' ) {
            $query = "INSERT INTO ";
        }
        elsif ( $operation eq 'del' ) {
            $query = "DELETE FROM ";
        }
        $query .= "$settings{'mysqltableprefix'}users ";
        if ( $operation eq 'add' ) {
            $query .= "(username,status) VALUES ($user,'ignore')";
        }
        elsif ( $operation eq 'del' ) {
            $query .= "WHERE username=$user";
        }

        &query($query);

        if ( $operation eq 'add' ) {
            $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "user $user added to whitelist" );
        }
        elsif ( $operation eq 'del' ) {
            $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "user $user removed from whitelist" );
        }
    }

    if ( $message =~ m/^refresh/) {
        my $rulespage=$editor->get_text("User:XLinkBot/RevertList");
        my @wikiblacklist = split(/\n/,$rulespage);
        $counter=0;
    }
    
    if ( $message =~ m/^source (.+)/ ) {
        my $revertfrom = $1;
        if (lc($cloak) eq "wikimedia/beetstra" || lc($cloak) eq "wikimedia/versageek") {
            if ($revertfrom =~ m/(SQL|Wiki)/) {
                $settings{'source'} = $revertfrom;
                $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "Blacklist source is now $revertfrom." );
            } else {
                $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "'$revertfrom' is not a valid Blacklist source." );
            }
        }
        else {
            $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "I only trust Versageek and Beetstra to issue this command." );
        }
        my $rulespage=$editor->get_text("User:XLinkBot/RevertList");
        my @wikiblacklist = split(/\n/,$rulespage);
        $counter=0;
    }   
    
    
    if ($message=~ m/^quit$/) {
        my $currenttime = time();
        my $timedifference = $currenttime - $starttime;
        $timedifference = $timedifference/60;
        my $printtimedifference = int($timedifference);
        my $ratio1 = int(10000 * $watchedspacecounter/$editcounter)/100 unless ($editcounter == 0);
        my $ratio2 = int(10000 * $whiteuser/$watchedspacecounter)/100 unless ($watchedspacecounter == 0);
        my $ratio3 = int(10000 * $linkadditions/$watchedspacecounter)/100 unless ($watchedspacecounter == 0);
        my $ratio4 = int(10000 * $whitelinks/$totallinks)/100 unless ($totallinks == 0);
        my $ratio5 = int(10000 * $redlinks/$totallinks)/100 unless ($totallinks == 0);
        my $ratio6 = int(10000 * $blacklinks/$totallinks)/100 unless ($totallinks == 0);
        my $editsperminute = int($editcounter/$timedifference) unless ($timedifference == 0);
        my $watchededitsperminute = int($watchedspacecounter/$timedifference) unless ($timedifference == 0);
        my $linksperminute = int($totallinks/$timedifference) unless ($timedifference == 0);
        my $blacklinksperminute = int($blacklinks/$timedifference) unless ($timedifference == 0);
        my $whitelinksperminute = int($whitelinks/$timedifference) unless ($timedifference == 0);
        my $redlinksperminute = int($redlinks/$timedifference) unless ($timedifference == 0);
        $kernel->post( $settings{'ircserver'} => privmsg => $where->[0] => "Quiting: $printtimedifference minutes active: E(T): $editcounter ($editsperminute PM); E(W): $watchedspacecounter ($ratio1%; $watchededitsperminute PM); E(L): $linkadditions ($ratio3%); U(W): $whiteuser ($ratio2%); L(T) $totallinks ($linksperminute PM); L(W): $whitelinks ($ratio4%; $whitelinksperminute PM); L(R): $redlinks ($ratio5%; $redlinksperminute PM); L(B): $blacklinks ($ratio6%; $blacklinksperminute PM). Sourcing: $settings{'source'}" );
        if (($cloak eq 'wikimedia/Versageek') || ($cloak eq 'Wikimedia/Beetstra') ) {
            $kernel->signal($kernel, 'POCOIRC_SHUTDOWN', "Bye!");
            die "\nDied after quit!\n";
        } 
    }

    if ($message=~ m/^channels/ ) {                                # ask for which channels LinkWatcher is on
        $channels = join(", ",@rcchannels);
        $kernel->post( $sender => privmsg => $where->[0] => "$settings{ircname} listens on irc.wikimedia.org to $channels." );
    }

    if ($message=~ m/^show whitelisted users/ ) {                             
        $settings{'showwhitelistedusers'}=1;
        $kernel->post( $sender => privmsg => $where->[0] => "Showing whitelisted users" );
    }

    if ($message=~ m/^hide whitelisted users/ ) {                             
        $settings{'showwhitelistedusers'}=0;
        $kernel->post( $sender => privmsg => $where->[0] => "Hiding whitelisted users" );
    }

    if ($message=~ m/^show whitelisted links/ ) {                             
        $settings{'showwhitelistedlinks'}=1;
        $kernel->post( $sender => privmsg => $where->[0] => "Showing whitelisted links" );
    }

    if ($message=~ m/^hide whitelisted links/ ) {                             
        $settings{'showwhitelistedlinks'}=0;
        $kernel->post( $sender => privmsg => $where->[0] => "Hiding whitelisted links" );
    }


    if ($message=~ m/^add channel (.+)/ || $message=~ m/^join channel (.+)/ ) {                        
        if (($cloak = 'wikimedia/Versageek') || ($cloak eq 'Wikimedia/Beetstra') ) {
            $newchannel = $1;
            unless ($newchannel eq '#en.wikipedia') {
                if (grep(/$newchannel/,@rcchannels)) {
                    $kernel->post( $sender => privmsg => $where->[0] => "Channel $newchannel already joined." );
                } else {
                    push (@rcchannels,$newchannel);
                    $kernel->post( 'irc.wikimedia.org' => join => $newchannel );
                    $kernel->post( $sender => privmsg => $where->[0] => "$settings{ircname} is now also parsing $newchannel." );
                    print "Connected to $newchannel.\n";
                }
            }
        }
    }

    if ($message=~ m/^part channel (.+)/ ) {
        if (($cloak = 'wikimedia/Versageek') || ($cloak eq 'Wikimedia/Beetstra') ) {
            $oldchannel = $1;
            $channel2 = join(",",@rcchannels);
            $channel = "!!$channel2";
            if ($channel =~ m/$oldchannel/) {
                $kernel->post( $settings{reportserver} => part => $oldchannel );
                $channel =~ s/,$oldchannel//;
                $channel =~ s/!$oldchannel//;
                $channel =~ s/!,//g;
                $channel =~ s/!//g;
                @rcchannels = split(/,/,$channel);
                $kernel->post( $sender => privmsg => $where->[0] => "$settings{ircname} has parted $oldchannel." );
                print "Parted $oldchannel on freenode.\n";
            } else {
                $kernel->post( $sender => privmsg => $where->[0] => "Channel $oldchannel not in list." );
            }
        }
    }
}

sub slave_input {
    my ( $kernel, $heap, $input ) = @_[ KERNEL, HEAP, ARG0 ];
    if ($input=~m/REQUEST/) {
        my $editref = pop(@editQueue);
        if ($editref) {
            my $message = "EDIT [[" . $editref->{pagename} . "]] [[" . $editref->{domain} . $editref->{lang} . ":User:" . $editref->{user} . "]] " . $editref->{diffurl} . " " . $editref->{size};
            print (" message request: $message\n");
            $heap->{client}->put($message);
        }
        else {
            $heap->{client}->put("NOEDIT");
        }
    }
    elsif ($input=~m{PARSED \[\[(.+)\]\] (http://.+?) (.+) \[\[(.+):User:(.+)\]\] \|(.+)\|}) {
        my $pagename = $1;
        my $diffurl  = $2;
        my $size     = $3;
        my $lang     = $4;
        my $username = $5;
        my $links    = $6;
        my $count = 0;
        print (" message parsed: $1 - $2 - $3 - $4 - $5 - $6\n");

        if ($settings{'loglinks'}) {
            my $query="INSERT INTO $settings{'mysqltableprefix'}log (pagename,diff,user,links) VALUES(";
            $query .= $mysql->quote($pagename) . ",";
            $query .= $mysql->quote($diffurl) . ",";
            $query .= $mysql->quote($username) . ",";
            $query .= $mysql->quote($links) . ")";
            &query($query);

            $query="SELECT COUNT(*) as total_record FROM $settings{'mysqltableprefix'}log WHERE user=" . $mysql->quote($username);
            $count = &query($query);
            $count = @{ $count }[0]->{total_record};
        }


        my $sql;
        my $sql="SELECT status FROM $settings{'mysqltableprefix'}users WHERE username=" . $mysql->quote($username);
        my $whitelisted = 0;
        $sql=&query($sql);
        if (defined $sql) {
            if (@{$sql}[0]->{status} eq 'ignore') {
                $whitelisted = 1;
                $whiteuser++;
            }
        }
        if ($whitelisted) {
            if ($settings{'showwhitelistedusers'}) {
                my $message=&build_output($kernel,$pagename,$diffurl,$size,$lang,$username,$whitelisted,$links);
                unless (length($message) < 2) {
                    $kernel->post($settings{'ircserver'}=>privmsg=>$settings{'ircreportchannel'}=>$message) unless ($settings{'spambotfeeder'});
                }
            }
        } else {
            my $message=&build_output($kernel,$pagename,$diffurl,$size,$lang,$username,$whitelisted,$links);
            print ("$message\n");
            unless (length($message) < 2) {
                $kernel->post($settings{'ircserver'}=>privmsg=>$settings{'ircreportchannel'}=>$message) unless ($settings{'spambotfeeder'});
                if ($count > $settings{'warninglevel'} ) {
                    $kernel->post($settings{'ircserver'}=>privmsg=>$settings{'ircreportchannel'}=>"\x034WARNING! [[$lang:user:$username]] ([[$lang:Special:Contributions/$username]]) has added $count links.\x03") unless ($settings{'spambotfeeder'});
                }
            }
        }

        print("Found: [[$lang:$pagename]] $diffurl [[$lang:User:$username]] $links\n");
        my @split_links = split( /\s/, $links );
        my @resolved_ips;
        if (@split_links) {
            $linkadditions++;
        }
        foreach my $link ( @split_links ) {
            $totallinks++;
            my $link_spare = $link;
            $link =~ s{https?://}{}i;
            $link =~ s{([^/]+)/.+}{$1};
            my $ip = &resolve( $link );
            push ( @resolved_ips, { name=>$link_spare, ip=>$ip } );
        }
        if ($whitelisted) {
            foreach my $entry ( @resolved_ips ) {
                if ($settings{'showwhitelistedusers'}) {
                    my $query = "SELECT id FROM $settings{'mysqltableprefix'}blacklist WHERE rule='resolve ".$entry->{ip}."'";
                    $query = &query($query);
                    if (defined $query) {
                        if (defined @{ $query }[0]->{id}) {
                            my $message = "\x034WARNING! Link ".$entry->{name}." resolved to blacklisted IP address ".$entry->{ip}." on $diffurl\x03" unless ($settings{'spambotfeeder'});
                            $kernel->post($settings{'ircserver'}=>privmsg=>$settings{'ircreportchannel'}=>$message) unless ($settings{'spambotfeeder'});
                            &generate_alert( $pagename, $diffurl, $size, $lang, $username, 'resolve '.$entry->{ip}, $kernel )
                        }
                    }
                }
            }
        } else {
            foreach my $entry ( @resolved_ips ) {
                my $query = "SELECT id FROM $settings{'mysqltableprefix'}blacklist WHERE rule='resolve ".$entry->{ip}."'";
                $query = &query($query);
                if (defined $query) {
                    if (defined @{ $query }[0]->{id}) {
                        my $message = "\x034WARNING! Link ".$entry->{name}." resolved to blacklisted IP address ".$entry->{ip}." on $diffurl\x03" unless ($settings{'spambotfeeder'});
                        $kernel->post($settings{'ircserver'}=>privmsg=>$settings{'ircreportchannel'}=>$message) unless ($settings{'spambotfeeder'});
                        &generate_alert( $pagename, $diffurl, $size, $lang, $username, 'resolve '.$entry->{ip}, $kernel )
                    }
                }
            }
        }
    }
}

sub slave_disconnect {
        system("perl","LinkParser.pl",$settings{'serverport'});
}

sub irc_disconnected {
    my ( $kernel, $sender, $server_name ) = @_[ KERNEL, SENDER, ARG0 ];
    if ( $server_name eq $settings{'ircserver'} ) {
        $kernel->post( $sender => 'connect' => { server=>$settings{'ircserver'}, port=>$settings{'ircport'}, } );
    }
    elsif ( $server_name eq $settings{'rcserver'} ) {
        $kernel->post( $sender => 'connect' => { server=>$settings{'rcserver'}, port=>$settings{'ircport'}, } );
    }
}

sub query {
    my $query=shift;
    if ( $query !~ m/^select/i ) {
        my $status=$mysql->do($query);
        return $status;
    }
    else {
        my $query_handle=$mysql->prepare($query);
        $query_handle->execute;
        my $results=$query_handle->fetchall_arrayref( {} );
        if ( $query_handle->rows > 0 ) {
            return $results;
        }
        else {
            return undef;
        }
    }
}

sub build_output {
    my ( $kernel, $pagename, $diffurl, $size, $lang, $username, $whitelisted, $links_pre ) = @_;
    my $message="\x034[[$lang:$pagename]]\x03 \x033$diffurl\x03 \x0312[[$lang:User:$username]]\x03 ";
    my @links = split( /\s/, $links_pre );
    my %links_hash;
    foreach (@links) {
        $links_hash{$_}='';
    }
    my $query_handle;
    my $blacklistrule;
    my $rule;
    my $blacklisted;
    unless ($settings{'spambotfeeder'}) {
        $query_handle=$mysql->prepare("SELECT rule FROM $settings{'mysqltableprefix'}whitelist");
        $query_handle->execute;
        while (my $rule=$query_handle->fetchrow_array) {
            foreach my $link (@links) {
                if($link=~m/$rule/) {
                    $links_hash{$link}.="\x039(WL: $rule)\x03 ";
                    $whitelinks++
                }
            }
            undef $rule;
        }
        $query_handle=$mysql->prepare("SELECT rule FROM $settings{'mysqltableprefix'}redlist");
        $query_handle->execute;
        while (my $rule=$query_handle->fetchrow_array) {
            foreach my $link (@links) {
                if($link=~m/$rule/) {
                    $links_hash{$link}.="\x034(RL: $rule)\x03 ";
                    $redlinks++;
                }
            }
            undef $rule;
        }
    }
    if ($settings{source} eq "SQL") {
        $query_handle=$mysql->prepare("SELECT rule FROM $settings{'mysqltableprefix'}blacklist");
        $query_handle->execute;
        my $blacklisted=0;
        while (my $rule=$query_handle->fetchrow_array) {
            foreach my $link (@links) {
                if($link=~m/$rule/i) {
                    unless ($whitelisted) {
                        &generate_alert( $pagename, $diffurl, $size, $lang, $username, $rule, $kernel ) unless $blacklisted;
                    }
                    $links_hash{$link}.="\x035(BL: $rule)\x03 ";
                    $blacklisted=1;
                    $blacklinks++;
                }
            }
            undef $rule
        }
    } elsif ($settings{source} eq "Wiki") {
        foreach $blacklistrule (@wikiblacklist) {
            foreach my $link (@links) {
                my $garbage;
                $blacklistrule .= "#";
                ($blacklistrule,$garbage) = split(/#/,$blacklistrule);
                $blacklistrule .= " ";
                ($blacklistrule,$garbage) = split(/\s/,$blacklistrule);
                if($link=~m/$blacklistrule/i) {
                    unless ($whitelisted) {
                        &generate_alert( $pagename, $diffurl, $size, $lang, $username, $blacklistrule, $kernel ) unless $blacklisted;
                    }
                    $links_hash{$link}.="\x035(BL: $blacklistrule)\x03 ";
                    $blacklisted=1;
                    $blacklinks++;
                }
            }
            undef $rule;
        }
    } else {
        $kernel->post($settings{'ircserver'}=>privmsg=>$settings{'ircreportchannel'}=>"Incorrect setting for $settings{source}");
    }
    my $links = "";
    foreach my $link (keys %links_hash) {
        if ($settings{'showwhitelistedlinks'}) {
            $links.="$link " . $links_hash{$link};
        } else {
            unless ($links_hash{$link} =~ m/WL:/) {
                $links.="$link " . $links_hash{$link};
            }
        }
    }
    if (length($links)>0) {
        $message .= $links;
    } else {
        $message = "";
    }
    return $message;
}

sub generate_alert {
    my ( $pagename, $diffurl, $size, $lang, $username, $rule, $kernel ) = @_;
    my $message="diff=<$diffurl> user=<$username> title=<$pagename> size=<$size> rule=<$rule>";
    $kernel->post( $settings{'ircserver'} => privmsg => $settings{'ircbotchannel'} => $message );
}

sub resolve {
    my $link = shift;
    my $ip_address = inet_aton( $link );
    if( length( $ip_address ) != 4 ) {
        print "$link didn't resolve properly, bailing out\n";
        return 0;
    }
    $ip_address = inet_ntoa( $ip_address );
    print "Resolved $link -> $ip_address\n";
    return $ip_address;
}