#!/bin/bash
#Psync - GPL - Robert Lane (tasmod). npierce 2013
#Synchronises system and hardware clock to a public time server

#exec &>/tmp/${0##*/}.log ; set -x ; env #debug

[ ! -f /usr/share/icons/hicolor/48x48/apps/clock_countdown.svg ] && \
ln -sf /usr/share/pixmaps/puppy/clock_countdown.svg /usr/share/icons/hicolor/48x48/apps && gtk-update-icon-cache -f -i /usr/share/icons/hicolor 2>/dev/null

set_time_from_server() {
	#set -x
	NTP_SERVER='pool.ntp.org' #precaution
	if [ -s "$HOME/.config/psync_server" ] ; then
		read NTP_SERVER < $HOME/.config/psync_server
	fi
	#--
	echo "* Synchronizing to $NTP_SERVER..."
	if which ntpdate &>/dev/null ; then
		ntpdate $NTP_SERVER &> /tmp/settertime
		RETVAL=$?
	else
		busybox ntpd -nqp $NTP_SERVER
		RETVAL=$?
	fi
	#--
	if [ $RETVAL -eq 0 ] ; then
		echo "* Success..."
	else
		echo "* ERROR..."
		return 1
	fi
	date
	set_hwclock_type -q --systohc #system time to hw
	if [ $? -ne 0 ] ; then
		echo "* Could not set hardware clock..."
	fi
	return 0
}

if [ -z "$HOME" -o "$HOME" = '/' ] ; then
	if [ -f /etc/plogin ] ; then
		read puser < /etc/plogin
		HOME=$(awk -F: '$1=="'${puser}'" {print $6}' /etc/passwd)
	fi
	if [ -z "$HOME" -o "$HOME" = '/' ] ; then
		HOME=/root
	fi
fi

#==============================================================
#                    SERVICE
#==============================================================
case $1 in
	start|restart)
		CONNECTED=no
		for i in $(seq 0 5 300) ; do
			if [ "$(LANG=C route -n | awk 'FNR == 3 {print $2}')" != "0.0.0.0" ] && \
				grep -wq nameserver ${SYSROOT}/etc/resolv.conf ; then
				CONNECTED=yes
				break
			fi
			sleep 5
		done
		if [ "$CONNECTED" = "no" ] ; then
			exit 1
		fi
		set_time_from_server || {
			# might need some more time..
			sleep 15
			set_time_from_server
		}
		exit $?
		;;
	stop)
		exit
		;;
esac
#==============================================================


#==============================================================
#                          APP
#==============================================================

PSYNC_ENABLED=false
if [ -x ${SYSROOT}/etc/init.d/psync ] ; then
	PSYNC_ENABLED=true
fi

psync_status() {
	if [ "$PSYNC_ENABLED" = "true" ] ; then
		echo "psync autostart is enabled..."
		return 0
	else
		echo "psync autostart is disabled..."
		return 1
	fi
}

enable_psync() {
	if [ ! -f ${SYSROOT}/etc/init.d/psync ] ; then
		echo '#!/bin/sh
case $1 in start|restart|stop)
	/usr/sbin/psync $1 1>/dev/null 2>&1 &
esac' > ${SYSROOT}/etc/init.d/psync
	fi
	chmod +x ${SYSROOT}/etc/init.d/psync
	[ ! "$GUI" ] && echo "psync autostart on bootup enabled"
}
disable_psync() {
	chmod -x ${SYSROOT}/etc/init.d/psync
	#rm -f ${SYSROOT}/etc/init.d/psync
	[ ! "$GUI" ] && echo "psync autostart on bootup disabled"
}

set_tz() {
	if [ ! "$1" ] ; then
		echo "You must specify a timezone."
		return 1
	fi
	if [ -f ${SYSROOT}/usr/share/zoneinfo/$1 ] ; then
		ln -snfv /usr/share/zoneinfo/$1 ${SYSROOT}/etc/localtime
		return $?
	else
		echo "File not found: ${SYSROOT}/usr/share/zoneinfo/$1"
		return 1
	fi
}

usage() {
	app=${0##*/}
	echo
	echo "  synchronize system and hardware clock to a public timeserver.."
	echo
	echo "usage: $app <option>"
	echo
	echo "Options:"
	echo " -cli           : force cli"
	echo " -gui           : force gui"
	echo " -sysroot <dir> : set root dir"
	echo " -autostart     : enable service"
	echo " -noautostart   : disable service"
	echo " -status        : report service status"
	echo " -sync          : sync to time server"
	echo " -timezone <tz> : set timezone"
	echo
}

[ -n "$DISPLAY" -o -n "$WAYLAND_DISPLAY" ] && export GUI=1

for i in $@; do
	case $1 in
		-sysroot)     export SYSROOT=$2 ; shift ;;
		-autostart)   enable_psync  ; exit $? ;;
		-noautostart) disable_psync ; exit $? ;;
		-status)      psync_status  ; exit $? ;;
		-timezone)    set_tz $2     ; exit $? ;;
		-sync)        set_time_from_server ; exit $? ;;
		-h|-help|--help) usage; exit ;;
		-cli|cli) GUI=  ;;
		-gui|gui) export GUI=1 ;;
		*) echo "unknown option: $1" ; usage ; exit 1 ;;
	esac
	shift
