summaryrefslogtreecommitdiffstats
path: root/lib/ASM
diff options
context:
space:
mode:
authorLibravatarWilliam Heimbigner <william.heimbigner@gmail.com>2016-01-14 13:56:55 -0700
committerLibravatarWilliam Heimbigner <william.heimbigner@gmail.com>2016-01-14 13:56:55 -0700
commitcca3bcc2cf7e0b7bd8d365aa77ae75716bdbcf6e (patch)
treec2c9dd8d1630968ce117e7c6c016a1f04af11470 /lib/ASM
parent84fea950fd61b14fd89888346ba09e3e93af6f45 (diff)
Remove commands.xml, move everything kinda-nicely into the main Commander module.
Diffstat (limited to 'lib/ASM')
-rw-r--r--lib/ASM/Commander.pm1051
-rw-r--r--lib/ASM/XML.pm2
2 files changed, 996 insertions, 57 deletions
diff --git a/lib/ASM/Commander.pm b/lib/ASM/Commander.pm
index 1ae2700..054c57c 100644
--- a/lib/ASM/Commander.pm
+++ b/lib/ASM/Commander.pm
@@ -9,61 +9,1002 @@ use Data::Dumper;
use URI::Escape;
no if $] >= 5.017011, warnings => 'experimental::smartmatch';
-sub new
-{
- my $module = shift;
- my $self = {};
- bless($self);
- return $self;
-}
-
-sub command
-{
- my ($self, $conn, $event) = @_;
- my $args = $event->{args}->[0];
- my $from = $event->{from};
- my $cmd = $args;
- my $d1;
- my $nick = lc $event->{nick};
- my $acct;
- if (defined($::sn{$nick}) && defined($::sn{$nick}->{account})) {
- $acct = lc $::sn{$nick}->{account};
- }
-# return 0 unless (ASM::Util->speak($event->{to}->[0]));
- foreach my $command ( @{$::commands->{command}} )
- {
- my $fail = 0;
- unless ( (ASM::Util->speak($event->{to}->[0])) ) {
- next unless (defined($command->{nohush}) && ($command->{nohush} eq "nohush"));
- }
- if (defined($command->{flag})) { #If the command is restricted,
- if (!defined($acct)) {
- $fail = 1;
- }
- elsif (!defined($::users->{person}->{$acct})) { #make sure the requester has an account
- $fail = 1;
- }
- elsif (!defined($::users->{person}->{$acct}->{flags})) { #make sure the requester has flags defined
- $fail = 1;
- }
- elsif (!(grep {$_ eq $command->{flag}} split('', $::users->{person}->{$acct}->{flags}))) { #make sure the requester has the needed flags
- $fail = 1;
- }
- }
- if ($cmd=~/$command->{cmd}/) {
- ASM::Util->dprint("$event->{from} told me: $cmd", "commander");
- if (!ASM::Util->notRestricted($nick, "nocommands")) {
- $fail = 1;
- }
- if ($fail == 1) {
- $conn->privmsg($nick, "You don't have permission to use that command, or you're not signed into nickserv.");
- } else {
- eval $command->{content};
- warn $@ if $@;
- }
- last;
- }
- }
+my $cmdtbl = {
+ '^;wallop' => {
+ 'flag' => 'd',
+ 'cmd' => \&cmd_wallop },
+ '^;;addwebuser (?<pass>.{6,})' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_addwebuser },
+ '^;delwebuser (?<user>\S+)' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_delwebuser },
+ '^;teredo (?<ip>\S+)' => {
+ 'cmd' => \&cmd_teredo },
+ '^;status$' => {
+ 'cmd' => \&cmd_status },
+ '^;mship (?<nick>\S+)' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_mship },
+ '^;source$' => {
+ 'cmd' => \&cmd_source },
+ '^;sql (?<db>main|log) (?<string>.*)' => {
+ 'flag' => 'd',
+ 'cmd' => \&cmd_sql },
+ '^;monitor (?<chan>\S+) *$' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_monitor },
+ '^;monitor (?<chan>\S+) ?(?<switch>yes|no)$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_monitor2 },
+ '^;suppress (?<chan>\S+) *$' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_suppress },
+ '^;silence (?<chan>\S+) *$' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_silence },
+ '^;silence (?<chan>\S+) (?<switch>yes|no) *$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_silence2 },
+ '^;help$' => {
+ 'cmd' => \&cmd_help },
+ '^;help (?<cmd>\S+)$' => {
+ 'cmd' => \&cmd_help2 },
+ '^;db$' => {
+ 'cmd' => \&cmd_db },
+ '^;query (\S+) ?(\S+)?$' => {
+ 'cmd' => \&cmd_query },
+ '^;investigate (\S+) *$' => {
+ 'cmd' => \&cmd_investigate },
+ '^;investigate2 (\S+) ?(\d*) *$' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_investigate2 },
+ '^;userx? add (\S+) (\S+)$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_user_add },
+ '^;userx? flags (\S+) ?$' => {
+ 'cmd' => \&cmd_user_flags },
+ '^;userx? flags (\S+) (\S+)$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_user_flags2 },
+ '^;userx? del (?<nick>\S+)$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_user_del },
+ '^;target (?<chan>\S+) (?<nick>\S+) ?(?<level>[a-z]*)$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_target },
+ '^;detarget (?<chan>\S+) (?<nick>\S+)' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_detarget },
+ '^;showhilights (?<nick>\S+) *$' => {
+ 'flag' => 'h',
+ 'cmd' => \&cmd_showhilights },
+ '^;hilight (?<chan>\S+) (?<nicks>\S+) ?(?<level>[a-z]*)$' => {
+ 'flag' => 'h',
+ 'cmd' => \&cmd_hilight },
+ '^;dehilight (?<chan>\S+) (?<nicks>\S+)' => {
+ 'flag' => 'h',
+ 'cmd' => \&cmd_dehilight },
+ '^;join (?<chan>\S+)' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_join },
+ '^;part (?<chan>\S+)' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_part },
+ '^;sl (?<string>.+)' => {
+ 'flag' => 'd',
+ 'cmd' => \&cmd_sl },
+ '^;quit ?(?<reason>.*)' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_quit },
+ '^;ev (?<string>.*)' => {
+ 'flag' => 'd',
+ 'cmd' => \&cmd_ev },
+ '^;rehash$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_rehash },
+ '^;restrict (?<type>nick|account|host) (?<who>\S+) (?<mode>\+|-)(?<restriction>[a-z0-9_-]+)$' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_restrict },
+ '^\s*\!ops ?(#\S+)? ?(.*)' => {
+ 'nohush' => 'nohush',
+ 'cmd' => \&cmd_ops },
+ '^;blacklist (?<string>.+)' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_blacklist },
+ '^;blacklistpcre (?<string>.+)' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_blacklistpcre },
+ '^;unblacklist (?<id>[0-9a-f]+)$' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_unblacklist },
+ '^;plugin (?<chan>\S+) (?<risk>\S+) (?<reason>.*)' => {
+ 'flag' => 'p',
+ 'cmd' => \&cmd_plugin },
+ '^;sync (?<chan>\S+)' => {
+ 'flag' => 'a',
+ 'cmd' => \&cmd_sync },
+ '^;ping\s*$' => {
+ 'cmd' => \&cmd_ping },
+ '^;ping (?<string>\S.*)$' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_ping2 },
+ '^;blreason (?<id>[0-9a-f]+) (?<reason>.*)' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_blreason },
+ '^;bllookup (?<id>[0-9a-f]+)$' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_bllookup },
+ '^;falsematch\b' => {
+ 'flag' => 's',
+ 'cmd' => \&cmd_falsematch },
+};
+
+sub new {
+ my $module = shift;
+ my $self = {};
+ $self->{cmdtbl} = $cmdtbl;
+ bless($self);
+ return $self;
+}
+
+sub command {
+ my ($self, $conn, $event) = @_;
+ my $args = $event->{args}->[0];
+ my $from = $event->{from};
+ my $cmd = $args;
+ my $d1;
+ my $nick = lc $event->{nick};
+ my $acct;
+ if (defined($::sn{$nick}) && defined($::sn{$nick}->{account})) {
+ $acct = lc $::sn{$nick}->{account};
+ }
+# return 0 unless (ASM::Util->speak($event->{to}->[0]));
+ foreach my $command ( keys %{$self->{cmdtbl}} )
+ {
+ my $fail = 0;
+ unless ( (ASM::Util->speak($event->{to}->[0])) ) {
+ next unless (defined($self->{cmdtbl}->{$command}->{nohush}));
+ }
+ if (defined($self->{cmdtbl}->{$command}->{flag})) { #If the command is restricted,
+ if (!defined($acct)) {
+ $fail = 1;
+ }
+ elsif (!defined($::users->{person}->{$acct})) { #make sure the requester has an account
+ $fail = 1;
+ }
+ elsif (!defined($::users->{person}->{$acct}->{flags})) { #make sure the requester has flags defined
+ $fail = 1;
+ }
+ elsif (!(grep {$_ eq $self->{cmdtbl}->{$command}->{flag}} split('', $::users->{person}->{$acct}->{flags}))) { #make sure the requester has the needed flags
+ $fail = 1;
+ }
+ }
+ if ($cmd=~/$command/) {
+ ASM::Util->dprint("$event->{from} told me: $cmd", "commander");
+ if (!ASM::Util->notRestricted($nick, "nocommands")) {
+ $fail = 1;
+ }
+ if ($fail == 1) {
+ $conn->privmsg($nick, "You don't have permission to use that command, or you're not signed into nickserv.");
+ } else {
+ &{$self->{cmdtbl}->{$command}->{cmd}}($conn, $event);
+ }
+ last;
+ }
+ }
}
1;
+
+sub cmd_wallop {
+ my ($conn, $event) = @_;
+
+ my @chans = ();
+ foreach my $chan (keys %{$::channels->{channel}}) {
+ if (defined($::channels->{channel}->{$chan}->{msgs})) {
+ foreach my $risk (keys %{$::channels->{channel}->{$chan}->{msgs}}) {
+ push @chans, @{$::channels->{channel}->{$chan}->{msgs}->{$risk}};
+ }
+ }
+ }
+ my %uniq = ();
+ foreach my $chan (@chans) { $uniq{$chan} = 1; }
+ @chans = keys(%uniq);
+ print Dumper(\@chans);
+}
+
+sub cmd_addwebuser {
+ my ($conn, $event) = @_;
+
+ my $pass = $+{pass};
+ if ($event->{to}->[0] =~ /^#/) {
+ $conn->privmsg($event->replyto, "This command must be used in PM. Try again WITH A DIFFERENT PASSWORD!");
+ return;
+ }
+ use Apache::Htpasswd; use Apache::Htgroup;
+ my $o_Htpasswd = new Apache::Htpasswd({passwdFile => $::settings->{web}->{userfile}, UseMD5 => 1});
+ my $o_Htgroup = new Apache::Htgroup($::settings->{web}->{groupfile});
+ my $user = lc $::sn{lc $event->{nick}}->{account};
+ $o_Htpasswd->htDelete($user);
+ $o_Htpasswd->htpasswd($user, $pass);
+ $o_Htpasswd->writeInfo($user, strftime("%F %T", gmtime));
+ $o_Htgroup->adduser($user, 'actionlogs');
+ $o_Htgroup->save();
+ $conn->privmsg($event->replyto, "Added $user to the list of authorized web users.")
+}
+
+sub cmd_delwebuser {
+ my ($conn, $event) = @_;
+
+ my $user = $+{user};
+ use Apache::Htpasswd;
+ use Apache::Htgroup;
+ my $o_Htpasswd = new Apache::Htpasswd({passwdFile => $::settings->{web}->{userfile}, UseMD5 => 1});
+ my $o_Htgroup = new Apache::Htgroup($::settings->{web}->{groupfile});
+ $o_Htpasswd->htDelete($user);
+ $o_Htgroup->deleteuser($user, 'actionlogs');
+ $o_Htgroup->save();
+ $conn->privmsg($event->replyto, "Removed $user from the list of authorized web users.")
+}
+
+sub cmd_teredo {
+ my ($conn, $event) = @_;
+
+ my $arg1 = $+{ip};
+ my @splitip = split(/:/, $arg1);
+ if ( (int($splitip[0]) != 2001) || (int($splitip[1]) != 0) ) {
+ $conn->privmsg($event->replyto, "This is not a teredo-tunnelled IP.");
+ return;
+ }
+ my $server = join('.', unpack('C4', pack('N', hex($splitip[2] . $splitip[3]))));
+ my $host = join('.', unpack('C4', pack('N', (hex($splitip[6] . $splitip[7])^hex('ffffffff')))));
+ my $port = hex($splitip[5]) ^ hex('ffff');
+ $conn->privmsg($event->replyto, "Source is $host:$port; teredo server in use is $server.");
+}
+
+sub cmd_status {
+ my ($conn, $event) = @_;
+
+ my $size = `ps -p $$ h -o size`;
+ my $cputime = `ps -p $$ h -o time`;
+ chomp $size; chomp $cputime;
+ my $upstr = '';
+ my $up = (time - $::starttime);
+ if (int($up/86400) != 0) { #days
+ $upstr = $upstr . int($up/86400) . 'd';
+ $up = $up % 86400;
+ }
+ if (int($up/3600) != 0) { #hours
+ $upstr = $upstr . int($up/3600) . 'h';
+ $up = $up % 3600;
+ }
+ if (int($up/60) != 0) { #minutes
+ $upstr = $upstr . int($up/60) . 'm';
+ $up = $up % 60;
+ }
+ if (int($up/1) != 0) { #seconds
+ $upstr = $upstr . int($up/1) . 's';
+ $up = $up % 1;
+ }
+ my ($tx, $rx);
+ if ($conn->{_tx}/1024 > 1024) {
+ $tx = sprintf("%.2fMB", $conn->{_tx}/(1024*1024));
+ } else {
+ $tx = sprintf("%.2fKB", $conn->{_tx}/1024);
+ }
+ if ($conn->{_rx}/1024 > 1024) {
+ $rx = sprintf("%.2fMB", $conn->{_rx}/(1024*1024));
+ } else {
+ $rx = sprintf("%.2fKB", $conn->{_rx}/1024);
+ }
+ $conn->privmsg($event->replyto, "This bot has been running for " . $upstr .
+ ", is tracking " . (scalar (keys %::sn)) . " nicks" .
+ " across " . (scalar (keys %::sc)) . " tracked channels." .
+ " It is using " . $size . "KB of RAM" .
+ ", has used $cputime of CPU time" .
+ ", has sent $tx of data, and received $rx of data.");
+}
+
+sub cmd_mship {
+ my ($conn, $event) = @_;
+
+ my $nick = $+{nick};
+ if (defined($::sn{lc $nick})) {
+ if ($event->{to}->[0] =~ /^#/) {
+ $conn->privmsg($event->replyto, $nick . " is on: " . ASM::Util->commaAndify(sort(grep { not grep { /^s$/ } @{$::sc{$_}{modes}} } @{$::sn{lc $nick}->{mship}})));
+ } else {
+ $conn->privmsg($event->replyto, $nick . " is on: " . ASM::Util->commaAndify(sort @{$::sn{lc $nick}->{mship}}));
+ }
+ } else {
+ $conn->privmsg($event->replyto, "I don't see $nick.");
+ }
+}
+
+sub cmd_source {
+ my ($conn, $event) = @_;
+
+ $conn->privmsg($event->replyto, "source is at https://gitlab.devlabs.linuxassist.net/asm/antispammeta/");
+}
+
+sub cmd_sql {
+ my ($conn, $event) = @_;
+
+ if (!defined $::db) {
+ $conn->privmsg($event->replyto, "I am set to run without a database, fool.");
+ return;
+ }
+
+ my $dbh = $::db->{DBH};
+ if ($+{db} eq 'log') {
+ $dbh = $::db->{DBH_LOG};
+ }
+ $::db->raw($conn, $event->{to}->[0], $dbh, $+{string});
+}
+
+sub cmd_monitor {
+ my ($conn, $event) = @_;
+
+ my $chan = lc $+{chan};
+ my $switch = $::channels->{channel}->{$chan}->{monitor} // 'yes';
+ $conn->privmsg($event->replyto, "Monitor flag for $chan is currently set to $switch");
+}
+
+sub cmd_monitor2 {
+ my ($conn, $event) = @_;
+
+ my $chan = lc $+{chan};
+ my $switch = lc $+{switch};
+ $::channels->{channel}->{$chan}->{monitor} = $switch;
+ ASM::XML->writeChannels();
+ $conn->privmsg($event->replyto, "Monitor flag for $chan set to $switch");
+}
+
+sub cmd_suppress {
+ my ($conn, $event) = @_;
+
+ my $chan = lc $1;
+ my $old = $::channels->{channel}->{$chan}->{monitor};
+ $::channels->{channel}->{$chan}->{monitor} = "no";
+ $conn->schedule(30*60, sub {
+ $::channels->{channel}->{$chan}->{monitor} = $old;
+ $conn->privmsg($event->replyto, "Unsuppressed $chan");
+ ASM::XML->writeChannels();
+ });
+ $conn->privmsg($event->replyto, "Suppressing alerts from $chan for 30 minutes. If the bot restarts or the config is changed, you will need to do ;monitor $chan to check the status of the monitor flag");
+}
+
+sub cmd_silence {
+ my ($conn, $event) = @_;
+
+ my $chan = lc $+{chan};
+ my $switch = $::channels->{channel}->{$chan}->{silence} // 'no';
+ $conn->privmsg($event->replyto, "Silence flag for $chan is currently set to $switch");
+}
+
+sub cmd_silence2 {
+ my ($conn, $event) = @_;
+
+ my $chan = lc $+{chan};
+ my $switch = lc $+{switch};
+ $::channels->{channel}->{$chan}->{silence} = $switch;
+ ASM::XML->writeChannels();
+ $conn->privmsg($event->replyto, "Silence flag for $chan set to $switch");
+}
+
+sub cmd_help {
+ my ($conn, $event) = @_;
+
+ $conn->privmsg($event->replyto, "Please refer to http://antispammeta.net and irc.freenode.net #antispammeta");
+}
+
+sub cmd_help2 {
+ my ($conn, $event) = @_;
+
+ my @cmds = grep { $_ =~ /$+{cmd}/} (keys %{$cmdtbl});
+ if ((scalar @cmds) > 2) {
+ $conn->privmsg($event->replyto, "Please refer to http://antispammeta.net and irc.freenode.net #antispammeta");
+ } else {
+ foreach my $cmd (@cmds) {
+ $conn->privmsg($event->replyto, ($cmdtbl->{$cmd}->{flag} // ' ') . ' ' . $cmd)
+ }
+ }
+}
+
+sub cmd_db {
+ my ($conn, $event) = @_;
+
+ $conn->privmsg($event->replyto, "db is at http://antispammeta.net/query.html");
+}
+
+sub cmd_query {
+ my ($conn, $event) = @_;
+
+ return unless defined $::db;
+ my $channel = defined($2) ? $1 : '%';
+ my @nuh = split(/(\!|\@)/, defined($2) ? $2 : $1);
+ my $result = $::db->query($channel, $nuh[0], $nuh[2], $nuh[4]);
+ $conn->privmsg($event->replyto, "$result results found.");
+}
+
+sub cmd_investigate {
+ my ($conn, $event) = @_;
+
+ return unless defined $::db;
+ my $nick = lc $1;
+ unless (defined($::sn{$nick})) {
+ $conn->privmsg($event->replyto, "I don't see $nick in my state tracking database, so I can't run any queries on their info, sorry :(" .
+ " You can try https://antispammeta.net/cgi-bin/secret/investigate.pl?nick=$nick instead!");
+ return;
+ }
+ my $person = $::sn{$nick};
+ my $dbh = $::db->{DBH};
+
+ my $mnicks = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE nick like " . $dbh->quote($nick) . ';');
+ my $musers = (lc $person->{user} ~~ $::mysql->{ignoredidents}) ? "didn't check" : $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE user like " . $dbh->quote($person->{user}) . ';');
+ my $mhosts = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE host like " . $dbh->quote($person->{host}) . ';');
+ my $maccts = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE account like " . $dbh->quote($person->{account}) . ';');
+ my $mgecos = (lc $person->{gecos} ~~ $::mysql->{ignoredgecos}) ? "didn't check" : $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE gecos like " . $dbh->quote($person->{gecos}) . ';');
+
+ my $ip = ASM::Util->getNickIP($nick);
+ my $matchedip = 0;
+ $matchedip = $dbh->do("SELECT * from $::db->{ACTIONTABLE} WHERE ip = " . $dbh->quote($ip) . ';') if defined($ip);
+ $mnicks =~ s/0E0/0/;
+ $musers =~ s/0E0/0/;
+ $mhosts =~ s/0E0/0/;
+ $maccts =~ s/0E0/0/;
+ $mgecos =~ s/0E0/0/;
+ $matchedip =~ s/0E0/0/;
+ my $dq = '';
+ if (defined($ip)) {
+ $dq = join '.', unpack 'C4', pack 'N', $ip;
+ }
+ $conn->privmsg($event->replyto, "I found $mnicks matches by nick ($nick), $musers by user ($person->{user}), $mhosts by hostname ($person->{host}), " .
+ "$maccts by NickServ account ($person->{account}), $mgecos by gecos field ($person->{gecos}), and $matchedip by real IP ($dq).");
+ $conn->privmsg($event->replyto, ' Web results are at https://antispammeta.net/cgi-bin/secret/investigate.pl?nick=' . uri_escape($nick) .
+ ((lc $person->{user} ~~ $::mysql->{ignoredidents}) ? '' : '&user=' . uri_escape($person->{user})) .
+ '&host=' . uri_escape($person->{host}) . '&account=' . uri_escape($person->{account}) .
+ ((lc $person->{gecos} ~~ $::mysql->{ignoredgecos}) ? '' : '&gecos=' . uri_escape($person->{gecos})) . '&realip=' . $dq);
+}
+
+sub cmd_investigate2 {
+ my ($conn, $event) = @_;
+
+ return unless defined $::db;
+ my $nick = lc $1;
+ my $skip = 0;
+ $skip = $2 if (defined($2) and ($2 ne ""));
+ foreach my $xcommand ( @{$::commands->{command}} ) {
+ next unless $xcommand->{cmd} eq '^;investigate (\S+) *$';
+ if (";investigate $nick" =~ /$xcommand->{cmd}/) {
+ eval $xcommand->{content};
+ warn $@ if $@;
+ last;
+ }
+ }
+ unless (defined($::sn{$nick})) {
+ return;
+ }
+ my $person = $::sn{$nick};
+ my $dbh = $::db->{DBH};
+
+ my $query = "SELECT * from $::db->{ACTIONTABLE} WHERE nick like " . $dbh->quote($nick) .
+ ((lc $person->{user} ~~ $::mysql->{ignoredidents}) ? '' : ' or user like ' . $dbh->quote($person->{user})) .
+ ' or host like ' . $dbh->quote($person->{host}) .
+ ' or account like ' . $dbh->quote($person->{account}) .
+ ((lc $person->{gecos} ~~ $::mysql->{ignoredgecos}) ? '' : ' or gecos like ' . $dbh->quote($person->{gecos}));
+ my $ip = ASM::Util->getNickIP($nick);
+ if (defined($ip)) {
+ $query = $query . ' or ip = ' . $dbh->quote($ip);
+ }
+ $query = $query . " order by time desc limit $skip,10;";
+ ASM::Util->dprint($query, 'mysql');
+ my $query_handle = $dbh->prepare($query);
+ $query_handle->execute();
+ my $dq = '';
+ if (defined($ip)) {
+ $dq = '&realip=' . join '.', unpack 'C4', pack 'N', $ip;
+ }
+ my @data = @{$query_handle->fetchall_arrayref()};
+ if (@data) {
+ $conn->privmsg($event->replyto, 'Sending you the results...');
+ } else {
+ $conn->privmsg($event->replyto, 'No results to send!');
+ }
+# reverse @data;
+#$data will be an array of arrays,
+ my ($xindex, $xtime, $xaction, $xreason, $xchannel, $xnick, $xuser, $xhost, $xip, $xgecos, $xaccount, $xbynick, $xbyuser, $xbyhost, $xbygecos, $xbyaccount ) = ( 0 .. 15 );
+ foreach my $line (@data) {
+ my $reason = ''; my $channel = '';
+ $reason = ' (' . $line->[$xreason] . ')' if defined($line->[$xreason]);
+ $channel = ' on ' . $line->[$xchannel] if defined($line->[$xchannel]);
+ $conn->privmsg($event->nick, '#' . $line->[$xindex] . ': ' . $line->[$xtime] . ' ' .
+ $line->[$xnick] . '!' . $line->[$xuser] . '@' . $line->[$xhost] . ' (' . $line->[$xgecos] . ') ' .
+ $line->[$xaction] . $reason . $channel . ' by ' . $line->[$xbynick]); # . "\n";
+ }
+ if (@data) {
+ $conn->privmsg($event->nick, "Only 10 results are shown at a time. For more, do ;investigate2 $nick " . ($skip+10) . '.');
+ }
+}
+
+sub cmd_user_add {
+ my ($conn, $event) = @_;
+
+ my $nick = lc $1;
+ my $flags = $2;
+ my %hasflagshash = ();
+ foreach my $item (split(//, $::users->{person}->{lc $::sn{lc $event->{nick}}->{account}}->{flags})) {
+ $hasflagshash{$item} = 1;
+ }
+ foreach my $flag (split(//, $flags)) {
+ if (!defined($hasflagshash{$flag})) {
+ $conn->privmsg($event->replyto, "You can't give a flag you don't already have.");
+ return;
+ }
+ }
+ if ($flags =~ /d/i) {
+ $conn->privmsg($event->replyto, "The d flag may not be assigned over IRC. Edit the configuration manually.");
+ return;
+ }
+ if ( (defined($::sn{$nick}->{account})) && ( lc $::sn{$nick}->{account} ne $nick ) ) {
+ $conn->privmsg($event->replyto, "I'm assuming you mean " . $nick . "'s nickserv account, " . lc $::sn{$nick}->{account} . '.');
+ $nick = lc $::sn{$nick}->{account};
+ }
+ if (defined($::users->{person}->{$nick}) &&
+ defined($::users->{person}->{$nick}->{flags}) &&
+ ($::users->{person}->{$nick}->{flags} =~ /d/)) {
+ return $conn->privmsg($event->replyto, "Users with the 'd' flag are untouchable. Edit the config file manually.");
+ }
+ $::users->{person}->{$nick} = { 'flags' => $flags };
+ ASM::XML->writeUsers();
+ $conn->privmsg($event->replyto, "Flags for NickServ account $nick set to $flags");
+}
+
+sub cmd_user_flags {
+ my ($conn, $event) = @_;
+
+ my $nick = lc $1;
+ if ( defined($::sn{$nick}) && (defined($::sn{$nick}->{account})) && ( lc $::sn{$nick}->{account} ne $nick ) ) {
+ $conn->privmsg($event->replyto, "I'm assuming you mean " . $nick . "'s nickserv account, " . lc $::sn{$nick}->{account} . '.');
+ $nick = lc $::sn{$nick}->{account};
+ }
+ my $sayNick = substr($nick, 0, 1) . "\x02\x02" . substr($nick, 1);
+ if (defined($::users->{person}->{$nick}->{flags})) {
+ $conn->privmsg($event->replyto, "Flags for $sayNick: $::users->{person}->{$nick}->{flags}");
+ } else {
+ $conn->privmsg($event->replyto, "$sayNick has no flags");
+ }
+}
+
+sub cmd_user_flags2 {
+ my ($conn, $event) = @_;
+
+ my $nick = lc $1;
+ my $flags = $2;
+ my %hasflagshash = ();
+ foreach my $item (split(//, $::users->{person}->{lc $::sn{lc $event->{nick}}->{account}}->{flags})) {
+ $hasflagshash{$item} = 1;
+ }
+ foreach my $flag (split(//, $flags)) {
+ if (!defined($hasflagshash{$flag})) {
+ $conn->privmsg($event->replyto, "You can't give a flag you don't already have.");
+ return;
+ }
+ }
+ if ($flags =~ /d/i) {
+ $conn->privmsg($event->replyto, "The d flag may not be assigned over IRC. Edit the configuration manually.");
+ return;
+ }
+ if ( (defined($::sn{$nick}->{account})) && ( lc $::sn{$nick}->{account} ne $nick ) ) {
+ $conn->privmsg($event->replyto, "I'm assuming you mean " . $nick . "'s nickserv account, " . lc $::sn{$nick}->{account} . '.');
+ $nick = lc $::sn{$nick}->{account};
+ }
+ if (defined($::users->{person}->{$nick}) &&
+ defined($::users->{person}->{$nick}->{flags}) &&
+ ($::users->{person}->{$nick}->{flags} =~ /d/)) {
+ return $conn->privmsg($event->replyto, "Users with the 'd' flag are untouchable. Edit the config file manually.");
+ }
+ if ($flags !~ /s/i) {
+ use Apache::Htpasswd; use Apache::Htgroup;
+ my $o_Htpasswd = new Apache::Htpasswd({passwdFile => $::settings->{web}->{userfile}, UseMD5 => 1});
+ my $o_Htgroup = new Apache::Htgroup($::settings->{web}->{groupfile});
+ $o_Htpasswd->htDelete($nick);
+ $o_Htgroup->deleteuser($nick, 'actionlogs');
+ $o_Htgroup->save();
+ }
+ $::users->{person}->{$nick}->{flags} = $flags;
+ ASM::XML->writeUsers();
+ $conn->privmsg($event->replyto, "Flags for $nick set to $flags");
+}
+
+sub cmd_user_del {
+ my ($conn, $event) = @_;
+
+ my $nick = lc $+{nick};
+ if (defined($::users->{person}->{$nick}) &&
+ defined($::users->{person}->{$nick}->{flags}) &&
+ ($::users->{person}->{$nick}->{flags} =~ /d/)) {
+ return $conn->privmsg($event->replyto, "Users with the 'd' flag are untouchable. Edit the config file manually.");
+ }
+ delete($::users->{person}->{$nick});
+ ASM::XML->writeUsers();
+ use Apache::Htpasswd; use Apache::Htgroup;
+ my $o_Htpasswd = new Apache::Htpasswd({passwdFile => $::settings->{web}->{userfile}, UseMD5 => 1});
+ my $o_Htgroup = new Apache::Htgroup($::settings->{web}->{groupfile});
+ $o_Htpasswd->htDelete($nick);
+ $o_Htgroup->deleteuser($nick, 'actionlogs');
+ $o_Htgroup->save();
+ $conn->privmsg($event->replyto, "Removed $nick from authorized users." .
+ " MAKE SURE YOU PROVIDED a nickserv account to this command, rather than an altnick of the accountholder");
+}
+
+sub cmd_target {
+ my ($conn, $event) = @_;
+
+ my $chan = $+{chan};
+ my $nick = lc $+{nick};
+ my $level= $+{level};
+ my $link = ASM::Util->getLink(lc $chan);
+ if ( lc $link ne lc $chan ) {
+ $conn->privmsg($event->replyto, "Error: $chan is linked to $link - use $link instead.");
+ return;
+ }
+ if ($level eq '') { $level = 'debug'; }
+ unless (defined($::channels->{channel}->{$chan}->{msgs})) {
+ $::channels->{channel}->{$chan}->{msgs} = {};
+ }
+ unless (defined($::channels->{channel}->{$chan}->{msgs}->{$level})) {
+ $::channels->{channel}->{$chan}->{msgs}->{$level} = [];
+ }
+ my @tmphl = @{$::channels->{channel}->{$chan}->{msgs}->{$level}};
+ push(@tmphl, $nick);
+ $::channels->{channel}->{$chan}->{msgs}->{$level} = \@tmphl;
+ ASM::XML->writeChannels();
+ $conn->privmsg($event->replyto, "$nick added to $level risk messages for $chan");
+}
+
+sub cmd_detarget {
+ my ($conn, $event) = @_;
+
+ my $chan = $+{chan};
+ my $nick = $+{nick};
+ my $link = ASM::Util->getLink(lc $chan);
+ if ( lc $link ne lc $chan ) {
+ $conn->privmsg($event->replyto, "Error: $chan is linked to $link - use $link instead.");
+ return;
+ }
+ foreach my $risk ( keys %::RISKS ) {
+ next unless defined($::channels->{channel}->{$chan}->{msgs}->{$risk});
+ my @ppl = @{$::channels->{channel}->{$chan}->{msgs}->{$risk}};
+ @ppl = grep { lc $_ ne lc $nick } @ppl;
+ $::channels->{channel}->{$chan}->{msgs}->{$risk} = \@ppl;
+ }
+ ASM::XML->writeChannels();
+ $conn->privmsg($event->replyto, "$nick removed from targets for $chan");
+}
+
+sub cmd_showhilights {
+ my ($conn, $event) = @_;
+
+ my $nick = $+{nick};
+ my @channels = ();
+ foreach my $chan (keys(%{$::channels->{channel}})) {
+ foreach my $level (keys(%{$::channels->{channel}->{$chan}->{hilights}})) {
+ if ( $nick ~~ $::channels->{channel}->{$chan}->{hilights}->{$level}) {
+ push @channels, $chan . " ($level)";
+ }
+ }
+ }
+ if (! @channels) {
+ $conn->privmsg($event->replyto, "$nick isn't on any hilights");
+ } else {
+ $conn->privmsg($event->replyto, "$nick is hilighted for " . join(', ', @channels));
+ }
+}
+
+sub cmd_hilight {
+ my ($conn, $event) = @_;
+
+ my $chan = $+{chan};
+ my $nick_str = $+{nicks};
+ my @nicks = split(/,/, $nick_str);
+ my $level= $+{level} // '';
+ if ($level eq '') { $level = 'info'; }
+ if ($level !~ /^(disable|debug|info|low|medium|high|opalert)$/) {
+ $conn->privmsg($event->replyto, "Error: I don't recognize $level as a valid level.");
+ return;
+ }
+ my $link = ASM::Util->getLink(lc $chan);
+ if ( lc $link ne lc $chan ) {
+ $conn->privmsg($event->replyto, "Error: $chan is linked to $link - use $link instead.");
+ return;
+ }
+ my $chan_regex = qr/^#|^default$|^master$/;
+ if ( $chan !~ $chan_regex ) {
+ my $msg = "Error: '$chan' doesn't look like a channel to me.";
+ if ( $nick_str =~ $chan_regex ) {
+ $msg .= ' (Maybe you just specified nick and channel in the wrong order?)';
+ }
+ $conn->privmsg($event->replyto, $msg);
+ return;
+ }
+ unless (defined($::channels->{channel}->{$chan}->{hilights})) {
+ $::channels->{channel}->{$chan}->{hilights} = {};
+ }
+ unless (defined($::channels->{channel}->{$chan}->{hilights}->{$level})) {
+ $::channels->{channel}->{$chan}->{hilights}->{$level} = [];
+ }
+ foreach my $nick (@nicks) {
+ my @tmphl = @{$::channels->{channel}->{$chan}->{hilights}->{$level}};
+ push(@tmphl, $nick);
+ $::channels->{channel}->{$chan}->{hilights}->{$level} = \@tmphl;
+ }
+ ASM::XML->writeChannels();
+ $conn->privmsg($event->replyto, ASM::Util->commaAndify(@nicks) . " added to $level risk hilights for $chan");
+}
+
+sub cmd_dehilight {
+ my ($conn, $event) = @_;
+
+ my $chan = $+{chan};
+ my @nicks = split(/,/, $+{nicks});
+ my $link = ASM::Util->getLink(lc $chan);
+ if ( lc $link ne lc $chan ) {
+ $conn->privmsg($event->replyto, "Error: $chan is linked to $link - use $link instead.");
+ return;
+ }
+ foreach my $risk ( keys %::RISKS ) {
+ next unless defined($::channels->{channel}->{$chan}->{hilights}->{$risk});
+ my @ppl = @{$::channels->{channel}->{$chan}->{hilights}->{$risk}};
+ foreach my $nick (@nicks) {
+ @ppl = grep { lc $_ ne lc $nick } @ppl;
+ }
+ $::channels->{channel}->{$chan}->{hilights}->{$risk} = \@ppl;
+ }
+ ASM::XML->writeChannels();
+ $conn->privmsg($event->replyto, "Removing hilights for " . ASM::Util->commaAndify(@nicks) . " in $chan");
+}
+
+sub cmd_join {
+ my ($conn, $event) = @_;
+
+ my $chan = lc $+{chan};
+ unless (defined($::channels->{channel}->{$chan})) {
+ $::channels->{channel}->{$chan} = { monitor => "yes", silence => "no" };
+ ASM::XML->writeChannels();
+ }
+ $conn->join($chan);
+ my @autojoins = @{$::settings->{autojoins}};
+ if (!grep { $chan eq lc $_ } @autojoins) {
+ @autojoins = (@autojoins, $chan);
+ $::settings->{autojoins} = \@autojoins;
+ ASM::XML->writeSettings();
+ }
+}
+
+sub cmd_part {
+ my ($conn, $event) = @_;
+
+ my $chan = lc $+{chan};
+ $conn->part($chan);
+ my @autojoins = @{$::settings->{autojoins}};
+ @autojoins = grep { lc $_ ne $chan } @autojoins;
+ $::settings->{autojoins} = \@autojoins;
+ ASM::XML->writeSettings();
+}
+
+sub cmd_sl {
+ my ($conn, $event) = @_;
+
+ $conn->sl($+{string});
+}
+
+sub cmd_quit {
+ my ($conn, $event) = @_;
+
+ $conn->quit($+{reason});
+}
+
+sub cmd_ev {
+ my ($conn, $event) = @_;
+
+ eval $+{string};
+ warn $@ if $@;
+}
+
+sub cmd_rehash {
+ my ($conn, $event) = @_;
+
+ ASM::XML->readXML();
+ $conn->privmsg($event->replyto, 'config files were re-read');
+}
+
+sub cmd_restrict {
+ my ($conn, $event) = @_;
+
+ $+{who} = lc $+{who};
+ if ($+{mode} eq '-') {
+ delete $::restrictions->{$+{type} . 's'}->{$+{type}}->{$+{who}}->{$+{restriction}};
+ $conn->privmsg($event->replyto, "Removed $+{restriction} restriction for $+{type} $+{who}");
+ }
+ if ($+{mode} eq '+') {
+ if (! defined($::restrictions->{$+{type} . 's'}->{$+{type}}->{$+{who}})) {
+ $::restrictions->{$+{type} . 's'}->{$+{type}}->{$+{who}} = {};
+ }
+ $::restrictions->{$+{type} . 's'}->{$+{type}}->{$+{who}}->{$+{restriction}} = $+{restriction};
+ $conn->privmsg($event->replyto, "Added $+{restriction} restriction for $+{type} $+{who}");
+ }
+ ASM::XML->writeRestrictions();
+}
+
+sub cmd_ops {
+ my ($conn, $event) = @_;
+
+ my $tgt = lc $event->{to}->[0];
+ $tgt = lc $1 if (defined($1));
+ my $msg = $1;
+ $msg = $2 if defined($2);
+ if ( (($::channels->{channel}->{$tgt}->{monitor} // "yes") eq "no") || #we're not monitoring this channel
+ !(lc $tgt ~~ $::sn{lc $event->{nick}}->{mship})) { #they're not on the channel they're calling !ops for
+ return;
+ }
+ if (defined($::ignored{$tgt}) && ($::ignored{$tgt} >= $::RISKS{'opalert'})) {
+ if (ASM::Util->notRestricted(lc $event->{nick}, "noops")) {
+ if (lc $event->{to}->[0] eq '##linux') {
+ $conn->privmsg($event->{nick}, "I've already been recently asked to summon op attention. " .
+ "In the future, please use /msg $conn->{_nick} !ops $event->{to}->[0] reasonGoesHere" .
+ " - this allows ops to be notified while minimizing channel hostility.");
+ } elsif (lc $event->{to}->[0] eq lc $conn->{_nick}) {
+ if (lc $tgt eq lc $conn->{_nick}) { # they privmsged the bot without providing a target
+ $conn->privmsg($event->{nick}, "Sorry, it looks like you've tried to use the !ops command " .
+ "via PM but haven't specified a target. Try again with /msg $conn->{_nick} " .
+ "!ops #channelGoesHere ReasonGoesHere");
+ } else {
+ $conn->privmsg($event->{nick}, "I've already recently notified $tgt ops.");
+ }
+ }
+ }
+ return;
+ }
+ if (ASM::Util->notRestricted(lc $event->{nick}, "noops")) {
+ my $tgt = lc $event->{to}->[0];
+ $tgt = lc $1 if (defined($1));
+ my $msg = $1;
+ $msg = $2 if defined($2);
+ if (lc $event->{to}->[0] eq '##linux') {
+ $conn->privmsg($event->{nick}, "I've summoned op attention. In the future, please use /msg " .
+ "$conn->{_nick} !ops $event->{to}->[0] reasonGoesHere - this allows ops to " .
+ "be notified while minimizing channel hostility.");
+ } elsif ((lc $event->{to}->[0] eq '#wikipedia-en-help') && (!defined($msg))) {
+ $conn->privmsg($event->{nick}, "I've summoned op attention, but in the future, please specify " .
+ "a reason, e.g. !ops reasongoeshere - so ops know what is going on. Thanks! :)");
+ } elsif (lc $event->{to}->[0] eq lc $conn->{_nick}) {
+ if (lc $tgt eq lc $conn->{_nick}) { # they privmsged the bot without providing a target
+ $conn->privmsg($event->{nick}, "Sorry, it looks like you've tried to use the !ops command " .
+ "via PM but haven't specified a target. Try again with /msg $conn->{_nick} " .
+ "!ops #channelGoesHere ReasonGoesHere");
+ return;
+ } else {
+ $conn->privmsg($event->{nick}, "Thanks, I'm notifying $tgt ops.");
+ }
+ }
+ my $hilite=ASM::Util->commaAndify(ASM::Util->getAlert($tgt, 'opalert', 'hilights'));
+ my $txtz = "[\x02$tgt\x02] - $event->{nick} wants op attention";
+ if ((time-$::sc{$tgt}{users}{lc $event->{nick}}{jointime}) > 90) {
+ $txtz = "$txtz ($msg) $hilite !att-$tgt-opalert";
+ }
+ my @tgts = ASM::Util->getAlert($tgt, 'opalert', 'msgs');
+ ASM::Util->sendLongMsg($conn, \@tgts, $txtz);
+ $::log->incident($tgt, "$tgt: $event->{nick} requested op attention\n");
+ } else {
+ unless (defined($::ignored{$tgt}) && ($::ignored{$tgt} >= $::RISKS{'opalert'})) {
+ my @tgts = ASM::Util->getAlert($tgt, 'opalert', 'msgs');
+ foreach my $chan (@tgts) {
+ $conn->privmsg($chan, $event->{nick} . " tried to use the ops trigger for $tgt but is restricted from doing so.");
+ }
+ }
+ }
+ $::ignored{$tgt} = $::RISKS{'opalert'};
+ $conn->schedule(45, sub { delete($::ignored{$tgt}) if $::ignored{$tgt} == $::RISKS{'opalert'} });
+}
+
+sub cmd_blacklist {
+ my ($conn, $event) = @_;
+
+ $+{string} = lc $+{string};
+ use String::CRC32;
+ my $id = sprintf("%08x", crc32($+{string}));
+ $::blacklist->{string}->{$id} = { "content" => $+{string}, "type" => "string", "setby" => $event->nick, "settime" => strftime('%F', gmtime) };
+ ASM::XML->writeBlacklist();
+ $conn->privmsg($event->replyto, "$+{string} blacklisted with id $id, please use ;blreason $id reasonGoesHere to set a reason");
+}
+
+sub cmd_blacklistpcre {
+ my ($conn, $event) = @_;
+
+ use String::CRC32;
+ my $id = sprintf("%08x", crc32($+{string}));
+ $::blacklist->{string}->{$id} = { "content" => $+{string}, "type" => "pcre", "setby" => $event->nick, "settime" => strftime('%F', gmtime) };
+ ASM::XML->writeBlacklist();
+ $conn->privmsg($event->replyto, "$+{string} blacklisted with id $id, please use ;blreason $id reasonGoesHere to set a reason");
+}
+
+sub cmd_unblacklist {
+ my ($conn, $event) = @_;
+
+ if (defined($::blacklist->{string}->{$+{id}})) {
+ delete $::blacklist->{string}->{$+{id}};
+ $conn->privmsg($event->replyto, "blacklist id $+{id} removed");
+ ASM::XML->writeBlacklist();
+ } else {
+ $conn->privmsg($event->replyto, "invalid id");
+ }
+}
+
+sub cmd_plugin {
+ my ($conn, $event) = @_;
+
+ my $txtz = "\x03" . $::RCOLOR{$::RISKS{$+{risk}}} . "\u$+{risk}\x03 risk threat [\x02$+{chan}\x02] - " .
+ "\x02($event->{nick} plugin)\x02 - $+{reason}; ping ";
+ $txtz = $txtz . ASM::Util->commaAndify(ASM::Util->getAlert(lc $+{chan}, $+{risk}, 'hilights')) if (ASM::Util->getAlert(lc $+{chan}, $+{risk}, 'hilights'));
+ $txtz = $txtz . ' !att-' . $+{chan} . '-' . $+{risk};
+ my @tgts = ASM::Util->getAlert(lc $+{chan}, $+{risk}, 'msgs');
+ ASM::Util->sendLongMsg($conn, \@tgts, $txtz);
+}
+
+sub cmd_sync {
+ my ($conn, $event) = @_;
+
+ $conn->sl("MODE $+{chan} bq");
+ $conn->sl("MODE $+{chan}");
+ $conn->sl("WHO $+{chan} %tcuihnar,314");
+}
+
+sub cmd_ping {
+ my ($conn, $event) = @_;
+#
+ $conn->privmsg($event->replyto, "pong");
+}
+
+sub cmd_ping2 {
+ my ($conn, $event) = @_;
+#
+ $conn->privmsg($event->replyto, "pong $+{string}");
+}
+
+sub cmd_blreason {
+ my ($conn, $event) = @_;
+
+ if (defined($::blacklist->{string}->{$+{id}})) {
+ $::blacklist->{string}->{$+{id}}->{reason} = $+{reason};
+ $conn->privmsg($event->replyto, "Reason set");
+ ASM::XML->writeBlacklist();
+ } else {
+ $conn->privmsg($event->replyto, "ID is invalid");
+ }
+}
+
+sub cmd_bllookup {
+ my ($conn, $event) = @_;
+
+ if (defined($::blacklist->{string}->{$+{id}})) {
+ my $content = $::blacklist->{string}->{$+{id}}->{content};
+ my $setby = $::blacklist->{string}->{$+{id}}->{setby};
+ my $settime = $::blacklist->{string}->{$+{id}}->{settime};
+ my $reason = $::blacklist->{string}->{$+{id}}->{reason};
+ my $type = $::blacklist->{string}->{$+{id}}->{type};
+ $reason = 'none ever provided' unless defined($reason);
+ $conn->privmsg($event->nick, "'$content' $type blacklisted by $setby on $settime with reason $reason");
+ if ($event->{to}->[0] =~ /^#/) {
+ $conn->privmsg($event->replyto, "Info on blacklist ID $+{id} sent via PM");
+ }
+ } else {
+ $conn->privmsg($event->replyto, "ID is invalid");
+ }
+}
+
+sub cmd_falsematch {
+ my ($conn, $event) = @_;
+
+ $conn->privmsg($event->replyto, 'To whitelist false matches for the impersonation check, have someone with the "a" flag run ";restrict nick LegitimateNickGoesHere +nonickbl_impersonate". Contact ilbelkyr if this issue reoccurs.');
+}
diff --git a/lib/ASM/XML.pm b/lib/ASM/XML.pm
index 15ec811..d464847 100644
--- a/lib/ASM/XML.pm
+++ b/lib/ASM/XML.pm
@@ -17,7 +17,6 @@ sub readXML {
autojoins => 'autojoin' });
$::channels = $::xs1->XMLin( "$p/channels.xml", ForceArray => \@fchan );
$::users = $::xs1->XMLin( "$p/users.xml", ForceArray => 'person');
- $::commands = $::xs1->XMLin( "$p/commands.xml", ForceArray => [qw/command/]);
$::mysql = $::xs1->XMLin( "$p/mysql.xml", ForceArray => ['ident', 'geco'],
'GroupTags' => { ignoredidents => 'ident', ignoredgecos => 'geco' });
$::dnsbl = $::xs1->XMLin( "$p/dnsbl.xml", ForceArray => []);
@@ -33,7 +32,6 @@ sub writeXML {
writeRestrictions();
writeBlacklist();
writeMysql();
-# $::xs1->XMLout($::commands, RootName => 'commands', KeyAttr => ['id']) > io("$::cset/commands.xml");
}
sub writeMysql {