474 lines
16 KiB
Bash
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
|
|
}
|