#!/bin/bash
#
# (C) Copyright 2018-2026, Bogen Communications LLC. All rights reserved.
#
# This script is used to set the Linux system clock in one of two ways: ntp or man.
#
# If the ntp parameter is passed, the script expects a valid IP address for the NTP server.
#
# If the man parameter is passed, the script will update the Linux system clock based on 
# the date and time provided.
# 
# Usage:
#   clock_set sync HH:MM:SS (used by I/O Controller Sync-Clock action)
#   clock_set ntp <ip address>
#   clock_set man <dd> <month> <yyyy> <hh> <mm> <ss>
#   clock_set timezone <system_timezone>
#   clock_set dhcp_override <enable | disable>
#   clock_set current
# 
# To manually set NTP Server:
#   clock_set ntp <ip address>
#
# To manually set date/time
#   clock_set man <dd> <month> <yyyy> <hh> <mm> <ss>
#
# To manually sync time
#   clock_set sync HH:MM:SS (24-hour military time)
#
#    The month parameter must be:
#    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
#
# Change TIMEZONE:
#   clock_set timezone <system_timezone>
#
#   where system_timezone is one of the predefined timezones recognized by Linux
#
#     examples:
#       America/New_York
#       Asia/Calcutta
#       Canada/Atlantic
#       Europe/London
#
# *IMPORTANT NOTE*
#  The only way the timezone parameter will "stick" is if you source this script:
#    source ./clock_set timezone America/New_York
#      or
#    . ./clock_set timezone America/New_York
#
# Set NTP Servers via DHCP;
#   clock_set dhcp_override <enable | disable>
#
#     enable -  causes Nyquist to rely on DHCP server to define NTP servers and
#               time services. The user will have no other control over system
#               time parameters.
#     disable - The user will be able to manually set the system time, or
#               specify the preferred NTP server.
#
# If "current" is chosen, this script will return the current NTP server being used.
#
# Modified for Debian 10
#

type=$1
paramnum="$#"

CONF_FILE=/etc/ntpsec/ntp.conf

check_num_parameters()
{
        # Exit if number of parameters are incorrect
        expectedparamnum=$1
        if [ "$paramnum" -ne $expectedparamnum ]; then
                echo "Expected $expectedparamnum arguments - exiting"
                exit 1
        fi
}


is_ipv4_address()
{
        case "$1" in
                *[!0-9.]*|"")
                        return 1
                        ;;
        esac

        IFS='.' read -r o1 o2 o3 o4 <<EOF
$1
EOF

        for octet in "$o1" "$o2" "$o3" "$o4"; do
                if [ -z "$octet" ] || [ "$octet" -lt 0 ] || [ "$octet" -gt 255 ] 2>/dev/null; then
                        return 1
                fi
        done

        [ -n "$o1" ] && [ -n "$o2" ] && [ -n "$o3" ] && [ -n "$o4" ]
}

is_ipv6_address()
{
        case "$1" in
                *:*)
                        return 0
                        ;;
                *)
                        return 1
                        ;;
        esac
}

is_pool_name()
{
        NTP_NAME="$1"

        # IP addresses are single servers, not pools.
        if is_ipv4_address "$NTP_NAME" || is_ipv6_address "$NTP_NAME"; then
                return 1
        fi

        # Treat common NTP pool DNS names as pools.
        # Examples:
        #   pool.ntp.org
        #   0.pool.ntp.org
        #   1.us.pool.ntp.org
        #   us.pool.ntp.org
        #   north-america.pool.ntp.org
        case "$NTP_NAME" in
                pool.ntp.org|*.pool.ntp.org)
                        return 0
                        ;;
        esac

        return 1
}

#
# Manually sync server time
#
if [ "$type" = "sync" ]; then
        check_num_parameters 2
        date --set="$2"
	/usr/local/bin/run_server_cmd restart-cron
	/usr/local/bin/schedule_events

	exit 0
fi

