<?php 


/**
 * file: network_settings.php
 *
 * Copyright Miller Electric Mfg. Co. as an unpublished work.
 * All rights reserved.
 *
 * The information contained herein is confidential property of
 * Miller Electric Mfg. Co.  The use of, copying, transfer or
 * disclosure of such information is prohibited except by express
 * written agreement with Miller Electric.
 */


class NetworkInterfaceInformation {
	public $name = "";
	public $ipAddress = array();
	public $dhcp = "";
	public $subnetMask = array();
	public $numberOfSubnetMaskBits = 0;
	public $gateway = array();
	public $macAddress = "";
	public $dnsServer = array();
	public $isDnsSet = false;


	public static function fromInterfaceName(string $inName): NetworkInterfaceInformation {
		$info = new NetworkInterfaceInformation();
		$info->populate($inName);
		return $info;
	}


	private function populate(string $inName): void {
		$this->name = $inName;
		$this->setInterfaceIpAddress();
		$this->setInterfaceDhcp();
		$this->setInterfaceGateway();
		$this->setInterfaceMacAddress();
		$this->setInterfaceSubnetMask();
		$this->setInterfaceDNSServerAddress();
	}


	/**
	 * Populates the IP address of this object's interface.
	 * If no address was found, populates the IP address with
	 * an invalid one, containing at least one -1 in the octet
	 * array.
	 */
	private function setInterfaceIpAddress(): void {
		$this->ipAddress = [ -1, -1, -1, -1 ];
		$shellResult = shell_exec("ip address show " . $this->name . " | awk '/inet\\>/ {print $2}' | awk -F/ '{print $1}'");
		$explodedResult = explode(".", $shellResult);
		for ($i = 0; $i < count($explodedResult); $i++) { 
			$this->ipAddress[$i] = intval($explodedResult[$i]);
		}
	}


	private function setInterfaceDhcp(): void {
		$shellResult = shell_exec("cat /etc/network/interfaces | grep iface | awk '/" . $this->name . "/ {print $4}'");
		$shellResult = trim($shellResult);
		if ($shellResult === "dhcp") {
			$this->dhcp = "dynamic";
		} else {
			$this->dhcp = "static";
		}
	}


	private function setInterfaceGateway(): void {
		$this->gateway = [ 0, 0, 0, 0 ];
		$shellResult = shell_exec("ip route | awk '/default/ {print}' | awk '/" . $this->name . "/ {print $3}'");
		if($shellResult != NULL)
		{
			$explodedResult = explode(".", $shellResult);
			for ($i = 0; $i < count($explodedResult); $i++) { 
				$this->gateway[$i] = intval($explodedResult[$i]);
			}
		}
	}


	private function setInterfaceMacAddress(): void {
		$shellResult = shell_exec("ip addr show " . $this->name . " | awk '/ether/ {print $2}'");
		$this->macAddress = $shellResult;
	}


	private function setInterfaceSubnetMask(): void {
		$this->subnetMask = [ 0, 0, 0, 0 ];

		// To get the subnet mask...
		// Get the number of bits from the ip address's CIDR notation 
		// x.x.x.x/<this number>.
		$numberOfBitsString = shell_exec("ip address show " . $this->name . " | awk '/inet\\>/ {print $2}' | awk -F/ '{print $2}'");
		$this->numberOfSubnetMaskBits = intval($numberOfBitsString);

		// Apply the bitmask to an array of 4 bytes representing the ip address's 
		// octets.
		$subnetMaskSize = 4;
		$i = $subnetMaskSize - 1;
		$numberOfBitsPerByte = 8;
		$tmpNumberOfBits = $this->numberOfSubnetMaskBits;
		while ($tmpNumberOfBits > 0)
		{
			// If there are at least 8 bits left to mask,
			// mask the whole octet.
			if ($tmpNumberOfBits >= $numberOfBitsPerByte)
			{
				$this->subnetMask[$subnetMaskSize  - $i - 1] = 0xFF;
				$tmpNumberOfBits -= $numberOfBitsPerByte;
			}
			else
			{
				// Otherwise, if there are less than 8 bits left
				// to mask, mask them starting with the most
				// significant bit. Then we are done.
				$bits = 0;
				for ($j = 0; $j < $tmpNumberOfBits; $j++)
				{
					$mask = 0x80;
					$bits |= $mask >> $j;
				}
				
				$this->subnetMask[$subnetMaskSize  - $i - 1] |= $bits;
				$tmpNumberOfBits = 0;
			}

			$i--;
		}
	}


