Finished replacing admin-levels with user-capabilities [FIN commit 2 of 2]; misc clean-ups

This commit is contained in:
Pragmatic Software 2020-02-03 17:19:04 -08:00
parent 2ca9634c66
commit 6267cc04d2
48 changed files with 426 additions and 685 deletions

View File

@ -78,7 +78,7 @@ sub initialize {
$self->{pbot}->{registry}->add_default('text', 'antiflood', 'debug_checkban', $conf{debug_checkban} // 0); $self->{pbot}->{registry}->add_default('text', 'antiflood', 'debug_checkban', $conf{debug_checkban} // 0);
$self->{pbot}->{commands}->register(sub { return $self->unbanme(@_) }, "unbanme", 0); $self->{pbot}->{commands}->register(sub { return $self->unbanme(@_) }, "unbanme", 0);
$self->{pbot}->{commands}->register(sub { return $self->whitelist(@_) }, "whitelist", 10); $self->{pbot}->{commands}->register(sub { return $self->whitelist(@_) }, "whitelist", 1);
$self->{pbot}->{event_dispatcher}->register_handler('irc.whoisaccount', sub { $self->on_whoisaccount(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.whoisaccount', sub { $self->on_whoisaccount(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.whoisuser', sub { $self->on_whoisuser(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.whoisuser', sub { $self->on_whoisuser(@_) });

View File

@ -41,7 +41,7 @@ sub initialize {
$self->{keywords}->load; $self->{keywords}->load;
$self->{pbot}->{registry}->add_default('text', 'antispam', 'enforce', $conf{enforce_antispam} // 1); $self->{pbot}->{registry}->add_default('text', 'antispam', 'enforce', $conf{enforce_antispam} // 1);
$self->{pbot}->{commands}->register(sub { return $self->antispam_cmd(@_) }, "antispam", 10); $self->{pbot}->{commands}->register(sub { return $self->antispam_cmd(@_) }, "antispam", 1);
} }
sub is_spam { sub is_spam {

View File

@ -24,12 +24,8 @@ $Data::Dumper::Sortkeys = 1;
use Carp (); use Carp ();
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to BanTracker should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to BanTracker should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -38,14 +34,14 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to BanTracker"); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to BanTracker");
$self->{banlist} = {}; $self->{banlist} = {};
$self->{pbot}->{registry}->add_default('text', 'bantracker', 'chanserv_ban_timeout', '604800'); $self->{pbot}->{registry}->add_default('text', 'bantracker', 'chanserv_ban_timeout', '604800');
$self->{pbot}->{registry}->add_default('text', 'bantracker', 'mute_timeout', '604800'); $self->{pbot}->{registry}->add_default('text', 'bantracker', 'mute_timeout', '604800');
$self->{pbot}->{registry}->add_default('text', 'bantracker', 'debug', '0'); $self->{pbot}->{registry}->add_default('text', 'bantracker', 'debug', '0');
$self->{pbot}->{commands}->register(sub { $self->dumpbans(@_) }, "dumpbans", 60); $self->{pbot}->{commands}->register(sub { $self->dumpbans(@_) }, "dumpbans", 1);
$self->{pbot}->{event_dispatcher}->register_handler('irc.endofnames', sub { $self->get_banlist(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.endofnames', sub { $self->get_banlist(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.banlist', sub { $self->on_banlist_entry(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.banlist', sub { $self->on_banlist_entry(@_) });
@ -54,7 +50,6 @@ sub initialize {
sub dumpbans { sub dumpbans {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
my $bans = Dumper($self->{banlist}); my $bans = Dumper($self->{banlist});
return $bans; return $bans;
} }

View File

@ -33,7 +33,7 @@ sub initialize {
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{filename} = $conf{filename}; $self->{filename} = $conf{filename};
$self->{blacklist} = {}; $self->{blacklist} = {};
$self->{pbot}->{commands}->register(sub { $self->blacklist(@_) }, "blacklist", 10); $self->{pbot}->{commands}->register(sub { $self->blacklist(@_) }, "blacklist", 1);
$self->load_blacklist; $self->load_blacklist;
} }

View File

@ -53,8 +53,9 @@ sub has {
my ($self, $cap, $subcap, $depth) = @_; my ($self, $cap, $subcap, $depth) = @_;
my $cap_data = $self->{caps}->get_data($cap); my $cap_data = $self->{caps}->get_data($cap);
return 0 if not defined $cap_data; return 0 if not defined $cap_data;
return 1 if $cap eq $subcap;
$depth //= 2; $depth //= 10;
if (--$depth <= 0) { if (--$depth <= 0) {
$self->{pbot}->{logger}->log("Max recursion reached for PBot::Capabilities->has()\n"); $self->{pbot}->{logger}->log("Max recursion reached for PBot::Capabilities->has()\n");
return 0; return 0;
@ -74,7 +75,7 @@ sub userhas {
return 1 if $user->{$cap}; return 1 if $user->{$cap};
foreach my $key (keys %{$user}) { foreach my $key (keys %{$user}) {
next if $key eq '_name'; next if $key eq '_name';
return 1 if $self->has($key, $cap, 10); return 1 if $self->has($key, $cap);
} }
return 0; return 0;
} }
@ -109,6 +110,15 @@ sub add {
} }
sub remove { sub remove {
my ($self, $cap) = @_;
$cap = lc $cap;
foreach my $c (keys %{$self->{caps}->{hash}}) {
next if $c eq '_name';
foreach my $sub_cap (keys %{$self->{caps}->{hash}->{$c}}) {
delete $self->{caps}->{hash}->{$c}->{$sub_cap} if $sub_cap eq $cap;
}
delete $self->{caps}->{hash}->{$c} if $c eq $cap;
}
} }
sub rebuild_botowner_capabilities { sub rebuild_botowner_capabilities {
@ -122,7 +132,7 @@ sub rebuild_botowner_capabilities {
sub list { sub list {
my ($self, $capability) = @_; my ($self, $capability) = @_;
$capability = lc $capability; $capability = lc $capability if defined $capability;
return "No such capability $capability." if defined $capability and not exists $self->{caps}->{hash}->{$capability}; return "No such capability $capability." if defined $capability and not exists $self->{caps}->{hash}->{$capability};
my @caps; my @caps;
@ -135,7 +145,7 @@ sub list {
$result = 'Capabilities: '; $result = 'Capabilities: ';
} else { } else {
@caps = sort keys %{$self->{caps}->{hash}->{$capability}}; @caps = sort keys %{$self->{caps}->{hash}->{$capability}};
return "Capability $capability has no sub-capabilities." if @caps == 1; return "Capability $capability has no sub-capabilities." if not @caps or @caps == 1;
$result = "Sub-capabilities for $capability: "; $result = "Sub-capabilities for $capability: ";
} }
@ -144,7 +154,7 @@ sub list {
foreach my $cap (@caps) { foreach my $cap (@caps) {
next if $cap eq '_name'; next if $cap eq '_name';
my $count = keys(%{$self->{caps}->{hash}->{$cap}}) - 1; my $count = keys(%{$self->{caps}->{hash}->{$cap}}) - 1;
if ($count) { if ($count > 0) {
push @cap_group, "$cap [$count]" if $count; push @cap_group, "$cap [$count]" if $count;
} else { } else {
push @cap_standalone, $cap; push @cap_standalone, $cap;
@ -166,6 +176,41 @@ sub capcmd {
} }
when ('userhas') { when ('userhas') {
my ($hostmask, $cap) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 2);
return "Usage: cap userhas <user> [capability]" if not defined $hostmask;
$cap = lc $cap if defined $cap;
my $u = $self->{pbot}->{users}->find_user('.*', $hostmask);
return "No such user $hostmask." if not defined $u;
if (defined $cap) {
return "Try again. No such capability $cap." if not $self->exists($cap);
if ($self->userhas($u, $cap)) {
return "Yes. User $u->{name} has capability $cap.";
} else {
return "No. User $u->{name} does not have capability $cap.";
}
} else {
my $result = "User $u->{name} has capabilities: ";
my @groups;
my @single;
foreach my $key (sort keys %{$u}) {
next if $key eq '_name';
next if not $self->exists($key);
my $count = keys (%{$self->{caps}->{hash}->{$key}}) - 1;
if ($count > 0) {
push @groups, "$key [$count]";
} else {
push @single, $key;
}
}
if (@groups or @single) {
$result .= join ', ', @groups, @single;
} else {
$result = "User $u->{name} has no capabilities.";
}
return $result;
}
} }
when ('add') { when ('add') {
@ -175,7 +220,7 @@ sub capcmd {
} }
default { default {
$result = "Usage: cap list [capability] | cap add <capability> [sub-capability] | cap remove <capability> [sub-capability] | cap userhas <user> <capability>"; $result = "Usage: cap list [capability] | cap add <capability> [sub-capability] | cap remove <capability> [sub-capability] | cap userhas <user> [capability]";
} }
} }
return $result; return $result;

View File

@ -19,10 +19,7 @@ use Time::HiRes qw(gettimeofday);
use Time::Duration qw(concise duration); use Time::Duration qw(concise duration);
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
@ -31,7 +28,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to ChanOps"); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to ChanOps");
$self->{unban_timeout} = PBot::DualIndexHashObject->new( $self->{unban_timeout} = PBot::DualIndexHashObject->new(

View File

@ -27,19 +27,18 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{channels} = PBot::HashObject->new(pbot => $self->{pbot}, name => 'Channels', filename => $conf{filename}); $self->{channels} = PBot::HashObject->new(pbot => $self->{pbot}, name => 'Channels', filename => $conf{filename});
$self->load_channels; $self->load_channels;
$self->{pbot}->{commands}->register(sub { $self->join(@_) }, "join", 40); $self->{pbot}->{commands}->register(sub { $self->join(@_) }, "join", 1);
$self->{pbot}->{commands}->register(sub { $self->part(@_) }, "part", 40); $self->{pbot}->{commands}->register(sub { $self->part(@_) }, "part", 1);
$self->{pbot}->{commands}->register(sub { $self->set(@_) }, "chanset", 40); $self->{pbot}->{commands}->register(sub { $self->set(@_) }, "chanset", 1);
$self->{pbot}->{commands}->register(sub { $self->unset(@_) }, "chanunset", 40); $self->{pbot}->{commands}->register(sub { $self->unset(@_) }, "chanunset", 1);
$self->{pbot}->{commands}->register(sub { $self->add(@_) }, "chanadd", 40); $self->{pbot}->{commands}->register(sub { $self->add(@_) }, "chanadd", 1);
$self->{pbot}->{commands}->register(sub { $self->remove(@_) }, "chanrem", 40); $self->{pbot}->{commands}->register(sub { $self->remove(@_) }, "chanrem", 1);
$self->{pbot}->{commands}->register(sub { $self->list(@_) }, "chanlist", 10); $self->{pbot}->{commands}->register(sub { $self->list(@_) }, "chanlist", 1);
} }
sub join { sub join {

View File

@ -40,7 +40,6 @@ sub initialize {
sub load { sub load {
my ($self, $filename) = @_; my ($self, $filename) = @_;
$filename = $self->{filename} if not defined $filename; $filename = $self->{filename} if not defined $filename;
if (not defined $filename) { if (not defined $filename) {
@ -104,7 +103,6 @@ sub load {
sub save { sub save {
my $self = shift; my $self = shift;
my $filename; my $filename;
if (@_) { $filename = shift; } else { $filename = $self->{filename}; } if (@_) { $filename = shift; } else { $filename = $self->{filename}; }
if (not defined $filename) { if (not defined $filename) {

View File

@ -25,26 +25,26 @@ use JSON;
use PBot::Utils::SafeFilename; use PBot::Utils::SafeFilename;
our %factoid_metadata_levels = ( our %factoid_metadata_capabilities = (
created_on => 90, created_on => 'botowner',
enabled => 10, enabled => 'chanop',
last_referenced_in => 90, last_referenced_in => 'botowner',
last_referenced_on => 90, last_referenced_on => 'botowner',
modulelauncher_subpattern => 90, modulelauncher_subpattern => 'botowner',
owner => 90, owner => 'botowner',
rate_limit => 10, rate_limit => 'chanop',
ref_count => 90, ref_count => 'botowner',
ref_user => 90, ref_user => 'botowner',
type => 90, type => 'botowner',
edited_by => 90, edited_by => 'botowner',
edited_on => 90, edited_on => 'botowner',
locked => 10, locked => 'chanop',
add_nick => 10, add_nick => 'chanop',
nooverride => 10, nooverride => 'chanop',
'effective-level' => 40, 'cap-override' => 'botowner',
'persist-key' => 20, 'persist-key' => 'admin',
'interpolate' => 10, 'interpolate' => 'chanop',
# all others are allowed to be factset by anybody/default to level 0 # all others are allowed to be factset by anybody
); );
sub new { sub new {
@ -78,14 +78,14 @@ sub initialize {
$self->{pbot}->{commands}->register(sub { return $self->call_factoid(@_) }, "fact", 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->factfind(@_) }, "factfind", 0);
$self->{pbot}->{commands}->register(sub { return $self->top20(@_) }, "top20", 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->load_module(@_) }, "load", 1);
$self->{pbot}->{commands}->register(sub { return $self->unload_module(@_) }, "unload", 90); $self->{pbot}->{commands}->register(sub { return $self->unload_module(@_) }, "unload", 1);
$self->{pbot}->{commands}->register(sub { return $self->histogram(@_) }, "histogram", 0); $self->{pbot}->{commands}->register(sub { return $self->histogram(@_) }, "histogram", 0);
$self->{pbot}->{commands}->register(sub { return $self->count(@_) }, "count", 0); $self->{pbot}->{commands}->register(sub { return $self->count(@_) }, "count", 0);
# the following commands have not yet been updated to use the new factoid structure # the following commands have not yet been updated to use the new factoid structure
# DO NOT USE!! Factoid corruption may occur. # DO NOT USE!! Factoid corruption may occur.
$self->{pbot}->{commands}->register(sub { return $self->add_regex(@_) }, "regex", 999); $self->{pbot}->{commands}->register(sub { return $self->add_regex(@_) }, "regex", 1);
} }
sub call_factoid { sub call_factoid {
@ -406,13 +406,12 @@ sub factundo {
} }
my $factoids = $self->{pbot}->{factoids}->{factoids}->{hash}; my $factoids = $self->{pbot}->{factoids}->{factoids}->{hash};
my $admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host"); my $userinfo = $self->{pbot}->{users}->loggedin($channel, "$nick!$user\@$host");
if ($factoids->{$channel}->{$trigger}->{'locked'}) { if ($factoids->{$channel}->{$trigger}->{'locked'}) {
return "/say $trigger_name is locked and cannot be reverted." if not defined $admininfo; return "/say $trigger_name is locked and cannot be reverted." if not $self->{pbot}->{capabilities}->userhas($userinfo, 'admin');
if (exists $factoids->{$channel}->{$trigger}->{'effective-level'} if (exists $factoids->{$channel}->{$trigger}->{'cap-override'} and not $self->{pbot}->{capabilities}->userhas($userinfo, 'botowner')) {
and $admininfo->{level} < $factoids->{$channel}->{$trigger}->{'effective-level'}) { return "/say $trigger_name is locked with a cap-override and cannot be reverted. Unlock the factoid first.";
return "/say $trigger_name is locked with an effective-level higher than your level and cannot be reverted.";
} }
} }
@ -499,13 +498,12 @@ sub factredo {
} }
my $factoids = $self->{pbot}->{factoids}->{factoids}->{hash}; my $factoids = $self->{pbot}->{factoids}->{factoids}->{hash};
my $admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host"); my $userinfo = $self->{pbot}->{users}->loggedin($channel, "$nick!$user\@$host");
if ($factoids->{$channel}->{$trigger}->{'locked'}) { if ($factoids->{$channel}->{$trigger}->{'locked'}) {
return "/say $trigger_name is locked and cannot be reverted." if not defined $admininfo; return "/say $trigger_name is locked and cannot be reverted." if not defined $self->{pbot}->{capabilities}->userhas($userinfo, 'admin');
if (exists $factoids->{$channel}->{$trigger}->{'effective-level'} if (exists $factoids->{$channel}->{$trigger}->{'cap-override'} and not $self->{pbot}->{capabilities}->userhas($userinfo, 'botowner')) {
and $admininfo->{level} < $factoids->{$channel}->{$trigger}->{'effective-level'}) { return "/say $trigger_name is locked with a cap-override and cannot be reverted. Unlock the factoid first.";
return "/say $trigger_name is locked with an effective-level higher than your level and cannot be reverted.";
} }
} }
@ -559,50 +557,39 @@ sub factset {
$channel = '.*' if $channel !~ /^#/; $channel = '.*' if $channel !~ /^#/;
my ($owner_channel, $owner_trigger) = $self->{pbot}->{factoids}->find_factoid($channel, $trigger, exact_channel => 1, exact_trigger => 1); my ($owner_channel, $owner_trigger) = $self->{pbot}->{factoids}->find_factoid($channel, $trigger, exact_channel => 1, exact_trigger => 1);
my $admininfo; my $userinfo;
if (defined $owner_channel) { if (defined $owner_channel) {
$admininfo = $self->{pbot}->{users}->loggedin_admin($owner_channel, "$nick!$user\@$host"); $userinfo = $self->{pbot}->{users}->loggedin($owner_channel, "$nick!$user\@$host");
} else { } else {
$admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host"); $userinfo = $self->{pbot}->{users}->loggedin($channel, "$nick!$user\@$host");
}
my $level = 0;
my $meta_level = 0;
if (defined $admininfo) {
$level = $admininfo->{level};
} }
my $meta_cap;
if (defined $key) { if (defined $key) {
if (defined $factoid_metadata_levels{$key}) { if (defined $factoid_metadata_capabilities{$key}) {
$meta_level = $factoid_metadata_levels{$key}; $meta_cap = $factoid_metadata_capabilities{$key};
} }
if ($meta_level > 0) { if (defined $meta_cap) {
if ($level == 0) { if (not $self->{pbot}->{capabilities}->userhas($userinfo, $meta_cap)) {
return "You must be an admin to set $key"; return "Your user account must have the $meta_cap capability to set $key.";
} elsif ($level < $meta_level) {
return "You must be at least level $meta_level to set $key";
} }
} }
if (defined $value and !$level and $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'locked'}) { if (defined $value and !$self->{pbot}->{capabilities}->userhas($userinfo, 'admin') and $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'locked'}) {
return "/say $trigger_name is locked; unlock before setting."; return "/say $trigger_name is locked; unlock before setting.";
} }
if (lc $key eq 'effective-level' and defined $value and $level > 0) { if (lc $key eq 'cap-override' and defined $value) {
if ($value > $level) { if (not $self->{pbot}->{capabilities}->exists($value)) {
return "You cannot set `effective-level` greater than your level, which is $level."; return "No such capability $value.";
} elsif ($value < 0) {
return "You cannot set a negative effective-level.";
} }
$self->{pbot}->{factoids}->{factoids}->set($channel, $trigger, 'locked', '1'); $self->{pbot}->{factoids}->{factoids}->set($channel, $trigger, 'locked', '1');
} }
if (lc $key eq 'locked' and exists $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'effective-level'}) { if (lc $key eq 'locked' and exists $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'cap-override'}) {
if ($level < $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'effective-level'}) { if (not $self->{pbot}->{capabilities}->userhas($userinfo, 'botowner')) {
return "You cannot unlock this factoid because its effective-level is greater than your level."; return "/say $trigger_name has a cap-override and cannot be unlocked until the override is removed.";
} }
} }
} }
@ -622,7 +609,7 @@ sub factset {
$mask = $nick; $mask = $nick;
} }
if ((defined $value and $key ne 'action' and $key ne 'action_with_args') and lc $mask ne lc $owner and $level == 0) { if ((defined $value and $key ne 'action' and $key ne 'action_with_args') and lc $mask ne lc $owner and not $self->{pbot}->{capabilities}->userhas($userinfo, 'admin')) {
return "You are not the owner of $trigger_name."; return "You are not the owner of $trigger_name.";
} }
} }
@ -651,43 +638,30 @@ sub factunset {
my ($owner_channel, $owner_trigger) = $self->{pbot}->{factoids}->find_factoid($channel, $trigger, exact_channel => 1, exact_trigger => 1); my ($owner_channel, $owner_trigger) = $self->{pbot}->{factoids}->find_factoid($channel, $trigger, exact_channel => 1, exact_trigger => 1);
my $admininfo; my $userinfo;
if (defined $owner_channel) { if (defined $owner_channel) {
$admininfo = $self->{pbot}->{users}->loggedin_admin($owner_channel, "$nick!$user\@$host"); $userinfo = $self->{pbot}->{users}->loggedin($owner_channel, "$nick!$user\@$host");
} else { } else {
$admininfo = $self->{pbot}->{users}->loggedin_admin($channel, "$nick!$user\@$host"); $userinfo = $self->{pbot}->{users}->loggedin($channel, "$nick!$user\@$host");
} }
my $level = 0; my $meta_cap;
my $meta_level = 0; if (exists $factoid_metadata_capabilities{$key}) {
$meta_cap = $factoid_metadata_capabilities{$key};
if (defined $admininfo) {
$level = $admininfo->{level};
} }
if (defined $factoid_metadata_levels{$key}) { if (defined $meta_cap) {
$meta_level = $factoid_metadata_levels{$key}; if (not $self->{pbot}->{capabilities}->userhas($userinfo, $meta_cap)) {
} return "Your user account must have the $meta_cap capability to unset $key.";
if ($meta_level > 0) {
if ($level == 0) {
return "You must be an admin to unset $key";
} elsif ($level < $meta_level) {
return "You must be at least level $meta_level to unset $key";
} }
} }
if (exists $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'effective-level'}) { if (exists $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'cap-override'}) {
if (lc $key eq 'locked') { if (lc $key eq 'locked') {
if ($level >= $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'effective-level'}) { if ($self->{pbot}->{capabilities}->userhas($userinfo, 'botowner')) {
$self->{pbot}->{factoids}->{factoids}->unset($channel, $trigger, 'effective-level'); $self->{pbot}->{factoids}->{factoids}->unset($channel, $trigger, 'cap-override');
} else { } else {
return "You cannot unlock this factoid because its effective-level is higher than your level."; return "You cannot unlock this factoid because it has a cap-override. Remove the override first.";
}
} elsif (lc $key eq 'effective-level') {
if ($level < $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{'effective-level'}) {
return "You cannot unset the effective-level because it is higher than your level.";
} }
} }
} }
@ -704,7 +678,7 @@ sub factunset {
my ($owner) = $factoid->{'owner'} =~ m/([^!]+)/; my ($owner) = $factoid->{'owner'} =~ m/([^!]+)/;
if ($key ne 'action_with_args' and lc $nick ne lc $owner and $level == 0) { if ($key ne 'action_with_args' and lc $nick ne lc $owner and not $self->{pbot}->{capabilities}->userhas($userinfo, 'admin')) {
return "You are not the owner of $trigger_name."; return "You are not the owner of $trigger_name.";
} }
$oldvalue = $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{$key}; $oldvalue = $self->{pbot}->{factoids}->{factoids}->{hash}->{$channel}->{$trigger}->{$key};
@ -717,7 +691,6 @@ sub factunset {
if ($result =~ m/unset/) { if ($result =~ m/unset/) {
$self->log_factoid($channel, $trigger, "$nick!$user\@$host", "unset $key (value: $oldvalue)"); $self->log_factoid($channel, $trigger, "$nick!$user\@$host", "unset $key (value: $oldvalue)");
} }
return $result; return $result;
} }
@ -1623,13 +1596,12 @@ 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."; 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}->{users}->loggedin_admin($channel, "$nick!$user\@$host"); my $userinfo = $self->{pbot}->{users}->loggedin($channel, "$nick!$user\@$host");
if ($factoids_hash->{$channel}->{$trigger}->{'locked'}) { if ($factoids_hash->{$channel}->{$trigger}->{'locked'}) {
return "/say $trigger_name is locked and cannot be changed." if not defined $admininfo; return "/say $trigger_name is locked and cannot be changed." if not $self->{pbot}->{capabilities}->userhas($userinfo, 'admin');
if (exists $factoids_hash->{$channel}->{$trigger}->{'effective-level'} if (exists $factoids_hash->{$channel}->{$trigger}->{'cap-override'} and not $self->{pbot}->{capabilities}->userhas($userinfo, 'botowner')) {
and $admininfo->{level} < $factoids_hash->{$channel}->{$trigger}->{'effective-level'}) { return "/say $trigger_name is locked with a cap-override set and cannot be changed until the override is removed.";
return "/say $trigger_name is locked with an effective-level higher than your level and cannot be changed.";
} }
} }
@ -1711,7 +1683,7 @@ sub factchange {
return $ret if length $ret; return $ret if length $ret;
} }
if (length $action > 8000 and not defined $admininfo) { if (length $action > 8000 and not $self->{pbot}->{capabilities}->userhas($userinfo, 'admin')) {
return "Change $trigger_name failed; result is too long."; return "Change $trigger_name failed; result is too long.";
} }

View File

@ -25,12 +25,8 @@ use Encode;
$SIG{CHLD} = sub { while (waitpid(-1, WNOHANG) > 0) {} }; $SIG{CHLD} = sub { while (waitpid(-1, WNOHANG) > 0) {} };
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to Commands should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -38,13 +34,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
my $pbot = delete $conf{pbot};
if (not defined $pbot) {
Carp::croak("Missing pbot reference to PBot::FactoidModuleLauncher");
}
$self->{pbot} = $pbot;
} }
sub execute_module { sub execute_module {

View File

@ -1009,12 +1009,12 @@ sub handle_action {
$self->{pbot}->{logger}->log("[" . (defined $stuff->{from} ? $stuff->{from} : "stdin") . "] ($stuff->{nick}!$stuff->{user}\@$stuff->{host}) $trigger_name aliased to: $command\n"); $self->{pbot}->{logger}->log("[" . (defined $stuff->{from} ? $stuff->{from} : "stdin") . "] ($stuff->{nick}!$stuff->{user}\@$stuff->{host}) $trigger_name aliased to: $command\n");
if (defined $self->{factoids}->{hash}->{$channel}->{$keyword}->{'effective-level'}) { if (defined $self->{factoids}->{hash}->{$channel}->{$keyword}->{'cap-override'}) {
if ($self->{factoids}->{hash}->{$channel}->{$keyword}->{'locked'}) { if ($self->{factoids}->{hash}->{$channel}->{$keyword}->{'locked'}) {
$self->{pbot}->{logger}->log("Effective-level set to $self->{factoids}->{hash}->{$channel}->{$keyword}->{'effective-level'}\n"); $self->{pbot}->{logger}->log("Capability override set to $self->{factoids}->{hash}->{$channel}->{$keyword}->{'cap-override'}\n");
$stuff->{'effective-level'} = $self->{factoids}->{hash}->{$channel}->{$keyword}->{'effective-level'}; $stuff->{'cap-override'} = $self->{factoids}->{hash}->{$channel}->{$keyword}->{'cap-override'};
} else { } else {
$self->{pbot}->{logger}->log("Ignoring effective-level of $self->{factoids}->{hash}->{$channel}->{$keyword}->{'effective-level'} on unlocked factoid\n"); $self->{pbot}->{logger}->log("Ignoring cap-override of $self->{factoids}->{hash}->{$channel}->{$keyword}->{'cap-override'} on unlocked factoid\n");
} }
} }
@ -1068,9 +1068,9 @@ sub handle_action {
# Don't allow user-custom /msg factoids, unless factoid triggered by admin # Don't allow user-custom /msg factoids, unless factoid triggered by admin
if ($action =~ m/^\/msg/i) { if ($action =~ m/^\/msg/i) {
my $admin = $self->{pbot}->{users}->loggedin_admin($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) { if (not $admin) {
$self->{pbot}->{logger}->log("[ABUSE] Bad factoid (contains /msg): $action\n"); $self->{pbot}->{logger}->log("[ABUSE] Bad factoid (contains /msg): $action\n");
return "You are not powerful enough to use /msg in a factoid."; return "You must be an admin to use /msg in a factoid.";
} }
} }
@ -1084,19 +1084,6 @@ sub handle_action {
} else { } else {
if ($action =~ m/^\/(?:say|me|msg)/i) { if ($action =~ m/^\/(?:say|me|msg)/i) {
return $action; return $action;
} elsif ($action =~ s/^\/kick\s+//) {
if (not exists $self->{factoids}->{hash}->{$channel}->{$keyword}->{'effective-level'}) {
$stuff->{authorized} = 0;
return "/say $stuff->{nick}: $trigger_name doesn't have the effective-level to do that.";
}
my $level = 10;
if ($self->{factoids}->{hash}->{$channel}->{$keyword}->{'effective-level'} >= $level) {
$stuff->{authorized} = 1;
return "/kick " . $action;
} else {
$stuff->{authorized} = 0;
return "/say $stuff->{nick}: My effective-level isn't high enough to do that.";
}
} else { } else {
return "/say $trigger_name is $action"; return "/say $trigger_name is $action";
} }

View File

@ -25,14 +25,10 @@ use warnings;
use strict; use strict;
use feature 'unicode_strings'; use feature 'unicode_strings';
use Carp (); use Carp ();
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
@ -41,7 +37,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to FactoidCommands"); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{commands}->register(sub { return $self->do_func(@_) }, 'func', 0); $self->{pbot}->{commands}->register(sub { return $self->do_func(@_) }, 'func', 0);
$self->init_funcs; $self->init_funcs;
} }

View File

@ -40,7 +40,6 @@ sub initialize {
sub load { sub load {
my $self = shift; my $self = shift;
my $filename; my $filename;
if (@_) { $filename = shift; } else { $filename = $self->{filename}; } if (@_) { $filename = shift; } else { $filename = $self->{filename}; }
if (not defined $filename) { if (not defined $filename) {
@ -85,7 +84,6 @@ sub load {
sub save { sub save {
my $self = shift; my $self = shift;
my $filename; my $filename;
if (@_) { $filename = shift; } else { $filename = $self->{filename}; } if (@_) { $filename = shift; } else { $filename = $self->{filename}; }
if (not defined $filename) { if (not defined $filename) {

View File

@ -20,12 +20,8 @@ use Data::Dumper;
$Data::Dumper::Sortkeys = 1; $Data::Dumper::Sortkeys = 1;
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -33,9 +29,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot parameter to " . __FILE__);
$self->{pbot} = delete $conf{pbot};
Carp::croak("Missing pbot parameter to " . __FILE__) if not defined $self->{pbot};
$self->{pbot}->{event_dispatcher}->register_handler('irc.welcome', sub { $self->on_connect(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.welcome', sub { $self->on_connect(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.disconnect', sub { $self->on_disconnect(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.disconnect', sub { $self->on_disconnect(@_) });

View File

@ -19,12 +19,8 @@ use Time::Duration;
use Carp (); use Carp ();
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to IgnoreListCommands should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -32,16 +28,9 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
my $pbot = delete $conf{pbot}; $self->{pbot}->{commands}->register(sub { $self->ignore_user(@_) }, "ignore", 1);
if (not defined $pbot) { $self->{pbot}->{commands}->register(sub { $self->unignore_user(@_) }, "unignore", 1);
Carp::croak("Missing pbot reference to IgnoreListCommands");
}
$self->{pbot} = $pbot;
$pbot->{commands}->register(sub { return $self->ignore_user(@_) }, "ignore", 10);
$pbot->{commands}->register(sub { return $self->unignore_user(@_) }, "unignore", 10);
} }
sub ignore_user { sub ignore_user {

View File

@ -23,10 +23,7 @@ use Carp ();
use PBot::Utils::ValidateString; use PBot::Utils::ValidateString;
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
@ -35,10 +32,8 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->SUPER::initialize(%conf); $self->SUPER::initialize(%conf);
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('text', 'general', 'compile_blocks', $conf{compile_blocks} // 1); $self->{pbot}->{registry}->add_default('text', 'general', 'compile_blocks', $conf{compile_blocks} // 1);
$self->{pbot}->{registry}->add_default('array', 'general', 'compile_blocks_channels', $conf{compile_blocks_channels} // '.*'); $self->{pbot}->{registry}->add_default('array', 'general', 'compile_blocks_channels', $conf{compile_blocks_channels} // '.*');
@ -174,8 +169,8 @@ sub process_line {
# check if user is ignored (and command isn't `login`) # check if user is ignored (and command isn't `login`)
if ($command !~ /^login / && defined $from && $pbot->{ignorelist}->check_ignore($nick, $user, $host, $from)) { if ($command !~ /^login / && defined $from && $pbot->{ignorelist}->check_ignore($nick, $user, $host, $from)) {
my $admin = $pbot->{users}->loggedin_admin($from, "$nick!$user\@$host"); my $admin = $pbot->{users}->loggedin_admin($from, "$nick!$user\@$host");
if (!defined $admin || $admin->{level} < 10) { if (!defined $admin) {
# hostmask ignored # user is ignored
return 1; return 1;
} }
} }
@ -791,7 +786,7 @@ sub handle_result {
$stuff->{prepend} = $1; $stuff->{prepend} = $1;
} }
if ($stuff->{pipe} and not $stuff->{authorized}) { if ($stuff->{pipe}) {
my ($pipe, $pipe_rest) = (delete $stuff->{pipe}, delete $stuff->{pipe_rest}); my ($pipe, $pipe_rest) = (delete $stuff->{pipe}, delete $stuff->{pipe_rest});
if (not $stuff->{alldone}) { if (not $stuff->{alldone}) {
$stuff->{command} = "$pipe $result $pipe_rest"; $stuff->{command} = "$pipe $result $pipe_rest";
@ -975,27 +970,6 @@ sub output_result {
$pbot->{conn}->privmsg($to, $line) if $to ne $botnick; $pbot->{conn}->privmsg($to, $line) if $to ne $botnick;
$pbot->{antiflood}->check_flood($to, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'pbot', $line, 0, 0, 0) if $stuff->{checkflood}; $pbot->{antiflood}->check_flood($to, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'pbot', $line, 0, 0, 0) if $stuff->{checkflood};
} }
} elsif ($stuff->{authorized} && $line =~ s/^\/kick\s+//) {
$pbot->{antiflood}->check_flood($stuff->{from}, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'pbot', '/kick ' . $line, 0, 0, 0) if $stuff->{checkflood};
my ($victim, $reason) = split /\s+/, $line, 2;
if (not defined $reason) {
if (open my $fh, '<', $self->{pbot}->{registry}->get_value('general', 'module_dir') . '/insults.txt') {
my @insults = <$fh>;
close $fh;
$reason = $insults[rand @insults];
chomp $reason;
} else {
$reason = 'Bye!';
}
}
if ($self->{pbot}->{chanops}->can_gain_ops($stuff->{from})) {
$self->{pbot}->{chanops}->add_op_command($stuff->{from}, "kick $stuff->{from} $victim $reason");
$self->{pbot}->{chanops}->gain_ops($stuff->{from});
} else {
$pbot->{conn}->privmsg($stuff->{from}, "$victim: $reason") if defined $stuff->{from} && $stuff->{from} ne $botnick;
}
} else { } else {
if (defined $stuff->{nickoverride} and ($stuff->{no_nickoverride} == 0 or $stuff->{force_nickoverride} == 1)) { if (defined $stuff->{nickoverride} and ($stuff->{no_nickoverride} == 0 or $stuff->{force_nickoverride} == 1)) {
$line = "$stuff->{nickoverride}: $line"; $line = "$stuff->{nickoverride}: $line";
@ -1087,9 +1061,9 @@ sub process_command_queue {
preserve_whitespace => 0 preserve_whitespace => 0
}; };
if (exists $command->{level}) { if (exists $command->{'cap-override'}) {
$self->{pbot}->{logger}->log("Override command effective-level to $command->{level}\n"); $self->{pbot}->{logger}->log("[command queue] Override command capability with $command->{'cap-override'}\n");
$stuff->{'effective-level'} = $command->{level}; $stuff->{'cap-override'} = $command->{'cap-override'};
} }
my $result = $self->interpret($stuff); my $result = $self->interpret($stuff);

View File

@ -30,7 +30,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to LagChecker"); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to LagChecker");
$self->{lag_average} = undef; # average of entries in lag history, in seconds $self->{lag_average} = undef; # average of entries in lag history, in seconds

View File

@ -14,45 +14,32 @@ use File::Basename;
use Carp (); use Carp ();
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to Logger should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to Logger should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class;
my $pbot = $conf{pbot} // Carp::croak "Missing pbot reference to " . __FILE__; $self->{pbot} = $conf{pbot} // Carp::croak "Missing pbot reference to " . __FILE__;
my $logfile = $conf{filename} // Carp::croak "Missing logfile parameter in " . __FILE__; $self->{logfile} = $conf{filename} // Carp::croak "Missing logfile parameter in " . __FILE__;
$self->{start} = time;
my $path = dirname $logfile; my $path = dirname $self->{logfile};
if (not -d $path) { if (not -d $path) {
print "Creating new logfile path: $path\n"; print "Creating new logfile path: $path\n";
mkdir $path or Carp::croak "Couldn't create logfile path: $!\n"; mkdir $path or Carp::croak "Couldn't create logfile path: $!\n";
} }
open LOGFILE, ">>$logfile" or Carp::croak "Couldn't open logfile $logfile: $!\n"; open LOGFILE, ">>$self->{logfile}" or Carp::croak "Couldn't open logfile $self->{logfile}: $!\n";
LOGFILE->autoflush(1); LOGFILE->autoflush(1);
my $self = bless {
logfile => $logfile,
pbot => $pbot,
start => time,
}, $class;
$self->{pbot}->{atexit}->register(sub { $self->rotate_log; return; }); $self->{pbot}->{atexit}->register(sub { $self->rotate_log; return; });
return $self; return $self;
} }
sub log { sub log {
my ($self, $text) = @_; my ($self, $text) = @_;
my $time = localtime; my $time = localtime;
$text =~ s/(\P{PosixGraph})/my $ch = $1; if ($ch =~ m{[\s]}) { $ch } else { sprintf "\\x%02X", ord $ch }/ge; $text =~ s/(\P{PosixGraph})/my $ch = $1; if ($ch =~ m{[\s]}) { $ch } else { sprintf "\\x%02X", ord $ch }/ge;
print LOGFILE "$time :: $text" if openhandle *LOGFILE;
if (openhandle *LOGFILE) {
print LOGFILE "$time :: $text";
}
print "$time :: $text"; print "$time :: $text";
} }

View File

@ -26,10 +26,7 @@ use Carp ();
use PBot::MessageHistory_SQLite; use PBot::MessageHistory_SQLite;
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
@ -38,8 +35,8 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{filename} = delete $conf{filename} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/message_history.sqlite3'; $self->{filename} = $conf{filename} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/message_history.sqlite3';
$self->{database} = PBot::MessageHistory_SQLite->new(pbot => $self->{pbot}, filename => $self->{filename}); $self->{database} = PBot::MessageHistory_SQLite->new(pbot => $self->{pbot}, filename => $self->{filename});
$self->{database}->begin(); $self->{database}->begin();
@ -55,9 +52,9 @@ sub initialize {
$self->{pbot}->{commands}->register(sub { $self->recall_message(@_) }, "recall", 0); $self->{pbot}->{commands}->register(sub { $self->recall_message(@_) }, "recall", 0);
$self->{pbot}->{commands}->register(sub { $self->list_also_known_as(@_) }, "aka", 0); $self->{pbot}->{commands}->register(sub { $self->list_also_known_as(@_) }, "aka", 0);
$self->{pbot}->{commands}->register(sub { $self->rebuild_aliases(@_) }, "rebuildaliases", 90); $self->{pbot}->{commands}->register(sub { $self->rebuild_aliases(@_) }, "rebuildaliases", 1);
$self->{pbot}->{commands}->register(sub { $self->aka_link(@_) }, "akalink", 60); $self->{pbot}->{commands}->register(sub { $self->aka_link(@_) }, "akalink", 1);
$self->{pbot}->{commands}->register(sub { $self->aka_unlink(@_) }, "akaunlink", 60); $self->{pbot}->{commands}->register(sub { $self->aka_unlink(@_) }, "akaunlink", 1);
$self->{pbot}->{atexit}->register(sub { $self->{database}->end(); return; }); $self->{pbot}->{atexit}->register(sub { $self->{database}->end(); return; });
} }

View File

@ -22,12 +22,8 @@ use Text::Levenshtein qw/fastdistance/;
use Time::Duration; use Time::Duration;
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -36,8 +32,8 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in " . __FILE__); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference in " . __FILE__);
$self->{filename} = delete $conf{filename} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/message_history.sqlite3'; $self->{filename} = $conf{filename} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/message_history.sqlite3';
$self->{new_entries} = 0; $self->{new_entries} = 0;
$self->{pbot}->{registry}->add_default('text', 'messagehistory', 'debug_link', 0); $self->{pbot}->{registry}->add_default('text', 'messagehistory', 'debug_link', 0);

View File

@ -32,10 +32,9 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{nicklist} = {};
$self->{nicklist} = {};
$self->{pbot}->{registry}->add_default('text', 'nicklist', 'debug', '0'); $self->{pbot}->{registry}->add_default('text', 'nicklist', 'debug', '0');
$self->{pbot}->{commands}->register(sub { $self->show_nicklist(@_) }, "nicklist", 0); $self->{pbot}->{commands}->register(sub { $self->show_nicklist(@_) }, "nicklist", 0);
@ -57,10 +56,7 @@ sub initialize {
sub show_nicklist { sub show_nicklist {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
my $nicklist; my $nicklist;
return "Usage: nicklist <channel> [nick]" if not length $arguments;
if (not length $arguments) {
return "Usage: nicklist <channel> [nick]";
}
my @args = split / /, $arguments; my @args = split / /, $arguments;
@ -77,7 +73,6 @@ sub show_nicklist {
} }
$nicklist = Dumper($self->{nicklist}->{lc $args[0]}->{lc $args[1]}); $nicklist = Dumper($self->{nicklist}->{lc $args[0]}->{lc $args[1]});
} }
return $nicklist; return $nicklist;
} }
@ -170,7 +165,6 @@ sub delete_meta {
or not exists $self->{nicklist}->{$channel}->{$nick}->{$key}) { or not exists $self->{nicklist}->{$channel}->{$nick}->{$key}) {
return undef; return undef;
} }
return delete $self->{nicklist}->{$channel}->{$nick}->{$key}; return delete $self->{nicklist}->{$channel}->{$nick}->{$key};
} }
@ -240,7 +234,6 @@ sub is_present_similar {
return $self->{nicklist}->{$channel}->{$person}->{nick}; return $self->{nicklist}->{$channel}->{$person}->{nick};
} }
} }
return 0; return 0;
} }
@ -290,7 +283,6 @@ sub on_namreply {
$self->set_meta($channel, $stripped_nick, '+h', 1); $self->set_meta($channel, $stripped_nick, '+h', 1);
} }
} }
return 0; return 0;
} }
@ -327,7 +319,6 @@ sub on_quit {
$self->remove_nick($channel, $nick); $self->remove_nick($channel, $nick);
} }
} }
return 0; return 0;
} }
@ -350,7 +341,6 @@ sub on_nickchange {
$self->{nicklist}->{$channel}->{lc $newnick} = $meta; $self->{nicklist}->{$channel}->{lc $newnick} = $meta;
} }
} }
return 0; return 0;
} }

View File

@ -49,10 +49,7 @@ use PBot::Utils::ParseDate;
use PBot::FuncCommand; use PBot::FuncCommand;
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to PBot should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to PBot should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->{atexit} = PBot::Registerable->new(%conf); $self->{atexit} = PBot::Registerable->new(%conf);
@ -63,7 +60,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{startup_timestamp} = time; $self->{startup_timestamp} = time;
my $data_dir = $conf{data_dir}; my $data_dir = $conf{data_dir};
@ -331,7 +327,7 @@ sub listcmd {
my ($from, $nick, $user, $host, $arguments) = @_; my ($from, $nick, $user, $host, $arguments) = @_;
my $text; my $text;
my $usage = "Usage: list <modules|commands|admins|users>"; my $usage = "Usage: list <modules|commands|users>";
if (not defined $arguments) { if (not defined $arguments) {
return $usage; return $usage;
@ -353,8 +349,11 @@ sub listcmd {
if ($arguments =~ /^commands$/i) { if ($arguments =~ /^commands$/i) {
$text = "Registered commands: "; $text = "Registered commands: ";
foreach my $command (sort { $a->{name} cmp $b->{name} } @{ $self->{commands}->{handlers} }) { foreach my $command (sort { $a->{name} cmp $b->{name} } @{ $self->{commands}->{handlers} }) {
$text .= "$command->{name} "; if ($command->{requires_cap}) {
$text .= "($command->{level}) " if $command->{level} > 0; $text .= "+$command->{name} ";
} else {
$text .= "$command->{name} ";
}
} }
return $text; return $text;
} }
@ -373,31 +372,17 @@ sub listcmd {
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} }) { 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 $hostmask eq '_name';
$text .= $sep; $text .= $sep;
my $has_cap = 0;
foreach my $key (keys %{$self->{users}->{users}->{hash}->{$channel}->{$hostmask}}) {
next if $key eq '_name';
if ($self->{capabilities}->exists($key)) {
print "has $key?\n";
$has_cap = 1;
last;
}
}
$text .= '+' if $has_cap;
$text .= $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{name}; $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 = " ";
}
$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 .= $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{name} . " (" . $self->{users}->{users}->{hash}->{$channel}->{$hostmask}->{level} . ")";
$sep = " "; $sep = " ";
} }
$sep = "; "; $sep = "; ";

View File

@ -18,12 +18,8 @@ use File::Basename;
use Carp (); use Carp ();
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -31,20 +27,16 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{plugins} = {}; $self->{plugins} = {};
$self->{pbot}->{commands}->register(sub { $self->load_cmd(@_) }, "plug", 1);
$self->{pbot}->{commands}->register(sub { $self->load_cmd(@_) }, "plug", 90); $self->{pbot}->{commands}->register(sub { $self->unload_cmd(@_) }, "unplug", 1);
$self->{pbot}->{commands}->register(sub { $self->unload_cmd(@_) }, "unplug", 90); $self->{pbot}->{commands}->register(sub { $self->reload_cmd(@_) }, "replug", 1);
$self->{pbot}->{commands}->register(sub { $self->reload_cmd(@_) }, "replug", 90); $self->{pbot}->{commands}->register(sub { $self->list_cmd(@_) }, "pluglist", 0);
$self->{pbot}->{commands}->register(sub { $self->list_cmd(@_) }, "pluglist", 0);
} }
sub autoload { sub autoload {
my ($self, %conf) = @_; my ($self, %conf) = @_;
return if $self->{pbot}->{registry}->get_value('plugins', 'noautoload'); return if $self->{pbot}->{registry}->get_value('plugins', 'noautoload');
my $path = $self->{pbot}->{registry}->get_value('general', 'plugin_dir') // 'Plugins'; my $path = $self->{pbot}->{registry}->get_value('general', 'plugin_dir') // 'Plugins';
@ -71,7 +63,6 @@ sub autoload {
$plugin_count++ if $self->load($plugin, %conf) $plugin_count++ if $self->load($plugin, %conf)
} }
$self->{pbot}->{logger}->log("$plugin_count plugin" . ($plugin_count == 1 ? '' : 's') . " loaded.\n"); $self->{pbot}->{logger}->log("$plugin_count plugin" . ($plugin_count == 1 ? '' : 's') . " loaded.\n");
} }
@ -112,7 +103,6 @@ sub load {
$self->{pbot}->{logger}->log("Error loading $plugin: $@\n"); $self->{pbot}->{logger}->log("Error loading $plugin: $@\n");
return 0; return 0;
} }
return $ret; return $ret;
} }
@ -189,7 +179,6 @@ sub unload_cmd {
sub list_cmd { sub list_cmd {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
my $result = "Loaded plugins: "; my $result = "Loaded plugins: ";
my $count = 0; my $count = 0;
my $comma = ''; my $comma = '';
@ -201,7 +190,6 @@ sub list_cmd {
} }
$result .= 'none' if $count == 0; $result .= 'none' if $count == 0;
return $result; return $result;
} }

View File

@ -22,10 +22,7 @@ use PBot::DualIndexHashObject;
use PBot::RegistryCommands; use PBot::RegistryCommands;
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be item/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be item/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
@ -34,15 +31,11 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
my $filename = $conf{filename} // Carp::croak("Missing filename reference in " . __FILE__); my $filename = $conf{filename} // Carp::croak("Missing filename reference in " . __FILE__);
$self->{registry} = PBot::DualIndexHashObject->new(name => 'Registry', filename => $filename, pbot => $self->{pbot}); $self->{registry} = PBot::DualIndexHashObject->new(name => 'Registry', filename => $filename, pbot => $self->{pbot});
$self->{triggers} = {}; $self->{triggers} = {};
$self->{pbot}->{atexit}->register(sub { $self->save; return; }); $self->{pbot}->{atexit}->register(sub { $self->save; return; });
PBot::RegistryCommands->new(pbot => $self->{pbot}); PBot::RegistryCommands->new(pbot => $self->{pbot});
} }
@ -107,7 +100,6 @@ sub remove {
if (not scalar keys %{ $self->{registry}->{hash}->{$section} }) { if (not scalar keys %{ $self->{registry}->{hash}->{$section} }) {
delete $self->{registry}->{hash}->{$section}; delete $self->{registry}->{hash}->{$section};
} }
$self->save; $self->save;
} }
@ -139,7 +131,6 @@ sub set {
} }
$self->save if !$dont_save && $result =~ m/set to/ && not $is_default; $self->save if !$dont_save && $result =~ m/set to/ && not $is_default;
return $result; return $result;
} }

