tbrehm
2007-06-29 e2d6ed954b42c72645aeb2476591e6d42cf48991
- added basic update script
- improved several functions in site module
- added server classes to restart services
12 files modified
8 files added
3748 ■■■■■ changed files
install/install.php 24 ●●●● patch | view | raw | blame | history
install/lib/installer_base.lib.php 2 ●●●●● patch | view | raw | blame | history
install/sql/ispconfig3.sql 2 ●●●●● patch | view | raw | blame | history
install/update.php 155 ●●●●● patch | view | raw | blame | history
interface/lib/classes/tform.inc.php 51 ●●●● patch | view | raw | blame | history
interface/lib/classes/tform_actions.inc.php 39 ●●●●● patch | view | raw | blame | history
interface/web/sites/form/ftp_user.tform.php 13 ●●●● patch | view | raw | blame | history
interface/web/sites/templates/ftp_user_advanced.htm 4 ●●●● patch | view | raw | blame | history
interface/web/sites/web_domain_edit.php 8 ●●●●● patch | view | raw | blame | history
server/conf/vhost.conf.master 39 ●●●● patch | view | raw | blame | history
server/lib/classes/file.inc.php 319 ●●●●● patch | view | raw | blame | history
server/lib/classes/services.inc.php 79 ●●●●● patch | view | raw | blame | history
server/lib/classes/system.inc.php 999 ●●●●● patch | view | raw | blame | history
server/lib/classes/tpl.inc.php 1499 ●●●●● patch | view | raw | blame | history
server/lib/classes/tpl_cache.inc.php 186 ●●●●● patch | view | raw | blame | history
server/lib/classes/tpl_error.inc.php 92 ●●●●● patch | view | raw | blame | history
server/lib/classes/tpl_ini.inc.php 116 ●●●●● patch | view | raw | blame | history
server/mods-enabled/web_module.inc.php 17 ●●●●● patch | view | raw | blame | history
server/plugins-enabled/apache2_plugin.inc.php 93 ●●●●● patch | view | raw | blame | history
server/server.php 11 ●●●● patch | view | raw | blame | history
install/install.php
@@ -115,17 +115,19 @@
spamd
*/
exec("/etc/init.d/mysql restart");
exec("/etc/init.d/postfix restart");
exec("/etc/init.d/saslauthd restart");
exec("/etc/init.d/amavis restart");
exec("/etc/init.d/clamav-daemon restart");
exec("/etc/init.d/courier-authdaemon restart");
exec("/etc/init.d/courier-imap restart");
exec("/etc/init.d/courier-imap-ssl restart");
exec("/etc/init.d/courier-pop restart");
exec("/etc/init.d/courier-pop-ssl restart");
exec("/etc/init.d/apache2 restart");
swriteln('Restarting services ...');
system("/etc/init.d/mysql restart");
system("/etc/init.d/postfix restart");
system("/etc/init.d/saslauthd restart");
system("/etc/init.d/amavis restart");
system("/etc/init.d/clamav-daemon restart");
system("/etc/init.d/courier-authdaemon restart");
system("/etc/init.d/courier-imap restart");
system("/etc/init.d/courier-imap-ssl restart");
system("/etc/init.d/courier-pop restart");
system("/etc/init.d/courier-pop-ssl restart");
system("/etc/init.d/apache2 restart");
system("/etc/init.d/pure-ftpd-mysql restart");
echo "Installation finished.\n";
install/lib/installer_base.lib.php
@@ -467,6 +467,8 @@
        wf($conf["dist_pureftpd_config_dir"].'/'.$configfile,$content);
        exec('chmod 600 '.$conf["dist_pureftpd_config_dir"].'/'.$configfile);
        exec('chown root:root '.$conf["dist_pureftpd_config_dir"].'/'.$configfile);
        // enable chrooting
        exec('echo "yes" > /etc/pure-ftpd/conf/ChrootEveryone');
    
    }
    