	private function setInterfaceDNSServerAddress(): void {
		$this->dnsServer = [ 0, 0, 0, 0 ];
		$shellResult = shell_exec("grep " . $this->name . " -A5 /etc/network/interfaces | awk '/dns-nameservers/ {print $2}'");
		if($shellResult != NULL)
		{
			$explodedResult = explode(".", $shellResult);

			$this->isDnsSet = (count($explodedResult) === 4);

			// If the DNS nameserver for this interface is in the interfaces file, set it.
			if ($this->isDnsSet) {
				for ($i = 0; $i < count($explodedResult); $i++) { 
					$this->dnsServer[$i] = intval($explodedResult[$i]);
				}
			} else {
				// Otherwise, get the nameservers from resolv.conf.
				$shellResult = shell_exec("cat /etc/resolv.conf | awk '/nameserver/ {print $2}'");

				// Convert each DNS entry into an array of strings of their addresses.
				$splitResult = preg_split('/\s+/', $shellResult);

				// Look for a DNS entry that has the same high octet.
				$foundMatchingHighOctet = false;
				$i = 0; 
				while (!$foundMatchingHighOctet && $i < count($splitResult)) {
					$explodedResult = explode(".", $splitResult[$i]);
					
					// If this is the first entry, default to it.
					if ($i == 0) {
						for ($j = 0; $j < count($explodedResult); $j++) { 
							$this->dnsServer[$j] = intval($explodedResult[$j]);
						}
					}

					// Compare the high octet.
					if ($this->ipAddress[0] == intval($explodedResult[0])) {
						$foundMatchingHighOctet = true;

						for ($j = 0; $j < count($explodedResult); $j++) { 
							$this->dnsServer[$j] = intval($explodedResult[$j]);
						}
					}

					$i++;
				}
			}
		}
	}
}


$Info_filespec = "/Insight/system.info";
$Config_filespec = "/Insight/devicePage2SBC.conf";
$NetworkSettings = ReadSettings($Info_filespec);
$ConfigSettings = ReadSettings($Config_filespec);
//echo "Stored NetworkSettings:<br>";
//print_r($NetworkSettings);

$NetworkSettings = MergePostSettings($Info_filespec, $NetworkSettings);


function MergePostSettings($filespec, $settings)
{
	// Check if new settings have been submitted
	if(!empty($_POST))
	{
		// echo "<br>Post:<br>";
		// print_r($_POST);
		$File = fopen($filespec, "w");
		if($File == NULL)
		{
			echo "Error opening " . $filespec . "<br>";
		}
		else
		{
			// Combine stored settings with new post
			if(!empty($settings))
			{
				$settings = array_merge($settings, $_POST);
			}
			else
			{
				$settings = $_POST;
			}
			
			$settings["SettingsApplied"] = "false";
			
			// Convert network settings to JSON
			$settings_json = json_encode($settings);
			
			fwrite($File, $settings_json);
			fwrite($File, "\n\n");
			fflush($File);
			fclose($File);
		}
		// Clear the file stats cache since we will re-read the file.  Not clearing
		// the stat cache will cause filesize() to report the value from the previous
		// call to ReadNetworkSettings()
		clearstatcache();
		$settings = ReadSettings($filespec);
		// echo "<br>Merged Settings:<br>";
		// print_r($settings);
	}
	return $settings;
}

function ReadSettings($filespec)
{
	// Read network settings
	$errorLvl = get_cfg_var('display_errors');
	error_reporting($errorLvl);

	$NetworkSettings_json = file_get_contents($filespec);

	$Settings = json_decode($NetworkSettings_json, true);

	return $Settings;
}

function UpdateSBCSettings()
{
	$Config_filespec = "/Insight/devicePage2SBC.conf";
	$stored = ReadSettings($Config_filespec);

	// Check if new settings have been submitted
	if(!empty($_POST))
	{
		// echo "<br>Post:<br>";
		// print_r($_POST);
		$File = fopen($Config_filespec, "w");
		if($File == NULL)
		{
			echo "Error opening " . $Config_filespec . "<br>";
		}
		else
		{
			$settings = $_POST;
			
			// ------------- WiFi Settings
			
			// Remove DHCP fields if DHCP is dynamic
			if(array_key_exists('WiFiDHCP', $settings) && $settings['WiFiDHCP'] == 'dynamic')
			{
				unset($settings['WiFiIP']);
				unset($settings['WiFiSubnet']);
				unset($settings['WiFiGateway']);
			}
			// Remove DNS fields if DNS is dynamic
			if(array_key_exists('WiFiDNS', $settings) && $settings['WiFiDNS'] == 'dynamic')
			{
				unset($settings['WiFiDNSAddr']);
			}
			
			// Remove Encryption field if not WPA or WPA2
			if(array_key_exists('Authentication', $settings) && 
				!($settings['Authentication'] == "WPA" || $settings['Authentication'] == "WPA2"))
			{
				unset($settings['Encryption']);
			}

			// ------------- Ethernet Settings
			// Remove DHCP fields if DHCP is dynamic
			if(array_key_exists('EthDHCP', $settings) && $settings['EthDHCP'] == 'dynamic')
			{
				unset($settings['EthIP']);
				unset($settings['EthSubnet']);
				unset($settings['EthGateway']);
			}
			// Remove DNS fields if DNS is dynamic
			if(array_key_exists('EthDNS', $settings) && $settings['EthDNS'] == 'dynamic')
			{
				unset($settings['EthDNSAddr']);
			}
			
			// ------------- Store Settings
			
			// Combine stored settings with new post
			if(!empty($stored))
			{
				$settings = array_merge($stored, $settings);
			}
			
			// Convert network settings to JSON
			$settings_json = json_encode($settings, JSON_PRETTY_PRINT);
			
			fwrite($File, $settings_json);
			fwrite($File, "\n\n");
			fflush($File);
			fclose($File);
		}
	}
}