View File

@ -17,10 +17,7 @@ use feature 'unicode_strings';
use Carp (); use Carp ();
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
@ -29,23 +26,19 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
my $pbot = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot}->{commands}->register(sub { $self->regset(@_) }, "regset", 1);
$self->{pbot} = $pbot; $self->{pbot}->{commands}->register(sub { $self->regunset(@_) }, "regunset", 1);
$self->{pbot}->{commands}->register(sub { $self->regshow(@_) }, "regshow", 0);
$pbot->{commands}->register(sub { return $self->regset(@_) }, "regset", 60); $self->{pbot}->{commands}->register(sub { $self->regsetmeta(@_) }, "regsetmeta", 1);
$pbot->{commands}->register(sub { return $self->regunset(@_) }, "regunset", 60); $self->{pbot}->{commands}->register(sub { $self->regunsetmeta(@_) }, "regunsetmeta", 1);
$pbot->{commands}->register(sub { return $self->regshow(@_) }, "regshow", 0); $self->{pbot}->{commands}->register(sub { $self->regchange(@_) }, "regchange", 1);
$pbot->{commands}->register(sub { return $self->regsetmeta(@_) }, "regsetmeta", 60); $self->{pbot}->{commands}->register(sub { $self->regfind(@_) }, "regfind", 0);
$pbot->{commands}->register(sub { return $self->regunsetmeta(@_) }, "regunsetmeta", 60);
$pbot->{commands}->register(sub { return $self->regchange(@_) }, "regchange", 60);
$pbot->{commands}->register(sub { return $self->regfind(@_) }, "regfind", 0);
} }
sub regset { sub regset {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $arguments, $stuff) = @_; my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
my $usage = "Usage: regset <section>.<item> <value>"; my $usage = "Usage: regset <section>.<item> <value>";
# support "<section>.<key>" syntax in addition to "<section> <key>" # support "<section>.<key>" syntax in addition to "<section> <key>"
@ -71,7 +64,6 @@ sub regset {
sub regunset { sub regunset {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $arguments, $stuff) = @_; my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
my $usage = "Usage: regunset <section>.<item>"; my $usage = "Usage: regunset <section>.<item>";
# support "<section>.<key>" syntax in addition to "<section> <key>" # support "<section>.<key>" syntax in addition to "<section> <key>"
@ -106,7 +98,6 @@ sub regunset {
sub regsetmeta { sub regsetmeta {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $arguments, $stuff) = @_; my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
my $usage = "Usage: regsetmeta <section>.<item> [key [value]]"; my $usage = "Usage: regsetmeta <section>.<item> [key [value]]";
# support "<section>.<key>" syntax in addition to "<section> <key>" # support "<section>.<key>" syntax in addition to "<section> <key>"
@ -125,14 +116,12 @@ sub regsetmeta {
$key = undef if not length $key; $key = undef if not length $key;
$value = undef if not length $value; $value = undef if not length $value;
return $self->{pbot}->{registry}->set($section, $item, $key, $value); return $self->{pbot}->{registry}->set($section, $item, $key, $value);
} }
sub regunsetmeta { sub regunsetmeta {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $arguments, $stuff) = @_; my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
my $usage = "Usage: regunsetmeta <section>.<item> <key>"; my $usage = "Usage: regunsetmeta <section>.<item> <key>";
# support "<section>.<key>" syntax in addition to "<section> <key>" # support "<section>.<key>" syntax in addition to "<section> <key>"
@ -148,7 +137,6 @@ sub regunsetmeta {
if (not defined $section or not defined $item or not defined $key) { if (not defined $section or not defined $item or not defined $key) {
return $usage; return $usage;
} }
return $self->{pbot}->{registry}->unset($section, $item, $key); return $self->{pbot}->{registry}->unset($section, $item, $key);
} }
@ -156,7 +144,6 @@ sub regshow {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $arguments, $stuff) = @_; my ($from, $nick, $user, $host, $arguments, $stuff) = @_;
my $registry = $self->{pbot}->{registry}->{registry}->{hash}; my $registry = $self->{pbot}->{registry}->{registry}->{hash};
my $usage = "Usage: regshow <section>.<item>"; my $usage = "Usage: regshow <section>.<item>";
# support "<section>.<key>" syntax in addition to "<section> <key>" # support "<section>.<key>" syntax in addition to "<section> <key>"
@ -192,7 +179,6 @@ sub regshow {
if ($registry->{$section}->{$item}->{type} eq 'array') { if ($registry->{$section}->{$item}->{type} eq 'array') {
$result .= ' [array]'; $result .= ' [array]';
} }
return $result; return $result;
} }
@ -200,15 +186,11 @@ sub regfind {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $arguments) = @_; my ($from, $nick, $user, $host, $arguments) = @_;
my $registry = $self->{pbot}->{registry}->{registry}->{hash}; my $registry = $self->{pbot}->{registry}->{registry}->{hash};
my $usage = "Usage: regfind [-showvalues] [-section section] <regex>"; my $usage = "Usage: regfind [-showvalues] [-section section] <regex>";
if (not defined $arguments) { return $usage if not defined $arguments;
return $usage;
}
my ($section, $showvalues); my ($section, $showvalues);
$section = $1 if $arguments =~ s/-section\s+([^\b\s]+)//i; $section = $1 if $arguments =~ s/-section\s+([^\b\s]+)//i;
$showvalues = 1 if $arguments =~ s/-showvalues?//i; $showvalues = 1 if $arguments =~ s/-showvalues?//i;
@ -216,9 +198,7 @@ sub regfind {
$arguments =~ s/\s+$//; $arguments =~ s/\s+$//;
$arguments =~ s/\s+/ /g; $arguments =~ s/\s+/ /g;
if ($arguments eq "") { return $usage if $arguments eq "";
return $usage;
}
$section = lc $section if defined $section;; $section = lc $section if defined $section;;

View File

@ -13,12 +13,8 @@ use IO::Select;
use Carp (); use Carp ();
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to SelectHandler should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to SelectHandler should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -26,8 +22,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference in SelectHandler");
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in SelectHandler");
$self->{select} = IO::Select->new(); $self->{select} = IO::Select->new();
$self->{readers} = {}; $self->{readers} = {};
$self->{buffers} = {}; $self->{buffers} = {};

View File

@ -22,7 +22,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference in StdinReader"); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference in StdinReader");
# create implicit bot-admin account for bot # create implicit bot-admin account for bot
@ -61,7 +60,6 @@ sub stdin_reader {
$from = $self->{pbot}->{registry}->get_value('irc', 'botnick') . "!stdin\@pbot"; $from = $self->{pbot}->{registry}->get_value('irc', 'botnick') . "!stdin\@pbot";
$text = $self->{pbot}->{registry}->get_value('irc', 'botnick') . " $input"; $text = $self->{pbot}->{registry}->get_value('irc', 'botnick') . " $input";
} }
return $self->{pbot}->{interpreter}->process_line($from, $self->{pbot}->{registry}->get_value('irc', 'botnick'), "stdin", "pbot", $text); return $self->{pbot}->{interpreter}->process_line($from, $self->{pbot}->{registry}->get_value('irc', 'botnick'), "stdin", "pbot", $text);
} }

