X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=src%2Fcore.pl;h=936f31cc784ec8aab6fb43951b23f72a67c7cdac;hb=a1e66b2243083626975203eb23c9c24405d90054;hp=c710bc54ed060dfb3e148ea8f2b9b4df32a2cd68;hpb=618f723b1608b0d93b7f026454d613bb8385a330;p=infobot.git diff --git a/src/core.pl b/src/core.pl index c710bc5..936f31c 100644 --- a/src/core.pl +++ b/src/core.pl @@ -7,25 +7,35 @@ use strict; -# dynamic scalar. MUST BE REDUCED IN SIZE!!! +# scalar. MUST BE REDUCED IN SIZE!!! ### TODO: reorder. use vars qw( - $answer $correction_plausible $talkchannel + $bot_misc_dir $bot_pid $bot_base_dir $bot_src_dir + $bot_data_dir $bot_config_dir $bot_state_dir $bot_run_dir + $answer $correction_plausible $talkchannel $bot_release $statcount $memusage $user $memusageOld $bot_version $dbh - $shm $host $msg $bot_misc_dir $bot_pid $bot_base_dir $noreply - $bot_src_dir $conn $irc $learnok $nick $ident $no_syscall + $shm $host $msg $noreply $conn $irc $learnok $nick $ident $force_public_reply $addrchar $userHandle $addressedother $floodwho $chan $msgtime $server $firsttime $wingaterun + $flag_quit $msgType $no_syscall + $utime_userfile $wtime_userfile $ucount_userfile + $utime_chanfile $wtime_chanfile $ucount_chanfile + $pubsize $pubcount $pubtime + $msgsize $msgcount $msgtime + $notsize $notcount $nottime + $running ); -# dynamic hash. -use vars qw(@joinchan @ircServers @wingateBad @wingateNow @wingateCache +# array. +use vars qw(@ircServers @wingateBad @wingateNow @wingateCache ); -# dynamic hash. MUST BE REDUCED IN SIZE!!! +### hash. MUST BE REDUCED IN SIZE!!! +# use vars qw(%count %netsplit %netsplitservers %flood %dcc %orig - %nuh %talkWho %seen %floodwarn %param %dbh %ircPort %userList - %jointime %topic %joinverb %moduleAge %last %time %mask %file + %nuh %talkWho %seen %floodwarn %param %dbh %ircPort + %topic %moduleAge %last %time %mask %file + %forked %chanconf %channels %cache ); # Signals. @@ -37,40 +47,98 @@ $SIG{'__WARN__'} = 'doWarn'; # initialize variables. $last{buflen} = 0; -$last{say} = ""; -$last{msg} = ""; -$userHandle = "default"; -$msgtime = time(); +$last{say} = ''; +$last{msg} = ''; +$userHandle = "_default"; $wingaterun = time(); $firsttime = 1; - -### CHANGE TO STATIC. -$bot_version = "blootbot 1.0.0 (20000725) -- $^O"; -$noreply = "NOREPLY"; +$utime_userfile = 0; +$wtime_userfile = 0; +$ucount_userfile = 0; +$utime_chanfile = 0; +$wtime_chanfile = 0; +$ucount_chanfile = 0; +$running = 0; +### more variables... +# static scalar variables. +$mask{ip} = '(\d+)\.(\d+)\.(\d+)\.(\d+)'; +$mask{host} = '[\d\w\_\-\/]+\.[\.\d\w\_\-\/]+'; +$mask{chan} = '[\#\&]\S*|_default'; +my $isnick1 = 'a-zA-Z\[\]\{\}\_\`\^\|\\\\'; +my $isnick2 = '0-9\-'; +$mask{nick} = "[$isnick1]{1}[$isnick1$isnick2]*"; +$mask{nuh} = '\S*!\S*\@\S*'; +$msgtime = time(); +$msgsize = 0; +$msgcount = 0; +$pubtime = 0; +$pubsize = 0; +$pubcount = 0; +$nottime = 0; +$notsize = 0; +$notcount = 0; +### +open(VERSION, ' || "(unknown version)"; +chomp($bot_release); +close(VERSION); +$bot_version = "infobot $bot_release -- $^O"; +$noreply = 'NOREPLY'; ########## ### misc commands. ### +sub whatInterface { + if (!&IsParam('Interface') or $param{'Interface'} =~ /IRC/) { + return 'IRC'; + } else { + return 'CLI'; + } +} + sub doExit { - my ($sig) = @_; + my ($sig) = @_; + + if (defined $flag_quit) { + &WARN("doExit: quit already called."); + return; + } + $flag_quit = 1; if (!defined $bot_pid) { # independent. exit 0; } elsif ($bot_pid == $$) { # parent. &status("parent caught SIG$sig (pid $$).") if (defined $sig); - my $type; - &closeDCC(); + &status("--- Start of quit."); + $ident ||= 'infobot'; # lame hack. + + &status("Memory Usage: $memusage KiB"); + &closePID(); - &seenFlush(); - &quit($param{'quitMsg'}) if (&whatInterface() =~ /IRC/); - &uptimeWriteFile(); - &closeDB(); + &closeStats(); + # shutdown IRC and related components. + if (&whatInterface() =~ /IRC/) { + &closeDCC(); + &seenFlush(); + &quit($param{'quitMsg'}); + } + &writeUserFile(); + &writeChanFile(); + &uptimeWriteFile() if (&IsParam('Uptime')); + &sqlCloseDB(); &closeSHM($shm); - &dumpallvars() if (&IsParam("dumpvarsAtExit")); + + if (&IsParam('dumpvarsAtExit')) { + &loadMyModule('DumpVars'); + &dumpallvars(); + } + &symdumpAll() if (&IsParam('symdumpAtExit')); &closeLog(); - &closeSQLDebug() if (&IsParam("SQLDebug")); + &closeSQLDebug() if (&IsParam('SQLDebug')); + + &status("--- QUIT."); } else { # child. &status("child caught SIG$sig (pid $$)."); } @@ -85,10 +153,11 @@ sub doWarn { &WARN("PERL: $_"); } - $SIG{__WARN__} = 'doWarn'; + $SIG{__WARN__} = 'doWarn'; # ??? } # Usage: &IsParam($param); +# infobot.config specific. sub IsParam { my $param = $_[0]; @@ -99,45 +168,253 @@ sub IsParam { return 1; } -sub showProc { - my ($prefix) = $_[0] || ""; +##### +# Usage: &ChanConfList($param) +# About: gets channels with 'param' enabled. (!!!) +# Return: array of channels +sub ChanConfList { + my $param = $_[0]; + return unless (defined $param); + my %chan = &getChanConfList($param); + + if (exists $chan{_default}) { + return keys %chanconf; + } else { + return keys %chan; + } +} - if (!open(IN, "/proc/$$/status")) { - &ERROR("cannot open '/proc/$$/status'."); - return; +##### +# Usage: &getChanConfList($param) +# About: gets channels with 'param' enabled, internal use only. +# Return: hash of channels +sub getChanConfList { + my $param = $_[0]; + my %chan; + + return unless (defined $param); + + foreach (keys %chanconf) { + my $chan = $_; + my @array = grep /^$param$/, keys %{ $chanconf{$chan} }; + #&DEBUG("gCCL param => $param, chan => $chan, keys => " . join(':',keys %{ $chanconf{$chan} }) . " array => " . join(':', @array)) if ($param eq 'whatever'); + + next unless (scalar @array); + + if (scalar @array > 1) { + &WARN("multiple items found?"); + } + + if ($chanconf{$chan}{$param} eq '0') { + $chan{$chan} = -1; + } else { + $chan{$chan} = 1; + } + } + + return %chan; +} + +##### +# Usage: &IsChanConf($param); +# About: Check for 'param' on the basis of channel config. +# Return: 1 for enabled, 0 for passive disable, -1 for active disable. +sub IsChanConf { + my($param) = shift; + + # knocked tons of bugs with this! :) + my $debug = 0; # 1 if ($param eq 'whatever'); + + if (!defined $param) { + &WARN("IsChanConf: param == NULL."); + return 0; + } + + # these should get moved to your .chan file instead of the .config + # .config items overide any .chan entries + if (&IsParam($param)) { + &WARN("ICC: found '$param' option in main config file."); + return 1; + } + + $chan ||= "_default"; + + my $old = $chan; + if ($chan =~ tr/A-Z/a-z/) { + &WARN("IsChanConf: lowercased chan. ($old)"); + } + + ### TODO: VERBOSITY on how chanconf returned 1 or 0 or -1. + my %chan = &getChanConfList($param); + my $nomatch = 0; + if (!defined $msgType) { + $nomatch++; + } else { + $nomatch++ if ($msgType eq ''); + $nomatch++ unless ($msgType =~ /^(public|private)$/i); } - if ($^O eq "linux") { +### debug purposes only. +# if ($debug) { +# &DEBUG("param => $param, msgType => $msgType."); +# foreach (keys %chan) { +# &DEBUG(" $_ => $chan{$_}"); +# } +# } + + if ($nomatch) { + if ($chan{$chan}) { + &DEBUG("ICC: other: $chan{$chan} (_default/$param)") if ($debug); + } elsif ($chan{_default}) { + &DEBUG("ICC: other: $chan{_default} (_default/$param)") if ($debug); + } else { + &DEBUG("ICC: other: 0 ($param)") if ($debug); + } + return $chan{$chan} || $chan{_default} || 0; + } elsif ($msgType =~ /^(public|private)$/i) { + if ($chan{$chan}) { + &DEBUG("ICC: $msgType: $chan{$chan} ($chan/$param)") if ($debug); + } elsif ($chan{_default}) { + &DEBUG("ICC: $msgType: $chan{_default} (_default/$param)") if ($debug); + } else { + &DEBUG("ICC: $msgType: 0 ($param)") if ($debug); + } + return $chan{$chan} || $chan{_default} || 0; + } + + &DEBUG("ICC: no-match: 0/$param (msgType = $msgType)"); + + return 0; +} + +##### +# Usage: &getChanConf($param); +# About: Retrieve value for 'param' value in current/default chan. +# Return: scalar for success, undef for failure. +sub getChanConf { + my($param,$c) = @_; + + if (!defined $param) { + &WARN("gCC: param == NULL."); + return 0; + } + + # this looks evil... + if (0 and !defined $chan) { + &DEBUG("gCC: ok !chan... doing _default instead."); + } + + $c ||= $chan; + $c ||= "_default"; + $c = "_default" if ($c eq "*"); # FIXME + my @c = grep /^\Q$c\E$/i, keys %chanconf; + + if (@c) { + if (0 and $c[0] ne $c) { + &WARN("c ne chan ($c[0] ne $chan)"); + } + if (!defined $chanconf{$c[0]}{$param} and ($c ne '_default')) { + return &getChanConf($param, '_default'); + } + &DEBUG("gCC: $param,$c \"" . $chanconf{$c[0]}{$param} . '"'); + return $chanconf{$c[0]}{$param}; + } + + #&DEBUG("gCC: returning _default... " . $chanconf{"_default"}{$param}); + return $chanconf{"_default"}{$param}; +} + +sub getChanConfDefault { + my($what, $default, $chan) = @_; + $chan ||= "_default"; + + if (exists $param{$what}) { + if (!exists $cache{config}{$what}) { + &status("config ($chan): backward-compatible option: found param{$what} ($param{$what}) instead of chan option"); + $cache{config}{$what} = 1; + } + + return $param{$what}; + } + my $val = &getChanConf($what, $chan); + return $val if (defined $val); + + $param{$what} = $default; + &status("config ($chan): auto-setting param{$what} = $default"); + $cache{config}{$what} = 1; + return $default; +} + + +##### +# Usage: &findChanConf($param); +# About: Retrieve value for 'param' value from any chan. +# Return: scalar for success, undef for failure. +sub findChanConf { + my($param) = @_; + + if (!defined $param) { + &WARN("param == NULL."); + return 0; + } + + my $c; + foreach $c (keys %chanconf) { + foreach (keys %{ $chanconf{$c} }) { + next unless (/^$param$/); + + return $chanconf{$c}{$_}; + } + } + + return; +} + +sub showProc { + my ($prefix) = $_[0] || ''; + + if ($^O eq 'linux') { + if (!open(IN, "/proc/$$/status")) { + &ERROR("cannot open '/proc/$$/status'."); + return; + } + while () { $memusage = $1 if (/^VmSize:\s+(\d+) kB/); } close IN; - if (defined $memusageOld and &IsParam("DEBUG")) { - # it's always going to be increase. - my $delta = $memusage - $memusageOld; - my $str; - if ($delta == 0) { - return; - } elsif ($delta > 500) { - $str = "MEM:$prefix increased by $delta kB. (total: $memusage kB)"; - } elsif ($delta > 0) { - $str = "MEM:$prefix increased by $delta kB"; - } else { # delta < 0. - $delta = -$delta; - # never knew RSS could decrease, probably Size can't? - $str = "MEM:$prefix decreased by $delta kB. YES YES YES"; - } - - &status($str); - &DCCBroadcast($str) if (&whatInterface() =~ /IRC/ && - grep(/Irc.pl/, keys %moduleAge)); - } - $memusageOld = $memusage; + } elsif ($^O eq 'netbsd') { + $memusage = int( (stat "/proc/$$/mem")[7]/1024 ); + + } elsif ($^O =~ /^(free|open)bsd$/) { + my @info = split /\s+/, `/bin/ps -l -p $$`; + $memusage = $info[20]; + } else { - $memusage = "UNKNOWN"; + $memusage = 'UNKNOWN'; + return; + } + + if (defined $memusageOld and &IsParam('DEBUG')) { + # it's always going to be increase. + my $delta = $memusage - $memusageOld; + my $str; + if ($delta == 0) { + return; + } elsif ($delta > 500) { + $str = "MEM:$prefix increased by $delta KiB. (total: $memusage KiB)"; + } elsif ($delta > 0) { + $str = "MEM:$prefix increased by $delta KiB"; + } else { # delta < 0. + $delta = -$delta; + # never knew RSS could decrease, probably Size can't? + $str = "MEM:$prefix decreased by $delta KiB."; + } + + &status($str); } - ### TODO: FreeBSD/*BSD support. + $memusageOld = $memusage; } ###### @@ -147,60 +424,96 @@ sub showProc { sub setup { &showProc(" (\&openLog before)"); &openLog(); # write, append. - - foreach ("debian","Temp") { - &status("Making dir $_"); - mkdir "$bot_base_dir/$_/", 0755; - } + &status("--- Started logging."); # read. - &loadIgnore($bot_misc_dir. "/blootbot.ignore"); - &loadLang($bot_misc_dir. "/blootbot.lang"); - &loadIRCServers($bot_misc_dir. "/ircII.servers"); - &loadUsers($bot_misc_dir. "/blootbot.users"); + &loadLang($bot_data_dir. "/infobot.lang"); + &loadIRCServers(); + &readUserFile(); + &readChanFile(); + &loadMyModulesNow(); # must be after chan file. $shm = &openSHM(); - &openSQLDebug() if (&IsParam("SQLDebug")); - &openDB($param{'DBName'}, $param{'SQLUser'}, $param{'SQLPass'}); - - &status("Setup: ". &countKeys("factoids") ." factoids."); - - &status("Initial memory usage: $memusage kB"); + &openSQLDebug() if (&IsParam('SQLDebug')); + &sqlOpenDB($param{'DBName'}, $param{'DBType'}, $param{'SQLUser'}, + $param{'SQLPass'}); + &checkTables(); + + &status("Setup: ". &countKeys('factoids') ." factoids."); + &getChanConfDefault('sendPrivateLimitLines', 3, $chan); + &getChanConfDefault('sendPrivateLimitBytes', 1000, $chan); + &getChanConfDefault('sendPublicLimitLines', 3, $chan); + &getChanConfDefault('sendPublicLimitBytes', 1000, $chan); + &getChanConfDefault('sendNoticeLimitLines', 3, $chan); + &getChanConfDefault('sendNoticeLimitBytes', 1000, $chan); + + $param{tempDir} =~ s#\~/#$ENV{HOME}/#; + + &status("Initial memory usage: $memusage KiB"); + &status("-------------------------------------------------------"); } sub setupConfig { $param{'VERBOSITY'} = 1; - &loadConfig($bot_misc_dir."/blootbot.config"); + &loadConfig($bot_config_dir."/infobot.config"); - foreach ("ircNick", "ircUser", "ircName", "DBType") { + foreach ( qw(ircNick ircUser ircName DBType tempDir) ) { next if &IsParam($_); &ERROR("Parameter $_ has not been defined."); exit 1; } + if ($param{tempDir} =~ s#\~/#$ENV{HOME}/#) { + &VERB("Fixing up tempDir.",2); + } + + if ($param{tempDir} =~ /~/) { + &ERROR("parameter tempDir still contains tilde."); + exit 1; + } + + if (! -d $param{tempDir}) { + &status("making $param{tempDir}..."); + mkdir $param{tempDir}, 0755; + } + # static scalar variables. - $file{utm} = "$bot_base_dir/$param{'ircUser'}.uptime"; - $file{PID} = "$bot_base_dir/$param{'ircUser'}.pid"; + $file{utm} = "$bot_state_dir/$param{'ircUser'}.uptime"; + $file{PID} = "$bot_run_dir/$param{'ircUser'}.pid"; } sub startup { - if (&IsParam("DEBUG")) { + if (&IsParam('DEBUG')) { &status("enabling debug diagnostics."); - ### I thought disabling this reduced memory usage by 1000 kB. + # I thought disabling this reduced memory usage by 1000 KiB. use diagnostics; } $count{'Question'} = 0; $count{'Update'} = 0; $count{'Dunno'} = 0; - - &loadMyModulesNow(); + $count{'Moron'} = 0; } sub shutdown { + my ($sig) = @_; # reverse order of &setup(). - &closeDB(); - &closeSHM($shm); # aswell. TODO: use this in &doExit? + &status("--- shutdown called."); + + # hack. + $ident ||= 'infobot'; + + if (!&isFileUpdated("$bot_state_dir/infobot.users", $wtime_userfile)) { + &writeUserFile() + } + + if (!&isFileUpdated("$bot_state_dir/infobot.chan", $wtime_chanfile)) { + &writeChanFile(); + } + + &sqlCloseDB(); + # aswell. TODO: use this in &doExit? + &closeSHM($shm); &closeLog(); } @@ -208,22 +521,28 @@ sub restart { my ($sig) = @_; if ($$ == $bot_pid) { - &status("$sig called."); + &status("--- $sig called."); ### crappy bug in Net::IRC? - if (!$conn->connected and time - $msgtime > 900) { - &status("reconnecting because of uncaught disconnect."); -## $irc->start; + my $delta = time() - $msgtime; + &DEBUG("restart: dtime = $delta"); + if (!$conn->connected or time() - $msgtime > 900) { + &status("reconnecting because of uncaught disconnect \@ ".scalar(gmtime) ); +### $irc->start; + &clearIRCVars(); $conn->connect(); - return; +### return; } - &shutdown(); - &loadConfig($bot_misc_dir."/blootbot.config"); - &reloadAllModules() if (&IsParam("DEBUG")); + &ircCheck(); # heh, evil! + + &DCCBroadcast("-HUP called.",'m'); + &shutdown($sig); + &loadConfig($bot_config_dir."/infobot.config"); + &reloadAllModules() if (&IsParam('DEBUG')); &setup(); - &status("End of $sig."); + &status("--- End of $sig."); } else { &status("$sig called; ignoring restart."); } @@ -234,9 +553,8 @@ sub loadConfig { my ($file) = @_; if (!open(FILE, $file)) { - &ERROR("FAILED loadConfig ($file): $!"); - &status("Please copy files/sample.config to files/blootbot.config"); - &status(" and edit files/blootbot.config, modify to tastes."); + &ERROR("Failed to read configuration file ($file): $!"); + &status("Please read the INSTALL file on how to install and setup this file."); exit 0; } @@ -247,7 +565,7 @@ sub loadConfig { next unless /\S/; my ($set,$key,$val) = split(/\s+/, $_, 3); - if ($set ne "set") { + if ($set ne 'set') { &status("loadConfig: invalid line '$_'."); next; } @@ -266,3 +584,5 @@ sub loadConfig { } 1; + +# vim:ts=4:sw=4:expandtab:tw=80