Initial commit. - annna - Annna the nice friendly bot. HTML git clone git://bitreich.org/annna/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/annna/ DIR Log DIR Files DIR Refs DIR Tags DIR README --- DIR commit a63f21cd1ad027bdff057acf9ee6d44273f778fa HTML Author: Annna Robert-Houdin <annna@bitreich.org> Date: Sun, 4 Feb 2018 12:53:46 +0000 Initial commit. Diffstat: A BUGS.md | 13 +++++++++++++ A annna-alive | 11 +++++++++++ A annna-checker | 21 +++++++++++++++++++++ A annna-checker-dbg | 25 +++++++++++++++++++++++++ A annna-say | 49 +++++++++++++++++++++++++++++++ A annna-shutdown | 10 ++++++++++ A annna-start | 60 +++++++++++++++++++++++++++++++ A annna-start-services | 166 +++++++++++++++++++++++++++++++ A annna-stop | 6 ++++++ A annna-stop-checker | 6 ++++++ A annna-stop-services | 4 ++++ A phlog-index | 136 +++++++++++++++++++++++++++++++ 12 files changed, 507 insertions(+), 0 deletions(-) --- DIR diff --git a/BUGS.md b/BUGS.md @@ -0,0 +1,13 @@ +# BUGS + +* annna is disconnecting now and then from IRC + * scaleway issue? + * socat? + * ii? +* listening for commands on channels does not properly work + * better event handling? + * see $HOME/bin/initimate-annna.sh for the handlers + * enter-annnas-world.sh is starting the script +* access rights to channels are o+rw + * add a group for annna users + DIR diff --git a/annna-alive b/annna-alive @@ -0,0 +1,11 @@ +#!/bin/sh +# +# Check if annna is alive. +# Use it this way: +# +# if annna-alive; then do-something; fi +# + +[ -z "$(pgrep -U annna -x socat)" ] && exit 1 +exit 0 + DIR diff --git a/annna-checker b/annna-checker @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Watch for annna, she's worth it. +# + +export PATH="$PATH:/home/annna/bin" + +while /bin/true; +do + # Is annna still in her world? + pid="$(pgrep -U annna -x socat)" + + if [ -z "$pid" ]; + then + annna-stop-services >/dev/null 2>&1 + annna-start >/dev/null 2>&1 + fi + + sleep 5 +done + DIR diff --git a/annna-checker-dbg b/annna-checker-dbg @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Watch for annna, she's worth it. +# + +export PATH="$PATH:/home/annna/bin" + +logfile="/home/annna/output.log" + +while /bin/true; +do + # Is annna still in her world? + pid="$(pgrep -U annna -x socat)" + + if [ -z "$pid" ]; + then + annna-stop-services >/dev/null 2>&1 + annna-start 2>&1 \ + | grep -v -e ' PRIVMSG ' -e ' JOIN ' -e ' PART ' \ + >> "$logfile" + fi + + sleep 5 +done + DIR diff --git a/annna-say b/annna-say @@ -0,0 +1,49 @@ +#!/bin/sh +# +# annna-say -c '#bitreich-en' Hello World! +# + +export PATH="$PATH:/home/annna/bin" + +usage() { + printf "usage: %s [-h] [-i ircbase] -c \"channel0 ... channel1 ...\" text\n" \ + "$(basename "$1")" >&2 + exit 1 +} + +channels="" +ircbase="/home/annna/irc/chat.freenode.net" + +while getopts "hb:c:" opt; +do + case $opt in + b) + ircbase="$OPTARG" + ;; + c) + channels="$OPTARG" + ;; + *) + usage $0 + ;; + esac +done +shift $(expr $OPTIND - 1) + +[ -z "$channels" ] && usage $0 + +# If annna is not alive, do not bother. +annna-alive || exit 0 + +for c in $channels; +do + ircpath="${ircbase}/$c" + + if [ -e "$ircpath/in" ]; + then + printf "%s\n" "$@" > "${ircpath}/in" + fi +done + +exit 0 + DIR diff --git a/annna-shutdown b/annna-shutdown @@ -0,0 +1,10 @@ +#!/bin/sh +# +# Dare you to execute this script! You are cruel! +# + +export PATH="$PATH:/home/annna/bin" + +annna-stop +annna-stop-services + DIR diff --git a/annna-start b/annna-start @@ -0,0 +1,60 @@ +#!/bin/sh + +export PATH="$PATH:/home/annna/bin" + +# #bitreich is a forward to #bitreich-en. Annna does not need to join it. +#channels="#bitreich #bitreich-con #bitreich-radio +# #bitreich-scm #bitreich-en #bitreich-de" +channels="#bitreich-con #bitreich-radio + #bitreich-scm #bitreich-en #bitreich-de + #bitreich-fr #bitreich-cooking" + +rm -rf $HOME/irc +mkdir -p $HOME/irc +cd $HOME/irc +rm -f $HOME/freenode.sock + +# Connect +socat openssl:chat.freenode.net:6697,keepalive,keepcnt=5,keepidle=1,keepintvl=1 \ + unix-l:$HOME/freenode.sock & +while [ ! -e $HOME/freenode.sock ]; +do + sleep 0.5 +done + +ii -s chat.freenode.net -u $HOME/freenode.sock -n annna -f "Annna Robert-Houdin" & + +sleep 5 + +# Nickserv Auth +ircuser="$(grep user $HOME/irc-credentials.txt | cut -d' ' -f 2)" +ircpass="$(grep pass $HOME/irc-credentials.txt | cut -d' ' -f 2)" +printf "/privmsg nickserv :identify %s %s\n" "${ircuser}" "${ircpass}" \ + > chat.freenode.net/in +sleep 0.5 + +# Join Channels +for chan in ${channels}; +do + printf "/j %s\n" "${chan}" > chat.freenode.net/in + sleep 0.5 +done + +# Give permissions to certain channels. +chmod o+rx $HOME/irc +chmod o+rx $HOME/irc/chat.freenode.net +## EN Channel +chmod o+rx "$HOME/irc/chat.freenode.net/#bitreich-en" +chmod o+w "$HOME/irc/chat.freenode.net/#bitreich-en/in" +## SCM +chmod o+rx "$HOME/irc/chat.freenode.net/#bitreich-scm" +chmod o+w "$HOME/irc/chat.freenode.net/#bitreich-scm/in" +## Radio +chmod o+rx "$HOME/irc/chat.freenode.net/#bitreich-radio" +chmod o+w "$HOME/irc/chat.freenode.net/#bitreich-radio/in" + +# Allow commands. +sleep 6 + +annna-start-services + DIR diff --git a/annna-start-services b/annna-start-services @@ -0,0 +1,166 @@ +#!/bin/sh +# +# Here follow scriplets to listen for commands in annna. +# If this gets too unmaintainable, consider adding some directory structure. +# + +brmembers="__20h__ Evil_Bob chripo posativ quinq stateless solene josuah" + +botname="annna" +iibase="/home/annna/irc/chat.freenode.net" +function annna_say { + channel="$1" + shift 1 + + [ $# -lt 1 ] && exit 1 + + if [ -e "${iibase}/${channel}/in" ]; + then + printf "%s\n" "$@" > "${iibase}/${channel}/in" + # No spamming allowed. + sleep 0.5 + else + # Might be a user. + printf "/j %s %s\n" "$channel" "$@" > "${iibase}/in" + fi +} + +echo '12345 <unknown> a' > ${iibase}/#bitreich-radio/out +sleep 1 +# bitreich-radio +{ + #tail -f -n 1 "${iibase}/#bitreich-radio/out" \ + ls "${iibase}/#bitreich-radio/out" | entr tail -n 1 "${iibase}/#bitreich-radio/out" \ + | sed -u 's,[0-9]* <\([^ >]*\)> \(.*\)$,\1\n\2,' \ + | { + while read user; + do + read text + echo "$user" + echo "$text" + + + [ "$user" = "${botname}" ] && continue + + if [ "${text}" = "${botname}, next please" ]; + then + /br/bin/bitreich-radio-playlist-next + annna_say "#bitreich-radio" "You are very kind ${user}. To your command." + continue; + fi + + if [ "${text}" = "${botname}, please help" ]; + then + annna_say "${user}" "»next please« gets the playlist further, ${user}." + annna_say "${user}" "»please help« gives you this help listing, ${user}." + continue; + fi + done + } +} & + +echo '12345 <unknown> a' > ${iibase}/#bitreich-en/out +sleep 1 +# bitreich-en +{ + ls "${iibase}/#bitreich-en/out" | entr tail -n 1 "${iibase}/#bitreich-en/out" \ + | sed -u 's,[0-9]* <\([^ >]*\)> \(.*\)$,\1\n\2,' \ + | { + while read user; + do + read text + + ismember=0 + for member in $brmembers; + do + [ "$user" = "$member" ] && ismember=1 + done + [ $ismember -lt 1 ] && continue + [ "$user" = "${botname}" ] && continue + + if [ "${text}" = "${botname}, can you show me the uptime please?" ]; + then + annna_say "#bitreich-en" "$(hostname) uptime: $(uptime)" + continue; + fi + + if [ "${text}" = "${botname}, please give me the count of online users." ]; + then + annna_say "#bitreich-en" "$(hostname): $(who -q | tail -n 1 | cut -d'=' -f 2)" + continue; + fi + + if [ "${text}" = "${botname}, please roll a dice for me." ]; + then + annna_say "#bitreich-en" "$((($RANDOM % 6) + 1))" + continue; + fi + + if [ "${text}" = "${botname}, please tell me your favourite flower." ]; + then + annna_say "#bitreich-en" "My favourite flower is the beer flower." + continue; + fi + + if [ "${text}" = "${botname}, please tell me your favourite color." ]; + then + annna_say "#bitreich-en" "My favourite color is yellow." + continue; + fi + + if [ "${text}" = "${botname}, please dance with me." ]; + then + if [ $(($RANDOM % 2)) -gt 0 ]; + then + annna_say "#bitreich-en" "I am not that kind of woman." + else + annna_say "#bitreich-en" "Thank you! Let us dance! :-D" + fi + + continue; + fi + + if [ "${text}" = "${botname}, please tell me who is your favourite pleasure man." ]; + then + annna_say "#bitreich-en" "My favourite pleasure man is of course Gunther!" + continue; + fi + + if [ "${text}" = "${botname}, sudo make me a sandwich" ]; + then + annna_say "#bitreich-en" "Humans are no objects." + continue; + fi + + if [ "${text}" = "${botname}, sudo please make me a sandwich" ]; + then + annna_say "#bitreich-en" "Here is your sandwich." + continue; + fi + + if [ "${text}" = "${botname}, please update the phlog index." ]; + then + /home/annna/bin/phlog-index.sh > /dev/null 2>&1 + annna_say "#bitreich-en" "Thank you for your kind request. I have done so." + continue; + fi + + if [ "${text}" = "${botname}, please help" ]; + then + annna_say "${user}" "»can you show me the uptime please?« gets you the uptime, ${user}." + annna_say "${user}" "»please give me the count of online users.«, ${user}." + annna_say "${user}" "»please tell me your favourite flower.«, ${user}." + annna_say "${user}" "»please tell me your favourite color.«, ${user}." + annna_say "${user}" "»please dance with me.«, ${user}." + annna_say "${user}" "»please update the phlog index.«, ${user}." + annna_say "${user}" "»sudo make me a sandwich«, ${user}." + annna_say "${user}" "»sudo please make me a sandwich«, ${user}." + annna_say "${user}" "»please tell me who is your favourite pleasure man.«, ${user}." + annna_say "${user}" "»please roll a dice for me.«, ${user}." + annna_say "${user}" "»please help« gives you this help listing, ${user}." + continue; + fi + done + } +} & + DIR diff --git a/annna-stop b/annna-stop @@ -0,0 +1,6 @@ +#!/bin/sh + +export PATH="$PATH:/home/annna/bin" + +pkill -KILL -U annna -x socat + DIR diff --git a/annna-stop-checker b/annna-stop-checker @@ -0,0 +1,6 @@ +#!/bin/sh + +export PATH="$PATH:/home/annna/bin" + +pkill -KILL -U annna -f annna-checker + DIR diff --git a/annna-stop-services b/annna-stop-services @@ -0,0 +1,4 @@ +#!/bin/sh + +pkill -f "tail -f -n 1 /home/annna/irc.*" + DIR diff --git a/phlog-index b/phlog-index @@ -0,0 +1,136 @@ +#!/bin/sh + +export PATH="$PATH:/home/annna/bin" + +doforce=0 +if [ $# -gt 0 ]; +then + if [ "$1" = "-f" ]; + then + doforce=1 + fi +fi + +base="$HOME/phlogs" +cache="$base/cache" +gopherbase="/usr/%s/phlog/%s" +ircchans="#bitreich-en #bitreich-de #bitreich-fr" + +find /home/*/gopher/phlog \ + -name "*.md" \ + -printf "%f %T@ %u %p\n" > $cache/lsr.new + +cd $cache + +if [ -e lsr.old -a $doforce -eq 0 ]; +then + diff lsr.new lsr.old > lsr.diff +else + cp lsr.new lsr.diff +fi + +if [ $(stat --printf="%s" lsr.diff) -eq 0 ]; +then + exit 0 +fi + +# First create the links for all news. +cat lsr.new \ +| sort -r \ +| while read f; +do + IFS=' ' read -r fname unixt user fpath <<< $f + tstamp="$(sed -n 1p "$fpath" | cut -d' ' -f 2)" + [ -z "$tstamp" ] && continue + title="$(sed -n 3p "$fpath" | sed 's,\t, ,g')" + [ -z "$title" ] && continue + + gphpth="$(printf "$gopherbase" "$user" "$fname")" + printf "[0|%s – »%s« by %s|%s|server|port]\n" \ + "$tstamp" "$title" "$user" \ + "$gphpth" +done \ + > ../agg.gph + +# Create the atom feed. Only the first 64 news items. +cat lsr.new \ +| sort -r \ +| head -n 64 \ +| while read f; +do + IFS=' ' read -r fname unixt user fpath <<< $f + tstamp="$(sed -n 1p "$fpath" | cut -d' ' -f 2-)" + [ -z "$tstamp" ] && continue + title="$(sed -n 3p "$fpath" | sed 's,\t, ,g')" + [ -z "$title" ] && continue + + updated="$(date -d "${tstamp}" -u +%FT%T%z)" + gphpth="$(printf "$gopherbase" "$user" "$fname")" + furi="$(printf "gopher://bitreich.org/0%s" "$gphpth")" + printf "\t\t<entry>\n" + printf "\t\t<id>%s</id>\n" "$furi" + printf "\t\t<title><![CDATA[%s]]></title>\n" "$title" + printf "\t\t<link href=\"%s\" />\n" "$furi" + printf "\t\t<author><name>%s</name></author>\n" "$user" + printf "\t\t<content><![CDATA[" + cat $fpath | sed 's,$,<br/>,g' + printf "]]></content>\n" + printf "\t\t<updated>%s</updated>\n" "$updated" + printf "\t\t</entry>\n" +done \ + > ../agg.atom.xml + +# Talk to IRC about the news. +if [ $doforce -eq 0 ]; +then + cat lsr.diff \ + | sort \ + | while read f; + do + IFS=' ' read -r dire fname unixt user fpath <<< $f + [ -z "$fpath" ] && continue + [ -z "$user" ] && continue + [ -z "$unixt" ] && continue + [ -z "$fname" ] && continue + [ -z "$dire" ] && continue + + # If the post disappeared, don't tell IRC. + [ "$dire" = ">" ] && continue + + tstamp="$(sed -n 1p "$fpath" | cut -d' ' -f 2)" + [ -z "$tstamp" ] && continue + title="$(sed -n 3p "$fpath" | sed 's,\t, ,g')" + [ -z "$title" ] && continue + + gphpth="$(printf "$gopherbase" "$user" "$fname")" + annna-say -c "$ircchans" \ + "$(printf "%s – »%s« by %s gopher://bitreich.org/0%s" \ + "$tstamp" "$title" "$user" "$gphpth")" + done +fi + +cp lsr.new lsr.old + +# Now change the gph files in a really easy way. +{ + printf "/N_E_W_S/+1,/C_O_M_M/-4d\n" + printf "/N_E_W_S/r !cat /home/annna/phlogs/agg.gph | head -n 4\n" + printf "w\nq\n" +} | ed -s /br/gopher/index.gph + +{ + printf "/N_E_W_S/+1,\$-3d\n" + printf "/N_E_W_S/r !cat /home/annna/phlogs/agg.gph | head -n 256\n" + printf "w\nq\n" +} | ed -s /br/gopher/news.gph + +# Make the atom news file ready for consumption. +{ + printf "/updated/+1,/\\/feed/-1d\n" + printf "/updated/c\n" + printf "\t<updated>%s</updated>\n" "$(date -u +%F%T%z)" + printf ".\n" + printf "/updated/r !cat /home/annna/phlogs/agg.atom.xml\n" + printf "w\nq\n" +} | ed -s /br/gopher/news.atom.xml +