install/sql/ispconfig3.sql
@@ -404,6 +404,8 @@
-- Daten für Tabelle `server`
-- 
INSERT INTO `server` (`server_id`, `sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `server_name`, `mail_server`, `web_server`, `dns_server`, `file_server`, `db_server`, `vserver_server`, `config`, `updated`, `active`) VALUES (1, 1, 1, 'riud', 'riud', 'r', 'Server 1', 1, 1, 1, 1, 1, 1, '[global]\nwebserver=apache\nmailserver=postfix\ndnsserver=mydns\n\n[mail]\nmodule=postfix_mysql\nmaildir_path=/home/vmail/[domain]/[localpart]/\nhomedir_path=/home/vmail/\nmailuser_uid=5000\nmailuser_gid=5000\nmailuser_name=vmail\nmailuser_group=vmail\n\n[getmail]\ngetmail_config_dir=/etc/getmail\n\n[web]\nwebsite_path=/var/clients/client[client_id]/web[website_id]\nwebsite_symlinks=/var/www/[website_domain]/:/var/clients/client[client_id]/[website_domain]/\n\n', 0, 1);
-- --------------------------------------------------------
-- 
install/update.php
New file
@@ -0,0 +1,155 @@
<?php
/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
    ISPConfig 3 installer.
*/
// Include the library with the basic installer functions
require_once('lib/install.lib.php');
// Include the base class of the installer class
require_once('lib/installer_base.lib.php');
$distname = get_distname();
include_once("/usr/local/ispconfig/server/lib/config.inc.php");
$conf_old = $conf;
unset $conf;
// Include the distribution specific installer class library
// and configuration
include_once('dist/lib/'.$distname.'.lib.php');
include_once('dist/conf/'.$distname.'.conf.php');
// Set the mysql login information
$conf["mysql_server_host"] = $conf_old["db_host"];
$conf["mysql_server_database"] = $conf_old["db_database"];
$conf["mysql_server_ispconfig_user"] = $conf_old["db_user"];
$conf["mysql_server_ispconfig_password"] = $conf_old["db_password"];
$inst = new installer();
echo "This application will update ISPConfig 3 on your server.\n";
// $conf["language"] = $inst->request_language();
// TODO: all other queries, for testing I will setup everything in $conf
// Initialize the MySQL server connection
include_once('lib/mysql.lib.php');
$inst->db = new db();
// Database update is a bit brute force and should be rebuild later ;)
// export the current database data
exec("mysqldump -h $conf[mysql_server_host] -u $conf[mysql_server_ispconfig_user] -p$conf[mysql_server_ispconfig_password] -c -t --add-drop-table --add-locks --all --quick --lock-tables $conf[mysql_server_database] > existing_db.sql  &> /dev/null");
// Delete the old database
exec("/etc/init.d/mysql stop");
exec("rm -rf /var/lib/mysql/".$conf["db_database"]);
exec("/etc/init.d/mysql start");
// Create the mysql database
$inst->configure_database();
// empty all databases
$db_tables = $inst->db->getTables();
foreach($db_tables as $table) {
    $inst->db->query("TRUNCATE $table");
}
// load old data back into database
exec("mysql -h $conf[mysql_server_host] -u $conf[mysql_server_ispconfig_user] -p$conf[mysql_server_ispconfig_password] $conf[mysql_server_database] < existing_db.sql  &> /dev/null");
// Configure postfix
$inst->configure_postfix();
// Configure saslauthd
swriteln('Configuring SASL');
$inst->configure_saslauthd();
// Configure PAM
swriteln('Configuring PAM');
$inst->configure_pam();
// Configure courier
swriteln('Configuring Courier');
$inst->configure_courier();
// Configure Spamasassin
swriteln('Configuring Spamassassin');
$inst->configure_spamassassin();
// Configure Amavis
swriteln('Configuring Amavisd');
$inst->configure_amavis();
// Configure Getmail
swriteln('Configuring Getmail');
$inst->configure_getmail();
// Configure Getmail
swriteln('Configuring Pureftpd');
$inst->configure_pureftpd();
// Configure ISPConfig
swriteln('Installing ISPConfig');
$inst->install_ispconfig();
// Configure ISPConfig
swriteln('Installing Crontab');
$inst->install_crontab();
/*
Restart services:
*/
swriteln('Restarting services ...');
system("/etc/init.d/mysql restart");
system("/etc/init.d/postfix restart");
system("/etc/init.d/saslauthd restart");
system("/etc/init.d/amavis restart");
system("/etc/init.d/clamav-daemon restart");
system("/etc/init.d/courier-authdaemon restart");
system("/etc/init.d/courier-imap restart");
system("/etc/init.d/courier-imap-ssl restart");
system("/etc/init.d/courier-pop restart");
system("/etc/init.d/courier-pop-ssl restart");
system("/etc/init.d/apache2 restart");
system("/etc/init.d/pure-ftpd-mysql restart");
echo "Update finished.\n";
?>
interface/lib/classes/tform.inc.php
@@ -766,9 +766,7 @@
                                $app->error("Primary ID fehlt!");
                        }
                }
                // Daten in History tabelle speichern
                if($this->errorMessage == '' and $this->formDef['db_history'] == 'yes') $this->datalogSave($action,$primary_id,$record);
                return $sql;
        }
@@ -839,11 +837,16 @@
                // Set Wordbook for this form
                $app->tpl->setVar($this->wordbook);
    }
        }
        function getDataRecord($primary_id) {
            global $app;
            $sql = "SELECT * FROM ".$escape.$this->formDef['db_table'].$escape." WHERE ".$this->formDef['db_table_idx']." = ".$primary_id;
            return $app->db->queryOneRecord($sql);
        }
        function datalogSave($action,$primary_id,$record_new) {
        function datalogSave($action,$primary_id, $record_old, $record_new) {
                global $app,$conf;
                // Füge Backticks nur bei unvollständigen Tabellennamen ein
@@ -852,17 +855,19 @@
                } else {
                        $escape = '`';
                }
                if($action == "UPDATE") {
                /*
                if($action == "UPDATE" or $action == "DELETE") {
                        $sql = "SELECT * FROM ".$escape.$this->formDef['db_table'].$escape." WHERE ".$this->formDef['db_table_idx']." = ".$primary_id;
                        $record_old = $app->db->queryOneRecord($sql);
                } else {
                        $record_old = array();
                }
                */
                $diffrec = array();
                
                if(is_array($record_new)) {
                if(is_array($record_new) && count($record_new) > 0) {
                        foreach($record_new as $key => $val) {
                                if($record_old[$key] != $val) {
                                        // Record has changed
@@ -870,13 +875,22 @@
                                                               'new' => $val);
                                }
                        }
                } elseif(is_array($record_old)) {
                        foreach($record_old as $key => $val) {
                                if($record_new[$key] != $val) {
                                        // Record has changed
                                        $diffrec[$key] = array('new' => $record_new[$key],
                                                               'old' => $val);
                                }
                        }
                }
                $this->diffrec = $diffrec;
                
                // Full diff records for ISPConfig, they have a different format then the simple diffrec
                $diffrec_full = array();
                if(is_array($record_old)) {
                if(is_array($record_old) && count($record_old) > 0) {
                        foreach($record_old as $key => $val) {
                                if(isset($record_new[$key]) && $record_new[$key] != $val) {
                                    // Record has changed
@@ -885,6 +899,17 @@
                                } else {
                                    $diffrec_full['old'][$key] = $val;
                                    $diffrec_full['new'][$key] = $val;
                                }
                        }
                } elseif(is_array($record_new)) {
                        foreach($record_new as $key => $val) {
                                if(isset($record_new[$key]) && $record_old[$key] != $val) {
                                    // Record has changed
                                    $diffrec_full['new'][$key] = $val;
                                    $diffrec_full['old'][$key] = $record_old[$key];
                                } else {
                                    $diffrec_full['new'][$key] = $val;
                                    $diffrec_full['old'][$key] = $val;
                                }
                        }
                }
@@ -903,7 +928,11 @@
                        $diffstr = $app->db->quote(serialize($diffrec_full));
                        $username = $app->db->quote($_SESSION["s"]["user"]["username"]);
                        $dbidx = $this->formDef['db_table_idx'].":".$primary_id;
                        $action = ($action == 'INSERT')?'i':'u';
                        // $action = ($action == 'INSERT')?'i':'u';
                        if($action == 'INSERT') $action = 'i';
                        if($action == 'UPDATE') $action = 'u';
                        if($action == 'DELETE') $action = 'd';
                        $sql = "INSERT INTO sys_datalog (dbtable,dbidx,server_id,action,tstamp,user,data) VALUES ('".$this->formDef['db_table']."','$dbidx','$server_id','$action','".time()."','$username','$diffstr')";
                        $app->db->query($sql);
                }
interface/lib/classes/tform_actions.inc.php
@@ -102,9 +102,13 @@
                $ext_where = '';
                $sql = $app->tform->getSQL($this->dataRecord,$app->tform->getCurrentTab(),'UPDATE',$this->id,$ext_where);
                if($app->tform->errorMessage == '') {
                        if($app->tform->formDef['db_history'] == 'yes') {
                            $old_data_record = $app->tform->getDataRecord($this->id);
                        }
                        if(!empty($sql)) {
                                $app->db->query($sql);
                            $app->db->query($sql);
                            if($app->db->errorMessage != '') die($app->db->errorMessage);
                        }
                        
@@ -118,6 +122,14 @@
                        }
                        $this->onAfterUpdate();
                        // Write data history (sys_datalog)
                        if($app->tform->formDef['db_history'] == 'yes') {
                            $new_data_record = $app->tform->getDataRecord($this->id);
                            $app->tform->datalogSave('UPDATE',$this->id,$old_data_record,$new_data_record);
                            unset($new_data_record);
                            unset($old_data_record);
                        }
                        if($_REQUEST["next_tab"] == '') {
                           $list_name = $_SESSION["s"]["form"]["return_to"];
@@ -175,6 +187,13 @@
                        }
                        $this->onAfterInsert();
                        // Write data history (sys_datalog)
                        if($app->tform->formDef['db_history'] == 'yes') {
                            $new_data_record = $app->tform->getDataRecord($this->id);
                            $app->tform->datalogSave('INSERT',$this->id,array(),$new_data_record);
                            unset($new_data_record);
                        }
                        
                     if($_REQUEST["next_tab"] == '') {
@@ -260,20 +279,10 @@
                        $record_old = $app->db->queryOneRecord("SELECT * FROM ".$liste["table"]." WHERE ".$liste["table_idx"]." = ".$this->id);
                        // Saving record to datalog when db_history enabled
                        if($form["db_history"] == 'yes') {
                                $diffrec = array();
                                foreach($record_old as $key => $val) {
                                        // Record has changed
                                        $diffrec[$key] = array('old' => $val,
                                                                                           'new' => '');
                                }
                                $diffstr = $app->db->quote(serialize($diffrec));
                                $username = $app->db->quote($_SESSION["s"]["user"]["username"]);
                                $dbidx = $app->tform->formDef['db_table_idx'].":".$this->id;
                                $sql = "INSERT INTO sys_datalog (dbtable,dbidx,action,tstamp,user,data) VALUES ('".$app->tform->formDef['db_table']."','$dbidx','d','".time()."','$username','$diffstr')";
                                $app->db->query($sql);
                        if($app->tform->formDef["db_history"] == 'yes') {
                            $old_data_record = $app->tform->getDataRecord($this->id);
                            $app->tform->datalogSave('DELETE',$this->id,$old_data_record,array());
                            unset($old_data_record);
                        }
                        $app->db->query("DELETE FROM ".$liste["table"]." WHERE ".$liste["table_idx"]." = ".$this->id);
interface/web/sites/form/ftp_user.tform.php
@@ -99,6 +99,7 @@
        'password' => array (
            'datatype'    => 'VARCHAR',
            'formtype'    => 'PASSWORD',
            'encryption' => 'CRYPT',
            'default'    => '',
            'value'        => '',
            'width'        => '30',
@@ -138,26 +139,26 @@
    # Begin Datatable fields
    ##################################
        'uid' => array (
            'datatype'    => 'INTEGER',
            'datatype'    => 'VARCHAR',
            'formtype'    => 'TEXT',
            'validators'    => array (     0 => array (    'type'    => 'NOTEMPTY',
                                                        'errmsg'=> 'uid_error_empty'),
                                    ),
            'default'    => '0',
            'value'        => '',
            'width'        => '5',
            'maxlength'    => '5'
            'width'        => '30',
            'maxlength'    => '255'
        ),
        'gid' => array (
            'datatype'    => 'INTEGER',
            'datatype'    => 'VARCHAR',
            'formtype'    => 'TEXT',
            'validators'    => array (     0 => array (    'type'    => 'NOTEMPTY',
                                                        'errmsg'=> 'uid_error_empty'),
                                    ),
            'default'    => '0',
            'value'        => '',
            'width'        => '5',
            'maxlength'    => '5'
            'width'        => '30',
            'maxlength'    => '255'
        ),
        'dir' => array (
            'datatype'    => 'VARCHAR',
interface/web/sites/templates/ftp_user_advanced.htm
@@ -1,11 +1,11 @@
<table width="500" border="0" cellspacing="0" cellpadding="2">
  <tr>
    <td class="frmText11">{tmpl_var name='uid_txt'}:</td>
    <td class="frmText11"><input name="uid" type="text" class="text" value="{tmpl_var name='uid'}" size="5" maxlength="5"></td>
    <td class="frmText11"><input name="uid" type="text" class="text" value="{tmpl_var name='uid'}" size="30" maxlength="255"></td>
  </tr>
  <tr>
    <td class="frmText11">{tmpl_var name='gid_txt'}:</td>
    <td class="frmText11"><input name="gid" type="text" class="text" value="{tmpl_var name='gid'}" size="5" maxlength="5"></td>
    <td class="frmText11"><input name="gid" type="text" class="text" value="{tmpl_var name='gid'}" size="30" maxlength="255"></td>
  </tr>
  <tr>
    <td class="frmText11">{tmpl_var name='dir_txt'}:</td>
interface/web/sites/web_domain_edit.php
@@ -167,7 +167,8 @@
        
        // Get configuration for the web system
        $app->uses("getconf");
        $web_config = $app->getconf->get_server_config(intval($this->dataRecord["server_id"]),'web');
        $web_rec = $app->tform->getDataRecord($this->id);
        $web_config = $app->getconf->get_server_config(intval($web_rec["server_id"]),'web');
        $document_root = str_replace("[website_id]",$this->id,$web_config["website_path"]);
        
        // get the ID of the client
@@ -202,7 +203,8 @@
        
        // Get configuration for the web system
        $app->uses("getconf");
        $web_config = $app->getconf->get_server_config(intval($this->dataRecord["server_id"]),'web');
        $web_rec = $app->tform->getDataRecord($this->id);
        $web_config = $app->getconf->get_server_config(intval($web_rec["server_id"]),'web');
        $document_root = str_replace("[website_id]",$this->id,$web_config["website_path"]);
        
        // get the ID of the client
@@ -211,7 +213,7 @@
            $client = $app->db->queryOneRecord("SELECT client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = $client_group_id");
            $client_id = intval($client["client_id"]);
        } else {
            $client_id = intval($this->dataRecord["client_group_id"]);
            $client_id = intval($web_rec["client_group_id"]);
            $client = $app->db->queryOneRecord("SELECT client_id FROM sys_group WHERE sys_group.groupid = ".intval($this->dataRecord["client_group_id"]));
            $client_id = intval($client["client_id"]);
        }
server/conf/vhost.conf.master
@@ -1,25 +1,26 @@
NameVirtualHost *:80
# NameVirtualHost *:80
<VirtualHost <tmpl_var name='ip_address'>:80>
    DocumentRoot <tmpl_var name='document_root'>
    ServerName <tmpl_var name='domain'>
    ServerAlias <tmpl_var name='alias'>
    
    <tmpl_if name='cgi'>
    </tmpl_if>
    <tmpl_if name='ssi'>
    </tmpl_if>
    <tmpl_if name='suexec'>
    </tmpl_if>
    <tmpl_if name='php' op='==' value='mod'>
    </tmpl_if>
    <tmpl_if name='php' op='==' value='suphp'>
    </tmpl_if>
    <tmpl_if name='php' op='==' value='cgi'>
    </tmpl_if>
<tmpl_if name='cgi'>
    # cgi enabled
</tmpl_if>
<tmpl_if name='ssi'>
    # ssi enabled
</tmpl_if>
<tmpl_if name='suexec'>
    # suexec enabled
</tmpl_if>
<tmpl_if name='php' op='==' value='mod'>
    # mod_php enabled
</tmpl_if>
<tmpl_if name='php' op='==' value='suphp'>
    # suphp enabled
</tmpl_if>
<tmpl_if name='php' op='==' value='cgi'>
    # php as cgi enabled
</tmpl_if>
</VirtualHost>
server/lib/classes/file.inc.php
New file
@@ -0,0 +1,319 @@
<?php
/*
Copyright (c) 2007, projektfarm Gmbh, Till Brehm, Falko Timme
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class file{
function rf($file){
  global $app;
  clearstatcache();
  if(!$fp = fopen ($file, "rb")){
    $app->log("WARNING: could not open file ".$file, 2);
    return false;
  } else {
    if(filesize($file) > 0){
      $content = fread($fp, filesize($file));
    } else {
      $content = "";
    }
    fclose($fp);
    return $content;
  }
}
function wf($file, $content){
  global $app;
  $this->mkdirs(dirname($file));
  if(!$fp = fopen ($file, "wb")){
    $app->log("WARNING: could not open file ".$file, 2);
    return false;
  } else {
    fwrite($fp,$content);
    fclose($fp);
    return true;
  }
}
function af($file, $content){
  global $app;
  $this->mkdirs(dirname($file));
  if(!$fp = fopen ($file, "ab")){
    $app->log("WARNING: could not open file ".$file, 2);
    return false;
  } else {
    fwrite($fp,$content);
    fclose($fp);
    return true;
  }
}
function no_comments($file, $comment = '#'){
  $content = $this->unix_nl($this->rf($file));
  $lines = explode("\n", $content);
  if(!empty($lines)){
    foreach($lines as $line){
      if(strstr($line, $comment)){
        $pos = strpos($line, $comment);
        if($pos != 0){
          $new_lines[] = substr($line,0,$pos);
        } else {
          $new_lines[] = "";
        }
      } else {
        $new_lines[] = $line;
      }
    }
  }
  if(is_array($new_lines)){
    $content_without_comments = implode("\n", $new_lines);
    $new_lines = NULL;
    return $content_without_comments;
  } else {
    return "";
  }
}
function manual_entries($file, $separator = '#### MAKE MANUAL ENTRIES BELOW THIS LINE! ####'){
  if(is_file($file)){
    $content = $this->rf($file);
    $parts = explode($separator, $content);
    $manual = "\n".trim($parts[1]);
    return $manual;
  } else {
    return "";
  }
}
function remove_blank_lines($input, $file = 1){
  //Leerzeilen löschen
  if($file){
    $content = $this->unix_nl($this->rf($input));
  } else {
    $content = $input;
  }
  $lines = explode("\n", $content);
  if(!empty($lines)){
    foreach($lines as $line){
      if(trim($line) != "") $new_lines[] = $line;
    }
  }
  if(is_array($new_lines)){
    $content = implode("\n", $new_lines);
  } else {
    $content = "";
  }
  if($file){
    $this->wf($input, $content);
  } else {
    return $content;
  }
}
function unix_nl($input){
  $output = str_replace("\r\n", "\n", $input);
  $output = str_replace("\r", "\n", $output);
  return $output;
}
function fileowner($file){
  $owner_id = fileowner($file);
  clearstatcache();
  return $owner_id;
}
function mkdirs($strPath, $mode = '0755'){
  // Verzeichnisse rekursiv erzeugen
  if(is_dir($strPath)) return true;
  $pStrPath = dirname($strPath);
  if(!$this->mkdirs($pStrPath, $mode)) return false;
  $old_umask = umask(0);
  $ret_val = mkdir($strPath, octdec($mode));
  umask($old_umask);
  return $ret_val;
}
function find_includes($file){
  ob_start();
  $httpd_root = system('httpd -V | awk -F"\"" \'$1==" -D HTTPD_ROOT="{print $2}\'');
  ob_end_clean();
  clearstatcache();
  if(is_file($file) && filesize($file) > 0){
    $includes[] = $file;
    $inhalt = $this->unix_nl($this->no_comments($file));
    $lines = explode("\n", $inhalt);
    if(!empty($lines)){
      foreach($lines as $line){
        if(stristr($line, "include ")){
          $include_file = str_replace("\n", "", trim(shell_exec("echo \"$line\" | awk '{print \$2}'")));
          if(substr($include_file,0,1) != "/"){
            $include_file = $httpd_root."/".$include_file;
          }
          if(is_file($include_file)){
            if($further_includes = $this->find_includes($include_file)){
              $includes = array_merge($includes, $further_includes);
            }
          } else {
            if(strstr($include_file, "*")){
              $more_files = explode("\n", shell_exec("ls -l $include_file | awk '{print \$9}'"));
              if(!empty($more_files)){
                foreach($more_files as $more_file){
                  if(is_file($more_file)){
                    if($further_includes = $this->find_includes($more_file)){
                      $includes = array_merge($includes, $further_includes);
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  if(is_array($includes)){
    $includes = array_unique($includes);
    return $includes;
  } else {
    return false;
  }
}
function edit_dist($var, $val){
  global $$var;
  $files = array("/root/ispconfig/dist.inc.php");
  foreach($files as $file){
    if(is_file($file)){
      $file_content = $this->unix_nl($this->rf($file));
      $lines = explode("\n", $file_content);
      for($i=0;$i<sizeof($lines);$i++){
        $parts = explode("=", $lines[$i]);
        if($parts[0] == $var || $parts[0] == '$'.$var.' '){
          $parts[1] = str_replace($$var, $val, $parts[1]);
        }
        $lines[$i] = implode("=", $parts);
      }
      $file_content = implode("\n", $lines);
      $this->wf($file, $file_content);
    }
  }
}
function getDirectoryListing($dirname, $sortorder = "a", $show_subdirs = 0, $show_subdirfiles = 0, $exts = "", $ext_save = 1){
// This function will return an array with filenames based on the criteria you can set in the variables
// @sortorder : a for ascending (the standard) or d for descending (you can use the "r" for reverse as well, works the same)
// @show_subdirs : 0 for NO, 1 for YES - meaning it will show the names of subdirectories if there are any
// Logically subdirnames will not be checked for the required extentions
// @show_subdirfiles : 0 for NO, 1 for YES - meaning it will show files from the subdirs
// Files from subdirs will be prefixed with the subdir name and checked for the required extentions.
// @exts can be either a string or an array, if not passed to the function, then the default will be a check for common image files
// If exts is set to "all" then all extentions are allowed
// @ext_save : 1 for YES, 0 for NO - meaning it will filter out system files or not (such as .htaccess)
   $dirname = realpath($dirname);
   if (!$exts || empty($exts) || $exts == "") {
       $exts = array("jpg", "gif", "jpeg", "png");
   }
   if ($handle = opendir($dirname)) {
       $filelist = array();
       while (false !== ($file = readdir($handle))) {
           // Filter out higher directory references
           if ($file != "." && $file != "..") {
               // Only look at directories or files, filter out symbolic links
               if ( filetype ($dirname."/".$file) != "link") {
                   // If it's a file, check against valid extentions and add to the list
                   if ( filetype ($dirname."/".$file) == "file" ) {
                       if ($this->checkFileExtension($file, $exts, $ext_save)) {
                                       $filelist[] = $file;
                       }
                   }
                   // If it's a directory and either subdirs should be listed or files from subdirs add relevant names to the list
                   else if ( filetype ($dirname."/".$file) == "dir" && ($show_subdirs == 1 || $show_subdirfiles == 1)) {
                       if ($show_subdirs == 1) {
                           $filelist[] = $file;
                       }
                       if ($show_subdirfiles == 1) {
                           $subdirname = $file;
                           $subdirfilelist = $this->getDirectoryListing($dirname."/".$subdirname."/", $sortorder, $show_subdirs, $show_subdirfiles, $exts, $ext_save);
                           for ($i = 0 ; $i < count($subdirfilelist) ; $i++) {
                               $subdirfilelist[$i] = $subdirname."/".$subdirfilelist[$i];
                           }
                           $filelist = array_merge($filelist, $subdirfilelist);
                       }
                   }
               }
           }
       }
       closedir($handle);
       // Sort the results
       if (count($filelist) > 1) {
           natcasesort($filelist);
           if ($sortorder == "d" || $sortorder == "r" ) {
               $filelist = array_reverse($filelist, TRUE);
           }
       }
       return $filelist;
   }
   else {
       return false;
   }
}
function checkFileExtension($filename, $exts, $ext_save = 1){
   $passed = FALSE;
   if ($ext_save == 1) {
       if (preg_match("/^\./", $filename)) {
           return $passed;
       }
   }
   if ($exts == "all") {
                   $passed = TRUE;
       return $passed;
   }
   if (is_string($exts)) {
       if (eregi("\.". $exts ."$", $filename)) {
                       $passed = TRUE;
           return $passed;
       }
   } else if (is_array($exts)) {
       foreach ($exts as $theExt) {
           if (eregi("\.". $theExt ."$", $filename)) {
               $passed = TRUE;
               return $passed;
           }
       }
   }
   return $passed;
}
}
?>
server/lib/classes/services.inc.php
New file
@@ -0,0 +1,79 @@
<?php
/*
Copyright (c) 2007, projektfarm Gmbh, Till Brehm, Falko Timme
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class services {
    var $registered_services = array();
    var $delayed_restarts = array();
    // This function adds a request for restarting
    // a service at the end of the configuration run.
    function restartServiceDelayed($service_name,$action = 'restart') {
        global $app;
        if(is_array($this->registered_services[$service_name])) {
            $this->delayed_restarts[$service_name] = $action;
        } else {
            $app->log("Unable to add a delayed restart for  '$service_name'. Service '$service_name' is not registered.",LOGLEVEL_WARNING);
        }
    }
    // This function restarts a service when the function is called
    function restartService($service_name,$action = 'restart') {
        global $app;
        if(is_array($this->registered_services[$service_name])) {
            $module_name = $this->registered_services[$service_name]["module"];
            $function_name = $this->registered_services[$service_name]["function"];
            $app->log("Call function '$function_name' in module '$module_name'.",LOGLEVEL_DEBUG);
            call_user_method($function_name,$app->loaded_modules[$module_name],$action);
        } else {
            $app->log("Unable to restart $service_name. Service $service_name is not registered.",LOGLEVEL_WARNING);
        }
    }
    // This function is used to register callback functions for services that can be restarted
    function registerService($service_name,$module_name, $function_name) {
        global $app;
        $this->registered_services[$service_name] = array('module' => $module_name, 'function' => $function_name);
        $app->log("Registered Service '$service_name' in module '$module_name' for processing function '$function_name'",LOGLEVEL_DEBUG);
    }
    // This function is called at the end of the server script to restart services.
    function processDelayedActions() {
        global $app;
        foreach($this->delayed_restarts as $service_name => $action) {
            $this->restartService($service_name,$action);
        }
    }
}
?>
server/lib/classes/system.inc.php
New file
@@ -0,0 +1,999 @@
<?php
/*
Copyright (c) 2007, projektfarm Gmbh, Till Brehm, Falko Timme
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class system{
var $FILE = "/root/ispconfig/scripts/lib/classes/ispconfig_system.lib.php";
var $server_id;
var $server_conf;
var $data;
function system(){
  global $go_info;
  $this->server_id = $go_info["isp"]["server_id"];
  $this->server_conf = $go_info["isp"]["server_conf"];
  $this->server_conf["passwd_datei"] = '/etc/passwd';
  $this->server_conf["shadow_datei"] = '/etc/shadow';
  $this->server_conf["group_datei"] = '/etc/group';
}
function hostname(){
  $dist = $this->server_conf["dist"];
  ob_start();
  passthru("hostname");
  $hostname = ob_get_contents();
  ob_end_clean();
  $hostname = trim($hostname);
  ob_start();
  if(!strstr($dist, "freebsd")){
    passthru("dnsdomainname");
  } else {
    passthru("domainname");
  }
  $domainname = ob_get_contents();
  ob_end_clean();
  $domainname = trim($domainname);
  if($domainname != ""){
    if(!strstr($hostname, $domainname)) $hostname .= ".".$domainname;
  }
  return $hostname;
}
function adduser($user_username, $uid, $gid, $username, $homedir, $shell, $passwort = '*'){
  global $app;
  if($this->is_user($user_username)){
    return false;
  } else {
          if(trim($user_username) != '') {
                $user_datei = $this->server_conf["passwd_datei"];
            $shadow_datei = $this->server_conf["shadow_datei"];
            $shell = realpath($shell);
            if(trim($passwort) == "") $passwort = '*';
            $new_user = "\n$user_username:x:$uid:$gid:$username:$homedir:$shell\n";
                $app->log->msg("USER: $new_user");
            $app->file->af($user_datei, $new_user);
            if($shadow_datei == "/etc/shadow"){
                      $datum = time();
                      $tage = floor($datum/86400);
                      $new_passwd = "\n$user_username:$passwort:$tage:0:99999:7:::\n";
            } else {
                      $new_passwd = "\n$user_username:$passwort:$uid:$gid::0:0:$username:$homedir:$shell\n";
            }
            $app->file->af($shadow_datei, $new_passwd);
                // TB: leere Zeilen entfernen
                $app->file->remove_blank_lines($shadow_datei);
                $app->file->remove_blank_lines($user_datei);
            // TB: user Sortierung deaktiviert
                //$this->order_users_groups();
            if($shadow_datei != "/etc/shadow"){
                      $app->file->af($shadow_datei, "\n");
                        // TB: leere Zeilen entfernen
                        $app->file->remove_blank_lines($shadow_datei);
                      $app->log->caselog("pwd_mkdb $shadow_datei &> /dev/null", $this->FILE, __LINE__);
            }
            return true;
        }
  }
}
function updateuser($user_username, $uid, $gid, $username, $homedir, $shell, $passwort = '*'){
  $this->deluser($user_username);
  $this->adduser($user_username, $uid, $gid, $username, $homedir, $shell, $passwort);
}
function deactivateuser($user_username){
  $passwort = str_rot13($this->getpasswd($user_username));
  $user_attr = $this->get_user_attributes($user_username);
  $uid = $user_attr["uid"];
  $gid = $user_attr["gid"];
  $username = $user_attr["name"];
  $homedir = $user_attr["homedir"];
  $shell = "/dev/null";
  $this->deluser($user_username);
  $this->adduser($user_username, $uid, $gid, $username, $homedir, $shell, $passwort);
}
function deluser($user_username){
  global $app;
  if($this->is_user($user_username)){
    $user_datei = $this->server_conf["passwd_datei"];
    $shadow_datei = $this->server_conf["shadow_datei"];
    $users = $app->file->rf($user_datei);
    $lines = explode("\n", $users);
    if(is_array($lines)){
      $num_lines = sizeof($lines);
      for($i=0;$i<$num_lines;$i++){
        if(trim($lines[$i]) != ""){
          list($f1,) = explode(":", $lines[$i]);
          if($f1 != $user_username) $new_lines[] = $lines[$i];
        }
      }
      $new_users = implode("\n", $new_lines);
      $app->file->wf($user_datei, $new_users);
      unset($new_lines);
      unset($lines);
      unset($new_users);
    }
    $app->file->remove_blank_lines($user_datei);
    $passwds = $app->file->rf($shadow_datei);
    $lines = explode("\n", $passwds);
    if(is_array($lines)){
      $num_lines = sizeof($lines);
      for($i=0;$i<$num_lines;$i++){
        if(trim($lines[$i]) != ""){
          list($f1,) = explode(":", $lines[$i]);
          if($f1 != $user_username) $new_lines[] = $lines[$i];
        }
      }
      $new_passwds = implode("\n", $new_lines);
      $app->file->wf($shadow_datei, $new_passwds);
      unset($new_lines);
      unset($lines);
      unset($new_passwds);
    }
    $app->file->remove_blank_lines($shadow_datei);
    $group_file = $app->file->rf($this->server_conf["group_datei"]);
    $group_file_lines = explode("\n", $group_file);
    foreach($group_file_lines as $group_file_line){
      if(trim($group_file_line) != ""){
        list($f1, $f2, $f3, $f4) = explode(":", $group_file_line);
        $group_users = explode(",", str_replace(" ", "", $f4));
        if(in_array($user_username, $group_users)){
          $g_users = array();
          foreach($group_users as $group_user){
            if($group_user != $user_username) $g_users[] = $group_user;
          }
          $f4 = implode(",", $g_users);
        }
        $new_group_file[] = $f1.":".$f2.":".$f3.":".$f4;
      }
    }
    $new_group_file = implode("\n", $new_group_file);
    $app->file->wf($this->server_conf["group_datei"], $new_group_file);
    // TB: auskommentiert
        //$this->order_users_groups();
    if($shadow_datei != "/etc/shadow"){
      $app->file->af($shadow_datei, "\n");
      $app->log->caselog("pwd_mkdb $shadow_datei &> /dev/null", $this->FILE, __LINE__);
    }
    return true;
  } else {
    return false;
  }
}
function addgroup($group, $gid, $members = ''){
  global $app;
  if($this->is_group($group)){
    return false;
  } else {
    $group_datei = $this->server_conf["group_datei"];
    $shadow_datei = $this->server_conf["shadow_datei"];
    $new_group = "\n$group:x:$gid:$members\n";
    $app->file->af($group_datei, $new_group);
        // TB: auskommentiert
        //$this->order_users_groups();
    if($shadow_datei != "/etc/shadow"){
      $app->log->caselog("pwd_mkdb $shadow_datei &> /dev/null", $this->FILE, __LINE__);
    }
    return true;
  }
}
function updategroup($group, $gid, $members = ''){
  $this->delgroup($group);
  $this->addgroup($group, $gid, $members);
}
function delgroup($group){
  global $app;
  if($this->is_group($group)){
    $group_datei = $this->server_conf["group_datei"];
    $shadow_datei = $this->server_conf["shadow_datei"];
    $groups = $app->file->rf($group_datei);
    $lines = explode("\n", $groups);
    if(is_array($lines)){
      $num_lines = sizeof($lines);
      for($i=0;$i<$num_lines;$i++){
        if(trim($lines[$i]) != ""){
          list($f1,) = explode(":", $lines[$i]);
          if($f1 != $group) $new_lines[] = $lines[$i];
        }
      }
      $new_groups = implode("\n", $new_lines);
      $app->file->wf($group_datei, $new_groups);
      unset($new_lines);
      unset($lines);
      unset($new_groups);
    }
        // TB: auskommentiert
    //$this->order_users_groups();
    if($shadow_datei != "/etc/shadow"){
      $app->log->caselog("pwd_mkdb $shadow_datei &> /dev/null", $this->FILE, __LINE__);
    }
    return true;
  } else {
    return false;
  }
}
function order_users_groups(){
  global $app;
  $user_datei = $this->server_conf["passwd_datei"];
  $shadow_datei = $this->server_conf["shadow_datei"];
  $group_datei = $this->server_conf["group_datei"];
  $groups = $app->file->no_comments($group_datei);
  $lines = explode("\n", $groups);
  if(is_array($lines)){
    foreach($lines as $line){
      if(trim($line) != ""){
        list($f1, $f2, $f3, $f4) = explode(":", $line);
        $arr[$f3] = $line;
      }
    }
  }
  ksort($arr);
  reset($arr);
  if($shadow_datei != "/etc/shadow"){
    $app->file->wf($group_datei, $app->file->remove_blank_lines(implode("\n", $arr), 0)."\n");
  }else {
    $app->file->wf($group_datei, $app->file->remove_blank_lines(implode("\n", $arr), 0));
  }
  unset($arr);
  $users = $app->file->no_comments($user_datei);
  $lines = explode("\n", $users);
  if(is_array($lines)){
    foreach($lines as $line){
      if(trim($line) != ""){
        list($f1, $f2, $f3,) = explode(":", $line);
        if($f1 != "toor"){
          $arr[$f3] = $line;
        } else {
          $arr[70000] = $line;
        }
      }
    }
  }
  ksort($arr);
  reset($arr);
  $app->file->wf($user_datei, $app->file->remove_blank_lines(implode("\n", $arr), 0));
  unset($arr);
  $passwds = $app->file->no_comments($shadow_datei);
  $lines = explode("\n", $passwds);
  if(is_array($lines)){
    foreach($lines as $line){
      if(trim($line) != ""){
        list($f1, $f2, $f3,) = explode(":", $line);
        if($f1 != "toor"){
          $uid = $this->getuid($f1);
          if(!is_bool($uid)) $arr[$uid] = $line;
        } else {
          $arr[70000] = $line;
        }
      }
    }
  }
  ksort($arr);
  reset($arr);
  $app->file->wf($shadow_datei, $app->file->remove_blank_lines(implode("\n", $arr), 0));
  unset($arr);
}
function find_uid_gid($min, $max){
  global $app;
  if($min < $max && $min >= 0 && $max >= 0 && $min <= 65536 && $max <= 65536 && is_int($min) && is_int($max)){
    for($i=$min;$i<=$max;$i++){
      $uid_arr[$i] = $gid_arr[$i] = 1;
    }
    $user_datei = $this->server_conf["passwd_datei"];
    $group_datei = $this->server_conf["group_datei"];
    $users = $app->file->no_comments($user_datei);
    $lines = explode("\n", $users);
    if(is_array($lines)){
      foreach($lines as $line){
        if(trim($line) != ""){
          list($f1, $f2, $f3, $f4, $f5, $f6, $f7) = explode(":", $line);
          if($f3 >= $min && $f3 <= $max) unset($uid_arr[$f3]);
        }
      }
      if(!empty($uid_arr)){
        foreach($uid_arr as $key => $val){
          $uids[] = $key;
        }
        $min_uid = min($uids);
        unset($uid_arr);
      } else {
        return false;
      }
    }
    $groups = $app->file->no_comments($group_datei);
    $lines = explode("\n", $groups);
    if(is_array($lines)){
      foreach($lines as $line){
        if(trim($line) != ""){
          list($f1, $f2, $f3, $f4) = explode(":", $line);
          if($f3 >= $min && $f3 <= $max) unset($gid_arr[$f3]);
        }
      }
      if(!empty($gid_arr)){
        foreach($gid_arr as $key => $val){
          $gids[] = $key;
        }
        $min_gid = min($gids);
        unset($gid_arr);
      } else {
        return false;
      }
    }
    $result = array_intersect($uids, $gids);
    $new_id = (max($result));
    unset($uids);
    unset($gids);
    unset($result);
    if($new_id <= $max){
      return $new_id;
    } else {
      return false;
    }
  } else {
    return false;
  }
}
function is_user($user){
  global $app;
  $user_datei = $this->server_conf["passwd_datei"];
  $users = $app->file->no_comments($user_datei);
  $lines = explode("\n", $users);
  if(is_array($lines)){
    foreach($lines as $line){
      if(trim($line) != ""){
        list($f1, $f2, $f3, $f4, $f5, $f6, $f7) = explode(":", $line);
        if($f1 == $user) return true;
      }
    }
  }
  return false;
}
function is_group($group){
  global $app;
  $group_datei = $this->server_conf["group_datei"];
  $groups = $app->file->no_comments($group_datei);
  $lines = explode("\n", $groups);
  if(is_array($lines)){
    foreach($lines as $line){
      if(trim($line) != ""){
        list($f1, $f2, $f3, $f4) = explode(":", $line);
        if($f1 == $group) return true;
      }
    }
  }
  return false;
}
function root_group(){
  global $app;
  $group_datei = $this->server_conf["group_datei"];
  $groups = $app->file->no_comments($group_datei);
  $lines = explode("\n", $groups);
  if(is_array($lines)){
    foreach($lines as $line){
      if(trim($line) != ""){
        list($f1, $f2, $f3, $f4) = explode(":", $line);
        if($f3 == 0) return $f1;
      }
    }
  }
  return false;
}
function get_user_groups($username){
  global $app;
  $user_groups = array();
  $group_datei = $this->server_conf["group_datei"];
  $groups = $app->file->no_comments($group_datei);
  $lines = explode("\n", $groups);
  if(is_array($lines)){
    foreach($lines as $line){
      if(trim($line) != ""){
        list($f1, $f2, $f3, $f4) = explode(":", $line);
        if(intval($f3) < intval($this->server_conf["groupid_von"]) && trim($f1) != 'users'){
          $tmp_group_users = explode(',', str_replace(' ', '', $f4));
          if(in_array($username, $tmp_group_users) && trim($f1) != '') $user_groups[] = $f1;
          unset($tmp_group_users);
        }
      }
    }
  }
  if(!empty($user_groups)) return implode(',', $user_groups);
  return '';
}
function getpasswd($user){
  global $app;
  if($this->is_user($user)){
    $shadow_datei = $this->server_conf["shadow_datei"];
    $passwds = $app->file->no_comments($shadow_datei);
    $lines = explode("\n", $passwds);
    if(is_array($lines)){
      foreach($lines as $line){
        if(trim($line) != ""){
          list($f1, $f2,) = explode(":", $line);
          if($f1 == $user) return $f2;
        }
      }
    }
  } else {
    return false;
  }
}
function getuid($user){
  global $app;
  if($this->is_user($user)){
    $user_datei = $this->server_conf["passwd_datei"];
    $users = $app->file->no_comments($user_datei);
    $lines = explode("\n", $users);
    if(is_array($lines)){
      foreach($lines as $line){
        if(trim($line) != ""){
          list($f1, $f2, $f3,) = explode(":", $line);
          if($f1 == $user) return $f3;
        }
      }
    }
  } else {
    return false;
  }
}
function get_user_attributes($user){
  global $app;
  if($this->is_user($user)){
    $user_datei = $this->server_conf["passwd_datei"];
    $users = $app->file->no_comments($user_datei);
    $lines = explode("\n", $users);
    if(is_array($lines)){
      foreach($lines as $line){
        if(trim($line) != ""){
          list($f1, $f2, $f3, $f4, $f5, $f6, $f7) = explode(":", $line);
          if($f1 == $user){
            $user_attr["username"] = $f1;
            $user_attr["x"] = $f2;
            $user_attr["uid"] = $f3;
            $user_attr["gid"] = $f4;
            $user_attr["name"] = $f5;
            $user_attr["homedir"] = $f6;
            $user_attr["shell"] = $f7;
            return $user_attr;
          }
        }
      }
    }
  } else {
    return false;
  }
}
function chown($file, $owner, $group = ''){
  $owner_change = @chown($file, $owner);
  if($group != ""){
    $group_change = @chgrp($file, $group);
  } else {
    $group_change = 1;
  }
  if($owner_change && $group_change){
    return true;
  } else {
    return false;
  }
}
function add_user_to_group($group, $user = 'admispconfig'){
  global $app;
  $group_file = $app->file->rf($this->server_conf["group_datei"]);
  $group_file_lines = explode("\n", $group_file);
  foreach($group_file_lines as $group_file_line){
    list($group_name,$group_x,$group_id,$group_users) = explode(":",$group_file_line);
    if($group_name == $group){
      $group_users = explode(",", str_replace(" ", "", $group_users));
      if(!in_array($user, $group_users)){
        $group_users[] = $user;
      }
      $group_users = implode(",", $group_users);
      if(substr($group_users,0,1) == ",") $group_users = substr($group_users,1);
      $group_file_line = $group_name.":".$group_x.":".$group_id.":".$group_users;
    }
    $new_group_file[] = $group_file_line;
  }
  $new_group_file = implode("\n", $new_group_file);
  $app->file->wf($this->server_conf["group_datei"], $new_group_file);
  $app->file->remove_blank_lines($this->server_conf["group_datei"]);
  if($this->server_conf["shadow_datei"] != "/etc/shadow"){
    $app->log->caselog("pwd_mkdb ".$this->server_conf["shadow_datei"]." &> /dev/null", $this->FILE, __LINE__);
  }
}
function usermod($user, $groups){
  global $app;
  if($this->is_user($user)){
    $groups = explode(",", str_replace(" ", "", $groups));
    $group_file = $app->file->rf($this->server_conf["group_datei"]);
    $group_file_lines = explode("\n", $group_file);
    foreach($group_file_lines as $group_file_line){
      if(trim($group_file_line) != ""){
        list($f1, $f2, $f3, $f4) = explode(":", $group_file_line);
        $group_users = explode(",", str_replace(" ", "", $f4));
        if(!in_array($f1, $groups)){
          if(in_array($user, $group_users)){
            $g_users = array();
            foreach($group_users as $group_user){
              if($group_user != $user) $g_users[] = $group_user;
            }
            $f4 = implode(",", $g_users);
          }
        } else {
          if(!in_array($user, $group_users)){
            if(trim($group_users[0]) == "") unset($group_users);
            $group_users[] = $user;
          }
          $f4 = implode(",", $group_users);
        }
        $new_group_file[] = $f1.":".$f2.":".$f3.":".$f4;
      }
    }
    $new_group_file = implode("\n", $new_group_file);
    $app->file->wf($this->server_conf["group_datei"], $new_group_file);
    $app->file->remove_blank_lines($this->server_conf["group_datei"]);
    if($this->server_conf["shadow_datei"] != "/etc/shadow"){
      $app->log->caselog("pwd_mkdb ".$this->server_conf["shadow_datei"]." &> /dev/null", $this->FILE, __LINE__);
    }
    return true;
  } else {
    return false;
  }
}
function rc_edit($service, $rl, $action){
  // $action = "on|off";
  global $app;
  $dist_init_scripts = $app->system->server_conf["dist_init_scripts"];
  $dist_runlevel = $app->system->server_conf["dist_runlevel"];
  $dist = $app->system->server_conf["dist"];
  if(trim($dist_runlevel) == ""){ // falls es keine runlevel gibt (FreeBSD)
    if($action == "on"){
      @symlink($dist_init_scripts."/".$service, $dist_init_scripts."/".$service.".sh");
    }
    if($action == "off"){
      if(is_link($dist_init_scripts."/".$service.".sh")){
        unlink($dist_init_scripts."/".$service.".sh");
      } else {
        exec("mv -f ".$dist_init_scripts."/".$service.".sh ".$dist_init_scripts."/".$service." &> /dev/null");
      }
    }
  } else { // Linux
    if(substr($dist, 0,4) == 'suse'){
      if($action == "on"){
        exec("chkconfig --add $service &> /dev/null");
      }
      if($action == "off"){
        exec("chkconfig --del $service &> /dev/null");
      }
    } else {
      $runlevels = explode(",", $rl);
      foreach($runlevels as $runlevel){
        $runlevel = trim($runlevel);
        if($runlevel != "" && is_dir($dist_runlevel."/rc".$runlevel.".d")){
          $handle=opendir($dist_runlevel."/rc".$runlevel.".d");
          while($file = readdir($handle)){
            if($file != "." && $file != ".."){
              $target = @readlink($dist_runlevel."/rc".$runlevel.".d/".$file);
              if(strstr($file, $service) && strstr($target, $service) && substr($file,0,1) == "S") $ln_arr[$runlevel][] = $dist_runlevel."/rc".$runlevel.".d/".$file;
            }
          }
          closedir($handle);
        }
        if($action == "on"){
          if(!is_array($ln_arr[$runlevel])) @symlink($dist_init_scripts."/".$service, $dist_runlevel."/rc".$runlevel.".d/S99".$service);
        }
        if($action == "off"){
          if(is_array($ln_arr[$runlevel])){
            foreach($ln_arr[$runlevel] as $link){
              unlink($link);
            }
          }
        }
      }
    }
  }
}
function grep($content, $string, $params = ''){
  global $app;
  // params: i, v, w
  $content = $app->file->unix_nl($content);
  $lines = explode("\n", $content);
  foreach($lines as $line){
    if(!strstr($params, 'w')){
      if(strstr($params, 'i')){
        if(strstr($params, 'v')){
          if(!stristr($line, $string)) $find[] = $line;
        } else {
          if(stristr($line, $string)) $find[] = $line;
        }
      } else {
        if(strstr($params, 'v')){
          if(!strstr($line, $string)) $find[] = $line;
        } else {
          if(strstr($line, $string)) $find[] = $line;
        }
      }
    } else {
      if(strstr($params, 'i')){
        if(strstr($params, 'v')){
          if(!$app->string->is_word($string, $line, 'i')) $find[] = $line;
        } else {
          if($app->string->is_word($string, $line, 'i')) $find[] = $line;
        }
      } else {
        if(strstr($params, 'v')){
          if(!$app->string->is_word($string, $line)) $find[] = $line;
        } else {
          if($app->string->is_word($string, $line)) $find[] = $line;
        }
      }
    }
  }
  if(is_array($find)){
    $ret_val = implode("\n", $find);
    if(substr($ret_val,-1) != "\n") $ret_val .= "\n";
    $find = NULL;
    return $ret_val;
  } else {
    return false;
  }
}
function cut($content, $field, $delimiter = ':'){
  global $app;
  $content = $app->file->unix_nl($content);
  $lines = explode("\n", $content);
  foreach($lines as $line){
    $elms = explode($delimiter, $line);
    $find[] = $elms[($field-1)];
  }
  if(is_array($find)){
    $ret_val = implode("\n", $find);
    if(substr($ret_val,-1) != "\n") $ret_val .= "\n";
    $find = NULL;
    return $ret_val;
  } else {
    return false;
  }
}
function cat($file){
  global $app;
  return $app->file->rf($file);
}
function daemon_init($daemon, $action){
  // $action = start|stop|restart|reload
  global $app;
  $dist = $this->server_conf["dist"];
  $dist_init_scripts = $this->server_conf["dist_init_scripts"];
  if(!strstr($dist, "freebsd")){
    $app->log->caselog("$dist_init_scripts/$daemon $action &> /dev/null", $this->FILE, __LINE__);
  } else {
    if(is_file($dist_init_scripts."/".$daemon.".sh") || is_link($dist_init_scripts."/".$daemon.".sh")){
      if($action == "start" || $action == "stop"){
        $app->log->caselog($dist_init_scripts."/".$daemon.".sh ".$action." &> /dev/null", $this->FILE, __LINE__);
      } else {
        $app->log->caselog($dist_init_scripts."/".$daemon.".sh stop &> /dev/null", $this->FILE, __LINE__);
        sleep(3);
        $app->log->caselog($dist_init_scripts."/".$daemon.".sh start &> /dev/null", $this->FILE, __LINE__);
      }
    } else {
      if(is_file($dist_init_scripts."/".$daemon) || is_link($dist_init_scripts."/".$daemon)){
        if($action == "start" || $action == "stop"){
          $app->log->caselog($dist_init_scripts."/".$daemon." ".$action." &> /dev/null", $this->FILE, __LINE__);
        } else {
          $app->log->caselog($dist_init_scripts."/".$daemon." stop &> /dev/null", $this->FILE, __LINE__);
          sleep(3);
          $app->log->caselog($dist_init_scripts."/".$daemon." start &> /dev/null", $this->FILE, __LINE__);
        }
      } else {
        if(is_file("/etc/rc.d/".$daemon) || is_link("/etc/rc.d/".$daemon)){
          if($action == "start" || $action == "stop"){
            $app->log->caselog("/etc/rc.d/".$daemon." ".$action." &> /dev/null", $this->FILE, __LINE__);
          } else {
            $app->log->caselog("/etc/rc.d/".$daemon." stop &> /dev/null", $this->FILE, __LINE__);
            sleep(3);
            $app->log->caselog("/etc/rc.d/".$daemon." start &> /dev/null", $this->FILE, __LINE__);
          }
        }
      }
    }
  }
}
function netmask($netmask){
  list($f1,$f2,$f3,$f4) = explode(".", trim($netmask));
  $bin = str_pad(decbin($f1),8,"0",STR_PAD_LEFT).str_pad(decbin($f2),8,"0",STR_PAD_LEFT).str_pad(decbin($f3),8,"0",STR_PAD_LEFT).str_pad(decbin($f4),8,"0",STR_PAD_LEFT);
  $parts = explode("0", $bin);
  $bin = str_pad($parts[0], 32, "0", STR_PAD_RIGHT);
  $bin = wordwrap($bin, 8, ".", 1);
  list($f1,$f2,$f3,$f4) = explode(".", trim($bin));
  return bindec($f1).".".bindec($f2).".".bindec($f3).".".bindec($f4);
}
function binary_netmask($netmask){
  list($f1,$f2,$f3,$f4) = explode(".", trim($netmask));
  $bin = str_pad(decbin($f1),8,"0",STR_PAD_LEFT).str_pad(decbin($f2),8,"0",STR_PAD_LEFT).str_pad(decbin($f3),8,"0",STR_PAD_LEFT).str_pad(decbin($f4),8,"0",STR_PAD_LEFT);
  $parts = explode("0", $bin);
  return substr_count($parts[0], "1");
}
function network($ip, $netmask){
  $netmask = $this->netmask($netmask);
  list($f1,$f2,$f3,$f4) = explode(".", $netmask);
  $netmask_bin = str_pad(decbin($f1),8,"0",STR_PAD_LEFT).str_pad(decbin($f2),8,"0",STR_PAD_LEFT).str_pad(decbin($f3),8,"0",STR_PAD_LEFT).str_pad(decbin($f4),8,"0",STR_PAD_LEFT);
  list($f1,$f2,$f3,$f4) = explode(".", $ip);
  $ip_bin = str_pad(decbin($f1),8,"0",STR_PAD_LEFT).str_pad(decbin($f2),8,"0",STR_PAD_LEFT).str_pad(decbin($f3),8,"0",STR_PAD_LEFT).str_pad(decbin($f4),8,"0",STR_PAD_LEFT);
  for($i=0;$i<32;$i++){
    $network_bin .= substr($netmask_bin,$i,1) * substr($ip_bin,$i,1);
  }
  $network_bin = wordwrap($network_bin, 8, ".", 1);
  list($f1,$f2,$f3,$f4) = explode(".", trim($network_bin));
  return bindec($f1).".".bindec($f2).".".bindec($f3).".".bindec($f4);
}
function broadcast($ip, $netmask){
  $netmask = $this->netmask($netmask);
  $binary_netmask = $this->binary_netmask($netmask);
  list($f1,$f2,$f3,$f4) = explode(".", $ip);
  $ip_bin = str_pad(decbin($f1),8,"0",STR_PAD_LEFT).str_pad(decbin($f2),8,"0",STR_PAD_LEFT).str_pad(decbin($f3),8,"0",STR_PAD_LEFT).str_pad(decbin($f4),8,"0",STR_PAD_LEFT);
  $broadcast_bin = str_pad(substr($ip_bin, 0, $binary_netmask),32,"1",STR_PAD_RIGHT);
  $broadcast_bin = wordwrap($broadcast_bin, 8, ".", 1);
  list($f1,$f2,$f3,$f4) = explode(".", trim($broadcast_bin));
  return bindec($f1).".".bindec($f2).".".bindec($f3).".".bindec($f4);
}
function network_info(){
  $dist = $this->server_conf["dist"];
  ob_start();
  passthru("ifconfig");
  $output = ob_get_contents();
  ob_end_clean();
  $lines = explode("\n", $output);
  foreach($lines as $line){
    $elms = explode(" ", $line);
    if(trim($elms[0]) != "" && substr($elms[0],0,1) != "\t"){
      $elms[0] = trim($elms[0]);
      if(strstr($dist, "freebsd")) $elms[0] = substr($elms[0],0,-1);
      $interfaces[] = $elms[0];
    }
  }
  if(!empty($interfaces)){
    foreach($interfaces as $interface){
      ob_start();
      if(!strstr($dist, "freebsd")){
        passthru("ifconfig ".$interface." | grep -iw 'inet' | cut -f2 -d: | cut -f1 -d' '");
      }else {
        passthru("ifconfig ".$interface." | grep -iw 'inet' | grep -iv 'inet6' | cut -f2 -d' '");
      }
      $output = trim(ob_get_contents());
      ob_end_clean();
      if($output != ""){
        $ifconfig["INTERFACE"][$interface] = $output;
        $ifconfig["IP"][$output] = $interface;
      }
    }
    if(!empty($ifconfig)){
      return $ifconfig;
    } else {
      return false;
    }
  } else {
    return false;
  }
}
function network_config(){
  $ifconfig = $this->network_info();
  if($ifconfig){
    $main_interface = $ifconfig["IP"][$this->server_conf["server_ip"]];
    if(strstr($main_interface, ":")){
      $parts = explode(":", $main_interface);
      $main_interface = trim($parts[0]);
    }
    if($main_interface != ""){
      $ips = $this->data["isp_server_ip"];
      if(!empty($ips)){
        foreach($ips as $ip){
          if(!isset($ifconfig["IP"][$ip["server_ip"]])){
            $to_set[] = $ip["server_ip"];
          } else {
            unset($ifconfig["IP"][$ip["server_ip"]]);
          }
        }
        if(!empty($ifconfig["IP"])){
          foreach($ifconfig["IP"] as $key => $val){
            if(!strstr($val, "lo") && !strstr($val, "lp") && strstr($val, $main_interface)){
              exec("ifconfig ".$val." down &> /dev/null");
              unset($ifconfig["INTERFACE"][$val]);
            }
          }
        }
        if(!empty($to_set)){
         foreach($to_set as $to){
           $i = 0;
           while($i >= 0){
             if(isset($ifconfig["INTERFACE"][$main_interface.":".$i])){
               $i++;
             } else {
               $new_interface = $main_interface.":".$i;
               $i = -1;
             }
           }
           exec("ifconfig ".$new_interface." ".$to." netmask ".$this->server_conf["server_netzmaske"]." up &> /dev/null");
           $ifconfig["INTERFACE"][$new_interface] = $to;
          }
        }
      }
    }
  }
}
function quota_dirs(){
  global $app;
  $content = $app->file->unix_nl($app->file->no_comments("/etc/fstab"));
  $lines = explode("\n", $content);
  foreach($lines as $line){
    $line = trim($line);
    if($line != ""){
      $elms = explode("\t", $line);
      foreach($elms as $elm){
        if(trim($elm) != "") $f[] = $elm;
      }
      if(!empty($f) && stristr($f[3], "userquota") && stristr($f[3], "groupquota")){
        $q_dirs[] = trim($f[1]);
      }
      unset($f);
    }
  }
  if(!empty($q_dirs)){
    return $q_dirs;
  } else {
    return false;
  }
}
function make_trashscan(){
  global $app;
  //trashscan erstellen
  // Template Öffnen
  $app->tpl->clear_all();
  $app->tpl->define( array(table    => "trashscan.master"));
  if(!isset($this->server_conf["virusadmin"]) || trim($this->server_conf["virusadmin"]) == "") $this->server_conf["virusadmin"] = "admispconfig@localhost";
  if(substr($this->server_conf["virusadmin"],0,1) == "#"){
    $notify = "no";
  } else {
    $notify = "yes";
  }
  // Variablen zuweisen
  $app->tpl->assign( array(VIRUSADMIN => $this->server_conf["virusadmin"],
                           NOTIFICATION => $notify));
  $app->tpl->parse(TABLE, table);
  $trashscan_text = $app->tpl->fetch();
  $datei = "/home/admispconfig/ispconfig/tools/clamav/bin/trashscan";
  $app->file->wf($datei, $trashscan_text);
  exec("chown admispconfig:admispconfig $datei &> /dev/null");
  exec("chmod 755 $datei");
}
function get_time(){
  $addr = "http://www.ispconfig.org/";
  $timeout = 1;
  $url_parts = parse_url($addr);
  $path = $url_parts["path"];
  $port = 80;
  $urlHandle = @fsockopen($url_parts["host"], $port, $errno, $errstr, $timeout);
  if ($urlHandle){
    socket_set_timeout($urlHandle, $timeout);
    $urlString = "GET $path HTTP/1.0\r\nHost: ".$url_parts["host"]."\r\nConnection: Keep-Alive\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n";
    if ($user) $urlString .= "Authorization: Basic ".base64_encode("$user:$pass")."\r\n";
    $urlString .= "\r\n";
    fputs($urlHandle, $urlString);
    $month["Jan"] = "01";
    $month["Feb"] = "02";
    $month["Mar"] = "03";
    $month["Apr"] = "04";
    $month["May"] = "05";
    $month["Jun"] = "06";
    $month["Jul"] = "07";
    $month["Aug"] = "08";
    $month["Sep"] = "09";
    $month["Oct"] = "10";
    $month["Nov"] = "11";
    $month["Dec"] = "12";
    $c = 0;
    $l = 0;
    $startzeit = time();
    while(!feof($urlHandle) && $c < 2 && $l == 0){
      $line = trim(fgets($urlHandle,128));
      $response .= $line;
      $c = time() - $startzeit;
      if($line == "" || substr($line, 0, 5) == "Date:") $l += 1; // nur den Header auslesen
      if(substr($line, 0, 5) == "Date:"){
        $parts = explode(" ", $line);
        $tag = $parts[2];
        $monat = $month[$parts[3]];
        $jahr = $parts[4];
        list($stunde, $minute, $sekunde) = explode(":", $parts[5]);
        $timestamp = mktime($stunde,$minute,$sekunde,$monat,$tag,$jahr);
      }
    }
    @fclose($urlHandle);
    return $timestamp;
  } else {
    @fclose($urlHandle);
    return false;
  }
}
}
?>
server/lib/classes/tpl.inc.php
New file
@@ -0,0 +1,1499 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002 Active Fish Group                                 |
// +----------------------------------------------------------------------+
// | Authors: Kelvin Jones <kelvin@kelvinjones.co.uk>                     |
// +----------------------------------------------------------------------+
//
// $Id: class.tpl.inc.php,v 1.1 2003/07/08 12:31:10 platinum Exp $
// check to avoid multiple including of class
if (!defined('vlibTemplateClassLoaded')) {
    define('vlibTemplateClassLoaded', 1);
       include_once ($conf['classpath'].'/tpl_error.inc.php');
       include_once ($conf['classpath'].'/tpl_ini.inc.php');
    /**
     * vlibTemplate is a class used to seperate PHP and HTML.
     * For instructions on how to use vlibTemplate, see the
     * vlibTemplate.html file, located in the 'docs' directory.
     *
     * @since 07/03/2002
     * @author Kelvin Jones <kelvin@kelvinjones.co.uk>
     * @package vLIB
     * @access public
     * @see vlibTemplate.html
     */
    class tpl {
    /*-----------------------------------------------------------------------------\
    |                                 ATTENTION                                    |
    |  Do not touch the following variables. vlibTemplate will not work otherwise. |
    \-----------------------------------------------------------------------------*/
        var $OPTIONS = array(
                        'MAX_INCLUDES'          =>   10,
                        'TEMPLATE_DIR'          => null,
                        'GLOBAL_VARS'           => null,
                        'GLOBAL_CONTEXT_VARS'   => null,
                        'LOOP_CONTEXT_VARS'     => null,
                        'SET_LOOP_VAR'          => null,
                        'DEFAULT_ESCAPE'        => null,
                        'STRICT'                => null,
                        'CASELESS'              => null,
                        'UNKNOWNS'              => null,
                        'TIME_PARSE'            => null,
                        'ENABLE_PHPINCLUDE'     => null,
                        'INCLUDE_PATHS'         => array(),
                        'CACHE_DIRECTORY'       => null,
                        'CACHE_LIFETIME'        => null,
                        'CACHE_EXTENSION'       => null
                             );
        /** open and close tags used for escaping */
        var $ESCAPE_TAGS = array(
                            'html' => array('open' => 'htmlspecialchars('
                                            ,'close'=> ', ENT_QUOTES)'),
                            'url' => array('open' => 'urlencode('
                                            ,'close'=> ')'),
                            'rawurl'=>array('open' => 'rawurlencode('
                                            ,'close'=> ')'),
                            'sq' => array('open' => 'addcslashes('
                                            ,'close'=> ", \"'\")"),
                            'dq' => array('open' => 'addcslashes('
                                            ,'close'=> ", '\"')"),
                            '1' => array('open' => 'htmlspecialchars('
                                            ,'close'=> ', ENT_QUOTES)'),
                            '0' => array('open' => ''
                                            ,'close'=> ''),
                            'none' => array('open' => ''
                                            ,'close'=> ''),
                            'hex'        => array('open' => '$this->_escape_hex(',
                                            'close'=> ', false)'),
                            'hexentity'  => array('open' => '$this->_escape_hex(',
                                            'close'=> ', true)')
                                );
        /** open and close tags used for formatting */
        var $FORMAT_TAGS = array(
                            'strtoupper' => array('open' => 'strtoupper(',
                                            'close'=> ')'),
                            'uc'         => array('open' => 'strtoupper(',
                                            'close'=> ')'),
                            'strtolower' => array('open' => 'strtolower(',
                                            'close'=> ')'),
                            'lc'         => array('open' => 'strtolower(',
                                            'close'=> ')'),
                            'ucfirst'    => array('open' => 'ucfirst(',
                                            'close'=> ')'),
                            'lcucfirst'  => array('open' => 'ucfirst(strtolower(',
                                            'close'=> '))'),
                            'ucwords'    => array('open' => 'ucwords(',
                                            'close'=> ')'),
                            'lcucwords'  => array('open' => 'ucwords(strtolower(',
                                            'close'=> '))')
                                );
        /** operators allowed when using extended TMPL_IF syntax */
        var $allowed_if_ops = array('==','!=','<>','<','>','<=','>=');
        /** dbs allowed by vlibTemplate::setDbLoop(). */
        var $allowed_loop_dbs = array('MYSQL','POSTGRESQL','INFORMIX','INTERBASE','INGRES',
                                      'MSSQL','MSQL','OCI8','ORACLE','OVRIMOS','SYBASE');
        /** root directory of vlibTemplate automagically filled in */
        var $VLIBTEMPLATE_ROOT = null;
        /** contains current directory used when doing recursive include */
        var $_currentincludedir = array();
        /** current depth of includes */
        var $_includedepth = 0;
        /** full path to tmpl file */
        var $_tmplfilename = null;
        /** file data before it's parsed */
        var $_tmplfile = null;
        /** parsed version of file, ready for eval()ing */
        var $_tmplfilep = null;
        /** eval()ed version ready for printing or whatever */
        var $_tmploutput = null;
        /** array for variables to be kept */
        var $_vars = array();
        /** array where loop variables are kept */
        var $_arrvars = array();
        /** array which holds the current namespace during parse */
        var $_namespace = array();
        /** variable is set to true once the template is parsed, to save re-parsing everything */
        var $_parsed = false;
        /** array holds all unknowns vars */
        var $_unknowns = array();
        /** microtime when template parsing began */
        var $_firstparsetime = null;
        /** total time taken to parse template */
        var $_totalparsetime = null;
        /** name of current loop being passed in */
        var $_currloopname = null;
        /** rows with the above loop */
        var $_currloop = array();
        /** define vars to avoid warnings */
        var $_debug = null;
        var $_cache = null;
        /** array which holds the dynamic Includes */
        var $_dyninclude = array();
    /*-----------------------------------------------------------------------------\
    |                           public functions                                   |
    \-----------------------------------------------------------------------------*/
        /**
         * FUNCTION: newTemplate
         *
         * Usually called by the class constructor.
         * Stores the filename in $this->_tmplfilename.
         * Raises an error if the template file is not found.
         *
         * @param string $tmplfile full path to template file
         * @return boolean true
         * @access public
         */
        function newTemplate ($tmplfile) {
            if (!$tfile = $this->_fileSearch($tmplfile)) vlibTemplateError::raiseError('VT_ERROR_NOFILE',KILL,$tmplfile);
            // make sure that any parsing vars are cleared for the new template
            $this->_tmplfile = null;
            $this->_tmplfilep = null;
            $this->_tmploutput = null;
            $this->_parsed = false;
            $this->_unknowns = array();
            $this->_firstparsetime = null;
            $this->_totalparsetime = null;
            // reset debug module
            if ($this->_debug) $this->_debugReset();
            $this->_tmplfilename = $tfile;
            return true;
        }
        /**
         * FUNCTION: setVar
         *
         * Sets variables to be used by the template
         * If $k is an array, then it will treat it as an associative array
         * using the keys as variable names and the values as variable values.
         *
         * @param mixed $k key to define variable name
         * @param mixed $v variable to assign to $k
         * @return boolean true/false
         * @access public
         */
        function setVar ($k,$v=null) {
            if (is_array($k)) {
                foreach($k as $key => $value){
                    $key = ($this->OPTIONS['CASELESS']) ? strtolower(trim($key)) : trim($key);
                    if (preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $key) && $value !== null ) {
                        $this->_vars[$key] = $value;
                    }
                }
            }
            else {
                if (preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $k) && $v !== null) {
                    if ($this->OPTIONS['CASELESS']) $k = strtolower($k);
                    $this->_vars[trim($k)] = $v;
                }
                else {
                    return false;
                }
            }
            return true;
        }
        /**
         * FUNCTION: setInclude
         *
         * Sets dynamic includes to be used by the template
         * If $k is an array, then it will treat it as an associative array
         * using the keys as variable names and the values as variable values.
         *
         * @param mixed $k key to define variable name
         * @param mixed $v variable to assign to $k
         * @return boolean true/false
         * @access public
         */
        function setInclude($k, $v = null) {
            if(is_array($k)) {
                foreach($k as $key => $val) {
                    $this->_dyninclude[$key] = $val;
                }
            } else {
                $this->_dyninclude[$k] = $v;
            }
            return true;
        }
        /**
         * FUNCTION: unsetVar
         *
         * Unsets a variable which has already been set
         * Parse in all vars wanted for deletion in seperate parametres
         *
         * @param string var name to remove use: vlibTemplate::unsetVar(var[, var..])
         * @return boolean true/false returns true unless called with 0 params
         * @access public
         */
        function unsetVar () {
            $num_args = func_num_args();
            if ($num_args < 1)  return false;
            for ($i = 0; $i < $num_args; $i++) {
                $var = func_get_arg($i);
                if ($this->OPTIONS['CASELESS']) $var = strtolower($var);
                if (!preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $var)) continue;
                unset($this->_vars[$var]);
            }
            return true;
        }
        /**
         * FUNCTION: getVars
         *
         * Gets all vars currently set in global namespace.
         *
         * @return array
         * @access public
         */
        function getVars () {
            if (empty($this->_vars)) return false;
            return $this->_vars;
        }
        /**
         * FUNCTION: getVar
         *
         * Gets a single var from the global namespace
         *
         * @return var
         * @access public
         */
        function getVar ($var) {
            if ($this->OPTIONS['CASELESS']) $var = strtolower($var);
            if (empty($var) || !isset($this->_vars[$var])) return false;
            return $this->_vars[$var];
        }
        /**
         * FUNCTION: setContextVars
         *
         * sets the GLOBAL_CONTEXT_VARS
         *
         * @return true
         * @access public
         */
        function setContextVars () {
            $_phpself = @$GLOBALS['HTTP_SERVER_VARS']['PHP_SELF'];
            $_pathinfo = @$GLOBALS['HTTP_SERVER_VARS']['PATH_INFO'];
            $_request_uri = @$GLOBALS['HTTP_SERVER_VARS']['REQUEST_URI'];
            $_qs   = @$GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'];
            // the following fixes bug of $PHP_SELF on Win32 CGI and IIS.
            $_self = (!empty($_pathinfo)) ? $_pathinfo : $_phpself;
            $_uri  = (!empty($_request_uri)) ? $_request_uri : $_self.'?'.$_qs;
            $this->setvar('__SELF__', $_self);
            $this->setvar('__REQUEST_URI__', $_uri);
            return true;
        }
        /**
         * FUNCTION: setLoop
         *
         * Builds the loop construct for use with <TMPL_LOOP>.
         *
         * @param string $k string to define loop name
         * @param array $v array to assign to $k
         * @return boolean true/false
         * @access public
         */
        function setLoop ($k,$v) {
            if (is_array($v) && preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $k)) {
                $k = ($this->OPTIONS['CASELESS']) ? strtolower(trim($k)) : trim($k);
                $this->_arrvars[$k] = array();
                if ($this->OPTIONS['SET_LOOP_VAR'] && !empty($v)) $this->setvar($k, 1);
                if (($this->_arrvars[$k] = $this->_arrayBuild($v)) == false) {
                    vlibTemplateError::raiseError('VT_WARNING_INVALID_ARR',WARNING,$k);
                }
            }
            return true;
        }
        /**
         * FUNCTION: setDbLoop [** EXPERIMENTAL **]
         *
         * Function to create a loop from a Db result resource link.
         *
         * @param string $loopname to commit loop. If not set, will use last loopname set using newLoop()
         * @param string $result link to a Db result resource
         * @param string $db_type, type of db that the result resource belongs to.
         * @return boolean true/false
         * @access public
         */
        function setDbLoop ($loopname, $result, $db_type='MYSQL') {
            $db_type = strtoupper($db_type);
            if (!in_array($db_type, $this->allowed_loop_dbs)) {
                vlibTemplateError::raiseError('VT_WARNING_INVALID_LOOP_DB',WARNING, $db_type);
                return false;
            }
            $loop_arr = array();
            switch ($db_type) {
                case 'MYSQL':
                    if (get_resource_type($result) != 'mysql result') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while($r = mysql_fetch_assoc($result)) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'POSTGRESQL':
                    if (get_resource_type($result) != 'pgsql result') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    $nr = (function_exists('pg_num_rows')) ? pg_num_rows($result) : pg_numrows($result);
                    for ($i=0; $i < $nr; $i++) {
                        $loop_arr[] = pg_fetch_array($result, $i, PGSQL_ASSOC);
                    }
                break;
                case 'INFORMIX':
                    if (!$result) {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while($r = ifx_fetch_row($result, 'NEXT')) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'INTERBASE':
                    if (get_resource_type($result) != 'interbase result') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while($r = ibase_fetch_row($result)) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'INGRES':
                    if (!$result) {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while($r = ingres_fetch_array(INGRES_ASSOC, $result)) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'MSSQL':
                    if (get_resource_type($result) != 'mssql result') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while($r = mssql_fetch_array($result)) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'MSQL':
                    if (get_resource_type($result) != 'msql result') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while($r = msql_fetch_array($result, MSQL_ASSOC)) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'OCI8':
                    if (get_resource_type($result) != 'oci8 statement') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while(OCIFetchInto($result, &$r, OCI_ASSOC+OCI_RETURN_LOBS)) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'ORACLE':
                    if (get_resource_type($result) != 'oracle Cursor') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while(ora_fetch_into($result, &$r, ORA_FETCHINTO_ASSOC)) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'OVRIMOS':
                    if (!$result) {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while(ovrimos_fetch_into($result, &$r, 'NEXT')) {
                        $loop_arr[] = $r;
                    }
                break;
                case 'SYBASE':
                    if (get_resource_type($result) != 'sybase-db result') {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE',WARNING, $db_type);
                        return false;
                    }
                    while($r = sybase_fetch_array($result)) {
                        $loop_arr[] = $r;
                    }
                break;
            }
            $this->setLoop($loopname, $loop_arr);
            return true;
        }
        /**
         * FUNCTION: newLoop
         *
         * Sets the name for the curent loop in the 3 step loop process.
         *
         * @param string $name string to define loop name
         * @return boolean true/false
         * @access public
         */
        function newLoop ($loopname) {
            if (preg_match('/^[a-z_]+[a-z0-9_]*$/i', $loopname)) {
                $this->_currloopname[$loopname] = $loopname;
                $this->_currloop[$loopname] = array();
                return true;
            }
            else {
                return false;
            }
        }
        /**
         * FUNCTION: addRow
         *
         * Adds a row to the current loop in the 3 step loop process.
         *
         * @param array $row loop row to add to current loop
         * @param string $loopname loop to which you want to add row, if not set will use last loop set using newLoop().
         * @return boolean true/false
         * @access public
         */
        function addRow ($row, $loopname=null) {
            if (!$loopname) $loopname = $this->_currloopname[(count($this->_currloopname)-1)];
            if (!isset($this->_currloop[$loopname]) || empty($this->_currloopname)) {
                vlibTemplateError::raiseError('VT_WARNING_LOOP_NOT_SET',WARNING);
                return false;
            }
            if (is_array($row)) {
                $this->_currloop[$loopname][] = $row;
                return true;
            }
            else {
                return false;
            }
        }
        /**
         * FUNCTION: addLoop
         *
         * Completes the 3 step loop process. This assigns the rows and resets
         * the variables used.
         *
         * @param string $loopname to commit loop. If not set, will use last loopname set using newLoop()
         * @return boolean true/false
         * @access public
         */
        function addLoop ($loopname=null) {
            if ($loopname == null) { // add last loop used
                if (!empty($this->_currloop)) {
                    foreach ($this->_currloop as $k => $v) {
                        $this->setLoop($k, $v);
                        unset($this->_currloop[$k]);
                    }
                    $this->_currloopname = array();
                    return true;
                }
                else {
                    return false;
                }
            }
            elseif (!isset($this->_currloop[$loopname]) || empty($this->_currloopname)) { // newLoop not yet envoked
                    vlibTemplateError::raiseError('VT_WARNING_LOOP_NOT_SET',WARNING);
                    return false;
            }
            else { // add a specific loop
                $this->setLoop($loopname, $this->_currloop[$loopname]);
                unset($this->_currloopname[$loopname], $this->_currloop[$loopname]);
            }
            return true;
        }
        /**
         * FUNCTION: unsetLoop
         *
         * Unsets a loop which has already been set.
         * Can only unset top level loops.
         *
         * @param string loop to remove use: vlibTemplate::unsetLoop(loop[, loop..])
         * @return boolean true/false returns true unless called with 0 params
         * @access public
         */
        function unsetLoop () {
            $num_args = func_num_args();
            if ($num_args < 1) return false;
            for ($i = 0; $i < $num_args; $i++) {
                $var = func_get_arg($i);
                if ($this->OPTIONS['CASELESS']) $var = strtolower($var);
                if (!preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $var)) continue;
                unset($this->_arrvars[$var]);
            }
            return true;
        }
        /**
         * FUNCTION: reset
         *
         * Resets the vlibTemplate object. After using vlibTemplate::reset() you must
         * use vlibTemplate::newTemplate(tmpl) to reuse, not passing in the options array.
         *
         * @return boolean true
         * @access public
         */
        function reset () {
            $this->clearVars();
            $this->clearLoops();
            $this->_tmplfilename = null;
            $this->_tmplfile = null;
            $this->_tmplfilep = null;
            $this->_tmploutput = null;
            $this->_parsed = false;
            $this->_unknowns = array();
            $this->_firstparsetime = null;
            $this->_totalparsetime = null;
            $this->_currloopname = null;
            $this->_currloop = array();
            return true;
        }
        /**
         * FUNCTION: clearVars
         *
         * Unsets all variables in the template
         *
         * @return boolean true
         * @access public
         */
        function clearVars () {
            $this->_vars = array();
            return true;
        }
        /**
         * FUNCTION: clearLoops
         *
         * Unsets all loops in the template
         *
         * @return boolean true
         * @access public
         */
        function clearLoops () {
            $this->_arrvars = array();
            $this->_currloopname = null;
            $this->_currloop = array();
            return true;
        }
        /**
         * FUNCTION: clearAll
         *
         * Unsets all variables and loops set using setVar/Loop()
         *
         * @return boolean true
         * @access public
         */
        function clearAll () {
            $this->clearVars();
            $this->clearLoops();
            return true;
        }
        /**
         * FUNCTION: unknownsExist
         *
         * Returns true if unknowns were found after parsing.
         * Function MUST be called AFTER one of the parsing functions to have any relevance.
         *
         * @return boolean true/false
         * @access public
         */
        function unknownsExist () {
            return (!empty($this->_unknowns));
        }
        /**
         * FUNCTION: unknowns
         *
         * Alias for unknownsExist.
         *
         * @access public
         */
        function unknowns () {
            return $this->unknownsExist();
        }
        /**
         * FUNCTION: getUnknowns
         *
         * Returns an array of all unknown vars found when parsing.
         * This function is only relevant after parsing a document.
         *
         * @return array
         * @access public
         */
        function getUnknowns () {
            return $this->_unknowns;
        }
        /**
         * FUNCTION: setUnknowns
         *
         * Sets how you want to handle variables that were found in the
         * template but not set in vlibTemplate using vlibTemplate::setVar().
         *
         * @param  string $arg ignore, remove, print, leave or comment
         * @return boolean
         * @access public
         */
        function setUnknowns ($arg) {
            $arg = strtolower(trim($arg));
            if (preg_match('/^ignore|remove|print|leave|comment$/', $arg)) {
                $this->OPTIONS['UNKNOWNS'] = $arg;
                return true;
            }
            return false;
        }
        /**
         * FUNCTION: setPath
         *
         * function sets the paths to use when including files.
         * Use of this function: vlibTemplate::setPath(string path [, string path, ..]);
         * i.e. if $tmpl is your template object do: $tmpl->setPath('/web/htdocs/templates','/web/htdocs/www');
         * with as many paths as you like.
         * if this function is called without any arguments, it will just delete any previously set paths.
         *
         * @param string path (mulitple)
         * @return bool success
         * @access public
         */
        function setPath () {
            $num_args = func_num_args();
            if ($num_args < 1) {
                $this->OPTIONS['INCLUDE_PATHS'] = array();
                return true;
            }
            for ($i = 0; $i < $num_args; $i++) {
                $thispath = func_get_arg($i);
                array_push($this->OPTIONS['INCLUDE_PATHS'], realpath($thispath));
            }
            return true;
        }
        /**
         * FUNCTION: getParseTime
         *
         * After using one of the parse functions, this will allow you
         * access the time taken to parse the template.
         * see OPTION 'TIME_PARSE'.
         *
         * @return float time taken to parse template
         * @access public
         */
        function getParseTime () {
            if ($this->OPTIONS['TIME_PARSE'] && $this->_parsed) {
                return $this->_totalparsetime;
            }
            return false;
        }
        /**
         * FUNCTION: fastPrint
         *
         * Identical to pparse() except that it uses output buffering w/ gz compression thus
         * printing the output directly and compressed if poss.
         * Will possibly if parsing a huge template.
         *
         * @access public
         * @return boolean true/false
         */
        function fastPrint () {
            $ret = $this->_parse('ob_gzhandler');
            print($this->_tmploutput);
            return $ret;
        }
        /**
         * FUNCTION: pparse
         *
         * Calls parse, and then prints out $this->_tmploutput
         *
         * @access public
         * @return boolean true/false
         */
        function pparse () {
            if (!$this->_parsed) $this->_parse();
            print($this->_tmploutput);
            return true;
        }
        /**
         * FUNCTION: pprint
         *
         * Alias for pparse()
         *
         * @access public
         */
        function pprint () {
            return $this->pparse();
        }
        /**
         * FUNCTION: grab
         *
         * Returns the parsed output, ready for printing, passing to mail() ...etc.
         * Invokes $this->_parse() if template has not yet been parsed.
         *
         * @access public
         * @return boolean true/false
         */
        function grab () {
            if (!$this->_parsed) $this->_parse();
            return $this->_tmploutput;
        }
    /*-----------------------------------------------------------------------------\
    |                           private functions                                  |
    \-----------------------------------------------------------------------------*/
        /**
         * FUNCTION: vlibTemplate
         *
         * vlibTemplate constructor.
         * if $tmplfile has been passed to it, it will send to $this->newTemplate()
         *
         * @param string $tmplfile full path to template file
         * @param array $options see above
         * @return boolean true/false
         * @access private
         */
        function tpl ($tmplfile=null, $options=null) {
            if (is_array($tmplfile) && $options == null) {
                $options = $tmplfile;
                unset($tmplfile);
            }
            $this->VLIBTEMPLATE_ROOT = dirname(realpath(__FILE__));
            if (is_array(vlibIni::vlibTemplate())) {
                foreach (vlibIni::vlibTemplate() as $name => $val) {
                    $this->OPTIONS[$name] = $val;
                }
            }
            if (is_array($options)) {
                foreach($options as $key => $val) {
                    $key = strtoupper($key);
                    if ($key == 'PATH') {
                        $this->setPath($val);
                    }
                    else {
                        $this->_setOption($key, strtolower($val));
                    }
                }
            }
            if($tmplfile) $this->newTemplate($tmplfile);
            if ($this->OPTIONS['GLOBAL_CONTEXT_VARS']) $this->setContextVars();
            return true;
        }
        /** FUNCTION: _getData
         *
         * function returns the text from the file, or if we're using cache, the text
         * from the cache file. MUST RETURN DATA.
         * @param string tmplfile contains path to template file
         * @param do_eval used for included files. If set then this function must do the eval()'ing.
         * @access private
         * @return mixed data/string or boolean
         */
        function _getData ($tmplfile, $do_eval=false) {
            //check the current file depth
            if ($this->_includedepth > $this->OPTIONS['MAX_INCLUDES'] || $tmplfile == false) {
                return;
            }
            else {
                if ($this->_debug) array_push ($this->_debugIncludedfiles, $tmplfile);
                if ($do_eval) {
                    array_push($this->_currentincludedir, dirname($tmplfile));
                    $this->_includedepth++;
                }
            }
            if($this->_cache && $this->_checkCache($tmplfile)) { // cache exists so lets use it
                $data = fread($fp = fopen($this->_cachefile, 'r'), filesize($this->_cachefile));
                fclose($fp);
            }
            else { // no cache lets parse the file
                $data = fread($fp = fopen($tmplfile, 'r'), filesize($tmplfile));
                fclose($fp);
                $regex = '/(<|<\/|{|{\/|<!--|<!--\/){1}\s*';
                $regex.= 'tmpl_([\w]+)\s*';
                $regex.= '(?:';
                $regex.=    '(?:';
                $regex.=        '(name|format|escape|op|value|file)';
                $regex.=        '\s*=\s*';
                $regex.=    ')?';
                $regex.=    '(?:[\"\'])?';
                $regex.=    '((?<=[\"\'])';
                $regex.=    '[^\"\']*|[a-z0-9_\.]*)';
                $regex.=    '[\"\']?';
                $regex.= ')?\s*';
                $regex.= '(?:';
                $regex.=    '(?:';
                $regex.=        '(name|format|escape|op|value)';
                $regex.=        '\s*=\s*';
                $regex.=    ')';
                $regex.=    '(?:[\"\'])?';
                $regex.=    '((?<=[\"\'])';
                $regex.=    '[^\"\']*|[a-z0-9_\.]*)';
                $regex.=    '[\"\']?';
                $regex.= ')?\s*';
                $regex.= '(?:';
                $regex.=    '(?:';
                $regex.=        '(name|format|escape|op|value)';
                $regex.=        '\s*=\s*';
                $regex.=    ')';
                $regex.=    '(?:[\"\'])?';
                $regex.=    '((?<=[\"\'])';
                $regex.=    '[^\"\']*|[a-z0-9_\.]*)';
                $regex.=    '[\"\']?';
                $regex.= ')?\s*';
                $regex.= '(?:>|\/>|}|-->){1}';
                $regex.= '/ie';
                //$regex.= '([\r\n|\n|\r])?/ie';
                $data = preg_replace($regex,"\$this->_parseTag(array('\\0','\\1','\\2','\\3','\\4','\\5','\\6','\\7','\\8','\\9'));",$data);
                if ($this->_cache) { // add cache if need be
                    $this->_createCache($data);
                }
            }
            // now we must parse the $data and check for any <tmpl_include>'s
            if ($this->_debug) $this->doDebugWarnings(file($tmplfile), $tmplfile);
            if ($do_eval) {
                $success = @eval('?>'.$data.'<?php return 1;');
                $this->_includedepth--;
                array_pop($this->_currentincludedir);
                return $success;
            }
            else {
                return $data;
            }
        }
        /**
         * FUNCTION: _fileSearch
         *
         * Searches for all possible instances of file { $file }
         *
         * @param string $file path of file we're looking for
         * @access private
         * @return mixed fullpath to file or boolean false
         */
        function _fileSearch ($file) {
            $filename = basename($file);
            $filepath = dirname($file);
            // check fullpath first..
            $fullpath = $filepath.'/'.$filename;
            if (is_file($fullpath)) return $fullpath;
            // ..then check for relative path for current directory..
            if (!empty($this->_currentincludedir)) {
                $currdir = $this->_currentincludedir[(count($this->_currentincludedir) -1)];
                $relativepath = realpath($currdir.'/'.$filepath.'/'.$filename);
                if (is_file($relativepath)) {
                    array_push ($this->_currentincludedir, dirname($relativepath));
                    return $relativepath;
                }
            }
            // ..then check for relative path for all additional given paths..
            if (!empty($this->OPTIONS['INCLUDE_PATHS'])) {
                foreach ($this->OPTIONS['INCLUDE_PATHS'] as $currdir) {
                    $relativepath = realpath($currdir.'/'.$filepath.'/'.$filename);
                    if (is_file($relativepath)) {
                        return $relativepath;
                    }
                }
            }
            // ..then check path from TEMPLATE_DIR..
            if (!empty($this->OPTIONS['TEMPLATE_DIR'])) {
                $fullpath = realpath($this->OPTIONS['TEMPLATE_DIR'].'/'.$filepath.'/'.$filename);
                if (is_file($fullpath)) return $fullpath;
            }
            // ..then check relative path from executing php script..
            $fullpath = realpath($filepath.'/'.$filename);
            if (is_file($fullpath)) return $fullpath;
            // ..then check path from template file.
            if (!empty($this->VLIBTEMPLATE_ROOT)) {
                $fullpath = realpath($this->VLIBTEMPLATE_ROOT.'/'.$filepath.'/'.$filename);
                if (is_file($fullpath)) return $fullpath;
            }
            return false; // uh oh, file not found
        }
        /**
         * FUNCTION: _arrayBuild
         *
         * Modifies the array $arr to add Template variables, __FIRST__, __LAST__ ..etc
         * if $this->OPTIONS['LOOP_CONTEXT_VARS'] is true.
         * Used by $this->setloop().
         *
         * @param array $arr
         * @return array new look array
         * @access private
         */
        function _arrayBuild ($arr) {
            if (is_array($arr) && !empty($arr)) {
                $arr = array_values($arr); // to prevent problems w/ non sequential arrays
                for ($i = 0; $i < count($arr); $i++) {
                    if(!is_array($arr[$i]))  return false;
                    foreach ($arr[$i] as $k => $v) {
                        unset($arr[$i][$k]);
                        if ($this->OPTIONS['CASELESS']) $k = strtolower($k);
                        if (preg_match('/^[0-9]+$/', $k)) $k = '_'.$k;
                        if (is_array($v)) {
                            if (($arr[$i][$k] = $this->_arrayBuild($v)) == false) return false;
                        }
                        else { // reinsert the var
                            $arr[$i][$k] = $v;
                        }
                    }
                    if ($this->OPTIONS['LOOP_CONTEXT_VARS']) {
                        if ($i == 0) $arr[$i]['__FIRST__'] = true;
                        if (($i + 1) == count($arr)) $arr[$i]['__LAST__'] = true;
                        if ($i != 0 && (($i + 1) < count($arr))) $arr[$i]['__INNER__'] = true;
                        if (is_int(($i+1) / 2))  $arr[$i]['__EVEN__'] = true;
                        if (!is_int(($i+1) / 2))  $arr[$i]['__ODD__'] = true;
                        $arr[$i]['__ROWNUM__'] = ($i + 1);
                    }
                }
                return $arr;
            }
            elseif (empty($arr)) {
                return true;
            }
        }
        /**
         * FUNCTION: _parseIf
         * returns a string used for parsing in tmpl_if statements.
         *
         * @param string $varname
         * @param string $value
         * @param string $op
         * @param string $namespace current namespace
         * @access private
         * @return string used for eval'ing
         */
        function _parseIf ($varname, $value=null, $op=null, $namespace=null) {
            if (isset($namespace)) $namespace = substr($namespace, 0, -1);
            $comp_str = ''; // used for extended if statements
            // work out what to put on the end id value="whatever" is used
            if (isset($value)) {
                // add the correct operator depending on whether it's been specified or not
                if (!empty($op)) {
                    if (in_array($op, $this->allowed_if_ops)) {
                        $comp_str .= $op;
                    }
                    else {
                        vlibTemplateError::raiseError('VT_WARNING_INVALID_IF_OP', WARNING, $op);
                    }
                }
                else {
                    $comp_str .= '==';
                }
                // now we add the value, if it's numeric, then we leave the quotes off
                if (is_numeric($value)) {
                    $comp_str .= $value;
                }
                else {
                    $comp_str .= '\''.$value.'\'';
                }
            }
            if (count($this->_namespace) == 0 || $namespace == 'global') return '$this->_vars[\''.$varname.'\']'.$comp_str;
            $retstr = '$this->_arrvars';
            $numnamespaces = count($this->_namespace);
            for ($i=0; $i < $numnamespaces; $i++) {
                if ($this->_namespace[$i] == $namespace || (($i + 1) == $numnamespaces && !empty($namespace))) {
                    $retstr .= "['".$namespace."'][\$_".$i."]";
                    break 1;
                }
                else {
                    $retstr .= "['".$this->_namespace[$i]."'][\$_".$i."]";
                }
            }
            if ($this->OPTIONS['GLOBAL_VARS'] && empty($namespace)) {
                return '(('.$retstr.'[\''.$varname.'\'] !== null) ? '.$retstr.'[\''.$varname.'\'] : $this->_vars[\''.$varname.'\'])'.$comp_str;
            }
            else {
                return $retstr."['".$varname."']".$comp_str;
            }
        }
        /**
         * FUNCTION: _parseLoop
         * returns a string used for parsing in tmpl_loop statements.
         *
         * @param string $varname
         * @access private
         * @return string used for eval'ing
         */
        function _parseLoop ($varname) {
            array_push($this->_namespace, $varname);
            $tempvar = count($this->_namespace) - 1;
            $retstr = "for (\$_".$tempvar."=0 ; \$_".$tempvar." < count(\$this->_arrvars";
            for ($i=0; $i < count($this->_namespace); $i++) {
                $retstr .= "['".$this->_namespace[$i]."']";
                if ($this->_namespace[$i] != $varname) $retstr .= "[\$_".$i."]";
            }
            return $retstr."); \$_".$tempvar."++) {";
        }
        /**
         * FUNCTION: _parseVar
         *
         * returns a string used for parsing in tmpl_var statements.
         *
         * @param string $wholetag
         * @param string $tag
         * @param string $varname
         * @param string $escape
         * @param string $format
         * @param string $namespace
         * @access private
         * @return string used for eval'ing
         */
        function _parseVar ($wholetag, $tag, $varname, $escape, $format, $namespace) {
            if (!empty($namespace)) $namespace = substr($namespace, 0, -1);
            $wholetag = stripslashes($wholetag);
            if (count($this->_namespace) == 0 || $namespace == 'global') {
                $var1 = '$this->_vars[\''.$varname.'\']';
            }
            else {
                $var1build = "\$this->_arrvars";
                $numnamespaces = count($this->_namespace);
                for ($i=0; $i < $numnamespaces; $i++) {
                    if ($this->_namespace[$i] == $namespace || (($i + 1) == $numnamespaces && !empty($namespace))) {
                        $var1build .= "['".$namespace."'][\$_".$i."]";
                        break 1;
                    }
                    else {
                        $var1build .= "['".$this->_namespace[$i]."'][\$_".$i."]";
                    }
                }
                $var1 = $var1build . "['$varname']";
                if ($this->OPTIONS['GLOBAL_VARS'] && empty($namespace)) {
                    $var2 = '$this->_vars[\''.$varname.'\']';
                }
            }
            $beforevar = '';
            $aftervar  = '';
            if (!empty($escape)&& isset($this->ESCAPE_TAGS[$escape])) {
                $beforevar .= $this->ESCAPE_TAGS[$escape]['open'];
                $aftervar   = $this->ESCAPE_TAGS[$escape]['close'] . $aftervar;
            }
            if (!empty($format)&& isset($this->FORMAT_TAGS[$format])) {
                $beforevar .= $this->FORMAT_TAGS[$format]['open'];
                $aftervar   = $this->FORMAT_TAGS[$format]['close'] . $aftervar;
            }
            // build return values
            $retstr  = 'if ('.$var1.' !== null) { ';
            $retstr .= 'print('.$beforevar.$var1.$aftervar.'); ';
            $retstr .= '}';
            if (@$var2) {
                $retstr .= ' elseif ('.$var2.' !== null) { ';
                $retstr .= 'print('.$beforevar.$var2.$aftervar.'); ';
                $retstr .= '}';
            }
            switch (strtolower($this->OPTIONS['UNKNOWNS'])) {
                case 'comment':
                    $comment = addcslashes('<!-- unknown variable '.ereg_replace('<!--|-->', '', $wholetag).'//-->', '"');
                    $retstr .= ' else { print("'.$comment.'"); $this->_setUnknown("'.$varname.'"); }';
                    return $retstr;
                break;
                case 'leave':
                    $retstr .= ' else { print("'.addcslashes($wholetag, '"').'"); $this->_setUnknown("'.$varname.'"); }';
                    return $retstr;
                break;
                case 'print':
                    $retstr .= ' else { print("'.htmlspecialchars($wholetag, ENT_QUOTES).'"); $this->_setUnknown("'.$varname.'"); }';
                    return $retstr;
                break;
                case 'ignore':
                    return $retstr;
                break;
                case 'remove':
                default:
                    $retstr .= ' else { $this->_setUnknown("'.$varname.'"); }';
                    return $retstr;
                break;
            }
        }
        /**
         * FUNCTION: _parseTag
         * takes values from preg_replace in $this->_intparse() and determines
         * the replace string.
         *
         * @param array $args array of all matches found by preg_replace
         * @access private
         * @return string replace values
         */
        function _parseTag ($args) {
            $wholetag = $args[0];
            $openclose = $args[1];
            $tag = strtolower($args[2]);
            $newline = $args[9];
            //echo "1#$newline#2";
            if ($tag == 'else') return '<?php } else { ?>'.$newline;
            if ($tag == 'tmpl_include') return $wholetag; // ignore tmpl_include tags
            if (preg_match("/^<\/|{\/|<!--\/$/s", $openclose) || preg_match("/^end[if|loop|unless|comment]$/", $tag)) {
                if ($tag == 'loop' || $tag == 'endloop') array_pop($this->_namespace);
                if ($tag == 'comment' || $tag == 'endcomment') {
                    return '<?php */ ?>'.$newline;
                }
                else {
                    return '<?php } ?>'.$newline;
                }
            }
            // arrange attributes
            for ($i=3; $i < 8; $i=($i+2)) {
                if (empty($args[$i]) && empty($args[($i+1)])) break;
                $key = (empty($args[$i])) ? 'name' : strtolower($args[$i]);
                if ($key == 'name' && preg_match('/^(php)?include$/', $tag)) $key = 'file';
                $$key = $args[($i+1)];
            }
            $var = ($this->OPTIONS['CASELESS']) ? strtolower($name) : $name;
            if ($this->_debug && !empty($var)) {
                if (preg_match("/^global\.([A-Za-z_]+[_A-Za-z0-9]*)$/", $var, $matches)) $var2 = $matches[1];
                if (empty($this->_debugTemplatevars[$tag])) $this->_debugTemplatevars[$tag] = array();
                if (!isset($var2)) $var2 = $var;
                if (!in_array($var2, $this->_debugTemplatevars[$tag])) array_push($this->_debugTemplatevars[$tag], $var2);
            }
            if (preg_match("/^([A-Za-z_]+[_A-Za-z0-9]*(\.)+)?([A-Za-z_]+[_A-Za-z0-9]*)$/", $var, $matches)) {
                $var = $matches[3];
                $namespace = $matches[1];
            }
            // return correct string (tag dependent)
            switch ($tag) {
                case 'var':
                    if (empty($escape) && (!empty($this->OPTIONS['DEFAULT_ESCAPE']) && strtolower($this->OPTIONS['DEFAULT_ESCAPE']) != 'none')) {
                        $escape = strtolower($this->OPTIONS['DEFAULT_ESCAPE']);
                    }
                    return '<?php '.$this->_parseVar ($wholetag, $tag, $var, @$escape, @$format, @$namespace).' ?>'.$newline."\n";
                break;
                case 'if':
                    return '<?php if ('. $this->_parseIf($var, @$value, @$op, @$namespace) .') { ?>'.$newline;
                break;
                case 'unless':
                      return '<?php if (!'. $this->_parseIf($var, @$value, @$op, @$namespace) .') { ?>'.$newline;
                break;
                case 'elseif':
                      return '<?php } elseif ('. $this->_parseIf($var, @$value, @$op, @$namespace) .') { ?>'.$newline;
                break;
                case 'loop':
                      return '<?php '. $this->_parseLoop($var) .'?>'.$newline;
                break;
                case 'comment':
                    if (empty($var)) { // full open/close style comment
                        return '<?php /* ?>'.$newline;
                    }
                    else { // just ignore tag if it was a one line comment
                        return;
                    }
                break;
                case 'phpinclude':
                    if ($this->OPTIONS['ENABLE_PHPINCLUDE']) {
                        return '<?php include(\''.$file.'\'); ?>'.$newline;
                    }
                break;
                case 'include':
                    return '<?php $this->_getData($this->_fileSearch(\''.$file.'\'), 1); ?>';
                break;
                case 'dyninclude':
                    return '<?php $this->_getData($this->_fileSearch($this->_dyninclude[\''.$name.'\']), 1); ?>';
                break;
                default:
                    if ($this->OPTIONS['STRICT']) vlibTemplateError::raiseError('VT_ERROR_INVALID_TAG', KILL, htmlspecialchars($wholetag, ENT_QUOTES));
                break;
            }
        }
        /**
         * FUNCTION: _intParse
         *
         * Parses $this->_tmplfile into correct format for eval() to work
         * Called by $this->_parse(), or $this->fastPrint, this replaces all <tmpl_*> references
         * with their correct php representation, i.e. <tmpl_var title> becomes $this->vars['title']
         * Sets final parsed file to $this->_tmplfilep.
         *
         * @access private
         * @return boolean true/false
         */
        function _intParse () {
            $mqrt = get_magic_quotes_runtime();
            set_magic_quotes_runtime(0);
            $this->_tmplfilep = '?>'.$this->_getData($this->_tmplfilename).'<?php return true;';
            set_magic_quotes_runtime($mqrt);
            return true;
        }
        /**
         * FUNCTION: _parse
         *
         * Calls _intParse, and eval()s $this->tmplfilep
         * and outputs the results to $this->tmploutput
         *
         * @param bool compress whether to compress contents
         * @access private
         * @return boolean true/false
         */
        function _parse ($compress='') {
            if (!$this->_parsed) {
                if ($this->OPTIONS['TIME_PARSE']) $this->_firstparsetime = $this->_getMicroTime();
                $this->_intParse();
                $this->_parsed = true;
                if ($this->OPTIONS['TIME_PARSE']) $this->_totalparsetime = ($this->_getMicroTime() - $this->_firstparsetime);
                if ($this->OPTIONS['TIME_PARSE'] && $this->OPTIONS['GLOBAL_CONTEXT_VARS']) $this->setVar('__PARSE_TIME__', $this->getParseTime());
            }
            // ob_start($compress);
            ob_start();
                array_push($this->_currentincludedir, dirname($this->_tmplfilename));
                $this->_includedepth++;
                $success = @eval($this->_tmplfilep);
                $this->_includedepth--;
                array_pop($this->_currentincludedir);
                if ($this->_debug) $this->doDebug();
                if (!$success) vlibTemplateError::raiseError('VT_ERROR_PARSE', FATAL);
                $this->_tmploutput .= ob_get_contents();
            ob_end_clean();
            return true;
        }
        /**
         * FUNCTION: _setOption
         *
         * Sets one or more of the boolean options 1/0, that control certain actions in the template.
         * Use of this function:
         * either: vlibTemplate::_setOptions(string option_name, bool option_val [, string option_name, bool option_val ..]);
         * or      vlibTemplate::_setOptions(array);
         *          with an associative array where the key is the option_name
         *          and the value is the option_value.
         *
         * @param mixed (mulitple)
         * @return bool true/false
         * @access private
         */
        function _setOption () {
            $numargs = func_num_args();
            if ($numargs < 1) {
                vlibTemplateError::raiseError('VT_ERROR_WRONG_NO_PARAMS', null, '_setOption()');
                return false;
            }
            if ($numargs == 1) {
                $options = func_get_arg(1);
                if (is_array($options)) {
                    foreach ($options as $k => $v) {
                        if ($v != null) {
                            if(in_array($k, array_keys($this->OPTIONS))) $this->OPTIONS[$k] = $v;
                        }
                        else {
                            continue;
                        }
                    }
                }
                else {
                    vlibTemplateError::raiseError('VT_ERROR_WRONG_NO_PARAMS', null, '_setOption()');
                    return false;
                }
            }
            elseif (is_int($numargs / 2)) {
                for ($i = 0; $i < $numargs; $i=($i+2)) {
                    $k  = func_get_arg($i);
                    $v = func_get_arg(($i+1));
                    if ($v != null) {
                        if(in_array($k, array_keys($this->OPTIONS))) $this->OPTIONS[$k] = $v;
                    }
                }
            }
            else {
                vlibTemplateError::raiseError('VT_ERROR_WRONG_NO_PARAMS', null, '_setOption()');
                return false;
            }
            return true;
        }
        /**
         * FUNCTION: _setUnknown
         *
         * Used during parsing, this function sets an unknown var checking to see if it
         * has been previously set.
         *
         * @param string var
         * @access private
         */
        function _setUnknown ($var) {
            if (!in_array($var, $this->_unknowns)) array_push($this->_unknowns, $var);
        }
        /**
         * FUNCTION: _getMicrotime
         * Returns microtime as a float number
         *
         * @return float microtime
         * @access private
         */
        function _getMicrotime () {
            list($msec, $sec) = explode(" ",microtime());
            return ((float)$msec + (float)$sec);
        }
        /**
         * FUNCTION: _escape_hex
         * Returns str encoded to hex code.
         *
         * @param string str to be encoded
         * @param bool true/false specify whether to use hex_entity
         * @return string encoded in hex
         * @access private
         */
        function _escape_hex($str="", $entity=false) {
            $prestr = $entity ? '&#x' : '%';
            $poststr= $entity ? ';' : '';
            for ($i=0; $i < strlen($str); $i++) {
                $return .= $prestr.bin2hex($str[$i]).$poststr;
            }
            return $return;
        }
    /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    The following functions have no use and are included just so that if the user
    is making use of vlibTemplateCache functions, this doesn't crash when changed to
    vlibTemplate if the user is quickly bypassing the vlibTemplateCache class.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
        function clearCache()        {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'clearCache()');}
        function recache()           {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'recache()');}
        function setCacheLifeTime()  {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'setCacheLifeTime()');}
        function setCacheExtension() {vlibTemplateError::raiseError('VT_WARNING_NOT_CACHE_OBJ', WARNING, 'setCacheExtension()');}
    }
    //include_once ($conf['classpath'].'/vlibTemplate/debug.php');
    include_once ($conf['classpath'].'/tpl_cache.inc.php');
} // << end if(!defined())..
?>
server/lib/classes/tpl_cache.inc.php
New file
@@ -0,0 +1,186 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002 Active Fish Group                                 |
// +----------------------------------------------------------------------+
// | Authors: Kelvin Jones <kelvin@kelvinjones.co.uk>                     |
// +----------------------------------------------------------------------+
//
// $Id: cache.php,v 1.1 2003/07/08 12:32:06 platinum Exp $
/**
 * Class uses all of vlibTemplate's functionality but caches the template files.
 * It creates an identical tree structure to your filesystem but with cached files.
 *
 * @author Kelvin Jones <kelvin@kelvinjones.co.uk>
 * @since 22/02/2002
 * @package vLIB
 * @access public
 */