View File

@ -27,8 +27,6 @@ $SIG{ALRM} = sub {
$seconds += $min_timeout; $seconds += $min_timeout;
alarm $min_timeout; alarm $min_timeout;
# print "ALARM! $seconds $min_timeout\n";
# call timer func subroutines # call timer func subroutines
foreach my $func (@timer_funcs) { &$func; } foreach my $func (@timer_funcs) { &$func; }

View File

@ -27,9 +27,9 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $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->{users} = PBot::DualIndexHashObject->new(name => 'Users', filename => $conf{filename}, pbot => $conf{pbot});
$self->load; $self->load;
$self->{pbot}->{commands}->register(sub { return $self->logincmd(@_) }, "login", 0); $self->{pbot}->{commands}->register(sub { return $self->logincmd(@_) }, "login", 0);
@ -74,7 +74,7 @@ sub on_join {
} }
if ($u->{autologin}) { if ($u->{autologin}) {
$self->{pbot}->{logger}->log("$nick!$user\@$host autologin to $u->{name} ($u->{level}) for $channel\n"); $self->{pbot}->{logger}->log("$nick!$user\@$host autologin to $u->{name} for $channel\n");
$u->{loggedin} = 1; $u->{loggedin} = 1;
} }
} }
@ -82,19 +82,23 @@ sub on_join {
} }
sub add_user { sub add_user {
my ($self, $name, $channel, $hostmask, $level, $password, $dont_save) = @_; my ($self, $name, $channel, $hostmask, $capabilities, $password, $dont_save) = @_;
$channel = '.*' if $channel !~ m/^#/; $channel = '.*' if $channel !~ m/^#/;
$level //= 0; $capabilities //= 'none';
$password //= $self->{pbot}->random_nick(16); $password //= $self->{pbot}->random_nick(16);
my $data = { my $data = {
name => $name, name => $name,
level => $level,
password => $password password => $password
}; };
$self->{pbot}->{logger}->log("Adding new user (level $level): name: $name hostmask: $hostmask channel: $channel\n"); foreach my $cap (split /\s*,\s*/, $capabilities) {
next if $cap eq 'none';
$data->{$cap} = 1;
}
$self->{pbot}->{logger}->log("Adding new user (caps: $capabilities): name: $name hostmask: $hostmask channel: $channel\n");
$self->{users}->add($channel, $hostmask, $data, $dont_save); $self->{users}->add($channel, $hostmask, $data, $dont_save);
return $data; return $data;
} }
@ -123,10 +127,9 @@ sub load {
next if $hostmask eq '_name'; next if $hostmask eq '_name';
$i++; $i++;
my $name = $self->{users}->{hash}->{$channel}->{$hostmask}->{name}; my $name = $self->{users}->{hash}->{$channel}->{$hostmask}->{name};
my $level = $self->{users}->{hash}->{$channel}->{$hostmask}->{level};
my $password = $self->{users}->{hash}->{$channel}->{$hostmask}->{password}; my $password = $self->{users}->{hash}->{$channel}->{$hostmask}->{password};
if (not defined $name or not defined $level or not defined $password) { if (not defined $name or not defined $password) {
Carp::croak "A user in $filename is missing critical data\n"; Carp::croak "A user in $filename is missing critical data\n";
} }
} }
@ -150,16 +153,13 @@ sub find_user_account {
foreach my $chan (keys %{ $self->{users}->{hash} }) { foreach my $chan (keys %{ $self->{users}->{hash} }) {
if ($channel !~ m/^#/ or $channel =~ m/^$chan$/i) { if ($channel !~ m/^#/ or $channel =~ m/^$chan$/i) {
if (not exists $self->{users}->{hash}->{$chan}->{$hostmask}) { if (not exists $self->{users}->{hash}->{$chan}->{$hostmask}) {
my $last_level = 0;
# find hostmask by account name or wildcard # find hostmask by account name or wildcard
foreach my $mask (keys %{ $self->{users}->{hash}->{$chan} }) { foreach my $mask (keys %{ $self->{users}->{hash}->{$chan} }) {
next if $mask eq '_name'; next if $mask eq '_name';
if (lc $self->{users}->{hash}->{$chan}->{$mask}->{name} eq $hostmask) { if (lc $self->{users}->{hash}->{$chan}->{$mask}->{name} eq $hostmask) {
if ($last_level <= $self->{users}->{hash}->{$chan}->{$mask}->{level}) { $found_hostmask = $mask;
$found_hostmask = $mask; $found_channel = $chan;
$found_channel = $chan; last;
$last_level = $self->{users}->{hash}->{$chan}->{$mask}->{level};
}
} }
if ($mask =~ /[*?]/) { if ($mask =~ /[*?]/) {
@ -168,26 +168,23 @@ sub find_user_account {
$mask_quoted =~ s/\\\*/.*?/g; $mask_quoted =~ s/\\\*/.*?/g;
$mask_quoted =~ s/\\\?/./g; $mask_quoted =~ s/\\\?/./g;
if ($hostmask =~ m/^$mask_quoted$/i) { if ($hostmask =~ m/^$mask_quoted$/i) {
if ($last_level <= $self->{users}->{hash}->{$chan}->{$mask}->{level}) { $found_hostmask = $mask;
$found_hostmask = $mask; $found_channel = $chan;
$found_channel = $chan; last;
$last_level = $self->{users}->{hash}->{$chan}->{$mask}->{level};
}
} }
} }
} }
} else { } else {
$found_channel = $chan; $found_channel = $chan;
last;
} }
} }
} }
return ($found_channel, $found_hostmask); return ($found_channel, $found_hostmask);
} }
sub find_admin { sub find_user {
my ($self, $channel, $hostmask, $min_level) = @_; my ($self, $channel, $hostmask) = @_;
$min_level //= 1;
($channel, $hostmask) = $self->find_user_account($channel, $hostmask); ($channel, $hostmask) = $self->find_user_account($channel, $hostmask);
$channel = '.*' if not defined $channel; $channel = '.*' if not defined $channel;
@ -195,7 +192,7 @@ sub find_admin {
$hostmask = lc $hostmask; $hostmask = lc $hostmask;
my $result = eval { my $result = eval {
my $admin; my $user;
foreach my $channel_regex (keys %{ $self->{users}->{hash} }) { foreach my $channel_regex (keys %{ $self->{users}->{hash} }) {
if ($channel !~ m/^#/ or $channel =~ m/^$channel_regex$/i) { if ($channel !~ m/^#/ or $channel =~ m/^$channel_regex$/i) {
foreach my $hostmask_regex (keys %{ $self->{users}->{hash}->{$channel_regex} }) { foreach my $hostmask_regex (keys %{ $self->{users}->{hash}->{$channel_regex} }) {
@ -206,51 +203,45 @@ sub find_admin {
$hostmask_quoted =~ s/\\\*/.*?/g; $hostmask_quoted =~ s/\\\*/.*?/g;
$hostmask_quoted =~ s/\\\?/./g; $hostmask_quoted =~ s/\\\?/./g;
if ($hostmask =~ m/^$hostmask_quoted$/i) { if ($hostmask =~ m/^$hostmask_quoted$/i) {
my $temp = $self->{users}->{hash}->{$channel_regex}->{$hostmask_regex}; return $self->{users}->{hash}->{$channel_regex}->{$hostmask_regex};
$admin = $temp if $temp->{level} >= $min_level and (not defined $admin or $admin->{level} <= $temp->{level});
} }
} else { } else {
# direct comparison # direct comparison
if ($hostmask eq lc $hostmask_regex) { if ($hostmask eq lc $hostmask_regex) {
my $temp = $self->{users}->{hash}->{$channel_regex}->{$hostmask_regex}; return $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; return undef;
}; };
if ($@) { if ($@) {
$self->{pbot}->{logger}->log("Error in find_admin parameters: $@\n"); $self->{pbot}->{logger}->log("Error in find_user parameters: $@\n");
} }
return $result; return $result;
} }
sub find_user { sub find_admin {
my ($self, $from, $hostmask) = @_; my ($self, $from, $hostmask) = @_;
return $self->find_admin($from, $hostmask, 0); my $user = $self->find_user($from, $hostmask);
return undef if not defined $user;
return undef if not $self->{pbot}->{capabilities}->userhas($user, 'admin');
return $user;
} }
sub loggedin { sub loggedin {
my ($self, $channel, $hostmask) = @_; my ($self, $channel, $hostmask) = @_;
my $user = $self->find_user($channel, $hostmask); my $user = $self->find_user($channel, $hostmask);
return $user if defined $user and $user->{loggedin};
if (defined $user and $user->{loggedin}) {
return $user;
}
return undef; return undef;
} }
sub loggedin_admin { sub loggedin_admin {
my ($self, $channel, $hostmask) = @_; my ($self, $channel, $hostmask) = @_;
my $user = $self->loggedin($channel, $hostmask); my $user = $self->loggedin($channel, $hostmask);
return $user if defined $user and $self->{pbot}->{capabilities}->userhas($user, 'admin');
if (defined $user and $user->{level} > 0) {
return $user;
}
return undef; return undef;
} }
@ -293,9 +284,7 @@ sub logincmd {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
my $channel = $from; my $channel = $from;
if (not $arguments) { return "Usage: login [channel] password" if not $arguments;
return "Usage: login [channel] password";
}
if ($arguments =~ m/^([^ ]+)\s+(.+)/) { if ($arguments =~ m/^([^ ]+)\s+(.+)/) {
$channel = $1; $channel = $1;
@ -303,10 +292,7 @@ sub logincmd {
} }
my ($user_channel, $user_hostmask) = $self->find_user_account($channel, "$nick!$user\@$host"); my ($user_channel, $user_hostmask) = $self->find_user_account($channel, "$nick!$user\@$host");
return "/msg $nick You do not have a user account." if not defined $user_channel;
if (not defined $user_channel) {
return "/msg $nick You do not have a user account.";
}
my $u = $self->{users}->{hash}->{$user_channel}->{$user_hostmask}; my $u = $self->{users}->{hash}->{$user_channel}->{$user_hostmask};
my $channel_text = $user_channel eq '.*' ? '' : " for $user_channel"; my $channel_text = $user_channel eq '.*' ? '' : " for $user_channel";
@ -343,29 +329,35 @@ sub logoutcmd {
sub useradd { sub useradd {
my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_; my ($self, $from, $nick, $user, $host, $arguments, $stuff) = @_;
my ($name, $channel, $hostmask, $level, $password) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 5); my ($name, $channel, $hostmask, $capabilities, $password) = $self->{pbot}->{interpreter}->split_args($stuff->{arglist}, 5);
$level //= 0; $capabilities //= 'none';
if (not defined $name or not defined $channel or not defined $hostmask) { if (not defined $name or not defined $channel or not defined $hostmask) {
return "Usage: useradd <account name> <channel> <hostmask> [level [password]]"; return "Usage: useradd <account name> <channel> <hostmask> [capabilities [password]]";
} }
$channel = '.*' if $channel !~ /^#/; $channel = '.*' if $channel !~ /^#/;
my $admin = $self->{pbot}->{users}->find_admin($channel, "$nick!$user\@$host"); my $u = $self->{pbot}->{users}->find_user($channel, "$nick!$user\@$host");
if (not $admin) { if (not defined $u) {
$channel = 'global' if $channel eq '.*'; $channel = 'global' if $channel eq '.*';
return "You are not an admin for $channel; cannot add users to that channel.\n"; return "You do not have a user account for $channel; cannot add users to that channel.\n";
} }
# don't allow non-bot-owners to add admins that can also add admins if ($capabilities ne 'none' and not $self->{pbot}->{capabilities}->userhas($u, 'can-modify-capabilities')) {
if ($admin->{level} < 90 and $level > 40) { return "Your user account does not have the can-modify-capabilities capability. You cannot create user accounts with capabilities.";
return "You may not set admin level higher than 40.\n";
} }
$self->{pbot}->{users}->add_user($name, $channel, $hostmask, $level, $password); foreach my $cap (split /\s*,\s*/, $capabilities) {
return !$level ? "User added." : "Admin added."; next if $cap eq 'none';
return "There is no such capability $cap." if not $self->{pbot}->{capabilities}->exists($cap);
if (not $self->{pbot}->{capabilities}->userhas($u, $cap)) {
return "To set the $cap capability your user account must also have it.";
}
}
$self->{pbot}->{users}->add_user($name, $channel, $hostmask, $capabilities, $password);
return "User added.";
} }
sub userdel { sub userdel {
@ -395,12 +387,12 @@ sub userset {
return "Usage: userset [channel] <hostmask or account name> [key [value]]"; return "Usage: userset [channel] <hostmask or account name> [key [value]]";
} }
my $admin = $self->find_admin($channel, "$nick!$user\@$host"); my $u = $self->find_user($channel, "$nick!$user\@$host");
my $target = $self->find_user($channel, $hostmask); my $target = $self->find_user($channel, $hostmask);
if (not $admin) { if (not $u) {
$channel = 'global' if $channel eq '.*'; $channel = 'global' if $channel eq '.*';
return "You are not an admin for $channel; cannot modify their users."; return "You do not have a user account for $channel; cannot modify their users.";
} }
if (not $target) { if (not $target) {
@ -411,13 +403,14 @@ sub userset {
} }
} }
# don't allow non-bot-owners to add admins that can also add admins if (defined $value and not $self->{pbot}->{capabilities}->userhas($u, 'can-modify-capabilities')) {
if (defined $key and $key eq 'level' and $admin->{level} < 90 and $value > 40) { if ($key =~ m/^can-/i or $self->{pbot}->{capabilities}->exists($key)) {
return "You may not set user level higher than 40.\n"; return "The $key metadata requires the can-modify-capabilities capability, which your user account does not have.";
}
} }
if (defined $key and $target->{level} > $admin->{level}) { if ($self->{pbot}->{capabilities}->exists($key) and not $self->{pbot}->{capabilities}->userhas($u, $key)) {
return "You may not modify users higher in level than you."; return "To set the $key capability your user account must also have it.";
} }
my ($found_channel, $found_hostmask) = $self->find_user_account($channel, $hostmask); my ($found_channel, $found_hostmask) = $self->find_user_account($channel, $hostmask);
@ -440,12 +433,12 @@ sub userunset {
return "Usage: userunset [channel] <hostmask or account name> <key>"; return "Usage: userunset [channel] <hostmask or account name> <key>";
} }
my $admin = $self->find_admin($channel, "$nick!$user\@$host"); my $u = $self->find_admin($channel, "$nick!$user\@$host");
my $target = $self->find_user($channel, $hostmask); my $target = $self->find_user($channel, $hostmask);
if (not $admin) { if (not $u) {
$channel = 'global' if $channel eq '.*'; $channel = 'global' if $channel eq '.*';
return "You are not an admin for $channel; cannot modify their users."; return "You do not have a user account for $channel; cannot modify their users.";
} }
if (not $target) { if (not $target) {
@ -456,8 +449,14 @@ sub userunset {
} }
} }
if ($target->{level} > $admin->{level}) { if (defined $key and not $self->{pbot}->{capabilities}->userhas($u, 'can-modify-capabilities')) {
return "You may not modify users higher in level than you."; if ($key =~ m/^can-/i or $self->{pbot}->{capabilities}->exists($key)) {
return "The $key metadata requires the can-modify-capabilities capability, which your user account does not have.";
}
}
if (defined $key and $self->{pbot}->{capabilities}->exists($key) and not $self->{pbot}->{capabilities}->userhas($u, $key)) {
return "To unset the $key capability your user account must also have it.";
} }
my ($found_channel, $found_hostmask) = $self->find_user_account($channel, $hostmask); my ($found_channel, $found_hostmask) = $self->find_user_account($channel, $hostmask);

View File

@ -78,7 +78,6 @@ sub version_cmd {
if ($self->{last_check}->{version} > BUILD_REVISION) { if ($self->{last_check}->{version} > BUILD_REVISION) {
$result .= "; new version available: $self->{last_check}->{version} $self->{last_check}->{date}!"; $result .= "; new version available: $self->{last_check}->{version} $self->{last_check}->{date}!";
} }
return $result; return $result;
} }

View File

@ -26,8 +26,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('text', 'antiaway', 'bad_nicks', $conf{bad_nicks} // '([[:punct:]](afk|brb|bbl|away|sleep|z+|work|gone|study|out|home|busy|off)[[:punct:]]*$|.+\[.*\]$)'); $self->{pbot}->{registry}->add_default('text', 'antiaway', 'bad_nicks', $conf{bad_nicks} // '([[:punct:]](afk|brb|bbl|away|sleep|z+|work|gone|study|out|home|busy|off)[[:punct:]]*$|.+\[.*\]$)');
$self->{pbot}->{registry}->add_default('text', 'antiaway', 'bad_actions', $conf{bad_actions} // '^/me (is (away|gone)|.*auto.?away)'); $self->{pbot}->{registry}->add_default('text', 'antiaway', 'bad_actions', $conf{bad_actions} // '^/me (is (away|gone)|.*auto.?away)');
@ -52,7 +51,6 @@ sub on_nickchange {
$self->{pbot}->{chanops}->gain_ops($chan); $self->{pbot}->{chanops}->gain_ops($chan);
} }
} }
return 0; return 0;
} }
@ -70,7 +68,6 @@ sub on_action {
$self->{pbot}->{chanops}->add_op_command($channel, "kick $channel $nick $kick_msg"); $self->{pbot}->{chanops}->add_op_command($channel, "kick $channel $nick $kick_msg");
$self->{pbot}->{chanops}->gain_ops($channel); $self->{pbot}->{chanops}->gain_ops($channel);
} }
return 0; return 0;
} }

