<?php
/**
 * @category 	Atmail
 * @package 	Application
 * @subpackage	Bootloader
 * @copyright 	Copyright (c) 2009-2011 ATMAIL. All rights reserved
 * @license 	See http://atmail.com/license.php for license agreement
 * @author		Atmail (http://atmail.com)
 */

error_reporting (0); //switch off error reporting until we set it to correct level later on in this file
error_reporting (E_ALL); //switch off error reporting until we set it to correct level later on in this file


if( array_key_exists('SessionID',$_REQUEST) )
{	
	session_id($_REQUEST['SessionID']);
}

//Start timer for checking how long hits take
define('DEBUG_START_MT', microtime(true) );

// define the namespaces in use
define('ATMAIL_ADMIN_NAMESPACE', 'atmail6_admin');
define('ATMAIL_NAMESPACE', 'atmail6');

// ensure timezone set correctly
$script_tz = date_default_timezone_get();

// ensure timezone set correctly
@date_default_timezone_set('GMT');

// Set to php.ini timezone setting if it is different
// and not blank
$ini_tz = ini_get('date.timezone');
if( $ini_tz != '')
{

	@date_default_timezone_set($ini_tz);

}

// Error reporting - To turn on debugging, set Config.debug=1 in the SQL DB:
//
// mysql> update Config set keyValue = 1 where keyName = 'debug' and section = 'global';
//
// If it doesn't yet exist, insert a new row:
//
// mysql> insert into Config (section, keyName, KeyValue, keyType) values ('global', 'debug', '1', 'Boolean');

// Allocate a maximum of 512M of RAM - Tweak as per your server requirements
ini_set('memory_limit', '512M');

// Limit PHP processing to 3 minutes CPU time - Terminate the thread otherwise
set_time_limit(180);

if( function_exists('mb_internal_encoding') ) 
{
	mb_internal_encoding('UTF-8');
}

if( function_exists('mb_regex_encoding') ) 
{
	mb_regex_encoding('UTF-8');
}

// Check iconv exists, otherwise display the error message in the Web-installer
if(function_exists("iconv_set_encoding"))	
{
	iconv_set_encoding("internal_encoding", "UTF-8");//setting gave grief at some point, i suspect it was surrounding Lucene, but needed for ZF mime header decoding. this doesnt work, possible because conflicts with php.ini setting
	iconv_set_encoding("input_encoding", "BASE-64");
	iconv_set_encoding("output_encoding", "UTF-8");
}

