2014-05-13 12:15:52 +02:00
# File: MessageHistory.pm
#
# Purpose: Keeps track of who has said what and when, as well as their
2019-06-26 18:34:19 +02:00
# nickserv accounts and alter-hostmasks.
2014-05-13 12:15:52 +02:00
#
# Used in conjunction with AntiFlood and Quotegrabs for kick/ban on
# flood/ban-evasion and grabbing quotes, respectively.
2021-07-11 00:00:22 +02:00
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
# SPDX-License-Identifier: MIT
2017-03-05 22:33:31 +01:00
2021-07-21 07:44:51 +02:00
package PBot::Core::MessageHistory ;
use parent 'PBot::Core::Class' ;
2014-05-13 12:15:52 +02:00
2021-06-19 06:23:34 +02:00
use PBot::Imports ;
2019-07-11 03:40:53 +02:00
2020-02-16 23:13:41 +01:00
use Getopt::Long qw( GetOptionsFromArray ) ;
2021-07-09 02:27:31 +02:00
use Time::HiRes qw( time tv_interval ) ;
2014-05-13 12:15:52 +02:00
use Time::Duration ;
2021-07-21 07:44:51 +02:00
use PBot::Core::MessageHistory::Storage::SQLite ;
2014-05-13 12:15:52 +02:00
sub initialize {
2020-02-15 23:38:32 +01:00
my ( $ self , % conf ) = @ _ ;
$ self - > { filename } = $ conf { filename } // $ self - > { pbot } - > { registry } - > get_value ( 'general' , 'data_dir' ) . '/message_history.sqlite3' ;
2014-05-13 12:15:52 +02:00
2021-07-21 07:44:51 +02:00
$ self - > { database } = PBot::Core::MessageHistory::Storage::SQLite - > new (
2021-07-21 06:38:07 +02:00
pbot = > $ self - > { pbot } ,
filename = > $ self - > { filename }
) ;
2020-02-15 23:38:32 +01:00
$ self - > { database } - > begin ( ) ;
$ self - > { database } - > devalidate_all_channels ( ) ;
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
$ self - > { pbot } - > { registry } - > add_default ( 'text' , 'messagehistory' , 'max_recall_time' , $ conf { max_recall_time } // 0 ) ;
2014-05-18 22:09:05 +02:00
2020-05-04 22:21:35 +02:00
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > cmd_recall_message ( @ _ ) } , "recall" , 0 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > cmd_rebuild_aliases ( @ _ ) } , "rebuildaliases" , 1 ) ;
2021-07-09 02:27:31 +02:00
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > cmd_list_also_known_as ( @ _ ) } , "aka" , 0 ) ;
2020-05-04 22:21:35 +02:00
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > cmd_aka_link ( @ _ ) } , "akalink" , 1 ) ;
$ self - > { pbot } - > { commands } - > register ( sub { $ self - > cmd_aka_unlink ( @ _ ) } , "akaunlink" , 1 ) ;
2014-05-17 00:11:31 +02:00
2021-07-09 02:27:31 +02:00
# add capabilities to admin group
2020-02-15 23:38:32 +01:00
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-akalink' , 1 ) ;
$ self - > { pbot } - > { capabilities } - > add ( 'admin' , 'can-akaunlink' , 1 ) ;
2020-02-06 02:55:31 +01:00
2020-02-15 23:38:32 +01:00
$ self - > { pbot } - > { atexit } - > register ( sub { $ self - > { database } - > end ( ) ; return ; } ) ;
2014-05-13 12:15:52 +02:00
}
2020-05-04 22:21:35 +02:00
sub cmd_list_also_known_as {
my ( $ self , $ context ) = @ _ ;
2020-02-15 23:38:32 +01:00
2020-05-18 09:05:15 +02:00
my $ usage = "Usage: aka [-hilngr] <nick> [-sort <by>]; -h show hostmasks; -i show ids; -l show last seen, -n show nickserv accounts; -g show gecos, -r show relationships" ;
2020-02-15 23:38:32 +01:00
2021-07-09 02:27:31 +02:00
if ( not length $ context - > { arguments } ) {
return $ usage ;
}
2020-02-15 23:38:32 +01:00
my $ getopt_error ;
local $ SIG { __WARN__ } = sub {
$ getopt_error = shift ;
chomp $ getopt_error ;
} ;
2020-05-18 09:05:15 +02:00
Getopt::Long:: Configure ( "bundling_override" ) ;
2020-02-15 23:38:32 +01:00
2020-05-18 19:57:23 +02:00
my $ sort_method = undef ;
2020-05-18 09:05:15 +02:00
my ( $ show_hostmasks , $ show_gecos , $ show_nickserv , $ show_id , $ show_relationship , $ show_weak , $ show_last_seen , $ dont_use_aliases_table ) ;
2020-05-04 22:21:35 +02:00
my @ opt_args = $ self - > { pbot } - > { interpreter } - > split_line ( $ context - > { arguments } , strip_quotes = > 1 ) ;
2020-02-16 23:13:41 +01:00
GetOptionsFromArray (
\ @ opt_args ,
2020-02-15 23:38:32 +01:00
'h' = > \ $ show_hostmasks ,
2020-05-18 09:05:15 +02:00
'l' = > \ $ show_last_seen ,
2020-02-15 23:38:32 +01:00
'n' = > \ $ show_nickserv ,
'r' = > \ $ show_relationship ,
'g' = > \ $ show_gecos ,
'w' = > \ $ show_weak ,
2020-05-17 07:39:48 +02:00
'z' = > \ $ dont_use_aliases_table ,
2020-05-18 09:05:15 +02:00
'i' = > \ $ show_id ,
'sort|s=s' = > \ $ sort_method ,
2020-02-15 23:38:32 +01:00
) ;
return "/say $getopt_error -- $usage" if defined $ getopt_error ;
2020-02-16 23:13:41 +01:00
return "Too many arguments -- $usage" if @ opt_args > 1 ;
return "Missing argument -- $usage" if @ opt_args != 1 ;
2020-02-15 23:38:32 +01:00
2020-05-18 19:57:23 +02:00
$ sort_method = 'seen' if $ show_last_seen and not defined $ sort_method ;
$ sort_method = 'nick' if not defined $ sort_method ;
2020-05-18 09:05:15 +02:00
my % sort = (
'id' = > sub {
if ( $ _ [ 1 ] eq '+' ) {
return $ _ [ 0 ] - > { $ a } - > { id } <=> $ _ [ 0 ] - > { $ b } - > { id } ;
} else {
return $ _ [ 0 ] - > { $ b } - > { id } <=> $ _ [ 0 ] - > { $ a } - > { id } ;
}
} ,
'seen' = > sub {
if ( $ _ [ 1 ] eq '+' ) {
return $ _ [ 0 ] - > { $ b } - > { last_seen } <=> $ _ [ 0 ] - > { $ a } - > { last_seen } ;
} else {
return $ _ [ 0 ] - > { $ a } - > { last_seen } <=> $ _ [ 0 ] - > { $ b } - > { last_seen } ;
}
} ,
'nickserv' = > sub {
if ( $ _ [ 1 ] eq '+' ) {
return lc $ _ [ 0 ] - > { $ a } - > { nickserv } cmp lc $ _ [ 0 ] - > { $ b } - > { nickserv } ;
} else {
return lc $ _ [ 0 ] - > { $ b } - > { nickserv } cmp lc $ _ [ 0 ] - > { $ a } - > { nickserv } ;
}
} ,
'nick' = > sub {
if ( $ _ [ 1 ] eq '+' ) {
return lc $ _ [ 0 ] - > { $ a } - > { nick } cmp lc $ _ [ 0 ] - > { $ b } - > { nick } ;
} else {
return lc $ _ [ 0 ] - > { $ b } - > { nick } cmp lc $ _ [ 0 ] - > { $ a } - > { nick } ;
}
} ,
'user' = > sub {
if ( $ _ [ 1 ] eq '+' ) {
return lc $ _ [ 0 ] - > { $ a } - > { user } cmp lc $ _ [ 0 ] - > { $ b } - > { user } ;
} else {
return lc $ _ [ 0 ] - > { $ b } - > { user } cmp lc $ _ [ 0 ] - > { $ a } - > { user } ;
}
} ,
'host' = > sub {
if ( $ _ [ 1 ] eq '+' ) {
return lc $ _ [ 0 ] - > { $ a } - > { host } cmp lc $ _ [ 0 ] - > { $ b } - > { host } ;
} else {
return lc $ _ [ 0 ] - > { $ b } - > { host } cmp lc $ _ [ 0 ] - > { $ a } - > { host } ;
}
} ,
2020-10-23 09:21:27 +02:00
'hostmask' = > sub {
2020-05-18 09:05:15 +02:00
if ( $ _ [ 1 ] eq '+' ) {
return lc $ _ [ 0 ] - > { $ a } - > { hostmask } cmp lc $ _ [ 0 ] - > { $ b } - > { hostmask } ;
} else {
return lc $ _ [ 0 ] - > { $ b } - > { hostmask } cmp lc $ _ [ 0 ] - > { $ a } - > { hostmask } ;
}
} ,
2020-05-18 10:00:18 +02:00
2020-10-23 09:21:27 +02:00
'gecos' = > sub {
2020-05-18 10:00:18 +02:00
if ( $ _ [ 1 ] eq '+' ) {
return lc $ _ [ 0 ] - > { $ a } - > { gecos } cmp lc $ _ [ 0 ] - > { $ b } - > { gecos } ;
} else {
return lc $ _ [ 0 ] - > { $ b } - > { gecos } cmp lc $ _ [ 0 ] - > { $ a } - > { gecos } ;
}
} ,
2020-05-18 09:05:15 +02:00
) ;
my $ sort_direction = '+' ;
if ( $ sort_method =~ s/^(\+|\-)// ) {
$ sort_direction = $ 1 ;
}
if ( not exists $ sort { $ sort_method } ) {
return "Invalid sort method '$sort_method'; valid methods are: " . join ( ', ' , sort keys % sort ) . "; prefix with - to invert sort direction." ;
}
2020-02-16 23:13:41 +01:00
my % akas = $ self - > { database } - > get_also_known_as ( $ opt_args [ 0 ] , $ dont_use_aliases_table ) ;
2020-02-15 23:38:32 +01:00
if ( % akas ) {
2020-02-16 23:13:41 +01:00
my $ result = "$opt_args[0] also known as:\n" ;
2015-05-13 06:46:40 +02:00
2020-02-15 23:38:32 +01:00
my % nicks ;
my $ sep = "" ;
2020-05-18 09:05:15 +02:00
foreach my $ aka ( sort { $ sort { $ sort_method } - > ( \ % akas , $ sort_direction ) } keys % akas ) {
2020-02-15 23:38:32 +01:00
next if $ aka =~ /^Guest\d+(?:!.*)?$/ ;
2020-05-17 07:39:48 +02:00
next if exists $ akas { $ aka } - > { type } and $ akas { $ aka } - > { type } == $ self - > { database } - > { alias_type } - > { WEAK } && not $ show_weak ;
2015-07-15 09:18:57 +02:00
2020-02-15 23:38:32 +01:00
if ( not $ show_hostmasks ) {
my ( $ nick ) = $ aka =~ m/([^!]+)/ ;
next if exists $ nicks { $ nick } ;
$ nicks { $ nick } - > { id } = $ akas { $ aka } - > { id } ;
$ result . = "$sep$nick" ;
} else {
$ result . = "$sep$aka" ;
}
$ result . = "?" if $ akas { $ aka } - > { nickchange } == 1 ;
$ result . = " ($akas{$aka}->{nickserv})" if $ show_nickserv and exists $ akas { $ aka } - > { nickserv } ;
$ result . = " {$akas{$aka}->{gecos}}" if $ show_gecos and exists $ akas { $ aka } - > { gecos } ;
if ( $ show_relationship ) {
2021-07-09 02:27:31 +02:00
if ( $ akas { $ aka } - > { id } == $ akas { $ aka } - > { alias } ) {
$ result . = " [$akas{$aka}->{id}]" ;
} else {
$ result . = " [$akas{$aka}->{id} -> $akas{$aka}->{alias}]" ;
}
2020-02-15 23:38:32 +01:00
} elsif ( $ show_id ) {
$ result . = " [$akas{$aka}->{id}]" ;
}
2020-05-17 07:39:48 +02:00
$ result . = " [WEAK]" if exists $ akas { $ aka } - > { type } and $ akas { $ aka } - > { type } == $ self - > { database } - > { alias_type } - > { WEAK } ;
2020-02-15 23:38:32 +01:00
2020-05-18 09:05:15 +02:00
if ( $ show_last_seen ) {
2021-07-09 02:27:31 +02:00
my $ seen = concise ago ( time - $ akas { $ aka } - > { last_seen } ) ;
2021-07-12 00:31:27 +02:00
$ result . = " (seen $seen)" ;
2020-05-18 09:05:15 +02:00
}
2021-07-09 02:27:31 +02:00
if ( $ show_hostmasks or $ show_nickserv or $ show_gecos or $ show_id or $ show_relationship ) {
$ sep = ",\n" ;
} else {
$ sep = ", " ;
}
2020-02-15 23:38:32 +01:00
}
return $ result ;
} else {
2020-02-16 23:13:41 +01:00
return "I don't know anybody named $opt_args[0]." ;
2014-07-11 14:57:18 +02:00
}
}
2020-05-04 22:21:35 +02:00
sub cmd_recall_message {
my ( $ self , $ context ) = @ _ ;
2014-05-13 12:15:52 +02:00
2020-05-04 22:21:35 +02:00
my $ usage = 'Usage: recall [nick [history [channel]]] [-c <channel>] [-t <text>] [-b <context before>] [-a <context after>] [-x <filter to nick>] [-n <count>] [-r raw mode] [+ ...]' ;
2014-05-14 23:23:59 +02:00
2020-05-04 22:21:35 +02:00
my $ arguments = $ context - > { arguments } ;
2021-07-09 02:27:31 +02:00
if ( not length $ arguments ) {
return $ usage ;
}
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
$ arguments = lc $ arguments ;
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
my @ recalls = split /\s\+\s/ , $ arguments ;
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
my $ getopt_error ;
local $ SIG { __WARN__ } = sub {
$ getopt_error = shift ;
chomp $ getopt_error ;
} ;
2014-05-14 23:23:59 +02:00
2020-06-05 23:32:37 +02:00
my $ result = '' ;
2020-04-30 02:49:31 +02:00
Getopt::Long:: Configure ( "bundling_override" ) ;
# global state
my ( $ recall_channel , $ raw , $ random ) ;
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
foreach my $ recall ( @ recalls ) {
2020-06-05 23:32:37 +02:00
my ( $ recall_nick , $ recall_text , $ recall_history , $ recall_before , $ recall_after , $ recall_context , $ recall_count ) ;
2014-05-14 23:23:59 +02:00
2020-02-28 06:06:52 +01:00
my @ opt_args = $ self - > { pbot } - > { interpreter } - > split_line ( $ recall , strip_quotes = > 1 ) ;
2020-02-16 23:13:41 +01:00
GetOptionsFromArray (
\ @ opt_args ,
2021-07-09 02:44:39 +02:00
'channel|c=s' = > \ $ recall_channel ,
'history|h=s' = > \ $ recall_history ,
'text|t=s' = > \ $ recall_text ,
'before|b=i' = > \ $ recall_before ,
'after|a=i' = > \ $ recall_after ,
'count|n=i' = > \ $ recall_count ,
'context|x=s' = > \ $ recall_context ,
2020-04-30 02:49:31 +02:00
'raw|r' = > \ $ raw ,
'random' = > \ $ random ,
2020-02-15 23:38:32 +01:00
) ;
2014-05-14 23:23:59 +02:00
2020-02-15 23:38:32 +01:00
return "/say $getopt_error -- $usage" if defined $ getopt_error ;
2014-05-14 23:23:59 +02:00
2020-06-05 23:56:53 +02:00
if ( defined $ recall_history and defined $ recall_text ) {
2020-06-05 23:32:37 +02:00
return "/say $context->{nick}: The -h and -t options cannot be used together." ;
}
# we swap these $recall variables around so much later on that we
# need to remember which flags were explicitly set...
2020-02-15 23:38:32 +01:00
my $ channel_arg = 1 if defined $ recall_channel ;
my $ history_arg = 1 if defined $ recall_history ;
2014-05-13 12:15:52 +02:00
2020-02-16 23:13:41 +01:00
$ recall_nick = shift @ opt_args if @ opt_args ;
2020-06-05 23:32:37 +02:00
$ recall_history = shift @ opt_args if @ opt_args and not $ history_arg and not defined $ recall_text ;
if ( not $ channel_arg ) {
$ recall_channel = "@opt_args" if @ opt_args ;
} else {
if ( defined $ recall_history ) {
$ recall_history . = ' ' ;
}
$ recall_history . = "@opt_args" if @ opt_args ;
}
if ( defined $ recall_text and not defined $ recall_history ) {
$ recall_history = $ recall_text ;
}
2015-06-16 02:58:25 +02:00
2021-02-07 22:40:40 +01:00
my $ max_count = $ self - > { pbot } - > { registry } - > get_value ( 'messagehistory' , 'max_recall_count' ) // 50 ;
2021-07-09 02:27:31 +02:00
if ( ( not defined $ recall_count ) || ( $ recall_count <= 0 ) ) {
$ recall_count = 1 ;
}
if ( $ recall_count > $ max_count ) {
return "You may only select a count of up to $max_count messages." ;
}
2015-06-16 02:58:25 +02:00
2020-02-15 23:38:32 +01:00
$ recall_before = 0 if not defined $ recall_before ;
$ recall_after = 0 if not defined $ recall_after ;
2015-09-04 05:50:07 +02:00
2021-07-09 02:27:31 +02:00
# imply -x if -n > 1 and -x isn't already set to somebody
if ( $ recall_count > 1 and not defined $ recall_context ) {
$ recall_context = $ recall_nick ;
}
2019-05-20 23:05:58 +02:00
2020-04-30 20:48:53 +02:00
# make -n behave like -b if -n > 1 and no history is specified
if ( not defined $ recall_history and $ recall_count > 1 ) {
2020-02-15 23:38:32 +01:00
$ recall_before = $ recall_count - 1 ;
$ recall_count = 0 ;
}
2019-05-20 23:05:58 +02:00
2020-04-22 00:14:11 +02:00
if ( $ recall_before + $ recall_after > 100 ) { return "You may only select up to 100 lines of surrounding context." ; }
2015-06-16 02:58:25 +02:00
2020-02-28 06:06:52 +01:00
if ( $ recall_count > 1 and ( $ recall_before > 0 or $ recall_after > 0 ) ) { return "The `count` and `before/after` options cannot be used together." ; }
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
# swap nick and channel if recall nick looks like channel and channel wasn't specified
if ( not $ channel_arg and $ recall_nick =~ m/^#/ ) {
my $ temp = $ recall_nick ;
$ recall_nick = $ recall_channel ;
$ recall_channel = $ temp ;
}
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
$ recall_history = 1 if not defined $ recall_history ;
2015-09-04 05:50:07 +02:00
2020-02-15 23:38:32 +01:00
# swap history and channel if history looks like a channel and neither history or channel were specified
if ( not $ channel_arg and not $ history_arg and $ recall_history =~ m/^#/ ) {
my $ temp = $ recall_history ;
$ recall_history = $ recall_channel ;
$ recall_channel = $ temp ;
}
2014-05-14 23:23:59 +02:00
2020-02-15 23:38:32 +01:00
# skip recall command if recalling self without arguments
2021-07-14 00:23:04 +02:00
if ( defined $ recall_nick and not defined $ recall_history ) {
$ recall_history = $ context - > { nick } eq $ recall_nick ? 2 : 1 ;
}
2014-05-14 23:23:59 +02:00
2020-02-15 23:38:32 +01:00
# set history to most recent message if not specified
$ recall_history = '1' if not defined $ recall_history ;
2014-05-14 23:23:59 +02:00
2020-02-15 23:38:32 +01:00
# set channel to current channel if not specified
2020-05-04 22:21:35 +02:00
$ recall_channel = $ context - > { from } if not defined $ recall_channel ;
2014-05-14 23:23:59 +02:00
2020-02-28 06:06:52 +01:00
# yet another sanity check for people using it wrong
2020-02-15 23:38:32 +01:00
if ( $ recall_channel !~ m/^#/ ) {
$ recall_history = "$recall_history $recall_channel" ;
2020-05-04 22:21:35 +02:00
$ recall_channel = $ context - > { from } ;
2020-02-15 23:38:32 +01:00
}
2017-04-11 04:18:20 +02:00
2021-07-14 00:23:04 +02:00
# set nick argument to -x argument if no nick was provided but -x was
if ( not defined $ recall_nick and defined $ recall_context ) {
$ recall_nick = $ recall_context ;
}
2015-01-23 20:44:38 +01:00
2021-07-14 00:23:04 +02:00
# message account and stored nickname with proper typographical casing
2020-02-15 23:38:32 +01:00
my ( $ account , $ found_nick ) ;
2014-05-14 23:23:59 +02:00
2021-07-14 00:23:04 +02:00
# get message account and found nick if a nick was provided
2020-02-15 23:38:32 +01:00
if ( defined $ recall_nick ) {
2021-07-14 00:23:04 +02:00
# account and hostmask
2020-02-15 23:38:32 +01:00
( $ account , $ found_nick ) = $ self - > { database } - > find_message_account_by_nick ( $ recall_nick ) ;
2014-05-14 23:23:59 +02:00
2021-07-14 00:23:04 +02:00
if ( not defined $ account ) {
return "I don't know anybody named $recall_nick." ;
}
2015-05-12 06:27:22 +02:00
2021-07-14 00:23:04 +02:00
# keep only nick portion of hostmask
2020-02-15 23:38:32 +01:00
$ found_nick =~ s/!.*$// ;
}
2014-05-13 12:15:52 +02:00
2021-07-14 00:23:04 +02:00
# matching message found in database, if any
2020-02-15 23:38:32 +01:00
my $ message ;
2020-04-30 02:49:31 +02:00
if ( $ random ) {
2021-07-14 00:23:04 +02:00
# get a random message
$ message = $ self - > { database } - > get_random_message ( $ account , $ recall_channel , $ recall_nick ) ;
2020-06-05 23:32:37 +02:00
} elsif ( $ recall_history =~ /^\d+$/ and not defined $ recall_text ) {
2020-02-15 23:38:32 +01:00
# integral history
2021-07-14 00:23:04 +02:00
# if a nick was given, ensure requested history is within range of nick's history count
2020-02-15 23:38:32 +01:00
if ( defined $ account ) {
2021-07-14 00:23:04 +02:00
my $ max_messages = $ self - > { database } - > get_max_messages ( $ account , $ recall_channel , $ recall_nick ) ;
2020-02-15 23:38:32 +01:00
if ( $ recall_history < 1 || $ recall_history > $ max_messages ) {
if ( $ max_messages == 0 ) {
2020-04-22 00:14:11 +02:00
return "No messages for $recall_nick in $recall_channel yet." ;
2020-02-15 23:38:32 +01:00
} else {
return "Please choose a history between 1 and $max_messages" ;
}
}
2015-09-12 10:52:45 +02:00
}
2020-02-15 23:38:32 +01:00
$ recall_history - - ;
2021-07-14 00:23:04 +02:00
$ message = $ self - > { database } - > recall_message_by_count ( $ account , $ recall_channel , $ recall_history , '(?:recall|mock|ftfy|fix|clapper)' , $ recall_nick ) ;
2020-02-15 23:38:32 +01:00
2021-07-09 02:27:31 +02:00
if ( not defined $ message ) {
2021-07-14 00:23:04 +02:00
if ( defined $ account ) {
return "No message found at index $recall_history for $found_nick in $recall_channel." ;
} else {
return "No message found at index $recall_history in $recall_channel." ;
}
2021-07-09 02:27:31 +02:00
}
2020-02-15 23:38:32 +01:00
} else {
# regex history
2021-07-14 00:23:04 +02:00
$ message = $ self - > { database } - > recall_message_by_text ( $ account , $ recall_channel , $ recall_history , '(?:recall|mock|ftfy|fix|clapper)' , $ recall_nick ) ;
2020-02-15 23:38:32 +01:00
if ( not defined $ message ) {
2021-07-09 02:27:31 +02:00
if ( defined $ account ) {
2021-07-14 00:23:04 +02:00
return "No message for $found_nick in $recall_channel containing \"$recall_history\"" ;
2021-07-09 02:27:31 +02:00
} else {
2021-07-14 00:23:04 +02:00
return "No message in $recall_channel containing \"$recall_history\"." ;
2021-07-09 02:27:31 +02:00
}
2015-09-12 10:52:45 +02:00
}
2014-05-14 23:23:59 +02:00
}
2014-05-13 12:15:52 +02:00
2021-07-14 00:23:04 +02:00
my ( $ context_account , $ context_nick ) ;
2014-05-13 12:15:52 +02:00
2020-02-15 23:38:32 +01:00
if ( defined $ recall_context ) {
2021-07-14 00:23:04 +02:00
( $ context_account , $ context_nick ) = $ self - > { database } - > find_message_account_by_nick ( $ recall_context ) ;
2014-05-14 23:23:59 +02:00
2021-07-14 00:23:04 +02:00
if ( not defined $ context_account ) {
return "I don't know anybody named $recall_context." ;
}
# keep only nick portion of hostmask
$ context_nick =~ s/!.*$// ;
2014-05-14 23:23:59 +02:00
}
2014-05-13 12:15:52 +02:00
2021-07-14 00:23:04 +02:00
my $ messages = $ self - > { database } - > get_message_context ( $ message , $ recall_before , $ recall_after , $ recall_count , $ recall_history , $ context_account , $ context_nick ) ;
2015-01-23 20:44:38 +01:00
2020-02-15 23:38:32 +01:00
my $ max_recall_time = $ self - > { pbot } - > { registry } - > get_value ( 'messagehistory' , 'max_recall_time' ) ;
2015-01-23 20:44:38 +01:00
2020-02-15 23:38:32 +01:00
foreach my $ msg ( @$ messages ) {
2021-07-14 00:23:04 +02:00
# optionally limit messages by by a maximum recall duration from the current time, for privacy
if ( $ max_recall_time && time - $ msg - > { timestamp } > $ max_recall_time
&& not $ self - > { pbot } - > { users } - > loggedin_admin ( $ context - > { from } , $ context - > { hostmask } ) )
{
$ max_recall_time = duration $ max_recall_time ;
2020-06-05 23:32:37 +02:00
$ result . = "Sorry, you can not recall messages older than $max_recall_time." ;
return $ result ;
2020-02-15 23:38:32 +01:00
}
2015-01-23 20:44:38 +01:00
2020-02-15 23:38:32 +01:00
my $ text = $ msg - > { msg } ;
2021-07-14 00:23:04 +02:00
my $ ago = concise ago ( time - $ msg - > { timestamp } ) ;
my $ nick ;
if ( not $ raw ) {
if ( $ msg - > { hostmask } ) {
( $ nick ) = $ msg - > { hostmask } =~ /^([^!]+)!/ ;
} else {
$ nick = $ self - > { database } - > find_most_recent_hostmask ( $ msg - > { id } ) ;
( $ nick ) = $ nick =~ m/^([^!]+)/ ;
}
}
2020-02-15 23:38:32 +01:00
if ( $ text =~ s/^(NICKCHANGE)\b/changed nick to/
or $ text =~ s/^(KICKED|QUIT)\b/lc "$1"/e
or $ text =~ s/^MODE ([^ ]+) (.*)/set mode $1 on $2/
or $ text =~ s/^(JOIN|PART)\b/lc "$1ed"/e )
{
2021-07-14 00:23:04 +02:00
$ text =~ s/^(quit) (.*)/$1 ($2)/ ; # fix ugly "[nick] quit Quit: Leaving."
$ result . = $ raw ? "$text\n" : "[$ago] $nick $text\n" ;
}
elsif ( $ text =~ s/^\/me\s+// ) {
$ result . = $ raw ? "$text\n" : "[$ago] * $nick $text\n" ;
}
else {
$ result . = $ raw ? "$text\n" : "[$ago] <$nick> $text\n" ;
2020-02-15 23:38:32 +01:00
}
}
2014-05-13 12:15:52 +02:00
}
2020-06-05 23:32:37 +02:00
return $ result ;
2014-05-13 12:15:52 +02:00
}
2020-05-04 22:21:35 +02:00
sub cmd_rebuild_aliases {
my ( $ self , $ context ) = @ _ ;
$ self - > { database } - > rebuild_aliases_table ;
}
sub cmd_aka_link {
my ( $ self , $ context ) = @ _ ;
my ( $ id , $ alias , $ type ) = split /\s+/ , $ context - > { arguments } ;
$ type = $ self - > { database } - > { alias_type } - > { STRONG } if not defined $ type ;
2021-07-09 02:27:31 +02:00
if ( not $ id or not $ alias ) {
return "Usage: link <target id> <alias id> [type]" ;
}
2020-05-04 22:21:35 +02:00
my $ source = $ self - > { database } - > find_most_recent_hostmask ( $ id ) ;
my $ target = $ self - > { database } - > find_most_recent_hostmask ( $ alias ) ;
2021-07-09 02:27:31 +02:00
if ( not $ source ) {
return "No such id $id found." ;
}
2020-05-04 22:21:35 +02:00
2021-07-09 02:27:31 +02:00
if ( not $ target ) {
return "No such id $alias found." ;
}
2020-05-04 22:21:35 +02:00
if ( $ self - > { database } - > link_alias ( $ id , $ alias , $ type ) ) {
return "/say $source " . ( $ type == $ self - > { database } - > { alias_type } - > { WEAK } ? "weakly" : "strongly" ) . " linked to $target." ;
} else {
return "Link failed." ;
}
}
sub cmd_aka_unlink {
my ( $ self , $ context ) = @ _ ;
my ( $ id , $ alias ) = split /\s+/ , $ context - > { arguments } ;
2021-07-09 02:27:31 +02:00
if ( not $ id or not $ alias ) {
return "Usage: unlink <target id> <alias id>" ;
}
2020-05-04 22:21:35 +02:00
my $ source = $ self - > { database } - > find_most_recent_hostmask ( $ id ) ;
my $ target = $ self - > { database } - > find_most_recent_hostmask ( $ alias ) ;
2021-07-09 02:27:31 +02:00
if ( not $ source ) {
return "No such id $id found." ;
}
2020-05-04 22:21:35 +02:00
2021-07-09 02:27:31 +02:00
if ( not $ target ) {
return "No such id $alias found." ;
}
2020-05-04 22:21:35 +02:00
2021-07-09 02:27:31 +02:00
if ( $ self - > { database } - > unlink_alias ( $ id , $ alias ) ) {
return "/say $source unlinked from $target." ;
} else {
return "Unlink failed." ;
}
2020-05-04 22:21:35 +02:00
}
sub get_message_account {
my ( $ self , $ nick , $ user , $ host ) = @ _ ;
return $ self - > { database } - > get_message_account ( $ nick , $ user , $ host ) ;
}
sub add_message {
my ( $ self , $ account , $ mask , $ channel , $ text , $ mode ) = @ _ ;
2021-07-09 02:27:31 +02:00
$ self - > { database } - > add_message ( $ account , $ mask , $ channel , { timestamp = > scalar time , msg = > $ text , mode = > $ mode } ) ;
2020-05-04 22:21:35 +02:00
}
2014-05-13 12:15:52 +02:00
1 ;