| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 | #!/bin/bash
usage() {
    local 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"
    local nick="$2"
    local message
    echo "NICK $nick"
    echo "USER $nick 8 * :notifirc bot"
    while read message;
    do
        echo "PRIVMSG $user :$message"
    done
    echo "QUIT"
}
mknick() {
    case "$context" in
        "") echo "$nick" ;;
        *)  echo "$nick|$context" ;;
    esac
}
die() {
    local msg="fatal: $1"
    log "$msg"
    log "-----END *-----"
    echo "$msg" >&2
    exit 3
}
warn() {
    local msg="warning: $1"
    echo "$msg" >&2
    log "$msg"
}
log_pipe() {
    local line
    while IFS= read line;
    do
        log "$line"
    done
}
log() {
    echo "$1" >>"$logfile"
}
load_defaults() {
    local rcfile=$1
    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
    local limit_c=$2
    local lines_read=0
    local suff=""
    while true;
    do
        test $lines_read -ge $limit_l && break
        IFS= read line || break
        (( lines_read++ ))
        test ${#line} -gt $limit_c && suff=…
        line=${line:0:$limit_c}$suff
        echo "$line"
    done
}
choose_logfile() {
    local path
    {
        echo /var/log/notifirc.log
        echo "$HOME/.notifirc.log"
        echo /tmp/notifirc.log
    } \
      | while read path;
        do
            if test -w "$(dirname "$path")" \
             || test -w "$path";
            then
                echo "$path"
                break
            fi
        done
}
main() {
    local context nick host port user message logfile msgfile
    local f_maxlines=3 f_maxwidth=80
    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 "$@"
 |