# SPDX-License-Identifier: 0BSD
# /etc/default/ratrun: demo config file, see ratrun(8)

RATRUN_REMINDERS='1h'  # '2h 30m', ...

# Debian-like: check runs for %users + root
RATRUN_USERS='root'
RATRUN_GROUPS='users'

#RERAT_DEFAULT='all archive=3mo archive-name=.%Y-Q%q'

# mailutils-like (you may want to inject a 'sed "s/^~/​~/" |' (that's a ZWSP) here for mailutils <3.13 to disable escapes.
#                 cf. https://www.mail-archive.com/bug-mailutils@gnu.org/msg02238.html):
alias mail='        mail -E "set nonullbodymsg"'
alias mail_noempty='mail -E "unset nullbody"'
# 4.4BSD-like (mail(1) already doesn't complain for empty bodies):
#alias mail_noempty='mail -E'

# Append filename to archive-name; must create archive-name if it doesn't exist
# If your tar handles "@filename" specially (NetBSD, FreeBSD), then you might want to use pax or cpio here instead (or not create events starting with an @);
# pax has max. 100 bytes for the filename, cpio doesn't; both split names on lines
archive() {  # archive-name filename
	flock -F -- "$1" tar -rf "$1" -- "$2"
	#printf '%s\n' "$2" | flock -F -- "$1" sh -c '! [ -s "$1" ] && exec cpio --quiet -o > "$1" || exec cpio --quiet -oAO "$1"' _ "$@"
}

command -v getent > /dev/null || getent() {
	f="/etc/$1"; shift
	if [ $# -gt 0 ]; then
		grep $(printf '	-e	^%s:' "$@") "$f"
	else
		cat "$f"
	fi
}


unsuff() {
	unsuff_mul() {
		[ "${val%"$1"}" != "$val" ] && {
			val="${val%"$1"}"
			val=$(( val * $2 ))"$3"
		}
	}

	val="$1"
	# These also agree with reminders.0 (ratrun.8, rerat.8, rat.8)
	unsuff_mul mo   4 wk
	unsuff_mul wk   7 d
	unsuff_mul yr 365 d
	unsuff_mul d   24 h
	unsuff_mul h   60 m
	unsuff_mul m   60
	unsuff_mul s    1
	printf '%s%s' "$val" "${2- }"
}

resuff() {
	resuff_div() {
		val_s="${val%"$3"}"
		{ [ -z "$3" ] || [ "$val_s" != "$val" ]; } && [ $(( val_s % $2 )) -eq 0 ] && {
			val=$(( val_s / $2 ))"$1"
		}
	}

	val="$1"
	[ "$val" -eq 0 ] && { printf '0%s' "${2- }"; return; }

	resuff_div s    1
	resuff_div m   60 s
	resuff_div h   60 m
	resuff_div d   24 h
	resuff_div yr 365 d
	resuff_div wk   7 d
	resuff_div mo   4 wk
	printf '%s%s' "$val" "${2- }"
}

archive_name='.old'
parse_config() {
	for cfg; do
		case "$cfg" in
			!|[1-9]*)        rerat="${cfg#!}"; rerat_lineno="$lineno"               ;;
			max=*)           max="${cfg#max=}"; max="${max#!}"                      ;;
			reratted=*)      reratted="${cfg#reratted=}"; reratted_lineno="$lineno" ;;
			original-time=*) original_time=; return                                 ;;

			archive=*)       archive="${cfg#archive=}"; archive="${archive#!}"      ;;
			archive-name=*)  archive_name="${cfg#archive-name=}"                    ;;

			verbose)         verbose=1                                              ;;
			!verbose)        verbose=                                               ;;
			all)             all_events=1                                           ;;
			!all)            all_events=                                            ;;
		esac
	done
}

