#!/bin/sh -e

record_reminder_time()
{
    current_time=$(date '+%s')
    current_time=$((current_time / 3600))
    mkdir -p $CONF_DIR
    printf "$current_time\n" > $CONF_DIR/last-reminder
}

hours_since_reminder()
{
    current_time=$(date '+%s')
    current_time=$((current_time / 3600))
    reminder_file=$CONF_DIR/last-reminder
    if [ -e $reminder_file ]; then
	last_reminder=$(cat $reminder_file)
	printf "$((current_time - last_reminder))\n"
    else
	# Assume updates are needed
	printf "24\n"
    fi
}

# Run as root by cron. Protect against trojans.
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
export PATH

CONF_DIR=/usr/local/etc/freebsd-update-notify

# Place a time stamp in the log
date

# pgrep doesn't find freebsd-update-notify processes.
# Read the man page thoroughly and tried all relevant flags
# This oddly causes two freebsd-update-notify processes to be spawned
# running=$(ps ax | fgrep -v fgrep | fgrep freebsd-update-notify | wc -l)
# Use a temp file instead
tmpfile=$(mktemp)
ps ax | fgrep -v fgrep | fgrep libexec/freebsd-update-notify > $tmpfile || true
running=$(cat $tmpfile | wc -l) # Use a pipe to hide filename from wc
rm -f $tmpfile
if [ $running -gt 1 ]; then
    printf 'freebsd-update-notify is already running.\n'
    exit 0
fi

# Notifications are only generally useful on the console
DISPLAY=:0
export DISPLAY

CONF_FILE=$CONF_DIR/freebsd-update-notify.conf

hours_since_update=$(/usr/local/sbin/auto-last-update)
if [ $hours_since_update = unknown ]; then
    # Assume updates are needed
    days_since_update=7
else
    days_since_update=$(( $hours_since_update / 24 ))
fi

# Max time between updates if no freebsd-update activity
# This ensures that packages are kept up-to-date when months pass
# between base updates
max_days_between_updates=$(awk '$1 == "max-days-between-updates" { print $2 }' $CONF_FILE)

# Make sure this matches cron file
hours_between_reminders=$(awk '$1 == "hours-between-reminders" { print $2 }' $CONF_FILE)

printf "Hours since last update   = $hours_since_update\n"
printf "Days since last update    = $days_since_update\n"
printf "Max days between updates  = $max_days_between_updates\n"
printf "Hours since last reminder = $(hours_since_reminder)\n"
printf "Hours between reminders   = $hours_between_reminders\n"

# Find out who owns DISPLAY
display_users=$(ps -aexwwj | grep "DISPLAY=$DISPLAY_ID" | awk '{ print $1 }' | sort -u)

# Make sure root can access the local display
# NetBSD laptop, quagga
for user in $display_users; do
    # su -l fails intermittently under KDE + sddm
    # su -m copies full env and aliases, which is less secure
    su $user -c 'env DISPLAY=:0 /usr/local/bin/xhost +local:root' > /dev/null || true
done

if freebsd-update updatesready || \
    [ $days_since_update -ge $max_days_between_updates ]; then
    if [ $(hours_since_reminder) -ge $hours_between_reminders ]; then
	for user in $display_users; do
	    # Zenity --question returns 0 if the user clicks Yes, but
	    # the exit code of su is not the exit code of zenity.
	    # Create a file if zenity returns 0 so we can determine the
	    # yes/no response after.
	    # su returns 0 if it can access the DISPLAY.
    
	    printf "Trying $user...\n"
	    # Test access to the DISPLAY
	    if su -l $user -c "env DISPLAY=:0 /usr/local/bin/xwininfo -root" > /dev/null; then
		# If we can access the display, start dialog
		if su -l $user -c "/usr/local/bin/zenity --display=:0 --question --text='Updates are available.\nInstall and reboot now?'" > /dev/null; then
		    # || true in case auto-update-system has never been run before
		    previous_update_time=$(cat /usr/local/etc/auto-admin/last-system-update || true)
		    su -l $user -c 'env DISPLAY=:0 /usr/local/bin/urxvt -e auto-update-system --pause --yes > /dev/null'
		    new_update_time=$(cat /usr/local/etc/auto-admin/last-system-update)
		else
		    su -l $user -c "/usr/local/bin/zenity --display=:0 --info --text='You will be reminded again in $hours_between_reminders hours.\nYou can update manually any time by running\n\n\tauto-admin'" > /dev/null
		    record_reminder_time
		fi
		break   # Don't repeat for other users in $display_users
	    else
		printf "Failed.\n"
	    fi
	done
    fi
fi
