From ff6119f99a9a4c804936a8e07f69a2d94795a77a Mon Sep 17 00:00:00 2001 From: Joseph Graham Date: Sat, 3 Jun 2017 18:48:12 +0100 Subject: Disabled ability to tell pbot to tell someone else a factoid. Someone started abusing it to spam the channel and other users on FreeNode. The feature could be secured but since nobody normally uses it anyway I think it's not worth it. Also tidied up to code a bit and got rid of some old files. --- HACKING | 8 +- INSTALL | 2 +- bug_tracker_change_detector | 94 ---------- chili_change_detector | 224 ---------------------- hack_of_all_hacks | 437 ------------------------------------------ lib/main.sh | 35 ++-- process_event | 449 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 465 insertions(+), 784 deletions(-) delete mode 100755 bug_tracker_change_detector delete mode 100755 chili_change_detector delete mode 100644 hack_of_all_hacks create mode 100644 process_event diff --git a/HACKING b/HACKING index 4661c33..a785b21 100644 --- a/HACKING +++ b/HACKING @@ -1,13 +1,13 @@ -Hi, this file was made by xyon. +Hi, this file was made by Xylon. Basically I made this bot by getting envbot and hacking it. When I first ran envbot it didn't do anything and I couldn't be bothered to read the documentation of how to use/add modules so i just opened up the main file and started hacking it up. -I modified lib/main.sh to source `hack_of_all_hacks' file once per minute and -I put all the code in `l33t_codes' function in that file. So you can modify/add -more code without having to restart the bot. +I modified lib/main.sh to source `process_event' file once per minute +and I put all the code in a function in that file. So you can +modify/add more code without having to restart the bot. Originally the bot was kind of; event driven, it could only respond to stuff that happens in the channel but couldn't say stuff `out of the blue', so in diff --git a/INSTALL b/INSTALL index ee423e5..f1ddf86 100644 --- a/INSTALL +++ b/INSTALL @@ -21,7 +21,7 @@ Copy over all necessary files. bot_settings.sh common_codez envbot - hack_of_all_hacks + process_event labs_change_detector pbot pbot-ng_fixer diff --git a/bug_tracker_change_detector b/bug_tracker_change_detector deleted file mode 100755 index e4de7ba..0000000 --- a/bug_tracker_change_detector +++ /dev/null @@ -1,94 +0,0 @@ -#! /bin/bash - -while true -do - source common_codez - - log_file=bug_sums - - temp_file=$( mktemp ) - - temp_changes=$( mktemp ) - - changes="/tmp/un-provoked-message-store" - - for url in $( curl --compressed "https://bugs.parabolagnulinux.org/bugs/issue?@pagesize=99999" 2> /dev/null | grep -E 'href="issue[[:digit:]]+' | cut -d '"' -f 2 ) - do - tfile="$( mktemp )" - - try_count=1 - - # Get the URL and make sure it's not empty. - until curl --compressed "https://bugs.parabolagnulinux.org/bugs/${url}" > "${tfile}" 2> /dev/null && (( $( wc -l "${tfile}" 2> /dev/null | cut -d ' ' -f 1 ) )) - do - # The time we sleep doubles each time up to a maximum of 512 - # seconds, before restarting the entire script. - sleep "${try_count}" - - if (( try_count < 512 )) - then - try_count=$(( try_count * 2 )) - else - continue 2 - fi - done - - echo "${url} $( md5sum < ${tfile} | cut -d ' ' -f 1 )" >> "${temp_file}" - - rm "${tfile}" - done - - # Check that the log file is not empty as a sanity check. TODO record WHEN - # it last checked the bug tracker for changes so we can also check if it was - # too long ago. - if (( $( wc -l "${log_file}" 2> /dev/null | cut -d ' ' -f 1 ) )) - then - cat "${temp_file}" | - while read -r line - do - bug_number="${line%% *}" - # If this bug is not in the log file then it must be new. - if { ! grep "${bug_number}" "${log_file}" > /dev/null ; } - then - tdir="$( mktemp -d )" - curl --compressed "https://bugs.parabolagnulinux.org/bugs/${bug_number}" 2> /dev/null | csplit -f "${tdir}/xx" - '%%1' - bug_title=$( head -1 ${tdir}/xx* | replace_wierd_html_chars ) - cat ${tdir}/xx* | csplit -f "${tdir}/gg" - '%<th class="required">Priority</th>%1' - priority=$( head -1 ${tdir}/gg* ) - priority=${priority#*>} - priority=${priority%<*} - rm -r "${tdir}" - echo "${bug_number} created: https://bugs.parabolagnulinux.org/bugs/${bug_number} (${bug_title% - Parabola\'s issue tracker} [${priority}])" >> "${temp_changes}" - # It is in the log file so now we check if the entire line is there, - # because if it's not then the md5sum must have changed. - elif { ! grep "${line}" "${log_file}" > /dev/null ; } - then - tdir="$( mktemp -d )" - curl --compressed "https://bugs.parabolagnulinux.org/bugs/${bug_number}" 2> /dev/null | csplit -f "${tdir}/xx" - '%<title>%1' - bug_title=$( head -1 ${tdir}/xx* | replace_wierd_html_chars ) - cat ${tdir}/xx* | csplit -f "${tdir}/gg" - '%<th class="required">Priority</th>%1' - priority=$( head -1 ${tdir}/gg* ) - priority=${priority#*>} - priority=${priority%<*} - rm -r "${tdir}" - echo "${bug_number} changed: https://bugs.parabolagnulinux.org/bugs/${bug_number} (${bug_title% - Parabola\'s issue tracker} [${priority}])" >> "${temp_changes}" - fi - done - fi - - if (( $( wc -l "${temp_changes}" 2> /dev/null | cut -d ' ' -f 1 ) > 12 )) - then - echo "More than 12 changes have been detected on the bug tracker. Ignoring." >> "${changes}" - else - while read line - do - echo "${line}" >> "${changes}" - done < "${temp_changes}" - fi - - mv "${temp_file}" "${log_file}" - - rm -f "${temp_changes}" - - sleep 5m -done diff --git a/chili_change_detector b/chili_change_detector deleted file mode 100755 index 030f6f2..0000000 --- a/chili_change_detector +++ /dev/null @@ -1,224 +0,0 @@ -#! /bin/bash - -check_every="37s" # Put `m' or `s' on the end because this will be used with the - # `sleep' command. -seen_issues_log="seen_issues_log" -atom_feed_log="atom_feed_log" -atom_url="https://labs.parabola.nu/activity.atom" -bot_ipc="/tmp/un-provoked-message-store" -# fauno wants him to deliver messages spaced out by two minutes so I need nother -# fifo -another_fifo="/tmp/pbot-ng_chili_change_detector_fifo" - -# If the fifo doesn't exist then create it. -[[ -p ${another_fifo} ]] || mkfifo "${another_fifo}" - -# OK this code will forward no more than two messages onto pbot-ng every two -# minutes (fauno doesn't want flood). It runs in the background. It could be -# sensible to split this out into a seperate file so it can tidily be used by -# other pbot-ng modules but I cba. This code is quite l33t actually because it -# doesn't delay the messages at all unless two messages get delivered in two -# minutes. -tail -f "${another_fifo}" | while true -do - read smile && echo "${smile}" >> "${bot_ipc}" - read -t 120 smile && echo "${smile}" >> "${bot_ipc}" || - continue - sleep 2m -done & - -declare -A bugs -declare -A old_bugs - -function get_feed_make_array -{ - # Download the feed. - feed=$( mktemp ) - header_dump=$( mktemp ) - - if [[ -n ${etag} ]] - then - curl --user-agent "pbot-ng" -D "${header_dump}" -H "If-None-Match: \"${etag}\"" "${atom_url}" 2> /dev/null > "${feed}" - ret_val="${?}" - else - curl --user-agent "pbot-ng" -D "${header_dump}" "${atom_url}" 2> /dev/null > "${feed}" - ret_val="${?}" - fi - - # Get the first line of the headers. - read http_response < "${header_dump}" - - # If curl's exit status was zero and the http response was 200. - if (( ! ret_val )) && [[ ${http_response} == *' 200 '* ]] - then - # Is there an ETag? - if etag_line=$( grep 'ETag:' "${header_dump}" ) - then - etag_line="${etag_line#*\"}" - etag="${etag_line%\"*}" # Now we have the ETag. - else - # It seems that the server no longer sends Etags - unset etag - fi - else - # This indicates either a failure to download the page or that the page - # has not changed since the last time it was downloaded. - rm "${feed}" - rm "${header_dump}" - return 1 - fi - - unset bugs - declare -A -g bugs - - # We want an array of all the bug titles and their urls. - stage=0 - while read -r line - do - case "${stage}" in - 0 ) - [[ ${line} == *'<entry>'* ]] && - { - title="" - url="" - updated="" - stage=1 - } - - ;; - 1 ) - case "${line}" in - *'<title>'*''* ) - booboo="${line#*>}" - title="${booboo%<*}" - ;; - *''*''* ) - foobar="${line#*>}" - updated="${foobar%<*}" - ;; - *''* ) - # We don't want revisions. - if [[ -n ${title} ]] && [[ -n ${url} ]] && [[ -n ${updated} ]] && [[ "${title}" != *' - Revision '* ]] - then - # Add this to the array, fixing the url if it's - # broken. - bugs["${title}🐵${updated}"]="${url/chili/labs.parabola.nu}" - fi - stage=0 - ;; - esac - ;; - esac - done < "${feed}" - - rm "${feed}" - rm "${header_dump}" - - return 0 -} - -function slide_and_write -{ - # We need to make the new array the old one. - unset old_bugs - declare -A -g old_bugs - - for key in "${!bugs[@]}" - do - ii=$( sed 's/([^)]\+)//' <<< "${key}" ) - old_bugs[${ii}]=${bugs[${key}]} - done - - # We now write this to the file. We seperate the fields with some sort of - # cat face: 🐱 - for i in "${!old_bugs[@]}" - do - echo "${i}🐱 ${old_bugs[${i}]}" - done > ${atom_feed_log} -} - -if [[ -f ${atom_feed_log} ]] -then - # Get the array that stores the info of all bug titles and their urls out of - # the file it's stored in. - while read -r line - do - old_bugs["${line%%🐱 *}"]="${line##*🐱 }" - done < "${atom_feed_log}" -else - # The log does not exist so we create it! - get_feed_make_array - slide_and_write - - # Also we need to create the log of seen issues. - for i in "${!bugs[@]}" - do - ii=$( sed 's/([^)]\+)//' <<< "${i}" ) - [[ "${ii%%🐵*}" =~ \#[[:digit:]]+ ]] # match the bug number e.g. #390 - echo "${BASH_REMATCH}" - done > "${seen_issues_log}" -fi - -while true -do - # Download the feed and make an array of the bugs in it. If it fails or - # hasn't changed then we just wait until it's time to check again and then - # continue with the next iteration of the loop. - get_feed_make_array || { sleep "${check_every}" ; continue ; } - - temp_changes=$( mktemp ) - - # Compare this array to the previous. If any new have appeared since last - # time then we check if it's in a log of seen issues, and if not, we add it, - # and we know that this is a creation, not a change. - for i in "${!bugs[@]}" - do - ii=$( sed 's/([^)]\+)//' <<< "${i}" ) - # If this bug is new since last time. - if [[ -z ${old_bugs[${ii}]} ]] - then - # Check the log of seen issues to find out if this is a creation or - # a change. - [[ "${ii%%🐵*}" =~ \#[[:digit:]]+ ]] # match the bug number e.g. #390 - - if grep "${BASH_REMATCH}" "${seen_issues_log}" > /dev/null 2> /dev/null - then - creation_or_change="changed" - else - creation_or_change="created" - - # Add this issue to the log. - echo "${BASH_REMATCH}" >> "${seen_issues_log}" - fi - - real_title="${i%%🐵*}" - real_title_a="${real_title%%:*}" - real_title_b="${real_title#*:}" - cat="${real_title_a%% - *}" # e.g. `pbot-ng' - num="${real_title_a#* - }" - echo "${num} ${creation_or_change}: ( ${cat} -${real_title_b} ) ${bugs[${i}]}" >> "${temp_changes}" - fi - done - - if (( $( wc -l "${temp_changes}" 2> /dev/null | cut -d ' ' -f 1 ) > 12 )) - then - echo "More than 12 changes have been detected on the bug tracker. Ignoring." >> "${bot_ipc}" - else - while read line - do - echo "${line}" >> "${another_fifo}" - done < "${temp_changes}" - fi - - rm -f "${temp_changes}" - - # Make this array the old one and write it to the file in case we need to - # retrieve it later. - slide_and_write - - sleep "${check_every}" -done diff --git a/hack_of_all_hacks b/hack_of_all_hacks deleted file mode 100644 index 547b64c..0000000 --- a/hack_of_all_hacks +++ /dev/null @@ -1,437 +0,0 @@ -#! /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 l33t_codes -{ - my_own_name='pbot' - - 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 bug 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: http://labs.parabola.nu" - 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: - # pbot: tell fauno: you suck - 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 - # pbot 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 # - ############ - - "${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 - ;; - ','+([!/]) ) - thing="${sentence#,}" - - 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 -,tell jack about foo -EOF - ;; - esac - -# ' this comment fixes a bug in emacs shell-script-mode that messes up the syntax highlighting - - ########################### - # answer nicks over query # - ########################### - - if [[ "${line}" =~ ,tell\ [^\ ]+\ about\ [^\ ]+ ]] - then - 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 -} diff --git a/lib/main.sh b/lib/main.sh index 4fc1adf..7bb7041 100644 --- a/lib/main.sh +++ b/lib/main.sh @@ -440,32 +440,19 @@ while true; do # Check if there is a command. commands_call_command "$sender" "$target" "$query" -################################################################################ -################################################################################ + # What happens next is important + config_update_time=-100 -# Hack of all hacks!!! + time_n0w=$( date +%s ) -# if [[ "${identified}" != yep ]] -# then -# send_msg "NickServ" "identify csukwHrqH9" -# identified=yep -# fi - -config_update_time=-100 - -time_n0w=$( date +%s ) - -# If it's been more than a minute since we updated the config. -if (( ( time_n0w - 60 ) > config_update_time )) -then - source hack_of_all_hacks - config_update_time=${time_n0w} -fi - -l33t_codes + # If it's been more than a minute since we updated the config. + if (( ( time_n0w - 60 ) > config_update_time )) + then + source process_event + config_update_time=${time_n0w} + fi -################################################################################ -################################################################################ + process_event # Check return code case $? in @@ -567,7 +554,7 @@ l33t_codes if (( yepyep )) then - if (( $(wc -l hack_of_all_hacks | cut -d ' ' -f 1) > 1 )) + if (( $(wc -l "announcements/people/${personoslashlower}/messages" | cut -d ' ' -f 1) > 1 )) then send_msg "${channel}" "${personoslash}: you have messages, type something to see them." else diff --git a/process_event b/process_event new file mode 100644 index 0000000..7d93ed5 --- /dev/null +++ b/process_event @@ -0,0 +1,449 @@ +#! /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='pbot' + + 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 bug 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: http://labs.parabola.nu" + 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: + # pbot: tell fauno: you suck + 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 + # pbot 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 # + ############ + + "${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 + ;; + ','+([!/]) ) + thing="${sentence#,}" + + 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 #parabola channel, not by query. + # # 2. pbot 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 +} -- cgit v1.2.3