View File

@ -28,7 +28,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('array', 'antikickautorejoin', 'punishment', '300,900,1800,3600,28800'); $self->{pbot}->{registry}->add_default('array', 'antikickautorejoin', 'punishment', '300,900,1800,3600,28800');
@ -36,7 +35,6 @@ sub initialize {
$self->{pbot}->{event_dispatcher}->register_handler('irc.kick', sub { $self->on_kick(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.kick', sub { $self->on_kick(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.join', sub { $self->on_join(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.join', sub { $self->on_join(@_) });
$self->{kicks} = {}; $self->{kicks} = {};
} }
@ -54,7 +52,6 @@ sub on_kick {
} }
$self->{kicks}->{$channel}->{$target}->{last_kick} = gettimeofday; $self->{kicks}->{$channel}->{$target}->{last_kick} = gettimeofday;
return 0; return 0;
} }
@ -82,7 +79,6 @@ sub on_join {
$self->{kicks}->{$channel}->{$nick}->{rejoins}++; $self->{kicks}->{$channel}->{$nick}->{rejoins}++;
} }
} }
return 0; return 0;
} }

View File

@ -30,10 +30,8 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.caction', sub { $self->on_action(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.caction', sub { $self->on_action(@_) });
$self->{nicks} = {}; $self->{nicks} = {};
} }
@ -98,7 +96,6 @@ sub clear_old_nicks {
last; last;
} }
} }
delete $self->{nicks}->{$channel} if not @{$self->{nicks}->{$channel}}; delete $self->{nicks}->{$channel} if not @{$self->{nicks}->{$channel}};
} }

