<?php
/**
 * Update script
 * Note : This script needs to run as a root user from the console
 *
 * @category 	Atmail
 * @package 	Server/Client Installer/Update
 * @subpackage 	Server/Client Update
 * @copyright 	Copyright (c) 2009-2011 ATMAIL. All rights reserved
 * @license 	See http://atmail.com/license.php for license agreement
 * @author 		Atmail (http://atmail.com)
 */
// ***************** setup php ********************* //
// give the script some ram! and some cpu ime; remove php time limit
error_reporting(E_ALL ^ (E_NOTICE|E_WARNING) );
ini_set('memory_limit', -1);
set_time_limit(0);
date_default_timezone_set("GMT");

define('LOG_NONE', 0);
define('LOG_INFO', 1);
define('LOG_DEBUG', 2);

checkSTDIO();

// ***************** INCLUDES ********************* //
// detect and set working directory for client / server installation
detectInstalledVersionLocation();
require('bootloader.php');
require_once('library/Atmail/Update.php');
require_once('library/Atmail/Deps/DepCheck.php');
require_once 'application/models/dbTables.php';
$dbAdapter = Zend_Registry::get('dbAdapter');
require_once 'application/models/config.php';

// ***************** INSTALLER VARIABLE SETUP ********************* //
$USEDEFAULTS = ''; 		# Set to 1 to use default responses where possible
$phpVersion = PHP_VERSION;
$phpOS = PHP_OS;
$global = Zend_Registry::get('config')->global;
$exim = Zend_Registry::get('config')->exim;
$dovecot = Zend_Registry::get('config')->dovecot;
$defaultUserSettings = Zend_Registry::get('config')->defaultUserSettings;
$client = ($dbAdapter->fetchOne('select keyValue from Config where keyName="install_type"') == 'server' ? false : true);
$dbVersion = $dbAdapter->fetchOne('select keyValue from Config where keyName="version"');
$cliVersion = $dbAdapter->fetchOne('select keyValue from Config where keyName="cli.version"');

// ***************** process usage/cli ********************* //
$failure = '';
try
{
	$opts = processCLIArgs($argv);
}
catch (Exception $e)
{
	$failure = $e->getMessage();
}

if(!isset($opts['version']) && $cliVersion == '')
{
	$failure = "Latest version already installed!\n\n";
}

else if (!isset($opts['version']))
{
	$opts['version'] = $cliVersion;	
}

if($failure != '')
{
	exit("\nAtmail Update Script\nUsage: [server/client]-update.php [force_version] [options]\n\n[force_version] : To re-run update scripts from a previous version\n\n[options]\n--force : force run script, ignoring sanity tests.\n\n\n********************\nError : " . $failure . "\n");	
}

/********* CHECK RUNNING FROM CLI AND ROOT ************/
if(!$opts['force'] && (!checkCLI() || ($rootTest = checkROOT()) !== true))
{
	if($rootTest == -2)
	{
		if(prompt("This script must be run from the console as root.\n*** It appears that the required php posix extension is not installed so this script cannot detect if root is in use.\nIf you are sure you are root type 'yes' to continue or re-run this script with --force", 'no') != 'yes')
		{
			exit("FATAL: This script must be run from the console as root.\nPlease su to root, and consult the installation details for further information..\n");		
		}
	}	
	else
	{
		exit("FATAL: This script must be run from the console as root.\nPlease su to root, and consult the installation details for further information..\n");
	}
}

$versionCurrentlyConfigured = $opts['version'] == 'fetch' ? '' : generateVersionString($opts['version'], true);

// If we're an appliance, and RPMEligibleAppliance
$tmpDownloadLocation = APP_ROOT . 'tmp/';
$downloadFilename = "atmail-mailserver.el6.x86_64.rpm";
//$logFilename = "download.log";
$isAppliance = false;
$isRPMEligibleAppliance = false;
$RPMUnpacked = false;
if( file_exists("/usr/local/atmail/mailserver/bin/atmail-update-version") )
{
	
	$isAppliance = true;

	$os = getOperatingSystemInfo();

	if($os['brand'] == 'CentOS' && version_compare($os['version'], '6.0', '>=') ) {

		$isRPMEligibleAppliance = true;

	}


}

//if appliance then unpack existing rpm (uploaded in previous step)
if( $isRPMEligibleAppliance )
{
	
	echo "RPM found.\nUpdating from RPM.\n";
	passthru("yum -y update " . $tmpDownloadLocation . $downloadFilename);//,$lines); //only unpacks the binaries and application files (no recompile necessary for appliance)
	//echo implode("\n", $lines);
	$RPMUnpacked = true;
	//ince RPM unpacked, this file will proceed so care must be taken that update.php does not get modified with update dependencies when unpacking new version
	
}
else if( $isAppliance && $opts['version'] == 'fetch')
{
	$server_source_dir = '../server_source/scripts/applicance/';
	$retries = 4;
	while(!is_dir(real_path($server_source_dir)) && $retries--)
	{
		$server_source_dir = '../' . $server_source_dir;
	}
	if(is_dir(real_path($server_source_dir)))
	{
		exec('php ' . real_path($server_source_dir) . '/fetchLatestVersion.php');
	}
	else
	{
		//something went wrong
		echo "Unable to find " . real_path($server_source_dir) . "/fetchLatestVersion.php";	
	}
	exit();
}

// ********** UPDATE SETUP ************* //
$versionCurrentLocalCodebase = generateVersionString($dbVersion, true);
$versionCurrentLocalCodebaseStr = generateVersionString($versionCurrentLocalCodebase);

// Display the welcome message
$msg = <<<EOF

