Significant refactoring of command passing

Instead of passing locally-scoped short-lived parameters to subroutines,
we now create and pass around a "stuff" context hash.

This allows contextual state to be passed and updated throughout the life
of a command.

This commit is a WIP and is 90% finished. There are likely to be a couple of
edge-cases where strange things may happen. But command-piping mostly works!
This commit is contained in:
Pragmatic Software 2017-11-16 09:23:58 -08:00
parent b12cf1d799
commit 3ed4d58570
4 changed files with 384 additions and 243 deletions

View File

@ -87,32 +87,33 @@ sub exists {
} }
sub interpreter { sub interpreter {
my $self = shift; my ($self, $stuff) = @_;
my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, $unused, $referenced, $root_keyword) = @_; #my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, $unused, $referenced, $root_keyword) = @_;
my $result; my $result;
my $pbot = $self->{pbot}; use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
my $admin = $pbot->{admins}->loggedin($from, "$nick!$user\@$host"); $self->{pbot}->{logger}->log("Commands::interpreter\n");
$self->{pbot}->{logger}->log(Dumper $stuff);
my $admin = $self->{pbot}->{admins}->loggedin($stuff->{from}, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
my $level = defined $admin ? $admin->{level} : 0; my $level = defined $admin ? $admin->{level} : 0;
my $keyword = lc $stuff->{keyword};
$keyword = lc $keyword;
foreach my $ref (@{ $self->{handlers} }) { foreach my $ref (@{ $self->{handlers} }) {
if($ref->{name} eq $keyword) { if ($ref->{name} eq $keyword) {
if($level >= $ref->{level}) { if ($level >= $ref->{level}) {
my $result = &{ $ref->{subref} }($from, $nick, $user, $host, $arguments); my $result = &{ $ref->{subref} }($stuff->{from}, $stuff->{nick}, $stuff->{user}, $stuff->{host}, $stuff->{arguments}, $stuff);
if ($referenced) { if ($stuff->{referenced}) {
return undef if $result =~ m/(?:usage:|no results)/i; return undef if $result =~ m/(?:usage:|no results)/i;
} }
return $result; return $result;
} else { } else {
return undef if $referenced; return undef if $stuff->{referenced};
if($level == 0) { if ($level == 0) {
return "/msg $nick You must login to use this command."; return "/msg $stuff->{nick} You must login to use this command.";
} else { } else {
return "/msg $nick You are not authorized to use this command."; return "/msg $stuff->{nick} You are not authorized to use this command.";
} }
} }
} }

View File

@ -44,68 +44,67 @@ sub initialize {
} }
sub execute_module { sub execute_module {
my ($self, $from, $tonick, $nick, $user, $host, $command, $root_channel, $root_keyword, $keyword, $arguments, $preserve_whitespace, $referenced) = @_; # my ($self, $from, $tonick, $nick, $user, $host, $command, $root_channel, $root_keyword, $keyword, $arguments, $preserve_whitespace, $referenced) = @_;
my ($self, $stuff) = @_;
my $text; my $text;
$arguments = "" if not defined $arguments; $stuff->{arguments} = "" if not defined $stuff->{arguments};
my %stuff = (from => $from, tonick => $tonick, nick => $nick, user => $user, host => $host, command => $command, root_channel => $root_channel, my @factoids = $self->{pbot}->{factoids}->find_factoid($stuff->{from}, $stuff->{keyword}, undef, 2, 2);
root_keyword => $root_keyword, keyword => $keyword, arguments => $arguments, preserve_whitespace => $preserve_whitespace, referenced => $referenced);
my @factoids = $self->{pbot}->{factoids}->find_factoid($from, $keyword, undef, 2, 2);
if(not @factoids or not $factoids[0]) { if(not @factoids or not $factoids[0]) {
$self->{pbot}->{interpreter}->handle_result($from, $nick, $user, $host, $command, "$keyword $arguments", "/msg $nick Failed to find module for '$keyword' in channel $from\n", 1, 0); $stuff->{checkflood} = 1;
$self->{pbot}->{interpreter}->handle_result($stuff, "/msg $stuff->{nick} Failed to find module for '$stuff->{keyword}' in channel $stuff->{from}\n");
return; return;
} }
my ($channel, $trigger) = ($factoids[0]->[0], $factoids[0]->[1]); my ($channel, $trigger) = ($factoids[0]->[0], $factoids[0]->[1]);
$stuff{channel} = $channel; $stuff->{channel} = $channel;
$stuff{trigger} = $trigger; $stuff->{keyword} = $trigger;
$stuff->{trigger} = $trigger;
my $module = $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{action}; my $module = $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{action};
my $module_dir = $self->{pbot}->{registry}->get_value('general', '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 [$command] $module $arguments\n"); $self->{pbot}->{logger}->log("(" . (defined $stuff->{from} ? $stuff->{from} : "(undef)") . "): $stuff->{nick}!$stuff->{user}\@$stuff->{host}: Executing module [$stuff->{command}] $module $stuff->{arguments}\n");
$arguments = $self->{pbot}->{factoids}->expand_special_vars($from, $nick, $root_keyword, $arguments); $stuff->{arguments} = $self->{pbot}->{factoids}->expand_special_vars($stuff->{from}, $stuff->{nick}, $stuff->{root_keyword}, $stuff->{arguments});
$arguments = quotemeta($arguments); $stuff->{arguments} = quotemeta $stuff->{arguments};
if($command eq 'code-factoid' or exists $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{unquote_spaces}) { if ($stuff->{command} eq 'code-factoid' or exists $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{unquote_spaces}) {
$arguments =~ s/\\ / /g; $stuff->{arguments} =~ s/\\ / /g;
} }
if(exists $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{modulelauncher_subpattern}) { if (exists $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{modulelauncher_subpattern}) {
if($self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{modulelauncher_subpattern} =~ m/s\/(.*?)\/(.*)\/(.*)/) { if ($self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{modulelauncher_subpattern} =~ m/s\/(.*?)\/(.*)\/(.*)/) {
my ($p1, $p2, $p3) = ($1, $2, $3); my ($p1, $p2, $p3) = ($1, $2, $3);
my ($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after); my ($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after);
if($p3 eq 'g') { if($p3 eq 'g') {
$arguments =~ s/$p1/$p2/g; $stuff->{arguments} =~ s/$p1/$p2/g;
($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $`, $'); ($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $`, $');
} else { } else {
$arguments =~ s/$p1/$p2/; $stuff->{arguments} =~ s/$p1/$p2/;
($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $`, $'); ($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $`, $');
} }
$arguments =~ s/\$1/$a/g if defined $a; $stuff->{arguments} =~ s/\$1/$a/g if defined $a;
$arguments =~ s/\$2/$b/g if defined $b; $stuff->{arguments} =~ s/\$2/$b/g if defined $b;
$arguments =~ s/\$3/$c/g if defined $c; $stuff->{arguments} =~ s/\$3/$c/g if defined $c;
$arguments =~ s/\$4/$d/g if defined $d; $stuff->{arguments} =~ s/\$4/$d/g if defined $d;
$arguments =~ s/\$5/$e/g if defined $e; $stuff->{arguments} =~ s/\$5/$e/g if defined $e;
$arguments =~ s/\$6/$f/g if defined $f; $stuff->{arguments} =~ s/\$6/$f/g if defined $f;
$arguments =~ s/\$7/$g/g if defined $g; $stuff->{arguments} =~ s/\$7/$g/g if defined $g;
$arguments =~ s/\$8/$h/g if defined $h; $stuff->{arguments} =~ s/\$8/$h/g if defined $h;
$arguments =~ s/\$9/$i/g if defined $i; $stuff->{arguments} =~ s/\$9/$i/g if defined $i;
$arguments =~ s/\$`/$before/g if defined $before; $stuff->{arguments} =~ s/\$`/$before/g if defined $before;
$arguments =~ s/\$'/$after/g if defined $after; $stuff->{arguments} =~ s/\$'/$after/g if defined $after;
#$self->{pbot}->{logger}->log("arguments subpattern: $arguments\n");
} else { } else {
$self->{pbot}->{logger}->log("Invalid module substitution pattern [" . $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{modulelauncher_subpattern}. "], ignoring.\n"); $self->{pbot}->{logger}->log("Invalid module substitution pattern [" . $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{modulelauncher_subpattern}. "], ignoring.\n");
} }
} }
my $argsbuf = $arguments; my $argsbuf = $self->{arguments};
$arguments = ""; $self->{arguments} = "";
my $lr; my $lr;
while(1) { while(1) {
@ -118,11 +117,11 @@ sub execute_module {
$e =~ s/'/'\\''/g; $e =~ s/'/'\\''/g;
$e =~ s/^'\\''/'/; $e =~ s/^'\\''/'/;
$e =~ s/'\\''$/'/; $e =~ s/'\\''$/'/;
$arguments .= $p; $stuff->{arguments} .= $p;
$arguments .= $e; $stuff->{arguments} .= $e;
$lr = $r; $lr = $r;
} else { } else {
$arguments .= $lr; $stuff->{arguments} .= $lr;
last; last;
} }
} }
@ -134,7 +133,8 @@ sub execute_module {
$self->{pbot}->{logger}->log("Could not fork module: $!\n"); $self->{pbot}->{logger}->log("Could not fork module: $!\n");
close $reader; close $reader;
close $writer; close $writer;
$self->{pbot}->{interpreter}->handle_result($from, $nick, $user, $host, $command, "$keyword $arguments", "/me groans loudly.\n", 1, 0); $stuff->{checkflood} = 1;
$self->{pbot}->{interpreter}->handle_result($stuff, "/me groans loudly.\n");
return; return;
} }
@ -157,10 +157,10 @@ sub execute_module {
chdir $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{workdir}; chdir $self->{pbot}->{factoids}->{factoids}->hash->{$channel}->{$trigger}->{workdir};
} }
$stuff{result} = `./$module $arguments 2>> $module-stderr`; $stuff->{result} = `./$module $stuff->{arguments} 2>> $module-stderr`;
chomp $stuff{result}; chomp $stuff->{result};
my $json = encode_json \%stuff; my $json = encode_json $stuff;
print $writer "$json\n"; print $writer "$json\n";
exit 0; exit 0;
} # end child block } # end child block
@ -189,27 +189,29 @@ sub module_pipe_reader {
$stuff->{result} =~ s/\s+$//g; $stuff->{result} =~ s/\s+$//g;
$self->{pbot}->{logger}->log("No text result from code-factoid.\n") and return if not length $stuff->{result}; $self->{pbot}->{logger}->log("No text result from code-factoid.\n") and return if not length $stuff->{result};
$stuff->{result} = $self->{pbot}->{factoids}->handle_action($stuff->{nick}, $stuff->{user}, $stuff->{host}, $stuff->{original_keyword} = $stuff->{root_keyword};
$stuff->{from}, $stuff->{root_channel}, $stuff->{root_keyword}, $stuff->{root_keyword}, $stuff->{arguments},
$stuff->{result}, $stuff->{tonick}, 0, $stuff->{referenced}, undef, $stuff->{root_keyword}); $stuff->{result} = $self->{pbot}->{factoids}->handle_action($stuff, $stuff->{result});
} }
if (defined $stuff->{tonick}) { $stuff->{checkflood} = 0;
$self->{pbot}->{logger}->log("($stuff->{from}): $stuff->{nick}!$stuff->{user}\@$stuff->{host}) sent to $stuff->{tonick}\n");
if (defined $stuff->{nickoverride}) {
$self->{pbot}->{logger}->log("($stuff->{from}): $stuff->{nick}!$stuff->{user}\@$stuff->{host}) sent to $stuff->{nickoverride}\n");
# get rid of original caller's nick # get rid of original caller's nick
$stuff->{result} =~ s/^\/([^ ]+) \Q$stuff->{nick}\E:\s+/\/$1 /; $stuff->{result} =~ s/^\/([^ ]+) \Q$stuff->{nick}\E:\s+/\/$1 /;
$stuff->{result} =~ s/^\Q$stuff->{nick}\E:\s+//; $stuff->{result} =~ s/^\Q$stuff->{nick}\E:\s+//;
$self->{pbot}->{interpreter}->handle_result($stuff->{from}, $stuff->{nick}, $stuff->{user}, $stuff->{host}, $stuff->{command}, "$stuff->{keyword} $stuff->{arguments}", "$stuff->{tonick}: $stuff->{result}", 0, $stuff->{preserve_whitespace}); $self->{pbot}->{interpreter}->handle_result($stuff, "$stuff->{nickoverride}: $stuff->{result}");
} else { } else {
if ($stuff->{command} ne 'code-factoid' and exists $self->{pbot}->{factoids}->{factoids}->hash->{$stuff->{channel}}->{$stuff->{trigger}}->{add_nick} and $self->{pbot}->{factoids}->{factoids}->hash->{$stuff->{channel}}->{$stuff->{trigger}}->{add_nick} != 0) { if ($stuff->{command} ne 'code-factoid' and exists $self->{pbot}->{factoids}->{factoids}->hash->{$stuff->{channel}}->{$stuff->{trigger}}->{add_nick} and $self->{pbot}->{factoids}->{factoids}->hash->{$stuff->{channel}}->{$stuff->{trigger}}->{add_nick} != 0) {
$self->{pbot}->{interpreter}->handle_result($stuff->{from}, $stuff->{nick}, $stuff->{user}, $stuff->{host}, $stuff->{command}, "$stuff->{keyword} $stuff->{arguments}", "$stuff->{nick}: $stuff->{result}", 0, $stuff->{preserve_whitespace}); $self->{pbot}->{interpreter}->handle_result($stuff, "$stuff->{nick}: $stuff->{result}");
} else { } else {
$self->{pbot}->{interpreter}->handle_result($stuff->{from}, $stuff->{nick}, $stuff->{user}, $stuff->{host}, $stuff->{command}, "$stuff->{keyword} $stuff->{arguments}", $stuff->{result}, 0, $stuff->{preserve_whitespace}); $self->{pbot}->{interpreter}->handle_result($stuff, $stuff->{result});
} }
} }
my $text = $self->{pbot}->{interpreter}->truncate_result($stuff->{channel}, $self->{pbot}->{registry}->get_value('irc', 'botnick'), 'undef', $stuff->{result}, $stuff->{result}, 0); my $text = $self->{pbot}->{interpreter}->truncate_result($stuff->{channel}, $self->{pbot}->{registry}->get_value('irc', 'botnick'), 'undef', $stuff->{result}, $stuff->{result}, 0);
$self->{pbot}->{antiflood}->check_flood($stuff->{channel}, $self->{pbot}->{registry}->get_value('irc', 'botnick'), $self->{pbot}->{registry}->get_value('irc', 'username'), 'localhost', $text, 0, 0, 0); $self->{pbot}->{antiflood}->check_flood($stuff->{from}, $self->{pbot}->{registry}->get_value('irc', 'botnick'), $self->{pbot}->{registry}->get_value('irc', 'username'), 'localhost', $text, 0, 0, 0);
} }
1; 1;

View File

@ -403,12 +403,12 @@ sub expand_factoid_vars {
my $depth = 0; my $depth = 0;
while (1) { while (1) {
last if ++$depth >= 20; last if ++$depth >= 100;
my $matches = 0; my $matches = 0;
$action =~ s/\$0/$root_keyword/g; $action =~ s/\$0/$root_keyword/g;
my $const_action = $action; my $const_action = $action;
while ($const_action =~ /(\ba\s*|\ban\s*)?(?<!\\)\$([a-zA-Z0-9_:\-#\[\]]+)/gi) { while ($const_action =~ /(\ba\s*|\ban\s*)?(?<!\\)\$([a-zA-Z0-9_:\-#\[\]]+)/gi) {
last if ++$depth >= 20; last if ++$depth >= 100;
my ($a, $v) = ($1, $2); my ($a, $v) = ($1, $2);
$v =~ s/(.):$/$1/; $v =~ s/(.):$/$1/;
next if $v =~ m/^_/; # underscore-prefixed vars reserved for code-factoids next if $v =~ m/^_/; # underscore-prefixed vars reserved for code-factoids
@ -526,7 +526,7 @@ sub expand_action_arguments {
while ($const_action =~ m/\$arg\[([^]]+)]/g) { while ($const_action =~ m/\$arg\[([^]]+)]/g) {
my $arg = $1; my $arg = $1;
last if ++$depth >= 20; last if ++$depth >= 100;
if ($arg eq '*') { if ($arg eq '*') {
if (not defined $input or $input eq '') { if (not defined $input or $input eq '') {
@ -683,21 +683,28 @@ sub execute_code_factoid_using_safe {
} }
sub execute_code_factoid_using_vm { sub execute_code_factoid_using_vm {
my ($self, $nick, $user, $host, $from, $chan, $root_keyword, $keyword, $arguments, $lang, $code, $tonick) = @_; # my ($self, $nick, $user, $host, $from, $chan, $root_keyword, $keyword, $arguments, $lang, $code, $tonick) = @_;
my ($self, $stuff) = @_;
unless (exists $self->{factoids}->hash->{$chan}->{$keyword}->{interpolate} and $self->{factoids}->hash->{$chan}->{$keyword}->{interpolate} eq '0') { unless (exists $self->{factoids}->hash->{$stuff->{channel}}->{$stuff->{keyword}}->{interpolate} and $self->{factoids}->hash->{$stuff->{channel}}->{$stuff->{keyword}}->{interpolate} eq '0') {
$code = $self->expand_factoid_vars($from, $nick, $root_keyword, $code); $stuff->{code} = $self->expand_factoid_vars($stuff->{from}, $stuff->{nick}, $stuff->{root_keyword}, $stuff->{code});
$code = $self->expand_action_arguments($code, $arguments, $nick); $stuff->{code} = $self->expand_action_arguments($stuff->{code}, $stuff->{arguments}, $stuff->{nick});
} }
my %h = (nick => $nick, channel => $from, lang => $lang, code => $code, arguments => $arguments, factoid => "$chan:$keyword"); my %h = (nick => $stuff->{nick}, channel => $stuff->{from}, lang => $stuff->{lang}, code => $stuff->{code}, arguments => $stuff->{arguments}, factoid => "$stuff->{channel}:$stuff->{keyword}");
if (exists $self->{factoids}->hash->{$chan}->{$keyword}->{'persist-key'}) { if (exists $self->{factoids}->hash->{$stuff->{channel}}->{$stuff->{keyword}}->{'persist-key'}) {
$h{'persist-key'} = $self->{factoids}->hash->{$chan}->{$keyword}->{'persist-key'}; $h{'persist-key'} = $self->{factoids}->hash->{$stuff->{channel}}->{$stuff->{keyword}}->{'persist-key'};
} }
my $json = encode_json \%h; my $json = encode_json \%h;
$self->{pbot}->{factoids}->{factoidmodulelauncher}->execute_module($from, $tonick, $nick, $user, $host, 'code-factoid', $chan, $root_keyword, "compiler", $json, 0);
$stuff->{command} = 'code-factoid';
$stuff->{root_channel} = $stuff->{channel};
$stuff->{keyword} = 'compiler';
$stuff->{arguments} = $json;
$self->{pbot}->{factoids}->{factoidmodulelauncher}->execute_module($stuff);
return ""; return "";
} }
@ -706,38 +713,45 @@ sub execute_code_factoid {
} }
sub interpreter { sub interpreter {
my ($self, $stuff) = @_;
=cut
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, $ref_from, $referenced, $root_keyword) = @_; my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, $ref_from, $referenced, $root_keyword) = @_;
my ($result, $channel); =cut
my $pbot = $self->{pbot}; my $pbot = $self->{pbot};
#$self->{pbot}->{logger}->log("enter factoid interpreter [$keyword][" . (defined $arguments ? $arguments : '') . "] referenced = $referenced\n"); use Data::Dumper;
return undef if not length $keyword or $depth > $self->{pbot}->{registry}->get_value('interpreter', 'max_recursion'); $Data::Dumper::Sortkeys = 1;
$self->{pbot}->{logger}->log("Factoids::interpreter\n");
$self->{pbot}->{logger}->log(Dumper $stuff);
$from = lc $from; #$self->{pbot}->{logger}->log("enter factoid interpreter [$keyword][" . (defined $arguments ? $arguments : '') . "] referenced = $referenced\n");
return undef if not length $stuff->{keyword} or $stuff->{interpret_depth} > $self->{pbot}->{registry}->get_value('interpreter', 'max_recursion');
$stuff->{from} = lc $stuff->{from};
#$self->{pbot}->{logger}->log("factoids interpreter: kw: [$keyword] args: [$arguments] from: [$from], ref_from: [" . (defined $ref_from ? $ref_from : "undef") . "]\n"); #$self->{pbot}->{logger}->log("factoids interpreter: kw: [$keyword] args: [$arguments] from: [$from], ref_from: [" . (defined $ref_from ? $ref_from : "undef") . "]\n");
# search for factoid against global channel and current channel (from unless ref_from is defined) # search for factoid against global channel and current channel (from unless ref_from is defined)
my $original_keyword = $keyword; my $original_keyword = $stuff->{keyword};
#$self->{pbot}->{logger}->log("calling find_factoid in Factoids.pm, interpreter() to search for factoid against global/current\n"); #$self->{pbot}->{logger}->log("calling find_factoid in Factoids.pm, interpreter() to search for factoid against global/current\n");
($channel, $keyword) = $self->find_factoid($ref_from ? $ref_from : $from, $keyword, $arguments, 1); my ($channel, $keyword) = $self->find_factoid($stuff->{ref_from} ? $stuff->{ref_from} : $stuff->{from}, $stuff->{keyword}, $stuff->{arguments}, 1);
if(not defined $ref_from or $ref_from eq '.*') { if (not $stuff->{ref_from} or $stuff->{ref_from} eq '.*') {
$ref_from = ""; $stuff->{ref_from} = "";
} else { } else {
$ref_from = "[$ref_from] "; $stuff->{ref_from} = "[$stuff->{ref_from}] ";
} }
if(defined $channel and not $channel eq '.*' and not lc $channel eq $from) { if (defined $channel and not $channel eq '.*' and not lc $channel eq $stuff->{from}) {
$ref_from = "[$channel] "; $stuff->{ref_from} = "[$channel] ";
} }
$arguments = "" if not defined $arguments; $stuff->{arguments} = "" if not defined $stuff->{arguments};
# if no match found, attempt to call factoid from another channel if it exists there # if no match found, attempt to call factoid from another channel if it exists there
if(not defined $keyword) { if (not defined $keyword) {
my $string = "$original_keyword $arguments"; my $string = "$original_keyword $stuff->{arguments}";
my $lc_keyword = lc $original_keyword; my $lc_keyword = lc $original_keyword;
my $comma = ""; my $comma = "";
my $found = 0; my $found = 0;
@ -748,7 +762,7 @@ sub interpreter {
foreach my $chan (keys %{ $self->{factoids}->hash }) { foreach my $chan (keys %{ $self->{factoids}->hash }) {
foreach my $trig (keys %{ $self->{factoids}->hash->{$chan} }) { foreach my $trig (keys %{ $self->{factoids}->hash->{$chan} }) {
my $type = $self->{factoids}->hash->{$chan}->{$trig}->{type}; my $type = $self->{factoids}->hash->{$chan}->{$trig}->{type};
if(($type eq 'text' or $type eq 'module') and lc $trig eq $lc_keyword) { if (($type eq 'text' or $type eq 'module') and lc $trig eq $lc_keyword) {
$chans .= $comma . $chan; $chans .= $comma . $chan;
$comma = ", "; $comma = ", ";
$found++; $found++;
@ -760,25 +774,28 @@ sub interpreter {
} }
# if multiple channels have this keyword, then ask user to disambiguate # if multiple channels have this keyword, then ask user to disambiguate
if($found > 1) { if ($found > 1) {
return undef if $referenced; return undef if $stuff->{referenced};
return $ref_from . "Ambiguous keyword '$original_keyword' exists in multiple channels (use 'fact <channel> <keyword>' to choose one): $chans"; return $stuff->{ref_from} . "Ambiguous keyword '$original_keyword' exists in multiple channels (use 'fact <channel> <keyword>' to choose one): $chans";
} }
# if there's just one other channel that has this keyword, trigger that instance # if there's just one other channel that has this keyword, trigger that instance
elsif($found == 1) { elsif ($found == 1) {
$pbot->{logger}->log("Found '$original_keyword' as '$fwd_trig' in [$fwd_chan]\n"); $pbot->{logger}->log("Found '$original_keyword' as '$fwd_trig' in [$fwd_chan]\n");
return $pbot->{factoids}->interpreter($from, $nick, $user, $host, ++$depth, $fwd_trig, $arguments, $tonick, $fwd_chan, $referenced, $root_keyword); $stuff->{keyword} = $fwd_trig;
$stuff->{interpret_depth}++;
$stuff->{ref_from} = $fwd_chan;
return $pbot->{factoids}->interpreter($stuff);
} }
# otherwise keyword hasn't been found, display similiar matches for all channels # otherwise keyword hasn't been found, display similiar matches for all channels
else { else {
# if a non-nick argument was supplied, e.g., a sentence using the bot's nick, don't say anything # if a non-nick argument was supplied, e.g., a sentence using the bot's nick, don't say anything
return undef if length $arguments and not $self->{pbot}->{nicklist}->is_present($from, $arguments); return undef if length $stuff->{arguments} and not $self->{pbot}->{nicklist}->is_present($stuff->{from}, $stuff->{arguments});
my $matches = $self->{commands}->factfind($from, $nick, $user, $host, quotemeta $original_keyword); my $matches = $self->{commands}->factfind($stuff->{from}, $stuff->{nick}, $stuff->{user}, $stuff->{host}, quotemeta $original_keyword);
# found factfind matches # found factfind matches
if($matches !~ m/^No factoids/) { if ($matches !~ m/^No factoids/) {
return undef if $referenced; return undef if $stuff->{referenced};
return "No such factoid '$original_keyword'; $matches"; return "No such factoid '$original_keyword'; $matches";
} }
@ -787,19 +804,19 @@ sub interpreter {
# don't say anything if nothing similiar was found # don't say anything if nothing similiar was found
return undef if $matches eq 'none'; return undef if $matches eq 'none';
return undef if $referenced; return undef if $stuff->{referenced};
return $ref_from . "No such factoid '$original_keyword'; did you mean $matches?"; return $stuff->{ref_from} . "No such factoid '$original_keyword'; did you mean $matches?";
} }
} }
return undef if $referenced and $self->{factoids}->hash->{$channel}->{$keyword}->{noembed}; return undef if $stuff->{referenced} and $self->{factoids}->hash->{$channel}->{$keyword}->{noembed};
if(exists $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on}) { if (exists $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on}) {
if(exists $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_in}) { if (exists $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_in}) {
if($self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_in} eq $from) { if ($self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_in} eq $stuff->{from}) {
if(gettimeofday - $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on} < $self->{factoids}->hash->{$channel}->{$keyword}->{rate_limit}) { if (gettimeofday - $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on} < $self->{factoids}->hash->{$channel}->{$keyword}->{rate_limit}) {
return "/msg $nick $ref_from'$keyword' is rate-limited; try again in " . duration ($self->{factoids}->hash->{$channel}->{$keyword}->{rate_limit} - int(gettimeofday - $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on})) . "." unless $self->{pbot}->{admins}->loggedin($channel, "$nick!$user\@$host"); return "/msg $stuff->{nick} $stuff->{ref_from}'$keyword' is rate-limited; try again in " . duration ($self->{factoids}->hash->{$channel}->{$keyword}->{rate_limit} - int(gettimeofday - $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on})) . "." unless $self->{pbot}->{admins}->loggedin($channel, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}");
} }
} }
} }
@ -808,13 +825,13 @@ sub interpreter {
my $type = $self->{factoids}->hash->{$channel}->{$keyword}->{type}; my $type = $self->{factoids}->hash->{$channel}->{$keyword}->{type};
$self->{factoids}->hash->{$channel}->{$keyword}->{ref_count}++; $self->{factoids}->hash->{$channel}->{$keyword}->{ref_count}++;
$self->{factoids}->hash->{$channel}->{$keyword}->{ref_user} = "$nick!$user\@$host"; $self->{factoids}->hash->{$channel}->{$keyword}->{ref_user} = "$stuff->{nick}!$stuff->{user}\@$stuff->{host}";
$self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on} = gettimeofday; $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_on} = gettimeofday;
$self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_in} = $from || "stdin"; $self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_in} = $stuff->{from} || "stdin";
my $action; my $action;
if (length $arguments and exists $self->{factoids}->hash->{$channel}->{$keyword}->{action_with_args}) { if (length $stuff->{arguments} and exists $self->{factoids}->hash->{$channel}->{$keyword}->{action_with_args}) {
$action = $self->{factoids}->hash->{$channel}->{$keyword}->{action_with_args}; $action = $self->{factoids}->hash->{$channel}->{$keyword}->{action_with_args};
} else { } else {
$action = $self->{factoids}->hash->{$channel}->{$keyword}->{action}; $action = $self->{factoids}->hash->{$channel}->{$keyword}->{action};
@ -822,36 +839,51 @@ sub interpreter {
if ($action =~ m{^/code\s+([^\s]+)\s+(.+)$}i) { if ($action =~ m{^/code\s+([^\s]+)\s+(.+)$}i) {
my ($lang, $code) = ($1, $2); my ($lang, $code) = ($1, $2);
$self->execute_code_factoid($nick, $user, $host, $from, $channel, $root_keyword, $keyword, $arguments, $lang, $code, $tonick); $stuff->{channel} = $channel;
$stuff->{lang} = $lang;
$stuff->{code} = $code;
$self->execute_code_factoid($stuff);
return ""; return "";
} }
return $self->handle_action($nick, $user, $host, $from, $channel, $root_keyword, $keyword, $arguments, $action, $tonick, $depth, $referenced, $ref_from, $original_keyword); $stuff->{channel} = $channel;
$stuff->{keyword} = $keyword;
$stuff->{original_keyword} = $original_keyword;
return $self->handle_action($stuff, $action);
} }
sub handle_action { sub handle_action {
my ($self, $nick, $user, $host, $from, $channel, $root_keyword, $keyword, $arguments, $action, $tonick, $depth, $referenced, $ref_from, $original_keyword) = @_; # my ($self, $nick, $user, $host, $from, $channel, $root_keyword, $keyword, $arguments, $action, $tonick, $depth, $referenced, $ref_from, $original_keyword) = @_;
my ($self, $stuff, $action) = @_;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
$self->{pbot}->{logger}->log("Factoids::handle_action [$action]\n");
$self->{pbot}->{logger}->log(Dumper $stuff);
return "" if not length $action; return "" if not length $action;
my ($channel, $keyword) = ($stuff->{channel}, $stuff->{keyword});
unless (exists $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} and $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} eq '0') { unless (exists $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} and $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} eq '0') {
$action = $self->expand_factoid_vars($from, $nick, $root_keyword, $action); $action = $self->expand_factoid_vars($stuff->{from}, $stuff->{nick}, $stuff->{root_keyword}, $action);
} }
if (length $arguments) { if (length $stuff->{arguments}) {
if ($action =~ m/\$args/ or $action =~ m/\$arg\[/) { if ($action =~ m/\$args/ or $action =~ m/\$arg\[/) {
unless ($self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} eq '0') { unless (defined $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} and $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} eq '0') {
$action = $self->expand_action_arguments($action, $arguments, $nick); $action = $self->expand_action_arguments($action, $stuff->{arguments}, $stuff->{nick});
} }
$arguments = ""; $stuff->{arguments} = "";
} else { } else {
if ($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'text') { if ($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'text') {
my $target = $self->{pbot}->{nicklist}->is_present_similar($from, $arguments); my $target = $self->{pbot}->{nicklist}->is_present_similar($stuff->{from}, $stuff->{arguments});
if ($target and $action !~ /\$(?:nick|args)\b/) { if ($target and $action !~ /\$(?:nick|args)\b/) {
if ($action !~ m/^(\/[^ ]+) /) { if ($action !~ m/^(\/[^ ]+) /) {
$action =~ s/^/\/say $target: $keyword is / unless defined $tonick; $action =~ s/^/\/say $target: $keyword is / unless defined $stuff->{nickoverride};
} else { } else {
if ($1 eq '/say') { if ($1 eq '/say') {
$action =~ s/^\/say /\/say $target: /; $action =~ s/^\/say /\/say $target: /;
@ -862,85 +894,90 @@ sub handle_action {
} }
} else { } else {
# no arguments supplied, replace $args with $nick/$tonick, etc # no arguments supplied, replace $args with $nick/$tonick, etc
$action = $self->expand_action_arguments($action, undef, $nick); $action = $self->expand_action_arguments($action, undef, $stuff->{nick});
} }
# Check if it's an alias # Check if it's an alias
if($action =~ /^\/call\s+(.*)$/) { if ($action =~ /^\/call\s+(.*)$/) {
my $command = $self->expand_factoid_vars($from, $nick, $root_keyword, $1); my $command = $self->expand_factoid_vars($stuff->{from}, $stuff->{nick}, $stuff->{root_keyword}, $1);
if(length $arguments) { if (length $stuff->{arguments}) {
$command .= " $arguments"; $command .= " $stuff->{arguments}";
} }
$self->{pbot}->{logger}->log("[" . (defined $from ? $from : "stdin") . "] ($nick!$user\@$host) [$keyword] aliased to: [$command]\n"); $stuff->{command} = $command;
return $self->{pbot}->{interpreter}->interpret($from, $nick, $user, $host, $depth, $command, $tonick, $referenced, $root_keyword);
$self->{pbot}->{logger}->log("[" . (defined $stuff->{from} ? $stuff->{from} : "stdin") . "] ($stuff->{nick}!$stuff->{user}\@$stuff->{host}) [$keyword] aliased to: [$command]\n");
return $self->{pbot}->{interpreter}->interpret($stuff);
} }
if(defined $tonick) { # !tell foo about bar if (defined $stuff->{nickoverride}) { # !tell foo about bar
$self->{pbot}->{logger}->log("($from): $nick!$user\@$host) sent to $tonick\n"); $self->{pbot}->{logger}->log("($stuff->{from}): $stuff->{nick}!$stuff->{user}\@$stuff->{host}) sent to $stuff->{nickoverride}\n");
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick'); my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
# get rid of original caller's nick # get rid of original caller's nick
$action =~ s/^\/([^ ]+) \Q$nick\E.\s+/\/$1 /; $action =~ s/^\/([^ ]+) \Q$stuff->{nick}\E.\s+/\/$1 /;
$action =~ s/^\Q$nick\E.\s+//; $action =~ s/^\Q$stuff->{nick}\E.\s+//;
if ($action =~ s/^\/say\s+//i || $action =~ s/^\/me\s+/* $botnick /i if ($action =~ s/^\/say\s+//i || $action =~ s/^\/me\s+/* $botnick /i || $action =~ /^\/msg\s+/i) {
|| $action =~ /^\/msg\s+/i) { $action = "/say $stuff->{nickoverride}: $action";
$action = "/say $tonick: $action";
} elsif ($action =~ m/^\/kick\s+/i) { } elsif ($action =~ m/^\/kick\s+/i) {
} else { } else {
$action = "/say $tonick: $keyword is $action"; $action = "/say $stuff->{nickoverride}: $stuff->{original_keyword} is $action";
} }
$self->{pbot}->{logger}->log("result set to [$action]\n"); $self->{pbot}->{logger}->log("result set to [$action]\n");
} }
$self->{pbot}->{logger}->log("(" . (defined $from ? $from : "(undef)") . "): $nick!$user\@$host: $keyword: action: \"$action\"\n"); $self->{pbot}->{logger}->log("(" . (defined $stuff->{from} ? $stuff->{from} : "(undef)") . "): $stuff->{nick}!$stuff->{user}\@$stuff->{host}: $keyword: action: \"$action\"\n");
if($self->{factoids}->hash->{$channel}->{$keyword}->{enabled} == 0) { if ($self->{factoids}->hash->{$channel}->{$keyword}->{enabled} == 0) {
$self->{pbot}->{logger}->log("$keyword disabled.\n"); $self->{pbot}->{logger}->log("$keyword disabled.\n");
return "/msg $nick $ref_from$keyword is currently disabled."; return "/msg $stuff->{nick} $stuff->{ref_from}$keyword is currently disabled.";
} }
unless (exists $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} and $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} eq '0') { unless (exists $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} and $self->{factoids}->hash->{$channel}->{$keyword}->{interpolate} eq '0') {
$action = $self->expand_factoid_vars($from, $nick, $root_keyword, $action); $action = $self->expand_factoid_vars($stuff->{from}, $stuff->{nick}, $stuff->{root_keyword}, $action);
$action = $self->expand_action_arguments($action, $arguments, $nick); $action = $self->expand_action_arguments($action, $stuff->{arguments}, $stuff->{nick});
} }
if($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'module') { return $action if $stuff->{command} eq 'code-factoid';
if ($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'module') {
my $preserve_whitespace = $self->{factoids}->hash->{$channel}->{$keyword}->{preserve_whitespace}; my $preserve_whitespace = $self->{factoids}->hash->{$channel}->{$keyword}->{preserve_whitespace};
$preserve_whitespace = 0 if not defined $preserve_whitespace; $preserve_whitespace = 0 if not defined $preserve_whitespace;
return $ref_from . $self->{factoidmodulelauncher}->execute_module($from, $tonick, $nick, $user, $host, "$keyword $arguments", $channel, $root_keyword, $keyword, $arguments, $preserve_whitespace, $referenced); $stuff->{preserve_whitespace} = $preserve_whitespace;
} $stuff->{root_keyword} = $keyword unless defined $stuff->{root_keyword};
elsif($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'text') { $stuff->{root_channel} = $channel;
$self->{pbot}->{logger}->log("Found factoid\n");
return $stuff->{ref_from} . $self->{factoidmodulelauncher}->execute_module($stuff);
}
elsif ($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'text') {
# Don't allow user-custom /msg factoids, unless factoid triggered by admin # Don't allow user-custom /msg factoids, unless factoid triggered by admin
if(($action =~ m/^\/msg/i) and (not $self->{pbot}->{admins}->loggedin($from, "$nick!$user\@$host"))) { if (($action =~ m/^\/msg/i) and (not $self->{pbot}->{admins}->loggedin($stuff->{from}, "$stuff->{nick}!$stuff->{user}\@$stuff->{host}"))) {
$self->{pbot}->{logger}->log("[ABUSE] Bad factoid (contains /msg): $action\n"); $self->{pbot}->{logger}->log("[ABUSE] Bad factoid (contains /msg): $action\n");
return "You must login to use this command." return "You must login to use this command.";
} }
if($ref_from) { if ($stuff->{ref_from}) {
if($action =~ s/^\/say\s+/$ref_from/i || $action =~ s/^\/me\s+(.*)/\/me $1 $ref_from/i if ($action =~ s/^\/say\s+/$stuff->{ref_from}/i || $action =~ s/^\/me\s+(.*)/\/me $1 $stuff->{ref_from}/i
|| $action =~ s/^\/msg\s+([^ ]+)/\/msg $1 $ref_from/i) { || $action =~ s/^\/msg\s+([^ ]+)/\/msg $1 $stuff->{ref_from}/i) {
return $action; return $action;
} else { } else {
return $ref_from . "$keyword is $action"; return $stuff->{ref_from} . "$keyword is $action";
} }
} else { } else {
if ($action =~ m/^\/(?:say|me|msg)/i) { if ($action =~ m/^\/(?:say|me|msg)/i) {
return $action; return $action;
} elsif ($action =~ s/^\/kick\s+//) { } elsif ($action =~ s/^\/kick\s+//) {
if (not exists $self->{factoids}->hash->{$channel}->{$keyword}->{'effective-level'}) { if (not exists $self->{factoids}->hash->{$channel}->{$keyword}->{'effective-level'}) {
return "/say $nick: $keyword doesn't have the effective-level to do that."; return "/say $stuff->{nick}: $keyword doesn't have the effective-level to do that.";
} }
my $level = 10; my $level = 10;
if ($self->{factoids}->hash->{$channel}->{$keyword}->{'effective-level'} >= $level) { if ($self->{factoids}->hash->{$channel}->{$keyword}->{'effective-level'} >= $level) {
return "/$self->{pbot}->{secretstuff}kick " . $action; return "/$self->{pbot}->{secretstuff}kick " . $action;
} else { } else {
return "/say $nick: My effective-level isn't high enough to do that."; return "/say $stuff->{nick}: My effective-level isn't high enough to do that.";
} }
} else { } else {
return "/say $keyword is $action"; return "/say $keyword is $action";
@ -948,9 +985,9 @@ sub handle_action {
} }
} elsif($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'regex') { } elsif($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'regex') {
my $result = eval { my $result = eval {
my $string = "$original_keyword" . (defined $arguments ? " $arguments" : ""); my $string = "$stuff->{original_keyword}" . (defined $stuff->{arguments} ? " $stuff->{arguments}" : "");
my $cmd; my $cmd;
if($string =~ m/$keyword/i) { if ($string =~ m/$keyword/i) {
$self->{pbot}->{logger}->log("[$string] matches [$keyword] - calling [" . $action . "$']\n"); $self->{pbot}->{logger}->log("[$string] matches [$keyword] - calling [" . $action . "$']\n");
$cmd = $action . $'; $cmd = $action . $';
my ($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $`, $'); my ($a, $b, $c, $d, $e, $f, $g, $h, $i, $before, $after) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $`, $');
@ -971,7 +1008,8 @@ sub handle_action {
$cmd = $action; $cmd = $action;
} }
return $self->{pbot}->{interpreter}->interpret($from, $nick, $user, $host, $depth, $cmd, $tonick, $referenced, $root_keyword); $stuff->{command} = $cmd;
return $self->{pbot}->{interpreter}->interpret($stuff);
}; };
if($@) { if($@) {
@ -979,10 +1017,10 @@ sub handle_action {
return ""; return "";
} }
return $ref_from . $result; return $stuff->{ref_from} . $result;
} else { } else {
$self->{pbot}->{logger}->log("($from): $nick!$user\@$host): Unknown command type for '$keyword'\n"); $self->{pbot}->{logger}->log("($stuff->{from}): $stuff->{nick}!$stuff->{user}\@$stuff->{host}): Unknown command type for '$keyword'\n");
return "/me blinks." . " $ref_from"; return "/me blinks." . " $stuff->{ref_from}";
} }
} }

View File

@ -65,11 +65,15 @@ sub process_line {
$from = lc $from if defined $from; $from = lc $from if defined $from;
my $stuff = { from => $from, nick => $nick, user => $user, host => $host, text => $text };
my $pbot = $self->{pbot}; my $pbot = $self->{pbot};
my $message_account = $pbot->{messagehistory}->get_message_account($nick, $user, $host); 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->{messagehistory}->add_message($message_account, "$nick!$user\@$host", $from, $text, $pbot->{messagehistory}->{MSG_CHAT});
$stuff->{message_account} = $message_account;
my $flood_threshold = $pbot->{registry}->get_value($from, 'chat_flood_threshold'); my $flood_threshold = $pbot->{registry}->get_value($from, 'chat_flood_threshold');
my $flood_time_threshold = $pbot->{registry}->get_value($from, 'chat_flood_time_threshold'); my $flood_time_threshold = $pbot->{registry}->get_value($from, 'chat_flood_time_threshold');
@ -111,7 +115,7 @@ sub process_line {
$nick_override = $1; $nick_override = $1;
$has_code = $2 if length $2 and $nick_override !~ /^(?:enum|struct|union)$/; $has_code = $2 if length $2 and $nick_override !~ /^(?:enum|struct|union)$/;
$preserve_whitespace = 1; $preserve_whitespace = 1;
my $nick_override = $self->{pbot}->{nicklist}->is_present($from, $nick_override); $nick_override = $self->{pbot}->{nicklist}->is_present($from, $nick_override);
$processed += 100; $processed += 100;
} elsif($cmd_text =~ s/^\s*([^!,:\(\)\+\*\/ ]+)[,:]?\s+$bot_trigger[`\{](.+?)[\}`]\s*//) { } elsif($cmd_text =~ s/^\s*([^!,:\(\)\+\*\/ ]+)[,:]?\s+$bot_trigger[`\{](.+?)[\}`]\s*//) {
$nick_override = $1; $nick_override = $1;
@ -182,41 +186,62 @@ sub process_line {
} }
} }
} else { } else {
$processed++ if $self->handle_result($from, $nick, $user, $host, $text, $command, $self->interpret($from, $nick, $user, $host, 1, $command, $nick_override, $referenced), 1, $preserve_whitespace); $stuff->{text} = $text;
$stuff->{command} = $command;
$stuff->{nickoverride} = $nick_override if $nick_override;
$stuff->{referenced} = $referenced;
$stuff->{interpret_depth} = 1;
$stuff->{preserve_whitespace} = $preserve_whitespace;
my $result = $self->interpret($stuff);
$stuff->{result} = $result;
$processed++ if $self->handle_result($stuff, $result);
} }
} }
return $processed; return $processed;
} }
sub interpret { sub interpret {
my $self = shift; my ($self, $stuff) = @_;
my ($from, $nick, $user, $host, $depth, $command, $tonick, $referenced, $root_keyword) = @_; # my ($from, $nick, $user, $host, $depth, $command, $tonick, $referenced, $root_keyword) = @_;
my ($keyword, $arguments) = ("", ""); my ($keyword, $arguments) = ("", "");
my $text; my $text;
my $pbot = $self->{pbot}; my $pbot = $self->{pbot};
$pbot->{logger}->log("=== Enter interpret_command: [" . (defined $from ? $from : "(undef)") . "][$nick!$user\@$host][$depth][$command]\n"); $pbot->{logger}->log("=== Enter interpret_command: [" . (defined $stuff->{from} ? $stuff->{from} : "(undef)") . "][$stuff->{nick}!$stuff->{user}\@$stuff->{host}][$stuff->{interpret_depth}][$stuff->{command}]\n");
return "Too many levels of recursion, aborted." if(++$depth > $self->{pbot}->{registry}->get_value('interpreter', 'max_recursion')); use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
$self->{pbot}->{logger}->log("Interpreter::interpret\n");
$self->{pbot}->{logger}->log(Dumper $stuff);
if(not defined $nick || not defined $user || not defined $host || return "Too many levels of recursion, aborted." if(++$stuff->{interpret_depth} > $self->{pbot}->{registry}->get_value('interpreter', 'max_recursion'));
not defined $command) {
if (not defined $stuff->{nick} || not defined $stuff->{user} || not defined $stuff->{host} || not defined $stuff->{command}) {
$pbot->{logger}->log("Error 1, bad parameters to interpret_command\n"); $pbot->{logger}->log("Error 1, bad parameters to interpret_command\n");
return undef; return undef;
} }
if($command =~ /^tell\s+(\p{PosixGraph}{1,20})\s+about\s+(.*?)\s+(.*)$/i) { if ($stuff->{command} =~ /^tell\s+(\p{PosixGraph}{1,20})\s+about\s+(.*?)\s+(.*)$/i) {
($keyword, $arguments, $tonick) = ($2, $3, $1); ($keyword, $arguments, $stuff->{nickoverride}) = ($2, $3, $1);
my $similar = $self->{pbot}->{nicklist}->is_present_similar($from, $tonick); my $similar = $self->{pbot}->{nicklist}->is_present_similar($stuff->{from}, $stuff->{nickoverride});
$tonick = $similar if $similar; if ($similar) {
} elsif($command =~ /^tell\s+(\p{PosixGraph}{1,20})\s+about\s+(.*)$/i) { $stuff->{nickoverride} = $similar;
($keyword, $tonick) = ($2, $1); } else {
my $similar = $self->{pbot}->{nicklist}->is_present_similar($from, $tonick); $stuff->{nickoverride} = undef;
$tonick = $similar if $similar; }
} elsif($command =~ /^(.*?)\s+(.*)$/) { } elsif ($stuff->{command} =~ /^tell\s+(\p{PosixGraph}{1,20})\s+about\s+(.*)$/i) {
($keyword, $stuff->{nickoverride}) = ($2, $1);
my $similar = $self->{pbot}->{nicklist}->is_present_similar($stuff->{from}, $stuff->{nickoverride});
if ($similar) {
$stuff->{nickoverride} = $similar;
} else {
$stuff->{nickoverride} = undef;
}
} elsif ($stuff->{command} =~ /^(.*?)\s+(.*)$/) {
($keyword, $arguments) = ($1, $2); ($keyword, $arguments) = ($1, $2);
} else { } else {
$keyword = $command; $keyword = $stuff->{command};
} }
if (length $keyword > 30) { if (length $keyword > 30) {
@ -224,25 +249,24 @@ sub interpret {
$self->{pbot}->{logger}->log("Truncating keyword to 30 chars: $keyword\n"); $self->{pbot}->{logger}->log("Truncating keyword to 30 chars: $keyword\n");
} }
$stuff->{nickoverride} = $stuff->{nick} if defined $stuff->{nickoverride} and $stuff->{nickoverride} eq 'me';
$tonick = $nick if defined $tonick and $tonick eq 'me';
if ($keyword !~ /^(?:factrem|forget|set|factdel|factadd|add|factfind|find|factshow|show|forget|factdel|factset|factchange|change|msg|tell|cc|eval|u|udict|ud|actiontrigger|urban|perl)$/) { if ($keyword !~ /^(?:factrem|forget|set|factdel|factadd|add|factfind|find|factshow|show|forget|factdel|factset|factchange|change|msg|tell|cc|eval|u|udict|ud|actiontrigger|urban|perl)$/) {
$keyword =~ s/(\w+)([?!.]+)$/$1/; $keyword =~ s/(\w+)([?!.]+)$/$1/;
$arguments =~ s/(?<![\w\/\-\\])me\b/$nick/gi if defined $arguments && $depth <= 2; $arguments =~ s/(?<![\w\/\-\\])me\b/$stuff->{nick}/gi if defined $arguments && $stuff->{interpret_depth} <= 2;
$arguments =~ s/(?<![\w\/\-\\])my\b/${nick}'s/gi if defined $arguments && $depth <= 2; $arguments =~ s/(?<![\w\/\-\\])my\b/$stuff->{nick}'s/gi if defined $arguments && $stuff->{interpret_depth} <= 2;
$arguments =~ s/\\my\b/my/gi if defined $arguments && $depth <= 2; $arguments =~ s/\\my\b/my/gi if defined $arguments && $stuff->{interpret_depth} <= 2;
$arguments =~ s/\\me\b/me/gi if defined $arguments && $depth <= 2; $arguments =~ s/\\me\b/me/gi if defined $arguments && $stuff->{interpret_depth} <= 2;
my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick'); my $botnick = $self->{pbot}->{registry}->get_value('irc', 'botnick');
if (defined $arguments && ($arguments =~ m/^(your|him|her|its|it|them|their)(self|selves)$/i || $arguments =~ m/^$botnick$/i)) { if (defined $arguments && ($arguments =~ m/^(your|him|her|its|it|them|their)(self|selves)$/i || $arguments =~ m/^$botnick$/i)) {
my $delay = (rand 10) + 8; my $delay = (rand 10) + 8;
my $message = { my $message = {
nick => $nick, user => $user, host => $host, command => $command, checkflood => 1, nick => $stuff->{nick}, user => $stuff->{user}, host => $stuff->{host}, command => $stuff->{command}, checkflood => 1,
message => "$nick: Why would I want to do that to myself?" message => "$stuff->{nick}: Why would I want to do that to myself?"
}; };
$self->add_message_to_output_queue($from, $message, $delay); $self->add_message_to_output_queue($stuff->{from}, $message, $delay);
$delay = duration($delay); $delay = duration($delay);
$self->{pbot}->{logger}->log("Final result ($delay delay) [$message->{message}]\n"); $self->{pbot}->{logger}->log("Final result ($delay delay) [$message->{message}]\n");
return undef; return undef;
@ -254,25 +278,27 @@ sub interpret {
return undef; return undef;
} }
$stuff->{keyword} = $keyword;
if (not exists $stuff->{root_keyword}) {
$stuff->{root_keyword} = $keyword;
}
$stuff->{arguments} = $arguments;
my $result; my $result;
if (defined $arguments && $arguments =~ m/\|\s*\{\s*[^}]+\}/) { if (defined $arguments && $arguments =~ m/\|\s*\{\s*[^}]+\}/) {
$arguments =~ m/(.*?)\s*\|\s*\{\s*([^}]+)\}(.*)/; $arguments =~ m/(.*?)\s*\|\s*\{\s*([^}]+)\}(.*)/;
my ($args, $pipe, $rest) = ($1, $2, $3); my ($args, $pipe, $rest) = ($1, $2, $3);
$pipe =~ s/\s+$//;
$self->{pbot}->{logger}->log("piping: [$args][$pipe][$rest]\n"); $self->{pbot}->{logger}->log("piping: [$args][$pipe][$rest]\n");
$result = $self->SUPER::execute_all($from, $nick, $user, $host, $depth, $keyword, $args, $tonick, undef, $referenced, defined $root_keyword ? $root_keyword : $keyword);
$self->{pbot}->{logger}->log("piping: first result: [$result]\n");
$result = $self->interpret($from, $nick, $user, $host, $depth + 1, "$pipe $result$rest", $tonick, $referenced, defined $root_keyword ? $root_keyword : $keyword); $stuff->{arguments} = $args;
$self->{pbot}->{logger}->log("piping: second result: [$result]\n"); $stuff->{pipe} = $pipe;
} $stuff->{pipe_rest} = $rest;
else {
$result = $self->SUPER::execute_all($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, undef, $referenced, defined $root_keyword ? $root_keyword : $keyword);
} }
return $result; return $self->SUPER::execute_all($stuff);
} }
sub truncate_result { sub truncate_result {
@ -306,26 +332,68 @@ sub truncate_result {
} }
sub handle_result { sub handle_result {
my ($self, $from, $nick, $user, $host, $text, $command, $result, $checkflood, $preserve_whitespace) = @_; my ($self, $stuff, $result) = @_;
# my ($self, $from, $nick, $user, $host, $text, $command, $result, $checkflood, $preserve_whitespace) = @_;
$preserve_whitespace = 0 if not defined $preserve_whitespace; $stuff->{preserve_whitespace} = 0 if not defined $stuff->{preserve_whitespace};
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
$self->{pbot}->{logger}->log("Interpreter::handle_result [$result]\n");
$self->{pbot}->{logger}->log(Dumper $stuff);
$result = $stuff->{result} if not defined $result;
if (not defined $result or length $result == 0) { if (not defined $result or length $result == 0) {
return 0; return 0;
} }
if ($stuff->{pipe}) {
my ($pipe, $pipe_rest) = ($stuff->{pipe}, $stuff->{pipe_rest});
delete $stuff->{pipe};
delete $stuff->{pipe_rest};
$self->{pbot}->{logger}->log("Handling pipe [$result][$pipe][$pipe_rest]\n");
if ($result =~ s{^(/say |/me )}{}i) {
$stuff->{prepend} = $1;
} elsif ($result =~ s{^/msg ([^ ]+) }{}i) {
$stuff->{prepend} = "/msg $1 ";
}
$stuff->{command} = "$pipe $result$pipe_rest";
$result = $self->interpret($stuff);
$stuff->{result} = $result;
$self->handle_result($stuff, $result);
return 0;
}
if ($stuff->{prepend}) {
# FIXME: do this better
if ($result =~ s{^(/say |/me )}{}i) {
#$stuff->{prepend} = $1;
} elsif ($result =~ s{^/msg ([^ ]+) }{}i) {
#$stuff->{prepend} = "/msg $1 ";
}
$result = "$stuff->{prepend}$result";
$self->{pbot}->{logger}->log("Prepending [$stuff->{prepend}] to result [$result]\n");
}
my $original_result = $result; my $original_result = $result;
my $use_output_queue = 0; my $use_output_queue = 0;
if (defined $command) { if (defined $stuff->{command}) {
my ($cmd, $args) = split /\s+/, $command, 2; my ($cmd, $args) = split /\s+/, $stuff->{command}, 2;
if (not $self->{pbot}->{commands}->exists($cmd)) { if (not $self->{pbot}->{commands}->exists($cmd)) {
my ($chan, $trigger) = $self->{pbot}->{factoids}->find_factoid($from, $cmd, $args, 1, 0, 1); my ($chan, $trigger) = $self->{pbot}->{factoids}->find_factoid($stuff->{from}, $cmd, $args, 1, 0, 1);
if(defined $trigger) { if(defined $trigger) {
if ($preserve_whitespace == 0) { if ($stuff->{preserve_whitespace} == 0) {
$preserve_whitespace = $self->{pbot}->{factoids}->{factoids}->hash->{$chan}->{$trigger}->{preserve_whitespace}; $stuff->{preserve_whitespace} = $self->{pbot}->{factoids}->{factoids}->hash->{$chan}->{$trigger}->{preserve_whitespace};
$preserve_whitespace = 0 if not defined $preserve_whitespace; $stuff->{preserve_whitespace} = 0 if not defined $stuff->{preserve_whitespace};
} }
$use_output_queue = $self->{pbot}->{factoids}->{factoids}->hash->{$chan}->{$trigger}->{use_output_queue}; $use_output_queue = $self->{pbot}->{factoids}->{factoids}->hash->{$chan}->{$trigger}->{use_output_queue};
@ -334,12 +402,12 @@ sub handle_result {
} }
} }
my $preserve_newlines = $self->{pbot}->{registry}->get_value($from, 'preserve_newlines'); my $preserve_newlines = $self->{pbot}->{registry}->get_value($stuff->{from}, 'preserve_newlines');
$result =~ s/[\n\r]/ /g unless $preserve_newlines; $result =~ s/[\n\r]/ /g unless $preserve_newlines;
$result =~ s/[ \t]+/ /g unless $preserve_whitespace; $result =~ s/[ \t]+/ /g unless $self->{preserve_whitespace};
my $max_lines = $self->{pbot}->{registry}->get_value($from, 'max_newlines'); my $max_lines = $self->{pbot}->{registry}->get_value($stuff->{from}, 'max_newlines');
$max_lines = 4 if not defined $max_lines; $max_lines = 4 if not defined $max_lines;
my $lines = 0; my $lines = 0;
@ -351,38 +419,39 @@ sub handle_result {
next if not length $stripped_line; next if not length $stripped_line;
if (++$lines >= $max_lines) { if (++$lines >= $max_lines) {
my $link = $self->paste("[" . (defined $from ? $from : "stdin") . "] <$nick> $text\n\n$original_result"); my $link = $self->paste("[" . (defined $stuff->{from} ? $stuff->{from} : "stdin") . "] <$stuff->{nick}> $stuff->{text}\n\n$original_result");
if ($use_output_queue) { if ($use_output_queue) {
my $message = { my $message = {
nick => $nick, user => $user, host => $host, command => $command, nick => $stuff->{nick}, user => $stuff->{user}, host => $stuff->{host}, command => $stuff->{command},
message => "And that's all I have to say about that. See $link for full text.", message => "And that's all I have to say about that. See $link for full text.",
checkflood => $checkflood checkflood => $stuff->{checkflood}
}; };
$self->add_message_to_output_queue($from, $message, 0); $self->add_message_to_output_queue($stuff->{from}, $message, 0);
} else { } else {
$self->{pbot}->{conn}->privmsg($from, "And that's all I have to say about that. See $link for full text."); $self->{pbot}->{conn}->privmsg($stuff->{from}, "And that's all I have to say about that. See $link for full text.");
} }
last; last;
} }
if ($preserve_newlines) { if ($preserve_newlines) {
$line = $self->truncate_result($from, $nick, $text, $line, $line, 1); $line = $self->truncate_result($stuff->{from}, $stuff->{nick}, $stuff->{text}, $line, $line, 1);
} else { } else {
$line = $self->truncate_result($from, $nick, $text, $original_result, $line, 1); $line = $self->truncate_result($stuff->{from}, $stuff->{nick}, $stuff->{text}, $original_result, $line, 1);
} }
if ($use_output_queue) { if ($use_output_queue) {
my $delay = (rand 5) + 5; # initial delay for reading/processing user's message my $delay = (rand 5) + 5; # initial delay for reading/processing user's message
$delay += (length $line) / 7; # additional delay of 7 characters per second typing speed $delay += (length $line) / 7; # additional delay of 7 characters per second typing speed
my $message = { my $message = {
nick => $nick, user => $user, host => $host, command => $command, nick => $stuff->{nick}, user => $stuff->{user}, host => $stuff->{host}, command => $stuff->{command},
message => $line, checkflood => $checkflood message => $line, checkflood => $stuff->{checkflood}
}; };
$self->add_message_to_output_queue($from, $message, $delay); $self->add_message_to_output_queue($stuff->{from}, $message, $delay);
$delay = duration($delay); $delay = duration($delay);
$self->{pbot}->{logger}->log("Final result ($delay delay) [$line]\n"); $self->{pbot}->{logger}->log("Final result ($delay delay) [$line]\n");
} else { } else {
$self->output_result($from, $nick, $user, $host, $command, $line, $checkflood); $stuff->{line} = $line;
$self->output_result($stuff);
$self->{pbot}->{logger}->log("Final result: [$line]\n"); $self->{pbot}->{logger}->log("Final result: [$line]\n");
} }
} }
@ -391,33 +460,41 @@ sub handle_result {
} }
sub output_result { sub output_result {
my ($self, $from, $nick, $user, $host, $command, $line, $checkflood) = @_; my ($self, $stuff) = @_;
# my ($self, $from, $nick, $user, $host, $command, $line, $checkflood) = @_;
my ($pbot, $botnick) = ($self->{pbot}, $self->{pbot}->{registry}->get_value('irc', 'botnick')); my ($pbot, $botnick) = ($self->{pbot}, $self->{pbot}->{registry}->get_value('irc', 'botnick'));
if($line =~ s/^\/say\s+//i) { use Data::Dumper;
$pbot->{conn}->privmsg($from, $line) if defined $from && $from !~ /\Q$botnick\E/i; $Data::Dumper::Sortkeys = 1;
$pbot->{antiflood}->check_flood($from, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $line, 0, 0, 0) if $checkflood; $self->{pbot}->{logger}->log("Interpreter::output_result\n");
} elsif($line =~ s/^\/me\s+//i) { $self->{pbot}->{logger}->log(Dumper $stuff);
$pbot->{conn}->me($from, $line) if defined $from && $from !~ /\Q$botnick\E/i;
$pbot->{antiflood}->check_flood($from, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/me ' . $line, 0, 0, 0) if $checkflood; my $line = $stuff->{line};
} elsif($line =~ s/^\/msg\s+([^\s]+)\s+//i) {
return if not defined $line or not length $line;
if ($line =~ s/^\/say\s+//i) {
$pbot->{conn}->privmsg($stuff->{from}, $line) if defined $stuff->{from} && $stuff->{from} !~ /\Q$botnick\E/i;
$pbot->{antiflood}->check_flood($stuff->{from}, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $line, 0, 0, 0) if $stuff->{checkflood};
} elsif ($line =~ s/^\/me\s+//i) {
$pbot->{conn}->me($stuff->{from}, $line) if defined $stuff->{from} && $stuff->{from} !~ /\Q$botnick\E/i;
$pbot->{antiflood}->check_flood($stuff->{from}, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/me ' . $line, 0, 0, 0) if $stuff->{checkflood};
} elsif ($line =~ s/^\/msg\s+([^\s]+)\s+//i) {
my $to = $1; my $to = $1;
if($to =~ /,/) { if ($to =~ /,/) {
$pbot->{logger}->log("[HACK] Possible HACK ATTEMPT /msg multiple users: [$nick!$user\@$host] [$command] [$line]\n"); $pbot->{logger}->log("[HACK] Possible HACK ATTEMPT /msg multiple users: [$stuff->{nick}!$stuff->{user}\@$stuff->{host}] [$stuff->{command}] [$line]\n");
} } elsif ($to =~ /.*serv$/i) {
elsif($to =~ /.*serv$/i) { $pbot->{logger}->log("[HACK] Possible HACK ATTEMPT /msg *serv: [$stuff->{nick}!$stuff->{user}\@$stuff->{host}] [$stuff->{command}] [$line]\n");
$pbot->{logger}->log("[HACK] Possible HACK ATTEMPT /msg *serv: [$nick!$user\@$host] [$command] [$line]\n"); } elsif ($line =~ s/^\/me\s+//i) {
}
elsif($line =~ s/^\/me\s+//i) {
$pbot->{conn}->me($to, $line) if $to !~ /\Q$botnick\E/i; $pbot->{conn}->me($to, $line) if $to !~ /\Q$botnick\E/i;
$pbot->{antiflood}->check_flood($to, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/me ' . $line, 0, 0, 0) if $checkflood; $pbot->{antiflood}->check_flood($to, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/me ' . $line, 0, 0, 0) if $stuff->{checkflood};
} else { } else {
$line =~ s/^\/say\s+//i; $line =~ s/^\/say\s+//i;
$pbot->{conn}->privmsg($to, $line) if $to !~ /\Q$botnick\E/i; $pbot->{conn}->privmsg($to, $line) if $to !~ /\Q$botnick\E/i;
$pbot->{antiflood}->check_flood($to, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $line, 0, 0, 0) if $checkflood; $pbot->{antiflood}->check_flood($to, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $line, 0, 0, 0) if $stuff->{checkflood};
} }
} elsif($line =~ s/^\/$self->{pbot}->{secretstuff}kick\s+//) { } elsif ($line =~ s/^\/$self->{pbot}->{secretstuff}kick\s+//) {
$pbot->{antiflood}->check_flood($from, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/kick ' . $line, 0, 0, 0) if $checkflood; $pbot->{antiflood}->check_flood($stuff->{from}, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', '/kick ' . $line, 0, 0, 0) if $stuff->{checkflood};
my ($victim, $reason) = split /\s+/, $line, 2; my ($victim, $reason) = split /\s+/, $line, 2;
if (not defined $reason) { if (not defined $reason) {
@ -431,15 +508,15 @@ sub output_result {
} }
} }
if ($self->{pbot}->{chanops}->can_gain_ops($from)) { if ($self->{pbot}->{chanops}->can_gain_ops($stuff->{from})) {
$self->{pbot}->{chanops}->add_op_command($from, "kick $from $victim $reason"); $self->{pbot}->{chanops}->add_op_command($stuff->{from}, "kick $stuff->{from} $victim $reason");
$self->{pbot}->{chanops}->gain_ops($from); $self->{pbot}->{chanops}->gain_ops($stuff->{from});
} else { } else {
$pbot->{conn}->privmsg($from, "$victim: $reason") if defined $from && $from !~ /\Q$botnick\E/i; $pbot->{conn}->privmsg($stuff->{from}, "$victim: $reason") if defined $stuff->{from} && $stuff->{from} !~ /\Q$botnick\E/i;
} }
} else { } else {
$pbot->{conn}->privmsg($from, $line) if defined $from && $from !~ /\Q$botnick\E/i; $pbot->{conn}->privmsg($stuff->{from}, $line) if defined $stuff->{from} && $stuff->{from} !~ /\Q$botnick\E/i;
$pbot->{antiflood}->check_flood($from, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $line, 0, 0, 0) if $checkflood; $pbot->{antiflood}->check_flood($stuff->{from}, $botnick, $pbot->{registry}->get_value('irc', 'username'), 'localhost', $line, 0, 0, 0) if $stuff->{checkflood};
} }
} }
@ -463,7 +540,17 @@ sub process_output_queue {
for (my $i = 0; $i < @{$self->{output_queue}->{$channel}}; $i++) { for (my $i = 0; $i < @{$self->{output_queue}->{$channel}}; $i++) {
my $message = $self->{output_queue}->{$channel}->[$i]; my $message = $self->{output_queue}->{$channel}->[$i];
if (gettimeofday >= $message->{when}) { if (gettimeofday >= $message->{when}) {
$self->output_result($channel, $message->{nick}, $message->{user}, $message->{host}, $message->{command}, $message->{message}, $message->{checkflood}); my $stuff = {
from => $channel,
nick => $message->{nick},
user => $message->{user},
host => $message->{host},
line => $message->{message},
command => $message->{command},
checkflood => $message->{checkflood}
};
$self->output_result($stuff);
splice @{$self->{output_queue}->{$channel}}, $i--, 1; splice @{$self->{output_queue}->{$channel}}, $i--, 1;
} }
} }
@ -502,7 +589,20 @@ sub process_command_queue {
for (my $i = 0; $i < @{$self->{command_queue}->{$channel}}; $i++) { for (my $i = 0; $i < @{$self->{command_queue}->{$channel}}; $i++) {
my $command = $self->{command_queue}->{$channel}->[$i]; my $command = $self->{command_queue}->{$channel}->[$i];
if (gettimeofday >= $command->{when}) { if (gettimeofday >= $command->{when}) {
$self->handle_result($channel, $command->{nick}, $command->{user}, $command->{host}, $command->{command}, $command->{command}, $self->interpret($channel, $command->{nick}, $command->{user}, $command->{host}, 0, $command->{command}), 0, 0); my $stuff = {
from => $channel,
nick => $command->{nick},
user => $command->{user},
host => $command->{host},
command => $command->{command},
interpret_depth => 0,
checkflood => 0,
preserve_whitespace => 0
};
my $result = $self->interpret($stuff);
$stuff->{result} = $result;
$self->handle_result($stuff, $result);
splice @{$self->{command_queue}->{$channel}}, $i--, 1; splice @{$self->{command_queue}->{$channel}}, $i--, 1;
} }
} }