<?php



/**
* Mambo basic error object
*/
define ('_MOS_ERROR_INFORM', 0);
define ('_MOS_ERROR_WARN', 1);
define ('_MOS_ERROR_SEVERE', 2);
define ('_MOS_ERROR_FATAL', 3);

/**
 * Enter description here...
 *
 */
class mosError {
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $text = '';
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $level = 0;

    /**
     * Enter description here...
     *
     * @param unknown_type $text
     * @param unknown_type $level
     * @return mosError
     */
    function mosError ($text='', $level=_MOS_ERROR_INFORM) {
        $this->text = $text;
        $this->level = $level;
    }
}

/**
* Mambo group of errors for some particular operation
*/
class mosErrorSet {
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $errors = array();
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $maxlevel = 0;

    // Parameter is an error object
    /**
     * Enter description here...
     *
     * @param unknown_type $error
     */
    function addError ($error) {
        $this->errors[] = $error;
        if ($error->level > $this->maxlevel) $this->maxlevel = $error->level;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $text
     * @param unknown_type $level
     */
    function addErrorDetails ($text='', $level=_MOS_ERROR_INFORM) {
        $error = new mosError($text, $level);
        $this->addError($error);
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function &getErrors () {
        return $this->errors;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function getMaxLevel () {
        return $this->maxlevel;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function getCount () {
        return count($this->errors);
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $errorset
     */
    function mergeAnother ($errorset) {
        $this->errors = array_merge($this->errors, $errorset->errors);
    }

}


/* This is the new error handler to store errors in the database
class mosErrorHandler {
var $types = array (
E_STRICT => 'Strict check',
E_USER_WARNING => 'User Warning',
E_USER_NOTICE => 'User Notice',
E_WARNING => 'Warning',
E_NOTICE => 'Notice',
E_CORE_WARNING => 'Core Warning',
E_COMPILE_WARNING => 'Compile Warning',
E_USER_ERROR => 'User Error',
E_ERROR => 'Error',
E_PARSE => 'Parse error',
E_CORE_ERROR => 'Core Error',
E_COMPILE_ERROR => 'Compile Error'
);

function mosErrorHandler () {
set_error_handler(array(&$this, 'handler'));
}

function handler ($errno, $errstr, $errfile, $errline, $errcontext) {
if ($errno = E_STRICT) return;
$string = $this->types[$errno].': '.$errstr.' in '.$errfile.' at '.$errline;
$database =& mamboDatabase::getInstance();
if (eregi('^(sql)$', $errstr)) {
$extra = $database->getErrorMsg();
}
if (function_exists('debug_backtrace')) {
foreach(debug_backtrace() as $back) {
if (@$back['file']) {
$extra .= "\n".$back['file'].':'.$back['line'];
}
}
}
$database->setQuery("DELETE FROM #__errors WHERE file=$errfile AND line=$errline AND number=$errno");
$database->query();
$database->setQuery("INSERT INTO #__errors VALUES (0, $errno, '$errfile', $errline, '$string', '$extra')");
$database->query();
}
}
*/

/**
 * Enter description here...
 *
 */
class mamboCore {
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $rootPath = '';
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $Itemid = 0;
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $option = '';
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $subdirectory;
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $current_user = null;
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $do_gzip_compress = false;
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $init_errorlevel = 0;

    /**
     * Enter description here...
     *
     * @return mamboCore
     */
    function mamboCore () {
        global $adminside;
        $this->init_errorlevel = error_reporting(0);
        //$this->rootPath = str_replace('\\', '/', realpath(str_replace('includes', '', dirname(__FILE__))));
        $this->rootPath = str_replace('\\', '/',str_replace('includes', '', dirname(__FILE__)));
        $this->checkConfig();
        $this->Itemid = mosGetParam($_REQUEST, 'Itemid', 0);
        $this->getConfig();
        $this->fixLanguage();
        @set_magic_quotes_runtime( 0 );
        if (@$this->mosConfig_error_reporting > 0 OR @$this->mosConfig_error_reporting ===0) error_reporting($this->mosConfig_error_reporting);
        else error_reporting($this->init_errorlevel);
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function &getMamboCore () {
        static $instance;
        if (!is_object($instance)) $instance = new mamboCore();
        return $instance;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function rootPath () {
        //if (realpath($this->rootPath) === false) die ('Invalid program load path');
        if (file_exists($this->rootPath) === false) die ('Invalid program load path');
        return $this->rootPath;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $property
     * @return unknown
     */
    function get ($property) {
        $config =& mamboCore::getMamboCore();
        if ($property == 'mosConfig_absolute_path') {
            //if (realpath($config->mosConfig_absolute_path) === false) die ('Invalid program load path');
            if (file_exists($config->mosConfig_absolute_path) === false) die ('Invalid program load path');
            else return $config->rootPath;
        }
        if (isset($config->$property)) return $config->$property;
        trigger_error("Invalid property ($property) requested from mamboCore");
        return null;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $property
     * @return unknown
     */
    function is_set ($property) {
        $config =& mamboCore::getMamboCore();
        return isset($config->$property);
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $property
     * @param unknown_type $value
     * @return unknown
     */
    function set ($property, $value) {
        $config =& mamboCore::getMamboCore();
        $config->$property = $value;
        $GLOBALS[$property] = $value;
        return $value;
    }

    /**
     * Enter description here...
     *
     */
    function checkConfig () {
        // checks for configuration file, if none found loads installation page
        if (!file_exists($this->rootPath.'/configuration.php') OR filesize($this->rootPath.'/configuration.php') < 10 ) {
            header( 'Location: installation/index.php' );
            exit();
        }
    }

    /**
     * Enter description here...
     *
     */
    function getConfig () {
        global $adminside;
        $code = '';
        $f = @fopen($this->rootPath.'/configuration.php','rb');
        if ($f) {
            while ($f AND !feof($f)) {
                $line = fgets($f);
                $altered = str_replace('$', '$this->', $line);
                if ($altered != $line) $code .= $altered;
            }
        }
        else {
            #header( 'Location: installation/index.php' );
            exit();
        }
        fclose($f);
        eval($code);


        if (isset($_SERVER['DOCUMENT_ROOT']) AND strlen($_SERVER['DOCUMENT_ROOT'])) {
            $docroot = str_replace('\\', '/', str_replace('\\\\', '\\', $_SERVER['DOCUMENT_ROOT']));
        }
        else {
            // Find information about where execution started
            $origin = array_pop(debug_backtrace());
            // Find the PHP script at the start, with a fix for Windows slashes
            $absolutepath = str_replace('\\', '/', $origin['file']);
            $localpath = $_SERVER['PHP_SELF'];
            $docroot = substr($absolutepath,0,strpos($absolutepath,$localpath));
        }
        $mamboroot = str_replace('\\', '/', rtrim($this->rootPath, '\/'));
        $this->subdirectory = substr($mamboroot, strlen($docroot));

        $scheme = isset($_SERVER['HTTP_SCHEME']) ? $_SERVER['HTTP_SCHEME'] : ((isset($_SERVER['HTTPS']) AND strtolower($_SERVER['HTTPS'] != 'off')) ? 'https' : 'http');
        if (isset($_SERVER['HTTP_HOST'])) {
            $withport = explode(':', $_SERVER['HTTP_HOST']);
            $servername = $withport[0];
            if (isset($withport[1])) $port = ':'.$withport[1];
        }
        elseif (isset($_SERVER['SERVER_NAME'])) $servername = $_SERVER['SERVER_NAME'];
        else trigger_error(T_('Impossible to determine the name of this server'), E_USER_ERROR);
        if (!isset($port) AND !empty($_SERVER['SERVER_PORT'])) $port = ':'.$_SERVER['SERVER_PORT'];
        if (isset($port)) {
            if (($scheme == 'http' AND $port == ':80') OR ($scheme == 'https' AND $port == ':443')) $port = '';
        }
        else $port = '';
        $afterscheme = '://'.$servername.$port.$this->subdirectory;
        //$this->mosConfig_live_site = $this->mosConfig_secure_site = $scheme.$afterscheme;
        $this->mosConfig_unsecure_site = 'http'.$afterscheme;
        $this->mosConfig_absolute_path = $this->rootPath;
        preg_match_all('/\$this\-\>([A-Za-z_][A-Za-z0-9_]*)/', $code, $matches);
        foreach ($matches[1] as $match) $GLOBALS[$match] = $this->$match;
        if (!isset($this->mosConfig_register_globals)) {
            $this->mosConfig_register_globals = 0;
            $GLOBALS['mosConfig_register_globals'] = 0;
        }

    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function getFavIcon () {
        // favourites icon
        if (!isset($this->mosConfig_favicon)) $this->mosConfig_favicon = 'favicon.ico';
        if (!file_exists($this->rootPath.'/images/'.$this->mosConfig_favicon)) $this->mosConfig_favicon = 'favicon.ico';
        return $this->mosConfig_live_site.'/images/'.$this->mosConfig_favicon;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $user
     * @param unknown_type $database
     */
    function offlineCheck (&$user, &$database) {
        if ($this->mosConfig_offline OR file_exists($this->rootPath.'/installation/index.php')) {
            require_once($this->rootPath().'/administrator/includes/admin.php');
            session_name(md5($this->mosConfig_live_site));
            session_start();
            $session =& mosSession::getCurrent();
            $my =& new mosUser();
            $my->getSessionData();
            if (mosSession::validate($my)) return;
            include("$this->mosConfig_absolute_path/offline.php");
            exit();
        }
    }

    /**
     * Enter description here...
     *
     */
    function fixLanguage () {
        require_once($this->mosConfig_absolute_path.'/includes/phpgettext/phpgettext.class.php');
        require_once($this->mosConfig_absolute_path.'/includes/phpgettext/error.php');
        require_once($this->mosConfig_absolute_path.'/includes/mambofunc.php');
        require_once($this->mosConfig_absolute_path.'/includes/mambolanguage.class.php');
        #error_reporting(E_ALL)        ;
        ##########  DEPRECATED ############
        if (isset($this->mosConfig_lang) AND $this->mosConfig_lang);
        else $this->set('mosConfig_lang', 'english');
        $language_file = "$this->mosConfig_absolute_path/language/$this->mosConfig_lang.php";
        if (file_exists($language_file)) require_once ($language_file);
        ###################################


        $this->mosConfig_lang = mosGetParam($_POST, 'user_lang', $this->mosConfig_lang);


        $language =& new mamboLanguage($this->mosConfig_lang, $this->rootPath.'/language/');
        $languages = $language->getLanguages();
        $charset = $language->get('charset');
        $dateformat = $language->get('dateformat');
        $this->current_language = $language;
        if (!defined('_ISO')) DEFINE('_ISO','charset='.$charset);
        if (!defined('_DATE_FORMAT_LC')) DEFINE('_DATE_FORMAT_LC', $dateformat); //Uses PHP's strftime Command Format
        if (!defined('_DATE_FORMAT_LC2')) DEFINE('_DATE_FORMAT_LC2', $dateformat);


    }

    /**
     * Enter description here...
     *
     */
	function handleGlobals () {
        $superglobals = array($_SERVER, $_ENV, $_FILES, $_COOKIE, $_POST, $_GET);
        if (isset( $_SESSION )) array_unshift ( $superglobals , $_SESSION );

        // Emulate register_globals on
        if (!ini_get('register_globals') && $this->mosConfig_register_globals) {
            while(list($key,$value)=each($_GET)) {
                if (!isset($GLOBALS[$key])) $GLOBALS[$key]=$value;
            }
            while(list($key,$value)=each($_POST)) {
                if (!isset($GLOBALS[$key])) $GLOBALS[$key]=$value;
            }
        }
        // Emulate register_globals off
        elseif (ini_get('register_globals') && !$this->mosConfig_register_globals) {
            foreach ( $superglobals as $superglobal ) {
                foreach ( $superglobal as $key => $value) {
                    unset( $GLOBALS[$key]);
                    unset( $GLOBALS[$key]);
                }
            }
        }
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function determineOptionAndItemid () {
        $this->Itemid = mosGetParam($_REQUEST, 'Itemid', 0);
        if ($option = strtolower(mosGetParam($_REQUEST, 'option')));
        else {
            $menuhandler =& mosMenuHandler::getInstance();
            $menus =& $menuhandler->getByParentOrder($this->Itemid, 'mainmenu');
            $this->Itemid = $menus[0]->id;
            $_REQUEST['Itemid'] = $this->Itemid;
            $link = $menus[0]->link;
            $pos = strpos( $link, '?' );
            if ($pos !== false) $link = substr( $link, $pos+1 ). '&Itemid='.$this->Itemid;
            parse_str( $link, $temp );
            /** this is a patch, need to rework when globals are handled better */
            foreach ($temp as $k=>$v) $_GET[$k] = $v;
            if (isset($temp['option'])) $option = $temp['option'];
            else return '';
        }
        /** patch to lessen the impact on templates */
        if ($option == 'search') $option = 'com_search';
        // checking if we can find the Itemid thru the component
        if ($this->Itemid === 0) {
            if ( $option == 'com_content') {
                require_once($this->rootPath().'/components/com_content/content.class.php');
                $handler =& contentHandler::getInstance();
                $this->Itemid = $handler->getItemid(mosGetParam($_REQUEST, 'id', 0 ));
                $_REQUEST['Itemid'] = $this->Itemid;
            }
            else {
                $menuhandler =& mosMenuHandler::getInstance();
                $this->Itemid = $menuhandler->getIdLikeLink("index.php?option=$option");
                if ($this->Itemid === 0) {
                    $menuhandler =& mosMenuHandler::getInstance();
                    $menus =& $menuhandler->getByParentOrder($this->Itemid, 'mainmenu');
                }
            }
        }
        return $option;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $url
     * @param unknown_type $msg
     */
    function redirect ($url, $msg='') {
        $callcheck = array('InputFilter', 'process');
        if (!is_callable($callcheck)) require_once(mamboCore::get('mosConfig_absolute_path').'/includes/phpInputFilter/class.inputfilter.php');
        // specific filters
        $iFilter =& new InputFilter();
        $url = $iFilter->process( $url );
        $message = trim($iFilter->process($msg));
        if ($iFilter->badAttributeValue(array('href', $url))) $url = mamboCore::get('mosConfig_live_site');
        if ($message) {
            if (strpos($url, '?')) $url .= '&mosmsg='.urlencode($message);
            else $url .= '?mosmsg='.urlencode($message);
        }
        if (headers_sent()) echo "<script>document.location.href='$url';</script>\n";
        else {
            @ob_end_clean(); // clear output buffer
            header( "Location: $url" );
        }
        exit();
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $text
     */
    function logMessage ($text) {
        // JS Popup message
        if (mosGetParam( $_POST, 'message', 0 )) {
			?>
			<script type="text/javascript">
			<!--//
			alert( "<?php echo $text; ?>" );
			//-->
			</script>
			<?php
        }
        if ($return = mosGetParam( $_REQUEST, 'return', '' )) {
            $this->redirect( $return );
        }
        else {
            $this->redirect( $this->mosConfig_live_site.'/index.php' );
        }
    }

    /**
     * Enter description here...
     *
     */
    function handleLogin () {
        require_once($this->rootPath().'/includes/authenticator.php');
        $authenticator =& mamboAuthenticator::getInstance();
        $loggedin = $authenticator->loginUser();
        if ($loggedin) $this->logMessage('_LOGIN_SUCCESS');
        else mamboCore::redirect('index.php');
    }

    /**
     * Enter description here...
     *
     */
    function handleLogout () {
        require_once($this->rootPath().'/includes/authenticator.php');
        $authenticator =& mamboAuthenticator::getInstance();
        $authenticator->logoutUser();
        $this->logMessage('_LOGOUT_SUCCESS');
    }

    /**
     * Enter description here...
     *
     */
    function standardHeaders () {
        header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
        header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' );
        header( 'Cache-Control: no-store, no-cache, must-revalidate' );
        header( 'Cache-Control: post-check=0, pre-check=0', false );
        header( 'Pragma: no-cache' );
        $mambothandler =& mosMambotHandler::getInstance();
        $mambothandler->loadBotGroup('system');
        $mambothandler->trigger('onHeaders', array($this));
    }

    /**
     * Enter description here...
     *
     */
    function initGzip() {
        $this->do_gzip_compress = FALSE;
        //zlib.output_compression and ob_gzhandler don't get along well so we'll check to make
        //that zlib.output_compression is not enable in the php.ini before turning on ob_gzhandler
        if ( $this->mosConfig_gzip == 1 AND (int)ini_get('zlib.output_compression') != 1 ) {
            $phpver = phpversion();
            $useragent = mosGetParam( $_SERVER, 'HTTP_USER_AGENT', '' );
            $canZip = mosGetParam( $_SERVER, 'HTTP_ACCEPT_ENCODING', '' );

            if ( $phpver >= '4.0.4pl1' AND
            ( strpos($useragent,'compatible') !== false ||
            strpos($useragent,'Gecko')      !== false
            )
            ) {
                if ( extension_loaded('zlib') ) {
                    ob_start( 'ob_gzhandler' );
                    return;
                }
            } else if ( $phpver > '4.0' ) {
                if ( strpos($canZip,'gzip') !== false ) {
                    if (extension_loaded( 'zlib' )) {
                        $this->do_gzip_compress = TRUE;
                        ob_start();
                        ob_implicit_flush(0);

                        header( 'Content-Encoding: gzip' );
                        return;
                    }
                }
            }
        }
        ob_start();
    }

    /**
	* Perform GZIP
	*/
    function doGzip() {
        if ( $this->do_gzip_compress ) {
            /**
			*Borrowed from php.net!
			*/
            $gzip_contents = ob_get_contents();
            ob_end_clean();

            $gzip_size = strlen($gzip_contents);
            $gzip_crc = crc32($gzip_contents);

            $gzip_contents = gzcompress($gzip_contents, 9);
            $gzip_contents = substr($gzip_contents, 0, strlen($gzip_contents) - 4);

            echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
            echo $gzip_contents;
            echo pack('V', $gzip_crc);
            echo pack('V', $gzip_size);
        } else {
            ob_end_flush();
        }
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $separator
     * @param unknown_type $field
     * @return unknown
     */
    function getLastPart ($separator, $field) {
        $parts = explode($separator, $field);
        return $parts[count($parts)-1];
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $separator
     * @param unknown_type $field
     * @return unknown
     */
    function allButLast ($separator, $field) {
        $lastSize = strlen(mamboCore::getLastPart($separator,$field));
        return substr($field, 0, strlen($field)-$lastSize);
    }

}


/**
* Sorts an Array of objects
*/
class mosObjectSorter {
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $_keyname = '';
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $_direction = 0;
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $_object_array = array();

    /**
     * Enter description here...
     *
     * @param unknown_type $a
     * @param unknown_type $k
     * @param unknown_type $sort_direction
     * @return mosObjectSorter
     */
    function mosObjectSorter (&$a, $k, $sort_direction=1) {
        $this->_keyname = $k;
        $this->_direction = $sort_direction;
        $this->_object_array =& $a;
        $this->sort();
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $a
     * @param unknown_type $b
     * @return unknown
     */
    function mosObjectCompare (&$a, &$b) {
        $key = $this->_keyname;
        if ($a->$key > $b->$key) return $this->_direction;
        if ($a->$key < $b->$key) return -$this->_direction;
        return 0;
    }

    /**
     * Enter description here...
     *
     */
    function sort () {
        usort($this->_object_array, array($this,'mosObjectCompare'));
    }

}

/**
* Pathway handler
* @package Mambo
*/
class mosPathway {
    /** @var array Names for display in pathway */
    var $_names = null;
    /** @var array URLs for links from pathway */
    var $_urls = null;

    /**
	* Constructor
	*/
    function mosPathway () {
        $menuhandler =& mosMenuHandler::getInstance();
        $menus =& $menuhandler->getByParentOrder(0,'mainmenu');
        $home = $menus[0];
        $this->_names[] = $home->name;
        $this->_urls[] = sefRelToAbs($home->link."&Itemid=$home->id");
    }

    /**
	* Singleton accessor
	*/
    function &getInstance () {
        static $instance;
        if (!is_object($instance)) $instance = new mosPathway();
        return $instance;
    }

    /**
	* Add an item to the pathway
	*/
    function addItem ($name, $givenurl) {
        $last = count($this->_names) - 1;
        if (!$name) return;
        $url = sefRelToAbs($givenurl);
        if ($name == $this->_names[$last] AND $url == $this->_urls[$last]) return;
        $this->_names[$last+1] = $name;
        $this->_urls[$last+1] = $url;
    }

    /**
     * Enter description here...
     *
     */
    function reduceToOne () {
        for ($i = count($this->_names) - 1; $i > 0; $i--) {
            unset($this->_names[$i]);
            unset($this->_urls[$i]);
        }
    }

    /**
	* Make a pathway string for display
	*/
    function makePathway () {
        $mainframe =& mosMainFrame::getInstance();
    	$customs = $mainframe->getCustomPathWay();
    	$last = count($this->_names) - 1;
        if ($last == 0 AND count($customs == 0)) return '';
        $result = "<span class='pathway'>";
        $config =& mamboCore::getMamboCore();
        $rootpath = $config->rootPath();
        $imgPath =  'templates/'.$mainframe->getTemplate().'/images/arrow.png';
        if (file_exists( "$rootpath/$imgPath" )) $img = "<img src='$config->mosConfig_live_site/$imgPath' border='0' alt='arrow' />";
        else {
            $imgPath = '/images/M_images/arrow.png';
            if (file_exists( "$rootpath/$imgPath" )) $img = "<img src='$config->mosConfig_live_site/images/M_images/arrow.png' alt='arrow' />";
            else $img = '&gt;';
        }
        foreach ($this->_names as $i=>$name) {
            if ($i === $last AND count($customs) == 0) $result .= "$name</span>";
            elseif (strstr($this->_urls[$i], 'view')) $result .= ""; 
            else {
                $sefurl = sefRelToAbs($this->_urls[$i]);
                $result .= "<a href='$sefurl' class='pathway'>$name</a>";
                $result .= "&nbsp;$img&nbsp;";
            }
        }
        foreach ($customs as $custom) $result .= $custom;
        if (count($customs)) $result .= '</span>';
        return $result;
    }

}

/**
* Module database table class
* @package Mambo
*/
class mosMenu extends mosDBTable {
    /** @var int Primary key */
    var $id=null;
    /** @var string */
    var $menutype=null;
    /** @var string */
    var $name=null;
    /** @var string */
    var $link=null;
    /** @var int */
    var $type=null;
    /** @var int */
    var $published=null;
    /** @var int */
    var $componentid=null;
    /** @var int */
    var $parent=null;
    /** @var int */
    var $sublevel=null;
    /** @var int */
    var $ordering=null;
    /** @var boolean */
    var $checked_out=null;
    /** @var datetime */
    var $checked_out_time=null;
    /** @var boolean */
    var $pollid=null;

    /** @var string */
    var $browserNav=null;
    /** @var int */
    var $access=null;
    /** @var int */
    var $utaccess=null;
    /** @var string */
    var $params=null;

    /**
	* @param database A database connector object
	*/
    function mosMenu() {
        $db =& mamboDatabase::getInstance();
        $this->mosDBTable( '#__menu', 'id', $db );
    }
    /**
	*	binds an array/hash to this object
	*	@param int $oid optional argument, if not specifed then the value of current key is used
	*	@return any result from the database operation
	*/
    function load( $oid=null ) {
        $k = $this->_tbl_key;
        if ($oid !== null) $this->$k = $oid;
        if ($this->$k === null) return false;
        $menuhandler =& mosMenuHandler::getInstance();
        $menu =& $menuhandler->getMenuById($this->$k);
        if ($menu) {
            foreach (get_object_vars($menu) as $key=>$data) $this->$key = $data;
            return true;
        }
        else return false;
    }

}

/**
* File Manager including safe mode provision?
* @package Mambo
*/
class mosFileManager {

    /**
	* Singleton accessor
	*/
    function &getInstance () {
        static $instance;
        if (!is_object($instance)) $instance = new mosFileManager();
        return $instance;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $file
     * @return unknown
     */
    function deleteFile ($file) {
        if (file_exists($file)) {
            @chmod($file, 0644);
            return unlink($file);
        }
        return true;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $dir
     * @return unknown
     */
    function deleteDirectory ($dir) {
        if (file_exists($dir)) {
            if (is_dir($dir)) {
                @chmod($dir, 0755);
                return rmdir($dir);
            }
            return false;
        }
        return true;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $fileSysObject
     */
    function setPermissions ($fileSysObject) {
        if (file_exists($fileSysObject))  {
            if (is_dir($fileSysObject)) $perms = mamboCore::get('mosConfig_dirperms');
            else $perms = mamboCore::get('mosConfig_fileperms');
            if ($perms) {
                $origmask = @umask(0);
                $mode = octdec($perms);
                @chmod($fileSysObject, $mode);
                @umask($origmask);
            }
        }
    }

    /**
	 * Enter description here...
	 *
	 * @param unknown_type $dir
	 * @return unknown
	 */
    function makeDirectory ($dir) {
        $perms = mamboCore::get('mosConfig_dirperms');
        $origmask = @umask(0);
        if ($perms) $result = @mkdir($dir, octdec($perms));
        else $result = @mkdir($dir, 0755);
        if ($result) $this->setPermissions($dir);
        @umask($origmask);
        return $result;
    }


    /**
	 * Enter description here...
	 *
	 * @param unknown_type $dir
	 * @param unknown_type $onlyCheck
	 * @return unknown
	 */
    function createDirectory ($dir, $onlyCheck=false) {
        if (file_exists($dir)) {
            if (is_dir($dir) AND is_writable($dir)) return true;
            else return false;
        }
        list($upDirectory, $count) = $this->containingDirectory($dir);
        if ($count > 1 AND !file_exists($upDirectory) AND !($result = $this->createDirectory($upDirectory, $onlyCheck))) return false;
        if ($onlyCheck AND isset($result)) return true;
        if (!is_dir($upDirectory) OR !is_writable($upDirectory)) return false;
        if ($onlyCheck) return true;
        else return $this->makeDirectory($dir);
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $dir
     * @return unknown
     */
    function containingDirectory ($dir) {
        $dirs = preg_split('*[/|\\\]*', $dir);
        for ($i = count($dirs)-1; $i >= 0; $i--) {
            $text = trim($dirs[$i]);
            unset($dirs[$i]);
            if ($text) break;
        }
        $result2 = count($dirs);
        $result1 = implode('/',$dirs).($result2 > 1 ? '' : '/');
        return array($result1, $result2);
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $from
     * @param unknown_type $to
     * @return unknown
     */
    function simpleCopy ($from, $to) {
        if (@copy($from, $to)) {
            $this->setPermissions($to);
            return true;
        }
        else return false;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $from
     * @param unknown_type $to
     * @return unknown
     */
    function forceCopy ($from, $to) {
        $todir = dirname($to);
        if (!file_exists($todir)) $this->createDirectory($todir);
        if (!file_exists($todir)) return false;
        $name = basename($from);
        $this->deleteFile($to.$name);
        return $this->simpleCopy ($from, $to);
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $from
     * @param unknown_type $to
     * @return unknown
     */
    function lightCopy ($from, $to) {
        $name = basename($from);
        if (file_exists($to.$name)) return false;
        $todir = dirname($to);
        if (!file_exists($todir)) $this->createDirectory($todir);
        if (!file_exists($todir)) return false;
        return $this->simpleCopy ($from, $to);
    }

    /**
	 * Enter description here...
	 *
	 * @param unknown_type $to
	 * @return unknown
	 */
    function acceptCopy ($to) {
        $todir = dirname($to);
        return $this->createDirectory($todir, true);
    }


    /**
	* Function to strip additional / or \ in a path name
	* @param string The path
	* @param boolean Add trailing slash
	*/
    function mosPathName($p_path, $p_addtrailingslash=true) {
        if (substr(PHP_OS, 0, 3) == 'WIN')	{
            $retval = str_replace( '/', '\\', $p_path );
            if ($p_addtrailingslash AND substr( $retval, -1 ) != '\\') $retval .= '\\';
            // Remove double \\
            $retval = str_replace( '\\\\', '\\', $retval );
        }
        else {
            $retval = str_replace( '\\', '/', $p_path );
            if ($p_addtrailingslash AND substr( $retval, -1 ) != '/') $retval .= '/';
            // Remove double //
            $retval = str_replace('//','/',$retval);
        }
        return $retval;
    }

    /**
	* Chmods files and directories recursively to mos global permissions. Available from 4.5.2 up.
	* @param path The starting file or directory (no trailing slash)
	* @param filemode Integer value to chmod files. NULL = dont chmod files.
	* @param dirmode Integer value to chmod directories. NULL = dont chmod directories.
	* @return TRUE=all succeeded FALSE=one or more chmods failed
	*/
    function mosChmod($path)
    {
        $fileperms = mamboCore::get('mosConfig_fileperms');
        if ($fileperms != '') $filemode = octdec($fileperms);
        else $filemode = null;
        $dirperms = mamboCore::get('mosConfig_dirperms');
        if ($dirperms != '') $dirmode = octdec($dirperms);
        else $dirmode = null;
        if (isset($filemode) OR isset($dirmode))
        return $this->mosChmodRecursive($path, $filemode, $dirmode);
        return true;
    } // mosChmod

    /**
	* Chmods files and directories recursively to given permissions. Available from 4.5.2 up.
	* @param path The starting file or directory (no trailing slash)
	* @param filemode Integer value to chmod files. NULL = dont chmod files.
	* @param dirmode Integer value to chmod directories. NULL = dont chmod directories.
	* @return TRUE=all succeeded FALSE=one or more chmods failed
	*/
    function mosChmodRecursive($path, $filemode=NULL, $dirmode=NULL) {
        $ret = true;
        if (is_dir($path)) {
            $topdir =& new mosDirectory($path);
            $files =& $topdir->listFiles ('', 'file', true, true);
            $dirs =& $topdir->listFiles ('', 'dir', true, true);
        }
        else {
            $files = array($path);
            $dirs = array();
        }
        if (isset($filemode)) foreach ($files as $file) $ret = @chmod($file, $filemode) ? $ret : false;
        if (isset($dirmode)) foreach ($dirs as $dir) $ret = @chmod($dir, $dirmode) ? $ret : false;
        return $ret;
    }

}

/**
 * Enter description here...
 *
 */
class mosDirectory {
    /**
     * Enter description here...
     *
     * @var unknown_type
     */
    var $path = '';

    /**
     * Enter description here...
     *
     * @param unknown_type $path
     * @return mosDirectory
     */
    function mosDirectory ($path) {
        $path = str_replace('\\', '/', $path);
        if (substr($path,-1,1) == '/') $this->path = $path;
        else $this->path = $path.'/';
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $type
     * @param unknown_type $recurse
     * @param unknown_type $fullpath
     * @return unknown
     */
    function &listAll ($type='file', $recurse=false, $fullpath=false) {
        $results = array();
        if ($dir = @opendir($this->path)) {
            while ($file = readdir($dir)) {
                if ($file == '.' OR $file == '..') continue;
                if (is_dir($this->path.$file)) {
                    if ($recurse) {
                        $subdir = new mosDirectory($this->path.$file);
                        $results = array_merge($results, $subdir->listAll($type, $recurse, $fullpath));
                        unset($subdir);
                    }
                    if ($type == 'file') continue;
                }
                elseif ($type == 'dir') continue;
                if ($fullpath) $results[] = $this->path.$file;
                else $results[] = $file;
            }
            closedir($dir);
        }
        return $results;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function soleDir () {
        $found = '';
        if ($dir = @opendir($this->path)) {
            while ($file = readdir($dir)) {
                if ($file == '.' OR $file == '..') continue;
                if (is_dir($this->path.$file)) {
                    if ($found) return '';
                    else $found = $file;
                }
                else return '';
            }
            closedir($dir);
        }
        return $found;
    }

    /**
     * Enter description here...
     *
     */
    function deleteAll () {
        if (!file_exists($this->path)) return;
        $subdirs =& $this->listAll ('dir', false, true);
        foreach ($subdirs as $subdir) {
            $subdirectory = new mosDirectory($subdir);
            $subdirectory->deleteAll();
            unset($subdirectory);
        }
        $filemanager =& mosFileManager::getInstance();
        $files =& $this->listAll ('file', false, true);
        foreach ($files as $file) $filemanager->deleteFile($file);
        $filemanager->deleteDirectory($this->path);
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function createFresh () {
        $this->deleteAll();
        $filemanager =& mosFileManager::getInstance();
        $filemanager->createDirectory($this->path);
        return true;
    }

    /**
     * Enter description here...
     *
     */
    function createIfNeeded () {
        if (!file_exists($this->path)) {
            $filemanager =& mosFileManager::getInstance();
            $filemanager->createDirectory($this->path);
        }
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $pattern
     * @param unknown_type $type
     * @param unknown_type $recurse
     * @param unknown_type $fullpath
     * @return unknown
     */
    function &listFiles ($pattern='', $type='file', $recurse=false, $fullpath=false) {
        $results = array();
        $all =& $this->listAll($type, $recurse, $fullpath);
        foreach ($all as $file) {
            $name = basename($file);
            if ($pattern AND !preg_match( "/$pattern/", $name )) continue;
            if (($name != 'index.html') AND ($name[0] != '.')) $results[] = $file;
        }
        return $results;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function getSize () {
        $totalsize = 0;
        $files =& $this->listFiles();
        foreach ($files as $file) $totalsize += filesize($this->path.$file);
        return $totalsize;
    }

}


/**
* Menu handler
* @package Mambo
*/
class mosMenuHandler {
    /** @var array Menu objects currently available */
    var $_menus = null;
    /** @var array Counts of menu items by type and published status */
    var $_counts = null;
    /** @var array Access to stored menu objects by ID */
    var $_idlinks = null;
    /** @var array Items that may be useful for setting Itemid */
    var $_byParentOrder = null;

    /**
	* Constructor
	*/
    function mosMenuHandler() {
        $database =& mamboDatabase::getInstance();
        $sql = "SELECT * FROM #__menu ORDER BY name";
        $this->_menus =& $database->doSQLget($sql, 'mosMenu');
        if (!$this->_menus) $this->_menus = array();
        foreach ($this->_menus as $key=>$menu) {
            $this->_idlinks[$menu->id] = $key;
            if ($menu->published == 1) $this->_byParentOrder[$menu->parent][$menu->ordering][$menu->menutype] = $key;
            if (isset($this->_counts[$menu->menutype][$menu->published])) $this->_counts[$menu->menutype][$menu->published]++;
            else $this->_counts[$menu->menutype][$menu->published] = 1;
        }
        if ($this->_byParentOrder) {
            foreach ($this->_byParentOrder as $parent=>$outer) ksort($this->_byParentOrder[$parent]);
            ksort($this->_byParentOrder);
        }
    }
    /**
	* Singleton accessor
	*/
    function &getInstance () {
        static $instance;
        if (!is_object($instance)) $instance = new mosMenuHandler();
        return $instance;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $id
     * @return unknown
     */
    function &getMenuByID ($id) {
        if (isset($this->_idlinks[$id])) {
            $key = $this->_idlinks[$id];
            $result = $this->_menus[$key];
        }
        else $result = null;
        return $result;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $type
     * @param unknown_type $published
     * @return unknown
     */
    function getMenuCount ($type, $published) {
        if (isset($this->_counts[$type][$published])) return $this->_counts[$type][$published];
        else return 0;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $types
     * @return unknown
     */
    function &getMenusByType ($types) {
        $checker = explode(',', $types);
        $result = null;
        foreach ($this->_menus as $menu) {
            if (in_array($menu->menutype, $checker)) $result[] = $menu;
        }
        return $result;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function &getMenuTypes () {
        $types = array();
        foreach ($this->_menus as $menu) {
            if (!isset($types[$menu->menutype])) $types[$menu->menutype] = 0;
            $types[$menu->menutype]++;
        }
        return $types;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $type
     * @param unknown_type $link
     * @return unknown
     */
    function getIDByTypeLink ($type, $link) {
        foreach ($this->_menus as $menu) {
            if ($menu->published == 1 AND ($type == '*' OR $menu->type == $type) AND $menu->link == $link) return $menu->id;
        }
        return null;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $link
     * @return unknown
     */
    function getIDLikeLink ($link) {
        $exact = $this->getIdByTypeLink('*', $link);
        if ($exact !== null) return $exact;
        foreach ($this->_menus as $menu) {
            if ($menu->published == 1 AND strpos($menu->link,$link) === 0) return $menu->id;
        }
        return 0;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $type
     * @param unknown_type $componentid
     * @return unknown
     */
    function getIDByTypeCid ($type, $componentid) {
        foreach ($this->_menus as $menu) {
            if ($menu->published == 1 AND $menu->type == $type AND $menu->componentid == $componentid) return $menu->id;
        }
        return null;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function getGlobalBlogSectionCount () {
        $count = 0;
        foreach ($this->_menus as $menu) {
            if ($menu->type == 'content_blog_section' AND $menu->published == 1 AND $menu->componentid == 0) $count++;
        }
        return $count;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $Itemid
     * @param unknown_type $type
     * @param unknown_type $id
     * @param unknown_type $catid
     * @return unknown
     */
    function getContentItemid ($Itemid, $type, $id, $catid=0) {
        if ($Itemid) return $Itemid;
        foreach ($this->_menus as $menu) {
            if (strpos($menu->link,'index.php?option=com_content') === false AND strpos($menu->link,'index.php?option=content') === false) continue;
            if (strpos($menu->link, $type) === false) continue;
            if ($catid) {
                if (strpos($menu->link, "&id=$catid") === false) continue;
                if (strpos($menu->link, "&sectionid=$id") === false) continue;
            }
            elseif (strpos($menu->link, "&id=$id") === false) continue;
            return $menu->id;
        }
        return 0;
    }

    /**
     * Enter description here...
     *
     * @return unknown
     */
    function getBestQueryMatch () {
        parse_str($_SERVER['QUERY_STRING'], $qitems);
        if (!isset($qitems['option'])) return 0;
        $failures = 999;
        $best = 0;
        foreach ($this->_menus as $menu) {
            $split = explode('?', $menu->link);
            if (isset($split[1])) parse_str($split[1], $mitems);
            else continue;
            if (!isset($mitems['option']) OR $mitems['option'] != $qitems['option']) continue;
            $thisfail = 0;
            foreach ($mitems as $key=>$mitem) if (!isset($qitems[$key]) OR $mitem != $qitems[$key]) $thisfail++;
            if ($thisfail < $failures) {
                $best = $menu->id;
                $failures = $thisfail;
            }
        }
        return $best;
    }


    /**
     * Enter description here...
     *
     * @param unknown_type $link
     * @return unknown
     */
    function &maxAccessLink ($link) {
        $selected = null;
        $access = 0;
        foreach ($this->_menus as $key=>$menu) {
            if (strpos($menu->link,$link) === 0 AND $menu->access > $access) {
                $access = $menu->access;
                $selected =& $this->_menus[$key];
            }
        }
        return $selected;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $Itemid
     * @param unknown_type $menutype
     * @param unknown_type $maxaccess
     * @param unknown_type $noparent
     * @return unknown
     */
    function &getByParentOrder ($Itemid, $menutype, $maxaccess=0, $noparent=false) {
        $result = array();
        if ($this->_byParentOrder !== null) {
            foreach ($this->_byParentOrder as $parent=>$outer) {
                foreach ($outer as $ordering=>$inner) {
                    foreach ($inner as $mtype=>$last) {
                        $key = $this->_byParentOrder[$parent][$ordering][$mtype];
                        $menu = $this->_menus[$key];
                        if ($menutype AND $mtype != $menutype) continue;
                        if ($Itemid AND $Itemid != $menu->id) continue;
                        if ($menu->access > $maxaccess) continue;
                        if ($noparent AND $parent != 0) continue;
                        $result[] = $this->_menus[$key];
                    }
                }
            }
        }
        return $result;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $Itemid
     */
    function setPathway ($Itemid) {
        if ($Itemid) {
            $menu =& $this->getMenuByID($Itemid);
            if ($menu->parent) $this->setPathway($menu->parent);
            $pathway =& mosPathway::getInstance();
            $pathway->addItem($menu->name, $menu->link."&Itemid=$Itemid");
        }
    }

    /**
	* Checks whether a menu option is within the users access level
	* @param int Item id number
	* @param string The menu option
	* @param int The users group ID number
	* @param database A database connector object
	* @return boolean True if the visitor's group at least equal to the menu access
	*/
    function menuCheck( $Itemid, $menu_option, $task, $gid ) {
        // Construct a link to this component - if no menu for it, assume it is OK
        $dblink="index.php?option=$menu_option";
        if ($this->getIDLikeLink($dblink) == 0) return true;
        if ($Itemid) {
            $menu =& $this->getMenuByID($Itemid);
            if (strpos($menu->link,$dblink) ===0) {
                $access = $menu->access;
            } elseif ($menu_option == 'com_content' AND $Itemid == 1) {
                return true;
            }
        }
        if (!isset($access)) {
            if ($task!='') $dblink .= "&task=$task";
            $menu =& $this->maxAccessLink($dblink);
            if (isset($menu)) {
                $access = $menu->access;
                mamboCore::set('Itemid', $menu->id);
            }
        }
        return isset($access) ? $access <= $gid : false;
    }

    /**
     * Enter description here...
     *
     * @param unknown_type $mitem
     * @param unknown_type $level
     * @param unknown_type $params
     * @param unknown_type $Itemid
     * @return unknown
     */
    function mosGetMenuLink( &$mitem, $level=0, &$params, $Itemid ) {
        $txt = '';

        switch ($mitem->type) {
            case 'separator':
            case 'component_item_link':
            break;
            case 'content_item_link':
            $temp = split("&task=view&id=", $mitem->link);
            if (isset($temp[1])) {
                require_once(mamboCore::get('mosConfig_absolute_path').'/components/com_content/content.class.php');
                $handler =& contentHandler::getInstance();
                $mitem->link .= '&Itemid='.$handler->getItemid($temp[1]);
            }
            break;
            case 'url':
            $link = strtolower($mitem->link);
            if (substr($link,0,10) == 'index.php?' AND strpos($link,'itemid=') === false) $mitem->link .= '&Itemid='. $mitem->id;
            break;
            case 'content_typed':
            default:
            $mitem->link .= '&Itemid='.$mitem->id;
            break;
        }
        // Active Menu highlighting
        if ( $Itemid == $mitem->id ) $id = 'id="active_menu'.$params->get( 'class_sfx' ).'"';
        else $id = '';
        $mitem->link = ampReplace( $mitem->link );
        if (strcasecmp(substr($mitem->link,0,4), 'http')) $mitem->link = sefRelToAbs( $mitem->link );
        if ($level > 0) $menuclass = 'sublevel';
        else $menuclass = 'mainlevel';
        $menuclass .= $params->get( 'class_sfx');

        switch ($mitem->browserNav) {
            // cases are slightly different
            case 1:
            // open in a new window
            $txt = '<a href="'. $mitem->link .'" target="_blank" class="'. $menuclass .'" '. $id .'>'. $mitem->name .'</a>';
            break;

            case 2:
            // open in a popup window
            $txt = "<a href=\"#\" onclick=\"javascript: window.open('". $mitem->link ."', '', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=550'); return false\" class=\"$menuclass\" ". $id .">". $mitem->name ."</a>\n";
            break;

            case 3:
            // don't link it
            $txt = '<span class="'. $menuclass .'" '. $id .'>'. $mitem->name .'</span>';
            break;

            default:	// formerly case 2
            // open in parent window
            $txt = '<a href="'. $mitem->link .'" class="'. $menuclass .'" '. $id .'>'. $mitem->name .'</a>';
            break;
        }

        if ( $params->get( 'menu_images' ) ) {
            $menu_params =& new mosParameters( $mitem->params );
            $menu_image = $menu_params->def( 'menu_image', -1 );
            if ($menu_image AND $menu_image <> '-1') {
                $image = '<img src="'. mamboCore::get('mosConfig_live_site') .'/images/stories/'. $menu_image .'" border="0" alt="'. $mitem->name .'"/>';
                if ( $params->get('menu_images_align')) $txt = $txt .' '. $image;
                else $txt = $image .' '. $txt;
            }
        }
        return $txt;
    }

    /**
	* Vertically Indented Menu
	*/
    function mosShowVIMenu(  &$params ) {
        global $my, $cur_template, $Itemid;
        if (mamboCore::get('mosConfig_shownoauth')) $maxaccess = 0;
        else $maxaccess = $my->gid;
        $rows =& $this->getByParentOrder(0, $params->get('menutype'), $maxaccess);
        foreach ($rows as $i=>$row) $crosslink[$row->id] = $i;
        // indent icons
        $base = mamboCore::get('mosConfig_live_site');
        switch ( $params->get( 'indent_image' ) ) {
            case '1':
            // Default images
            for ( $i = 1; $i < 7; $i++ ) {
                $img[$i] = "<img src=\"$base/images/M_images/indent$i.png\" alt=\"indent$i\" />";
            }
            break;
            case '2':
            // Use Params
            for ( $i = 1; $i < 7; $i++ ) {
                $parm = $params->get('indent_image'. $i);
                if ($parm == '-1' ) $img[$i] = NULL;
                else $img[$i] = "<img src=\"$base/images/M_images/$parm\" alt=\"indent$i\" />";
            }
            break;
            case '3':
            // None
            for ( $i = 1; $i < 7; $i++ ) $img[$i] = NULL;
            break;
            default:
            // Template
            $imgpath = $base.'/templates/'. $cur_template .'/images';
            for ( $i = 1; $i < 7; $i++ ) {
                $img[$i] = "<img src=\"$base/templates/$cur_template/images/indent$i.png\" alt=\"indent$i\" />";
            }
            break;
        }

        $indents = array(
        // block prefix / item prefix / item suffix / block suffix
        array( '<table width="100%" border="0" cellpadding="0" cellspacing="0">', '<tr align="left"><td>' , '</td></tr>', '</table>' ),
        array( '', '<div style="padding-left: 4px">'. $img[1] , '</div>', '' ),
        array( '', '<div style="padding-left: 8px">'. $img[2] , '</div>', '' ),
        array( '', '<div style="padding-left: 12px">'. $img[3] , '</div>', '' ),
        array( '', '<div style="padding-left: 16px">'. $img[4] , '</div>', '' ),
        array( '', '<div style="padding-left: 20px">'. $img[5] , '</div>', '' ),
        array( '', '<div style="padding-left: 24px">'. $img[6] , '</div>', '' ),
        );

        // establish the hierarchy of the menu
        $children = array();
        // first pass - collect children
        foreach ($rows as $v ) $children[$v->parent][] = $v;
        // second pass - collect 'open' menus
        $open = array( $Itemid );
        for ($i = 0; $i < 20 AND isset($crosslink[$open[$i]]) AND isset($rows[$crosslink[$open[$i]]]); $i++) {
            $next = $rows[$crosslink[$open[$i]]]->parent;
            if ($next) $open[$i+1] = $next;
            else break;
        }

        $this->mosRecurseVIMenu( 0, 0, $children, $open, $indents, $params );

    }

    /**
	* Utility function to recursively work through a vertically indented
	* hierarchial menu
	*/
    function mosRecurseVIMenu( $id, $level, &$children, &$open, &$indents, &$params ) {
        global $Itemid;
        if (@$children[$id]) {
            $n = min( $level, count($indents )-1);
            echo "\n".$indents[$n][0];
            foreach ($children[$id] as $row) {
                echo "\n".$indents[$n][1];
                echo $this->mosGetMenuLink( $row, $level, $params, $Itemid );
                // show menu with menu expanded - submenus visible
                if ($params->get('expand_menu') OR in_array($row->id, $open)) $this->mosRecurseVIMenu( $row->id, $level+1, $children, $open, $indents, $params );
                echo $indents[$n][2];
            }
            echo "\n".$indents[$n][3];
        }
    }

    /**
	* Draws a horizontal 'flat' style menu (very simple case)
	*/
    function mosShowHFMenu(  &$params, $style=0 ) {
        global $my, $cur_template, $Itemid;

        if (mamboCore::get('mosConfig_shownoauth')) $maxaccess = 0;
        else $maxaccess = $my->gid;
        $rows =& $this->getByParentOrder(0, $params->get('menutype'), $maxaccess, true);

        $links = array();
        foreach ($rows as $row) $links[] = $this->mosGetMenuLink( $row, 0, $params, $Itemid );
        $menuclass = 'mainlevel'. $params->get( 'class_sfx' );
        if (count( $links )) {
            if ($style == 1) {
                echo '<ul id="'. $menuclass .'">';
                foreach ($links as $link) echo '<li>' . $link . '</li>';
                echo '</ul>';
            }
            else {
                echo '<table width="100%" border="0" cellpadding="0" cellspacing="1">';
                echo '<tr>';
                echo '<td nowrap="nowrap">';
                echo '<span class="'. $menuclass .'"> '. $params->get( 'end_spacer' ) .' </span>';
                echo implode( '<span class="'. $menuclass .'"> '. $params->get( 'spacer' ) .' </span>', $links );
                echo '<span class="'. $menuclass .'"> '. $params->get( 'end_spacer' ) .' </span>';
                echo '</td></tr>';
                echo '</table>';
            }
        }
    }
}

/**
* Plugin handler
* @package Mambo
*/
class mosMambotHandler {
    /** @var array An array of functions in event groups */
    var $_events=null;
    /** @var array An array of lists */
    var $_lists=null;
    /** @var array An array of mambots */
    var $_bots=null;
    /** @var array An array of bools showing if corresponding bot is registered */
    var $_registered=array();
    /** @var int Index of the mambot being loaded */
    var $_loading=null;

    /**
	* Constructor
	*/
    function mosMambotHandler() {
        $my = mamboCore::is_set('currentUser') ? mamboCore::get('currentUser') : null;
        $gid = $my ? $my->gid : 0;
        $this->_events = array();
        $database =& mamboDatabase::getInstance();
        $database->setQuery( "SELECT folder, element, published, params, CONCAT_WS('/',folder,element) AS lookup"
        . "\nFROM #__mambots"
        . "\nWHERE published >= 1 AND access <= $gid"
        . "\nORDER BY ordering"
        );
        $this->_bots = $database->loadObjectList();
        if (!$this->_bots) $this->_bots = array();
    }
    /**
	* Singleton accessor
	*/
    function &getInstance () {
        static $instance;
        if (!is_object($instance)) $instance = new mosMambotHandler();
        return $instance;
    }
    /**
    * Register a class-type mambot, provided it has a perform method
    * - can register for multiple events if desired
    * @param object The mambot object
    * @param mixed string or array of strings - the mambot events to be registered
    * @param int the subscript for use in the main array of mambots
    */
    function _botRegister (&$botObject, &$selected, $i) {
        $function = array(&$botObject, 'perform');
        if (!is_callable($function)) return;
        if (is_array($selected)) foreach ($selected as $select) $this->_botRegister($botObject, $select);
        $this->_events[$selected][] = array ($function, $i);
        $this->_registered[$i] = true;
    }

    /**
	* Loads all the bot files for a particular group
	* @param string The group name, relates to the sub-directory in the mambots directory
	*/
    function loadBotGroup( $group ) {
        global $_MAMBOTS;
        $group = trim( $group );
        $total = 0;
        $basepath = mamboCore::get('mosConfig_absolute_path');
        foreach ($this->_bots as $i=>$bot) {
            if ($bot->folder != $group OR isset($this->_registered[$i])) continue;
            $path = "$basepath/mambots/$bot->folder/$bot->element.php";
            if (file_exists( $path )) {
                $this->_loading = $i;
                require_once( $path );
                if (!isset($this->_registered[$i])) {
                    $botclass = str_replace('.','_',$bot->element);
                    if (class_exists($botclass)) {
                        $newbot = new $botclass();
                        if (is_callable(array(&$newbot, 'register'))) {
                            $selected = $newbot->register();
                            $this->_botRegister($newbot, $selected, $i);
                        }
                    }
                }
                $total++;
            }
        }
        $this->_loading = null;
        if ($total) return true;
        return false;
    }
    /**
	* Registers a function to a particular event group
	* @param string The event name
	* @param string The function name
	*/
    function registerFunction( $event, $function ) {
        $this->_events[$event][] = array( $function, $this->_loading );
        $this->_registered[$this->_loading] = true;
    }
    /**
	* Makes a option for a particular list in a group
	* @param string The group name
	* @param string The list name
	* @param string The value for the list option
	* @param string The text for the list option
	*/
    function addListOption( $group, $listName, $value, $text='' ) {
        $this->_lists[$group][$listName][] = mosHTML::makeOption( $value, $text );
    }
    /**
	* @param string The group name
	* @param string The list name
	* @return array
	*/
    function getList( $group, $listName ) {
        return $this->_lists[$group][$listName];
    }
    /**
	* Calls all functions according to passed parameters
	* @param string The event name
	* @param array An array of arguments
	* @param boolean True is unpublished bots are to be processed
	* @return array An array of results from each function call
	*/
    function &_runBots ($event, $args, $doUnpublished=false) {
        $result = array();
        if (isset( $this->_events[$event] )) {
            foreach ($this->_events[$event] as $func) {
                if (is_callable( $func[0] )) {
                    $botparams = $this->_bots[$func[1]]->params;
                    $args[] = new mosParameters($botparams);
                    $args[] = $event;
                    if ($doUnpublished) {
                        $args[0] = $this->_bots[$func[1]]->published;
                        $result[] = call_user_func_array( $func[0], $args );
                    } else if ($this->_bots[$func[1]]->published) {
                        $result[] = call_user_func_array( $func[0], $args );
                    }
                }
            }
        }
        return $result;
    }
    /**
	* Calls all functions associated with an event group
	* @param string The event name
	* @param array An array of arguments
	* @param boolean True is unpublished bots are to be processed
	* @return array An array of results from each function call
	*/
    function trigger( $event, $args=null, $doUnpublished=false ) {
        if ($args === null) $args = array();
        // prepend the published argument
        if ($doUnpublished) array_unshift( $args, null );
        $result =& $this->_runBots($event, $args, $doUnpublished);
        return $result;
    }
    /**
	* Same as trigger but only returns the first event and
	* allows for a variable argument list
	* @param string The event name
	* @return array The result of the first function call
	*/
    function call( $event ) {
        $args =& func_get_args();
        array_shift( $args );
        $result =& $this->_runBots($event, $args);
        if (isset($result[0])) return $result[0];
        return null;
    }
}

/**
* Users Table Class
*
* Provides access to the mos_templates table
* @package Mambo
*/
class mosUser extends mosDBTable {
    /** @var int Unique id*/
    var $id=null;
    /** @var string The users real name (or nickname)*/
    var $name=null;
    /** @var string The login name*/
    var $username=null;
    /** @var string email*/
    var $email=null;
    /** @var string MD5 encrypted password*/
    var $password=null;
    /** @var string */
    var $usertype=null;
    /** @var int */
    var $block=null;
    /** @var int */
    var $sendEmail=null;
    /** @var int The group id number */
    var $gid=null;
    /** @var int Group number from ACL */
    var $grp=null;
    /** @var datetime */
    var $registerDate=null;
    /** @var datetime */
    var $lastvisitDate=null;
    /** @var string activation hash*/
    var $activation=null;
    /** @var string */
    var $params=null;

    /**
	* @param database A database connector object
	*/
    function mosUser() {
        $database =& mamboDatabase::getInstance();
        $this->mosDBTable( '#__users', 'id', $database );
    }

    /**
	 * Return true if this user is an administrator, false otherwise
	 */
    function isAdmin() {
        return ( strtolower( $this->usertype ) == 'superadministrator' OR strtolower( $this->usertype ) == 'super administrator' OR (isset($this->grp) AND $this->grp == 16) ) ? true : false;
    }

    /**
	 * Fill a user object with information from the current session
	 */
    function getSessionData() {
        $session =& mosSession::getCurrent();
        $this->id = intval( $session->userid );
        $this->username = $session->username;
        $this->usertype = $session->usertype;
        $this->gid = intval ($session->gid);
    }

    function getSession () {
        $this->id = mosGetParam( $_SESSION, 'session_user_id', 0 );
        $this->username = mosGetParam( $_SESSION, 'session_username', '' );
        $this->usertype = mosGetParam( $_SESSION, 'session_usertype', '' );
        $this->gid = mosGetParam( $_SESSION, 'session_gid', 0 );
        $this->grp = mosGetParam( $_SESSION, 'session_grp', 0);
    }
    /**
	 * Validation and filtering
	 * @return boolean True is satisfactory
	 */
    function check() {
    	Global $mosConfig_absolute_path;
    	include $mosConfig_absolute_path . ('/language/english.php');
        $this->_error = '';
        if ($this->name == '') $this->_error = _REGWARN_NAME;
        elseif ($this->username == '') $this->_error = _REGWARN_UNAME;
        elseif (strlen($this->username) < 3 OR preg_match("/[\\<\\>\\\"\\'\\%\\;\\(\\)\\&\\+\\-]/", $this->username)) $this->_error = sprintf( _VALID_AZ09, _PROMPT_UNAME, 2 );
        elseif (($this->email == '') OR preg_match("/[\w\.\-]+@\w+[\w\.\-]*?\.\w{1,4}/", $this->email ) == 0) $this->_error = _REGWARN_MAIL;
        else {
            // check for existing username
            $username = strtolower($this->username);
            $this->_db->setQuery( "SELECT COUNT(id) FROM #__users "
            . "\nWHERE LOWER(username)='$username' AND id!='$this->id'"
            );
            if ($this->_db->loadResult()) $this->_error = _REGWARN_INUSE;
            elseif (mamboCore::get('mosConfig_uniquemail')) {
                // check for existing email
                $this->_db->setQuery( "SELECT COUNT(id) FROM #__users "
                . "\nWHERE email='$this->email' AND id!='$this->id'"
                );
                if ($this->_db->loadResult()) $this->_error = _REGWARN_EMAIL_INUSE;
            }
        }
        if ($this->_error) return false;
        return true;
    }

    function store( $updateNulls=false ) {
        global $acl, $migrate;
        $section_value = 'users';
        if( $this->id AND !$migrate) {
            // update existing record
            $ret = $this->_db->updateObject( $this->_tbl, $this, 'id', $updateNulls );
            // syncronise ACL
            // single group handled at the moment
            // trivial to expand to multiple groups
            $groups = $acl->get_object_groups( $section_value, $this->id, 'ARO' );
            $acl->del_group_object( $groups[0], $section_value, $this->id, 'ARO' );
            $acl->add_group_object( $this->gid, $section_value, $this->id, 'ARO' );
            $object_id = $acl->get_object_id( $section_value, $this->id, 'ARO' );
            $acl->edit_object( $object_id, $section_value, $this->_db->getEscaped( $this->name ), $this->id, 0, 0, 'ARO' );
        }
        else {
            // new record
            $ret = $this->_db->insertObject( $this->_tbl, $this, 'id' );
            // syncronise ACL
            $acl->add_object( $section_value, $this->_db->getEscaped( $this->name ), $this->id, null, null, 'ARO' );
            $acl->add_group_object( $this->gid, $section_value, $this->id, 'ARO' );
        }
        if ($ret) return true;
        $this->_error = "mosUser::store failed <br />" . $this->_db->getErrorMsg();
        return false;
    }

    function delete($oid=null) {
        global $acl;
        $k = $this->_tbl_key;
        if ($oid) $this->id = intval( $oid );
        $aro_id = $acl->get_object_id( 'users', $this->$k, 'ARO' );
        $acl->del_object( $aro_id, 'ARO', true );
        //		$authoriser = mosAuthorisationAdmin::getInstance();
        //		$authoriser->dropAccess('mosUser', $this->id);
        $this->_error = '';
        $this->_db->setQuery( "DELETE FROM $this->_tbl WHERE id = '".$this->id."'" );
        if ($this->_db->query()) {
            // cleanup related data

            // :: private messaging
            $this->_db->setQuery( "DELETE FROM #__messages_cfg WHERE user_id='".$this->id."'" );
            if (!$this->_db->query()) $this->_error = $this->_db->getErrorMsg();
            else {
                $this->_db->setQuery( "DELETE FROM #__messages WHERE user_id_to='".$this->$k."'" );
                if (!$this->_db->query()) $this->_error = $this->_db->getErrorMsg();
            }
        } else $this->_error = $this->_db->getErrorMsg();
        if ($this->_error) return false;
        return true;
    }
}

/**
* User login details class
* @package Mambo
*/
class mosLoginDetails {
    var $_user = '';
    var $_password = '';
    var $_remember = '';

    function mosLoginDetails ($user, $password='', $remember='') {
        $this->_user = $user;
        $this->_password = $password;
        $this->_remember = $remember;
    }

    function getUser () {
        return $this->_user;
    }

    function getPassword () {
        return $this->_password;
    }

    function getRemember () {
        return $this->_remember;
    }

}
/**
* Mambo Mainframe class
*
* Provide many supporting API functions
* @package Mambo
*/
class mosMainFrame {
    /** @var database Internal database class pointer */
    var $_db=null;
    /** @var object A default option (e.g. component) */
    var $_option=null;
    /** @var string The current template */
    var $_template=null;
    /** @var array An array to hold global user state within a session */
    var $_userstate=null;
    /** @var array An array of page meta information */
    var $_head=null;
    /** @var string Custom html string to append to the pathway */
    var $_custom_pathway=array();

    /**
	* Class constructor
	* @param database A database connection object
	* @param string The url option
	* @param string The path of the mos directory
	*/
    function mosMainFrame( &$db, $option, $basePath, $isAdmin=false ) {
        $this->_db =& $db;
        // load the configuration values
        //return( $this->loadConfig() );
        $this->_setTemplate($isAdmin);
        if (substr($option,0,4) != 'com_') $this->_option = "com_$option";
        else $this->_option = $option;
        if (isset( $_SESSION['session_userstate'] )) $this->_userstate =& $_SESSION['session_userstate'];
        else $this->_userstate = null;
        $this->_head['title'] = $GLOBALS['mosConfig_sitename'];
        $this->_head['meta'] = array();
        $this->_head['custom'] = array();
        mosMainFrame::getInstance($this);
    }

    /**
    * Get the current user - deprecated - use mamboCore instead
    */
    function getUser() {
        return mamboCore::get('currentUser');
    }
    /**
    * Logout the current user - deprecated - use the code here directly
    */
    function logout() {
        require_once(mamboCore::get('mosConfig_absolute_path').'/includes/authenticator.php');
        $authenticator =& mamboAuthenticator::getInstance();
        $authenticator->logoutUser();
    }
    /**
    * Login a user given name and password - deprecated - use the code here directly
    */
    function login ($username=null,$passwd=null) {
        require_once(mamboCore::get('mosConfig_absolute_path').'/includes/authenticator.php');
        $authenticator =& mamboAuthenticator::getInstance();
        return $authenticator->loginUser($username, $passwd);
    }

    /**
	* @param object
	*/
	function &getInstance () {
	    global $mainframe;
	    if (isset($mainframe)) {
	        return $mainframe;
	    } else {
	        $result = null;
	        return $result;
	    }
	}

    /**
	* @param string
	*/
    function setPageTitle( $title=null ) {
        if (mamboCore::get('mosConfig_pagetitles')) {
            $title = trim(htmlspecialchars($title));
            $base = mamboCore::get('mosConfig_sitename');
            $this->_head['title'] = $title ?  $title.' - '.$base : $base;
        }
    }
    /**
	* @return string
	*/
    function getPageTitle() {
        return $this->_head['title'];
    }

    /**
	* @param string The value of the name attibute
	* @param string The value of the content attibute
	* @param string Text to display before the tag
	* @param string Text to display after the tag
	*/
    function addMetaTag( $name, $content, $prepend='', $append='' ) {
        list($name, $content) = $this->_tidyMetaData($name, $content);
        $prepend = trim($prepend);
        $append = trim($append);
        $this->_head['meta'][$name] = array($content, $prepend, $append);
    }
    /**
	* @param string The value of the name attibute
	*/
    function _getMetaTag ($name) {
        return isset($this->_head['meta'][$name]) ?  $this->_head['meta'][$name] : array('', '', '');
    }
    /**
	* @param string The value of the name attibute
	* @param string The value of the content attibute to append to the existing
	*/
    function _tidyMetaData($name, $content) {
        $result[] = trim(htmlspecialchars($name));
        $result[] = trim(htmlspecialchars($content));
        return $result;
    }
    /**
	* @param string The value of the name attibute
	* @param string The value of the content attibute to append to the existing
	* Tags ordered in with Site Keywords and Description first
	*/
    function appendMetaTag( $name, $content, $ifEmpty=false ) {
        list($name, $content) = $this->_tidyMetaData($name, $content);
        $tag = $this->_getMetaTag($name);
        if ($tag[0] AND $ifEmpty) return;
        if ($tag[0] AND $content) $content .= ', ';
        $tag[0] = $content.$tag[0];
        $this->_head['meta'][$name] =  $tag;
    }

    /**
	* @param string The value of the name attibute
	* @param string The value of the content attibute to append to the existing
	*/
    function prependMetaTag( $name, $content ) {
        list($name, $content) = $this->_tidyMetaData($name, $content);
        $tag = $this->_getMetaTag($name);
        $tag[0] = $content.$tag[0];
        $this->_head['meta'][$name] =  $tag;
    }
    /**
	 * Adds a custom html string to the head block
	 * @param string The html to add to the head
	 */
    function addCustomHeadTag( $html ) {
        $this->_head['custom'][] = trim( $html );
    }
    /**
	* @return string
	*/
    function getHead() {
        $head[] = '<title>'.$this->_head['title'].'</title>';
        foreach ($this->_head['meta'] as $name=>$meta) {
            if ($meta[1]) $head[] = $meta[1];
            $head[] = '<meta name="' . $name . '" content="' . $meta[0] . '" />';
            if ($meta[2]) $head[] = $meta[2];
        }
        foreach ($this->_head['custom'] as $html) $head[] = $html;
        return implode( "\n", $head )."\n";
    }
    /**
	* @return string
	*/
    function getCustomPathWay() {
        return $this->_custom_pathway;
    }

    function appendPathWay($html) {
        $this->_custom_pathway[] = $html;
    }

    /**
	* Gets the value of a user state variable
	* @param string The name of the variable
	*/
    function getUserState( $var_name ) {
        return is_array($this->_userstate) ? mosGetParam($this->_userstate, $var_name, null) : null;
    }
    /**
	* Sets the value of a user state variable
	* @param string The name of the variable
	* @param string The value of the variable
	*/
    function setUserState( $var_name, $var_value ) {
        if (is_array( $this->_userstate )) $this->_userstate[$var_name] = $var_value;
    }
    /**
	* Gets the value of a user state variable
	* @param string The name of the user state variable
	* @param string The name of the variable passed in a request
	* @param string The default value for the variable if not found
	*/
    function getUserStateFromRequest( $var_name, $req_name, $var_default=null ) {
		if (is_array($this->_userstate)) {
			if (isset($_REQUEST[$req_name])) $this->setUserState($var_name, $_REQUEST[$req_name]);
			else if (isset($var_default) AND !isset($this->_userstate[$var_name])) $this->setUserState($var_name, $var_default);
			return $this->_userstate[$var_name];
		} else {
			return null;
		}
    }
    /**
	* Initialises the user session
	*
	* Old sessions are flushed based on the configuration value for the cookie
	* lifetime. If an existing session, then the last access time is updated.
	* If a new session, a session id is generated and a record is created in
	* the mos_sessions table.
	*/
    function &initSession() {
        $session =& mosSession::getCurrent();
        return $session;
    }

    /**
	* @param string The name of the variable (from configuration.php)
	* @return mixed The value of the configuration variable or null if not found
	*/
    function getCfg( $varname ) {
        return mamboCore::get('mosConfig_'.$varname);
    }

    function _setTemplate( $isAdmin=false ) {
        global $Itemid;
        $cur_template = '';
        $sql = "SELECT template, client_id, menuid FROM #__templates_menu WHERE (client_id=0 or client_id=1)";
        if (isset($Itemid) AND $Itemid) $sql .= " AND (menuid=0 OR menuid=$Itemid)";
        else $sql .= " AND menuid=0";
        $sql .= " ORDER BY client_id, menuid";
        $this->_db->setQuery($sql);
        $templates = $this->_db->loadObjectList();
        foreach ($templates as $template) {
            if ($template->client_id == 1) {
                if ($isAdmin) $cur_template = $template->template;
            }
            else $cur_template = $template->template;
        }
        if ($isAdmin) {
            $path = mamboCore::get('mosConfig_absolute_path')."/administrator/templates/$cur_template/index.php";
            if (!file_exists( $path )) $cur_template = 'mambo_admin';
        }
        else {
            // TemplateChooser Start
            $mos_user_template = mosGetParam( $_COOKIE, 'mos_user_template', '' );
            $mos_change_template = mosGetParam( $_REQUEST, 'mos_change_template', $mos_user_template );
            if ($mos_change_template) {
                // check that template exists in case it was deleted
                $path = mamboCore::get('mosConfig_absolute_path')."/templates/$mos_change_template/index.php";
                if (strpos($mos_change_template,'..') == false AND strpos($mos_change_template,':') == false AND file_exists($path)) {
                    $lifetime = 60*10;
                    $cur_template = $mos_change_template;
                    setcookie( "mos_user_template", "$mos_change_template", time()+$lifetime);
                } else 	setcookie( "mos_user_template", "", time()-3600 );
            }
            // TemplateChooser End
        }
        $this->_template = $cur_template;
    }

    function getTemplate() {
        return $this->_template;
    }

    /**
	* Checks to see if an image exists in the current templates image directory
 	* if it does it loads this image.  Otherwise the default image is loaded.
	* Also can be used in conjunction with the menulist param to create the chosen image
	* load the default or use no image
	*/
    function ImageCheck( $file, $directory='/images/M_images/', $param=NULL, $param_directory='/images/M_images/', $alt=NULL, $name='image', $type=1, $align='middle' ) {
        $basepath = mamboCore::get('mosConfig_live_site');
        if ($param) $image = $basepath.$param_directory.$param;
        else {
            $endpath = '/templates/'.$this->getTemplate().'/images/'.$file;
            if (file_exists(mamboCore::get('mosConfig_absolute_path').$endpath)) $image = $basepath.$endpath;
            else $image = $basepath.$directory.$file;  // outputs only path to image
        }
        // outputs actual html <img> tag
        if ($type) $image = '<img src="'. $image .'" alt="'. $alt .'" align="'. $align .'" name="'. $name .'" border="0" />';
        return $image;
    }

    /**
	* Returns the first to be found of one or more files, or null
	*
	*/
    function tryFiles ($first_choice, $second_choice=null, $third_choice=null) {
        if (file_exists($first_choice)) return $first_choice;
        elseif ($second_choice AND file_exists($second_choice)) return $second_choice;
        elseif ($third_choice AND file_exists($third_choice)) return $third_choice;
        else return null;
    }

    /**
	* Returns a standard path variable
	*
	*/
    function getPath( $varname, $option='' ) {
        $base = mamboCore::get('mosConfig_absolute_path');
        $origoption = $option;
        if (!$option) $option = $this->_option;
        $name = substr($option,4);
        $bac_admin = "$base/administrator/components/com_admin/";
        $baco = "$base/administrator/components/$option/";
        $bttc = "$base/templates/$this->_template/components/";
        $bco = "$base/components/$option/";
        $bai = "$base/administrator/includes/";
        $bi = "$base/includes/";

        switch ($varname) {
            case 'front': return $this->tryFiles ($bco."$name.php");
            case 'front_html': return $this->tryFiles ($bttc."$name.html.php", $bco."$name.html.php");
            case 'admin': return $this->tryFiles ($baco."admin.$name.php", $bac_admin.'admin.admin.php');
            case 'admin_html': return $this->tryFiles ($baco."admin.$name.html.php", $bac_admin.'admin.admin.html.php');
            case 'toolbar': return $this->tryFiles ($baco."toolbar.$name.php");
            case 'toolbar_html': return $this->tryFiles ($baco."toolbar.$name.html.php");
            case 'toolbar_default': return $this->tryFiles ($bai.'toolbar.html.php');
            case 'class': return $this->tryFiles ($bco."$name.class.php", $baco."$name.class.php", $bi."$name.php");
            case 'com_xml': return $this->tryFiles ($baco."$name.xml", $bco."$name.xml");
            case 'mod0_xml':
            if ($origoption) $path = $base."/modules/$option.xml";
            else $path = $base.'/modules/custom.xml';
            return $this->tryFiles ($path);
            case 'mod1_xml':
            if ($origoption) $path = $base."/administrator/modules/$option.xml";
            else $path = $base.'/administrator/modules/custom.xml';
            return $this->tryFiles ($path);
            case 'bot_xml': return $this->tryFiles ($base."/mambots/$option.xml");
            case 'menu_xml': return $this->tryFiles ($base."/administrator/components/com_menus/$option/$option.xml");
            case 'installer_html': return $this->tryFiles($base."/administrator/components/com_installer/$option/$option.html.php");
            case 'installer_class': return $this->tryFiles($base."/administrator/components/com_installer/$option/$option.class.php");
        }
    }

    /**
	* Detects a 'visit'
	*
	* This function updates the agent and domain table hits for a particular
	* visitor.  The user agent is recorded/incremented if this is the first visit.
	* A cookie is set to mark the first visit.
	*/
    function detect() {
        if (mamboCore::get('mosConfig_enable_stats') == 1) {
            if (mosGetParam( $_COOKIE, 'mosvisitor', 0 )) return;
            setcookie( "mosvisitor", "1" );

            $agent = $_SERVER['HTTP_USER_AGENT'];
            $browser = mosGetBrowser( $agent );
            $os = mosGetOS( $agent );
            $domain = gethostbyaddr( $_SERVER['REMOTE_ADDR'] );
            // tease out the last element of the domain
            $tldomain = split( "\.", $domain );
            $tldomain = $tldomain[count( $tldomain )-1];
            if (is_numeric( $tldomain )) {
                $tldomain = "Unknown";
            }

            $this->_db->setQuery( "SELECT count(*), type FROM #__stats_agents WHERE (agent='$browser' AND type=0) OR (agent='$os' AND type=1) OR (agent='$tldomain' AND type=2) GROUP BY type");
            $stats = $this->_db->loadObjectList();
            $sql['browser'] = "INSERT INTO #__stats_agents (agent,type) VALUES ('$browser',0)";
            $sql['os'] = "INSERT INTO #__stats_agents (agent,type) VALUES ('$os',1)";
            $sql['domain'] = "INSERT INTO #__stats_agents (agent,type) VALUES ('$tldomain',2)";
            if ($stats) foreach ($stats as $stat) {
                if ($stat->type == 0) $sql['agents'] = "UPDATE #__stats_agents SET hits=(hits+1) WHERE agent='$browser' AND type=0";
                if ($stat->type == 1) $sql['os'] = "UPDATE #__stats_agents SET hits=(hits+1) WHERE agent='$os' AND type=1";
                if ($stat->type == 2) $sql['domain'] = "UPDATE #__stats_agents SET hits=(hits+1) WHERE agent='$tldomain' AND type=2";
            }
            $this->_db->setQuery(implode('; ',$sql));
            $this->_db->query_batch();
        }
    }

    /**
	* @return correct Itemid for Content Item
	*/
    function getItemid ($id, $typed=1, $link=1, $bs=1, $bc=1, $gbs=1) {
        require_once(mamboCore::get('mosConfig_absolute_path').'/components/com_content/content.class.php');
        $handler =& contentHandler::getInstance();
        return $handler->getItemid($id, $typed, $link, $bs, $bc, $gbs);
    }

    function liveBookMark () {
        // support for Firefox Live Bookmarks ability for site syndication
        $c_handler =& mosComponentHandler::getInstance();
        $params = $c_handler->getParamsByName('Syndicate');
        $live_bookmark = $params->get( 'live_bookmark', 0 );
        if ($live_bookmark) {
            // custom bookmark file name
            $bookmark_file = $params->get( 'bookmark_file', $live_bookmark );
            $link_file 	= mamboCore::get('mosConfig_live_site').'/cache/'. $bookmark_file;
            $filename 	= mamboCore::get('mosConfig_absolute_path').'/cache/'. $bookmark_file;
            $cache 		= $params->get( 'cache', 1 );
            $cache_time = $params->get( 'cache_time', 3600 );
            $title 		= $params->def( 'title', mamboCore::get('mosConfig_sitename') );
            // checks to see if cache file exists, to determine whether to create a new one
            if ( !file_exists( $filename ) || ( ( time() - filemtime( $filename ) ) > $cache_time ) ) {
                $task		= 'live_bookmark';
                // sets bookmark feed type
                $_GET['feed'] = str_replace( '.xml', '', $live_bookmark );
                // loads rss component to create bookmark file
                require_once( mamboCore::get('mosConfig_absolute_path').'/components/com_rss/rss.php' );
            }
            // outputs link tag for page
			?>
			<link rel="alternate" type="application/rss+xml" title="<?php echo $title; ?>" href="<?php echo $link_file; ?>" />
			<?php
        }
    }

    function mosShowHead () {
        global $_VERSION;
        $mosConfig_live_site = mamboCore::get('mosConfig_live_site');
        $this->appendMetaTag( 'description', mamboCore::get('mosConfig_MetaDesc'), true );
        $this->appendMetaTag( 'keywords', mamboCore::get('mosConfig_MetaKeys'), true );
        echo $this->getHead();
        if (mamboCore::get('mosConfig_sef')) {
            echo "<base href=\"$mosConfig_live_site/\" />\r\n";
        }
        $my = mamboCore::get('currentUser');
        if ( $my->id ) {
			?>
			<script language="JavaScript1.2" src="<?php echo $mosConfig_live_site;?>/includes/js/mambojavascript.js" type="text/javascript"></script>
			<?php
        }
        $this->liveBookMark();
        // outputs link tag for page
        $configuration =& mamboCore::getMamboCore();
		?>
		<link rel="shortcut icon" href="<?php echo $configuration->getFavIcon();?>" />
		<?php
    }


    /**
	* retained for backward compatability
	*/
	function getBlogSectionCount() {
		require_once(mamboCore::get('mosConfig_absolute_path').'/components/com_content/content.class.php');
		$handler =& new contentHandler();
		return $handler->getBlogSectionCount();
	}

	function getBlogCategoryCount() {
		require_once(mamboCore::get('mosConfig_absolute_path').'/components/com_content/content.class.php');
		$handler =& new contentHandler();
		return $handler->getBlogCategoryCount();
	}

	function getGlobalBlogSectionCount() {
		require_once(mamboCore::get('mosConfig_absolute_path').'/components/com_content/content.class.php');
		$handler =& new contentHandler();
		return $handler->getGlobalBlogSectionCount();
	}

	function getStaticContentCount() {
		require_once(mamboCore::get('mosConfig_absolute_path').'/components/com_content/content.class.php');
		$handler =& new contentHandler();
		return $handler->getStaticContentCount();
	}

	function getContentItemLinkCount() {
		require_once(mamboCore::get('mosConfig_absolute_path').'/components/com_content/content.class.php');
		$handler =& new contentHandler();
		return $handler->getContentItemLinkCount();
	}
	/**
	* retained for backward compatability
	*/

}

/**
* Class to support function caching
* @package Mambo
*/
class mosCache {
    /**
	* @return object A function cache object
	*/
    function &getCache(  $group=''  ) {
        $mosConfig_absolute_path = mamboCore::get('mosConfig_absolute_path');
        require_once($mosConfig_absolute_path.'/includes/Cache/Lite/Function.php');
        $path = mamboCore::get('mosConfig_cachepath');
        $caching = mamboCore::get('mosConfig_caching');
        $time = mamboCore::get('mosConfig_cachetime');
        $options = array(
        'cacheDir' => "$path/",
        'caching' => $caching,
        'defaultGroup' => $group,
        'lifeTime' => $time
        );
        $cache =& new Cache_Lite_Function( $options );
        return $cache;
    }
    /**
	* Cleans the cache
	*/
    function cleanCache ($group=false) {
        if (mamboCore::get('mosConfig_caching')) {
            $cache =& mosCache::getCache( $group );
            $cache->clean( $group );
        }
    }
}

/**
* Session database table class
* @package Mambo
*/
class mosSession extends mosDBTable {
    /** @var int Primary key */
    var $session_id=null;
    /** @var time */
    var $time=null;
    /** @var int User ID */
    var $userid=0;
    /** @var string */
    var $usertype=null;
    /** @var string */
    var $username='';
    /** @var int User group ID */
    var $gid=0;
    /** @var int */
    var $guest=1;
    /** @var string */
    var $_session_cookie=null;

    /**
	* @param database A database connector object
	*/
    function mosSession() {
        $database =& mamboDatabase::getInstance();
        $this->mosDBTable( '#__session', 'session_id', $database );
        $this->time = time();
    }

    function validate ($user) {
        // check against db record of session
        $session_id = mosGetParam( $_SESSION, 'session_id', '' );
        $logintime = mosGetParam( $_SESSION, 'session_logintime', '' );
        if ($session_id == md5( $user->id.$user->username.$user->usertype.$logintime )) {
            $current_time = time();
            $database =& mamboDatabase::getInstance();
            $database->setQuery ("UPDATE #__session"
            . "\nSET time='$current_time', guest=-3-guest"
            . "\nWHERE session_id='$session_id'"
            . " AND username = '" . $database->getEscaped( $user->username ) . "'"
            . " AND userid = " . intval( $user->id )
            );
            if (!$result = $database->query()) echo $database->stderr();
            elseif ($database->getAffectedRows() == 1) return true;
        }
        return false;
    }

    function &getCurrent () {
        static $currentSession;
        if (!is_object($currentSession)) {
            $currentSession = new mosSession();
            mosSession::purge();
            $sessionCookieName = md5('site'.mamboCore::get('mosConfig_live_site'));
            $sessioncookie = mosGetParam($_COOKIE, $sessionCookieName, null);
            $usercookie = mosGetParam($_COOKIE, 'usercookie', null);
            if ($currentSession->load(md5($sessioncookie.$_SERVER['REMOTE_ADDR']))) {
                // Session cookie exists, update time in session table
                $currentSession->time = time();
                $currentSession->update();
            } else {
                $currentSession->generateId();
                if (!$currentSession->insert()) {
                    die( $currentSession->getError() );
                }
                setcookie( $sessionCookieName, $currentSession->getCookie(), time() + 43200, '/' );
                //$_COOKIE["sessioncookie"] = $session->getCookie();
                if ($usercookie) {
                    // Remember me cookie exists. Login with usercookie info.
                    require_once (mamboCore::get('mosConfig_absolute_path').'/includes/authenticator.php');
                    $authenticator =& mamboAuthenticator::getInstance();
                    $authenticator->authenticateUser ($message, $usercookie['username'], $usercookie['password'], null, $currentSession);
                }
            }
        }
        return $currentSession;
    }

    function insert() {
        $ret = $this->_db->insertObject( $this->_tbl, $this );

        if( !$ret ) {
            $this->_error = strtolower(get_class( $this ))."::store failed <br />" . $this->_db->stderr();
            return false;
        } else {
            return true;
        }
    }

    function update( $updateNulls=false ) {
        $ret = $this->_db->updateObject( $this->_tbl, $this, 'session_id', $updateNulls );

        if( !$ret ) {
            $this->_error = strtolower(get_class( $this ))."::store failed <br />" . $this->_db->stderr();
            return false;
        } else {
            return true;
        }
    }

    function generateId() {
        $failsafe = 20;
        $randnum = 0;
        while ($failsafe--) {
            $randnum = md5( uniqid( microtime(), 1 ) );
            if ($randnum != "") {
                $cryptrandnum = md5( $randnum );
                $this->_db->setQuery( "SELECT $this->_tbl_key FROM $this->_tbl WHERE $this->_tbl_key=MD5('$randnum')" );
                if(!($result = $this->_db->query())) {
                    die( $this->_db->stderr( true ));
                    // todo: handle gracefully
                }
                if ($this->_db->getNumRows($result) == 0) {
                    break;
                }
            }
        }
        $this->_session_cookie = $randnum;
        $this->session_id = md5( $randnum . $_SERVER['REMOTE_ADDR'] );
    }

    function getCookie() {
        return $this->_session_cookie;
    }

    function purge() {
        $past = time() - intval(mamboCore::get('mosConfig_lifetime'));
        $adminpast = time() - 3600;
        $database =& mamboDatabase::getInstance();
        $database->setQuery("DELETE FROM #__session WHERE (time<$past AND guest>=0) OR (time<$adminpast AND guest<0)");
        return $database->query();
    }

}

/**
* Parameters handler
* @package Mambo
*/
class mosParameters {
    /** @var object */
    var $_params = null;
    /** @var string The raw params string */
    var $_raw = null;
    /**
* Constructor
* @param string The raw parms text
* @param string Path to the xml setup file
* @var string The type of setup file
*/
    function mosParameters( $text, $process_sections = false) {
        $this->_params = $this->parse( $text, $process_sections );
        $this->_raw = $text;
    }
    /**
* Get the result of parsing the string provided on creation
* @return string parsed result
*/
    function getParams () {
        return $this->_params;
    }
    /**
* @param string The name of the param
* @param string The value of the parameter
* @return string The set value
*/
    function set( $key, $value='' ) {
        $this->_params->$key = $value;
        return $value;
    }
    /**
* Sets a default value if not alreay assigned
* @param string The name of the param
* @param string The value of the parameter
* @return string The set value
*/
    function def( $key, $value='' ) {
        return $this->set( $key, $this->get( $key, $value ) );
    }
    /**
* @param string The name of the param
* @param mixed The default value if not found
* @return string
*/
    function get( $key, $default='' ) {
        if (isset( $this->_params->$key )) return $this->_params->$key === '' ? $default : $this->_params->$key;
        else return $default;
    }
    /**
* Look to see if string is bracketed by opener and closer
* If so, extract and trim the bracketed string
* Otherwise, return a null string
**/
    function getBracketed ($text, $opener, $closer) {
        if (strlen($text) > 1 AND ($text[0] != $opener OR substr($text,-1) != $closer)) return '';
        else return trim(substr($text,1,-1));
    }
    /**
* Parse an .ini string, based on phpDocumentor phpDocumentor_parse_ini_file function
* @param mixed The ini string or array of lines
* @param boolean add an associative index for each section [in brackets]
* @return object
*/
    function parse( $txt, $process_sections = false ) {
        $result = new stdClass();
        if (is_string($txt)) $lines = explode( "\n", $txt );
        elseif (is_array($txt)) $lines = $txt;
        else return $result;

        $sec_name = '';
        $unparsed = 0;

        foreach ($lines as $line) {
            // ignore comments and null lines
            $line = trim($line);
            if (strlen($line) == 0 OR $line[0] == ';') continue;

            if ($sec_name = $this->getBracketed($line, '[', ']')) {
                if ($process_sections) $result->$sec_name = new stdClass();
                continue;
            }

            if (count($propsetter = explode ('=', $line, 2)) == 2) {
                $property = trim($propsetter[0]);
                if ($pquoted = $this->getBracketed($property, '"', '"')) $property = stripcslashes($pquoted);
                $value = trim($propsetter[1]);
                if ($value == 'false') $value = false;
                elseif ($value == 'true') $value = true;
                else if ($vquoted = $this->getBracketed($value, '"', '"')) $value = stripcslashes($vquoted);
                if ($process_sections AND $sec_name) $result->$sec_name->$property = $value;
                else $result->$property = $value;
            }
            else {
                $property = '__invalid' . $unparsed++ . '__';
                if ($process_sections AND $sec_name) $result->$sec_name->$property = $line;
                else $result->$property = $line;
            }
        }
        return $result;
    }
    /**
	* @param string The name of the control, or the default text area if a setup file is not found
	* @return string HTML
	*/
    function render( $name='params' ) {
        if (is_file($this->_path)) {
            $parser = new mosXMLParams ($this->_path, $this, $name);
            if (count($parser->html)) return implode("\n", $parser->html);
        }
        $raw = $this->_raw;
        return "<textarea name='$name' cols='40' rows='10' class='text_area'>$raw</textarea>";
    }

    /**
	* special handling for textarea param
	*/
    function textareaHandling( &$txt ) {
        foreach ($txt as $key=>$value) $txt[$key] = str_replace("\n", '<br />', $value);
        return implode( "\n", $txt );
    }
}

/**
* Page generation time
* @package Mambo
*/
class mosProfiler {
    var $start=0;
    var $prefix='';

    function mosProfiler( $prefix='' ) {
        $this->start = $this->getmicrotime();
        $this->prefix = $prefix;
    }

    function mark( $label ) {
        return sprintf ( "\n<div class=\"profiler\">$this->prefix %.3f $label</div>", $this->getmicrotime() - $this->start );
    }

    function getmicrotime(){
        list($usec, $sec) = explode(" ",microtime());
        return ((float)$usec + (float)$sec);
    }
}
?>
