#!/usr/bin/env perl no autovivification; use strict; use warnings; use FindBin; use lib "$FindBin::Bin/lib";; use Net::IRC 0.91; use Data::Dumper; use IO::All; use Getopt::Long; use POSIX qw(strftime); use Term::ANSIColor qw(:constants); use File::Monitor; use feature qw(say); use HTTP::Async; use Carp; use Tie::CPHash; use Net::DNS::Async; use ASM::Util; use ASM::Config; use ASM::Inspect; use ASM::Event; use ASM::Services; use ASM::Log; use ASM::Commander; use ASM::Classes; use ASM::Fifo; use ASM::Statsp; no if $] >= 5.017011, warnings => 'experimental::smartmatch'; $|++; $Data::Dumper::Useqq=1; @::nick_blacklist=(); $::netsplit = 0; $::netsplit_ignore_lag = 0; $::no_autojoins = 0; $::debug = 0; $::cset = ''; $::pacealerts = 1; $::settingschanged = 0; %::wordlist = (); %::httpRequests = (); $::version = ''; ## debug variables. 0 to turn off debugging, else set it to a Term::ANSIColor constant. %::debugx = ( "dnsbl" => 0, # BLUE, "pingpong" => 0, #BLUE, "snotice" => YELLOW, "sync" => CYAN, "chanstate" => MAGENTA, "restrictions" => BLUE, "startup" => YELLOW, "mysql" => 0, #CYAN, "inspector" => 0, "commander" => GREEN, "msg" => GREEN, "dcc" => RED, "misc" => 0, #RED, "latency" => RED, "statsp" => MAGENTA, "ctcp" => 0, #RED, "logger" => 0, "dns" => 0 #MAGENTA ); $::starttime = time; @::syncqueue = (); @::bansyncqueue = (); @::quietsyncqueue = (); $::pendingsync = 0; %::watchRegged = (); $::lastline = ""; %::sn = (); %::sc = (); tie %::sc, 'Tie::CPHash'; tie %::sn, 'Tie::CPHash'; %::sa = (); tie %::sa, 'Tie::CPHash'; $SIG{__WARN__} = sub { $Data::Dumper::Useqq=1; print STDERR 'last line: ' . Dumper($::lastline); print STDERR strftime("%F %T", gmtime), RED, ' WARNING: ', RESET, $_[0]; }; sub alarmdeath { $Data::Dumper::Useqq=1; confess "SIG ALARM!!! last line: " . Dumper($::lastline); } $SIG{ALRM} = \&alarmdeath; alarm 300; sub startup_checks { my $config_bad = 0; if (exists $::mysql->{table}) { if ($::mysql->{table} ne 'alertlog') { warn "FATAL - The 'table' option in mysql.json is no longer supported. Please ensure your table is named 'alertlog'.\n"; $config_bad++; } else { warn "The 'table' option in mysql.json is no longer supported. Please remove it from the configuration.\n"; } } if (exists $::mysql->{actiontable}) { if ($::mysql->{actiontable} ne 'actionlog') { warn "FATAL - The 'actiontable' option in mysql.json is no longer supported. Please ensure your table is named 'actionlog'.\n"; $config_bad++; } else { warn "The 'actiontable' option in mysql.json is no longer supported. Please remove it from the configuration.\n"; } } if (exists $::settings->{pass}) { warn "The 'pass' option in settings.json has been split into 'server_pass' and 'account_pass'. Please update your configuration accordingly.\n"; $::settings->{server_pass} //= $::settings->{account_pass} //= $::settings->{pass}; } if ($config_bad) { die "The bot cannot operate with the current configuration.\n"; } } sub init { my ( $conn, $host ); $::version .= `git merge-base remotes/origin/master HEAD`; chomp $::version; $::version .= ' '; $::version .= `git describe --long --all --dirty`; chomp $::version; $::version .= ' '; $::version .= `git rev-parse HEAD`; chomp $::version; my $irc = new Net::IRC; GetOptions( 'debug|d!' => \$::debug, 'config|c=s' => \$::cset ); if (-e "debugmode") { $::debug = 1; } if ($::cset eq '') { $::cset = 'config-default'; } else { $::cset = "config-$::cset"; } ASM::Config->readConfig(); startup_checks(); $::async = HTTP::Async->new(); $::dns = Net::DNS::Async->new(QueueSize => 5000, Retries => 3); $host = ${$::settings->{server}}[rand @{$::settings->{server}}]; ASM::Util->dprint( "Connecting to $host", "startup"); $irc->debug($::debug); if (-e "debugsock") { $irc->debugsock(1); } if (!$::mysql->{disable}) { my $dsn; if (exists $::mysql->{dsn}) { $dsn = $::mysql->{dsn}; } else { # This isn't what we *should* do - notably, we'd have to wrap IPv6 addresses given # as host in brackets. It's what the old code did, though, and all we need is # compatibility with that. $dsn = sprintf 'DBI:mysql:database=%s;host=%s;port=%s', @{ $::mysql }{'db', 'host', 'port'}; } require ASM::DB; $::db = ASM::DB->connect($dsn, $::mysql->{user}, $::mysql->{pass}); } $conn = $irc->newconn( Server => $host, Port => $::settings->{port} || '6667', SSL => defined($::settings->{ssl}), Nick => $::settings->{nick}, Ircname => $::settings->{realname}, Username => $::settings->{username}, Password => $::settings->{server_pass}, Pacing => 0 ); $conn->debug($::debug); if (-e "debugsock") { $conn->debugsock(1); } ASM::Event->new($conn); ASM::Inspect->new($conn); $::log = ASM::Log->new($conn); ASM::Commander->new($conn); ASM::Services->new($conn); ASM::Statsp->new($conn); $::classes = ASM::Classes->new(); ASM::Fifo->new($irc, $conn); if (-e 'nick_blacklist.txt') { my @nickbl = io('nick_blacklist.txt')->getlines; chomp @nickbl; @::nick_blacklist = @nickbl; } %::proxies = (); if (-e 'proxy.txt') { my @proxy = io('proxy.txt')->getlines; chomp @proxy; foreach my $line (@proxy) { if ($line =~ /(\d+\.\d+\.\d+\.\d+):\d+/) { $::proxies{$1} = 1; } } } if (-e 'wordlist.txt') { my @wl=io('wordlist.txt')->getlines; chomp @wl; foreach my $item (@wl) { $::wordlist{lc $item} = 1; } } $::fm = File::Monitor->new(); foreach my $file ("channels", "dnsbl", "mysql", "restrictions", "rules", "settings", "users", "blacklist") { $::fm->watch("./" . $::cset . '/' . $file . ".json"); } $::fm->scan(); $irc->start(); } init(); # vim: ts=2:sts=2:sw=2:expandtab