#!/usr/bin/env bash # Bash Finger client using /dev/tcp (shell I/O, slower than direct socket calls) # Supports 8-bit characters, long files, ASCII art # License: Blue Oak Model License 1.0.0 # Copyright: https://640kb.neocities.org # 09 Jul 2026: Added finger://domain.com format support; improved trap handling # 24 Jun 2026: Help section, help flags, removed version numbers # 14 Nov 2025: Fixed help flags # 11 Oct 2025: 128k Transfer limit as default, minor other edits # 30 May 2025: Added Transfer limit (BFINGER_MAX_BYTES) & timeouts # 01 May 2025: Initial release # ------------------------------ Start Script ------------------------------- set -eo pipefail [ -n "${DEBUG:-}" ] && set -xu VERSION="09 Jul 2026" export LC_ALL=C cleanup() { exec 3<&- 3>&- 2>/dev/null || true exit 130 } trap cleanup INT TERM EXIT # Transfer limit: default is ~128KB. Adjust as needed. MAX_BYTES=${BFINGER_MAX_BYTES:-128000} if [ $# -eq 0 ] || [[ "$1" =~ ^(-h|--help)$ ]]; then echo "" echo " .-------------------------------------------------------------------------." echo " | bfinger - A Bash-based Finger Client ($VERSION) |" echo " | |" echo " | Uses Bash's /dev/tcp for socket connections to query remote Finger |" echo " | servers. Full support for 8-bit characters, long files and ASCII art. |" echo " | ----------------------------------------------------------------------- |" echo " | Usage: |" echo " | bfinger @domain.com # Queries host |" echo " | bfinger user@domain.com # Specific user |" echo " | bfinger finger://domain.com/user # URL format |" echo " | bfinger @localhost # when fingerd installed locally |" echo " | ----------------------------------------------------------------------- |" echo " | Options: |" echo " | -v, --version Show version info |" echo " | -h, --help Show this help message |" echo " | ----------------------------------------------------------------------- |" echo " | Examples: |" echo " | bfinger originsfinger@happynetbox.com | less |" echo " | bfinger @plan.cat | head -n 20 |" echo " | bfinger finger://happynetbox.com/originsfinger |" echo " | ----------------------------------------------------------------------- |" echo " | Compatibility: Linux, macOS, *BSD |" echo " '-------------------------------------------------------------------------'" echo "" exit 0 fi if [[ "${1:-}" == "--version" || "${1:-}" == "-v" ]]; then echo echo "bfinger - A Bash-based finger client ($VERSION)" echo exit 0 fi if [[ "$1" == finger://* ]]; then path="${1#finger://}" if [[ "$path" == */* ]]; then HOST="${path%%/*}" USER="${path#*/}" else HOST="$path" USER="" fi elif [[ "$1" == @* ]]; then USER="" HOST="${1#@}" elif [[ "$1" =~ @ ]]; then USER="${1%%@*}" HOST="${1##*@}" else echo "Error: Invalid format. Use user@domain.com, @domain.com, or finger://domain.com/user" >&2 exit 1 fi PORT=79 if [ -z "$HOST" ]; then echo "Error: No host specified" >&2 exit 1 fi if [[ ! "$HOST" =~ ^[a-zA-Z0-9._-]+$ ]]; then echo "Error: Hostname contains invalid characters" >&2 exit 1 fi if ! getent hosts "$HOST" >/dev/null; then echo "Error: Host '$HOST' could not be resolved" >&2 exit 1 fi if ! timeout 5 bash -c "exec 3<>/dev/tcp/$HOST/$PORT"; then echo "Error: Connection to $HOST:$PORT timed out or failed" >&2 echo "Tip: Try 'telnet $HOST $PORT' to debug" >&2 exit 1 fi exec 3<>/dev/tcp/"$HOST"/"$PORT" printf "%s\r\n" "$USER" >&3 bytes_read=0 while IFS= read -r -t 5 -N 1 char <&3 && (( bytes_read++ < MAX_BYTES )); do printf "%s" "$char" done (( bytes_read >= MAX_BYTES )) && echo >&2 (( bytes_read >= MAX_BYTES )) && echo "Output truncated after $MAX_BYTES bytes." >&2 exec 3<&- 3>&-