View File

@ -28,7 +28,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('text', 'antiflood', 'antirepeat', $conf{antirepeat} // 1); $self->{pbot}->{registry}->add_default('text', 'antiflood', 'antirepeat', $conf{antirepeat} // 1);
@ -40,17 +39,11 @@ sub initialize {
$self->{pbot}->{event_dispatcher}->register_handler('irc.caction', sub { $self->on_public(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.caction', sub { $self->on_public(@_) });
$self->{pbot}->{timer}->register(sub { $self->adjust_offenses }, 60 * 60 * 1, 'antirepeat'); $self->{pbot}->{timer}->register(sub { $self->adjust_offenses }, 60 * 60 * 1, 'antirepeat');
$self->{offenses} = {}; $self->{offenses} = {};
} }
sub unload { sub unload {
my $self = shift; my $self = shift;
# perform plugin clean-up here
# normally we'd unregister the 'irc.public' event handler; however, the
# event dispatcher will do this automatically for us when it sees there
# is no longer an existing sub.
$self->{pbot}->{timer}->unregister('antirepeat'); $self->{pbot}->{timer}->unregister('antirepeat');
} }
@ -161,7 +154,6 @@ sub on_public {
return 0; return 0;
} }
} }
return 0; return 0;
} }

View File

@ -28,20 +28,17 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('array', 'autorejoin', 'rejoin_delay', '900,1800,3600'); $self->{pbot}->{registry}->add_default('array', 'autorejoin', 'rejoin_delay', '900,1800,3600');
$self->{pbot}->{event_dispatcher}->register_handler('irc.kick', sub { $self->on_kick(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.kick', sub { $self->on_kick(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.part', sub { $self->on_part(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.part', sub { $self->on_part(@_) });
$self->{rejoins} = {}; $self->{rejoins} = {};
} }
sub rejoin_channel { sub rejoin_channel {
my ($self, $channel) = @_; my ($self, $channel) = @_;
$self->{rejoins}->{$channel}->{rejoins} = 0 if not exists $self->{rejoins}->{$channel}; $self->{rejoins}->{$channel}->{rejoins} = 0 if not exists $self->{rejoins}->{$channel};
my $delay = $self->{pbot}->{registry}->get_array_value($channel, 'rejoin_delay', $self->{rejoins}->{$channel}->{rejoins}); my $delay = $self->{pbot}->{registry}->get_array_value($channel, 'rejoin_delay', $self->{rejoins}->{$channel}->{rejoins});
@ -51,8 +48,6 @@ sub rejoin_channel {
$delay = duration $delay; $delay = duration $delay;
$self->{pbot}->{logger}->log("Rejoining $channel in $delay.\n"); $self->{pbot}->{logger}->log("Rejoining $channel in $delay.\n");
#$self->{rejoins}->{$channel}->{rejoins}++;
$self->{rejoins}->{$channel}->{last_rejoin} = gettimeofday; $self->{rejoins}->{$channel}->{last_rejoin} = gettimeofday;
} }
@ -66,7 +61,6 @@ sub on_kick {
if ($target eq $self->{pbot}->{registry}->get_value('irc', 'botnick')) { if ($target eq $self->{pbot}->{registry}->get_value('irc', 'botnick')) {
$self->rejoin_channel($channel); $self->rejoin_channel($channel);
} }
return 0; return 0;
} }
@ -80,7 +74,6 @@ sub on_part {
if ($nick eq $self->{pbot}->{registry}->get_value('irc', 'botnick')) { if ($nick eq $self->{pbot}->{registry}->get_value('irc', 'botnick')) {
$self->rejoin_channel($channel); $self->rejoin_channel($channel);
} }
return 0; return 0;
} }

View File

@ -29,7 +29,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{commands}->register(sub { $self->battleship_cmd(@_) }, 'battleship', 0); $self->{pbot}->{commands}->register(sub { $self->battleship_cmd(@_) }, 'battleship', 0);

View File

@ -29,7 +29,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot}; $self->{pbot} = $conf{pbot};
$self->{pbot}->{commands}->register(sub { $self->connect4_cmd(@_) }, 'connect4', 0); $self->{pbot}->{commands}->register(sub { $self->connect4_cmd(@_) }, 'connect4', 0);

View File

@ -27,7 +27,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{commands}->register(sub { $self->counteradd(@_) }, 'counteradd', 0); $self->{pbot}->{commands}->register(sub { $self->counteradd(@_) }, 'counteradd', 0);
@ -40,7 +39,6 @@ sub initialize {
$self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) });
$self->{filename} = $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/counters.sqlite3'; $self->{filename} = $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/counters.sqlite3';
$self->create_database; $self->create_database;
} }
@ -130,7 +128,6 @@ sub add_counter {
$self->{pbot}->{logger}->log("Add counter failed: $@"); $self->{pbot}->{logger}->log("Add counter failed: $@");
return 0; return 0;
} }
return 1; return 1;
} }
@ -155,7 +152,6 @@ sub reset_counter {
$self->{pbot}->{logger}->log("Reset counter failed: $@"); $self->{pbot}->{logger}->log("Reset counter failed: $@");
return (undef, undef); return (undef, undef);
} }
return ($description, $timestamp); return ($description, $timestamp);
} }
@ -179,7 +175,6 @@ sub delete_counter {
$self->{pbot}->{logger}->log("Delete counter failed: $@"); $self->{pbot}->{logger}->log("Delete counter failed: $@");
return 0; return 0;
} }
return 1; return 1;
} }
@ -196,7 +191,6 @@ sub list_counters {
if ($@) { if ($@) {
$self->{pbot}->{logger}->log("List counters failed: $@"); $self->{pbot}->{logger}->log("List counters failed: $@");
} }
return map { $_->[0] } @$counters; return map { $_->[0] } @$counters;
} }
@ -216,7 +210,6 @@ sub get_counter {
$self->{pbot}->{logger}->log("Get counter failed: $@"); $self->{pbot}->{logger}->log("Get counter failed: $@");
return undef; return undef;
} }
return ($description, $time, $counter, $created_on, $created_by); return ($description, $time, $counter, $created_on, $created_by);
} }
@ -240,7 +233,6 @@ sub add_trigger {
$self->{pbot}->{logger}->log("Add trigger failed: $@"); $self->{pbot}->{logger}->log("Add trigger failed: $@");
return 0; return 0;
} }
return 1; return 1;
} }
@ -256,7 +248,6 @@ sub delete_trigger {
$sth->bind_param(1, lc $channel); $sth->bind_param(1, lc $channel);
$sth->bind_param(2, lc $trigger); $sth->bind_param(2, lc $trigger);
$sth->execute(); $sth->execute();
return 1; return 1;
} }
@ -273,7 +264,6 @@ sub list_triggers {
if ($@) { if ($@) {
$self->{pbot}->{logger}->log("List triggers failed: $@"); $self->{pbot}->{logger}->log("List triggers failed: $@");
} }
return @$triggers; return @$triggers;
} }
@ -293,17 +283,12 @@ sub get_trigger {
$self->{pbot}->{logger}->log("Get trigger failed: $@"); $self->{pbot}->{logger}->log("Get trigger failed: $@");
return undef; return undef;
} }
return $target; return $target;
} }
sub counteradd { sub counteradd {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
return "Internal error." if not $self->dbi_begin;
if (not $self->dbi_begin) {
return "Internal error.";
}
my ($channel, $name, $description); my ($channel, $name, $description);
if ($from !~ m/^#/) { if ($from !~ m/^#/) {
@ -325,18 +310,13 @@ sub counteradd {
} else { } else {
$result = "Counter '$name' already exists."; $result = "Counter '$name' already exists.";
} }
$self->dbi_end; $self->dbi_end;
return $result; return $result;
} }
sub counterdel { sub counterdel {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
return "Internal error." if not $self->dbi_begin;
if (not $self->dbi_begin) {
return "Internal error.";
}
my ($channel, $name); my ($channel, $name);
if ($from !~ m/^#/) { if ($from !~ m/^#/) {
@ -358,18 +338,13 @@ sub counterdel {
} else { } else {
$result = "No such counter."; $result = "No such counter.";
} }
$self->dbi_end; $self->dbi_end;
return $result; return $result;
} }
sub counterreset { sub counterreset {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
return "Internal error." if not $self->dbi_begin;
if (not $self->dbi_begin) {
return "Internal error.";
}
my ($channel, $name); my ($channel, $name);
if ($from !~ m/^#/) { if ($from !~ m/^#/) {
@ -400,11 +375,7 @@ sub counterreset {
sub countershow { sub countershow {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
return "Internal error." if not $self->dbi_begin;
if (not $self->dbi_begin) {
return "Internal error.";
}
my ($channel, $name); my ($channel, $name);
if ($from !~ m/^#/) { if ($from !~ m/^#/) {
@ -436,11 +407,7 @@ sub countershow {
sub counterlist { sub counterlist {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
return "Internal error." if not $self->dbi_begin;
if (not $self->dbi_begin) {
return "Internal error.";
}
my $channel; my $channel;
if ($from !~ m/^#/) { if ($from !~ m/^#/) {
@ -472,11 +439,7 @@ sub counterlist {
sub countertrigger { sub countertrigger {
my ($self, $from, $nick, $user, $host, $arguments) = @_; my ($self, $from, $nick, $user, $host, $arguments) = @_;
return "Internal error." if not $self->dbi_begin;
if (not $self->dbi_begin) {
return "Internal error.";
}
my $command; my $command;
($command, $arguments) = split / /, $arguments, 2; ($command, $arguments) = split / /, $arguments, 2;
@ -642,9 +605,7 @@ sub on_public {
$self->{pbot}->{logger}->log("Skipping bad trigger $trigger->{trigger}: $@"); $self->{pbot}->{logger}->log("Skipping bad trigger $trigger->{trigger}: $@");
} }
} }
$self->dbi_end; $self->dbi_end;
return 0; return 0;
} }

View File

@ -21,10 +21,8 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) });
$self->{pbot}->{event_dispatcher}->register_handler('irc.public', sub { $self->on_public(@_) });
} }
sub unload { sub unload {
@ -45,7 +43,6 @@ sub on_public {
} }
$self->{pbot}->{logger}->log("Example plugin: got message from $nick!$user\@$host: $msg\n"); $self->{pbot}->{logger}->log("Example plugin: got message from $nick!$user\@$host: $msg\n");
return 0; return 0;
} }

View File

@ -26,7 +26,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('text', 'googlesearch', 'api_key', ''); $self->{pbot}->{registry}->add_default('text', 'googlesearch', 'api_key', '');
@ -107,7 +106,6 @@ sub googlesearch {
$comma = " -- "; $comma = " -- ";
last if --$matches <= 0; last if --$matches <= 0;
} }
return $output; return $output;
} }

