123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- #!/bin/bash
-
- #
- # Extra defaults file
- #
- # Options here override /etc and ~/, but are overrided
- # by command line options.
- #
- NOTIFIRC_RC=${NOTIFIRC_RC:-}
-
- usage() {
- #
- # Print usage message and exit with status 2
- #
- local self # our name
- self=$(basename "$0")
- {
- echo "usage: $self [options] message"
- echo "usage: $self [options] [-l max_lines] [-L max_width] -f message_file|-"
- echo "options: [-h host] [-p port] [-n nick] [-c context] [-u user]"
- echo ""
- echo "user can be user name but also channel name, in that case notifirc"
- echo "will JOIN the channel first."
- echo ""
- echo "Defaults for options can be defined as POSIX shell assignments under"
- echo "/etc/notifirc.rc, ~/.notifirc.rc or file specified by NOTIFIRC_RC"
- echo "envvar. (E.g. 'nick=jdoe', 'max_width=40')."
- echo ""
- echo "All is logged under /var/log/notifirc.log, ~/.notifirc.log, or"
- echo "/tmp/notifirc.log, whichever $self can write to."
- } >&2
- exit 2
- }
-
- mkcommands() {
- #
- # Print all IRC commands
- #
- local user="$1" # target user
- local nick="$2" # our nickname
- local message
- echo "NICK $nick"
- echo "USER $nick 8 * :notifirc bot"
- if test "${user:0:1}" == '#'; then
- echo "JOIN $user"
- fi
- while read -r message;
- do
- echo "PRIVMSG $user :$message"
- done
- echo "QUIT"
- }
-
- mknick() {
- #
- # Compose bot's nickname
- #
- case "$context" in
- "") echo "$nick" ;;
- *) echo "$nick|$context" ;;
- esac
- }
-
- die() {
- #
- # End script with fatal error $1
- #
- local msg="fatal: $1" # message
- log "$msg"
- log "-----END *-----"
- echo "$msg" >&2
- exit 3
- }
-
- warn() {
- #
- # Issue message $1 as warning to logfile and stderr
- #
- local msg="warning: $1" # full message
- echo "$msg" >&2
- log "$msg"
- }
-
- log_pipe() {
- #
- # Log contents of standard input
- #
- local line # each line of input
- local stamp
- while IFS= read -r line;
- do
- stamp=$(date -Isec)
- log "$stamp $line"
- done
- }
-
- log() {
- #
- # Log message $1 to $logfile
- #
- local stamp
- stamp=$(date -Isec)
- echo "$stamp | $1" >>"$logfile"
- }
-
- load_defaults() {
- #
- # Load defaults from RC file $1
- #
- 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
- }
- #shellcheck disable=SC1090
- . "$rcfile" || {
- warn "error in defaults file: $rcfile"
- return 3
- }
- }
-
- trim() {
- #
- # Trim to maximum $1 lines and $2 characters per line
- #
- 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() {
- #
- # Decide which log file to use (/var, /home or /tmp)
- #
- 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"
- load_defaults "$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 "$@"
|