#!/usr/bin/env bash
## (c) 2025 Tor Houghton <th@bogus.net>
## pushover notification script; i use it to send a pushover notification when 
## a command fails, e.g. when an NFS mount is offline:
## /usr/local/bin/pushover.sh -x 15 -t 90 -s /tmp/pushover.state -c touch /nfs/mail/.mounted

TOKEN="" # pushover application token
USER="" # pushover user token

## all user-configurable variables (TOKEN/USER) can be redefined in /etc/pushoverrc 
## or $HOME/.pushoverrc; the latter takes precedence
if [ -r "/etc/pushoverrc" ]; then
    source "/etc/pushoverrc"
fi
if [ -r "$HOME/.pushoverrc" ]; then
    source "$HOME/.pushoverrc"
fi

usage() {
    if [ -z "$TOKEN" ]; then
        pushover_token="MISSING!"
    else
        pushover_token="defined."
    fi
    echo "Usage: $0 [-h] [-x <seconds>] [-s statefile] [-t seconds] -c <command> [args...] "
    echo "  -h: this help message"
    echo "  -x <seconds>: timeout for command"
    echo "  -c <command> [args...]: command to run and test exit status of"
    echo "  -s <file>: state file to rate-limit notifications"
    echo "  -t <seconds>: minimum interval between notifications (requires -s)"
    echo "  Pushover token is $pushover_token"
    exit 1
}

pushover_notify() {
    pushover_message="$1"
    hostname=$(hostname)

    if [ -n "$STATEFILE" ] && [ -n "$INTERVAL" ]; then
        if [ -f "$STATEFILE" ]; then
            last_time=$(stat -c %Y "$STATEFILE")
            now=$(date +%s)
            delta=$((now - last_time))
            if [ "$delta" -lt "$INTERVAL" ]; then
                echo "Notification suppressed (rate limit: $delta < $INTERVAL seconds)"
                return
            fi
        fi
        touch "$STATEFILE"
    fi

    pushover_status=$(curl -s \
      --form-string "token=$TOKEN" \
      --form-string "user=$USER" \
      --form-string "message=[$hostname] $pushover_message" \
      https://api.pushover.net/1/messages.json | jq -r .status)
    if [ "$pushover_status" -ne 1 ]; then
        echo "Warning: Pushover notification didn't succeed, server responded with: $pushover_status"
    fi
}

COMMAND=""
STATEFILE=""
INTERVAL=""
TIMEOUT=""

while [[ $# -gt 0 ]]; do
    case $1 in
        -h)
            usage
            ;;
        -s)
            STATEFILE="$2"
            shift 2
            ;;
        -t)
            INTERVAL="$2"
            shift 2
            ;;
        -x)
            TIMEOUT="$2"
            shift 2
            ;;
        -c)
            shift
            COMMAND=("$@")
            break
            ;;
        *)
            usage
            ;;
    esac
done

if [ -z "$TOKEN" ] || [ -z "$USER" ]; then
    echo "Error: TOKEN and USER must be defined (set them in /etc/pushoverrc or ~/.pushoverrc)" >&2
    exit 1
fi

if [ -n "${COMMAND[0]}" ]; then
    if [ -n "$TIMEOUT" ]; then
        timeout "$TIMEOUT" "${COMMAND[@]}"
    else
        "${COMMAND[@]}"
    fi
    EXIT_STATUS=$?
    if [ $EXIT_STATUS -ne 0 ]; then
        pushover_notify "Command failed with status $EXIT_STATUS: ${COMMAND[*]}"
    fi
    exit $EXIT_STATUS
fi

usage