class tplc extends tpl {
/*-----------------------------------------------------------------------------\
|     DO NOT TOUCH ANYTHING IN THIS CLASS, IT MAY NOT WORK OTHERWISE           |
\-----------------------------------------------------------------------------*/
    var $_cache = 1;     // tells vlibTemplate that we're caching
    var $_cachefile;     // full path to current cache file (even if it doesn't yet exist)
    var $_cacheexists;   // has this file been cached before
    var $_cachefilelocked; // is this file currently locked whilst writing
    var $_cachefiledir;  // dir of current cache file
    var $_clearcache = 0;
    /**
     * FUNCTION: clearCache
     * will unset a file, and set $this->_cacheexists to 0.
     *
     * @access public
     * @return boolean
     */
    function clearCache() {
        $this->_clearcache = 1;
        return true;
    }
    /**
     * FUNCTION: recache
     * alias for clearCache().
     *
     * @access public
     * @return boolean
     */
    function recache() {
        return $this->clearCache();
    }
    /**
     * FUNCTION: setCacheLifeTime
     * sets the lifetime of the cached file
     *
     * @param int $int number of seconds to set lifetime to
     * @access public
     * @return boolean
     */
    function setCacheLifeTime($int = null) {
        if ($int == null || !is_int($int)) return false;
        if ($int == 0) $int = 60;
        if ($int == -1) $int = 157680000; // set to 5 yrs time
        $this->OPTIONS['CACHE_LIFETIME'] = $int;
        return true;
    }
    /**
     * FUNCTION: setCacheExtension
     * sets the extention of the cache file
     *
     * @param str $str name of new cache extention
     * @access public
     * @return boolean
     */
    function setCacheExtension($str = null) {
        if ($str == null || !ereg('^[a-z0-9]+$', strtolower($str))) return false;
        $this->OPTIONS['CACHE_EXTENSION'] = strtolower($str);
        return true;
    }
/*----------------------------------------\
          Private Functions
-----------------------------------------*/
    /**
     * FUNCTION: _checkCache
     * checks if there's a cache, if there is then it will read the cache file as the template.
     */
    function _checkCache ($tmplfile) {
        $this->_cachefile = $this->_getFilename($tmplfile);
        if ($this->_clearcache) {
            if (file_exists($this->_cachefile)) unlink($this->_cachefile);
            return false;
        }
        if (file_exists($this->_cachefile)) {
            $this->_cacheexists = 1;
            // if it's expired
            if ((filemtime($this->_cachefile) + $this->OPTIONS['CACHE_LIFETIME']) < date ('U')
                  || filectime($this->_cachefile) < filemtime($tmplfile)) {
                $this->_cacheexists = 0;
                return false; // so that we know to recache
            }
            else {
                return true;
            }
        } else {
            $this->_cacheexists = 0;
            return false;
        }
    }
    /**
     * FUNCTION: _getFilename
     * gets the full pathname for the cached file
     *
     */
    function _getFilename($tmplfile) {
        return $this->OPTIONS['CACHE_DIRECTORY'].'/'.md5('vlibCachestaR'.realpath($tmplfile)).'.'.$this->OPTIONS['CACHE_EXTENSION'];
    }
    /**
     * FUNCTION: _createCache
     * creates the cached file
     *
     */
    function _createCache($data) {
        $cache_file = $this->_cachefile;
        if(!$this->_prepareDirs($cache_file)) return false; // prepare all of the directories
        $f = fopen ($cache_file, "w");
        flock($f, 2); // set an EXclusive lock
        if (!$f) vlibTemplateError::raiseError('VT_ERROR_NO_CACHE_WRITE',KILL,$cache_file);
        fputs ($f, $data); // write the parsed string from vlibTemplate
        flock($f, 3); // UNlock file
        fclose ($f);
        touch ($cache_file);
        return true;
    }
    /**
     * FUNCTION: _prepareDirs
     * prepares the directory structure
     *
     */
    function _prepareDirs($file) {
        if (empty($file)) die('no filename'); //do error in future
        $filepath = dirname($file);
        if (is_dir($filepath)) return true;
        $dirs = split('[\\/]', $filepath);
        $currpath;
        foreach ($dirs as $dir) {
            $currpath .= $dir .'/';
            $type = @filetype($currpath);
            ($type=='link') and $type = 'dir';
            if ($type != 'dir' && $type != false && !empty($type)) {
                vlibTemplateError::raiseError('VT_ERROR_WRONG_CACHE_TYPE',KILL,'directory: '.$currpath.', type: '.$type);
            }
            if ($type == 'dir') {
                continue;
            }
            else {
                $s = @mkdir($currpath, 0775);
                if (!$s) vlibTemplateError::raiseError('VT_ERROR_CACHE_MKDIR_FAILURE',KILL,'directory: '.$currpath);
            }
        }
        return true;
    }
} // -- end vlibTemplateCache class
?>
server/lib/classes/tpl_error.inc.php
New file
@@ -0,0 +1,92 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002 Active Fish Group                                 |
// +----------------------------------------------------------------------+
// | Authors: Kelvin Jones <kelvin@kelvinjones.co.uk>                     |
// +----------------------------------------------------------------------+
//
// $Id: error.php,v 1.1 2003/07/08 12:32:06 platinum Exp $
define('FATAL', E_USER_ERROR);
define('WARNING', E_USER_WARNING);
define('NOTICE', E_USER_NOTICE);
define('KILL',   -1); // used for killing inside parsing.
/**
 * Class is used by vlibTemplate.
 * It handles all of the error reporting for vlibTemplate.
 *
 * @author Kelvin Jones <kelvin@kelvinjones.co.uk>
 * @since 06/03/2002
 * @package vLIB
 * @access private
 */
