#! /bin/bash readonly PROCESS_EVENT_SOURCED=1 # This function reads tags of xml in the same way read normally reads lines. function rdom { local IFS=\> read -r -d \< element content } function format_cgit_title { if [[ "${url_to_get}" =~ /git.parabola.nu/([^/]+\.git)/tree/ ]] then repo="${BASH_REMATCH[1]}" title=$(sed 's|\\.* - '${repo}'| - '${repo}'|' <<< ${title}) fi } function tell_fact # (thing , channel) { thing="${1}" declare -l lower_case_thing="${thing}" channel="${2}" if [[ -s "info/${lower_case_thing}" ]] then while read line do send_msg "${channel}" "${thing} is: ${line}" done < <(cat "info/${lower_case_thing}") return 0 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} == ${INJECT_NICK} ]] then send_msg "${channel_it_came_from}" "${line_filtered}" injected_data=1 fi # NOTE: this 'injected_data' clause is apparently the IPC mechanism # used by the ./labs_change_detector script # see ./labs_change_detector, transport/socat.sh, and transport/dev-tcp.sh # the clause above was originally mutually exclusive # with the remaining entirety of this function # and it is the only place where 'injected_data' is set # yet, 'injected_data' is tested below in the 'Page title getter' section # so, presumably this 'injected_data' was intended to fall through? ############################################################### # 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 # ########################## # 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 last_time=$( stat -c %Y ${sharlibsrecfile} ) (( last_time > the_time_now - 86400 )) && 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; # unless it was directed at me. if [[ ${sentence} == ${lastline} ]] && [[ ${person} != ${lastsender} ]] && \ [[ ${say_again} != nono ]] && [[ ${sentence} != "${my_own_name}: "* ]] 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" rm "announcements/people/${personoslashlower}/you_have_mail" 2> /dev/null || true fi ##################### # Page title getter # ##################### # We don't want to get the page title if it's injected data # nor if it probably came from a spambot 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 title="${content}" [[ "${url_to_get}" =~ /git.parabola.nu/ ]] && format_cgit_title sed 's/ / /g' <<< "${title}" | replace_wierd_html_chars fi done ) if ! [[ -z ${the_title} ]] then send_msg "${channel_it_came_from}" "Page title: '${the_title}'" fi fi ###################### # main chat triggers # ###################### case "${sentence}" in ######### # hello # ######### hello|hi) send_msg "${channel_it_came_from}" "hello ${person}, it works!!!" ;; ######## # 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 # ######## "${server_nick_current}: tell "+([![:space:]:])?(:)+([[:space:]])+([![:space:]])* ) # The line will be something such as: # pbot: tell fauno: you suck # pbot: tell xylon i have heard that lemons are yummy local query="${sentence}" local bot_nick=${server_nick_current} local receiver=$(expr match "$query" ${bot_nick}': tell \([^\ :]*\):\? ') local message=$( expr match "$query" ${bot_nick}': tell [^\ ]* \(.*\)' ) if [[ "${receiver}" == "${bot_nick}" ]] then send_msg "${channel_it_came_from}" "${bot_nick}: ${personoslash} told me to tell you, (0 seconds ago): ${message}" else declare -l receiver_lower=${receiver//\/} local receiver_dir="announcements/people/${receiver_lower}" [[ -d "${receiver_dir}" ]] || mkdir -p "${receiver_dir}" # 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}" >> "${receiver_dir}/messages" local response="Certainly! I will relay your message to ${receiver} the next time i see activity by that nick." send_msg "${channel_it_came_from}" "${personoslash}: ${response}" if ! [[ -f "${receiver_dir}/seen" ]] then send_msg "${channel_it_came_from}" "${personoslash}: WARNING: I HAVE NEVER SEEN \"${receiver}\" 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}" ;; # 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}" ;; # 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 ;; # delete factoid "${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 ;; ############# # 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}:* | ','* ) local module local modules_help='' local help_msg_line for module in ${config_modules} do case ${module} in 'translate' ) [[ "${sentence}" =~ ^"${my_own_name}: translate " ]] && return 0 modules_help="${modules_help} modules/m_translate.help.inc" ;; esac done while IFS='' read help_msg_line do help_msg_line=$(sed "s|_BOT_NICK_|${my_own_name}|" <<< ${help_msg_line}) send_msg "${personoslash}" "${help_msg_line}" ; sleep 1 ; done < <(cat process_event.help.inc ${modules_help}) ;; esac # TODO: add a birthday announcement feature, cointoss feature, timer feature. ######### # Tests # ######### #echo "${line}" }