View File

@ -13,7 +13,6 @@ use warnings;
use strict; use strict;
use feature 'unicode_strings'; use feature 'unicode_strings';
use Carp (); use Carp ();
sub new { sub new {
@ -26,7 +25,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{commands}->register(sub { return $self->magic(@_)}, "mc", 90); $self->{pbot}->{commands}->register(sub { return $self->magic(@_)}, "mc", 90);
} }
@ -39,7 +37,6 @@ sub unload {
sub magic { sub magic {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $arguments) = @_; my ($from, $nick, $user, $host, $arguments) = @_;
# do something magical! # do something magical!
return "Did something magical."; return "Did something magical.";
} }

View File

@ -10,7 +10,6 @@ use warnings;
use strict; use strict;
use feature 'unicode_strings'; use feature 'unicode_strings';
use Carp (); use Carp ();
use Time::Duration qw/duration/; use Time::Duration qw/duration/;

View File

@ -26,12 +26,8 @@ use PBot::Utils::ValidateString;
use POSIX qw(strftime); use POSIX qw(strftime);
sub new { sub new {
if (ref($_[1]) eq 'HASH') { Carp::croak("Options to Quotegrabs should be key/value pairs, not hash reference") if ref($_[1]) eq 'HASH';
Carp::croak("Options to Quotegrabs should be key/value pairs, not hash reference");
}
my ($class, %conf) = @_; my ($class, %conf) = @_;
my $self = bless {}, $class; my $self = bless {}, $class;
$self->initialize(%conf); $self->initialize(%conf);
return $self; return $self;
@ -39,7 +35,6 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference in Quotegrabs"); $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference in Quotegrabs");
$self->{filename} = $conf{quotegrabs_file} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/quotegrabs.sqlite3'; $self->{filename} = $conf{quotegrabs_file} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/quotegrabs.sqlite3';

View File

@ -30,31 +30,23 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); $self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{commands}->register(sub { $self->remindme(@_) }, 'remindme', 0); $self->{pbot}->{commands}->register(sub { $self->remindme(@_) }, 'remindme', 0);
$self->{filename} = $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/reminders.sqlite3'; $self->{filename} = $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/reminders.sqlite3';
$self->{pbot}->{timer}->register(sub { $self->check_reminders(@_) }, 1, 'RemindMe'); $self->{pbot}->{timer}->register(sub { $self->check_reminders(@_) }, 1, 'RemindMe');
$self->dbi_begin; $self->dbi_begin;
$self->create_database; $self->create_database;
} }
sub unload { sub unload {
my $self = shift; my $self = shift;
$self->dbi_end; $self->dbi_end;
$self->{pbot}->{commands}->unregister('remindme'); $self->{pbot}->{commands}->unregister('remindme');
$self->{pbot}->{timer}->unregister('RemindMe'); $self->{pbot}->{timer}->unregister('RemindMe');
} }
sub create_database { sub create_database {
my $self = shift; my $self = shift;
return if not $self->{dbh}; return if not $self->{dbh};
eval { eval {
@ -154,7 +146,6 @@ sub get_reminder {
$self->{pbot}->{logger}->log("List reminders failed: $@"); $self->{pbot}->{logger}->log("List reminders failed: $@");
return undef; return undef;
} }
return $reminder; return $reminder;
} }

View File

@ -26,8 +26,7 @@ sub new {
sub initialize { sub initialize {
my ($self, %conf) = @_; my ($self, %conf) = @_;
$self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
$self->{pbot}->{registry}->add_default('text', 'general', 'show_url_titles', $conf{show_url_titles} // 1); $self->{pbot}->{registry}->add_default('text', 'general', 'show_url_titles', $conf{show_url_titles} // 1);
$self->{pbot}->{registry}->add_default('array', 'general', 'show_url_titles_channels', $conf{show_url_titles_channels} // '.*'); $self->{pbot}->{registry}->add_default('array', 'general', 'show_url_titles_channels', $conf{show_url_titles_channels} // '.*');
@ -37,9 +36,7 @@ sub initialize {
$self->{pbot}->{event_dispatcher}->register_handler('irc.caction', sub { $self->show_url_titles(@_) }); $self->{pbot}->{event_dispatcher}->register_handler('irc.caction', sub { $self->show_url_titles(@_) });
} }
sub unload { sub unload {}
my $self = shift;
}
sub show_url_titles { sub show_url_titles {
my ($self, $event_type, $event) = @_; my ($self, $event_type, $event) = @_;
@ -88,7 +85,6 @@ sub show_url_titles {
$self->{pbot}->{factoids}->{factoidmodulelauncher}->execute_module($stuff); $self->{pbot}->{factoids}->{factoidmodulelauncher}->execute_module($stuff);
} }
} }
return 0; return 0;
} }

View File

@ -71,7 +71,6 @@ sub weathercmd {
if (not length $arguments) { if (not length $arguments) {
return $usage; return $usage;
} }
return $self->get_weather($arguments); return $self->get_weather($arguments);
} }
@ -125,7 +124,6 @@ sub get_weather {
last; last;
} }
} }
return $result; return $result;
} }

230
data/commands vendored
View File

