<?php
// +--------------------------------------------+
// | Utility.php								|
// +--------------------------------------------+
// | Utility functions for @Mail CLI tools		|
// | such as server-install.php					|
// +--------------------------------------------+
// | Copyright CalaCode.com						|
// | Date: May 2006								|
// +--------------------------------------------+

require_once('Apache_Utility.php');

if (!defined('STDOUT'))
{
	// Define stream constants
	define('STDIN', fopen('php://stdin', 'r'));
	define('STDOUT', fopen('php://stdout', 'w'));
    define('STDERR', fopen('php://stderr', 'w'));

   // Close the streams on script termination
   register_shutdown_function(
       create_function('',
       'fclose(STDIN); fclose(STDOUT); fclose(STDERR); return true;')
       );
}

function is_function( &$mixed )
{
    if ( is_object( $mixed ) ) {
        return ( $mixed instanceof Closure );
    } elseif( is_string( $mixed ) ) {
        return function_exists( $mixed );
    } else {
        return false;
    }
}

function prompt($prompt, $default=null, $required=null)
{
	if ($default)
		$prompt .= " [$default]: ";

	fwrite(STDOUT, "\n$prompt");
	$resp = fgets(STDIN);

	$resp = trim($resp);

	$resp = $resp ? $resp : $default;

	if($required and empty($resp))	{
		echo "Please specify a value to continue.\n";
		return prompt($prompt, '', 1);
	}

	return $resp;
}

/**
 * Find where a specified file is on the server
 *
 * @param string $file Filename to locate
 * @return array
 */
function locate($name)
{
	$output = `locate $name`;

	$lines = explode("\n", $output);

	return $lines;
}

/**
 * Find where a specfied command is on the server
 *
 * @param string $command Command to search for
 * @return mixed string|bool
 */
function whereis($command)
{
	// Find where a specified command is on the server
	$line = `whereis -b $command`;
	$line = trim($line);

	if(!isset($line) || empty($line))
		return false;

	$result = explode(' ', $line);
	if (array_key_exists(1, $result) && is_executable($result[1]))
			return $result[1];

	return false;
}


function getProcessUser($proc)
{
	$process = preg_quote(basename($proc));
	$line = `ps aux | grep $process`;

	if (preg_match("/^(.+?)\s+.+?php .*?$process/", $line, $m))
		return $m[1];

	return '';
}

function getUID($user)
{
	if (!$file = @file('/etc/passwd'))
		return false;

	foreach ($file as $line)
	{
		if (preg_match("/^$user:(\d+)/", $line, $m))
			return $m[1];
	}

	return false;
}

function userExists($user)
{
	if (!$file = @file('/etc/passwd'))
		return -1;

	foreach ($file as $line)
	{
		if (preg_match("/^$user:/", $line))
			return 1;
	}

	return 0;
}

function groupExists($group)
{
	if (!$file = @file('/etc/group'))
		return -1;

	foreach ($file as $line)
	{
		if (preg_match("/^$group:/", $line))
			return 1;
	}

	return 0;
}

function makeDirectory($dir, $mode = 0700)
{                                         

	if (is_dir($dir) || @mkdir($dir,$mode))
	{
	
		return TRUE;
		
	}
	return @mkdir($dir,$mode, true);
	
}

function promptWithOptions($command, $prompt, $default=null, $regex=null)
{
	$results = array();
	exec($command, $results);
	$opNum = 1;

	foreach($results as $option)
	{
		if (!empty($regex) && !preg_match($regex, $option))
            continue;

	    $prompt .= "[$opNum]$option\n";
		$opNum++;
	}

	fwrite(STDOUT, "$prompt\n");

	while (true)
	{
		$selection = prompt('Enter choice or the full path: ', $default);

		if ($selection > 0 && $selection <= $opNum)
		{
			return $results[$selection-1];
		}

		clearstatcache();

		if ($selection && is_file($selection))
		{
			return $selection;
		}

		fwrite(STDOUT, "\nInvalid selection or path, try again\n");
	}
}

