mirror of
https://github.com/pragma-/pbot.git
synced 2024-12-23 11:12:42 +01:00
Add centralized configuration registry module
Allows changing of bot configuration values without needing to restart bot instance or needing to edit pbot.pl script. Registry will initially be populated with default values from pbot.pl, but if a registry file exists then the registry values will take precedence over the pbot.pl values. For instance, if you regset the bot trigger to '%' then the trigger will be '%' even if pbot.pl has '!' or something else explicitly set. Some registry items can have trigger hooks associated with them. For instance, the irc->botnick registry entry has a change_botnick_trigger associated with it which changes the IRC nick on the server when a new value is set via regset/regadd. Tons of other fixes and improvements throughout.
This commit is contained in:
parent
d8d26b1cea
commit
d955bfa06c
@ -14,9 +14,6 @@ use strict;
|
||||
|
||||
use feature 'switch';
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use PBot::DualIndexHashObject;
|
||||
use PBot::LagChecker;
|
||||
|
||||
@ -45,14 +42,10 @@ sub initialize {
|
||||
$self->{NICKSERV_VALIDATED} = (1<<0);
|
||||
$self->{NEEDS_CHECKBAN} = (1<<1);
|
||||
|
||||
$self->{ENTER_ABUSE_MAX_LINES} = 4;
|
||||
$self->{ENTER_ABUSE_MAX_OFFENSES} = 3;
|
||||
$self->{ENTER_ABUSE_MAX_SECONDS} = 20;
|
||||
|
||||
$self->{channels} = {}; # per-channel statistics, e.g. for optimized tracking of last spoken nick for enter-abuse detection, etc
|
||||
$self->{channels} = {}; # per-channel statistics, e.g. for optimized tracking of last spoken nick for enter-abuse detection, etc
|
||||
$self->{nickflood} = {}; # statistics to track nickchange flooding
|
||||
|
||||
my $filename = delete $conf{banwhitelist_file} // $self->{pbot}->{data_dir} . '/ban_whitelist';
|
||||
my $filename = delete $conf{banwhitelist_file} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/ban_whitelist';
|
||||
$self->{ban_whitelist} = PBot::DualIndexHashObject->new(name => 'BanWhitelist', filename => $filename);
|
||||
$self->{ban_whitelist}->load;
|
||||
|
||||
@ -212,7 +205,7 @@ sub check_flood {
|
||||
}
|
||||
|
||||
# do not do flood processing for bot messages
|
||||
if($nick eq $self->{pbot}->botnick) {
|
||||
if($nick eq $self->{pbot}->{registry}->get_value('irc', 'botnick')) {
|
||||
$self->{channels}->{$channel}->{last_spoken_nick} = $nick;
|
||||
return;
|
||||
}
|
||||
@ -229,9 +222,9 @@ sub check_flood {
|
||||
}
|
||||
}
|
||||
|
||||
if($max_messages > $self->{pbot}->{MAX_NICK_MESSAGES}) {
|
||||
$self->{pbot}->logger->log("Warning: max_messages greater than MAX_NICK_MESSAGES; truncating.\n");
|
||||
$max_messages = $self->{pbot}->{MAX_NICK_MESSAGES};
|
||||
if($max_messages > $self->{pbot}->{registry}->get_value('messagehistory', 'max_messages')) {
|
||||
$self->{pbot}->logger->log("Warning: max_messages greater than max_messages limit; truncating.\n");
|
||||
$max_messages = $self->{pbot}->{registry}->get_value('messagehistory', 'max_messages');
|
||||
}
|
||||
|
||||
# check for ban evasion if channel begins with # (not private message) and hasn't yet been validated against ban evasion
|
||||
@ -257,11 +250,15 @@ sub check_flood {
|
||||
if(defined $self->{channels}->{$channel}->{last_spoken_nick} and $nick eq $self->{channels}->{$channel}->{last_spoken_nick}) {
|
||||
my $messages = $self->{pbot}->{messagehistory}->{database}->get_recent_messages($account, $channel, 2, $self->{pbot}->{messagehistory}->{MSG_CHAT});
|
||||
|
||||
if($messages->[1]->{timestamp} - $messages->[0]->{timestamp} <= $self->{ENTER_ABUSE_MAX_SECONDS}) {
|
||||
if(++$channel_data->{enter_abuse} >= $self->{ENTER_ABUSE_MAX_LINES} - 1) {
|
||||
$channel_data->{enter_abuse} = $self->{ENTER_ABUSE_MAX_LINES} / 2 - 1;
|
||||
if(++$channel_data->{enter_abuses} >= $self->{ENTER_ABUSE_MAX_OFFENSES}) {
|
||||
my $offenses = $channel_data->{enter_abuses} - $self->{ENTER_ABUSE_MAX_OFFENSES} + 1;
|
||||
my $enter_abuse_max_lines = $self->{pbot}->{registry}->get_value('antiflood', 'enter_abuse_max_lines');
|
||||
my $enter_abuse_max_seconds = $self->{pbot}->{registry}->get_value('antiflood', 'enter_abuse_max_seconds');
|
||||
my $enter_abuse_max_offenses = $self->{pbot}->{registry}->get_value('antiflood', 'enter_abuse_max_offenses');
|
||||
|
||||
if($messages->[1]->{timestamp} - $messages->[0]->{timestamp} <= $enter_abuse_max_seconds) {
|
||||
if(++$channel_data->{enter_abuse} >= $enter_abuse_max_lines - 1) {
|
||||
$channel_data->{enter_abuse} = $enter_abuse_max_lines / 2 - 1;
|
||||
if(++$channel_data->{enter_abuses} >= $enter_abuse_max_offenses) {
|
||||
my $offenses = $channel_data->{enter_abuses} - $enter_abuse_max_offenses + 1;
|
||||
my $ban_length = $offenses ** $offenses * $offenses * 30;
|
||||
$self->{pbot}->chanops->ban_user_timed("*!$user\@$host", $channel, $ban_length);
|
||||
$ban_length = duration($ban_length);
|
||||
@ -276,7 +273,7 @@ sub check_flood {
|
||||
$self->{pbot}->{messagehistory}->{database}->update_channel_data($account, $channel, $channel_data);
|
||||
} else {
|
||||
if($channel_data->{enter_abuse} > 0) {
|
||||
#$self->{pbot}->logger->log("$nick $channel more than $self->{ENTER_ABUSE_MAX_SECONDS} seconds since last message, enter abuse counter reset\n");
|
||||
#$self->{pbot}->logger->log("$nick $channel more than $enter_abuse_max_seconds seconds since last message, enter abuse counter reset\n");
|
||||
$channel_data->{enter_abuse} = 0;
|
||||
$self->{pbot}->{messagehistory}->{database}->update_channel_data($account, $channel, $channel_data);
|
||||
}
|
||||
@ -396,7 +393,7 @@ sub unbanme {
|
||||
my ($self, $from, $nick, $user, $host, $arguments) = @_;
|
||||
my $channel = lc $arguments;
|
||||
|
||||
if(not defined $arguments or not defined $channel) {
|
||||
if(not $arguments or not $channel) {
|
||||
return "/msg $nick Usage: unbanme <channel>";
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,6 @@ package PBot::BanTracker;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Time::HiRes qw/gettimeofday/;
|
||||
use Time::Duration;
|
||||
use Data::Dumper;
|
||||
|
@ -8,9 +8,6 @@ package PBot::BotAdminCommands;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
|
@ -8,9 +8,6 @@ package PBot::BotAdmins;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use PBot::DualIndexHashObject;
|
||||
|
||||
use Carp ();
|
||||
@ -58,7 +55,7 @@ sub initialize {
|
||||
|
||||
sub add_admin {
|
||||
my $self = shift;
|
||||
my ($name, $channel, $hostmask, $level, $password) = @_;
|
||||
my ($name, $channel, $hostmask, $level, $password, $dont_save) = @_;
|
||||
|
||||
$channel = lc $channel;
|
||||
$hostmask = lc $hostmask;
|
||||
@ -69,7 +66,7 @@ sub add_admin {
|
||||
|
||||
$self->{pbot}->logger->log("Adding new level $level admin: [$name] [$hostmask] for channel [$channel]\n");
|
||||
|
||||
$self->save_admins;
|
||||
$self->save_admins unless $dont_save;
|
||||
}
|
||||
|
||||
sub remove_admin {
|
||||
@ -144,7 +141,7 @@ sub export_admins {
|
||||
sub find_admin {
|
||||
my ($self, $from, $hostmask) = @_;
|
||||
|
||||
$from = $self->{pbot}->botnick if not defined $from;
|
||||
$from = $self->{pbot}->{registry}->get_value('irc', 'botnick') if not defined $from;
|
||||
$hostmask = '.*' if not defined $hostmask;
|
||||
|
||||
my $result = eval {
|
||||
|
@ -8,9 +8,6 @@ package PBot::ChanOpCommands;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
@ -62,7 +59,8 @@ sub ban_user {
|
||||
$length = 60 * 60; # one hour
|
||||
}
|
||||
|
||||
return "" if $target =~ /\Q$self->{pbot}->botnick\E/i;
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
return "" if $target =~ /\Q$botnick\E/i;
|
||||
|
||||
$self->{pbot}->chanops->ban_user_timed($target, $from, $length);
|
||||
return "/msg $nick $target banned in $from for $length seconds";
|
||||
|
@ -8,9 +8,6 @@ package PBot::ChanOps;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
sub new {
|
||||
@ -34,7 +31,10 @@ sub initialize {
|
||||
}
|
||||
|
||||
$self->{pbot} = $pbot;
|
||||
$self->{unban_timeout} = PBot::DualIndexHashObject->new(pbot => $pbot, name => 'Unban Timeouts', filename => "$pbot->{data_dir}/unban_timeouts");
|
||||
|
||||
$self->{unban_timeout} = PBot::DualIndexHashObject->new(pbot => $pbot, name => 'Unban Timeouts', filename => $pbot->{registry}->get_value('general', 'data_dir') . '/unban_timeouts');
|
||||
$self->{unban_timeout}->load;
|
||||
|
||||
$self->{op_commands} = {};
|
||||
$self->{is_opped} = {};
|
||||
|
||||
@ -57,7 +57,7 @@ sub gain_ops {
|
||||
sub lose_ops {
|
||||
my $self = shift;
|
||||
my $channel = shift;
|
||||
$self->{pbot}->conn->privmsg("chanserv", "op $channel -" . $self->{pbot}->botnick);
|
||||
$self->{pbot}->conn->privmsg("chanserv", "op $channel -" . $self->{pbot}->{registry}->get_value('irc', 'botnick'));
|
||||
}
|
||||
|
||||
sub add_op_command {
|
||||
@ -68,6 +68,7 @@ sub add_op_command {
|
||||
sub perform_op_commands {
|
||||
my $self = shift;
|
||||
my $channel = shift;
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
|
||||
$self->{pbot}->logger->log("Performing op commands...\n");
|
||||
while(my $command = shift @{ $self->{op_commands}->{$channel} }) {
|
||||
@ -75,7 +76,7 @@ sub perform_op_commands {
|
||||
$self->{pbot}->conn->mode($1, $2);
|
||||
$self->{pbot}->logger->log(" executing mode $1 $2\n");
|
||||
} elsif($command =~ /^kick (.*?) (.*?) (.*)/i) {
|
||||
$self->{pbot}->conn->kick($1, $2, $3) unless $1 =~ /\Q$self->{pbot}->botnick\E/i;
|
||||
$self->{pbot}->conn->kick($1, $2, $3) unless $1 =~ /\Q$botnick\E/i;
|
||||
$self->{pbot}->logger->log(" executing kick on $1 $2 $3\n");
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,6 @@ package PBot::Channels;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Carp ();
|
||||
use PBot::HashObject;
|
||||
|
||||
@ -29,17 +26,16 @@ sub new {
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
my $pbot = delete $conf{pbot} // Carp::croak("Missing pbot reference to Channels");
|
||||
my $filename = delete $conf{filename};
|
||||
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to Channels");
|
||||
|
||||
$self->{pbot} = $pbot;
|
||||
$self->{channels} = PBot::HashObject->new(pbot => $pbot, name => 'Channels', filename => $filename);
|
||||
$self->{channels} = PBot::HashObject->new(pbot => $self->{pbot}, name => 'Channels', filename => delete $conf{filename});
|
||||
$self->load_channels;
|
||||
|
||||
$pbot->commands->register(sub { $self->set(@_) }, "chanset", 40);
|
||||
$pbot->commands->register(sub { $self->unset(@_) }, "chanunset", 40);
|
||||
$pbot->commands->register(sub { $self->add(@_) }, "chanadd", 40);
|
||||
$pbot->commands->register(sub { $self->remove(@_) }, "chanrem", 40);
|
||||
$pbot->commands->register(sub { $self->list(@_) }, "chanlist", 10);
|
||||
$self->{pbot}->commands->register(sub { $self->set(@_) }, "chanset", 40);
|
||||
$self->{pbot}->commands->register(sub { $self->unset(@_) }, "chanunset", 40);
|
||||
$self->{pbot}->commands->register(sub { $self->add(@_) }, "chanadd", 40);
|
||||
$self->{pbot}->commands->register(sub { $self->remove(@_) }, "chanrem", 40);
|
||||
$self->{pbot}->commands->register(sub { $self->list(@_) }, "chanlist", 10);
|
||||
}
|
||||
|
||||
sub set {
|
||||
|
@ -13,9 +13,6 @@ use strict;
|
||||
|
||||
use base 'PBot::Registerable';
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '1.0.0';
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
|
@ -9,9 +9,6 @@ package PBot::DualIndexHashObject;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = "1.0";
|
||||
|
||||
use Text::Levenshtein qw(fastdistance);
|
||||
use Carp ();
|
||||
|
||||
@ -30,18 +27,9 @@ sub new {
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
my $name = delete $conf{name};
|
||||
if(not defined $name) {
|
||||
$name = "dual index hash object";
|
||||
}
|
||||
|
||||
my $filename = delete $conf{filename};
|
||||
if(not defined $filename) {
|
||||
Carp::carp("Missing filename to DualIndexHashObject, will not be able to save to or load from file.");
|
||||
}
|
||||
|
||||
$self->{name} = $name;
|
||||
$self->{filename} = $filename;
|
||||
$self->{name} = delete $conf{name} // 'Dual Index hash object';
|
||||
$self->{filename} = delete $conf{filename} // Carp::carp("Missing filename to DualIndexHashObject, will not be able to save to or load from file.");
|
||||
$self->{ignore_duplicates} = delete $conf{ignore_duplicates} // 0;
|
||||
$self->{hash} = {};
|
||||
}
|
||||
|
||||
@ -50,7 +38,7 @@ sub load_hash_add {
|
||||
my ($self, $primary_index_key, $secondary_index_key, $hash, $i, $filename) = @_;
|
||||
|
||||
if(defined $hash) {
|
||||
if(exists $self->hash->{$primary_index_key}->{$secondary_index_key}) {
|
||||
if(not $self->{ignore_duplicates} and exists $self->hash->{$primary_index_key}->{$secondary_index_key}) {
|
||||
if($i) {
|
||||
Carp::croak "Duplicate secondary_index_key '$secondary_index_key' found in $filename around line $i\n";
|
||||
} else {
|
||||
@ -67,10 +55,9 @@ sub load_hash_add {
|
||||
}
|
||||
|
||||
sub load {
|
||||
my $self = shift;
|
||||
my $filename;
|
||||
my ($self, $filename) = @_;
|
||||
|
||||
if(@_) { $filename = shift; } else { $filename = $self->filename; }
|
||||
$filename = $self->filename if not defined $filename;
|
||||
|
||||
if(not defined $filename) {
|
||||
Carp::carp "No $self->{name} filename specified -- skipping loading from file";
|
||||
@ -93,19 +80,13 @@ sub load {
|
||||
|
||||
if($line =~ /^\[(.*)\]$/) {
|
||||
$primary_index_key = $1;
|
||||
|
||||
if(exists $self->hash->{$primary_index_key} and $primary_index_key ne '.*') {
|
||||
Carp::croak "Duplicate primary_index_key '$primary_index_key' at line $i of $filename\n";
|
||||
}
|
||||
|
||||
$self->hash->{$primary_index_key} = {};
|
||||
next;
|
||||
}
|
||||
|
||||
if($line =~ /^<(.*)>$/) {
|
||||
$secondary_index_key = $1;
|
||||
|
||||
if(exists $self->hash->{$primary_index_key}->{$secondary_index_key}) {
|
||||
if(not $self->{ignore_duplicates} and exists $self->hash->{$primary_index_key}->{$secondary_index_key}) {
|
||||
Carp::croak "Duplicate secondary_index_key '$secondary_index_key' at line $i of $filename\n";
|
||||
}
|
||||
|
||||
@ -237,12 +218,12 @@ sub levenshtein_matches {
|
||||
}
|
||||
|
||||
sub set {
|
||||
my ($self, $primary_index_key, $secondary_index_key, $key, $value) = @_;
|
||||
my ($self, $primary_index_key, $secondary_index_key, $key, $value, $dont_save) = @_;
|
||||
|
||||
my $primary = $self->find_index($primary_index_key);
|
||||
|
||||
if(not $primary) {
|
||||
my $result = "No such $self->{name} object group '$primary_index_key'; similiar matches: ";
|
||||
my $result = "No such $self->{name} object [$primary_index_key]; similiar matches: ";
|
||||
$result .= $self->levenshtein_matches($primary_index_key);
|
||||
return $result;
|
||||
}
|
||||
@ -250,13 +231,13 @@ sub set {
|
||||
my $secondary = $self->find_index($primary, $secondary_index_key);
|
||||
|
||||
if(not $secondary) {
|
||||
my $result = "No such $self->{name} object '$secondary_index_key'; similiar matches: ";
|
||||
my $result = "No such $self->{name} object [$primary_index_key] $secondary_index_key; similiar matches: ";
|
||||
$result .= $self->levenshtein_matches($primary, $secondary_index_key);
|
||||
return $result;
|
||||
}
|
||||
|
||||
if(not defined $key) {
|
||||
my $result = "[$self->{name}] (" . ($primary eq '.*' ? 'global' : $primary) . ") $secondary keys: ";
|
||||
my $result = "[" . ($primary eq '.*' ? 'global' : $primary) . "] $secondary keys: ";
|
||||
my $comma = '';
|
||||
foreach my $key (sort keys %{ $self->hash->{$primary}->{$secondary} }) {
|
||||
$result .= $comma . "$key => " . $self->hash->{$primary}->{$secondary}->{$key};
|
||||
@ -270,11 +251,11 @@ sub set {
|
||||
$value = $self->hash->{$primary}->{$secondary}->{$key};
|
||||
} else {
|
||||
$self->hash->{$primary}->{$secondary}->{$key} = $value;
|
||||
$self->save();
|
||||
$self->save unless $dont_save;
|
||||
}
|
||||
|
||||
$primary = 'global' if $primary eq '.*';
|
||||
return "[$self->{name}] ($primary) $secondary: '$key' " . (defined $value ? "set to '$value'" : "is not set.");
|
||||
return "[$primary] $secondary: '$key' " . (defined $value ? "set to '$value'" : "is not set.");
|
||||
}
|
||||
|
||||
sub unset {
|
||||
|
@ -8,9 +8,6 @@ package PBot::FactoidCommands;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Carp ();
|
||||
use Time::Duration;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
@ -87,7 +84,7 @@ sub call_factoid {
|
||||
my ($chan, $keyword, $args) = split / /, $arguments, 3;
|
||||
|
||||
if(not defined $chan or not defined $keyword) {
|
||||
return "Usage: !fact <channel> <keyword> [arguments]";
|
||||
return "Usage: fact <channel> <keyword> [arguments]";
|
||||
}
|
||||
|
||||
my ($channel, $trigger) = $self->{pbot}->factoids->find_factoid($chan, $keyword, $args, 1);
|
||||
@ -105,7 +102,7 @@ sub factset {
|
||||
my ($channel, $trigger, $key, $value) = split / /, $arguments, 4 if defined $arguments;
|
||||
|
||||
if(not defined $channel or not defined $trigger) {
|
||||
return "Usage: factset <channel> <factoid> [key <value>]"
|
||||
return "Usage: factset <channel> <factoid> [key [value]]";
|
||||
}
|
||||
|
||||
my $admininfo = $self->{pbot}->admins->loggedin($from, "$nick!$user\@$host");
|
||||
@ -194,13 +191,14 @@ sub factunset {
|
||||
sub list {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my $botnick = $self->{pbot}->botnick;
|
||||
my $text;
|
||||
|
||||
if(not defined $arguments) {
|
||||
return "/msg $nick Usage: list <modules|factoids|commands|admins>";
|
||||
}
|
||||
|
||||
# TODO - update this to use new MessageHistory API
|
||||
=cut
|
||||
if($arguments =~/^messages\s+(.*)$/) {
|
||||
my ($mask_search, $channel_search, $text_search) = split / /, $1;
|
||||
|
||||
@ -215,12 +213,12 @@ sub list {
|
||||
$nickserv = $self->{pbot}->antiflood->message_history->{$history_mask}->{nickserv_account} if exists $self->{pbot}->antiflood->message_history->{$history_mask}->{nickserv_account};
|
||||
|
||||
if($history_mask =~ m/$mask_search/i) {
|
||||
my $bot_trigger = $self->{pbot}->{registry}->get_value('general', 'trigger');
|
||||
foreach my $history_channel (keys %{ $self->{pbot}->antiflood->message_history->{$history_mask}->{channels} }) {
|
||||
if($history_channel =~ m/$channel_search/i) {
|
||||
my @messages = @{ $self->{pbot}->antiflood->message_history->{$history_mask}->{channels}->{$history_channel}{messages} };
|
||||
|
||||
for(my $i = 0; $i <= $#messages; $i++) {
|
||||
next if $messages[$i]->{msg} =~ /^\Q$self->{pbot}->{trigger}\E?login/; # don't reveal login passwords
|
||||
next if $messages[$i]->{msg} =~ /^\Q$bot_trigger\E?login/; # don't reveal login passwords
|
||||
|
||||
print "$history_mask, $history_channel\n";
|
||||
print "joinwatch: ", $self->{pbot}->antiflood->message_history->{$history_mask}->{channels}->{$history_channel}{join_watch}, "\n";
|
||||
@ -264,6 +262,7 @@ sub list {
|
||||
$self->{pbot}->logger->log($text);
|
||||
return "Messages:\n\n$text";
|
||||
}
|
||||
=cut
|
||||
|
||||
if($arguments =~ /^modules$/i) {
|
||||
$from = '.*' if not defined $from or $from !~ /^#/;
|
||||
|
@ -8,9 +8,6 @@ package PBot::FactoidModuleLauncher;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use POSIX qw(WNOHANG); # for children process reaping
|
||||
use Carp ();
|
||||
use Text::Balanced qw(extract_delimited);
|
||||
@ -55,7 +52,7 @@ sub execute_module {
|
||||
}
|
||||
|
||||
my $module = $self->{pbot}->factoids->factoids->hash->{$channel}->{$trigger}->{action};
|
||||
my $module_dir = $self->{pbot}->module_dir;
|
||||
my $module_dir = $self->{pbot}->{registry}->get_value('general', 'module_dir');
|
||||
|
||||
$self->{pbot}->logger->log("(" . (defined $from ? $from : "(undef)") . "): $nick!$user\@$host: Executing module $module $arguments\n");
|
||||
|
||||
@ -187,8 +184,8 @@ sub module_pipe_reader {
|
||||
my ($self, $buf) = @_;
|
||||
my ($channel, $text) = split / /, $buf, 2;
|
||||
return if not defined $text or not length $text;
|
||||
$text = $self->{pbot}->interpreter->truncate_result($channel, $self->{pbot}->{botnick}, 'undef', $text, $text, 0);
|
||||
$self->{pbot}->antiflood->check_flood($channel, $self->{pbot}->{botnick}, $self->{pbot}->{username}, 'localhost', $text, 0, 0, 0);
|
||||
$text = $self->{pbot}->interpreter->truncate_result($channel, $self->{pbot}->{registry}->get_value('irc', 'botnick'), 'undef', $text, $text, 0);
|
||||
$self->{pbot}->antiflood->check_flood($channel, $self->{pbot}->{registry}->get_value('irc', 'botnick'), $self->{pbot}->{registry}->get_value('irc', 'username'), 'localhost', $text, 0, 0, 0);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -8,14 +8,12 @@ package PBot::Factoids;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use HTML::Entities;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
use Carp ();
|
||||
use POSIX qw(strftime);
|
||||
|
||||
use PBot::PBot qw($VERSION);
|
||||
use PBot::FactoidModuleLauncher;
|
||||
use PBot::DualIndexHashObject;
|
||||
|
||||
@ -48,6 +46,9 @@ sub initialize {
|
||||
$self->{factoidmodulelauncher} = PBot::FactoidModuleLauncher->new(pbot => $pbot);
|
||||
|
||||
$self->{pbot}->{atexit}->register(sub { $self->save_factoids; return; });
|
||||
|
||||
$self->load_factoids;
|
||||
$self->add_factoid('text', '.*', $self->{pbot}->{registry}->get_value('irc', 'botnick'), 'version', "/say $VERSION", 1);
|
||||
}
|
||||
|
||||
sub load_factoids {
|
||||
@ -80,7 +81,7 @@ sub save_factoids {
|
||||
|
||||
sub add_factoid {
|
||||
my $self = shift;
|
||||
my ($type, $channel, $owner, $trigger, $action) = @_;
|
||||
my ($type, $channel, $owner, $trigger, $action, $dont_save) = @_;
|
||||
|
||||
$type = lc $type;
|
||||
$channel = lc $channel;
|
||||
@ -94,7 +95,7 @@ sub add_factoid {
|
||||
$self->factoids->hash->{$channel}->{$trigger}->{ref_user} = "nobody";
|
||||
$self->factoids->hash->{$channel}->{$trigger}->{rate_limit} = 15;
|
||||
|
||||
$self->save_factoids;
|
||||
$self->save_factoids unless $dont_save;
|
||||
}
|
||||
|
||||
sub remove_factoid {
|
||||
@ -104,6 +105,11 @@ sub remove_factoid {
|
||||
$channel = lc $channel;
|
||||
|
||||
delete $self->factoids->hash->{$channel}->{$trigger};
|
||||
|
||||
if(not scalar keys $self->factoids->hash->{$channel}) {
|
||||
delete $self->factoids->hash->{$channel};
|
||||
}
|
||||
|
||||
$self->save_factoids;
|
||||
}
|
||||
|
||||
@ -449,7 +455,7 @@ sub interpreter {
|
||||
|
||||
if(defined $tonick) { # !tell foo about bar
|
||||
$self->{pbot}->logger->log("($from): $nick!$user\@$host) sent to $tonick\n");
|
||||
my $botnick = $self->{pbot}->botnick;
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
|
||||
# get rid of original caller's nick
|
||||
$result =~ s/^\/([^ ]+) \Q$nick\E:\s+/\/$1 /;
|
||||
|
@ -9,9 +9,6 @@ package PBot::HashObject;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Text::Levenshtein qw(fastdistance);
|
||||
use Carp ();
|
||||
|
||||
|
@ -8,9 +8,6 @@ package PBot::IRCHandlers;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Carp();
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
@ -70,15 +67,16 @@ sub on_public {
|
||||
my $host = $event->host;
|
||||
my $text = $event->{args}[0];
|
||||
|
||||
$self->pbot->interpreter->process_line($from, $nick, $user, $host, $text);
|
||||
$self->{pbot}->interpreter->process_line($from, $nick, $user, $host, $text);
|
||||
}
|
||||
|
||||
sub on_msg {
|
||||
my ($self, $conn, $event) = @_;
|
||||
my ($nick, $host) = ($event->nick, $event->host);
|
||||
my $text = $event->{args}[0];
|
||||
my $bot_trigger = $self->{pbot}->{registry}->get_value('general', 'trigger');
|
||||
|
||||
$text =~ s/^\Q$self->{pbot}->{trigger}\E?(.*)/$self->{pbot}->{trigger}$1/;
|
||||
$text =~ s/^\Q$bot_trigger\E?(.*)/$bot_trigger$1/;
|
||||
$event->{to}[0] = $nick;
|
||||
$event->{args}[0] = $text;
|
||||
$self->on_public($conn, $event);
|
||||
@ -93,7 +91,7 @@ sub on_notice {
|
||||
|
||||
if($nick eq "NickServ" && $text =~ m/This nickname is registered/) {
|
||||
$self->{pbot}->logger->log("Identifying with NickServ . . .\n");
|
||||
$conn->privmsg("nickserv", "identify " . $self->pbot->identify_password);
|
||||
$conn->privmsg("nickserv", "identify " . $self->{pbot}->{registry}->get_value('irc', 'identify_password'));
|
||||
}
|
||||
|
||||
if($nick eq "NickServ" && $text =~ m/You are now identified/) {
|
||||
@ -143,7 +141,7 @@ sub on_mode {
|
||||
$self->{pbot}->bantracker->track_mode("$nick!$user\@$host", $mode, $target, $channel);
|
||||
}
|
||||
|
||||
if(defined $target && $target eq $self->{pbot}->botnick) { # bot targeted
|
||||
if(defined $target && $target eq $self->{pbot}->{registry}->get_value('irc', 'botnick')) { # bot targeted
|
||||
if($mode eq "+o") {
|
||||
$self->{pbot}->logger->log("$nick opped me in $channel\n");
|
||||
$self->{pbot}->chanops->{is_opped}->{$channel}{timeout} = gettimeofday + 300; # 5 minutes
|
||||
@ -165,7 +163,7 @@ sub on_mode {
|
||||
$self->{pbot}->chanops->{unban_timeout}->save;
|
||||
}
|
||||
}
|
||||
elsif($mode eq "+e" && $channel eq $self->{pbot}->botnick) {
|
||||
elsif($mode eq "+e" && $channel eq $self->{pbot}->{registry}->get_value('irc', 'botnick')) {
|
||||
foreach my $chan (keys %{ $self->{pbot}->channels->channels->hash }) {
|
||||
if($self->channels->channels->hash->{$chan}{enabled}) {
|
||||
$self->{pbot}->logger->log("Joining channel: $chan\n");
|
||||
@ -185,7 +183,7 @@ sub on_join {
|
||||
|
||||
my $message_account = $self->{pbot}->{messagehistory}->get_message_account($nick, $user, $host);
|
||||
$self->{pbot}->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $channel, "JOIN", $self->{pbot}->{messagehistory}->{MSG_JOIN});
|
||||
$self->{pbot}->antiflood->check_flood($channel, $nick, $user, $host, "JOIN", 4, 60 * 30, $self->{pbot}->{messagehistory}->{MSG_JOIN});
|
||||
$self->{pbot}->antiflood->check_flood($channel, $nick, $user, $host, "JOIN", $self->{pbot}->{registry}->get_value('antiflood', 'max_join_flood'), 60 * 30, $self->{pbot}->{messagehistory}->{MSG_JOIN});
|
||||
}
|
||||
|
||||
sub on_kick {
|
||||
@ -203,7 +201,7 @@ sub on_kick {
|
||||
my $text = "KICKED by $nick!$user\@$host ($reason)";
|
||||
|
||||
$self->{pbot}->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $channel, $text, $self->{pbot}->{messagehistory}->{MSG_DEPARTURE});
|
||||
$self->{pbot}->antiflood->check_flood($channel, $target_nick, $target_user, $target_host, $text, 4, 60 * 30, $self->{pbot}->{messagehistory}->{MSG_DEPARTURE});
|
||||
$self->{pbot}->antiflood->check_flood($channel, $target_nick, $target_user, $target_host, $text, $self->{pbot}->{registry}->get_value('antiflood', 'max_join_flood'), 60 * 30, $self->{pbot}->{messagehistory}->{MSG_DEPARTURE});
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,7 +225,7 @@ sub on_departure {
|
||||
$self->{pbot}->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $channel, $text, $self->{pbot}->{messagehistory}->{MSG_DEPARTURE});
|
||||
}
|
||||
|
||||
$self->{pbot}->antiflood->check_flood($channel, $nick, $user, $host, $text, 4, 60 * 30, $self->{pbot}->{messagehistory}->{MSG_DEPARTURE});
|
||||
$self->{pbot}->antiflood->check_flood($channel, $nick, $user, $host, $text, $self->{pbot}->{registry}->get_value('antiflood', 'max_join_flood'), 60 * 30, $self->{pbot}->{messagehistory}->{MSG_DEPARTURE});
|
||||
|
||||
my $admin = $self->{pbot}->admins->find_admin($channel, "$nick!$user\@$host");
|
||||
if(defined $admin and $admin->{loggedin}) {
|
||||
@ -255,12 +253,7 @@ sub on_nickchange {
|
||||
$self->{pbot}->{messagehistory}->{database}->devalidate_all_channels($newnick_account);
|
||||
$self->{pbot}->{messagehistory}->{database}->update_hostmask_data($newnick_account, { last_seen => scalar gettimeofday });
|
||||
|
||||
$self->{pbot}->antiflood->check_flood("$nick!$user\@$host", $nick, $user, $host, "NICKCHANGE $newnick", 3, 60 * 30, $self->{pbot}->{messagehistory}->{MSG_NICKCHANGE});
|
||||
}
|
||||
|
||||
sub pbot {
|
||||
my $self = shift;
|
||||
return $self->{pbot};
|
||||
$self->{pbot}->antiflood->check_flood("$nick!$user\@$host", $nick, $user, $host, "NICKCHANGE $newnick", $self->{pbot}->{registry}->get_value('antiflood', 'max_nick_flood'), 60 * 30, $self->{pbot}->{messagehistory}->{MSG_NICKCHANGE});
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -8,9 +8,6 @@ package PBot::IgnoreList;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
sub new {
|
||||
@ -28,20 +25,16 @@ sub new {
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
my $pbot = delete $conf{pbot};
|
||||
if(not defined $pbot) {
|
||||
Carp::croak("Missing pbot reference to Channels");
|
||||
}
|
||||
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to Channels");
|
||||
$self->{filename} = delete $conf{filename};
|
||||
|
||||
my $filename = delete $conf{filename};
|
||||
|
||||
$self->{pbot} = $pbot;
|
||||
$self->{ignore_list} = {};
|
||||
$self->{ignore_flood_counter} = {};
|
||||
$self->{last_timestamp} = {};
|
||||
$self->{filename} = $filename;
|
||||
|
||||
$pbot->timer->register(sub { $self->check_ignore_timeouts }, 10);
|
||||
$self->load_ignores;
|
||||
|
||||
$self->{pbot}->timer->register(sub { $self->check_ignore_timeouts }, 10);
|
||||
}
|
||||
|
||||
sub add {
|
||||
|
@ -8,9 +8,6 @@ package PBot::IgnoreListCommands;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
use Carp ();
|
||||
|
||||
|
@ -13,9 +13,6 @@ use base 'PBot::Registerable';
|
||||
use LWP::UserAgent;
|
||||
use Carp ();
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '1.0.0';
|
||||
|
||||
sub new {
|
||||
if(ref($_[1]) eq 'HASH') {
|
||||
Carp::croak("Options to Interpreter should be key/value pairs, not hash reference");
|
||||
@ -91,7 +88,7 @@ sub process_line {
|
||||
my $has_url;
|
||||
my $has_code;
|
||||
my $nick_override;
|
||||
my $mynick = $self->pbot->botnick;
|
||||
my $mynick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
|
||||
$from = lc $from if defined $from;
|
||||
|
||||
@ -100,7 +97,7 @@ sub process_line {
|
||||
my $message_account = $pbot->{messagehistory}->get_message_account($nick, $user, $host);
|
||||
$pbot->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $from, $text, $pbot->{messagehistory}->{MSG_CHAT});
|
||||
|
||||
$pbot->antiflood->check_flood($from, $nick, $user, $host, $text, $pbot->{MAX_FLOOD_MESSAGES}, 10, $pbot->{messagehistory}->{MSG_CHAT}) if defined $from;
|
||||
$pbot->antiflood->check_flood($from, $nick, $user, $host, $text, $pbot->{registry}->get_value('antiflood', 'max_chat_flood'), 10, $pbot->{messagehistory}->{MSG_CHAT}) if defined $from;
|
||||
|
||||
$text =~ s/^\s+//;
|
||||
$text =~ s/\s+$//;
|
||||
@ -109,10 +106,12 @@ sub process_line {
|
||||
my $cmd_text = $text;
|
||||
$cmd_text =~ s/^\/me\s+//;
|
||||
|
||||
if($cmd_text =~ /^$pbot->{trigger}?\s*{\s*(.*)\s*}\s*$/) {
|
||||
my $bot_trigger = $pbot->{registry}->get_value('general', 'trigger');
|
||||
|
||||
if($cmd_text =~ /^$bot_trigger?\s*{\s*(.*)\s*}\s*$/) {
|
||||
$has_code = $1 if length $1;
|
||||
$preserve_whitespace = 1;
|
||||
} elsif($cmd_text =~ /^\Q$pbot->{trigger}\E(.*)$/) {
|
||||
} elsif($cmd_text =~ /^\Q$bot_trigger\E(.*)$/) {
|
||||
$command = $1;
|
||||
} elsif($cmd_text =~ /^.?$mynick.?\s+(.*?)$/i) {
|
||||
$command = $1;
|
||||
@ -147,8 +146,9 @@ sub process_line {
|
||||
|
||||
sub truncate_result {
|
||||
my ($self, $from, $nick, $text, $original_result, $result, $paste) = @_;
|
||||
my $max_msg_len = $self->{pbot}->{registry}->get_value('irc', 'max_msg_len');
|
||||
|
||||
if(length $result > $self->{pbot}->max_msg_len) {
|
||||
if(length $result > $max_msg_len) {
|
||||
my $link;
|
||||
if($paste) {
|
||||
$link = paste_sprunge("[" . (defined $from ? $from : "stdin") . "] <$nick> $text\n\n$original_result");
|
||||
@ -159,7 +159,7 @@ sub truncate_result {
|
||||
my $trunc = "... [truncated; see $link for full text.]";
|
||||
$self->{pbot}->logger->log("Message truncated -- pasted to $link\n") if $paste;
|
||||
|
||||
my $trunc_len = length $result < $self->{pbot}->max_msg_len ? length $result : $self->{pbot}->max_msg_len;
|
||||
my $trunc_len = length $result < $max_msg_len ? length $result : $max_msg_len;
|
||||
$result = substr($result, 0, $trunc_len);
|
||||
substr($result, $trunc_len - length $trunc) = $trunc;
|
||||
}
|
||||
@ -169,7 +169,7 @@ sub truncate_result {
|
||||
|
||||
sub handle_result {
|
||||
my ($self, $from, $nick, $user, $host, $text, $command, $result, $checkflood, $preserve_whitespace) = @_;
|
||||
my ($pbot, $mynick) = ($self->{pbot}, $self->{pbot}->{botnick});
|
||||
my ($pbot, $mynick) = ($self->{pbot}, $self->{pbot}->{registry}->get_value('irc', 'botnick'));
|
||||
|
||||
if(not defined $result or length $result == 0) {
|
||||
return;
|
||||
@ -194,10 +194,10 @@ sub handle_result {
|
||||
|
||||
if($result =~ s/^\/say\s+//i) {
|
||||
$pbot->conn->privmsg($from, $result) if defined $from && $from !~ /\Q$mynick\E/i;
|
||||
$pbot->antiflood->check_flood($from, $pbot->{botnick}, $pbot->{username}, 'localhost', $result, 0, 0, 0) if $checkflood;
|
||||
$pbot->antiflood->check_flood($from, $mynick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $result, 0, 0, 0) if $checkflood;
|
||||
} elsif($result =~ s/^\/me\s+//i) {
|
||||
$pbot->conn->me($from, $result) if defined $from && $from !~ /\Q$mynick\E/i;
|
||||
$pbot->antiflood->check_flood($from, $pbot->{botnick}, $pbot->{username}, 'localhost', '/me ' . $result, 0, 0, 0) if $checkflood;
|
||||
$pbot->antiflood->check_flood($from, $mynick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/me ' . $result, 0, 0, 0) if $checkflood;
|
||||
} elsif($result =~ s/^\/msg\s+([^\s]+)\s+//i) {
|
||||
my $to = $1;
|
||||
if($to =~ /,/) {
|
||||
@ -208,15 +208,15 @@ sub handle_result {
|
||||
}
|
||||
elsif($result =~ s/^\/me\s+//i) {
|
||||
$pbot->conn->me($to, $result) if $to !~ /\Q$mynick\E/i;
|
||||
$pbot->antiflood->check_flood($to, $pbot->{botnick}, $pbot->{username}, 'localhost', '/me ' . $result, 0, 0, 0) if $checkflood;
|
||||
$pbot->antiflood->check_flood($to, $mynick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/me ' . $result, 0, 0, 0) if $checkflood;
|
||||
} else {
|
||||
$result =~ s/^\/say\s+//i;
|
||||
$pbot->conn->privmsg($to, $result) if $to !~ /\Q$mynick\E/i;
|
||||
$pbot->antiflood->check_flood($to, $pbot->{botnick}, $pbot->{username}, 'localhost', $result, 0, 0, 0) if $checkflood;
|
||||
$pbot->antiflood->check_flood($to, $mynick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $result, 0, 0, 0) if $checkflood;
|
||||
}
|
||||
} else {
|
||||
$pbot->conn->privmsg($from, $result) if defined $from && $from !~ /\Q$mynick\E/i;
|
||||
$pbot->antiflood->check_flood($from, $pbot->{botnick}, $pbot->{username}, 'localhost', $result, 0, 0, 0) if $checkflood;
|
||||
$pbot->antiflood->check_flood($from, $mynick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $result, 0, 0, 0) if $checkflood;
|
||||
}
|
||||
$pbot->logger->log("---------------------------------------------\n");
|
||||
}
|
||||
|
@ -11,9 +11,6 @@ use strict;
|
||||
|
||||
use feature 'switch';
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use Time::HiRes qw(gettimeofday tv_interval);
|
||||
use Time::Duration;
|
||||
use Carp ();
|
||||
|
@ -3,9 +3,6 @@ package PBot::Logger;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '1.0.0';
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
|
@ -33,7 +33,7 @@ sub new {
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
|
||||
$self->{filename} = delete $conf{filename} // $self->{pbot}->{data_dir} . '/message_history.sqlite3';
|
||||
$self->{filename} = delete $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}->begin();
|
||||
|
@ -27,7 +27,7 @@ sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference in " . __FILE__);
|
||||
$self->{filename} = delete $conf{filename} // $self->{pbot}->{data_dir} . '/message_history.sqlite3';
|
||||
$self->{filename} = delete $conf{filename} // $self->{pbot}->{registry}->get_value('general', 'data_dir') . '/message_history.sqlite3';
|
||||
|
||||
$self->{pbot}->timer->register(sub { $self->commit_message_history }, 5);
|
||||
$self->{new_entries} = 0;
|
||||
@ -433,8 +433,10 @@ sub recall_message_by_count {
|
||||
$self->{pbot}->logger->log($@) if $@;
|
||||
|
||||
if(defined $ignore_command) {
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
my $bot_trigger = $self->{pbot}->{registry}->get_value('general', 'trigger');
|
||||
foreach my $message (@$messages) {
|
||||
next if $message->{msg} =~ m/^$self->{pbot}->{botnick}. $ignore_command/ or $message->{msg} =~ m/^$self->{pbot}->{trigger}$ignore_command/;
|
||||
next if $message->{msg} =~ m/^$botnick. $ignore_command/ or $message->{msg} =~ m/^$bot_trigger$ignore_command/;
|
||||
return $message;
|
||||
}
|
||||
return undef;
|
||||
@ -474,8 +476,10 @@ sub recall_message_by_text {
|
||||
$self->{pbot}->logger->log($@) if $@;
|
||||
|
||||
if(defined $ignore_command) {
|
||||
my $bot_trigger = $self->{pbot}->{registry}->get_value('general', 'trigger');
|
||||
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
|
||||
foreach my $message (@$messages) {
|
||||
next if $message->{msg} =~ m/^$self->{pbot}->{botnick}. $ignore_command/ or $message->{msg} =~ m/^$self->{pbot}->{trigger}$ignore_command/;
|
||||
next if $message->{msg} =~ m/^$botnick. $ignore_command/ or $message->{msg} =~ m/^$bot_trigger$ignore_command/;
|
||||
return $message;
|
||||
}
|
||||
return undef;
|
||||
|
207
PBot/PBot.pm
207
PBot/PBot.pm
@ -12,8 +12,14 @@ use warnings;
|
||||
|
||||
use PBot::VERSION;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = PBot::VERSION::BUILD_NAME . " revision " . PBot::VERSION::BUILD_REVISION . " " . PBot::VERSION::BUILD_DATE;
|
||||
BEGIN {
|
||||
use Exporter;
|
||||
our @ISA = 'Exporter';
|
||||
our @EXPORT = qw($VERSION);
|
||||
|
||||
our $VERSION = PBot::VERSION::BUILD_NAME . " revision " . PBot::VERSION::BUILD_REVISION . " " . PBot::VERSION::BUILD_DATE;
|
||||
print "PBot version $VERSION\n";
|
||||
}
|
||||
|
||||
# unbuffer stdout
|
||||
STDOUT->autoflush(1);
|
||||
@ -21,6 +27,8 @@ STDOUT->autoflush(1);
|
||||
use Carp ();
|
||||
use PBot::Logger;
|
||||
|
||||
use PBot::Registry;
|
||||
|
||||
use PBot::SelectHandler;
|
||||
use PBot::StdinReader;
|
||||
|
||||
@ -69,73 +77,70 @@ sub new {
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
my $log_file = delete $conf{log_file};
|
||||
# logger created first to allow other modules to log things
|
||||
$self->{logger} = PBot::Logger->new(log_file => delete $conf{log_file});
|
||||
|
||||
$self->{config_dir} = delete $conf{config_dir} // "$ENV{HOME}/pbot/config";
|
||||
$self->{data_dir} = delete $conf{data_dir} // "$ENV{HOME}/pbot/data";
|
||||
$self->{module_dir} = delete $conf{module_dir} // "$ENV{HOME}/pbot/modules";
|
||||
$self->{atexit} = PBot::Registerable->new();
|
||||
$self->{timer} = PBot::Timer->new(timeout => 10);
|
||||
$self->{commands} = PBot::Commands->new(pbot => $self);
|
||||
|
||||
$self->{ircserver} = delete $conf{ircserver} // "irc.freenode.net";
|
||||
$self->{port} = delete $conf{port} // 6667;
|
||||
$self->{SSL} = delete $conf{SSL} // 0;
|
||||
$self->{SSL_ca_file} = delete $conf{SSL_ca_file} // undef;
|
||||
$self->{SSL_ca_path} = delete $conf{SSL_ca_path} // undef;
|
||||
$self->{botnick} = delete $conf{botnick} // "pbot3";
|
||||
$self->{username} = delete $conf{username} // "pbot3";
|
||||
$self->{ircname} = delete $conf{ircname} // "http://code.google.com/p/pbot2-pl/";
|
||||
$self->{identify_password} = delete $conf{identify_password} // "";
|
||||
my $config_dir = delete $conf{config_dir} // "$ENV{HOME}/pbot/config";
|
||||
|
||||
$self->{max_msg_len} = delete $conf{max_msg_len} // 425;
|
||||
$self->{MAX_FLOOD_MESSAGES} = delete $conf{MAX_FLOOD_MESSAGES} // 4;
|
||||
$self->{MAX_NICK_MESSAGES} = delete $conf{MAX_NICK_MESSAGES} // 32;
|
||||
# registry created, but not yet loaded, to allow modules to create default values and triggers
|
||||
$self->{registry} = PBot::Registry->new(pbot => $self, filename => delete $conf{registry_file} // "$config_dir/registry");
|
||||
|
||||
$self->{trigger} = delete $conf{trigger} // '!';
|
||||
$self->{registry}->add_default('text', 'general', 'config_dir', $config_dir);
|
||||
$self->{registry}->add_default('text', 'general', 'data_dir', delete $conf{data_dir} // "$ENV{HOME}/pbot/data");
|
||||
$self->{registry}->add_default('text', 'general', 'module_dir', delete $conf{module_dir} // "$ENV{HOME}/pbot/modules");
|
||||
$self->{registry}->add_default('text', 'general', 'trigger', delete $conf{trigger} // '!');
|
||||
|
||||
my $messagehistory_file = delete $conf{message_history_file};
|
||||
my $channels_file = delete $conf{channels_file};
|
||||
my $admins_file = delete $conf{admins_file};
|
||||
my $ignorelist_file = delete $conf{ignorelist_file};
|
||||
$self->{registry}->add_default('text', 'irc', 'max_msg_len', delete $conf{max_msg_len} // 425);
|
||||
$self->{registry}->add_default('text', 'irc', 'ircserver', delete $conf{ircserver} // "irc.freenode.net");
|
||||
$self->{registry}->add_default('text', 'irc', 'port', delete $conf{port} // 6667);
|
||||
$self->{registry}->add_default('text', 'irc', 'SSL', delete $conf{SSL} // 0);
|
||||
$self->{registry}->add_default('text', 'irc', 'SSL_ca_file', delete $conf{SSL_ca_file} // 'none');
|
||||
$self->{registry}->set('irc', 'SSL_ca_file', 'private', 1);
|
||||
$self->{registry}->add_default('text', 'irc', 'SSL_ca_path', delete $conf{SSL_ca_path} // 'none');
|
||||
$self->{registry}->set('irc', 'SSL_ca_path', 'private', 1);
|
||||
$self->{registry}->add_default('text', 'irc', 'botnick', delete $conf{botnick} // "pbot3");
|
||||
$self->{registry}->add_default('text', 'irc', 'username', delete $conf{username} // "pbot3");
|
||||
$self->{registry}->add_default('text', 'irc', 'ircname', delete $conf{ircname} // "http://code.google.com/p/pbot2-pl/");
|
||||
$self->{registry}->add_default('text', 'irc', 'identify_password', delete $conf{identify_password} // "");
|
||||
$self->{registry}->set('irc', 'identify_password', 'private', 1);
|
||||
|
||||
my $factoids_file = delete $conf{factoids_file};
|
||||
my $export_factoids_path = delete $conf{export_factoids_path};
|
||||
my $export_factoids_site = delete $conf{export_factoids_site};
|
||||
$self->{registry}->add_trigger('irc', 'botnick', sub { $self->change_botnick_trigger(@_) });
|
||||
|
||||
my $quotegrabs_file = delete $conf{quotegrabs_file};
|
||||
my $export_quotegrabs_path = delete $conf{export_quotegrabs_path};
|
||||
my $export_quotegrabs_site = delete $conf{export_quotegrabs_site};
|
||||
$self->{registry}->add_default('text', 'antiflood', 'max_join_flood', delete $conf{max_join_flood} // 4);
|
||||
$self->{registry}->add_default('text', 'antiflood', 'max_chat_flood', delete $conf{max_chat_flood} // 4);
|
||||
$self->{registry}->add_default('text', 'antiflood', 'max_enter_flood', delete $conf{max_enter_flood} // 4);
|
||||
$self->{registry}->add_default('text', 'antiflood', 'max_nick_flood', delete $conf{max_nick_flood} // 3);
|
||||
|
||||
$self->{logger} = PBot::Logger->new(log_file => $log_file);
|
||||
$self->{commands} = PBot::Commands->new(pbot => $self);
|
||||
$self->{timer} = PBot::Timer->new(timeout => 10);
|
||||
|
||||
$self->{atexit} = PBot::Registerable->new();
|
||||
$self->{registry}->add_default('text', 'antiflood', 'enter_abuse_max_lines', delete $conf{enter_abuse_max_lines} // 4);
|
||||
$self->{registry}->add_default('text', 'antiflood', 'enter_abuse_max_seconds', delete $conf{enter_abuse_max_seconds} // 20);
|
||||
$self->{registry}->add_default('text', 'antiflood', 'enter_abuse_max_offenses', delete $conf{enter_abuse_max_offenses} // 3);
|
||||
|
||||
$self->{registry}->add_default('text', 'messagehistory', 'max_messages', delete $conf{max_messages} // 32);
|
||||
|
||||
$self->{select_handler} = PBot::SelectHandler->new(pbot => $self);
|
||||
$self->{stdin_reader} = PBot::StdinReader->new(pbot => $self);
|
||||
|
||||
$self->{admins} = PBot::BotAdmins->new(pbot => $self, filename => $admins_file);
|
||||
$self->{admins} = PBot::BotAdmins->new(pbot => $self, filename => delete $conf{admins_file});
|
||||
$self->admins->load_admins();
|
||||
$self->admins->add_admin($self->{botnick}, '.*', "$self->{botnick}!stdin\@localhost", 60, 'admin');
|
||||
$self->admins->login($self->{botnick}, "$self->{botnick}!stdin\@localhost", 'admin');
|
||||
|
||||
$self->{factoids} = PBot::Factoids->new(
|
||||
pbot => $self,
|
||||
filename => $factoids_file,
|
||||
export_path => $export_factoids_path,
|
||||
export_site => $export_factoids_site,
|
||||
filename => delete $conf{factoids_file},
|
||||
export_path => delete $conf{export_factoids_path},
|
||||
export_site => delete $conf{export_factoids_site},
|
||||
);
|
||||
|
||||
$self->factoids->load_factoids() if defined $factoids_file;
|
||||
$self->factoids->add_factoid('text', '.*', $self->{botnick}, 'version', "/say $VERSION");
|
||||
|
||||
$self->{bantracker} = PBot::BanTracker->new(pbot => $self);
|
||||
|
||||
$self->{lagchecker} = PBot::LagChecker->new(pbot => $self);
|
||||
$self->{messagehistory} = PBot::MessageHistory->new(pbot => $self, filename => $messagehistory_file);
|
||||
$self->{messagehistory} = PBot::MessageHistory->new(pbot => $self, filename => delete $conf{messagehistory_file});
|
||||
$self->{antiflood} = PBot::AntiFlood->new(pbot => $self);
|
||||
|
||||
$self->{ignorelist} = PBot::IgnoreList->new(pbot => $self, filename => $ignorelist_file);
|
||||
$self->{ignorelist}->load_ignores() if defined $ignorelist_file;
|
||||
$self->{ignorelist} = PBot::IgnoreList->new(pbot => $self, filename => delete $conf{ignorelist_file});
|
||||
|
||||
$self->interpreter(PBot::Interpreter->new(pbot => $self));
|
||||
$self->interpreter->register(sub { return $self->commands->interpreter(@_); });
|
||||
@ -148,21 +153,27 @@ sub initialize {
|
||||
$self->{irc} = PBot::IRC->new();
|
||||
$self->{irchandlers} = PBot::IRCHandlers->new(pbot => $self);
|
||||
|
||||
$self->{channels} = PBot::Channels->new(pbot => $self, filename => $channels_file);
|
||||
$self->channels->load_channels() if defined $channels_file;
|
||||
$self->{channels} = PBot::Channels->new(pbot => $self, filename => delete $conf{channels_file});
|
||||
|
||||
$self->{chanops} = PBot::ChanOps->new(pbot => $self);
|
||||
$self->{chanopcmds} = PBot::ChanOpCommands->new(pbot => $self);
|
||||
|
||||
$self->{chanops}->{unban_timeout}->load;
|
||||
|
||||
$self->{quotegrabs} = PBot::Quotegrabs->new(
|
||||
pbot => $self,
|
||||
filename => $quotegrabs_file,
|
||||
export_path => $export_quotegrabs_path,
|
||||
export_site => $export_quotegrabs_site,
|
||||
filename => delete $conf{quotegrabs_file},
|
||||
export_path => delete $conf{export_quotegrabs_path},
|
||||
export_site => delete $conf{export_quotegrabs_site},
|
||||
);
|
||||
|
||||
# load registry entries from file to overwrite defaults
|
||||
$self->{registry}->load;
|
||||
|
||||
# create implicit bot-admin account for bot
|
||||
my $botnick = $self->{registry}->get_value('irc', 'botnick');
|
||||
$self->admins->add_admin($botnick, '.*', "$botnick!stdin\@localhost", 60, 'admin', 1);
|
||||
$self->admins->login($botnick, "$botnick!stdin\@localhost", 'admin');
|
||||
|
||||
# start timer
|
||||
$self->timer->start();
|
||||
}
|
||||
|
||||
@ -171,47 +182,47 @@ sub initialize {
|
||||
sub connect {
|
||||
my ($self, $server) = @_;
|
||||
|
||||
$server = $self->ircserver if not defined $server;
|
||||
|
||||
if($self->{connected}) {
|
||||
# TODO: disconnect, clean-up, etc
|
||||
}
|
||||
|
||||
$server = $self->{registry}->get_value('irc', 'ircserver') if not defined $server;
|
||||
|
||||
$self->logger->log("Connecting to $server ...\n");
|
||||
|
||||
$self->conn($self->irc->newconn(
|
||||
Nick => $self->{botnick},
|
||||
Username => $self->{username},
|
||||
Ircname => $self->{ircname},
|
||||
Nick => $self->{registry}->get_value('irc', 'botnick'),
|
||||
Username => $self->{registry}->get_value('irc', 'username'),
|
||||
Ircname => $self->{registry}->get_value('irc', 'ircname'),
|
||||
Server => $server,
|
||||
SSL => $self->{SSL},
|
||||
SSL_ca_file => $self->{SSL_ca_file},
|
||||
SSL_ca_path => $self->{SSL_ca_path},
|
||||
Port => $self->{port}))
|
||||
SSL => $self->{registry}->get_value('irc', 'SSL'),
|
||||
SSL_ca_file => $self->{registry}->get_value('irc', 'SSL_ca_file'),
|
||||
SSL_ca_path => $self->{registry}->get_value('irc', 'SSL_ca_path'),
|
||||
Port => $self->{registry}->get_value('irc', 'port')))
|
||||
or Carp::croak "$0: Can't connect to IRC server.\n";
|
||||
|
||||
$self->{connected} = 1;
|
||||
|
||||
#set up default handlers for the IRC engine
|
||||
$self->conn->add_handler([ 251,252,253,254,302,255 ], sub { $self->irchandlers->on_init(@_) });
|
||||
$self->conn->add_handler(376 , sub { $self->irchandlers->on_connect(@_) });
|
||||
$self->conn->add_handler('disconnect' , sub { $self->irchandlers->on_disconnect(@_) });
|
||||
$self->conn->add_handler('notice' , sub { $self->irchandlers->on_notice(@_) });
|
||||
$self->conn->add_handler('caction' , sub { $self->irchandlers->on_action(@_) });
|
||||
$self->conn->add_handler('public' , sub { $self->irchandlers->on_public(@_) });
|
||||
$self->conn->add_handler('msg' , sub { $self->irchandlers->on_msg(@_) });
|
||||
$self->conn->add_handler('mode' , sub { $self->irchandlers->on_mode(@_) });
|
||||
$self->conn->add_handler('part' , sub { $self->irchandlers->on_departure(@_) });
|
||||
$self->conn->add_handler('join' , sub { $self->irchandlers->on_join(@_) });
|
||||
$self->conn->add_handler('kick' , sub { $self->irchandlers->on_kick(@_) });
|
||||
$self->conn->add_handler('quit' , sub { $self->irchandlers->on_departure(@_) });
|
||||
$self->conn->add_handler('nick' , sub { $self->irchandlers->on_nickchange(@_) });
|
||||
$self->conn->add_handler('pong' , sub { $self->lagchecker->on_pong(@_) });
|
||||
$self->conn->add_handler('whoisaccount' , sub { $self->antiflood->on_whoisaccount(@_) });
|
||||
$self->conn->add_handler([ 251,252,253,254,302,255 ], sub { $self->irchandlers->on_init(@_) });
|
||||
$self->conn->add_handler(376 , sub { $self->irchandlers->on_connect(@_) });
|
||||
$self->conn->add_handler('disconnect' , sub { $self->irchandlers->on_disconnect(@_) });
|
||||
$self->conn->add_handler('notice' , sub { $self->irchandlers->on_notice(@_) });
|
||||
$self->conn->add_handler('caction' , sub { $self->irchandlers->on_action(@_) });
|
||||
$self->conn->add_handler('public' , sub { $self->irchandlers->on_public(@_) });
|
||||
$self->conn->add_handler('msg' , sub { $self->irchandlers->on_msg(@_) });
|
||||
$self->conn->add_handler('mode' , sub { $self->irchandlers->on_mode(@_) });
|
||||
$self->conn->add_handler('part' , sub { $self->irchandlers->on_departure(@_) });
|
||||
$self->conn->add_handler('join' , sub { $self->irchandlers->on_join(@_) });
|
||||
$self->conn->add_handler('kick' , sub { $self->irchandlers->on_kick(@_) });
|
||||
$self->conn->add_handler('quit' , sub { $self->irchandlers->on_departure(@_) });
|
||||
$self->conn->add_handler('nick' , sub { $self->irchandlers->on_nickchange(@_) });
|
||||
$self->conn->add_handler('pong' , sub { $self->lagchecker->on_pong(@_) });
|
||||
$self->conn->add_handler('whoisaccount' , sub { $self->antiflood->on_whoisaccount(@_) });
|
||||
$self->conn->add_handler('banlist' , sub { $self->bantracker->on_banlist_entry(@_) });
|
||||
$self->conn->add_handler('endofnames' , sub { $self->bantracker->get_banlist(@_) });
|
||||
# freenode quietlist
|
||||
$self->conn->add_handler(728 , sub { $self->bantracker->on_quietlist_entry(@_) });
|
||||
$self->conn->add_handler('endofnames' , sub { $self->bantracker->get_banlist(@_) });
|
||||
}
|
||||
|
||||
#main loop
|
||||
@ -228,7 +239,7 @@ sub do_one_loop {
|
||||
sub start {
|
||||
my $self = shift;
|
||||
|
||||
if(not defined $self->{connected} or $self->{connected} == 0) {
|
||||
if(not $self->{connected}) {
|
||||
$self->connect();
|
||||
}
|
||||
|
||||
@ -247,6 +258,14 @@ sub atexit {
|
||||
$self->{atexit}->execute_all;
|
||||
}
|
||||
|
||||
sub change_botnick_trigger {
|
||||
my ($self, $section, $item, $newvalue) = @_;
|
||||
|
||||
if($self->{connected}) {
|
||||
$self->conn->nick($newvalue);
|
||||
}
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------------
|
||||
# Getters/Setters
|
||||
#-----------------------------------------------------------------------------------
|
||||
@ -310,30 +329,6 @@ sub commands {
|
||||
return $self->{commands};
|
||||
}
|
||||
|
||||
sub botnick {
|
||||
my $self = shift;
|
||||
if(@_) { $self->{botnick} = shift; }
|
||||
return $self->{botnick};
|
||||
}
|
||||
|
||||
sub identify_password {
|
||||
my $self = shift;
|
||||
if(@_) { $self->{identify_password} = shift; }
|
||||
return $self->{identify_password};
|
||||
}
|
||||
|
||||
sub max_msg_len {
|
||||
my $self = shift;
|
||||
if(@_) { $self->{max_msg_len} = shift; }
|
||||
return $self->{max_msg_len};
|
||||
}
|
||||
|
||||
sub module_dir {
|
||||
my $self = shift;
|
||||
if(@_) { $self->{module_dir} = shift; }
|
||||
return $self->{module_dir};
|
||||
}
|
||||
|
||||
sub ignorelist {
|
||||
my $self = shift;
|
||||
if(@_) { $self->{ignorelist} = shift; }
|
||||
@ -370,10 +365,4 @@ sub chanops {
|
||||
return $self->{chanops};
|
||||
}
|
||||
|
||||
sub ircserver {
|
||||
my $self = shift;
|
||||
if(@_) { $self->{ircserver} = shift; }
|
||||
return $self->{ircserver};
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -8,9 +8,6 @@ package PBot::Quotegrabs;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use HTML::Entities;
|
||||
use Time::Duration;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
@ -8,9 +8,6 @@ package PBot::Quotegrabs_Hashtable;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use HTML::Entities;
|
||||
use Time::Duration;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
@ -8,9 +8,6 @@ package PBot::Quotegrabs_SQLite;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = $PBot::PBot::VERSION;
|
||||
|
||||
use DBI;
|
||||
use Carp qw(shortmess);
|
||||
|
||||
|
@ -8,9 +8,6 @@ package PBot::Registerable;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '1.0.0';
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
|
156
PBot/Registry.pm
Normal file
156
PBot/Registry.pm
Normal file
@ -0,0 +1,156 @@
|
||||
# File: Registry.pm
|
||||
# Author: pragma_
|
||||
#
|
||||
# Purpose: Provides a centralized registry of configuration settings that can
|
||||
# easily be examined and updated via set/unset commands without restarting.
|
||||
|
||||
package PBot::Registry;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
use Carp ();
|
||||
|
||||
use PBot::DualIndexHashObject;
|
||||
use PBot::RegistryCommands;
|
||||
|
||||
sub new {
|
||||
if(ref($_[1]) eq 'HASH') {
|
||||
Carp::croak("Options to " . __FILE__ . " should be item/value pairs, not hash reference");
|
||||
}
|
||||
|
||||
my ($class, %conf) = @_;
|
||||
my $self = bless {}, $class;
|
||||
$self->initialize(%conf);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
$self->{pbot} = delete $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__);
|
||||
my $filename = delete $conf{filename};
|
||||
|
||||
$self->{registry} = PBot::DualIndexHashObject->new(name => 'Registry', filename => $filename, ignore_duplicates => 1);
|
||||
$self->{triggers} = {};
|
||||
|
||||
$self->{pbot}->{atexit}->register(sub { $self->save; return; });
|
||||
|
||||
PBot::RegistryCommands->new(pbot => $self->{pbot});
|
||||
}
|
||||
|
||||
sub load {
|
||||
my $self = shift;
|
||||
|
||||
$self->{pbot}->logger->log("Loading registry from " . $self->{registry}->{filename} . " ...\n");
|
||||
|
||||
$self->{registry}->load;
|
||||
|
||||
foreach my $section (keys %{ $self->{registry}->hash }) {
|
||||
foreach my $item (keys %{ $self->{registry}->hash->{$section} }) {
|
||||
$self->process_trigger($section, $item, $self->{registry}->hash->{$section}->{$item}->{value});
|
||||
}
|
||||
}
|
||||
|
||||
$self->{pbot}->logger->log("Done.\n");
|
||||
}
|
||||
|
||||
sub save {
|
||||
my $self = shift;
|
||||
$self->{registry}->save;
|
||||
}
|
||||
|
||||
sub add_default {
|
||||
my ($self, $type, $section, $item, $value) = @_;
|
||||
$self->add($type, $section, $item, $value, 1);
|
||||
}
|
||||
|
||||
sub add {
|
||||
my $self = shift;
|
||||
my ($type, $section, $item, $value, $is_default) = @_;
|
||||
|
||||
$type = lc $type;
|
||||
$section = lc $section;
|
||||
$item = lc $item;
|
||||
|
||||
$self->{registry}->hash->{$section}->{$item}->{value} = $value;
|
||||
$self->{registry}->hash->{$section}->{$item}->{type} = $type;
|
||||
|
||||
$self->process_trigger($section, $item, $value) unless $is_default;
|
||||
$self->save_registry unless $is_default;
|
||||
}
|
||||
|
||||
sub remove {
|
||||
my $self = shift;
|
||||
my ($section, $item) = @_;
|
||||
|
||||
$section = lc $section;
|
||||
|
||||
delete $self->{registry}->hash->{$section}->{$item};
|
||||
|
||||
if(not scalar keys $self->{registry}->hash->{$section}) {
|
||||
delete $self->{registry}->hash->{$section};
|
||||
}
|
||||
|
||||
$self->save_registry;
|
||||
}
|
||||
|
||||
sub set {
|
||||
my ($self, $section, $item, $key, $value) = @_;
|
||||
|
||||
$section = lc $section;
|
||||
$item = lc $item;
|
||||
$key = lc $key if defined $key;
|
||||
|
||||
my $oldvalue = $self->get_value($section, $item, 1) if defined $value;
|
||||
$oldvalue = '' if not defined $oldvalue;
|
||||
|
||||
my $result = $self->{registry}->set($section, $item, $key, $value, 1);
|
||||
|
||||
if(defined $key and $key eq 'value' and defined $value and $oldvalue ne $value) {
|
||||
$self->process_trigger($section, $item, $value);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub unset {
|
||||
my ($self, $section, $item, $key) = @_;
|
||||
|
||||
$section = lc $section;
|
||||
$item = lc $item;
|
||||
$key = lc $key;
|
||||
|
||||
return $self->{registry}->unset($section, $item, $key);
|
||||
}
|
||||
|
||||
sub get_value {
|
||||
my ($self, $section, $item, $as_text) = @_;
|
||||
|
||||
if(exists $self->{registry}->hash->{$section} and exists $self->{registry}->hash->{$section}->{$item}) {
|
||||
if(not $as_text and $self->{registry}->hash->{$section}->{$item}->{type} eq 'array') {
|
||||
return split /\s*,\s*/, $self->{registry}->hash->{$section}->{$item}->{value};
|
||||
} else {
|
||||
return $self->{registry}->hash->{$section}->{$item}->{value};
|
||||
}
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub add_trigger {
|
||||
my ($self, $section, $item, $subref) = @_;
|
||||
$self->{triggers}->{$section}->{$item} = $subref;
|
||||
}
|
||||
|
||||
sub process_trigger {
|
||||
my $self = shift;
|
||||
my ($section, $item) = @_;
|
||||
|
||||
if(exists $self->{triggers}->{$section} and exists $self->{triggers}->{$section}->{$item}) {
|
||||
return &{ $self->{triggers}->{$section}->{$item} }(@_);
|
||||
}
|
||||
return undef;
|
||||
}
|
||||
|
||||
1;
|
240
PBot/RegistryCommands.pm
Normal file
240
PBot/RegistryCommands.pm
Normal file
@ -0,0 +1,240 @@
|
||||
# File: RegistryCommands.pm
|
||||
# Author: pragma_
|
||||
#
|
||||
# Purpose: Commands to introspect and update Registry
|
||||
|
||||
package PBot::RegistryCommands;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub new {
|
||||
if(ref($_[1]) eq 'HASH') {
|
||||
Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference");
|
||||
}
|
||||
|
||||
my ($class, %conf) = @_;
|
||||
my $self = bless {}, $class;
|
||||
$self->initialize(%conf);
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub initialize {
|
||||
my ($self, %conf) = @_;
|
||||
|
||||
my $pbot = delete $conf{pbot} // Carp::croak("Missing pbot reference to FactoidCommands");
|
||||
$self->{pbot} = $pbot;
|
||||
|
||||
$pbot->commands->register(sub { return $self->regadd(@_) }, "regadd", 60);
|
||||
$pbot->commands->register(sub { return $self->regrem(@_) }, "regrem", 60);
|
||||
$pbot->commands->register(sub { return $self->regshow(@_) }, "regshow", 0);
|
||||
$pbot->commands->register(sub { return $self->regset(@_) }, "regset", 60);
|
||||
$pbot->commands->register(sub { return $self->regunset(@_) }, "regunset", 60);
|
||||
$pbot->commands->register(sub { return $self->regchange(@_) }, "regchange", 60);
|
||||
$pbot->commands->register(sub { return $self->regfind(@_) }, "regfind", 0);
|
||||
}
|
||||
|
||||
sub regset {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my ($section, $item, $key, $value) = split / /, $arguments, 4 if defined $arguments;
|
||||
|
||||
if(not defined $section or not defined $item) {
|
||||
return "Usage: regset <section> <item> [key [value]]";
|
||||
}
|
||||
|
||||
$key = undef if not length $key;
|
||||
$value = undef if not length $value;
|
||||
|
||||
return $self->{pbot}->{registry}->set($section, $item, $key, $value);
|
||||
}
|
||||
|
||||
sub regunset {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my ($section, $item, $key) = split / /, $arguments, 3 if defined $arguments;
|
||||
|
||||
if(not defined $section or not defined $item or not defined $key) {
|
||||
return "Usage: regunset <section> <item> <key>"
|
||||
}
|
||||
|
||||
return $self->{pbot}->{registry}->unset($section, $item, $key);
|
||||
}
|
||||
|
||||
sub regadd {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my ($section, $item, $value) = split / /, $arguments, 3 if defined $arguments;
|
||||
|
||||
if(not defined $section or not defined $item or not defined $value) {
|
||||
return "/msg $nick Usage: regadd <section> <item> <value>";
|
||||
}
|
||||
|
||||
$self->{pbot}->{registry}->add('text', $section, $item, $value);
|
||||
|
||||
$self->{pbot}->logger->log("$nick!$user\@$host added registry entry [$section] $item => $value\n");
|
||||
return "/msg $nick [$section] $item set to $value";
|
||||
}
|
||||
|
||||
sub regrem {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my ($section, $item) = split / /, $arguments if defined $arguments;
|
||||
|
||||
if(not defined $section or not defined $item) {
|
||||
return "/msg $nick Usage: regrem <section> <item>";
|
||||
}
|
||||
|
||||
if(not exists $self->{pbot}->{registry}->{registry}->hash->{$section}) {
|
||||
return "/msg $nick No such registry section $section.";
|
||||
}
|
||||
|
||||
if(not exists $self->{pbot}->{registry}->{registry}->hash->{$section}->{$item}) {
|
||||
return "/msg $nick No such item $item in section $section.";
|
||||
}
|
||||
|
||||
$self->{pbot}->logger->log("$nick!$user\@$host removed registry item [$section][$item]\n");
|
||||
$self->{pbot}->{registry}->remove($section, $item);
|
||||
return "/msg $nick Registry item $item removed from section $section.";
|
||||
}
|
||||
|
||||
sub regshow {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my $registry = $self->{pbot}->{registry}->{registry}->hash;
|
||||
|
||||
my ($section, $item) = split / /, $arguments if defined $arguments;
|
||||
|
||||
if(not defined $section or not defined $item) {
|
||||
return "Usage: regshow <section> <item>";
|
||||
}
|
||||
|
||||
if(not exists $registry->{$section}) {
|
||||
return "/msg $nick No such registry section $section.";
|
||||
}
|
||||
|
||||
if(not exists $registry->{$section}->{$item}) {
|
||||
return "/msg $nick No such registry item $item in section $section.";
|
||||
}
|
||||
|
||||
if($registry->{$section}->{$item}->{private}) {
|
||||
return "/msg $nick [$section] $item is private.";
|
||||
}
|
||||
|
||||
my $result = "[$section] $item: $registry->{$section}->{$item}->{value}";
|
||||
|
||||
if($registry->{$section}->{$item}->{type} eq 'array') {
|
||||
$result .= ' [array]';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
sub regfind {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my $registry = $self->{pbot}->{registry}->{registry}->hash;
|
||||
|
||||
if(not defined $arguments) {
|
||||
return "/msg $nick Usage: regfind [-section section] <text>";
|
||||
}
|
||||
|
||||
my $section;
|
||||
|
||||
$section = $1 if $arguments =~ s/-section\s+([^\b\s]+)//i;
|
||||
|
||||
$arguments =~ s/^\s+//;
|
||||
$arguments =~ s/\s+$//;
|
||||
$arguments =~ s/\s+/ /g;
|
||||
|
||||
if($arguments eq "") {
|
||||
return "/msg $nick Usage: regfind [-section section] <text>";
|
||||
}
|
||||
|
||||
my ($text, $last_item, $last_section, $i);
|
||||
$last_section = "";
|
||||
$i = 0;
|
||||
eval {
|
||||
foreach my $section_key (sort keys %{ $registry }) {
|
||||
next if defined $section and $section_key !~ /^$section$/i;
|
||||
foreach my $item_key (sort keys %{ $registry->{$section_key} }) {
|
||||
next if $registry->{$section_key}->{$item_key}->{private};
|
||||
next if $registry->{$section_key}->{$item_key}->{value} !~ /$arguments/i and $item_key !~ /$arguments/i;
|
||||
|
||||
$i++;
|
||||
|
||||
if($section_key ne $last_section) {
|
||||
$text .= "[$section_key] ";
|
||||
$last_section = $section_key;
|
||||
}
|
||||
$text .= "$item_key ";
|
||||
$last_item = $item_key;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return "/msg $nick $arguments: $@" if $@;
|
||||
|
||||
if($i == 1) {
|
||||
chop $text;
|
||||
return "Found one registry entry: [$last_section] $last_item: $registry->{$last_section}->{$last_item}->{value}";
|
||||
} else {
|
||||
return "found $i registry entries: $text" unless $i == 0;
|
||||
|
||||
my $sections = (defined $section ? "section $section" : 'any sections');
|
||||
return "No registry entries matching query found in $sections.";
|
||||
}
|
||||
}
|
||||
|
||||
sub regchange {
|
||||
my $self = shift;
|
||||
my ($from, $nick, $user, $host, $arguments) = @_;
|
||||
my ($section, $item, $delim, $tochange, $changeto, $modifier);
|
||||
|
||||
if(defined $arguments) {
|
||||
if($arguments =~ /^([^\s]+) ([^\s]+)\s+s(.)/) {
|
||||
$section = $1;
|
||||
$item = $2;
|
||||
$delim = $3;
|
||||
}
|
||||
|
||||
if($arguments =~ /$delim(.*?)$delim(.*)$delim(.*)?$/) {
|
||||
$tochange = $1;
|
||||
$changeto = $2;
|
||||
$modifier = $3;
|
||||
}
|
||||
}
|
||||
|
||||
if(not defined $section or not defined $item or not defined $changeto) {
|
||||
return "Usage: regchange <section> <item> s/<pattern>/<replacement>/";
|
||||
}
|
||||
|
||||
my $registry = $self->{pbot}->{registry}->{registry}->hash;
|
||||
|
||||
if(not exists $registry->{$section}) {
|
||||
return "/msg $nick No such registry section $section.";
|
||||
}
|
||||
|
||||
if(not exists $registry->{$section}->{$item}) {
|
||||
return "/msg $nick No such registry item $item in section $section.";
|
||||
}
|
||||
|
||||
my $ret = eval {
|
||||
use re::engine::RE2 -strict => 1;
|
||||
if(not $registry->{$section}->{$item}->{value} =~ s|$tochange|$changeto|) {
|
||||
$self->{pbot}->logger->log("($from) $nick!$user\@$host: failed to change [$section] $item 's$delim$tochange$delim$changeto$delim$modifier\n");
|
||||
return "/msg $nick Change [$section] $item failed.";
|
||||
} else {
|
||||
$self->{pbot}->logger->log("($from) $nick!$user\@$host: changed [$section] $item 's/$tochange/$changeto/\n");
|
||||
$self->{pbot}->{registry}->process_trigger($section, $item, 'value', $registry->{$section}->{$item}->{value});
|
||||
$self->{pbot}->{registry}->save;
|
||||
return "Changed: [$section] $item set to $registry->{$section}->{$item}->{value}";
|
||||
}
|
||||
};
|
||||
return "/msg $nick Change [$section] $item: $@" if $@;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
1;
|
@ -3,9 +3,6 @@ package PBot::SelectHandler;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '1.0.0';
|
||||
|
||||
use IO::Select;
|
||||
use Carp ();
|
||||
|
||||
|
@ -3,9 +3,6 @@ package PBot::StdinReader;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '1.0.0';
|
||||
|
||||
use POSIX qw(tcgetpgrp getpgrp); # to check whether process is in background or foreground
|
||||
use Carp ();
|
||||
|
||||
@ -46,13 +43,13 @@ sub stdin_reader {
|
||||
|
||||
if($input =~ m/^~([^ ]+)\s+(.*)/) {
|
||||
$from = $1;
|
||||
$text = "$self->{pbot}->{trigger}$2";
|
||||
$text = $self->{pbot}->{registry}->get_value('general', 'trigger') . $2;
|
||||
} else {
|
||||
$from = "$self->{pbot}->{botnick}!stdin\@localhost";
|
||||
$text = "$self->{pbot}->{trigger}$input";
|
||||
$from = $self->{pbot}->{registry}->get_value('irc', 'botnick') . "!stdin\@localhost";
|
||||
$text = $self->{pbot}->{registry}->get_value('general', 'trigger') . $input;
|
||||
}
|
||||
|
||||
return $self->{pbot}->interpreter->process_line($from, $self->{pbot}->{botnick}, "stdin", "localhost", $text);
|
||||
return $self->{pbot}->interpreter->process_line($from, $self->{pbot}->{registry}->get_value('irc', 'botnick'), "stdin", "localhost", $text);
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -10,9 +10,6 @@ package PBot::Timer;
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use vars qw($VERSION);
|
||||
$VERSION = '1.0.0';
|
||||
|
||||
use Carp ();
|
||||
|
||||
our $min_timeout = 10;
|
||||
|
@ -13,8 +13,8 @@ use warnings;
|
||||
# These are set automatically by the build/commit script
|
||||
use constant {
|
||||
BUILD_NAME => "PBot",
|
||||
BUILD_REVISION => 581,
|
||||
BUILD_DATE => "2014-05-16",
|
||||
BUILD_REVISION => 582,
|
||||
BUILD_DATE => "2014-05-17",
|
||||
};
|
||||
|
||||
1;
|
||||
|
7
pbot.pl
7
pbot.pl
@ -77,8 +77,8 @@ my %config = (
|
||||
# You shouldn't need to change anything below this line.
|
||||
# -----------------------------------------------------
|
||||
|
||||
# Maximum messages to remember per nick/hostmask
|
||||
MAX_NICK_MESSAGES => 256,
|
||||
# Maximum messages to remember per nick/hostmask in message history
|
||||
MAX_MESSAGES => 256,
|
||||
|
||||
# Path to data directory
|
||||
data_dir => "$bothome/data",
|
||||
@ -94,6 +94,9 @@ my %config = (
|
||||
log_file => "$bothome/log/log",
|
||||
);
|
||||
|
||||
# Location of file containing configuration registry
|
||||
$config{registry_file} = "$config{config_dir}/registry";
|
||||
|
||||
# Location of file containing bot admin information
|
||||
$config{admins_file} = "$config{config_dir}/admins";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user