#!/bin/bash


usage() {
    local self      # our name
    self=$(basename "$0")
    echo "usage: $self [options] message" >&2
    echo "usage: $self [options] [-l max_lines] [-L max_width] -f message_file|-" >&2
    echo "options: [-h host] [-p port] [-n nick] [-c context] [-u user]" >&2
    exit 2
}

mkcommands() {
    local user="$1"     # target user
    local nick="$2"     # our nickname
    local message
    echo "NICK $nick"
    echo "USER $nick 8 * :notifirc bot"
    while read -r message;
    do
        echo "PRIVMSG $user :$message"
    done
    echo "QUIT"
}

mknick() {
    case "$context" in
        "") echo "$nick" ;;
        *)  echo "$nick|$context" ;;
    esac
}

die() {
    local msg="fatal: $1"       # message
    log "$msg"
    log "-----END *-----"
    echo "$msg" >&2
    exit 3
}

warn() {
    local msg="warning: $1"     # full message
    echo "$msg" >&2
    log "$msg"
}

log_pipe() {
    local line      # each line of input
    while IFS= read -r line;
    do
        log "$line"
    done
}

log() {
    echo "$1" >>"$logfile"
}

load_defaults() {
    local rcfile=$1     # RC file to load
    test -e "$rcfile" || return 0
    test -f "$rcfile" || {
        warn "defaults file is not a file: $rcfile"
        return 3
    }
    test -r "$rcfile" || {
        warn "defaults file not readable: $rcfile"
        return 3
    }
    bash -n "$rcfile" || {
        warn "syntax error in defaults file: $rcfile"
        return 3
    }
    . "$rcfile" || {
        warn "error in defaults file: $rcfile"
        return 3
    }
}

trim() {
    local limit_l=$1        # max. lines per message
    local limit_c=$2        # max. chars per line
    local lines_read=0      # how many lines we read
    local suff=""           # suffix (ellipsis)
    while true;
    do
        test $lines_read -ge "$limit_l" && break
        IFS= read -r line || break
        (( lines_read++ ))
        test ${#line} -gt "$limit_c" && suff=…
        line=${line:0:$limit_c}$suff
        echo "$line"
    done
}

choose_logfile() {
    local path      # path to log file
    {
        echo /var/log/notifirc.log
        echo "$HOME/.notifirc.log"
        echo /tmp/notifirc.log
    } \
      | while read -r path;
        do
            if test -w "$(dirname "$path")" \
             || test -w "$path";
            then
                echo "$path"
                break
            fi
        done
}

main() {
    local context           # context tag for nickname
    local nick              # bot's nickname
    local host              # IRC server hostname
    local port              # ... ^^ ... port
    local user              # user to notify
    local message           # message to send
    local logfile           # logfile to use
    local msgfile           # file to read message from
    local f_maxlines=3      # maximum number of lines per notification
    local f_maxwidth=80     # maximum characters per notification line

    logfile=$(choose_logfile)
    test -n "$logfile" || {
        echo "could not find writable logfile location" >&2
        echo "logging will be off!" >&2
        logfile=/dev/null
    }

    load_defaults /etc/notifirc.rc
    load_defaults "$HOME/.notifirc.rc"

    while true; do case $1 in
        -c) context=$2; shift 2 || usage ;;
        -f) msgfile=$2; shift 2 || usage ;;
        -h) host=$2;    shift 2 || usage ;;
        -l) f_maxlines=$2; shift 2 || usage ;;
        -L) f_maxwidth=$2; shift 2 || usage ;;
        -n) nick=$2;    shift 2 || usage ;;
        -p) port=$2;    shift 2 || usage ;;
        -u) user=$2;    shift 2 || usage ;;
        --) shift; break ;;
        -*) usage ;;
        *)  break ;;
    esac done
    message="$*"

    test -n "$host"    || usage
    test -n "$port"    || usage
    test -n "$user"    || usage
    test -n "$nick"    || nick="notifirc"
    test -z "$message$msgfile" && usage

    log "-----BEGIN sending notification-----"
    log "host='$host'"
    log "port='$port'"
    log "nick='$nick'"
    log "context='$context'"
    log "user='$user'"
    log "msgfile='$msgfile'"
    log "f_maxlines='$f_maxlines'"
    log "f_maxwidth='$f_maxwidth'"
    log "message='$message'"
    {
        test -n "$message" && printf '%s\n' "$message"
        test -n "$msgfile" && grep . "$msgfile" | trim "$f_maxlines" "$f_maxwidth"
    } \
      | mkcommands "$user" "$(mknick)" \
      | nc "$host" "$port" 2>&1 \
      | log_pipe
    log "-----END sending notification-----"
}

main "$@"