3
0
mirror of https://github.com/pragma-/pbot.git synced 2024-10-03 01:48:38 +02:00

Allow factoids to be referenced from within messages

E.g.,

<pragma-> Userbob: You can learn more about candide by reading its !help page and checking out its !source
<candide> Userbob: To learn all about me, see http://www.iso-9899.info/wiki/Candide
<candide> Userbob: My guts can be browsed at https://github.com/pragma-/pbot

Only three triggers will be processed per message.  (I should create a
registry entry to customize this.)

Messages that are addressed at a specific user that exists in the channel will
have that user's name prepended to the factoid output.

Factoid triggers that are referenced from within messages will not produce
error messages if the factoid is not found.

Factoids that have an $arg or $nick special variable will not be triggered as
a reference.

Factoids that have the `noembed` meta-data value set to a true value will not
be invoked as a reference.
This commit is contained in:
Pragmatic Software 2015-09-03 20:56:44 -07:00
parent d570dd7dd4
commit 8c16fbd3e5
4 changed files with 84 additions and 45 deletions

View File

@ -86,7 +86,7 @@ sub exists {
sub interpreter { sub interpreter {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick) = @_; my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, $unused, $referenced) = @_;
my $result; my $result;
my $pbot = $self->{pbot}; my $pbot = $self->{pbot};
@ -98,8 +98,13 @@ sub interpreter {
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}) {
return &{ $ref->{subref} }($from, $nick, $user, $host, $arguments); my $result = &{ $ref->{subref} }($from, $nick, $user, $host, $arguments);
if ($referenced) {
return undef if $result =~ m/(?:usage:|no results)/i;
}
return $result;
} else { } else {
return undef if $referenced;
if($level == 0) { if($level == 0) {
return "/msg $nick You must login to use this command."; return "/msg $nick You must login to use this command.";
} else { } else {

View File

@ -39,7 +39,7 @@ sub initialize {
} }
sub execute_module { sub execute_module {
my ($self, $from, $tonick, $nick, $user, $host, $command, $keyword, $arguments, $preserve_whitespace) = @_; my ($self, $from, $tonick, $nick, $user, $host, $command, $keyword, $arguments, $preserve_whitespace, $referenced) = @_;
my $text; my $text;
$arguments = "" if not defined $arguments; $arguments = "" if not defined $arguments;
@ -152,6 +152,10 @@ sub execute_module {
$text = `./$module $arguments 2>> $module-stderr`; $text = `./$module $arguments 2>> $module-stderr`;
if ($referenced) {
exit 0 if $text =~ m/(?:no results)/i;
}
if(defined $tonick) { if(defined $tonick) {
$self->{pbot}->{logger}->log("($from): $nick!$user\@$host) sent to $tonick\n"); $self->{pbot}->{logger}->log("($from): $nick!$user\@$host) sent to $tonick\n");
if(defined $text && length $text > 0) { if(defined $text && length $text > 0) {

View File

@ -454,11 +454,11 @@ sub expand_action_arguments {
sub interpreter { sub interpreter {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, $ref_from) = @_; my ($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, $ref_from, $referenced) = @_;
my ($result, $channel); my ($result, $channel);
my $pbot = $self->{pbot}; my $pbot = $self->{pbot};
#$self->{pbot}->{logger}->log("enter factoid interpreter [$keyword][" . (defined $arguments ? $arguments : '') . "]\n"); #$self->{pbot}->{logger}->log("enter factoid interpreter [$keyword][" . (defined $arguments ? $arguments : '') . "] referenced = $referenced\n");
return undef if not length $keyword or $depth > $self->{pbot}->{registry}->get_value('interpreter', 'max_recursion'); return undef if not length $keyword or $depth > $self->{pbot}->{registry}->get_value('interpreter', 'max_recursion');
$from = lc $from; $from = lc $from;
@ -508,22 +508,24 @@ 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 $ref_from . "Ambiguous keyword '$original_keyword' exists in multiple channels (use 'fact <channel> <keyword>' to choose one): $chans"; return $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); return $pbot->{factoids}->interpreter($from, $nick, $user, $host, ++$depth, $fwd_trig, $arguments, $tonick, $fwd_chan, $referenced);
} }
# 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 "" if length $arguments and not $self->{pbot}->{nicklist}->is_present($from, $arguments); return undef if length $arguments and not $self->{pbot}->{nicklist}->is_present($from, $arguments);
my $matches = $self->{commands}->factfind($from, $nick, $user, $host, quotemeta $original_keyword); my $matches = $self->{commands}->factfind($from, $nick, $user, $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 "No such factoid '$original_keyword'; $matches"; return "No such factoid '$original_keyword'; $matches";
} }
@ -532,11 +534,14 @@ 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 $ref_from . "No such factoid '$original_keyword'; did you mean $matches?"; return $ref_from . "No such factoid '$original_keyword'; did you mean $matches?";
} }
} }
return undef if $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 $from) {
@ -567,7 +572,7 @@ sub interpreter {
} 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($from, $arguments); my $target = $self->{pbot}->{nicklist}->is_present($from, $arguments);
if ($target) { if ($target and $action !~ /\$nick/) {
if ($action !~ m/^(\/[^ ]+) /) { if ($action !~ m/^(\/[^ ]+) /) {
$action =~ s/^/\/say $target: $keyword is / unless defined $tonick; $action =~ s/^/\/say $target: $keyword is / unless defined $tonick;
} else { } else {
@ -601,7 +606,7 @@ sub interpreter {
} }
$pbot->{logger}->log("[" . (defined $from ? $from : "stdin") . "] ($nick!$user\@$host) [$keyword] aliased to: [$command]\n"); $pbot->{logger}->log("[" . (defined $from ? $from : "stdin") . "] ($nick!$user\@$host) [$keyword] aliased to: [$command]\n");
return $pbot->{interpreter}->interpret($from, $nick, $user, $host, $depth, $command, $tonick); return $pbot->{interpreter}->interpret($from, $nick, $user, $host, $depth, $command, $tonick, $referenced);
} }
if(defined $tonick) { # !tell foo about bar if(defined $tonick) { # !tell foo about bar
@ -624,6 +629,11 @@ sub interpreter {
$self->{pbot}->{logger}->log("(" . (defined $from ? $from : "(undef)") . "): $nick!$user\@$host: $keyword: action: \"$action\"\n"); $self->{pbot}->{logger}->log("(" . (defined $from ? $from : "(undef)") . "): $nick!$user\@$host: $keyword: action: \"$action\"\n");
if ($referenced) {
return undef if $action =~ m/\$(?:nick|arg)/;
return undef if $arguments =~ m/\$(?:nick|arg)/;
}
$action =~ s/\$nick/$nick/g; $action =~ s/\$nick/$nick/g;
$action =~ s/\$channel/$from/g; $action =~ s/\$channel/$from/g;
$action =~ s/\$randomnick/my $random = $self->{pbot}->{nicklist}->random_nick($from); $random ? $random : $nick/ge; $action =~ s/\$randomnick/my $random = $self->{pbot}->{nicklist}->random_nick($from); $random ? $random : $nick/ge;
@ -639,7 +649,7 @@ sub interpreter {
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", $keyword, $arguments, $preserve_whitespace); return $ref_from . $self->{factoidmodulelauncher}->execute_module($from, $tonick, $nick, $user, $host, "$keyword $arguments", $keyword, $arguments, $preserve_whitespace, $referenced);
} }
elsif($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'text') { elsif($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'text') {
$self->{pbot}->{logger}->log("Found factoid\n"); $self->{pbot}->{logger}->log("Found factoid\n");
@ -689,7 +699,7 @@ sub interpreter {
$cmd = $action; $cmd = $action;
} }
$result = $pbot->{interpreter}->interpret($from, $nick, $user, $host, $depth, $cmd, $tonick); $result = $pbot->{interpreter}->interpret($from, $nick, $user, $host, $depth, $cmd, $tonick, $referenced);
return $result; return $result;
}; };

View File

@ -89,24 +89,44 @@ sub process_line {
$bot_trigger = $pbot->{registry}->get_value('general', 'trigger'); $bot_trigger = $pbot->{registry}->get_value('general', 'trigger');
} }
if($cmd_text =~ /^(?:$bot_trigger|$botnick.?)?\s*{\s*(.*)\s*}\s*$/) { my $referenced;
$has_code = $1 if length $1; my $count = 0;
$preserve_whitespace = 1; while (++$count <= 3) {
} elsif($cmd_text =~ /^$bot_trigger(.*)$/) { $referenced = 0;
$command = $1; $command = undef;
} elsif($cmd_text =~ /^.?$botnick.?\s*(.*?)$/i) { $has_url = undef;
$command = $1; $has_code = undef;
} elsif($cmd_text =~ /^(.*?),?\s*$botnick[?!.]*$/i) {
$command = $1; if($cmd_text =~ s/^(?:$bot_trigger|$botnick.?)?\s*{\s*(.*)\s*}\s*$//) {
} elsif($cmd_text =~ /https?:\/\/([^\s]+)/i) { $has_code = $1 if length $1;
$has_url = $1; $preserve_whitespace = 1;
} elsif($cmd_text =~ /^\s*([^,:\(\)\+\*\/ ]+)[,:]*\s*{\s*(.*)\s*}\s*$/) { } elsif($cmd_text =~ s/^$bot_trigger(.*)$//) {
$nick_override = $1; $command = $1;
$has_code = $2 if length $2 and $nick_override ne 'enum' and $nick_override ne 'struct'; } elsif($cmd_text =~ s/^.?$botnick.?\s*(.*?)$//i) {
$preserve_whitespace = 1; $command = $1;
} } elsif($cmd_text =~ s/^(.*?),?\s*$botnick[?!.]*$//i) {
$command = $1;
} elsif($cmd_text =~ s/https?:\/\/([^\s]+)//i) {
$has_url = $1;
} elsif($cmd_text =~ s/^\s*([^,:\(\)\+\*\/ ]+)[,:]*\s*{\s*(.*)\s*}\s*$//) {
$nick_override = $1;
$has_code = $2 if length $2 and $nick_override ne 'enum' and $nick_override ne 'struct';
$preserve_whitespace = 1;
} elsif ($cmd_text =~ s/\B$bot_trigger([^ ]+)//) {
my $cmd = $1;
$cmd =~ s/(.)[.!?;,)]$/$1/;
my ($nick) = $cmd_text =~ m/^([^ ,:;]+)/;
$nick = $self->{pbot}->{nicklist}->is_present($from, $nick);
if ($nick) {
$command = "tell $nick about $cmd";
} else {
$command = $cmd;
}
$referenced = 1;
}
last if not defined $command and not defined $has_url and not defined $has_code;
if(defined $command || defined $has_url || defined $has_code) {
if((defined $command && $command !~ /^login/i) || defined $has_url || defined $has_code) { if((defined $command && $command !~ /^login/i) || defined $has_url || defined $has_code) {
if(defined $from && $pbot->{ignorelist}->check_ignore($nick, $user, $host, $from)) { if(defined $from && $pbot->{ignorelist}->check_ignore($nick, $user, $host, $from)) {
my $admin = $pbot->{admins}->loggedin($from, "$nick!$user\@$host"); my $admin = $pbot->{admins}->loggedin($from, "$nick!$user\@$host");
@ -115,31 +135,31 @@ sub process_line {
return; return;
} }
} }
}
if(defined $has_url) { if(defined $has_url) {
if($pbot->{registry}->get_value('general', 'show_url_titles') and not $pbot->{registry}->get_value($from, 'no_url_titles') if($pbot->{registry}->get_value('general', 'show_url_titles') and not $pbot->{registry}->get_value($from, 'no_url_titles')
and not grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'show_url_titles_ignore_channels') and not grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'show_url_titles_ignore_channels')
and grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'show_url_titles_channels')) { and grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'show_url_titles_channels')) {
$pbot->{factoids}->{factoidmodulelauncher}->execute_module($from, undef, $nick, $user, $host, $text, "title", "$nick http://$has_url", $preserve_whitespace); $pbot->{factoids}->{factoidmodulelauncher}->execute_module($from, undef, $nick, $user, $host, $text, "title", "$nick http://$has_url", $preserve_whitespace);
}
} elsif(defined $has_code) {
if($pbot->{registry}->get_value('general', 'compile_blocks') and not $pbot->{registry}->get_value($from, 'no_compile_blocks')
and not grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'compile_blocks_ignore_channels')
and grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'compile_blocks_channels')) {
if (not defined $nick_override or (defined $nick_override and $self->{pbot}->{nicklist}->is_present($from, $nick_override))) {
$pbot->{factoids}->{factoidmodulelauncher}->execute_module($from, undef, $nick, $user, $host, $text, "compiler_block", (defined $nick_override ? $nick_override : $nick) . " $from $has_code }", $preserve_whitespace);
} }
} elsif(defined $has_code) {
if($pbot->{registry}->get_value('general', 'compile_blocks') and not $pbot->{registry}->get_value($from, 'no_compile_blocks')
and not grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'compile_blocks_ignore_channels')
and grep { $from =~ /$_/i } $pbot->{registry}->get_value('general', 'compile_blocks_channels')) {
if (not defined $nick_override or (defined $nick_override and $self->{pbot}->{nicklist}->is_present($from, $nick_override))) {
$pbot->{factoids}->{factoidmodulelauncher}->execute_module($from, undef, $nick, $user, $host, $text, "compiler_block", (defined $nick_override ? $nick_override : $nick) . " $from $has_code }", $preserve_whitespace);
}
}
} else {
$self->handle_result($from, $nick, $user, $host, $text, $command, $self->interpret($from, $nick, $user, $host, 1, $command, undef, $referenced), 1, $preserve_whitespace);
} }
} else {
$self->handle_result($from, $nick, $user, $host, $text, $command, $self->interpret($from, $nick, $user, $host, 1, $command), 1, $preserve_whitespace);
} }
} }
} }
sub interpret { sub interpret {
my $self = shift; my $self = shift;
my ($from, $nick, $user, $host, $depth, $command, $tonick) = @_; my ($from, $nick, $user, $host, $depth, $command, $tonick, $referenced) = @_;
my ($keyword, $arguments) = ("", ""); my ($keyword, $arguments) = ("", "");
my $text; my $text;
my $pbot = $self->{pbot}; my $pbot = $self->{pbot};
@ -194,7 +214,7 @@ sub interpret {
return undef; return undef;
} }
return $self->SUPER::execute_all($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick); return $self->SUPER::execute_all($from, $nick, $user, $host, $depth, $keyword, $arguments, $tonick, undef, $referenced);
} }
sub truncate_result { sub truncate_result {