diff --git a/rowbot b/rowbot index 380f4dc..7070850 100755 --- a/rowbot +++ b/rowbot @@ -1,5 +1,7 @@ #!/usr/bin/env bash +shopt -s nullglob dotglob extglob + ### # logger ### @@ -76,6 +78,10 @@ if [[ $tls = yes ]]; then exit 1 fi + if [[ -v opts[client-cert] ]]; then + client_cert=${opts[client-cert]} + fi + port=${opts[port]:-6697} else port=${opts[port]:-6667} @@ -130,6 +136,7 @@ trap cleanup EXIT ### if [[ $reload = yes ]]; then + debug "starting reload. pid is %d" "$$" in_sock=$IN_SOCK out_sock=$OUT_SOCK if [[ $tls = yes ]]; then @@ -143,12 +150,21 @@ if [[ $reload = yes ]]; then elif [[ $tls = yes ]]; then sock_dir=$(mktemp -d) mkfifo "$sock_dir"/rb{in,out} - socat OPENSSL:"$server":"$port" - <"$sock_dir"/rbin >"$sock_dir"/rbout & + + if [[ -v client_cert ]]; then + conn_args=OPENSSL:$server:$port,cert=$client_cert + else + conn_args=OPENSSL:$server:$port + fi + + socat "$conn_args" - <"$sock_dir"/rbin >"$sock_dir"/rbout & tls_pid=$! + debug "created tls connection (pid %d)" "$tls_pid" exec {out_sock}>"$sock_dir"/rbin {in_sock}<"$sock_dir"/rbout else exec {sock}<>/dev/tcp/"$server"/"$port" in_sock=$sock out_sock=$sock + debug "created plaintext connection" fi send() { @@ -181,15 +197,27 @@ on_JOIN() { 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" + elif (( ${#params[@]} > 2 )); then + info "%s: %s sets mode(s) %s" "${params[0]}" "$from" "${params[*]:1}" fi } +on_NICK() { + info "%s has changed their name to %s" "$from" "${params[0]}" +} + on_NOTICE() { info "[%s/%s] %s" "$from" "${params[0]}" "${params[1]}" } +on_PART() { + if (( ${#params[@]} > 1 )); then + info "%s has left %s: %s" "$from" "${params[0]}" "${params[1]}" + else + info "%s has left %s" "$from" "${params[0]}" + fi +} + on_PING() { pong "${params[1]}" debug "received ping: %s" "${params[0]}" @@ -322,7 +350,21 @@ join() { nick() { send "NICK %s" "$1" - info "changing nickname to %s" "$1" +} + +notice() { + send "NOTICE %s :%s" "$1" "$2" + info "[%s/%s] %s" "$nick" "$1" "$2" +} + +part() { + if (( $# )); then + if (( $# > 1 )); then + send "PART $1 :$2" + else + send "PART $1" + fi + fi } ping() { @@ -338,14 +380,68 @@ privmsg() { info "<%s/%s> %s" "$nick" "$1" "$2" } +quit() { + if (( $# )); then + send "QUIT :%s" "$1" + else + send QUIT + fi +} + user() { - send "USER %s * * :%s" "$ident" "$realname" + send "USER %s 0 * :%s" "$ident" "$realname" } ### # app hooks ## +hook_pre_PRIVMSG_CTCP() { + if [[ ${params[1]} != $'\x01'*$'\x01' ]]; then + return 0 + fi + + local cmd msg + cmd=${params[1]#$'\x01'} cmd=${cmd%% *} + msg=${params[1]#* } msg=${msg%$'\x01'} + + if [[ ${cmd^^} = ACTION ]]; then + if [[ ${params[0]:0:1} = \# ]]; then + info "ctcp: %s: %s %s" "${params[0]}" "$from" "$msg" + else + info "privately, %s %s" "$from" "$msg" + fi + + return 1 + elif [[ ${params[0]:0:1} = \# ]]; then + info "ctcp: %s has requested %s in %s" "$from" "${cmd^^}" "${params[0]}" + return 1 + fi + + info "ctcp: sending %s to %s" "${cmd^^}" "$from" + + case ${cmd^^} in + CLIENTINFO) + notice "$from" $'\x01'"CLIENTINFO ACTION CLIENTINFO PING SOURCE TIME VERSION"$'\x01' + ;; + PING) + local msg + msg=${params[1]#* } msg=${msg%$'\x01'} + notice "$from" $'\x01'"PING $msg"$'\x01' + ;; + SOURCE) + notice "$from" $'\x01'"SOURCE https://ahti.space/git/uplime/rowbot"$'\x01' + ;; + TIME) + notice "$from" $'\x01'"TIME time for you to get a watch"$'\x01' + ;; + VERSION) + notice "$from" $'\x01'"VERSION rowbot v2"$'\x01' + esac + + return 1 +} + hook_post_PRIVMSG_factoids() { if [[ ${params[0]:0:1} != \# ]]; then return 0 @@ -414,9 +510,11 @@ hook_post_PRIVMSG_control_panel() { ;; join) join "${words[1]}" + privmsg "$to" "joined ${words[1]}" ;; reload) export IN_SOCK=$in_sock OUT_SOCK=$out_sock LOG_FD=$log + export RELOAD_TO=$to if [[ $tls = yes ]]; then export SOCK_DIR=$sock_dir @@ -430,6 +528,24 @@ hook_post_PRIVMSG_control_panel() { privmsg "$to" "reloading..." exec "${original_args[@]}" --reload ;; + level) + level=${words[1]} + privmsg "$to" "log level is now set to $level" + ;; + dev) + if [[ $dev = yes ]]; then + dev=no + privmsg "$to" "developer status disabled" + else + dev=yes + privmsg "$to" "developer status enabled" + fi + ;; + trigger) + if (( ${#words[@]} > 1 )); then + trigger=${words[1]} + privmsg "$to" "trigger is now $trigger" + fi esac fi } @@ -438,7 +554,9 @@ hook_post_PRIVMSG_control_panel() { # driver ### -if [[ $reload != yes ]]; then +if [[ $reload = yes ]]; then + privmsg "$RELOAD_TO" done. +else nick "$nick" user "$ident" "$realname" fi