class vlibTemplateError {
/*-----------------------------------------------------------------------------\
|     DO NOT TOUCH ANYTHING IN THIS CLASS IT MAY NOT WORK OTHERWISE            |
\-----------------------------------------------------------------------------*/
    function raiseError ($code, $level = null, $extra=null) {
        if (!($level & error_reporting())&& $level != KILL) return; // binary AND checks for reporting level
        $error_codes = array(
                        'VT_ERROR_NOFILE'               => 'vlibTemplate Error: Template ('.$extra.') file not found.',
                        'VT_ERROR_PARSE'                => 'vlibTemplate Error: Parse error!<br>To debug this file, use vlibTemplateDebug instead of vlibTemplate in the class instantiation(i.e. new vlibTemplateDebug).',
                        'VT_NOTICE_INVALID_TAG'         => 'vlibTemplate Notice: Invalid tag ('.$extra.').',
                        'VT_ERROR_INVALID_TAG'          => 'vlibTemplate Error: Invalid tag ('.$extra.'). To disable this you must turn of the STRICT option.',
                        'VT_NOTICE_INVALID_ATT'         => 'vlibTemplate Notice: Invalid attribute ('.$extra.').',
                        'VT_WARNING_INVALID_ARR'        => 'vlibTemplate Warning: Invalid loop structure passed to vlibTemplate::setLoop() (loop name: '.$extra.').',
                        'VT_ERROR_INVALID_ERROR_CODE'   => 'vlibTemplate Error: Invalid error raised.',
                        'VT_ERROR_WRONG_NO_PARAMS'      => 'vlibTemplate Warning: Wrond parameter count passed to '.$extra.'.',
                        'VT_ERROR_UNKNOWN_VAR'          => 'vlibTemplate Error: template var not found.',
                        'VT_ERROR_NO_CACHE_WRITE'       => 'vlibTemplate Error: unable to write to cache file ('.$extra.').',
                        'VT_ERROR_WRONG_CACHE_TYPE'     => 'vlibTemplate Error: non-directory file found in cache root with same name as directory ('.$extra.').',
                        'VT_ERROR_CACHE_MKDIR_FAILURE'  => 'vlibTemplate Error: failed to create directory in cache root ('.$extra.').',
                        'VT_WARNING_NOT_CACHE_OBJ'      => 'vlibTemplate Warning: called a vlibTemplateCache function ('.$extra.') without instantiating the vlibTemplateCache class.',
                        'VT_WARNING_LOOP_NOT_SET'       => 'vlibTemplate Warning: called vlibTemplate::addRow() or vlibTemplate::addLoop() with an invalid loop name.',
                        'VT_WARNING_INVALID_RESOURCE'   => 'vlibTemplate Warning: Invalid resource type passed to vlibTemplate::setDbLoop() for Db "'.$extra.'".',
                        'VT_WARNING_INVALID_LOOP_DB'    => 'vlibTemplate Warning: Invalid Db type passed to vlibTemplate::setDbLoop(), "'.$extra.'" not currently available.',
                        'VT_WARNING_INVALID_IF_OP'      => 'vlibTemplate Warning: The Operator "'.$extra.'" is not supported by vlibTemplate.'
                            );
        $error_levels = array(
                        'VT_ERROR_NOFILE'               => FATAL,
                        'VT_ERROR_PARSE'                => FATAL,
                        'VT_NOTICE_INVALID_TAG'         => NOTICE,
                        'VT_ERROR_INVALID_TAG'          => FATAL,
                        'VT_NOTICE_INVALID_ATT'         => NOTICE,
                        'VT_WARNING_INVALID_ARR'        => WARNING,
                        'VT_ERROR_INVALID_ERROR_CODE'   => FATAL,
                        'VT_ERROR_WRONG_NO_PARAMS'      => WARNING,
                        'VT_ERROR_UNKNOWN_VAR'          => WARNING,
                        'VT_ERROR_NO_CACHE_WRITE'       => KILL,
                        'VT_ERROR_WRONG_CACHE_TYPE'     => KILL,
                        'VT_ERROR_CACHE_MKDIR_FAILURE'  => KILL,
                        'VT_WARNING_NOT_CACHE_OBJ'      => WARNING,
                        'VT_WARNING_LOOP_NOT_SET'       => WARNING,
                        'VT_WARNING_INVALID_RESOURCE'   => WARNING,
                        'VT_WARNING_INVALID_LOOP_DB'    => WARNING,
                        'VT_WARNING_INVALID_IF_OP'      => WARNING
                            );
        ($level === null) and $level = $error_levels[$code];
        if ($level == KILL) {
            die ($error_codes[$code]);
        }
        if ($msg = $error_codes[$code]) {
            trigger_error($msg, $level);
        } else {
            $level = $error_levels['VT_ERROR_INVALID_ERROR_CODE'];
            $msg = $error_codes['VT_ERROR_INVALID_ERROR_CODE'];
            trigger_error($msg, $level);
        }
        return;
    }
}
?>
server/lib/classes/tpl_ini.inc.php
New file
@@ -0,0 +1,116 @@
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4.0                                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002 Active Fish Group                                 |
// +----------------------------------------------------------------------+
// | Authors: Kelvin Jones <kelvin@kelvinjones.co.uk>                     |
// +----------------------------------------------------------------------+
//
// $Id: vlibIni.php,v 1.1 2003/07/08 12:31:10 platinum Exp $
/*
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This file contains configuration parametres for use  ;
; with the vLIB library. [ NOW A CLASS!! ]             ;
;                                                      ;
; vLIB uses this file so that for future releases, you ;
; will not have to delve through all the php script    ;
; again to set your specific variable/properties ..etc ;
;                                                      ;
; ---------------------------------------------------- ;
; ATTENTION: Do NOT remove any variable given in the   ;
; configurations below as they will probably still be  ;
; needed by vLIB. If you do not need a variable simply ;
; let it be.                                           ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
*/
if (!defined('vlibIniClassLoaded')) {
    define('vlibIniClassLoaded', 1);
    /**
     * vlibIni is a class used to store configuration parameters
     * for the vLIB library.
     *
     * @since 21/07/2002
     * @author Kelvin Jones <kelvin@kelvinjones.co.uk>
     * @package vLIB
     * @access private
     */
    class vlibIni {
        /** config vars for vlibTemplate */
        function vlibTemplate () {
            global $conf;
            $tpl_dir = $conf["rootpath"]."/conf";
            return array(
                        'TEMPLATE_DIR' => $tpl_dir,   // Default directory for your template files (full path)
                                                                   // leave the '/' or '\' off the end of the directory.
                        'MAX_INCLUDES' => 10,                      // Drill depth for tmpl_include's
                        'GLOBAL_VARS' => 1,                        // if set to 1, any variables not found in a
                                                                   // loop will search for a global var as well
                        'GLOBAL_CONTEXT_VARS' => 1,                // if set to 1, vlibTemplate will add global vars
                                                                   // reflecting the environment.
                        'LOOP_CONTEXT_VARS' => 1,                  // if set to 1, vlibTemplate will add loop specific vars
                                                                   // on each row of the loop.
                        'SET_LOOP_VAR' => 1,                       // Sets a global variable for each top level loops
                        'DEFAULT_ESCAPE' => 'none',                // 1 of the following: html, url, sq, dq, none
                        'STRICT' => 0,                             // Dies when encountering an incorrect tmpl_*
                                                                   // style tags i.e. tmpl_vae
                        'CASELESS' => 0,                           // Removes case sensitivity on all variables
                        'UNKNOWNS' => 'ignore',                    // How to handle unknown variables.
                                                                   // 1 of the following: ignore, remove, leave,print, comment
                                                                   // 1 of the following: ignore, remove, leave, print, comment
                        'TIME_PARSE' => '0',                       // Will enable you to time how long vlibTemplate takes to parse
                                                                   // your template. You then use the function: getParseTime().
                        'ENABLE_PHPINCLUDE' => '1',                // Will allow template to include a php file using <TMPL_PHPINCLUDE>
                        /* the following are only used by the vlibTemplateCache class. */
                        'CACHE_DIRECTORY' => $conf["template"]["cache_dir"],
                                                                   // Directory where the cached filesystem
                                                                   // will be set up (full path, and must be writable)
                                                                   // '/' or '\' off the end of the directory.
                        'CACHE_LIFETIME' => 604800,                // Duration until file is re-cached in seconds (604800 = 1 week)
                        'CACHE_EXTENSION' => 'vtc'                  // extention to be used by the cached file i.e. index.php will become
                                                                   // index.vtc (vlibTemplate Compiled)
                    );
        } // << end function vlibTemplate
        /** config vars for vlibDate */
        function vlibDate () {
            return array(
                        'DEFAULT_LANG' => 'de'                     // default language for the date displays
                    );
        }// << end function vlibDate
    }// << end class vlibIni
}
?>
server/mods-enabled/web_module.inc.php
@@ -60,7 +60,10 @@
         class that contains the function functionname.
        */
        
        $app->modules->registerTableHook('web_domain','mail_module','process');
        $app->modules->registerTableHook('web_domain','web_module','process');
        // Register service
        $app->services->registerService('httpd','web_module','restartHttpd');
        
    }
    