\033[1;32mWelcome to Atmail {$versionCurrentLocalCodebaseStr} Update script\033[0;39m
-----------------------------------

PHP Version: {$phpVersion}
Operating System: {$phpOS}

This script will update Atmail for your system

When requesting your input during the installation the default values are
presented within square brackets -- to choose the default value, hit "Enter"

EOF;

echo $msg;

if($client)
{
	echo "Client detected.\n";
}

_sanityCheckInstallation($versionCurrentlyConfigured, $versionCurrentLocalCodebase);

echo "Atmail is checking package dependancies, please standby\n\n";
// call the dep checker
check_deps($_SERVER['argv'], true);

if(file_exists('./webmail/library/Atmail/.mysqlrestart'))
{
	unlink('./webmail/library/Atmail/.mysqlrestart');
	$mysqlrestart = 1;
}

// depcheck has already complained to the user, lets just exit
if( $mysqlrestart )
{

	exit(1);

}

echo "Updating Atmail " . $versionCurrentLocalCodebaseStr . ", please standby\n\n";
echo "Shutting down Atmail services.\n";
_controlServerServices(false);

//we only need to run the intermediate (and required (creates Config->cli.version ) ) db update if in RPM Appliance mode
if( $isRPMEligibleAppliance )
{

	echo "Initiating database update.\n";

	$Atmail_Update_Db = new Atmail_Update_Db($dbAdapter);
	// set the log file for this update attempt (trunc)
	//$dbUpdateLogFilename = rtrim(APP_ROOT . 'log', '/') . '/atmail.dbupdate.log';
	$Atmail_Update_Db->setLogFile("php://stdout");
	$cliRequired = false;
	try
	{

		$cliRequired = $Atmail_Update_Db->updateAll();
		echo "Database update is complete.\n";
	
	}
	catch(Exception $e)
	{

		// some sort of error.
		$error = true;
		$Atmail_Update_Db->log( "Database update ran into issues while trying to update to". $versionCurrentLocalCodebaseStr . ": Error details : " . $e->getMessage() );
		exit();

	}
}
else
	$cliRequired = true;

//if the DB update complete, then we need to run the cli update.
if( $cliRequired )
{

	echo "Initiating CLI update.\n";
	$updater = new Atmail_Update_Cli($dbAdapter, $client);

	$updater->setLogFile("php://stdout");
	try
	{
		
		$updater->updateAll();
		echo "CLI update is complete.\n";
		
	}
	catch(Exception $e)
	{

		// some sort of error.
		$error = true;
		$Atmail_Update_Db->log( "CLI update ran into issues while trying to update to". $versionCurrentLocalCodebaseStr . ": Error details : " . $e->getMessage() );
		exit();
	}
}
else
	echo "No CLI update required.\n";

echo "Restarting atmail services.\n";
_controlServerServices(true);

$versionCurrentLocalCodebaseStr = $versionCurrentLocalCodebase;

// Display the success message
$msg = <<<EOF


\033[1;32mSuccessfully updated Atmail {$versionCurrentLocalCodebaseStr} \033[0;39m

If you pick up any bugs or other problems with the new update please create a support ticket at:

http://atmail.com/ticketing/ - Login with your existing account and password.

The Atmail team.

EOF;

echo $msg;

function detectInstalledVersionLocation()
{
	// detects and corrects cwd to root/webmail
	if(is_file('./.VERSION'))
	{
		return getcwd();
	}
	else if(is_file('../.VERSION'))
	{
		chdir('../');
	}
	else if(is_file('../../.VERSION'))
	{
		chdir('../../');
	}
	else if(is_file('../../../.VERSION'))
	{
		chdir('../../../');
	}
	else if(is_file('webmail/.VERSION'))
	{
		chdir('webmail');
	}
	else if(is_file('/var/www/html/atmail/webmail/.VERSION'))
	{
		chdir('/var/www/html/atmail/webmail');
	}
	else if(is_file('/usr/local/atmail/webmail/.VERSION'))
	{
		chdir('/usr/local/atmail/webmail');
	}
	set_include_path(get_include_path() . PATH_SEPARATOR . getcwd());

	return getcwd();
}

function checkSTDIO()
{
	// If we don't have the STDOUT, STDIN, STDERR constants defined
	// as we should in CLI environment then define them
	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 checkCLI()
{
	return ( PHP_SAPI == 'cli' );
}

function checkROOT()
{
	//TODO: detect CPanel installations running as apache - may need specific changes
	if( function_exists('posix_getpwuid') && function_exists('posix_getuid'))
	{
		$currentUser = posix_getpwuid(posix_getuid());
		if( $currentUser['name'] != 'root' )
		{
			return -1;
		}
	} elseif ( !empty($_SERVER['LOGNAME']) && $_SERVER['LOGNAME'] == 'root') {

	} elseif ( trim(`whoami`) == 'root') {
		
	} elseif ( `id -u` != "0" ) {
	} else
	{
		return -2;
	}

	return true;
}

function processCLIArgs($arguments)
{
	$opts = array( 'force' => false, 'dryrun' => false, 'loglevel' => LOG_INFO );
	array_shift($arguments);
	foreach($arguments as $key=>$arg)
	{
	    if (strpos($arg,'-')===0)
	    {
	        switch($arg)
	        {
	        	case '--force' :
	        		$opts['force'] = true;
	        	break;
	            case '--dry-run' :
	                $opts['dryRun'] = true;
	            break;
	            case '-v' :
	                $opts['logLevel'] = LOG_INFO;
	                break;
	            case '-vv' :
	                $opts['logLevel'] = LOG_DEBUG;
	                break;
	            default :
	                throw new Exception('Unknown option: ' . $arg);
			}
	    }
	    else
	    {
	        $opts['version'] = $arg;
	    }
	}
	return $opts;
}
