diff --git a/irc/irc.sh b/irc/irc.sh new file mode 100644 index 0000000..3381ffc --- /dev/null +++ b/irc/irc.sh @@ -0,0 +1,139 @@ +#!/bin/sh + +# irc; Deven Blake 2022; Public domain +# I stopped understanding this at 81 lines. + +alias cat='cat -u' +alias sed='sed -u' + +# defaults +DEFAULT_HOST="example.com" +PORT=6667 +[ -n "$IRC_QUIT_MESSAGE" ] \ + || IRC_QUIT_MESSAGE="Bye bye!" + +# defaults (standard-defined) +URI_FRAGMENT_DELIMITER='#' # RFC 3986 + +argv0="$0" +URL="$1" + +usage(){ + printf "Usage: %s [url]\n" "$argv0" + exit 1 +} + +one_character_per_line(){ + sed 's/./&\n/g' +} + +host_ex_url(){ + # filter out scheme URI subcomponent + # filter out userinfo URI subcomponent + # filter out port + # filter out heirarchy path + # filter out query + # filter out fragment + printf "%s\n" "$URL" \ + | sed 's/.*:\/\///' \ + | sed 's/.*@//' \ + | sed 's/:.*$//' \ + | sed 's/\/.*$//' \ + | sed 's/\?.*$//' \ + | sed 's/#.*$//' +} + +port_ex_url(){ + # filter out scheme URI subcomponent + # filter out userinfo URI subcomponent + local_url="$(printf "%s\n" "$URL" \ + | sed 's/.*:\/\///' \ + | sed 's/.*@//')" + + # check to ensure there Is a port in the URL + # this will also catch if we fucked up + if ! [ "$(printf "%s\n" "$local_url" \ + | one_character_per_line \ + | grep ':' \ + | wc -l)" \ + = 1 ] + then + # give up, gracefully + printf "%s\n" "$PORT" + return 0 + fi + + # filter out query URI subcomponent + # filter out heirarchy path + # filter out everything preceding the port + local_url="$(printf "%s\n" "$local_url" \ + | sed 's/\?.*$//' \ + | sed 's/\/.*$//' \ + | sed 's/.*://')" + + printf "%s\n" "$local_url" +} + +username_ex_url(){ + # only go if there's actually userinfo in the URL + # filter out scheme URI subcomponent + # filter out everything after userinfo URI subcomponent + # filter out password in userinfo, if present + printf "%s\n" "$URL" \ + | grep '@' \ + | sed 's/.*:\/\///' \ + | sed 's/@.*$//' \ + | sed 's/:.*$//' +} + +[ -n "$URL" ] \ + || usage + +[ -n "$IRC_NICK" ] \ + || IRC_NICK="$USER" + +# check if URL matches /^irc:\/\// +if ! printf "%s\n" "$URL" | grep "^irc://" >/dev/null 2>&1; then + printf "%s: %s: URL incorrectly formatted or scheme not specified.\n" "$argv0" "$URL" + exit 1 +fi + +# easy; the fragment is the last part of the URI +CHANNEL="#$(printf "%s\n" "$URL" \ + | sed 's/.*#//' )" + +# not easy +PORT="$(port_ex_url)" + +# slow, so don't rerun +a="$(username_ex_url)" +[ -z "$a" ] \ + || IRC_NICK="$a" + +HOST="$(host_ex_url)" + +[ -n "$HOST" ] \ + || HOST="$DEFAULT_HOST" + +if ! TEMP="$(mktemp)" || ! TEMP_FIN="$(mktemp)"; then + printf "%s: mktemp: Could not make temporary file.\n" "$argv0" + exit 1 +fi + +# RFC 1459 section 4.1.2 +printf "NICK %s\n" "$IRC_NICK" >"$TEMP" + +# RFC 1459 section 4.1.3; USER +# not really important +printf "USER %s 0 0 :\n" "$IRC_NICK" >>"$TEMP" + +# RFC 1459 section 4.2.1 +printf "JOIN %s\n" "$CHANNEL" >>"$TEMP" + +# RFC 1459 section 4.1.6 +printf "QUIT :%s\n" "$IRC_QUIT_MESSAGE" >"$TEMP_FIN" + +# RFC 1459 section 4.4.1 +sed "s/^/PRIVMSG $CHANNEL :/g" \ + | cat "$TEMP" /dev/stdin "$TEMP_FIN" \ + | nc "$HOST" "$PORT"