@@ -80,6 +83,18 @@
            break;
        } // end switch
    } // end function
    // This function is used
    function restartHttpd($action = 'restart') {
        global $app;
        if($action == 'restart') {
            exec('/etc/init.d/apache2 restart');
        } else {
            exec('/etc/init.d/apache2 reload');
        }
    }
} // end class
server/plugins-enabled/apache2_plugin.inc.php
@@ -31,7 +31,7 @@
class apache2_plugin {
    
    var $plugin_name = 'apache2_plugin';
    var $class_name = $this->plugin_name;
    var $class_name = 'apache2_plugin';
    
        
    /*
@@ -54,7 +54,8 @@
    function insert($event_name,$data) {
        global $app, $conf;
        
        // just run the update function
        $this->update($event_name,$data);
        
        
    }
@@ -67,12 +68,100 @@
        $app->uses("getconf");
        $web_config = $app->getconf->get_server_config($conf["server_id"], 'web');
        
        if($data["new"]["document_root"] == '') {
            $app->log("document_root not set",LOGLEVEL_WARN);
            return 0;
        }
        //print_r($data);
        // Check if the directories are there and create them if nescessary.
        if(!is_dir($data["new"]["document_root"]."/web")) exec("mkdir -p ".$data["new"]["document_root"]."/web");
        if(!is_dir($data["new"]["document_root"]."/log")) exec("mkdir -p ".$data["new"]["document_root"]."/log");
        if(!is_dir($data["new"]["document_root"]."/ssl")) exec("mkdir -p ".$data["new"]["document_root"]."/ssl");
        if(!is_dir($data["new"]["document_root"]."/cgi-bin")) exec("mkdir -p ".$data["new"]["document_root"]."/cgi-bin");
        // TODO: Create the symlinks
        // Create group and user, if not exist
        $app->uses("system");
        $groupname = escapeshellcmd($data["new"]["system_group"]);
        if($data["new"]["system_group"] != '' && !$app->system->is_group($data["new"]["system_group"])) {
            exec("groupadd $groupname");
            $app->log("Adding the group: $groupname",LOGLEVEL_DEBUG);
        }
        $username = escapeshellcmd($data["new"]["system_user"]);
        if($data["new"]["system_user"] != '' && !$app->system->is_user($data["new"]["system_user"])) {
            exec("useradd -d ".escapeshellcmd($data["new"]["document_root"])." -g $groupname $username");
            $app->log("Adding the user: $username",LOGLEVEL_DEBUG);
        }
        // Chown and chmod the directories
        exec("chown -R $username:$groupname ".escapeshellcmd($data["new"]["document_root"]));
        // Create the vhost config file
        $app->load('tpl');
        $tpl = new tpl();
        $tpl->newTemplate("vhost.conf.master");
        $vhost_data = $data["new"];
        $vhost_data["document_root"] = $data["new"]["document_root"]."/web";
        $tpl->setVar($vhost_data);
        // get alias domains
        $aliases = $app->db->queryAllRecords("SELECT * FROM web_domain WHERE parent_domain_id = ".$data["new"]["domain_id"]);
        $server_alias = '';
        foreach($aliases as $alias) {
            $server_alias .= $alias["domain"].' ';
        }
        $tpl->setVar('alias',trim($server_alias));
        $vhost_file = escapeshellcmd($web_config["vhost_conf_dir"].'/'.$data["new"]["domain"].'.vhost');
        file_put_contents($vhost_file,$tpl->grab());
        $app->log("Writing the vhost file: $vhost_file",LOGLEVEL_DEBUG);
        unset($tpl);
        // Set the symlink to enable the vhost
        $vhost_symlink = escapeshellcmd($web_config["vhost_conf_enabled_dir"].'/'.$data["new"]["domain"].'.vhost');
        if($data["new"]["active"] == 'y' && !is_link($vhost_symlink)) {
            symlink($vhost_file,$vhost_symlink);
            $app->log("Creating the symlink: $vhost_symlink => $vhost_file",LOGLEVEL_DEBUG);
        }
        // Remove the symlink, if site is inactive
        if($data["new"]["active"] == 'n' && is_link($vhost_symlink)) {
            unlink($vhost_symlink);
            $app->log("Removing symlink: $vhost_symlink => $vhost_file",LOGLEVEL_DEBUG);
        }
        // request a httpd reload when all records have been processed
        $app->services->restartServiceDelayed('httpd','reload');
        
    }
    
    function delete($event_name,$data) {
        global $app, $conf;
        
        // load the server configuration options
        $app->uses("getconf");
        $web_config = $app->getconf->get_server_config($conf["server_id"], 'web');
        // Deleting the vhost file, symlink and the data directory
        $vhost_symlink = escapeshellcmd($web_config["vhost_conf_enabled_dir"].'/'.$data["old"]["domain"].'.vhost');
        unlink($vhost_symlink);
        $app->log("Removing symlink: $vhost_symlink => $vhost_file",LOGLEVEL_DEBUG);
        $vhost_file = escapeshellcmd($web_config["vhost_conf_dir"].'/'.$data["old"]["domain"].'.vhost');
        unlink($vhost_file);
        $app->log("Removing vhost file: $vhost_file",LOGLEVEL_DEBUG);
        $docroot = escapeshellcmd($data["old"]["document_root"]);
        if($docroot != '' && !stristr($docroot,'..')) exec("rm -rf $docroot");
        $app->log("Removing website: $docroot",LOGLEVEL_DEBUG);
        
    }
    
server/server.php
@@ -76,7 +76,7 @@
    $app->log("Found $tmp_num_records changes, starting update process.",LOGLEVEL_DEBUG);
    
    // Load required base-classes
    $app->uses('ini_parser,modules,plugins');
    $app->uses('ini_parser,modules,plugins,file,services');
    
    
    // Get server configuration
@@ -99,8 +99,15 @@
     in the modules that are hooked on to the table actions
    */
    $app->modules->processDatalog();
    /*
     Restart services that need to be restarted after configuration
    */
    $app->services->processDelayedActions();
} else {
    $app->log('Nothing to Update.',LOGLEVEL_DEBUG);
    $app->log('No Updated records found.',LOGLEVEL_DEBUG);
}
/*