//Site application root and paths
//all references to directories have / appended to eliminate posibility of direcory reference composition resulting in '/....' as in root 
//i.e. when composing a directory string, all components dont/cant/wont start with a / eliminating the possibility if a resulting string referring to OS root
define('APP_ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR);
set_include_path(APP_ROOT . ';' .
				 APP_ROOT . 'library' . DIRECTORY_SEPARATOR . ';' .
				 APP_ROOT . 'library' . DIRECTORY_SEPARATOR . 'Pear' . DIRECTORY_SEPARATOR . ';' .
				 APP_ROOT . 'application/models/' . ';' .
				 APP_ROOT . 'calendar'. DIRECTORY_SEPARATOR . 'lib' . ';' .
				 APP_ROOT . 'sso'. DIRECTORY_SEPARATOR . 'phpseclib'
);

// Detect if we are installed
if ( !file_exists(APP_ROOT .'config/dbconfig.ini') || !file_exists(APP_ROOT .'.installed') ) {
    header('Location: install/index.php');
}

require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
//$loader->registerNamespace('App_'); //for model namespacing
$loader->setFallbackAutoloader(true);
$loader->suppressNotFoundWarnings(false);
                                  
//HTMLPURIFIER prefix needed for HTMLfilter plugin
define('HTMLPURIFIER_PREFIX', APP_ROOT . 'library');

$siteBaseUrl = substr($_SERVER["SCRIPT_NAME"],0,strpos($_SERVER["SCRIPT_NAME"],'index.php'));
	
Zend_Registry::set( 'siteBaseUrl', $siteBaseUrl );

//Load general functions
Zend_Loader::loadFile('Atmail/General.php', null, true);
Zend_Loader::loadFile('Atmail/Password.php', null, true);
Zend_Loader::loadFile('Atmail/RenderHelpers.php', null, true);
Zend_Loader::loadFile('Atmail/Exception.php', null, true);

try
{

	$dbConfig = new Zend_Config_Ini( APP_ROOT . 'config/dbconfig.ini', 'production');
	Zend_Registry::set('dbConfig', $dbConfig);

}
catch(Exception $e)
{

	if(isset($_SERVER['REQUEST_URI']) && strstr($_SERVER['REQUEST_URI'], "default/index/dberror") == null)
	{
		$error = $e->getMessage();
		include( APP_ROOT . 'application/modules/default/views/scripts/index/dberror.phtml');
		exit();
	}

}
$dbAdapter = dbAdapterFactory($dbConfig);
$dbConfig = Zend_Registry::get('dbConfig');
Zend_Db_Table::setDefaultAdapter($dbAdapter);
Zend_Registry::set('dbAdapter', $dbAdapter);
class TimeoutHandlerPlugin extends Zend_Controller_Plugin_Abstract
{
	public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
	{
		try
		{
			if($request->getModuleName() == 'admin')
			{	
				session_name(ATMAIL_ADMIN_NAMESPACE);
				$session = new Zend_Session_Namespace(ATMAIL_ADMIN_NAMESPACE);
				if( isset($session->timeout) && (int)time() > (int)$session->timeout )
				{
					$session->timeout = 0;
					Zend_Auth::getInstance()->clearIdentity();
					$session->Username = null;
					$session->Password = null;
					Zend_Session::expireSessionCookie();
					session_destroy();
					
				}
				else
				{
					
					$global = Zend_Registry::get('config')->global;
					if( !isset( $global['session_timeout'] ) )
					{
					
						$global['session_timeout'] = 3600;	
					
					}
					
					$session->setExpirationSeconds($global['session_timeout'] * 60);
					$session->timeout = time() + $global['session_timeout'] * 60;
				
				}
				
			}
			else
			{

				$specialSessionHandling = array(
					array(
						'module' => 'mail',
						'controller' => 'calendar',
						'action' => 'alarms'
					),
					array(
						'module' => 'mail',
						'controller' => 'mail',
						'action' => 'listfoldermessages',
						'params' => array('refresh' => 'true')
					)
				);

				$sessionUpdate = true;

				$currentRequest = array(
					'module' => $request->getModuleName(),
					'controller' => $request->getControllerName(),
					'action' => $request->getActionName()
				);

				foreach($specialSessionHandling as $specialRequest)
				{
					$testRequest =
						array(
							'module' => $specialRequest['module'],
							'controller' => $specialRequest['controller'],
							'action' => $specialRequest['action']
						);
					if(in_array($testRequest, array($currentRequest)))
					{
						$paramsOk = true;
						// see if we need to check params
						if(array_key_exists('params', $specialRequest))
						{
							$testParams = $request->getParams();
							$paramsOk = false;
							foreach($specialRequest['params'] as $testKey => $testParam)
							{
								if(array_key_exists($testKey, $testParams) && $testParams[$testKey] == $testParam)
								{
									$paramsOk = true;
								}
							}
						}
						$sessionUpdate = $paramsOk ? false : true;
					}
				}

                // todo:dtb: add session domain

                $currentCookieParams = session_get_cookie_params();

                $hostName = $_SERVER["SERVER_NAME"];
                $hostNameArr = explode('.', $hostName);
                $hostNameCount = count($hostNameArr);

                $rootDomain = '';

                if ($hostNameCount > 2)
                {
                    for ($i = 1; $i < $hostNameCount; $i++)
                    {
                        $rootDomain .= '.' . $hostNameArr[$i];
                    }
                }
                else
                {
                    $rootDomain = $hostName;
                }

                session_set_cookie_params(
                    $currentCookieParams["lifetime"],
                    $currentCookieParams["path"],
                    $rootDomain,
                    $currentCookieParams["secure"],
                    $currentCookieParams["httponly"]
                );




                session_name(ATMAIL_NAMESPACE);
				$session = new Zend_Session_Namespace(ATMAIL_NAMESPACE);

                $monkey = session_get_cookie_params();

				// clear the identity of a user who has not accessed a controller for
				// longer than a timeout period.
				
				// SKIP TIMEOUT CHECK IF USER IS SENDING EMAIL!!
				if (($request->getControllerName() != 'composemessage' && $request->getActionName() != 'send') && isset($session->timeout) && time() > $session->timeout)
				{
					
					Zend_Session::expireSessionCookie();
					Zend_Auth::getInstance()->clearIdentity();
					
				}
				else if($sessionUpdate)
				{
				// User is still active - update the timeout time.
					$global = Zend_Registry::get('config')->global;
					//$session->setExpirationSeconds($global['session_timeout'] * 60);
					$session->timeout = time() + ($global['session_timeout'] * 60);
					
					// Store the request URI so that an authentication after a timeout
					// can be directed back to the pre-timeout display.  The base URL needs to
					// be stripped off of the request URI to function properly.
					$session->requestUri = substr($this->_request->getRequestUri(), strlen(Zend_Controller_Front::getInstance()->getBaseUrl()));

                    $monkey = session_get_cookie_params();


                }
			}
		
		}
		catch ( Exception $e )
		{
		}
	}
} 


//Get main configuration from database
$config = new Atmail_Config_Mysql($dbConfig, true);
Zend_Registry::set('config', $config);


/**
 * this function will overwrite the session.gc_maxlifetime only when it lower than the timeout setting
 * and keep unchanged when greater than timeout setting
 * @param timeout: session_time value in seconds
 */
function adjust_gc_maxlifetime()
{

	$global = Zend_Registry::get('config')->global;
	$timeout = isset( $global['session_timeout'] )? $global['session_timeout'] * 60 : 3600;

	$gcTimeout = min($timeout, 7200);

	if( ini_get('session.gc_maxlifetime') < $gcTimeout ) {
		// file_put_contents('php://stderr', "\nWARNING session.gc_maxlifetime is lower than atmail settings, please adjust it in php.ini, overwritten here\n");
		ini_set('session.gc_maxlifetime', $gcTimeout);
	}
}

adjust_gc_maxlifetime();


try
{
	/* Setup logs */
	$log = new Atmail_Log();
	$log->addPriority('atmail', 10);
	$log->addPriority('sysadmin', 20);
	$log->addPriority('imap', 30);
	$log->addPriority('firebug', 40);

	$logBasePath = APP_ROOT . 'log' . DIRECTORY_SEPARATOR;
	//log errors by default even if not set in config
	//INTENTION: log all priority < INFO
	$errorLogging = ( isset( Zend_Registry::get('config')->global['errorLogging'] )? Zend_Registry::get('config')->global['errorLogging']:true);
	if( $errorLogging == true || $errorLogging == 'true' || $errorLogging == 1 )
	{
		$logPath = $logBasePath . 'error.log';
		if( !file_exists($logPath))
			touch($logPath);
		$writer = new Zend_Log_Writer_Stream($logPath);
		$filter = new Zend_Log_Filter_Priority(Zend_Log::INFO, '<'); //will only log entries to this log that are < INFO
		$writer->addFilter($filter);
		$log->addWriter($writer);
	}
	// main debug log (no filters set so will log everything) - other logs also for more specific logging
	//Only enabled if config debug == true
	//INTENTION: only log priority == DEBUG
	//INTENTION: only log priority == FIREBUG - i.e. use this to send errors to browser if they are ajax or XML (as in the RPC calls) so that it doesnt mess up the normal responce
	//To switch debug logging (log/debug.log) on:
	// INSERT INTO `Config` (`section` ,`keyName` ,`keyValue` ,`keyType`) VALUES ( 'global', 'debug', '1', 'Boolean');

	ini_set('html_errors', 0);	// ensure html errors are turned off
	$debugLogging = ( isset(Zend_Registry::get('config')->global['debug'])? Zend_Registry::get('config')->global['debug']:false);
	if( $debugLogging == true || $debugLogging == 'true' || $debugLogging == 1 )
	{
		//Error reporting - To turn on debugging, set Config.debug=1 in the SQL DB
		error_reporting(E_ALL);
		ini_set('display_startup_errors', 1);
		ini_set('display_errors', 1);

		//no filters set so will log everything
		$logPath = $logBasePath . 'debug.log';
		if( !file_exists($logPath))
			touch($logPath);
		$writer = new Zend_Log_Writer_Stream($logPath);
		$filter = new Zend_Log_Filter_Priority(Zend_Log::INFO, '>='); //will only log entries to this log where priority >= INFO
		$filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG, '<='); //will only log entries to this log where priority <= DEBUG
		$writer->addFilter($filter);

		$log->addWriter($writer);
		$log->debug('');
		$log->debug('------------------------------');
		$log->debug('Hit starting up: ' . time());

		//we also set up a logger to log things to firebug console for debugging ajax, RPC, XML responces so that debug content doesnt mess with the body
		//set up a logger to log things to firebug console for debugging ajax, RPC, XML responces so that debug content doesnt mess with the body
		$writer = new Zend_Log_Writer_Firebug();
		$filter = new Zend_Log_Filter_Priority(40, '=='); //will only log entries to this log where priority == DEBUG
		$writer->addFilter($filter);
		$log->addWriter($writer);
	}
	else
	{
		//switch off conventional error displaying if debug dissabled
		//error_reporting(0);
		ini_set('display_startup_errors', 0);
		ini_set('display_errors', 0);
	}
	//log IMAP communication only if enabled in config
	//INTENTION: log only where priority == IMAP
	//To switch IMAP logging (log/imap.log) on:
	// INSERT INTO `Config` (`section` ,`keyName` ,`keyValue` ,`keyType`) VALUES ( 'global', 'imapLogging', '1', 'Boolean');
	$imapLogging = (isset(Zend_Registry::get('config')->global['imapLogging'])? Zend_Registry::get('config')->global['imapLogging']:false);
	if( $imapLogging == true || $imapLogging == 'true' || $imapLogging == 1 )
	{

		$logPath = $logBasePath . 'imap.log';
		define('IMAP_LOG_PATH', $logPath); //needed by imap debug shutdown logging, because registry gets shut down before imap connection being logged
		if( !file_exists($logPath))
			touch($logPath);
		try
		{
			$writer = new Zend_Log_Writer_Stream($logPath);
			$filter = new Zend_Log_Filter_Priority(30, '=='); //will only log entries to this log that are == IMAP
			$writer->addFilter($filter);
			$log->addWriter($writer);
		}
		catch (Exception $e)
		{
		}
	}

	//log sysAdmin communication on by default unless diasbled in Config
	//INTENTION: log only where priority == SYSADMIN e.g. quota warnings, login failures (with reasons)
	$sysAdminLogging = (isset(Zend_Registry::get('config')->global['sysAdminLogging'])? Zend_Registry::get('config')->global['sysAdminLogging']:true);
	if( $sysAdminLogging == true || $sysAdminLogging == 'true' || $sysAdminLogging == 1 )
	{

		$logPath = $logBasePath . 'sysadmin.log';
		if( !file_exists($logPath))
			touch($logPath);
		try
		{
			$writer = new Zend_Log_Writer_Stream($logPath);
			$filter = new Zend_Log_Filter_Priority(20, '=='); //will only log entries to this log that are == SYSADMIN
			$writer->addFilter($filter);
			$log->addWriter($writer);
		}
		catch (Exception $e)
		{

		}
	}
	Zend_Registry::set('log', $log);
}
catch(Exception $e)
{
	echo "<html><title>Whoops!</title><header>Whoops!</header><body>There was a fatal error accessing the log directory. Please ensure that the webmail/log directory is writable by the webserver user.</body></html>";
	return;
}
/* log setup complete */