done

#==============================================================
#                          CLI
#==============================================================

dlg() {
	local ret file=/tmp/psync$$
	dialog --backtitle "pSync - $(date)" "$@" >/dev/tty 2> $file
	ret=$?
	retstr="$(cat $file)" # can be multiple lines
	rm -f $file
	return $ret
}

msgbox() { dlg --msgbox "$*" 0 0 ; }
infobox() { dlg --infobox "$*" 0 0 ; }

if [ ! "$GUI" ] ; then
	while [ 1 ] ; do
		if psync_status >/dev/null ; then
			st=enabled
		else
			st=disabled
		fi
		zi=$(readlink /etc/localtime | sed 's%/usr/share/zoneinfo/%%')
		eval dlg --menu "'pSync - autostart $st - $zi'" 0 0 0 \
			autostart   "'enable service on bootup'" \
			noautostart "'disable service'" \
			timezone    "'set timezone...'" \
			sync        "'sync to timeserver'" \
			exit "'$(gettext 'Exit')'" || exit
		case $retstr in
			autostart) enable_psync ; sleep 3 ;;
			noautostart) disable_psync ; sleep 3 ;;
			timezone) timezone-set cli ;;
			sync) set_time_from_server ; sleep 5 ;;
			exit) exit ;;
		esac
	done
	exit
fi

#==============================================================
#                          GUI
#==============================================================

export -f enable_psync
export -f disable_psync
export psync_chkbox='
          <checkbox>
          <label>'$(gettext 'Synchronise your clock at each system startup')'</label>
          <default>'${PSYNC_ENABLED}'</default>
          <variable>PSYNC_ENABLED</variable>
          <action>if true enable_psync</action>
          <action>if false disable_psync</action>
        </checkbox>
'

function synchronise_clock() {
	NTP_SERVER='pool.ntp.org' #precaution
	if [ -s "$HOME/.config/psync_server" ] ; then
		read NTP_SERVER < $HOME/.config/psync_server
	fi
	/usr/lib/gtkdialog/box_splash -close never -text "Synchronizing to $NTP_SERVER..." &
	X1PID=$!
	set_time_from_server
	if [ $? -ne 0 ] ; then
		kill $X1PID
		/usr/lib/gtkdialog/box_ok "Psync" error "$(gettext 'Error synchronizing to NTP server')"
		exit 1
	fi
	kill $X1PID
	NEWCURRENT_TIME=`date +%c`
	if which ntpdate &>/dev/null ; then
		secs=`cat /tmp/settertime | tail -2 | grep 'offset'`
		offset=${secs#*offset}
		[ -z "$offset" ] && offset=N/A
		offset_txt='<text use-markup="true"><label>" <b>  Offset was '${offset}'      </b>"</label></text>'
	else
		offset_txt=''
	fi
	#=
	cd $HOME
	export timeis='<window title="Synchronised System Time" icon-name="clock_countdown">
    <vbox>
      <frame Updated Time>
        <text use-markup="true"><label>"<b>'${NEWCURRENT_TIME}'</b>"</label></text>
        <text><label>"       "</label></text>
        '${offset_txt}'
      </frame>
      <frame>
        '${psync_chkbox}'
        <text><label>"       "</label></text>
        <hbox>
          <button space-expand="true" space-fill="true">
            <label>'$(gettext "Exit")'</label>
            '"`/usr/lib/gtkdialog/xml_button-icon quit`"'
            <action>EXIT:quit</action>
          </button>
          <button space-expand="true" space-fill="true">
            <label>'$(gettext "Show main dialog")'</label>
            <action>EXIT:0</action>
          </button>
        </hbox>
      </frame>
    </vbox>
</window>'

    #execute gtkdialog
    eval "$(gtkdialog -c -p timeis)"
    [ "$EXIT" != "0" ] && return 10
}
export -f synchronise_clock
case $1 in synchronise_clock|set)
    shift
    synchronise_clock "$@"
    exit ;;
esac
#=========================================================

#Add services for ntp
if [ ! "`grep 'ntp 123/tcp' /etc/services`" ] ; then
    echo -e "ntp 123/tcp\nntp 123/udp" >> /etc/services
fi

#DST report variables
YEAR=`date +%Y`
#Read hwclock --debug and send to temp file (hwclock --debug is deprecated: https://github.com/abchk1234/timeset/issues/3)
hwclock --help > /tmp/tmp
[ "`grep -- '--verbose' /tmp/tmp 2>/dev/null`" ] && OPTION=verbose || OPTION=debug
hwclock --$OPTION | tail -5 > /tmp/psyncreport 
CURRENT_DATE=`cat /tmp/psyncreport | grep 'Time read from Hardware Clock:' | cut -d " " -f6-` 
CURRENT_HW=`cat /tmp/psyncreport | tail -1 `
CURRENT_TIME=`date +%X%t%Z`
OFF=`date +%z`

