Compare commits

..

7 commits

20 changed files with 958 additions and 13 deletions

View file

@ -5,13 +5,13 @@ LmdpdGhvb2tzL2dpdGF0dHJpYnV0ZXNkYg== 1757608819 1757608819 root:root 0755 - -
LmdpdGhvb2tzL3Bvc3QtY2hlY2tvdXQ= 1757519106 1757519106 root:root 0755 - -
LmdpdGhvb2tzL3Bvc3QtbWVyZ2U= 1757519106 1757519106 root:root 0755 - -
LmdpdGhvb2tzL3ByZS1jb21taXQ= 1757519106 1757519106 root:root 0755 - -
LmdpdGlnbm9yZQ== 1757789404 1757593248 root:root 0644 - -
LmdpdGlnbm9yZQ== 1758124916 1757593248 root:root 0644 - -
LmdpdG1vZHVsZXM= 1757607701 1757607701 root:root 0644 - -
ZXRjLy5naXRpZ25vcmU= 1758049461 1757611781 root:root 0644 - -
ZXRjLy5naXRpZ25vcmU= 1758218823 1757611781 root:root 0644 - -
ZXRjL2FwYWNoZTIvLmdpdGlnbm9yZQ== 1757775950 1757775932 root:root 0644 - -
ZXRjL2FwYWNoZTIvaHR0cGQuY29uZg== 1758045891 1757785514 root:root 0644 - -
ZXRjL2FwYWNoZTIvc2l0ZXMuZC9jb3JlLnNsYWNrd2FyZS51ay5uZXQuY29uZg== 1758045929 1757785113 root:root 0644 - -
ZXRjL2NvbmYuZC8uZ2l0aWdub3Jl 1757609410 1757609410 root:root 0644 - -
ZXRjL2NvbmYuZC8uZ2l0aWdub3Jl 1758050750 1757609410 root:root 0644 - -
ZXRjL2NvbmYuZC9ib290bWlzYw== 1757591865 1757591865 root:root 0644 - -
ZXRjL2NvbmYuZC9ub2RlLWV4cG9ydGVy 1757592526 1757592526 root:root 0644 - -
ZXRjL2NvbmYuZC9zYW1iYQ== 1757592912 1757592912 root:root 0644 - -
@ -33,17 +33,22 @@ ZXRjL2hvc3RuYW1l 1757594311 1757594311 root:root 0644 - -
ZXRjL2hvc3Rz 1757594362 1757594362 root:root 0644 - -
ZXRjL2lwdGFibGVzL3J1bGVzLXNhdmU= 1757789154 1757789154 root:root 0600 - -
ZXRjL2lwdGFibGVzL3J1bGVzNi1zYXZl 1757789154 1757789154 root:root 0600 - -
ZXRjL2tyYjUuY29uZg== 1758214709 1583171707 root:root 0644 - -
ZXRjL2xvY2FsLmQvLmdpdGlnbm9yZQ== 1757595481 1757595481 root:root 0644 - -
ZXRjL2xvY2FsLmQvcHVzaG92ZXItYWxlcnQuc3RhcnQ= 1758225142 1758225089 root:root 0755 - -
ZXRjL2xvY2FsLmQvcHVzaG92ZXItYWxlcnQuc3RvcA== 1758225254 1758225155 root:root 0755 - -
ZXRjL2xvY2FsLmQvdGVycmFmb3JtLWh0dHAtYmFja2VuZC5zdGFydA== 1757595926 1757595926 root:root 0755 - -
ZXRjL21zbXRwLmFsaWFzZXM= 1758035451 1758035451 root:root 0644 - -
ZXRjL21zbXRwcmMuZ3Bn 1758049424 1758049424 root:root 0644 - -
ZXRjL25ldHdvcmsvLmdpdGlnbm9yZQ== 1757596572 1757596572 root:root 0644 - -
ZXRjL25ldHdvcmsvaW50ZXJmYWNlcw== 1757759982 1757596330 root:root 0644 - -
ZXRjL3Bhc3N3ZA== 1757873724 1757869538 root:root 0644 - -
ZXRjL3BlcmlvZGljL2RhaWx5L2Nyb25qb2ItZGVoeWRyYXRlZA== 1757708520 1757708520 root:root 0777 - -
ZXRjL3BlcmlvZGljL2RhaWx5L2Nyb25qb2ItdXBkYXRlLXBhY2thZ2VzLWxpc3Q= 1757708520 1757708520 root:root 0777 - -
ZXRjL3BlcmlvZGljL2RhaWx5L2Nyb25qb2Itd2Fybi1naXQtc3RhdHVz 1757708520 1757708520 root:root 0777 - -
ZXRjL3BrZ2xpc3Q= 1758046586 1757609913 root:root 0644 - -
ZXRjL3BlcmlvZGljL2RhaWx5LzAtcm90YXRlLWxvZ3Mtc3ltbGlua3M= 1758222266 1758222266 root:root 0777 - -
ZXRjL3BlcmlvZGljL2RhaWx5LzEwLWRlaHlkcmF0ZWQ= 1757708520 1757708520 root:root 0777 - -
ZXRjL3BlcmlvZGljL2RhaWx5LzUtdXBkYXRlLXBhY2thZ2VzLWxpc3Q= 1757708520 1757708520 root:root 0777 - -
ZXRjL3BlcmlvZGljL2RhaWx5Lzctd2Fybi1naXQtc3RhdHVz 1757708520 1757708520 root:root 0777 - -
ZXRjL3BrZ2xpc3Q= 1758211839 1757609913 root:root 0644 - -
ZXRjL3B1c2hvdmVyLWNsaWVudC9kZWZhdWx0 1758224985 1758224590 root:root 0600 - -
ZXRjL3Jlc29sdi5jb25m 1757611605 1757611605 root:root 0644 - -
ZXRjL3J1bmxldmVscy9ib290Ly5naXRpZ25vcmU= 1757769666 1757598667 root:root 0644 - -
ZXRjL3J1bmxldmVscy9ib290L3JzeXNsb2c= 1757708520 1757708520 root:root 0777 - -
@ -59,10 +64,14 @@ ZXRjL3J1bmxldmVscy9kZWZhdWx0L3RlcnJhZm9ybS1odHRwLWJhY2tlbmQ= 1757772274 17577722
ZXRjL3J1bmxldmVscy9zaHV0ZG93bi9pcDZ0YWJsZXM= 1757770292 1757770292 root:root 0777 - -
ZXRjL3J1bmxldmVscy9zaHV0ZG93bi9pcHRhYmxlcw== 1757770284 1757770284 root:root 0777 - -
ZXRjL3J1bmxldmVscy9zaHV0ZG93bi9zYW1iYQ== 1757708520 1757708520 root:root 0777 - -
ZXRjL3NhbWJhL3NtYi5jb25m 1758215678 1758208516 root:root 0644 - -
ZXRjL3NhbWJhL3NtYnVzZXJz 1758121825 1758121586 root:root 0644 - -
ZXRjL3NoYWRvdy5ncGc= 1757599010 1757599010 root:root 0644 - -
ZXRjL3NzaC8uZ2l0aWdub3Jl 1757606957 1757606957 root:root 0644 - -
ZXRjL3NzaC9zc2hfY29uZmln 1757606630 1757606630 root:root 0644 - -
ZXRjL3NzaC9zc2hkX2NvbmZpZw== 1757606896 1757606896 root:root 0644 - -
ZXRjL3NzaC9zc2hkX2NvbmZpZw== 1758202229 1757606896 root:root 0644 - -
ZXRjL3NzaGd1YXJkLmNvbmY= 1758050700 1758050700 root:root 0644 - -
ZXRjL3NzaGd1YXJkLndoaXRlbGlzdA== 1758050235 1758050235 root:root 0644 - -
ZXRjL3N1ZG9lcnMuZC9kZWZhdWx0cw== 1757599359 1757599359 root:root 0640 - -
ZXRjL3N1ZG9lcnMuZC9yb290LWFjY2Vzcw== 1757600157 1757600157 root:root 0640 - -
aG9tZS8uZ2l0aWdub3Jl 1757762052 1757762052 root:root 0644 - -
@ -76,9 +85,11 @@ aG9tZS9zeXNhZG1pbi8ubmFub3Jj 1757585756 1757585756 sysadmin:users 0644 - -
aG9tZS9zeXNhZG1pbi8uc3NoLy5naXRpZ25vcmU= 1757593349 1757593349 sysadmin:users 0644 - -
aG9tZS9zeXNhZG1pbi8uc3NoL2F1dGhvcml6ZWRfa2V5cw== 1757763178 1757587611 sysadmin:users 0644 - -
b3B0L3NiaW4vY3JvbmpvYi1kZWh5ZHJhdGVk 1758033093 1757531685 root:root 0755 - -
b3B0L3NiaW4vY3JvbmpvYi1yb3RhdGUtbG9ncy1zeW1saW5rcw== 1758224324 1758224324 root:root 0755 - -
b3B0L3NiaW4vY3JvbmpvYi11cGRhdGUtcGFja2FnZXMtbGlzdA== 1757531121 1757531121 root:root 0755 - -
b3B0L3NiaW4vY3JvbmpvYi13YXJuLWdpdC1zdGF0dXM= 1757591137 1757591137 root:root 0755 - -
b3B0L3NiaW4vY3JvbmpvYi13YXJuLWdpdC1zdGF0dXM= 1758221607 1757591137 root:root 0755 - -
b3B0L3NiaW4vZGVoeWRyYXRlZA== 1757531557 1757531557 root:root 0755 - -
b3B0L3NiaW4vcHVzaG92ZXItY2xpZW50 1758224526 1758224526 root:root 0755 - -
b3B0L3NiaW4vdGVycmFmb3JtLWh0dHAtYmFja2VuZA== 1757590543 1757590543 root:root 0755 - -
cm9vdC8uYmFzaF9sb2dvdXQ= 1757582867 1757582867 root:root 0644 - -
cm9vdC8uYmFzaF9wcm9maWxl 1757584711 1757584711 root:root 0644 - -