#
# Manually set NTP server
#
if [ "$type" = "ntp" ]; then
        check_num_parameters 2

	NTP_SERVERS="$2"

	# Convert comma-separated input to space-separated input.
	NTP_SERVERS="${NTP_SERVERS//,/ }"

	systemctl stop ntpd

	mkdir -p /var/log/ntpsec
	chown ntpsec:ntpsec /var/log/ntpsec
	chmod 775 /var/log/ntpsec

	sed -i \
	    -e 's/\<nopeer\>[[:space:]]*//g' \
	    -e 's/\<notrap\>[[:space:]]*//g' \
	    -e '/^[[:space:]]*tos[[:space:]]\+minclock/d' \
	    -e '/^server 127\.127\.1\.0$/d' \
	    -e '/^fudge 127\.127\.1\.0 stratum 10$/d' \
	    -e '/^[[:space:]]*#/!{/^[[:space:]]*statsdir[[:space:]]/s/^/#/}' \
	    -e '/^[[:space:]]*#/!{/^[[:space:]]*statistics[[:space:]]/s/^/#/}' \
	    -e '/^[[:space:]]*#/!{/^[[:space:]]*filegen[[:space:]]\+loopstats/s/^/#/}' \
	    -e '/^[[:space:]]*#/!{/^[[:space:]]*filegen[[:space:]]\+peerstats/s/^/#/}' \
	    -e '/^[[:space:]]*#/!{/^[[:space:]]*filegen[[:space:]]\+clockstats/s/^/#/}' \
	    "$CONF_FILE"

	# Provide current local time as a default if Internet/server connection is lost
	grep -q '^refclock local stratum 10$' "$CONF_FILE" || \
		echo 'refclock local stratum 10' >> "$CONF_FILE"

        # sntp can accept one or more servers/hostnames.
        sntp --timeout=5 -s $NTP_SERVERS 2>/dev/null
        SNTP_RC="$?"

        if [ "$SNTP_RC" -eq 0 ]; then
                # Remove existing time sources and unwanted tos minclock line.
                sed -i \
                        -e '/^[[:space:]]*server[[:space:]]/d' \
                        -e '/^[[:space:]]*pool[[:space:]]/d' \
                        -e '/^[[:space:]]*tos[[:space:]]\+minclock/d' \
                        "$CONF_FILE"

                for NTP_SERVER in $NTP_SERVERS
                do
                        if is_pool_name "$NTP_SERVER"; then
                                echo "pool $NTP_SERVER iburst" >> "$CONF_FILE"
                        else
                                echo "server $NTP_SERVER iburst" >> "$CONF_FILE"
                        fi
                done

                echo "Time set correctly from NTP server"
        elif [ "$SNTP_RC" -eq 1 ]; then
                echo "SNTP Error -- Operation Failed."
        elif [ "$SNTP_RC" -eq 2 ]; then
                echo "SNTP Parameter Error -- A parameter passed to this function is invalid."
        else
                echo "SNTP Unknown Error"
        fi

	# Copy ntpsec conf file to old ntp conf file location
	cp "$CONF_FILE" /etc/ntp.conf

	#
	# Tell NetworkManager's ntp dispatcher script that we want to
	# manually configure NTP servers, not use DHCP configured NTP.
	#
	touch /var/opt/nyquist/use-manual-ntp

	# Tell ntpsec to ignore NTP servers from DHCP
	sed -i "s/IGNORE_DHCP.*/IGNORE_DHCP=\"yes\"/" /etc/default/ntpsec

	systemctl restart ntpd

	/usr/local/bin/schedule_events

	exit 0
fi

#
# Manually set date/time
#

if [ "$type" == "man" ]; then
        check_num_parameters 7
        date --set="$2 $3 $4 $5:$6:$7"
	/usr/local/bin/run_server_cmd restart-cron
	/usr/local/bin/schedule_events

	exit 0
fi

#
# Set system timezone
#
if [ "$type" == "timezone" ]; then
	/usr/local/bin/run_server_cmd update-tzdata > /dev/null 2>&1
        check_num_parameters 2
        sed -i '1s|^.*$|'$2'|' /etc/timezone
	ln -sfn /usr/share/zoneinfo/$2 /etc/localtime
	export TZ=$2
	if [ -f "/usr/bin/timedatectl" ]; then
		timedatectl set-timezone $2
	fi
	/usr/local/bin/run_server_cmd restart-cron
	/usr/local/bin/schedule_events
	/usr/local/bin/update-voicemail-conf --tz system

	exit 0
fi

