#!/bin/bash # Version: 0.1.0 # Copyright (c) 2023: # Darren 'Tadgy' Austin # Licensed under the terms of the GNU General Public License version 3. # # A PushOver client to send alert messages. # Configuration. CONFIG_API_URL="https://api.pushover.net/1/messages.json" CONFIG_SOUNDS_API_URL="https://api.pushover.net/1/sounds.json" # Defaults. DEFAULT_SYSTEM_DIR="/etc/pushover-client" DEFAULT_USER_DIR="${HOME}/.pushover-client" DEFAULT_CONFIG_FILE="default" DEFAULT_EXPIRY="3600" DEFAULT_RETRY="60" # Functions. show_help() { local SCRIPT="${0##*/}" #........1.........2.........3.........4.........5.........6.........7.........8 cat <<-EOF Usage: $SCRIPT [config file] [options] Push notifications to your https://pushover.net registered devices. If [config_file] is specified it is used to read the default configuration. If [config_file] is not specified, a custom user or system 'default' file will be read to obtain the defaults. If no 'default' custom user or system config file can be read, command line options are required for operation. Command line [options] override any config file. Options: -a, --attachment The picture to send with the alert. No default. -A, --api-url The API URL to use for this submission. Default is: $CONFIG_API_URL. Quote if it contains shell special chars. -c, --callback A URL which is accessed by API server when the user acknowledges the alert. This option is only used in priority 2 alerts. Quote if it contains shell special chars. -d, --devices A comma seperated list of the devices to receive the alert. Default is to send to all devices. -e, --expiry Set the expiration time for alerts sent with priority 2. Default is 3600 (1 hour). The maximum expiry time is 10800 (3 hours). --examples Show extended example usage of this program. -h, --help Show this help page. -m, --message The plain text message to send. Quote if it contains spaces. This option or -M is required if a message is not available from a config file. -M, --html-message The HTML message to send. Quote if it contains spaces. This option or -m is required if a message is not available from a config file. --monospace Use a monospace font to display the message given with -m. Default is to use regular font. This option cannot be used with -M. -p, --priority Set the priority of the message: -2 Lowest priority - no alert/notification will be generated. However, the app badge or number will update on devices. -1 Low priority - no alert sound is emitted but a notification will appear. During a user's configured quiet hours, priority -1 is used for messages. 0 Normal priority (the default) - an alert sound and notification are generated. 1 High priority - bypass the user's configured quiet hours and generate an alert and notification. 2 Emergency - as priority 1, but the alert and notification is repeated (subject to the -r and -e options) until it is acknowledged by the recipient. -q, --quiet Do not print the API execution reply to stdout. -r, --retry Set the retry interval for alerts sent with priority 2. Default is 60 (1 minute). The minimum retry time is 30 seconds. -s, --subject The subject/title of the message. If unset, the configured app name is used. Quote if it contains spaces. -S, --sound Set the alert sound to play with message: none None/silent. vibrate Vibrate only. pushover Pushover (short, default). bike Bike (short). bugle Bugle (short). cashregister Cash Register (short). classical Classical (short). cosmic Cosmic (short). falling Falling (short). gamelan Gamelan (short). incoming Incoming (short). intermission Intermission (short). magic Magic (short). mechanical Mechanical (short). pianobar Piano Bar (short). siren Siren (short). spacealarm Space Alarm (short). tugboat Tug Boat (short). alien Alien Alarm (long). climb Climb (long). persistent Persistent (long). echo Pushover Echo (long). updown Up Down (long). Or a sound uploaded to the user's account. -t, --token The pushover.net API token/key for the specific application. This option is required if not available from a config file. -T, --ttl The number of seconds the alert will live (or be displayed) on a users device before being automatically removed. The default is no ttl. This option is ignored when alerts are sent with priority (-p) 2. --timestamp The number of seconds since the unix epoch to use as the timestamp for the alert. The default timestamp is the time the API received the message. -u, --user The pushover.net user key(s). If a single user key is specified, that account's configuration will be used for the alerts. If a comma separated list (maximum 50) of user keys is given, the alert is sent only to those users. This option is required if not available from a config file. -U, --url Set the URL to send with the alert. Quote if it contains shell special chars. --url-title The title of the URL given with -U. Ignored if -U is not used also. Quote if it contains spaces. Option processing ceases with "--". For example usage, use: $SCRIPT --examples EOF } show_examples() { local SCRIPT="${0##*/}" #........1.........2.........3.........4.........5.........6.........7.........8 cat <<-EOF Basic usage is: $SCRIPT [config file] [options] [config file] configuration options are overridden by command line [options]. All or part settings may be specified in the [config file], with the addition of command line [options] to augment the [config file] settings. [options] can be seen by running: $SCRIPT --help Command line examples: Send a plain text message to all devices, showing all required [options]. $SCRIPT -u -t -m "Test message" Same as the above, but do not show any response from the API server (an appropriate error/return code is set). $SCRIPT -q -u -t -m "Test message" Send a HTML message (which will be underlined) to all devices, showing all required [options]. $SCRIPT -u -t -M "Test message" Send a plain text message to all devices, with the addition of a subject/title to the message. $SCRIPT -u -t -s "Test subject" -m "..." Send a message to all devices, including a picture attachment. $SCRIPT -u -t -a -m "..." Send a message to all devices, including a supplimentary URL with a title. $SCRIPT -u -t -U "https://afterdark.org.uk" \\ --url-title "Afterdark" -m "Check out the included URL!" Send a message to all devices, selecting an alternative sound alert. $SCRIPT -u -t -s "magic" -m "..." Send a message to a specific list of devices. $SCRIPT -u -t -d "iphone,ipad" -m "..." Send an emergency alert, repeated every minute for an 2 hours until it is acknowledged by the user. $SCRIPT -u -t -p 2 -r 60 -e 7200 -m "..." Read all configuration from path and use that for sending the alert. If this path does not exist, search for a file matching the the name in the user's private pushover directory (~/.pushover-client) or the system wide pushover directory (/etc/pushover-client), in that order. $SCRIPT EOF } # Pick out possible config file and '--' arguments of the command line. ARGS=( "$@" ) (( ${#ARGS[@]} >= 1 )) && FIRST_ARG="${ARGS[0]}" (( ${#ARGS[@]} >= 2 )) && SECOND_ARG="${ARGS[1]}" # Get the config filename if it was given on the command line, or use the default. [[ -z "$FIRST_ARG" ]] || [[ "$FIRST_ARG" =~ -[^-] ]] && FILENAME="$DEFAULT_CONFIG_FILE" && SKIP_CUSTOM=1 [[ ! -v FILENAME ]] && [[ "$FIRST_ARG" != -* ]] && FILENAME="$FIRST_ARG" && unset "ARGS[0]" [[ ! -v FILENAME ]] && [[ "$FIRST_ARG" == "--" ]] && [[ -n "$SECOND_ARG" ]] && FILENAME="$SECOND_ARG" && unset "ARGS[1]" # Find and validate the correct config filename. if (( ${SKIP_CUSTOM:-0} == 1 )) && [[ -e "$DEFAULT_USER_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_USER_DIR/$FILENAME" ]] && \ [[ -r "$DEFAULT_USER_DIR/$FILENAME" ]]; then FILENAME="$DEFAULT_USER_DIR/$FILENAME" elif (( ${SKIP_CUSTOM:-0} == 1 )) && [[ -e "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && \ [[ -r "$DEFAULT_SYSTEM_DIR/$FILENAME" ]]; then FILENAME="$DEFAULT_SYSTEM_DIR/$FILENAME" elif [[ "${FILENAME:0:1}" != "/" ]] && [[ -e "$FILENAME" ]] && [[ ! -d "$FILENAME" ]] && [[ -r "$FILENAME" ]]; then : elif [[ "${FILENAME:0:1}" != "/" ]] && [[ -e "$DEFAULT_USER_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_USER_DIR/$FILENAME" ]] && \ [[ -r "$DEFAULT_USER_DIR/$FILENAME" ]]; then FILENAME="$DEFAULT_USER_DIR/$FILENAME" elif [[ "${FILENAME:0:1}" != "/" ]] && [[ -e "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && [[ ! -d "$DEFAULT_SYSTEM_DIR/$FILENAME" ]] && \ [[ -r "$DEFAULT_SYSTEM_DIR/$FILENAME" ]]; then FILENAME="$DEFAULT_SYSTEM_DIR/$FILENAME" elif [[ "${FILENAME:0:1}" == "/" ]] && [[ -e "$FILENAME" ]] && [[ ! -d "$FILENAME" ]] && [[ -r "$FILENAME" ]]; then : elif [[ -n "$FILENAME" ]]; then printf "%s: '%s' %s\\n" "${0##*/}" "$FILENAME" "invalid config file name" >&2 exit 1 fi # Read the config file. [[ -n "$FILENAME" ]] && { eval "$(awk '!/^(#|$|[[:blank:]]*$)/ { print "CONFIG_"$0 }' "$FILENAME")" 2>/dev/null || { printf "%s: %s '%s'\\n" "${0##*/}" "error in config file" "$FILENAME" >&2 exit 1 } } # Parse command line options. set -- "${ARGS[@]}" while [[ -n "$1" ]]; do case "$1" in -a|-attachment|--attachment) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "attachment filename cannot be an empty value" >&2 exit 1 else CONFIG_ATTACHMENT="$2" fi shift ;; -A|-api-url|--api-url) # Setting is validated below. CONFIG_API_URL="$2" shift ;; -c|-callback|--callback) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "callback URL address cannot be empty" >&2 exit 1 else CONFIG_CALLBACK_URL="$2" fi shift ;; -d|-devices|--devices) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "device list cannot be an empty value" >&2 exit 1 else CONFIG_DEVICES="$2" fi shift ;; -e|-expiry|--expiry) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "expiry time cannot be an empty value" >&2 exit 1 else CONFIG_EXPIRY="$2" fi shift ;; -examples|--examples) show_examples exit 0 ;; -h|-help|--help) show_help exit 0 ;; -m|-message|--message) # Setting is validated below. CONFIG_MESSAGE="$2" shift ;; -M|-html-message|--html-message) # Setting is validated below. CONFIG_HTML_MESSAGE="$2" shift ;; -monospace|--monospace) # Setting is validated below. CONFIG_MONOSPACE="1" shift ;; -p|-priority|--priority) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "priority setting cannot be an empty value" >&2 exit 1 else CONFIG_PRIORITY="$2" fi shift ;; -q|-quiet|--quiet) CONFIG_QUIET=1 shift ;; -r|-retry|--retry) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "retry time cannot be an empty value" >&2 exit 1 else CONFIG_RETRY="$2" fi shift ;; -s|-subject|--subject) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "subject/title cannot be an empty value" >&2 exit 1 else CONFIG_SUBJECT="$2" fi shift ;; -S|-sound|--sound) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "sound selection cannot be empty" >&2 exit 1 else CONFIG_SOUND="$2" fi shift ;; -t|-token|--token) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "token key cannot be an empty value" >&2 exit 1 else CONFIG_TOKEN="$2" fi shift ;; -T|-ttl|--ttl) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "ttl cannot be an empty value" >&2 exit 1 else CONFIG_TTL="$2" fi shift ;; -timestamp|--timestamp) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "timestamp cannot be an empty value" >&2 exit 1 else CONFIG_TIMESTAMP="$2" fi shift ;; -u|-user|--user) # Setting is validated below. CONFIG_USER_KEYS="$2" shift ;; -U|-url|--url) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "URL address cannot be empty" >&2 exit 1 else CONFIG_URL="$2" fi shift ;; -url-title|--url-title) if [[ "$2" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "URL title cannot be empty" >&2 exit 1 else CONFIG_URL_TITLE="$2" fi shift ;; --) shift break ;; *) printf "%s: %s: %s\\n" "${0##*/}" "invalid option" "$1" >&2 printf "%s: %s %s\\n" "Try" "${0##*/}" "--help" >&2 exit 1 ;; esac shift done # The options list should be empty if the correct syntax was used. [[ -n "$1" ]] && { printf "%s: %s\\n" "${0##*/}" "options cannot come after --" >&2 exit 1 } # Validate all the CONFIG_* settings. [[ "$CONFIG_API_URL" =~ ^[[:blank:]]*$ ]] && { printf "%s: %s\\n" "${0##*/}" "API URL (-A) cannot be an empty value" >&2 exit 1 } if [[ ! "$CONFIG_ATTACHMENT" =~ ^[[:blank:]]*$ ]]; then if [[ ! -e "$CONFIG_ATTACHMENT" ]]; then printf "%s: %s '%s' %s\\n" "${0##*/}" "attachment (-a)" "$CONFIG_ATTACHMENT" "does not exist" >&2 exit 1 elif [[ -d "$CONFIG_ATTACHMENT" ]]; then printf "%s: %s '%s' %s\\n" "${0##*/}" "attachment (-a)" "$CONFIG_ATTACHMENT" "is a directory, not a file" >&2 exit 1 elif [[ ! -r "$CONFIG_ATTACHMENT" ]]; then printf "%s: %s '%s' %s\\n" "${0##*/}" "attachment (-a)" "$CONFIG_ATTACHMENT" "is not readable by you" >&2 exit 1 elif (( $(stat --printf=%s "$CONFIG_ATTACHMENT") > 2621440 )); then printf "%s: %s\\n" "${0##*/}" "attachment (-a) is too large (2.5MB maximum)" >&2 exit 1 fi else unset "CONFIG_ATTACHMENT" fi if [[ ! "$CONFIG_CALLBACK_URL" =~ ^[[:blank:]]*$ ]]; then (( ${#CONFIG_CALLBACK_URL} > 512 )) && { printf "%s: %s\\n" "${0##*/}" "callback URL (-c) is too long (maximum 512 characters)" >&2 exit 1 } else unset "CONFIG_CALLBACK_URL" fi if [[ ! "$CONFIG_DEVICES" =~ ^[[:blank:]]*$ ]]; then while read -r -d , DEV; do [[ -z "$DEV" ]] && continue if (( "${#DEV}" > 25 )); then printf "%s: %s\\n" "${0##*/}" "device IDs (-d) are 25 characters or less in length" >&2 exit 1 elif [[ ! "$DEV" =~ ^[[:alnum:]_-]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "device IDs (-d) can only be letters, numbers, _ and -" >&2 exit 1 else if [[ -z "$LIST" ]]; then LIST="$DEV" else LIST+=",$DEV" fi fi done <<<"$CONFIG_DEVICES," # The , on the end is required. CONFIG_DEVICES="$LIST" else unset "CONFIG_DEVICES" fi if [[ ! "$CONFIG_EXPIRY" =~ ^[[:blank:]]*$ ]]; then if [[ ! "$CONFIG_EXPIRY" =~ [[:digit:]] ]]; then printf "%s: %s\\n" "${0##*/}" "expiry time (-e) must be a number" >&2 exit 1 elif (( CONFIG_EXPIRY < 30 )); then printf "%s: %s\\n" "${0##*/}" "expiry time (-e) cannot be that short (30s minimum)" >&2 exit 1 elif (( CONFIG_EXPIRY > 10800 )); then printf "%s: %s\\n" "${0##*/}" "expiry time (-e) cannot be that long (10800s/3h maximum)" >&2 exit 1 elif [[ -n "$CONFIG_RETRY" ]] && (( CONFIG_EXPIRY < CONFIG_RETRY )); then printf "%s: %s\\n" "${0##*/}" "expiry time (-e) is less than retry time" >&2 exit 1 fi else unset "CONFIG_EXPIRY" fi if [[ "$CONFIG_MONOSPACE" =~ ^[[:blank:]]*$ ]] || [[ "$CONFIG_MONOSPACE" =~ ^(false|0)$ ]]; then CONFIG_MONOSPACE=0 elif [[ "$CONFIG_MONOSPACE" =~ ^(true|1)$ ]]; then CONFIG_MONOSPACE=1 else printf "%s: %s\\n" "${0##*/}" "monospace (--monospace) setting must be 'true', '1', 'false' or '0'" >&2 exit 1 fi if [[ ! "$CONFIG_MESSAGE" =~ ^[[:blank:]]*$ ]] && [[ ! "$CONFIG_HTML_MESSAGE" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "cannot mix a plain text (-m) and HTML (-M) message setting" >&2 exit 1 elif [[ "$CONFIG_MESSAGE" =~ ^[[:blank:]]*$ ]] && [[ "$CONFIG_HTML_MESSAGE" =~ ^[[:blank:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "must set either a plain text (-m) or HTML (-M) message" >&2 exit 1 elif [[ ! "$CONFIG_HTML_MESSAGE" =~ ^[[:blank:]]*$ ]] && (( CONFIG_MONOSPACE == 1 )); then printf "%s: %s\\n" "${0##*/}" "HTML messages (-M) cannot be used with a monospace font (--monospace)" >&2 exit 1 elif (( ${#CONFIG_MESSAGE} > 1024 )) || (( ${#CONFIG_HTML_MESSAGE} > 1024 )); then printf "%s: %s\\n" "${0##*/}" "message (-m/-M) length is too long (maximum 1024 characters)" >&2 exit 1 fi if [[ ! "$CONFIG_PRIORITY" =~ ^[[:blank:]]*$ ]]; then if [[ ! "$CONFIG_PRIORITY" =~ [[:digit:]] ]]; then printf "%s: %s\\n" "${0##*/}" "priority (-p) setting must be a number" >&2 exit 1 elif (( CONFIG_PRIORITY < -2 )) || (( CONFIG_PRIORITY > 2 )); then printf "%s: %s\\n" "${0##*/}" "priority (-p) setting must be in the range -2 - 2" >&2 exit 1 fi else unset "CONFIG_PRIORITY" fi if [[ "$CONFIG_QUIET" =~ ^[[:blank:]]*$ ]] || [[ "$CONFIG_QUIET" =~ ^(false|0)$ ]]; then CONFIG_QUIET=0 elif [[ "$CONFIG_QUIET" =~ ^(true|1)$ ]]; then CONFIG_QUIET=1 else printf "%s: %s\\n" "${0##*/}" "quiet (-q) setting must be 'true', '1', 'false' or '0'" >&2 exit 1 fi if [[ ! "$CONFIG_RETRY" =~ ^[[:blank:]]*$ ]]; then if [[ ! "$CONFIG_RETRY" =~ [[:digit:]] ]]; then printf "%s: %s\\n" "${0##*/}" "retry time (-r) must be a number" >&2 exit 1 elif (( CONFIG_RETRY < 30 )); then printf "%s: %s\\n" "${0##*/}" "retry time (-r) cannot be that short (30s minimum)" >&2 exit 1 elif [[ -n "$CONFIG_EXPIRY" ]] && (( CONFIG_RETRY > CONFIG_EXPIRY )); then printf "%s: %s\\n" "${0##*/}" "retry time (-r) exceeds expiry time" >&2 exit 1 fi else unset "CONFIG_RETRY" fi if [[ ! "$CONFIG_SUBJECT" =~ ^[[:blank:]]*$ ]]; then (( ${#CONFIG_SUBJECT} > 250 )) && { printf "%s: %s\\n" "${0##*/}" "subject/title (-s) is too long (maximum 250 characters)" >&2 exit 1 } else unset "CONFIG_SUBJECT" fi if [[ ! "$CONFIG_TOKEN" =~ ^[[:blank:]]*$ ]]; then if (( "${#CONFIG_TOKEN}" != 30 )); then printf "%s: %s\\n" "${0##*/}" "token key (-t) must be 30 characters in length" >&2 exit 1 elif [[ ! "$CONFIG_TOKEN" =~ ^[[:alnum:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "token key (-t) can only be letters and numbers" >&2 exit 1 fi else printf "%s: %s\\n" "${0##*/}" "token key (-t) cannot be an empty value" >&2 exit 1 fi if [[ ! "$CONFIG_SOUND" =~ ^[[:blank:]]*$ ]]; then [[ ! "$CONFIG_SOUND" =~ ^(none|vibrate|pushover|bike|bugle|cashregister|classical|cosmic|falling|gamelan|incoming|intermission|magic|mechanical|pianobar|siren|spacealarm|tugboat|alien|climb|persistent|echo|updown)$ ]] && { JSON="$(curl -s "$CONFIG_SOUNDS_API_URL?token=$CONFIG_TOKEN" 2>/dev/null)" if [[ "$JSON" =~ \"status\":1, ]]; then [[ ! "$JSON" =~ \"$CONFIG_SOUND\": ]] && { printf "%s: %s\\n" "${0##*/}" "sound (-S) must be a built-in or user uploaded custom sound" >&2 exit 1 } else printf "%s: %s\\n" "${0##*/}" "failed to get list of custom sounds from API (invalid API token?)" >&2 exit 1 fi } else unset "CONFIG_SOUND" fi if [[ ! "$CONFIG_TTL" =~ ^[[:blank:]]*$ ]]; then if [[ ! "$CONFIG_TTL" =~ [[:digit:]] ]]; then printf "%s: %s\\n" "${0##*/}" "TTL (-T) must be a number" >&2 exit 1 elif (( CONFIG_TTL < 0 )); then printf "%s: %s\\n" "${0##*/}" "TTL (-T) must be a positive number of seconds" >&2 exit 1 fi else unset "CONFIG_TTL" fi if [[ ! "$CONFIG_TIMESTAMP" =~ ^[[:blank:]]*$ ]]; then if [[ ! "$CONFIG_TIMESTAMP" =~ [[:digit:]] ]]; then printf "%s: %s\\n" "${0##*/}" "timestamp (--timestamp) must be a number" >&2 exit 1 elif (( CONFIG_TIMESTAMP < 0 )); then printf "%s: %s\\n" "${0##*/}" "timestamp (--timestamp) must be a positive number of seconds" >&2 exit 1 fi else unset "CONFIG_TIMESTAMP" fi if [[ ! "$CONFIG_USER_KEYS" =~ ^[[:blank:]]*$ ]]; then unset COUNT LIST while read -r -d , KEY; do [[ -z "$KEY" ]] && continue if (( "${#KEY}" != 30 )); then printf "%s: %s\\n" "${0##*/}" "user keys (-u) must be 30 characters in length" >&2 exit 1 elif [[ ! "$KEY" =~ ^[[:alnum:]]*$ ]]; then printf "%s: %s\\n" "${0##*/}" "user keys (-u) can only be letters and numbers" >&2 exit 1 else if [[ -z "$LIST" ]]; then LIST="$KEY" COUNT=1 else LIST+=",$KEY" (( COUNT++ )) fi fi done <<<"$CONFIG_USER_KEYS," # The , on the end is required. (( COUNT > 50 )) && { printf "%s: %s\\n" "${0##*/}" "too many user keys (-u) (maximum 50)" >&2 exit 1 } CONFIG_USER_KEYS="$LIST" else printf "%s: %s\\n" "${0##*/}" "user keys (-u) cannot be an empty value" >&2 exit 1 fi if [[ ! "$CONFIG_URL" =~ ^[[:blank:]]*$ ]]; then (( ${#CONFIG_URL} > 512 )) && { printf "%s: %s\\n" "${0##*/}" "URL (-U) is too long (maximum 512 characters)" >&2 exit 1 } else unset "CONFIG_URL" fi if [[ ! "$CONFIG_URL_TITLE" =~ ^[[:blank:]]*$ ]]; then (( ${#CONFIG_URL_TITLE} > 100 )) && { printf "%s: %s\\n" "${0##*/}" "URL title (--url-title) is too long (maximum 100 characters)" >&2 exit 1 } else unset "CONFIG_URL_TITLE" fi # Build the curl command line. COMMAND_LINE=('-s') # Required API elements. COMMAND_LINE+=('--form-string' user="$CONFIG_USER_KEYS") COMMAND_LINE+=('--form-string' token="$CONFIG_TOKEN") if [[ -v CONFIG_MESSAGE ]]; then COMMAND_LINE+=('--form-string' message="$CONFIG_MESSAGE") (( CONFIG_MONOSPACE == 1 )) && COMMAND_LINE+=('--form-string' 'monospace=1') else COMMAND_LINE+=('--form-string' message="$CONFIG_HTML_MESSAGE") COMMAND_LINE+=('--form-string' 'html=1') fi # Optional API elements. [[ -v CONFIG_ATTACHMENT ]] && COMMAND_LINE+=('--form' attachment="@$CONFIG_ATTACHMENT") [[ -v CONFIG_DEVICES ]] && COMMAND_LINE+=('--form-string' device="$CONFIG_DEVICES") [[ -v CONFIG_PRIORITY ]] && { COMMAND_LINE+=('--form-string' priority="$CONFIG_PRIORITY") (( CONFIG_PRIORITY == 2 )) && { [[ -v CONFIG_CALLBACK_URL ]] && COMMAND_LINE+=('--form-string' callback="$CONFIG_CALLBACK_URL") COMMAND_LINE+=('--form-string' expire="${CONFIG_EXPIRY:-$DEFAULT_EXPIRY}") COMMAND_LINE+=('--form-string' retry="${CONFIG_RETRY:-$DEFAULT_RETRY}") } } [[ -v CONFIG_SUBJECT ]] && COMMAND_LINE+=('--form-string' title="$CONFIG_SUBJECT") [[ -v CONFIG_SOUND ]] && COMMAND_LINE+=('--form-string' sound="$CONFIG_SOUND") [[ -v CONFIG_TTL ]] && COMMAND_LINE+=('--form-string' ttl="$CONFIG_TTL") [[ -v CONFIG_TIMESTAMP ]] && COMMAND_LINE+=('--form-string' timestamp="$CONFIG_TIMESTAMP") [[ -v CONFIG_URL ]] && COMMAND_LINE+=('--form-string' url="$CONFIG_URL") [[ -v CONFIG_URL_TITLE ]] && COMMAND_LINE+=('--form-string' url_title="$CONFIG_URL_TITLE") # Make the call to the messaging API. JSON="$(curl "${COMMAND_LINE[@]}" "$CONFIG_API_URL" 2>/dev/null)" || { printf "%s: %s\\n" "${0##*/}" "API call failed" >&2 exit 3 } if [[ "$JSON" =~ \"status\":1, ]]; then (( CONFIG_QUIET == 0 )) && printf "%s\\n" "$JSON" else printf "%s: %s\\n" "${0##*/}" "API returned a non-success status code" >&2 (( CONFIG_QUIET == 0 )) && printf "%s\\n" "$JSON" >&2 exit 2 fi # 0 = Request submitted OK. # 1 = Usage error. # 2 = Request status error from API # 3 = Error accessing API exit 0