@ -2,532 +2,546 @@
"actiontrigger" : { "actiontrigger" : {
"_name" : "actiontrigger", "_name" : "actiontrigger",
"help" : "Adds a new actiontrigger to PBot. See https://github.com/pragma-/pbot/blob/master/doc/ActionTrigger.md", "help" : "Adds a new actiontrigger to PBot. See https://github.com/pragma-/pbot/blob/master/doc/ActionTrigger.md",
"level" : 10 "requires_cap" : 1
}, },
"aka" : { "aka" : {
"_name" : "aka", "_name" : "aka",
"help" : "Lists known aliases for a given nick. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#aka", "help" : "Lists known aliases for a given nick. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#aka",
"level" : 0 "requires_cap" : 0
}, },
"akalink" : { "akalink" : {
"_name" : "akalink", "_name" : "akalink",
"help" : "Manually link a known alias to a nick. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#akalink", "help" : "Manually link a known alias to a nick. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#akalink",
"level" : 60 "requires_cap" : 1
}, },
"akaunlink" : { "akaunlink" : {
"_name" : "akaunlink", "_name" : "akaunlink",
"help" : "Manually unlink a known alias from a nick. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#akaunlink", "help" : "Manually unlink a known alias from a nick. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#akaunlink",
"level" : 60 "requires_cap" : 1
}, },
"antispam" : { "antispam" : {
"_name" : "antispam", "_name" : "antispam",
"help" : "See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#antispam", "help" : "See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#antispam",
"level" : 10 "requires_cap" : 1
}, },
"ban" : { "ban" : {
"_name" : "ban", "_name" : "ban",
"help" : "Bans a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#banmute", "help" : "Bans a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#banmute",
"level" : 10 "requires_cap" : 1
}, },
"battleship" : { "battleship" : {
"_name" : "battleship", "_name" : "battleship",
"help" : "The classic Battleship board game, modified for IRC. See https://github.com/pragma-/pbot/blob/master/doc/Battleship.md", "help" : "The classic Battleship board game, modified for IRC. See https://github.com/pragma-/pbot/blob/master/doc/Battleship.md",
"level" : 0 "requires_cap" : 0
}, },
"blacklist" : { "blacklist" : {
"_name" : "blacklist", "_name" : "blacklist",
"help" : "Blacklists a hostmask from joining a channel. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#blacklist", "help" : "Blacklists a hostmask from joining a channel. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#blacklist",
"level" : 10 "requires_cap" : 1
},
"cap" : {
"_name" : "cap",
"help" : "",
"requires_cap" : 0
}, },
"chanadd" : { "chanadd" : {
"_name" : "chanadd", "_name" : "chanadd",
"help" : "Permanently adds a channel to PBot's list of channels to auto-join and manage. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanadd", "help" : "Permanently adds a channel to PBot's list of channels to auto-join and manage. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanadd",
"level" : 40 "requires_cap" : 1
}, },
"chanlist" : { "chanlist" : {
"_name" : "chanlist", "_name" : "chanlist",
"help" : "Lists all added channels and their metadata keys and values. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanlist", "help" : "Lists all added channels and their metadata keys and values. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanlist",
"level" : 10 "requires_cap" : 1
}, },
"chanrem" : { "chanrem" : {
"_name" : "chanrem", "_name" : "chanrem",
"help" : "Removes a channel from PBot's list of channels to auto-join and manage. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanrem", "help" : "Removes a channel from PBot's list of channels to auto-join and manage. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanrem",
"level" : 40 "requires_cap" : 1
}, },
"chanset" : { "chanset" : {
"_name" : "chanset", "_name" : "chanset",
"help" : "Sets a channel's metadata. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanset and https://github.com/pragma-/pbot/blob/master/doc/Admin.md#channel-metadata-list", "help" : "Sets a channel's metadata. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanset and https://github.com/pragma-/pbot/blob/master/doc/Admin.md#channel-metadata-list",
"level" : 40 "requires_cap" : 1
}, },
"chanunset" : { "chanunset" : {
"_name" : "chanunset", "_name" : "chanunset",
"help" : "Deletes a channel's metadata key. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanunset", "help" : "Deletes a channel's metadata key. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#chanunset",
"level" : 40 "requires_cap" : 1
}, },
"checkban" : { "checkban" : {
"_name" : "checkban", "_name" : "checkban",
"help" : "Shows the reason a mask was banned and how long the ban lasts. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#checkban", "help" : "Shows the reason a mask was banned and how long the ban lasts. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#checkban",
"level" : 0 "requires_cap" : 0
}, },
"checkmute" : { "checkmute" : {
"_name" : "checkmute", "_name" : "checkmute",
"help" : "Shows the reason a mask was muted and how long the mute lasts. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#checkmute", "help" : "Shows the reason a mask was muted and how long the mute lasts. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#checkmute",
"level" : 0 "requires_cap" : 0
}, },
"cmdset" : { "cmdset" : {
"_name" : "cmdset", "_name" : "cmdset",
"help" : "Sets or shows command metadata. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#cmdset", "help" : "Sets or shows command metadata. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#cmdset",
"level" : 90 "requires_cap" : 1
}, },
"cmdunset" : { "cmdunset" : {
"_name" : "cmdunset", "_name" : "cmdunset",
"help" : "Deletes a channel metadata key. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#cmdunset", "help" : "Deletes a channel metadata key. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#cmdunset",
"level" : 90 "requires_cap" : 1
}, },
"connect4" : { "connect4" : {
"_name" : "connect4", "_name" : "connect4",
"help" : "The classic Connect-4 board game. See https://github.com/pragma-/pbot/blob/master/doc/Connect4.md", "help" : "The classic Connect-4 board game. See https://github.com/pragma-/pbot/blob/master/doc/Connect4.md",
"level" : 0 "requires_cap" : 0
}, },
"count" : { "count" : {
"_name" : "count", "_name" : "count",
"help" : "Shows how many factoids and what percentage of the database <nick> has submitted. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#count", "help" : "Shows how many factoids and what percentage of the database <nick> has submitted. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#count",
"level" : 0 "requires_cap" : 0
}, },
"counteradd" : { "counteradd" : {
"_name" : "counteradd", "_name" : "counteradd",
"help" : "Adds a new counter. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#add", "help" : "Adds a new counter. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#add",
"level" : 0 "requires_cap" : 0
}, },
"counterdel" : { "counterdel" : {
"_name" : "counterdel", "_name" : "counterdel",
"help" : "Deletes a counter. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#del", "help" : "Deletes a counter. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#del",
"level" : 0 "requires_cap" : 0
}, },
"counterlist" : { "counterlist" : {
"_name" : "counterlist", "_name" : "counterlist",
"help" : "Lists counters. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#list", "help" : "Lists counters. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#list",
"level" : 0 "requires_cap" : 0
}, },
"counterreset" : { "counterreset" : {
"_name" : "counterreset", "_name" : "counterreset",
"help" : "Resets a counter. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#reset", "help" : "Resets a counter. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#reset",
"level" : 0 "requires_cap" : 0
}, },
"countershow" : { "countershow" : {
"_name" : "countershow", "_name" : "countershow",
"help" : "Shows a counter's data. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#show", "help" : "Shows a counter's data. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#show",
"level" : 0 "requires_cap" : 0
}, },
"countertrigger" : { "countertrigger" : {
"_name" : "countertrigger", "_name" : "countertrigger",
"help" : "Manages counter triggers. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#trigger", "help" : "Manages counter triggers. See https://github.com/pragma-/pbot/blob/master/doc/Counter.md#trigger",
"level" : 10 "requires_cap" : 1
}, },
"date" : { "date" : {
"_name" : "date", "_name" : "date",
"help" : "Shows date and time for a timezone. Accepts Linux timezone locations. You can set `!my timezone ...` to remember your timezone.", "help" : "Shows date and time for a timezone. Accepts Linux timezone locations. You can set `!my timezone ...` to remember your timezone.",
"level" : 0 "requires_cap" : 0
}, },
"delq" : { "delq" : {
"_name" : "delq", "_name" : "delq",
"help" : "Deletes a quote from the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#delq", "help" : "Deletes a quote from the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#delq",
"level" : 0 "requires_cap" : 0
}, },
"deop" : { "deop" : {
"_name" : "deop", "_name" : "deop",
"help" : "Removes OP status from users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#deop", "help" : "Removes OP status from users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#deop",
"level" : 10 "requires_cap" : 1
}, },
"devoice" : { "devoice" : {
"_name" : "devoice", "_name" : "devoice",
"help" : "Removes VOICE status from users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#devoice", "help" : "Removes VOICE status from users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#devoice",
"level" : 10 "requires_cap" : 1
}, },
"die" : { "die" : {
"_name" : "die", "_name" : "die",
"help" : "Tells PBot to disconnect and exit. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#die", "help" : "Tells PBot to disconnect and exit. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#die",
"level" : 90 "requires_cap" : 1
}, },
"dumpbans" : { "dumpbans" : {
"_name" : "dumpbans", "_name" : "dumpbans",
"help" : "Displays PBot's internal banlist data structure. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#dumpbans", "help" : "Displays PBot's internal banlist data structure. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#dumpbans",
"level" : 60 "requires_cap" : 1
}, },
"eval" : { "eval" : {
"_name" : "eval", "_name" : "eval",
"help" : "Evaluates Perl code within PBot's context. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#eval", "help" : "Evaluates Perl code within PBot's context. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#eval",
"level" : 99 "requires_cap" : 1
}, },
"export" : { "export" : {
"_name" : "export", "_name" : "export",
"help" : "Exports specified list to HTML file. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#export", "help" : "Exports specified list to HTML file. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#export",
"level" : 90 "requires_cap" : 1
}, },
"fact" : { "fact" : {
"_name" : "fact", "_name" : "fact",
"help" : "Displays or invokes a factoid belonging to a specific channel. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#fact", "help" : "Displays or invokes a factoid belonging to a specific channel. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#fact",
"level" : 0 "requires_cap" : 0
}, },
"factadd" : { "factadd" : {
"_name" : "factadd", "_name" : "factadd",
"help" : "Creates a new factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factadd", "help" : "Creates a new factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factadd",
"level" : 0 "requires_cap" : 0
}, },
"factalias" : { "factalias" : {
"_name" : "factalias", "_name" : "factalias",
"help" : "Creates a factoid that acts as an alias for a command. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factalias", "help" : "Creates a factoid that acts as an alias for a command. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factalias",
"level" : 0 "requires_cap" : 0
}, },
"factchange" : { "factchange" : {
"_name" : "factchange", "_name" : "factchange",
"help" : "Changes a factoid using a regular expression. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factchange", "help" : "Changes a factoid using a regular expression. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factchange",
"level" : 0 "requires_cap" : 0
}, },
"factfind" : { "factfind" : {
"_name" : "factfind", "_name" : "factfind",
"help" : "Searches the database for a factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factfind", "help" : "Searches the database for a factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factfind",
"level" : 0 "requires_cap" : 0
}, },
"factinfo" : { "factinfo" : {
"_name" : "factinfo", "_name" : "factinfo",
"help" : "Displays information about a factoid, such as who submitted it and when. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factinfo", "help" : "Displays information about a factoid, such as who submitted it and when. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factinfo",
"level" : 0 "requires_cap" : 0
}, },
"factlog" : { "factlog" : {
"_name" : "factlog", "_name" : "factlog",
"help" : "Displays a factoid's changelog history. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factlog", "help" : "Displays a factoid's changelog history. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factlog",
"level" : 0 "requires_cap" : 0
}, },
"factmove" : { "factmove" : {
"_name" : "factmove", "_name" : "factmove",
"help" : "Renames a factoid or moves a factoid to a different channel. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factmove", "help" : "Renames a factoid or moves a factoid to a different channel. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factmove",
"level" : 0 "requires_cap" : 0
}, },
"factredo" : { "factredo" : {
"_name" : "factredo", "_name" : "factredo",
"help" : "Reverts a factoid to a newer revision. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factredo", "help" : "Reverts a factoid to a newer revision. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factredo",
"level" : 0 "requires_cap" : 0
}, },
"factrem" : { "factrem" : {
"_name" : "factrem", "_name" : "factrem",
"help" : "Deletes a factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factrem", "help" : "Deletes a factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factrem",
"level" : 0 "requires_cap" : 0
}, },
"factset" : { "factset" : {
"_name" : "factset", "_name" : "factset",
"help" : "Displays or sets factoid metadata, such as owner, rate-limit, etc. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factset and https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factoid-metadata-list", "help" : "Displays or sets factoid metadata, such as owner, rate-limit, etc. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factset and https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factoid-metadata-list",
"level" : 0 "requires_cap" : 0
}, },
"factshow" : { "factshow" : {
"_name" : "factshow", "_name" : "factshow",
"help" : "Displays a factoid's literal value without invoking the factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factshow", "help" : "Displays a factoid's literal value without invoking the factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factshow",
"level" : 0 "requires_cap" : 0
}, },
"factundo" : { "factundo" : {
"_name" : "factundo", "_name" : "factundo",
"help" : "Reverts a factoid to an older revision. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factundo", "help" : "Reverts a factoid to an older revision. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factundo",
"level" : 0 "requires_cap" : 0
}, },
"factunset" : { "factunset" : {
"_name" : "factunset", "_name" : "factunset",
"help" : "Unsets a factoid metadata key. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factunset and https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factoid-metadata-list", "help" : "Unsets a factoid metadata key. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factunset and https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factoid-metadata-list",
"level" : 0 "requires_cap" : 0
}, },
"forget" : { "forget" : {
"_name" : "forget", "_name" : "forget",
"help" : "Deletes a factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#forget", "help" : "Deletes a factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#forget",
"level" : 0 "requires_cap" : 0
}, },
"func" : { "func" : {
"_name" : "func", "_name" : "func",
"help" : "Invokes built-in functions. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#func", "help" : "Invokes built-in functions. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#func",
"level" : 0 "requires_cap" : 0
}, },
"getq" : { "getq" : {
"_name" : "getq", "_name" : "getq",
"help" : "Retrieves and displays a specific quote from the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#getq", "help" : "Retrieves and displays a specific quote from the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#getq",
"level" : 0 "requires_cap" : 0
}, },
"google" : { "google" : {
"_name" : "google", "_name" : "google",
"help" : "Displays Google search results for a query. See https://github.com/pragma-/pbot/blob/master/doc/Modules.md#google", "help" : "Displays Google search results for a query. See https://github.com/pragma-/pbot/blob/master/doc/Modules.md#google",
"level" : 0 "requires_cap" : 0
}, },
"grab" : { "grab" : {
"_name" : "grab", "_name" : "grab",
"help" : "Grabs a message someone says, and adds it to the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#grab", "help" : "Grabs a message someone says, and adds it to the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#grab",
"level" : 0 "requires_cap" : 0
}, },
"help" : { "help" : {
"_name" : "help", "_name" : "help",
"help" : "Displays the `help` metadata for commands and factoids.", "help" : "Displays the `help` metadata for commands and factoids.",
"level" : "0" "requires_cap" : 0
}, },
"histogram" : { "histogram" : {
"_name" : "histogram", "_name" : "histogram",
"help" : "Displays a histogram of the top factoid submitters. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#histogram", "help" : "Displays a histogram of the top factoid submitters. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#histogram",
"level" : 0 "requires_cap" : 0
}, },
"ignore" : { "ignore" : {
"_name" : "ignore", "_name" : "ignore",
"help" : "Ignores a user. If you omit [channel] PBot will ignore the user in all channels, including private messages. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#ignore", "help" : "Ignores a user. If you omit [channel] PBot will ignore the user in all channels, including private messages. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#ignore",
"level" : 10 "requires_cap" : 1
}, },
"in" : { "in" : {
"_name" : "in", "_name" : "in",
"help" : "Performs a command in a specific channel. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#in", "help" : "Performs a command in a specific channel. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#in",
"level" : 0 "requires_cap" : 1
}, },
"invite" : { "invite" : {
"_name" : "invite", "_name" : "invite",
"help" : "Invites a user to a channel. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#invite", "help" : "Invites a user to a channel. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#invite",
"level" : 10 "requires_cap" : 1
}, },
"join" : { "join" : {
"_name" : "join", "_name" : "join",
"help" : "Temporarily joins a channel without adding it to PBot's list of channels to manage/auto-join. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#join", "help" : "Temporarily joins a channel without adding it to PBot's list of channels to manage/auto-join. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#join",
"level" : 40 "requires_cap" : 1
}, },
"kick" : { "kick" : {
"_name" : "kick", "_name" : "kick",
"help" : "Removes a user from the channel. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#kick", "help" : "Removes a user from the channel. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#kick",
"level" : "10" "requires_cap" : 1
}, },
"lagcheck" : { "lagcheck" : {
"_name" : "lagcheck", "_name" : "lagcheck",
"help" : "Displays history of PING times. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#lagcheck", "help" : "Displays history of PING times. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#lagcheck",
"level" : 0 "requires_cap" : 0
}, },
"learn" : { "learn" : {
"_name" : "learn", "_name" : "learn",
"help" : "Creates a new factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factadd", "help" : "Creates a new factoid. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#factadd",
"level" : 0 "requires_cap" : 0
}, },
"list" : { "list" : {
"_name" : "list", "_name" : "list",
"help" : "Lists various collections, such as channels or admins. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#list", "help" : "Lists various collections, such as channels or admins. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#list"
"level" : 0
}, },
"load" : { "load" : {
"_name" : "load", "_name" : "load",
"help" : "This command loads a module as a PBot command. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#load", "help" : "This command loads a module as a PBot command. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#load",
"level" : 90 "requires_cap" : 1
}, },
"login" : { "login" : {
"_name" : "login", "_name" : "login",
"help" : "Logs into a PBot admin account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#login", "help" : "Logs into a PBot admin account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#login",
"level" : 0 "requires_cap" : 0
}, },
"logout" : { "logout" : {
"_name" : "logout", "_name" : "logout",
"help" : "Logs out of a PBot admin account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#logout", "help" : "Logs out of a PBot admin account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#logout",
"level" : 0 "requires_cap" : 0
},
"mod" : {
"_name" : "mod",
"help" : "Provides restricted moderation abilities to voiced users. They can kick/ban/etc only users that are not admins, whitelisted, voiced or opped.",
"requires_cap" : 0
}, },
"mode" : { "mode" : {
"_name" : "mode", "_name" : "mode",
"help" : "Sets or unsets channel or user modes. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#mode", "help" : "Sets or unsets channel or user modes. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#mode",
"level" : 40 "requires_cap" : 1
}, },
"mute" : { "mute" : {
"_name" : "mute", "_name" : "mute",
"help" : "Mutes a user. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#banmute", "help" : "Mutes a user. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#banmute",
"level" : 10 "requires_cap" : 1
}, },
"my" : { "my" : {
"_name" : "my", "_name" : "my",
"help" : "Lets users view and manipulate their own user metadata. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#my and https://github.com/pragma-/pbot/blob/master/doc/Admin.md#user-metadata-list", "help" : "Lets users view and manipulate their own user metadata. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#my and https://github.com/pragma-/pbot/blob/master/doc/Admin.md#user-metadata-list",
"level" : 0 "requires_cap" : 0
}, },
"nicklist" : { "nicklist" : {
"_name" : "nicklist", "_name" : "nicklist",
"help" : "Dumps the internal nicklist structure. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#nicklist", "help" : "Dumps the internal nicklist structure. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#nicklist",
"level" : 0 "requires_cap" : 0
}, },
"op" : { "op" : {
"_name" : "op", "_name" : "op",
"help" : "Gives channel operator status to users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#op", "help" : "Gives channel operator status to users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#op",
"level" : 10 "requires_cap" : "1"
}, },
"part" : { "part" : {
"_name" : "part", "_name" : "part",
"help" : "Departs a channel, without removing it from PBot's list of channels to manage/auto-join. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#part", "help" : "Departs a channel, without removing it from PBot's list of channels to manage/auto-join. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#part",
"level" : 40 "requires_cap" : 1
}, },
"plug" : { "plug" : {
"_name" : "plug", "_name" : "plug",
"help" : "Loads a plugin into PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#plug", "help" : "Loads a plugin into PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#plug",
"level" : 90 "requires_cap" : 1
}, },
"pluglist" : { "pluglist" : {
"_name" : "pluglist", "_name" : "pluglist",
"help" : "Lists all currently loaded plugins. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#pluglist", "help" : "Lists all currently loaded plugins. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#pluglist",
"level" : 0 "requires_cap" : 0
}, },
"rebuildaliases" : { "rebuildaliases" : {
"_name" : "rebuildaliases", "_name" : "rebuildaliases",
"help" : "Rebuilds the aka link table. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#rebuildaliases", "help" : "Rebuilds the aka link table. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#rebuildaliases",
"level" : 90 "requires_cap" : 1
}, },
"recall" : { "recall" : {
"_name" : "recall", "_name" : "recall",
"help" : "Recalls previous chat history for a channel. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#recall", "help" : "Recalls previous chat history for a channel. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#recall",
"level" : 0 "requires_cap" : 0
}, },
"refresh" : { "refresh" : {
"_name" : "refresh", "_name" : "refresh",
"help" : "Refreshes and reloads PBot core modules and plugins. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#refresh", "help" : "Refreshes and reloads PBot core modules and plugins. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#refresh",
"level" : 90 "requires_cap" : 0
}, },
"regchange" : { "regchange" : {
"_name" : "regchange", "_name" : "regchange",
"help" : "Changes the value of a registry item using a regular expression. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regchange", "help" : "Changes the value of a registry item using a regular expression. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regchange",
"level" : 60 "requires_cap" : 1
}, },
"regex" : { "regex" : {
"_name" : "regex", "_name" : "regex",
"help" : "Manages regular expression commands. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#regex", "help" : "Manages regular expression commands. See https://github.com/pragma-/pbot/blob/master/doc/Commands.md#regex",
"level" : 999 "requires_cap" : 1
}, },
"regfind" : { "regfind" : {
"_name" : "regfind", "_name" : "regfind",
"help" : "Searches the registry for keywords or values. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regfind", "help" : "Searches the registry for keywords or values. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regfind",
"level" : 0 "requires_cap" : 0
}, },
"regset" : { "regset" : {
"_name" : "regset", "_name" : "regset",
"help" : "Creates a new registry item or updates an existing item. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regset", "help" : "Creates a new registry item or updates an existing item. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regset",
"level" : 60 "requires_cap" : 1
}, },
"regsetmeta" : { "regsetmeta" : {
"_name" : "regsetmeta", "_name" : "regsetmeta",
"help" : "Sets or displays the metadata for a specific registry key. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regsetmeta and https://github.com/pragma-/pbot/blob/master/doc/Registry.md#metadata-list", "help" : "Sets or displays the metadata for a specific registry key. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regsetmeta and https://github.com/pragma-/pbot/blob/master/doc/Registry.md#metadata-list",
"level" : 60 "requires_cap" : 1
}, },
"regshow" : { "regshow" : {
"_name" : "regshow", "_name" : "regshow",
"help" : "Displays the type and value of a registry item. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regshow", "help" : "Displays the type and value of a registry item. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regshow",
"level" : 0 "requires_cap" : 0
}, },
"regunset" : { "regunset" : {
"_name" : "regunset", "_name" : "regunset",
"help" : "Deletes a registry item from a specific section/channel. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regunset", "help" : "Deletes a registry item from a specific section/channel. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regunset",
"level" : 60 "requires_cap" : 1
}, },
"regunsetmeta" : { "regunsetmeta" : {
"_name" : "regunsetmeta", "_name" : "regunsetmeta",
"help" : "Deletes a metadata key from a registry item. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regsetmeta and https://github.com/pragma-/pbot/blob/master/doc/Registry.md#metadata", "help" : "Deletes a metadata key from a registry item. See https://github.com/pragma-/pbot/blob/master/doc/Registry.md#regsetmeta and https://github.com/pragma-/pbot/blob/master/doc/Registry.md#metadata",
"level" : 60 "requires_cap" : 1
}, },
"reload" : { "reload" : {
"_name" : "reload", "_name" : "reload",
"help" : "Reloads a data or configuration file. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#reload", "help" : "Reloads a data or configuration file. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#reload",
"level" : 90 "requires_cap" : 1
}, },
"remindme" : { "remindme" : {
"_name" : "remindme", "_name" : "remindme",
"help" : "Manages user reminders. See https://github.com/pragma-/pbot/blob/master/doc/Remindme.md", "help" : "Manages user reminders. See https://github.com/pragma-/pbot/blob/master/doc/Remindme.md",
"level" : 0 "requires_cap" : 0
}, },
"replug" : { "replug" : {
"_name" : "replug", "_name" : "replug",
"help" : "Reloads a plugin into PBot. The plugin is first unloaded and then it is loaded again. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#replug", "help" : "Reloads a plugin into PBot. The plugin is first unloaded and then it is loaded again. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#replug",
"level" : 90 "requires_cap" : 1
}, },
"rq" : { "rq" : {
"_name" : "rq", "_name" : "rq",
"help" : "Retrieves and displays a random quote from the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#rq", "help" : "Retrieves and displays a random quote from the quotegrabs database. See https://github.com/pragma-/pbot/blob/master/doc/Quotegrabs.md#rq",
"level" : 0 "requires_cap" : 0
}, },
"sl" : { "sl" : {
"_name" : "sl", "_name" : "sl",
"help" : "Sends a raw IRC command to the server. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#sl", "help" : "Sends a raw IRC command to the server. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#sl",
"level" : 90 "requires_cap" : 1
}, },
"spinach" : { "spinach" : {
"_name" : "spinach", "_name" : "spinach",
"help" : "Manages and interacts with the Spinach trivia game. See https://github.com/pragma-/pbot/blob/master/doc/Spinach.md", "help" : "Manages and interacts with the Spinach trivia game. See https://github.com/pragma-/pbot/blob/master/doc/Spinach.md",
"level" : 0 "requires_cap" : 0
}, },
"top20" : { "top20" : {
"_name" : "top20", "_name" : "top20",
"help" : "Displays the top 20 most popular factoids. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#top20", "help" : "Displays the top 20 most popular factoids. See https://github.com/pragma-/pbot/blob/master/doc/Factoids.md#top20",
"level" : 0 "requires_cap" : 0
}, },
"unban" : { "unban" : {
"_name" : "unban", "_name" : "unban",
"help" : "Unbans a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unbanunmute", "help" : "Unbans a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unbanunmute",
"level" : 10 "requires_cap" : 1
}, },
"unbanme" : { "unbanme" : {
"_name" : "unbanme", "_name" : "unbanme",
"help" : "Removes a join-flood ban. See https://github.com/pragma-/pbot/blob/master/doc/Abuse.md#unbanme", "help" : "Removes a join-flood ban. See https://github.com/pragma-/pbot/blob/master/doc/Abuse.md#unbanme",
"level" : 0 "requires_cap" : 0
}, },
"unignore" : { "unignore" : {
"_name" : "unignore", "_name" : "unignore",
"help" : "Unignores a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unignore", "help" : "Unignores a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unignore",
"level" : 10 "requires_cap" : 1
}, },
"unload" : { "unload" : {
"_name" : "unload", "_name" : "unload",
"help" : "Unloads a module and removes its associated command. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unload", "help" : "Unloads a module and removes its associated command. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unload",
"level" : 90 "requires_cap" : 1
}, },
"unmute" : { "unmute" : {
"_name" : "unmute", "_name" : "unmute",
"help" : "Unmutes a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unbanunmute", "help" : "Unmutes a user. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unbanunmute",
"level" : 10 "requires_cap" : 1
}, },
"unplug" : { "unplug" : {
"_name" : "unplug", "_name" : "unplug",
"help" : "Unloads a plugin from PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unplug", "help" : "Unloads a plugin from PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#unplug",
"level" : 90 "requires_cap" : 1
}, },
"uptime" : { "uptime" : {
"_name" : "uptime", "_name" : "uptime",
"help" : "", "help" : "Displays the date and time this instance of PBot was started and how long it has been running.",
"level" : 0 "requires_cap" : 0
}, },
"useradd" : { "useradd" : {
"_name" : "useradd", "_name" : "useradd",
"help" : "Adds a new user to PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#useradd", "help" : "Adds a new user to PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#useradd",
"level" : 60 "requires_cap" : 1
}, },
"userdel" : { "userdel" : {
"_name" : "userdel", "_name" : "userdel",
"help" : "Removes an user from PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#userdel", "help" : "Removes an user from PBot. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#userdel",
"level" : 60 "requires_cap" : 1
}, },
"userset" : { "userset" : {
"_name" : "userset", "_name" : "userset",
"help" : "Sets metadata for an user account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#userset and https://github.com/pragma-/pbot/blob/master/doc/Admin.md#user-metadata-list", "help" : "Sets metadata for an user account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#userset and https://github.com/pragma-/pbot/blob/master/doc/Admin.md#user-metadata-list",
"level" : 60 "requires_cap" : 1
}, },
"userunset" : { "userunset" : {
"_name" : "userunset", "_name" : "userunset",
"help" : "Deletes a metadata key from an user account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#userunset", "help" : "Deletes a metadata key from an user account. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#userunset",
"level" : 60 "requires_cap" : 1
}, },
"version" : { "version" : {
"_name" : "version", "_name" : "version",
"help" : "", "help" : "",
"level" : 0 "requires_cap" : 0
}, },
"voice" : { "voice" : {
"_name" : "voice", "_name" : "voice",
"help" : "Sets mode +v on users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#voice", "help" : "Sets mode +v on users. Accepts wildcards. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#voice",
"level" : 10 "requires_cap" : 1
}, },
"weather" : { "weather" : {
"_name" : "weather", "_name" : "weather",
"help" : "Fetches and displays weather data. You may set `!my location ...` to remember your location.", "help" : "Fetches and displays weather data. You may set `!my location ...` to remember your location.",
"level" : 0 "requires_cap" : 0
}, },
"whitelist" : { "whitelist" : {
"_name" : "whitelist", "_name" : "whitelist",
"help" : "Whitelists a hostmask to be exempted from ban evasions or anti-flood enforcement. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#whitelist", "help" : "Whitelists a hostmask to be exempted from ban evasions or anti-flood enforcement. See https://github.com/pragma-/pbot/blob/master/doc/Admin.md#whitelist",
"level" : 10 "requires_cap" : 1
},
"wttr" : {
"_name" : "wttr",
"help" : "",
"requires_cap" : "0"
} }
} }