1
etc/.gitignore vendored
View file

@ -52,3 +52,4 @@
/sysctl.d/
/terminfo/
/udhcpc/
/xattr.conf

View file

@ -21,6 +21,7 @@
/ntpd
/rdate
/seedrng
/sshguard
/staticroute
/swap
/swclock

24
etc/krb5.conf Normal file
View file

@ -0,0 +1,24 @@
[logging]
# default = FILE:/var/log/krb5libs
# kdc = FILE:/var/log/krb5kdc
# admin_server = FILE:/var/log/kadmind
[libdefaults]
default_realm = SLACKWARE.UK.NET
dns_lookup_realm = false
dns_lookup_kdc = false
rdns = true
forwardable = true
ticket_lifetime = 24h
renew_lifetime = 7d
[realms]
SLACKWARE.UK.NET = {
default_domain = slackware.uk.net
admin_server = core.slackware.uk.net
kdc = core.slackware.uk.net
}
[domain_realm]
.slackware.uk.net = SLACKWARE.UK.NET
core = SLACKWARE.UK.NET

View file

@ -0,0 +1,4 @@
#!/bin/bash
# Alert that this host is up.
( sleep 30; [[ -x /opt/sbin/pushover-client ]] && /opt/sbin/pushover-client -p -1 -m "Boot up: ${HOSTNAME%%.*}" ) &

