mirror of
https://github.com/pragma-/pbot.git
synced 2024-11-22 20:09:43 +01:00
Massive refactor: added support for generic users!
Renamed data/admins to data/users Moved Admins.pm to Users.pm Moved various subroutines in AdminCommands.pm to more appropriate locations Deleted AdminCommands.pm Improvements to Users.pm Added `my` command
This commit is contained in:
parent
cc8f2b827a
commit
5dd03f1c0c
@ -1,394 +0,0 @@
|
||||
# File: AdminCommands.pm
|
||||
# Author: pragma_
|
||||
#
|
||||
# Purpose: Administrative command subroutines.
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package PBot::AdminCommands;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use feature 'unicode_strings';
|
||||
|
||||
use feature 'switch';
|
||||
no if $] >= 5.018, warnings => "experimental::smartmatch";
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
|
||||
my ($class, %conf) = @_;
|
||||
my $self = bless {}, $class;
|
||||
$self->initialize(%conf);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
|
||||
|
||||
$self->{pbot}->{commands}->register(sub { return $self->login(@_) }, "login", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->logout(@_) }, "logout", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->in_channel(@_) }, "in", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->join_channel(@_) }, "join", 40);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->part_channel(@_) }, "part", 40);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->ack_die(@_) }, "die", 90);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->adminadd(@_) }, "adminadd", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->adminrem(@_) }, "adminrem", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->adminset(@_) }, "adminset", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->adminunset(@_) }, "adminunset", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->sl(@_) }, "sl", 90);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->export(@_) }, "export", 90);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->reload(@_) }, "reload", 90);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->evalcmd(@_) }, "eval", 99);
|
||||
}
|
||||
|
||||
sub sl {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
if (not length $arguments) {
|
||||
return "Usage: sl <ircd command>";
|
||||
}
|
||||
|
||||
$self->{pbot}->{conn}->sl($arguments);
|
||||
return "";
|
||||
}
|
||||
|
||||
sub in_channel {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
|
||||
my $usage = "Usage: in <channel> <command>";
|
||||
|
||||
if (not $arguments) {
|
||||
return $usage;
|
||||
}
|
||||
|
||||
my ($channel, $command) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
|
||||
return $usage if not defined $channel or not defined $command;
|
||||
|
||||
$stuff->{admin_channel_override} = $channel;
|
||||
$stuff->{command} = $command;
|
||||
return $self->{pbot}->{interpreter}->interpret($stuff);
|
||||
}
|
||||
|
||||
sub login {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my $channel = $from;
|
||||
|
||||
if (not $arguments) {
|
||||
return "Usage: login [channel] password";
|
||||
}
|
||||
|
||||
if ($arguments =~ m/^([^ ]+)\s+(.+)/) {
|
||||
$channel = $1;
|
||||
$arguments = $2;
|
||||
}
|
||||
|
||||
if ($self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host")) {
|
||||
return "/msg $nick You are already logged into channel $channel.";
|
||||
}
|
||||
|
||||
my $result = $self->{pbot}->{admins}->login($channel, "$nick!$user\@$host", $arguments);
|
||||
return "/msg $nick $result";
|
||||
}
|
||||
|
||||
sub logout {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
return "/msg $nick Uh, you aren't logged into channel $from." if (not $self->{pbot}->{admins}->loggedin($from, "$nick!$user\@$host"));
|
||||
$self->{pbot}->{admins}->logout($from, "$nick!$user\@$host");
|
||||
return "/msg $nick Good-bye, $nick.";
|
||||
}
|
||||
|
||||
sub adminadd {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
|
||||
my ($name, $channel, $hostmask, $level, $password) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 5);
|
||||
|
||||
if (not defined $name or not defined $channel or not defined $hostmask or not defined $level
|
||||
or not defined $password) {
|
||||
return "/msg $nick Usage: adminadd <name> <channel> <hostmask> <level> <password>";
|
||||
}
|
||||
|
||||
$channel = '.*' if lc $channel eq 'global';
|
||||
|
||||
my $admin = $self->{pbot}->{admins}->find_admin($from, "$nick!$user\@$host");
|
||||
|
||||
if (not $admin) {
|
||||
return "You are not an admin in $from.\n";
|
||||
}
|
||||
|
||||
if ($admin->{level} < 90 and $level > 60) {
|
||||
return "You may not set admin level higher than 60.\n";
|
||||
}
|
||||
|
||||
$self->{pbot}->{admins}->add_admin($name, $channel, $hostmask, $level, $password);
|
||||
return "Admin added.";
|
||||
}
|
||||
|
||||
sub adminrem {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
|
||||
my ($channel, $hostmask) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
|
||||
|
||||
if (not defined $channel or not defined $hostmask) {
|
||||
return "/msg $nick Usage: adminrem <channel> <hostmask/name>";
|
||||
}
|
||||
|
||||
$channel = lc $channel;
|
||||
$hostmask = lc $hostmask;
|
||||
|
||||
$channel = '.*' if $channel eq 'global';
|
||||
|
||||
if (exists $self->{pbot}->{admins}->{admins}->{hash}->{$channel}) {
|
||||
if (not exists $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$hostmask}) {
|
||||
foreach my $mask (keys %{ $self->{pbot}->{admins}->{admins}->{hash}->{$channel} }) {
|
||||
next if $mask eq '_name';
|
||||
if ($self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$mask}->{name} eq $hostmask) {
|
||||
$hostmask = $mask;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $self->{pbot}->{admins}->remove_admin($channel, $hostmask);
|
||||
}
|
||||
|
||||
sub adminset {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
my ($channel, $hostmask, $key, $value) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 4);
|
||||
|
||||
if (not defined $channel or not defined $hostmask) {
|
||||
return "Usage: adminset <channel> <hostmask/name> [key] [value]";
|
||||
}
|
||||
|
||||
$channel = lc $channel;
|
||||
$hostmask = lc $hostmask;
|
||||
|
||||
$channel = '.*' if $channel eq 'global';
|
||||
|
||||
if (exists $self->{pbot}->{admins}->{admins}->{hash}->{$channel}) {
|
||||
if (not exists $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$hostmask}) {
|
||||
foreach my $mask (keys %{ $self->{pbot}->{admins}->{admins}->{hash}->{$channel} }) {
|
||||
next if $mask eq '_name';
|
||||
if ($self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$mask}->{name} eq $hostmask) {
|
||||
$hostmask = $mask;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $admin = $self->{pbot}->{admins}->find_admin($from, "$nick!$user\@$host");
|
||||
my $target = $self->{pbot}->{admins}->find_admin($channel, $hostmask);
|
||||
|
||||
if (not $admin) {
|
||||
return "You are not an admin in $from.";
|
||||
}
|
||||
|
||||
if (not $target) {
|
||||
return "There is no admin $hostmask in channel $channel.";
|
||||
}
|
||||
|
||||
if ($key eq 'level' && $admin->{level} < 90 and $value > 60) {
|
||||
return "You may not set admin level higher than 60.\n";
|
||||
}
|
||||
|
||||
if ($target->{level} > $admin->{level}) {
|
||||
return "You may not modify admins higher in level than you.";
|
||||
}
|
||||
|
||||
my $result = $self->{pbot}->{admins}->{admins}->set($channel, $hostmask, $key, $value);
|
||||
$result =~ s/^password => .*;$/password => <private>;/m;
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub adminunset {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
my ($channel, $hostmask, $key) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 3);
|
||||
|
||||
if (not defined $channel or not defined $hostmask) {
|
||||
return "Usage: adminunset <channel> <hostmask/name> <key>";
|
||||
}
|
||||
|
||||
$channel = lc $channel;
|
||||
$hostmask = lc $hostmask;
|
||||
|
||||
$channel = '.*' if $channel eq 'global';
|
||||
|
||||
if (exists $self->{pbot}->{admins}->{admins}->{hash}->{$channel}) {
|
||||
if (not exists $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$hostmask}) {
|
||||
foreach my $mask (keys %{ $self->{pbot}->{admins}->{admins}->{hash}->{$channel} }) {
|
||||
next if $mask eq '_name';
|
||||
if ($self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$mask}->{name} eq $hostmask) {
|
||||
$hostmask = $mask;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $self->{pbot}->{admins}->{admins}->unset($channel, $hostmask, $key);
|
||||
}
|
||||
|
||||
|
||||
sub join_channel {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
foreach my $channel (split /[\s+,]/, $arguments) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host made me join $channel\n");
|
||||
$self->{pbot}->{chanops}->join_channel($channel);
|
||||
}
|
||||
|
||||
return "/msg $nick Joining $arguments";
|
||||
}
|
||||
|
||||
sub part_channel {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
$arguments = $from if not $arguments;
|
||||
|
||||
foreach my $channel (split /[\s+,]/, $arguments) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host made me part $channel\n");
|
||||
$self->{pbot}->{chanops}->part_channel($channel);
|
||||
}
|
||||
|
||||
return "/msg $nick Parting $arguments";
|
||||
}
|
||||
|
||||
sub ack_die {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host made me exit.\n");
|
||||
$self->{pbot}->atexit();
|
||||
$self->{pbot}->{conn}->privmsg($from, "Good-bye.") if defined $from;
|
||||
$self->{pbot}->{conn}->quit("Departure requested.");
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub export {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
if (not defined $arguments) {
|
||||
return "/msg $nick Usage: export <factoids>";
|
||||
}
|
||||
|
||||
if ($arguments =~ /^factoids$/i) {
|
||||
return $self->{pbot}->{factoids}->export_factoids;
|
||||
}
|
||||
}
|
||||
|
||||
sub evalcmd {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
$self->{pbot}->{logger}->log("[$from] $nick!$user\@$host Evaluating [$arguments]\n");
|
||||
|
||||
my $ret;
|
||||
my $result = eval $arguments;
|
||||
if ($@) {
|
||||
if (length $result) {
|
||||
$ret .= "[Error: $@] ";
|
||||
} else {
|
||||
$ret .= "Error: $@";
|
||||
}
|
||||
$ret =~ s/ at \(eval \d+\) line 1.//;
|
||||
}
|
||||
return "/say $ret $result";
|
||||
}
|
||||
|
||||
sub reload {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
my %reloadables = (
|
||||
'commands' => sub {
|
||||
$self->{pbot}->{commands}->load_metadata;
|
||||
return "Commands metadata reloaded.";
|
||||
},
|
||||
|
||||
'blacklist' => sub {
|
||||
$self->{pbot}->{blacklist}->clear_blacklist;
|
||||
$self->{pbot}->{blacklist}->load_blacklist;
|
||||
return "Blacklist reloaded.";
|
||||
},
|
||||
|
||||
'whitelist' => sub {
|
||||
$self->{pbot}->{antiflood}->{whitelist}->clear;
|
||||
$self->{pbot}->{antiflood}->{whitelist}->load;
|
||||
return "Whitelist reloaded.";
|
||||
},
|
||||
|
||||
'ignores' => sub {
|
||||
$self->{pbot}->{ignorelist}->clear_ignores;
|
||||
$self->{pbot}->{ignorelist}->load_ignores;
|
||||
return "Ignore list reloaded.";
|
||||
},
|
||||
|
||||
'admins' => sub {
|
||||
$self->{pbot}->{admins}->{admins}->clear;
|
||||
$self->{pbot}->{admins}->load_admins;
|
||||
return "Admins reloaded.";
|
||||
},
|
||||
|
||||
'channels' => sub {
|
||||
$self->{pbot}->{channels}->{channels}->clear;
|
||||
$self->{pbot}->{channels}->load_channels;
|
||||
return "Channels reloaded.";
|
||||
},
|
||||
|
||||
'bantimeouts' => sub {
|
||||
$self->{pbot}->{chanops}->{unban_timeout}->clear;
|
||||
$self->{pbot}->{chanops}->{unban_timeout}->load;
|
||||
return "Ban timeouts reloaded.";
|
||||
},
|
||||
|
||||
'mutetimeouts' => sub {
|
||||
$self->{pbot}->{chanops}->{unmute_timeout}->clear;
|
||||
$self->{pbot}->{chanops}->{unmute_timeout}->load;
|
||||
return "Mute timeouts reloaded.";
|
||||
},
|
||||
|
||||
'registry' => sub {
|
||||
$self->{pbot}->{registry}->{registry}->clear;
|
||||
$self->{pbot}->{registry}->load;
|
||||
return "Registry reloaded.";
|
||||
},
|
||||
|
||||
'factoids' => sub {
|
||||
$self->{pbot}->{factoids}->{factoids}->clear;
|
||||
$self->{pbot}->{factoids}->load_factoids;
|
||||
return "Factoids reloaded.";
|
||||
},
|
||||
|
||||
'funcs' => sub {
|
||||
$self->{pbot}->{func_cmd}->init_funcs;
|
||||
return "Funcs reloaded.";
|
||||
}
|
||||
);
|
||||
|
||||
if (not length $arguments or not exists $reloadables{$arguments}) {
|
||||
my $usage = 'Usage: reload <';
|
||||
$usage .= join '|', sort keys %reloadables;
|
||||
$usage .= '>';
|
||||
return $usage;
|
||||
}
|
||||
|
||||
return $reloadables{$arguments}();
|
||||
}
|
||||
|
||||
1;
|
218
PBot/Admins.pm
218
PBot/Admins.pm
@ -1,218 +0,0 @@
|
||||
# File: Admins.pm
|
||||
# Author: pragma_
|
||||
#
|
||||
# Purpose: Manages list of bot admins and whether they are logged in.
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package PBot::Admins;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use feature 'unicode_strings';
|
||||
|
||||
use PBot::DualIndexHashObject;
|
||||
use PBot::AdminCommands;
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
|
||||
my ($class, %conf) = @_;
|
||||
my $self = bless {}, $class;
|
||||
$self->initialize(%conf);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
|
||||
|
||||
$self->{admins} = PBot::DualIndexHashObject->new(name => 'Admins', filename => $conf{filename}, pbot => $conf{pbot});
|
||||
$self->load_admins;
|
||||
|
||||
$self->{pbot}->{event_dispatcher}->register_handler('irc.join', sub { $self->on_join(@_) });
|
||||
|
||||
$self->{commands} = PBot::AdminCommands->new(pbot => $conf{pbot});
|
||||
}
|
||||
|
||||
sub on_join {
|
||||
my ($self, $event_type, $event) = @_;
|
||||
my ($nick, $user, $host, $channel) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host, $event->{event}->to);
|
||||
($nick, $user, $host) = $self->{pbot}->{irchandlers}->normalize_hostmask($nick, $user, $host);
|
||||
|
||||
my $admin = $self->find_admin($channel, "$nick!$user\@$host");
|
||||
|
||||
if (defined $admin) {
|
||||
if ($self->{pbot}->{chanops}->can_gain_ops($channel)) {
|
||||
my $modes = '+';
|
||||
my $targets = '';
|
||||
|
||||
if ($admin->{autoop}) {
|
||||
$self->{pbot}->{logger}->log("[admin] $nick!$user\@$host autoop in $channel\n");
|
||||
$modes .= 'o';
|
||||
$targets .= "$nick ";
|
||||
}
|
||||
|
||||
if ($admin->{autovoice}) {
|
||||
$self->{pbot}->{logger}->log("[admin] $nick!$user\@$host autovoice in $channel\n");
|
||||
$modes .= 'v';
|
||||
$targets .= "$nick ";
|
||||
}
|
||||
|
||||
if (length $modes > 1) {
|
||||
$self->{pbot}->{chanops}->add_op_command($channel, "mode $channel $modes $targets");
|
||||
$self->{pbot}->{chanops}->gain_ops($channel);
|
||||
}
|
||||
}
|
||||
|
||||
if ($admin->{autologin}) {
|
||||
$self->{pbot}->{logger}->log("[admin] $nick!$user\@$host autologin to $admin->{name} ($admin->{level}) for $channel\n");
|
||||
$admin->{loggedin} = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub add_admin {
|
||||
my $self = shift;
|
||||
my ($name, $channel, $hostmask, $level, $password, $dont_save) = @_;
|
||||
$channel = '.*' if $channel !~ m/^#/;
|
||||
|
||||
my $data = {
|
||||
name => $name,
|
||||
level => $level,
|
||||
password => $password
|
||||
};
|
||||
|
||||
$self->{pbot}->{logger}->log("Adding new level $level admin: [$name] [$hostmask] for channel [$channel]\n");
|
||||
$self->{admins}->add($channel, $hostmask, $data, $dont_save);
|
||||
}
|
||||
|
||||
sub remove_admin {
|
||||
my $self = shift;
|
||||
my ($channel, $hostmask) = @_;
|
||||
return $self->{admins}->remove($channel, $hostmask);
|
||||
}
|
||||
|
||||
sub load_admins {
|
||||
my $self = shift;
|
||||
my $filename;
|
||||
|
||||
if (@_) { $filename = shift; } else { $filename = $self->{admins}->{filename}; }
|
||||
|
||||
if (not defined $filename) {
|
||||
Carp::carp "No admins path specified -- skipping loading of admins";
|
||||
return;
|
||||
}
|
||||
|
||||
$self->{admins}->load;
|
||||
|
||||
my $i = 0;
|
||||
foreach my $channel (sort keys %{ $self->{admins}->{hash} } ) {
|
||||
foreach my $hostmask (sort keys %{ $self->{admins}->{hash}->{$channel} }) {
|
||||
next if $hostmask eq '_name';
|
||||
$i++;
|
||||
my $name = $self->{admins}->{hash}->{$channel}->{$hostmask}->{name};
|
||||
my $level = $self->{admins}->{hash}->{$channel}->{$hostmask}->{level};
|
||||
my $password = $self->{admins}->{hash}->{$channel}->{$hostmask}->{password};
|
||||
|
||||
if (not defined $name or not defined $level or not defined $password) {
|
||||
Carp::croak "An admin in $filename is missing critical data\n";
|
||||
}
|
||||
|
||||
my $chan = $channel eq '.*' ? 'global' : $channel;
|
||||
$self->{pbot}->{logger}->log("Adding new level $level $chan admin: $name $hostmask\n");
|
||||
}
|
||||
}
|
||||
|
||||
$self->{pbot}->{logger}->log(" $i admins loaded.\n");
|
||||
}
|
||||
|
||||
sub save_admins {
|
||||
my $self = shift;
|
||||
$self->{admins}->save;
|
||||
}
|
||||
|
||||
sub find_admin {
|
||||
my ($self, $from, $hostmask) = @_;
|
||||
|
||||
$from = $self->{pbot}->{registry}->get_value('irc', 'botnick') if not defined $from;
|
||||
$hostmask = '.*' if not defined $hostmask;
|
||||
$hostmask = lc $hostmask;
|
||||
|
||||
my $result = eval {
|
||||
my $admin;
|
||||
foreach my $channel_regex (keys %{ $self->{admins}->{hash} }) {
|
||||
if ($from !~ m/^#/ or $from =~ m/^$channel_regex$/i) {
|
||||
foreach my $hostmask_regex (keys %{ $self->{admins}->{hash}->{$channel_regex} }) {
|
||||
next if $hostmask_regex eq '_name';
|
||||
if ($hostmask_regex =~ m/[*?]/) {
|
||||
# contains * or ? so it's converted to a regex
|
||||
my $hostmask_quoted = quotemeta $hostmask_regex;
|
||||
$hostmask_quoted =~ s/\\\*/.*?/g;
|
||||
$hostmask_quoted =~ s/\\\?/./g;
|
||||
if ($hostmask =~ m/^$hostmask_quoted$/i) {
|
||||
my $temp = $self->{admins}->{hash}->{$channel_regex}->{$hostmask_regex};
|
||||
$admin = $temp if not defined $admin or $admin->{level} < $temp->{level};
|
||||
}
|
||||
} else {
|
||||
# direct comparison
|
||||
if ($hostmask eq lc $hostmask_regex) {
|
||||
my $temp = $self->{admins}->{hash}->{$channel_regex}->{$hostmask_regex};
|
||||
$admin = $temp if not defined $admin or $admin->{level} < $temp->{level};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $admin;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
$self->{pbot}->{logger}->log("Error in find_admin parameters: $@\n");
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub loggedin {
|
||||
my ($self, $channel, $hostmask) = @_;
|
||||
my $admin = $self->find_admin($channel, $hostmask);
|
||||
|
||||
if (defined $admin && $admin->{loggedin}) {
|
||||
return $admin;
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub login {
|
||||
my ($self, $channel, $hostmask, $password) = @_;
|
||||
my $admin = $self->find_admin($channel, $hostmask);
|
||||
|
||||
if (not defined $admin) {
|
||||
$self->{pbot}->{logger}->log("Attempt to login non-existent [$channel][$hostmask] failed\n");
|
||||
return "You do not have an account in $channel.";
|
||||
}
|
||||
|
||||
if ($admin->{password} ne $password) {
|
||||
$self->{pbot}->{logger}->log("Bad login password for [$channel][$hostmask]\n");
|
||||
return "I don't think so.";
|
||||
}
|
||||
|
||||
$admin->{loggedin} = 1;
|
||||
$self->{pbot}->{logger}->log("$hostmask logged into $channel\n");
|
||||
return "Logged into $channel.";
|
||||
}
|
||||
|
||||
sub logout {
|
||||
my ($self, $channel, $hostmask) = @_;
|
||||
my $admin = $self->find_admin($channel, $hostmask);
|
||||
delete $admin->{loggedin} if defined $admin;
|
||||
}
|
||||
|
||||
1;
|
@ -446,7 +446,7 @@ sub check_flood {
|
||||
}
|
||||
|
||||
# do not do flood enforcement for logged in bot admins
|
||||
if ($self->{pbot}->{registry}->get_value('antiflood', 'dont_enforce_admins') and $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host")) {
|
||||
if ($self->{pbot}->{registry}->get_value('antiflood', 'dont_enforce_admins') and $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host")) {
|
||||
$self->{channels}->{$channel}->{last_spoken_nick} = $nick;
|
||||
next;
|
||||
}
|
||||
|
@ -251,7 +251,7 @@ sub mode {
|
||||
# removing mode -- check against whitelist, etc
|
||||
next if $nick_data->{nick} eq $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
next if $self->{pbot}->{antiflood}->whitelisted($channel, $nick_data->{hostmask});
|
||||
next if $self->{pbot}->{admins}->loggedin($channel, $nick_data->{hostmask});
|
||||
next if $self->{pbot}->{users}->loggedin_admin($channel, $nick_data->{hostmask});
|
||||
}
|
||||
|
||||
# skip nick if already has mode set/unset
|
||||
@ -418,7 +418,7 @@ sub ban_user {
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
return "I don't think so." if $target =~ /^\Q$botnick\E!/i;
|
||||
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host")) {
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host")) {
|
||||
return "/msg $nick You are not an admin for $channel.";
|
||||
}
|
||||
|
||||
@ -485,7 +485,7 @@ sub unban_user {
|
||||
|
||||
return "/msg $nick Usage for /msg: unban <nick/mask> <channel> [false value to use unban queue]" if $channel !~ /^#/;
|
||||
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host")) {
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host")) {
|
||||
return "/msg $nick You are not an admin for $channel.";
|
||||
}
|
||||
|
||||
@ -549,7 +549,7 @@ sub mute_user {
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
return "I don't think so." if $target =~ /^\Q$botnick\E!/i;
|
||||
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host")) {
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host")) {
|
||||
return "/msg $nick You are not an admin for $channel.";
|
||||
}
|
||||
|
||||
@ -616,7 +616,7 @@ sub unmute_user {
|
||||
|
||||
return "/msg $nick Usage for /msg: unmute <nick/mask> <channel> [false value to use unban queue]" if $channel !~ /^#/;
|
||||
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host")) {
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host")) {
|
||||
return "/msg $nick You are not an admin for $channel.";
|
||||
}
|
||||
|
||||
@ -670,7 +670,7 @@ sub kick_user {
|
||||
$channel = $1;
|
||||
}
|
||||
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host")) {
|
||||
if ($self->{pbot}->{commands}->get_meta($stuff->{keyword}, 'level') and not $stuff->{'effective-level'} and not $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host")) {
|
||||
return "/msg $nick You are not an admin for $channel.";
|
||||
}
|
||||
|
||||
@ -704,7 +704,7 @@ sub kick_user {
|
||||
|
||||
next if $nick_data->{nick} eq $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
next if $self->{pbot}->{antiflood}->whitelisted($channel, $nick_data->{hostmask});
|
||||
next if $self->{pbot}->{admins}->loggedin($channel, $nick_data->{hostmask});
|
||||
next if $self->{pbot}->{users}->loggedin_admin($channel, $nick_data->{hostmask});
|
||||
|
||||
$self->{pbot}->{chanops}->add_op_command($channel, "kick $channel $nl $reason");
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ sub initialize {
|
||||
$self->{channels} = PBot::HashObject->new(pbot => $self->{pbot}, name => 'Channels', filename => $conf{filename});
|
||||
$self->load_channels;
|
||||
|
||||
$self->{pbot}->{commands}->register(sub { $self->join(@_) }, "join", 40);
|
||||
$self->{pbot}->{commands}->register(sub { $self->part(@_) }, "part", 40);
|
||||
$self->{pbot}->{commands}->register(sub { $self->set(@_) }, "chanset", 40);
|
||||
$self->{pbot}->{commands}->register(sub { $self->unset(@_) }, "chanunset", 40);
|
||||
$self->{pbot}->{commands}->register(sub { $self->add(@_) }, "chanadd", 40);
|
||||
@ -40,6 +42,30 @@ sub initialize {
|
||||
$self->{pbot}->{commands}->register(sub { $self->list(@_) }, "chanlist", 10);
|
||||
}
|
||||
|
||||
sub join {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
foreach my $channel (split /[\s+,]/, $arguments) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host made me join $channel\n");
|
||||
$self->{pbot}->{chanops}->join_channel($channel);
|
||||
}
|
||||
|
||||
return "/msg $nick Joining $arguments";
|
||||
}
|
||||
|
||||
sub part {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
$arguments = $from if not $arguments;
|
||||
|
||||
foreach my $channel (split /[\s+,]/, $arguments) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host made me part $channel\n");
|
||||
$self->{pbot}->{chanops}->part_channel($channel);
|
||||
}
|
||||
|
||||
return "/msg $nick Parting $arguments";
|
||||
}
|
||||
|
||||
sub set {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
my ($channel, $key, $value) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 3);
|
||||
|
@ -39,10 +39,11 @@ sub initialize {
|
||||
$self->{metadata} = PBot::HashObject->new(pbot => $self->{pbot}, name => 'Commands', filename => $conf{filename});
|
||||
$self->load_metadata;
|
||||
|
||||
$self->register(sub { $self->cmdset(@_) }, "cmdset", 90);
|
||||
$self->register(sub { $self->cmdunset(@_) }, "cmdunset", 90);
|
||||
$self->register(sub { $self->help(@_) }, "help", 0);
|
||||
$self->register(sub { $self->uptime(@_) }, "uptime", 0);
|
||||
$self->register(sub { $self->cmdset(@_) }, "cmdset", 90);
|
||||
$self->register(sub { $self->cmdunset(@_) }, "cmdunset", 90);
|
||||
$self->register(sub { $self->help(@_) }, "help", 0);
|
||||
$self->register(sub { $self->uptime(@_) }, "uptime", 0);
|
||||
$self->register(sub { $self->in_channel(@_) }, "in", 0);
|
||||
}
|
||||
|
||||
sub register {
|
||||
@ -97,7 +98,7 @@ sub interpreter {
|
||||
my $from = exists $stuff->{admin_channel_override} ? $stuff->{admin_channel_override} : $stuff->{from};
|
||||
my ($admin_channel) = $stuff->{arguments} =~ m/\B(#[^ ]+)/; # assume first channel-like argument
|
||||
$admin_channel = $from if not defined $admin_channel;
|
||||
my $admin = $self->{pbot}->{admins}->loggedin($admin_channel, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
|
||||
my $admin = $self->{pbot}->{users}->loggedin_admin($admin_channel, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
|
||||
my $admin_level = defined $admin ? $admin->{level} : 0;
|
||||
my $keyword = lc $stuff->{keyword};
|
||||
|
||||
@ -244,4 +245,18 @@ sub uptime {
|
||||
return localtime ($self->{pbot}->{startup_timestamp}) . " [" . duration (time - $self->{pbot}->{startup_timestamp}) . "]";
|
||||
}
|
||||
|
||||
sub in_channel {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
|
||||
my $usage = "Usage: in <channel> <command>";
|
||||
return $usage if not $arguments;
|
||||
|
||||
my ($channel, $command) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
|
||||
return $usage if not defined $channel or not defined $command;
|
||||
|
||||
$stuff->{admin_channel_override} = $channel;
|
||||
$stuff->{command} = $command;
|
||||
return $self->{pbot}->{interpreter}->interpret($stuff);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -78,7 +78,6 @@ sub initialize {
|
||||
$self->{pbot}->{commands}->register(sub { return $self->factmove(@_) }, "factmove", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->call_factoid(@_) }, "fact", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->factfind(@_) }, "factfind", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->list(@_) }, "list", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->top20(@_) }, "top20", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->load_module(@_) }, "load", 90);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->unload_module(@_) }, "unload", 90);
|
||||
@ -408,7 +407,7 @@ sub factundo {
|
||||
}
|
||||
|
||||
my $factoids = $self->{pbot}->{factoids}->{factoids}->{hash};
|
||||
my $admininfo = $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host");
|
||||
my $admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host");
|
||||
if ($factoids->{$channel}->{$trigger}->{'locked'}) {
|
||||
return "/say $trigger_name is locked and cannot be reverted." if not defined $admininfo;
|
||||
|
||||
@ -501,7 +500,7 @@ sub factredo {
|
||||
}
|
||||
|
||||
my $factoids = $self->{pbot}->{factoids}->{factoids}->{hash};
|
||||
my $admininfo = $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host");
|
||||
my $admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host");
|
||||
if ($factoids->{$channel}->{$trigger}->{'locked'}) {
|
||||
return "/say $trigger_name is locked and cannot be reverted." if not defined $admininfo;
|
||||
|
||||
@ -563,9 +562,9 @@ sub factset {
|
||||
|
||||
my $admininfo;
|
||||
if (defined $owner_channel) {
|
||||
$admininfo = $self->{pbot}->{admins}->loggedin($owner_channel, "$nick!$user\@$host");
|
||||
$admininfo = $self->{pbot}->{users}->loggedin_admin($owner_channel, "$nick!$user\@$host");
|
||||
} else {
|
||||
$admininfo = $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host");
|
||||
$admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host");
|
||||
}
|
||||
|
||||
my $level = 0;
|
||||
@ -656,9 +655,9 @@ sub factunset {
|
||||
my $admininfo;
|
||||
|
||||
if (defined $owner_channel) {
|
||||
$admininfo = $self->{pbot}->{admins}->loggedin($owner_channel, "$nick!$user\@$host");
|
||||
$admininfo = $self->{pbot}->{users}->loggedin_admin($owner_channel, "$nick!$user\@$host");
|
||||
} else {
|
||||
$admininfo = $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host");
|
||||
$admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host");
|
||||
}
|
||||
|
||||
my $level = 0;
|
||||
@ -723,63 +722,6 @@ sub factunset {
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub list {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my $text;
|
||||
|
||||
my $usage = "Usage: list <modules|commands|admins>";
|
||||
|
||||
if (not defined $arguments) {
|
||||
return $usage;
|
||||
}
|
||||
|
||||
if ($arguments =~ /^modules$/i) {
|
||||
$text = "Loaded modules: ";
|
||||
foreach my $channel (sort keys %{ $self->{pbot}->{factoids}->{factoids}->{hash} }) {
|
||||
foreach my $command (sort keys %{ $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel} }) {
|
||||
next if $command eq '_name';
|
||||
if ($self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$command}->{type} eq 'module') {
|
||||
$text .= "$self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$command}->{_name} ";
|
||||
}
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
if ($arguments =~ /^commands$/i) {
|
||||
$text = "Registered commands: ";
|
||||
foreach my $command (sort { $a->{name} cmp $b->{name} } @{ $self->{pbot}->{commands}->{handlers} }) {
|
||||
$text .= "$command->{name} ";
|
||||
$text .= "($command->{level}) " if $command->{level} > 0;
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
if ($arguments =~ /^admins$/i) {
|
||||
$text = "Admins: ";
|
||||
my $last_channel = "";
|
||||
my $sep = "";
|
||||
foreach my $channel (sort keys %{ $self->{pbot}->{admins}->{admins}->{hash} }) {
|
||||
next if $from =~ m/^#/ and $channel ne $from and $channel ne '.*';
|
||||
if ($last_channel ne $channel) {
|
||||
$text .= $sep . ($channel eq ".*" ? "global" : $channel) . ": ";
|
||||
$last_channel = $channel;
|
||||
$sep = "";
|
||||
}
|
||||
foreach my $hostmask (sort { return 0 if $a eq '_name' or $b eq '_name'; $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$a}->{name} cmp $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$b}->{name} } keys %{ $self->{pbot}->{admins}->{admins}->{hash}->{$channel} }) {
|
||||
next if $hostmask eq '_name';
|
||||
$text .= $sep;
|
||||
$text .= "*" if $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$hostmask}->{loggedin};
|
||||
$text .= $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$hostmask}->{name} . " (" . $self->{pbot}->{admins}->{admins}->{hash}->{$channel}->{$hostmask}->{level} . ")";
|
||||
$sep = "; ";
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
return $usage;
|
||||
}
|
||||
|
||||
sub factmove {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
@ -827,7 +769,7 @@ sub factmove {
|
||||
|
||||
my ($owner) = $factoids->{$found_src_channel}->{$found_source}->{'owner'} =~ m/([^!]+)/;
|
||||
|
||||
if ((lc $nick ne lc $owner) and (not $self->{pbot}->{admins}->loggedin($found_src_channel, "$nick!$user\@$host"))) {
|
||||
if ((lc $nick ne lc $owner) and (not $self->{pbot}->{users}->loggedin_admin($found_src_channel, "$nick!$user\@$host"))) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host attempted to move [$found_src_channel] $found_source (not owner)\n");
|
||||
my $chan = ($found_src_channel eq '.*' ? 'the global channel' : $found_src_channel);
|
||||
return "You are not the owner of $source_trigger_name for $source_channel_name.";
|
||||
@ -1080,7 +1022,7 @@ sub factadd {
|
||||
|
||||
my ($owner) = $factoids->{$channel}->{$trigger}->{'owner'} =~ m/([^!]+)/;
|
||||
|
||||
if ((lc $nick ne lc $owner) and (not $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host"))) {
|
||||
if ((lc $nick ne lc $owner) and (not $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host"))) {
|
||||
return "You are not the owner of $trigger_name for $channel_name; cannot force overwrite.";
|
||||
}
|
||||
}
|
||||
@ -1136,7 +1078,7 @@ sub factrem {
|
||||
|
||||
my ($owner) = $factoids->{$channel}->{$trigger}->{'owner'} =~ m/([^!]+)/;
|
||||
|
||||
if ((lc $nick ne lc $owner) and (not $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host"))) {
|
||||
if ((lc $nick ne lc $owner) and (not $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host"))) {
|
||||
return "You are not the owner of $trigger_name for $channel_name.";
|
||||
}
|
||||
|
||||
@ -1682,7 +1624,7 @@ sub factchange {
|
||||
return "/say $trigger_name belongs to $channel_name, but this is $from_chan. Please switch to $channel_name or use /msg to change this factoid.";
|
||||
}
|
||||
|
||||
my $admininfo = $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host");
|
||||
my $admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host");
|
||||
if ($factoids_hash->{$channel}->{$trigger}->{'locked'}) {
|
||||
return "/say $trigger_name is locked and cannot be changed." if not defined $admininfo;
|
||||
|
||||
|
@ -876,7 +876,7 @@ sub interpreter {
|
||||
$ratelimit = $self->{factoids}->{hash}->{$channel}->{$keyword}->{rate_limit} if not defined $ratelimit;
|
||||
if (gettimeofday - $self->{factoids}->{hash}->{$channel}->{$keyword}->{last_referenced_on} < $ratelimit) {
|
||||
my $ref_from = $stuff->{ref_from} ? "[$stuff->{ref_from}] " : "";
|
||||
return "/msg $stuff->{nick} $ref_from'$trigger_name' is rate-limited; try again in " . duration ($ratelimit - int(gettimeofday - $self->{factoids}->{hash}->{$channel}->{$keyword}->{last_referenced_on})) . "." unless $self->{pbot}->{admins}->loggedin($channel, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
|
||||
return "/msg $stuff->{nick} $ref_from'$trigger_name' is rate-limited; try again in " . duration ($ratelimit - int(gettimeofday - $self->{factoids}->{hash}->{$channel}->{$keyword}->{last_referenced_on})) . "." unless $self->{pbot}->{users}->loggedin_admin($channel, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1067,7 +1067,7 @@ sub handle_action {
|
||||
elsif ($self->{factoids}->{hash}->{$channel}->{$keyword}->{type} eq 'text') {
|
||||
# Don't allow user-custom /msg factoids, unless factoid triggered by admin
|
||||
if ($action =~ m/^\/msg/i) {
|
||||
my $admin = $self->{pbot}->{admins}->loggedin($stuff->{from}, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
|
||||
my $admin = $self->{pbot}->{users}->loggedin_admin($stuff->{from}, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
|
||||
if (not $admin or $admin->{level} < 60) {
|
||||
$self->{pbot}->{logger}->log("[ABUSE] Bad factoid (contains /msg): $action\n");
|
||||
return "You are not powerful enough to use /msg in a factoid.";
|
||||
|
@ -448,9 +448,9 @@ sub on_departure {
|
||||
$self->{pbot}->{registry}->get_value('antiflood', 'join_flood_time_threshold'),
|
||||
$self->{pbot}->{messagehistory}->{MSG_DEPARTURE});
|
||||
|
||||
my $admin = $self->{pbot}->{admins}->find_admin($channel, "$nick!$user\@$host");
|
||||
# auto-logout admins but not users
|
||||
my $admin = $self->{pbot}->{users}->find_admin($channel, "$nick!$user\@$host");
|
||||
if (defined $admin and $admin->{loggedin} and not $admin->{stayloggedin}) {
|
||||
$self->{pbot}->{logger}->log("Whoops, $nick left while still logged in.\n");
|
||||
$self->{pbot}->{logger}->log("Logged out $nick.\n");
|
||||
delete $admin->{loggedin};
|
||||
}
|
||||
|
@ -18,12 +18,8 @@ use PBot::IgnoreListCommands;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
sub new {
|
||||
if (ref($_[1]) eq 'HASH') {
|
||||
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
|
||||
}
|
||||
|
||||
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
|
||||
my ($class, %conf) = @_;
|
||||
|
||||
my $self = bless {}, $class;
|
||||
$self->initialize(%conf);
|
||||
return $self;
|
||||
@ -32,8 +28,8 @@ sub new {
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
|
||||
$self->{filename} = delete $conf{filename};
|
||||
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
|
||||
$self->{filename} = $conf{filename};
|
||||
|
||||
$self->{ignore_list} = {};
|
||||
$self->{ignore_flood_counter} = {};
|
||||
@ -41,7 +37,7 @@ sub initialize {
|
||||
|
||||
$self->{commands} = PBot::IgnoreListCommands->new(pbot => $self->{pbot});
|
||||
|
||||
$self->load_ignores;
|
||||
$self->load_ignores();
|
||||
|
||||
$self->{pbot}->{timer}->register(sub { $self->check_ignore_timeouts }, 10);
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ sub process_line {
|
||||
foreach $command (@commands) {
|
||||
# check if user is ignored (and command isn't `login`)
|
||||
if ($command !~ /^login / && defined $from && $pbot->{ignorelist}->check_ignore($nick, $user, $host, $from)) {
|
||||
my $admin = $pbot->{admins}->loggedin($from, "$nick!$user\@$host");
|
||||
my $admin = $pbot->{users}->loggedin_admin($from, "$nick!$user\@$host");
|
||||
if (!defined $admin || $admin->{level} < 10) {
|
||||
# hostmask ignored
|
||||
return 1;
|
||||
|
@ -397,7 +397,7 @@ sub recall_message {
|
||||
foreach my $msg (@$messages) {
|
||||
$self->{pbot}->{logger}->log("$nick ($from) recalled <$msg->{nick}/$msg->{channel}> $msg->{msg}\n");
|
||||
|
||||
if ($max_recall_time && gettimeofday - $msg->{timestamp} > $max_recall_time && not $self->{pbot}->{admins}->loggedin($from, "$nick!$user\@$host")) {
|
||||
if ($max_recall_time && gettimeofday - $msg->{timestamp} > $max_recall_time && not $self->{pbot}->{users}->loggedin_admin($from, "$nick!$user\@$host")) {
|
||||
$max_recall_time = duration($max_recall_time);
|
||||
$recall_text .= "Sorry, you can not recall messages older than $max_recall_time.";
|
||||
return $recall_text;
|
||||
|
@ -58,29 +58,24 @@ sub show_nicklist {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
my $nicklist;
|
||||
|
||||
my $admin = $self->{pbot}->{admins}->loggedin($from, "$nick!$user\@$host");
|
||||
|
||||
if (not length $arguments) {
|
||||
if (not $admin) {
|
||||
return "Usage: nicklist <channel> [nick]";
|
||||
}
|
||||
$nicklist = Dumper($self->{nicklist});
|
||||
} else {
|
||||
my @args = split / /, $arguments;
|
||||
return "Usage: nicklist <channel> [nick]";
|
||||
}
|
||||
|
||||
if (@args == 1) {
|
||||
if (not exists $self->{nicklist}->{$arguments}) {
|
||||
return "No nicklist for $arguments.";
|
||||
}
|
||||
$nicklist = Dumper($self->{nicklist}->{$arguments});
|
||||
} else {
|
||||
if (not exists $self->{nicklist}->{$args[0]}) {
|
||||
return "No nicklist for $args[0].";
|
||||
} elsif (not exists $self->{nicklist}->{$args[0]}->{$args[1]}) {
|
||||
return "No such nick $args[1] in channel $args[0].";
|
||||
}
|
||||
$nicklist = Dumper($self->{nicklist}->{$args[0]}->{$args[1]});
|
||||
my @args = split / /, $arguments;
|
||||
|
||||
if (@args == 1) {
|
||||
if (not exists $self->{nicklist}->{lc $arguments}) {
|
||||
return "No nicklist for $arguments.";
|
||||
}
|
||||
$nicklist = Dumper($self->{nicklist}->{lc $arguments});
|
||||
} else {
|
||||
if (not exists $self->{nicklist}->{lc $args[0]}) {
|
||||
return "No nicklist for $args[0].";
|
||||
} elsif (not exists $self->{nicklist}->{lc $args[0]}->{lc $args[1]}) {
|
||||
return "No such nick $args[1] in channel $args[0].";
|
||||
}
|
||||
$nicklist = Dumper($self->{nicklist}->{lc $args[0]}->{lc $args[1]});
|
||||
}
|
||||
|
||||
return $nicklist;
|
||||
|
227
PBot/PBot.pm
227
PBot/PBot.pm
@ -37,7 +37,7 @@ use PBot::Interpreter;
|
||||
use PBot::Commands;
|
||||
use PBot::ChanOps;
|
||||
use PBot::Factoids;
|
||||
use PBot::Admins;
|
||||
use PBot::Users;
|
||||
use PBot::IgnoreList;
|
||||
use PBot::BlackList;
|
||||
use PBot::Timer;
|
||||
@ -102,7 +102,15 @@ sub initialize {
|
||||
# then commands so the modules can register new commands
|
||||
$self->{commands} = PBot::Commands->new(pbot => $self, filename => "$data_dir/commands", %conf);
|
||||
|
||||
# the version
|
||||
# add some commands
|
||||
$self->{commands}->register(sub { $self->listcmd(@_) }, "list", 0);
|
||||
$self->{commands}->register(sub { $self->ack_die(@_) }, "die", 90);
|
||||
$self->{commands}->register(sub { $self->export(@_) }, "export", 90);
|
||||
$self->{commands}->register(sub { $self->reload(@_) }, "reload", 90);
|
||||
$self->{commands}->register(sub { $self->evalcmd(@_) }, "eval", 99);
|
||||
$self->{commands}->register(sub { $self->sl(@_) }, "sl", 90);
|
||||
|
||||
# prepare the version
|
||||
$self->{version} = PBot::VERSION->new(pbot => $self, %conf);
|
||||
$self->{logger}->log($self->{version}->version . "\n");
|
||||
$self->{logger}->log("Args: @ARGV\n") if @ARGV;
|
||||
@ -187,7 +195,7 @@ sub initialize {
|
||||
$self->{event_dispatcher} = PBot::EventDispatcher->new(pbot => $self, %conf);
|
||||
$self->{irchandlers} = PBot::IRCHandlers->new(pbot => $self, %conf);
|
||||
$self->{select_handler} = PBot::SelectHandler->new(pbot => $self, %conf);
|
||||
$self->{admins} = PBot::Admins->new(pbot => $self, filename => "$data_dir/admins", %conf);
|
||||
$self->{users} = PBot::Users->new(pbot => $self, filename => "$data_dir/users", %conf);
|
||||
$self->{stdin_reader} = PBot::StdinReader->new(pbot => $self, %conf);
|
||||
$self->{bantracker} = PBot::BanTracker->new(pbot => $self, %conf);
|
||||
$self->{lagchecker} = PBot::LagChecker->new(pbot => $self, %conf);
|
||||
@ -219,9 +227,11 @@ sub initialize {
|
||||
}
|
||||
|
||||
sub random_nick {
|
||||
my ($self, $length) = @_;
|
||||
$length //= 9;
|
||||
my @chars = ("A".."Z", "a".."z", "0".."9");
|
||||
my $nick = $chars[rand @chars - 10]; # nicks cannot start with a digit
|
||||
$nick .= $chars[rand @chars] for 1..9;
|
||||
$nick .= $chars[rand @chars] for 1..$length;
|
||||
return $nick;
|
||||
}
|
||||
|
||||
@ -238,7 +248,7 @@ sub connect {
|
||||
$self->{logger}->log("Connecting to $server ...\n");
|
||||
|
||||
while (not $self->{conn} = $self->{irc}->newconn(
|
||||
Nick => $self->{registry}->get_value('irc', 'randomize_nick') ? random_nick : $self->{registry}->get_value('irc', 'botnick'),
|
||||
Nick => $self->{registry}->get_value('irc', 'randomize_nick') ? $self->random_nick : $self->{registry}->get_value('irc', 'botnick'),
|
||||
Username => $self->{registry}->get_value('irc', 'username'),
|
||||
Ircname => $self->{registry}->get_value('irc', 'realname'),
|
||||
Server => $server,
|
||||
@ -305,4 +315,211 @@ sub change_botnick_trigger {
|
||||
$self->{conn}->nick($newvalue) if $self->{connected};
|
||||
}
|
||||
|
||||
sub listcmd {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my $text;
|
||||
|
||||
my $usage = "Usage: list <modules|commands|admins|users>";
|
||||
|
||||
if (not defined $arguments) {
|
||||
return $usage;
|
||||
}
|
||||
|
||||
if ($arguments =~ /^modules$/i) {
|
||||
$text = "Loaded modules: ";
|
||||
foreach my $channel (sort keys %{ $self->{factoids}->{factoids}->{hash} }) {
|
||||
foreach my $command (sort keys %{ $self->{factoids}->{factoids}->{hash}->{$channel} }) {
|
||||
next if $command eq '_name';
|
||||
if ($self->{factoids}->{factoids}->{hash}->{$channel}->{$command}->{type} eq 'module') {
|
||||
$text .= "$self->{factoids}->{factoids}->{hash}->{$channel}->{$command}->{_name} ";
|
||||
}
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
if ($arguments =~ /^commands$/i) {
|
||||
$text = "Registered commands: ";
|
||||
foreach my $command (sort { $a->{name} cmp $b->{name} } @{ $self->{commands}->{handlers} }) {
|
||||
$text .= "$command->{name} ";
|
||||
$text .= "($command->{level}) " if $command->{level} > 0;
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
if ($arguments =~ /^users$/i) {
|
||||
$text = "Users: ";
|
||||
my $last_channel = "";
|
||||
my $sep = "";
|
||||
foreach my $channel (sort keys %{ $self->{users}->{users}->{hash} }) {
|
||||
next if $from =~ m/^#/ and $channel ne $from and $channel ne '.*';
|
||||
if ($last_channel ne $channel) {
|
||||
$text .= $sep . ($channel eq ".*" ? "global" : $channel) . ": ";
|
||||
$last_channel = $channel;
|
||||
$sep = "";
|
||||
}
|
||||
foreach my $hostmask (sort { return 0 if $a eq '_name' or $b eq '_name'; $self->{users}->{users}->{hash}->{$channel}->{$a}->{name} cmp $self->{users}->{users}->{hash}->{$channel}->{$b}->{name} } keys %{ $self->{users}->{users}->{hash}->{$channel} }) {
|
||||
next if $hostmask eq '_name';
|
||||
$text .= $sep;
|
||||
$text .= "*" if $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{loggedin};
|
||||
$text .= $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{name};
|
||||
$text .= " (" . $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{level} . ")" if $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{level} > 0;
|
||||
$sep = "; ";
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
if ($arguments =~ /^admins$/i) {
|
||||
$text = "Admins: ";
|
||||
my $last_channel = "";
|
||||
my $sep = "";
|
||||
foreach my $channel (sort keys %{ $self->{users}->{users}->{hash} }) {
|
||||
next if $from =~ m/^#/ and $channel ne $from and $channel ne '.*';
|
||||
if ($last_channel ne $channel) {
|
||||
$text .= $sep . ($channel eq ".*" ? "global" : $channel) . ": ";
|
||||
$last_channel = $channel;
|
||||
$sep = "";
|
||||
}
|
||||
foreach my $hostmask (sort { return 0 if $a eq '_name' or $b eq '_name'; $self->{users}->{users}->{hash}->{$channel}->{$a}->{name} cmp $self->{users}->{users}->{hash}->{$channel}->{$b}->{name} } keys %{ $self->{users}->{users}->{hash}->{$channel} }) {
|
||||
next if $hostmask eq '_name';
|
||||
next if $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{level} <= 0;
|
||||
$text .= $sep;
|
||||
$text .= "*" if $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{loggedin};
|
||||
$text .= $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{name} . " (" . $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{level} . ")";
|
||||
$sep = "; ";
|
||||
}
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
return $usage;
|
||||
}
|
||||
|
||||
sub sl {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
return "Usage: sl <ircd command>" if not length $arguments;
|
||||
$self->{conn}->sl($arguments);
|
||||
return "";
|
||||
}
|
||||
|
||||
sub ack_die {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
$self->{logger}->log("$nick!$user\@$host made me exit.\n");
|
||||
$self->atexit();
|
||||
$self->{conn}->privmsg($from, "Good-bye.") if defined $from;
|
||||
$self->{conn}->quit("Departure requested.");
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub export {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
return "/msg $nick Usage: export <factoids>" if not defined $arguments;
|
||||
|
||||
if ($arguments =~ /^factoids$/i) {
|
||||
return $self->{factoids}->export_factoids;
|
||||
}
|
||||
}
|
||||
|
||||
sub evalcmd {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
$self->{logger}->log("[$from] $nick!$user\@$host Evaluating [$arguments]\n");
|
||||
|
||||
my $ret;
|
||||
my $result = eval $arguments;
|
||||
if ($@) {
|
||||
if (length $result) {
|
||||
$ret .= "[Error: $@] ";
|
||||
} else {
|
||||
$ret .= "Error: $@";
|
||||
}
|
||||
$ret =~ s/ at \(eval \d+\) line 1.//;
|
||||
}
|
||||
return "/say $ret $result";
|
||||
}
|
||||
|
||||
sub reload {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
|
||||
my %reloadables = (
|
||||
'commands' => sub {
|
||||
$self->{commands}->load_metadata;
|
||||
return "Commands metadata reloaded.";
|
||||
},
|
||||
|
||||
'blacklist' => sub {
|
||||
$self->{blacklist}->clear_blacklist;
|
||||
$self->{blacklist}->load_blacklist;
|
||||
return "Blacklist reloaded.";
|
||||
},
|
||||
|
||||
'whitelist' => sub {
|
||||
$self->{antiflood}->{whitelist}->clear;
|
||||
$self->{antiflood}->{whitelist}->load;
|
||||
return "Whitelist reloaded.";
|
||||
},
|
||||
|
||||
'ignores' => sub {
|
||||
$self->{ignorelist}->clear_ignores;
|
||||
$self->{ignorelist}->load_ignores;
|
||||
return "Ignore list reloaded.";
|
||||
},
|
||||
|
||||
'users' => sub {
|
||||
$self->{users}->load;
|
||||
return "Users reloaded.";
|
||||
},
|
||||
|
||||
'channels' => sub {
|
||||
$self->{channels}->{channels}->clear;
|
||||
$self->{channels}->load_channels;
|
||||
return "Channels reloaded.";
|
||||
},
|
||||
|
||||
'bantimeouts' => sub {
|
||||
$self->{chanops}->{unban_timeout}->clear;
|
||||
$self->{chanops}->{unban_timeout}->load;
|
||||
return "Ban timeouts reloaded.";
|
||||
},
|
||||
|
||||
'mutetimeouts' => sub {
|
||||
$self->{chanops}->{unmute_timeout}->clear;
|
||||
$self->{chanops}->{unmute_timeout}->load;
|
||||
return "Mute timeouts reloaded.";
|
||||
},
|
||||
|
||||
'registry' => sub {
|
||||
$self->{registry}->{registry}->clear;
|
||||
$self->{registry}->load;
|
||||
return "Registry reloaded.";
|
||||
},
|
||||
|
||||
'factoids' => sub {
|
||||
$self->{factoids}->{factoids}->clear;
|
||||
$self->{factoids}->load_factoids;
|
||||
return "Factoids reloaded.";
|
||||
},
|
||||
|
||||
'funcs' => sub {
|
||||
$self->{func_cmd}->init_funcs;
|
||||
return "Funcs reloaded.";
|
||||
}
|
||||
);
|
||||
|
||||
if (not length $arguments or not exists $reloadables{$arguments}) {
|
||||
my $usage = 'Usage: reload <';
|
||||
$usage .= join '|', sort keys %reloadables;
|
||||
$usage .= '>';
|
||||
return $usage;
|
||||
}
|
||||
|
||||
return $reloadables{$arguments}();
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -26,12 +26,12 @@ sub initialize {
|
||||
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference in StdinReader");
|
||||
|
||||
# create implicit bot-admin account for bot
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
if (not $self->{pbot}->{admins}->find_admin('.*', '*!stdin@pbot')) {
|
||||
if (not $self->{pbot}->{users}->find_admin('.*', '*!stdin@pbot')) {
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
$self->{pbot}->{logger}->log("Adding stdin admin *!stdin\@pbot...\n");
|
||||
$self->{pbot}->{admins}->add_admin($botnick, '.*', '*!stdin@pbot', 100, 'notused', 1);
|
||||
$self->{pbot}->{admins}->login($botnick, "$botnick!stdin\@pbot", 'notused');
|
||||
$self->{pbot}->{admins}->save_admins;
|
||||
$self->{pbot}->{users}->add_user($botnick, '.*', '*!stdin@pbot', 100, undef, 1);
|
||||
$self->{pbot}->{users}->login($botnick, "$botnick!stdin\@pbot", undef);
|
||||
$self->{pbot}->{users}->save;
|
||||
}
|
||||
|
||||
# used to check whether process is in background or foreground, for stdin reading
|
||||
|
443
PBot/Users.pm
Normal file
443
PBot/Users.pm
Normal file
@ -0,0 +1,443 @@
|
||||
# File: Users.pm
|
||||
# Author: pragma_
|
||||
#
|
||||
# Purpose: Manages list of bot users/admins and their metadata.
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package PBot::Users;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use feature 'unicode_strings';
|
||||
|
||||
use PBot::DualIndexHashObject;
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
|
||||
my ($class, %conf) = @_;
|
||||
my $self = bless {}, $class;
|
||||
$self->initialize(%conf);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
|
||||
|
||||
$self->{users} = PBot::DualIndexHashObject->new(name => 'Users', filename => $conf{filename}, pbot => $conf{pbot});
|
||||
$self->load;
|
||||
|
||||
$self->{pbot}->{commands}->register(sub { return $self->logincmd(@_) }, "login", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->logoutcmd(@_) }, "logout", 0);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->useradd(@_) }, "useradd", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->userdel(@_) }, "userdel", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->userset(@_) }, "userset", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->userunset(@_) }, "userunset", 60);
|
||||
$self->{pbot}->{commands}->register(sub { return $self->mycmd(@_) }, "my", 0);
|
||||
|
||||
$self->{pbot}->{event_dispatcher}->register_handler('irc.join', sub { $self->on_join(@_) });
|
||||
}
|
||||
|
||||
sub on_join {
|
||||
my ($self, $event_type, $event) = @_;
|
||||
my ($nick, $user, $host, $channel) = ($event->{event}->nick, $event->{event}->user, $event->{event}->host, $event->{event}->to);
|
||||
($nick, $user, $host) = $self->{pbot}->{irchandlers}->normalize_hostmask($nick, $user, $host);
|
||||
|
||||
my $u = $self->find_user($channel, "$nick!$user\@$host");
|
||||
|
||||
if (defined $u) {
|
||||
if ($self->{pbot}->{chanops}->can_gain_ops($channel)) {
|
||||
my $modes = '+';
|
||||
my $targets = '';
|
||||
|
||||
if ($u->{autoop}) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host autoop in $channel\n");
|
||||
$modes .= 'o';
|
||||
$targets .= "$nick ";
|
||||
}
|
||||
|
||||
if ($u->{autovoice}) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host autovoice in $channel\n");
|
||||
$modes .= 'v';
|
||||
$targets .= "$nick ";
|
||||
}
|
||||
|
||||
if (length $modes > 1) {
|
||||
$self->{pbot}->{chanops}->add_op_command($channel, "mode $channel $modes $targets");
|
||||
$self->{pbot}->{chanops}->gain_ops($channel);
|
||||
}
|
||||
}
|
||||
|
||||
if ($u->{autologin}) {
|
||||
$self->{pbot}->{logger}->log("$nick!$user\@$host autologin to $user->{name} ($user->{level}) for $channel\n");
|
||||
$user->{loggedin} = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub add_user {
|
||||
my ($self, $name, $channel, $hostmask, $level, $password, $dont_save) = @_;
|
||||
$channel = '.*' if $channel !~ m/^#/;
|
||||
|
||||
$level //= 0;
|
||||
$password //= $self->{pbot}->random_nick(16);
|
||||
|
||||
my $data = {
|
||||
name => $name,
|
||||
level => $level,
|
||||
password => $password
|
||||
};
|
||||
|
||||
$self->{pbot}->{logger}->log("Adding new user (level $level): name: $name hostmask: $hostmask channel: $channel\n");
|
||||
$self->{users}->add($channel, $hostmask, $data, $dont_save);
|
||||
return $data;
|
||||
}
|
||||
|
||||
sub remove_user {
|
||||
my ($self, $channel, $hostmask) = @_;
|
||||
return $self->{users}->remove($channel, $hostmask);
|
||||
}
|
||||
|
||||
sub load {
|
||||
my $self = shift;
|
||||
my $filename;
|
||||
|
||||
if (@_) { $filename = shift; } else { $filename = $self->{users}->{filename}; }
|
||||
|
||||
if (not defined $filename) {
|
||||
Carp::carp "No users path specified -- skipping loading of users";
|
||||
return;
|
||||
}
|
||||
|
||||
$self->{users}->load;
|
||||
|
||||
my $i = 0;
|
||||
foreach my $channel (sort keys %{ $self->{users}->{hash} } ) {
|
||||
foreach my $hostmask (sort keys %{ $self->{users}->{hash}->{$channel} }) {
|
||||
next if $hostmask eq '_name';
|
||||
$i++;
|
||||
my $name = $self->{users}->{hash}->{$channel}->{$hostmask}->{name};
|
||||
my $level = $self->{users}->{hash}->{$channel}->{$hostmask}->{level};
|
||||
my $password = $self->{users}->{hash}->{$channel}->{$hostmask}->{password};
|
||||
|
||||
if (not defined $name or not defined $level or not defined $password) {
|
||||
Carp::croak "A user in $filename is missing critical data\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$self->{pbot}->{logger}->log(" $i users loaded.\n");
|
||||
}
|
||||
|
||||
sub save {
|
||||
my ($self) = @_;
|
||||
$self->{users}->save;
|
||||
}
|
||||
|
||||
sub hostmask_or_account_name {
|
||||
my ($self, $channel, $hostmask) = @_;
|
||||
|
||||
$channel = lc $channel;
|
||||
$hostmask = lc $hostmask;
|
||||
$channel = '.*' if $channel !~ /^#/;
|
||||
|
||||
if (exists $self->{users}->{hash}->{$channel}) {
|
||||
if (not exists $self->{users}->{hash}->{$channel}->{$hostmask}) {
|
||||
my $last_level = 0;
|
||||
# find hostmask by account name or wildcard
|
||||
foreach my $mask (keys %{ $self->{users}->{hash}->{$channel} }) {
|
||||
next if $mask eq '_name';
|
||||
if (lc $self->{users}->{hash}->{$channel}->{$mask}->{name} eq $hostmask) {
|
||||
if ($last_level < $self->{users}->{hash}->{$channel}->{$mask}->{level}) {
|
||||
$hostmask = $mask;
|
||||
$last_level = $self->{users}->{hash}->{$channel}->{$mask}->{level};
|
||||
}
|
||||
}
|
||||
|
||||
if ($mask =~ /[*?]/) {
|
||||
# contains * or ? so it's converted to a regex
|
||||
my $mask_quoted = quotemeta $mask;
|
||||
$mask_quoted =~ s/\\\*/.*?/g;
|
||||
$mask_quoted =~ s/\\\?/./g;
|
||||
if ($hostmask =~ m/^$mask_quoted$/i) {
|
||||
if ($last_level < $self->{users}->{hash}->{$channel}->{$mask}->{level}) {
|
||||
$hostmask = $mask;
|
||||
$last_level = $self->{users}->{hash}->{$channel}->{$mask}->{level};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $hostmask;
|
||||
}
|
||||
|
||||
sub find_admin {
|
||||
my ($self, $channel, $hostmask, $min_level) = @_;
|
||||
$min_level //= 1;
|
||||
|
||||
$channel = $self->{pbot}->{registry}->get_value('irc', 'botnick') if not defined $channel;
|
||||
$hostmask = '.*' if not defined $hostmask;
|
||||
$hostmask = lc $hostmask;
|
||||
|
||||
my $result = eval {
|
||||
my $admin;
|
||||
foreach my $channel_regex (keys %{ $self->{users}->{hash} }) {
|
||||
if ($channel !~ m/^#/ or $channel =~ m/^$channel_regex$/i) {
|
||||
foreach my $hostmask_regex (keys %{ $self->{users}->{hash}->{$channel_regex} }) {
|
||||
next if $hostmask_regex eq '_name';
|
||||
if ($hostmask_regex =~ m/[*?]/) {
|
||||
# contains * or ? so it's converted to a regex
|
||||
my $hostmask_quoted = quotemeta $hostmask_regex;
|
||||
$hostmask_quoted =~ s/\\\*/.*?/g;
|
||||
$hostmask_quoted =~ s/\\\?/./g;
|
||||
if ($hostmask =~ m/^$hostmask_quoted$/i) {
|
||||
my $temp = $self->{users}->{hash}->{$channel_regex}->{$hostmask_regex};
|
||||
$admin = $temp if $temp->{level} >= $min_level and (not defined $admin or $admin->{level} < $temp->{level});
|
||||
}
|
||||
} else {
|
||||
# direct comparison
|
||||
if ($hostmask eq lc $hostmask_regex) {
|
||||
my $temp = $self->{users}->{hash}->{$channel_regex}->{$hostmask_regex};
|
||||
$admin = $temp if $temp->{level} >= $min_level and (not defined $admin or $admin->{level} < $temp->{level});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $admin;
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
$self->{pbot}->{logger}->log("Error in find_admin parameters: $@\n");
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub find_user {
|
||||
my ($self, $from, $hostmask) = @_;
|
||||
return $self->find_admin($from, $hostmask, 0);
|
||||
}
|
||||
|
||||
sub loggedin {
|
||||
my ($self, $channel, $hostmask) = @_;
|
||||
my $user = $self->find_user($channel, $hostmask);
|
||||
|
||||
if (defined $user and $user->{loggedin}) {
|
||||
return $user;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub loggedin_admin {
|
||||
my ($self, $channel, $hostmask) = @_;
|
||||
my $user = $self->loggedin($channel, $hostmask);
|
||||
|
||||
if (defined $user and $user->{level} > 0) {
|
||||
return $user;
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub login {
|
||||
my ($self, $channel, $hostmask, $password) = @_;
|
||||
my $user = $self->find_user($channel, $hostmask);
|
||||
|
||||
if (not defined $user) {
|
||||
$self->{pbot}->{logger}->log("Attempt to login non-existent [$channel][$hostmask] failed\n");
|
||||
return "You do not have an account in $channel.";
|
||||
}
|
||||
|
||||
if (defined $password and $user->{password} ne $password) {
|
||||
$self->{pbot}->{logger}->log("Bad login password for [$channel][$hostmask]\n");
|
||||
return "I don't think so.";
|
||||
}
|
||||
|
||||
$user->{loggedin} = 1;
|
||||
$self->{pbot}->{logger}->log("$hostmask logged into $channel\n");
|
||||
return "Logged into $channel.";
|
||||
}
|
||||
|
||||
sub logout {
|
||||
my ($self, $channel, $hostmask) = @_;
|
||||
my $user = $self->find_user($channel, $hostmask);
|
||||
delete $user->{loggedin} if defined $user;
|
||||
}
|
||||
|
||||
sub logincmd {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
my $channel = $from;
|
||||
|
||||
if (not $arguments) {
|
||||
return "Usage: login [channel] password";
|
||||
}
|
||||
|
||||
if ($arguments =~ m/^([^ ]+)\s+(.+)/) {
|
||||
$channel = $1;
|
||||
$arguments = $2;
|
||||
}
|
||||
|
||||
if ($self->loggedin($channel, "$nick!$user\@$host")) {
|
||||
return "/msg $nick You are already logged into channel $channel.";
|
||||
}
|
||||
|
||||
my $result = $self->login($channel, "$nick!$user\@$host", $arguments);
|
||||
return "/msg $nick $result";
|
||||
}
|
||||
|
||||
sub logoutcmd {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
return "/msg $nick Uh, you aren't logged into channel $from." if (not $self->loggedin($from, "$nick!$user\@$host"));
|
||||
$self->logout($from, "$nick!$user\@$host");
|
||||
return "/msg $nick Good-bye, $nick.";
|
||||
}
|
||||
|
||||
sub useradd {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
|
||||
my ($name, $channel, $hostmask, $level, $password) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 5);
|
||||
$level //= 0;
|
||||
|
||||
if (not defined $name or not defined $channel or not defined $hostmask) {
|
||||
return "/msg $nick Usage: useradd <account name> <channel> <hostmask> [level] [password]";
|
||||
}
|
||||
|
||||
$channel = '.*' if $channel !~ /^#/;
|
||||
|
||||
my $admin = $self->{pbot}->{users}->find_admin($channel, "$nick!$user\@$host");
|
||||
|
||||
if (not $admin) {
|
||||
return "You are not an admin for $channel; cannot add users to that channel.\n";
|
||||
}
|
||||
|
||||
# don't allow non-bot-owners to add admins that can also add admins
|
||||
if ($admin->{level} < 90 and $level > 40) {
|
||||
return "You may not set admin level higher than 40.\n";
|
||||
}
|
||||
|
||||
$self->{pbot}->{users}->add_user($name, $channel, $hostmask, $level, $password);
|
||||
return not $level ? "User added." : "Admin added.";
|
||||
}
|
||||
|
||||
sub userdel {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
|
||||
my ($channel, $hostmask) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
|
||||
|
||||
if (not defined $channel or not defined $hostmask) {
|
||||
return "/msg $nick Usage: userdel <channel> <hostmask or account name>";
|
||||
}
|
||||
|
||||
$hostmask = $self->hostmask_or_account_name($channel, $hostmask);
|
||||
$channel = '.*' if $channel !~ /^#/;
|
||||
return $self->remove_user($channel, $hostmask);
|
||||
}
|
||||
|
||||
sub userset {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
my ($channel, $hostmask, $key, $value) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 4);
|
||||
|
||||
if (not defined $channel or not defined $hostmask) {
|
||||
return "Usage: userset <channel> <hostmask or account name> [key] [value]";
|
||||
}
|
||||
|
||||
$hostmask = $self->hostmask_or_account_name($channel, $hostmask);
|
||||
my $admin = $self->find_admin($channel, "$nick!$user\@$host");
|
||||
my $target = $self->find_user($channel, $hostmask);
|
||||
|
||||
if (not $admin) {
|
||||
return "You are not an admin for $channel; cannot modify their users.";
|
||||
}
|
||||
|
||||
if (not $target) {
|
||||
return "There is no user $hostmask in channel $channel.";
|
||||
}
|
||||
|
||||
# don't allow non-bot-owners to add admins that can also add admins
|
||||
if (defined $key and $key eq 'level' and $admin->{level} < 90 and $value > 40) {
|
||||
return "You may not set user level higher than 40.\n";
|
||||
}
|
||||
|
||||
if (defined $key and $target->{level} > $admin->{level}) {
|
||||
return "You may not modify users higher in level than you.";
|
||||
}
|
||||
|
||||
$channel = '.*' if $channel !~ /^#/;
|
||||
my $result = $self->{users}->set($channel, $hostmask, $key, $value);
|
||||
$result =~ s/^password => .*;$/password => <private>;/m;
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub userunset {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
my ($channel, $hostmask, $key) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 3);
|
||||
|
||||
if (not defined $channel or not defined $hostmask) {
|
||||
return "Usage: userunset <channel> <hostmask or account name> <key>";
|
||||
}
|
||||
|
||||
my $admin = $self->find_admin($channel, "$nick!$user\@$host");
|
||||
$hostmask = $self->hostmask_or_account_name($channel, $hostmask);
|
||||
my $target = $self->find_user($channel, $hostmask);
|
||||
|
||||
if (not $admin) {
|
||||
return "You are not an admin for $channel; cannot modify their users.";
|
||||
}
|
||||
|
||||
if (not $target) {
|
||||
return "There is no user $hostmask in channel $channel.";
|
||||
}
|
||||
|
||||
if ($target->{level} >= $user->{level}) {
|
||||
return "You may not modify users equal or higher in level than you.";
|
||||
}
|
||||
|
||||
$channel = '.*' if $channel !~ /^#/;
|
||||
return $self->{users}->unset($channel, $hostmask, $key);
|
||||
}
|
||||
|
||||
sub mycmd {
|
||||
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
|
||||
my ($key, $value) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
|
||||
|
||||
if (not defined $key) {
|
||||
return "Usage: my <key> [value]";
|
||||
}
|
||||
|
||||
my $channel = $from;
|
||||
$channel = '.*' if $channel !~ /^#/;
|
||||
my $hostmask = $self->hostmask_or_account_name($channel, "$nick!$user\@$host");
|
||||
my $u = $self->find_user($channel, $hostmask);
|
||||
|
||||
print "hostmask: $hostmask\n";
|
||||
use Data::Dumper;
|
||||
print Dumper \$u;
|
||||
|
||||
if (not $u) {
|
||||
$channel = '.*';
|
||||
$hostmask = "$nick!*\@*";
|
||||
$u = $self->add_user("my_$nick", $channel, $hostmask);
|
||||
$u->{autologin} = 1;
|
||||
$u->{loggedin} = 1;
|
||||
}
|
||||
|
||||
if ($u->{level} == 0) {
|
||||
my @disallowed = qw/level autoop autovoice/;
|
||||
if (grep { lc $key } @disallowed) {
|
||||
return "You must be an admin to set $key.";
|
||||
}
|
||||
}
|
||||
|
||||
my $result = $self->{users}->set($channel, $hostmask, $key, $value);
|
||||
$result =~ s/^password => .*;$/password => <private>;/m;
|
||||
return $result;
|
||||
}
|
||||
|
||||
1;
|
Loading…
Reference in New Issue
Block a user