help_box() {
    echo  "
<b>GMT-/+ time zones</b>
If you use a GMT timezone with offset then the top line hardware report will show the offset in reverse notation. 
After setting the time there is an option to run Psync automatically at each startup.

<b>Timezone..</b>
Use this to set a proper time zone

<b>Synchronise to time server</b>
For this to work as expected, you should have already selected a proper timezone for your location.

<b>The time is wrong</b>
And more importantly, if the time is wrong.. try not using a GMT* timezone, but a more specific one: America/... Asia/... Africa/... Europe/...

<b>Server</b>
In most cases it's best to use pool.ntp.org to find an NTP server (or 0.pool.ntp.org, 1.pool.ntp.org, etc if you need multiple server names). The system will try finding the closest available servers for you.
" > /tmp/box_help
    /usr/lib/gtkdialog/box_help Psync
}
export -f help_box

combo_servers='
       <comboboxtext width-request="150" space-expand="false" space-fill="false" tooltip-text=" Public time server (/etc/psync.servers) ">
          <variable>PSYNC_SERVER</variable>
'

if [ -s "$HOME/.config/psync_server" ] ; then
	read def < "$HOME/.config/psync_server"
			combo_servers="$combo_servers
<item>${def}</item>"
fi

if [ -f /etc/psync.servers ] ; then
	servers=$(cat /etc/psync.servers)
	if [ "$def" ] ; then
		servers=$(echo "$servers" | grep -v "^${def}$")
	fi
	while read s ; do
		[ -z "$s" ] && continue
		combo_servers="$combo_servers
<item>${s}</item>"
	done <<< "$servers"
fi

combo_servers="$combo_servers
</comboboxtext>"

TZ_REAL=`readlink /etc/localtime | sed -e 's%^.*share/zoneinfo/%%' -e 's%Etc/%%'`
[ -f /usr/sbin/fix_gmt ] && echo "$TZ_REAL" | grep 'GMT[+-]' && TZ_REAL=$(fix_gmt $TZ_REAL)

cd $HOME
MSG_1="<b><span size='"'large'"'>$(gettext "Psync Time Server Synchroniser")</span></b>"
MSG_2="<b>$(gettext "Synchronise clock with time server")</b>"
WELCOME_MSG="<hbox height-request="'"70"'">
    $(/usr/lib/gtkdialog/xml_info scale clock_countdown.svg 45 "$MSG_1" "$MSG_2")
    </hbox>"
export Psync='
<window title="Psync" icon-name="clock_countdown.svg" resizable="false">
 <vbox>
   '${WELCOME_MSG}'

   <frame '$(gettext 'Time Server')'>
   '$combo_servers'

   <hbox space-expand="true" space-fill="true">
     '${psync_chkbox}'
   </hbox>
   </frame>

   <frame '$(gettext 'Clock Status')'>
     <text><label>System Time & Offset to current Hardware Clock</label></text>
     <text use-markup="true"><label>"<b>'${CURRENT_HW}'</b>"</label></text>

     <text><label>" "</label></text>

     <text><label>Hardware Time</label></text>
     <text use-markup="true"><label>"<b>'${CURRENT_DATE}'</b>"</label></text>

     <text><label>" "</label></text>

    <vbox>
     <text><label>Time Zone</label></text>
     <text use-markup="true"><label>"<b>'${TZ_REAL}'</b>"</label></text>

     <text><label>" "</label></text>

     <text><label>True Offset to UTC</label></text>
     <text use-markup="true"><label>"<b>'${OFF}'</b>"</label></text>
    </vbox>
   </frame>

   <hbox space-expand="true" space-fill="true">
      <button>
        '"`/usr/lib/gtkdialog/xml_button-icon help`"'
        <action>help_box &</action>
      </button>

      <button>
         <label>'$(gettext "Timezone...")'</label>
         '"`/usr/lib/gtkdialog/xml_button-icon country_timezone.svg icon`"'
         <action>exit:set_timezone</action>
      </button>
      <button>
         <label>'$(gettext "Synchronise")'</label>
         '"`/usr/lib/gtkdialog/xml_button-icon clock_countdown.svg`"'
         <action>exit:sync</action>
      </button>
      <button>
         '"`/usr/lib/gtkdialog/xml_button-icon quit`"'
         <action>EXIT:quit</action>
      </button>
   </hbox>
 </vbox>
</window>'

#execute gtkdialog
. /usr/lib/gtkdialog/xml_info gtk
eval "$(gtkdialog -c -p Psync --styles=/tmp/gtkrc_xml_info.css)"

if [ "$EXIT" = "set_timezone" ] ; then
	timezone-set
	exec $0
elif [ "$EXIT" = "sync" ] ; then
	if [ "$PSYNC_SERVER" ] ; then
		echo "$PSYNC_SERVER" > "$HOME/.config/psync_server"
	fi
	synchronise_clock
	[ $? -eq 10 ] && exit #quit
	exec $0
fi

### EOF ###