$locale = new Zend_Locale();
Zend_Registry::set('Zend_Locale', $locale);

$frontController = Zend_Controller_Front::getInstance();
Zend_Controller_Action_HelperBroker::addPrefix('Atmail_Controller_Action_Helper');

// register plugin for determining which authentication handler to use
$frontController->registerPlugin(new Atmail_Controller_Plugin_Authenticate);

// register plugin for determining session save handler
$frontController->registerPlugin(new Atmail_Controller_Plugin_SessionSaveHandler);

// create a plugin to handle moving session timeout
$frontController->registerPlugin(new TimeoutHandlerPlugin);

$frontController->throwExceptions(false); 
$frontController->addModuleDirectory(APP_ROOT . 'application/modules');


// todo:dtb: rest stuff
$restRoute = new Zend_Rest_Route($frontController, array(), array('inbox'));

// $restRoute = new Zend_Rest_Route($frontController, array(), array('inbox' => array('Test', 'Account', 'Contact', 'EmailAttachment', 'EmailBody', 'Email', 'EmailHeader', 'Envelope', 'Group', 'ImapFolder', 'Message', 'Settings')));
//$restRoute = new Zend_Rest_Route($frontController, array(), array('default' => array('UploadAPI', 'LocationMatchesAPI', 'GetMatchesByIdAPI', 'AuthAPIController')  ));