View file

@ -0,0 +1,4 @@
#!/bin/bash
# Alert that this host is going down.
[[ -x /opt/sbin/pushover-client ]] && /opt/sbin/pushover-client -p -1 -m "Shut down: ${HOSTNAME%%.*}" &

View file

@ -0,0 +1 @@
/opt/sbin/cronjob-rotate-logs-symlinks

View file

@ -16,6 +16,7 @@ apk-tools
apr
apr-util
argon2-libs
attr
avahi-libs
bash
bridge
@ -54,6 +55,7 @@ ldb
libapk2
libarchive
libassuan
libattr
libauth-samba
libbsd
libbz2
@ -102,6 +104,7 @@ lynx
lz4-libs
mailx
mdev-conf
mpdecimal
msmtp
msmtp-openrc
musl
@ -132,6 +135,24 @@ popt
procps-ng
prometheus-node-exporter
prometheus-node-exporter-openrc
py3-cffi
py3-cffi-pyc
py3-cparser
py3-cparser-pyc
py3-cryptography
py3-cryptography-pyc
py3-dnspython
py3-dnspython-pyc
py3-ldb
py3-markdown
py3-markdown-pyc
py3-samba
py3-talloc
py3-tdb
pyc
python3
python3-pyc
python3-pycache-pyc0
readline
rsyslog
rsyslog-openrc
@ -141,10 +162,15 @@ samba-client-libs
samba-common
samba-common-server-libs
samba-common-tools
samba-dc
samba-dc-libs
samba-libs
samba-libs-py3
samba-server
samba-server-libs
samba-server-openrc
samba-util-libs
samba-winbind
scanelf
skalibs-libs
sqlite-libs
@ -153,6 +179,7 @@ sshguard-openrc
ssl_client
sudo
talloc
tdb
tdb-libs
tevent
utmps-libs