29
data/factoids vendored
View File

@ -419,7 +419,7 @@
"created_on" : "1519931258.36575", "created_on" : "1519931258.36575",
"edited_by" : "iamgarp!~chaos@unaffiliated/pragmatic-chaos", "edited_by" : "iamgarp!~chaos@unaffiliated/pragmatic-chaos",
"edited_on" : "1555805847.25419", "edited_on" : "1555805847.25419",
"effective-level" : "100", "cap-override" : "botowner",
"enabled" : "1", "enabled" : "1",
"last_referenced_in" : "##spinach", "last_referenced_in" : "##spinach",
"last_referenced_on" : 1578910468.98602, "last_referenced_on" : 1578910468.98602,
@ -10231,10 +10231,10 @@
}, },
"kickme" : { "kickme" : {
"_name" : "kickme", "_name" : "kickme",
"action" : "/kick $nick", "action" : "/call kick $nick",
"action_with_args" : "/kick $nick $args", "action_with_args" : "/call kick $nick $args",
"created_on" : "1524347954.63458", "created_on" : "1524347954.63458",
"effective-level" : "10", "cap-override" : "can-kick",
"enabled" : "1", "enabled" : "1",
"last_referenced_in" : "##c-offtopic", "last_referenced_in" : "##c-offtopic",
"last_referenced_on" : 1572992043.13307, "last_referenced_on" : 1572992043.13307,
@ -14908,7 +14908,7 @@
"_name" : "removeme", "_name" : "removeme",
"action" : "/call sl remove $channel $nick :Bye!", "action" : "/call sl remove $channel $nick :Bye!",
"created_on" : 1567373781.37961, "created_on" : 1567373781.37961,
"effective-level" : "90", "cap-override" : "botowner",
"enabled" : "1", "enabled" : "1",
"last_referenced_in" : "##c-offtopic", "last_referenced_in" : "##c-offtopic",
"last_referenced_on" : 1567721282.13253, "last_referenced_on" : 1567721282.13253,
@ -15257,7 +15257,7 @@
"created_on" : "1254874530", "created_on" : "1254874530",
"edited_by" : "pragma-!~chaos@unaffiliated/pragmatic-chaos", "edited_by" : "pragma-!~chaos@unaffiliated/pragmatic-chaos",
"edited_on" : "1504601046.70364", "edited_on" : "1504601046.70364",
"effective-level" : "20", "cap-override" : "can-kick",
"enabled" : "1", "enabled" : "1",
"last_referenced_in" : "##c-offtopic", "last_referenced_in" : "##c-offtopic",
"last_referenced_on" : 1579041706.76328, "last_referenced_on" : 1579041706.76328,
@ -15270,7 +15270,7 @@
}, },
"roulette_outcome" : { "roulette_outcome" : {
"_name" : "roulette_outcome", "_name" : "roulette_outcome",
"action" : "\"/kick $nick *BANG!*\" \"/say $args: *click*\" \"/say $args: *click*\"", "action" : "\"/call kick $nick *BANG!*\" \"/say $args: *click*\" \"/say $args: *click*\"",
"created_on" : "1254874748", "created_on" : "1254874748",
"edited_by" : "pragma-!~chaos@unaffiliated/pragmatic-chaos", "edited_by" : "pragma-!~chaos@unaffiliated/pragmatic-chaos",
"edited_on" : "1492056512.90395", "edited_on" : "1492056512.90395",
@ -21511,21 +21511,6 @@
"ref_user" : "k!~krok@unaffiliated/krok", "ref_user" : "k!~krok@unaffiliated/krok",
"type" : "text" "type" : "text"
}, },
"wang" : {
"_name" : "wang",
"action" : "/msg mnrmnaugh wtf",
"created_on" : "1519278998.50208",
"effective-level" : "60",
"enabled" : "1",
"last_referenced_in" : "#pbot2",
"last_referenced_on" : "1519979002.921",
"locked" : "1",
"owner" : "pragma-!~chaos@unaffiliated/pragmatic-chaos",
"rate_limit" : "15",
"ref_count" : "8",
"ref_user" : "mnrmnaugh!~mnrmnaugh@unaffiliated/mnrmnaugh",
"type" : "text"
},
"warning-labels" : { "warning-labels" : {
"_name" : "warning-labels", "_name" : "warning-labels",
"action" : "http://www.myconfinedspace.com/2007/03/23/internet-warning-labels/", "action" : "http://www.myconfinedspace.com/2007/03/23/internet-warning-labels/",