Renamed src/ to lib/ because it's more Perly.
This commit is contained in:
1 parent
cd2d91a430
commit
951ae133c2
12 files changed
+1
No files matched your search
+189
@@ -0,0 +1,189 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# IRC API subroutines.
|
||||
package API::IRC;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Exporter;
|
||||
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT_OK = qw(cjoin cpart cmode umode kick privmsg notice quit nick names topic
|
||||
usrc match_mask);
|
||||
|
||||
|
||||
# Join a channel.
|
||||
sub cjoin
|
||||
{
|
||||
my ($svr, $chan) = @_;
|
||||
|
||||
Auto::socksnd($svr, "JOIN $chan");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Part a channel.
|
||||
sub cpart
|
||||
{
|
||||
my ($svr, $chan, $reason) = @_;
|
||||
|
||||
if (defined $reason) {
|
||||
Auto::socksnd($svr, "PART $chan :$reason");
|
||||
}
|
||||
else {
|
||||
Auto::socksnd($svr, "PART $chan :Leaving");
|
||||
}
|
||||
|
||||
if (defined $Parser::IRC::botchans{$svr}{$chan}) { delete $Parser::IRC::botchans{$svr}{$chan}; }
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Set mode(s) on a channel.
|
||||
sub cmode
|
||||
{
|
||||
my ($svr, $chan, $modes) = @_;
|
||||
|
||||
Auto::socksnd($svr, "MODE $chan $modes");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Set mode(s) on us.
|
||||
sub umode
|
||||
{
|
||||
my ($svr, $modes) = @_;
|
||||
|
||||
Auto::socksnd($svr, "MODE ".$Parser::IRC::botnick{$svr}{nick}." $modes");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Send a PRIVMSG.
|
||||
sub privmsg
|
||||
{
|
||||
my ($svr, $target, $message) = @_;
|
||||
|
||||
Auto::socksnd($svr, "PRIVMSG $target :$message");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Send a NOTICE.
|
||||
sub notice
|
||||
{
|
||||
my ($svr, $target, $message) = @_;
|
||||
|
||||
Auto::socksnd($svr, "NOTICE $target :$message");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Send an ACTION PRIVMSG.
|
||||
sub act
|
||||
{
|
||||
my ($svr, $target, $message) = @_;
|
||||
|
||||
Auto::socksnd($svr, "PRIVMSG $target :\001ACTION $message\001");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Change bot nickname.
|
||||
sub nick
|
||||
{
|
||||
my ($svr, $newnick) = @_;
|
||||
|
||||
Auto::socksnd($svr, "NICK $newnick");
|
||||
|
||||
$Parser::IRC::botnick{$svr}{newnick} = $newnick;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Request the users of a channel.
|
||||
sub names
|
||||
{
|
||||
my ($svr, $chan) = @_;
|
||||
|
||||
Auto::socksnd($svr, "NAMES $chan");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Send a topic to the channel.
|
||||
sub topic
|
||||
{
|
||||
my ($svr, $chan, $topic) = @_;
|
||||
|
||||
Auto::socksnd($svr, "TOPIC $chan :$topic");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Kick a user.
|
||||
sub kick
|
||||
{
|
||||
my ($svr, $chan, $nick, $msg) = @_;
|
||||
|
||||
Auto::socksnd($svr, "KICK $chan $nick :$msg");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Quit IRC.
|
||||
sub quit
|
||||
{
|
||||
my ($svr, $reason) = @_;
|
||||
|
||||
if (defined $reason) {
|
||||
Auto::socksnd($svr, "QUIT :$reason");
|
||||
}
|
||||
else {
|
||||
Auto::socksnd($svr, "QUIT :Leaving");
|
||||
}
|
||||
|
||||
delete $Parser::IRC::got_001{$svr} if (defined $Parser::IRC::got_001{$svr});
|
||||
delete $Parser::IRC::botnick{$svr} if (defined $Parser::IRC::botnick{$svr});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# Get nick, ident and host from a <nick>!<ident>@<host>
|
||||
sub usrc
|
||||
{
|
||||
my ($ex) = @_;
|
||||
|
||||
my @si = split('!', $ex);
|
||||
my @sii = split('@', $si[1]);
|
||||
|
||||
return (
|
||||
nick => $si[0],
|
||||
user => $sii[0],
|
||||
host => $sii[1]
|
||||
);
|
||||
}
|
||||
|
||||
# Match two IRC masks.
|
||||
sub match_mask
|
||||
{
|
||||
my ($mu, $mh) = @_;
|
||||
|
||||
# Prepare the regex.
|
||||
$mh =~ s/\./\\\./g;
|
||||
$mh =~ s/\?/\./g;
|
||||
$mh =~ s/\*/\.\*/g;
|
||||
$mh = '^'.$mh.'$';
|
||||
|
||||
# Let's grep the user's mask.
|
||||
if (grep(/$mh/, $mu)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# API logging subroutines.
|
||||
package API::Log;
|
||||
use strict;
|
||||
use warnings;
|
||||
use English qw(-no_match_vars);
|
||||
use POSIX;
|
||||
use Time::Local;
|
||||
use Exporter;
|
||||
use base qw(Exporter);
|
||||
use API::Std qw(conf_get);
|
||||
|
||||
our $VERSION = 3.000000;
|
||||
our @EXPORT_OK = qw(println dbug alog);
|
||||
|
||||
|
||||
# Print with the system newline appended.
|
||||
sub println
|
||||
{
|
||||
my ($out) = @_;
|
||||
|
||||
if (!defined $out) {
|
||||
print $RS;
|
||||
}
|
||||
else {
|
||||
print $out.$RS;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Print only if in debug mode.
|
||||
sub dbug
|
||||
{
|
||||
my ($out) = @_;
|
||||
|
||||
if ($Auto::DEBUG) {
|
||||
# We're in debug mode; print it out.
|
||||
println $out;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Log to file.
|
||||
sub alog
|
||||
{
|
||||
my ($lmsg) = @_;
|
||||
|
||||
# Expire old logs first.
|
||||
expire_logs();
|
||||
|
||||
# Get date and time in the desired format.
|
||||
my $date = POSIX::strftime('%Y%m%d', localtime);
|
||||
my $time = POSIX::strftime('%Y-%m-%d %I:%M:%S %p', localtime);
|
||||
|
||||
# Create var/ if it doesn't exist.
|
||||
if (!-d "$Auto::Bin/../var") {
|
||||
mkdir "$Auto::Bin/../var", 0600; ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers)
|
||||
}
|
||||
# Create var/DATE.log if it doesn't exist.
|
||||
if (!-e "$Auto::Bin/../var/$date.log") {
|
||||
system "touch $Auto::Bin/../var/$date.log";
|
||||
}
|
||||
|
||||
# Open the logfile, print the log message to it and close it.
|
||||
open my $FLOG, '>>', "$Auto::Bin/../var/$date.log" or return;
|
||||
print {$FLOG} "[$time] $lmsg\n" or return;
|
||||
close $FLOG or return;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Expire old logs.
|
||||
sub expire_logs
|
||||
{
|
||||
# Get configuration value.
|
||||
my $celog = (conf_get('expire_logs'))[0][0] or return;
|
||||
|
||||
# Check for invalid values.
|
||||
if ($celog =~ m/[^0-9]/sm) { ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
# Must be numbers only.
|
||||
return;
|
||||
}
|
||||
elsif (!$celog) {
|
||||
# No expire.
|
||||
return;
|
||||
}
|
||||
|
||||
# Iterate through each logfile.
|
||||
foreach my $file (glob "$Auto::Bin/../var/*") {
|
||||
my (undef, $file) = split 'bin/../var/', $file; ## no critic qw(BuiltinFunctions::ProhibitStringySplit)
|
||||
|
||||
# Convert filename to UNIX time.
|
||||
my $yyyy = substr $file, 0, 4; ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers)
|
||||
my $mm = substr $file, 4, 2; ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers)
|
||||
$mm = $mm - 1;
|
||||
my $dd = substr $file, 6, 2; ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers)
|
||||
my $epoch = timelocal(0, 0, 0, $dd, $mm, $yyyy);
|
||||
|
||||
# If it's older than <config_value> days, delete it.
|
||||
if (time - $epoch > 86_400 * $celog) { ## no critic qw(ValuesAndExpressions::ProhibitMagicNumbers)
|
||||
unlink "$Auto::Bin/../var/$file";
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
# vim: set ai sw=4 ts=4:
|
||||
+473
@@ -0,0 +1,473 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# Standard API subroutines.
|
||||
package API::Std;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Exporter;
|
||||
use base qw(Exporter);
|
||||
|
||||
|
||||
our $VERSION = 3.000000;
|
||||
our (%LANGE, %MODULE, %EVENTS, %HOOKS, %CMDS);
|
||||
our @EXPORT_OK = qw(conf_get trans err awarn timer_add timer_del cmd_add
|
||||
cmd_del hook_add hook_del rchook_add rchook_del match_user
|
||||
has_priv mod_exists);
|
||||
|
||||
|
||||
# Initialize a module.
|
||||
sub mod_init
|
||||
{
|
||||
my ($name, $author, $version, $autover, $pkg) = @_;
|
||||
|
||||
# Log/debug.
|
||||
API::Log::dbug('MODULES: Attempting to load '.$name.' (version '.$version.') by '.$author.'...');
|
||||
API::Log::alog('MODULES: Attempting to load '.$name.' (version '.$version.') by '.$author.'...');
|
||||
|
||||
# Check if this module is compatible with this version of Auto.
|
||||
if ($autover ne '3.0.0d') {
|
||||
API::Log::dbug('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.');
|
||||
API::Log::alog('MODULES: Failed to load '.$name.': Incompatible with your version of Auto.');
|
||||
return;
|
||||
}
|
||||
|
||||
# Run the module's _init sub.
|
||||
my $mi = eval($pkg.'::_init();'); ## no critic qw(BuiltinFunctions::ProhibitStringyEval)
|
||||
|
||||
if ($mi) {
|
||||
# If successful, add to hash.
|
||||
$MODULE{$name}{name} = $name;
|
||||
$MODULE{$name}{version} = $version;
|
||||
$MODULE{$name}{author} = $author;
|
||||
$MODULE{$name}{pkg} = $pkg;
|
||||
|
||||
API::Log::dbug('MODULES: '.$name.' successfully loaded.');
|
||||
API::Log::alog('MODULES: '.$name.' successfully loaded.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
# Otherwise, return a failed to load message.
|
||||
API::Log::dbug('MODULES: Failed to load '.$name.q{.});
|
||||
API::Log::alog('MODULES: Failed to load '.$name.q{.});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Check if a module exists.
|
||||
sub mod_exists
|
||||
{
|
||||
my ($name) = @_;
|
||||
|
||||
if (defined $API::Std::MODULE{$name}) { return 1; }
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# Void a module.
|
||||
sub mod_void
|
||||
{
|
||||
my ($module) = @_;
|
||||
|
||||
# Log/debug.
|
||||
API::Log::dbug('MODULES: Attempting to unload module: '.$module.'...');
|
||||
API::Log::alog('MODULES: Attempting to unload module: '.$module.'...');
|
||||
|
||||
# Check if this module exists.
|
||||
if (!defined $MODULE{$module}) {
|
||||
API::Log::dbug('MODULES: Failed to unload '.$module.'. No such module?');
|
||||
API::Log::alog('MODULES: Failed to unload '.$module.'. No such module?');
|
||||
return;
|
||||
}
|
||||
|
||||
# Run the module's _void sub.
|
||||
my $mi = eval($MODULE{$module}{pkg}.'::_void();'); ## no critic qw(BuiltinFunctions::ProhibitStringyEval)
|
||||
|
||||
if ($mi) {
|
||||
# If successful, delete class from program and delete module from hash.
|
||||
Class::Unload->unload($MODULE{$module}{pkg});
|
||||
delete $MODULE{$module};
|
||||
API::Log::dbug('MODULES: Successfully unloaded '.$module.q{.});
|
||||
API::Log::alog('MODULES: Successfully unloaded '.$module.q{.});
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
# Otherwise, return a failed to unload message.
|
||||
API::Log::dbug('MODULES: Failed to unload '.$module.q{.});
|
||||
API::Log::alog('MODULES: Failed to unload '.$module.q{.});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Add a command to Auto.
|
||||
sub cmd_add
|
||||
{
|
||||
my ($cmd, $lvl, $priv, $help, $sub) = @_;
|
||||
$cmd = uc $cmd;
|
||||
|
||||
if (defined $API::Std::CMDS{$cmd}) { return; }
|
||||
if ($lvl =~ m/[^0-2]/sm) { return; } ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
|
||||
$API::Std::CMDS{$cmd}{lvl} = $lvl;
|
||||
$API::Std::CMDS{$cmd}{help} = $help;
|
||||
$API::Std::CMDS{$cmd}{priv} = $priv;
|
||||
$API::Std::CMDS{$cmd}{sub} = $sub;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
# Delete a command from Auto.
|
||||
sub cmd_del
|
||||
{
|
||||
my ($cmd) = @_;
|
||||
$cmd = uc $cmd;
|
||||
|
||||
if (defined $API::Std::CMDS{$cmd}) {
|
||||
delete $API::Std::CMDS{$cmd};
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Add an event to Auto.
|
||||
sub event_add
|
||||
{
|
||||
my ($name) = @_;
|
||||
|
||||
if (!defined $EVENTS{lc $name}) {
|
||||
$EVENTS{lc $name} = 1;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
API::Log::dbug('DEBUG: Attempt to add a pre-existing event ('.lc $name.')! Ignoring...');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Delete an event from Auto.
|
||||
sub event_del
|
||||
{
|
||||
my ($name) = @_;
|
||||
|
||||
if (defined $EVENTS{lc $name}) {
|
||||
delete $EVENTS{lc $name};
|
||||
delete $HOOKS{lc $name};
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
API::Log::dbug('DEBUG: Attempt to delete a non-existing event ('.lc $name.')! Ignoring...');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Trigger an event.
|
||||
sub event_run
|
||||
{
|
||||
my ($event, @args) = @_;
|
||||
|
||||
if (defined $EVENTS{lc $event} and defined $HOOKS{lc $event}) {
|
||||
foreach my $hk (keys %{ $HOOKS{lc $event} }) {
|
||||
&{ $HOOKS{lc $event}{$hk} }(@args);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Add a hook to Auto.
|
||||
sub hook_add
|
||||
{
|
||||
my ($event, $name, $sub) = @_;
|
||||
|
||||
if (!defined $API::Std::HOOKS{lc $name}) {
|
||||
if (defined $API::Std::EVENTS{lc $event}) {
|
||||
$API::Std::HOOKS{lc $event}{lc $name} = $sub;
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Delete a hook from Auto.
|
||||
sub hook_del
|
||||
{
|
||||
my ($event, $name) = @_;
|
||||
|
||||
if (defined $API::Std::HOOKS{lc $event}{lc $name}) {
|
||||
delete $API::Std::HOOKS{lc $event}{lc $name};
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Add a timer to Auto.
|
||||
sub timer_add
|
||||
{
|
||||
my ($name, $type, $time, $sub) = @_;
|
||||
$name = lc $name;
|
||||
|
||||
# Check for invalid type/time.
|
||||
if ($type =~ m/[^1-2]/sm) { ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
return;
|
||||
}
|
||||
if ($time =~ m/[^0-9]/sm) { ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!defined $Auto::TIMERS{$name}) {
|
||||
$Auto::TIMERS{$name}{type} = $type;
|
||||
$Auto::TIMERS{$name}{time} = time + $time;
|
||||
if ($type == 2) { $Auto::TIMERS{$name}{secs} = $time; }
|
||||
$Auto::TIMERS{$name}{sub} = $sub;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Delete a timer from Auto.
|
||||
sub timer_del
|
||||
{
|
||||
my ($name) = @_;
|
||||
$name = lc $name;
|
||||
|
||||
if (defined $Auto::TIMERS{$name}) {
|
||||
delete $Auto::TIMERS{$name};
|
||||
return 1;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# Hook onto a raw command.
|
||||
sub rchook_add
|
||||
{
|
||||
my ($cmd, $sub) = @_;
|
||||
$cmd = uc $cmd;
|
||||
|
||||
if (defined $Parser::IRC::RAWC{$cmd}) { return; }
|
||||
|
||||
$Parser::IRC::RAWC{$cmd} = $sub;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Delete a raw command hook.
|
||||
sub rchook_del
|
||||
{
|
||||
my ($cmd) = @_;
|
||||
$cmd = uc $cmd;
|
||||
|
||||
if (!defined $Parser::IRC::RAWC{$cmd}) { return; }
|
||||
|
||||
delete $Parser::IRC::RAWC{$cmd};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Configuration value getter.
|
||||
sub conf_get
|
||||
{
|
||||
my ($value) = @_;
|
||||
|
||||
# Create an array out of the value.
|
||||
my @val;
|
||||
if ($value =~ m/:/sm) { ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
@val = split m/[:]/sm, $value; ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
}
|
||||
else {
|
||||
@val = ($value);
|
||||
}
|
||||
# Undefine this as it's unnecessary now.
|
||||
undef $value;
|
||||
|
||||
# Get the count of elements in the array.
|
||||
my $count = scalar @val;
|
||||
|
||||
# Return the requested configuration value(s).
|
||||
if ($count == 1) {
|
||||
if (ref $Auto::SETTINGS{$val[0]} eq 'HASH') {
|
||||
return %{ $Auto::SETTINGS{$val[0]} };
|
||||
}
|
||||
else {
|
||||
return $Auto::SETTINGS{$val[0]};
|
||||
}
|
||||
}
|
||||
elsif ($count == 2) {
|
||||
if (ref $Auto::SETTINGS{$val[0]}{$val[1]} eq 'HASH') {
|
||||
return %{ $Auto::SETTINGS{$val[0]}{$val[1]} };
|
||||
}
|
||||
else {
|
||||
return $Auto::SETTINGS{$val[0]}{$val[1]};
|
||||
}
|
||||
}
|
||||
elsif ($count == 3) {
|
||||
if (ref $Auto::SETTINGS{$val[0]}{$val[1]}{$val[2]} eq 'HASH') {
|
||||
return %{ $Auto::SETTINGS{$val[0]}{$val[1]}{$val[2]} };
|
||||
}
|
||||
else {
|
||||
return $Auto::SETTINGS{$val[0]}{$val[1]}{$val[2]};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Translation subroutine.
|
||||
sub trans
|
||||
{
|
||||
my ($id) = @_;
|
||||
$id =~ s/ /_/gsm;
|
||||
|
||||
if (defined $API::Std::LANGE{$id}) {
|
||||
return $API::Std::LANGE{$id};
|
||||
}
|
||||
else {
|
||||
$id =~ s/_/ /gsm;
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
|
||||
# Match user subroutine.
|
||||
sub match_user
|
||||
{
|
||||
my (%user) = @_;
|
||||
|
||||
# Get data from config.
|
||||
if (!conf_get('user')) { return; }
|
||||
my %uhp = conf_get('user');
|
||||
|
||||
foreach my $userkey (keys %uhp) {
|
||||
# For each user block.
|
||||
my %ulhp = %{ $uhp{$userkey} };
|
||||
foreach my $uhk (keys %ulhp) {
|
||||
# For each user.
|
||||
|
||||
if ($uhk eq 'net') {
|
||||
if (defined $user{svr}) {
|
||||
if (lc $user{svr} ne lc(($ulhp{$uhk})[0][0])) {
|
||||
# config.user:net conflicts with irc.user:svr.
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($uhk eq 'mask') {
|
||||
# Put together the user information.
|
||||
my $mask = $user{nick}.q{!}.$user{user}.q{@}.$user{host};
|
||||
if (API::IRC::match_mask($mask, ($ulhp{$uhk})[0][0])) {
|
||||
# We've got a host match.
|
||||
return $userkey;
|
||||
}
|
||||
}
|
||||
elsif ($uhk eq 'chanstatus' and defined $ulhp{'net'}) {
|
||||
my ($ccst, $ccnm) = split m/[:]/sm, ($ulhp{$uhk})[0][0]; ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
my $svr = $ulhp{net}[0];
|
||||
if (defined $Auto::SOCKET{$svr}) {
|
||||
if ($ccnm eq 'CURRENT' and defined $user{chan}) {
|
||||
if (defined $Parser::IRC::chanusers{$svr}{$user{chan}}{$user{nick}}) {
|
||||
if ($Parser::IRC::chanusers{$svr}{$user{chan}}{$user{nick}} =~ m/($ccst)/sm) { return $userkey; } ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach my $bcj (keys %{ $Parser::IRC::botchans{$svr} }) {
|
||||
if (API::IRC::match_mask($bcj, $ccnm)) {
|
||||
if (defined $Parser::IRC::chanusers{$svr}{$bcj}{$user{nick}}) {
|
||||
if ($Parser::IRC::chanusers{$svr}{$bcj}{$user{nick}} =~ m/($ccst)/sm) { return $userkey; } ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# Privilege subroutine.
|
||||
sub has_priv
|
||||
{
|
||||
my ($cuser, $cpriv) = @_;
|
||||
|
||||
if (conf_get("user:$cuser:privs")) {
|
||||
my $cups = (conf_get("user:$cuser:privs"))[0][0];
|
||||
|
||||
if (defined $Auto::PRIVILEGES{$cups}) {
|
||||
foreach (@{ $Auto::PRIVILEGES{$cups} }) {
|
||||
if ($_ eq $cpriv or $_ eq 'ALL') { return 1; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# Error subroutine.
|
||||
sub err ## no critic qw(Subroutines::ProhibitBuiltinHomonyms)
|
||||
{
|
||||
my ($lvl, $msg, $fatal) = @_;
|
||||
|
||||
# Check for an invalid level.
|
||||
if ($lvl =~ m/[^0-9]/sm) { ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
return;
|
||||
}
|
||||
if ($fatal =~ m/[^0-1]/sm) { ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
return;
|
||||
}
|
||||
|
||||
# Level 1: Print to screen.
|
||||
if ($lvl >= 1) {
|
||||
API::Log::println("ERROR: $msg");
|
||||
}
|
||||
# Level 2: Log to file.
|
||||
if ($lvl >= 2) {
|
||||
API::Log::alog("ERROR: $msg");
|
||||
}
|
||||
|
||||
# If it's a fatal error, exit the program.
|
||||
if ($fatal) { exit; }
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Warn subroutine.
|
||||
sub awarn
|
||||
{
|
||||
my ($lvl, $msg) = @_;
|
||||
|
||||
# Check for an invalid level.
|
||||
if ($lvl =~ m/[^0-9]/sm) { ## no critic qw(RegularExpressions::RequireExtendedFormatting)
|
||||
return;
|
||||
}
|
||||
|
||||
# Level 1: Print to screen.
|
||||
if ($lvl >= 1) {
|
||||
API::Log::println("WARNING: $msg");
|
||||
}
|
||||
# Level 2: Log to file.
|
||||
if ($lvl >= 2) {
|
||||
API::Log::alog("WARNING: $msg");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
# vim: set ai sw=4 ts=4:
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# Core::Cmd - Core commands.
|
||||
package Core::Cmd;
|
||||
use strict;
|
||||
use warnings;
|
||||
use English;
|
||||
use API::Std qw(trans has_priv match_user);
|
||||
use API::Log qw(dbug alog);
|
||||
use API::IRC qw(notice quit usrc);
|
||||
|
||||
# Help hash for MODLOAD. Spanish, French and German needed.
|
||||
our %HELP_MODLOAD = (
|
||||
'en' => 'Loads a module into the running Auto live.',
|
||||
);
|
||||
# MODLOAD callback.
|
||||
sub cmd_modload
|
||||
{
|
||||
my (%data) = @_;
|
||||
my @argv = @{ $data{args} };
|
||||
|
||||
# Check for the needed parameters.
|
||||
if (!defined $argv[0]) {
|
||||
notice($data{svr}, $data{nick}, trans("Not enough parameters").".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Check if the module is already loaded.
|
||||
if (API::Std::mod_exists($argv[0])) {
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 is already loaded.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Go for it!
|
||||
my $tn = Auto::mod_load($argv[0]);
|
||||
|
||||
# Check if we were successful or not.
|
||||
if ($tn) {
|
||||
# We were!
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 successfully loaded.");
|
||||
}
|
||||
else {
|
||||
# We weren't.
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 failed to load.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Help hash for MODUNLOAD. Spanish, French and German needed.
|
||||
our %HELP_MODUNLOAD = (
|
||||
'en' => 'Unloads a module from the running Auto live.',
|
||||
);
|
||||
# MODUNLOAD callback.
|
||||
sub cmd_modunload
|
||||
{
|
||||
my (%data) = @_;
|
||||
my @argv = @{ $data{args} };
|
||||
|
||||
# Check for the needed parameters.
|
||||
if (!defined $argv[0]) {
|
||||
notice($data{svr}, $data{nick}, trans("Not enough parameters").".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Check if the module exists.
|
||||
if (!API::Std::mod_exists($argv[0])) {
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 is not loaded.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Go for it!
|
||||
my $tn = API::Std::mod_void($argv[0]);
|
||||
|
||||
# Check if we were successful or not.
|
||||
if ($tn) {
|
||||
# We were!
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 successfully unloaded.");
|
||||
}
|
||||
else {
|
||||
# We weren't.
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 failed to unload.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Help hash for MODRELOAD. Spanish, French and German needed.
|
||||
our %HELP_MODRELOAD = (
|
||||
'en' => 'Unloads then loads a module into the running Auto live.',
|
||||
);
|
||||
# MODRELOAD callback.
|
||||
sub cmd_modreload
|
||||
{
|
||||
my (%data) = @_;
|
||||
my @argv = @{ $data{args} };
|
||||
|
||||
# Check for the needed parameters.
|
||||
if (!defined $argv[0]) {
|
||||
notice($data{svr}, $data{nick}, trans("Not enough parameters").".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Check if the module exists.
|
||||
if (!API::Std::mod_exists($argv[0])) {
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 is not loaded.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Go for it!
|
||||
my ($tvn, $tln) = (0, 0);
|
||||
$tvn = API::Std::mod_void($argv[0]);
|
||||
$tln = Auto::mod_load($argv[0]) if $tvn;
|
||||
|
||||
# Check if we were successful or not.
|
||||
if ($tvn and $tln) {
|
||||
# We were!
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 successfully reloaded.");
|
||||
}
|
||||
else {
|
||||
# We weren't.
|
||||
notice($data{svr}, $data{nick}, "Module \002".$argv[0]."\002 failed to reload.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Help hash for SHUTDOWN. Spanish, French and German needed.
|
||||
our %HELP_SHUTDOWN = (
|
||||
'en' => 'This will send out shutdown notifications, quit all networks, flush the database then exit the program.',
|
||||
);
|
||||
# SHUTDOWN callback.
|
||||
sub cmd_shutdown
|
||||
{
|
||||
my (%data) = @_;
|
||||
|
||||
# Goodbye world!
|
||||
notice($data{svr}, $data{nick}, "Shutting down.");
|
||||
dbug "Got SHUTDOWN from ".$data{nick}."!".$data{user}."@".$data{host}."/".$data{svr}."! Shutting down. . .";
|
||||
alog "Got SHUTDOWN from ".$data{nick}."!".$data{user}."@".$data{host}."/".$data{svr}."! Shutting down. . .";
|
||||
quit($_, "SHUTDOWN from ".$data{nick}."/".$data{svr}) foreach (keys %Auto::SOCKET);
|
||||
$Auto::DB->disconnect;
|
||||
system("rm $Auto::Bin/auto.pid");
|
||||
exit;
|
||||
|
||||
# To appease PerlCritic.
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Help hash for RESTART. Spanish, French and German needed.
|
||||
our %HELP_RESTART = (
|
||||
'en' => 'This will send out restart notifications, quit all networks, flush the database, start a new Auto process, then exit the program.',
|
||||
);
|
||||
# RESTART callback.
|
||||
sub cmd_restart
|
||||
{
|
||||
my (%data) = @_;
|
||||
|
||||
# Goodbye world!
|
||||
notice($data{svr}, $data{nick}, "Restarting.");
|
||||
dbug "Got RESTART from ".$data{nick}."!".$data{user}."@".$data{host}."/".$data{svr}."! Restarting. . .";
|
||||
alog "Got RESTART from ".$data{nick}."!".$data{user}."@".$data{host}."/".$data{svr}."! Restarting. . .";
|
||||
quit($_, "RESTART from ".$data{nick}."/".$data{svr}) foreach (keys %Auto::SOCKET);
|
||||
$Auto::DB->disconnect;
|
||||
system("rm $Auto::Bin/auto.pid") if -e "$Auto::Bin/auto.pid";
|
||||
|
||||
# Time to come back from the dead!
|
||||
if ($Auto::DEBUG) {
|
||||
system("$Auto::Bin/auto -d -nuc");
|
||||
}
|
||||
else {
|
||||
system("$Auto::Bin/auto -nuc");
|
||||
}
|
||||
exit;
|
||||
|
||||
# To appease PerlCritic.
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Help hash for HELP. Spanish, French and German needed.
|
||||
our %HELP_HELP = (
|
||||
'en' => 'Displays help for commands.',
|
||||
);
|
||||
# HELP callback.
|
||||
sub cmd_help
|
||||
{
|
||||
my (%data) = @_;
|
||||
my @argv = @{ $data{args} }; delete $data{args};
|
||||
|
||||
# Check for arguments and reply accordingly.
|
||||
if (!defined $argv[0]) {
|
||||
# No command specified. List commands.
|
||||
my $cmdlist = '';
|
||||
foreach (sort keys %API::Std::CMDS) {
|
||||
if (defined $data{chan}) {
|
||||
if ($API::Std::CMDS{$_}{lvl} == 0 or $API::Std::CMDS{$_}{lvl} == 2) {
|
||||
if ($API::Std::CMDS{$_}{priv}) {
|
||||
if (has_priv(match_user(%data), $API::Std::CMDS{$_}{priv})) {
|
||||
$cmdlist .= ", \002".uc($_)."\002";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$cmdlist .= ", \002".uc($_)."\002";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($API::Std::CMDS{$_}{lvl} == 1 or $API::Std::CMDS{$_}{lvl} == 2) {
|
||||
if ($API::Std::CMDS{$_}{priv}) {
|
||||
if (has_priv(match_user(%data), $API::Std::CMDS{$_}{priv})) {
|
||||
$cmdlist .= ", \002".uc($_)."\002";
|
||||
}
|
||||
}
|
||||
else {
|
||||
$cmdlist .= ", \002".uc($_)."\002";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$cmdlist = substr($cmdlist, 2);
|
||||
|
||||
notice($data{svr}, $data{nick}, "Command List: ".$cmdlist);
|
||||
}
|
||||
else {
|
||||
# Help for a specific command was requested. Lets get it.
|
||||
my $rcm = uc($argv[0]);
|
||||
|
||||
if (defined $API::Std::CMDS{$rcm}{help}) {
|
||||
# If there is help for this command.
|
||||
|
||||
# Check for necessary privileges.
|
||||
if ($API::Std::CMDS{$rcm}{priv}) {
|
||||
if (!has_priv(match_user(%data), $API::Std::CMDS{$rcm}{priv})) {
|
||||
notice($data{svr}, $data{nick}, trans("Access denied").".");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($API::Std::CMDS{$rcm}{help}) {
|
||||
# If there is valid help for this command.
|
||||
|
||||
# Get the language.
|
||||
my ($lang, undef) = split('_', $Auto::LOCALE);
|
||||
|
||||
if (defined ${ $API::Std::CMDS{$rcm}{help} }{$lang}) {
|
||||
# If help for this command is available in the configured language.
|
||||
notice($data{svr}, $data{nick}, "Help for \002".$rcm."\002: ".${ $API::Std::CMDS{$rcm}{help} }{$lang});
|
||||
}
|
||||
else {
|
||||
# If it isn't, default to English.
|
||||
if (defined ${ $API::Std::CMDS{$rcm}{help} }{en}) {
|
||||
# If help for this command is available in English.
|
||||
notice($data{svr}, $data{nick}, "Help for \002".$rcm."\002: ".${ $API::Std::CMDS{$rcm}{help} }{en});
|
||||
}
|
||||
else {
|
||||
# If it isn't, no help.
|
||||
notice($data{svr}, $data{nick}, "No help for \002".$rcm."\002 available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# If it isn't valid, no help.
|
||||
notice($data{svr}, $data{nick}, "No help for \002".$rcm."\002 available.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
# If there is no help, don't give any.
|
||||
notice($data{svr}, $data{nick}, "No help for \002".$rcm."\002 available.");
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
# vim: set ai sw=4 ts=4:
|
||||
@@ -0,0 +1,92 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# Core::IRC - Core IRC hooks.
|
||||
package Core::IRC;
|
||||
use strict;
|
||||
use warnings;
|
||||
use English qw(-no_match_vars);
|
||||
use API::Std qw(hook_add conf_get);
|
||||
use API::IRC qw(notice usrc);
|
||||
our $VERSION = 3.000000;
|
||||
|
||||
# CTCP VERSION reply.
|
||||
hook_add("on_uprivmsg", "ctcp_version_reply", sub {
|
||||
my (($svr, @ex)) = @_;
|
||||
my %src = usrc(substr($ex[0], 1));
|
||||
|
||||
if ($ex[3] eq ":\001VERSION\001") {
|
||||
if (Auto::RSTAGE ne 'd') {
|
||||
notice($svr, $src{nick}, "\001VERSION ".Auto::NAME." ".Auto::VER.".".Auto::SVER.".".Auto::REV.Auto::RSTAGE." ".$OSNAME."\001");
|
||||
}
|
||||
else {
|
||||
notice($svr, $src{nick}, "\001VERSION ".Auto::NAME." ".Auto::VER.".".Auto::SVER.".".Auto::REV.Auto::RSTAGE."-".Auto::GR." ".$OSNAME."\001");
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
# QUIT hook; delete user from chanusers.
|
||||
hook_add("on_quit", "quit_update_chanusers", sub {
|
||||
my (($svr, $src, undef)) = @_;
|
||||
my %src = %{ $src };
|
||||
|
||||
# Delete the user from all channels.
|
||||
foreach my $ccu (keys %{ $Parser::IRC::chanusers{$svr} }) {
|
||||
if (defined $Parser::IRC::chanusers{$svr}{$ccu}{$src{nick}}) { delete $Parser::IRC::chanusers{$svr}{$ccu}{$src{nick}}; }
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
# Modes on connect.
|
||||
hook_add("on_connect", "on_connect_modes", sub {
|
||||
my ($svr) = @_;
|
||||
|
||||
if (conf_get("server:$svr:modes")) {
|
||||
my $connmodes = (conf_get("server:$svr:modes"))[0][0];
|
||||
API::IRC::umode($svr, $connmodes);
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
# Plaintext auth.
|
||||
hook_add("on_connect", "plaintext_auth", sub {
|
||||
my ($svr) = @_;
|
||||
|
||||
if (conf_get("server:$svr:idstr")) {
|
||||
my $idstr = (conf_get("server:$svr:idstr"))[0][0];
|
||||
Auto::socksnd($svr, $idstr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
# Auto join.
|
||||
hook_add("on_connect", "autojoin", sub {
|
||||
my ($svr) = @_;
|
||||
|
||||
# Get the auto-join from the config.
|
||||
my @cajoin = @{ (conf_get("server:$svr:ajoin"))[0] };
|
||||
|
||||
# Join the channels.
|
||||
if (!defined $cajoin[1]) {
|
||||
# For single-line ajoins.
|
||||
my @sajoin = split(',', $cajoin[0]);
|
||||
|
||||
API::IRC::cjoin($svr, $_) foreach (@sajoin);
|
||||
}
|
||||
else {
|
||||
# For multi-line ajoins.
|
||||
API::IRC::cjoin($svr, $_) foreach (@cajoin);
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
|
||||
1;
|
||||
# vim: set ai sw=4 ts=4:
|
||||
@@ -0,0 +1,133 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# Database subroutines for the Auto-Flatfile database format.
|
||||
package DB;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my (%MEM);
|
||||
|
||||
|
||||
# Database initial loading.
|
||||
sub load
|
||||
{
|
||||
# Open, read and close the database.
|
||||
open(my $FDB, q{<}, "$Auto::Bin/../etc/auto.db") or return 0;
|
||||
my @fbuf = <$FDB> or return 0;
|
||||
close $FDB or return 0;
|
||||
|
||||
# Make sure the database version is compatible.
|
||||
if ($fbuf[0] ne "DBV Auto-Flatfile_1.0\n") {
|
||||
# It is not. Bail.
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Iterate the buffer.
|
||||
foreach my $buff (@fbuf) {
|
||||
# Check if the buffer is defined.
|
||||
if (defined $buff) {
|
||||
# Space buffer.
|
||||
my @lbuf = split(' ', $buff);
|
||||
|
||||
# Check if the first two values are defined.
|
||||
if (defined $lbuf[0] and defined $lbuf[1]) {
|
||||
# Make sure it isn't DBV.
|
||||
if ($lbuf[0] eq "DBV") {
|
||||
next;
|
||||
}
|
||||
# Get a count of the values in the buffer minus one.
|
||||
my $c = scalar(@lbuf) - 1;
|
||||
|
||||
# Create an array of the values excluding the first.
|
||||
my @vs;
|
||||
for (my $i = $c; $i <= $c; $i++) {
|
||||
push(@vs, $lbuf[$i]);
|
||||
}
|
||||
|
||||
# Insert data into memory.
|
||||
if (defined $MEM{$lbuf[0]}) {
|
||||
# There is a database entry of the same name already, add to existing array.
|
||||
push(@{ $MEM{$lbuf[0]} }, [ @vs ]);
|
||||
}
|
||||
else {
|
||||
# This is the first database entry of this name, create an array.
|
||||
@{ $MEM{$lbuf[0]} } = [ @vs ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Database flush to disk.
|
||||
sub flush
|
||||
{
|
||||
my $wd = "DBV Auto-Flatfile_1.0\n";
|
||||
# Iterate through all the database data in memory.
|
||||
foreach my $mek (keys %MEM) {
|
||||
foreach my $mas (@{ $MEM{$mek} }) {
|
||||
$wd .= $mek;
|
||||
foreach my $masl (@{ $mas }) {
|
||||
$wd .= " ".$masl;
|
||||
}
|
||||
$wd .= "\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Write to disk.
|
||||
unless (-e "$Auto::Bin/../etc/auto.db") {
|
||||
`touch $Auto::Bin/../etc/auto.db`;
|
||||
}
|
||||
open(my $FDB, q{>}, "$Auto::Bin/../etc/auto.db") or return 0;
|
||||
print $FDB $wd or return 0;
|
||||
close $FDB or return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Get database value.
|
||||
sub get
|
||||
{
|
||||
my ($name) = @_;
|
||||
|
||||
if (defined $MEM{$name}) {
|
||||
return $MEM{$name};
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Write to database.
|
||||
sub mwrite
|
||||
{
|
||||
my ($name, @values) = @_;
|
||||
|
||||
if (defined $MEM{$name}) {
|
||||
# There is a database entry of the same name already, add to existing array.
|
||||
push(@{ $MEM{$name} }, [ @values ]);
|
||||
}
|
||||
else {
|
||||
# This is the first database entry of this name, create an array.
|
||||
@{ $MEM{$name} } = [ @values ];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Delete from database.
|
||||
sub mdelete
|
||||
{
|
||||
my ($name, $i) = @_;
|
||||
|
||||
if (defined $MEM{$name}[$i]) {
|
||||
delete $MEM{$name}[$i];
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,41 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
package Lib::Auto;
|
||||
use strict;
|
||||
use warnings;
|
||||
use API::Log qw(println);
|
||||
our $VERSION = 3.000000;
|
||||
|
||||
# Update checker.
|
||||
sub checkver
|
||||
{
|
||||
if (!$Auto::NUC and Auto::RSTAGE ne 'd') {
|
||||
println '* Connecting to update server...';
|
||||
my $uss = IO::Socket::INET->new(
|
||||
'Proto' => 'tcp',
|
||||
'PeerAddr' => 'dist.xelhua.org',
|
||||
'PeerPort' => 80,
|
||||
'Timeout' => 30
|
||||
) or err(1, 'Cannot connect to update server! Aborting update check.');
|
||||
send $uss, "GET http://dist.xelhua.org/auto/version.txt\n", 0;
|
||||
my $dll = q{};
|
||||
while (my $data = readline $uss) {
|
||||
$data =~ s/(\n|\r)//g;
|
||||
my ($v, $c) = split m/[=]/, $data;
|
||||
|
||||
if ($v eq 'url') {
|
||||
$dll = $c;
|
||||
}
|
||||
elsif ($v eq 'version') {
|
||||
if (Auto::VER.q{.}.Auto::SVER.q{.}.Auto::REV.Auto::RSTAGE ne $c) {
|
||||
println('!!! NOTICE !!! Your copy of Auto is outdated. Current version: '.Auto::VER.q{.}.Auto::SVER.q{.}.Auto::REV.Auto::RSTAGE.' - Latest version: '.$c);
|
||||
println('!!! NOTICE !!! You can get the latest Auto by downloading '.$dll);
|
||||
}
|
||||
else {
|
||||
println('* Auto is up-to-date.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
package Lib::Install;
|
||||
use strict;
|
||||
use warnings;
|
||||
use Exporter;
|
||||
use English qw(-no_match_vars);
|
||||
use FindBin qw($Bin);
|
||||
our $Bin = $Bin;
|
||||
|
||||
our $VERSION = 1.00;
|
||||
our @ISA = qw(Exporter);
|
||||
our @EXPORT = qw(println modfind build checkver);
|
||||
|
||||
sub println
|
||||
{
|
||||
my ($out) = @_;
|
||||
|
||||
if (defined $out) {
|
||||
print $out.$/;
|
||||
}
|
||||
else {
|
||||
print $/;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub modfind
|
||||
{
|
||||
my ($mod) = @_;
|
||||
|
||||
print "Checking for $mod..... ";
|
||||
eval('require '.$mod.'; 1;') and println "OK" or println "Not Found" and exit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub build
|
||||
{
|
||||
my ($features) = @_;
|
||||
|
||||
open(my $FTIME, q{>}, "$Bin/build/time") or println "Failed to install." and exit;
|
||||
print $FTIME time."\n" or println "Failed to install." and exit;
|
||||
close $FTIME or println "Failed to install." and exit;
|
||||
|
||||
open(my $FOS, q{>}, "$Bin/build/os") or println "Failed to install." and exit;
|
||||
print $FOS $OSNAME."\n" or println "Failed to install." and exit;
|
||||
close $FOS or println "Failed to install." and exit;
|
||||
|
||||
open(my $FFEAT, q{>}, "$Bin/build/feat") or println "Failed to install." and exit;
|
||||
print $FFEAT $features."\n" or println "Failed to install." and exit;
|
||||
close $FFEAT or println "Failed to install." and exit;
|
||||
|
||||
open(my $FPERL, q{>}, "$Bin/build/perl") or println "Failed to install." and exit;
|
||||
print $FPERL "$]\n" or println "Failed to install." and exit;
|
||||
close $FPERL or println "Failed to install." and exit;
|
||||
|
||||
open(my $FVER, q{>}, "$Bin/build/ver") or println "Failed to install." and exit;
|
||||
print $FVER "3.0.0d\n" or println "Failed to install." and exit;
|
||||
close $FVER or println "Failed to install." and exit;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub checkver
|
||||
{
|
||||
my ($ver) = @_;
|
||||
|
||||
println "* Connecting to update server...";
|
||||
my $uss = IO::Socket::INET->new(
|
||||
'Proto' => 'tcp',
|
||||
'PeerAddr' => 'dist.xelhua.org',
|
||||
'PeerPort' => 80,
|
||||
'Timeout' => 30
|
||||
) or println "Cannot connect to update server! Aborting update check.";
|
||||
send($uss, "GET http://dist.xelhua.org/auto/version.txt\n", 0);
|
||||
my $dll = '';
|
||||
while (my $data = readline($uss)) {
|
||||
$data =~ s/(\n|\r)//g;
|
||||
my ($v, $c) = split('=', $data);
|
||||
|
||||
if ($v eq "url") {
|
||||
$dll = $c;
|
||||
}
|
||||
elsif ($v eq "version") {
|
||||
if ($ver ne $c) {
|
||||
println("!!! NOTICE !!! Your copy of Auto is outdated. Current version: ".$ver." - Latest version: ".$c);
|
||||
println("!!! NOTICE !!! You can get the latest Auto by downloading ".$dll);
|
||||
println("!!! NOTICE !!! Won't install without force.");
|
||||
exit;
|
||||
}
|
||||
else {
|
||||
println("* Auto is up-to-date.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# Parser::Config - Configuration parser.
|
||||
package Parser::Config;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Create a new instance.
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
my ($file) = @_;
|
||||
my $self = bless {}, $class;
|
||||
|
||||
# Check to see if the configuration file exists.
|
||||
if (!-e "$Auto::Bin/../etc/$file") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Open, read and close the config.
|
||||
open(my $FCONF, q{<}, "$Auto::Bin/../etc/$file") or return 0;
|
||||
my @cosfl = <$FCONF> or return 0;
|
||||
close $FCONF or return 0;
|
||||
|
||||
# Save it to self variable.
|
||||
$self->{'config'}->{'path'} = "$Auto::Bin/../etc/$file";
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
# Parse the configuration file.
|
||||
sub parse
|
||||
{
|
||||
# Get the path to the file.
|
||||
my $self = shift;
|
||||
my $file = $self->{'config'}->{'path'};
|
||||
my $blk = 0;
|
||||
my (%rs);
|
||||
|
||||
# Open, read and close it.
|
||||
open(my $FCONF, q{<}, "$file") or return 0;
|
||||
my @fbuf = <$FCONF> or return 0;
|
||||
close $FCONF or return 0;
|
||||
|
||||
# Iterate the file.
|
||||
foreach my $buff (@fbuf) {
|
||||
# Main newline buffer.
|
||||
if (defined $buff) {
|
||||
# If the line begins with a #, it's a comment so ignore it.
|
||||
if (substr($buff, 0, 1) eq '#') {
|
||||
next;
|
||||
}
|
||||
|
||||
if ($buff =~ m/;/) {
|
||||
# Semicolon buffer.
|
||||
my @asbuf = split(';', $buff);
|
||||
foreach my $asbuff (@asbuf) {
|
||||
if (defined $asbuff) {
|
||||
|
||||
# Space buffer.
|
||||
my @ebuf = split(' ', $asbuff);
|
||||
if (!defined $ebuf[0] or !defined $ebuf[1]) {
|
||||
# Garbage. Ignoring.
|
||||
next;
|
||||
}
|
||||
my $param = $ebuf[1];
|
||||
|
||||
if (substr($param, 0, 1) eq '"' and substr($param, length($param) - 1, 1) ne '"') {
|
||||
# Multi-word string.
|
||||
$param = substr($param, 1);
|
||||
|
||||
for (my $i = 2; $i < scalar(@ebuf); $i++) {
|
||||
if (substr($ebuf[$i], length($ebuf[$i]) - 1, 1) eq '"') {
|
||||
$param .= " ".substr($ebuf[$i], 0, length($ebuf[$i]) - 1);
|
||||
last;
|
||||
}
|
||||
else {
|
||||
$param .= " ".$ebuf[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif (substr($param, 0, 1) eq '"' and substr($param, length($param) - 1, 1) eq '"') {
|
||||
# Single-word string.
|
||||
$param = substr($param, 1, length($ebuf[1]) - 2);
|
||||
}
|
||||
elsif ($param =~ m/[0-9]/) {
|
||||
# Numeric.
|
||||
$param =~ s/[^0-9.]//g;
|
||||
}
|
||||
else {
|
||||
# Garbage.
|
||||
next;
|
||||
}
|
||||
|
||||
my @param = ($param);
|
||||
|
||||
unless (!$blk) {
|
||||
# We're inside a block.
|
||||
if ($blk =~ m/@@@/) {
|
||||
# We're inside a block with a parameter.
|
||||
my @sblk = split('@@@', $blk);
|
||||
|
||||
# Check to see if this config option already exists.
|
||||
if (defined $rs{$sblk[0]}{$sblk[1]}{$ebuf[0]}) {
|
||||
# It does, so merely push this second one to the existing array.
|
||||
push(@{ $rs{$sblk[0]}{$sblk[1]}{$ebuf[0]} }, $param);
|
||||
}
|
||||
else {
|
||||
# It doesn't, create it as an array.
|
||||
@{ $rs{$sblk[0]}{$sblk[1]}{$ebuf[0]} } = @param;
|
||||
}
|
||||
}
|
||||
else {
|
||||
# We're inside a block with no parameter.
|
||||
|
||||
# Check to see if this config option already exists.
|
||||
if (defined $rs{$blk}{$ebuf[0]}) {
|
||||
# It does, so merely push this second one to the existing array.
|
||||
push(@{ $rs{$blk}{$ebuf[0]} }, $param);
|
||||
}
|
||||
else {
|
||||
# It doesn't, create it as an array.
|
||||
@{ $rs{$blk}{$ebuf[0]} } = @param;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# We're not inside a block.
|
||||
|
||||
# Check to see if this config option already exists.
|
||||
if (defined $rs{$ebuf[0]}) {
|
||||
# It does, so merely push this second one to the existing array.
|
||||
push(@{ $rs{$ebuf[0]} }, $param);
|
||||
}
|
||||
else {
|
||||
# It doesn't, create it as an array.
|
||||
@{ $rs{$ebuf[0]} } = @param;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# No semicolon space buffer.
|
||||
my @ebuf = split(' ', $buff);
|
||||
|
||||
if (!defined $ebuf[0]) {
|
||||
# Garbage. Ignoring.
|
||||
next;
|
||||
}
|
||||
|
||||
if (defined $ebuf[1]) {
|
||||
if ($ebuf[1] eq '{') {
|
||||
# This is the beginning of a block with no parameter.
|
||||
$blk = $ebuf[0];
|
||||
}
|
||||
elsif (defined $ebuf[2]) {
|
||||
if ($ebuf[2] eq '{') {
|
||||
# This is the beginning of a block with a parameter.
|
||||
my $param = $ebuf[1];
|
||||
$param =~ s/"//g;
|
||||
$blk = $ebuf[0].'@@@'.$param;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($ebuf[0] eq '}') {
|
||||
# This is the end of a block.
|
||||
$blk = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Return the configuration data.
|
||||
return %rs;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
# vim: set ai sw=4 ts=4:
|
||||
@@ -0,0 +1,630 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# Parser::IRC - Subroutines for parsing incoming data from IRC.
|
||||
package Parser::IRC;
|
||||
use strict;
|
||||
use warnings;
|
||||
use API::Std qw(conf_get err awarn);
|
||||
use API::IRC;
|
||||
|
||||
# Raw parsing hash.
|
||||
our %RAWC = (
|
||||
'001' => \&num001,
|
||||
'005' => \&num005,
|
||||
'353' => \&num353,
|
||||
'432' => \&num432,
|
||||
'433' => \&num433,
|
||||
'438' => \&num438,
|
||||
'465' => \&num465,
|
||||
'471' => \&num471,
|
||||
'473' => \&num473,
|
||||
'474' => \&num474,
|
||||
'475' => \&num475,
|
||||
'477' => \&num477,
|
||||
'JOIN' => \&cjoin,
|
||||
'KICK' => \&kick,
|
||||
'MODE' => \&mode,
|
||||
'NICK' => \&nick,
|
||||
'NOTICE' => \¬ice,
|
||||
'PART' => \&part,
|
||||
'PRIVMSG' => \&privmsg,
|
||||
'QUIT' => \&quit,
|
||||
'TOPIC' => \&topic,
|
||||
);
|
||||
|
||||
# Variables for various functions.
|
||||
our (%got_001, %botnick, %botchans, %csprefix, %chanusers, %chanmodes);
|
||||
|
||||
# Events.
|
||||
API::Std::event_add("on_connect");
|
||||
API::Std::event_add("on_rcjoin");
|
||||
API::Std::event_add("on_ucjoin");
|
||||
API::Std::event_add("on_kick");
|
||||
API::Std::event_add("on_nick");
|
||||
API::Std::event_add("on_notice");
|
||||
API::Std::event_add("on_cprivmsg");
|
||||
API::Std::event_add("on_uprivmsg");
|
||||
API::Std::event_add("on_quit");
|
||||
API::Std::event_add("on_topic");
|
||||
|
||||
# Parse raw data.
|
||||
sub ircparse
|
||||
{
|
||||
my ($svr, $data) = @_;
|
||||
|
||||
# Split spaces into @ex.
|
||||
my @ex = split(' ', $data);
|
||||
|
||||
# Make sure there is enough data.
|
||||
if (defined $ex[0] and defined $ex[1]) {
|
||||
# If it's a ping...
|
||||
if ($ex[0] eq 'PING') {
|
||||
# send a PONG.
|
||||
Auto::socksnd($svr, "PONG ".$ex[1]);
|
||||
}
|
||||
# If it's AUTHENTICATE
|
||||
elsif ($ex[0] eq 'AUTHENTICATE') {
|
||||
if (API::Std::mod_exists("SASLAuth")) {
|
||||
m_SASLAuth::handle_authenticate($svr, @ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
# otherwise, check %RAWC for ex[1].
|
||||
if (defined $RAWC{$ex[1]}) {
|
||||
&{ $RAWC{$ex[1]} }($svr, @ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
###########################
|
||||
# Raw parsing subroutines #
|
||||
###########################
|
||||
|
||||
# Parse: Numeric:001
|
||||
# Successful connection.
|
||||
sub num001
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
|
||||
$got_001{$svr} = 1;
|
||||
|
||||
# In case we don't get NICK from the server.
|
||||
if (defined $botnick{$svr}{newnick}) {
|
||||
$botnick{$svr}{nick} = $botnick{$svr}{newnick};
|
||||
delete $botnick{$svr}{newnick};
|
||||
}
|
||||
|
||||
# Trigger on_connect.
|
||||
API::Std::event_run("on_connect", $svr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:005
|
||||
# Prefixes and channel modes.
|
||||
sub num005
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
|
||||
# Find PREFIX and CHANMODES.
|
||||
foreach my $ex (@ex) {
|
||||
if ($ex =~ m/^PREFIX/xsm) {
|
||||
# Found PREFIX.
|
||||
my $rpx = substr($ex, 8);
|
||||
my ($pm, $pp) = split('\)', $rpx);
|
||||
my @apm = split(//, $pm);
|
||||
my @app = split(//, $pp);
|
||||
foreach my $ppm (@apm) {
|
||||
# Store data.
|
||||
$csprefix{$svr}{$ppm} = shift(@app);
|
||||
}
|
||||
}
|
||||
elsif ($ex =~ m/^CHANMODES/xsm) {
|
||||
# Found CHANMODES.
|
||||
my ($mtl, $mtp, $mtpp, $mts) = split m/[,]/xsm, substr($ex, 10);
|
||||
# List modes.
|
||||
foreach (split(//, $mtl)) { $chanmodes{$svr}{$_} = 1; }
|
||||
# Modes with parameter.
|
||||
foreach (split(//, $mtp)) { $chanmodes{$svr}{$_} = 2; }
|
||||
# Modes with parameter when +.
|
||||
foreach (split(//, $mtpp)) { $chanmodes{$svr}{$_} = 3; }
|
||||
# Modes without parameter.
|
||||
foreach (split(//, $mts)) { $chanmodes{$svr}{$_} = 4; }
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:353
|
||||
# NAMES reply.
|
||||
sub num353
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
|
||||
# Get rid of the colon.
|
||||
$ex[5] = substr($ex[5], 1);
|
||||
# Delete the old chanusers hash if it exists.
|
||||
delete $chanusers{$svr}{$ex[4]} if (defined $chanusers{$svr}{$ex[4]});
|
||||
# Iterate through each user.
|
||||
for (my $i = 5; $i < scalar(@ex); $i++) {
|
||||
my $fi = 0;
|
||||
foreach (keys %{ $csprefix{$svr} }) {
|
||||
# Check if the user has status in the channel.
|
||||
if (substr($ex[$i], 0, 1) eq $csprefix{$svr}{$_}) {
|
||||
# He/she does. Lets set that.
|
||||
if (defined $chanusers{$svr}{$ex[4]}{lc(substr($ex[$i], 1))}) {
|
||||
# If the user has multiple statuses.
|
||||
$chanusers{$svr}{$ex[4]}{lc(substr($ex[$i], 1))} .= $_;
|
||||
}
|
||||
else {
|
||||
# Or not.
|
||||
$chanusers{$svr}{$ex[4]}{lc(substr($ex[$i], 1))} = $_;
|
||||
}
|
||||
$fi = 1;
|
||||
}
|
||||
}
|
||||
# They had status, so go to the next user.
|
||||
next if $fi;
|
||||
# They didn't, set them as a normal user.
|
||||
if (!defined $chanusers{$svr}{$ex[4]}{lc($ex[$i])}) {
|
||||
$chanusers{$svr}{$ex[4]}{lc($ex[$i])} = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:432
|
||||
# Erroneous nickname.
|
||||
sub num432
|
||||
{
|
||||
my ($svr, undef) = @_;
|
||||
|
||||
if ($got_001{$svr}) {
|
||||
err(3, "Got error from server[".$svr."]: Erroneous nickname.", 0);
|
||||
}
|
||||
else {
|
||||
err(2, "Got error from server[".$svr."] before 001: Erroneous nickname. Closing connection.", 0);
|
||||
API::IRC::quit($svr, "An error occurred.");
|
||||
}
|
||||
|
||||
delete $botnick{$svr}{newnick} if (defined $botnick{$svr}{newnick});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:433
|
||||
# Nickname is already in use.
|
||||
sub num433
|
||||
{
|
||||
my ($svr, undef) = @_;
|
||||
|
||||
if (defined $botnick{$svr}{newnick}) {
|
||||
API::IRC::nick($svr, $botnick{$svr}{newnick}."_");
|
||||
delete $botnick{$svr}{newnick} if (defined $botnick{$svr}{newnick});
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:438
|
||||
# Nick change too fast.
|
||||
sub num438
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
|
||||
if (defined $botnick{$svr}{newnick}) {
|
||||
API::Std::timer_add("num438_".$botnick{$svr}{newnick}, 1, $ex[11], sub {
|
||||
API::IRC::nick($Parser::IRC::botnick{$svr}{newnick});
|
||||
delete $botnick{$svr}{newnick} if (defined $botnick{$svr}{newnick});
|
||||
});
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:465
|
||||
# You're banned creep!
|
||||
sub num465
|
||||
{
|
||||
my ($svr, undef) = @_;
|
||||
|
||||
err(3, "Banned from ".$svr."! Closing link...", 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:471
|
||||
# Cannot join channel: Channel is full.
|
||||
sub num471
|
||||
{
|
||||
my ($svr, (undef, undef, undef, $chan)) = @_;
|
||||
|
||||
err(3, "Cannot join channel ".$chan." on ".$svr.": Channel is full.", 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:473
|
||||
# Cannot join channel: Channel is invite-only.
|
||||
sub num473
|
||||
{
|
||||
my ($svr, (undef, undef, undef, $chan)) = @_;
|
||||
|
||||
err(3, "Cannot join channel ".$chan." on ".$svr.": Channel is invite-only.", 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:474
|
||||
# Cannot join channel: Banned from channel.
|
||||
sub num474
|
||||
{
|
||||
my ($svr, (undef, undef, undef, $chan)) = @_;
|
||||
|
||||
err(3, "Cannot join channel ".$chan." on ".$svr.": Banned from channel.", 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:475
|
||||
# Cannot join channel: Bad key.
|
||||
sub num475
|
||||
{
|
||||
my ($svr, (undef, undef, undef, $chan)) = @_;
|
||||
|
||||
err(3, "Cannot join channel ".$chan." on ".$svr.": Bad key.", 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: Numeric:477
|
||||
# Cannot join channel: Need registered nickname.
|
||||
sub num477
|
||||
{
|
||||
my ($svr, (undef, undef, undef, $chan)) = @_;
|
||||
|
||||
err(3, "Cannot join channel ".$chan." on ".$svr.": Need registered nickname.", 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: JOIN
|
||||
sub cjoin
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
my %src = API::IRC::usrc(substr($ex[0], 1));
|
||||
|
||||
# Check if this is coming from ourselves.
|
||||
if ($src{nick} eq $botnick{$svr}{nick}) {
|
||||
$botchans{$svr}{substr $ex[2], 1} = 1;
|
||||
API::Std::event_run("on_ucjoin", ($svr, substr($ex[2], 1)));
|
||||
}
|
||||
else {
|
||||
# It isn't. Update chanusers and trigger on_rcjoin.
|
||||
$chanusers{$svr}{substr $ex[2], 1}{$src{nick}} = 1;
|
||||
API::Std::event_run("on_rcjoin", ($svr, \%src, substr($ex[2], 1)));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: KICK
|
||||
sub kick
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
my %src = API::IRC::usrc(substr($ex[0], 1));
|
||||
|
||||
# Update chanusers.
|
||||
delete $chanusers{$svr}{$ex[2]}{$ex[3]} if defined $chanusers{$svr}{$ex[2]}{$ex[3]};
|
||||
|
||||
# Set $msg to the kick message.
|
||||
my $msg = 0;
|
||||
if (defined $ex[4]) {
|
||||
$msg = substr($ex[4], 1);
|
||||
if (defined $ex[5]) {
|
||||
for (my $i = 5; $i < scalar(@ex); $i++) {
|
||||
$msg .= " ".$ex[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Check if we were the ones kicked.
|
||||
if (lc($ex[3]) eq lc($botnick{$svr}{nick})) {
|
||||
# We were kicked!
|
||||
|
||||
# Delete channel from botchans.
|
||||
delete $botchans{$svr}{$ex[2]};
|
||||
|
||||
# Log this horrible act.
|
||||
API::Log::alog("I was kicked from ".$svr."/".$ex[2]." by ".$src{nick}."! Reason: ".$msg);
|
||||
|
||||
# Rejoin if we're told to in config.
|
||||
if (conf_get("server:$svr:autorejoin")) {
|
||||
if ((conf_get("server:$svr:autorejoin"))[0][0] eq 1) {
|
||||
API::IRC::cjoin($svr, $ex[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
# We weren't. Update chanusers and trigger on_kick.
|
||||
if (defined $chanusers{$svr}{$ex[2]}{$ex[3]}) { delete $chanusers{$svr}{$ex[2]}{$ex[3]}; }
|
||||
API::Std::event_run("on_kick", ($svr, \%src, $ex[2], $ex[3], $msg));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: MODE
|
||||
sub mode
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
|
||||
if ($ex[2] ne $botnick{$svr}{nick}) {
|
||||
# Set data we'll need later.
|
||||
my $chan = $ex[2];
|
||||
my $modes = $ex[3];
|
||||
# Get rid of the useless data, so the mode parser will work smoothly.
|
||||
shift @ex; shift @ex; shift @ex; shift @ex;
|
||||
|
||||
# Check if the modes contain any status modes.
|
||||
my $nt = 0;
|
||||
foreach (keys %{ $csprefix{$svr} }) {
|
||||
if ($modes =~ /($_)/) {
|
||||
$nt = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ($nt) {
|
||||
# It did. Lets parse the changes.
|
||||
|
||||
my @ma = split(//, $modes);
|
||||
|
||||
my $op = 1;
|
||||
foreach my $maf (@ma) {
|
||||
if ($maf eq '+') {
|
||||
# If it's a +, change the operator to 1.
|
||||
$op = 1;
|
||||
}
|
||||
elsif ($maf eq '-') {
|
||||
# If it's a -, change the operator to 2.
|
||||
$op = 2;
|
||||
}
|
||||
else {
|
||||
# It's a mode, lets check if it's a status mode.
|
||||
my $nnt = 0;
|
||||
foreach (keys %{ $csprefix{$svr} }) {
|
||||
if ($maf eq $_) {
|
||||
$nnt = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ($nnt) {
|
||||
# It is a status mode, lets parse changes.
|
||||
my $user = shift(@ex);
|
||||
|
||||
if (defined $chanusers{$svr}{$chan}{$user}) {
|
||||
if ($op == 1) {
|
||||
if ($chanusers{$svr}{$chan}{$user} eq 1) {
|
||||
$chanusers{$svr}{$chan}{$user} = $maf;
|
||||
}
|
||||
else {
|
||||
$chanusers{$svr}{$chan}{$user} .= $maf;
|
||||
}
|
||||
}
|
||||
elsif ($op == 2) {
|
||||
if (length($chanusers{$svr}{$chan}{$user}) == 1) {
|
||||
$chanusers{$svr}{$chan}{$user} = 1;
|
||||
}
|
||||
else {
|
||||
$chanusers{$svr}{$chan}{$user} =~ s/($maf)//gxsm;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$chanusers{$svr}{$chan}{$user} = $maf;
|
||||
}
|
||||
}
|
||||
else {
|
||||
# It is not. Lets adjust arguments accordingly.
|
||||
if (defined $chanmodes{$svr}{$maf}) {
|
||||
if ($chanmodes{$svr}{$maf} == 1 || $chanmodes{$svr}{$maf} == 2) { shift @ex; }
|
||||
if ($chanmodes{$svr}{$maf} == 3) {
|
||||
if ($op == 1) { shift @ex; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: NICK
|
||||
sub nick
|
||||
{
|
||||
my ($svr, ($uex, undef, $nex)) = @_;
|
||||
$nex = substr($nex, 1);
|
||||
|
||||
my %src = API::IRC::usrc(substr($uex, 1));
|
||||
|
||||
# Check if this is coming from ourselves.
|
||||
if ($src{nick} eq $botnick{$svr}{nick}) {
|
||||
# It is. Update bot nick hash.
|
||||
$botnick{$svr}{nick} = $nex;
|
||||
delete $botnick{$svr}{newnick} if (defined $botnick{$svr}{newnick});
|
||||
}
|
||||
else {
|
||||
# It isn't. Update chanusers and trigger on_nick.
|
||||
foreach my $chk (keys %{ $chanusers{$svr} }) {
|
||||
if (defined $chanusers{$svr}{$chk}{$src{nick}}) {
|
||||
$chanusers{$svr}{$chk}{$nex} = $chanusers{$svr}{$chk}{$src{nick}};
|
||||
delete $chanusers{$svr}{$chk}{$src{nick}};
|
||||
}
|
||||
}
|
||||
API::Std::event_run("on_nick", ($svr, \%src, $nex));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: NOTICE
|
||||
sub notice
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
|
||||
API::Std::event_run("on_notice", ($svr, @ex));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: PART
|
||||
sub part
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
my %src = API::IRC::usrc(substr($ex[0], 1));
|
||||
|
||||
# Delete them from chanusers.
|
||||
delete $chanusers{$svr}{$ex[2]}{$src{nick}} if defined $chanusers{$svr}{$ex[2]}{$src{nick}};
|
||||
|
||||
# Set $msg to the part message.
|
||||
my $msg = 0;
|
||||
if (defined $ex[3]) {
|
||||
$msg = substr($ex[3], 1);
|
||||
if (defined $ex[4]) {
|
||||
for (my $i = 4; $i < scalar(@ex); $i++) {
|
||||
$msg .= " ".$ex[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Trigger on_part.
|
||||
API::Std::event_run("on_part", ($svr, \%src, $ex[2], $msg));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: PRIVMSG
|
||||
sub privmsg
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
my %data = API::IRC::usrc(substr($ex[0], 1));
|
||||
|
||||
my @argv;
|
||||
for (my $i = 4; $i < scalar(@ex); $i++) {
|
||||
push(@argv, $ex[$i]);
|
||||
}
|
||||
$data{svr} = $svr;
|
||||
@{ $data{args} } = @argv;
|
||||
|
||||
my ($cmd, $cprefix, $rprefix);
|
||||
# Check if it's to a channel or to us.
|
||||
if (lc($ex[2]) eq lc($botnick{$svr}{nick})) {
|
||||
# It is coming to us in a private message.
|
||||
$cmd = uc(substr($ex[3], 1));
|
||||
if (defined $API::Std::CMDS{$cmd}) {
|
||||
if ($API::Std::CMDS{$cmd}{lvl} == 1 or $API::Std::CMDS{$cmd}{lvl} == 2) {
|
||||
if ($API::Std::CMDS{$cmd}{priv}) {
|
||||
if (API::Std::has_priv(API::Std::match_user(%data), $API::Std::CMDS{$cmd}{priv})) {
|
||||
&{ $API::Std::CMDS{$cmd}{sub} }(%data);
|
||||
}
|
||||
else {
|
||||
API::IRC::notice($data{svr}, $data{nick}, API::Std::trans("Permission denied").".");
|
||||
}
|
||||
}
|
||||
else {
|
||||
&{ $API::Std::CMDS{$cmd}{sub} }(%data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Trigger event on_uprivmsg.
|
||||
API::Std::event_run("on_uprivmsg", ($svr, @ex));
|
||||
}
|
||||
else {
|
||||
# It is coming to us in a channel message.
|
||||
$data{chan} = $ex[2];
|
||||
$cprefix = (conf_get("fantasy_pf"))[0][0];
|
||||
$rprefix = substr($ex[3], 1, 1);
|
||||
$cmd = uc(substr($ex[3], 2));
|
||||
if (defined $API::Std::CMDS{$cmd}) {
|
||||
if ($API::Std::CMDS{$cmd}{lvl} == 0 or $API::Std::CMDS{$cmd}{lvl} == 2) {
|
||||
if ($API::Std::CMDS{$cmd}{priv}) {
|
||||
if (API::Std::has_priv(API::Std::match_user(%data), $API::Std::CMDS{$cmd}{priv})) {
|
||||
&{ $API::Std::CMDS{$cmd}{sub} }(%data) if $rprefix eq $cprefix;
|
||||
}
|
||||
else {
|
||||
API::IRC::notice($data{svr}, $data{nick}, API::Std::trans("Permission denied").".");
|
||||
}
|
||||
}
|
||||
else {
|
||||
&{ $API::Std::CMDS{$cmd}{sub} }(%data) if $rprefix eq $cprefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Trigger event on_cprivmsg.
|
||||
API::Std::event_run("on_cprivmsg", ($svr, @ex));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: QUIT
|
||||
sub quit
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
my %src = API::IRC::usrc(substr($ex[0], 1));
|
||||
|
||||
# Set $msg to the quit message.
|
||||
my $msg = 0;
|
||||
if (defined $ex[2]) {
|
||||
$msg = substr($ex[2], 1);
|
||||
if (defined $ex[3]) {
|
||||
for (my $i = 3; $i < scalar(@ex); $i++) {
|
||||
$msg .= " ".$ex[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Trigger on_quit.
|
||||
API::Std::event_run("on_quit", ($svr, \%src, $msg));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Parse: TOPIC
|
||||
sub topic
|
||||
{
|
||||
my ($svr, @ex) = @_;
|
||||
my %src = API::IRC::usrc(substr($ex[0], 1));
|
||||
|
||||
# Ignore it if it's coming from us.
|
||||
if (lc($src{nick}) ne lc($botnick{$svr}{nick})) {
|
||||
$src{chan} = $ex[2];
|
||||
my (@argv);
|
||||
$argv[0] = substr($ex[3], 1);
|
||||
if (defined $ex[4]) {
|
||||
for (my $i = 4; $i < scalar(@ex); $i++) {
|
||||
push(@argv, $ex[$i]);
|
||||
}
|
||||
}
|
||||
API::Std::event_run("on_topic", ($svr, \%src, @argv));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
# vim: set ai sw=4 ts=4:
|
||||
@@ -0,0 +1,69 @@
|
||||
# Auto IRC Bot. An advanced, lightweight and powerful IRC bot.
|
||||
# Copyright (C) 2010-2011 Xelhua Development Team (doc/CREDITS)
|
||||
# This program is free software; rights to this code are stated in doc/LICENSE.
|
||||
|
||||
# Parser::Lang - Language file parser.
|
||||
package Parser::Lang;
|
||||
use strict;
|
||||
use warnings;
|
||||
use API::Log qw(dbug alog);
|
||||
|
||||
|
||||
# Parser.
|
||||
sub parse
|
||||
{
|
||||
my ($lang) = @_;
|
||||
|
||||
# Check that the language file exists.
|
||||
unless (-e "$Auto::Bin/../lang/$lang.alf") {
|
||||
# Otherwise, use English.
|
||||
dbug "Language '$lang' not found. Using English.";
|
||||
alog "Language '$lang' not found. Using English.";
|
||||
$lang = "en";
|
||||
}
|
||||
|
||||
# Open, read and close the file.
|
||||
open(my $FALF, q{<}, "$Auto::Bin/../lang/$lang.alf") or return 0;
|
||||
my @fbuf = <$FALF>;
|
||||
close $FALF;
|
||||
|
||||
# Iterate the file buffer.
|
||||
foreach my $buff (@fbuf) {
|
||||
if (defined $buff) {
|
||||
# Space buffer.
|
||||
my @sbuf = split(' ', $buff);
|
||||
|
||||
# Check for all required values.
|
||||
if (!defined $sbuf[0] or !defined $sbuf[1] or !defined $sbuf[2]) {
|
||||
# Missing a value.
|
||||
next;
|
||||
}
|
||||
|
||||
# Make sure the first value is "msge".
|
||||
if ($sbuf[0] ne "msge") {
|
||||
# It isn't.
|
||||
next;
|
||||
}
|
||||
|
||||
my $id = $sbuf[1];
|
||||
my $val = $sbuf[2];
|
||||
|
||||
# If the translation is multi-word, continue to parse.
|
||||
if (defined $sbuf[3]) {
|
||||
for (my $i = 3; $i < scalar(@sbuf); $i++) {
|
||||
$val .= " ".$sbuf[$i];
|
||||
}
|
||||
}
|
||||
|
||||
# Save to memory.
|
||||
$id =~ s/"//g;
|
||||
$val =~ s/"//g;
|
||||
$API::Std::LANGE{$id} = $val;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
# vim: set ai sw=4 ts=4:
|
||||
Reference in new issue
Block a user