function createAtmailUser()
{
	if (!userExists('atmail'))
	{
		fwrite(STDOUT, "Creating the atmail user ...\n");
		$useradd = whereis("useradd");

		if ($useradd)
			system("$useradd -D -u 3000 -s bash atmail >/dev/null 2>&1");
		else
			fwrite(STDOUT, "Cannot locate useradd utility. Please create the 'atmail'
			                user manually on your system with UID 3000\n");
	}
}

function returnBytes($val)
{

    $val = trim($val);
    $last = strtolower($val{strlen($val)-1});
    switch($last) 
	{
	
	    // The 'G' modifier is available since PHP 5.1.0
		case 'g':    $val *= 1024*1024*1024;
		case 'm':    $val *= 1024*1024;
		case 'k':    $val *= 1024;
	
	}

	return $val;
	
}

/*
 * Find a binary
*/

function findBinary($searcharray)
{
	// Check for safe mode, otherwise we cannot exec
	if( ini_get('safe_mode') || strtoupper(substr(PHP_OS, 0, 3)) == 'WIN')
	   return;

	// Find where a specified command is on the server
	foreach ( $searcharray as $command)
	{
		$cmd = `whereis -b $command`;
		$cmd = trim($cmd);
		
		if (preg_match('/:\s(.*)\s?/', $cmd, $m))
		{
			return $m[1];
		}
	}

	return '';
}

/**
 * Check if ports are available for use
 * 
 * @param Array|Int $ports ports to check for availability
 * @param String $host host for which to check ports
 * @return Boolean|Array
 */
function checkPortAvailability($ports, $host='localhost')
{
    // If a numeric argument was given for $ports
    // then check if available and return true if yes or false if not
    if (is_numeric($ports)) {
        if ($sock = @fsockopen($host, $ports)) {
            fclose($sock);
            return false;
        }
        
        return true;
        
    } elseif (!is_array($ports)) {
        // If $ports is neither numeric nor an array then return false
        return false;
    }
    
    $results = array();
    foreach ($ports as $p) {
        if ($sock = @fsockopen($host, $p)) {
            fclose($sock);
            $results[$p] = false;
        } else {
            $results[$p] = true;
        }
    }
    
    return $results;
}

function editIni($setting, $value='', $prepend=null)
{

	$phpIniPath = '';
	$phpIni = '';

	// find where php.ini is if need be
	if( function_exists('php_ini_loaded_file') && php_ini_loaded_file() !== false )
	{
		
		$phpIniPath = php_ini_loaded_file();
		
	}   
	else
	{
		
		$phpIniLine = strip_tags(`php -i | grep php.ini`);
		$lastSpace = strrpos( $phpIniLine, ' ');
		$phpIniPath = trim(substr( $phpIniLine, $lastSpace));
		
	}
	if( substr($phpIniPath, -7) != 'php.ini' )
	{
		if( substr( $phpIniPath, -1) != DIRECTORY_SEPARATOR )
		{
		
			$phpIniPath .= DIRECTORY_SEPARATOR;
			
		}
		$phpIniPath .= "php.ini";
		
	}
	
	if( file_exists($phpIniPath) )
	{
	
		$phpIni = file($phpIniPath);

	}
	else
	{

		return false;

	}	
	$altered = false;

	// Now look for setting to alter
	if( !empty($value) )
	{

		foreach ($phpIni as $num => $line)
		{

			// If prepend is set but we find the setting already
			// then set $altered to true
			if($prepend && trim($line) == "$setting = $value")
			{

				$altered = true;
				break;

			}

			if( !$prepend && preg_match("/^(.*?)($setting\s*=)/", $line, $m) )
			{

				// we dont really want to alter examples in php.ini
				// so we will be cautious and only alter uncommented
				// lines or lines where the setting directly comes after
				// a ; with no spaces
				if(empty($m[1]) || $m[1] == ';')
				{

					$phpIni[$num] = "$setting = $value\n";
					$altered = true;
					break;

				}

			}

		}

	}

	// If the setting was not found we will need to add it
	if( !$altered )
	{

		if( !empty($value) )
		{
		
			$setting .= " = $value";
			
		}

		foreach ($phpIni as $num => $line)
		{

			// I guess the easiest place to put settings is directly after
			// the opening of the PHP section ??
			if(trim($line) ==  '[PHP]')
			{

				$phpIni[$num] = $line . "\n; added by Atmail\n$setting\n";
				$altered = true;
				break;

			}

		}

		if(!$altered)
		{
		
			return false;

		}
		
	}

	// Only go ahead if backup of current php.ini OK
	if( copy($phpIniPath, $phpIniPath . '.atmail.bak') )
	{

		// make $phpIni back into a string and get its size
		$newIni = implode('', $phpIni);
		$size = strlen($newIni);
		$fh = fopen($phpIniPath, 'w');

		if( $fh )
		{

			// Make sure we write the entire string, if not
			// restore from backup and return false
			if( fwrite($fh, $newIni) !== $size )
			{

				rename($phpIniPath . 'atmail.bak', $phpIniPath);
				return false;

			}

			// no errors encountered
			fclose($fh);
			return true;
		}

	}

	// If we got here something went wrong
	return false;

}

function callStackPrint($stacktrace) 
{
	file_put_contents("php://stderr", str_repeat("=", 50) ."\n");
	$i = 1;
	foreach($stacktrace as $node) {
		$className = isset($node['class'])? $node['class'] . "::" : "";
		file_put_contents("php://stderr", "$i. " . $className .$node['function']. "()\n\t\t\t\t\t\t\t" .basename($node['file']) .":" .$node['line'] .  "\n" );
		$i++;
	}
} 