View file

@ -0,0 +1,3 @@
QUIET="true"
TOKEN="a484bt3qn6d78noowrik1rwhk3beuk"
USER_KEYS="uscT77WKKzaNoLWXZDiBaECab3pE9z"

40
etc/samba/smb.conf Normal file
View file

@ -0,0 +1,40 @@
[global]
realm = SLACKWARE.UK.NET
netbios name = CORE
workgroup = SLACKWAREUKNET
server string = "slackware.uk.net Domain Controller"
# dns forwarder = 5.101.171.216 5.101.171.217 185.176.90.169
dns forwarder = 216.119.155.58 185.176.90.169
allow dns updates = disabled
tls cafile = /etc/certificates/core.slackware.uk.net_fullchain.pem
tls certfile = /etc/certificates/core.slackware.uk.net_cert.pem
tls keyfile = /etc/certificates/core.slackware.uk.net_key.pem
tls verify peer = ca_and_name_if_available
log level = 1
logging = syslog:local5
idmap config * : backend = tdb
# There are only 568 IDs mapped into the container by TrueNAS, so limit the number that can be used.
idmap config * : range = 10000-10500
idmap_ldb:use rfc2307 = yes
password hash userPassword schemes = CryptSHA512
server role = active directory domain controller
username map = /etc/samba/smbusers
vfs objects = dfs_samba4 posixacl acl_xattr
nfs4acl_xattr:encoding = nfs
nfs4acl_xattr:version = 41
nfs4acl_xattr:xattr_name = user.nfs4_acl
nfs4acl_xattr:default acl style = windows
acl_xattr:security_acl_name = user.NTACL
acl_xattr:default acl style = windows
# [homes]
# [printers]
[sysvol]
path = /var/lib/samba/sysvol
write list = @'Domain Admins@slackware.uk.net'
[netlogon]
path = /var/lib/samba/sysvol/slackware.uk.net/scripts
write list = @'Domain Admins@slackware.uk.net'

1
etc/samba/smbusers Normal file
View file

@ -0,0 +1 @@
root = Administrator

View file

@ -8,5 +8,4 @@ MaxStartups 5
PermitRootLogin prohibit-password
StreamLocalBindUnlink yes
Subsystem sftp internal-sftp
UsePAM yes
X11Forwarding no

54
etc/sshguard.conf Normal file
View file