if [ "$type" == "dhcp_override" ]; then
        check_num_parameters 2
        ntp_conf_dhcp_dir="/var/lib/ntp"
        ntp_exit_hook_dir="/etc/dhcp/dhclient-exit-hooks.d"
        ntp_conf_dhcp_file="$ntp_conf_dhcp_dir/ntp.conf.dhcp"
        ntp_conf_dhcp_backup="$ntp_conf_dhcp_file".backup
	ntp_exit_hook_file="$ntp_exit_hook_dir/ntp"
	ntp_exit_hook_backup="$ntp_exit_hook_file".backup
        dhclient_loc="/etc/dhcp/dhclient.conf"

        if [ "$2" == "enable" ]; then
                if grep -q ntp-servers $dhclient_loc; then
                        echo "NTP servers are already being configured via DHCP"
                else
                        echo "Adding ntp-servers to $dhclient_loc"
                        sed -i 's/request /request ntp-servers, /g' $dhclient_loc  
                fi
                if [ -f "$ntp_conf_dhcp_backup" ]; then
			echo "Restoring $ntp_conf_dhcp_backup to $ntp_conf_dhcp_file"
			mv $ntp_conf_dhcp_backup $ntp_conf_dhcp_file
                else
			if [ -f "$ntp_conf_dhcp_file" ]; then
	                       	echo "$ntp_conf_dhcp_file is already present"
			else
				echo "$ntp_conf_dhcp_file does not exist"
			fi
                fi

		if [ -f "$ntp_exit_hook_backup" ]; then
                        echo "Restoring $ntp_exit_hook_backup to $ntp_exit_hook_file"
                        mv $ntp_exit_hook_backup $ntp_exit_hook_file
                else
                        if [ -f "$ntp_exit_hook_file" ]; then
                                echo "$ntp_exit_hook_file is already present"
                        else
                                echo "$ntp_exit_hook_file does not exist"
                        fi
                fi

		#
		# Tell NetworkManager's ntp dispatcher script that we want to
		# configure NTP servers via DHCP, not manually.
		#
		rm -f /var/opt/nyquist/use-manual-ntp > /dev/null 2>&1
		sed -i "s/IGNORE_DHCP.*/IGNORE_DHCP=\"\"/" /etc/default/ntpsec

		/sbin/ifdown -a --exclude=lo > /dev/null 2>&1 ;sleep 1;/sbin/ifup -a > /dev/null 2>&1

		/usr/bin/nmcli networking off > /dev/null 2>&1 ;sleep 2;nmcli networking on > /dev/null 2>&1
		/usr/local/bin/add-mcast-route -b
		/sbin/ifup lo > /dev/null 2>&1

		systemctl restart ntp > /dev/null 2>&1

		/usr/local/bin/schedule_events

        elif [ "$2" == "disable" ]; then
                sed -i 's/, ntp-servers;/;/g;s/ntp-servers, //g' $dhclient_loc
                echo "Removing ntp-servers from $dhclient_loc"
		if [ -f "$ntp_conf_dhcp_file" ]; then
                        echo "Renaming $ntp_conf_dhcp_file to $ntp_conf_dhcp_backup"
                        mv $ntp_conf_dhcp_file $ntp_conf_dhcp_backup
                else
                       echo "$ntp_conf_dhcp_file does not exist"
                fi


		if [ -f "$ntp_exit_hook_file" ]; then
                        echo "Renaming $ntp_exit_hook_file to $ntp_exit_hook_backup"
                        mv $ntp_exit_hook_file $ntp_exit_hook_backup
                else
                       echo "$ntp_exit_hook_file does not exist"
                fi

		/sbin/ifdown -a --exclude=lo > /dev/null 2>&1 ;sleep 1;/sbin/ifup -a > /dev/null 2>&1
		/usr/bin/nmcli networking off > /dev/null 2>&1 ;sleep 2;nmcli networking on > /dev/null 2>&1
		/sbin/ifup lo > /dev/null 2>&1

		sed -i \
		    -e 's/\<nopeer\>[[:space:]]*//g' \
		    -e 's/\<notrap\>[[:space:]]*//g' \
		    -e '/^[[:space:]]*tos[[:space:]]\+minclock/d' \
		    -e '/^server 127\.127\.1\.0$/d' \
		    -e '/^fudge 127\.127\.1\.0 stratum 10$/d' \
		    -e '/^[[:space:]]*#/!{/^[[:space:]]*statsdir[[:space:]]/s/^/#/}' \
		    -e '/^[[:space:]]*#/!{/^[[:space:]]*statistics[[:space:]]/s/^/#/}' \
		    -e '/^[[:space:]]*#/!{/^[[:space:]]*filegen[[:space:]]\+loopstats/s/^/#/}' \
		    -e '/^[[:space:]]*#/!{/^[[:space:]]*filegen[[:space:]]\+peerstats/s/^/#/}' \
		    -e '/^[[:space:]]*#/!{/^[[:space:]]*filegen[[:space:]]\+clockstats/s/^/#/}' \
		    "$CONF_FILE"

		# Provide current local time as a default if Internet/server connection is lost
		grep -q '^refclock local stratum 10$' "$CONF_FILE" || \
			echo 'refclock local stratum 10' >> "$CONF_FILE"

		#
		# Tell NetworkManager's ntp dispatcher script that we want to
		# manually configure NTP servers, not use DHCP configured NTP.
		#
		touch /var/opt/nyquist/use-manual-ntp

		sed -i "s/IGNORE_DHCP.*/IGNORE_DHCP=\"yes\"/" /etc/default/ntpsec

		systemctl restart ntpd

		/usr/local/bin/add-mcast-route -b

		/usr/local/bin/schedule_events
        fi

	exit 0
fi

#
# Return current NTP server IP address
#
if [ "$type" == "current" ]; then

	NTP_IP="$(ntpq -pn|awk '/^\*/ {print substr($1,2);}' -)"
	NTP_NAME="$(ntpq -pw|awk '/^\*/ {print substr($1,2);}' -)"

	if [ "$NTP_IP" != "" ]; then
		echo "<br>Current NTP Server: $NTP_IP<br>Current NTP Server Name: $NTP_NAME"
	else
		echo "<br>Current NTP Server: not syncronized, refresh screen to update"
	fi
else
        echo First argument must be ntp, man, timezone, dhcp_override, or current
fi