$frontController->getRouter()->addRoute('rest', $restRoute);






// Load Plugins (new method, only load once DB updated to at least 6.1.6)
if ($config->global['allowPlugins'] && version_compare($config->global['version'], '6.1.6', '>=')) {
    
    // Get the requested module. The request object has not
    // yet been created so we cannot use
    // $frontController->getRequest()->getModuleName()
    if (isset($_SERVER['REQUEST_URI']) && preg_match('/\/index\.php\/(admin|mail|api|mobile)/i', $_SERVER['REQUEST_URI'], $m)) {
        $module = $m[1];    
    } else {
        // default to mail
        $module = 'mail';    
    }
    
    $loaded = array();
    
    foreach (plugins::getEnabled($module) as $p) {
		
		$path = APP_ROOT . "application/modules/{$p['module']}/plugins";
		$className = "{$p['company']}_{$p['name']}_Plugin";
		if (in_array($className, $loaded)) {
			continue;
		}
		
        $myPath = "$path/{$p['company']}/{$p['name']}";
        if (file_exists("$myPath/Plugin.php")) {
        
	        try {
                include_once("$myPath/Plugin.php");
          
    	        $plugin = new $className;
    	        if ($plugin instanceof Atmail_Controller_Plugin) {
    	    		$frontController->registerPlugin($plugin);
    			}
    			
    			// insert into the $loaded array so we don't
    			// load same plugin more than once
    			$loaded[$className] = 1;
	        } catch (Zend_Exception $e) { }

	    }
    }
}

$writer = new Zend_Log_Writer_Firebug(); 
$logger = new Zend_Log($writer); 

unset($config);
unset($settings);

Zend_Registry::set('ATMAIL_UNIT_TESTING',0);

$siteBaseUrl = Zend_Registry::get('siteBaseUrl');
$appBaseUrl = rtrim($siteBaseUrl, '/') . (strpos($siteBaseUrl,'index.php')?'':'/index.php');
$cookie_path = '';


if (isset($_SERVER['REQUEST_URI']) && preg_match('/\/index\.php\/(admin|mail|api|mobile)/i', $_SERVER['REQUEST_URI'], $m) && isset($m[1]) && $m[1] == 'admin') {
	$module = $m[1];
	$cookie_path = rtrim($appBaseUrl, '/') . '/' . $module;
}
else
{
	// unable to detect site url, lets use a wider one
	$cookie_path = ($siteBaseUrl != '/' ? rtrim($siteBaseUrl, '/') : '/');
}

Zend_Session::setOptions(array('cookie_path' => $cookie_path));