# output in TZ; rollback in unzone_e
guess_tz() {
	read -r tmpzone
	[ -n "$tmpzone" ] && {
		[ -e "/usr/share/zoneinfo/$tmpzone" ] ||
			{ tmpzone2=$(printf '%s' "$tmpzone"  | sed 's/Standard *//'); [ -e "/usr/share/zoneinfo/$tmpzone2" ] && tmpzone="$tmpzone2"; } ||
			{ tmpzone2=$(printf '%s' "$tmpzone2" | tr -cd 'A-Z');         [ -e "/usr/share/zoneinfo/$tmpzone2" ] && tmpzone="$tmpzone2"; } ||
			{ tmpzone=$( printf '%s' "$tmpzone"  | tr -cd 'A-Z');         [ -e "/usr/share/zoneinfo/$tmpzone" ]; } ||
			tmpzone=
	}
	[ -n "$tmpzone" ] && {
		unzone_e="$(export -p | grep -m1 '^export TZ')"  # 2.5x faster than shell equiv.
		export TZ="$tmpzone"
	}
}

# This is, spiritually, mv -bS "-rawtime" -S "-$(date ...)" -- "$f" 'old/', but coreutils mv doesn't accept multiple fallback suffixes,
#                       and mv -n returns 0 even if it didn't move anything!
# This requires that ~/.ratrun and ~/.ratrun/old are the same filesystem, but that's universally true.
#
# If you have a weird filesystem that forbids hardlinks, then make this an alias for the equivalent of this C program (or just build this):
#   #include <errno.h>
#   #include <fcntl.h>
#   #include <stdio.h>
#   #include <stdlib.h>
#   #include <string.h>
#   #include <time.h>
#   int main(int argc, const char * const * argv) {
#   	const char * basename = *(argv + 1);
#   	const char * dirname  = *(argv + 2);
#
#   	int dir = open(dirname, O_PATH | O_DIRECTORY | O_CLOEXEC);
#   	if(dir == -1)
#   		return fprintf(stderr, "%s: %s: %s\n", argv[0], dirname, strerror(errno)), 1;
#
#   	if(!renameat2(AT_FDCWD, basename, dir, basename, RENAME_NOREPLACE))
#   		return 0;
#
#
#   	const char * rawtime = *(argv + 3);
#   	char buf[64 * 1024];
#   	if(snprintf(buf, sizeof(buf), "%s-%s", basename, rawtime) >= sizeof(buf))
#   		abort();
#   	if(!renameat2(AT_FDCWD, basename, dir, buf, RENAME_NOREPLACE))
#   		return 0;
#
#
#   	time_t filetime = strtoull(*(argv + 4), NULL, 10);
#   	struct tm tm;
#   	if(!localtime_r(&filetime, &tm))
#   		return fprintf(stderr, "%s: localtime(%llu): %s\n", argv[0], (unsigned long long)filetime, strerror(errno)), 1;
#
#   	char tmbuf[128];
#   	strftime(tmbuf, sizeof(tmbuf), "%Y-%m-%dT%H:%M", &tm);  // -Iminutes sans %:z, which is not in strftime()
#
#   	if(tm.tm_isdst < 0) {
#   		if(snprintf(buf, sizeof(buf), "%s-%s", basename, rawtime) >= sizeof(buf))
#   			abort();
#   	} else {
#   		int8_t hm[2];  // see voreutils, include/vore-time, discussion around tm_gmtoff_for() if your system doesn't provide tm_gmtoff
#   		hm[1] = labs((tm.tm_gmtoff / 60) % 60);
#   		hm[0] = tm.tm_gmtoff / 60 / 60;
#
#   		if(snprintf(buf, sizeof(buf), "%s-%s%+03hhd:%02hhd", basename, tmbuf, hm[0], hm[1]) >= sizeof(buf))
#   			abort();
#   	}
#
#   	if(renameat2(AT_FDCWD, basename, dir, buf, 0) == -1)
#   		return fprintf(stderr, "%s: %s -> %s%s: %s\n", argv[0], basename, dirname, buf, strerror(errno)), 1;
#   }
datemove() {  # basename dirname raw-time time-in-seconds
	{
		ln    -- "$1" "$2"      2>&- ||
		ln    -- "$1" "$2$1-$3" 2>&- ||
		ln -f -- "$1" "$2$1-$(date -d"@$4" +'%Y-%m-%dT%H:%M%:z')"  # -Iminutes
	} && rm -f -- "$1"
}
