hyperbot/process_event
2023-07-22 10:51:26 -05:00

474 lines
16 KiB
Bash

#! /bin/bash
# This function reads tags of xml in the same way read normally reads lines.
function rdom
{
local IFS=\>
read -d \< element content
}
function tell_fact # thing channel
{
thing="${1}"
declare -l lower_case_thing="${thing}"
channel="${2}"
if [[ -s "info/${lower_case_thing}" ]]
then
# For the first entry we will say like: `thing is: '
first="${thing} is: "
uniq "info/${lower_case_thing}" |
while read line
do
send_msg "${channel}" "${first}${line}"
first=''
done
return
else
return 1
fi
}
source common_codez
function remember_fact
{
if grep "^${is}$" "info/${thing}" &>/dev/null
then
send_msg "${channel_it_came_from}" "${personoslash}: I know."
else
echo "${is}" >> "info/${thing}"
send_msg "${channel_it_came_from}" "${personoslash}: Remembered."
fi
}
function forget_fact
{
number_of_matching_lines=$(grep -c "^${isnt}" "info/${thing}")
case "${number_of_matching_lines}" in
0 )
send_msg "${channel_it_came_from}" "${personoslash}: I know."
;;
1 )
grep -v "^${isnt}" "info/${thing}" | sponge "info/${thing}"
send_msg "${channel_it_came_from}" "${personoslash}: OK, entry removed."
;;
* )
send_msg "${channel_it_came_from}" "${personoslash}: Ambiguos."
;;
esac
}
function process_event
{
my_own_name='hyperbot'
person="${sender%%!*}"
# Remove any forward slashes.
personoslash="${person//\/}"
declare -l personoslashlower="${personoslash}"
channel_it_came_from="$( echo ${line} | cut -d ' ' -f 3 )"
# If it's a private message
[[ "${channel_it_came_from}" == "${my_own_name}" ]] && channel_it_came_from="${personoslash}"
######################
# Echo injected data #
######################
# Should send a message like: echo 'This is the message' > /tmp/un-provoked-message-store
injected_data=0
line_filtered=${line##*PRIVMSG +([![:space:]]) :}
if [[ ${personoslash} == tlCJ99mfZl ]]
then
send_msg "${channel_it_came_from}" "${line_filtered}"
injected_data=1
else
###############################################################
# This is a message from a user. Make preperations to process #
###############################################################
the_time_now=$(date +%s)
# Make this person a folder if they don't already have one.
if ! [[ -d "announcements/people/${personoslashlower}" ]]
then
mkdir -p "announcements/people/${personoslashlower}"
fi
# Record that the person has been seen, and when.
touch "announcements/people/${personoslashlower}/seen"
shopt -s extglob
# We want to get only the message part of the line
sentence="${line#* }"
sentence="${sentence#* }"
sentence="${sentence#* :}"
##########################
# Shared libraries error #
##########################
the_time_now=$(date +%s)
# If someone complains about error while loading shared libraries error
# then recomend them to the issue tracker.
if [[ ${sentence} == *"error while loading shared libraries"* ]]
then
# Make sure they have not already been recommended to the bug
# tracker less than one day ago.
sharlibsrecfile="announcements/people/${personoslashlower}/shared_libs"
# Have we recommended them to the bug tracker before?
if [[ -f ${sharlibsrecfile} ]]
then
# Was it less than a day ago?
(( ( $( stat -c %Y ${sharlibsrecfile} ) + 86400 ) > the_time_now )) && rec_recent=1 || rec_recent=0
else
rec_recent=0
fi
if ! (( rec_recent ))
then
send_msg "${channel_it_came_from}" "${person}: please report a bug, specifying the exact error message, package of the failing command and architecture: https://issues.hyperbola.info"
touch "${sharlibsrecfile}"
fi
fi
##########
# Repeat #
##########
[[ ${sentence} != ${i_repeated} ]] && say_again=yesyes
# If two different people say the same thing in a row then say it again
# for fun.
if [[ ${sentence} == ${lastline} ]] && [[ ${person} != ${lastsender} ]] && [[ ${say_again} != nono ]] && [[ ${sentence} != "${my_own_name}: "* ]] # If two different people say the same thing to me in quick sucession I shouldn't repeat them.
then
send_msg "${channel_it_came_from}" "${sentence}"
i_repeated="${sentence}"
say_again=nono
fi
lastline="${sentence}"
lastsender="${person}"
#################
# Announcements #
#################
# If someone has sent this person a message then echo it to
# them.
if [[ -f "announcements/people/${personoslashlower}/messages" ]]
then
uniq "announcements/people/${personoslashlower}/messages" |
while read line
do
# The first field is the time, in *nix seconds, that
# the message was sent. The second is the name of the
# sender. And the rest is the message.
intermediate="${line#* }"
sender_u="${intermediate%% *}"
message_u="${intermediate#* }"
time_sent="${line%% *}"
seconds_ago_seen="$(( the_time_now - time_sent ))"
minutes_ago_seen="$(( ( the_time_now - time_sent ) / 60 ))"
hours_ago_seen="$(( ( the_time_now - time_sent ) / 3600 ))"
days_ago_seen="$(( ( the_time_now - time_sent ) / 86400 ))"
months_ago_seen="$(( ( the_time_now - time_sent ) / 2592000 ))"
years_ago_seen="$(( ( the_time_now - time_sent ) / 31104000 ))"
if (( seconds_ago_seen < 120 ))
then
units="${seconds_ago_seen} seconds"
elif (( minutes_ago_seen < 120 ))
then
units="${minutes_ago_seen} minutes"
elif (( hours_ago_seen < 48 ))
then
units="${hours_ago_seen} hours"
elif (( days_ago_seen < 60 ))
then
units="${days_ago_seen} days"
elif (( months_ago_seen < 24 ))
then
units="${months_ago_seen} months"
else
units="${years_ago_seen} years"
fi
send_msg "${channel_it_came_from}" "${personoslash}: ${sender_u} told me to tell you, (${units} ago): ${message_u}"
done
rm "announcements/people/${personoslashlower}/messages"
fi
#####################
# Page title getter #
#####################
# We don't want to get the page title if it's injected data.
if [[ ${line} =~ http://[^\ ]+ ]] || [[ ${line} =~ https://[^\ ]+ ]] &&
(( ! injected_data ))
then
url_to_get="${BASH_REMATCH}"
the_title=$(
curl -L --compressed "${url_to_get}" 2> /dev/null |
while rdom
do
if [[ ${element} = title ]] || [[ ${element} = TITLE ]]
then
sed 's/ / /g' <<< "${content}" | replace_wierd_html_chars
fi
done
)
if ! [[ -z ${the_title} ]]
then
send_msg "${channel_it_came_from}" "Page title: \`${the_title}'"
fi
fi
case "${sentence}" in
########
# Seen #
########
"${my_own_name}: when did you last see"* )
subject="${sentence##${my_own_name}: when did you last see }"
subject="${subject##${my_own_name}: when did you last see: }" # If there's an `:', we can still handle it.
subject="${subject%\?}"
subject="${subject%% *}"
declare -l subjectlower="${subject}"
if [[ "${subject}" == ${my_own_name} ]]
then
send_msg "${channel_it_came_from}" "I last saw ${subject} speak 0 seconds ago."
elif [[ -f "announcements/people/${subjectlower}/seen" ]]
then
seconds_ago_seen="$(( the_time_now - $( stat -c %Y announcements/people/${subjectlower}/seen ) ))"
minutes_ago_seen="$(( ( the_time_now - $( stat -c %Y announcements/people/${subjectlower}/seen ) ) / 60 ))"
hours_ago_seen="$(( ( the_time_now - $( stat -c %Y announcements/people/${subjectlower}/seen ) ) / 3600 ))"
days_ago_seen="$(( ( the_time_now - $( stat -c %Y announcements/people/${subjectlower}/seen ) ) / 86400 ))"
months_ago_seen="$(( ( the_time_now - $( stat -c %Y announcements/people/${subjectlower}/seen ) ) / 2592000 ))"
years_ago_seen="$(( ( the_time_now - $( stat -c %Y announcements/people/${subjectlower}/seen ) ) / 31104000 ))"
if (( seconds_ago_seen < 120 ))
then
send_msg "${channel_it_came_from}" "I last saw ${subject} speak ${seconds_ago_seen} seconds ago."
elif (( minutes_ago_seen < 120 ))
then
send_msg "${channel_it_came_from}" "I last saw ${subject} speak ${minutes_ago_seen} minutes ago."
elif (( hours_ago_seen < 48 ))
then
send_msg "${channel_it_came_from}" "I last saw ${subject} speak ${hours_ago_seen} hours ago."
elif (( days_ago_seen < 60 ))
then
send_msg "${channel_it_came_from}" "I last saw ${subject} speak ${days_ago_seen} days ago."
elif (( months_ago_seen < 24 ))
then
send_msg "${channel_it_came_from}" "I last saw ${subject} speak ${months_ago_seen} months ago."
else
send_msg "${channel_it_came_from}" "I last saw ${subject} speak ${years_ago_seen} years ago."
fi
else
send_msg "${channel_it_came_from}" "I never saw ${subject} speak."
fi
;;
########
# tell #
########
"${my_own_name}: tell "+([![:space:]])":"+([[:space:]])+([![:space:]])* )
# The line will be something such as:
# hyperbot: tell user: hi
process="${sentence##${my_own_name}: tell }"
subject="${process%%:*}"
message="${process#*:}"
message="${message# }"
if [[ "${subject}" == "${my_own_name}" ]]
then
send_msg "${channel_it_came_from}" "${my_own_name}: ${personoslash} told me to tell you, (0 seconds ago): ${message}"
else
declare -l subjectlower="${subject}"
[[ -d "announcements/people/${subjectlower}" ]] || mkdir -p "announcements/people/${subjectlower}"
# The time in *nix seconds is saved there so that
# hyperbot can say how long ago the massage was sent
# when he gives it to it's recipient.
echo "$(date +%s) ${personoslash} ${message}" >> "announcements/people/${subjectlower}/messages"
response='certainly'
send_msg "${channel_it_came_from}" "${personoslash}: ${response}"
if ! [[ -f "announcements/people/${subjectlower}/seen" ]]
then
send_msg "${channel_it_came_from}" "${personoslash}: WARNING: I HAVE NEVER SEEN \"${subject}\" HERE BEFORE. CHECK YOUR SPELLING."
fi
fi
;;
############
# factoids #
############
# list factoids
',' | ',list' | ',factoids' | "${my_own_name}: list factoids" )
local factoids=( $(ls info/) )
local n_factoids=${#factoids[*]}
local begin_msg="ask me about:"
local end_msg="e.g. ${server_nick_current}: what is ${factoids[0]} (or ,${factoids[0]})"
send_msg "${personoslash}" "${begin_msg}"
for (( factoid_n = 0 ; factoid_n < n_factoids ; factoid_n = factoid_n + 10 ))
do send_msg "${personoslash}" " ${factoids[*]:${factoid_n}:10}"
sleep 1
done
send_msg "${personoslash}" "${end_msg}"
;;
# set factoid
"${my_own_name}: "+([!/])" is "+([![:space:]])* )
declare -l thing="${sentence#${my_own_name}: }"
thing="${thing%% is *}"
is="${sentence#* is }"
remember_fact
;;
"${my_own_name}: "+([!/])" is: "+([![:space:]])* )
declare -l thing="${sentence#${my_own_name}: }"
thing="${thing%% is: *}"
is="${sentence#* is: }"
remember_fact
;;
"${my_own_name}: "+([![:space:]])" isn't "+([![:space:]])* )
declare -l thing="${sentence#${my_own_name}: }"
thing="${thing%% isn\'t *}"
isnt="${sentence#* isn\'t }"
forget_fact
;;
"${my_own_name}: "+([![:space:]])" isn't: "+([![:space:]])* )
declare -l thing="${sentence#${my_own_name}: }"
thing="${thing%% isn\'t: *}"
isnt="${sentence#* isn\'t: }"
forget_fact
;;
# display factoid
','+([!/]) )
thing="${sentence#,}"
tell_fact "${thing}" "${channel_it_came_from}"
;;
"${my_own_name}: what is "+([![:space:]]) )
thing="${sentence#${my_own_name}: what is }"
tell_fact "${thing}" "${channel_it_came_from}"
;;
#############
# Footnotes #
#############
*\[[[:digit:]]\]* )
declare -a fn
while read -d $'\0' file
do
#if match = grep "${file##*/}[ ]\?\[[[:digit:]]\]" <<< "${sentence}"
filename="${file##*/}"
declare -l lowersentence="${sentence}"
if [[ " ${lowersentence}" =~ [^[:alnum:]]${filename}[\ ]?\[[[:digit:]]\] ]]
then
index="${BASH_REMATCH: -2:1}"
fn[${index}]=$(head -1 "${file}")
fi
done < <(find info -print0)
for (( n=0 ; n<50 ; n++ ))
do
str="${fn[${n}]}"
[[ -z "${str}" ]] && continue
send_msg "${channel_it_came_from}" "[${n}] ${str}"
done
;;
########################
# unrecognised command #
########################
${my_own_name}:* | ','* )
while read line
do
send_msg "${personoslash}" "${line}"
done <<< cat << EOF
Command not recognised. Example commands:
${my_own_name}: tell Jack: hi Jack
${my_own_name}: when did you last see Jill?
${my_own_name}: lemon is yummy
${my_own_name}: lemon isn't yummy
,lemon
EOF
;;
esac
# ' this comment fixes a bug in emacs shell-script-mode that messes up the syntax highlighting
# I'm dissabling this feature for now as it was being abused
# and would need an overhaul to be abuse-proof + nobody uses it afaik
# ##########################
# # tell someone something #
# ##########################
# # TODO: this should be in the case statement
# if [[ "${sentence}" =~ ${my_own_name}: tell\ [^\ ]+\ about\ [^\ ]+ ]]
# then
# # TODO: There should be the following three constraints to
# # prevent abuse.
# # 1. People may only ask the bot to tell someone about
# # something in the #hyperbola channel, not by query.
# # 2. hyperbot will only tell someone something if they're a user
# # he has seen in the past week
# # 3. each person may use tell no more than 10 times in
# # three hours.
# gotit="${BASH_REMATCH}" # will be like: `,tell jack about blah'
# dudep1="${gotit#,tell }"
# dude="${dudep1%% *}"
# thing="${gotit##* }"
# if [[ -n "${dude}" ]] && [[ -n "${thing}" ]]
# then
# tell_fact "${thing}" "${dude}" || send_msg "${channel_it_came_from}" "${personoslash}: Error, failed to tell ${dude} about ${thing}"
# fi
# fi
# TODO: add a birthday announcement feature, cointoss feature, timer
# feature.
#########
# Tests #
#########
#echo "${line}"
fi
}