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 {
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 $pbot = $self->{pbot};
@ -98,8 +98,13 @@ sub interpreter {
foreach my $ref (@{ $self->{handlers} }) {
if($ref->{name} eq $keyword) {
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 {
return undef if $referenced;
if($level == 0) {
return "/msg $nick You must login to use this command.";
} else {

View File

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

View File

@ -454,11 +454,11 @@ sub expand_action_arguments {
sub interpreter {
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 $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');
$from = lc $from;
@ -508,22 +508,24 @@ sub interpreter {
# if multiple channels have this keyword, then ask user to disambiguate
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";
}
# if there's just one other channel that has this keyword, trigger that instance
elsif($found == 1) {
$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
else {
# 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);
# found factfind matches
if($matches !~ m/^No factoids/) {
return undef if $referenced;
return "No such factoid '$original_keyword'; $matches";
}
@ -532,11 +534,14 @@ sub interpreter {
# don't say anything if nothing similiar was found
return undef if $matches eq 'none';
return undef if $referenced;
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_in}) {
if($self->{factoids}->hash->{$channel}->{$keyword}->{last_referenced_in} eq $from) {
@ -567,7 +572,7 @@ sub interpreter {
} else {
if ($self->{factoids}->hash->{$channel}->{$keyword}->{type} eq 'text') {
my $target = $self->{pbot}->{nicklist}->is_present($from, $arguments);
if ($target) {
if ($target and $action !~ /\$nick/) {
if ($action !~ m/^(\/[^ ]+) /) {
$action =~ s/^/\/say $target: $keyword is / unless defined $tonick;
} else {
@ -601,7 +606,7 @@ sub interpreter {
}
$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
@ -624,6 +629,11 @@ sub interpreter {
$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/\$channel/$from/g;
$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};
$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') {
$self->{pbot}->{logger}->log("Found factoid\n");
@ -689,7 +699,7 @@ sub interpreter {
$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;
};

View File

@ -89,24 +89,44 @@ sub process_line {
$bot_trigger = $pbot->{registry}->get_value('general', 'trigger');
}
if($cmd_text =~ /^(?:$bot_trigger|$botnick.?)?\s*{\s*(.*)\s*}\s*$/) {
$has_code = $1 if length $1;
$preserve_whitespace = 1;
} elsif($cmd_text =~ /^$bot_trigger(.*)$/) {
$command = $1;
} elsif($cmd_text =~ /^.?$botnick.?\s*(.*?)$/i) {
$command = $1;
} elsif($cmd_text =~ /^(.*?),?\s*$botnick[?!.]*$/i) {
$command = $1;
} elsif($cmd_text =~ /https?:\/\/([^\s]+)/i) {
$has_url = $1;
} elsif($cmd_text =~ /^\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;
}
my $referenced;
my $count = 0;
while (++$count <= 3) {
$referenced = 0;
$command = undef;
$has_url = undef;
$has_code = undef;
if($cmd_text =~ s/^(?:$bot_trigger|$botnick.?)?\s*{\s*(.*)\s*}\s*$//) {
$has_code = $1 if length $1;
$preserve_whitespace = 1;
} elsif($cmd_text =~ s/^$bot_trigger(.*)$//) {
$command = $1;
} elsif($cmd_text =~ s/^.?$botnick.?\s*(.*?)$//i) {
$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 $from && $pbot->{ignorelist}->check_ignore($nick, $user, $host, $from)) {
my $admin = $pbot->{admins}->loggedin($from, "$nick!$user\@$host");
@ -115,31 +135,31 @@ sub process_line {
return;
}
}
}
if(defined $has_url) {
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 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);
}
} 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);
if(defined $has_url) {
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 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);
}
} 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 {
my $self = shift;
my ($from, $nick, $user, $host, $depth, $command, $tonick) = @_;
my ($from, $nick, $user, $host, $depth, $command, $tonick, $referenced) = @_;
my ($keyword, $arguments) = ("", "");
my $text;
my $pbot = $self->{pbot};
@ -194,7 +214,7 @@ sub interpret {
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 {