@ -0,0 +1,54 @@
#!/bin/sh
# sshguard.conf -- SSHGuard configuration
# Full path to backend executable (required, no default)
BACKEND="/usr/libexec/sshg-fw-iptables"
# Space-separated list of log files to monitor. (optional, no default)
FILES="/var/log/core.slackware.uk.net/auth"
# Shell command that provides logs on standard output. (optional, no default)
# Example 1: ssh and sendmail from systemd journal:
#LOGREADER="LANG=C /usr/bin/journalctl -afb -p info -n1 -t sshd -t sendmail -o cat"
# Example 2: ssh from os_log (macOS 10.12+)
#LOGREADER="/usr/bin/log stream --style syslog --predicate '(processImagePath contains \"sshd\")'"
# Block attackers when their cumulative attack score exceeds THRESHOLD.
# Most attacks have a score of 10. (optional, default 30)
THRESHOLD=10
# Block attackers for initially BLOCK_TIME seconds after exceeding THRESHOLD.
# Subsequent blocks increase by a factor of 1.5. (optional, default 120)
BLOCK_TIME=86400
# Remember potential attackers for up to DETECTION_TIME seconds before
# resetting their score. (optional, default 1800)
DETECTION_TIME=28800
# Size of IPv6 subnet to block. Defaults to a single address, CIDR notation. (optional, default to 128)
IPV6_SUBNET=128
# Size of IPv4 subnet to block. Defaults to a single address, CIDR notation. (optional, default to 32)
IPV4_SUBNET=32
# Full path to PID file (optional, no default)
PID_FILE=/run/sshguard.pid
# Colon-separated blacklist threshold and full path to blacklist file.
# (optional, no default)
BLACKLIST_FILE=10:/var/lib/sshguard/blacklist
# IP addresses listed in the WHITELIST_FILE are considered to be
# friendlies and will never be blocked.
WHITELIST_FILE=/etc/sshguard.whitelist
# If PARSER is unset, SSHGuard will use the installed sshg-parser as its
# parser. Setting PARSER overrides this, so that you can use your own parser.
#PARSER=
# Run POST_PARSER as a filter after the parser. POST_PARSER must read as input
# and produce as output lines in the format used by sshg-parser. This example
# implements primitive whitelisting, preventing sshg-blocker from seeing
# attacks from 1.2.3.4. Unlike whitelisting, attacks filtered by POST_PARSER
# are not logged by SSHGuard.
#POST_PARSER="grep -v 1.2.3.4"

19
etc/sshguard.whitelist Normal file
View file

@ -0,0 +1,19 @@
# Localhost.
127.0.0.1/8
::1
# UK Servers
5.101.171.208/28
2a01:a500:2981:1::/64
# Linode
172.236.16.105
2600:3c13::2000:50ff:fef4:7f56
# Loveservers
185.176.90.169
2a07:4580:b0d:57f::169
# Afterdark
afterdark.org.uk
2001:470:1f1c:58::/64

View file

@ -0,0 +1,45 @@
#!/bin/bash
# Default configuration.
LOGS_DIR="/var/log"
DIR_MODE="0750"
UMASK="027"
# Allow /etc/default/rotate-logs-symlinks to override default configuration.
[[ -e /etc/default/rotate-logs-symlinks ]] && {
# shellcheck disable=SC1091
source /etc/default/rotate-logs-symlinks || {
printf "%s: %s\\n" "${0##*/}" "failed reading /etc/default/rotate-logs-symlinks" >&2
exit 1
}
}
# Process the directories in the logs directory.
[[ -d "$LOGS_DIR" ]] && {
TODAY="$(printf "%(%Y/%m/%d)T")"
umask "$UMASK"
# Process all the directories in the logs directory.
for DIR in "$LOGS_DIR"/*; do
cd "$DIR" 2>/dev/null || {
printf "%s: %s\\n" "${0##*/}" "failed to change directory to '$DIR'" >&2
continue
}
# Create a new logs directory for today.
# shellcheck disable=SC2174
mkdir -p -m "$DIR_MODE" "$TODAY" 2>/dev/null || {
printf "%s: %s\\n" "${0##*/}" "failed to create directory '$DIR/$TODAY'" >&2
continue
}
# Create a 'today' symlink to the new days' directory.
( cd "$DIR" 2>/dev/null && ln -sf "$TODAY" "today" 2>/dev/null ) || {
printf "%s: %s\\n" "${0##*/}" "creating 'today' symlink failed" >&2
continue
}
done
}
exit 0

View file

