From 8e6bcdb0e54e142841f9454f0eaf3f03d003b45b Mon Sep 17 00:00:00 2001 From: Nick Chambers Date: Tue, 15 Jun 2021 01:33:30 -0500 Subject: [PATCH] Implement the IRC protocol --- rowbot | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 169 insertions(+), 1 deletion(-) diff --git a/rowbot b/rowbot index b835afb..ea7b7bd 100755 --- a/rowbot +++ b/rowbot @@ -88,13 +88,18 @@ else log=1 fi +nick=${opts[nick]:-rowbot-dev} +ident=${opts[ident]:-rowbot} +realname=${opts[realname]:-rowbot} +chan=${opts[chan]:-} + ### # net code ### if [[ $tls = yes ]]; then coproc sock { socat OPENSSL:"$server":"$port" -; } - in_sock=${sock[0]} out_sock=${sock[1]} + exec {in_sock}<&"${sock[0]}" {out_sock}>&"${sock[1]}" else exec {sock}<>/dev/tcp/"$server"/"$port" in_sock=$sock out_sock=$sock @@ -104,18 +109,177 @@ send() { local fmt printf -v fmt "$1" "${@:2}" printf '%s\r\n' "$fmt" >&"$out_sock" + debug "sending line: %s" "$fmt" } recv() { declare -n sock_line=$1 IFS= read -r "$1" <&"$in_sock" sock_line=${sock_line%$'\r'} + debug "received line: %s" "$sock_line" +} + +### +# irc recv code +### + +on_ERROR() { + error "${params[0]}" + exit +} + +on_MODE() { + if (( ${#params[@]} == 2 )); then + info "%s sets mode(s) %s on %s" "$from" "${params[1]}" "${params[0]}" + else + warn "mode line was not handled: %s" "$orig_line" + fi +} + +on_NOTICE() { + info "[%s/%s] %s" "$from" "${params[0]}" "${params[1]}" +} + +on_PING() { + pong "${params[1]}" + debug "received ping: %s" "${params[0]}" +} + +on_PONG() { + debug "received pong: %s" "${params[1]}" +} + +on_QUIT() { + info "%s has disconnected: %s" "$from" "${params[0]}" +} + +on_001() { + info %s "${params[1]}" + + if [[ $chan ]]; then + join "$chan" + fi + + while true; do + ping "row your bot gently down the stream" + sleep 10 + done & + + trap "kill $!" EXIT +} + +on_002() { + info %s "${params[1]}" +} + +on_003() { + info %s "${params[1]}" +} + +on_004() { + debug "%s " "${params[@]:1}" +} + +declare -A isupport + +on_005() { + local param key value + + for param in "${params[@]:1:${#params[@]}-2}"; do + IFS== read -r key value <<< "$param" + isupport[$key]=$value + debug "isupport: %s = %s" "$key" "$value" + done +} + +on_250() { + info %s "${params[1]}" +} + +on_251() { + info %s "${params[1]}" +} + +on_252() { + info "There are %d operators online" "${params[1]}" +} + +on_253() { + info "There are %d unknown connections" "${params[1]}" +} + +on_254() { + info "There are %d channels formed" "${params[1]}" +} + +on_255() { + info %s "${params[1]}" +} + +on_265() { + info %s "${params[3]}" +} + +on_266() { + info %s "${params[3]}" +} + +on_372() { + info %s "${params[1]}" +} + +on_375() { + debug %s "${params[1]}" +} + +on_376() { + debug %s "${params[1]}" +} + +### +# irc send code +### + +join() { + send "JOIN %s" "$1" +} + +nick() { + send "NICK %s" "$1" + info "changing nickname to %s" "$1" +} + +ping() { + send "PING :%s" "$1" +} + +pong() { + send "PONG %s" "$1" +} + +privmsg() { + send "PRIVMSG %s :%s" "$1" "$2" +} + +user() { + send "USER %s * * :%s" "$ident" "$realname" +} + +### +# utility hooks +## + +hook_JOIN_greet() { + privmsg "${params[0]}" "Hello, $from!" } ### # driver ### +nick "$nick" +user "$ident" "$realname" + while recv line; do params=( ) has_words=no @@ -150,6 +314,10 @@ while recv line; do words=( ) fi + while IFS= read -r hook; do + "$hook" + done < <(compgen -A function "hook_${cmd^^}_") + if hash "on_${cmd^^}" 2>/dev/null; then "on_${cmd^^}" else