@ -1,8 +1,18 @@
#!/bin/bash
# Default configuration.
CHECK_DIRS=('/')
EMAIL_TO=('sysadmin@slackware.uk')
EMAIL_FROM="${HOSTNAME%%.*} <noreply@slackware.uk>"
EMAIL_FROM="\"Server: ${HOSTNAME%%.*}\" <noreply@slackware.uk>"
# Allow /etc/default/warn-git-status to override default configuration.
[[ -e /etc/default/warn-git-status ]] && {
source /etc/default/warn-git-status || {
printf "%s: %s\\n" "${0##*/}" "failed reading /etc/default/warn-git-status" >&2
exit 1
}
}
OUTPUT_FILE="/tmp/${0##*/}-$$-$RANDOM"
# Remove the OUTPUT_FILE when done.
@ -22,8 +32,8 @@ done
# Send the message.
if [[ -n "${EMAIL_TO[*]}" ]]; then
mailx "${MAILX_ARGS[@]}" -S "from=$EMAIL_FROM" -s "Git statuses" "${EMAIL_TO[@]}" <<<"$(cat "$OUTPUT_FILE")" 2>/dev/null || {
printf "%s: %s\\n" "${0##*/}" "mailx command failed" >&2
mail -r "$EMAIL_FROM" -s "Git statuses" "${EMAIL_TO[@]}" <"$OUTPUT_FILE" >/dev/null 2>&1 || {
printf "%s: %s\\n" "${0##*/}" "mail command failed" >&2
exit 1
}
else

701
opt/sbin/pushover-client Executable file
View file

@ -0,0 +1,701 @@
#!/bin/bash
# Version: 0.1.0
# Copyright (c) 2023:
# Darren 'Tadgy' Austin <darren (at) afterdark.org.uk>
# 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 <filename> The picture to send with the alert. No default.
-A, --api-url <url> The API URL to use for this submission. Default
is: $CONFIG_API_URL.
Quote <url> if it contains shell special chars.
-c, --callback <url> A URL which is accessed by API server when the
user acknowledges the alert. This option is
only used in priority 2 alerts.
Quote <url> if it contains shell special chars.
-d, --devices <devices> A comma seperated list of the devices to receive
the alert. Default is to send to all devices.
-e, --expiry <seconds> 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 <text> The plain text message to send.
Quote <text> if it contains spaces.
This option or -M is required if a message is
not available from a config file.
-M, --html-message <text> The HTML message to send.
Quote <text> 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 <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 <seconds> Set the retry interval for alerts sent with
priority 2. Default is 60 (1 minute). The
minimum retry time is 30 seconds.
-s, --subject <text> The subject/title of the message. If unset,
the configured app name is used.
Quote <text> if it contains spaces.
-S, --sound <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 <token> The pushover.net API token/key for the specific
application. This option is required if not
available from a config file.
-T, --ttl <seconds> 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 <seconds> 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 <user_key> 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 <url> Set the URL to send with the alert.
Quote <url> if it contains shell special chars.
--url-title <text> The title of the URL given with -U. Ignored
if -U is not used also.
Quote <text> 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 <user key> -t <API token> -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 <user key> -t <API token> -m "Test message"
Send a HTML message (which will be underlined) to all devices, showing all
required [options].
$SCRIPT -u <user key> -t <API token> -M "<u>Test message</u>"
Send a plain text message to all devices, with the addition of a subject/title
to the message.
$SCRIPT -u <user key> -t <API token> -s "Test subject" -m "..."
Send a message to all devices, including a picture attachment.
$SCRIPT -u <user key> -t <API token> -a </path/to/image> -m "..."
Send a message to all devices, including a supplimentary URL with a title.
$SCRIPT -u <user key> -t <API token> -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 <user key> -t <API token> -s "magic" -m "..."
Send a message to a specific list of devices.
$SCRIPT -u <user key> -t <API token> -d "iphone,ipad" -m "..."
Send an emergency alert, repeated every minute for an 2 hours until it is
acknowledged by the user.
$SCRIPT -u <user key> -t <API token> -p 2 -r 60 -e 7200 -m "..."
Read all configuration from <config file> path and use that for sending the
alert. If this path does not exist, search for a file matching the the
<config file> name in the user's private pushover directory (~/.pushover-client)
or the system wide pushover directory (/etc/pushover-client), in that order.
$SCRIPT <config file>
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