Code

Completed migration
authorcajus <cajus@594d385d-05f5-0310-b6e9-bd551577e9d8>
Thu, 12 May 2005 06:45:38 +0000 (06:45 +0000)
committercajus <cajus@594d385d-05f5-0310-b6e9-bd551577e9d8>
Thu, 12 May 2005 06:45:38 +0000 (06:45 +0000)
git-svn-id: https://oss.gonicus.de/repositories/gosa/trunk@188 594d385d-05f5-0310-b6e9-bd551577e9d8

100 files changed:
include/class_config.inc [new file with mode: 0644]
include/class_ldap.inc [new file with mode: 0644]
include/class_mail-methods-cyrus.inc [new file with mode: 0644]
include/class_mail-methods-kolab.inc [new file with mode: 0644]
include/class_mail-methods-sendmail-cyrus.inc [new file with mode: 0644]
include/class_mail-methods.inc [new file with mode: 0644]
include/class_password-methods-clear.inc [new file with mode: 0644]
include/class_password-methods-crypt.inc [new file with mode: 0644]
include/class_password-methods-kerberos.inc [new file with mode: 0644]
include/class_password-methods-md5.inc [new file with mode: 0644]
include/class_password-methods-sha.inc [new file with mode: 0644]
include/class_password-methods-smd5.inc [new file with mode: 0644]
include/class_password-methods-ssha.inc [new file with mode: 0644]
include/class_password-methods.inc [new file with mode: 0644]
include/class_plugin.inc [new file with mode: 0644]
include/class_pluglist.inc [new file with mode: 0644]
include/class_sambaMungedDial.inc [new file with mode: 0644]
include/class_sieve.inc [new file with mode: 0644]
include/class_tabs.inc [new file with mode: 0644]
include/class_userinfo.inc [new file with mode: 0644]
include/debuglib.inc [new file with mode: 0644]
include/functions.inc [new file with mode: 0644]
include/functions_cli.inc [new file with mode: 0644]
include/php_setup.inc [new file with mode: 0644]
include/scanner.inc [new file with mode: 0644]
include/setup_checks.inc [new file with mode: 0644]
include/smarty/Config_File.class.php [new file with mode: 0644]
include/smarty/Smarty.class.php [new file with mode: 0644]
include/smarty/Smarty_Compiler.class.php [new file with mode: 0644]
include/smarty/debug.tpl [new file with mode: 0644]
include/smarty/internals/core.assemble_plugin_filepath.php [new file with mode: 0644]
include/smarty/internals/core.assign_smarty_interface.php [new file with mode: 0644]
include/smarty/internals/core.create_dir_structure.php [new file with mode: 0644]
include/smarty/internals/core.display_debug_console.php [new file with mode: 0644]
include/smarty/internals/core.get_include_path.php [new file with mode: 0644]
include/smarty/internals/core.get_microtime.php [new file with mode: 0644]
include/smarty/internals/core.get_php_resource.php [new file with mode: 0644]
include/smarty/internals/core.is_secure.php [new file with mode: 0644]
include/smarty/internals/core.is_trusted.php [new file with mode: 0644]
include/smarty/internals/core.load_plugins.php [new file with mode: 0644]
include/smarty/internals/core.load_resource_plugin.php [new file with mode: 0644]
include/smarty/internals/core.process_cached_inserts.php [new file with mode: 0644]
include/smarty/internals/core.process_compiled_include.php [new file with mode: 0644]
include/smarty/internals/core.read_cache_file.php [new file with mode: 0644]
include/smarty/internals/core.rm_auto.php [new file with mode: 0644]
include/smarty/internals/core.rmdir.php [new file with mode: 0644]
include/smarty/internals/core.run_insert_handler.php [new file with mode: 0644]
include/smarty/internals/core.smarty_include_php.php [new file with mode: 0644]
include/smarty/internals/core.write_cache_file.php [new file with mode: 0644]
include/smarty/internals/core.write_compiled_include.php [new file with mode: 0644]
include/smarty/internals/core.write_compiled_resource.php [new file with mode: 0644]
include/smarty/internals/core.write_file.php [new file with mode: 0644]
include/smarty/plugins/block.t.php [new file with mode: 0644]
include/smarty/plugins/block.textformat.php [new file with mode: 0644]
include/smarty/plugins/compiler.assign.php [new file with mode: 0644]
include/smarty/plugins/function.assign.php [new file with mode: 0644]
include/smarty/plugins/function.assign_debug_info.php [new file with mode: 0644]
include/smarty/plugins/function.config_load.php [new file with mode: 0644]
include/smarty/plugins/function.counter.php [new file with mode: 0644]
include/smarty/plugins/function.cycle.php [new file with mode: 0644]
include/smarty/plugins/function.debug.php [new file with mode: 0644]
include/smarty/plugins/function.eval.php [new file with mode: 0644]
include/smarty/plugins/function.fetch.php [new file with mode: 0644]
include/smarty/plugins/function.html_checkboxes.php [new file with mode: 0644]
include/smarty/plugins/function.html_image.php [new file with mode: 0644]
include/smarty/plugins/function.html_options.php [new file with mode: 0644]
include/smarty/plugins/function.html_radios.php [new file with mode: 0644]
include/smarty/plugins/function.html_select_date.php [new file with mode: 0644]
include/smarty/plugins/function.html_select_time.php [new file with mode: 0644]
include/smarty/plugins/function.html_table.php [new file with mode: 0644]
include/smarty/plugins/function.mailto.php [new file with mode: 0644]
include/smarty/plugins/function.math.php [new file with mode: 0644]
include/smarty/plugins/function.popup.php [new file with mode: 0644]
include/smarty/plugins/function.popup_init.php [new file with mode: 0644]
include/smarty/plugins/modifier.capitalize.php [new file with mode: 0644]
include/smarty/plugins/modifier.cat.php [new file with mode: 0644]
include/smarty/plugins/modifier.count_characters.php [new file with mode: 0644]
include/smarty/plugins/modifier.count_paragraphs.php [new file with mode: 0644]
include/smarty/plugins/modifier.count_sentences.php [new file with mode: 0644]
include/smarty/plugins/modifier.count_words.php [new file with mode: 0644]
include/smarty/plugins/modifier.date_format.php [new file with mode: 0644]
include/smarty/plugins/modifier.debug_print_var.php [new file with mode: 0644]
include/smarty/plugins/modifier.default.php [new file with mode: 0644]
include/smarty/plugins/modifier.escape.php [new file with mode: 0644]
include/smarty/plugins/modifier.indent.php [new file with mode: 0644]
include/smarty/plugins/modifier.lower.php [new file with mode: 0644]
include/smarty/plugins/modifier.nl2br.php [new file with mode: 0644]
include/smarty/plugins/modifier.regex_replace.php [new file with mode: 0644]
include/smarty/plugins/modifier.replace.php [new file with mode: 0644]
include/smarty/plugins/modifier.spacify.php [new file with mode: 0644]
include/smarty/plugins/modifier.string_format.php [new file with mode: 0644]
include/smarty/plugins/modifier.strip.php [new file with mode: 0644]
include/smarty/plugins/modifier.strip_tags.php [new file with mode: 0644]
include/smarty/plugins/modifier.truncate.php [new file with mode: 0644]
include/smarty/plugins/modifier.upper.php [new file with mode: 0644]
include/smarty/plugins/modifier.wordwrap.php [new file with mode: 0644]
include/smarty/plugins/outputfilter.trimwhitespace.php [new file with mode: 0644]
include/smarty/plugins/shared.escape_special_chars.php [new file with mode: 0644]
include/smarty/plugins/shared.make_timestamp.php [new file with mode: 0644]
include/version.inc [new file with mode: 0644]

diff --git a/include/class_config.inc b/include/class_config.inc
new file mode 100644 (file)
index 0000000..bbab2e2
--- /dev/null
@@ -0,0 +1,448 @@
+<?php
+/*
+ * This code is part of GOsa (https://gosa.gonicus.de)
+ * Copyright (C) 2003  Cajus Pollmeier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+class config  {
+
+  /* XML parser */
+  var $parser;
+  var $config_found= FALSE;
+  var $tags= array();
+  var $level= 0;
+  var $gpc= 0;
+  var $section= "";
+  var $currentLocation= "";
+
+  /* Selected connection */
+  var $current= array();
+
+  /* Link to LDAP-server */
+  var $ldap= NULL;
+  var $referrals= array();
+
+  /* Configuration data */
+  var $data= array( 'TABS' => array(), 'LOCATIONS' => array(), 'SERVERS' => array(),
+               'MAIN' => array( 'LANGUAGES' => array(), 'FAXFORMATS' => array() ),
+               'MENU' => array(), 'SERVICE' => array());
+  var $basedir= "";
+
+  /* Keep a copy of the current deparment list */
+  var $departments= array();
+  var $idepartments= array();
+
+  function config($filename, $basedir= "")
+  {
+       $this->parser = xml_parser_create();
+       $this->basedir= $basedir;
+
+       xml_set_object($this->parser, $this);
+       xml_set_element_handler($this->parser, "tag_open", "tag_close");
+
+       /* Parse config file directly? */
+       if ($filename != ""){
+               $this->parse($filename);
+       }
+  }
+
+  function parse($filename)
+  { 
+       $fh= fopen($filename, "r"); 
+       $xmldata= fread($fh, 100000);
+       fclose($fh); 
+       if(!xml_parse($this->parser, chop($xmldata))){
+               print_red(sprintf(_("XML error in gosa.conf: %s at line %d"),
+                       xml_error_string(xml_get_error_code($this->parser)),
+                       xml_get_current_line_number($this->parser)));
+               echo $_SESSION['errors'];
+               exit;
+       }
+  }
+
+  function tag_open($parser, $tag, $attrs)
+  { 
+       /* Save last and current tag for reference */
+       $this->tags[$this->level]= $tag;
+       $this->level++;
+
+       /* Trigger on CONF section */
+       if ($tag == 'CONF'){
+               $this->config_found= TRUE;
+       }
+
+       /* Return if we're not in config section */
+       if (!$this->config_found){
+               return;
+       }
+
+       /* Look through attributes */
+       switch ($this->tags[$this->level-1]){
+
+               /* Handle tab section */
+               case 'TAB':     $name= $this->tags[$this->level-2];
+               
+                               /* Create new array? */
+                               if (!isset($this->data['TABS'][$name])){
+                                       $this->data['TABS'][$name]= array();
+                               }
+
+                               /* Add elements */
+                               $this->data['TABS'][$name][]= $attrs;
+                               break;
+
+               /* Handle location */
+               case 'LOCATION':
+                               if ($this->tags[$this->level-2] == 'MAIN'){
+                                       $name= $attrs['NAME'];
+                                       $this->currentLocation= $name;
+
+                                       /* Add location elements */
+                                       $this->data['LOCATIONS'][$name]= $attrs;
+                               }
+                               break;
+
+               /* Handle referral tags */
+               case 'REFERRAL':
+                               if ($this->tags[$this->level-2] == 'LOCATION'){
+                                       $url= $attrs['URL'];
+                                       $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
+
+                                       /* Add location elements */
+                                       if (!isset($this->data['LOCATIONS'][$this->currentLocation]['REFERRAL'])){
+                                                $this->data['LOCATIONS'][$this->currentLocation]['REFERRAL']= array();
+                                        }
+
+                                       $this->data['LOCATIONS'][$this->currentLocation]['REFERRAL'][$server]= $attrs;
+                               }
+                               break;
+
+               /* Handle language */
+               case 'LANGUAGE':
+                               if ($this->tags[$this->level-2] == 'MAIN'){
+                                       /* Add languages */
+                                       $this->data['MAIN']['LANGUAGES'][$attrs['NAME']]= 
+                                               $attrs['TAG'];
+                               }
+                               break;
+
+               /* Handle faxformat */
+               case 'FAXFORMAT':       
+                               if ($this->tags[$this->level-2] == 'MAIN'){
+                                       /* Add fax formats */
+                                       $this->data['MAIN']['FAXFORMATS'][]= $attrs['TYPE'];
+                               }
+                               break;
+
+               /* Load main parameters */
+               case 'MAIN':
+                               $this->data['MAIN']= array_merge ($this->data['MAIN'], $attrs);
+                               break;
+
+               /* Load menu */
+               case 'SECTION':
+                               if ($this->tags[$this->level-2] == 'MENU'){
+                                       $this->section= $attrs['NAME'];
+                                       $this->data['MENU'][$this->section]= array(); ;
+                               }
+                               break;
+
+               /* Inser plugins */
+               case 'PLUGIN':
+                               if ($this->tags[$this->level-3] == 'MENU' &&
+                                   $this->tags[$this->level-2] == 'SECTION'){
+               
+                                       $this->data['MENU'][$this->section][$this->gpc++]= $attrs;
+                               }
+                               if ($this->tags[$this->level-2] == 'SERVICEMENU'){
+                                       $this->data['SERVICE'][$attrs['CLASS']]= $attrs;
+                               }
+                               break;
+       }
+  }
+
+  function tag_close($parser, $tag)
+  {
+       /* Close config section */
+       if ($tag == 'CONF'){
+               $this->config_found= FALSE;
+       }
+       $this->level--;
+  }
+
+  function get_ldap_link($sizelimit= FALSE)
+  {
+       /* Build new connection */
+       $this->ldap= ldap_init ($this->current['SERVER'], $this->current['BASE'],
+                       $this->current['ADMIN'], $this->current['PASSWORD']);
+
+       /* Check for connection */
+       if (is_null($this->ldap) || (is_int($this->ldap) && $this->ldap == 0)){
+               print_red (_("Can't bind to LDAP. Please contact the system administrator."));
+               echo $_SESSION['errors'];
+               exit;
+       }
+
+       if (!isset($_SESSION['size_limit'])){
+               $_SESSION['size_limit']= $this->current['SIZELIMIT'];
+               $_SESSION['size_ignore']= $this->current['SIZEIGNORE'];
+       }
+
+       if ($sizelimit){
+               $this->ldap->set_size_limit($_SESSION['size_limit']);
+       } else {
+                $this->ldap->set_size_limit(0);
+        }
+
+       /* Move referrals */
+       if (!isset($this->current['REFERRAL'])){
+               $this->ldap->referrals= array();
+       } else {
+               $this->ldap->referrals= $this->current['REFERRAL'];
+       }
+
+       return ($this->ldap);
+  }
+
+  function set_current($name)
+  {
+       $this->current= $this->data['LOCATIONS'][$name];
+       if (!isset($this->current['PEOPLE'])){
+               $this->current['PEOPLE']= "ou=people";
+       }
+       if (!isset($this->current['GROUPS'])){
+               $this->current['GROUPS']= "ou=groups";
+       }
+       if (!isset($this->current['WINSTATIONS'])){
+               $this->current['WINSTATIONS']= "ou=winstations,ou=systems";
+       }
+       if (!isset($this->current['HASH'])){
+               $this->current['HASH']= "crypt";
+       }
+       if (!isset($this->current['DNMODE'])){
+               $this->current['DNMODE']= "cn";
+       }
+       if (!isset($this->current['MINID'])){
+               $this->current['MINID']= 100;
+       }
+       if (!isset($this->current['SIZELIMIT'])){
+               $this->current['SIZELIMIT']= 200;
+       }
+       if (!isset($this->current['SIZEINGORE'])){
+               $this->current['SIZEIGNORE']= TRUE;
+       } else {
+               if (preg_match("/true/i", $this->current['SIZEIGNORE'])){
+                       $this->current['SIZEIGNORE']= TRUE;
+               } else {
+                       $this->current['SIZEIGNORE']= FALSE;
+               }
+       }
+
+       /* Sort referrals, if present */
+       if (isset ($this->current['REFERRAL'])){
+               $bases= array();
+               $servers= array();
+               foreach ($this->current['REFERRAL'] as $ref){
+                       $server= preg_replace('%^(.*)/[^/]+$%', '\\1', $ref['URL']);
+                       $base= preg_replace('%^.*/([^/]+)$%', '\\1', $ref['URL']);
+                       $bases[$base]= strlen($base);
+                       $servers[$base]= $server;
+               }
+               asort($bases);
+               reset($bases);
+       }
+
+       /* SERVER not defined? Load the one with the shortest base */
+       if (!isset($this->current['SERVER'])){
+               $this->current['SERVER']= $servers[key($bases)];
+       }
+
+       /* BASE not defined? Load the one with the shortest base */
+       if (!isset($this->current['BASE'])){
+               $this->current['BASE']= key($bases);
+       }
+
+       /* Parse LDAP referral informations */
+       if (!isset($this->current['ADMIN']) || !isset($this->current['PASSWORD'])){
+               $url= $this->current['SERVER'];
+               $referral= $this->current['REFERRAL'][$url];
+               $this->current['ADMIN']= $referral['ADMIN'];
+               $this->current['PASSWORD']= $referral['PASSWORD'];
+       }
+
+       /* Load server informations */
+       $this->load_servers();
+  }
+
+  function load_servers ()
+  {
+       /* Only perform actions if current is set */
+       if ($this->current == NULL){
+               return;
+       }
+
+       /* Fill imap servers */
+       $ldap= $this->get_ldap_link();
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goImapServer)");
+
+       $this->data['SERVERS']['IMAP']= array();
+       error_reporting(0);
+       while ($attrs= $ldap->fetch()){
+               $name= $attrs['goImapName'][0];
+               $this->data['SERVERS']['IMAP'][$name]= array( "connect" => $attrs['goImapConnect'][0],
+                                       "admin" => $attrs['goImapAdmin'][0],
+                                       "password" => $attrs['goImapPassword'][0],
+                                       "sieve_server" => $attrs['goImapSieveServer'][0],
+                                       "sieve_port" => $attrs['goImapSievePort'][0]);
+       }
+       error_reporting(E_ALL);
+
+       /* Get kerberos server. FIXME: only one is supported currently */
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goKrbServer)");
+       if ($ldap->count()){
+               $attrs= $ldap->fetch();
+               $this->data['SERVERS']['KERBEROS']= array( 'SERVER' => $attrs['cn'][0],
+                                               'REALM' => $attrs['goKrbRealm'][0],
+                                               'ADMIN' => $attrs['goKrbAdmin'][0],
+                                               'PASSWORD' => $attrs['goKrbPassword'][0]);
+       }
+
+       /* Get cups server. FIXME: only one is supported currently */
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goCupsServer)");
+       if ($ldap->count()){
+               $attrs= $ldap->fetch();
+               $this->data['SERVERS']['CUPS']= $attrs['cn'][0];        
+       }
+
+       /* Get fax server. FIXME: only one is supported currently */
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goFaxServer)");
+       if ($ldap->count()){
+               $attrs= $ldap->fetch();
+               $this->data['SERVERS']['FAX']= array( 'SERVER' => $attrs['cn'][0],
+                                               'LOGIN' => $attrs['goFaxAdmin'][0],
+                                               'PASSWORD' => $attrs['goFaxPassword'][0]);
+       }
+
+       /* Get asterisk servers */
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goFonServer)");
+       if ($ldap->count()){
+               $attrs= $ldap->fetch();
+               $this->data['SERVERS']['FON']= array( 'SERVER' => $attrs['cn'][0],
+                                               'LOGIN' => $attrs['goFonAdmin'][0],
+                                               'PASSWORD' => $attrs['goFonPassword'][0]);
+       }
+       /* Get logdb server */
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goLogDBServer)");
+       if ($ldap->count()){
+               $attrs= $ldap->fetch();
+               $this->data['SERVERS']['LOG']= array( 'SERVER' => $attrs['cn'][0],
+                                               'LOGIN' => $attrs['goLogAdmin'][0],
+                                               'PASSWORD' => $attrs['goLogPassword'][0]);
+       }
+
+       /* Get NFS server lists */
+       $tmp= array("default");
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(&(objectClass=goNfsServer)(goExportEntry=*))");
+       while ($attrs= $ldap->fetch()){
+               for ($i= 0; $i<$attrs["goExportEntry"]["count"]; $i++){
+                       $path= preg_replace ("/\s.*$/", "", $attrs["goExportEntry"][$i]);
+                       $tmp[]= $attrs["cn"][0].":$path";
+               }
+       }
+       $this->data['SERVERS']['NFS']= $tmp;
+
+
+       /* Load Terminalservers */
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goTerminalServer)");
+       $this->data['SERVERS']['TERMINAL'][]= "default";
+       $this->data['SERVERS']['FONT'][]= "default";
+       while ($attrs= $ldap->fetch()){
+               $this->data['SERVERS']['TERMINAL'][]= $attrs["cn"][0];
+               for ($i= 0; $i<$attrs["goFontPath"]["count"]; $i++){
+                       $this->data['SERVERS']['FONT'][]= $attrs["goFontPath"][$i];
+               }
+       }
+
+       /* Ldap Server */
+       $this->data['SERVERS']['LDAP']= array("default");
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goLdapServer)");
+       while ($attrs= $ldap->fetch()){
+               for ($i= 0; $i<$attrs["goLdapBase"]["count"]; $i++){
+                       $this->data['SERVERS']['LDAP'][]= $attrs["cn"][0].":".$attrs["goLdapBase"][$i];
+               }
+       }
+
+       /* Get misc server lists */
+       $this->data['SERVERS']['SYSLOG']= array("default");
+       $this->data['SERVERS']['NTP']= array("default");
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goNtpServer)");
+       while ($attrs= $ldap->fetch()){
+               $this->data['SERVERS']['NTP'][]= $attrs["cn"][0];
+       }
+       $ldap->cd ($this->current['BASE']);
+       $ldap->search ("(objectClass=goSyslogServer)");
+       while ($attrs= $ldap->fetch()){
+               $this->data['SERVERS']['SYSLOG'][]= $attrs["cn"][0];
+       }
+
+       /* Get samba servers from LDAP, in case of samba3 */
+       if ($this->current['SAMBAVERSION'] == 3){
+               $this->data['SERVERS']['SAMBA']= array();
+               $ldap->cd ($this->current['BASE']);
+               $ldap->search ("(objectClass=sambaDomain)");
+               while ($attrs= $ldap->fetch()){
+                       $this->data['SERVERS']['SAMBA'][$attrs['sambaDomainName'][0]]= array(
+                               "SID" => $attrs["sambaSID"][0],
+                               "RIDBASE" => $attrs["sambaAlgorithmicRidBase"][0]);
+               }
+
+               /* If no samba servers are found, look for configured sid/ridbase */
+               if (count($this->data['SERVERS']['SAMBA']) == 0){
+                       if (!isset($this->current["SID"]) || !isset($this->current["RIDBASE"])){
+                               print_red(_("SID and/or RIDBASE missing in your configuration!"));
+                               echo $_SESSION['errors'];
+                               exit;
+                       } else {
+                               $this->data['SERVERS']['SAMBA']['DEFAULT']= array(
+                                       "SID" => $this->current["SID"],
+                                       "RIDBASE" => $this->current["RIDBASE"]);
+                       }
+               }
+       }
+  }
+
+  function make_idepartments()
+  {
+       $this->idepartments= array();
+       foreach ($this->departments as $key => $val){
+               $this->idepartments[$val]= $key;
+       }
+  }
+
+}
+
+?>
diff --git a/include/class_ldap.inc b/include/class_ldap.inc
new file mode 100644 (file)
index 0000000..f3650a5
--- /dev/null
@@ -0,0 +1,775 @@
+<?php
+/*****************************************************************************
+  newldap.inc - version 1.0
+  Copyright (C) 2003 Alejandro Escanero Blanco <alex@ofmin.com>
+  Copyright (C) 2004 Cajus Pollmeier <pollmeier@gonicus.de>
+
+  Based in code of ldap.inc of
+  Copyright (C) 1998  Eric Kilfoil <eric@ipass.net>
+ *****************************************************************************/
+
+define("ALREADY_EXISTING_ENTRY",-10001);
+define("UNKNOWN_TOKEN_IN_LDIF_FILE",-10002);
+define("NO_FILE_UPLOADED",10003);
+
+
+define("INSERT_OK",10000);
+
+
+
+class LDAP{
+
+  var $hascon   =false;
+  var $hasres   =false;
+  var $reconnect=false;
+  var $tls      = false;
+  var $basedn   ="";
+  var $cid;
+  var $error    = ""; // Any error messages to be returned can be put here
+  var $start    = 0; // 0 if we are fetching the first entry, otherwise 1
+  var $objectClasses = array(); // Information read from slapd.oc.conf
+  var $binddn   = "";
+  var $bindpw   = "";
+  var $hostname = "";
+  var $follow_referral = FALSE;
+  var $referrals= array();
+
+  function LDAP($binddn,$bindpw, $hostname, $follow_referral= FALSE, $tls= FALSE)
+  {
+    $this->follow_referral= $follow_referral;
+    $this->tls=$tls;
+    $this->binddn=$binddn;
+    $this->bindpw=$bindpw;
+    $this->hostname=$hostname;
+    $this->connect();
+  }
+
+  function connect()
+  {
+    $this->hascon=false;
+    $this->reconnect=false;
+    if ($this->cid= @ldap_connect($this->hostname)) {
+      @ldap_set_option($this->cid, LDAP_OPT_PROTOCOL_VERSION, 3);
+      if (function_exists("ldap_set_rebind_proc") && $this->follow_referral) {
+        @ldap_set_option($this->cid, LDAP_OPT_REFERRALS, 1);
+        @ldap_set_rebind_proc($this->cid, array(&$this, "rebind"));
+      }
+      if (function_exists("ldap_start_tls") && $this->tls){
+        @ldap_start_tls($this->cid);
+      }
+
+      $this->error = "No Error";
+      if ($bid = @ldap_bind($this->cid, $this->binddn, $this->bindpw)) {
+        $this->error = "Success";
+        $this->hascon=true;
+      } else {
+        if ($this->reconnect){
+          if ($this->error != "Success"){
+            $this->error = "Could not rebind to " . $this->binddn;
+          }
+        } else {
+          $this->error = "Could not bind to " . $this->binddn;
+        }
+      }
+    } else {
+      $this->error = "Could not connect to LDAP server";
+    }
+  }
+
+  function rebind($ldap, $referral)
+  {
+    $credentials= $this->get_credentials($referral);
+    if (@ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
+      $this->error = "Success";
+      $this->hascon=true;
+      $this->reconnect= true;
+      return (0);
+    } else {
+      $this->error = "Could not bind to " . $binddn;
+      return NULL;
+    }
+  }
+
+  function reconnect()
+  {
+    if ($this->reconnect){
+      @ldap_unbind($this->cid);
+      $this->cid = NULL;
+    }
+  }
+
+  function unbind()
+  {
+    @ldap_unbind($this->cid);
+    $this->cid = NULL;
+  }
+
+  function disconnect()
+  {
+    if($this->hascon){
+      @ldap_close($this->cid);
+      $this->hascon=false;
+    }
+  }
+
+  function cd($dir)
+  {
+    if ($dir == "..")
+      $this->basedn = $this->getParentDir();
+    else
+      $this->basedn = $dir;
+  }
+
+  function getParentDir($basedn = "")
+  {
+    if ($basedn=="")
+      $basedn = $this->basedn;
+    return(ereg_replace("[^,]*[,]*[ ]*(.*)", "\\1", $basedn));
+  }
+
+  function search($filter, $attrs= array())
+  {
+    
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      $this->clearResult();
+      $this->sr = @ldap_search($this->cid, $this->basedn, $filter, $attrs);
+      $this->error = @ldap_error($this->cid);
+      $this->resetResult();
+      $this->hasres=true;
+      return($this->sr);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function ls($filter = "(objectclass=*)", $basedn = "")
+  {
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      $this->clearResult();
+      if ($basedn == "")
+        $basedn = $this->basedn;
+      $this->sr = @ldap_list($this->cid, $basedn, $filter);
+      $ldap->error = @ldap_error($this->cid);
+      $this->resetResult();
+      $this->hasres=true;
+      return($this->sr);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function cat($dn)
+  {
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      $this->clearResult();
+      $filter = "(objectclass=*)";
+      $this->sr = @ldap_read($this->cid, $dn, $filter);
+      $this->error = @ldap_error($this->cid);
+      $this->resetResult();
+      $this->hasres=true;
+      return($this->sr);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function set_size_limit($size)
+  {
+    /* Ignore zero settings */
+    if ($size == 0){
+      @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, 10000000);
+    }
+    if($this->hascon){
+      @ldap_set_option($this->cid, LDAP_OPT_SIZELIMIT, $size);
+    } else {
+      $this->error = "Could not connect to LDAP server";
+    }
+  }
+
+  function fetch()
+  {
+    if($this->hascon){
+      if($this->hasres){
+        if ($this->start == 0)
+        {
+          $this->start = 1;
+          $this->re= @ldap_first_entry($this->cid, $this->sr);
+        } else {
+          $this->re= @ldap_next_entry($this->cid, $this->re);
+        }
+        if ($this->re)
+        {
+          $att= @ldap_get_attributes($this->cid, $this->re);
+          $att['dn']= @ldap_get_dn($this->cid, $this->re);
+        }
+        $ldap->error = @ldap_error($this->cid);
+        if (!isset($att)){
+          $att= array();
+        }
+        return($att);
+      }else{
+        $this->error = "Perform a Fetch with no Search";
+        return("");
+      }
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function resetResult()
+  {
+    $this->start = 0;
+  }
+
+  function clearResult()
+  {
+    if($this->hasres){
+      $this->hasres = false;
+      @ldap_free_result($this->sr);
+    }
+  }
+
+  function getDN()
+  {
+    if($this->hascon){
+      if($this->hasres){
+
+        if(!$this->re)
+          {
+          $this->error = "Perform a Fetch with no valid Result";
+          }
+          else
+          {
+          $rv = @ldap_get_dn($this->cid, $this->re);
+        
+          $ldap->error = @ldap_error($this->cid);
+          $rv= preg_replace("/[ ]*,[ ]*/", ",", $rv);
+          return($rv);
+           }
+      }else{
+        $this->error = "Perform a Fetch with no Search";
+        return("");
+      }
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function count()
+  {
+    if($this->hascon){
+      if($this->hasres){
+        $rv = @ldap_count_entries($this->cid, $this->sr);
+        $ldap->error = @ldap_error($this->cid);
+        return($rv);
+      }else{
+        $this->error = "Perform a Fetch with no Search";
+        return("");
+      }
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function rm($attrs = "", $dn = "")
+  {
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      if ($dn == "")
+        $dn = $this->basedn;
+
+      $r = @ldap_mod_del($this->cid, $dn, $attrs);
+      $ldap->error = @ldap_error($this->cid);
+      return($r);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function rename($attrs, $dn = "")
+  {
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      if ($dn == "")
+        $dn = $this->basedn;
+
+      $r = @ldap_mod_replace($this->cid, $dn, $attrs);
+      $ldap->error = @ldap_error($this->cid);
+      return($r);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function rmdir($deletedn)
+  {
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      $r = @ldap_delete($this->cid, $deletedn);
+      $this->error = @ldap_error($this->cid);
+      return($r ? $r : 0);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function modify($attrs)
+  {
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      $r = @ldap_modify($this->cid, $this->basedn, $attrs);
+      $this->error = @ldap_error($this->cid);
+      return($r ? $r : 0);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function add($attrs)
+  {
+    if($this->hascon){
+      if ($this->reconnect) $this->connect();
+      $r = @ldap_add($this->cid, $this->basedn, $attrs);
+      $this->error = @ldap_error($this->cid);
+      return($r ? $r : 0);
+    }else{
+      $this->error = "Could not connect to LDAP server";
+      return("");
+    }
+  }
+
+  function create_missing_trees($target)
+  {
+    
+    /* Ignore create_missing trees if the base equals target */
+    if ($target == $this->basedn){
+     return;
+    }
+    $l= array_reverse(explode(",", preg_replace("/,".$this->basedn."/", "", $target)));
+    $cdn= $this->basedn;
+    foreach ($l as $part){
+      $cdn= "$part,$cdn";
+
+      /* Ignore referrals */
+      $found= false;
+      foreach($this->referrals as $ref){
+        $base= preg_replace('!^[^:]+://[^/]+/([^?]+).*$!', '\\1', $ref['URL']);
+        if ($base == $cdn){
+          $found= true;
+          break;
+        }
+      }
+      if ($found){
+        continue;
+      }
+
+      $this->cat ($cdn);
+      $attrs= $this->fetch();
+
+      /* Create missing entry? */
+      if (!count ($attrs)){
+        $type= preg_replace('/^([^=]+)=.*$/', '\\1', $cdn);
+        $param= preg_replace('/^[^=]+=([^,]+),.*$/', '\\1', $cdn);
+
+        $na= array();
+        switch ($type){
+          case 'ou':
+            $na["objectClass"]= "organizationalUnit";
+            $na["ou"]= $param;
+            break;
+          case 'dc':
+            $na["objectClass"]= array("dcObject", "top", "locality");
+            $na["dc"]= $param;
+            break;
+          default:
+            print_red(sprintf(_("Autocreation of type '%s' is currently not supported. Please report to the GOsa team."), $type));
+            exit;
+        }
+        $this->cd($cdn);
+        $this->add($na);
+      }
+    }
+  }
+
+  function recursive_remove()
+  {
+    $delarray= array();
+
+    /* Get sorted list of dn's to delete */
+    $this->search ("(objectClass=*)");
+    while ($this->fetch()){
+      $deldn= $this->getDN();
+      $delarray[$deldn]= strlen($deldn);
+    }
+    arsort ($delarray);
+    reset ($delarray);
+
+    /* Delete all dn's in subtree */
+    foreach ($delarray as $key => $value){
+      $this->rmdir($key);
+    }
+  }
+
+  function get_attribute($dn, $name)
+  {
+    $data= "";
+    if ($this->reconnect) $this->connect();
+    $sr= @ldap_read($this->cid, $dn, "objectClass=*", array("$name"));
+
+    /* fill data from LDAP */
+    if ($sr) {
+      $ei= @ldap_first_entry($this->cid, $sr);
+      if ($ei) {
+        if ($info= @ldap_get_values_len($this->cid, $ei, "$name")){
+          $data= $info[0];
+        }
+      }
+    }
+
+    return ($data);
+  }
+
+  function get_additional_error()
+  {
+    $error= "";
+    @ldap_get_option ($this->cid, LDAP_OPT_ERROR_STRING, $error);
+    return ($error);
+  }
+
+  function get_error()
+  {
+    if ($this->error == 'Success'){
+      return $this->error;
+    } else {
+      $error= $this->error." (".$this->get_additional_error().")";
+      return $error;
+    }
+  }
+
+  function get_credentials($url, $referrals= NULL)
+  {
+    $ret= array();
+    $url= preg_replace('!\?\?.*$!', '', $url);
+    $server= preg_replace('!^([^:]+://[^/]+)/.*$!', '\\1', $url);
+
+    if ($referrals == NULL){
+      $referrals= $this->referrals;
+    }
+
+    if (isset($referrals[$server])){
+      return ($referrals[$server]);
+    } else {
+      $ret['ADMIN']= $this->binddn;
+      $ret['PASSWORD']= $this->bindpw;
+    }
+
+    return ($ret);
+  }
+
+
+  function gen_ldif ($dn, $filter= "(objectClass=*)", $attributes= array('*'), $recursive= TRUE)
+  {
+    $display= "";
+
+    if ($recursive){
+      $this->cd($dn);
+      $this->search("$filter", array('dn'));
+      while ($attrs= $this->fetch()){
+        $display.= $this->gen_one_entry($attrs['dn'], $filter, $attributes);
+        $display.= "\n";
+      }
+    } else {
+      $display.= $this->gen_one_entry($dn);
+    }
+
+    return ($display);
+  }
+
+
+  function gen_one_entry($dn, $filter= "(objectClass=*)" , $name= array("*"))
+  {
+    $ret = "";
+    $data = "";
+    if($this->reconnect){
+      $this->connect();
+    }
+
+    /* Searching Ldap Tree */
+    $sr= @ldap_read($this->cid, $dn, $filter, $name);
+
+    /* Get the first entry */          
+    $entry= @ldap_first_entry($this->cid, $sr);
+
+    /* Get all attributes related to that Objekt */
+    $atts = array();
+    
+    /* Assemble dn */
+    $atts[0]['name']  = "dn";
+    $atts[0]['value'] = array('count' => 1, 0 => $dn);
+
+    /* Reset index */
+    $i = 1 ; 
+
+    $attribute= @ldap_first_attribute($this->cid,$entry,$identifier);
+    while ($attribute) {
+      $i++;
+      $atts[$i]['name']  = $attribute;
+      $atts[$i]['value'] = @ldap_get_values_len($this->cid, $entry, "$attribute");
+
+      /* Next one */
+      $attribute= @ldap_next_attribute($this->cid,$entry,$identifier);
+    }
+
+    foreach($atts as $at)
+    {
+      for ($i= 0; $i<$at['value']['count']; $i++){
+
+        /* Check if we must encode the data */
+        if(!preg_match('/^[a-z0-9+@#.=, \/ -]+$/i', $at['value'][$i])) {
+          $ret .= $at['name'].":: ".base64_encode($at['value'][$i])."\n";
+        } else {
+          $ret .= $at['name'].": ".$at['value'][$i]."\n";
+        }
+      }
+    }
+
+    return($ret);
+  }
+
+
+  function dn_exists($dn)
+  {
+    return @ldap_list($this->cid, $dn, "(objectClass=*)", array("objectClass"));
+  }
+  
+
+
+  function import_complete_ldif($str_attr,&$error,$overwrite,$cleanup)
+  {
+    if($this->reconnect) $this->connect();
+
+    /* First we have to splitt the string ito detect empty lines
+       An empty line indicates an new Entry */
+    $entries = split("\n",$str_attr);
+
+    $data = "";
+    $cnt = 0; 
+    $current_line = 0;
+
+    /* Every single line ... */
+    foreach($entries as $entry) {
+      $current_line ++;
+
+      /* Removing Spaces to .. 
+         .. test if a new entry begins */
+      $tmp  = str_replace(" ","",$data );
+
+      /* .. prevent empty lines in an entry */
+      $tmp2 = str_replace(" ","",$entry);
+
+      /* If the Block ends (Empty Line) */
+      if((empty($entry))&&(!empty($tmp))) {
+        /* Add collected lines as a complete block */
+        $all[$cnt] = $data;
+        $cnt ++;
+        $data ="";
+      } else {
+
+        /* Append lines ... */
+        if(!empty($tmp2)) {
+          /* check if we need base64_decode for this line */
+          if(ereg("::",$tmp2))
+          {
+            $encoded = split("::",$entry);
+            $attr  = $encoded[0];
+            $value = base64_decode($encoded[1]);
+            /* Add linenumber */
+            $data .= $current_line."#".$attr.":".$value."\n";
+          }
+          else
+          {
+            /* Add Linenumber */ 
+            $data .= $current_line."#".$entry."\n";
+          }
+        }
+      }
+    }
+
+    /* The Data we collected is not in the array all[];
+       For example the Data is stored like this..
+
+       all[0] = "1#dn : .... \n 
+       2#ObjectType: person \n ...."
+       
+       Now we check every insertblock and try to insert */
+    foreach ( $all as $single) {
+      $lineone = split("\n",$single);  
+      $ndn = split("#", $lineone[0]);
+      $line = $ndn[1];
+
+      $dnn = split (":",$line);
+      $current_line = $ndn[0];
+      $dn    = $dnn[0];
+      $value = $dnn[1];
+
+      /* Every block must begin with a dn */
+      if($dn != "dn") {
+        $error= sprintf(_("This is not a valid DN: '%s'. A block for import should begin with 'dn: ...' in line %s"),
+                        $line, $current_line);
+        return -2;  
+      }
+      
+
+      // Should we use Modify instead of Add
+      $usemodify = false;
+
+      // Delete before insert
+      $usermdir = false;
+    
+
+    
+      /* The dn address already exists! */
+      if (($this->dn_exists($value))&&((!$overwrite)&&(!$cleanup))) {
+        $error= sprintf(_("The dn: '%s' (from line %s) already exists in the LDAP database."), $line, $current_line);
+        return ALREADY_EXISTING_ENTRY;   
+      }
+      elseif(($this->dn_exists($value))&&($cleanup)){
+        ;//Delete first, then add
+        $usermdir = true;        
+      }
+      elseif(($this->dn_exists($value))&&($overwrite)) {
+        ;//Modify instead of Add  
+        $usemodify = true;
+      }
+
+     
+      /* If we can't Import, return with a file error */
+      if(!$this->import_single_entry($single,$usemodify,$usermdir) ) {
+        $error= sprintf(_("Error while importing dn: '%s', please check your LDIF from line %s on!"), $line,
+                        $current_line);
+        return UNKNOWN_TOKEN_IN_LDIF_FILE;      }
+
+    }
+    return (INSERT_OK);
+  }
+
+  /* Imports a single entry */
+  function import_single_entry($str_attr,$modify,$delete)
+  {
+
+  
+       
+    if($this->reconnect) $this->connect();
+
+    $ret = false;
+
+    $rows = split("\n",$str_attr);
+    $data = false;
+    foreach($rows as $row) {
+      
+      /* Check if we use Linenumbers (when import_complete_ldif is called we use
+         Linenumbers) Linenumbers are use like this 123#attribute : value */
+      if(!empty($row)) {
+        if((strpos($row,"#")!=FALSE)&&(strpos($row,"#")<strpos($row,":"))) {
+          /* We are using line numbers 
+             Because there is a # before a : */
+          $tmp1 = split("#",$row);
+          $current_line = $tmp1[0];
+          $row = $tmp1[1];
+        }
+
+        /* Split the line into  attribute  and value */
+        $attr = split(":", $row);
+        $attr[0] = trim($attr[0]);  /* attribute */
+        $attr[1] = trim($attr[1]);  /* value */
+
+        /* Check for attributes that are used more than once */
+        if(!isset($data[$attr[0]])) {
+          $data[$attr[0]]=$attr[1];
+        } else {
+          $tmp = $data[$attr[0]];
+
+          if(!is_array($tmp)) {
+            $new[0]=$tmp;
+            $new[1]=$attr[1];
+            $datas[$attr[0]]['count']=1;             
+            $data[$attr[0]]=$new;
+          } else {
+            $cnt = $datas[$attr[0]]['count'];           
+            $cnt ++;
+            $data[$attr[0]][$cnt]=$attr[1];
+            $datas[$attr[0]]['count'] = $cnt;
+          }
+        }
+      }
+    } 
+    
+    /* If dn is an index of data, we should try to insert the data */
+    if(isset($data['dn'])) {
+      /* Creating Entry */
+      $this->cd($data['dn']);
+
+      /* Delete existing entry */
+      if($delete)
+         $this->rmdir($data['dn']);
+
+      
+      /* Create missing trees */
+      $this->create_missing_trees($data['dn']);
+      unset($data['dn']);
+      
+      /* If entry exists use modify */
+      if(!$modify)
+        $ret = $this->add($data);
+      else
+        $ret = $this->modify($data);
+      
+      
+      
+    }
+
+    return($ret);
+  }
+
+  
+  function importcsv($str)
+  {
+    $lines = split("\n",$str);
+    foreach($lines as $line)
+    {
+      /* continue if theres a comment */
+      if(substr(trim($line),0,1)=="#")
+        continue; 
+
+      $line= str_replace ("\t\t","\t",$line);
+      $line= str_replace ("\t"  ,"," ,$line);
+      print $line;
+
+
+
+      $cells = split(",",$line )  ;
+      #print_a($cells);
+      $linet= str_replace ("\t\t",",",$line);
+      $cells = split("\t",$line);
+      $count = count($cells);  
+    }
+
+  }
+
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_mail-methods-cyrus.inc b/include/class_mail-methods-cyrus.inc
new file mode 100644 (file)
index 0000000..239cd2e
--- /dev/null
@@ -0,0 +1,317 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+class mailMethodCyrus extends mailMethod
+{
+  var $mbox= "-";
+  var $config;
+  var $gosaMailServer= "";
+
+  function mailMethodCyrus($config)
+  {
+    $this->config= $config->data['SERVERS']['IMAP'];
+  }
+
+  function connect($gosaMailServer)
+  {
+    /* Connect to IMAP server. I don't want to see these warning here... */
+    error_reporting (0);
+    $this->gosaMailServer= $gosaMailServer;
+    $cfg= $this->config[$gosaMailServer];
+    $this->mbox = @imap_open($cfg['connect'], $cfg['admin'], $cfg['password'], OP_HALFOPEN);
+    error_reporting (E_ALL);
+
+    /* Mailbox reachable? */
+    if ($this->mbox === FALSE){
+      print_red (_("Warning: IMAP Server cannot be reached! If you save this account, some mail settings will not be stored on your server!"));
+      return (FALSE);
+    }
+    return (TRUE);
+  }
+
+  function disconnect()
+  {
+    imap_close ($this->mbox);
+  }
+
+  function getQuota($folder)
+  {
+    $result= array('quotaUsage' => '', 'gosaMailQuota' => '');
+
+    /* Load quota settings */
+    error_reporting (0);
+    $quota_value = @imap_get_quota($this->mbox, $folder);
+    if(is_array($quota_value)) {
+      if (isset($quota_value["STORAGE"]) && is_array($quota_value["STORAGE"])){
+        /* use for PHP >= 4.3 */
+        $result['quotaUsage']=    $quota_value["STORAGE"]['usage'];
+        $result['gosaMailQuota']= $quota_value["STORAGE"]['limit'];
+      } else {
+        /* backward compatible */
+        $result['quotaUsage']=    $quota_value['usage'];
+        $result['gosaMailQuota']= $quota_value['limit'];
+      }
+    }
+    error_reporting (E_ALL);
+
+    return ($result);
+  }
+
+  function getMailboxList($folder, $uid= "")
+  {
+    /* Initialize depending on group or user mode */
+    if ($uid != ""){
+      $result= array("INBOX");
+    } else {
+      $result= array();
+    }
+
+    /* Get list of mailboxes for combo box */
+    $cfg= $this->config[$this->gosaMailServer];
+    $list = imap_listmailbox($this->mbox, $cfg["connect"], $folder.".*");
+    if (is_array($list)){
+      foreach ($list as $val){
+        $result[]=preg_replace ("/.*user\.".$uid."\./",
+            "INBOX.", imap_utf7_decode ($val));
+      }
+    }
+
+    return ($result);
+  }
+
+  function updateMailbox($folder)
+  {
+    /* Check if mailbox exists */
+    $cfg= $this->config[$this->gosaMailServer];
+    $list = imap_listmailbox($this->mbox, $cfg["connect"], $folder);
+    if ($list === FALSE){
+      if (!imap_createmailbox($this->mbox, $cfg["connect"]. $folder)){
+        print_red(sprintf(_("Can't create IMAP mailbox. Server says '%s'."), imap_last_error()));
+        return;
+      }
+    }
+  }
+
+
+  function setQuota($folder, $gosaMailQuota)
+  {
+    /* Workaround for the php imap extension */
+    if ($gosaMailQuota == ""){
+      $gosaMailQuota= "0";
+    }
+
+    /* Write mail quota */
+    if (!imap_set_quota($this->mbox, $folder, $gosaMailQuota)){
+      print_red(sprintf(_("Can't write IMAP quota. Server says '%s'."), imap_last_error()));
+      return (FALSE);
+    }
+    return (TRUE);
+  }
+
+
+  function setSharedFolderPermissions($folder, $permissions)
+  {
+    /* Show warning message in case of missing imap_getacl */
+    if (!function_exists('imap_getacl')){
+      print_red (_("Warning: imap_getacl is not implemented, wouldn't modify acl informations."));
+      return;
+    }
+
+    /* Get list of subfolders */
+    $folders= $this->getMailboxList($folder, "");
+    $folders[]= $folder;
+    
+    foreach ($folders as $subfolder){
+
+      /* Set shared folder acl's */
+      if (function_exists('imap_getacl')){
+
+        /* Remove all acl's for this folder */
+        $users= imap_getacl ($this->mbox, $subfolder);
+        foreach ($users as $userid => $perms){
+          imap_setacl ($this->mbox, $subfolder, $userid, "");
+        }
+      }
+
+      /* Set permissions for this folder */
+      foreach ($permissions as $user => $acl){
+        imap_setacl ($this->mbox, $subfolder, $user, $acl);
+      }
+    }
+
+  }
+
+
+  function getSharedFolderPermissions($folder)
+  {
+    $result= array();
+
+    /* imap_getacl available? */
+    if (!function_exists('imap_getacl')){
+      print_red (_("Warning: imap_getacl is not available, can't get imap permissions!"));
+    }
+
+    /* Get permissions in case of shared folders */
+    else {
+      $users= imap_getacl ($this->mbox, $folder);
+
+      foreach ($users as $userid => $perms){
+        $result[preg_replace('/^user\./', '', $userid)]= $perms;
+      }
+
+    }
+
+    return ($result);
+  }
+
+
+  function deleteMailbox($folder)
+  {
+    $cfg= $this->config[$this->gosaMailServer];
+    imap_setacl ($this->mbox, $folder, $cfg["admin"], "lrswipcda");
+    if (!imap_deletemailbox($this->mbox, $cfg["connect"].$folder)){
+      print_red(sprintf(_("Can't remove IMAP mailbox. Server says '%s'."), imap_last_error()));
+      return (FALSE);
+    }
+    return (TRUE);
+  }
+
+
+  function configureFilter($user, $gosaMailDeliveryMode,
+      $mail, $gosaMailAlternateAddress,
+      $gosaMailMaxSize,
+      $gosaSpamMailbox, $gosaSpamSortLevel,
+      $gosaVacationMessage)
+  {
+    $cfg= $this->config[$this->gosaMailServer];
+
+    /* Build spamlevel. Spamassassin tags mails with "*" for each integer
+       point of spam. So a spam level of 5.3 gets "*****" which can be
+       checked easily by spam filters */
+    $spamlevel= "";
+    for ($i= 0; $i<$gosaSpamSortLevel; $i++){
+      $spamlevel .= "*";
+    }
+
+    /* Log into the mail server */
+    $sieve= new sieve($cfg["sieve_server"], $cfg["sieve_port"], $user,
+        $cfg["password"], $cfg["admin"]);
+
+    if (!$sieve->sieve_login()){
+      print_red(sprintf(_("Can't log into SIEVE server. Server says '%s'."),
+            to_string($sieve->error_raw)));
+      return;
+    }
+
+    /* Load current script from server and remove everything between the comments
+       "###GOSA" */
+    $script= "";
+    if($sieve->sieve_listscripts()){
+      if (in_array("gosa", $sieve->response)){
+
+        /* get old GOsa script */
+        if(!$sieve->sieve_getscript("gosa")){
+          print_red(sprintf(_("Can't get sieve script. Server says '%s'."), to_string($sieve->error_raw)));
+          return;
+        }
+
+        foreach ($sieve->response as $line){
+          if (preg_match ("/^###GOSA/", $line)){
+            break;
+          }
+          $line= rtrim($line);
+          if (!preg_match ('/^\s*$/', $line)){
+            $script .= $line."\n";
+          }
+        }
+
+      }
+    }
+
+    /* Only create a new one, if it is not empty */
+    if (is_integer(strpos($gosaMailDeliveryMode, "R")) ||
+        is_integer(strpos($gosaMailDeliveryMode, "C")) ||
+        !is_integer(strpos($gosaMailDeliveryMode, "L")) ||
+        is_integer(strpos($gosaMailDeliveryMode, "V")) ||
+        is_integer(strpos($gosaMailDeliveryMode, "S"))){
+
+      $text= preg_replace('/"/', '\\"', implode ("", file(CONFIG_DIR."/sieve-header.txt")));
+      eval ("\$script.=\"$text\";");
+    }
+
+    /* Add anti-spam code */
+    if (is_integer(strpos($gosaMailDeliveryMode, "S"))){
+      $spambox= $gosaSpamMailbox;
+      $text= preg_replace('/"/', '\\"', implode ("", file(CONFIG_DIR."/sieve-spam.txt")));
+      eval ("\$script.=\"$text\";");
+    }
+
+    /* Add "reject due to mailsize" code, message is currently not
+       adjustable through GOsa. */
+    if (is_integer(strpos($gosaMailDeliveryMode, "R"))){
+      $maxsize= $gosaMailMaxSize;
+      $text= preg_replace('/"/', '\\"', implode ("", file(CONFIG_DIR."/sieve-mailsize.txt")));
+      eval ("\$script.=\"$text\";");
+    }
+
+    /* Add vacation information */
+    if (is_integer(strpos($gosaMailDeliveryMode, "V"))){
+
+      /* Sieve wants all destination addresses for the
+         vacation message, so we've to assemble them from
+         mail and mailAlternateAddress */
+      $addrlist= "\"".$mail."\"";
+      foreach ($gosaMailAlternateAddress as $val){
+        $addrlist .= ", \"$val\"";
+      }
+      $vacmsg= $gosaVacationMessage;
+      $text= preg_replace('/"/', '\\"', implode ("", file(CONFIG_DIR."/sieve-vacation.txt")));
+      eval ("\$script.=\"$text\";");
+    }
+
+    /* If no local delivery is wanted, tell the script to discard the mail */
+    if (!is_integer(strpos($gosaMailDeliveryMode, "L"))){
+      $text= preg_replace('/"/', '\\"', implode ("", file(CONFIG_DIR."/sieve-discard.txt")));
+      eval ("\$script.=\"$text\";");
+    }
+
+    /* Just be aware of null scripts... */
+    if (!isset ($script)){
+      $script= "";
+    }
+
+    /* Upload script and make it the default one */
+    if (!$sieve->sieve_sendscript("gosa", $script)){
+      print_red(sprintf(_("Can't send sieve script. Server says '%s'."), to_string($sieve->error_raw)));
+      return;
+    }
+    if(!$sieve->sieve_setactivescript("gosa")){
+      print_red(sprintf(_("Can't activate GOsa sieve script. Server says '%s'."), to_string($sieve->error_raw)));
+      return;
+    }
+
+    $sieve->sieve_logout();
+  }
+
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_mail-methods-kolab.inc b/include/class_mail-methods-kolab.inc
new file mode 100644 (file)
index 0000000..4f28ecf
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+require_once("class_mail-methods-cyrus.inc");
+
+class mailMethodKolab extends mailMethodCyrus
+{
+  var $mbox= "-";
+  var $config;
+  var $gosaMailServer= "";
+  var $uattrib= "mail";
+
+  var $attribute_map= array("gosaMailAlternateAddress"  =>  "alias",
+                            "gosaMailQuota"             =>  "cyrus-userquota",
+                            "gosaMailServer"            =>  "kolabHomeServer");
+
+  function mailMethodKolab($config)
+  {
+    $this->config= $config->data['SERVERS']['IMAP'];
+  }
+
+  function updateMailbox($folder)
+  {
+  }
+
+  function setQuota($folder, $gosaMailQuota)
+  {
+    return (TRUE);
+  }
+
+  function setSharedFolderPermissions($folder, $permissions)
+  {
+  }
+
+  function deleteMailbox($folder)
+  {
+    return (TRUE);
+  }
+
+
+  function fixAttributesOnLoad(&$mailObject)
+  {
+    /* Convert attributes and objectClasses */
+    foreach ($this->attribute_map as $dest => $source){
+      if (isset($mailObject->attrs[$source])){
+        $mailObject->attrs[$dest]= $mailObject->attrs[$source];
+        unset ($mailObject->attrs[$source]);
+      }
+    }
+
+    /* Adjust server name if needed */
+    foreach ($mailObject->config->data['SERVERS']['IMAP'] as $srv => $dummy){
+      if (preg_match("%".$mailObject->attrs['gosaMailServer'][0]."$%", $srv)){
+        $mailObject->attrs['gosaMailServer']= array(0 => $srv, "count" => 1);
+        break;
+      }
+    }
+  }
+
+
+  function fixAttributesOnStore(&$mailObject)
+  {
+    /* Convert attributes and objectClasses */
+    foreach ($this->attribute_map as $source => $dest){
+      if (isset($mailObject->attrs[$source])){
+        $mailObject->attrs[$dest]= $mailObject->attrs[$source];
+        unset ($mailObject->attrs[$source]);
+      }
+    }
+    $objectclasses= array();
+    foreach ($mailObject->attrs['objectClass'] as $oc){
+      if ($oc !=  'kolabInetOrgPerson'){
+        $objectclasses[]= $oc;
+      }
+    }
+    $mailObject->attrs['objectClass']= $objectclasses;
+    $mailObject->attrs['objectClass'][]= 'kolabInetOrgPerson';
+
+    /* Remove imap:// tagging */
+    $mailObject->attrs['kolabHomeServer']= preg_replace('%imap://%', '', $mailObject->attrs['kolabHomeServer']);
+    $mailObject->attrs['gosaMailServer']= $mailObject->attrs['kolabHomeServer'];
+    $mailObject->attrs['kolabDeleteFlag']= array();
+  }
+
+
+  function fixAttributesOnRemove(&$mailObject)
+  {
+    /* Add attribute for object deletion and remove GOsa specific
+       values from entry. */
+    unset ($mailObject->attrs['mail']);
+    $mailObject->attrs['kolabDeleteFlag']= preg_replace('%imap://%', '', $mailObject->gosaMailServer);
+  }
+
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_mail-methods-sendmail-cyrus.inc b/include/class_mail-methods-sendmail-cyrus.inc
new file mode 100644 (file)
index 0000000..f8cb7c3
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+require_once("class_mail-methods-cyrus.inc");
+
+class mailMethodSendmailCyrus extends mailMethodCyrus
+{
+
+  function mailMethodSendmailCyrus($config)
+  {
+    $this->config= $config->data['SERVERS']['IMAP'];
+  }
+
+  function fixAttributesOnLoad(&$mailObject)
+  {
+    /* Remove possible local alias from forwarders */
+    $newForwarder= array();
+    foreach ($mailObject->gosaMailForwardingAddress as $addr){
+      if (!preg_match('/^\\\\/', $addr)){
+        $newForwarder[]= $addr;
+      }
+    }
+    $mailObject->gosaMailForwardingAddress= $newForwarder;
+  }
+
+  function fixAttributesOnStore(&$mailObject)
+  {
+    /* Add local user if checked */
+    if (preg_match("/L/", $mailObject->gosaMailDeliveryMode)) {
+      $mailObject->gosaMailForwardingAddress[]= "\\".$mailObject->uid;
+    }
+  }
+
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_mail-methods.inc b/include/class_mail-methods.inc
new file mode 100644 (file)
index 0000000..2e67f7e
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+class mailMethod
+{
+  var $uattrib= "uid";
+  
+  function mailMethod($config)
+  {
+  }
+
+  function connect($gosaMailServer)
+  {
+    return (TRUE);
+  }
+
+  function disconnect()
+  {
+  }
+
+  function getQuota($folder)
+  {
+    return (array('quotaUsage' => 0, 'gosaMailQuota' => 0));
+  }
+
+  function getMailboxList($folder, $uid)
+  {
+    return (array("INBOX"));
+  }
+
+  function setQuota($folder, $gosaMailQuota)
+  {
+    return (TRUE);
+  }
+
+  function updateMailbox($folder)
+  {
+  }
+
+  function deleteMailbox($folder)
+  {
+    return (TRUE);
+  }
+
+  function setSharedFolderPermissions($folder, $permissions)
+  {
+  }
+
+  function configureFilter($user, $gosaMailDeliveryMode,
+      $mail, $gosaMailAlternateAddress,
+      $gosaMailMaxSize,
+      $gosaSpamMailbox, $gosaSpamSortLevel,
+      $gosaVacationMessage)
+  {
+  }
+
+  function fixAttributesOnLoad(&$mailObject)
+  {
+  }
+
+  function fixAttributesOnStore(&$mailObject)
+  {
+  }
+
+  function fixAttributesOnRemove(&$mailObject)
+  {
+  }
+
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods-clear.inc b/include/class_password-methods-clear.inc
new file mode 100644 (file)
index 0000000..e4d28e9
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004 Fabian Hickert 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+class passwordMethodClear extends passwordMethod
+{
+
+       function passwordMethodClear($config)  
+       {
+       }
+
+       function is_available()
+       {
+               return true;
+       }
+
+
+       function generate_hash($pwd)
+       {
+               return $pwd;       
+       }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods-crypt.inc b/include/class_password-methods-crypt.inc
new file mode 100644 (file)
index 0000000..c3d21c8
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Fabian Hickert 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+class passwordMethodCrypt extends passwordMethod
+{
+  function passwordMethodCrypt($config)  
+  {
+  }
+
+  function is_available()
+  {
+    if(function_exists("crypt")){
+      return true;
+    }else{
+      return false;
+    }
+  }
+
+
+  function generate_hash($pwd)
+  {
+    return "{crypt}".crypt($pwd, substr(session_id(),0,2));
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods-kerberos.inc b/include/class_password-methods-kerberos.inc
new file mode 100644 (file)
index 0000000..1e8ba72
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004 Fabian Hickert 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+class passwordMethodkerberos extends passwordMethod
+{
+
+       function passwordMethodkerberos($config)  
+       {
+       }
+
+  function is_available()
+  {
+    if (function_exists('kadm5_init_with_password')){
+      return(true);
+    }else{
+      return false;
+    }
+  }
+
+       function generate_hash($pwd)
+       {
+               $cfg= $this->config->data['SERVERS']['KERBEROS'];
+
+               if (!function_exists('kadm5_init_with_password'))
+               {
+                       print_red (_("Warning: Can't set kerberos password. Your PHP version has no kerberos support, password has not been changed."));
+               } 
+               else 
+               {
+                       $handle = kadm5_init_with_password($cfg['SERVER'],
+                                       $cfg['REALM'], $cfg['ADMIN'], $cfg['PASSWORD']);
+
+                       if ($handle === FALSE)
+                       {
+                               print_red (_("Kerberos database communication failed!"));
+                       }
+
+                       $ret= kadm5_chpass_principal($handle, $attrs['uid'][0]."@".$cfg['REALM'],$password);
+
+                       if ($ret === FALSE)
+                       {
+                               print_red (_("Changing password in kerberos database failed!"));
+                       }
+
+                       kadm5_destroy($handle);
+
+                       $newpass= "{kerberos}".$attrs['uid'][0]."@".$cfg['REALM'];
+
+                       return $newpass;       
+               }
+       }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods-md5.inc b/include/class_password-methods-md5.inc
new file mode 100644 (file)
index 0000000..b271036
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Fabian Hickert 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+class passwordMethodMd5 extends passwordMethod
+{
+       function passwordMethodMd5($config)  
+       {
+       }
+
+
+       function is_available()
+       {
+               if (function_exists('crypt')){
+                       return(true);
+               }else{
+                       return false;
+               }
+       }
+
+
+       function generate_hash($pwd)
+       {
+               return  "{crypt}".crypt($pwd, substr(session_id(),0,2));       
+       }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods-sha.inc b/include/class_password-methods-sha.inc
new file mode 100644 (file)
index 0000000..0780a76
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Fabian Hickert 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+class passwordMethodsha extends passwordMethod
+{
+  function passwordMethodsha($config)  
+  {
+  }
+
+  function is_available()
+  {
+    if (function_exists('sha1')){
+      return(true);
+    }elseif(function_exists('mhash')){
+      return true;
+    }elseif(function_exists('crypt')){
+      return true;
+    }else{
+      return false;
+    }
+  }
+
+
+  function generate_hash($password)
+  {
+    if (function_exists('sha1')) {
+      $hash = "{SHA}" . base64_encode(pack("H*",sha1($password)));
+    }elseif (function_exists('mhash')) {
+      $hash = "{SHA}" . base64_encode(mHash(MHASH_SHA1, $password));
+    }elseif(function_exists('crypt')) {
+      $hash = "{CRYPT}" . crypt($password);
+    }else{
+      print_red(_("Can't use sha for encryption, missing function sha1 / mhash / crypt"));
+      return false;
+    }
+
+    return $hash; 
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods-smd5.inc b/include/class_password-methods-smd5.inc
new file mode 100644 (file)
index 0000000..fea58f6
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Fabian Hickert 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+class passwordMethodsmd5 extends passwordMethod
+{
+  function passwordMethodsmd5($config)  
+  {
+  }
+
+  function is_available()
+  {
+    if ((!function_exists('md5'))){
+      return false;    
+    }else{
+      return true;
+    }
+  }
+
+  function generate_hash($pwd)
+  {
+    mt_srand(microtime()* 10000000);
+    $salt0= substr(pack("h*", md5(mt_rand())), 0, 8);
+    $salt = substr(pack("H*", md5($salt0 . $pwd)), 0, 4);
+    $hash = "{SMD5}".base64_encode(pack("H*",md5($pwd . $salt)) . $salt);
+    return $hash;       
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods-ssha.inc b/include/class_password-methods-ssha.inc
new file mode 100644 (file)
index 0000000..e80e566
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Fabian Hickert 
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+
+class passwordMethodssha extends passwordMethod
+{
+  function passwordMethodssha($config)  
+  {
+  }
+
+  function is_available()
+  {
+    if(function_exists("sha1")){
+      return true;
+    }elseif(function_exists("mhash")){
+      return true;
+    }else{
+      return false;
+    }
+  }
+
+  function generate_hash($pwd)
+  {
+    if (function_exists("sha1")) {
+      $salt= substr(pack("h*", md5(mt_rand())), 0, 8);
+      $salt= substr(pack("H*", sha1($salt.$pwd)), 0, 4);
+      $pwd= "{ssha}".base64_encode(pack("H*", sha1($pwd.$salt)).$salt);
+      return $pwd;       
+    } elseif(function_exists("mhash")) {
+      $salt=mhash_keygen_s2k(MHASH_SHA1,$pwd, substr(pack("h*",md5(mt_rand())),0,8),4);
+      $pwd= "{ssha}".base64_encode(mhash(MHASH_SHA1, $pwd.$salt).$salt);
+    } else {
+      print_red(_("Can't use ssha for encryption. (Missing function mhash / sha1)"));
+      return(false);
+    }
+    return $pwd;
+  }
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_password-methods.inc b/include/class_password-methods.inc
new file mode 100644 (file)
index 0000000..9715780
--- /dev/null
@@ -0,0 +1,219 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2004  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+class passwordMethod
+{
+  var $config = false;
+
+  // Konstructor
+  function passwordMethod($config)
+  {
+  }
+
+  // Loads Methods in annother way as  get_available_methods do, (For setup ..)
+  // and loads them,.
+  function get_available_methods_if_not_loaded($path_to_load="../include")
+  {
+    $oh = opendir($path_to_load);
+    $i = 0; 
+    $ret = false;
+    while ($file = readdir($oh)) {
+      $one = strtolower($file); 
+      if((strstr($one,"class_password-methods-" ))&&($one[0]!=".")){
+        require_once($file);
+      }
+    }
+    return(passwordMethod::get_available_methods());
+  }
+
+
+
+
+  // Crypts a single string, with given Method
+  function crypt_single_str($string,$method)
+  {
+    $available = passwordMethod::get_available_methods();
+    if(!is_array($available))
+    {
+      $available = passwordMethod::get_available_methods_if_not_loaded();
+    }
+
+    $test = new  $available[$method](false);
+    $newpass =  $test->generate_hash($string);
+    return( $newpass); 
+  }
+
+
+  // this function returns all loaded classes for password encryption
+  function get_available_methods()
+  {
+    $ret =false;
+    $all = (get_declared_classes());
+    $i = 0;
+    foreach($all as $one) {
+      if((strstr($one,"passwordmethod" ))&&($one  != "passwordmethod")){
+        $name = str_replace ("passwordmethod","",$one);
+        $test = new $one(false);
+        if($test->is_available()) {
+          $ret['name'][$i]=str_replace ("passwordmethod","",$one);
+          $ret['class'][$i]=$one;
+          $ret[$i]['name']=str_replace ("passwordmethod","",$one);
+          $ret[$i]['class']=$one;
+          $ret[str_replace ("passwordmethod","",$one)]=$one;                    
+          $i++;
+        }
+      }
+    }
+    return($ret);
+  }
+
+}
+
+// change_password, changes the Password, of the given dn
+function change_password ($dn, $password, $mode=0, $hash= "")
+{
+
+  global $config;
+  $newpass= "";
+
+
+  // Get all available encryption Methods 
+  $available = passwordMethod::get_available_methods();
+
+
+  // read current password entry for $dn, to detect the encryption Method
+  $ldap       = $config->get_ldap_link();
+  $ldap->cat ($dn);
+  $attrs      = $ldap->fetch ();
+
+  // Set encryption type to clear if required 
+  if (isset($attrs['userPassword'][0]) && preg_match('/^[^{}]+$/', $attrs['userPassword'][0]) && $hash == ""){
+    $hash= "clear";
+  }
+
+
+
+  // Detect the encryption Method
+  if ( (isset($attrs['userPassword'][0]) &&  preg_match ("/^{([^}]+)}(.+)/", $attrs['userPassword'][0], $matches)) ||  $hash != ""){
+
+    /* Check for supported algorithm */
+    mt_srand((double) microtime()*1000000);
+
+    /* Extract used hash */
+    if ($hash == ""){
+      $hash= strtolower($matches[1]);
+    }
+
+
+    // Crypt with the detected Method
+    $test = new  $available[$hash]($config);
+    $newpass =  $test->generate_hash($password);
+
+  } else {
+    // Crypt it by default 
+    $test = new  $available['md5']($config);
+    $newpass =  $test->generate_hash($password);
+  }
+
+
+
+  // Update shadow timestamp? 
+  if (isset($attrs["shadowLastChange"][0])){
+    $shadow= (int)(date("U") / 86400);
+  } else {
+    $shadow= 0;
+  }
+
+  // Write back modified entry 
+  $ldap->cd($dn);
+  $attrs= array();
+
+  // Not for groups 
+  if ($mode == 0){
+
+    if ($shadow != 0){
+      $attrs['shadowLastChange']= $shadow;
+    }
+
+    // Create SMB Password 
+    $attrs =    generate_smb_nt_hash($password);
+  }
+
+  $attrs['userPassword']= array();
+  $attrs['userPassword']= $newpass;
+
+
+  $ldap->modify($attrs);
+
+
+  if ($ldap->error != 'Success')
+  {
+    print_red(sprintf(_("Setting the password failed. LDAP server says '%s'."),
+          $ldap->get_error()));
+  }
+}
+
+
+// Retrun something like array['sambaLMPassword']= "lalla..." 
+function generate_smb_nt_hash($password)
+{
+  global $config;
+  $tmp= $config->data['MAIN']['SMBHASH']." ".escapeshellarg($password);
+  @DEBUG (DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $tmp, "Execute");
+
+  exec($tmp, $ar);
+  flush();
+  reset($ar);
+  $hash= current($ar);
+  if ($hash == "")
+  {
+    print_red (_("Setting for SMBHASH in gosa.conf is incorrect! Can't change Samba password."));
+  }
+  else 
+  {
+    list($lm,$nt)= split (":", trim($hash));
+
+    if ($config->current['SAMBAVERSION'] == 3)
+    {
+      $attrs['sambaLMPassword']= $lm;
+      $attrs['sambaNTPassword']= $nt;
+      $attrs['sambaPwdLastSet']= date('U');
+      $attrs['sambaBadPasswordCount']= "0";
+      $attrs['sambaBadPasswordTime']= "0";
+    } else {
+      $attrs['lmPassword']= $lm;
+      $attrs['ntPassword']= $nt;
+      $attrs['pwdLastSet']= date('U');
+    }
+    return($attrs);
+  }
+} 
+
+function crypt_single($string,$enc_type )
+{
+  if(!class_exists("passwordMethod")){
+    require_once("class_password-methods.inc");
+  }
+  return( passwordMethod::crypt_single_str($string,$enc_type));
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_plugin.inc b/include/class_plugin.inc
new file mode 100644 (file)
index 0000000..5fd4220
--- /dev/null
@@ -0,0 +1,682 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2003  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*! \brief   The plugin base class
+  \author  Cajus Pollmeier <pollmeier@gonicus.de>
+  \version 2.00
+  \date    24.07.2003
+
+  This is the base class for all plugins. It can be used standalone or
+  can be included by the tabs class. All management should be done 
+  within this class. Extend your plugins from this class.
+ */
+
+class plugin
+{
+  /*!
+    \brief Reference to parent object
+
+    This variable is used when the plugin is included in tabs
+    and keeps reference to the tab class. Communication to other
+    tabs is possible by 'name'. So the 'fax' plugin can ask the
+    'userinfo' plugin for the fax number.
+
+    \sa tab
+   */
+  var $parent= NULL;
+
+  /*!
+    \brief Configuration container
+
+    Access to global configuration
+   */
+  var $config= NULL;
+
+  /*!
+    \brief Mark plugin as account
+
+    Defines whether this plugin is defined as an account or not.
+    This has consequences for the plugin to be saved from tab
+    mode. If it is set to 'FALSE' the tab will call the delete
+    function, else the save function. Should be set to 'TRUE' if
+    the construtor detects a valid LDAP object.
+
+    \sa plugin::plugin()
+   */
+  var $is_account= FALSE;
+  var $initially_was_account= FALSE;
+
+  /*!
+    \brief Mark plugin as template
+
+    Defines whether we are creating a template or a normal object.
+    Has conseqences on the way execute() shows the formular and how
+    save() puts the data to LDAP.
+
+    \sa plugin::save() plugin::execute()
+   */
+  var $is_template= FALSE;
+  var $ignore_account= FALSE;
+  var $is_modified= FALSE;
+
+  /*!
+    \brief Represent temporary LDAP data
+
+    This is only used internally.
+   */
+  var $attrs= array();
+
+
+  /*!
+    \brief Used standard values
+
+    dn
+   */
+  var $dn= "";
+  var $uid= "";
+  var $sn= "";
+  var $givenName= "";
+  var $acl= "*none*";
+  var $dialog= FALSE;
+
+  /* attribute list for save action */
+  var $attributes= array();
+  var $objectclasses= array();
+  var $new= TRUE;
+
+  /*! \brief plugin constructor
+
+    If 'dn' is set, the node loads the given 'dn' from LDAP
+
+    \param dn Distinguished name to initialize plugin from
+    \sa plugin()
+   */
+  function plugin ($config, $dn= NULL)
+  {
+    /* Configuration is fine, allways */
+    $this->config= $config;    
+    $this->dn= $dn;
+
+    /* Handle new accounts, don't read information from LDAP */
+    if ($dn == "new"){
+      return;
+    }
+
+    /* Get LDAP descriptor */
+    $ldap= $this->config->get_ldap_link();
+    if ($dn != NULL){
+
+      /* Load data to 'attrs' and save 'dn' */
+      $ldap->cat ($dn);
+      $this->attrs= $ldap->fetch();
+
+      /* Copy needed attributes */
+      foreach ($this->attributes as $val){
+        if (isset($this->attrs["$val"][0])){
+          $this->$val= $this->attrs["$val"][0];
+        }
+      }
+
+      /* Set the template flag according to the existence of objectClass
+         gosaUserTemplate */
+      if (isset($this->attrs['objectClass'])){
+        if (in_array ("gosaUserTemplate", $this->attrs['objectClass'])){
+          $this->is_template= TRUE;
+          @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
+              "found", "Template check");
+        }
+      }
+
+      /* Is Account? */
+      error_reporting(0);
+      $found= TRUE;
+      foreach ($this->objectclasses as $obj){
+        if (preg_match('/top/i', $obj)){
+          continue;
+        }
+        if (!in_array_ics ($obj, $this->attrs['objectClass'])){
+          $found= FALSE;
+          break;
+        }
+      }
+      error_reporting(E_ALL);
+      if ($found){
+        $this->is_account= TRUE;
+        @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
+            "found", "Object check");
+      }
+    }
+
+    /* Save initial account state */
+    $this->initially_was_account= $this->is_account;
+  }
+
+  /*! \brief execute plugin
+
+    Generates the html output for this node
+   */
+  function execute()
+  {
+    /* Do we represent a valid account? */
+    if (!$this->is_account){
+      echo "<img src=\"images/stop.png\" align=center>&nbsp;<b>".
+        _("This 'dn' has no account extensions.")."</b>";
+      return;
+    }
+
+    /* Show dummy message */
+    echo _("This is an empty plugin.");
+  }
+
+  /* remove object from parent */
+  function remove_from_parent()
+  {
+    /* include global link_info */
+    $ldap= $this->config->get_ldap_link();
+
+    /* Get current objectClasses in order to add the required ones */
+    $ldap->cat($this->dn);
+    $tmp= $ldap->fetch ();
+    if (isset($tmp['objectClass'])){
+      $oc= $tmp['objectClass'];
+    } else {
+      $oc= array("count" => 0);
+    }
+
+    /* Remove objectClasses from entry */
+    $ldap->cd($this->dn);
+    $this->attrs= array();
+    $this->attrs['objectClass']= array();
+    for ($i= 0; $i<$oc["count"]; $i++){
+      if (!in_array_ics($oc[$i], $this->objectclasses)){
+        $this->attrs['objectClass'][]= $oc[$i];
+      }
+    }
+
+    /* Unset attributes from entry */
+    foreach ($this->attributes as $val){
+      $this->attrs["$val"]= array();
+    }
+
+    /* Unset account info */
+    $this->is_account= FALSE;
+
+    /* Do not write in plugin base class, this must be done by
+       children, since there are normally additional attribs,
+       lists, etc. */
+    /*
+       $ldap->modify($this->attrs);
+     */
+  }
+
+
+  /* Save data to object */
+  function save_object()
+  {
+    /* Save values to object */
+    foreach ($this->attributes as $val){
+      if (chkacl ($this->acl, "$val") == "" && isset ($_POST["$val"])){
+
+        /* Check for modifications */
+        if (get_magic_quotes_gpc()) {
+          $data= stripcslashes($_POST["$val"]);
+        } else {
+          $data= $this->$val = $_POST["$val"];
+        }
+        if ($this->$val != $data){
+          $this->is_modified= TRUE;
+        }
+        $this->$val= $data;
+      }
+    }
+  }
+
+
+  /* Save data to LDAP, depending on is_account we save or delete */
+  function save()
+  {
+    /* include global link_info */
+    $ldap= $this->config->get_ldap_link();
+
+    /* Start with empty array */
+    $this->attrs= array();
+
+    /* Get current objectClasses in order to add the required ones */
+    $ldap->cat($this->dn);
+    
+    $tmp= $ldap->fetch ();
+    
+    if (isset($tmp['objectClass'])){
+      $oc= $tmp["objectClass"];
+      $this->new= FALSE;
+    } else {
+      $oc= array("count" => 0);
+      $this->new= TRUE;
+    }
+
+    /* Load (minimum) attributes, add missing ones */
+    $this->attrs['objectClass']= $this->objectclasses;
+    for ($i= 0; $i<$oc["count"]; $i++){
+      if (!in_array_ics($oc[$i], $this->objectclasses)){
+        $this->attrs['objectClass'][]= $oc[$i];
+      }
+    }
+
+    /* Copy standard attributes */
+    foreach ($this->attributes as $val){
+      if ($this->$val != ""){
+        $this->attrs["$val"]= $this->$val;
+      } elseif (!$this->new) {
+        $this->attrs["$val"]= array();
+      }
+    }
+
+  }
+
+  /* Check formular input */
+  function check()
+  {
+    $message= array();
+    return ($message);
+  }
+
+  /* Adapt from template, using 'dn' */
+  function adapt_from_template($dn)
+  {
+    /* Include global link_info */
+    $ldap= $this->config->get_ldap_link();
+
+    /* Load requested 'dn' to 'attrs' */
+    $ldap->cat ($dn);
+    $this->attrs= $ldap->fetch();
+
+    /* Walk through attributes */
+    foreach ($this->attributes as $val){
+
+      if (isset($this->attrs["$val"][0])){
+
+        /* If attribute is set, replace dynamic parts: 
+           %sn, %givenName and %uid. Fill these in our local variables. */
+        $value= $this->attrs["$val"][0];
+
+        foreach (array("sn", "givenName", "uid") as $repl){
+          if (preg_match("/%$repl/i", $value)){
+            $value= preg_replace ("/%$repl/i", $this->parent->$repl, $value);
+          }
+        }
+        $this->$val= $value;
+      }
+    }
+
+    /* Is Account? */
+    $found= TRUE;
+    foreach ($this->objectclasses as $obj){
+      if (preg_match('/top/i', $obj)){
+        continue;
+      }
+      if (!in_array_ics ($obj, $this->attrs['objectClass'])){
+        $found= FALSE;
+        break;
+      }
+    }
+    if ($found){
+      $this->is_account= TRUE;
+    }
+  }
+
+  /* Indicate whether a password change is needed or not */
+  function password_change_needed()
+  {
+    return FALSE;
+  }
+
+  /* Show header message for tab dialogs */
+  function show_header($button_text, $text, $disabled= FALSE)
+  {
+    if ($disabled == TRUE){
+      $state= "disabled";
+    } else {
+      $state= "";
+    }
+    $display= "<table width=100%><tr>\n<td colspan=2><p><b>$text</b></p>\n";
+    $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".
+      chkacl($this->acl, "all")." ".$state.
+      "><p class=\"seperator\">&nbsp;</p></td></tr></table>";
+
+    return($display);
+  }
+
+  function postcreate()
+  {
+    /* Find postcreate entries for this class */
+    $command= $this->search($this->config->data['MENU'], get_class($this), "POSTCREATE");
+    if ($command == ""){
+      $command= $this->search($this->config->data['SERVICE'], get_class($this), "POSTCREATE");
+    }
+
+    if ($command != ""){
+      /* Walk through attribute list */
+      foreach ($this->attributes as $attr){
+        $command= preg_replace("/%$attr/", $this->$attr, $command);
+      }
+      $command= preg_replace("/%dn/", $this->dn, $command);
+      if (check_command($command)){
+        @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
+            $command, "Execute");
+
+        exec($command);
+      } else {
+        $message= sprintf(_("Command '%s', specified as POSTCREATE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
+        print_red ($message);
+      }
+    }
+  }
+
+  function postmodify()
+  {
+    /* Find postcreate entries for this class */
+    $command= $this->search($this->config->data['MENU'], get_class($this), "POSTMODIFY");
+    if ($command == ""){
+      $command= $this->search($this->config->data['SERVICE'], get_class($this), "POSTMODIFY");
+    }
+
+    if ($command != ""){
+      /* Walk through attribute list */
+      foreach ($this->attributes as $attr){
+        $command= preg_replace("/%$attr/", $this->$attr, $command);
+      }
+      $command= preg_replace("/%dn/", $this->dn, $command);
+      if (check_command($command)){
+        @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
+            $command, "Execute");
+
+        exec($command);
+      } else {
+        $message= sprintf(_("Command '%s', specified as POSTMODIFY for plugin '%s' doesn't seem to exist."), $command, get_class($this));
+        print_red ($message);
+      }
+    }
+  }
+
+  function postremove()
+  {
+    /* Find postremove entries for this class */
+    $command= $this->search($this->config->data['MENU'], get_class($this), "POSTREMOVE");
+    if ($command == ""){
+      $command= $this->search($this->config->data['SERVICE'], get_class($this), "POSTREMOVE");
+    }
+
+    if ($command != ""){
+      /* Walk through attribute list */
+      foreach ($this->attributes as $attr){
+        $command= preg_replace("/%$attr/", $this->$attr, $command);
+      }
+      $command= preg_replace("/%dn/", $this->dn, $command);
+      if (check_command($command)){
+        @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
+            $command, "Execute");
+
+        exec($command);
+      } else {
+        $message= sprintf(_("Command '%s', specified as POSTREMOVE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
+        print_red ($message);
+      }
+    }
+  }
+
+  function search($arr, $name, $return)
+  {
+    if (is_array($arr)){
+      foreach ($arr as $a){
+        if (isset($a['CLASS']) &&
+            strtolower($a['CLASS']) == strtolower($name)){
+
+          if (isset($a[$return])){
+            return ($a[$return]);
+          } else {
+            return ("");
+          }
+        } else {
+          $res= $this->search ($a, $name, $return);
+          if ($res != ""){
+            return $res;
+          }
+        }
+      }
+    }
+    return ("");
+  }
+
+  /* Create unique DN */
+  function create_unique_dn($attribute, $base)
+  {
+    $ldap= $this->config->get_ldap_link();
+    $base= preg_replace("/^,*/", "", $base);
+
+    /* Try to use plain entry first */
+    $dn= "$attribute=".$this->$attribute.",$base";
+    $ldap->cat ($dn);
+    if (!$ldap->fetch()){
+      return ($dn);
+    }
+
+    /* Look for additional attributes */
+    foreach ($this->attributes as $attr){
+      if ($attr == $attribute || $this->$attr == ""){
+        continue;
+      }
+
+      $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
+      $ldap->cat ($dn);
+      if (!$ldap->fetch()){
+        return ($dn);
+      }
+    }
+
+    /* None found */
+    return ("none");
+  }
+
+  function rebind($ldap, $referral)
+  {
+    $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
+    if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
+      $this->error = "Success";
+      $this->hascon=true;
+      $this->reconnect= true;
+      return (0);
+    } else {
+      $this->error = "Could not bind to " . $binddn;
+      return NULL;
+    }
+  }
+
+  /* This is a workaround function. */
+  function copy($src_dn, $dst_dn)
+  {
+    /* Rename dn in possible object groups */
+    $ldap= $this->config->get_ldap_link();
+    $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.$src_dn.'))',
+        array('cn'));
+    while ($attrs= $ldap->fetch()){
+      $og= new ogroup($this->config, $ldap->getDN());
+      unset($og->member[$src_dn]);
+      $og->member[$dst_dn]= $dst_dn;
+      $og->save ();
+    }
+
+    $ldap->cat($dst_dn);
+    $attrs= $ldap->fetch();
+    if (count($attrs)){
+      trigger_error("Trying to overwrite $dst_dn, which already exists.",
+          E_USER_WARNING);
+      return (FALSE);
+    }
+
+    $ldap->cat($src_dn);
+    $attrs= array();
+    $attrs= $ldap->fetch();
+    if (!count($attrs)){
+      trigger_error("Trying to move $src_dn, which does not seem to exist.",
+          E_USER_WARNING);
+      return (FALSE);
+    }
+
+    /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
+    $ds= ldap_connect($this->config->current['SERVER']);
+    ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
+    if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
+      ldap_set_rebind_proc($ds, array(&$this, "rebind"));
+    }
+
+    $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
+    error_reporting (0);
+    $sr=ldap_read($ds, $src_dn, "objectClass=*");
+
+    /* Fill data from LDAP */
+    $new= array();
+    if ($sr) {
+      $ei=ldap_first_entry($ds, $sr);
+      if ($ei) {
+        foreach($attrs as $attr => $val){
+          if ($info = ldap_get_values_len($ds, $ei, $attr)){
+            for ($i= 0; $i<$info['count']; $i++){
+              if ($info['count'] == 1){
+                $new[$attr]= $info[$i];
+              } else {
+                $new[$attr][]= $info[$i];
+              }
+            }
+          }
+        }
+      }
+    }
+
+    /* close conncetion */
+    error_reporting (E_ALL);
+    ldap_unbind($ds);
+
+    /* Adapt naming attribute */
+    $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
+    $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
+    $new[$dst_name]= $dst_val;
+
+    /* Save copy */
+    $ldap->connect();
+    $ldap->cd($this->config->current['BASE']);
+    $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
+    $ldap->cd($dst_dn);
+    $ldap->add($new);
+
+    if ($ldap->error != "Success"){
+      trigger_error("Trying to save $dst_dn failed.",
+          E_USER_WARNING);
+      return(FALSE);
+    }
+
+    return (TRUE);
+  }
+
+
+  function move($src_dn, $dst_dn)
+  {
+    /* Copy source to destination */
+    if (!$this->copy($src_dn, $dst_dn)){
+      return (FALSE);
+    }
+
+    /* Delete source */
+    $ldap= $this->config->get_ldap_link();
+    $ldap->rmdir($src_dn);
+    if ($ldap->error != "Success"){
+      trigger_error("Trying to delete $src_dn failed.",
+          E_USER_WARNING);
+      return (FALSE);
+    }
+
+    return (TRUE);
+  }
+
+
+  /* Move/Rename complete trees */
+  function recursive_move($src_dn, $dst_dn)
+  {
+    /* Check if the destination entry exists */
+    $ldap= $this->config->get_ldap_link();
+
+    /* Check if destination exists - abort */
+    $ldap->cat($dst_dn);
+    if ($ldap->fetch()){
+      trigger_error("recursive_move $dst_dn already exists.",
+          E_USER_WARNING);
+      return (FALSE);
+    }
+
+    /* Perform a search for all objects to be moved */
+    $objects= array();
+    $ldap->cd($src_dn);
+    $ldap->search("(objectClass=*)", array("dn"));
+    while($attrs= $ldap->fetch()){
+      $dn= $attrs['dn'];
+      $objects[$dn]= strlen($dn);
+    }
+
+    /* Sort objects by indent level */
+    asort($objects);
+    reset($objects);
+
+    /* Copy objects from small to big indent levels by replacing src_dn by dst_dn */
+    foreach ($objects as $object => $len){
+      $src= $object;
+      $dst= preg_replace("/$src_dn$/", "$dst_dn", $object);
+      if (!$this->copy($src, $dst)){
+        return (FALSE);
+      }
+    }
+
+    /* Remove src_dn */
+    $ldap->cd($src_dn);
+    $ldap->recursive_remove();
+    return (TRUE);
+  }
+
+
+  function handle_post_events($mode)
+  {
+    switch ($mode){
+      case "add":
+        $this->postcreate();
+      break;
+
+      case "modify":
+        $this->postmodify();
+      break;
+
+      case "remove":
+        $this->postremove();
+      break;
+    }
+  }
+
+
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/class_pluglist.inc b/include/class_pluglist.inc
new file mode 100644 (file)
index 0000000..f6963d1
--- /dev/null
@@ -0,0 +1,259 @@
+<?php
+/*
+  This code is part of GOsa (https://gosa.gonicus.de)
+  Copyright (C) 2003  Cajus Pollmeier
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+class pluglist {
+  var $index= 0;
+  var $menu= "";
+  var $iconmenu= "";
+  var $menuparts= array();
+  var $config= NULL;
+  var $dirlist= array();
+  var $ui= NULL;
+  var $current= "";
+
+  function pluglist($config, $ui)
+  {
+       $this->ui= $ui;
+       $this->config= $config;
+
+       /* Create dirlist for all plugins */
+       $this->dirlist= $this->get_plugins ($this->dirlist, $this->config->data);
+  }
+
+  function get_plugins($list, $config)
+  {
+       /* Error reporting, because I'm getting strange messages in PHP 4.2.x */
+       error_reporting(0);
+       if (!isset($config['PATH']) && !isset($config['CLASS'])){
+               if (is_array($config)){
+                       foreach ($config as $val){
+                               $list= $this->get_plugins($list, $val);
+                       }
+               }
+       } else {
+               if (isset ($config['PATH']) && is_array($config)){
+                       $list[$this->index++]= $config['PATH'];
+               }
+       }
+       error_reporting(E_ALL);
+
+       return ($list);
+  }
+
+  function check_access($modname)
+  {
+       /* This plugin is readable for everyone, return true */
+       if ($modname == 'default'){
+               return (TRUE);
+       }
+
+       /* Look through ACL's */
+       foreach($this->ui->subtreeACL as $arr){
+               foreach($arr as $value){
+                       if ($value == ':all' || preg_match("/[,:]$modname#/", $value)){
+                               if (!preg_match('/^!/', $value)){
+                                       return (TRUE);
+                               }
+                       }
+               }
+       }
+
+       return (FALSE);
+  }
+
+  function gen_menu()
+  {
+       if ($this->menu == ""){
+               $cfg= $this->config->data['MENU'];
+
+               /* Parse headlines */
+               foreach ($cfg as $headline => $plug){
+                       $menu= "<p class=\"menuheader\">"._($headline)."</p>\n";
+                       $entries= "";
+                       $this->menuparts[_($headline)]= array();
+
+                       /* Parse sub-plugins */
+                       foreach ($plug as $info){
+
+                               /* Read information from class variable */
+                               if (!isset($info['CLASS'])){
+                                       print_red(_("Your gosa.conf information has changed partly. Please convert it using the contributed script fix_config.sh!"));
+                                       echo $_SESSION['errors'];
+                                       exit;
+                               }
+                               $vars= get_class_vars($info['CLASS']);
+                               $plHeadline= $vars['plHeadline'];
+                               $plDescription= $vars['plDescription'];
+
+                               $index= $this->get_index($info['PATH']);
+                               $image= get_template_path('images/'.$info['ICON']);
+                               $href= "main.php?plug=$index&amp;reset=1";
+
+                               if ($this->check_access($info['ACL'])){
+
+                                       $entries= $entries."<p class=\"menuitem\" ".
+                                               "onClick='return question(\""._("You are currently editing a database entry. Do you want to dismiss the changes?")."\", \"$href\");'>".
+                                               "<a class=\"menuitem\" ".
+                                               "href=\"$href\">".
+                                               _($plHeadline)."</a></p>\n";
+
+                               /* Generate icon entry with description */
+                               $this->menuparts[_($headline)][]= '<table class="menuitem" onClick=\'location.href="'.$href.'"\'><tr><td style="background-color:#F0F0F0;"><a href="'.$href.'"><img border=0 src="'.$image.'"></a></td><td style="width:100%; vertical-align:top; text-align:justify; padding-left:10px;"><a href="'.$href.'"><b>'._($plHeadline).'</b></a><br><a href="'.$href.'">'._($plDescription).'</a></td></tr></table>';
+
+                               }
+                       }
+
+                       /* Append to menu */
+                       if ($entries != ""){
+                               $this->menu.= $menu.$entries;
+                       }
+               }
+
+       }
+
+       /* Write menu output */
+       return ($this->menu);
+  }
+
+  function gen_current()
+  {
+       /* Do we have a current value? */
+       if ($this->current == ""){
+               $tmp= array_keys($this->menuparts);
+               $this->current= $tmp[0];
+       }
+
+       /* Fill current array */
+       $result= "<table width=100%>";
+       $count= 0;
+       foreach ($this->menuparts[$this->current] as $entry){
+               if ($count == 2){
+                       $result.= "</tr>";
+                       $count= 0;
+               }
+               if ($count == 0){
+                       $result.= "<tr>";
+               }
+               $result.= "<td>$entry</td>";
+               $count++;
+       }
+
+       /* Add missing cell? */
+       if ($count == 1){
+               $result.= "<td>&nbsp;</td>";
+       }
+
+       $result.= "</table>";
+       return $result;
+  }
+  
+
+  function show_iconmenu()
+  {
+       if ($this->iconmenu == ""){
+               $cfg= $this->config->data['MENU'];
+
+               if (isset($this->config->current['ICONSIZE'])){
+                       list($x, $y)= split("x", $this->config->current['ICONSIZE']);
+                       $isize= "width=\"$x\" height=\"$y\"";
+               } else {
+                       $isize= "";
+               }
+
+               /* Parse headlines */
+               foreach ($cfg as $headline => $plug){
+                       $col= 1;
+                       $menu= "<h1 class=\"menuheader\">".
+                                       _($headline)."</h1>\n<table style=\"width:100%;".
+                                       "font-size: 14px;\" cellpadding=7 border=0>\n<tr>\n";
+                       $entries= "";
+
+                       foreach ($plug as $info){
+
+                               /* Read information from class variable */
+                               $vars= get_class_vars($info['CLASS']);
+                               $plHeadline= $vars['plHeadline'];
+                               $plDescription= $vars['plDescription'];
+
+                               $index= $this->get_index($info['PATH']);
+
+                               if ($this->check_access($info['ACL'])){
+
+                                       /* next row? */
+                                       $image= get_template_path('images/'.$info['ICON']);
+                                       if ($col % 5){
+                                               $entries= $entries."<td class=\"iconmenu\" style=\"width:20%;\" onClick='location.href=\"main.php?plug=$index&amp;reset=1\"'".
+                                                       "><a class=\"iconmenu\" href=\"main.php?plug=$index&amp;reset=1\">".
+                                                       "<img $isize border=0 align=middle src=\"$image".
+                                                       "\" alt=\"*\">&nbsp;".
+                                                       _($plHeadline)."</a></td>\n";
+                                               $col++;
+                                       } else {
+                                               $entries= $entries."<td class=\"iconmenu\" style=\"width:20%;\" onClick='location.href=\"main.php?plug=$index&amp;reset=1\"'".
+                                                       "><a class=\"iconmenu\" href=\"main.php?plug=$index&amp;reset=1\">".
+                                                       "<img $isize border=0 align=middle src=\"$image".
+                                                       "\" alt=\"*\">&nbsp;".
+                                                       _($plHeadline)."</a></td>\n</tr>\n<tr>\n";
+                                               $col= 1;
+                                       }
+                               }
+                       }
+
+                       /* Append to menu */
+                       if ($entries != ""){
+                               $this->iconmenu.= $menu.$entries;
+
+                               /* Fill up remaining columns */
+                               if ($col != 1){
+                                       $col--;
+                                       while ($col % 5){
+                                               $this->iconmenu= $this->iconmenu.
+                                                       "<td style=\"width:20%\">&nbsp;</td>\n";
+                                               $col++;
+                                       }
+                               }
+
+                               /* close table */
+                               $this->iconmenu= $this->iconmenu."</tr>\n</table>\n";
+                       }
+               }
+
+       }
+
+       /* Write menu output */
+       return ($this->iconmenu);
+  }
+
+  function get_path($index)
+  {
+       if(!isset($this->dirlist[$index])){
+               return ("");
+       }
+       return ("../".$this->dirlist[$index]);
+  }
+
+  function get_index($path)
+  {
+       return (array_search($path, $this->dirlist));
+  }
+}
+
+?>
diff --git a/include/class_sambaMungedDial.inc b/include/class_sambaMungedDial.inc
new file mode 100644 (file)
index 0000000..82b514b
--- /dev/null
@@ -0,0 +1,546 @@
+<?php
+/*
+  This code is part of GOsa (https://gosa.gonicus.de)
+  Copyright (C) 2004  Cajus Pollmeier
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+
+/* File header is treated as constant. It cannot be defined inside the class if $PHP_VERSION < 5 */
+define ("FILEHEADER",   "6d00080020002000200020002000200020002000200020002000200020".
+                        "0020002000200020002000200020006400010020002000200020002000".
+                       "2000200020002000200020002000200020002000200020002000200020".
+                       "00200020002000200050001000");
+
+class sambaMungedDial
+{
+  /* Terminal server variables (samba3) */
+  var $ctx= array('CtxCfgPresent' =>          '551e0bb0',
+                       'CtxCfgFlags1'=>            '00e00010',
+                       'CtxCallback'=>             '0000000e',
+                       'CtxShadow'=>               '01000000',
+                       'CtxKeyboardLayout' =>      '00000000',
+                       'CtxMinEncryptionLevel' =>  '',
+                       'CtxWorkDirectory' =>       '',
+                       'CtxNWLogonServer' =>       '',  
+                       'CtxWFHomeDir' =>           '',
+                       'CtxWFHomeDirDrive' =>      '',
+                       'CtxWFProfilePath' =>       '',
+                       'CtxInitialProgram' =>      '',
+                       'CtxCallbackNumber' =>      '');
+
+  /* attribute list for save action */
+  var $ctxattributes= array("CtxCfgPresent", "CtxCfgFlags1", "CtxCallback",
+        "CtxMaxConnectionTime", "CtxMaxDisconnectionTime",
+        "CtxMaxIdleTime", "CtxKeyboardLayout", "CtxMinEncryptionLevel",
+        "CtxWorkDirectory", "CtxNWLogonServer", "CtxWFHomeDir",
+        "CtxWFHomeDirDrive", "CtxWFProfilePath", "CtxInitialProgram",
+        "CtxCallbackNumber");  
+
+  /* These parameters are treated as strings and get a trailing zero */
+  var $stringParams= array( "CtxWorkDirectory", "CtxNWLogonServer", 
+                       "CtxWFHomeDir", "CtxWFHomeDirDrive", 
+                       "CtxWFProfilePath", "CtxInitialProgram", "CtxCallbackNumber");
+
+  /* These parameters are treated as time values and get converted */
+  var $timeParams= array("CtxMaxConnectionTime", "CtxMaxDisconnectionTime", "CtxMaxIdleTime");
+
+
+  function strhex($string)
+  {
+       $hex="";
+       for ($i=0; $i<strlen($string); $i++) {
+               $hex.= dechex(ord($string[$i]));
+  }
+       
+       return ($hex);
+  }
+
+  function hexstr($hex)
+  {
+       $string="";
+       for ($i=0; $i<strlen($hex)-1; $i+=2) {
+               $string.= chr(hexdec($hex[$i].$hex[$i+1]));
+       }
+
+       return ($string);
+  }
+
+  function endian($src)
+  {
+       return (substr($src, 2, 2).substr($src, 0, 2));
+  }
+
+  function genTime ($minutes)
+  {
+       $usec= (int) ($minutes * 60 * 1000);
+       $src=  sprintf('%04X%04X', $usec & 0x0FFFF, ($usec & 0x0FFFF0000) >> 16);
+       return (sambaMungedDial::endian(substr($src, 0, 4)).sambaMungedDial::endian(substr($src, 4, 4)));
+  }
+
+  function readTime ($time)
+  {
+       $lo= substr($time, 0, 4);
+       $hi= substr($time, 4, 4);
+
+       $usecs= (hexdec(substr($lo, 2, 2)) * 256 + hexdec(substr($lo, 0, 2))) +
+               (hexdec(substr($hi, 2 ,2)) * 256 + hexdec(substr($hi, 0, 2))) * 256 * 256;
+
+       return ((int)($usecs / (60 * 1000)));
+  }
+
+  function to8bit($string)
+  {
+       $result= "";
+
+       /* Strip zeros */
+       for ($i= 0; $i<strlen($string); $i++){
+               if ($string[$i] != chr(0)){
+                       $result.= $string[$i];
+               }
+       }
+
+       return ($result);
+  }
+
+  function is_samba_path($path)
+  {
+       if ($path == ""){
+               return (TRUE);
+       }
+
+       if (!preg_match('/^[a-z0-9%\\\\_.:+-\\\\$]+$/i', $path)){
+               return (FALSE);
+       }
+
+       return preg_match ("/\\\\.+$/", $path);
+  }
+
+  /* Encode full MungedDial-String */
+  function encode_munged ($params)
+  {
+       /* Walk through the parameters and convert them */
+       $result= sambaMungedDial::hexstr(FILEHEADER);
+       foreach ($params as $paramName => $paramValue) {
+               
+               /* String parameter? */
+               if (in_array($paramName, $this->stringParams)){
+                       $isString= TRUE;
+                       $paramValue= sambaMungedDial::strhex($paramValue.chr(0).chr(0));
+               } else {
+                       $isString= FALSE;
+               }
+
+               /* Time parameter? */
+               if (in_array($paramName, $this->timeParams)){
+                       $paramValue= sambaMungedDial::genTime($paramValue);
+               }
+
+               $result.= sambaMungedDial::munge($paramName, $paramValue, $isString);
+       }
+       
+       return ($result);
+  }
+
+  /* Setup parameter given by paramName to MungedDial-Format */
+  function munge($paramName, $paramValue, $isString) 
+  {
+       $result= "";
+       
+       /* Encode paramName to UTF-16 */
+        if (function_exists("recode")){
+                $utfName= recode("ISO8859-15..UTF-16", $paramName);
+        } else {
+                $utfName= iconv("ISO8859-15", "UTF-16BE", $paramName);
+        }
+
+       /* Set parameter length, high and low byte */
+       $paramLen= strlen($utfName);
+       $result.= chr($paramLen & 0x0FF);
+       $result.= chr(($paramLen & 0x0FF00) >> 8);
+
+       /* String parameters have additional trailing bytes */
+       $valueLen= strlen($paramValue);
+       $result.= chr($valueLen & 0x0FF);
+       $result.= chr(($valueLen & 0x0FF00) >> 8);
+       
+       /* Length fields have a trailing '01' appended by the UTF-16 converted name */
+       $result.= chr(1);
+       $result.= $utfName;
+
+       /* Parameter is padded with '00' */
+       $result.= chr(0);
+       $result.= $paramValue;
+
+       /* Append a trailing '00' to string parameters */
+       if ($isString && (strlen($paramValue) & 1)){
+               $result.= chr(0);
+       }
+       
+       return ($result);
+  }
+
+  /* Takes a base64-encoded MungedDial-String and returns an array of included parameters and values */
+  function decode_munged($munge)
+  {
+       $result= array();
+               
+       /* Remove base64 encoding and skip FILEHEADER */
+       $ctxField= substr(base64_decode($munge), strlen(FILEHEADER) / 2);
+
+       /* Decode parameters */
+       while ($ctxField!=""){
+
+               /* Read value lengths */
+               $ctxParmNameLength= ord($ctxField[0]) + 16 * ord($ctxField[1]);
+               $ctxParmLength= ord($ctxField[2]) + 16 * ord($ctxField[3]);
+                               
+               /* Reposition ctxField on start of parameter name, read parameter name */
+               $ctxField= substr($ctxField, 6);
+               $ctxParmName= sambaMungedDial::to8bit(substr($ctxField, 0, $ctxParmNameLength));
+                               
+               /* Reposition ctxField on start of parameter */
+               $ctxField= substr($ctxField, $ctxParmNameLength);
+               $ctxParm= substr($ctxField, 0, $ctxParmLength);
+                               
+               /* If string parameter, convert */
+               if (in_array($ctxParmName, $this->stringParams)){
+                               $ctxParm= sambaMungedDial::hexstr($ctxParm);
+               }
+               /* If time parameter, convert */
+               if (in_array($ctxParmName, $this->timeParams)){
+                       $ctxParm= sambaMungedDial::readTime($ctxParm);
+               }
+
+               /* Assign in result array */
+               $result[$ctxParmName]= trim($ctxParm);
+                               
+               /* Reposition ctxField on end of parameter and continue */
+               $ctxField= substr($ctxField, $ctxParmLength);
+       }
+
+       return ($result);
+  }
+
+  /* function takes a base64-encoded sambaMungedDial */
+  function load ($mungedDial)
+  {
+       $this->ctx= $this->decode_munged($mungedDial);
+  }
+
+  /* Returns ready-to-run mungedDialString to be filled into ldap */
+  function getMunged ()
+  {
+       // Do extra check for valid timeParams (they must be set to 0 if disabled)
+       foreach($this->timeParams as $value) {
+               if(!isset($this->ctx[$value])) {
+                       $this->ctx[$value]= 0;
+               }
+       }
+       $result= base64_encode($this->encode_munged($this->ctx));
+       return $result;
+  }
+
+  /* Returns array of flags, which can be set on-demand with activated java-script */
+  function getOnDemandFlags ()
+  {
+       $result= array();
+       if ($_SESSION["js"]){
+               foreach ($this->timeParams as $value) {
+                       if (!isset($this->ctx[$value]) || (isset($this->ctx[$value]) && $this->ctx[$value] == 0)) {
+                               $result[$value."Mode"]= "disabled";
+                       }
+               }
+               
+               if (substr($this->ctx['CtxCfgFlags1'], 6, 1) == "1") {
+                       $result['CtxInitialProgramMode'] = "disabled";
+               }
+       }
+
+       return $result;
+  }
+
+  /*Gets Terminal-Server-Login value: enabled/disabled */
+  function getTsLogin ()
+  {
+       $flags= ord(substr($this->ctx['CtxCfgFlags1'], 5, 1));
+       
+       if ($flags & 1) {
+               $result= false;
+       } else {
+               $result= true;
+  }
+
+       return $result;
+  }
+
+  /* Sets Terminal-Server-Login value: enabled/disabled */
+  function setTsLogin ($checked)
+  {
+       $flag= substr($this->ctx['CtxCfgFlags1'], 5, 1);
+       
+       if ($checked) {
+               $flag|= 1;
+       } else {
+               $flag&= 0xFE;
+       }
+       
+       $this->ctx['CtxCfgFlags1'][5]= sprintf('%1X', $flag);
+  }
+
+  /* gets Broken-Connection value: disconnect/reset */
+  function getBrokenConn ()
+  {
+       $flags= ord(substr($this->ctx['CtxCfgFlags1'], 5, 1));
+       if ($flags & 4) {
+               $result= "1";
+       } else {
+               $result= "0";
+       }
+       
+       return $result;
+  }
+
+  /* sets Broken-Connection value: disconnect/reset */
+  function setBrokenConn ($checked) 
+  {
+       $flag= substr($this->ctx['CtxCfgFlags1'], 5, 1);
+       
+       if ($checked) {
+               $flag|= 4;
+       } else {
+               $flag&= 0xFB;
+       }
+       
+       $this->ctx['CtxCfgFlags1'][5]= sprintf('%1X', $flag);
+  }
+
+  /* gets Reconnection value: from any client/from previous client only */
+  function getReConn ()
+  {
+       $flags= ord(substr($this->ctx['CtxCfgFlags1'], 5, 1));
+       if ($flags & 2) {
+               $result= "1";
+       } else {
+               $result= "0";   
+       }
+       
+       return $result;
+  }
+
+  /* sets Reconnection value: from any client/from previous client only */
+  function setReConn ($checked)
+  {
+       $flag= substr($this->ctx['CtxCfgFlags1'], 5, 1);
+       
+       if ($checked) {
+               $flag|= 2;
+       } else {
+               $flag&= 0xFD;
+       }
+       
+       $this->ctx['CtxCfgFlags1'][5]= sprintf('%1X', $flag);
+  }
+
+  /* gets Inherit-config-from-client value: enabled/disabled */
+  function getInheritMode ()
+  {
+       if (substr($this->ctx['CtxCfgFlags1'], 6, 1) == "1") {
+               $result= true;
+       } else {
+               $result= false;
+       }
+
+       return $result;
+  }
+
+  /* sets Inherit-config-from-client value: enabled/disabled */
+  function setInheritMode ($checked)
+  {
+       if ($checked) {
+               $this->ctx['CtxCfgFlags1'][6]= "1";
+       } else {
+               $this->ctx['CtxCfgFlags1'][6]= "0";
+       }
+  }
+
+  /* gets shadow value (enum): 0-4
+       0: disabled
+       1: input on, notify on
+       2: input on, notify off
+       3: input off, notify on
+       4: input off, notify off 
+  */
+  function getShadow ()
+  {
+       $result= substr($this->ctx['CtxCfgFlags1'], 1, 1);
+       return $result;
+  }
+
+  /* sets shadow value */
+  function setShadow ($checked, $value)
+  {
+       if ($checked) {
+               $this->ctx['CtxCfgFlags1'][1]= sprintf('%1X', $value);
+       }
+  }
+
+  /* gets connect-client-drive-at-logon value: enabled/disabled */
+  function getConnectClientDrives ()
+  {
+       $connections= hexdec(substr($this->ctx['CtxCfgFlags1'], 2, 1));
+       if ($connections & 8) {
+               $result= true;
+       } else {
+               $result= false;
+       }
+
+       return $result;
+  }
+
+  /* sets connect-client-drive-at-logon value: enabled/disabled */
+  function setConnectClientDrives ($checked)
+  {
+       $flag= hexdec(substr($this->ctx['CtxCfgFlags1'], 2, 1));
+       if ($checked) {
+               $flag|= 8;
+       } else {
+               $flag&= 0xF7;
+       }
+
+       $this->ctx['CtxCfgFlags1'][2]= sprintf('%1X', $flag);
+  }
+
+  /* gets connect-client-printers-at-logon value: enabled/disabled */
+  function getConnectClientPrinters ()
+  {
+       $connections= hexdec(substr($this->ctx['CtxCfgFlags1'], 2, 1));
+       if ($connections & 4) {
+               $result= true;
+       } else {
+               $result= false;
+       }
+       
+       return $result;
+  }
+
+  /* sets connect-client-printers-at-logon value: enabled/disabled */
+  function setConnectClientPrinters ($checked)
+  {
+       $flag= hexdec(substr($this->ctx['CtxCfgFlags1'], 2, 1));
+       
+       if ($checked) {
+               $flag|= 4;
+       } else {
+               $flag&= 0xFB;
+       }
+       
+       $this->ctx['CtxCfgFlags1'][2]= sprintf('%1X', $flag);
+  }
+
+  /* gets set-client-printer-to-default value: enabled/disabled */
+  function getDefaultPrinter ()
+  {
+       $connections= hexdec(substr($this->ctx['CtxCfgFlags1'], 2, 1));
+       if ($connections & 2) {
+               $result= true;
+       } else {
+               $result= false;
+       }
+
+       return $result;
+  }
+
+  /* sets set-client-printer-to-default value: enabled/disabled */
+  function setDefaultPrinter ($checked)
+  {
+       $flag= hexdec(substr($this->ctx['CtxCfgFlags1'], 2, 1));
+       
+       if ($checked) {
+               $flag|= 2;
+       } else {
+               $flag&= 0xFD;
+       }
+       
+       $this->ctx['CtxCfgFlags1'][2]= sprintf('%1X', $flag);
+  }
+
+  /* SMARTY: gets the checkbox state of "Connection" */
+  function getCtxMaxConnectionTimeF ()
+  {
+       // Connection Time is 0 if disabled
+       if (isset($this->ctx['CtxMaxConnectionTime']) && ($this->ctx['CtxMaxConnectionTime'] != 0)) {
+               $result= true;
+       } else {
+               $result= false;
+       }
+
+       return $result;
+  }
+
+  /* SMARTY: sets the checkbox "Connection" to unchecked */
+  function setCtxMaxConnectionTimeF ($checked)
+  {
+       if ($checked) {
+               unset ($this->ctx['CtxMaxConnectionTime']);
+       }
+  }
+
+  /* SMARTY: gets the checkbox state of "Disconnection" */
+  function getCtxMaxDisconnectionTimeF ()
+  {
+       // Connection Time is 0 if disabled
+       if (isset($this->ctx['CtxMaxDisconnectionTime']) && ($this->ctx['CtxMaxDisconnectionTime'] != 0)) {
+               $result= true;
+       } else {
+               $result= false;
+       }
+
+       return $result;
+  }
+
+  /* SMARTY: sets the checkbox "Disconnection" to unchecked */
+  function setCtxMaxDisconnectionTimeF ($checked)
+  {
+       if ($checked) {
+               unset ($this->ctx['CtxMaxDisconnectionTime']);
+       } 
+  }
+
+  /* SMARTY: gets the checkbox state of "Idle" */
+  function getCtxMaxIdleTimeF ()
+  {
+       // Connection Time is 0 if disabled
+       if (isset($this->ctx['CtxMaxIdleTime']) && ($this->ctx['CtxMaxIdleTime'] != 0)) {
+               $result= true;
+       } else {
+               $result= false;
+       }
+
+       return $result;
+  }
+
+  /* SMARTY: sets the checkbox "Idle" to unchecked */
+  function setCtxMaxIdleTimeF ($checked)
+  {
+       if ($checked) {
+               unset ($this->ctx['CtxMaxIdleTime']);
+       }
+  }
+
+}
+
+?>
diff --git a/include/class_sieve.inc b/include/class_sieve.inc
new file mode 100644 (file)
index 0000000..a2b62a3
--- /dev/null
@@ -0,0 +1,514 @@
+<?
+
+/*
+ * $Id: class_sieve.inc,v 1.1 2005/02/21 09:33:01 cajus Exp $ 
+ *
+ * Copyright 2001 Dan Ellis <danellis@rushmore.com>
+ *
+ * See the enclosed file COPYING for license information (GPL).  If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+// TODO before next release:   remove ::status() and dependencies
+
+
+define ("F_NO", 0);            
+define ("F_OK", 1);
+define ("F_DATA", 2);
+define ("F_HEAD", 3);
+
+define ("EC_NOT_LOGGED_IN", 0);
+define ("EC_QUOTA", 10);
+define ("EC_NOSCRIPTS", 20);
+define ("EC_UNKNOWN", 255);
+/*
+
+SIEVE-PHP.LIB VERSION 0.0.8
+
+(C) 2001 Dan Ellis.
+
+PLEASE READ THE README FILE FOR MORE INFORMATION.
+
+Basically, this is the first re-release.  Things are much better than before.
+
+Notes:
+This program/libary has bugs.
+       .       This was quickly hacked out, so please let me know what is wrong and if you feel ambitious submit
+               a patch :).
+
+Todo:
+       .       Provide better error diagnostics.                       (mostly done with ver 0.0.5)
+       .       Allow other auth mechanisms besides plain               (in progress)
+       .       Have timing mechanism when port problems arise.         (not done yet)
+       .       Maybe add the NOOP function.                            (not done yet)
+       .       Other top secret stuff....                              (some done, believe me?)
+
+Dan Ellis (danellis@rushmore.com)
+
+This program is released under the GNU Public License.
+
+You should have received a copy of the GNU Public
+ License along with this package; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.        
+
+See CHANGES for updates since last release
+
+Contributers of patches:
+       Atif Ghaffar
+       Andrew Sterling Hanenkamp <sterling@hanenkamp.com>
+*/
+
+
+class sieve
+{
+  var $host;
+  var $port;
+  var $user;
+  var $pass;
+  var $auth_types;             /* a comma seperated list of allowed auth types, in order of preference */
+  var $auth_in_use;            /* type of authentication attempted */
+  
+  var $line;
+  var $fp;
+  var $retval;
+  var $tmpfile;
+  var $fh;
+  var $len;
+  var $script;
+
+  var $loggedin;
+  var $capabilities;
+  var $error;
+  var $error_raw;
+  var $responses;
+
+  //maybe we should add an errorlvl that the user will pass to new sieve = sieve(,,,,E_WARN)
+  //so we can decide how to handle certain errors?!?
+
+  //also add a connection type, like PLAIN, MD5, etc...
+
+
+  function get_response()
+  {
+    if($this->loggedin == false or feof($this->fp)){
+        $this->error = EC_NOT_LOGGED_IN;
+        $this->error_raw = "You are not logged in.";
+        return false;
+    }
+
+    unset($this->response);
+    unset($this->error);
+    unset($this->error_raw);
+
+    $this->line=fgets($this->fp,1024);
+    $this->token = split(" ", $this->line, 2);
+
+    if($this->token[0] == "NO"){
+        /* we need to try and extract the error code from here.  There are two possibilites: one, that it will take the form of:
+           NO ("yyyyy") "zzzzzzz" or, two, NO {yyyyy} "zzzzzzzzzzz" */
+        $this->x = 0;
+        list($this->ltoken, $this->mtoken, $this->rtoken) = split(" ", $this->line." ", 3);
+        if($this->mtoken[0] == "{"){
+            while($this->mtoken[$this->x] != "}" or $this->err_len < 1){
+                $this->err_len = substr($this->mtoken, 1, $this->x);
+                $this->x++;    
+            }
+            //print "<br>Trying to receive $this->err_len bytes for result<br>";
+            $this->line = fgets($this->fp,$this->err_len);
+            $this->error_raw[]=substr($this->line, 0, strlen($this->line) -2);    //we want to be nice and strip crlf's
+            $this->err_recv = strlen($this->line);
+
+            while($this->err_recv < $this->err_len){
+                //print "<br>Trying to receive ".($this->err_len-$this->err_recv)." bytes for result<br>";
+                $this->line = fgets($this->fp, ($this->err_len-$this->err_recv));
+                $this->error_raw[]=substr($this->line, 0, strlen($this->line) -2);    //we want to be nice and strip crlf's
+                $this->err_recv += strlen($this->line);
+            } /* end while */
+            $this->line = fgets($this->fp, 1024);      //we need to grab the last crlf, i think.  this may be a bug...
+            $this->error=EC_UNKNOWN;
+      
+        } /* end if */
+        elseif($this->mtoken[0] == "("){
+            switch($this->mtoken){
+                case "(\"QUOTA\")":
+                    $this->error = EC_QUOTA;
+                    $this->error_raw=$this->rtoken;
+                    break;
+                default:
+                    $this->error = EC_UNKNOWN;
+                    $this->error_raw=$this->rtoken;
+                    break;
+            } /* end switch */
+        } /* end elseif */
+        else{
+            $this->error = EC_UNKNOWN;
+            $this->error_raw = $this->line;
+        }     
+        return false;
+
+    } /* end if */
+    elseif(substr($this->token[0],0,-2) == "OK"){
+         return true;
+    } /* end elseif */
+    elseif($this->token[0][0] == "{"){
+        
+        /* Unable wild assumption:  that the only function that gets here is the get_script(), doesn't really matter though */       
+
+        /* the first line is the len field {xx}, which we don't care about at this point */
+        $this->line = fgets($this->fp,1024);
+        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
+            $this->response[]=$this->line;
+            $this->line = fgets($this->fp, 1024);
+        }
+        if(substr($this->line,0,2) == "OK")
+            return true;
+        else
+            return false;
+    } /* end elseif */
+    elseif($this->token[0][0] == "\""){
+
+        /* I'm going under the _assumption_ that the only function that will get here is the listscripts().
+           I could very well be mistaken here, if I am, this part needs some rework */
+
+        $this->found_script=false;        
+
+        while(substr($this->line,0,2) != "OK" and substr($this->line,0,2) != "NO"){
+            $this->found_script=true;
+            list($this->ltoken, $this->rtoken) = explode(" ", $this->line." ",2);
+               //hmmm, a bug in php, if there is no space on explode line, a warning is generated...
+           
+            if(strcmp(rtrim($this->rtoken), "ACTIVE")==0){
+                $this->response["ACTIVE"] = substr(rtrim($this->ltoken),1,-1);  
+            }
+            else
+                $this->response[] = substr(rtrim($this->ltoken),1,-1);
+            $this->line = fgets($this->fp, 1024);
+        } /* end while */
+        
+        return true;
+        
+    } /* end elseif */
+    else{
+            $this->error = EC_UNKNOWN;
+            $this->error_raw = $this->line;
+            print "<b><i>UNKNOWN ERROR (Please report this line to danellis@rushmore.com to include in future releases): $this->line</i></b><br>";
+            return false;
+    } /* end else */   
+  } /* end get_response() */
+
+  function sieve($host, $port, $user, $pass, $auth="", $auth_types="PLAIN DIGEST-MD5")
+  {
+    $this->host=$host;
+    $this->port=$port;
+    $this->user=$user;
+    $this->pass=$pass;
+    if(!strcmp($auth, ""))             /* If there is no auth user, we deem the user itself to be the auth'd user */
+        $this->auth = $this->user;
+    else
+        $this->auth = $auth;
+    $this->auth_types=$auth_types;     /* Allowed authentication types */
+    $this->fp=0;
+    $this->line="";
+    $this->retval="";
+    $this->tmpfile="";
+    $this->fh=0;
+    $this->len=0;
+    $this->capabilities="";
+    $this->loggedin=false;
+    $this->error= "";
+    $this->error_raw="";
+  }
+
+  function parse_for_quotes($string)
+  {
+      /* This function tokenizes a line of input by quote marks and returns them as an array */
+
+      $start = -1;
+      $index = 0;
+
+      for($ptr = 0; $ptr < strlen($string); $ptr++){
+          if($string[$ptr] == '"' and $string[$ptr] != '\\'){
+              if($start == -1){
+                  $start = $ptr;
+              } /* end if */
+              else{
+                  $token[$index++] = substr($string, $start + 1, $ptr - $start - 1);
+                  $found = true;
+                  $start = -1;
+              } /* end else */
+
+          } /* end if */  
+
+      } /* end for */
+
+      if(isset($token))
+          return $token;
+      else
+          return false;
+  } /* end function */            
+
+  function status($string)
+  {
+      //this should probably be replaced by a smarter parser.
+
+      /*  Need to remove this and all dependencies from the class */
+
+      switch (substr($string, 0,2)){
+          case "NO":
+              return F_NO;             //there should be some function to extract the error code from this line
+                                       //NO ("quota") "You are oly allowed x number of scripts"
+              break;
+          case "OK":
+              return F_OK;
+              break;
+          default:
+              switch ($string[0]){
+                  case "{":
+                      //do parse here for {}'s  maybe modify parse_for_quotes to handle any parse delimiter?
+                      return F_HEAD;
+                      break;
+                  default:
+                      return F_DATA;
+                      break;
+              } /* end switch */
+        } /* end switch */
+  } /* end status() */
+
+  function sieve_login()
+  {
+
+    $this->fp=fsockopen($this->host,$this->port);
+    if($this->fp == false)
+        return false;
+    $this->line=fgets($this->fp,1024);
+
+    //Hack for older versions of Sieve Server.  They do not respond with the Cyrus v2. standard
+    //response.  They repsond as follows: "Cyrus timsieved v1.0.0" "SASL={PLAIN,........}"
+    //So, if we see IMLEMENTATION in the first line, then we are done.
+
+    if(ereg("IMPLEMENTATION",$this->line))
+    {
+      //we're on the Cyrus V2 sieve server
+      while(sieve::status($this->line) == F_DATA){
+
+          $this->item = sieve::parse_for_quotes($this->line);
+
+          if(strcmp($this->item[0], "IMPLEMENTATION") == 0)
+              $this->capabilities["implementation"] = $this->item[1];
+        
+          elseif(strcmp($this->item[0], "SIEVE") == 0 or strcmp($this->item[0], "SASL") == 0){
+
+              if(strcmp($this->item[0], "SIEVE") == 0)
+                  $this->cap_type="modules";
+              else
+                  $this->cap_type="auth";            
+
+              $this->modules = split(" ", $this->item[1]);
+              if(is_array($this->modules)){
+                  foreach($this->modules as $this->module)
+                      $this->capabilities[$this->cap_type][$this->module]=true;
+              } /* end if */
+              elseif(is_string($this->modules))
+                  $this->capabilites[$this->cap_type][$this->modules]=true;
+          }    
+          else{ 
+              $this->capabilities["unknown"][]=$this->line;
+          }    
+      $this->line=fgets($this->fp,1024);
+
+       }// end while
+    }
+    else
+    {
+        //we're on the older Cyrus V1. server  
+        //this version does not support module reporting.  We only have auth types.
+        $this->cap_type="auth";
+       
+        //break apart at the "Cyrus timsieve...." "SASL={......}"
+        $this->item = sieve::parse_for_quotes($this->line);
+
+        $this->capabilities["implementation"] = $this->item[0];
+
+        //we should have "SASL={..........}" now.  Break out the {xx,yyy,zzzz}
+        $this->modules = substr($this->item[1], strpos($this->item[1], "{"),strlen($this->item[1])-1);
+
+        //then split again at the ", " stuff.
+        $this->modules = split($this->modules, ", ");
+        //fill up our $this->modules property
+        if(is_array($this->modules)){
+            foreach($this->modules as $this->module)
+                $this->capabilities[$this->cap_type][$this->module]=true;
+        } /* end if */
+        elseif(is_string($this->modules))
+            $this->capabilites[$this->cap_type][$this->module]=true;
+    }
+
+
+
+
+    if(sieve::status($this->line) == F_NO){            //here we should do some returning of error codes?
+        $this->error=EC_UNKNOWN;
+        $this->error_raw = "Server not allowing connections.";
+        return false;
+    }
+
+    /* decision login to decide what type of authentication to use... */
+
+     /* Loop through each allowed authentication type and see if the server allows the type */
+     foreach(split(" ",$this->auth_types) as $auth_type)
+     {
+        if ($this->capabilities["auth"][$auth_type])
+        {
+            /* We found an auth type that is allowed. */
+            $this->auth_in_use = $auth_type;
+            break;
+        }
+     }
+    
+    /* Fill error message if no auth types are present */
+    if (!isset($this->capabilities["auth"])){
+        $this->error=EC_UNKNOWN;
+       $this->error_raw = "No authentication methods found - please check your sieve setup for missing sasl modules";
+       return false;
+    }
+
+     /* call our authentication program */  
+    return sieve::authenticate();
+
+  }
+
+  function sieve_logout()
+  {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp,"LOGOUT\r\n");
+    fclose($this->fp);
+    $this->loggedin=false;
+    return true;
+  }
+
+  function sieve_sendscript($scriptname, $script)
+  {
+    if($this->loggedin==false)
+        return false;
+    $this->script=stripslashes($script);
+    $len=strlen($this->script);
+    fputs($this->fp, "PUTSCRIPT \"$scriptname\" \{$len+}\r\n");
+    fputs($this->fp, "$this->script\r\n");
+  
+    return sieve::get_response();
+
+  }  
+  
+  //it appears the timsieved does not honor the NUMBER type.  see lex.c in timsieved src.
+  //don't expect this function to work yet.  I might have messed something up here, too.
+  function sieve_havespace($scriptname, $scriptsize)
+  {
+    if($this->loggedin==false)
+        return false;
+    fputs($this->fp, "HAVESPACE \"$scriptname\" $scriptsize\r\n");
+    return sieve::get_response();
+
+  }  
+
+  function sieve_setactivescript($scriptname)
+  {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "SETACTIVE \"$scriptname\"\r\n");   
+    return sieve::get_response();
+
+  }
+  
+  function sieve_getscript($scriptname)
+  {
+    unset($this->script);
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "GETSCRIPT \"$scriptname\"\r\n");
+    return sieve::get_response();
+   
+  }
+
+
+  function sieve_deletescript($scriptname)
+  {
+    if($this->loggedin==false)
+        return false;
+
+    fputs($this->fp, "DELETESCRIPT \"$scriptname\"\r\n");    
+
+    return sieve::get_response();
+  }
+
+  
+  function sieve_listscripts() 
+   { 
+     fputs($this->fp, "LISTSCRIPTS\r\n"); 
+     sieve::get_response();            //should always return true, even if there are no scripts...
+     if(isset($this->found_script) and $this->found_script)
+         return true;
+     else{
+         $this->error=EC_NOSCRIPTS;    //sieve::getresponse has no way of telling wether a script was found...
+         $this->error_raw="No scripts found for this account.";
+         return false;
+     }
+   }
+
+  function sieve_alive()
+  {
+      if(!isset($this->fp) or $this->fp==0){
+          $this->error = EC_NOT_LOGGED_IN;
+          return false;
+      }
+      elseif(feof($this->fp)){                 
+          $this->error = EC_NOT_LOGGED_IN;
+          return false;
+      }
+      else
+          return true;
+  }
+
+  function authenticate()
+  {
+
+    switch ($this->auth_in_use) {
+    
+        case "PLAIN":
+            $auth=base64_encode("$this->user\0$this->auth\0$this->pass");
+   
+            $this->len=strlen($auth);                  
+            fputs($this->fp, "AUTHENTICATE \"PLAIN\" \{$this->len+}\r\n");
+            fputs($this->fp, "$auth\r\n");
+
+            $this->line=fgets($this->fp,1024);         
+            while(sieve::status($this->line) == F_DATA)
+               $this->line=fgets($this->fp,1024);
+
+             if(sieve::status($this->line) == F_NO)
+               return false;
+             $this->loggedin=true;
+               return true;    
+             break;
+
+        default:
+            return false;
+            break;
+
+    }//end switch
+
+
+  }//end authenticate()
+
+
+}
+
+
+
+?>
diff --git a/include/class_tabs.inc b/include/class_tabs.inc
new file mode 100644 (file)
index 0000000..f94d985
--- /dev/null
@@ -0,0 +1,243 @@
+<?php
+/*
+  This code is part of GOsa (https://gosa.gonicus.de)
+  Copyright (C) 2003  Cajus Pollmeier
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+class tabs
+{
+  var $dn;
+  var $config;
+  var $acl;
+  var $is_template;
+
+  var $last= "";
+  var $current= "";
+  var $disabled= "";
+  var $by_name= array();
+  var $by_object= array();
+
+  function tabs($config, $data, $dn)
+  {
+       /* Save dn */
+       $this->dn= $dn;
+       $this->config= $config;
+
+       foreach ($data as $tab){
+               $this->by_name[$tab['CLASS']]= $tab['NAME'];
+               $this->by_object[$tab['CLASS']]= new $tab['CLASS']($this->config, $this->dn);
+               $this->by_object[$tab['CLASS']]->parent= &$this;
+
+               /* Initialize current */
+               if ($this->current == ""){
+                       $this->current= $tab['CLASS'];
+               }
+       }
+
+  }
+
+  function execute()
+  {
+       /* Rotate current to last */
+       $this->last= $this->current;
+
+       /* Look for pressed tab button */
+       foreach ($this->by_object as $class => $obj){
+               if (isset($_POST[$class]) || (isset($_POST['arg']) && $_POST['arg'] == "$class")){
+                       $this->current= $class;
+                       break;
+               }
+       }
+
+       /* Save last tab object */
+       if ($this->last == $this->current){
+               $this->save_object(TRUE);
+       } else {
+               $this->save_object(FALSE);
+       }
+
+       /* Build tab line */
+       $display= $this->gen_tabs();
+
+       /* Show object */
+       $display.= "<table cellpadding=4 cellspacing=0 border=0 style=\"width:100%; background-color:#F0F0F0; border-style:solid; border-color:black; border-top-width:0px; border-bottom-width:1px; border-left-width:1px; border-right-width:1px;\">\n";
+       $display.= "<tr><td>\n";
+
+       $obj= $this->by_object[$this->current];
+       $display.= $obj->execute ();
+       $this->by_object[$this->current]= $obj;
+
+       /* Footer for tabbed dialog */
+       $display.= "</td></tr></table>";
+       return ($display);
+  }
+
+  function save_object($save_current= FALSE)
+  {
+       /* Save last tab */
+       if ($this->last != ""){
+               @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
+                       $this->last, "Saving");
+
+               $obj= $this->by_object[$this->last];
+               $obj->save_object ();
+               $this->by_object[$this->last]= $obj;
+       }
+
+       /* Skip if curent and last are the same object */
+       if ($this->last == $this->current){
+               return;
+       }
+
+       $obj= $this->by_object[$this->current];
+       $this->disabled= $obj->parent->disabled;
+
+       if ($save_current){
+               @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
+                       $this->current, "Saving (current)");
+
+               $obj->save_object ();
+               $this->by_object[$this->current]= $obj;
+       }
+
+  }
+
+  function gen_tabs()
+  {
+       $display= "<input type=\"hidden\" name=\"arg\" value=\"\">";
+       $display.= "<table cellpadding=0 cellspacing=0 border=0 style=\"width:100%;\"><tr>";
+       $index= 0;
+       $style= array("tab_left", "tab_active", "tab_near_active", "tab_right");
+       foreach ($this->by_name as $class => $name){
+
+               /* Activate right tabs with style "tab_right"
+                  Activate near current with style "tab_near_active" */
+               if ($index == 2 || $index == 1){
+                       $index++;
+               }
+
+               /* Activate current tab with style "tab_active " */
+               if ($class == $this->current){
+                       $index++;
+               }
+
+               /* Paint tab */
+               $display.= "<td style=\"vertical-align:bottom; width:100px;\">";
+               if ($_SESSION['js']==FALSE){    
+                       $display.= "<div class=\"$style[$index]\"><input type=\"submit\" name=\"$class\"".
+                                  " class=\"$style[$index]\" value=\""._($name)."\"";
+               } else {                         
+                       $display.= "<div class=\"$style[$index]\"><a class=\"$style[$index]\" onclick=\"return true;\" href=\"javascript:document.mainform.arg.value='$class';document.mainform.submit();\">"._($name)."</a";
+               }
+               $display.= "></div></td>";
+       }
+       $display.= "<td style=\"vertical-align:bottom;\">\n";
+       $display.= "<div class=\"tab_border\">&nbsp;</div></td></tr></table>";
+
+       return($display);
+  }
+
+
+  function set_acl($acl)
+  {
+       /* Set local acl */
+       $this->acl= $acl;
+
+       /* Setup for all plugins */
+       foreach ($this->by_object as $key => $obj){
+               $sacl= get_module_permission($acl, "$key", $this->dn);
+               $obj->acl= $sacl;
+               $this->by_object[$key]= $obj;
+       }
+  }
+
+  function delete()
+  {
+       /* Delete for all plugins */
+       foreach (array_reverse($this->by_object) as $key => $obj){
+               $obj->remove_from_parent();
+       }
+  }
+
+  function password_change_needed()
+  {
+       /* Ask all plugins for needed password changes */
+       foreach ($this->by_object as $key => $obj){
+               if ($obj->password_change_needed()){
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+  }
+
+  function check($ignore_account= FALSE)
+  {
+       $this->save_object(TRUE);
+       $messages= array();
+
+       /* Check all plugins */
+       foreach ($this->by_object as $key => $obj){
+               if ($obj->is_account || $ignore_account || $obj->ignore_account){
+                       @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
+                               $key, "Checking");
+
+                       $messages= $obj->check();
+                       if (count($messages)){
+                               $this->current= $key;
+                               break;
+                       }
+               }
+       }
+
+       return ($messages);
+  }
+
+  function save($ignore_account= FALSE)
+  {
+       /* Save all plugins */
+       foreach ($this->by_object as $key => $obj){
+               @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
+                       $key, "Saving");
+
+               $obj->dn= $this->dn;
+               
+               if ($obj->is_account || $ignore_account || $obj->ignore_account){
+                       if ($obj->save() == 1){
+                               return (1);
+                       }
+               } else {
+                       $obj->remove_from_parent();
+               }
+       }
+       return (0);
+  }
+
+  function adapt_from_template($dn)
+  {
+         foreach ($this->by_object as $key => $obj){
+                 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
+                                 $key, "Adapting");
+                 $obj->parent= &$this;
+                 $obj->adapt_from_template($dn);
+                 $this->by_object[$key]= $obj;
+         }
+  }
+
+}
+
+?>
diff --git a/include/class_userinfo.inc b/include/class_userinfo.inc
new file mode 100644 (file)
index 0000000..337c398
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2003-2005  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+class userinfo
+{
+  var $dn;
+  var $ip;
+  var $username;
+  var $cn;
+  var $config;
+  var $subtreeACL= array();
+
+  /* get acl's an put them into the userinfo object
+     attr subtreeACL (userdn:components, userdn:component1#sub1#sub2,component2,...) */
+  function userinfo($config, $userdn){
+    $this->config= $config;
+    $ldap= $this->config->get_ldap_link();
+    $ldap->cat($userdn);
+    $attrs= $ldap->fetch();
+
+    if (isset($attrs['givenName'][0]) && isset($attrs['sn'][0])){
+      $this->cn= $attrs['givenName'][0]." ".$attrs['sn'][0];
+    } else {
+      $this->cn= $attrs['uid'][0];
+    }
+
+    $this->dn= $userdn;
+    $this->ip= $_SERVER['REMOTE_ADDR'];
+  }
+
+
+  function loadACL()
+  {
+    $ldap= $this->config->get_ldap_link();
+
+    /* Load ACL's from all groups we're in */
+    $this->subtreeACL= array();
+    $ldap->cd($this->config->current['BASE']);
+    $ldap->search("(&(objectClass=posixGroup)(objectClass=gosaObject)".
+        "(|(memberUid=$this->username)(cn=$this->username)))");
+
+    while($attrs = $ldap->fetch()){
+      $base= preg_replace('/^[^,]+,ou=[^,]+,/i', "",$ldap->getDN());
+      $base= preg_replace("/[ ]*,[ ]*/", ",", $base);
+
+      for ($i= 0; $i<$attrs["gosaSubtreeACL"]["count"]; $i++){
+        $this->subtreeACL[$base][]= $attrs["gosaSubtreeACL"][$i];
+      }
+    }
+  }
+
+}
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/debuglib.inc b/include/debuglib.inc
new file mode 100644 (file)
index 0000000..9fd5d8b
--- /dev/null
@@ -0,0 +1,418 @@
+<?php
+/************************************************ 
+** Title.........: Debug Lib
+** Version.......: 0.5.4
+** Author........: Thomas Schüßler <tulpe@atomar.de> 
+** Filename......: debuglib.php(s)
+** Last changed..: 16. July 2003
+** License.......: Free to use. Postcardware ;)
+**
+*************************************************
+** 
+** Functions in this library:
+** 
+** print_a( array array [,int mode] )
+**   prints arrays in a readable, understandable form.
+**   if mode is defined the function returns the output instead of
+**   printing it to the browser
+**   
+**   
+** show_vars([int mode])
+**   use this function on the bottom of your script to see all
+**   superglobals and global variables in your script in a nice
+**   formated way
+**   
+**   show_vars() without parameter shows $_GET, $_POST, $_SESSION,
+**   $_FILES and all global variables you've defined in your script
+**
+**   show_vars(1) shows $_SERVER and $_ENV in addition
+**
+**   
+**   
+** print_result( result_handle )
+**   prints a mysql_result set returned by mysql_query() as a table
+**   this function is work in progress! use at your own risk
+**
+**
+**
+**
+** Happy debugging and feel free to email me your comments.
+**
+**
+**
+** History: (starting with version 0.5.3 at 2003-02-24)
+**
+**   - added tooltips to the td's showing the type of keys and values (thanks Itomic)
+** 2003-07-16
+**   - pre() function now trims trailing tabs
+************************************************/
+
+
+# This file must be the first include on your page.
+
+/* used for tracking of generation-time */
+{
+       $MICROTIME_START = microtime();
+       @$GLOBALS_initial_count = count($GLOBALS);
+}
+       
+/************************************************ 
+** print_a class and helper function
+** prints out an array in a more readable way
+** than print_r()
+**
+** based on the print_a() function from
+** Stephan Pirson (Saibot)
+************************************************/
+
+class Print_a_class {
+       
+       # this can be changed to FALSE if you don't like the fancy string formatting
+       var $look_for_leading_tabs = TRUE;
+
+       var $output;
+       var $iterations;
+       var $key_bg_color = '1E32C8';
+       var $value_bg_color = 'DDDDEE';
+       var $fontsize = '8pt';
+       var $keyalign = 'center';
+       var $fontfamily = 'Verdana';
+       var $export_flag;
+       var $show_object_vars;
+       var $export_dumper_path = 'http://tools.www.mdc.xmc.de/print_a_dumper/print_a_dumper.php';
+       # i'm still working on the dumper! don't use it now
+       # put the next line into the print_a_dumper.php file (optional)
+       # print htmlspecialchars( stripslashes ( $_POST['array'] ) );  
+       var $export_hash;
+               
+       function Print_a_class() {
+               $this->export_hash = uniqid('');
+       }
+       
+       # recursive function!
+       function print_a($array, $iteration = FALSE, $key_bg_color = FALSE) {
+               $key_bg_color or $key_bg_color = $this->key_bg_color;
+               
+                       # if print_a() was called with a fourth parameter (1 or 2)
+                       # and you click on the table a window opens with only the output of print_a() in it
+                       # 1 = serialized array
+                       # 2 = normal print_a() display
+                       
+                       /* put the following code on the page defined with $export_dumper_path;
+                       --->%---- snip --->%----
+                       
+                               if($_GET['mode'] == 1) {
+                                       print htmlspecialchars( stripslashes ( $_POST['array'] ) );
+                               } elseif($_GET['mode'] == 2) {
+                                       print_a(unserialize( stripslashes($_POST['array'])) );
+                               }
+
+                       ---%<---- snip ---%<----
+                       */
+                       
+               if( !$iteration && isset($this->export_flag) ) {
+                       $this->output .= '<form id="pa_form_'.$this->export_hash.'" action="'.$this->export_dumper_path.'?mode='.$this->export_flag.'" method="post" target="_blank"><input name="array" type="hidden" value="'.htmlspecialchars( serialize( $array ) ).'"></form>';
+               }
+               
+               # lighten up the background color for the key td's =)
+               if( $iteration ) {
+                       for($i=0; $i<6; $i+=2) {
+                               $c = substr( $key_bg_color, $i, 2 );
+                               $c = hexdec( $c );
+                               ( $c += 15 ) > 255 and $c = 255;
+                               isset($tmp_key_bg_color) or $tmp_key_bg_color = '';
+                               $tmp_key_bg_color .= sprintf( "%02X", $c );
+                       }
+                       $key_bg_color = $tmp_key_bg_color;
+               }
+               
+               # build a single table ... may be nested
+               $this->output .= '<table style="border:none;" cellspacing="1" '.( !$iteration && $this->export_flag ? 'onClick="document.getElementById(\'pa_form_'.$this->export_hash.'\').submit();" )' : '' ).'>';
+               foreach( $array as $key => $value ) {
+                       
+                       $value_style = 'color:black;';
+                       $key_style = 'color:white;';
+                       
+                       $type = gettype( $value );
+                       # print $type.'<br />';
+                       
+                       # change the color and format of the value
+                       switch( $type ) {
+                               case 'array':
+                                       break;
+                               
+                               case 'object':
+                                       $key_style = 'color:#FF9B2F;';
+                                       break;
+                               
+                               case 'integer':
+                                       $value_style = 'color:green;';
+                                       break;
+                               
+                               case 'double':
+                                       $value_style = 'color:red;';
+                                       break;
+                               
+                               case 'bool':
+                                       $value_style = 'color:blue;';
+                                       break;
+                                       
+                               case 'resource':
+                                       $value_style = 'color:darkblue;';
+                                       break;
+                               
+                               case 'string':
+                                       if( $this->look_for_leading_tabs && preg_match('/^\t/m', $value) ) {
+                                               $search = array('/\t/', "/\n/");
+                                               $replace = array('&nbsp;&nbsp;&nbsp;','<br />');
+                                               $value = preg_replace( $search, $replace, htmlspecialchars( $value ) );
+                                               $value_style = 'color:black;border:1px gray dotted;';
+                                       } else {
+                                               $value_style = 'color:black;';
+                                               $value = nl2br( htmlspecialchars( $value ) );
+                                       }
+                                       break;
+                       }
+
+                       $this->output .= '<tr>';
+                       $this->output .= '<td nowrap align="'.$this->keyalign.'" style="background-color:#'.$key_bg_color.';'.$key_style.';font:bold '.$this->fontsize.' '.$this->fontfamily.';" title="'.gettype( $key ).'['.$type.']">';
+                       $this->output .= $key;
+                       $this->output .= '</td>';
+                       $this->output .= '<td nowrap="nowrap" style="background-color:#'.$this->value_bg_color.';font: '.$this->fontsize.' '.$this->fontfamily.'; color:black;">';
+
+                       
+                       # value output
+                       if($type == 'array') {
+                               $this->print_a( $value, TRUE, $key_bg_color );
+                       } elseif($type == 'object') {
+                               if( $this->show_object_vars ) {
+                                       $this->print_a( get_object_vars( $value ), TRUE, $key_bg_color );
+                               } else {
+                                       $this->output .= '<div style="'.$value_style.'">OBJECT</div>';
+                               }
+                       } else {
+                               $this->output .= '<div style="'.$value_style.'" title="'.$type.'">'.$value.'</div>';
+                       }
+                       
+                       $this->output .= '</td>';
+                       $this->output .= '</tr>';
+               }
+               $this->output .= '</table>';
+       }
+}
+
+# helper function.. calls print_a() inside the print_a_class
+function print_a( $array, $return_mode = FALSE, $show_object_vars = FALSE, $export_flag = FALSE ) {
+       $e= error_reporting (0);        
+       if( is_array( $array ) or is_object( $array ) ) {
+               $pa = new Print_a_class;
+               $show_object_vars and $pa->show_object_vars = TRUE;
+               $export_flag and $pa->export_flag = $export_flag;
+               
+               $pa->print_a( $array );
+               
+               # $output = $pa->output; unset($pa);
+               $output = &$pa->output;
+       } else {
+               $output = '<span style="color:red;font-size:small;">print_a( '.gettype( $array ).' )</span>';
+       }
+       
+       error_reporting ($e);   
+       if($return_mode) {
+               return $output;
+       } else {
+               print $output;
+               return TRUE;
+       }
+}
+
+
+// shows mysql-result as a table.. # not ready yet :(
+function print_result($RESULT) {
+       
+       if(!$RESULT) return;
+       
+       $fieldcount = mysql_num_fields($RESULT);
+       
+       for($i=0; $i<$fieldcount; $i++) {
+               $tables[mysql_field_table($RESULT, $i)]++;
+       }
+       
+       print '
+               <style type="text/css">
+                       .rs_tb_th {
+                               font-family: Verdana;
+                               font-size:9pt;
+                               font-weight:bold;
+                               color:white;
+                       }
+                       .rs_f_th {
+                               font-family:Verdana;
+                               font-size:7pt;
+                               font-weight:bold;
+                               color:white;
+                       }
+                       .rs_td {
+                               font-family:Verdana;
+                               font-size:7pt;
+                       }
+               </style>
+               <script type="text/javascript" language="JavaScript">
+                       var lastID;
+                       function highlight(id) {
+                               if(lastID) {
+                                       lastID.style.color = "#000000";
+                                       lastID.style.textDecoration = "none";
+                               }
+                               tdToHighlight = document.getElementById(id);
+                               tdToHighlight.style.color ="#FF0000";
+                               tdToHighlight.style.textDecoration = "underline";
+                               lastID = tdToHighlight;
+                       }
+               </script>
+       ';
+
+       print '<table border="0" bgcolor="#000000" cellspacing="1" cellpadding="1">';
+       
+       print '<tr>';
+       foreach($tables as $tableName => $tableCount) {
+               $col == '0054A6' ? $col = '003471' : $col = '0054A6';
+               print '<th colspan="'.$tableCount.'" class="rs_tb_th" style="background-color:#'.$col.';">'.$tableName.'</th>';
+       }
+       print '</tr>';
+       
+       print '<tr>';
+       for($i=0;$i < mysql_num_fields($RESULT);$i++) {
+               $FIELD = mysql_field_name($RESULT, $i);
+               $col == '0054A6' ? $col = '003471' : $col = '0054A6';
+               print '<td align="center" bgcolor="#'.$col.'" class="rs_f_th">'.$FIELD.'</td>';
+       }
+       print '</tr>';
+
+       mysql_data_seek($RESULT, 0);
+
+       while($DB_ROW = mysql_fetch_array($RESULT, MYSQL_NUM)) {
+               $pointer++;
+               if($toggle) {
+                       $col1 = "E6E6E6";
+                       $col2 = "DADADA";
+               } else {
+                       $col1 = "E1F0FF";
+                       $col2 = "DAE8F7";
+               }
+               $toggle = !$toggle;
+               print '<tr id="ROW'.$pointer.'" onMouseDown="highlight(\'ROW'.$pointer.'\');">';
+               foreach($DB_ROW as $value) {
+                       $col == $col1 ? $col = $col2 : $col = $col1;
+                       print '<td valign="top" bgcolor="#'.$col.'" class="rs_td" nowrap>'.nl2br($value).'</td>';
+               }
+               print '</tr>';
+       }
+       print '</table>';
+       mysql_data_seek($RESULT, 0);
+}
+
+function _script_globals() {
+       global $GLOBALS_initial_count;
+
+       $varcount = 0;
+
+       foreach($GLOBALS as $GLOBALS_current_key => $GLOBALS_current_value) {
+               if(++$varcount > $GLOBALS_initial_count) {
+                       /* die wollen wir nicht! */
+                       if ($GLOBALS_current_key != 'HTTP_SESSION_VARS' && $GLOBALS_current_key != '_SESSION') {
+                               $script_GLOBALS[$GLOBALS_current_key] = $GLOBALS_current_value;
+                       }
+               }
+       }
+       
+       unset($script_GLOBALS['GLOBALS_initial_count']);
+       return $script_GLOBALS;
+}
+
+function show_runtime() {
+       $MICROTIME_END          = microtime();
+       $MICROTIME_START        = explode(' ', $GLOBALS['MICROTIME_START']);
+       $MICROTIME_END          = explode(' ', $MICROTIME_END);
+       $GENERATIONSEC          = $MICROTIME_END[1] - $MICROTIME_START[1];
+       $GENERATIONMSEC = $MICROTIME_END[0] - $MICROTIME_START[0];
+       $GENERATIONTIME = substr($GENERATIONSEC + $GENERATIONMSEC, 0, 8);
+       
+       return '<span style="color:red;font-weight:normal;font-size:9px;">(runtime: '.$GENERATIONTIME.' sec)</span>';
+}
+
+
+######################
+# function shows all superglobals and script defined global variables
+# show_vars() without the first parameter shows all superglobals except $_ENV and $_SERVER
+# show_vars(1) shows all
+# show_vars(,1) shows object properties in addition
+#
+function show_vars($show_all_vars = FALSE, $show_object_vars = FALSE) {
+       if(isset($GLOBALS['no_vars'])) return;
+       
+       $script_globals = _script_globals();
+       print '
+               <style type="text/css">
+               .vars-container {
+                       font-family: Verdana, Arial, Helvetica, Geneva, Swiss, SunSans-Regular, sans-serif;
+                       font-size: 8pt;
+                       padding:5px;
+               }
+               .varsname {
+                       font-weight:bold;
+               }
+               </style>
+       ';
+
+       print '<br />
+               <div style="border-style:dotted;border-width:1px;padding:2px;font-family:Verdana;font-size:10pt;font-weight:bold;">
+               DEBUG '.show_runtime().'
+       ';
+
+       $vars_arr['script_globals'] = array('global script variables', '#7ACCC8');
+       $vars_arr['_GET'] = array('$_GET', '#7DA7D9');
+       $vars_arr['_POST'] = array('$_POST', '#F49AC1');
+       $vars_arr['_FILES'] = array('$_POST FILES', '#82CA9C');
+       $vars_arr['_SESSION'] = array('$_SESSION', '#FCDB26');
+       $vars_arr['_COOKIE'] = array('$_COOKIE', '#A67C52');
+
+       if($show_all_vars) {
+               $vars_arr['_SERVER'] =  array('SERVER', '#A186BE');
+               $vars_arr['_ENV'] =  array('ENV', '#7ACCC8');
+       }
+
+       foreach($vars_arr as $vars_name => $vars_data) {
+               if($vars_name != 'script_globals') global $$vars_name;
+               if($$vars_name) {
+                       print '<div class="vars-container" style="background-color:'.$vars_data[1].';"><span class="varsname">'.$vars_data[0].'</span><br />';
+                       print_a($$vars_name, FALSE, $show_object_vars, FALSE );
+                       print '</div>';
+               }
+       }
+       print '</div>';
+}
+
+
+######################
+# function prints sql strings
+#
+function pre($sql_string, $simple_mode = FALSE) {
+       
+       if(!$simple_mode) {
+               # erste leere Zeile im SQL löschen
+               $sql_string = preg_replace('/\^s+/m','', $sql_string);
+               # letze leere Zeile im SQL löschen
+               $sql_string = preg_replace('/\s+$/m','', $sql_string);
+               
+               # kleinste Anzahl von führenden TABS zählen
+               preg_match_all('/^\t+/m', $sql_string, $matches);
+               $minTabCount = strlen(min($matches[0]));
+               
+               # und entfernen
+               $sql_string = preg_replace('/^\t{'.$minTabCount.'}/m', '', $sql_string);
+       }
+                       
+       print '<pre>'.$sql_string.'</pre>';
+}
+?>
diff --git a/include/functions.inc b/include/functions.inc
new file mode 100644 (file)
index 0000000..5493624
--- /dev/null
@@ -0,0 +1,1499 @@
+<?php
+/*
+ * This code is part of GOsa (https://gosa.gonicus.de)
+ * Copyright (C) 2003  Cajus Pollmeier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Configuration file location */
+define ("CONFIG_DIR", "/etc/gosa");
+define ("CONFIG_TEMPLATE_DIR", "../contrib/");
+
+/* Include required files */
+require_once ("class_ldap.inc");
+require_once ("class_config.inc");
+require_once ("class_userinfo.inc");
+require_once ("class_plugin.inc");
+require_once ("class_pluglist.inc");
+require_once ("class_tabs.inc");
+require_once ("class_mail-methods.inc");
+require_once("class_password-methods.inc");
+require_once ("debuglib.inc");
+
+/* Define constants for debugging */
+define ("DEBUG_TRACE",   1);
+define ("DEBUG_LDAP",    2);
+define ("DEBUG_MYSQL",   4);
+define ("DEBUG_SHELL",   8);
+define ("DEBUG_POST",   16);
+define ("DEBUG_SESSION",32);
+define ("DEBUG_CONFIG", 64);
+
+/* Rewrite german 'umlauts' and spanish 'accents'
+   to get better results */
+$REWRITE= array( "ä" => "ae",
+    "ö" => "oe",
+    "ü" => "ue",
+    "Ä" => "Ae",
+    "Ö" => "Oe",
+    "Ü" => "Ue",
+    "ß" => "ss",
+    "á" => "a",
+    "é" => "e",
+    "í" => "i",
+    "ó" => "o",
+    "ú" => "u",
+    "Á" => "A",
+    "É" => "E",
+    "Í" => "I",
+    "Ó" => "O",
+    "Ú" => "U",
+    "ñ" => "ny",
+    "Ñ" => "Ny" );
+
+
+/* Function to include all class_ files starting at a
+   given directory base */
+function get_dir_list($folder= ".")
+{
+  $currdir=getcwd();
+  if ($folder){
+    chdir("$folder");
+  }
+
+  $dh = opendir(".");
+  while(false !== ($file = readdir($dh))){
+
+    /* Recurse through all "common" directories */
+    if(is_dir($file) && $file!="." && $file!=".." && $file!="CVS"){
+      get_dir_list($file);
+      continue;
+    }
+
+    /* Include existing class_ files */
+    if (!is_dir($file) && preg_match("/^class_.*\.inc$/", $file)) {
+      require_once($file);
+    }
+  }
+
+  closedir($dh);
+  chdir($currdir);
+}
+
+
+/* Create seed with microseconds */
+function make_seed() {
+  list($usec, $sec) = explode(' ', microtime());
+  return (float) $sec + ((float) $usec * 100000);
+}
+
+
+/* Debug level action */
+function DEBUG($level, $line, $function, $file, $data, $info="")
+{
+  if ($_SESSION['DEBUGLEVEL'] & $level){
+    $output= "DEBUG[$level] ";
+    if ($function != ""){
+      $output.= "($file:$function():$line) - $info: ";
+    } else {
+      $output.= "($file:$line) - $info: ";
+    }
+    echo $output;
+    if (is_array($data)){
+      print_a($data);
+    } else {
+      echo "'$data'";
+    }
+    echo "<br>";
+  }
+}
+
+
+/* Simple function to get browser language and convert it to
+   xx_XY needed by locales. Ignores sublanguages and weights. */
+function get_browser_language()
+{
+  global $BASE_DIR;
+
+  /* Get list of languages */
+  if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){
+    $lang= preg_replace("/\s+/", "", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
+    $languages= split (',', $lang);
+    $languages[]= "C";
+  } else {
+    $languages= array("C");
+  }
+
+  /* Walk through languages and get first supported */
+  foreach ($languages as $val){
+
+    /* Strip off weight */
+    $lang= preg_replace("/;q=.*$/i", "", $val);
+
+    /* Simplify sub language handling */
+    $lang= preg_replace("/-.*$/", "", $lang);
+
+    /* Cancel loop if available in GOsa, or the last
+       entry has been reached */
+    if (is_dir("$BASE_DIR/locale/$lang")){
+      break;
+    }
+  }
+
+  return (strtolower($lang)."_".strtoupper($lang));
+}
+
+
+/* Rewrite ui object to another dn */
+function change_ui_dn($dn, $newdn)
+{
+  $ui= $_SESSION['ui'];
+  if ($ui->dn == $dn){
+    $ui->dn= $newdn;
+    $_SESSION['ui']= $ui;
+  }
+}
+
+
+/* Return theme path for specified file */
+function get_template_path($filename= '', $plugin= FALSE, $path= "")
+{
+  global $config, $BASE_DIR;
+
+  if (!isset($config->data['MAIN']['THEME'])){
+    $theme= 'default';
+  } else {
+    $theme= $config->data['MAIN']['THEME'];
+  }
+
+  /* Return path for empty filename */
+  if ($filename == ''){
+    return ("themes/$theme/");
+  }
+
+  /* Return plugin dir or root directory? */
+  if ($plugin){
+    if ($path == ""){
+      $nf= preg_replace("!^".$BASE_DIR."/!", "", $_SESSION['plugin_dir']);
+    } else {
+      $nf= preg_replace("!^".$BASE_DIR."/!", "", $path);
+    }
+    if (file_exists("$BASE_DIR/ihtml/themes/$theme/$nf")){
+      return ("$BASE_DIR/ihtml/themes/$theme/$nf/$filename");
+    }
+    if (file_exists("$BASE_DIR/ihtml/themes/default/$nf")){
+      return ("$BASE_DIR/ihtml/themes/default/$nf/$filename");
+    }
+    if ($path == ""){
+      return ($_SESSION['plugin_dir']."/$filename");
+    } else {
+      return ($path."/$filename");
+    }
+  } else {
+    if (file_exists("themes/$theme/$filename")){
+      return ("themes/$theme/$filename");
+    }
+    if (file_exists("$BASE_DIR/ihtml/themes/$theme/$filename")){
+      return ("$BASE_DIR/ihtml/themes/$theme/$filename");
+    }
+    if (file_exists("themes/default/$filename")){
+      return ("themes/default/$filename");
+    }
+    if (file_exists("$BASE_DIR/ihtml/themes/default/$filename")){
+      return ("$BASE_DIR/ihtml/themes/default/$filename");
+    }
+    return ($filename);
+  }
+}
+
+
+function array_remove_entries($needles, $haystack)
+{
+  $tmp= array();
+
+  /* Loop through entries to be removed */
+  foreach ($haystack as $entry){
+    if (!in_array($entry, $needles)){
+      $tmp[]= $entry;
+    }
+  }
+
+  return ($tmp);
+}
+
+
+function gosa_log ($message)
+{
+  global $ui;
+
+  /* Preset to something reasonable */
+  $username= " unauthenticated";
+
+  /* Replace username if object is present */
+  if (isset($ui)){
+    if ($ui->username != ""){
+      $username= "[$ui->username]";
+    } else {
+      $username= "unknown";
+    }
+  }
+
+  syslog(LOG_WARNING,"GOsa$username: $message");
+}
+
+
+function ldap_init ($server, $base, $binddn='', $pass='')
+{
+  global $config;
+
+  $ldap = new LDAP ($binddn, $pass, $server, isset($config->current['RECURSIVE'])                                                && $config->current['RECURSIVE'] == "true",
+      isset($config->current['TLS']) && $config->current['TLS'] == "true");
+
+  /* Sadly we've no proper return values here. Use the error message instead. */
+  if (!preg_match("/Success/i", $ldap->error)){
+    print_red(sprintf(_("Error when connecting the LDAP. Server said '%s'."),
+          $ldap->get_error()));
+    echo $_SESSION['errors'];
+
+    /* Hard error. We'd like to use the LDAP, anyway... */
+    exit;
+  }
+
+  /* Preset connection base to $base and return to caller */
+  $ldap->cd ($base);
+  return $ldap;
+}
+
+
+function ldap_login_user ($username, $password)
+{
+  global $config;
+
+  /* look through the entire ldap */
+  $ldap = $config->get_ldap_link();
+  if (!preg_match("/Success/i", $ldap->error)){
+    print_red(sprintf(_("User login failed. LDAP server said '%s'."), $ldap->get_error()));
+    echo $_SESSION['errors'];
+    exit;
+  }
+  $ldap->cd($config->current['BASE']);
+  $ldap->search("(&(uid=$username)(objectClass=gosaAccount))", array("uid"));
+
+  /* get results, only a count of 1 is valid */
+  switch ($ldap->count()){
+
+    /* user not found */
+    case 0:    return (NULL);
+            break;
+
+            /* valid uniq user */
+    case 1: 
+            break;
+
+            /* found more than one matching id */
+    default:
+            print_red(_("Username / UID is not unique. Please check your LDAP database."));
+            return (NULL);
+  }
+
+  /* LDAP schema is not case sensitive. Perform additional check. */
+  $attrs= $ldap->fetch();
+  if ($attrs['uid'][0] != $username){
+    return(NULL);
+  }
+
+  /* got user dn, fill acl's */
+  $ui= new userinfo($config, $ldap->getDN());
+  $ui->username= $username;
+
+  /* password check, bind as user with supplied password  */
+  $ldap->disconnect();
+  $ldap= new LDAP($ui->dn, $password, $config->current['SERVER'],
+      isset($config->current['RECURSIVE']) &&
+      $config->current['RECURSIVE'] == "true",
+      isset($config->current['TLS'])
+      && $config->current['TLS'] == "true");
+  if (!preg_match("/Success/i", $ldap->error)){
+    return (NULL);
+  }
+
+  /* Username is set, load subtreeACL's now */
+  $ui->loadACL();
+
+  return ($ui);
+}
+
+
+function add_lock ($object, $user)
+{
+  global $config;
+
+  /* Just a sanity check... */
+  if ($object == "" || $user == ""){
+    print_red(_("Error while adding a lock. Parameters are not set correctly, please check the source!"));
+    return;
+  }
+
+  /* Check for existing entries in lock area */
+  $ldap= $config->get_ldap_link();
+  $ldap->cd ($config->current['CONFIG']);
+  $ldap->search("(&(objectClass=gosaLockEntry)(gosaUser=$user)(gosaObject=$object))",
+      array("gosaUser"));
+  if (!preg_match("/Success/i", $ldap->error)){
+    print_red (sprintf(_("Can't set locking information in LDAP database. Please check the 'config' entry in gosa.conf! LDAP server says '%s'."), $ldap->get_error()));
+    return;
+  }
+
+  /* Add lock if none present */
+  if ($ldap->count() == 0){
+    $attrs= array();
+    $name= md5($object);
+    $ldap->cd("cn=$name,".$config->current['CONFIG']);
+    $attrs["objectClass"] = "gosaLockEntry";
+    $attrs["gosaUser"] = $user;
+    $attrs["gosaObject"] = $object;
+    $attrs["cn"] = "$name";
+    $ldap->add($attrs);
+    if (!preg_match("/Success/i", $ldap->error)){
+      print_red(sprintf(_("Adding a lock failed. LDAP server says '%s'."),
+            $ldap->get_error()));
+      return;
+    }
+  }
+}
+
+
+function del_lock ($object)
+{
+  global $config;
+
+  /* Sanity check */
+  if ($object == ""){
+    return;
+  }
+
+  /* Check for existance and remove the entry */
+  $ldap= $config->get_ldap_link();
+  $ldap->cd ($config->current['CONFIG']);
+  $ldap->search ("(&(objectClass=gosaLockEntry)(gosaObject=$object))", array("gosaObject"));
+  $attrs= $ldap->fetch();
+  if ($ldap->getDN() != "" && preg_match("/Success/i", $ldap->error)){
+    $ldap->rmdir ($ldap->getDN());
+
+    if (!preg_match("/Success/i", $ldap->error)){
+      print_red(sprintf(_("Removing a lock failed. LDAP server says '%s'."),
+            $ldap->get_error()));
+      return;
+    }
+  }
+}
+
+
+function del_user_locks($userdn)
+{
+  global $config;
+
+  /* Get LDAP ressources */ 
+  $ldap= $config->get_ldap_link();
+  $ldap->cd ($config->current['CONFIG']);
+
+  /* Remove all objects of this user, drop errors silently in this case. */
+  $ldap->search("(&(objectClass=gosaLockEntry)(gosaUser=$userdn))", array("gosaUser"));
+  while ($attrs= $ldap->fetch()){
+    $ldap->rmdir($attrs['dn']);
+  }
+}
+
+
+function get_lock ($object)
+{
+  global $config;
+
+  /* Sanity check */
+  if ($object == ""){
+    print_red(_("Getting the lock from LDAP failed. Parameters are not sed correctly, please check the source!"));
+    return("");
+  }
+
+  /* Get LDAP link, check for presence of the lock entry */
+  $user= "";
+  $ldap= $config->get_ldap_link();
+  $ldap->cd ($config->current['CONFIG']);
+  $ldap->search("(&(objectClass=gosaLockEntry)(gosaObject=$object))", array("gosaUser"));
+  if (!preg_match("/Success/i", $ldap->error)){
+    print_red (_("Can't get locking information in LDAP database. Please check the 'config' entry in gosa.conf!"));
+    return("");
+  }
+
+  /* Check for broken locking information in LDAP */
+  if ($ldap->count() > 1){
+
+    /* Hmm. We're removing broken LDAP information here and issue a warning. */
+    print_red(_("Found multiple locks for object to be locked. This should not be possible - cleaning up multiple references."));
+
+    /* Clean up these references now... */
+    while ($attrs= $ldap->fetch()){
+      $ldap->rmdir($attrs['dn']);
+    }
+
+    return("");
+
+  } elseif ($ldap->count() == 1){
+    $attrs = $ldap->fetch();
+    $user= $attrs['gosaUser'][0];
+  }
+
+  return ($user);
+}
+
+
+function get_list($subtreeACL, $filter, $subsearch= TRUE, $base="", $attrs= array(), $flag= FALSE)
+{
+  global $config;
+
+  /* Base the search on default base if not set */
+  $ldap= $config->get_ldap_link($flag);
+  if ($base == ""){
+    $ldap->cd ($config->current['BASE']);
+  } else {
+    $ldap->cd ($base);
+  }
+
+  /* Perform ONE or SUB scope searches? */
+  if ($subsearch) {
+    $ldap->search ($filter, $attrs);
+  } else {
+    $ldap->ls ($filter);
+  }
+
+  /* Check for size limit exceeded messages for GUI feedback */
+  if (preg_match("/size limit/i", $ldap->error)){
+    $_SESSION['limit_exceeded']= TRUE;
+  } else {
+    $_SESSION['limit_exceeded']= FALSE;
+  }
+
+  /* Crawl through reslut entries and perform the migration to the
+     result array */
+  $result= array();
+  while($attrs = $ldap->fetch()) {
+    $dn= preg_replace("/[ ]*,[ ]*/", ",", $ldap->getDN());
+    foreach ($subtreeACL as $key => $value){
+      if (preg_match("/$key/", $dn)){
+        $attrs["dn"]= $dn;
+        $result[]= $attrs;
+        break;
+      }
+    }
+  }
+
+  return ($result);
+}
+
+
+function check_sizelimit()
+{
+  /* Ignore dialog? */
+  if (isset($_SESSION['size_ignore']) && $_SESSION['size_ignore']){
+    return ("");
+  }
+
+  /* Eventually show dialog */
+  if (isset($_SESSION['limit_exceeded']) && $_SESSION['limit_exceeded']){
+    $smarty= get_smarty();
+    $smarty->assign('warning', sprintf(_("The size limit of %d entries is exceed!"),
+          $_SESSION['size_limit']));
+    $smarty->assign('limit_message', sprintf(_("Set the new size limit to %s and show me this message if the limit still exceeds"), '<input type="text" name="new_limit" maxlength="10" size="5" value="'.($_SESSION['size_limit']+100).'">'));
+    return($smarty->fetch(get_template_path('sizelimit.tpl')));
+  }
+
+  return ("");
+}
+
+
+function print_sizelimit_warning()
+{
+  if (isset($_SESSION['size_limit']) && $_SESSION['size_limit'] >= 10000000 ||
+      (isset($_SESSION['limit_exceeded']) && $_SESSION['limit_exceeded'])){
+    $config= "<input type='submit' name='edit_sizelimit' value="._("Configure").">";
+  } else {
+    $config= "";
+  }
+  if (isset($_SESSION['limit_exceeded']) && $_SESSION['limit_exceeded']){
+    return ("("._("incomplete").") $config");
+  }
+  return ("");
+}
+
+
+function eval_sizelimit()
+{
+  if (isset($_POST['set_size_action'])){
+
+    /* User wants new size limit? */
+    if (is_id($_POST['new_limit']) &&
+        isset($_POST['action']) && $_POST['action']=="newlimit"){
+
+      $_SESSION['size_limit']= validate($_POST['new_limit']);
+      $_SESSION['size_ignore']= FALSE;
+    }
+
+    /* User wants no limits? */
+    if (isset($_POST['action']) && $_POST['action']=="ignore"){
+      $_SESSION['size_limit']= 0;
+      $_SESSION['size_ignore']= TRUE;
+    }
+
+    /* User wants incomplete results */
+    if (isset($_POST['action']) && $_POST['action']=="limited"){
+      $_SESSION['size_ignore']= TRUE;
+    }
+  }
+
+  /* Allow fallback to dialog */
+  if (isset($_POST['edit_sizelimit'])){
+    $_SESSION['size_ignore']= FALSE;
+  }
+}
+
+
+function get_permissions ($dn, $subtreeACL)
+{
+  global $config;
+
+  $base= $config->current['BASE'];
+  $tmp= "d,".$dn;
+  $sacl= array();
+
+  /* Sort subacl's for lenght to simplify matching
+     for subtrees */
+  foreach ($subtreeACL as $key => $value){
+    $sacl[$key]= strlen($key);
+  }
+  arsort ($sacl);
+  reset ($sacl);
+
+  /* Successively remove leading parts of the dn's until
+     it doesn't contain commas anymore */
+  while (preg_match('/,/', $tmp)){
+    $tmp= ltrim(strstr($tmp, ","), ",");
+
+    /* Check for acl that may apply */
+    foreach ($sacl as $key => $value){
+      if (preg_match("/$key$/", $tmp)){
+        return ($subtreeACL[$key]);
+      }
+    }
+  }
+
+  return array("");
+}
+
+
+function get_module_permission($acl_array, $module, $dn)
+{
+  global $ui;
+
+  $final= "";
+  foreach($acl_array as $acl){
+
+    /* Check for selfflag (!) in ACL to determine if
+       the user is allowed to change parts of his/her
+       own account */
+    if (preg_match("/^!/", $acl)){
+      if ($dn != "" && $dn != $ui->dn){
+
+        /* No match for own DN, give up on this ACL */
+        continue;
+
+      } else {
+
+        /* Matches own DN, remove the selfflag */
+        $acl= preg_replace("/^!/", "", $acl);
+
+      }
+    }
+
+    /* Remove leading garbage */
+    $acl= preg_replace("/^:/", "", $acl);
+
+    /* Discover if we've access to the submodule by comparing
+       all allowed submodules specified in the ACL */
+    $tmp= split(",", $acl);
+    foreach ($tmp as $mod){
+      if (preg_match("/$module#/", $mod)){
+        $final= strstr($mod, "#")."#";
+        continue;
+      }
+      if (preg_match("/[^#]$module$/", $mod)){
+        return ("#all#");
+      }
+      if (preg_match("/^all$/", $mod)){
+        return ("#all#");
+      }
+    }
+  }
+
+  /* Return assembled ACL, or none */
+  if ($final != ""){
+    return (preg_replace('/##/', '#', $final));
+  }
+
+  /* Nothing matches - disable access for this object */
+  return ("#none#");
+}
+
+
+function get_userinfo()
+{
+  global $ui;
+
+  return $ui;
+}
+
+
+function get_smarty()
+{
+  global $smarty;
+
+  return $smarty;
+}
+
+
+function convert_department_dn($dn)
+{
+  $dep= "";
+
+  /* Build a sub-directory style list of the tree level
+     specified in $dn */
+  foreach (split (",", $dn) as $val){
+
+    /* We're only interested in organizational units... */
+    if (preg_match ("/ou=/", $val)){
+      $dep= preg_replace("/ou=([^,]+)/", "\\1", $val)."/$dep";
+    }
+
+    /* ... and location objects */
+    if (preg_match ("/l=/", $val)){
+      $dep= preg_replace("/l=([^,]+)/", "\\1", $val)."/$dep";
+    }
+  }
+
+  /* Return and remove accidently trailing slashes */
+  return rtrim($dep, "/");
+}
+
+
+function get_ou($name)
+{
+  global $config;
+
+  $ou= $config->current[$name];
+  if ($ou != ""){
+    if (!preg_match('/^[^=]+=[^=]+/', $ou)){
+      return "ou=$ou,";
+    } else {
+      return "$ou,";
+    }
+  } else {
+    return "";
+  }
+}
+
+
+function get_people_ou()
+{
+  return (get_ou("PEOPLE"));
+}
+
+
+function get_groups_ou()
+{
+  return (get_ou("GROUPS"));
+}
+
+
+function get_winstations_ou()
+{
+  return (get_ou("WINSTATIONS"));
+}
+
+
+function get_base_from_people($dn)
+{
+  global $config;
+
+  $pattern= "/^[^,]+,".preg_quote(get_people_ou())."/";
+  $base= preg_replace($pattern, '', $dn);
+
+  /* Set to base, if we're not on a correct subtree */
+  if (!isset($config->idepartments[$base])){
+    $base= $config->current['BASE'];
+  }
+
+  return ($base);
+}
+
+
+function get_departments($ignore_dn= "")
+{
+  global $config;
+
+  /* Initialize result hash */
+  $result= array();
+  $result['/']= $config->current['BASE'];
+
+  /* Get list of department objects */
+  $ldap= $config->get_ldap_link();
+  $ldap->cd ($config->current['BASE']);
+  $ldap->search ("(objectClass=gosaDepartment)", array("ou"));
+  while ($attrs= $ldap->fetch()){
+    $dn= $ldap->getDN();
+    if ($dn == $ignore_dn){
+      continue;
+    }
+    $result[convert_department_dn($dn)]= $dn;
+  }
+
+  return ($result);
+}
+
+
+function chkacl($acl, $name)
+{
+  /* Look for attribute in ACL */
+  if (preg_match("/#$name#/", $acl) || $acl == "#all#"){
+    return ("");
+  }
+
+  /* Optically disable html object for no match */
+  return (" disabled ");
+}
+
+
+function is_phone_nr($nr)
+{
+  if ($nr == ""){
+    return (TRUE);
+  }
+
+  return preg_match ("/^[0-9 ()+*-]+$/", $nr);
+}
+
+
+function is_url($url)
+{
+  if ($url == ""){
+    return (TRUE);
+  }
+
+  return preg_match ("/^(http|https):\/\/((?:[a-zA-Z0-9_-]+\.?)+):?(\d*)/", $url);
+}
+
+
+function is_dn($dn)
+{
+  if ($dn == ""){
+    return (TRUE);
+  }
+
+  return preg_match ("/^[a-z0-9 _-]+$/i", $dn);
+}
+
+
+function is_uid($uid)
+{
+  global $config;
+
+  if ($uid == ""){
+    return (TRUE);
+  }
+
+  /* STRICT adds spaces and case insenstivity to the uid check.
+     This is dangerous and should not be used. */
+  if (isset($config->current['STRICT']) && preg_match('/^no$/i', $config->current['STRICT'])){
+    return preg_match ("/^[a-z0-9 _.-]+$/i", $uid);
+  } else {
+    return preg_match ("/^[a-z0-9_-]+$/", $uid);
+  }
+}
+
+
+function is_id($id)
+{
+  if ($id == ""){
+    return (FALSE);
+  }
+
+  return preg_match ("/^[0-9]+$/", $id);
+}
+
+
+function is_path($path)
+{
+  if ($path == ""){
+    return (TRUE);
+  }
+  if (!preg_match('/^[a-z0-9%\/_.+-]+$/i', $path)){
+    return (FALSE);
+  }
+
+  return preg_match ("/\/.+$/", $path);
+}
+
+
+function is_email($address, $template= FALSE)
+{
+  if ($address == ""){
+    return (TRUE);
+  }
+  if ($template){
+    return preg_match ("/^[._a-z0-9%-]+@[_a-z0-9-]+(\.[a-z0-9-]+)(\.[a-z0-9-]+)*$/i",
+        $address);
+  } else {
+    return preg_match ("/^[._a-z0-9-]+@[_a-z0-9-]+(\.[a-z0-9i-]+)(\.[a-z0-9-]+)*$/i",
+        $address);
+  }
+}
+
+
+function print_red()
+{
+  /* Check number of arguments */
+  if (func_num_args() < 1){
+    return;
+  }
+
+  /* Get arguments, save string */
+  $array = func_get_args();
+  $string= $array[0];
+
+  /* Step through arguments */
+  for ($i= 1; $i<count($array); $i++){
+    $string= preg_replace ("/%s/", $array[$i], $string, 1);
+  }
+
+  /* If DEBUGLEVEL is set, we're in web mode, use textual output in
+     the other case... */
+  if (isset($_SESSION['DEBUGLEVEL'])){
+    $_SESSION['errors'].= "<div align=center style=\"border-width:5px;".
+      "border-style:solid;border-color:red; background-color:black;".
+      "margin-bottom:10px; padding:8px;\"><table><tr><td><img src=\"".
+      get_template_path('images/warning.png')."\"></td>".
+      "<td width=100% align=center><font color=#FFFFFF>".
+      "<b style='font-size:16px;'>$string</b></font></td><td>".
+      "<img src=\"".get_template_path('images/warning.png').
+      "\"></td></tr></table></div>\n";
+  } else {
+    echo "Error: $string\n";
+  }
+}
+
+
+function gen_locked_message($user, $dn)
+{
+  global $plug, $config;
+
+  $_SESSION['dn']= $dn;
+  $ldap= $config->get_ldap_link();
+  $ldap->cat ($user);
+  $attrs= $ldap->fetch();
+  $uid= $attrs["uid"][0];
+
+  /* Prepare and show template */
+  $smarty= get_smarty();
+  $smarty->assign ("dn", $dn);
+  $smarty->assign ("message", sprintf(_("You're going to edit the LDAP entry '%s' which appears to be used by '%s'. Please contact the person in order to clarify proceedings."), $dn, "<a href=main.php?plug=0&viewid=$uid>$uid</a>"));
+
+  return ($smarty->fetch (get_template_path('islocked.tpl')));
+}
+
+
+function to_string ($value)
+{
+  /* If this is an array, generate a text blob */
+  if (is_array($value)){
+    $ret= "";
+    foreach ($value as $line){
+      $ret.= $line."<br>\n";
+    }
+    return ($ret);
+  } else {
+    return ($value);
+  }
+}
+
+
+function get_printer_list($cups_server)
+{
+  global $config;
+
+  $res= array();
+
+  /* Use CUPS, if we've access to it */
+  if (function_exists('cups_get_dest_list')){
+    $dest_list= cups_get_dest_list ($cups_server);
+
+    foreach ($dest_list as $prt){
+      $attr= cups_get_printer_attributes ($cups_server, $prt->name);
+
+      foreach ($attr as $prt_info){
+        if ($prt_info->name == "printer-info"){
+          $info= $prt_info->value;
+          break;
+        }
+      }
+      $res[$prt->name]= "$info [$prt->name]";
+    }
+
+    /* CUPS is not available, try lpstat as a replacement */
+  } else {
+    unset ($ar);
+    exec("lpstat -p", $ar);
+    foreach($ar as $val){
+      list($dummy, $printer, $rest)= split(' ', $val, 3);
+      if (preg_match('/^[^@]+$/', $printer)){
+        $res[$printer]= "$printer";
+      }
+    }
+  }
+
+  /* Merge in printers from LDAP */
+  $ldap= $config->get_ldap_link();
+  $ldap->cd ($config->current['BASE']);
+  $ldap->search('(objectClass=gotoPrinter)', array('cn'));
+  while ($attrs= $ldap->fetch()){
+    $res[$attrs["cn"][0]]= $attrs["cn"][0];
+  }
+
+  return $res;
+}
+
+
+function sess_del ($var)
+{
+  /* New style */
+  unset ($_SESSION[$var]);
+
+  /* ... work around, since the first one
+     doesn't seem to work all the time */
+  session_unregister ($var);
+}
+
+
+function show_errors($message)
+{
+  $complete= "";
+
+  /* Assemble the message array to a plain string */
+  foreach ($message as $error){
+    if ($complete == ""){
+      $complete= $error;
+    } else {
+      $complete= "$error<br>$complete";
+    }
+  }
+
+  /* Fill ERROR variable with nice error dialog */
+  print_red($complete);
+}
+
+
+function show_ldap_error($message)
+{
+  if (!preg_match("/Success/i", $message)){
+    print_red (_("LDAP error:")." $message");
+    return TRUE;
+  } else {
+    return FALSE;
+  }
+}
+
+
+function rewrite($s)
+{
+  global $REWRITE;
+
+  foreach ($REWRITE as $key => $val){
+    $s= preg_replace("/$key/", "$val", $s);
+  }
+
+  return ($s);
+}
+
+
+function dn2base($dn)
+{
+  global $config;
+
+  if (get_people_ou() != ""){
+    $dn= preg_replace('/,'.get_people_ou().'/' , ',', $dn);
+  }
+  if (get_groups_ou() != ""){
+    $dn= preg_replace('/,'.get_groups_ou().'/' , ',', $dn);
+  }
+  $base= preg_replace ('/^[^,]+,/i', '', $dn);
+
+  return ($base);
+}
+
+
+
+function check_command($cmdline)
+{
+  $cmd= preg_replace("/ .*$/", "", $cmdline);
+
+  /* Check if command exists in filesystem */
+  if (!file_exists($cmd)){
+    return (FALSE);
+  }
+
+  /* Check if command is executable */
+  if (!is_executable($cmd)){
+    return (FALSE);
+  }
+
+  return (TRUE);
+}
+
+
+function print_header($image, $headline, $info= "")
+{
+  $display= "<div class=\"plugtop\">\n";
+  $display.= "  <img src=\"$image\" align=\"middle\" alt=\"*\">&nbsp;$headline\n";
+  $display.= "</div>\n";
+
+  if ($info != ""){
+    $display.= "<div class=\"pluginfo\">\n";
+    $display.= "$info";
+    $display.= "</div>\n";
+  } else {
+    $display.= "<div style=\"height:5px;\">\n";
+    $display.= "&nbsp;";
+    $display.= "</div>\n";
+  }
+
+  return ($display);
+}
+
+
+function register_global($name, $object)
+{
+  $_SESSION[$name]= $object;
+}
+
+
+function is_global($name)
+{
+  return isset($_SESSION[$name]);
+}
+
+
+function get_global($name)
+{
+  return $_SESSION[$name];
+}
+
+
+function range_selector($dcnt,$start,$range=25)
+{
+
+  /* Entries shown left and right from the selected entry */
+  $max_entries= 10;
+
+  /* Initialize and take care that max_entries is even */
+  $output="";
+  if ($max_entries & 1){
+    $max_entries++;
+  }
+
+  /* Prevent output to start or end out of range */
+  if ($start < 0 ){
+    $start= 0 ;
+  }
+  if ($start >= $dcnt){
+    $start= $range * (int)(($dcnt / $range) + 0.5);
+  }
+
+  $numpages= (($dcnt / $range));
+  if(((int)($numpages))!=($numpages))
+    $numpages = (int)$numpages + 1;
+  $ppage= (int)(($start / $range) + 0.5);
+
+
+  /* Align selected page to +/- max_entries/2 */
+  $begin= $ppage - $max_entries/2;
+  $end= $ppage + $max_entries/2;
+
+  /* Adjust begin/end, so that the selected value is somewhere in
+     the middle and the size is max_entries if possible */
+  if ($begin < 0){
+    $end-= $begin + 1;
+    $begin= 0;
+  }
+  if ($end > $numpages) {
+    $end= $numpages;
+  }
+  if (($end - $begin) < $max_entries && ($end - $max_entries) > 0){
+    $begin= $end - $max_entries;
+  }
+
+  /* Draw decrement */
+  if ($start > 0 ) {
+    $output.="  <a href= \"main.php?plug=".validate($_GET['plug'])."&start=".
+      (($start-$range))."\">".
+      "<img src=\"images/back.png\" border=0 align=\"center\"></a>";
+  }
+
+  /* Draw pages */
+  for ($i= $begin; $i < $end; $i++) {
+    if ($ppage == $i){
+      $output.= "<a style=\"background-color:#D0D0D0;\" href=\"main.php?plug=".
+        validate($_GET['plug'])."&start=".
+        ($i*$range)."\">&nbsp;".($i+1)."&nbsp;</a>";
+    } else {
+      $output.= "<a href=\"main.php?plug=".validate($_GET['plug']).
+        "&start=".($i*$range)."\">&nbsp;".($i+1)."&nbsp;</a>";
+    }
+  }
+
+  /* Draw increment */
+  if($start < ($dcnt-$range)) {
+    $output.="  <a href= \"main.php?plug=".validate($_GET['plug'])."&start=".
+      (($start+($range)))."\">".
+      "<img src=\"images/forward.png\" border=0 align=\"center\"></a>";
+  }
+
+  return($output);
+}
+
+
+function apply_filter()
+{
+  $apply= "";
+
+  $apply= '<p class="contentboxb" style="border-top:1px solid #B0B0B0">'.
+    '<table width="100%"><tr><td width="100%" align="right">'.
+    '<input type="submit" name="apply" value="'._("Apply").'"></td></tr></table></p>';
+
+  return ($apply);
+}
+
+
+function back_to_main()
+{
+  $string= '<br><p class="plugbottom"><input type=submit name="password_back" value="'.
+    _("Back").'"></p><input type="hidden" name="ignore">';
+
+  return ($string);
+}
+
+
+function normalize_netmask($netmask)
+{
+  /* Check for notation of netmask */
+  if (!preg_match('/^([0-9]+\.){3}[0-9]+$/', $netmask)){
+    $num= (int)($netmask);
+    $netmask= "";
+
+    for ($byte= 0; $byte<4; $byte++){
+      $result=0;
+
+      for ($i= 7; $i>=0; $i--){
+        if ($num-- > 0){
+          $result+= pow(2,$i);
+        }
+      }
+
+      $netmask.= $result.".";
+    }
+
+    return (preg_replace('/\.$/', '', $netmask));
+  }
+
+  return ($netmask);
+}
+
+
+function netmask_to_bits($netmask)
+{
+  list($nm0, $nm1, $nm2, $nm3)= split('\.', $netmask);
+  $res= 0;
+
+  for ($n= 0; $n<4; $n++){
+    $start= 255;
+    $name= "nm$n";
+
+    for ($i= 0; $i<8; $i++){
+      if ($start == (int)($$name)){
+        $res+= 8 - $i;
+        break;
+      }
+      $start-= pow(2,$i);
+    }
+  }
+
+  return ($res);
+}
+
+
+function recurse($rule, $variables)
+{
+  $result= array();
+
+  if (!count($variables)){
+    return array($rule);
+  }
+
+  reset($variables);
+  $key= key($variables);
+  $val= current($variables);
+  unset ($variables[$key]);
+
+  foreach($val as $possibility){
+    $nrule= preg_replace("/\{$key\}/", $possibility, $rule);
+    $result= array_merge($result, recurse($nrule, $variables));
+  }
+
+  return ($result);
+}
+
+
+function expand_id($rule, $attributes)
+{
+  /* Check for id rule */
+  if(preg_match('/^id(:|#)\d+$/',$rule)){
+    return (array("\{$rule}"));
+  }
+
+  /* Check for clean attribute */
+  if (preg_match('/^%[a-zA-Z0-9]+$/', $rule)){
+    $rule= preg_replace('/^%/', '', $rule);
+    $val= rewrite(preg_replace('/ /', '', strtolower($attributes[$rule])));
+    return (array($val));
+  }
+
+  /* Check for attribute with parameters */
+  if (preg_match('/^%[a-zA-Z0-9]+\[[0-9-]+\]$/', $rule)){
+    $param= preg_replace('/^[^[]+\[([^]]+)]$/', '\\1', $rule);
+    $part= preg_replace('/^%/', '', preg_replace('/\[.*$/', '', $rule));
+    $val= rewrite(preg_replace('/ /', '', strtolower($attributes[$part])));
+    $start= preg_replace ('/-.*$/', '', $param);
+    $stop = preg_replace ('/^[^-]+-/', '', $param);
+
+    /* Assemble results */
+    $result= array();
+    for ($i= $start; $i<= $stop; $i++){
+      $result[]= substr($val, 0, $i);
+    }
+    return ($result);
+  }
+
+  echo "Error in idgen string: don't know how to handle rule $rule.\n";
+  return (array($rule));
+}
+
+
+function gen_uids($rule, $attributes)
+{
+  global $config;
+
+  /* Search for keys and fill the variables array with all 
+     possible values for that key. */
+  $part= "";
+  $trigger= false;
+  $stripped= "";
+  $variables= array();
+
+  for ($pos= 0; $pos < strlen($rule); $pos++){
+
+    if ($rule[$pos] == "{" ){
+      $trigger= true;
+      $part= "";
+      continue;
+    }
+
+    if ($rule[$pos] == "}" ){
+      $variables[$pos]= expand_id($part, $attributes);
+      $stripped.= "\{$pos}";
+      $trigger= false;
+      continue;
+    }
+
+    if ($trigger){
+      $part.= $rule[$pos];
+    } else {
+      $stripped.= $rule[$pos];
+    }
+  }
+
+  /* Recurse through all possible combinations */
+  $proposed= recurse($stripped, $variables);
+
+  /* Get list of used ID's */
+  $used= array();
+  $ldap= $config->get_ldap_link();
+  $ldap->cd($config->current['BASE']);
+  $ldap->search('(uid=*)');
+
+  while($attrs= $ldap->fetch()){
+    $used[]= $attrs['uid'][0];
+  }
+
+  /* Remove used uids and watch out for id tags */
+  $ret= array();
+  foreach($proposed as $uid){
+
+    /* Check for id tag and modify uid if needed */
+    if(preg_match('/\{id:\d+}/',$uid)){
+      $size= preg_replace('/^.*{id:(\d+)}.*$/', '\\1', $uid);
+
+      for ($i= 0; $i < pow(10,$size); $i++){
+        $number= sprintf("%0".$size."d", $i);
+        $res= preg_replace('/{id:(\d+)}/', $number, $uid);
+        if (!in_array($res, $used)){
+          $uid= $res;
+          break;
+        }
+      }
+    }
+
+    if(preg_match('/\{id#\d+}/',$uid)){
+      $size= preg_replace('/^.*{id#(\d+)}.*$/', '\\1', $uid);
+
+      while (true){
+        mt_srand((double) microtime()*1000000);
+        $number= sprintf("%0".$size."d", mt_rand(0, pow(10, $size)-1));
+        $res= preg_replace('/{id#(\d+)}/', $number, $uid);
+        if (!in_array($res, $used)){
+          $uid= $res;
+          break;
+        }
+      }
+    }
+
+    /* Don't assign used ones */
+    if (!in_array($uid, $used)){
+      $ret[]= $uid;
+    }
+  }
+
+  return(array_unique($ret));
+}
+
+
+function array_search_r($needle, $key, $haystack){
+
+  foreach($haystack as $index => $value){
+    $match= 0;
+
+    if (is_array($value)){
+      $match= array_search_r($needle, $key, $value);
+    }
+
+    if ($index==$key && !is_array($value) && preg_match("/$needle/i", $value)){
+      $match=1;
+    }
+
+    if ($match){
+      return 1;
+    }
+  }
+
+  return 0;
+} 
+
+
+/* Sadly values like memory_limit are perpended by K, M, G, etc.
+   Need to convert... */
+function to_byte($value) {
+  $value= strtolower(trim($value));
+
+  if(!is_numeric(substr($value, -1))) {
+
+    switch(substr($value, -1)) {
+      case 'g':
+        $mult= 1073741824;
+        break;
+      case 'm':
+        $mult= 1048576;
+        break;
+      case 'k':
+        $mult= 1024;
+        break;
+    }
+
+    return ($mult * (int)substr($value, 0, -1));
+  } else {
+    return $value;
+  }
+}
+
+
+function in_array_ics($value, $items)
+{
+  foreach ($items as $item){
+    if (strtolower($item) == strtolower($value)) {
+      return (TRUE);
+    }
+  }
+
+  return (FALSE);
+} 
+
+
+function generate_alphabet($count= 10)
+{
+  $characters= _("*ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
+  $alphabet= "";
+  $c= 0;
+
+  /* Fill cells with charaters */
+  for ($i= 0; $i<mb_strlen($characters, 'UTF8'); $i++){
+    if ($c == 0){
+      $alphabet.= "<tr>";
+    }
+
+    $ch = mb_substr($characters, $i, 1, "UTF8");
+    $alphabet.= "<td><a class=\"alphaselect\" href=\"main.php?plug=".
+      validate($_GET['plug'])."&amp;search=".$ch."\">&nbsp;".$ch."&nbsp;</a></td>";
+
+    if ($c++ == $count){
+      $alphabet.= "</tr>";
+      $c= 0;
+    }
+  }
+
+  /* Fill remaining cells */
+  while ($c++ <= $count){
+    $alphabet.= "<td>&nbsp;</td>";
+  }
+
+  return ($alphabet);
+}
+
+
+function validate($string)
+{
+  return (strip_tags(preg_replace('/\0/', '', $string)));
+}
+
+
+
+  
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/functions_cli.inc b/include/functions_cli.inc
new file mode 100644 (file)
index 0000000..06b7621
--- /dev/null
@@ -0,0 +1,105 @@
+<?php
+
+function print_usage()
+{
+       echo "Usage: gosa command [options] <attributes>\n";
+       echo "Commands:\n";
+       echo "\tcreate\t\tCreates an object under 'entry dn', the content\n";
+       echo "\t\t\tand type is set by the -plugin option\n";
+       echo "\tdelete\t\tRemoves the either the entry given by 'entry dn',\n";
+       echo "\t\t\tor removes a property set by the -plugin option\n";
+       echo "\tlist\t\tLists either all objects, object types given by\n";
+       echo "\t\t\tthe -plugin option or a single object given by\n";
+       echo "\t\t\tthe 'entry dn'. Use -list to specify the list type\n";
+       echo "\tmodify\t\tModifies the entry given by 'entry dn' using\n";
+       echo "\t\t\tthe object type given by the -plugin option\n";
+       echo "Options:\n";
+       echo "\t--location=name\tChoose the LDAP profile to work on\n";
+       echo "\t--entry-dn=<dn>\tDN to perform actions on\n";
+       echo "\t--entry-id=<id>\tID to perform actions on. This option is more fuzzy\n";
+       echo "\t\t\tthan the -entry-dn one. It depends on the selected plugin\n";
+       echo "\t\t\tand can be i.e. an uid in case of the user plugin or a cn\n";
+       echo "\t\t\tin case of a group or department\n";
+       echo "\t--list=<type>\tSpecifys the detail of the list command. Possible\n";
+       echo "\t\t\tvalues are 'summary' and 'ldif'. The list command defaults\n";
+       echo "\t\t\tto 'summary'\n";
+       echo "\t--modifyer=<id>\tSet the name of the person who's performing changes\n";
+       echo "\t--plugin=<name>\tSelect plugin to work with, use 'list'\n";
+       echo "\t\t\tto get a list of available plugins. Every plguin\n";
+       echo "\t\t\trequires one or more attributes to be set. You can\n";
+       echo "\t\t\tget the list of attributes by using '<name>-help'\n";
+}
+
+
+function get_plugin_list($config)
+{
+        $plugins= array();
+        foreach($config->data['MENU'] as $plugin){
+                foreach ($plugin as $value){
+                        if (isset($value['CLASS'])){
+                               if (class_exists($value['CLASS'])){
+                                       $obj= new $value['CLASS']($config, 'new');
+                                       if (isset($obj->cli_summary)){
+                                               $plugins[$value['CLASS']]= $obj->cli_summary;
+                                       } else {
+                                               $plugins[$value['CLASS']]= "- no description -";
+                                       }
+                               }
+                        }
+                }
+        }
+        foreach($config->data['TABS'] as $plugin){
+                foreach ($plugin as $value){
+                        if (isset($value['CLASS'])){
+                               if (class_exists($value['CLASS'])){
+                                       $obj= new $value['CLASS']($config, 'new');
+                                       if (isset($obj->cli_summary)){
+                                               $plugins[$value['CLASS']]= $obj->cli_summary;
+                                       } else {
+                                               $plugins[$value['CLASS']]= "- no description -";
+                                       }
+                               }
+                        }
+                }
+        }
+        #ksort ($plugins);
+
+       return ($plugins);
+}
+
+
+function show_plugin_list($config)
+{
+        printf ("\t%-25s%s\n", "Plugin", "Description");
+       $plugins= get_plugin_list($config);
+        foreach ($plugins as $plugin => $description){
+                printf ("\t %-25s%s\n", $plugin, $description);
+        }
+}
+
+
+function show_plugin_help($plugin)
+{
+       global $config;
+
+       $plugins= get_plugin_list($config);
+       if (!class_exists($plugin)){
+               echo "Plugin '$plugin' does not exist\n";
+       } else {
+               $obj= new $plugin($config, 'new');
+               if (isset($obj->cli_summary)){
+                       echo $obj->cli_summary."\n\n";
+               }
+               if (isset($obj->cli_description)){
+                       echo $obj->cli_description."\n\n";
+               }
+               if (isset($obj->cli_parameters)){
+                       print_r ($obj->cli_parameters);
+               } else {
+                       echo "There's no parameter description for this plugin, sorry.\n";
+               }
+       }
+       
+}
+
+?>
diff --git a/include/php_setup.inc b/include/php_setup.inc
new file mode 100644 (file)
index 0000000..e74f4ee
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/*
+   This code is part of GOsa (https://gosa.gonicus.de)
+   Copyright (C) 2003  Cajus Pollmeier
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Get base dir for reference */
+$BASE_DIR= dirname(dirname(__FILE__));
+$ROOT_DIR= $BASE_DIR."/html";
+error_reporting (E_ALL);
+
+$variables_order= "ES";
+ini_set("register_globals",0);
+ini_set("track_vars",1);
+ini_set("include_path",".:$BASE_DIR/include");
+#ini_set("display_errors",0);
+
+/* Do smarty setup */
+require("smarty/Smarty.class.php");
+$smarty = new Smarty;
+$smarty->template_dir = $BASE_DIR.'/ihtml/';
+$smarty->caching= false;
+$smarty->php_handling= SMARTY_PHP_REMOVE;
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/scanner.inc b/include/scanner.inc
new file mode 100644 (file)
index 0000000..3ebf2a1
--- /dev/null
@@ -0,0 +1,533 @@
+abaton "Abaton" "Scan 300/GS" "SCSI"
+abaton "Abaton" "Scan 300/S" "SCSI"
+agfafocus "AGFA" "Focus GS Scanner" "SCSI"
+agfafocus "AGFA" "Focus Lineart Scanner" "SCSI"
+agfafocus "AGFA" "Focus II" "SCSI"
+agfafocus "AGFA" "Focus Color" "SCSI"
+agfafocus "AGFA" "Focus Color Plus" "SCSI"
+agfafocus "Siemens" "S9036" "SCSI"
+apple "Apple" "Apple Scanner" "SCSI"
+apple "Apple" "OneScanner" "SCSI"
+apple "Apple" "ColorOneScanner" "SCSI"
+artec "Artec/Ultima" "AT3" "SCSI"
+artec "Artec/Ultima" "A6000C" "SCSI"
+artec "Artec/Ultima" "A6000C PLUS" "SCSI"
+artec "Artec/Ultima" "AT6" "SCSI"
+artec "Artec/Ultima" "AT12" "SCSI"
+artec "Artec/Ultima" "AM12S" "SCSI"
+artec "BlackWidow" "BW4800SP" "SCSI"
+artec "Plustek" "OpticPro 19200S" "SCSI"
+artec_eplus48u "Artec" "E+ 48U" "USB"
+artec_eplus48u "Tevion" "MD9693" "USB"
+artec_eplus48u "Medion" "MD9693" "USB"
+artec_eplus48u "Medion" "MD9705" "USB"
+artec_eplus48u "Medion" "MD4394" "USB"
+artec_eplus48u "Trust" "Easy Webscan 19200" "USB"
+artec_eplus48u "Memorex" "Mem 48 u" "USB"
+as6e "Artec/Ultima" "AS6E" "Parport"
+avision "Avision" "AV100CS" "SCSI"
+avision "Avision" "AV100IIICS" "SCSI"
+avision "Avision" "AV100S" "SCSI"
+avision "Avision" "AV240SC" "SCSI"
+avision "Avision" "AV260CS" "SCSI"
+avision "Avision" "AV360CS" "SCSI"
+avision "Avision" "AV363CS" "SCSI"
+avision "Avision" "AV420CS" "SCSI"
+avision "Avision" "AV6120" "SCSI"
+avision "Avision" "AV620CS" "SCSI"
+avision "Avision" "AV620CS Plus" "SCSI"
+avision "Avision" "AV630CS" "SCSI"
+avision "Avision" "AV630CSL" "SCSI"
+avision "Avision" "AV6240" "SCSI"
+avision "Avision" "AV600U" "USB"
+avision "Avision" "AV660S" "USB"
+avision "Avision" "AV680S" "USB"
+avision "Avision" "AV690U" "USB"
+avision "Avision" "AV800S" "SCSI"
+avision "Avision" "AV810C" "SCSI"
+avision "Avision" "AV820" "SCSI"
+avision "Avision" "AV820C" "SCSI"
+avision "Avision" "AV820C Plus" "SCSI"
+avision "Avision" "AV830C" "SCSI"
+avision "Avision" "AV830C Plus" "SCSI"
+avision "Avision" "AV880" "SCSI"
+avision "Avision" "AV880C" "SCSI"
+avision "Avision" "AV8000S" "SCSI"
+avision "Avision" "AVA3" "SCSI"
+avision "Hewlett-Packard" "ScanJet 5300C" "USB"
+avision "Hewlett-Packard" "ScanJet 5370C" "USB"
+avision "Hewlett-Packard" "ScanJet 7400c" "USB"
+avision "Minolta" "FS-V1" "USB"
+avision "Mitsubishi" "MCA-ADFC" "SCSI"
+avision "Mitsubishi" "S1200C" "SCSI"
+avision "Mitsubishi" "S600C" "SCSI"
+avision "Mitsubishi" "SS600" "SCSI"
+avision "Fujitsu" "ScanPartner" "SCSI"
+avision "Fujitsu" "ScanPartner 10" "SCSI"
+avision "Fujitsu" "ScanPartner 10C" "SCSI"
+avision "Fujitsu" "ScanPartner 15C" "SCSI"
+avision "Fujitsu" "ScanPartner 300C" "SCSI"
+avision "Fujitsu" "ScanPartner 600C" "SCSI"
+avision "Fujitsu" "ScanPartner Jr" "SCSI"
+bh "Bell and Howell" "COPISCAN II 6338" "SCSI"
+bh "Bell and Howell" "COPISCAN II 2135" "SCSI"
+bh "Bell and Howell" "COPISCAN II 2137(A)" "SCSI"
+bh "Bell and Howell" "COPISCAN II 2138A" "SCSI"
+bh "Bell and Howell" "COPISCAN II 3238" "SCSI"
+bh "Bell and Howell" "COPISCAN II 3338(A)" "SCSI"
+canon "Canon" "CanoScan 300" "SCSI"
+canon "Canon" "CanoScan 600" "SCSI"
+canon "Canon" "CanoScan 620S" "SCSI"
+canon "Canon" "CanoScan 2700F" "SCSI"
+canon "Canon" "CanoScan 2710" "SCSI"
+canon630u "Canon" "CanoScan fb630u" "USB"
+canon630u "Canon" "CanoScan fb636u" "USB"
+canon_pp "Canon" "CanoScan FB310P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan FB610P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan FB320P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan FB620P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan FB330P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan FB630P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan N340P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan N640P" "Parport (ECP)"
+canon_pp "Canon" "CanoScan N640P ex" "Parport (ECP)"
+coolscan "Nikon" "LS-20" "SCSI"
+coolscan "Nikon" "LS-30" "SCSI"
+coolscan "Nikon" "LS-2000" "SCSI"
+coolscan "Nikon" "LS-1000" "SCSI"
+coolscan2 "Nikon" "LS 30" "SCSI"
+coolscan2 "Nikon" "LS 2000" "SCSI"
+coolscan2 "Nikon" "LS 40 ED" "USB"
+coolscan2 "Nikon" "LS 4000 ED" "IEEE1394"
+coolscan2 "Nikon" "LS 8000 ED" "IEEE1394"
+dc210 "Kodak" "DC210" "Serial port"
+dc240 "Kodak" "DC240" "Serial port"
+dc25 "Kodak" "DC25" "Serial port"
+dc25 "Kodak" "DC20" "Serial port"
+dmc "Polaroid" "DMC" "SCSI"
+epson "Epson" "GT-5000" "Parport"
+epson "Epson" "Actionscanner II" "Parport"
+epson "Epson" "GT-6000" "SCSI Parport"
+epson "Epson" "ES-300C" "SCSI Parport"
+epson "Epson" "GT-5500" "SCSI"
+epson "Epson" "GT-6500" "Parport"
+epson "Epson" "ES-600C" "Parport"
+epson "Epson" "ES-1200C" "Parport"
+epson "Epson" "GT-7000" "SCSI"
+epson "Epson" "GT-8000" "SCSI"
+epson "Epson" "ES-8500" "SCSI"
+epson "Epson" "Perfection 636S" "SCSI"
+epson "Epson" "Perfection 636U" "USB"
+epson "Epson" "Perfection 610" "USB"
+epson "Epson" "Perfection 640" "USB"
+epson "Epson" "Perfection 1200S" "SCSI"
+epson "Epson" "Perfection 1200U" "USB"
+epson "Epson" "Perfection 1200Photo" "USB"
+epson "Epson" "Perfection 1240" "SCSI USB"
+epson "Epson" "Perfection 1640" "SCSI USB"
+epson "Epson" "Perfection 1650" "USB"
+epson "Epson" "Perfection 1660" "USB"
+epson "Epson" "Perfection 2400" "USB"
+epson "Epson" "Perfection 2450" "USB IEEE-1394"
+epson "Epson" "Perfection 3200" "USB"
+epson "Epson" "Expression 636" "SCSI"
+epson "Epson" "Expression 800" "SCSI"
+epson "Epson" "Expression 1600" "SCSI USB IEEE-1394"
+epson "Epson" "Expression 1680" "SCSI USB IEEE-1394"
+epson "Epson" "FilmScan 200" "SCSI"
+epson "Epson" "CX-3200" "USB"
+epson "Epson" "CX-5200" "USB"
+fujitsu "Fujitsu" "M3096G" "SCSI"
+fujitsu "Fujitsu" "M3091DCd" "SCSI"
+fujitsu "Fujitsu" "M3092DCd" "SCSI"
+fujitsu "Fujitsu" "M3093GXim" "SCSI"
+fujitsu "Fujitsu" "M3093GDim" "SCSI"
+fujitsu "Fujitsu" "M4097" "SCSI"
+fujitsu "Fujitsu" "fi-4340C" "SCSI"
+gt68xx "Mustek" "BearPaw 1200 CS" "USB"
+gt68xx "Mustek" "BearPaw 1200 CU" "USB"
+gt68xx "Mustek" "BearPaw 1200 CU Plus" "USB"
+gt68xx "Mustek" "BearPaw 1200 TA" "USB"
+gt68xx "Mustek" "BearPaw 2400 CS" "USB"
+gt68xx "Mustek" "BearPaw 2400 CS Plus" "USB"
+gt68xx "Mustek" "BearPaw 2400 CU" "USB"
+gt68xx "Mustek" "BearPaw 2400 CU Plus" "USB"
+gt68xx "Mustek" "BearPaw 2400 TA" "USB"
+gt68xx "Mustek" "BearPaw 2400 TA Plus" "USB"
+gt68xx "Mustek" "ScanExpress 1200 UB Plus" "USB"
+gt68xx "Mustek" "ScanExpress A3 USB" "USB"
+gt68xx "Mustek" "ScanExpress 2400 USB" "USB"
+gt68xx "Plustek" "OpticPro 1248U" "USB"
+gt68xx "Plustek" "OpticPro UT16B" "USB"
+gt68xx "Artec" "Ultima 2000" "USB"
+gt68xx "Artec" "Ultima 2000 e+" "USB"
+gt68xx "Boeder" "Sm@rtScan Slim Edition" "USB"
+gt68xx "Packard Bell" "Diamond 1200" "USB"
+gt68xx "Medion/Lifetec/Tevion/Cytron" "LT 9452" "USB"
+gt68xx "Medion/Lifetec/Tevion/Cytron" "MD/LT 9375" "USB"
+gt68xx "Medion/Lifetec/Tevion/Cytron" "MD/LT 9385" "USB"
+gt68xx "Medion/Lifetec/Tevion/Cytron" "MD 9458" "USB"
+gt68xx "Trust" "Flat Scan USB 19200" "USB"
+gt68xx "Trust" "Compact Scan USB 19200" "USB"
+gt68xx "Lexmark" "X70" "USB"
+gt68xx "Lexmark" "X73" "USB"
+gt68xx "Genius" "Colorpage Vivid3x" "USB"
+hp "Hewlett-Packard" "ScanJet Plus" "Propietary"
+hp "Hewlett-Packard" "ScanJet IIc" "SCSI"
+hp "Hewlett-Packard" "ScanJet IIp" "SCSI"
+hp "Hewlett-Packard" "ScanJet IIcx" "SCSI"
+hp "Hewlett-Packard" "ScanJet 3c" "SCSI"
+hp "Hewlett-Packard" "ScanJet 3p" "SCSI"
+hp "Hewlett-Packard" "ScanJet 4c" "SCSI"
+hp "Hewlett-Packard" "ScanJet 4p" "SCSI"
+hp "Hewlett-Packard" "ScanJet 4100C" "USB"
+hp "Hewlett-Packard" "ScanJet 5p" "SCSI"
+hp "Hewlett-Packard" "ScanJet 5100C" "Parport"
+hp "Hewlett-Packard" "ScanJet 5200C" "Parport USB"
+hp "Hewlett-Packard" "ScanJet 6100C" "SCSI"
+hp "Hewlett-Packard" "ScanJet 6200C" "SCSI USB"
+hp "Hewlett-Packard" "ScanJet 6250C" "SCSI USB"
+hp "Hewlett-Packard" "ScanJet 6300C" "SCSI USB"
+hp "Hewlett-Packard" "ScanJet 6350C" "SCSI USB"
+hp "Hewlett-Packard" "ScanJet 6390C" "SCSI USB"
+hp "Hewlett-Packard" "PhotoSmart PhotoScanner" "SCSI"
+hpsj5s "Hewlett-Packard" "ScanJet 5s" "Parport (EPP)"
+leo "LEO" "LEOScan S3" "SCSI"
+leo "Across Technologies" "FS-1130" "SCSI"
+leo "Genius" "FS-1130 Colorpage Scanner" "SCSI"
+matsushita "Panasonic" "KV-SS25" "SCSI"
+matsushita "Panasonic" "KV-SS25D" "SCSI"
+matsushita "Panasonic" "KV-SS50" "SCSI"
+matsushita "Panasonic" "KV-SS55" "SCSI"
+matsushita "Panasonic" "KV-SS50EX" "SCSI"
+matsushita "Panasonic" "KV-SS55EX" "SCSI"
+matsushita "Panasonic" "KV-SS850" "SCSI"
+matsushita "Panasonic" "KV-SS855" "SCSI"
+microtek "Microtek" "Scanmaker E6" "SCSI"
+microtek "Microtek" "Scanmaker E3" "SCSI"
+microtek "Microtek" "Scanmaker E2" "SCSI"
+microtek "Microtek" "Scanmaker 35t+" "SCSI"
+microtek "Microtek" "Scanmaker 45t" "SCSI"
+microtek "Microtek" "Scanmaker 35" "SCSI"
+microtek "Microtek" "Scanmaker III" "SCSI"
+microtek "Microtek" "Scanmaker IISP" "SCSI"
+microtek "Microtek" "Scanmaker IIHR" "SCSI"
+microtek "Microtek" "Scanmaker IIG" "SCSI"
+microtek "Microtek" "Scanmaker II" "SCSI"
+microtek "Microtek" "Scanmaker 600Z(S)" "SCSI"
+microtek "Microtek" "Scanmaker 600G(S)" "SCSI"
+microtek "Microtek" "Color PageWiz" "SCSI (Parport)"
+microtek "Agfa" "Arcus II" "SCSI"
+microtek "Agfa" "StudioScan" "SCSI"
+microtek "Agfa" "StudioScan II" "SCSI"
+microtek "Agfa" "StudioScan IIsi" "SCSI"
+microtek "Agfa" "DuoScan" "SCSI"
+microtek2 "Microtek" "ScanMaker E3plus" "Parport"
+microtek2 "Microtek" "ScanMaker E3plus" "SCSI"
+microtek2 "Microtek" "ScanMaker X6" "SCSI"
+microtek2 "Microtek" "ScanMaker X6EL" "SCSI"
+microtek2 "Microtek" "ScanMaker X6USB" "USB"
+microtek2 "Microtek" "ScanMaker V300" "SCSI"
+microtek2 "Microtek" "ScanMaker V300" "Parport"
+microtek2 "Microtek" "ScanMaker V310" "SCSI"
+microtek2 "Microtek" "ScanMaker V310" "Parport"
+microtek2 "Microtek" "ScanMaker V600" "SCSI"
+microtek2 "Microtek" "ScanMaker V600" "Parport"
+microtek2 "Microtek" "ScanMaker 330" "SCSI"
+microtek2 "Microtek" "ScanMaker 630" "SCSI"
+microtek2 "Microtek" "ScanMaker 636" "SCSI"
+microtek2 "Microtek" "ScanMaker 9600XL" "SCSI"
+microtek2 "Microtek" "ScanMaker 9600XL" "SCSI"
+microtek2 "Microtek" "Phantom 330CX" "Parport"
+microtek2 "Microtek" "SlimScan C3" "Parport"
+microtek2 "Microtek" "Phantom 636" "SCSI"
+microtek2 "Microtek" "Phantom 636CX" "Parport"
+microtek2 "Microtek" "SlimScan C6" "USB"
+microtek2 "Microtek" "ScanMaker V6USL" "SCSI"
+microtek2 "Microtek" "ScanMaker V6USL" "USB"
+microtek2 "Microtek" "ScanMaker X12USL" "SCSI"
+microtek2 "Vobis" "HighScan" "SCSI"
+microtek2 "Scanport" "SQ300" "Parport?"
+microtek2 "Scanport" "SQ2030" "Parport"
+microtek2 "Scanport" "SQ4836" "SCSI"
+mustek "Mustek" "Paragon MFS-6000CX" "SCSI"
+mustek "Mustek" "Paragon MFS-12000CX" "SCSI"
+mustek "Mustek" "Paragon MFC-600S" "SCSI"
+mustek "Mustek" "Paragon 600 II CD" "SCSI"
+mustek "Mustek" "ScanMagic 600 II SP" "SCSI"
+mustek "Mustek" "Paragon MFC-800S" "SCSI"
+mustek "Mustek" "Paragon 800 II SP" "SCSI"
+mustek "Mustek" "Paragon MFS-6000SP" "SCSI"
+mustek "Mustek" "Paragon MFS-8000SP" "SCSI"
+mustek "Mustek" "Paragon MFS-1200SP" "SCSI"
+mustek "Mustek" "Paragon MFS-12000SP" "SCSI"
+mustek "Mustek" "ScanExpress 6000SP" "SCSI"
+mustek "Mustek" "ScanExpress 12000SP" "SCSI"
+mustek "Mustek" "ScanExpress 12000SP Plus" "SCSI"
+mustek "Mustek" "Paragon 1200 III SP" "SCSI"
+mustek "Mustek" "Paragon 1200 LS" "SCSI"
+mustek "Mustek" "ScanMagic 9636S" "SCSI"
+mustek "Mustek" "ScanMagic 9636S Plus" "SCSI"
+mustek "Mustek" "ScanExpress A3 SP" "SCSI"
+mustek "Mustek" "Paragon 1200 SP Pro" "SCSI"
+mustek "Mustek" "Paragon 1200 A3 Pro" "SCSI"
+mustek "Mustek" "Paragon 600 II N" "Proprietary"
+mustek "Trust" "Imagery 1200" "SCSI"
+mustek "Trust" "Imagery 1200 SP" "SCSI"
+mustek "Trust" "Imagery 4800 SP" "SCSI"
+mustek "Trust" "SCSI Connect 19200" "SCSI"
+mustek "Trust" "SCSI excellence series 19200" "SCSI"
+mustek "Primax" "Compact 4800 SCSI" "SCSI"
+mustek_pp "Mustek" "ScanExpress 6000 P" "Parport (EPP)"
+mustek_pp "Mustek" "ScanExpress 600 SEP" "Parport (EPP)"
+mustek_pp "Mustek" "ScanMagic 4800 P" "Parport (EPP)"
+mustek_pp "Mustek" "600 III EP Plus" "Parport (EPP)"
+mustek_pp "Mustek" "ScanExpress 600 CP" "Parport (EPP)"
+mustek_pp "Mustek" "ScanMagic 600 CP" "Parport (EPP)"
+mustek_pp "Mustek" "1200 CP" "Parport (EPP)"
+mustek_pp "Mustek" "1200 CP+" "Parport (EPP)"
+mustek_pp "Medion/Tevion/LifeTec" "MD 9848" "Parport (EPP)"
+mustek_pp "Medion/Tevion/LifeTec" "MD/LT 935x" "Parport (EPP)"
+mustek_pp "Medion/Tevion/LifeTec" "MD/LT 985x" "Parport (EPP)"
+mustek_pp "Medion/Tevion/LifeTec" "MD/LT 9890" "Parport (EPP)"
+mustek_pp "Targa" "Funline TS12 EP" "Parport (EPP)"
+mustek_pp "Targa" "Funline TS6 EP" "Parport (EPP)"
+mustek_pp "Trust Easy Connect" "9600+" "Parport (EPP)"
+mustek_pp "Viviscan" "Compact II" "Parport (EPP)"
+mustek_pp "Cybercom" "9352" "Parport (EPP)"
+mustek_pp "Gallery" "4800" "Parport (EPP)"
+mustek_usb "Mustek" "ScanExpress 600 CU" "USB"
+mustek_usb "Mustek" "ScanExpress 1200 CU" "USB"
+mustek_usb "Mustek" "ScanExpress 1200 CU Plus" "USB"
+mustek_usb "Mustek" "ScanExpress 1200 UB" "USB"
+mustek_usb "Trust" "Compact Scan USB 19200" "USB"
+nec "NEC" "PC-IN500/4C" "SCSI"
+pie "Devcom" "9636PRO" "SCSI"
+pie "Devcom" "9636S" "SCSI"
+pie "Devcom" "9630S" "SCSI"
+pie "PIE" "ScanAce 1236S" "SCSI"
+pie "PIE" "ScanAce 1230S" "SCSI"
+pie "PIE" "ScanAce II" "SCSI"
+pie "PIE" "ScanAce III" "SCSI"
+pie "PIE" "ScanAce Plus" "SCSI"
+pie "PIE" "ScanAce II Plus" "SCSI"
+pie "PIE" "ScanAce III Plus" "SCSI"
+pie "PIE" "ScanAce V" "SCSI"
+pie "PIE" "ScanAce ScanMedia" "SCSI"
+pie "PIE" "ScanAce ScanMedia II" "SCSI"
+pie "PIE" "ScanAce 630S" "SCSI"
+pie "PIE" "ScanAce 636S" "SCSI"
+pie "Adlib" "JetScan630" "SCSI"
+pie "Adlib" "JetScan636PRO" "SCSI"
+plustek "Plustek" "OpticPro 4800P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 4830P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 600P/6000P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 4831P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 9630P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 9630PL" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 9600P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 1236P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 12000P/96000P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 9636P" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 9636P+/Turbo" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 9636T" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro 12000T" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro AI3" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro P8" "Parport"
+plustek "Plustek" "OpticPro P12" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro PT12" "Parport (SPP, EPP)"
+plustek "Plustek" "OpticPro U12" "USB"
+plustek "Plustek" "OpticPro UT12" "USB"
+plustek "Plustek" "OpticPro UT16" "USB"
+plustek "Plustek" "OpticPro U24" "USB"
+plustek "Plustek" "OpticPro UT24" "USB"
+plustek "Plustek" "OpticPro 19200S" "SCSI"
+plustek "Primax" "Colorado 4800" "Parport (SPP, EPP)"
+plustek "Primax" "Compact 4800 Direct" "Parport (SPP, EPP)"
+plustek "Primax" "Compact 4800 Direct-30" "Parport (SPP, EPP)"
+plustek "Primax" "Compact 9600 Direct-30" "Parport (SPP, EPP)"
+plustek "Genius" "Colorpage Vivid III V2" "Parport (SPP, EPP)"
+plustek "Genius" "Colorpage Vivid Pro II Film" "Parport (SPP, EPP)"
+plustek "Genius" "Colorpage HR6 V2" "USB"
+plustek "Genius" "Colorpage HR7" "USB"
+plustek "Genius" "Colorpage HR6A" "USB"
+plustek "Genius" "Colorpage HR7LE" "USB"
+plustek "Genius" "Colorpage HR6X" "USB"
+plustek "Aries" "Scan-It Pro 4800" "Parport (SPP, EPP)"
+plustek "BrightScan" "BrighScan OpticPro" "Parport (SPP, EPP)"
+plustek "Mustek" "BearPaw 1200" "USB"
+plustek "Mustek" "BearPaw 2400" "USB"
+plustek "Hewlett-Packard" "ScanJet 2100C" "USB"
+plustek "Hewlett-Packard" "ScanJet 2200C" "USB"
+plustek "Epson" "Perfection 1250" "USB"
+plustek "Epson" "Perfection 1250Photo" "USB"
+plustek "Epson" "Perfection 1260" "USB"
+plustek "Epson" "Perfection 1260Photo" "USB"
+plustek "Umax" "UMAX 3400" "USB"
+plustek "Umax" "UMAX 5400" "USB"
+plustek "Canon" "CanoScan N650U/N656U" "USB"
+plustek "Canon" "CanoScan N1220U" "USB"
+plustek "Canon" "CanoScan N670U/N676U" "USB"
+plustek "Canon" "CanoScan N1240U" "USB"
+plustek "Canon" "CanoScan LiDE20" "USB"
+plustek "Canon" "CanoScan LiDE30" "USB"
+qcam "Connectix" "Color QuickCam" "Parport"
+qcam "Connectix" "Greyscale QuickCam" "Parport"
+ricoh "Ricoh" "Ricoh IS50" "SCSI"
+ricoh "Ricoh" "Ricoh IS60" "SCSI"
+s9036 "Siemens" "9036 Flatbed scanner" "SCSI"
+sceptre "Sceptre" "Vividscan S1200" "SCSI"
+sceptre "Komodo" "S1200" "SCSI"
+sharp "Sharp" "JX-610" "SCSI"
+sharp "Sharp" "JX-250" "SCSI"
+sharp "Sharp" "JX-320" "SCSI"
+sharp "Sharp" "JX-325" "SCSI"
+sharp "Sharp" "JX-330" "SCSI"
+sharp "Sharp" "JX-350" "SCSI"
+sm3600 "Microtek" "ScanMaker 3600" "USB"
+sm3600 "Microtek" "ScanMaker 3700" "USB"
+sm3600 "Microtek" "ScanMaker 3750" "USB"
+SnapScan "AGFA" "SnapScan 300" "SCSI"
+SnapScan "AGFA" "SnapScan 310" "SCSI"
+SnapScan "AGFA" "SnapScan 600" "SCSI"
+SnapScan "AGFA" "SnapScan 1236s" "SCSI"
+SnapScan "AGFA" "SnapScan 1236u" "USB"
+SnapScan "AGFA" "SnapScan 1212u" "USB"
+SnapScan "AGFA" "SnapScan e10" "USB"
+SnapScan "AGFA" "SnapScan e20" "USB"
+SnapScan "AGFA" "SnapScan e25" "USB"
+SnapScan "AGFA" "SnapScan e26" "USB"
+SnapScan "AGFA" "SnapScan e40" "USB"
+SnapScan "AGFA" "SnapScan e42" "USB"
+SnapScan "AGFA" "SnapScan e50" "USB"
+SnapScan "AGFA" "SnapScan e52" "USB"
+SnapScan "AGFA" "SnapScan e60" "USB"
+SnapScan "Benq" "300f" "SCSI"
+SnapScan "Benq" "310s" "SCSI"
+SnapScan "Benq" "610s" "SCSI"
+SnapScan "Benq" "610plus" "SCSI"
+SnapScan "Benq" "620s" "SCSI"
+SnapScan "Benq" "310u" "USB"
+SnapScan "Benq" "320u" "USB"
+SnapScan "Benq" "340u" "USB"
+SnapScan "Benq" "620u" "USB"
+SnapScan "Benq" "640u" "USB"
+SnapScan "Benq" "640bu" "USB"
+SnapScan "Benq" "1240" "USB"
+SnapScan "Benq" "3300" "USB"
+SnapScan "Benq" "4300" "USB"
+SnapScan "Benq" "5000" "USB"
+SnapScan "Benq" "5300" "USB"
+SnapScan "Guillemot / Hercules" "Maxi Scan A4 Deluxe (SCSI)" "SCSI"
+SnapScan "Guillemot / Hercules" "Scan@home Touch 1248 (USB)" "USB"
+SnapScan "Mitsubishi" "Diamondview 648UT" "USB"
+SnapScan "Mitsubishi" "Diamondview 650U" "USB"
+sp15c "Fujitsu" "SP15C" "SCSI"
+st400 "Siemens" "ST400" "SCSI"
+st400 "Siemens" "ST800" "SCSI"
+tamarack "Tamarack" "Artiscan 6000C" "SCSI"
+tamarack "Tamarack" "Artiscan 8000C" "SCSI"
+tamarack "Tamarack" "Artiscan 12000C" "SCSI"
+teco1 "Relisys" "RELI 2412" "SCSI"
+teco1 "Relisys" "AVEC 2400" "SCSI"
+teco1 "Relisys" "RELI 4830" "SCSI"
+teco1 "Relisys" "AVEC 2412" "SCSI"
+teco1 "Relisys" "AVEC 4800" "SCSI"
+teco1 "Relisys" "AVEC 4816" "SCSI"
+teco1 "Relisys" "RELI DS6" "SCSI"
+teco1 "Relisys" "RELI DS15" "SCSI"
+teco1 "Relisys" "RELI 2400" "SCSI"
+teco1 "Relisys" "RELI 4816" "SCSI"
+teco1 "Relisys" "RELI 9600" "SCSI"
+teco1 "Relisys" "RELI 9612" "SCSI"
+teco1 "Relisys" "RELI 9624" "SCSI"
+teco1 "Relisys" "RELI 9630" "SCSI"
+teco1 "Actown" "ACT Scan I 30" "SCSI"
+teco1 "Dextra" "DF-600P" "SCSI"
+teco1 "Dextra" "DF-1200T+" "SCSI"
+teco1 "Dextra" "DF-4830T" "SCSI"
+teco1 "Dextra" "DF-9624" "SCSI"
+teco2 "Relisys" "AVEC Super 3" "SCSI"
+teco2 "Relisys" "SCORPIO Super 3" "SCSI"
+teco2 "Relisys" "APOLLO Express 6" "SCSI"
+teco2 "Relisys" "SCORPIO Pro" "SCSI"
+teco2 "Relisys" "SCORPIO Pro-S" "SCSI"
+teco2 "Primax" "Profi 9600" "SCSI"
+teco2 "Primax" "Profi 19200" "SCSI"
+teco3 "Relisys" "Infinity Scorpio" "SCSI"
+teco3 "Plustek" "OpticPro 2400SP" "SCSI"
+teco3 "PIOTECH" "Splendeur 3024" "SCSI"
+teco3 "Trust" "Imagery 2400 SP" "SCSI"
+teco3 "Trust" "Imagery 4800 SP+" "SCSI"
+teco3 "Trust" "Imagery 9600 SP" "SCSI"
+umax "UMAX" "Vista S6" "SCSI"
+umax "UMAX" "Vista S6E" "SCSI"
+umax "UMAX" "UMAX S-6E" "SCSI"
+umax "UMAX" "UMAX S-6EG" "SCSI"
+umax "UMAX" "Vista-S8" "SCSI"
+umax "UMAX" "Supervista S-12" "SCSI"
+umax "UMAX" "UMAX S-12" "SCSI"
+umax "UMAX" "UMAX S-12G" "SCSI"
+umax "UMAX" "Astra 600S" "SCSI"
+umax "UMAX" "Astra 610S" "SCSI"
+umax "UMAX" "Astra 1200S" "SCSI"
+umax "UMAX" "Astra 1220S" "SCSI"
+umax "UMAX" "Astra 2100S" "SCSI"
+umax "UMAX" "Astra 2200 (SU)" "SCSI"
+umax "UMAX" "Astra 2200 (SU)" "USB"
+umax "UMAX" "Astra 2400S" "SCSI"
+umax "UMAX" "Astra 6400" "IEEE-1394"
+umax "UMAX" "Astra 6450" "IEEE-1394"
+umax "UMAX" "Astra MX3" "SCSI"
+umax "UMAX" "Astra MX3" "USB"
+umax "UMAX" "Mirage D-16L" "SCSI"
+umax "UMAX" "Mirage II" "SCSI"
+umax "UMAX" "Mirage IIse" "SCSI"
+umax "UMAX" "PSD" "SCSI"
+umax "UMAX" "PowerLook" "SCSI"
+umax "UMAX" "PL-II" "SCSI"
+umax "UMAX" "PowerLook III" "SCSI"
+umax "UMAX" "PowerLook 270" "SCSI"
+umax "UMAX" "PowerLook 270plus" "SCSI"
+umax "UMAX" "PowerLook 1100" "IEEE-1394"
+umax "UMAX" "PowerLook 2000" "SCSI"
+umax "UMAX" "PowerLook 2100XL" "SCSI"
+umax "UMAX" "PowerLook 3000" "SCSI"
+umax "UMAX" "Gemini D-16" "SCSI"
+umax "UMAX" "UMAX VT600" "SCSI"
+umax "UMAX" "Vista-T630" "SCSI"
+umax "UMAX" "UC 630" "SCSI"
+umax "UMAX" "UG 630" "SCSI"
+umax "UMAX" "UG 80" "SCSI"
+umax "UMAX" "UC 840" "SCSI"
+umax "UMAX" "UC 1200S" "SCSI"
+umax "UMAX" "UC 1200SE" "SCSI"
+umax "UMAX" "UC 1260" "SCSI"
+umax "Linotype Hell" "Jade" "SCSI"
+umax "Linotype Hell" "Jade" "SCSI"
+umax "Linotype Hell" "Jade2" "SCSI"
+umax "Linotype Hell" "Saphir" "SCSI"
+umax "Linotype Hell" "Saphir2" "SCSI"
+umax "Linotype Hell" "Saphir3" "SCSI"
+umax "Linotype Hell" "Saphir Ultra" "SCSI"
+umax "Linotype Hell" "Saphir Ultra II" "SCSI"
+umax "Linotype Hell" "Saphir HiRes" "SCSI"
+umax "Linotype Hell" "Opal" "SCSI"
+umax "Linotype Hell" "Opal Ultra" "SCSI"
+umax "Linotype Hell" "Linoscan 1400" "SCSI"
+umax "Vobis" "Highscreen Scanboostar Premium" "SCSI"
+umax "EDGE" "KTX-9600US" "SCSI"
+umax "Epson" "Perfection 600" "SCSI"
+umax "Escom" "Image Scanner 256" "SCSI"
+umax "Escort" "Galleria 600" "SCSI"
+umax "Genius" "ColorPage-HR5 (Pro)" "SCSI"
+umax "Nikon" "AX-110 / Scantouch 110" "SCSI"
+umax "Nikon" "AX-210" "SCSI"
+umax1220u "UMAX" "Astra 1220U" "USB"
+umax1220u "UMAX" "Astra 2000U" "USB"
+umax1220u "UMAX" "Astra 2200U" "USB"
+umax_pp "UMAX" "Astra 1220P" "Parport (EPP)"
+umax_pp "UMAX" "Astra 2000P" "Parport (EPP)"
+umax_pp "UMAX" "Astra 1600P" "Parport (EPP)"
+umax_pp "UMAX" "Astra 610P" "Parport (EPP)"
+umax_pp "Hewlett-Packard" "Scanjet 3200C" "Parport (EPP)"
diff --git a/include/setup_checks.inc b/include/setup_checks.inc
new file mode 100644 (file)
index 0000000..2c097bd
--- /dev/null
@@ -0,0 +1,1167 @@
+<?php
+
+function minimum_version($vercheck)
+{
+  $minver = (int)str_replace('.', '', $vercheck);
+  $curver = (int)str_replace('.', '', phpversion());
+
+  if($curver >= $minver){
+    return (true);
+  }
+
+  return (false);
+}
+
+
+function check_schema_version($description, $version)
+{
+  $desc= preg_replace("/^.* DESC\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $description);
+
+  return preg_match("/\(v$version\)/", $desc);
+}
+
+function view_schema_check($table)
+{
+  $message="<table class=\"check\">";
+  foreach ($table as $key => $msg){
+    $message.= "<tr><td class=\"check\">$msg";
+    if(strstr($msg,"enabled")) {
+      $message.="</td><td style='text-align:center' ><img src=images/true.png alt='true' /></td></tr>";
+    }
+    else
+    {
+      $message.="</td><td style='text-align:center' ><img src=images/button_cancel.png alt='false' /></td></tr>";}
+  }
+  $message.="</table>";
+  return $message;
+}
+
+function schema_check($server, $admin, $password,$aff=0)
+{
+  global $config;
+
+  $messages= array();
+  $required_classes= array(
+      "gosaObject"            => array("version" => "2.1"),
+      "gosaAccount"           => array("version" => "2.1.2"),
+      "gosaLockEntry"         => array("version" => "2.1"),
+      "gosaCacheEntry"        => array("version" => "2.1"),
+      "gosaDepartment"        => array("version" => "2.1"),
+
+      "goFaxAccount"          => array("version" => "1.0.4", "class" => "gofaxAccount","file" => "gofax.schema"),
+      "goFaxSBlock"           => array("version" => "1.0.4", "class" => "gofaxAccount","file" => "gofax.schema"),
+      "goFaxRBlock"           => array("version" => "1.0.4", "class" => "gofaxAccount","file" => "gofax.schema"),
+
+      "gosaUserTemplate"      => array("version" => "2.1", "class" => "posixAccount","file" => "nis.schema"),
+      "gosaMailAccount"       => array("version" => "2.1", "class" => "mailAccount","file" => "gosa+samba3.schema"),
+      "gosaProxyAccount"      => array("version" => "2.1.2", "class" => "proxyAccount","file" => "gosa+samba3.schema"),
+      "gosaApplication"       => array("version" => "2.1", "class" => "appgroup","file" => "gosa.schema"),
+      "gosaApplicationGroup"  => array("version" => "2.1", "class" => "appgroup","file" => "gosa.schema"),
+
+      "GOhard"                => array("version" => "2.1", "class" => "terminals","file" => "goto.schema"),
+      "gotoTerminal"          => array("version" => "2.0", "class" => "terminals","file" => "goto.schema"),
+      "goServer"              => array("version" => "2.1","class" => "server","file" => "goserver.schema"),
+      "goTerminalServer"      => array("version" => "2.1", "class" => "terminals","file" => "goto.schema"),
+      "goNfsServer"           => array("version" => "2.1", "class" => "terminals","file" => "goto.schema"),
+      "goNtpServer"           => array("version" => "2.1", "class" => "terminals","file" => "goto.schema"),
+      "goSyslogServer"        => array("version" => "2.1", "class" => "terminals","file" => "goto.schema"),
+      "goLdapServer"          => array("version" => "2.1"),
+      "goCupsServer"          => array("version" => "2.1", "class" => array("posixAccount", "terminals"),),
+      "goImapServer"          => array("version" => "2.1", "class" => array("mailAccount", "mailgroup"),"file" => "gosa+samba3.schema"),
+      "goKrbServer"           => array("version" => "2.1"),
+      "goFaxServer"           => array("version" => "2.1", "class" => "gofaxAccount","file" => "gofax.schema")
+        );
+
+  /* Build LDAP connection */
+  $ds= ldap_connect ($server);
+  if (!$ds) {
+    return (array(_("Can't bind to LDAP. No schema check possible!")));
+  }
+  ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
+  $r= ldap_bind ($ds, $admin, $password);
+
+  /* Get base to look for schema */
+  $sr  = @ldap_read ($ds, "", "objectClass=*", array("subschemaSubentry"));
+  $attr= @ldap_get_entries($ds,$sr);
+  if (!isset($attr[0]['subschemasubentry'][0])){
+    return (array(_("Can't get schema information from server. No schema check possible!")));
+  }
+
+  /* Get list of objectclasses */
+  $nb= $attr[0]['subschemasubentry'][0];
+  $objectclasses= array();
+  $sr= ldap_read ($ds, $nb, "objectClass=*", array("objectclasses"));
+  $attrs= ldap_get_entries($ds,$sr);
+  if (!isset($attrs[0])){
+    return (array(_("Can't get schema information from server. No schema check possible!")));
+  }
+  foreach ($attrs[0]['objectclasses'] as $val){
+    $name= preg_replace("/^.* NAME\s+\(*\s*'([^']+)'\s*\)*.*$/", '\\1', $val);
+    if ($name != $val){
+      $objectclasses[$name]= $val;
+    }
+  }
+  /* Walk through objectclasses and check if they are needed or not */
+  foreach ($required_classes as $key => $value){
+    if (isset($value['class'])){
+      if (!is_array($value['class'])){
+        $classes= array($value['class']);
+      } else {
+        $classes= $value['class'];
+      }
+
+      /* Check if we are using the class that requires */
+      foreach($classes as $class){
+        if (!isset($objectclasses[$key])){
+          $messages[$key]= sprintf(_("Optional objectclass '%s' required by plugin '%s' is not present in LDAP setup"), $key, $class);
+        } else {
+          if (!check_schema_version($objectclasses[$key], $value['version'])){
+            $messages[$key]= sprintf(_("Optional objectclass '%s' required by plugin '%s' does not have version %s"), $key, $class, $value['version']);
+          }else {
+            if(!isset($affich2[$class])){
+              $affich2[$class]="Support for <b>$class</b> enabled <td class=\"check\"> ".$value['file']."</td>";
+            }
+          }
+        }
+
+      }
+    } else {
+      /* Required class */
+      if (!isset($objectclasses[$key])){
+        $messages[$key]= sprintf(_("Required objectclass '%s' is not present in LDAP setup"), $key);
+      } else {
+        if (!check_schema_version($objectclasses[$key], $value['version'])){
+          $messages[$key]= sprintf(_("Required objectclass '%s' does not have version %s"), $key, $value['version']);
+        }
+      }
+    }
+  }
+
+  /* Check for correct samba parameters */
+  if (!isset($objectclasses['sambaSamAccount'])){
+    $messages['samba3']= _("<b>SAMBA 3</b> support disabled, no schema seems to be installed");
+    $affich['samba3']= $messages['samba3']."<td class=\"check\">gosa+samba3.schema</td>";
+  }else{$affich['samba3']=_("<b>SAMBA 3</b> support enabled<td class=\"check\">gosa+samba3.schema</td>");}
+
+  if (!isset($objectclasses['sambaAccount'])){
+    $messages['samba2']= _("<b>SAMBA 2</b> support disabled, no schema seems to be installed");
+    $affich['samba2']=$messages['samba2']."<td class=\"check\">samba.schema</td>";
+  }else{$affich['samba2']=_("<b>SAMBA 2</b> support enabled<td class=\"check\">samba.schema</td>");}
+
+  /* Check pureftp/dns/ */
+  if (!isset($objectclasses['PureFTPdUser'])){
+    $messages['pureftp']= _("Support for <b>pureftp</b> disabled, no schema seems to be installed");
+    $affich['pureftp']= $messages['pureftp']."<td class=\"check\">pureftpd.schema</td>";
+  }else{$affich['pureftp']=_("Support for <b>pureftp</b> enabled<td class=\"check\">pureftpd.schema</td>");}
+
+  if (!isset($objectclasses['gosaWebdavAccount'])){
+    $messages['webdav']= _("Support for <b>WebDAV</b> disabled, no schema seems to be installed");
+    $affich['webdav']=$messages['webdav']."<td class=\"check\"></td>";
+  }else{$affich['webdav']=_("Support for <b>WebDAV</b> enabled<td class=\"check\">gosa+samba3.schema</td>");}
+
+  if (!isset($objectclasses['phpgwAccount'])){
+    $messages['phpgroupware']= _("Support for <b>phpgroupware</b> disabled, no schema seems to be installed");
+    $affich['phpgroupware']=$messages['phpgroupware']."<td class=\"check\">phpgwaccount.schema</td>";
+  }else{$affich['phpgroupware']=_("Support for <b>phpgroupware</b> enabled<td class=\"check\">phpgwaccount.schema</td>");}
+
+  if (!isset($objectclasses['goFonAccount'])){
+    $messages['phoneaccount']= _("Support for <b>gofon</b> disabled, no schema seems to be installed");
+    $affich['phoneaccount']=$messages['phoneaccount']."<td class=\"check\">gofon.schema</td>";
+  }else{$affich['phoneaccount']=_("Support for <b>gofon</b> enabled<td class=\"check\">gofon.schema</td>");}
+
+  if($aff==0)return ($messages);
+  else return(array_merge($affich,$affich2));
+}
+
+
+
+function check(&$faults, $message, $description, $test, $required= TRUE)
+{
+  $msg= "<table class='check'><tr><td class='check' style='font-size:14px;'>$message</td><td rowspan=2 style='vertical-align:middle; text-align:center;width:45px;'>";
+  if ($test){
+    $msg.= _("OK")."<br>";
+  } else {
+    if (!$required){
+      $msg.="<font color=red>"._("Ignored")."</font><br>";
+    } else {
+      $msg.="<font color=red>"._("Failed")."</font><br>";
+      $faults++;
+    }
+  }
+  $msg.= "</td></tr><tr><td class='check' style='padding-left:20px;background-color:#F0F0F0;'>$description</td></tr></table><br>";
+
+  return $msg;
+}
+
+function perform_php_checks(&$faults)
+{
+  global $check_globals;
+
+  $faults= 0;
+  $msg= "";
+
+  $msg.= "<h1>"._("PHP setup inspection")."</h1>";
+  $msg.= check (       $faults, _("Checking for PHP version (>=4.1.0)"),
+      _("PHP must be of version 4.1.0 or above for some functions and known bugs in PHP language."),
+      minimum_version('4.1.0'));
+
+  $msg.= check (       $faults, _("Checking if register_globals is set to 'off'"),
+      _("register_globals is a PHP mechanism to register all global varibales to be accessible from scripts without changing the scope. This may be a security risk. GOsa will run in both modes."),
+      $check_globals == 0, FALSE);
+
+  $msg.= check (       $faults, _("Checking for ldap module"),
+      _("This is the main module used by GOsa and therefore really required."),
+      function_exists('ldap_bind'));
+
+  $msg.= check (       $faults, _("Checking for gettext support"),
+      _("Gettext support is required for internationalized GOsa."), function_exists('bindtextdomain'));
+
+  $msg.= check (       $faults, _("Checking for mhash module"),
+      _("To use SSHA encryption, you'll need this module. If you are just using crypt or md5 encryption, ignore this message. GOsa will run without it."),
+      function_exists('mhash'), FALSE);
+
+  $msg.= check (       $faults, _("Checking for imap module"),
+      _("The IMAP module is needed to communicate with the IMAP server. It gets status informations, creates and deletes mail users."),
+      function_exists('imap_open'));
+  $msg.= check (       $faults, _("Checking for getacl in imap"),
+      _("The getacl support is needed for shared folder permissions. The standard IMAP module is not capable of reading acl's. You need a recend PHP version for this feature."),
+      function_exists('imap_getacl'), FALSE);
+  $msg.= check (       $faults, _("Checking for mysql module"),
+      _("MySQL support is needed for reading GOfax reports from databases."),
+      function_exists('mysql_query'), FALSE);
+  $msg.= check (       $faults, _("Checking for cups module"),
+      _("In order to read available printers from IPP protocol instead of printcap files, you've to install the CUPS module."),
+      function_exists('cups_get_dest_list'), FALSE);
+  $msg.= check (       $faults, _("Checking for kadm5 module"),
+      _("Managing users in kerberos requires the kadm5 module which is downloadable via PEAR network."),
+      function_exists('kadm5_init_with_password'), FALSE);
+  return ($msg);
+}
+
+
+function perform_additional_checks(&$faults)
+{
+# Programm check
+  $msg= "<h1>"._("Checking for some additional programms")."</h1>";
+
+# Image Magick
+  $query= "LC_ALL=C LANG=C convert -help";
+  $output= shell_exec ($query);
+  if ($output != ""){
+    $lines= split ("\n", $output);
+    $version= preg_replace ("/^Version:[^I]+ImageMagick ([^\s]+).*/", "\\1", $lines[0]);
+    list($major, $minor)= split("\.", $version);
+    $msg.= check (     $faults, _("Checking for ImageMagick (>=5.4.0)"),
+        _("ImageMagick is used to convert user supplied images to fit the suggested size and the unified JPEG format."),
+        ($major > 5 || ($major == 5 && $minor >= 4)));
+  } else {
+    $msg.= check (     $faults, _("Checking imagick module for PHP"),
+        _("Imagick is used to convert user supplied images to fit the suggested size and the unified JPEG format from PHP script."), function_exists('imagick_blob2image'), TRUE);
+  }
+
+# Check for fping
+  $query= "LC_ALL=C LANG=C fping -v 2>&1";
+  $output= shell_exec ($query);
+  $have_fping= preg_match("/^fping:/", $output);
+  $msg.= check (       $faults, _("Checking for fping utility"),
+      _("The fping utility is only used if you've got a thin client based terminal environment running."),
+      $have_fping, FALSE);
+
+# Check for smb hash generation tool
+  $query= "mkntpwd 2>&1";
+  $output= shell_exec ($query);
+  $have_mkntpwd= preg_match("/^Usage: mkntpwd /", $output);
+  $alt = 0;
+
+  if (!$have_mkntpwd){
+    $query= "LC_ALL=C LANG=C perl -MCrypt::SmbHash -e 'ntlmgen \"PASSWD\", \$lm, \$nt; print \"\${lm}:\${nt}\\n\";' &>/dev/null";
+    system ($query, $ret);
+    $alt= ($ret == 0);
+  }
+
+  $msg.= check (       $faults, _("Checking for a way to generate LM/NT password hashes"),
+      _("In order to use SAMBA 2/3, you've to install some additional packages to generate password hashes."),
+      ($have_mkntpwd || $alt));
+# checking for some PHP.ini Options
+
+/* seesio.auto_start should be off, in order to without trouble*/
+
+$arra = ini_get_all();
+
+/* This array contains folling info now : 
+  global_value  0
+  local_value   0
+  access        7               
+
+-->Access types
+PHP_INI_USER      1          Entry can be set in user scripts
+PHP_INI_PERDIR    2          Entry can be set in php.ini, .htaccess or httpd.conf 
+PHP_INI_SYSTEM    4          Entry can be set in php.ini or httpd.conf 
+PHP_INI_ALL       7          Entry can be set anywhere 
+
+*/
+
+$session_auto_start =     ($arra['session.auto_start']);
+$implicit_flush     =     ($arra['implicit_flush']);
+$max_execution_time =     ($arra['max_execution_time']);
+$memory_limit =           ($arra['memory_limit']);
+$expose_php =             ($arra['expose_php']);
+$magic_quotes_gpc =       ($arra['magic_quotes_gpc']);
+$register_globals =       ($arra['register_globals']);
+
+
+// auto_register
+$msg.= check (  $faults, _("PHP.ini check -> session.auto_register"),
+      _("In Order to use GOsa without any trouble, the session.auto_register option in your php.ini musst be 'Off'."),
+      (!$session_auto_start['local_value']));
+
+
+
+//implicit_flush
+$msg.= check (  $faults, _("PHP.ini check -> implicit_flush"),
+      _("This Option defines the Ouput handling, turn this Option off, to increase performance."),
+        !$implicit_flush['local_value'],0,false);
+
+//max_execution_time
+if($max_execution_time['local_value'] < 30 )
+  $max_execution_time['local_value']=false;
+$msg.= check (  $faults, _("PHP.ini check -> max_execution_time"),
+      _("The Execution time, should be 30 seconds minimun, cause some actions will need huge ammount of time ."),
+        $max_execution_time['local_value'],0,false);
+
+//memory_limit
+if($memory_limit['local_value'] < 8 )
+  $memory_limit['local_value']=false;
+$msg.= check (  $faults, _("PHP.ini check -> memory_limit"),
+      _("GOsa need at least 8M of memory, less will cause unpredictable errors, sometimes without error message!. Best would be 32 M here."),
+        !$implicit_flush['local_value'],0,false);
+
+//expose_php
+$msg.= check (  $faults, _("PHP.ini check -> expose_php"),
+      _("PHP won't send any Information about the Server you are running, should be a security fact."),
+        !$implicit_flush['local_value'],0,false);
+
+//magic_quotes_gpc
+$msg.= check (  $faults, _("PHP.ini check -> magic_quotes_gpc"),
+      _("Security option, php will escape all quotes in strings ."),
+        $magic_quotes_gpc['local_value'],0,false);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  return $msg;
+}
+
+
+
+//! Added by Hickert
+//
+// Parse /contrib/gosa.conf to set user defined values
+//This function may create the ldap.conf
+// Lets try
+function parse_contrib_conf()
+{
+  /* First gather all needed informations */
+
+
+
+  /* Variables */
+  $str                = "";
+  $used_samba_version = 0;
+  $query              = ""; 
+  $fp                 = false;
+  $output             = "";
+  $needridbase_sid    = false;
+  $pwdhash            = "";
+  $replacements       = array();
+  $ldapconf           = $_SESSION['ldapconf']; // The Installation information
+  $classes            = $_SESSION['classes'];  // Class information needed to define which features are enabled
+  $possible_plugins   = array();
+
+  if(isset($classes['samba3']))  // means Samba 3 is disabled
+    $used_samba_version = 2;
+  else
+    $used_samba_version = 3;
+
+
+  if(file_exists("/usr/lib/gosa/mkntpasswd"))    {
+    $pwdhash  = "/usr/lib/gosa/mkntpasswd";
+  }
+  elseif (preg_match("/^Usage: mkntpwd /", shell_exec ("mkntpwd 2>&1")))    {
+    $pwdhash= "mkntpwd";
+  } else {
+    $pwdhash=addslashes('  perl -MCrypt::SmbHash -e "ntlmgen \"\$ARGV[0]\", \$lm, \$nt; print \"\${lm}:\${nt}\n\";" $1');
+    //    $pwdhash= 'perl -MCrypt::SmbHash -e \"ntlmgen \\"\\$ARGV[0]\\", \\$lm, \\$nt; print \\"\\${lm}:\\${nt}\\\";\"'; 
+  }
+
+
+  // Define which variables will be replaced
+  $replacements['{LOCATIONNAME}']           =   $ldapconf['location'];
+  $replacements['{SAMBAVERSION}']           =   $used_samba_version;
+  $replacements['{LDAPBASE}']               =   $ldapconf['base'];
+  $replacements['{LDAPADMIN}']              =   $ldapconf['admin'];
+  $replacements['{DNMODE}']                 =   $ldapconf['peopledn'];
+  $replacements['{LOCALHOST}']              =   $ldapconf['uri'];
+  $replacements['{PASSWORD}']               =   $ldapconf['password'];
+  $replacements['{CRYPT}']                  =   $ldapconf['arr_cryptkeys'][$ldapconf['arr_crypts']];
+  $replacements['{SID}']                    =   "";
+  $replacements['{RIDBASE}']                =   "";
+  $replacements['{MAILMETHOD}']             =   $ldapconf['mail_methods'][$ldapconf['mail']];
+  $replacements['{SMBHASH}']                =   $pwdhash;
+  $replacements['{GOVERNMENTMODE}']         =   "false"; 
+
+
+
+
+  // This array contains all preg_replace syntax to delete all unused plugins
+  // THE kEY MUST BE THE CLASSNAME so we can check it with $ldapconf['classes']
+
+  $possible_plugins['fonreport'][]      ="'\n.*<plugin.*fonreport+.*\n.*>.*\n'i";
+  $possible_plugins['phoneaccount'][]   ="'\n.*<tab.*phoneAccount.*>.*\n'i";
+
+  $possible_plugins['logview'][]        ="'\n.*<plugin.*logview+.*\n.*>.*\n'i";
+
+  $possible_plugins['pureftp'][]        ="'\n.*<tab.*pureftp.*>.*\n'i";
+
+  $possible_plugins['webdav'][]         ="'\n.*<tab.*webdav.*>.*\n'i";
+
+  $possible_plugins['phpgroupware'][]   ="'\n.*<tab.*phpgroupware.*>'i";
+
+
+  // Header information
+  // Needed to send the generated gosa.conf to the browser
+  header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+  header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
+  header("Cache-Control: no-cache");
+  header("Pragma: no-cache");
+  header("Cache-Control: post-check=0, pre-check=0");
+  header("Content-type: text/plain");
+
+  if (preg_match('/MSIE 5.5/', $_SERVER['HTTP_USER_AGENT']) ||  preg_match('/MSIE 6.0/', $_SERVER['HTTP_USER_AGENT']))
+  {
+    header('Content-Disposition: filename="gosa.conf"');
+  } else {
+    header('Content-Disposition: attachment; filename="gosa.conf"');
+  }
+
+
+  if(!$fp=fopen(CONFIG_TEMPLATE_DIR."/gosa.conf","r"))
+  {
+    echo "Can't open file ".CONFIG_TEMPLATE_DIR."/gosa.conf";
+    // Don't write anything else
+  }
+  else
+  {
+    // Read out Data .....  
+    while(!feof($fp))
+    {
+      $str.= fread($fp,512);
+    }
+
+
+    // Lets check which samba version we will use
+
+    // in case of samba 2 we don't need to add additional objets in gosa.conf
+    // in case of samba 3 we musst detect if theres an objectType = SambaObjekt defined
+    //   if theres is one, then do nothing, because the setup will detect the the SID themself
+    //   if theres none defined add SID and RIDBASE to gosa.conf
+
+
+    if($used_samba_version == 2)
+    {
+      // Do nothing ...
+    }
+    else
+    {
+      // Create LDAP connection, to check if theres a domain Objekt definen in the Ldap scheme
+      $ldap= new LDAP($ldapconf['admin'], $ldapconf['password'], $ldapconf['uri']);
+
+
+      // Try to find a Samba Domain Objekt
+      $ldap->search("(objectClass=sambaDomain)");
+
+      // Something found ??? so we need to define ridbase an SID by ourselfs
+      if($ldap->count()< 1)
+      {
+        $replacements['{SID}']                  =   "sid=\"123412-11\"";
+        $replacements['{RIDBASE}']              =   "ridbase=\"1000\"";  
+      } 
+    }// else --> $used_samba_version == 2
+
+    // Data readed, types replaced, samba version detected and checked if we need to add SID and RIDBASE 
+
+
+    // Check if there is an ivbbEntry in the LDAP tree, in this case we will set the governmentmode to true
+    // Create LDAP connection, to check if theres a domain Objekt definen in the Ldap scheme
+
+    if(!isset($ldap))
+      $ldap= new LDAP($ldapconf['admin'], $ldapconf['password'], $ldapconf['uri']);
+
+
+    // Try to find a Samba Domain Objekt
+    $ldap->search("(objectClass=ivbbEntry)");
+
+    // Something found ??? so we need to define ridbase an SID by ourselfs
+    if($ldap->count()> 0)
+    {
+      $replacements['{GOVERNMENTMODE}']                  =   "true";
+    }
+
+
+    // Replace all colleted information with placeholder
+    foreach($replacements as $key => $val)
+    {
+      $str = preg_replace("/".$key."/",$val,$str);
+      //      $str = ereg_replace($key,$val,$str);
+    }    
+
+    // Remove all unused plugins
+    foreach($possible_plugins as $plugin)
+    {
+      foreach($plugin as $key=>$val)
+      {
+        if(in_array($plugin,$classes))
+        {
+          $str = preg_replace($val,"\n",$str);
+        }
+      }
+    }
+
+
+  }// else -->  !$fp=fopen("../contrib/gosa.conf","r")
+
+  return ( $str);
+}
+
+
+// This ist the first page shown in setup
+// This page test some packages, like php version, ldap_module aso
+// The funtion don't save anything, it tests only, when withoutput = false
+// (called from setup.php);
+function show_setup_page1($withoutput = true)
+{
+  $smarty = get_smarty();  
+
+  $smarty->assign ("content", get_template_path('setup_introduction.tpl'));
+  $smarty->assign ("tests", perform_php_checks($faults));
+
+
+
+  // This var is true if there is anything went wrong
+  if ($faults)
+  {
+    $smarty->assign("mode", "disabled");
+  }
+
+  // This line displays the template only if (withoutput is set)
+  if($withoutput) 
+    $smarty->display (get_template_path('headers.tpl'));
+
+  if (isset($_SESSION['errors']))
+  {
+    $smarty->assign("errors", $_SESSION['errors']);
+  }
+
+  if($withoutput)
+    $smarty->display (get_template_path('setup.tpl'));
+
+  return (!$faults);
+}
+
+
+
+
+
+
+
+/* Shows Setup_page 2*/
+function show_setup_page2($withoutput = true)
+{
+  $smarty = get_smarty();
+
+  $smarty->assign ("content", get_template_path('setup_step2.tpl'));
+  $smarty->assign ("tests", perform_additional_checks($faults));
+
+  if ($faults) {
+    $smarty->assign("mode", "disabled");
+  }
+  if($withoutput){
+    $smarty->display (get_template_path('headers.tpl'));
+  }
+
+  if (isset($_SESSION['errors']))  {
+    $smarty->assign("errors", $_SESSION['errors']);
+  }
+  if($withoutput){
+    $smarty->display (get_template_path('setup.tpl'));
+  }
+  return (!$faults);                               
+}
+
+
+/* Setup page 3 asks for the server address
+ "Now we're going to include your LDAP server and create an initial configuration"*/
+function show_setup_page3($withoutput = true)
+{
+
+  // Take the Post oder the Sessioin saved data  
+  if(isset($_POST['uri']))
+    $uri = $_POST['uri'];
+  elseif(isset($_SESSION['ldapconf']['uri']))
+    $uri = $_SESSION['ldapconf']['uri'];
+
+  // If Page called first time, field is empty 
+  if((!isset($uri))||(empty($uri)))
+    $uri = "ldap://localhost:389";
+
+
+  $smarty = get_smarty();
+
+  // if isset $uri save it to session
+  if(isset($uri))
+  {
+    $_SESSION['ldapconf']['uri'] = $uri;
+    $smarty->assign ("uri", validate($uri));
+  }
+
+
+  // No error till now
+  $fault = false;
+
+
+  // If we pushed the Button continue
+  if(isset($_POST['continue3']))
+    if(!isset($uri))
+    {
+      $fault = true;
+      // Output the Error
+      if($withoutput)
+      {
+        print_red (_("You've to specify an ldap server before continuing!"));
+        $smarty->assign ("content", get_template_path('setup_step3.tpl'));
+      }
+    }
+  elseif (!$ds = @ldap_connect (validate($uri)))
+  {
+    $fault =true;
+    // Output the Error
+    if($withoutput)
+    {
+      print_red (_("Can't connect to the specified LDAP server! Please make sure that is reachable for GOsa."));
+      $smarty->assign ("uri", validate($uri));
+      $smarty->assign ("content", get_template_path('setup_step3.tpl'));
+    }
+  }
+    else
+    {
+      // Try to bind the connection     
+      ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
+
+      // if we can't bind , print error
+      if (!$r  =  @ldap_bind ($ds))
+      {
+        $fault = true;
+        // Output the Error
+        if($withoutput)      
+        {
+          print_red (_("Can't bind to the specified LDAP server! Please make sure that is reachable for GOsa."));
+          $smarty->assign ("content", get_template_path('setup_step3.tpl'));
+          $smarty->assign ("uri", validate($uri));
+        }
+      }
+      else
+      {
+        $fault = false;
+      }
+    }
+
+
+  $smarty->assign ("content", get_template_path('setup_step3.tpl'));
+
+
+  // Load Header
+  if($withoutput)
+    $smarty->display (get_template_path('headers.tpl'));
+
+  // Set Errors to Smarty
+  if (isset($_SESSION['errors']))
+  {
+    $smarty->assign("errors", $_SESSION['errors']);
+  }
+
+  // Print out Template 
+  if($withoutput)
+    $smarty->display (get_template_path('setup.tpl'));
+
+
+
+  return (!$fault);                             
+}
+
+
+
+// Setup page 4
+// This page asked for detailed info, like base dn or admin user
+// if evrything is ok , but there's a missing user with ACL :all we show a a user creation page before we show page 5
+function show_setup_page4($withoutput = true)
+{
+
+
+  require_once("class_password-methods.inc");
+
+  error_reporting(E_ALL);
+
+
+
+
+  $fault        = false;                        // If an error occures we set this var to true 
+  $smarty       = get_smarty();                 // Our smarty instance
+  $uri          = $_SESSION['ldapconf']['uri']; // This is the the connect path to the ldapserver like ldap://lo..
+  $ldapconf     = $_SESSION['ldapconf'];        // The ldap Configuration informations, we collected while setup 
+  $arr_crypts   = array();                      // array which includes contains all possible password crypting methods
+  $temp         = "";                           // Temp
+  $checkvars    = array("location","admin","password","peopleou","peopledn","arr_crypts","mail","uidbase");
+
+
+  if(!isset($_SESSION['ldapconf']['arr_cryptkeys']))
+  {
+    require_once("class_password-methods.inc");
+    $tmp = passwordMethod::get_available_methods_if_not_loaded();
+    $_SESSION['ldapconf']['arr_cryptkeys']= $tmp['name'];
+  }
+
+
+
+  if(!isset($_SESSION['ldapconf']['mail_methods']))
+  {
+    $_SESSION['ldapconf']['mail_methods']=array();
+    $temp = get_available_mail_classes();
+    $_SESSION['ldapconf']['mail_methods']= $temp['name'];
+  }
+
+
+
+
+  // If there are some empty vars in ldapconnect
+  // This values also represent out default values 
+
+# first try to get $base 
+  if(!$ds = ldap_connect (validate($uri)))    
+  {
+    $fault = true;
+  }
+  elseif(!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3))    
+  {
+    $fault = true;
+  }
+  elseif(! $r =  ldap_bind ($ds))    
+  {
+    $fault = true;
+  }
+  else
+  {
+    $sr=      ldap_search ($ds, "", "objectClass=*", array("namingContexts"));
+
+
+    $attr=    ldap_get_entries($ds,$sr);
+    if((empty($attr)))
+    {
+      $base= "dc=example,dc=net";
+
+
+      if($withoutput)
+        print_red(_("Bind to server successfull, but the server seems to be completly empty, please check all informations twice"));
+
+    }
+    else
+    {
+      $base= $attr[0]['dn'];
+    }
+  }
+
+
+
+  if(!isset($_SESSION['ldapconf']['base']))           $_SESSION['ldapconf']['base']         = $base;
+  if(!isset($_SESSION['ldapconf']['admin']))          $_SESSION['ldapconf']['admin']        = "cn=ldapadmin,".$base;
+  if(!isset($_SESSION['ldapconf']['peopleou']))       $_SESSION['ldapconf']['peopleou']     = "ou=people";
+  if(!isset($_SESSION['ldapconf']['groupou']))        $_SESSION['ldapconf']['groupou']      = "ou=groups";
+  if(!isset($_SESSION['ldapconf']['peopledn']))       $_SESSION['ldapconf']['peopledn']     = "cn";
+  if(!isset($_SESSION['ldapconf']['password']))       $_SESSION['ldapconf']['password']     = "";
+  if(!isset($_SESSION['ldapconf']['location']))       $_SESSION['ldapconf']['location']     = "Example";
+  if(!isset($_SESSION['ldapconf']['uidbase']))        $_SESSION['ldapconf']['uidbase']      = "1000";
+  if(!isset($_SESSION['ldapconf']['mail']))           $_SESSION['ldapconf']['mail']         = 0;
+  $tmp = array_flip($_SESSION['ldapconf']['arr_cryptkeys']);
+  if(!isset($_SESSION['ldapconf']['arr_crypts']))     $_SESSION['ldapconf']['arr_crypts']   = $tmp['md5'];
+
+
+  // check Post data
+
+  if(isset($_POST['check']))
+  {
+    // Check if all needed vars are submitted
+    foreach($checkvars as $key)
+    {
+      if((isset($_POST[$key]))&&($_POST[$key]!=""))
+      {
+        $_SESSION['ldapconf'][$key] = $_POST[$key];
+      }
+      else
+      {
+        if($withoutput)
+        {
+          print_red(sprintf(_("You're missing the required attribute '%s' from this formular. Please complete!"), $key));
+        }
+        $fault = true;
+      }
+    }
+
+    // check if another base is given ... (ldapadmin...dc=base,dc=de)   ..
+
+    $base     =   $_SESSION['ldapconf']['admin'];
+    $tmp      =   array_reverse ( split(",",$base));
+    $base     =   $tmp[1].",".$tmp[0];
+    $_SESSION['ldapconf']['base']         = $base;
+
+
+  }
+
+
+
+  $smarty->assign("arr_cryptkeys",$_SESSION['ldapconf']['arr_cryptkeys']);
+  $smarty->assign("mail_methods", $_SESSION['ldapconf']['mail_methods']);
+
+  foreach($_SESSION['ldapconf'] as $key => $val)
+  {
+    $smarty->assign($key,$val);
+  }
+
+  if(isset($_POST['check']))
+  {
+    $ldap= new LDAP($_SESSION['ldapconf']['admin'], $_SESSION['ldapconf']['password'], $_SESSION['ldapconf']['uri']);
+
+    $m= schema_check($_SESSION['ldapconf']['uri'], $_SESSION['ldapconf']['admin'], $_SESSION['ldapconf']['password']);
+    $_SESSION['classes']= $m;
+
+
+    if ($ldap->error != "Success")
+    {
+      if($withoutput)
+      {
+        print_red(sprintf(_("Can't log into LDAP server. Reason was: %s."), $ldap->get_error()));
+      }
+      $fault = true;
+    }
+  }
+
+
+
+  // Set smarty output
+  $smarty->assign ("content", get_template_path('setup_step4.tpl'));
+
+  $smarty->assign ("peopledns", array("cn", "uid"));
+  if($withoutput)
+    $smarty->display (get_template_path('headers.tpl'));
+
+  if(isset($_SESSION['errors']))
+  {
+    $smarty->assign("errors", $_SESSION['errors']);
+  }
+  if($withoutput)
+    $smarty->display (get_template_path('setup.tpl'));
+
+
+  return (!$fault);
+
+
+}
+
+
+
+
+// This page shows your configuration 
+// and wants you to download the gosa.conf ....
+function show_setup_page5($withoutput=true)
+{
+
+  // Get ldapconf
+  $ldapconf= $_SESSION['ldapconf'];
+
+  // get smarty
+  $smarty = get_smarty();
+
+  $classes = $_SESSION['classes'];
+
+  $info= posix_getgrgid(posix_getgid());
+  $smarty->assign ("webgroup", $info['name']);
+  $smarty->assign ("path", CONFIG_DIR);
+  $message = "";
+  $message.="<table class=\"check\">";
+  $m= schema_check($ldapconf['uri'], $ldapconf['admin'], $ldapconf['password'],1);
+
+  if($withoutput)
+  {
+    $smarty->assign ("schemas", view_schema_check($m));
+    $smarty->assign ("content", get_template_path('setup_finish.tpl'));
+  }
+  // Output templates ....
+
+  if($withoutput)
+    $smarty->display (get_template_path('headers.tpl'));
+
+  if (isset($_SESSION['errors']))
+  {
+    $smarty->assign("errors", $_SESSION['errors']);
+  }
+  if($withoutput)
+    $smarty->display (get_template_path('setup.tpl'));
+  return(true);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+// this function is called by setup step 5, in order to create a missinf Administrator 
+// and or Administrational user
+// on success go on with setup_page5
+// else show this page aggain
+function create_user_for_setup($withoutput=true)
+{
+
+  error_reporting(E_ALL);
+
+  global $samba;
+
+  $ldapconf = $_SESSION['ldapconf'];
+  $smarty = get_smarty();
+
+  $classes= $_SESSION['classes'];
+
+  // Everything runns perfect ...
+  // So we do a last test on this page
+  // is there a user with ACLs :all which will be able to adminsitrate GOsa
+  // We check that, if this user or group is missing we ask for creating them
+
+  $ldap= new LDAP($_SESSION['ldapconf']['admin'], $_SESSION['ldapconf']['password'], $_SESSION['ldapconf']['uri']);
+
+  //  $ldap= new LDAP($ldapconf['admin'], $ldapconf['password'], $ldapconf['uri']);
+
+  // Now we are testing for a group, with the rights :all
+  $ldap->cd($ldapconf['base']);
+  $ldap->search("(&(objectClass=gosaObject)(gosaSubtreeACL=:all))");
+
+  $group_cnt       = $ldap->count();
+  $data           = $ldap->fetch();
+  $create_user    = false;
+
+  // We need to create Administrative user and group
+  // Because theres no Group found
+  if($group_cnt < 1)
+  {
+    // Set var to create user
+    $create_user    =   true;
+
+    // Output error
+    if(($withoutput)&&(!isset($_POST['new_admin'])))
+      print_red(_("You're missing an administrative account for GOsa, you'll not be able to administrate anything!"));
+  }
+  else
+  {
+
+    // We found an Administrative Group, is there a user too
+    if(isset($data['memberUid'][0]))
+    {
+      $ldap->search("(&(objectClass=gosaAccount)(objectClass=person))",array("uid=".$data['memberUid'][0]));
+      $data2      = $ldap->fetch();
+      $user_cnt   = $ldap->count();
+    }
+
+    // We must create a user
+    if (($ldap->count() < 1)||(!isset($data2)))
+    {
+      $create_user = true;
+      if(($withoutput)&&(!isset($_POST['new_admin'])))
+        print_red(_("You're missing an administrative account for GOsa, you'll not be able to administrate anything!"));
+    }
+    else
+    {
+      // We don't need to add a user
+      return(true);
+    }
+
+  }// if($group_cn)
+
+  // We need to create a new user with group
+  if(isset($_POST['new_admin']))
+  {
+    // Is there a running user ?
+    // Then add additional
+
+    if (isset($classes['samba3']))
+    {
+      $samba= "2";
+      $lmPassword = "lmPassword";
+      $ntPassword = "ntPassword";
+    } else {
+      $samba= "3";
+      $lmPassword = "sambaLMPassword";
+      $ntPassword = "sambaNtPassword";
+    }
+
+
+    // Nothing submitted
+    if(( (empty($_POST['admin_name']))||(empty($_POST['admin_pass'])) )&&(!$create_user))
+    {
+      return(true);
+    }
+
+    // We have the order to create on Admin ^^
+    // Detect Samba version to define the Attribute names shown below
+    // go to base
+    $ldap->cd($ldapconf['base']);
+
+    // Define the user we are going to create
+    $dn =  "cn=".$_POST['admin_name'].",".$ldapconf['peopleou'].",".$ldapconf['base'];
+
+
+    $arr['objectClass'][0] ="person";
+    $arr['objectClass'][1] ="organizationalPerson";
+    $arr['objectClass'][2] ="inetOrgPerson";
+    $arr['objectClass'][3] ="gosaAccount";
+    $arr['uid']            = $_POST['admin_name'];
+    $arr['cn']             = $_POST['admin_name'];
+    $arr['sn']             = $_POST['admin_name'];
+
+    $arr['givenName']     = "GOsa main administrator";
+    $arr[$lmPassword]     = "10974C6EFC0AEE1917306D272A9441BB";
+    $arr[$ntPassword]     = "38F3951141D0F71A039CFA9D1EC06378";
+    $arr['userPassword']  = crypt_single($_POST['admin_pass'],"md5");
+    if( ! $ldap->dn_exists ( $dn )) { 
+      $ldap->cd($dn); 
+      $ldap->create_missing_trees($dn);
+      $ldap->add($arr);
+      if($ldap->error!="Success")      {
+        print_red("Can't create user, and / or Group, possibly this problem  depends on an empty LDAP server. Check your configuration and try again!");
+      }
+    }
+
+    // theres already a group for administrator, so we only need to add the user
+    if($group_cnt)
+    {
+      if(!isset($data['memberUid']))
+      {
+        $arrr['memberUid']= $_POST['admin_name'];
+      }
+      else
+      {
+        $data['memberUid'][$data['memberUid']['count']]=$_POST['admin_name'];
+        $arrr['memberUid'] = $data['memberUid'];
+        unset($arrr['memberUid']['count']);
+      }
+      $ldap->cd($data['dn']);
+      $ldap->modify($arrr);
+    }
+    else
+    {
+      // there was no group defined, so we must create one
+      $dn                       = "cn=administrators,".$ldapconf['groupou'].",".$ldapconf['base'];
+      $arrr['objectClass'][0]   = "gosaObject";
+      $arrr['objectClass'][1]   = "posixGroup";
+      $arrr['gosaSubtreeACL']   = ":all";
+      $arrr['cn']               = "administrators";
+      $arrr['gidNumber']        = "999";
+      $arrr['memberUid']        = $_POST['admin_name'];
+      $ldap->cd($dn);
+      $ldap->add($arrr);
+    }
+
+
+    // We created the Group and the user, so we can go on with the next setup step
+    return(true);
+  }
+  else
+  {
+    if(!($create_user))
+    {
+      $smarty->assign ("content", get_template_path('setup_useradmin.tpl'));
+      $smarty->assign("exists",true);
+    }
+    else
+    {
+      $smarty->assign ("content", get_template_path('setup_useradmin.tpl'));
+      $smarty->assign("exists",false);
+    }
+  }
+
+
+  // Smarty outout  
+
+  if($withoutput)
+    $smarty->display (get_template_path('headers.tpl'));
+
+  if (isset($_SESSION['errors']))
+  {
+    $smarty->assign("errors", $_SESSION['errors']);
+  }
+  if($withoutput)
+    $smarty->display (get_template_path('setup.tpl'));
+
+
+  return(false);
+}
+
+
+// Returns the classnames auf the mail classes
+function get_available_mail_classes()
+{
+  $dir = opendir( "../include");
+  $methods = array();
+  $suffix = "class_mail-methods-";
+  $lensuf = strlen($suffix);
+  $prefix = ".inc";
+  $lenpre = strlen($prefix);
+
+
+  $i = 0;
+  while (($file = readdir($dir)) !== false) 
+  {
+    if(stristr($file,$suffix))
+    {
+      $lenfile = strlen($file);
+      $methods['name'][$i] = substr($file,$lensuf,($lenfile-$lensuf)-$lenpre);
+      $methods['file'][$i] = $file;
+      $methods[$i]['file'] = $file;
+      $methods[$i]['name'] = substr($file,$lensuf,($lenfile-$lensuf)-$lenpre);
+      $i++;
+    }
+  }
+  return($methods);
+}
+
+
+
+
+
+
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>
diff --git a/include/smarty/Config_File.class.php b/include/smarty/Config_File.class.php
new file mode 100644 (file)
index 0000000..b5fdd22
--- /dev/null
@@ -0,0 +1,389 @@
+<?php
+
+/**
+ * Config_File class.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @link http://smarty.php.net/
+ * @version 2.6.9
+ * @copyright Copyright: 2001-2005 New Digital Group, Inc.
+ * @author Andrei Zmievski <andrei@php.net>
+ * @access public
+ * @package Smarty
+ */
+
+/* $Id: Config_File.class.php,v 1.78 2005/03/22 08:45:06 messju Exp $ */
+
+/**
+ * Config file reading class
+ * @package Smarty
+ */
+class Config_File {
+    /**#@+
+     * Options
+     * @var boolean
+     */
+    /**
+     * Controls whether variables with the same name overwrite each other.
+     */
+    var $overwrite        =    true;
+
+    /**
+     * Controls whether config values of on/true/yes and off/false/no get
+     * converted to boolean values automatically.
+     */
+    var $booleanize        =    true;
+
+    /**
+     * Controls whether hidden config sections/vars are read from the file.
+     */
+    var $read_hidden     =    true;
+
+    /**
+     * Controls whether or not to fix mac or dos formatted newlines.
+     * If set to true, \r or \r\n will be changed to \n.
+     */
+    var $fix_newlines =    true;
+    /**#@-*/
+
+    /** @access private */
+    var $_config_path    = "";
+    var $_config_data    = array();
+    /**#@-*/
+
+    /**
+     * Constructs a new config file class.
+     *
+     * @param string $config_path (optional) path to the config files
+     */
+    function Config_File($config_path = NULL)
+    {
+        if (isset($config_path))
+            $this->set_path($config_path);
+    }
+
+
+    /**
+     * Set the path where configuration files can be found.
+     *
+     * @param string $config_path path to the config files
+     */
+    function set_path($config_path)
+    {
+        if (!empty($config_path)) {
+            if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) {
+                $this->_trigger_error_msg("Bad config file path '$config_path'");
+                return;
+            }
+            if(substr($config_path, -1) != DIRECTORY_SEPARATOR) {
+                $config_path .= DIRECTORY_SEPARATOR;
+            }
+
+            $this->_config_path = $config_path;
+        }
+    }
+
+
+    /**
+     * Retrieves config info based on the file, section, and variable name.
+     *
+     * @param string $file_name config file to get info for
+     * @param string $section_name (optional) section to get info for
+     * @param string $var_name (optional) variable to get info for
+     * @return string|array a value or array of values
+     */
+    function &get($file_name, $section_name = NULL, $var_name = NULL)
+    {
+        if (empty($file_name)) {
+            $this->_trigger_error_msg('Empty config file name');
+            return;
+        } else {
+            $file_name = $this->_config_path . $file_name;
+            if (!isset($this->_config_data[$file_name]))
+                $this->load_file($file_name, false);
+        }
+
+        if (!empty($var_name)) {
+            if (empty($section_name)) {
+                return $this->_config_data[$file_name]["vars"][$var_name];
+            } else {
+                if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]))
+                    return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name];
+                else
+                    return array();
+            }
+        } else {
+            if (empty($section_name)) {
+                return (array)$this->_config_data[$file_name]["vars"];
+            } else {
+                if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"]))
+                    return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"];
+                else
+                    return array();
+            }
+        }
+    }
+
+
+    /**
+     * Retrieves config info based on the key.
+     *
+     * @param $file_name string config key (filename/section/var)
+     * @return string|array same as get()
+     * @uses get() retrieves information from config file and returns it
+     */
+    function &get_key($config_key)
+    {
+        list($file_name, $section_name, $var_name) = explode('/', $config_key, 3);
+        $result = &$this->get($file_name, $section_name, $var_name);
+        return $result;
+    }
+
+    /**
+     * Get all loaded config file names.
+     *
+     * @return array an array of loaded config file names
+     */
+    function get_file_names()
+    {
+        return array_keys($this->_config_data);
+    }
+
+
+    /**
+     * Get all section names from a loaded file.
+     *
+     * @param string $file_name config file to get section names from
+     * @return array an array of section names from the specified file
+     */
+    function get_section_names($file_name)
+    {
+        $file_name = $this->_config_path . $file_name;
+        if (!isset($this->_config_data[$file_name])) {
+            $this->_trigger_error_msg("Unknown config file '$file_name'");
+            return;
+        }
+
+        return array_keys($this->_config_data[$file_name]["sections"]);
+    }
+
+
+    /**
+     * Get all global or section variable names.
+     *
+     * @param string $file_name config file to get info for
+     * @param string $section_name (optional) section to get info for
+     * @return array an array of variables names from the specified file/section
+     */
+    function get_var_names($file_name, $section = NULL)
+    {
+        if (empty($file_name)) {
+            $this->_trigger_error_msg('Empty config file name');
+            return;
+        } else if (!isset($this->_config_data[$file_name])) {
+            $this->_trigger_error_msg("Unknown config file '$file_name'");
+            return;
+        }
+
+        if (empty($section))
+            return array_keys($this->_config_data[$file_name]["vars"]);
+        else
+            return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]);
+    }
+
+
+    /**
+     * Clear loaded config data for a certain file or all files.
+     *
+     * @param string $file_name file to clear config data for
+     */
+    function clear($file_name = NULL)
+    {
+        if ($file_name === NULL)
+            $this->_config_data = array();
+        else if (isset($this->_config_data[$file_name]))
+            $this->_config_data[$file_name] = array();
+    }
+
+
+    /**
+     * Load a configuration file manually.
+     *
+     * @param string $file_name file name to load
+     * @param boolean $prepend_path whether current config path should be
+     *                              prepended to the filename
+     */
+    function load_file($file_name, $prepend_path = true)
+    {
+        if ($prepend_path && $this->_config_path != "")
+            $config_file = $this->_config_path . $file_name;
+        else
+            $config_file = $file_name;
+
+        ini_set('track_errors', true);
+        $fp = @fopen($config_file, "r");
+        if (!is_resource($fp)) {
+            $this->_trigger_error_msg("Could not open config file '$config_file'");
+            return false;
+        }
+
+        $contents = ($size = filesize($config_file)) ? fread($fp, $size) : '';
+        fclose($fp);
+
+        $this->_config_data[$config_file] = $this->parse_contents($contents);
+        return true;
+    }
+
+    /**
+     * Store the contents of a file manually.
+     *
+     * @param string $config_file file name of the related contents
+     * @param string $contents the file-contents to parse
+     */
+    function set_file_contents($config_file, $contents)
+    {
+        $this->_config_data[$config_file] = $this->parse_contents($contents);
+        return true;
+    }
+
+    /**
+     * parse the source of a configuration file manually.
+     *
+     * @param string $contents the file-contents to parse
+     */
+    function parse_contents($contents)
+    {
+        if($this->fix_newlines) {
+            // fix mac/dos formatted newlines
+            $contents = preg_replace('!\r\n?!', "\n", $contents);
+        }
+
+        $config_data = array();
+        $config_data['sections'] = array();
+        $config_data['vars'] = array();
+
+        /* reference to fill with data */
+        $vars =& $config_data['vars'];
+
+        /* parse file line by line */
+        preg_match_all('!^.*\r?\n?!m', $contents, $match);
+        $lines = $match[0];
+        for ($i=0, $count=count($lines); $i<$count; $i++) {
+            $line = $lines[$i];
+            if (empty($line)) continue;
+
+            if ( $line{0} == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) {
+                /* section found */
+                if ($match[1]{0} == '.') {
+                    /* hidden section */
+                    if ($this->read_hidden) {
+                        $section_name = substr($match[1], 1);
+                    } else {
+                        /* break reference to $vars to ignore hidden section */
+                        unset($vars);
+                        $vars = array();
+                        continue;
+                    }
+                } else {                    
+                    $section_name = $match[1];
+                }
+                if (!isset($config_data['sections'][$section_name]))
+                    $config_data['sections'][$section_name] = array('vars' => array());
+                $vars =& $config_data['sections'][$section_name]['vars'];
+                continue;
+            }
+
+            if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) {
+                /* variable found */
+                $var_name = rtrim($match[1]);
+                if (strpos($match[2], '"""') === 0) {
+                    /* handle multiline-value */
+                    $lines[$i] = substr($match[2], 3);
+                    $var_value = '';
+                    while ($i<$count) {
+                        if (($pos = strpos($lines[$i], '"""')) === false) {
+                            $var_value .= $lines[$i++];
+                        } else {
+                            /* end of multiline-value */
+                            $var_value .= substr($lines[$i], 0, $pos);
+                            break;
+                        }
+                    }
+                    $booleanize = false;
+
+                } else {
+                    /* handle simple value */
+                    $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2]));
+                    $booleanize = $this->booleanize;
+
+                }
+                $this->_set_config_var($vars, $var_name, $var_value, $booleanize);
+            }
+            /* else unparsable line / means it is a comment / means ignore it */
+        }
+        return $config_data;
+    }
+
+    /**#@+ @access private */
+    /**
+     * @param array &$container
+     * @param string $var_name
+     * @param mixed $var_value
+     * @param boolean $booleanize determines whether $var_value is converted to
+     *                            to true/false
+     */
+    function _set_config_var(&$container, $var_name, $var_value, $booleanize)
+    {
+        if ($var_name{0} == '.') {
+            if (!$this->read_hidden)
+                return;
+            else
+                $var_name = substr($var_name, 1);
+        }
+
+        if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) {
+            $this->_trigger_error_msg("Bad variable name '$var_name'");
+            return;
+        }
+
+        if ($booleanize) {
+            if (preg_match("/^(on|true|yes)$/i", $var_value))
+                $var_value = true;
+            else if (preg_match("/^(off|false|no)$/i", $var_value))
+                $var_value = false;
+        }
+
+        if (!isset($container[$var_name]) || $this->overwrite)
+            $container[$var_name] = $var_value;
+        else {
+            settype($container[$var_name], 'array');
+            $container[$var_name][] = $var_value;
+        }
+    }
+
+    /**
+     * @uses trigger_error() creates a PHP warning/error
+     * @param string $error_msg
+     * @param integer $error_type one of
+     */
+    function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING)
+    {
+        trigger_error("Config_File error: $error_msg", $error_type);
+    }
+    /**#@-*/
+}
+
+?>
diff --git a/include/smarty/Smarty.class.php b/include/smarty/Smarty.class.php
new file mode 100644 (file)
index 0000000..bb51290
--- /dev/null
@@ -0,0 +1,1934 @@
+<?php
+
+/**
+ * Project:     Smarty: the PHP compiling template engine
+ * File:        Smarty.class.php
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * For questions, help, comments, discussion, etc., please join the
+ * Smarty mailing list. Send a blank e-mail to
+ * smarty-general-subscribe@lists.php.net
+ *
+ * @link http://smarty.php.net/
+ * @copyright 2001-2005 New Digital Group, Inc.
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Andrei Zmievski <andrei@php.net>
+ * @package Smarty
+ * @version 2.6.9
+ */
+
+/* $Id: Smarty.class.php,v 1.514 2005/03/22 08:45:06 messju Exp $ */
+
+/**
+ * DIR_SEP isn't used anymore, but third party apps might
+ */
+if(!defined('DIR_SEP')) {
+    define('DIR_SEP', DIRECTORY_SEPARATOR);
+}
+
+/**
+ * set SMARTY_DIR to absolute path to Smarty library files.
+ * if not defined, include_path will be used. Sets SMARTY_DIR only if user
+ * application has not already defined it.
+ */
+
+if (!defined('SMARTY_DIR')) {
+    define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR);
+}
+
+if (!defined('SMARTY_CORE_DIR')) {
+    define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR);
+}
+
+define('SMARTY_PHP_PASSTHRU',   0);
+define('SMARTY_PHP_QUOTE',      1);
+define('SMARTY_PHP_REMOVE',     2);
+define('SMARTY_PHP_ALLOW',      3);
+
+/**
+ * @package Smarty
+ */
+class Smarty
+{
+    /**#@+
+     * Smarty Configuration Section
+     */
+
+    /**
+     * The name of the directory where templates are located.
+     *
+     * @var string
+     */
+    var $template_dir    =  'templates';
+
+    /**
+     * The directory where compiled templates are located.
+     *
+     * @var string
+     */
+    var $compile_dir     =  'templates_c';
+
+    /**
+     * The directory where config files are located.
+     *
+     * @var string
+     */
+    var $config_dir      =  'configs';
+
+    /**
+     * An array of directories searched for plugins.
+     *
+     * @var array
+     */
+    var $plugins_dir     =  array('plugins');
+
+    /**
+     * If debugging is enabled, a debug console window will display
+     * when the page loads (make sure your browser allows unrequested
+     * popup windows)
+     *
+     * @var boolean
+     */
+    var $debugging       =  false;
+
+    /**
+     * When set, smarty does uses this value as error_reporting-level.
+     *
+     * @var boolean
+     */
+    var $error_reporting  =  null;
+
+    /**
+     * This is the path to the debug console template. If not set,
+     * the default one will be used.
+     *
+     * @var string
+     */
+    var $debug_tpl       =  '';
+
+    /**
+     * This determines if debugging is enable-able from the browser.
+     * <ul>
+     *  <li>NONE => no debugging control allowed</li>
+     *  <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li>
+     * </ul>
+     * @link http://www.foo.dom/index.php?SMARTY_DEBUG
+     * @var string
+     */
+    var $debugging_ctrl  =  'NONE';
+
+    /**
+     * This tells Smarty whether to check for recompiling or not. Recompiling
+     * does not need to happen unless a template or config file is changed.
+     * Typically you enable this during development, and disable for
+     * production.
+     *
+     * @var boolean
+     */
+    var $compile_check   =  true;
+
+    /**
+     * This forces templates to compile every time. Useful for development
+     * or debugging.
+     *
+     * @var boolean
+     */
+    var $force_compile   =  false;
+
+    /**
+     * This enables template caching.
+     * <ul>
+     *  <li>0 = no caching</li>
+     *  <li>1 = use class cache_lifetime value</li>
+     *  <li>2 = use cache_lifetime in cache file</li>
+     * </ul>
+     * @var integer
+     */
+    var $caching         =  0;
+
+    /**
+     * The name of the directory for cache files.
+     *
+     * @var string
+     */
+    var $cache_dir       =  'cache';
+
+    /**
+     * This is the number of seconds cached content will persist.
+     * <ul>
+     *  <li>0 = always regenerate cache</li>
+     *  <li>-1 = never expires</li>
+     * </ul>
+     *
+     * @var integer
+     */
+    var $cache_lifetime  =  3600;
+
+    /**
+     * Only used when $caching is enabled. If true, then If-Modified-Since headers
+     * are respected with cached content, and appropriate HTTP headers are sent.
+     * This way repeated hits to a cached page do not send the entire page to the
+     * client every time.
+     *
+     * @var boolean
+     */
+    var $cache_modified_check = false;
+
+    /**
+     * This determines how Smarty handles "<?php ... ?>" tags in templates.
+     * possible values:
+     * <ul>
+     *  <li>SMARTY_PHP_PASSTHRU -> print tags as plain text</li>
+     *  <li>SMARTY_PHP_QUOTE    -> escape tags as entities</li>
+     *  <li>SMARTY_PHP_REMOVE   -> remove php tags</li>
+     *  <li>SMARTY_PHP_ALLOW    -> execute php tags</li>
+     * </ul>
+     *
+     * @var integer
+     */
+    var $php_handling    =  SMARTY_PHP_PASSTHRU;
+
+    /**
+     * This enables template security. When enabled, many things are restricted
+     * in the templates that normally would go unchecked. This is useful when
+     * untrusted parties are editing templates and you want a reasonable level
+     * of security. (no direct execution of PHP in templates for example)
+     *
+     * @var boolean
+     */
+    var $security       =   false;
+
+    /**
+     * This is the list of template directories that are considered secure. This
+     * is used only if {@link $security} is enabled. One directory per array
+     * element.  {@link $template_dir} is in this list implicitly.
+     *
+     * @var array
+     */
+    var $secure_dir     =   array();
+
+    /**
+     * These are the security settings for Smarty. They are used only when
+     * {@link $security} is enabled.
+     *
+     * @var array
+     */
+    var $security_settings  = array(
+                                    'PHP_HANDLING'    => false,
+                                    'IF_FUNCS'        => array('array', 'list',
+                                                               'isset', 'empty',
+                                                               'count', 'sizeof',
+                                                               'in_array', 'is_array',
+                                                               'true', 'false', 'null'),
+                                    'INCLUDE_ANY'     => false,
+                                    'PHP_TAGS'        => false,
+                                    'MODIFIER_FUNCS'  => array('count'),
+                                    'ALLOW_CONSTANTS'  => false
+                                   );
+
+    /**
+     * This is an array of directories where trusted php scripts reside.
+     * {@link $security} is disabled during their inclusion/execution.
+     *
+     * @var array
+     */
+    var $trusted_dir        = array();
+
+    /**
+     * The left delimiter used for the template tags.
+     *
+     * @var string
+     */
+    var $left_delimiter  =  '{';
+
+    /**
+     * The right delimiter used for the template tags.
+     *
+     * @var string
+     */
+    var $right_delimiter =  '}';
+
+    /**
+     * The order in which request variables are registered, similar to
+     * variables_order in php.ini E = Environment, G = GET, P = POST,
+     * C = Cookies, S = Server
+     *
+     * @var string
+     */
+    var $request_vars_order    = 'EGPCS';
+
+    /**
+     * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false)
+     * are uses as request-vars or $_*[]-vars. note: if
+     * request_use_auto_globals is true, then $request_vars_order has
+     * no effect, but the php-ini-value "gpc_order"
+     *
+     * @var boolean
+     */
+    var $request_use_auto_globals      = true;
+
+    /**
+     * Set this if you want different sets of compiled files for the same
+     * templates. This is useful for things like different languages.
+     * Instead of creating separate sets of templates per language, you
+     * set different compile_ids like 'en' and 'de'.
+     *
+     * @var string
+     */
+    var $compile_id            = null;
+
+    /**
+     * This tells Smarty whether or not to use sub dirs in the cache/ and
+     * templates_c/ directories. sub directories better organized, but
+     * may not work well with PHP safe mode enabled.
+     *
+     * @var boolean
+     *
+     */
+    var $use_sub_dirs          = false;
+
+    /**
+     * This is a list of the modifiers to apply to all template variables.
+     * Put each modifier in a separate array element in the order you want
+     * them applied. example: <code>array('escape:"htmlall"');</code>
+     *
+     * @var array
+     */
+    var $default_modifiers        = array();
+
+    /**
+     * This is the resource type to be used when not specified
+     * at the beginning of the resource path. examples:
+     * $smarty->display('file:index.tpl');
+     * $smarty->display('db:index.tpl');
+     * $smarty->display('index.tpl'); // will use default resource type
+     * {include file="file:index.tpl"}
+     * {include file="db:index.tpl"}
+     * {include file="index.tpl"} {* will use default resource type *}
+     *
+     * @var array
+     */
+    var $default_resource_type    = 'file';
+
+    /**
+     * The function used for cache file handling. If not set, built-in caching is used.
+     *
+     * @var null|string function name
+     */
+    var $cache_handler_func   = null;
+
+    /**
+     * This indicates which filters are automatically loaded into Smarty.
+     *
+     * @var array array of filter names
+     */
+    var $autoload_filters = array();
+
+    /**#@+
+     * @var boolean
+     */
+    /**
+     * This tells if config file vars of the same name overwrite each other or not.
+     * if disabled, same name variables are accumulated in an array.
+     */
+    var $config_overwrite = true;
+
+    /**
+     * This tells whether or not to automatically booleanize config file variables.
+     * If enabled, then the strings "on", "true", and "yes" are treated as boolean
+     * true, and "off", "false" and "no" are treated as boolean false.
+     */
+    var $config_booleanize = true;
+
+    /**
+     * This tells whether hidden sections [.foobar] are readable from the
+     * tempalates or not. Normally you would never allow this since that is
+     * the point behind hidden sections: the application can access them, but
+     * the templates cannot.
+     */
+    var $config_read_hidden = false;
+
+    /**
+     * This tells whether or not automatically fix newlines in config files.
+     * It basically converts \r (mac) or \r\n (dos) to \n
+     */
+    var $config_fix_newlines = true;
+    /**#@-*/
+
+    /**
+     * If a template cannot be found, this PHP function will be executed.
+     * Useful for creating templates on-the-fly or other special action.
+     *
+     * @var string function name
+     */
+    var $default_template_handler_func = '';
+
+    /**
+     * The file that contains the compiler class. This can a full
+     * pathname, or relative to the php_include path.
+     *
+     * @var string
+     */
+    var $compiler_file        =    'Smarty_Compiler.class.php';
+
+    /**
+     * The class used for compiling templates.
+     *
+     * @var string
+     */
+    var $compiler_class        =   'Smarty_Compiler';
+
+    /**
+     * The class used to load config vars.
+     *
+     * @var string
+     */
+    var $config_class          =   'Config_File';
+
+/**#@+
+ * END Smarty Configuration Section
+ * There should be no need to touch anything below this line.
+ * @access private
+ */
+    /**
+     * where assigned template vars are kept
+     *
+     * @var array
+     */
+    var $_tpl_vars             = array();
+
+    /**
+     * stores run-time $smarty.* vars
+     *
+     * @var null|array
+     */
+    var $_smarty_vars          = null;
+
+    /**
+     * keeps track of sections
+     *
+     * @var array
+     */
+    var $_sections             = array();
+
+    /**
+     * keeps track of foreach blocks
+     *
+     * @var array
+     */
+    var $_foreach              = array();
+
+    /**
+     * keeps track of tag hierarchy
+     *
+     * @var array
+     */
+    var $_tag_stack            = array();
+
+    /**
+     * configuration object
+     *
+     * @var Config_file
+     */
+    var $_conf_obj             = null;
+
+    /**
+     * loaded configuration settings
+     *
+     * @var array
+     */
+    var $_config               = array(array('vars'  => array(), 'files' => array()));
+
+    /**
+     * md5 checksum of the string 'Smarty'
+     *
+     * @var string
+     */
+    var $_smarty_md5           = 'f8d698aea36fcbead2b9d5359ffca76f';
+
+    /**
+     * Smarty version number
+     *
+     * @var string
+     */
+    var $_version              = '2.6.9';
+
+    /**
+     * current template inclusion depth
+     *
+     * @var integer
+     */
+    var $_inclusion_depth      = 0;
+
+    /**
+     * for different compiled templates
+     *
+     * @var string
+     */
+    var $_compile_id           = null;
+
+    /**
+     * text in URL to enable debug mode
+     *
+     * @var string
+     */
+    var $_smarty_debug_id      = 'SMARTY_DEBUG';
+
+    /**
+     * debugging information for debug console
+     *
+     * @var array
+     */
+    var $_smarty_debug_info    = array();
+
+    /**
+     * info that makes up a cache file
+     *
+     * @var array
+     */
+    var $_cache_info           = array();
+
+    /**
+     * default file permissions
+     *
+     * @var integer
+     */
+    var $_file_perms           = 0644;
+
+    /**
+     * default dir permissions
+     *
+     * @var integer
+     */
+    var $_dir_perms               = 0771;
+
+    /**
+     * registered objects
+     *
+     * @var array
+     */
+    var $_reg_objects           = array();
+
+    /**
+     * table keeping track of plugins
+     *
+     * @var array
+     */
+    var $_plugins              = array(
+                                       'modifier'      => array(),
+                                       'function'      => array(),
+                                       'block'         => array(),
+                                       'compiler'      => array(),
+                                       'prefilter'     => array(),
+                                       'postfilter'    => array(),
+                                       'outputfilter'  => array(),
+                                       'resource'      => array(),
+                                       'insert'        => array());
+
+
+    /**
+     * cache serials
+     *
+     * @var array
+     */
+    var $_cache_serials = array();
+
+    /**
+     * name of optional cache include file
+     *
+     * @var string
+     */
+    var $_cache_include = null;
+
+    /**
+     * indicate if the current code is used in a compiled
+     * include
+     *
+     * @var string
+     */
+    var $_cache_including = false;
+
+    /**#@-*/
+    /**
+     * The class constructor.
+     */
+    function Smarty()
+    {
+      $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME']
+                    : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']);
+    }
+
+    /**
+     * assigns values to template variables
+     *
+     * @param array|string $tpl_var the template variable name(s)
+     * @param mixed $value the value to assign
+     */
+    function assign($tpl_var, $value = null)
+    {
+        if (is_array($tpl_var)){
+            foreach ($tpl_var as $key => $val) {
+                if ($key != '') {
+                    $this->_tpl_vars[$key] = $val;
+                }
+            }
+        } else {
+            if ($tpl_var != '')
+                $this->_tpl_vars[$tpl_var] = $value;
+        }
+    }
+
+    /**
+     * assigns values to template variables by reference
+     *
+     * @param string $tpl_var the template variable name
+     * @param mixed $value the referenced value to assign
+     */
+    function assign_by_ref($tpl_var, &$value)
+    {
+        if ($tpl_var != '')
+            $this->_tpl_vars[$tpl_var] = &$value;
+    }
+
+    /**
+     * appends values to template variables
+     *
+     * @param array|string $tpl_var the template variable name(s)
+     * @param mixed $value the value to append
+     */
+    function append($tpl_var, $value=null, $merge=false)
+    {
+        if (is_array($tpl_var)) {
+            // $tpl_var is an array, ignore $value
+            foreach ($tpl_var as $_key => $_val) {
+                if ($_key != '') {
+                    if(!@is_array($this->_tpl_vars[$_key])) {
+                        settype($this->_tpl_vars[$_key],'array');
+                    }
+                    if($merge && is_array($_val)) {
+                        foreach($_val as $_mkey => $_mval) {
+                            $this->_tpl_vars[$_key][$_mkey] = $_mval;
+                        }
+                    } else {
+                        $this->_tpl_vars[$_key][] = $_val;
+                    }
+                }
+            }
+        } else {
+            if ($tpl_var != '' && isset($value)) {
+                if(!@is_array($this->_tpl_vars[$tpl_var])) {
+                    settype($this->_tpl_vars[$tpl_var],'array');
+                }
+                if($merge && is_array($value)) {
+                    foreach($value as $_mkey => $_mval) {
+                        $this->_tpl_vars[$tpl_var][$_mkey] = $_mval;
+                    }
+                } else {
+                    $this->_tpl_vars[$tpl_var][] = $value;
+                }
+            }
+        }
+    }
+
+    /**
+     * appends values to template variables by reference
+     *
+     * @param string $tpl_var the template variable name
+     * @param mixed $value the referenced value to append
+     */
+    function append_by_ref($tpl_var, &$value, $merge=false)
+    {
+        if ($tpl_var != '' && isset($value)) {
+            if(!@is_array($this->_tpl_vars[$tpl_var])) {
+             settype($this->_tpl_vars[$tpl_var],'array');
+            }
+            if ($merge && is_array($value)) {
+                foreach($value as $_key => $_val) {
+                    $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key];
+                }
+            } else {
+                $this->_tpl_vars[$tpl_var][] = &$value;
+            }
+        }
+    }
+
+
+    /**
+     * clear the given assigned template variable.
+     *
+     * @param string $tpl_var the template variable to clear
+     */
+    function clear_assign($tpl_var)
+    {
+        if (is_array($tpl_var))
+            foreach ($tpl_var as $curr_var)
+                unset($this->_tpl_vars[$curr_var]);
+        else
+            unset($this->_tpl_vars[$tpl_var]);
+    }
+
+
+    /**
+     * Registers custom function to be used in templates
+     *
+     * @param string $function the name of the template function
+     * @param string $function_impl the name of the PHP function to register
+     */
+    function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null)
+    {
+        $this->_plugins['function'][$function] =
+            array($function_impl, null, null, false, $cacheable, $cache_attrs);
+
+    }
+
+    /**
+     * Unregisters custom function
+     *
+     * @param string $function name of template function
+     */
+    function unregister_function($function)
+    {
+        unset($this->_plugins['function'][$function]);
+    }
+
+    /**
+     * Registers object to be used in templates
+     *
+     * @param string $object name of template object
+     * @param object &$object_impl the referenced PHP object to register
+     * @param null|array $allowed list of allowed methods (empty = all)
+     * @param boolean $smarty_args smarty argument format, else traditional
+     * @param null|array $block_functs list of methods that are block format
+     */
+    function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array())
+    {
+        settype($allowed, 'array');
+        settype($smarty_args, 'boolean');
+        $this->_reg_objects[$object] =
+            array(&$object_impl, $allowed, $smarty_args, $block_methods);
+    }
+
+    /**
+     * Unregisters object
+     *
+     * @param string $object name of template object
+     */
+    function unregister_object($object)
+    {
+        unset($this->_reg_objects[$object]);
+    }
+
+
+    /**
+     * Registers block function to be used in templates
+     *
+     * @param string $block name of template block
+     * @param string $block_impl PHP function to register
+     */
+    function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null)
+    {
+        $this->_plugins['block'][$block] =
+            array($block_impl, null, null, false, $cacheable, $cache_attrs);
+    }
+
+    /**
+     * Unregisters block function
+     *
+     * @param string $block name of template function
+     */
+    function unregister_block($block)
+    {
+        unset($this->_plugins['block'][$block]);
+    }
+
+    /**
+     * Registers compiler function
+     *
+     * @param string $function name of template function
+     * @param string $function_impl name of PHP function to register
+     */
+    function register_compiler_function($function, $function_impl, $cacheable=true)
+    {
+        $this->_plugins['compiler'][$function] =
+            array($function_impl, null, null, false, $cacheable);
+    }
+
+    /**
+     * Unregisters compiler function
+     *
+     * @param string $function name of template function
+     */
+    function unregister_compiler_function($function)
+    {
+        unset($this->_plugins['compiler'][$function]);
+    }
+
+    /**
+     * Registers modifier to be used in templates
+     *
+     * @param string $modifier name of template modifier
+     * @param string $modifier_impl name of PHP function to register
+     */
+    function register_modifier($modifier, $modifier_impl)
+    {
+        $this->_plugins['modifier'][$modifier] =
+            array($modifier_impl, null, null, false);
+    }
+
+    /**
+     * Unregisters modifier
+     *
+     * @param string $modifier name of template modifier
+     */
+    function unregister_modifier($modifier)
+    {
+        unset($this->_plugins['modifier'][$modifier]);
+    }
+
+    /**
+     * Registers a resource to fetch a template
+     *
+     * @param string $type name of resource
+     * @param array $functions array of functions to handle resource
+     */
+    function register_resource($type, $functions)
+    {
+        if (count($functions)==4) {
+            $this->_plugins['resource'][$type] =
+                array($functions, false);
+
+        } elseif (count($functions)==5) {
+            $this->_plugins['resource'][$type] =
+                array(array(array(&$functions[0], $functions[1])
+                            ,array(&$functions[0], $functions[2])
+                            ,array(&$functions[0], $functions[3])
+                            ,array(&$functions[0], $functions[4]))
+                      ,false);
+
+        } else {
+            $this->trigger_error("malformed function-list for '$type' in register_resource");
+
+        }
+    }
+
+    /**
+     * Unregisters a resource
+     *
+     * @param string $type name of resource
+     */
+    function unregister_resource($type)
+    {
+        unset($this->_plugins['resource'][$type]);
+    }
+
+    /**
+     * Registers a prefilter function to apply
+     * to a template before compiling
+     *
+     * @param string $function name of PHP function to register
+     */
+    function register_prefilter($function)
+    {
+    $_name = (is_array($function)) ? $function[1] : $function;
+        $this->_plugins['prefilter'][$_name]
+            = array($function, null, null, false);
+    }
+
+    /**
+     * Unregisters a prefilter function
+     *
+     * @param string $function name of PHP function
+     */
+    function unregister_prefilter($function)
+    {
+        unset($this->_plugins['prefilter'][$function]);
+    }
+
+    /**
+     * Registers a postfilter function to apply
+     * to a compiled template after compilation
+     *
+     * @param string $function name of PHP function to register
+     */
+    function register_postfilter($function)
+    {
+    $_name = (is_array($function)) ? $function[1] : $function;
+        $this->_plugins['postfilter'][$_name]
+            = array($function, null, null, false);
+    }
+
+    /**
+     * Unregisters a postfilter function
+     *
+     * @param string $function name of PHP function
+     */
+    function unregister_postfilter($function)
+    {
+        unset($this->_plugins['postfilter'][$function]);
+    }
+
+    /**
+     * Registers an output filter function to apply
+     * to a template output
+     *
+     * @param string $function name of PHP function
+     */
+    function register_outputfilter($function)
+    {
+    $_name = (is_array($function)) ? $function[1] : $function;
+        $this->_plugins['outputfilter'][$_name]
+            = array($function, null, null, false);
+    }
+
+    /**
+     * Unregisters an outputfilter function
+     *
+     * @param string $function name of PHP function
+     */
+    function unregister_outputfilter($function)
+    {
+        unset($this->_plugins['outputfilter'][$function]);
+    }
+
+    /**
+     * load a filter of specified type and name
+     *
+     * @param string $type filter type
+     * @param string $name filter name
+     */
+    function load_filter($type, $name)
+    {
+        switch ($type) {
+            case 'output':
+                $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false)));
+                require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+                smarty_core_load_plugins($_params, $this);
+                break;
+
+            case 'pre':
+            case 'post':
+                if (!isset($this->_plugins[$type . 'filter'][$name]))
+                    $this->_plugins[$type . 'filter'][$name] = false;
+                break;
+        }
+    }
+
+    /**
+     * clear cached content for the given template and cache id
+     *
+     * @param string $tpl_file name of template file
+     * @param string $cache_id name of cache_id
+     * @param string $compile_id name of compile_id
+     * @param string $exp_time expiration time
+     * @return boolean
+     */
+    function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null)
+    {
+
+        if (!isset($compile_id))
+            $compile_id = $this->compile_id;
+
+        if (!isset($tpl_file))
+            $compile_id = null;
+
+        $_auto_id = $this->_get_auto_id($cache_id, $compile_id);
+
+        if (!empty($this->cache_handler_func)) {
+            return call_user_func_array($this->cache_handler_func,
+                                  array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time));
+        } else {
+            $_params = array('auto_base' => $this->cache_dir,
+                            'auto_source' => $tpl_file,
+                            'auto_id' => $_auto_id,
+                            'exp_time' => $exp_time);
+            require_once(SMARTY_CORE_DIR . 'core.rm_auto.php');
+            return smarty_core_rm_auto($_params, $this);
+        }
+
+    }
+
+
+    /**
+     * clear the entire contents of cache (all templates)
+     *
+     * @param string $exp_time expire time
+     * @return boolean results of {@link smarty_core_rm_auto()}
+     */
+    function clear_all_cache($exp_time = null)
+    {
+        return $this->clear_cache(null, null, null, $exp_time);
+    }
+
+
+    /**
+     * test to see if valid cache exists for this template
+     *
+     * @param string $tpl_file name of template file
+     * @param string $cache_id
+     * @param string $compile_id
+     * @return string|false results of {@link _read_cache_file()}
+     */
+    function is_cached($tpl_file, $cache_id = null, $compile_id = null)
+    {
+        if (!$this->caching)
+            return false;
+
+        if (!isset($compile_id))
+            $compile_id = $this->compile_id;
+
+        $_params = array(
+            'tpl_file' => $tpl_file,
+            'cache_id' => $cache_id,
+            'compile_id' => $compile_id
+        );
+        require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');
+        return smarty_core_read_cache_file($_params, $this);
+    }
+
+
+    /**
+     * clear all the assigned template variables.
+     *
+     */
+    function clear_all_assign()
+    {
+        $this->_tpl_vars = array();
+    }
+
+    /**
+     * clears compiled version of specified template resource,
+     * or all compiled template files if one is not specified.
+     * This function is for advanced use only, not normally needed.
+     *
+     * @param string $tpl_file
+     * @param string $compile_id
+     * @param string $exp_time
+     * @return boolean results of {@link smarty_core_rm_auto()}
+     */
+    function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null)
+    {
+        if (!isset($compile_id)) {
+            $compile_id = $this->compile_id;
+        }
+        $_params = array('auto_base' => $this->compile_dir,
+                        'auto_source' => $tpl_file,
+                        'auto_id' => $compile_id,
+                        'exp_time' => $exp_time,
+                        'extensions' => array('.inc', '.php'));
+        require_once(SMARTY_CORE_DIR . 'core.rm_auto.php');
+        return smarty_core_rm_auto($_params, $this);
+    }
+
+    /**
+     * Checks whether requested template exists.
+     *
+     * @param string $tpl_file
+     * @return boolean
+     */
+    function template_exists($tpl_file)
+    {
+        $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false);
+        return $this->_fetch_resource_info($_params);
+    }
+
+    /**
+     * Returns an array containing template variables
+     *
+     * @param string $name
+     * @param string $type
+     * @return array
+     */
+    function &get_template_vars($name=null)
+    {
+        if(!isset($name)) {
+            return $this->_tpl_vars;
+        }
+        if(isset($this->_tpl_vars[$name])) {
+            return $this->_tpl_vars[$name];
+        }
+    }
+
+    /**
+     * Returns an array containing config variables
+     *
+     * @param string $name
+     * @param string $type
+     * @return array
+     */
+    function &get_config_vars($name=null)
+    {
+        if(!isset($name) && is_array($this->_config[0])) {
+            return $this->_config[0]['vars'];
+        } else if(isset($this->_config[0]['vars'][$name])) {
+            return $this->_config[0]['vars'][$name];
+        }
+    }
+
+    /**
+     * trigger Smarty error
+     *
+     * @param string $error_msg
+     * @param integer $error_type
+     */
+    function trigger_error($error_msg, $error_type = E_USER_WARNING)
+    {
+        trigger_error("Smarty error: $error_msg", $error_type);
+    }
+
+
+    /**
+     * executes & displays the template results
+     *
+     * @param string $resource_name
+     * @param string $cache_id
+     * @param string $compile_id
+     */
+    function display($resource_name, $cache_id = null, $compile_id = null)
+    {
+        $this->fetch($resource_name, $cache_id, $compile_id, true);
+    }
+
+    /**
+     * executes & returns or displays the template results
+     *
+     * @param string $resource_name
+     * @param string $cache_id
+     * @param string $compile_id
+     * @param boolean $display
+     */
+    function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false)
+    {
+        static $_cache_info = array();
+        
+        $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting)
+               ? $this->error_reporting : error_reporting() & ~E_NOTICE);
+
+        if (!$this->debugging && $this->debugging_ctrl == 'URL') {
+            $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING'];
+            if (@strstr($_query_string, $this->_smarty_debug_id)) {
+                if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) {
+                    // enable debugging for this browser session
+                    @setcookie('SMARTY_DEBUG', true);
+                    $this->debugging = true;
+                } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) {
+                    // disable debugging for this browser session
+                    @setcookie('SMARTY_DEBUG', false);
+                    $this->debugging = false;
+                } else {
+                    // enable debugging for this page
+                    $this->debugging = true;
+                }
+            } else {
+                $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']);
+            }
+        }
+
+        if ($this->debugging) {
+            // capture time for debugging info
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $_debug_start_time = smarty_core_get_microtime($_params, $this);
+            $this->_smarty_debug_info[] = array('type'      => 'template',
+                                                'filename'  => $resource_name,
+                                                'depth'     => 0);
+            $_included_tpls_idx = count($this->_smarty_debug_info) - 1;
+        }
+
+        if (!isset($compile_id)) {
+            $compile_id = $this->compile_id;
+        }
+
+        $this->_compile_id = $compile_id;
+        $this->_inclusion_depth = 0;
+
+        if ($this->caching) {
+            // save old cache_info, initialize cache_info
+            array_push($_cache_info, $this->_cache_info);
+            $this->_cache_info = array();
+            $_params = array(
+                'tpl_file' => $resource_name,
+                'cache_id' => $cache_id,
+                'compile_id' => $compile_id,
+                'results' => null
+            );
+            require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php');
+            if (smarty_core_read_cache_file($_params, $this)) {
+                $_smarty_results = $_params['results'];
+                if (!empty($this->_cache_info['insert_tags'])) {
+                    $_params = array('plugins' => $this->_cache_info['insert_tags']);
+                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+                    smarty_core_load_plugins($_params, $this);
+                    $_params = array('results' => $_smarty_results);
+                    require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');
+                    $_smarty_results = smarty_core_process_cached_inserts($_params, $this);
+                }
+                if (!empty($this->_cache_info['cache_serials'])) {
+                    $_params = array('results' => $_smarty_results);
+                    require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php');
+                    $_smarty_results = smarty_core_process_compiled_include($_params, $this);
+                }
+
+
+                if ($display) {
+                    if ($this->debugging)
+                    {
+                        // capture time for debugging info
+                        $_params = array();
+                        require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+                        $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time;
+                        require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');
+                        $_smarty_results .= smarty_core_display_debug_console($_params, $this);
+                    }
+                    if ($this->cache_modified_check) {
+                        $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
+                        $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3);
+                        $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT';
+                        if (@count($this->_cache_info['insert_tags']) == 0
+                            && !$this->_cache_serials
+                            && $_gmt_mtime == $_last_modified_date) {
+                            if (php_sapi_name()=='cgi')
+                                header('Status: 304 Not Modified');
+                            else
+                                header('HTTP/1.1 304 Not Modified');
+
+                        } else {
+                            header('Last-Modified: '.$_gmt_mtime);
+                            echo $_smarty_results;
+                        }
+                    } else {
+                            echo $_smarty_results;
+                    }
+                    error_reporting($_smarty_old_error_level);
+                    // restore initial cache_info
+                    $this->_cache_info = array_pop($_cache_info);
+                    return true;
+                } else {
+                    error_reporting($_smarty_old_error_level);
+                    // restore initial cache_info
+                    $this->_cache_info = array_pop($_cache_info);
+                    return $_smarty_results;
+                }
+            } else {
+                $this->_cache_info['template'][$resource_name] = true;
+                if ($this->cache_modified_check && $display) {
+                    header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT');
+                }
+            }
+        }
+
+        // load filters that are marked as autoload
+        if (count($this->autoload_filters)) {
+            foreach ($this->autoload_filters as $_filter_type => $_filters) {
+                foreach ($_filters as $_filter) {
+                    $this->load_filter($_filter_type, $_filter);
+                }
+            }
+        }
+
+        $_smarty_compile_path = $this->_get_compile_path($resource_name);
+
+        // if we just need to display the results, don't perform output
+        // buffering - for speed
+        $_cache_including = $this->_cache_including;
+        $this->_cache_including = false;
+        if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) {
+            if ($this->_is_compiled($resource_name, $_smarty_compile_path)
+                    || $this->_compile_resource($resource_name, $_smarty_compile_path))
+            {
+                include($_smarty_compile_path);
+            }
+        } else {
+            ob_start();
+            if ($this->_is_compiled($resource_name, $_smarty_compile_path)
+                    || $this->_compile_resource($resource_name, $_smarty_compile_path))
+            {
+                include($_smarty_compile_path);
+            }
+            $_smarty_results = ob_get_contents();
+            ob_end_clean();
+
+            foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) {
+                $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this));
+            }
+        }
+
+        if ($this->caching) {
+            $_params = array('tpl_file' => $resource_name,
+                        'cache_id' => $cache_id,
+                        'compile_id' => $compile_id,
+                        'results' => $_smarty_results);
+            require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php');
+            smarty_core_write_cache_file($_params, $this);
+            require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php');
+            $_smarty_results = smarty_core_process_cached_inserts($_params, $this);
+
+            if ($this->_cache_serials) {
+                // strip nocache-tags from output
+                $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s'
+                                                ,''
+                                                ,$_smarty_results);
+            }
+            // restore initial cache_info
+            $this->_cache_info = array_pop($_cache_info);
+        }
+        $this->_cache_including = $_cache_including;
+
+        if ($display) {
+            if (isset($_smarty_results)) { echo $_smarty_results; }
+            if ($this->debugging) {
+                // capture time for debugging info
+                $_params = array();
+                require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+                $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time);
+                require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');
+                echo smarty_core_display_debug_console($_params, $this);
+            }
+            error_reporting($_smarty_old_error_level);
+            return;
+        } else {
+            error_reporting($_smarty_old_error_level);
+            if (isset($_smarty_results)) { return $_smarty_results; }
+        }
+    }
+
+    /**
+     * load configuration values
+     *
+     * @param string $file
+     * @param string $section
+     * @param string $scope
+     */
+    function config_load($file, $section = null, $scope = 'global')
+    {
+        require_once($this->_get_plugin_filepath('function', 'config_load'));
+        smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this);
+    }
+
+    /**
+     * return a reference to a registered object
+     *
+     * @param string $name
+     * @return object
+     */
+    function &get_registered_object($name) {
+        if (!isset($this->_reg_objects[$name]))
+        $this->_trigger_fatal_error("'$name' is not a registered object");
+
+        if (!is_object($this->_reg_objects[$name][0]))
+        $this->_trigger_fatal_error("registered '$name' is not an object");
+
+        return $this->_reg_objects[$name][0];
+    }
+
+    /**
+     * clear configuration values
+     *
+     * @param string $var
+     */
+    function clear_config($var = null)
+    {
+        if(!isset($var)) {
+            // clear all values
+            $this->_config = array(array('vars'  => array(),
+                                         'files' => array()));
+        } else {
+            unset($this->_config[0]['vars'][$var]);
+        }
+    }
+
+    /**
+     * get filepath of requested plugin
+     *
+     * @param string $type
+     * @param string $name
+     * @return string|false
+     */
+    function _get_plugin_filepath($type, $name)
+    {
+        $_params = array('type' => $type, 'name' => $name);
+        require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php');
+        return smarty_core_assemble_plugin_filepath($_params, $this);
+    }
+
+   /**
+     * test if resource needs compiling
+     *
+     * @param string $resource_name
+     * @param string $compile_path
+     * @return boolean
+     */
+    function _is_compiled($resource_name, $compile_path)
+    {
+        if (!$this->force_compile && file_exists($compile_path)) {
+            if (!$this->compile_check) {
+                // no need to check compiled file
+                return true;
+            } else {
+                // get file source and timestamp
+                $_params = array('resource_name' => $resource_name, 'get_source'=>false);
+                if (!$this->_fetch_resource_info($_params)) {
+                    return false;
+                }
+                if ($_params['resource_timestamp'] <= filemtime($compile_path)) {
+                    // template not expired, no recompile
+                    return true;
+                } else {
+                    // compile template
+                    return false;
+                }
+            }
+        } else {
+            // compiled template does not exist, or forced compile
+            return false;
+        }
+    }
+
+   /**
+     * compile the template
+     *
+     * @param string $resource_name
+     * @param string $compile_path
+     * @return boolean
+     */
+    function _compile_resource($resource_name, $compile_path)
+    {
+
+        $_params = array('resource_name' => $resource_name);
+        if (!$this->_fetch_resource_info($_params)) {
+            return false;
+        }
+
+        $_source_content = $_params['source_content'];
+        $_cache_include    = substr($compile_path, 0, -4).'.inc';
+
+        if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) {
+            // if a _cache_serial was set, we also have to write an include-file:
+            if ($this->_cache_include_info) {
+                require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php');
+                smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)),  $this);
+            }
+
+            $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content);
+            require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php');
+            smarty_core_write_compiled_resource($_params, $this);
+
+            return true;
+        } else {
+            return false;
+        }
+
+    }
+
+   /**
+     * compile the given source
+     *
+     * @param string $resource_name
+     * @param string $source_content
+     * @param string $compiled_content
+     * @return boolean
+     */
+    function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null)
+    {
+        if (file_exists(SMARTY_DIR . $this->compiler_file)) {
+            require_once(SMARTY_DIR . $this->compiler_file);
+        } else {
+            // use include_path
+            require_once($this->compiler_file);
+        }
+
+
+        $smarty_compiler = new $this->compiler_class;
+
+        $smarty_compiler->template_dir      = $this->template_dir;
+        $smarty_compiler->compile_dir       = $this->compile_dir;
+        $smarty_compiler->plugins_dir       = $this->plugins_dir;
+        $smarty_compiler->config_dir        = $this->config_dir;
+        $smarty_compiler->force_compile     = $this->force_compile;
+        $smarty_compiler->caching           = $this->caching;
+        $smarty_compiler->php_handling      = $this->php_handling;
+        $smarty_compiler->left_delimiter    = $this->left_delimiter;
+        $smarty_compiler->right_delimiter   = $this->right_delimiter;
+        $smarty_compiler->_version          = $this->_version;
+        $smarty_compiler->security          = $this->security;
+        $smarty_compiler->secure_dir        = $this->secure_dir;
+        $smarty_compiler->security_settings = $this->security_settings;
+        $smarty_compiler->trusted_dir       = $this->trusted_dir;
+        $smarty_compiler->use_sub_dirs      = $this->use_sub_dirs;
+        $smarty_compiler->_reg_objects      = &$this->_reg_objects;
+        $smarty_compiler->_plugins          = &$this->_plugins;
+        $smarty_compiler->_tpl_vars         = &$this->_tpl_vars;
+        $smarty_compiler->default_modifiers = $this->default_modifiers;
+        $smarty_compiler->compile_id        = $this->_compile_id;
+        $smarty_compiler->_config            = $this->_config;
+        $smarty_compiler->request_use_auto_globals  = $this->request_use_auto_globals;
+
+        if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) {
+            $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path];
+        }
+        $smarty_compiler->_cache_include = $cache_include_path;
+
+
+        $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content);
+
+        if ($smarty_compiler->_cache_serial) {
+            $this->_cache_include_info = array(
+                'cache_serial'=>$smarty_compiler->_cache_serial
+                ,'plugins_code'=>$smarty_compiler->_plugins_code
+                ,'include_file_path' => $cache_include_path);
+
+        } else {
+            $this->_cache_include_info = null;
+
+        }
+
+        return $_results;
+    }
+
+    /**
+     * Get the compile path for this resource
+     *
+     * @param string $resource_name
+     * @return string results of {@link _get_auto_filename()}
+     */
+    function _get_compile_path($resource_name)
+    {
+        return $this->_get_auto_filename($this->compile_dir, $resource_name,
+                                         $this->_compile_id) . '.php';
+    }
+
+    /**
+     * fetch the template info. Gets timestamp, and source
+     * if get_source is true
+     *
+     * sets $source_content to the source of the template, and
+     * $resource_timestamp to its time stamp
+     * @param string $resource_name
+     * @param string $source_content
+     * @param integer $resource_timestamp
+     * @param boolean $get_source
+     * @param boolean $quiet
+     * @return boolean
+     */
+
+    function _fetch_resource_info(&$params)
+    {
+        if(!isset($params['get_source'])) { $params['get_source'] = true; }
+        if(!isset($params['quiet'])) { $params['quiet'] = false; }
+
+        $_return = false;
+        $_params = array('resource_name' => $params['resource_name']) ;
+        if (isset($params['resource_base_path']))
+            $_params['resource_base_path'] = $params['resource_base_path'];
+        else
+            $_params['resource_base_path'] = $this->template_dir;
+
+        if ($this->_parse_resource_name($_params)) {
+            $_resource_type = $_params['resource_type'];
+            $_resource_name = $_params['resource_name'];
+            switch ($_resource_type) {
+                case 'file':
+                    if ($params['get_source']) {
+                        $params['source_content'] = $this->_read_file($_resource_name);
+                    }
+                    $params['resource_timestamp'] = filemtime($_resource_name);
+                    $_return = is_file($_resource_name);
+                    break;
+
+                default:
+                    // call resource functions to fetch the template source and timestamp
+                    if ($params['get_source']) {
+                        $_source_return = isset($this->_plugins['resource'][$_resource_type]) &&
+                            call_user_func_array($this->_plugins['resource'][$_resource_type][0][0],
+                                                 array($_resource_name, &$params['source_content'], &$this));
+                    } else {
+                        $_source_return = true;
+                    }
+
+                    $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) &&
+                        call_user_func_array($this->_plugins['resource'][$_resource_type][0][1],
+                                             array($_resource_name, &$params['resource_timestamp'], &$this));
+
+                    $_return = $_source_return && $_timestamp_return;
+                    break;
+            }
+        }
+
+        if (!$_return) {
+            // see if we can get a template with the default template handler
+            if (!empty($this->default_template_handler_func)) {
+                if (!is_callable($this->default_template_handler_func)) {
+                    $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist.");
+                } else {
+                    $_return = call_user_func_array(
+                        $this->default_template_handler_func,
+                        array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this));
+                }
+            }
+        }
+
+        if (!$_return) {
+            if (!$params['quiet']) {
+                $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"');
+            }
+        } else if ($_return && $this->security) {
+            require_once(SMARTY_CORE_DIR . 'core.is_secure.php');
+            if (!smarty_core_is_secure($_params, $this)) {
+                if (!$params['quiet'])
+                    $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed');
+                $params['source_content'] = null;
+                $params['resource_timestamp'] = null;
+                return false;
+            }
+        }
+        return $_return;
+    }
+
+
+    /**
+     * parse out the type and name from the resource
+     *
+     * @param string $resource_base_path
+     * @param string $resource_name
+     * @param string $resource_type
+     * @param string $resource_name
+     * @return boolean
+     */
+
+    function _parse_resource_name(&$params)
+    {
+
+        // split tpl_path by the first colon
+        $_resource_name_parts = explode(':', $params['resource_name'], 2);
+
+        if (count($_resource_name_parts) == 1) {
+            // no resource type given
+            $params['resource_type'] = $this->default_resource_type;
+            $params['resource_name'] = $_resource_name_parts[0];
+        } else {
+            if(strlen($_resource_name_parts[0]) == 1) {
+                // 1 char is not resource type, but part of filepath
+                $params['resource_type'] = $this->default_resource_type;
+                $params['resource_name'] = $params['resource_name'];
+            } else {
+                $params['resource_type'] = $_resource_name_parts[0];
+                $params['resource_name'] = $_resource_name_parts[1];
+            }
+        }
+
+        if ($params['resource_type'] == 'file') {
+            if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) {
+                // relative pathname to $params['resource_base_path']
+                // use the first directory where the file is found
+                foreach ((array)$params['resource_base_path'] as $_curr_path) {
+                    $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name'];
+                    if (file_exists($_fullpath) && is_file($_fullpath)) {
+                        $params['resource_name'] = $_fullpath;
+                        return true;
+                    }
+                    // didn't find the file, try include_path
+                    $_params = array('file_path' => $_fullpath);
+                    require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
+                    if(smarty_core_get_include_path($_params, $this)) {
+                        $params['resource_name'] = $_params['new_file_path'];
+                        return true;
+                    }
+                }
+                return false;
+            } else {
+                /* absolute path */
+                return file_exists($params['resource_name']);
+            }
+        } elseif (empty($this->_plugins['resource'][$params['resource_type']])) {
+            $_params = array('type' => $params['resource_type']);
+            require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php');
+            smarty_core_load_resource_plugin($_params, $this);
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Handle modifiers
+     *
+     * @param string|null $modifier_name
+     * @param array|null $map_array
+     * @return string result of modifiers
+     */
+    function _run_mod_handler()
+    {
+        $_args = func_get_args();
+        list($_modifier_name, $_map_array) = array_splice($_args, 0, 2);
+        list($_func_name, $_tpl_file, $_tpl_line) =
+            $this->_plugins['modifier'][$_modifier_name];
+
+        $_var = $_args[0];
+        foreach ($_var as $_key => $_val) {
+            $_args[0] = $_val;
+            $_var[$_key] = call_user_func_array($_func_name, $_args);
+        }
+        return $_var;
+    }
+
+    /**
+     * Remove starting and ending quotes from the string
+     *
+     * @param string $string
+     * @return string
+     */
+    function _dequote($string)
+    {
+        if (($string{0} == "'" || $string{0} == '"') &&
+            $string{strlen($string)-1} == $string{0})
+            return substr($string, 1, -1);
+        else
+            return $string;
+    }
+
+
+    /**
+     * read in a file
+     *
+     * @param string $filename
+     * @return string
+     */
+    function _read_file($filename)
+    {
+        if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) {
+            $contents = ($size = filesize($filename)) ? fread($fd, $size) : '';
+            fclose($fd);
+            return $contents;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * get a concrete filename for automagically created content
+     *
+     * @param string $auto_base
+     * @param string $auto_source
+     * @param string $auto_id
+     * @return string
+     * @staticvar string|null
+     * @staticvar string|null
+     */
+    function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null)
+    {
+        $_compile_dir_sep =  $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^';
+        $_return = $auto_base . DIRECTORY_SEPARATOR;
+
+        if(isset($auto_id)) {
+            // make auto_id safe for directory names
+            $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id)));
+            // split into separate directories
+            $_return .= $auto_id . $_compile_dir_sep;
+        }
+
+        if(isset($auto_source)) {
+            // make source name safe for filename
+            $_filename = urlencode(basename($auto_source));
+            $_crc32 = sprintf('%08X', crc32($auto_source));
+            // prepend %% to avoid name conflicts with
+            // with $params['auto_id'] names
+            $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep .
+                      substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32;
+            $_return .= '%%' . $_crc32 . '%%' . $_filename;
+        }
+
+        return $_return;
+    }
+
+    /**
+     * unlink a file, possibly using expiration time
+     *
+     * @param string $resource
+     * @param integer $exp_time
+     */
+    function _unlink($resource, $exp_time = null)
+    {
+        if(isset($exp_time)) {
+            if(time() - @filemtime($resource) >= $exp_time) {
+                return @unlink($resource);
+            }
+        } else {
+            return @unlink($resource);
+        }
+    }
+
+    /**
+     * returns an auto_id for auto-file-functions
+     *
+     * @param string $cache_id
+     * @param string $compile_id
+     * @return string|null
+     */
+    function _get_auto_id($cache_id=null, $compile_id=null) {
+    if (isset($cache_id))
+        return (isset($compile_id)) ? $cache_id . '|' . $compile_id  : $cache_id;
+    elseif(isset($compile_id))
+        return $compile_id;
+    else
+        return null;
+    }
+
+    /**
+     * trigger Smarty plugin error
+     *
+     * @param string $error_msg
+     * @param string $tpl_file
+     * @param integer $tpl_line
+     * @param string $file
+     * @param integer $line
+     * @param integer $error_type
+     */
+    function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null,
+            $file = null, $line = null, $error_type = E_USER_ERROR)
+    {
+        if(isset($file) && isset($line)) {
+            $info = ' ('.basename($file).", line $line)";
+        } else {
+            $info = '';
+        }
+        if (isset($tpl_line) && isset($tpl_file)) {
+            $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type);
+        } else {
+            $this->trigger_error($error_msg . $info, $error_type);
+        }
+    }
+
+
+    /**
+     * callback function for preg_replace, to call a non-cacheable block
+     * @return string
+     */
+    function _process_compiled_include_callback($match) {
+        $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3];
+        ob_start();
+        $_func($this);
+        $_ret = ob_get_contents();
+        ob_end_clean();
+        return $_ret;
+    }
+
+
+    /**
+     * called for included templates
+     *
+     * @param string $_smarty_include_tpl_file
+     * @param string $_smarty_include_vars
+     */
+
+    // $_smarty_include_tpl_file, $_smarty_include_vars
+
+    function _smarty_include($params)
+    {
+        if ($this->debugging) {
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $debug_start_time = smarty_core_get_microtime($_params, $this);
+            $this->_smarty_debug_info[] = array('type'      => 'template',
+                                                  'filename'  => $params['smarty_include_tpl_file'],
+                                                  'depth'     => ++$this->_inclusion_depth);
+            $included_tpls_idx = count($this->_smarty_debug_info) - 1;
+        }
+
+        $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']);
+
+        // config vars are treated as local, so push a copy of the
+        // current ones onto the front of the stack
+        array_unshift($this->_config, $this->_config[0]);
+
+        $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']);
+
+
+        if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path)
+            || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path))
+        {
+            include($_smarty_compile_path);
+        }
+
+        // pop the local vars off the front of the stack
+        array_shift($this->_config);
+
+        $this->_inclusion_depth--;
+
+        if ($this->debugging) {
+            // capture time for debugging info
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time;
+        }
+
+        if ($this->caching) {
+            $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true;
+        }
+    }
+
+
+    /**
+     * get or set an array of cached attributes for function that is
+     * not cacheable
+     * @return array
+     */
+    function &_smarty_cache_attrs($cache_serial, $count) {
+        $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count];
+
+        if ($this->_cache_including) {
+            /* return next set of cache_attrs */
+            $_return =& current($_cache_attrs);
+            next($_cache_attrs);
+            return $_return;
+
+        } else {
+            /* add a reference to a new set of cache_attrs */
+            $_cache_attrs[] = array();
+            return $_cache_attrs[count($_cache_attrs)-1];
+
+        }
+
+    }
+
+
+    /**
+     * wrapper for include() retaining $this
+     * @return mixed
+     */
+    function _include($filename, $once=false, $params=null)
+    {
+        if ($once) {
+            return include_once($filename);
+        } else {
+            return include($filename);
+        }
+    }
+
+
+    /**
+     * wrapper for eval() retaining $this
+     * @return mixed
+     */
+    function _eval($code, $params=null)
+    {
+        return eval($code);
+    }
+    /**#@-*/
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/Smarty_Compiler.class.php b/include/smarty/Smarty_Compiler.class.php
new file mode 100644 (file)
index 0000000..b9cb808
--- /dev/null
@@ -0,0 +1,2304 @@
+<?php
+
+/**
+ * Project:     Smarty: the PHP compiling template engine
+ * File:        Smarty_Compiler.class.php
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @link http://smarty.php.net/
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author Andrei Zmievski <andrei@php.net>
+ * @version 2.6.9
+ * @copyright 2001-2005 New Digital Group, Inc.
+ * @package Smarty
+ */
+
+/* $Id: Smarty_Compiler.class.php,v 1.367 2005/03/30 16:48:41 mohrt Exp $ */
+
+/**
+ * Template compiling class
+ * @package Smarty
+ */
+class Smarty_Compiler extends Smarty {
+
+    // internal vars
+    /**#@+
+     * @access private
+     */
+    var $_folded_blocks         =   array();    // keeps folded template blocks
+    var $_current_file          =   null;       // the current template being compiled
+    var $_current_line_no       =   1;          // line number for error messages
+    var $_capture_stack         =   array();    // keeps track of nested capture buffers
+    var $_plugin_info           =   array();    // keeps track of plugins to load
+    var $_init_smarty_vars      =   false;
+    var $_permitted_tokens      =   array('true','false','yes','no','on','off','null');
+    var $_db_qstr_regexp        =   null;        // regexps are setup in the constructor
+    var $_si_qstr_regexp        =   null;
+    var $_qstr_regexp           =   null;
+    var $_func_regexp           =   null;
+    var $_reg_obj_regexp        =   null;
+    var $_var_bracket_regexp    =   null;
+    var $_num_const_regexp      =   null;
+    var $_dvar_guts_regexp      =   null;
+    var $_dvar_regexp           =   null;
+    var $_cvar_regexp           =   null;
+    var $_svar_regexp           =   null;
+    var $_avar_regexp           =   null;
+    var $_mod_regexp            =   null;
+    var $_var_regexp            =   null;
+    var $_parenth_param_regexp  =   null;
+    var $_func_call_regexp      =   null;
+    var $_obj_ext_regexp        =   null;
+    var $_obj_start_regexp      =   null;
+    var $_obj_params_regexp     =   null;
+    var $_obj_call_regexp       =   null;
+    var $_cacheable_state       =   0;
+    var $_cache_attrs_count     =   0;
+    var $_nocache_count         =   0;
+    var $_cache_serial          =   null;
+    var $_cache_include         =   null;
+
+    var $_strip_depth           =   0;
+    var $_additional_newline    =   "\n";
+
+    /**#@-*/
+    /**
+     * The class constructor.
+     */
+    function Smarty_Compiler()
+    {
+        // matches double quoted strings:
+        // "foobar"
+        // "foo\"bar"
+        $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
+
+        // matches single quoted strings:
+        // 'foobar'
+        // 'foo\'bar'
+        $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'';
+
+        // matches single or double quoted strings
+        $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')';
+
+        // matches bracket portion of vars
+        // [0]
+        // [foo]
+        // [$bar]
+        $this->_var_bracket_regexp = '\[\$?[\w\.]+\]';
+
+        // matches numerical constants
+        // 30
+        // -12
+        // 13.22
+        $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)';
+
+        // matches $ vars (not objects):
+        // $foo
+        // $foo.bar
+        // $foo.bar.foobar
+        // $foo[0]
+        // $foo[$bar]
+        // $foo[5][blah]
+        // $foo[5].bar[$foobar][4]
+        $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))';
+        $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]';
+        $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp
+                . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?';
+        $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp;
+
+        // matches config vars:
+        // #foo#
+        // #foobar123_foo#
+        $this->_cvar_regexp = '\#\w+\#';
+
+        // matches section vars:
+        // %foo.bar%
+        $this->_svar_regexp = '\%\w+\.\w+\%';
+
+        // matches all valid variables (no quotes, no modifiers)
+        $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|'
+           . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')';
+
+        // matches valid variable syntax:
+        // $foo
+        // $foo
+        // #foo#
+        // #foo#
+        // "text"
+        // "text"
+        $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')';
+
+        // matches valid object call (one level of object nesting allowed in parameters):
+        // $foo->bar
+        // $foo->bar()
+        // $foo->bar("text")
+        // $foo->bar($foo, $bar, "text")
+        // $foo->bar($foo, "foo")
+        // $foo->bar->foo()
+        // $foo->bar->foo->bar()
+        // $foo->bar($foo->bar)
+        // $foo->bar($foo->bar())
+        // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar))
+        $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')';
+        $this->_obj_restricted_param_regexp = '(?:'
+                . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')'
+                . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)';
+        $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
+                . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)';
+        $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp
+                . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)';
+        $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)';
+        $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)';
+        
+        // matches valid modifier syntax:
+        // |foo
+        // |@foo
+        // |foo:"bar"
+        // |foo:$bar
+        // |foo:"bar":$foobar
+        // |foo|bar
+        // |foo:$foo->bar
+        $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|'
+           . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)';
+
+        // matches valid function name:
+        // foo123
+        // _foo_bar
+        $this->_func_regexp = '[a-zA-Z_]\w*';
+
+        // matches valid registered object:
+        // foo->bar
+        $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*';
+
+        // matches valid parameter values:
+        // true
+        // $foo
+        // $foo|bar
+        // #foo#
+        // #foo#|bar
+        // "text"
+        // "text"|bar
+        // $foo->bar
+        $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|'
+           . $this->_var_regexp . '|' . $this->_num_const_regexp  . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)';
+
+        // matches valid parenthesised function parameters:
+        //
+        // "text"
+        //    $foo, $bar, "text"
+        // $foo|bar, "foo"|bar, $foo->bar($foo)|bar
+        $this->_parenth_param_regexp = '(?:\((?:\w+|'
+                . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|'
+                . $this->_param_regexp . ')))*)?\))';
+
+        // matches valid function call:
+        // foo()
+        // foo_bar($foo)
+        // _foo_bar($foo,"bar")
+        // foo123($foo,$foo->bar(),"foo")
+        $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:'
+           . $this->_parenth_param_regexp . '))';
+    }
+
+    /**
+     * compile a resource
+     *
+     * sets $compiled_content to the compiled source
+     * @param string $resource_name
+     * @param string $source_content
+     * @param string $compiled_content
+     * @return true
+     */
+    function _compile_file($resource_name, $source_content, &$compiled_content)
+    {
+
+        if ($this->security) {
+            // do not allow php syntax to be executed unless specified
+            if ($this->php_handling == SMARTY_PHP_ALLOW &&
+                !$this->security_settings['PHP_HANDLING']) {
+                $this->php_handling = SMARTY_PHP_PASSTHRU;
+            }
+        }
+
+        $this->_load_filters();
+
+        $this->_current_file = $resource_name;
+        $this->_current_line_no = 1;
+        $ldq = preg_quote($this->left_delimiter, '~');
+        $rdq = preg_quote($this->right_delimiter, '~');
+
+        // run template source through prefilter functions
+        if (count($this->_plugins['prefilter']) > 0) {
+            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
+                if ($prefilter === false) continue;
+                if ($prefilter[3] || is_callable($prefilter[0])) {
+                    $source_content = call_user_func_array($prefilter[0],
+                                                            array($source_content, &$this));
+                    $this->_plugins['prefilter'][$filter_name][3] = true;
+                } else {
+                    $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented");
+                }
+            }
+        }
+
+        /* fetch all special blocks */
+        $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s";
+
+        preg_match_all($search, $source_content, $match,  PREG_SET_ORDER);
+        $this->_folded_blocks = $match;
+        reset($this->_folded_blocks);
+
+        /* replace special blocks by "{php}" */
+        $source_content = preg_replace($search.'e', "'"
+                                       . $this->_quote_replace($this->left_delimiter) . 'php'
+                                       . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'"
+                                       . $this->_quote_replace($this->right_delimiter)
+                                       . "'"
+                                       , $source_content);
+
+        /* Gather all template tags. */
+        preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match);
+        $template_tags = $_match[1];
+        /* Split content by template tags to obtain non-template content. */
+        $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content);
+
+        /* loop through text blocks */
+        for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) {
+            /* match anything resembling php tags */
+            if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?php[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) {
+                /* replace tags with placeholders to prevent recursive replacements */
+                $sp_match[1] = array_unique($sp_match[1]);
+                usort($sp_match[1], '_smarty_sort_length');
+                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
+                    $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]);
+                }
+                /* process each one */
+                for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) {
+                    if ($this->php_handling == SMARTY_PHP_PASSTHRU) {
+                        /* echo php contents */
+                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]);
+                    } else if ($this->php_handling == SMARTY_PHP_QUOTE) {
+                        /* quote php tags */
+                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]);
+                    } else if ($this->php_handling == SMARTY_PHP_REMOVE) {
+                        /* remove php tags */
+                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]);
+                    } else {
+                        /* SMARTY_PHP_ALLOW, but echo non php starting tags */
+                        $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]);
+                        $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]);
+                    }
+                }
+            }
+        }
+
+        /* Compile the template tags into PHP code. */
+        $compiled_tags = array();
+        for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) {
+            $this->_current_line_no += substr_count($text_blocks[$i], "\n");
+            $compiled_tags[] = $this->_compile_tag($template_tags[$i]);
+            $this->_current_line_no += substr_count($template_tags[$i], "\n");
+        }
+        if (count($this->_tag_stack)>0) {
+            list($_open_tag, $_line_no) = end($this->_tag_stack);
+            $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__);
+            return;
+        }
+
+        /* Reformat $text_blocks between 'strip' and '/strip' tags,
+           removing spaces, tabs and newlines. */
+        $strip = false;
+        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
+            if ($compiled_tags[$i] == '{strip}') {
+                $compiled_tags[$i] = '';
+                $strip = true;
+                /* remove leading whitespaces */
+                $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]);
+            }
+            if ($strip) {
+                /* strip all $text_blocks before the next '/strip' */
+                for ($j = $i + 1; $j < $for_max; $j++) {
+                    /* remove leading and trailing whitespaces of each line */
+                    $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]);
+                    if ($compiled_tags[$j] == '{/strip}') {                       
+                        /* remove trailing whitespaces from the last text_block */
+                        $text_blocks[$j] = rtrim($text_blocks[$j]);
+                    }
+                    $text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>";
+                    if ($compiled_tags[$j] == '{/strip}') {
+                        $compiled_tags[$j] = "\n"; /* slurped by php, but necessary
+                                    if a newline is following the closing strip-tag */
+                        $strip = false;
+                        $i = $j;
+                        break;
+                    }
+                }
+            }
+        }
+        $compiled_content = '';
+
+        /* Interleave the compiled contents and text blocks to get the final result. */
+        for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) {
+            if ($compiled_tags[$i] == '') {
+                // tag result empty, remove first newline from following text block
+                $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]);
+            }
+            $compiled_content .= $text_blocks[$i].$compiled_tags[$i];
+        }
+        $compiled_content .= $text_blocks[$i];
+
+        // remove \n from the end of the file, if any
+        if (($_len=strlen($compiled_content)) && ($compiled_content{$_len - 1} == "\n" )) {
+            $compiled_content = substr($compiled_content, 0, -1);
+        }
+
+        if (!empty($this->_cache_serial)) {
+            $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content;
+        }
+
+        // remove unnecessary close/open tags
+        $compiled_content = preg_replace('~\?>\n?<\?php~', '', $compiled_content);
+
+        // run compiled template through postfilter functions
+        if (count($this->_plugins['postfilter']) > 0) {
+            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
+                if ($postfilter === false) continue;
+                if ($postfilter[3] || is_callable($postfilter[0])) {
+                    $compiled_content = call_user_func_array($postfilter[0],
+                                                              array($compiled_content, &$this));
+                    $this->_plugins['postfilter'][$filter_name][3] = true;
+                } else {
+                    $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented");
+                }
+            }
+        }
+
+        // put header at the top of the compiled template
+        $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
+        $template_header .= "         compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n";
+
+        /* Emit code to load needed plugins. */
+        $this->_plugins_code = '';
+        if (count($this->_plugin_info)) {
+            $_plugins_params = "array('plugins' => array(";
+            foreach ($this->_plugin_info as $plugin_type => $plugins) {
+                foreach ($plugins as $plugin_name => $plugin_info) {
+                    $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], ";
+                    $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),';
+                }
+            }
+            $_plugins_params .= '))';
+            $plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n";
+            $template_header .= $plugins_code;
+            $this->_plugin_info = array();
+            $this->_plugins_code = $plugins_code;
+        }
+
+        if ($this->_init_smarty_vars) {
+            $template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n";
+            $this->_init_smarty_vars = false;
+        }
+
+        $compiled_content = $template_header . $compiled_content;
+        return true;
+    }
+
+    /**
+     * Compile a template tag
+     *
+     * @param string $template_tag
+     * @return string
+     */
+    function _compile_tag($template_tag)
+    {
+        /* Matched comment. */
+        if ($template_tag{0} == '*' && $template_tag{strlen($template_tag) - 1} == '*')
+            return '';
+        
+        /* Split tag into two three parts: command, command modifiers and the arguments. */
+        if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp
+                . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*))
+                      (?:\s+(.*))?$
+                    ~xs', $template_tag, $match)) {
+            $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__);
+        }
+        
+        $tag_command = $match[1];
+        $tag_modifier = isset($match[2]) ? $match[2] : null;
+        $tag_args = isset($match[3]) ? $match[3] : null;
+
+        if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) {
+            /* tag name is a variable or object */
+            $_return = $this->_parse_var_props($tag_command . $tag_modifier);
+            return "<?php echo $_return; ?>" . $this->_additional_newline;
+        }
+
+        /* If the tag name is a registered object, we process it. */
+        if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) {
+            return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier);
+        }
+
+        switch ($tag_command) {
+            case 'include':
+                return $this->_compile_include_tag($tag_args);
+
+            case 'include_php':
+                return $this->_compile_include_php_tag($tag_args);
+
+            case 'if':
+                $this->_push_tag('if');
+                return $this->_compile_if_tag($tag_args);
+
+            case 'else':
+                list($_open_tag) = end($this->_tag_stack);
+                if ($_open_tag != 'if' && $_open_tag != 'elseif')
+                    $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__);
+                else
+                    $this->_push_tag('else');
+                return '<?php else: ?>';
+
+            case 'elseif':
+                list($_open_tag) = end($this->_tag_stack);
+                if ($_open_tag != 'if' && $_open_tag != 'elseif')
+                    $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__);
+                if ($_open_tag == 'if')
+                    $this->_push_tag('elseif');
+                return $this->_compile_if_tag($tag_args, true);
+
+            case '/if':
+                $this->_pop_tag('if');
+                return '<?php endif; ?>';
+
+            case 'capture':
+                return $this->_compile_capture_tag(true, $tag_args);
+
+            case '/capture':
+                return $this->_compile_capture_tag(false);
+
+            case 'ldelim':
+                return $this->left_delimiter;
+
+            case 'rdelim':
+                return $this->right_delimiter;
+
+            case 'section':
+                $this->_push_tag('section');
+                return $this->_compile_section_start($tag_args);
+
+            case 'sectionelse':
+                $this->_push_tag('sectionelse');
+                return "<?php endfor; else: ?>";
+                break;
+
+            case '/section':
+                $_open_tag = $this->_pop_tag('section');
+                if ($_open_tag == 'sectionelse')
+                    return "<?php endif; ?>";
+                else
+                    return "<?php endfor; endif; ?>";
+
+            case 'foreach':
+                $this->_push_tag('foreach');
+                return $this->_compile_foreach_start($tag_args);
+                break;
+
+            case 'foreachelse':
+                $this->_push_tag('foreachelse');
+                return "<?php endforeach; else: ?>";
+
+            case '/foreach':
+                $_open_tag = $this->_pop_tag('foreach');
+                if ($_open_tag == 'foreachelse')
+                    return "<?php endif; unset(\$_from); ?>";
+                else
+                    return "<?php endforeach; endif; unset(\$_from); ?>";
+                break;
+
+            case 'strip':
+            case '/strip':
+                if ($tag_command{0}=='/') {
+                    $this->_pop_tag('strip');
+                    if (--$this->_strip_depth==0) { /* outermost closing {/strip} */
+                        $this->_additional_newline = "\n";
+                        return '{' . $tag_command . '}';
+                    }
+                } else {
+                    $this->_push_tag('strip');
+                    if ($this->_strip_depth++==0) { /* outermost opening {strip} */
+                        $this->_additional_newline = "";
+                        return '{' . $tag_command . '}';
+                    }
+                }
+                return '';
+
+            case 'php':
+                /* handle folded tags replaced by {php} */
+                list(, $block) = each($this->_folded_blocks);
+                $this->_current_line_no += substr_count($block[0], "\n");
+                /* the number of matched elements in the regexp in _compile_file()
+                   determins the type of folded tag that was found */
+                switch (count($block)) {
+                    case 2: /* comment */
+                        return '';
+
+                    case 3: /* literal */
+                        return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline;
+
+                    case 4: /* php */
+                        if ($this->security && !$this->security_settings['PHP_TAGS']) {
+                            $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__);
+                            return;
+                        }
+                        return '<?php ' . $block[3] .' ?>';
+                }
+                break;
+
+            case 'insert':
+                return $this->_compile_insert_tag($tag_args);
+
+            default:
+                if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) {
+                    return $output;
+                } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) {
+                    return $output;
+                } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) {
+                    return $output;                    
+                } else {
+                    $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__);
+                }
+
+        }
+    }
+
+
+    /**
+     * compile the custom compiler tag
+     *
+     * sets $output to the compiled custom compiler tag
+     * @param string $tag_command
+     * @param string $tag_args
+     * @param string $output
+     * @return boolean
+     */
+    function _compile_compiler_tag($tag_command, $tag_args, &$output)
+    {
+        $found = false;
+        $have_function = true;
+
+        /*
+         * First we check if the compiler function has already been registered
+         * or loaded from a plugin file.
+         */
+        if (isset($this->_plugins['compiler'][$tag_command])) {
+            $found = true;
+            $plugin_func = $this->_plugins['compiler'][$tag_command][0];
+            if (!is_callable($plugin_func)) {
+                $message = "compiler function '$tag_command' is not implemented";
+                $have_function = false;
+            }
+        }
+        /*
+         * Otherwise we need to load plugin file and look for the function
+         * inside it.
+         */
+        else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) {
+            $found = true;
+
+            include_once $plugin_file;
+
+            $plugin_func = 'smarty_compiler_' . $tag_command;
+            if (!is_callable($plugin_func)) {
+                $message = "plugin function $plugin_func() not found in $plugin_file\n";
+                $have_function = false;
+            } else {
+                $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true);
+            }
+        }
+
+        /*
+         * True return value means that we either found a plugin or a
+         * dynamically registered function. False means that we didn't and the
+         * compiler should now emit code to load custom function plugin for this
+         * tag.
+         */
+        if ($found) {
+            if ($have_function) {
+                $output = call_user_func_array($plugin_func, array($tag_args, &$this));
+                if($output != '') {
+                $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command)
+                                   . $output
+                                   . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>';
+                }
+            } else {
+                $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * compile block function tag
+     *
+     * sets $output to compiled block function tag
+     * @param string $tag_command
+     * @param string $tag_args
+     * @param string $tag_modifier
+     * @param string $output
+     * @return boolean
+     */
+    function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output)
+    {
+        if ($tag_command{0} == '/') {
+            $start_tag = false;
+            $tag_command = substr($tag_command, 1);
+        } else
+            $start_tag = true;
+
+        $found = false;
+        $have_function = true;
+
+        /*
+         * First we check if the block function has already been registered
+         * or loaded from a plugin file.
+         */
+        if (isset($this->_plugins['block'][$tag_command])) {
+            $found = true;
+            $plugin_func = $this->_plugins['block'][$tag_command][0];
+            if (!is_callable($plugin_func)) {
+                $message = "block function '$tag_command' is not implemented";
+                $have_function = false;
+            }
+        }
+        /*
+         * Otherwise we need to load plugin file and look for the function
+         * inside it.
+         */
+        else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) {
+            $found = true;
+
+            include_once $plugin_file;
+
+            $plugin_func = 'smarty_block_' . $tag_command;
+            if (!function_exists($plugin_func)) {
+                $message = "plugin function $plugin_func() not found in $plugin_file\n";
+                $have_function = false;
+            } else {
+                $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true);
+
+            }
+        }
+
+        if (!$found) {
+            return false;
+        } else if (!$have_function) {
+            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
+            return true;
+        }
+
+        /*
+         * Even though we've located the plugin function, compilation
+         * happens only once, so the plugin will still need to be loaded
+         * at runtime for future requests.
+         */
+        $this->_add_plugin('block', $tag_command);
+
+        if ($start_tag)
+            $this->_push_tag($tag_command);
+        else
+            $this->_pop_tag($tag_command);
+
+        if ($start_tag) {
+            $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command);
+            $attrs = $this->_parse_attrs($tag_args);
+            $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs='');
+            $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); ';
+            $output .= $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat=true);';
+            $output .= 'while ($_block_repeat) { ob_start(); ?>';
+        } else {
+            $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); ';
+            $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat=false)';
+            if ($tag_modifier != '') {
+                $this->_parse_modifiers($_out_tag_text, $tag_modifier);
+            }
+            $output .= 'echo '.$_out_tag_text.'; } ';
+            $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>';
+        }
+
+        return true;
+    }
+
+
+    /**
+     * compile custom function tag
+     *
+     * @param string $tag_command
+     * @param string $tag_args
+     * @param string $tag_modifier
+     * @return string
+     */
+    function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output)
+    {
+        $found = false;
+        $have_function = true;
+
+        /*
+         * First we check if the custom function has already been registered
+         * or loaded from a plugin file.
+         */
+        if (isset($this->_plugins['function'][$tag_command])) {
+            $found = true;
+            $plugin_func = $this->_plugins['function'][$tag_command][0];
+            if (!is_callable($plugin_func)) {
+                $message = "custom function '$tag_command' is not implemented";
+                $have_function = false;
+            }
+        }
+        /*
+         * Otherwise we need to load plugin file and look for the function
+         * inside it.
+         */
+        else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) {
+            $found = true;
+
+            include_once $plugin_file;
+
+            $plugin_func = 'smarty_function_' . $tag_command;
+            if (!function_exists($plugin_func)) {
+                $message = "plugin function $plugin_func() not found in $plugin_file\n";
+                $have_function = false;
+            } else {
+                $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true);
+
+            }
+        }
+
+        if (!$found) {
+            return false;
+        } else if (!$have_function) {
+            $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__);
+            return true;
+        }
+
+        /* declare plugin to be loaded on display of the template that
+           we compile right now */
+        $this->_add_plugin('function', $tag_command);
+
+        $_cacheable_state = $this->_push_cacheable_state('function', $tag_command);
+        $attrs = $this->_parse_attrs($tag_args);
+        $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs='');
+
+        $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)";
+        if($tag_modifier != '') {
+            $this->_parse_modifiers($output, $tag_modifier);
+        }
+
+        if($output != '') {
+            $output =  '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';'
+                . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline;
+        }
+
+        return true;
+    }
+
+    /**
+     * compile a registered object tag
+     *
+     * @param string $tag_command
+     * @param array $attrs
+     * @param string $tag_modifier
+     * @return string
+     */
+    function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier)
+    {
+        if ($tag_command{0} == '/') {
+            $start_tag = false;
+            $tag_command = substr($tag_command, 1);
+        } else {
+            $start_tag = true;
+        }
+
+        list($object, $obj_comp) = explode('->', $tag_command);
+
+        $arg_list = array();
+        if(count($attrs)) {
+            $_assign_var = false;
+            foreach ($attrs as $arg_name => $arg_value) {
+                if($arg_name == 'assign') {
+                    $_assign_var = $arg_value;
+                    unset($attrs['assign']);
+                    continue;
+                }
+                if (is_bool($arg_value))
+                    $arg_value = $arg_value ? 'true' : 'false';
+                $arg_list[] = "'$arg_name' => $arg_value";
+            }
+        }
+
+        if($this->_reg_objects[$object][2]) {
+            // smarty object argument format
+            $args = "array(".implode(',', (array)$arg_list)."), \$this";
+        } else {
+            // traditional argument format
+            $args = implode(',', array_values($attrs));
+            if (empty($args)) {
+                $args = 'null';
+            }
+        }
+
+        $prefix = '';
+        $postfix = '';
+        $newline = '';
+        if(!is_object($this->_reg_objects[$object][0])) {
+            $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
+        } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) {
+            $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
+        } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) {
+            // method
+            if(in_array($obj_comp, $this->_reg_objects[$object][3])) {
+                // block method
+                if ($start_tag) {
+                    $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); ";
+                    $prefix .= "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat=true); ";
+                    $prefix .= "while (\$_block_repeat) { ob_start();";
+                    $return = null;
+                    $postfix = '';
+            } else {
+                    $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); ";
+                    $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat=false)";
+                    $postfix = "} array_pop(\$this->_tag_stack);";
+                }
+            } else {
+                // non-block method
+                $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)";
+            }
+        } else {
+            // property
+            $return = "\$this->_reg_objects['$object'][0]->$obj_comp";
+        }
+
+        if($return != null) {
+            if($tag_modifier != '') {
+                $this->_parse_modifiers($return, $tag_modifier);
+            }
+
+            if(!empty($_assign_var)) {
+                $output = "\$this->assign('" . $this->_dequote($_assign_var) ."',  $return);";
+            } else {
+                $output = 'echo ' . $return . ';';
+                $newline = $this->_additional_newline;
+            }
+        } else {
+            $output = '';
+        }
+
+        return '<?php ' . $prefix . $output . $postfix . "?>" . $newline;
+    }
+
+    /**
+     * Compile {insert ...} tag
+     *
+     * @param string $tag_args
+     * @return string
+     */
+    function _compile_insert_tag($tag_args)
+    {
+        $attrs = $this->_parse_attrs($tag_args);
+        $name = $this->_dequote($attrs['name']);
+
+        if (empty($name)) {
+            $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        if (!empty($attrs['script'])) {
+            $delayed_loading = true;
+        } else {
+            $delayed_loading = false;
+        }
+
+        foreach ($attrs as $arg_name => $arg_value) {
+            if (is_bool($arg_value))
+                $arg_value = $arg_value ? 'true' : 'false';
+            $arg_list[] = "'$arg_name' => $arg_value";
+        }
+
+        $this->_add_plugin('insert', $name, $delayed_loading);
+
+        $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))";
+
+        return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline;
+    }
+
+    /**
+     * Compile {include ...} tag
+     *
+     * @param string $tag_args
+     * @return string
+     */
+    function _compile_include_tag($tag_args)
+    {
+        $attrs = $this->_parse_attrs($tag_args);
+        $arg_list = array();
+
+        if (empty($attrs['file'])) {
+            $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        foreach ($attrs as $arg_name => $arg_value) {
+            if ($arg_name == 'file') {
+                $include_file = $arg_value;
+                continue;
+            } else if ($arg_name == 'assign') {
+                $assign_var = $arg_value;
+                continue;
+            }
+            if (is_bool($arg_value))
+                $arg_value = $arg_value ? 'true' : 'false';
+            $arg_list[] = "'$arg_name' => $arg_value";
+        }
+
+        $output = '<?php ';
+
+        if (isset($assign_var)) {
+            $output .= "ob_start();\n";
+        }
+
+        $output .=
+            "\$_smarty_tpl_vars = \$this->_tpl_vars;\n";
+
+
+        $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))";
+        $output .= "\$this->_smarty_include($_params);\n" .
+        "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" .
+        "unset(\$_smarty_tpl_vars);\n";
+
+        if (isset($assign_var)) {
+            $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n";
+        }
+
+        $output .= ' ?>';
+
+        return $output;
+
+    }
+
+    /**
+     * Compile {include ...} tag
+     *
+     * @param string $tag_args
+     * @return string
+     */
+    function _compile_include_php_tag($tag_args)
+    {
+        $attrs = $this->_parse_attrs($tag_args);
+
+        if (empty($attrs['file'])) {
+            $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']);
+        $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true';
+
+        $arg_list = array();
+        foreach($attrs as $arg_name => $arg_value) {
+            if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') {
+                if(is_bool($arg_value))
+                    $arg_value = $arg_value ? 'true' : 'false';
+                $arg_list[] = "'$arg_name' => $arg_value";
+            }
+        }
+
+        $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))";
+
+        return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline;
+    }
+
+
+    /**
+     * Compile {section ...} tag
+     *
+     * @param string $tag_args
+     * @return string
+     */
+    function _compile_section_start($tag_args)
+    {
+        $attrs = $this->_parse_attrs($tag_args);
+        $arg_list = array();
+
+        $output = '<?php ';
+        $section_name = $attrs['name'];
+        if (empty($section_name)) {
+            $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        $output .= "unset(\$this->_sections[$section_name]);\n";
+        $section_props = "\$this->_sections[$section_name]";
+
+        foreach ($attrs as $attr_name => $attr_value) {
+            switch ($attr_name) {
+                case 'loop':
+                    $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
+                    break;
+
+                case 'show':
+                    if (is_bool($attr_value))
+                        $show_attr_value = $attr_value ? 'true' : 'false';
+                    else
+                        $show_attr_value = "(bool)$attr_value";
+                    $output .= "{$section_props}['show'] = $show_attr_value;\n";
+                    break;
+
+                case 'name':
+                    $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
+                    break;
+
+                case 'max':
+                case 'start':
+                    $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
+                    break;
+
+                case 'step':
+                    $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
+                    break;
+
+                default:
+                    $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__);
+                    break;
+            }
+        }
+
+        if (!isset($attrs['show']))
+            $output .= "{$section_props}['show'] = true;\n";
+
+        if (!isset($attrs['loop']))
+            $output .= "{$section_props}['loop'] = 1;\n";
+
+        if (!isset($attrs['max']))
+            $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
+        else
+            $output .= "if ({$section_props}['max'] < 0)\n" .
+                       "    {$section_props}['max'] = {$section_props}['loop'];\n";
+
+        if (!isset($attrs['step']))
+            $output .= "{$section_props}['step'] = 1;\n";
+
+        if (!isset($attrs['start']))
+            $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
+        else {
+            $output .= "if ({$section_props}['start'] < 0)\n" .
+                       "    {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" .
+                       "else\n" .
+                       "    {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
+        }
+
+        $output .= "if ({$section_props}['show']) {\n";
+        if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) {
+            $output .= "    {$section_props}['total'] = {$section_props}['loop'];\n";
+        } else {
+            $output .= "    {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n";
+        }
+        $output .= "    if ({$section_props}['total'] == 0)\n" .
+                   "        {$section_props}['show'] = false;\n" .
+                   "} else\n" .
+                   "    {$section_props}['total'] = 0;\n";
+
+        $output .= "if ({$section_props}['show']):\n";
+        $output .= "
+            for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
+                 {$section_props}['iteration'] <= {$section_props}['total'];
+                 {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
+        $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
+        $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
+        $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
+        $output .= "{$section_props}['first']      = ({$section_props}['iteration'] == 1);\n";
+        $output .= "{$section_props}['last']       = ({$section_props}['iteration'] == {$section_props}['total']);\n";
+
+        $output .= "?>";
+
+        return $output;
+    }
+
+
+    /**
+     * Compile {foreach ...} tag.
+     *
+     * @param string $tag_args
+     * @return string
+     */
+    function _compile_foreach_start($tag_args)
+    {
+        $attrs = $this->_parse_attrs($tag_args);
+        $arg_list = array();
+
+        if (empty($attrs['from'])) {
+            return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__);
+        }
+        $from = $attrs['from'];
+
+        if (empty($attrs['item'])) {
+            return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__);
+        }
+        $item = $this->_dequote($attrs['item']);
+        if (!preg_match('~^\w+$~', $item)) {
+            return $this->_syntax_error("'foreach: item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        if (isset($attrs['key'])) {
+            $key  = $this->_dequote($attrs['key']);
+            if (!preg_match('~^\w+$~', $key)) {
+                return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__);
+            }
+            $key_part = "\$this->_tpl_vars['$key'] => ";
+        } else {
+            $key = null;
+            $key_part = '';
+        }
+
+        if (isset($attrs['name'])) {
+            $name = $attrs['name'];
+        } else {
+            $name = null;
+        }
+
+        $output = '<?php ';
+        $output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }";
+        if (isset($name)) {
+            $foreach_props = "\$this->_foreach[$name]";
+            $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n";
+            $output .= "if ({$foreach_props}['total'] > 0):\n";
+            $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
+            $output .= "        {$foreach_props}['iteration']++;\n";
+        } else {
+            $output .= "if (count(\$_from)):\n";
+            $output .= "    foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n";
+        }
+        $output .= '?>';
+
+        return $output;
+    }
+
+
+    /**
+     * Compile {capture} .. {/capture} tags
+     *
+     * @param boolean $start true if this is the {capture} tag
+     * @param string $tag_args
+     * @return string
+     */
+
+    function _compile_capture_tag($start, $tag_args = '')
+    {
+        $attrs = $this->_parse_attrs($tag_args);
+
+        if ($start) {
+            if (isset($attrs['name']))
+                $buffer = $attrs['name'];
+            else
+                $buffer = "'default'";
+
+            if (isset($attrs['assign']))
+                $assign = $attrs['assign'];
+            else
+                $assign = null;
+            $output = "<?php ob_start(); ?>";
+            $this->_capture_stack[] = array($buffer, $assign);
+        } else {
+            list($buffer, $assign) = array_pop($this->_capture_stack);
+            $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); ";
+            if (isset($assign)) {
+                $output .= " \$this->assign($assign, ob_get_contents());";
+            }
+            $output .= "ob_end_clean(); ?>";
+        }
+
+        return $output;
+    }
+
+    /**
+     * Compile {if ...} tag
+     *
+     * @param string $tag_args
+     * @param boolean $elseif if true, uses elseif instead of if
+     * @return string
+     */
+    function _compile_if_tag($tag_args, $elseif = false)
+    {
+
+        /* Tokenize args for 'if' tag. */
+        preg_match_all('~(?>
+                ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call
+                ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)?    | # var or quoted string
+                \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@    | # valid non-word token
+                \b\w+\b                                                        | # valid word token
+                \S+                                                           # anything else
+                )~x', $tag_args, $match);
+
+        $tokens = $match[0];
+
+        // make sure we have balanced parenthesis
+        $token_count = array_count_values($tokens);
+        if(isset($token_count['(']) && $token_count['('] != $token_count[')']) {
+            $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        $is_arg_stack = array();
+
+        for ($i = 0; $i < count($tokens); $i++) {
+
+            $token = &$tokens[$i];
+
+            switch (strtolower($token)) {
+                case '!':
+                case '%':
+                case '!==':
+                case '==':
+                case '===':
+                case '>':
+                case '<':
+                case '!=':
+                case '<>':
+                case '<<':
+                case '>>':
+                case '<=':
+                case '>=':
+                case '&&':
+                case '||':
+                case '|':
+                case '^':
+                case '&':
+                case '~':
+                case ')':
+                case ',':
+                case '+':
+                case '-':
+                case '*':
+                case '/':
+                case '@':
+                    break;
+
+                case 'eq':
+                    $token = '==';
+                    break;
+
+                case 'ne':
+                case 'neq':
+                    $token = '!=';
+                    break;
+
+                case 'lt':
+                    $token = '<';
+                    break;
+
+                case 'le':
+                case 'lte':
+                    $token = '<=';
+                    break;
+
+                case 'gt':
+                    $token = '>';
+                    break;
+
+                case 'ge':
+                case 'gte':
+                    $token = '>=';
+                    break;
+
+                case 'and':
+                    $token = '&&';
+                    break;
+
+                case 'or':
+                    $token = '||';
+                    break;
+
+                case 'not':
+                    $token = '!';
+                    break;
+
+                case 'mod':
+                    $token = '%';
+                    break;
+
+                case '(':
+                    array_push($is_arg_stack, $i);
+                    break;
+
+                case 'is':
+                    /* If last token was a ')', we operate on the parenthesized
+                       expression. The start of the expression is on the stack.
+                       Otherwise, we operate on the last encountered token. */
+                    if ($tokens[$i-1] == ')')
+                        $is_arg_start = array_pop($is_arg_stack);
+                    else
+                        $is_arg_start = $i-1;
+                    /* Construct the argument for 'is' expression, so it knows
+                       what to operate on. */
+                    $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
+
+                    /* Pass all tokens from next one until the end to the
+                       'is' expression parsing function. The function will
+                       return modified tokens, where the first one is the result
+                       of the 'is' expression and the rest are the tokens it
+                       didn't touch. */
+                    $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
+
+                    /* Replace the old tokens with the new ones. */
+                    array_splice($tokens, $is_arg_start, count($tokens), $new_tokens);
+
+                    /* Adjust argument start so that it won't change from the
+                       current position for the next iteration. */
+                    $i = $is_arg_start;
+                    break;
+
+                default:
+                    if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) {
+                            // function call
+                            if($this->security &&
+                               !in_array($token, $this->security_settings['IF_FUNCS'])) {
+                                $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);
+                            }
+                    } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') {
+                        // variable function call
+                        $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__);                      
+                    } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) {
+                        // object or variable
+                        $token = $this->_parse_var_props($token);
+                    } elseif(is_numeric($token)) {
+                        // number, skip it
+                    } else {
+                        $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__);
+                    }
+                    break;
+            }
+        }
+
+        if ($elseif)
+            return '<?php elseif ('.implode(' ', $tokens).'): ?>';
+        else
+            return '<?php if ('.implode(' ', $tokens).'): ?>';
+    }
+
+
+    function _compile_arg_list($type, $name, $attrs, &$cache_code) {
+        $arg_list = array();
+
+        if (isset($type) && isset($name)
+            && isset($this->_plugins[$type])
+            && isset($this->_plugins[$type][$name])
+            && empty($this->_plugins[$type][$name][4])
+            && is_array($this->_plugins[$type][$name][5])
+            ) {
+            /* we have a list of parameters that should be cached */
+            $_cache_attrs = $this->_plugins[$type][$name][5];
+            $_count = $this->_cache_attrs_count++;
+            $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');";
+
+        } else {
+            /* no parameters are cached */
+            $_cache_attrs = null;
+        }
+
+        foreach ($attrs as $arg_name => $arg_value) {
+            if (is_bool($arg_value))
+                $arg_value = $arg_value ? 'true' : 'false';
+            if (is_null($arg_value))
+                $arg_value = 'null';
+            if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) {
+                $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)";
+            } else {
+                $arg_list[] = "'$arg_name' => $arg_value";
+            }
+        }
+        return $arg_list;
+    }
+
+    /**
+     * Parse is expression
+     *
+     * @param string $is_arg
+     * @param array $tokens
+     * @return array
+     */
+    function _parse_is_expr($is_arg, $tokens)
+    {
+        $expr_end = 0;
+        $negate_expr = false;
+
+        if (($first_token = array_shift($tokens)) == 'not') {
+            $negate_expr = true;
+            $expr_type = array_shift($tokens);
+        } else
+            $expr_type = $first_token;
+
+        switch ($expr_type) {
+            case 'even':
+                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
+                    $expr_end++;
+                    $expr_arg = $tokens[$expr_end++];
+                    $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
+                } else
+                    $expr = "!(1 & $is_arg)";
+                break;
+
+            case 'odd':
+                if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') {
+                    $expr_end++;
+                    $expr_arg = $tokens[$expr_end++];
+                    $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))";
+                } else
+                    $expr = "(1 & $is_arg)";
+                break;
+
+            case 'div':
+                if (@$tokens[$expr_end] == 'by') {
+                    $expr_end++;
+                    $expr_arg = $tokens[$expr_end++];
+                    $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")";
+                } else {
+                    $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__);
+                }
+                break;
+
+            default:
+                $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__);
+                break;
+        }
+
+        if ($negate_expr) {
+            $expr = "!($expr)";
+        }
+
+        array_splice($tokens, 0, $expr_end, $expr);
+
+        return $tokens;
+    }
+
+
+    /**
+     * Parse attribute string
+     *
+     * @param string $tag_args
+     * @return array
+     */
+    function _parse_attrs($tag_args)
+    {
+
+        /* Tokenize tag attributes. */
+        preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+)
+                         )+ |
+                         [=]
+                        ~x', $tag_args, $match);
+        $tokens       = $match[0];
+
+        $attrs = array();
+        /* Parse state:
+            0 - expecting attribute name
+            1 - expecting '='
+            2 - expecting attribute value (not '=') */
+        $state = 0;
+
+        foreach ($tokens as $token) {
+            switch ($state) {
+                case 0:
+                    /* If the token is a valid identifier, we set attribute name
+                       and go to state 1. */
+                    if (preg_match('~^\w+$~', $token)) {
+                        $attr_name = $token;
+                        $state = 1;
+                    } else
+                        $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__);
+                    break;
+
+                case 1:
+                    /* If the token is '=', then we go to state 2. */
+                    if ($token == '=') {
+                        $state = 2;
+                    } else
+                        $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
+                    break;
+
+                case 2:
+                    /* If token is not '=', we set the attribute value and go to
+                       state 0. */
+                    if ($token != '=') {
+                        /* We booleanize the token if it's a non-quoted possible
+                           boolean value. */
+                        if (preg_match('~^(on|yes|true)$~', $token)) {
+                            $token = 'true';
+                        } else if (preg_match('~^(off|no|false)$~', $token)) {
+                            $token = 'false';
+                        } else if ($token == 'null') {
+                            $token = 'null';
+                        } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) {
+                            /* treat integer literally */
+                        } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) {
+                            /* treat as a string, double-quote it escaping quotes */
+                            $token = '"'.addslashes($token).'"';
+                        }
+
+                        $attrs[$attr_name] = $token;
+                        $state = 0;
+                    } else
+                        $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__);
+                    break;
+            }
+            $last_token = $token;
+        }
+
+        if($state != 0) {
+            if($state == 1) {
+                $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__);
+            } else {
+                $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__);
+            }
+        }
+
+        $this->_parse_vars_props($attrs);
+
+        return $attrs;
+    }
+
+    /**
+     * compile multiple variables and section properties tokens into
+     * PHP code
+     *
+     * @param array $tokens
+     */
+    function _parse_vars_props(&$tokens)
+    {
+        foreach($tokens as $key => $val) {
+            $tokens[$key] = $this->_parse_var_props($val);
+        }
+    }
+
+    /**
+     * compile single variable and section properties token into
+     * PHP code
+     *
+     * @param string $val
+     * @param string $tag_attrs
+     * @return string
+     */
+    function _parse_var_props($val)
+    {
+        $val = trim($val);
+
+        if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) {
+            // $ variable or object
+            $return = $this->_parse_var($match[1]);
+            $modifiers = $match[2];
+            if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) {
+                $_default_mod_string = implode('|',(array)$this->default_modifiers);
+                $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers;
+            }
+            $this->_parse_modifiers($return, $modifiers);
+            return $return;
+        } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+                // double quoted text
+                preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
+                $return = $this->_expand_quoted_text($match[1]);
+                if($match[2] != '') {
+                    $this->_parse_modifiers($return, $match[2]);
+                }
+                return $return;
+            }
+        elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+                // numerical constant
+                preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
+                if($match[2] != '') {
+                    $this->_parse_modifiers($match[1], $match[2]);
+                    return $match[1];
+                }
+            }
+        elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+                // single quoted text
+                preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match);
+                if($match[2] != '') {
+                    $this->_parse_modifiers($match[1], $match[2]);
+                    return $match[1];
+                }
+            }
+        elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+                // config var
+                return $this->_parse_conf_var($val);
+            }
+        elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) {
+                // section var
+                return $this->_parse_section_prop($val);
+            }
+        elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) {
+            // literal string
+            return $this->_expand_quoted_text('"' . $val .'"');
+        }
+        return $val;
+    }
+
+    /**
+     * expand quoted text with embedded variables
+     *
+     * @param string $var_expr
+     * @return string
+     */
+    function _expand_quoted_text($var_expr)
+    {
+        // if contains unescaped $, expand it
+        if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) {
+            $_match = $_match[0];
+            rsort($_match);
+            reset($_match);
+            foreach($_match as $_var) {
+                $var_expr = str_replace ($_var, '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."', $var_expr);
+            }
+            $_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr);
+        } else {
+            $_return = $var_expr;
+        }
+        // replace double quoted literal string with single quotes
+        $_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return);
+        return $_return;
+    }
+
+    /**
+     * parse variable expression into PHP code
+     *
+     * @param string $var_expr
+     * @param string $output
+     * @return string
+     */
+    function _parse_var($var_expr)
+    {
+        $_has_math = false;
+        $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE);
+
+        if(count($_math_vars) > 1) {
+            $_first_var = "";
+            $_complete_var = "";
+            $_output = "";
+            // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter)
+            foreach($_math_vars as $_k => $_math_var) {
+                $_math_var = $_math_vars[$_k];
+
+                if(!empty($_math_var) || is_numeric($_math_var)) {
+                    // hit a math operator, so process the stuff which came before it
+                    if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) {
+                        $_has_math = true;
+                        if(!empty($_complete_var) || is_numeric($_complete_var)) {
+                            $_output .= $this->_parse_var($_complete_var);
+                        }
+
+                        // just output the math operator to php
+                        $_output .= $_math_var;
+
+                        if(empty($_first_var))
+                            $_first_var = $_complete_var;
+
+                        $_complete_var = "";
+                    } else {
+                        $_complete_var .= $_math_var;
+                    }
+                }
+            }
+            if($_has_math) {
+                if(!empty($_complete_var) || is_numeric($_complete_var))
+                    $_output .= $this->_parse_var($_complete_var);
+
+                // get the modifiers working (only the last var from math + modifier is left)
+                $var_expr = $_complete_var;
+            }
+        }
+
+        // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit)
+        if(is_numeric($var_expr{0}))
+            $_var_ref = $var_expr;
+        else
+            $_var_ref = substr($var_expr, 1);
+        
+        if(!$_has_math) {
+            
+            // get [foo] and .foo and ->foo and (...) pieces
+            preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match);
+                        
+            $_indexes = $match[0];
+            $_var_name = array_shift($_indexes);
+
+            /* Handle $smarty.* variable references as a special case. */
+            if ($_var_name == 'smarty') {
+                /*
+                 * If the reference could be compiled, use the compiled output;
+                 * otherwise, fall back on the $smarty variable generated at
+                 * run-time.
+                 */
+                if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) {
+                    $_output = $smarty_ref;
+                } else {
+                    $_var_name = substr(array_shift($_indexes), 1);
+                    $_output = "\$this->_smarty_vars['$_var_name']";
+                }
+            } elseif(is_numeric($_var_name) && is_numeric($var_expr{0})) {
+                // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers
+                if(count($_indexes) > 0)
+                {
+                    $_var_name .= implode("", $_indexes);
+                    $_indexes = array();
+                }
+                $_output = $_var_name;
+            } else {
+                $_output = "\$this->_tpl_vars['$_var_name']";
+            }
+
+            foreach ($_indexes as $_index) {
+                if ($_index{0} == '[') {
+                    $_index = substr($_index, 1, -1);
+                    if (is_numeric($_index)) {
+                        $_output .= "[$_index]";
+                    } elseif ($_index{0} == '$') {
+                        if (strpos($_index, '.') !== false) {
+                            $_output .= '[' . $this->_parse_var($_index) . ']';
+                        } else {
+                            $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]";
+                        }
+                    } else {
+                        $_var_parts = explode('.', $_index);
+                        $_var_section = $_var_parts[0];
+                        $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index';
+                        $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]";
+                    }
+                } else if ($_index{0} == '.') {
+                    if ($_index{1} == '$')
+                        $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]";
+                    else
+                        $_output .= "['" . substr($_index, 1) . "']";
+                } else if (substr($_index,0,2) == '->') {
+                    if(substr($_index,2,2) == '__') {
+                        $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__);
+                    } elseif($this->security && substr($_index, 2, 1) == '_') {
+                        $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
+                    } elseif ($_index{2} == '$') {
+                        if ($this->security) {
+                            $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__);
+                        } else {
+                            $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}';
+                        }
+                    } else {
+                        $_output .= $_index;
+                    }
+                } elseif ($_index{0} == '(') {
+                    $_index = $this->_parse_parenth_args($_index);
+                    $_output .= $_index;
+                } else {
+                    $_output .= $_index;
+                }
+            }
+        }
+
+        return $_output;
+    }
+
+    /**
+     * parse arguments in function call parenthesis
+     *
+     * @param string $parenth_args
+     * @return string
+     */
+    function _parse_parenth_args($parenth_args)
+    {
+        preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match);
+        $orig_vals = $match = $match[0];
+        $this->_parse_vars_props($match);
+        $replace = array();
+        for ($i = 0, $count = count($match); $i < $count; $i++) {
+            $replace[$orig_vals[$i]] = $match[$i];
+        }
+        return strtr($parenth_args, $replace);
+    }
+
+    /**
+     * parse configuration variable expression into PHP code
+     *
+     * @param string $conf_var_expr
+     */
+    function _parse_conf_var($conf_var_expr)
+    {
+        $parts = explode('|', $conf_var_expr, 2);
+        $var_ref = $parts[0];
+        $modifiers = isset($parts[1]) ? $parts[1] : '';
+
+        $var_name = substr($var_ref, 1, -1);
+
+        $output = "\$this->_config[0]['vars']['$var_name']";
+
+        $this->_parse_modifiers($output, $modifiers);
+
+        return $output;
+    }
+
+    /**
+     * parse section property expression into PHP code
+     *
+     * @param string $section_prop_expr
+     * @return string
+     */
+    function _parse_section_prop($section_prop_expr)
+    {
+        $parts = explode('|', $section_prop_expr, 2);
+        $var_ref = $parts[0];
+        $modifiers = isset($parts[1]) ? $parts[1] : '';
+
+        preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match);
+        $section_name = $match[1];
+        $prop_name = $match[2];
+
+        $output = "\$this->_sections['$section_name']['$prop_name']";
+
+        $this->_parse_modifiers($output, $modifiers);
+
+        return $output;
+    }
+
+
+    /**
+     * parse modifier chain into PHP code
+     *
+     * sets $output to parsed modified chain
+     * @param string $output
+     * @param string $modifier_string
+     */
+    function _parse_modifiers(&$output, $modifier_string)
+    {
+        preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match);
+        list(, $_modifiers, $modifier_arg_strings) = $_match;
+
+        for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) {
+            $_modifier_name = $_modifiers[$_i];
+
+            if($_modifier_name == 'smarty') {
+                // skip smarty modifier
+                continue;
+            }
+
+            preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match);
+            $_modifier_args = $_match[1];
+
+            if ($_modifier_name{0} == '@') {
+                $_map_array = false;
+                $_modifier_name = substr($_modifier_name, 1);
+            } else {
+                $_map_array = true;
+            }
+
+            if (empty($this->_plugins['modifier'][$_modifier_name])
+                && !$this->_get_plugin_filepath('modifier', $_modifier_name)
+                && function_exists($_modifier_name)) {
+                if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) {
+                    $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__);
+                } else {
+                    $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name,  null, null, false);
+                }
+            }
+            $this->_add_plugin('modifier', $_modifier_name);
+
+            $this->_parse_vars_props($_modifier_args);
+
+            if($_modifier_name == 'default') {
+                // supress notifications of default modifier vars and args
+                if($output{0} == '$') {
+                    $output = '@' . $output;
+                }
+                if(isset($_modifier_args[0]) && $_modifier_args[0]{0} == '$') {
+                    $_modifier_args[0] = '@' . $_modifier_args[0];
+                }
+            }
+            if (count($_modifier_args) > 0)
+                $_modifier_args = ', '.implode(', ', $_modifier_args);
+            else
+                $_modifier_args = '';
+
+            if ($_map_array) {
+                $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))";
+
+            } else {
+
+                $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)";
+
+            }
+        }
+    }
+
+
+    /**
+     * add plugin
+     *
+     * @param string $type
+     * @param string $name
+     * @param boolean? $delayed_loading
+     */
+    function _add_plugin($type, $name, $delayed_loading = null)
+    {
+        if (!isset($this->_plugin_info[$type])) {
+            $this->_plugin_info[$type] = array();
+        }
+        if (!isset($this->_plugin_info[$type][$name])) {
+            $this->_plugin_info[$type][$name] = array($this->_current_file,
+                                                      $this->_current_line_no,
+                                                      $delayed_loading);
+        }
+    }
+
+
+    /**
+     * Compiles references of type $smarty.foo
+     *
+     * @param string $indexes
+     * @return string
+     */
+    function _compile_smarty_ref(&$indexes)
+    {
+        /* Extract the reference name. */
+        $_ref = substr($indexes[0], 1);
+        foreach($indexes as $_index_no=>$_index) {
+            if ($_index{0} != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) {
+                $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
+            }
+        }
+
+        switch ($_ref) {
+            case 'now':
+                $compiled_ref = 'time()';
+                $_max_index = 1;
+                break;
+
+            case 'foreach':
+                array_shift($indexes);
+                $_var = $this->_parse_var_props(substr($indexes[0], 1));
+                $_propname = substr($indexes[1], 1);
+                $_max_index = 1;
+                switch ($_propname) {
+                    case 'index':
+                        array_shift($indexes);
+                        $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)";
+                        break;
+                        
+                    case 'first':
+                        array_shift($indexes);
+                        $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)";
+                        break;
+
+                    case 'last':
+                        array_shift($indexes);
+                        $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])";
+                        break;
+                        
+                    case 'show':
+                        array_shift($indexes);
+                        $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)";
+                        break;
+                        
+                    default:
+                        unset($_max_index);
+                        $compiled_ref = "\$this->_foreach[$_var]";
+                }
+                break;
+
+            case 'section':
+                array_shift($indexes);
+                $_var = $this->_parse_var_props(substr($indexes[0], 1));
+                $compiled_ref = "\$this->_sections[$_var]";
+                break;
+
+            case 'get':
+                $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']";
+                break;
+
+            case 'post':
+                $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']";
+                break;
+
+            case 'cookies':
+                $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']";
+                break;
+
+            case 'env':
+                $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']";
+                break;
+
+            case 'server':
+                $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']";
+                break;
+
+            case 'session':
+                $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']";
+                break;
+
+            /*
+             * These cases are handled either at run-time or elsewhere in the
+             * compiler.
+             */
+            case 'request':
+                if ($this->request_use_auto_globals) {
+                    $compiled_ref = '$_REQUEST';
+                    break;
+                } else {
+                    $this->_init_smarty_vars = true;
+                }
+                return null;
+
+            case 'capture':
+                return null;
+
+            case 'template':
+                $compiled_ref = "'$this->_current_file'";
+                $_max_index = 1;
+                break;
+
+            case 'version':
+                $compiled_ref = "'$this->_version'";
+                $_max_index = 1;
+                break;
+
+            case 'const':
+                if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) {
+                    $this->_syntax_error("(secure mode) constants not permitted",
+                                         E_USER_WARNING, __FILE__, __LINE__);
+                    return;
+                }
+                array_shift($indexes);
+                if (preg_match('!^\.\w+$!', $indexes[0])) {
+                    $compiled_ref = '@' . substr($indexes[0], 1);
+                } else {
+                    $_val = $this->_parse_var_props(substr($indexes[0], 1));
+                    $compiled_ref = '@constant(' . $_val . ')';
+                }
+                $_max_index = 1;
+                break;
+
+            case 'config':
+                $compiled_ref = "\$this->_config[0]['vars']";
+                $_max_index = 3;
+                break;
+
+            case 'ldelim':
+                $compiled_ref = "'$this->left_delimiter'";
+                break;
+
+            case 'rdelim':
+                $compiled_ref = "'$this->right_delimiter'";
+                break;
+                
+            default:
+                $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__);
+                break;
+        }
+
+        if (isset($_max_index) && count($indexes) > $_max_index) {
+            $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        array_shift($indexes);
+        return $compiled_ref;
+    }
+
+    /**
+     * compiles call to plugin of type $type with name $name
+     * returns a string containing the function-name or method call
+     * without the paramter-list that would have follow to make the
+     * call valid php-syntax
+     *
+     * @param string $type
+     * @param string $name
+     * @return string
+     */
+    function _compile_plugin_call($type, $name) {
+        if (isset($this->_plugins[$type][$name])) {
+            /* plugin loaded */
+            if (is_array($this->_plugins[$type][$name][0])) {
+                return ((is_object($this->_plugins[$type][$name][0][0])) ?
+                        "\$this->_plugins['$type']['$name'][0][0]->"    /* method callback */
+                        : (string)($this->_plugins[$type][$name][0][0]).'::'    /* class callback */
+                       ). $this->_plugins[$type][$name][0][1];
+
+            } else {
+                /* function callback */
+                return $this->_plugins[$type][$name][0];
+
+            }
+        } else {
+            /* plugin not loaded -> auto-loadable-plugin */
+            return 'smarty_'.$type.'_'.$name;
+
+        }
+    }
+
+    /**
+     * load pre- and post-filters
+     */
+    function _load_filters()
+    {
+        if (count($this->_plugins['prefilter']) > 0) {
+            foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) {
+                if ($prefilter === false) {
+                    unset($this->_plugins['prefilter'][$filter_name]);
+                    $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false)));
+                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+                    smarty_core_load_plugins($_params, $this);
+                }
+            }
+        }
+        if (count($this->_plugins['postfilter']) > 0) {
+            foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) {
+                if ($postfilter === false) {
+                    unset($this->_plugins['postfilter'][$filter_name]);
+                    $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false)));
+                    require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');
+                    smarty_core_load_plugins($_params, $this);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Quote subpattern references
+     *
+     * @param string $string
+     * @return string
+     */
+    function _quote_replace($string)
+    {
+        return strtr($string, array('\\' => '\\\\', '$' => '\\$'));
+    }
+
+    /**
+     * display Smarty syntax error
+     *
+     * @param string $error_msg
+     * @param integer $error_type
+     * @param string $file
+     * @param integer $line
+     */
+    function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null)
+    {
+        $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type);
+    }
+
+
+    /**
+     * check if the compilation changes from cacheable to
+     * non-cacheable state with the beginning of the current
+     * plugin. return php-code to reflect the transition.
+     * @return string
+     */
+    function _push_cacheable_state($type, $name) {
+        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
+        if ($_cacheable
+            || 0<$this->_cacheable_state++) return '';
+        if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty'));
+        $_ret = 'if ($this->caching && !$this->_cache_including) { echo \'{nocache:'
+            . $this->_cache_serial . '#' . $this->_nocache_count
+            . '}\';}';
+        return $_ret;
+    }
+
+
+    /**
+     * check if the compilation changes from non-cacheable to
+     * cacheable state with the end of the current plugin return
+     * php-code to reflect the transition.
+     * @return string
+     */
+    function _pop_cacheable_state($type, $name) {
+        $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4];
+        if ($_cacheable
+            || --$this->_cacheable_state>0) return '';
+        return 'if ($this->caching && !$this->_cache_including) { echo \'{/nocache:'
+            . $this->_cache_serial . '#' . ($this->_nocache_count++)
+            . '}\';}';
+    }
+
+
+    /**
+     * push opening tag-name, file-name and line-number on the tag-stack
+     * @param string the opening tag's name
+     */
+    function _push_tag($open_tag)
+    {
+        array_push($this->_tag_stack, array($open_tag, $this->_current_line_no));
+    }
+
+    /**
+     * pop closing tag-name
+     * raise an error if this stack-top doesn't match with the closing tag
+     * @param string the closing tag's name
+     * @return string the opening tag's name
+     */
+    function _pop_tag($close_tag)
+    {
+        $message = '';
+        if (count($this->_tag_stack)>0) {
+            list($_open_tag, $_line_no) = array_pop($this->_tag_stack);
+            if ($close_tag == $_open_tag) {
+                return $_open_tag;
+            }
+            if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) {
+                return $this->_pop_tag($close_tag);
+            }
+            if ($close_tag == 'section' && $_open_tag == 'sectionelse') {
+                $this->_pop_tag($close_tag);
+                return $_open_tag;
+            }
+            if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') {
+                $this->_pop_tag($close_tag);
+                return $_open_tag;
+            }
+            if ($_open_tag == 'else' || $_open_tag == 'elseif') {
+                $_open_tag = 'if';
+            } elseif ($_open_tag == 'sectionelse') {
+                $_open_tag = 'section';
+            } elseif ($_open_tag == 'foreachelse') {
+                $_open_tag = 'foreach';
+            }
+            $message = " expected {/$_open_tag} (opened line $_line_no).";
+        }
+        $this->_syntax_error("mismatched tag {/$close_tag}.$message",
+                             E_USER_ERROR, __FILE__, __LINE__);
+    }
+
+}
+
+/**
+ * compare to values by their string length
+ *
+ * @access private
+ * @param string $a
+ * @param string $b
+ * @return 0|-1|1
+ */
+function _smarty_sort_length($a, $b)
+{
+    if($a == $b)
+        return 0;
+
+    if(strlen($a) == strlen($b))
+        return ($a > $b) ? -1 : 1;
+
+    return (strlen($a) > strlen($b)) ? -1 : 1;
+}
+
+
+/* vim: set et: */
+
+?>
diff --git a/include/smarty/debug.tpl b/include/smarty/debug.tpl
new file mode 100644 (file)
index 0000000..7f1c9d4
--- /dev/null
@@ -0,0 +1,64 @@
+{* Smarty *}
+
+{* debug.tpl, last updated version 2.0.1 *}
+
+{assign_debug_info}
+
+{if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"}
+       <table border=0 width=100%>
+       <tr bgcolor=#cccccc><th colspan=2>Smarty Debug Console</th></tr>
+       <tr bgcolor=#cccccc><td colspan=2><b>included templates & config files (load time in seconds):</b></td></tr>
+       {section name=templates loop=$_debug_tpls}
+               <tr bgcolor={if %templates.index% is even}#eeeeee{else}#fafafa{/if}><td colspan=2><tt>{section name=indent loop=$_debug_tpls[templates].depth}&nbsp;&nbsp;&nbsp;{/section}<font color={if $_debug_tpls[templates].type eq "template"}brown{elseif $_debug_tpls[templates].type eq "insert"}black{else}green{/if}>{$_debug_tpls[templates].filename|escape:html}</font>{if isset($_debug_tpls[templates].exec_time)} <font size=-1><i>({$_debug_tpls[templates].exec_time|string_format:"%.5f"}){if %templates.index% eq 0} (total){/if}</i></font>{/if}</tt></td></tr>
+       {sectionelse}
+               <tr bgcolor=#eeeeee><td colspan=2><tt><i>no templates included</i></tt></td></tr>       
+       {/section}
+       <tr bgcolor=#cccccc><td colspan=2><b>assigned template variables:</b></td></tr>
+       {section name=vars loop=$_debug_keys}
+               <tr bgcolor={if %vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=blue>{ldelim}${$_debug_keys[vars]}{rdelim}</font></tt></td><td nowrap><tt><font color=green>{$_debug_vals[vars]|@debug_print_var}</font></tt></td></tr>
+       {sectionelse}
+               <tr bgcolor=#eeeeee><td colspan=2><tt><i>no template variables assigned</i></tt></td></tr>      
+       {/section}
+       <tr bgcolor=#cccccc><td colspan=2><b>assigned config file variables (outer template scope):</b></td></tr>
+       {section name=config_vars loop=$_debug_config_keys}
+               <tr bgcolor={if %config_vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=maroon>{ldelim}#{$_debug_config_keys[config_vars]}#{rdelim}</font></tt></td><td><tt><font color=green>{$_debug_config_vals[config_vars]|@debug_print_var}</font></tt></td></tr>
+       {sectionelse}
+               <tr bgcolor=#eeeeee><td colspan=2><tt><i>no config vars assigned</i></tt></td></tr>     
+       {/section}
+       </table>
+</BODY></HTML>
+{else}
+<SCRIPT language=javascript>
+       if( self.name == '' ) {ldelim}
+          var title = 'Console';
+       {rdelim}
+       else {ldelim}
+          var title = 'Console_' + self.name;
+       {rdelim}
+       _smarty_console = window.open("",title.value,"width=680,height=600,resizable,scrollbars=yes");
+       _smarty_console.document.write("<HTML><HEAD><TITLE>Smarty Debug Console_"+self.name+"</TITLE></HEAD><BODY bgcolor=#ffffff>");
+       _smarty_console.document.write("<table border=0 width=100%>");
+       _smarty_console.document.write("<tr bgcolor=#cccccc><th colspan=2>Smarty Debug Console</th></tr>");
+       _smarty_console.document.write("<tr bgcolor=#cccccc><td colspan=2><b>included templates & config files (load time in seconds):</b></td></tr>");
+       {section name=templates loop=$_debug_tpls}
+               _smarty_console.document.write("<tr bgcolor={if %templates.index% is even}#eeeeee{else}#fafafa{/if}><td colspan=2><tt>{section name=indent loop=$_debug_tpls[templates].depth}&nbsp;&nbsp;&nbsp;{/section}<font color={if $_debug_tpls[templates].type eq "template"}brown{elseif $_debug_tpls[templates].type eq "insert"}black{else}green{/if}>{$_debug_tpls[templates].filename|escape:html|escape:javascript}</font>{if isset($_debug_tpls[templates].exec_time)} <font size=-1><i>({$_debug_tpls[templates].exec_time|string_format:"%.5f"}){if %templates.index% eq 0} (total){/if}</i></font>{/if}</tt></td></tr>");
+       {sectionelse}
+               _smarty_console.document.write("<tr bgcolor=#eeeeee><td colspan=2><tt><i>no templates included</i></tt></td></tr>");    
+       {/section}
+       _smarty_console.document.write("<tr bgcolor=#cccccc><td colspan=2><b>assigned template variables:</b></td></tr>");
+       {section name=vars loop=$_debug_keys}
+               _smarty_console.document.write("<tr bgcolor={if %vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=blue>{ldelim}${$_debug_keys[vars]}{rdelim}</font></tt></td><td nowrap><tt><font color=green>{$_debug_vals[vars]|@debug_print_var|escape:javascript}</font></tt></td></tr>");
+       {sectionelse}
+               _smarty_console.document.write("<tr bgcolor=#eeeeee><td colspan=2><tt><i>no template variables assigned</i></tt></td></tr>");   
+       {/section}
+       _smarty_console.document.write("<tr bgcolor=#cccccc><td colspan=2><b>assigned config file variables (outer template scope):</b></td></tr>");
+       {section name=config_vars loop=$_debug_config_keys}
+               _smarty_console.document.write("<tr bgcolor={if %config_vars.index% is even}#eeeeee{else}#fafafa{/if}><td valign=top><tt><font color=maroon>{ldelim}#{$_debug_config_keys[config_vars]}#{rdelim}</font></tt></td><td><tt><font color=green>{$_debug_config_vals[config_vars]|@debug_print_var|escape:javascript}</font></tt></td></tr>");
+       {sectionelse}
+               _smarty_console.document.write("<tr bgcolor=#eeeeee><td colspan=2><tt><i>no config vars assigned</i></tt></td></tr>");  
+       {/section}
+       _smarty_console.document.write("</table>");
+       _smarty_console.document.write("</BODY></HTML>");
+       _smarty_console.document.close();
+</SCRIPT>
+{/if}
diff --git a/include/smarty/internals/core.assemble_plugin_filepath.php b/include/smarty/internals/core.assemble_plugin_filepath.php
new file mode 100644 (file)
index 0000000..690d3dd
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * assemble filepath of requested plugin
+ *
+ * @param string $type
+ * @param string $name
+ * @return string|false
+ */
+function smarty_core_assemble_plugin_filepath($params, &$smarty)
+{
+    static $_filepaths_cache = array();
+
+    $_plugin_filename = $params['type'] . '.' . $params['name'] . '.php';
+    if (isset($_filepaths_cache[$_plugin_filename])) {
+        return $_filepaths_cache[$_plugin_filename];
+    }
+    $_return = false;
+
+    foreach ((array)$smarty->plugins_dir as $_plugin_dir) {
+
+        $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;
+
+        // see if path is relative
+        if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) {
+            $_relative_paths[] = $_plugin_dir;
+            // relative path, see if it is in the SMARTY_DIR
+            if (@is_readable(SMARTY_DIR . $_plugin_filepath)) {
+                $_return = SMARTY_DIR . $_plugin_filepath;
+                break;
+            }
+        }
+        // try relative to cwd (or absolute)
+        if (@is_readable($_plugin_filepath)) {
+            $_return = $_plugin_filepath;
+            break;
+        }
+    }
+
+    if($_return === false) {
+        // still not found, try PHP include_path
+        if(isset($_relative_paths)) {
+            foreach ((array)$_relative_paths as $_plugin_dir) {
+
+                $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename;
+
+                $_params = array('file_path' => $_plugin_filepath);
+                require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
+                if(smarty_core_get_include_path($_params, $smarty)) {
+                    $_return = $_params['new_file_path'];
+                    break;
+                }
+            }
+        }
+    }
+    $_filepaths_cache[$_plugin_filename] = $_return;
+    return $_return;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.assign_smarty_interface.php b/include/smarty/internals/core.assign_smarty_interface.php
new file mode 100644 (file)
index 0000000..7e65a73
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty assign_smarty_interface core plugin
+ *
+ * Type:     core<br>
+ * Name:     assign_smarty_interface<br>
+ * Purpose:  assign the $smarty interface variable
+ * @param array Format: null
+ * @param Smarty
+ */
+function smarty_core_assign_smarty_interface($params, &$smarty)
+{
+        if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) {
+            return;
+        }
+
+        $_globals_map = array('g'  => 'HTTP_GET_VARS',
+                             'p'  => 'HTTP_POST_VARS',
+                             'c'  => 'HTTP_COOKIE_VARS',
+                             's'  => 'HTTP_SERVER_VARS',
+                             'e'  => 'HTTP_ENV_VARS');
+
+        $_smarty_vars_request  = array();
+
+        foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) {
+            if (isset($_globals_map[$_c])) {
+                $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]);
+            }
+        }
+        $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']);
+
+        $smarty->_smarty_vars['request'] = $_smarty_vars_request;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.create_dir_structure.php b/include/smarty/internals/core.create_dir_structure.php
new file mode 100644 (file)
index 0000000..999cf59
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * create full directory structure
+ *
+ * @param string $dir
+ */
+
+// $dir
+
+function smarty_core_create_dir_structure($params, &$smarty)
+{
+    if (!file_exists($params['dir'])) {
+        $_open_basedir_ini = ini_get('open_basedir');
+
+        if (DIRECTORY_SEPARATOR=='/') {
+            /* unix-style paths */
+            $_dir = $params['dir'];
+            $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);
+            $_new_dir = ($_dir{0}=='/') ? '/' : getcwd().'/';
+            if($_use_open_basedir = !empty($_open_basedir_ini)) {
+                $_open_basedirs = explode(':', $_open_basedir_ini);
+            }
+
+        } else {
+            /* other-style paths */
+            $_dir = str_replace('\\','/', $params['dir']);
+            $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY);
+            if (preg_match('!^((//)|([a-zA-Z]:/))!', $_dir, $_root_dir)) {
+                /* leading "//" for network volume, or "[letter]:/" for full path */
+                $_new_dir = $_root_dir[1];
+                /* remove drive-letter from _dir_parts */
+                if (isset($_root_dir[3])) array_shift($_dir_parts);
+
+            } else {
+                $_new_dir = str_replace('\\', '/', getcwd()).'/';
+
+            }
+
+            if($_use_open_basedir = !empty($_open_basedir_ini)) {
+                $_open_basedirs = explode(';', str_replace('\\', '/', $_open_basedir_ini));
+            }
+
+        }
+
+        /* all paths use "/" only from here */
+        foreach ($_dir_parts as $_dir_part) {
+            $_new_dir .= $_dir_part;
+
+            if ($_use_open_basedir) {
+                // do not attempt to test or make directories outside of open_basedir
+                $_make_new_dir = false;
+                foreach ($_open_basedirs as $_open_basedir) {
+                    if (substr($_new_dir, 0, strlen($_open_basedir)) == $_open_basedir) {
+                        $_make_new_dir = true;
+                        break;
+                    }
+                }
+            } else {
+                $_make_new_dir = true;
+            }
+
+            if ($_make_new_dir && !file_exists($_new_dir) && !@mkdir($_new_dir, $smarty->_dir_perms) && !is_dir($_new_dir)) {
+                $smarty->trigger_error("problem creating directory '" . $_new_dir . "'");
+                return false;
+            }
+            $_new_dir .= '/';
+        }
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.display_debug_console.php b/include/smarty/internals/core.display_debug_console.php
new file mode 100644 (file)
index 0000000..a5d7291
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty debug_console function plugin
+ *
+ * Type:     core<br>
+ * Name:     display_debug_console<br>
+ * Purpose:  display the javascript debug console window
+ * @param array Format: null
+ * @param Smarty
+ */
+function smarty_core_display_debug_console($params, &$smarty)
+{
+    // we must force compile the debug template in case the environment
+    // changed between separate applications.
+
+    if(empty($smarty->debug_tpl)) {
+        // set path to debug template from SMARTY_DIR
+        $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl';
+        if($smarty->security && is_file($smarty->debug_tpl)) {
+            $smarty->secure_dir[] = dirname(realpath($smarty->debug_tpl));
+        }
+        $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl';
+    }
+
+    $_ldelim_orig = $smarty->left_delimiter;
+    $_rdelim_orig = $smarty->right_delimiter;
+
+    $smarty->left_delimiter = '{';
+    $smarty->right_delimiter = '}';
+
+    $_compile_id_orig = $smarty->_compile_id;
+    $smarty->_compile_id = null;
+
+    $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl);
+    if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path))
+    {
+        ob_start();
+        $smarty->_include($_compile_path);
+        $_results = ob_get_contents();
+        ob_end_clean();
+    } else {
+        $_results = '';
+    }
+
+    $smarty->_compile_id = $_compile_id_orig;
+
+    $smarty->left_delimiter = $_ldelim_orig;
+    $smarty->right_delimiter = $_rdelim_orig;
+
+    return $_results;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.get_include_path.php b/include/smarty/internals/core.get_include_path.php
new file mode 100644 (file)
index 0000000..4343241
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Get path to file from include_path
+ *
+ * @param string $file_path
+ * @param string $new_file_path
+ * @return boolean
+ * @staticvar array|null
+ */
+
+//  $file_path, &$new_file_path
+
+function smarty_core_get_include_path(&$params, &$smarty)
+{
+    static $_path_array = null;
+
+    if(!isset($_path_array)) {
+        $_ini_include_path = ini_get('include_path');
+
+        if(strstr($_ini_include_path,';')) {
+            // windows pathnames
+            $_path_array = explode(';',$_ini_include_path);
+        } else {
+            $_path_array = explode(':',$_ini_include_path);
+        }
+    }
+    foreach ($_path_array as $_include_path) {
+        if (@is_readable($_include_path . DIRECTORY_SEPARATOR . $params['file_path'])) {
+               $params['new_file_path'] = $_include_path . DIRECTORY_SEPARATOR . $params['file_path'];
+            return true;
+        }
+    }
+    return false;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.get_microtime.php b/include/smarty/internals/core.get_microtime.php
new file mode 100644 (file)
index 0000000..f1a28e0
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Get seconds and microseconds
+ * @return double
+ */
+function smarty_core_get_microtime($params, &$smarty)
+{
+    $mtime = microtime();
+    $mtime = explode(" ", $mtime);
+    $mtime = (double)($mtime[1]) + (double)($mtime[0]);
+    return ($mtime);
+}
+
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.get_php_resource.php b/include/smarty/internals/core.get_php_resource.php
new file mode 100644 (file)
index 0000000..786d4e7
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Retrieves PHP script resource
+ *
+ * sets $php_resource to the returned resource
+ * @param string $resource
+ * @param string $resource_type
+ * @param  $php_resource
+ * @return boolean
+ */
+
+function smarty_core_get_php_resource(&$params, &$smarty)
+{
+
+    $params['resource_base_path'] = $smarty->trusted_dir;
+    $smarty->_parse_resource_name($params, $smarty);
+
+    /*
+     * Find out if the resource exists.
+     */
+
+    if ($params['resource_type'] == 'file') {
+        $_readable = false;
+        if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) {
+            $_readable = true;
+        } else {
+            // test for file in include_path
+            $_params = array('file_path' => $params['resource_name']);
+            require_once(SMARTY_CORE_DIR . 'core.get_include_path.php');
+            if(smarty_core_get_include_path($_params, $smarty)) {
+                $_include_path = $_params['new_file_path'];
+                $_readable = true;
+            }
+        }
+    } else if ($params['resource_type'] != 'file') {
+        $_template_source = null;
+        $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0])
+            && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0],
+                                    array($params['resource_name'], &$_template_source, &$smarty));
+    }
+
+    /*
+     * Set the error function, depending on which class calls us.
+     */
+    if (method_exists($smarty, '_syntax_error')) {
+        $_error_funcc = '_syntax_error';
+    } else {
+        $_error_funcc = 'trigger_error';
+    }
+
+    if ($_readable) {
+        if ($smarty->security) {
+            require_once(SMARTY_CORE_DIR . 'core.is_trusted.php');
+            if (!smarty_core_is_trusted($params, $smarty)) {
+                $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted');
+                return false;
+            }
+        }
+    } else {
+        $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable');
+        return false;
+    }
+
+    if ($params['resource_type'] == 'file') {
+        $params['php_resource'] = $params['resource_name'];
+    } else {
+        $params['php_resource'] = $_template_source;
+    }
+    return true;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.is_secure.php b/include/smarty/internals/core.is_secure.php
new file mode 100644 (file)
index 0000000..342f3af
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * determines if a resource is secure or not.
+ *
+ * @param string $resource_type
+ * @param string $resource_name
+ * @return boolean
+ */
+
+//  $resource_type, $resource_name
+
+function smarty_core_is_secure($params, &$smarty)
+{
+    if (!$smarty->security || $smarty->security_settings['INCLUDE_ANY']) {
+        return true;
+    }
+
+    if ($params['resource_type'] == 'file') {
+        $_rp = realpath($params['resource_name']);
+        if (isset($params['resource_base_path'])) {
+            foreach ((array)$params['resource_base_path'] as $curr_dir) {
+                if ( ($_cd = realpath($curr_dir)) !== false &&
+                     strncmp($_rp, $_cd, strlen($_cd)) == 0 &&
+                     $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) {
+                    return true;
+                }
+            }
+        }
+        if (!empty($smarty->secure_dir)) {
+            foreach ((array)$smarty->secure_dir as $curr_dir) {
+                if ( ($_cd = realpath($curr_dir)) !== false &&
+                     strncmp($_rp, $_cd, strlen($_cd)) == 0 &&
+                     $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) {
+                    return true;
+                }            
+            }
+        }
+    } else {
+        // resource is not on local file system
+        return call_user_func_array(
+            $smarty->_plugins['resource'][$params['resource_type']][0][2],
+            array($params['resource_name'], &$smarty));
+    }
+
+    return false;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.is_trusted.php b/include/smarty/internals/core.is_trusted.php
new file mode 100644 (file)
index 0000000..f0bd2fb
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * determines if a resource is trusted or not
+ *
+ * @param string $resource_type
+ * @param string $resource_name
+ * @return boolean
+ */
+
+ // $resource_type, $resource_name
+
+function smarty_core_is_trusted($params, &$smarty)
+{
+    $_smarty_trusted = false;
+    if ($params['resource_type'] == 'file') {
+        if (!empty($smarty->trusted_dir)) {
+            $_rp = realpath($params['resource_name']);
+            foreach ((array)$smarty->trusted_dir as $curr_dir) {
+                if (!empty($curr_dir) && is_readable ($curr_dir)) {
+                    $_cd = realpath($curr_dir);
+                    if (strncmp($_rp, $_cd, strlen($_cd)) == 0
+                        && $_rp{strlen($_cd)} == DIRECTORY_SEPARATOR ) {
+                        $_smarty_trusted = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+    } else {
+        // resource is not on local file system
+        $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3],
+                                                array($params['resource_name'], $smarty));
+    }
+
+    return $_smarty_trusted;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.load_plugins.php b/include/smarty/internals/core.load_plugins.php
new file mode 100644 (file)
index 0000000..6db1dc5
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Load requested plugins
+ *
+ * @param array $plugins
+ */
+
+// $plugins
+
+function smarty_core_load_plugins($params, &$smarty)
+{
+
+    foreach ($params['plugins'] as $_plugin_info) {
+        list($_type, $_name, $_tpl_file, $_tpl_line, $_delayed_loading) = $_plugin_info;
+        $_plugin = &$smarty->_plugins[$_type][$_name];
+
+        /*
+         * We do not load plugin more than once for each instance of Smarty.
+         * The following code checks for that. The plugin can also be
+         * registered dynamically at runtime, in which case template file
+         * and line number will be unknown, so we fill them in.
+         *
+         * The final element of the info array is a flag that indicates
+         * whether the dynamically registered plugin function has been
+         * checked for existence yet or not.
+         */
+        if (isset($_plugin)) {
+            if (empty($_plugin[3])) {
+                if (!is_callable($_plugin[0])) {
+                    $smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__);
+                } else {
+                    $_plugin[1] = $_tpl_file;
+                    $_plugin[2] = $_tpl_line;
+                    $_plugin[3] = true;
+                    if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */
+                }
+            }
+            continue;
+        } else if ($_type == 'insert') {
+            /*
+             * For backwards compatibility, we check for insert functions in
+             * the symbol table before trying to load them as a plugin.
+             */
+            $_plugin_func = 'insert_' . $_name;
+            if (function_exists($_plugin_func)) {
+                $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false);
+                continue;
+            }
+        }
+
+        $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name);
+
+        if (! $_found = ($_plugin_file != false)) {
+            $_message = "could not load plugin file '$_type.$_name.php'\n";
+        }
+
+        /*
+         * If plugin file is found, it -must- provide the properly named
+         * plugin function. In case it doesn't, simply output the error and
+         * do not fall back on any other method.
+         */
+        if ($_found) {
+            include_once $_plugin_file;
+
+            $_plugin_func = 'smarty_' . $_type . '_' . $_name;
+            if (!function_exists($_plugin_func)) {
+                $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__);
+                continue;
+            }
+        }
+        /*
+         * In case of insert plugins, their code may be loaded later via
+         * 'script' attribute.
+         */
+        else if ($_type == 'insert' && $_delayed_loading) {
+            $_plugin_func = 'smarty_' . $_type . '_' . $_name;
+            $_found = true;
+        }
+
+        /*
+         * Plugin specific processing and error checking.
+         */
+        if (!$_found) {
+            if ($_type == 'modifier') {
+                /*
+                 * In case modifier falls back on using PHP functions
+                 * directly, we only allow those specified in the security
+                 * context.
+                 */
+                if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) {
+                    $_message = "(secure mode) modifier '$_name' is not allowed";
+                } else {
+                    if (!function_exists($_name)) {
+                        $_message = "modifier '$_name' is not implemented";
+                    } else {
+                        $_plugin_func = $_name;
+                        $_found = true;
+                    }
+                }
+            } else if ($_type == 'function') {
+                /*
+                 * This is a catch-all situation.
+                 */
+                $_message = "unknown tag - '$_name'";
+            }
+        }
+
+        if ($_found) {
+            $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true);
+        } else {
+            // output error
+            $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__);
+        }
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.load_resource_plugin.php b/include/smarty/internals/core.load_resource_plugin.php
new file mode 100644 (file)
index 0000000..a7d37d1
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * load a resource plugin
+ *
+ * @param string $type
+ */
+
+// $type
+
+function smarty_core_load_resource_plugin($params, &$smarty)
+{
+    /*
+     * Resource plugins are not quite like the other ones, so they are
+     * handled differently. The first element of plugin info is the array of
+     * functions provided by the plugin, the second one indicates whether
+     * all of them exist or not.
+     */
+
+    $_plugin = &$smarty->_plugins['resource'][$params['type']];
+    if (isset($_plugin)) {
+        if (!$_plugin[1] && count($_plugin[0])) {
+            $_plugin[1] = true;
+            foreach ($_plugin[0] as $_plugin_func) {
+                if (!is_callable($_plugin_func)) {
+                    $_plugin[1] = false;
+                    break;
+                }
+            }
+        }
+
+        if (!$_plugin[1]) {
+            $smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__);
+        }
+
+        return;
+    }
+
+    $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']);
+    $_found = ($_plugin_file != false);
+
+    if ($_found) {            /*
+         * If the plugin file is found, it -must- provide the properly named
+         * plugin functions.
+         */
+        include_once($_plugin_file);
+
+        /*
+         * Locate functions that we require the plugin to provide.
+         */
+        $_resource_ops = array('source', 'timestamp', 'secure', 'trusted');
+        $_resource_funcs = array();
+        foreach ($_resource_ops as $_op) {
+            $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op;
+            if (!function_exists($_plugin_func)) {
+                $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__);
+                return;
+            } else {
+                $_resource_funcs[] = $_plugin_func;
+            }
+        }
+
+        $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true);
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.process_cached_inserts.php b/include/smarty/internals/core.process_cached_inserts.php
new file mode 100644 (file)
index 0000000..29cb007
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Replace cached inserts with the actual results
+ *
+ * @param string $results
+ * @return string
+ */
+function smarty_core_process_cached_inserts($params, &$smarty)
+{
+    preg_match_all('!'.$smarty->_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis',
+                   $params['results'], $match);
+    list($cached_inserts, $insert_args) = $match;
+
+    for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) {
+        if ($smarty->debugging) {
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $debug_start_time = smarty_core_get_microtime($_params, $smarty);
+        }
+
+        $args = unserialize($insert_args[$i]);
+        $name = $args['name'];
+
+        if (isset($args['script'])) {
+            $_params = array('resource_name' => $smarty->_dequote($args['script']));
+            require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');
+            if(!smarty_core_get_php_resource($_params, $smarty)) {
+                return false;
+            }
+            $resource_type = $_params['resource_type'];
+            $php_resource = $_params['php_resource'];
+
+
+            if ($resource_type == 'file') {
+                $smarty->_include($php_resource, true);
+            } else {
+                $smarty->_eval($php_resource);
+            }
+        }
+
+        $function_name = $smarty->_plugins['insert'][$name][0];
+        if (empty($args['assign'])) {
+            $replace = $function_name($args, $smarty);
+        } else {
+            $smarty->assign($args['assign'], $function_name($args, $smarty));
+            $replace = '';
+        }
+
+        $params['results'] = str_replace($cached_inserts[$i], $replace, $params['results']);
+        if ($smarty->debugging) {
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $smarty->_smarty_debug_info[] = array('type'      => 'insert',
+                                                'filename'  => 'insert_'.$name,
+                                                'depth'     => $smarty->_inclusion_depth,
+                                                'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time);
+        }
+    }
+
+    return $params['results'];
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.process_compiled_include.php b/include/smarty/internals/core.process_compiled_include.php
new file mode 100644 (file)
index 0000000..3e1d4c1
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Replace nocache-tags by results of the corresponding non-cacheable
+ * functions and return it
+ *
+ * @param string $compiled_tpl
+ * @param string $cached_source
+ * @return string
+ */
+
+function smarty_core_process_compiled_include($params, &$smarty)
+{
+    $_cache_including = $smarty->_cache_including;
+    $smarty->_cache_including = true;
+
+    $_return = $params['results'];
+    foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) {
+        $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s',
+                                         array(&$smarty, '_process_compiled_include_callback'),
+                                         $_return);
+    }
+    $smarty->_cache_including = $_cache_including;
+    return $_return;
+}
+
+?>
diff --git a/include/smarty/internals/core.read_cache_file.php b/include/smarty/internals/core.read_cache_file.php
new file mode 100644 (file)
index 0000000..ecb1470
--- /dev/null
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * read a cache file, determine if it needs to be
+ * regenerated or not
+ *
+ * @param string $tpl_file
+ * @param string $cache_id
+ * @param string $compile_id
+ * @param string $results
+ * @return boolean
+ */
+
+//  $tpl_file, $cache_id, $compile_id, &$results
+
+function smarty_core_read_cache_file(&$params, &$smarty)
+{
+    static  $content_cache = array();
+
+    if ($smarty->force_compile) {
+        // force compile enabled, always regenerate
+        return false;
+    }
+
+    if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) {
+        list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']];
+        return true;
+    }
+
+    if (!empty($smarty->cache_handler_func)) {
+        // use cache_handler function
+        call_user_func_array($smarty->cache_handler_func,
+                             array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null));
+    } else {
+        // use local cache file
+        $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']);
+        $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id);
+        $params['results'] = $smarty->_read_file($_cache_file);
+    }
+
+    if (empty($params['results'])) {
+        // nothing to parse (error?), regenerate cache
+        return false;
+    }
+
+    $_contents = $params['results'];
+    $_info_start = strpos($_contents, "\n") + 1;
+    $_info_len = (int)substr($_contents, 0, $_info_start - 1);
+    $_cache_info = unserialize(substr($_contents, $_info_start, $_info_len));
+    $params['results'] = substr($_contents, $_info_start + $_info_len);
+
+    if ($smarty->caching == 2 && isset ($_cache_info['expires'])){
+        // caching by expiration time
+        if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) {
+            // cache expired, regenerate
+            return false;
+        }
+    } else {
+        // caching by lifetime
+        if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) {
+            // cache expired, regenerate
+            return false;
+        }
+    }
+
+    if ($smarty->compile_check) {
+        $_params = array('get_source' => false, 'quiet'=>true);
+        foreach (array_keys($_cache_info['template']) as $_template_dep) {
+            $_params['resource_name'] = $_template_dep;
+            if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {
+                // template file has changed, regenerate cache
+                return false;
+            }
+        }
+
+        if (isset($_cache_info['config'])) {
+            $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true);
+            foreach (array_keys($_cache_info['config']) as $_config_dep) {
+                $_params['resource_name'] = $_config_dep;
+                if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) {
+                    // config file has changed, regenerate cache
+                    return false;
+                }
+            }
+        }
+    }
+
+    foreach ($_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) {
+        if (empty($smarty->_cache_serials[$_include_file_path])) {
+            $smarty->_include($_include_file_path, true);
+        }
+
+        if ($smarty->_cache_serials[$_include_file_path] != $_cache_serial) {
+            /* regenerate */
+            return false;
+        }
+    }
+    $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info);
+
+    $smarty->_cache_info = $_cache_info;
+    return true;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.rm_auto.php b/include/smarty/internals/core.rm_auto.php
new file mode 100644 (file)
index 0000000..b251f64
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * delete an automagically created file by name and id
+ *
+ * @param string $auto_base
+ * @param string $auto_source
+ * @param string $auto_id
+ * @param integer $exp_time
+ * @return boolean
+ */
+
+// $auto_base, $auto_source = null, $auto_id = null, $exp_time = null
+
+function smarty_core_rm_auto($params, &$smarty)
+{
+    if (!@is_dir($params['auto_base']))
+      return false;
+
+    if(!isset($params['auto_id']) && !isset($params['auto_source'])) {
+        $_params = array(
+            'dirname' => $params['auto_base'],
+            'level' => 0,
+            'exp_time' => $params['exp_time']
+        );
+        require_once(SMARTY_CORE_DIR . 'core.rmdir.php');
+        $_res = smarty_core_rmdir($_params, $smarty);
+    } else {
+        $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']);
+
+        if(isset($params['auto_source'])) {
+            if (isset($params['extensions'])) {
+                $_res = false;
+                foreach ((array)$params['extensions'] as $_extension)
+                    $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']);
+            } else {
+                $_res = $smarty->_unlink($_tname, $params['exp_time']);
+            }
+        } elseif ($smarty->use_sub_dirs) {
+            $_params = array(
+                'dirname' => $_tname,
+                'level' => 1,
+                'exp_time' => $params['exp_time']
+            );
+            require_once(SMARTY_CORE_DIR . 'core.rmdir.php');
+            $_res = smarty_core_rmdir($_params, $smarty);
+        } else {
+            // remove matching file names
+            $_handle = opendir($params['auto_base']);
+            $_res = true;
+            while (false !== ($_filename = readdir($_handle))) {
+                if($_filename == '.' || $_filename == '..') {
+                    continue;
+                } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) {
+                    $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']);
+                }
+            }
+        }
+    }
+
+    return $_res;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.rmdir.php b/include/smarty/internals/core.rmdir.php
new file mode 100644 (file)
index 0000000..4fdbccc
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * delete a dir recursively (level=0 -> keep root)
+ * WARNING: no tests, it will try to remove what you tell it!
+ *
+ * @param string $dirname
+ * @param integer $level
+ * @param integer $exp_time
+ * @return boolean
+ */
+
+//  $dirname, $level = 1, $exp_time = null
+
+function smarty_core_rmdir($params, &$smarty)
+{
+   if(!isset($params['level'])) { $params['level'] = 1; }
+   if(!isset($params['exp_time'])) { $params['exp_time'] = null; }
+
+   if($_handle = @opendir($params['dirname'])) {
+
+        while (false !== ($_entry = readdir($_handle))) {
+            if ($_entry != '.' && $_entry != '..') {
+                if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) {
+                    $_params = array(
+                        'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry,
+                        'level' => $params['level'] + 1,
+                        'exp_time' => $params['exp_time']
+                    );
+                    require_once(SMARTY_CORE_DIR . 'core.rmdir.php');
+                    smarty_core_rmdir($_params, $smarty);
+                }
+                else {
+                    $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']);
+                }
+            }
+        }
+        closedir($_handle);
+   }
+
+   if ($params['level']) {
+       return @rmdir($params['dirname']);
+   }
+   return (bool)$_handle;
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.run_insert_handler.php b/include/smarty/internals/core.run_insert_handler.php
new file mode 100644 (file)
index 0000000..71c3845
--- /dev/null
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Handle insert tags
+ *
+ * @param array $args
+ * @return string
+ */
+function smarty_core_run_insert_handler($params, &$smarty)
+{
+
+    require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+    if ($smarty->debugging) {
+        $_params = array();
+        $_debug_start_time = smarty_core_get_microtime($_params, $smarty);
+    }
+
+    if ($smarty->caching) {
+        $_arg_string = serialize($params['args']);
+        $_name = $params['args']['name'];
+        if (!isset($smarty->_cache_info['insert_tags'][$_name])) {
+            $smarty->_cache_info['insert_tags'][$_name] = array('insert',
+                                                             $_name,
+                                                             $smarty->_plugins['insert'][$_name][1],
+                                                             $smarty->_plugins['insert'][$_name][2],
+                                                             !empty($params['args']['script']) ? true : false);
+        }
+        return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5;
+    } else {
+        if (isset($params['args']['script'])) {
+            $_params = array('resource_name' => $smarty->_dequote($params['args']['script']));
+            require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');
+            if(!smarty_core_get_php_resource($_params, $smarty)) {
+                return false;
+            }
+
+            if ($_params['resource_type'] == 'file') {
+                $smarty->_include($_params['php_resource'], true);
+            } else {
+                $smarty->_eval($_params['php_resource']);
+            }
+            unset($params['args']['script']);
+        }
+
+        $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0];
+        $_content = $_funcname($params['args'], $smarty);
+        if ($smarty->debugging) {
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $smarty->_smarty_debug_info[] = array('type'      => 'insert',
+                                                'filename'  => 'insert_'.$params['args']['name'],
+                                                'depth'     => $smarty->_inclusion_depth,
+                                                'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time);
+        }
+
+        if (!empty($params['args']["assign"])) {
+            $smarty->assign($params['args']["assign"], $_content);
+        } else {
+            return $_content;
+        }
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.smarty_include_php.php b/include/smarty/internals/core.smarty_include_php.php
new file mode 100644 (file)
index 0000000..30c6e76
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * called for included php files within templates
+ *
+ * @param string $smarty_file
+ * @param string $smarty_assign variable to assign the included template's
+ *               output into
+ * @param boolean $smarty_once uses include_once if this is true
+ * @param array $smarty_include_vars associative array of vars from
+ *              {include file="blah" var=$var}
+ */
+
+//  $file, $assign, $once, $_smarty_include_vars
+
+function smarty_core_smarty_include_php($params, &$smarty)
+{
+    $_params = array('resource_name' => $params['smarty_file']);
+    require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php');
+    smarty_core_get_php_resource($_params, $smarty);
+    $_smarty_resource_type = $_params['resource_type'];
+    $_smarty_php_resource = $_params['php_resource'];
+
+    if (!empty($params['smarty_assign'])) {
+        ob_start();
+        if ($_smarty_resource_type == 'file') {
+            $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']);
+        } else {
+            $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']);
+        }
+        $smarty->assign($params['smarty_assign'], ob_get_contents());
+        ob_end_clean();
+    } else {
+        if ($_smarty_resource_type == 'file') {
+            $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']);
+        } else {
+            $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']);
+        }
+    }
+}
+
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.write_cache_file.php b/include/smarty/internals/core.write_cache_file.php
new file mode 100644 (file)
index 0000000..72f785b
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Prepend the cache information to the cache file
+ * and write it
+ *
+ * @param string $tpl_file
+ * @param string $cache_id
+ * @param string $compile_id
+ * @param string $results
+ * @return true|null
+ */
+
+ // $tpl_file, $cache_id, $compile_id, $results
+
+function smarty_core_write_cache_file($params, &$smarty)
+{
+
+    // put timestamp in cache header
+    $smarty->_cache_info['timestamp'] = time();
+    if ($smarty->cache_lifetime > -1){
+        // expiration set
+        $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime;
+    } else {
+        // cache will never expire
+        $smarty->_cache_info['expires'] = -1;
+    }
+
+    // collapse nocache.../nocache-tags
+    if (preg_match_all('!\{(/?)nocache\:[0-9a-f]{32}#\d+\}!', $params['results'], $match, PREG_PATTERN_ORDER)) {
+        // remove everything between every pair of outermost noache.../nocache-tags
+        // and replace it by a single nocache-tag
+        // this new nocache-tag will be replaced by dynamic contents in
+        // smarty_core_process_compiled_includes() on a cache-read
+        
+        $match_count = count($match[0]);
+        $results = preg_split('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE);
+        
+        $level = 0;
+        $j = 0;
+        for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) {
+            if ($results[$i] == $match[0][$j]) {
+                // nocache tag
+                if ($match[1][$j]) { // closing tag
+                    $level--;
+                    unset($results[$i]);
+                } else { // opening tag
+                    if ($level++ > 0) unset($results[$i]);
+                }
+                $j++;
+            } elseif ($level > 0) {
+                unset($results[$i]);
+            }
+        }
+        $params['results'] = implode('', $results);
+    }
+    $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials;
+
+    // prepend the cache header info into cache file
+    $_cache_info = serialize($smarty->_cache_info);
+    $params['results'] = strlen($_cache_info) . "\n" . $_cache_info . $params['results'];
+
+    if (!empty($smarty->cache_handler_func)) {
+        // use cache_handler function
+        call_user_func_array($smarty->cache_handler_func,
+                             array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null));
+    } else {
+        // use local cache file
+
+        if(!@is_writable($smarty->cache_dir)) {
+            // cache_dir not writable, see if it exists
+            if(!@is_dir($smarty->cache_dir)) {
+                $smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR);
+                return false;
+            }
+            $smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR);
+            return false;
+        }
+
+        $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']);
+        $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id);
+        $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true);
+        require_once(SMARTY_CORE_DIR . 'core.write_file.php');
+        smarty_core_write_file($_params, $smarty);
+        return true;
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.write_compiled_include.php b/include/smarty/internals/core.write_compiled_include.php
new file mode 100644 (file)
index 0000000..5e0b2e0
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Extract non-cacheable parts out of compiled template and write it
+ *
+ * @param string $compile_path
+ * @param string $template_compiled
+ * @return boolean
+ */
+
+function smarty_core_write_compiled_include($params, &$smarty)
+{
+    $_tag_start = 'if \(\$this->caching && \!\$this->_cache_including\) \{ echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\';\}';
+    $_tag_end   = 'if \(\$this->caching && \!\$this->_cache_including\) \{ echo \'\{/nocache\:(\\2)#(\\3)\}\';\}';
+
+    preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us',
+                   $params['compiled_content'], $_match_source, PREG_SET_ORDER);
+
+    // no nocache-parts found: done
+    if (count($_match_source)==0) return;
+
+    // convert the matched php-code to functions
+    $_include_compiled =  "<?php /* Smarty version ".$smarty->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n";
+    $_include_compiled .= "         compiled from " . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . " */\n\n";
+
+    $_compile_path = $params['include_file_path'];
+
+    $smarty->_cache_serials[$_compile_path] = $params['cache_serial'];
+    $_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>";
+
+    $_include_compiled .= $params['plugins_code'];
+    $_include_compiled .= "<?php";
+
+    $this_varname = ((double)phpversion() >= 5.0) ? '_smarty' : 'this';
+    for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) {
+        $_match =& $_match_source[$_i];
+        $source = $_match[4];
+        if ($this_varname == '_smarty') {
+            /* rename $this to $_smarty in the sourcecode */
+            $tokens = token_get_all('<?php ' . $_match[4]);
+
+            /* remove trailing <?php */
+            $open_tag = '';
+            while ($tokens) {
+                $token = array_shift($tokens);
+                if (is_array($token)) {
+                    $open_tag .= $token[1];
+                } else {
+                    $open_tag .= $token;
+                }
+                if ($open_tag == '<?php ') break;
+            }
+
+            for ($i=0, $count = count($tokens); $i < $count; $i++) {
+                if (is_array($tokens[$i])) {
+                    if ($tokens[$i][0] == T_VARIABLE && $tokens[$i][1] == '$this') {
+                        $tokens[$i] = '$' . $this_varname;
+                    } else {
+                        $tokens[$i] = $tokens[$i][1];
+                    }                   
+                }
+            }
+            $source = implode('', $tokens);
+        }
+
+        /* add function to compiled include */
+        $_include_compiled .= "
+function _smarty_tplfunc_$_match[2]_$_match[3](&\$$this_varname)
+{
+$source
+}
+
+";
+    }
+    $_include_compiled .= "\n\n?>\n";
+
+    $_params = array('filename' => $_compile_path,
+                     'contents' => $_include_compiled, 'create_dirs' => true);
+
+    require_once(SMARTY_CORE_DIR . 'core.write_file.php');
+    smarty_core_write_file($_params, $smarty);
+    return true;
+}
+
+
+?>
diff --git a/include/smarty/internals/core.write_compiled_resource.php b/include/smarty/internals/core.write_compiled_resource.php
new file mode 100644 (file)
index 0000000..b902eff
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * write the compiled resource
+ *
+ * @param string $compile_path
+ * @param string $compiled_content
+ * @return true
+ */
+function smarty_core_write_compiled_resource($params, &$smarty)
+{
+    if(!@is_writable($smarty->compile_dir)) {
+        // compile_dir not writable, see if it exists
+        if(!@is_dir($smarty->compile_dir)) {
+            $smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR);
+            return false;
+        }
+        $smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR);
+        return false;
+    }
+
+    $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true);
+    require_once(SMARTY_CORE_DIR . 'core.write_file.php');
+    smarty_core_write_file($_params, $smarty);
+    return true;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/internals/core.write_file.php b/include/smarty/internals/core.write_file.php
new file mode 100644 (file)
index 0000000..09e1698
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * write out a file to disk
+ *
+ * @param string $filename
+ * @param string $contents
+ * @param boolean $create_dirs
+ * @return boolean
+ */
+function smarty_core_write_file($params, &$smarty)
+{
+    $_dirname = dirname($params['filename']);
+
+    if ($params['create_dirs']) {
+        $_params = array('dir' => $_dirname);
+        require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php');
+        smarty_core_create_dir_structure($_params, $smarty);
+    }
+
+    // write to tmp file, then rename it to avoid
+    // file locking race condition
+    $_tmp_file = tempnam($_dirname, 'wrt');
+
+    if (!($fd = @fopen($_tmp_file, 'wb'))) {
+        $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt');
+        if (!($fd = @fopen($_tmp_file, 'wb'))) {
+            $smarty->trigger_error("problem writing temporary file '$_tmp_file'");
+            return false;
+        }
+    }
+
+    fwrite($fd, $params['contents']);
+    fclose($fd);
+
+    // Delete the file if it allready exists (this is needed on Win,
+    // because it cannot overwrite files with rename()
+    if (file_exists($params['filename'])) {
+        @unlink($params['filename']);
+    }
+    @rename($_tmp_file, $params['filename']);
+    @chmod($params['filename'], $smarty->_file_perms);
+
+    return true;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/block.t.php b/include/smarty/plugins/block.t.php
new file mode 100644 (file)
index 0000000..dc5cf42
--- /dev/null
@@ -0,0 +1,146 @@
+<?
+/*
+ * Smarty plugin
+ * -------------------------------------------------------------
+ * File:     block.t.php
+ * Type:     block function
+ * Name:     t (short for translate through gettext)
+ * Purpose:  return a translated string and, if
+ *      development = true, check for translations and store in
+ *      appropriate file.  Use babelfish to generate a translation if
+ *      use_babelfish = true
+ * Usage:  {t}Some text which could be translated if you wish{/t}
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * -------------------------------------------------------------
+ * 
+ * @link http://www.gnu.org/copyleft/lesser.html
+ * @copyright 2003 Tom Anderson
+ * @author Tom Anderson <toma@etree.org>
+ * @param string $language override global t_language variable
+ * @version: 1.3
+ */
+function smarty_block_t($params, $content, &$this)
+{
+        if (!$content) return $content;
+        // Setup local development variables.
+        // If $development = false then use_babelfish is ignored.
+        $development = false;
+        // If use_babelfish is false, placeholders will be put in .po files
+        // but no translation will be attempted using babelfish.
+        $use_babelfish = false;
+
+        global $t_language, $t_language_from, $t_msgfmt_location, $t_gettext_message_dir;
+
+        // Check for new language
+        if (isset($params['language']) && $params['language']) {
+                $t_language = $params['language'];
+                putenv ("LC_ALL={$GLOBALS[t_language]}");
+        }
+
+        // If under development, check for necessary files
+        if ($development) {
+                // Translate string once for every language supported
+                foreach ($GLOBALS['t_language_all'] as $t_language) {
+                        // Check for language directory; create if necessary
+                        if (!is_dir($t_gettext_message_dir . $t_language)) {
+                                mkdir ($t_gettext_message_dir . $t_language);
+                                mkdir ("$t_gettext_message_dir$t_language/LC_MESSAGES");
+                        }
+                        // Check for .po file
+                        $po = "$t_gettext_message_dir$t_language/LC_MESSAGES/messages.po";
+                        if (!file_exists($po)) _create_po_file($po);
+
+                        // Load the .po file and check for the current translation string
+                        $text = file($po);
+                        $cst_content = addcslashes(trim($content), '\\"');
+                        if (!_in_array_trim('msgid "' . $cst_content . '"', $text)) {
+                                // String is not in translation file; add it
+                                // Get translated string from babelfish if set to true
+                                if ($use_babelfish) {
+                                        $translated = '';
+                                        $url ="http://babelfish.altavista.com/babelfish/tr?lp={$t_language_from}_{$t_language}&intl=1&tt=urltext&doit=done&urltext=" . urlencode(htmlspecialchars($content, ENT_NOQUOTES, 'UTF-8'));
+                                        $fp = fopen($url, 'r');
+                                        // Find the translated string
+                                        //foreach ($babel as $line) {
+                                        while ($line = fgets($fp)) {
+                                                if (strstr($line, "lang=$t_language")) {
+                                                        // multibytes do not work yet with
+                                                        // html_entity_decode but that is ok,
+                                                        // since altavista does not seem to send entities.
+                                                        $translated = html_entity_decode(trim(addcslashes(strip_tags($line), '\\"')), ENT_NOQUOTES);
+
+                                                        break;
+                                                }
+                                        }
+                                        fclose($fp);
+                                        unset($url);
+                                }
+
+                                // Add string to .po
+                                // mark translation as babelfish, so we know 
+                                // that we need to look after it.
+                                if ($use_babelfish) {
+                                        error_log("#: babelfish\n", 3, $po);
+                                }
+                                error_log("#: " . $this->_plugins['block']['t'][1] . "\nmsgid \"" . $cst_content . "\"\nmsgstr \"$translated\"\n\n", 3, $po);
+
+                                // Recompile translation file
+                                `$t_msgfmt_location -o $t_gettext_message_dir$t_language/LC_MESSAGES/messages.mo $po`;
+                        }
+                }
+        }
+        // Do the actual translation through gettext.
+        bindtextdomain ('messages', $t_gettext_message_dir);
+        return gettext(trim($content));
+}
+
+// Helper functions
+function _in_array_trim($needle, $haystack) {
+        $needle = trim($needle);
+        foreach ($haystack as $ck) {
+                if ($needle == trim($ck)) return true;
+        }
+        return false;
+}
+
+function _create_po_file($po) {
+        touch ($po);
+        // put header info for .po file
+        $year = date('Y');
+        $date = date('r');
+        $body = <<<EOD
+# Smarty gettext generated translation file
+# Author toma@etree.org
+# Version 1.0 - 4/29/2003
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Smarty Gettext 1.0\\n"
+"POT-Creation-Date: $date\\n"
+"PO-Revision-Date: $date\\n"
+"Last-Translator: Smarty Generated\\n"
+"Language-Team: http://babelfish.altavista.com/babelfish/\\n"
+"MIME-Version: 1.0n\\n"
+"Content-Type: text/plain; charset=utf-8\\n"
+"Content-Transfer-Encoding: 8bit\\n"
+\n
+EOD;
+        error_log($body, 3, $po);
+
+}
+
+/* vim: set expandtab: */
+?>
diff --git a/include/smarty/plugins/block.textformat.php b/include/smarty/plugins/block.textformat.php
new file mode 100644 (file)
index 0000000..aaebab2
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {textformat}{/textformat} block plugin
+ *
+ * Type:     block function<br>
+ * Name:     textformat<br>
+ * Purpose:  format text a certain way with preset styles
+ *           or custom wrap/indent settings<br>
+ * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat}
+ *       (Smarty online manual)
+ * @param array
+ * <pre>
+ * Params:   style: string (email)
+ *           indent: integer (0)
+ *           wrap: integer (80)
+ *           wrap_char string ("\n")
+ *           indent_char: string (" ")
+ *           wrap_boundary: boolean (true)
+ * </pre>
+ * @param string contents of the block
+ * @param Smarty clever simulation of a method
+ * @return string string $content re-formatted
+ */
+function smarty_block_textformat($params, $content, &$smarty)
+{
+    if (is_null($content)) {
+        return;
+    }
+
+    $style = null;
+    $indent = 0;
+    $indent_first = 0;
+    $indent_char = ' ';
+    $wrap = 80;
+    $wrap_char = "\n";
+    $wrap_cut = false;
+    $assign = null;
+    
+    foreach ($params as $_key => $_val) {
+        switch ($_key) {
+            case 'style':
+            case 'indent_char':
+            case 'wrap_char':
+            case 'assign':
+                $$_key = (string)$_val;
+                break;
+
+            case 'indent':
+            case 'indent_first':
+            case 'wrap':
+                $$_key = (int)$_val;
+                break;
+
+            case 'wrap_cut':
+                $$_key = (bool)$_val;
+                break;
+
+            default:
+                $smarty->trigger_error("textformat: unknown attribute '$_key'");
+        }
+    }
+
+    if ($style == 'email') {
+        $wrap = 72;
+    }
+
+    // split into paragraphs
+    $_paragraphs = preg_split('![\r\n][\r\n]!',$content);
+    $_output = '';
+
+    for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) {
+        if ($_paragraphs[$_x] == '') {
+            continue;
+        }
+        // convert mult. spaces & special chars to single space
+        $_paragraphs[$_x] = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'), array(' ',''), $_paragraphs[$_x]);
+        // indent first line
+        if($indent_first > 0) {
+            $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x];
+        }
+        // wordwrap sentences
+        $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut);
+        // indent lines
+        if($indent > 0) {
+            $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]);
+        }
+    }
+    $_output = implode($wrap_char . $wrap_char, $_paragraphs);
+
+    return $assign ? $smarty->assign($assign, $_output) : $_output;
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/compiler.assign.php b/include/smarty/plugins/compiler.assign.php
new file mode 100644 (file)
index 0000000..2e02017
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {assign} compiler function plugin
+ *
+ * Type:     compiler function<br>
+ * Name:     assign<br>
+ * Purpose:  assign a value to a template variable
+ * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign}
+ *       (Smarty online manual)
+ * @param string containing var-attribute and value-attribute
+ * @param Smarty_Compiler
+ */
+function smarty_compiler_assign($tag_attrs, &$compiler)
+{
+    $_params = $compiler->_parse_attrs($tag_attrs);
+
+    if (!isset($_params['var'])) {
+        $compiler->_syntax_error("assign: missing 'var' parameter", E_USER_WARNING);
+        return;
+    }
+
+    if (!isset($_params['value'])) {
+        $compiler->_syntax_error("assign: missing 'value' parameter", E_USER_WARNING);
+        return;
+    }
+
+    return "\$this->assign({$_params['var']}, {$_params['value']});";
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.assign.php b/include/smarty/plugins/function.assign.php
new file mode 100644 (file)
index 0000000..ad23f04
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {assign} function plugin
+ *
+ * Type:     function<br>
+ * Name:     assign<br>
+ * Purpose:  assign a value to a template variable
+ * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign}
+ *       (Smarty online manual)
+ * @param array Format: array('var' => variable name, 'value' => value to assign)
+ * @param Smarty
+ */
+function smarty_function_assign($params, &$smarty)
+{
+    extract($params);
+
+    if (empty($var)) {
+        $smarty->trigger_error("assign: missing 'var' parameter");
+        return;
+    }
+
+    if (!in_array('value', array_keys($params))) {
+        $smarty->trigger_error("assign: missing 'value' parameter");
+        return;
+    }
+
+    $smarty->assign($var, $value);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.assign_debug_info.php b/include/smarty/plugins/function.assign_debug_info.php
new file mode 100644 (file)
index 0000000..8015624
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {assign_debug_info} function plugin
+ *
+ * Type:     function<br>
+ * Name:     assign_debug_info<br>
+ * Purpose:  assign debug info to the template<br>
+ * @param array unused in this plugin, this plugin uses {@link Smarty::$_config},
+ *              {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info}
+ * @param Smarty
+ */
+function smarty_function_assign_debug_info($params, &$smarty)
+{
+    $assigned_vars = $smarty->_tpl_vars;
+    ksort($assigned_vars);
+    if (@is_array($smarty->_config[0])) {
+        $config_vars = $smarty->_config[0];
+        ksort($config_vars);
+        $smarty->assign("_debug_config_keys", array_keys($config_vars));
+        $smarty->assign("_debug_config_vals", array_values($config_vars));
+    }
+    
+    $included_templates = $smarty->_smarty_debug_info;
+    
+    $smarty->assign("_debug_keys", array_keys($assigned_vars));
+    $smarty->assign("_debug_vals", array_values($assigned_vars));
+    
+    $smarty->assign("_debug_tpls", $included_templates);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.config_load.php b/include/smarty/plugins/function.config_load.php
new file mode 100644 (file)
index 0000000..db7f8f6
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {config_load} function plugin
+ *
+ * Type:     function<br>
+ * Name:     config_load<br>
+ * Purpose:  load config file vars
+ * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load}
+ *       (Smarty online manual)
+ * @param array Format:
+ * <pre>
+ * array('file' => required config file name,
+ *       'section' => optional config file section to load
+ *       'scope' => local/parent/global
+ *       'global' => overrides scope, setting to parent if true)
+ * </pre>
+ * @param Smarty
+ */
+function smarty_function_config_load($params, &$smarty)
+{
+        if ($smarty->debugging) {
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $_debug_start_time = smarty_core_get_microtime($_params, $smarty);
+        }
+
+        $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null;
+        $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null;
+        $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global';
+        $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false;
+
+        if (!isset($_file) || strlen($_file) == 0) {
+            $smarty->trigger_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__);
+        }
+
+        if (isset($_scope)) {
+            if ($_scope != 'local' &&
+                $_scope != 'parent' &&
+                $_scope != 'global') {
+                $smarty->trigger_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__);
+            }
+        } else {
+            if ($_global) {
+                $_scope = 'parent';
+            } else {
+                $_scope = 'local';
+            }
+        }
+
+        $_params = array('resource_name' => $_file,
+                         'resource_base_path' => $smarty->config_dir,
+                         'get_source' => false);
+        $smarty->_parse_resource_name($_params);
+        $_file_path = $_params['resource_type'] . ':' . $_params['resource_name'];
+        if (isset($_section))
+            $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section);
+        else
+            $_compile_file = $smarty->_get_compile_path($_file_path);
+
+        if($smarty->force_compile || !file_exists($_compile_file)) {
+            $_compile = true;
+        } elseif ($smarty->compile_check) {
+            $_params = array('resource_name' => $_file,
+                             'resource_base_path' => $smarty->config_dir,
+                             'get_source' => false);
+            $_compile = $smarty->_fetch_resource_info($_params) &&
+                $_params['resource_timestamp'] > filemtime($_compile_file);
+        } else {
+            $_compile = false;
+        }
+
+        if($_compile) {
+            // compile config file
+            if(!is_object($smarty->_conf_obj)) {
+                require_once SMARTY_DIR . $smarty->config_class . '.class.php';
+                $smarty->_conf_obj = new $smarty->config_class();
+                $smarty->_conf_obj->overwrite = $smarty->config_overwrite;
+                $smarty->_conf_obj->booleanize = $smarty->config_booleanize;
+                $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden;
+                $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines;
+            }
+
+            $_params = array('resource_name' => $_file,
+                             'resource_base_path' => $smarty->config_dir,
+                             $_params['get_source'] = true);
+            if (!$smarty->_fetch_resource_info($_params)) {
+                return;
+            }
+            $smarty->_conf_obj->set_file_contents($_file, $_params['source_content']);
+            $_config_vars = array_merge($smarty->_conf_obj->get($_file),
+                    $smarty->_conf_obj->get($_file, $_section));
+            if(function_exists('var_export')) {
+                $_output = '<?php $_config_vars = ' . var_export($_config_vars, true) . '; ?>';
+            } else {
+                $_output = '<?php $_config_vars = unserialize(\'' . strtr(serialize($_config_vars),array('\''=>'\\\'', '\\'=>'\\\\')) . '\'); ?>';
+            }
+            $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp']));
+            require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php');
+            smarty_core_write_compiled_resource($_params, $smarty);
+        } else {
+            include($_compile_file);
+        }
+
+        if ($smarty->caching) {
+            $smarty->_cache_info['config'][$_file] = true;
+        }
+
+        $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars);
+        $smarty->_config[0]['files'][$_file] = true;
+
+        if ($_scope == 'parent') {
+                $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars);
+                $smarty->_config[1]['files'][$_file] = true;
+        } else if ($_scope == 'global') {
+            for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) {
+                $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars);
+                $smarty->_config[$i]['files'][$_file] = true;
+            }
+        }
+
+        if ($smarty->debugging) {
+            $_params = array();
+            require_once(SMARTY_CORE_DIR . 'core.get_microtime.php');
+            $smarty->_smarty_debug_info[] = array('type'      => 'config',
+                                                'filename'  => $_file.' ['.$_section.'] '.$_scope,
+                                                'depth'     => $smarty->_inclusion_depth,
+                                                'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time);
+        }
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.counter.php b/include/smarty/plugins/function.counter.php
new file mode 100644 (file)
index 0000000..cfe5dd8
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {counter} function plugin
+ *
+ * Type:     function<br>
+ * Name:     counter<br>
+ * Purpose:  print out a counter value
+ * @link http://smarty.php.net/manual/en/language.function.counter.php {counter}
+ *       (Smarty online manual)
+ * @param array parameters
+ * @param Smarty
+ * @return string|null
+ */
+function smarty_function_counter($params, &$smarty)
+{
+    static $counters = array();
+
+    $name = (isset($params['name'])) ? $params['name'] : 'default';
+    if (!isset($counters[$name])) {
+        $counters[$name] = array(
+            'start'=>1,
+            'skip'=>1,
+            'direction'=>'up',
+            'count'=>1
+            );
+    }
+    $counter =& $counters[$name];
+
+    if (isset($params['start'])) {
+        $counter['start'] = $counter['count'] = (int)$params['start'];
+    }
+
+    if (!empty($params['assign'])) {
+        $counter['assign'] = $params['assign'];
+    }
+
+    if (isset($counter['assign'])) {
+        $smarty->assign($counter['assign'], $counter['count']);
+    }
+    
+    if (isset($params['print'])) {
+        $print = (bool)$params['print'];
+    } else {
+        $print = empty($counter['assign']);
+    }
+
+    if ($print) {
+        $retval = $counter['count'];
+    } else {
+        $retval = null;
+    }
+
+    if (isset($params['skip'])) {
+        $counter['skip'] = $params['skip'];
+    }
+    
+    if (isset($params['direction'])) {
+        $counter['direction'] = $params['direction'];
+    }
+
+    if ($counter['direction'] == "down")
+        $counter['count'] -= $counter['skip'];
+    else
+        $counter['count'] += $counter['skip'];
+    
+    return $retval;
+    
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.cycle.php b/include/smarty/plugins/function.cycle.php
new file mode 100644 (file)
index 0000000..fe78bb8
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {cycle} function plugin
+ *
+ * Type:     function<br>
+ * Name:     cycle<br>
+ * Date:     May 3, 2002<br>
+ * Purpose:  cycle through given values<br>
+ * Input:
+ *         - name = name of cycle (optional)
+ *         - values = comma separated list of values to cycle,
+ *                    or an array of values to cycle
+ *                    (this can be left out for subsequent calls)
+ *         - reset = boolean - resets given var to true
+ *         - print = boolean - print var or not. default is true
+ *         - advance = boolean - whether or not to advance the cycle
+ *         - delimiter = the value delimiter, default is ","
+ *         - assign = boolean, assigns to template var instead of
+ *                    printed.
+ *
+ * Examples:<br>
+ * <pre>
+ * {cycle values="#eeeeee,#d0d0d0d"}
+ * {cycle name=row values="one,two,three" reset=true}
+ * {cycle name=row}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle}
+ *       (Smarty online manual)
+ * @author Monte Ohrt <monte at ohrt dot com>
+ * @author credit to Mark Priatel <mpriatel@rogers.com>
+ * @author credit to Gerard <gerard@interfold.com>
+ * @author credit to Jason Sweat <jsweat_php@yahoo.com>
+ * @version  1.3
+ * @param array
+ * @param Smarty
+ * @return string|null
+ */
+function smarty_function_cycle($params, &$smarty)
+{
+    static $cycle_vars;
+    
+    $name = (empty($params['name'])) ? 'default' : $params['name'];
+    $print = (isset($params['print'])) ? (bool)$params['print'] : true;
+    $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true;
+    $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false;
+            
+    if (!in_array('values', array_keys($params))) {
+        if(!isset($cycle_vars[$name]['values'])) {
+            $smarty->trigger_error("cycle: missing 'values' parameter");
+            return;
+        }
+    } else {
+        if(isset($cycle_vars[$name]['values'])
+            && $cycle_vars[$name]['values'] != $params['values'] ) {
+            $cycle_vars[$name]['index'] = 0;
+        }
+        $cycle_vars[$name]['values'] = $params['values'];
+    }
+
+    $cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ',';
+    
+    if(is_array($cycle_vars[$name]['values'])) {
+        $cycle_array = $cycle_vars[$name]['values'];
+    } else {
+        $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']);
+    }
+    
+    if(!isset($cycle_vars[$name]['index']) || $reset ) {
+        $cycle_vars[$name]['index'] = 0;
+    }
+    
+    if (isset($params['assign'])) {
+        $print = false;
+        $smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]);
+    }
+        
+    if($print) {
+        $retval = $cycle_array[$cycle_vars[$name]['index']];
+    } else {
+        $retval = null;
+    }
+
+    if($advance) {
+        if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) {
+            $cycle_vars[$name]['index'] = 0;
+        } else {
+            $cycle_vars[$name]['index']++;
+        }
+    }
+    
+    return $retval;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.debug.php b/include/smarty/plugins/function.debug.php
new file mode 100644 (file)
index 0000000..4345230
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {debug} function plugin
+ *
+ * Type:     function<br>
+ * Name:     debug<br>
+ * Date:     July 1, 2002<br>
+ * Purpose:  popup debug window
+ * @link http://smarty.php.net/manual/en/language.function.debug.php {debug}
+ *       (Smarty online manual)
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @version  1.0
+ * @param array
+ * @param Smarty
+ * @return string output from {@link Smarty::_generate_debug_output()}
+ */
+function smarty_function_debug($params, &$smarty)
+{
+    if (isset($params['output'])) {
+        $smarty->assign('_smarty_debug_output', $params['output']);
+    }
+    require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php');
+    return smarty_core_display_debug_console(null, $smarty);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.eval.php b/include/smarty/plugins/function.eval.php
new file mode 100644 (file)
index 0000000..3a4b8b2
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {eval} function plugin
+ *
+ * Type:     function<br>
+ * Name:     eval<br>
+ * Purpose:  evaluate a template variable as a template<br>
+ * @link http://smarty.php.net/manual/en/language.function.eval.php {eval}
+ *       (Smarty online manual)
+ * @param array
+ * @param Smarty
+ */
+function smarty_function_eval($params, &$smarty)
+{
+
+    if (!isset($params['var'])) {
+        $smarty->trigger_error("eval: missing 'var' parameter");
+        return;
+    }
+
+    if($params['var'] == '') {
+        return;
+    }
+
+    $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled);
+
+    ob_start();
+    $smarty->_eval('?>' . $_var_compiled);
+    $_contents = ob_get_contents();
+    ob_end_clean();
+
+    if (!empty($params['assign'])) {
+        $smarty->assign($params['assign'], $_contents);
+    } else {
+        return $_contents;
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.fetch.php b/include/smarty/plugins/function.fetch.php
new file mode 100644 (file)
index 0000000..f5a6987
--- /dev/null
@@ -0,0 +1,220 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {fetch} plugin
+ *
+ * Type:     function<br>
+ * Name:     fetch<br>
+ * Purpose:  fetch file, web or ftp data and display results
+ * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch}
+ *       (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string|null if the assign parameter is passed, Smarty assigns the
+ *                     result to a template variable
+ */
+function smarty_function_fetch($params, &$smarty)
+{
+    if (empty($params['file'])) {
+        $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty");
+        return;
+    }
+
+    $content = '';
+    if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) {
+        $_params = array('resource_type' => 'file', 'resource_name' => $params['file']);
+        require_once(SMARTY_CORE_DIR . 'core.is_secure.php');
+        if(!smarty_core_is_secure($_params, $smarty)) {
+            $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed');
+            return;
+        }
+        
+        // fetch the file
+        if($fp = @fopen($params['file'],'r')) {
+            while(!feof($fp)) {
+                $content .= fgets ($fp,4096);
+            }
+            fclose($fp);
+        } else {
+            $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\'');
+            return;
+        }
+    } else {
+        // not a local file
+        if(preg_match('!^http://!i',$params['file'])) {
+            // http fetch
+            if($uri_parts = parse_url($params['file'])) {
+                // set defaults
+                $host = $server_name = $uri_parts['host'];
+                $timeout = 30;
+                $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*";
+                $agent = "Smarty Template Engine ".$smarty->_version;
+                $referer = "";
+                $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/';
+                $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : '';
+                $_is_proxy = false;
+                if(empty($uri_parts['port'])) {
+                    $port = 80;
+                } else {
+                    $port = $uri_parts['port'];
+                }
+                if(!empty($uri_parts['user'])) {
+                    $user = $uri_parts['user'];
+                }
+                if(!empty($uri_parts['pass'])) {
+                    $pass = $uri_parts['pass'];
+                }
+                // loop through parameters, setup headers
+                foreach($params as $param_key => $param_value) {
+                    switch($param_key) {
+                        case "file":
+                        case "assign":
+                        case "assign_headers":
+                            break;
+                        case "user":
+                            if(!empty($param_value)) {
+                                $user = $param_value;
+                            }
+                            break;
+                        case "pass":
+                            if(!empty($param_value)) {
+                                $pass = $param_value;
+                            }
+                            break;
+                        case "accept":
+                            if(!empty($param_value)) {
+                                $accept = $param_value;
+                            }
+                            break;
+                        case "header":
+                            if(!empty($param_value)) {
+                                if(!preg_match('![\w\d-]+: .+!',$param_value)) {
+                                    $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'");
+                                    return;
+                                } else {
+                                    $extra_headers[] = $param_value;
+                                }
+                            }
+                            break;
+                        case "proxy_host":
+                            if(!empty($param_value)) {
+                                $proxy_host = $param_value;
+                            }
+                            break;
+                        case "proxy_port":
+                            if(!preg_match('!\D!', $param_value)) {
+                                $proxy_port = (int) $param_value;
+                            } else {
+                                $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'");
+                                return;
+                            }
+                            break;
+                        case "agent":
+                            if(!empty($param_value)) {
+                                $agent = $param_value;
+                            }
+                            break;
+                        case "referer":
+                            if(!empty($param_value)) {
+                                $referer = $param_value;
+                            }
+                            break;
+                        case "timeout":
+                            if(!preg_match('!\D!', $param_value)) {
+                                $timeout = (int) $param_value;
+                            } else {
+                                $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'");
+                                return;
+                            }
+                            break;
+                        default:
+                            $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'");
+                            return;
+                    }
+                }
+                if(!empty($proxy_host) && !empty($proxy_port)) {
+                    $_is_proxy = true;
+                    $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout);
+                } else {
+                    $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout);
+                }
+
+                if(!$fp) {
+                    $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)");
+                    return;
+                } else {
+                    if($_is_proxy) {
+                        fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n");
+                    } else {
+                        fputs($fp, "GET $uri HTTP/1.0\r\n");
+                    }
+                    if(!empty($host)) {
+                        fputs($fp, "Host: $host\r\n");
+                    }
+                    if(!empty($accept)) {
+                        fputs($fp, "Accept: $accept\r\n");
+                    }
+                    if(!empty($agent)) {
+                        fputs($fp, "User-Agent: $agent\r\n");
+                    }
+                    if(!empty($referer)) {
+                        fputs($fp, "Referer: $referer\r\n");
+                    }
+                    if(isset($extra_headers) && is_array($extra_headers)) {
+                        foreach($extra_headers as $curr_header) {
+                            fputs($fp, $curr_header."\r\n");
+                        }
+                    }
+                    if(!empty($user) && !empty($pass)) {
+                        fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n");
+                    }
+
+                    fputs($fp, "\r\n");
+                    while(!feof($fp)) {
+                        $content .= fgets($fp,4096);
+                    }
+                    fclose($fp);
+                    $csplit = split("\r\n\r\n",$content,2);
+
+                    $content = $csplit[1];
+
+                    if(!empty($params['assign_headers'])) {
+                        $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0]));
+                    }
+                }
+            } else {
+                $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax");
+                return;
+            }
+        } else {
+            // ftp fetch
+            if($fp = @fopen($params['file'],'r')) {
+                while(!feof($fp)) {
+                    $content .= fgets ($fp,4096);
+                }
+                fclose($fp);
+            } else {
+                $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\'');
+                return;
+            }
+        }
+
+    }
+
+
+    if (!empty($params['assign'])) {
+        $smarty->assign($params['assign'],$content);
+    } else {
+        return $content;
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.html_checkboxes.php b/include/smarty/plugins/function.html_checkboxes.php
new file mode 100644 (file)
index 0000000..ed8ad7f
--- /dev/null
@@ -0,0 +1,143 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_checkboxes} function plugin
+ *
+ * File:       function.html_checkboxes.php<br>
+ * Type:       function<br>
+ * Name:       html_checkboxes<br>
+ * Date:       24.Feb.2003<br>
+ * Purpose:    Prints out a list of checkbox input types<br>
+ * Input:<br>
+ *           - name       (optional) - string default "checkbox"
+ *           - values     (required) - array
+ *           - options    (optional) - associative array
+ *           - checked    (optional) - array default not set
+ *           - separator  (optional) - ie <br> or &nbsp;
+ *           - output     (optional) - the output next to each checkbox
+ *           - assign     (optional) - assign the output as an array to this variable
+ * Examples:
+ * <pre>
+ * {html_checkboxes values=$ids output=$names}
+ * {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
+ * {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes}
+ *      (Smarty online manual)
+ * @author     Christopher Kvarme <christopher.kvarme@flashjab.com>
+ * @author credits to Monte Ohrt <monte at ohrt dot com>
+ * @version    1.0
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_checkboxes($params, &$smarty)
+{
+    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+
+    $name = 'checkbox';
+    $values = null;
+    $options = null;
+    $selected = null;
+    $separator = '';
+    $labels = true;
+    $output = null;
+
+    $extra = '';
+
+    foreach($params as $_key => $_val) {
+        switch($_key) {
+            case 'name':
+            case 'separator':
+                $$_key = $_val;
+                break;
+
+            case 'labels':
+                $$_key = (bool)$_val;
+                break;
+
+            case 'options':
+                $$_key = (array)$_val;
+                break;
+
+            case 'values':
+            case 'output':
+                $$_key = array_values((array)$_val);
+                break;
+
+            case 'checked':
+            case 'selected':
+                $selected = array_map('strval', array_values((array)$_val));
+                break;
+
+            case 'checkboxes':
+                $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING);
+                $options = (array)$_val;
+                break;
+
+            case 'assign':
+                break;
+
+            default:
+                if(!is_array($_val)) {
+                    $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+                } else {
+                    $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (!isset($options) && !isset($values))
+        return ''; /* raise error here? */
+
+    settype($selected, 'array');
+    $_html_result = array();
+
+    if (isset($options)) {
+
+        foreach ($options as $_key=>$_val)
+            $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
+
+
+    } else {
+        foreach ($values as $_i=>$_key) {
+            $_val = isset($output[$_i]) ? $output[$_i] : '';
+            $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
+        }
+
+    }
+
+    if(!empty($params['assign'])) {
+        $smarty->assign($params['assign'], $_html_result);
+    } else {
+        return implode("\n",$_html_result);
+    }
+
+}
+
+function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) {
+    $_output = '';
+    if ($labels) $_output .= '<label>';
+    $_output .= '<input type="checkbox" name="'
+        . smarty_function_escape_special_chars($name) . '[]" value="'
+        . smarty_function_escape_special_chars($value) . '"';
+
+    if (in_array((string)$value, $selected)) {
+        $_output .= ' checked="checked"';
+    }
+    $_output .= $extra . ' />' . $output;
+    if ($labels) $_output .= '</label>';
+    $_output .=  $separator;
+
+    return $_output;
+}
+
+?>
diff --git a/include/smarty/plugins/function.html_image.php b/include/smarty/plugins/function.html_image.php
new file mode 100644 (file)
index 0000000..c62b0fe
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_image} function plugin
+ *
+ * Type:     function<br>
+ * Name:     html_image<br>
+ * Date:     Feb 24, 2003<br>
+ * Purpose:  format HTML tags for the image<br>
+ * Input:<br>
+ *         - file = file (and path) of image (required)
+ *         - height = image height (optional, default actual height)
+ *         - width = image width (optional, default actual width)
+ *         - basedir = base directory for absolute paths, default
+ *                     is environment variable DOCUMENT_ROOT
+ *
+ * Examples: {html_image file="images/masthead.gif"}
+ * Output:   <img src="images/masthead.gif" width=400 height=23>
+ * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image}
+ *      (Smarty online manual)
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author credits to Duda <duda@big.hu> - wrote first image function
+ *           in repository, helped with lots of functionality
+ * @version  1.0
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_image($params, &$smarty)
+{
+    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+    
+    $alt = '';
+    $file = '';
+    $height = '';
+    $width = '';
+    $extra = '';
+    $prefix = '';
+    $suffix = '';
+    $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS'];
+    $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : '';
+    foreach($params as $_key => $_val) {
+        switch($_key) {
+            case 'file':
+            case 'height':
+            case 'width':
+            case 'dpi':
+            case 'basedir':
+                $$_key = $_val;
+                break;
+
+            case 'alt':
+                if(!is_array($_val)) {
+                    $$_key = smarty_function_escape_special_chars($_val);
+                } else {
+                    $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+
+            case 'link':
+            case 'href':
+                $prefix = '<a href="' . $_val . '">';
+                $suffix = '</a>';
+                break;
+
+            default:
+                if(!is_array($_val)) {
+                    $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+                } else {
+                    $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (empty($file)) {
+        $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE);
+        return;
+    }
+
+    if (substr($file,0,1) == '/') {
+        $_image_path = $basedir . $file;
+    } else {
+        $_image_path = $file;
+    }
+
+    if(!isset($params['width']) || !isset($params['height'])) {
+        if ($smarty->security &&
+            ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) &&
+            (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) &&
+            (!smarty_core_is_secure($_params, $smarty)) ) {
+            $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE);
+
+        } elseif (!$_image_data = @getimagesize($_image_path)) {
+            if(!file_exists($_image_path)) {
+                $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE);
+                return;
+            } else if(!is_readable($_image_path)) {
+                $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE);
+                return;
+            } else {
+                $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE);
+                return;
+            }
+        }
+
+        if(!isset($params['width'])) {
+            $width = $_image_data[0];
+        }
+        if(!isset($params['height'])) {
+            $height = $_image_data[1];
+        }
+
+    }
+
+    if(isset($params['dpi'])) {
+        if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) {
+            $dpi_default = 72;
+        } else {
+            $dpi_default = 96;
+        }
+        $_resize = $dpi_default/$params['dpi'];
+        $width = round($width * $_resize);
+        $height = round($height * $_resize);
+    }
+
+    return $prefix . '<img src="'.$file.'" alt="'.$alt.'" width="'.$width.'" height="'.$height.'"'.$extra.' />' . $suffix;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.html_options.php b/include/smarty/plugins/function.html_options.php
new file mode 100644 (file)
index 0000000..ae864f7
--- /dev/null
@@ -0,0 +1,121 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_options} function plugin
+ *
+ * Type:     function<br>
+ * Name:     html_options<br>
+ * Input:<br>
+ *           - name       (optional) - string default "select"
+ *           - values     (required if no options supplied) - array
+ *           - options    (required if no values supplied) - associative array
+ *           - selected   (optional) - string default not set
+ *           - output     (required if not options supplied) - array
+ * Purpose:  Prints the list of <option> tags generated from
+ *           the passed parameters
+ * @link http://smarty.php.net/manual/en/language.function.html.options.php {html_image}
+ *      (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_options($params, &$smarty)
+{
+    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+    
+    $name = null;
+    $values = null;
+    $options = null;
+    $selected = array();
+    $output = null;
+    
+    $extra = '';
+    
+    foreach($params as $_key => $_val) {
+        switch($_key) {
+            case 'name':
+                $$_key = (string)$_val;
+                break;
+            
+            case 'options':
+                $$_key = (array)$_val;
+                break;
+                
+            case 'values':
+            case 'output':
+                $$_key = array_values((array)$_val);
+                break;
+
+            case 'selected':
+                $$_key = array_map('strval', array_values((array)$_val));
+                break;
+                
+            default:
+                if(!is_array($_val)) {
+                    $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+                } else {
+                    $smarty->trigger_error("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (!isset($options) && !isset($values))
+        return ''; /* raise error here? */
+
+    $_html_result = '';
+
+    if (isset($options)) {
+        
+        foreach ($options as $_key=>$_val)
+            $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
+
+    } else {
+        
+        foreach ($values as $_i=>$_key) {
+            $_val = isset($output[$_i]) ? $output[$_i] : '';
+            $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected);
+        }
+
+    }
+
+    if(!empty($name)) {
+        $_html_result = '<select name="' . $name . '"' . $extra . '>' . "\n" . $_html_result . '</select>' . "\n";
+    }
+
+    return $_html_result;
+
+}
+
+function smarty_function_html_options_optoutput($key, $value, $selected) {
+    if(!is_array($value)) {
+        $_html_result = '<option label="' . smarty_function_escape_special_chars($value) . '" value="' .
+            smarty_function_escape_special_chars($key) . '"';
+        if (in_array((string)$key, $selected))
+            $_html_result .= ' selected="selected"';
+        $_html_result .= '>' . smarty_function_escape_special_chars($value) . '</option>' . "\n";
+    } else {
+        $_html_result = smarty_function_html_options_optgroup($key, $value, $selected);
+    }
+    return $_html_result;
+}
+
+function smarty_function_html_options_optgroup($key, $values, $selected) {
+    $optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n";
+    foreach ($values as $key => $value) {
+        $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected);
+    }
+    $optgroup_html .= "</optgroup>\n";
+    return $optgroup_html;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.html_radios.php b/include/smarty/plugins/function.html_radios.php
new file mode 100644 (file)
index 0000000..dc7baee
--- /dev/null
@@ -0,0 +1,150 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_radios} function plugin
+ *
+ * File:       function.html_radios.php<br>
+ * Type:       function<br>
+ * Name:       html_radios<br>
+ * Date:       24.Feb.2003<br>
+ * Purpose:    Prints out a list of radio input types<br>
+ * Input:<br>
+ *           - name       (optional) - string default "radio"
+ *           - values     (required) - array
+ *           - options    (optional) - associative array
+ *           - checked    (optional) - array default not set
+ *           - separator  (optional) - ie <br> or &nbsp;
+ *           - output     (optional) - the output next to each radio button
+ *           - assign     (optional) - assign the output as an array to this variable
+ * Examples:
+ * <pre>
+ * {html_radios values=$ids output=$names}
+ * {html_radios values=$ids name='box' separator='<br>' output=$names}
+ * {html_radios values=$ids checked=$checked separator='<br>' output=$names}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios}
+ *      (Smarty online manual)
+ * @author     Christopher Kvarme <christopher.kvarme@flashjab.com>
+ * @author credits to Monte Ohrt <monte at ohrt dot com>
+ * @version    1.0
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_function_escape_special_chars()
+ */
+function smarty_function_html_radios($params, &$smarty)
+{
+    require_once $smarty->_get_plugin_filepath('shared','escape_special_chars');
+   
+    $name = 'radio';
+    $values = null;
+    $options = null;
+    $selected = null;
+    $separator = '';
+    $labels = true;
+    $output = null;
+    $extra = '';
+
+    foreach($params as $_key => $_val) {
+        switch($_key) {
+            case 'name':
+            case 'separator':
+                $$_key = (string)$_val;
+                break;
+
+            case 'checked':
+            case 'selected':
+                if(is_array($_val)) {
+                    $smarty->trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING);
+                } else {
+                    $selected = (string)$_val;
+                }
+                break;
+
+            case 'labels':
+                $$_key = (bool)$_val;
+                break;
+
+            case 'options':
+                $$_key = (array)$_val;
+                break;
+
+            case 'values':
+            case 'output':
+                $$_key = array_values((array)$_val);
+                break;
+
+            case 'radios':
+                $smarty->trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING);
+                $options = (array)$_val;
+                break;
+
+            case 'assign':
+                break;
+
+            default:
+                if(!is_array($_val)) {
+                    $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"';
+                } else {
+                    $smarty->trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE);
+                }
+                break;
+        }
+    }
+
+    if (!isset($options) && !isset($values))
+        return ''; /* raise error here? */
+
+    $_html_result = array();
+
+    if (isset($options)) {
+
+        foreach ($options as $_key=>$_val)
+            $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
+
+    } else {
+
+        foreach ($values as $_i=>$_key) {
+            $_val = isset($output[$_i]) ? $output[$_i] : '';
+            $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels);
+        }
+
+    }
+
+    if(!empty($params['assign'])) {
+        $smarty->assign($params['assign'], $_html_result);
+    } else {
+        return implode("\n",$_html_result);
+    }
+
+}
+
+function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels) {
+    $_output = '';
+    if ($labels) {
+      $_id = smarty_function_escape_special_chars($name . '_' . $value);
+      $_output .= '<label for="' . $_id . '">';
+   }
+   $_output .= '<input type="radio" name="'
+        . smarty_function_escape_special_chars($name) . '" value="'
+        . smarty_function_escape_special_chars($value) . '"';
+
+   if ($labels) $_output .= ' id="' . $_id . '"';
+
+    if ($value==$selected) {
+        $_output .= ' checked="checked"';
+    }
+    $_output .= $extra . ' />' . $output;
+    if ($labels) $_output .= '</label>';
+    $_output .=  $separator;
+
+    return $_output;
+}
+
+?>
diff --git a/include/smarty/plugins/function.html_select_date.php b/include/smarty/plugins/function.html_select_date.php
new file mode 100644 (file)
index 0000000..fc2d449
--- /dev/null
@@ -0,0 +1,316 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty {html_select_date} plugin
+ *
+ * Type:     function<br>
+ * Name:     html_select_date<br>
+ * Purpose:  Prints the dropdowns for date selection.
+ *
+ * ChangeLog:<br>
+ *           - 1.0 initial release
+ *           - 1.1 added support for +/- N syntax for begin
+ *                and end year values. (Monte)
+ *           - 1.2 added support for yyyy-mm-dd syntax for
+ *                time value. (Jan Rosier)
+ *           - 1.3 added support for choosing format for
+ *                month values (Gary Loescher)
+ *           - 1.3.1 added support for choosing format for
+ *                day values (Marcus Bointon)
+ *           - 1.3.2 suppport negative timestamps, force year
+ *             dropdown to include given date unless explicitly set (Monte)
+ * @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date}
+ *      (Smarty online manual)
+ * @version 1.3.2
+ * @author   Andrei Zmievski
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_html_select_date($params, &$smarty)
+{
+    require_once $smarty->_get_plugin_filepath('shared','make_timestamp');
+    require_once $smarty->_get_plugin_filepath('function','html_options');
+    /* Default values. */
+    $prefix          = "Date_";
+    $start_year      = strftime("%Y");
+    $end_year        = $start_year;
+    $display_days    = true;
+    $display_months  = true;
+    $display_years   = true;
+    $month_format    = "%B";
+    /* Write months as numbers by default  GL */
+    $month_value_format = "%m";
+    $day_format      = "%02d";
+    /* Write day values using this format MB */
+    $day_value_format = "%d";
+    $year_as_text    = false;
+    /* Display years in reverse order? Ie. 2000,1999,.... */
+    $reverse_years   = false;
+    /* Should the select boxes be part of an array when returned from PHP?
+       e.g. setting it to "birthday", would create "birthday[Day]",
+       "birthday[Month]" & "birthday[Year]". Can be combined with prefix */
+    $field_array     = null;
+    /* <select size>'s of the different <select> tags.
+       If not set, uses default dropdown. */
+    $day_size        = null;
+    $month_size      = null;
+    $year_size       = null;
+    /* Unparsed attributes common to *ALL* the <select>/<input> tags.
+       An example might be in the template: all_extra ='class ="foo"'. */
+    $all_extra       = null;
+    /* Separate attributes for the tags. */
+    $day_extra       = null;
+    $month_extra     = null;
+    $year_extra      = null;
+    /* Order in which to display the fields.
+       "D" -> day, "M" -> month, "Y" -> year. */
+    $field_order     = 'MDY';
+    /* String printed between the different fields. */
+    $field_separator = "\n";
+    $time = time();
+    $all_empty       = null;
+    $day_empty       = null;
+    $month_empty     = null;
+    $year_empty      = null;
+
+    foreach ($params as $_key=>$_value) {
+        switch ($_key) {
+            case 'prefix':
+            case 'time':
+            case 'start_year':
+            case 'end_year':
+            case 'month_format':
+            case 'day_format':
+            case 'day_value_format':
+            case 'field_array':
+            case 'day_size':
+            case 'month_size':
+            case 'year_size':
+            case 'all_extra':
+            case 'day_extra':
+            case 'month_extra':
+            case 'year_extra':
+            case 'field_order':
+            case 'field_separator':
+            case 'month_value_format':
+            case 'month_empty':
+            case 'day_empty':
+            case 'year_empty':
+                $$_key = (string)$_value;
+                break;
+
+            case 'all_empty':
+                $$_key = (string)$_value;
+                $day_empty = $month_empty = $year_empty = $all_empty;
+                break;
+
+            case 'display_days':
+            case 'display_months':
+            case 'display_years':
+            case 'year_as_text':
+            case 'reverse_years':
+                $$_key = (bool)$_value;
+                break;
+
+            default:
+                $smarty->trigger_error("[html_select_date] unknown parameter $_key", E_USER_WARNING);
+
+        }
+    }
+
+    if(preg_match('!^-\d+$!',$time)) {
+        // negative timestamp, use date()
+        $time = date('Y-m-d',$time);
+    }
+    // If $time is not in format yyyy-mm-dd
+    if (!preg_match('/^\d{0,4}-\d{0,2}-\d{0,2}$/', $time)) {
+        // use smarty_make_timestamp to get an unix timestamp and
+        // strftime to make yyyy-mm-dd
+        $time = strftime('%Y-%m-%d', smarty_make_timestamp($time));
+    }
+    // Now split this in pieces, which later can be used to set the select
+    $time = explode("-", $time);
+    
+    // make syntax "+N" or "-N" work with start_year and end_year
+    if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) {
+        if ($match[1] == '+') {
+            $end_year = strftime('%Y') + $match[2];
+        } else {
+            $end_year = strftime('%Y') - $match[2];
+        }
+    }
+    if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) {
+        if ($match[1] == '+') {
+            $start_year = strftime('%Y') + $match[2];
+        } else {
+            $start_year = strftime('%Y') - $match[2];
+        }
+    }
+    if (strlen($time[0]) > 0) { 
+        if ($start_year > $time[0] && !isset($params['start_year'])) {
+            // force start year to include given date if not explicitly set
+            $start_year = $time[0];
+        }
+        if($end_year < $time[0] && !isset($params['end_year'])) {
+            // force end year to include given date if not explicitly set
+            $end_year = $time[0];
+        }
+    }
+
+    $field_order = strtoupper($field_order);
+
+    $html_result = $month_result = $day_result = $year_result = "";
+
+    if ($display_months) {
+        $month_names = array();
+        $month_values = array();
+        if(isset($month_empty)) {
+            $month_names[''] = $month_empty;
+            $month_values[''] = '';
+        }
+        for ($i = 1; $i <= 12; $i++) {
+            $month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000));
+            $month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000));
+        }
+
+        $month_result .= '<select name=';
+        if (null !== $field_array){
+            $month_result .= '"' . $field_array . '[' . $prefix . 'Month]"';
+        } else {
+            $month_result .= '"' . $prefix . 'Month"';
+        }
+        if (null !== $month_size){
+            $month_result .= ' size="' . $month_size . '"';
+        }
+        if (null !== $month_extra){
+            $month_result .= ' ' . $month_extra;
+        }
+        if (null !== $all_extra){
+            $month_result .= ' ' . $all_extra;
+        }
+        $month_result .= '>'."\n";
+
+        $month_result .= smarty_function_html_options(array('output'     => $month_names,
+                                                            'values'     => $month_values,
+                                                            'selected'   => $a=$time[1] ? strftime($month_value_format, mktime(0, 0, 0, (int)$time[1], 1, 2000)) : '',
+                                                            'print_result' => false),
+                                                      $smarty);
+        $month_result .= '</select>';
+    }
+
+    if ($display_days) {
+        $days = array();
+        if (isset($day_empty)) {
+            $days[''] = $day_empty;
+            $day_values[''] = '';
+        }
+        for ($i = 1; $i <= 31; $i++) {
+            $days[] = sprintf($day_format, $i);
+            $day_values[] = sprintf($day_value_format, $i);
+        }
+
+        $day_result .= '<select name=';
+        if (null !== $field_array){
+            $day_result .= '"' . $field_array . '[' . $prefix . 'Day]"';
+        } else {
+            $day_result .= '"' . $prefix . 'Day"';
+        }
+        if (null !== $day_size){
+            $day_result .= ' size="' . $day_size . '"';
+        }
+        if (null !== $all_extra){
+            $day_result .= ' ' . $all_extra;
+        }
+        if (null !== $day_extra){
+            $day_result .= ' ' . $day_extra;
+        }
+        $day_result .= '>'."\n";
+        $day_result .= smarty_function_html_options(array('output'     => $days,
+                                                          'values'     => $day_values,
+                                                          'selected'   => $time[2],
+                                                          'print_result' => false),
+                                                    $smarty);
+        $day_result .= '</select>';
+    }
+
+    if ($display_years) {
+        if (null !== $field_array){
+            $year_name = $field_array . '[' . $prefix . 'Year]';
+        } else {
+            $year_name = $prefix . 'Year';
+        }
+        if ($year_as_text) {
+            $year_result .= '<input type="text" name="' . $year_name . '" value="' . $time[0] . '" size="4" maxlength="4"';
+            if (null !== $all_extra){
+                $year_result .= ' ' . $all_extra;
+            }
+            if (null !== $year_extra){
+                $year_result .= ' ' . $year_extra;
+            }
+            $year_result .= '>';
+        } else {
+            $years = range((int)$start_year, (int)$end_year);
+            if ($reverse_years) {
+                rsort($years, SORT_NUMERIC);
+            } else {
+                sort($years, SORT_NUMERIC);
+            }
+            $yearvals = $years;
+            if(isset($year_empty)) {
+                array_unshift($years, $year_empty);
+                array_unshift($yearvals, '');
+            }
+            $year_result .= '<select name="' . $year_name . '"';
+            if (null !== $year_size){
+                $year_result .= ' size="' . $year_size . '"';
+            }
+            if (null !== $all_extra){
+                $year_result .= ' ' . $all_extra;
+            }
+            if (null !== $year_extra){
+                $year_result .= ' ' . $year_extra;
+            }
+            $year_result .= '>'."\n";
+            $year_result .= smarty_function_html_options(array('output' => $years,
+                                                               'values' => $yearvals,
+                                                               'selected'   => $time[0],
+                                                               'print_result' => false),
+                                                         $smarty);
+            $year_result .= '</select>';
+        }
+    }
+
+    // Loop thru the field_order field
+    for ($i = 0; $i <= 2; $i++){
+        $c = substr($field_order, $i, 1);
+        switch ($c){
+            case 'D':
+                $html_result .= $day_result;
+                break;
+
+            case 'M':
+                $html_result .= $month_result;
+                break;
+
+            case 'Y':
+                $html_result .= $year_result;
+                break;
+        }
+        // Add the field seperator
+        if($i != 2) {
+            $html_result .= $field_separator;
+        }
+    }
+
+    return $html_result;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.html_select_time.php b/include/smarty/plugins/function.html_select_time.php
new file mode 100644 (file)
index 0000000..00cd1ae
--- /dev/null
@@ -0,0 +1,192 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_select_time} function plugin
+ *
+ * Type:     function<br>
+ * Name:     html_select_time<br>
+ * Purpose:  Prints the dropdowns for time selection
+ * @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time}
+ *          (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string
+ * @uses smarty_make_timestamp()
+ */
+function smarty_function_html_select_time($params, &$smarty)
+{
+    require_once $smarty->_get_plugin_filepath('shared','make_timestamp');
+    require_once $smarty->_get_plugin_filepath('function','html_options');
+    /* Default values. */
+    $prefix             = "Time_";
+    $time               = time();
+    $display_hours      = true;
+    $display_minutes    = true;
+    $display_seconds    = true;
+    $display_meridian   = true;
+    $use_24_hours       = true;
+    $minute_interval    = 1;
+    $second_interval    = 1;
+    /* Should the select boxes be part of an array when returned from PHP?
+       e.g. setting it to "birthday", would create "birthday[Hour]",
+       "birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]".
+       Can be combined with prefix. */
+    $field_array        = null;
+    $all_extra          = null;
+    $hour_extra         = null;
+    $minute_extra       = null;
+    $second_extra       = null;
+    $meridian_extra     = null;
+
+    foreach ($params as $_key=>$_value) {
+        switch ($_key) {
+            case 'prefix':
+            case 'time':
+            case 'field_array':
+            case 'all_extra':
+            case 'hour_extra':
+            case 'minute_extra':
+            case 'second_extra':
+            case 'meridian_extra':
+                $$_key = (string)$_value;
+                break;
+
+            case 'display_hours':
+            case 'display_minutes':
+            case 'display_seconds':
+            case 'display_meridian':
+            case 'use_24_hours':
+                $$_key = (bool)$_value;
+                break;
+
+            case 'minute_interval':
+            case 'second_interval':
+                $$_key = (int)$_value;
+                break;
+
+            default:
+                $smarty->trigger_error("[html_select_time] unknown parameter $_key", E_USER_WARNING);
+        }
+    }
+
+    $time = smarty_make_timestamp($time);
+
+    $html_result = '';
+
+    if ($display_hours) {
+        $hours       = $use_24_hours ? range(0, 23) : range(1, 12);
+        $hour_fmt = $use_24_hours ? '%H' : '%I';
+        for ($i = 0, $for_max = count($hours); $i < $for_max; $i++)
+            $hours[$i] = sprintf('%02d', $hours[$i]);
+        $html_result .= '<select name=';
+        if (null !== $field_array) {
+            $html_result .= '"' . $field_array . '[' . $prefix . 'Hour]"';
+        } else {
+            $html_result .= '"' . $prefix . 'Hour"';
+        }
+        if (null !== $hour_extra){
+            $html_result .= ' ' . $hour_extra;
+        }
+        if (null !== $all_extra){
+            $html_result .= ' ' . $all_extra;
+        }
+        $html_result .= '>'."\n";
+        $html_result .= smarty_function_html_options(array('output'          => $hours,
+                                                           'values'          => $hours,
+                                                           'selected'      => strftime($hour_fmt, $time),
+                                                           'print_result' => false),
+                                                     $smarty);
+        $html_result .= "</select>\n";
+    }
+
+    if ($display_minutes) {
+        $all_minutes = range(0, 59);
+        for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval)
+            $minutes[] = sprintf('%02d', $all_minutes[$i]);
+        $selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval);
+        $html_result .= '<select name=';
+        if (null !== $field_array) {
+            $html_result .= '"' . $field_array . '[' . $prefix . 'Minute]"';
+        } else {
+            $html_result .= '"' . $prefix . 'Minute"';
+        }
+        if (null !== $minute_extra){
+            $html_result .= ' ' . $minute_extra;
+        }
+        if (null !== $all_extra){
+            $html_result .= ' ' . $all_extra;
+        }
+        $html_result .= '>'."\n";
+        
+        $html_result .= smarty_function_html_options(array('output'          => $minutes,
+                                                           'values'          => $minutes,
+                                                           'selected'      => $selected,
+                                                           'print_result' => false),
+                                                     $smarty);
+        $html_result .= "</select>\n";
+    }
+
+    if ($display_seconds) {
+        $all_seconds = range(0, 59);
+        for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval)
+            $seconds[] = sprintf('%02d', $all_seconds[$i]);
+        $selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval);
+        $html_result .= '<select name=';
+        if (null !== $field_array) {
+            $html_result .= '"' . $field_array . '[' . $prefix . 'Second]"';
+        } else {
+            $html_result .= '"' . $prefix . 'Second"';
+        }
+        
+        if (null !== $second_extra){
+            $html_result .= ' ' . $second_extra;
+        }
+        if (null !== $all_extra){
+            $html_result .= ' ' . $all_extra;
+        }
+        $html_result .= '>'."\n";
+        
+        $html_result .= smarty_function_html_options(array('output'          => $seconds,
+                                                           'values'          => $seconds,
+                                                           'selected'      => $selected,
+                                                           'print_result' => false),
+                                                     $smarty);
+        $html_result .= "</select>\n";
+    }
+
+    if ($display_meridian && !$use_24_hours) {
+        $html_result .= '<select name=';
+        if (null !== $field_array) {
+            $html_result .= '"' . $field_array . '[' . $prefix . 'Meridian]"';
+        } else {
+            $html_result .= '"' . $prefix . 'Meridian"';
+        }
+        
+        if (null !== $meridian_extra){
+            $html_result .= ' ' . $meridian_extra;
+        }
+        if (null !== $all_extra){
+            $html_result .= ' ' . $all_extra;
+        }
+        $html_result .= '>'."\n";
+        
+        $html_result .= smarty_function_html_options(array('output'          => array('AM', 'PM'),
+                                                           'values'          => array('am', 'pm'),
+                                                           'selected'      => strtolower(strftime('%p', $time)),
+                                                           'print_result' => false),
+                                                     $smarty);
+        $html_result .= "</select>\n";
+    }
+
+    return $html_result;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.html_table.php b/include/smarty/plugins/function.html_table.php
new file mode 100644 (file)
index 0000000..62d7410
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {html_table} function plugin
+ *
+ * Type:     function<br>
+ * Name:     html_table<br>
+ * Date:     Feb 17, 2003<br>
+ * Purpose:  make an html table from an array of data<br>
+ * Input:<br>
+ *         - loop = array to loop through
+ *         - cols = number of columns
+ *         - rows = number of rows
+ *         - table_attr = table attributes
+ *         - tr_attr = table row attributes (arrays are cycled)
+ *         - td_attr = table cell attributes (arrays are cycled)
+ *         - trailpad = value to pad trailing cells with
+ *         - vdir = vertical direction (default: "down", means top-to-bottom)
+ *         - hdir = horizontal direction (default: "right", means left-to-right)
+ *         - inner = inner loop (default "cols": print $loop line by line,
+ *                   $loop will be printed column by column otherwise)
+ *
+ *
+ * Examples:
+ * <pre>
+ * {table loop=$data}
+ * {table loop=$data cols=4 tr_attr='"bgcolor=red"'}
+ * {table loop=$data cols=4 tr_attr=$colors}
+ * </pre>
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @version  1.0
+ * @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table}
+ *          (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_html_table($params, &$smarty)
+{
+    $table_attr = 'border="1"';
+    $tr_attr = '';
+    $td_attr = '';
+    $cols = 3;
+    $rows = 3;
+    $trailpad = '&nbsp;';
+    $vdir = 'down';
+    $hdir = 'right';
+    $inner = 'cols';
+
+    if (!isset($params['loop'])) {
+        $smarty->trigger_error("html_table: missing 'loop' parameter");
+        return;
+    }
+
+    foreach ($params as $_key=>$_value) {
+        switch ($_key) {
+            case 'loop':
+                $$_key = (array)$_value;
+                break;
+
+            case 'cols':
+            case 'rows':
+                $$_key = (int)$_value;
+                break;
+
+            case 'table_attr':
+            case 'trailpad':
+            case 'hdir':
+            case 'vdir':
+            case 'inner':
+                $$_key = (string)$_value;
+                break;
+
+            case 'tr_attr':
+            case 'td_attr':
+                $$_key = $_value;
+                break;
+        }
+    }
+
+    $loop_count = count($loop);
+    if (empty($params['rows'])) {
+        /* no rows specified */
+        $rows = ceil($loop_count/$cols);
+    } elseif (empty($params['cols'])) {
+        if (!empty($params['rows'])) {
+            /* no cols specified, but rows */
+            $cols = ceil($loop_count/$rows);
+        }
+    }
+
+    $output = "<table $table_attr>\n";
+
+    for ($r=0; $r<$rows; $r++) {
+        $output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n";
+        $rx =  ($vdir == 'down') ? $r*$cols : ($rows-1-$r)*$cols;
+
+        for ($c=0; $c<$cols; $c++) {
+            $x =  ($hdir == 'right') ? $rx+$c : $rx+$cols-1-$c;
+            if ($inner!='cols') {
+                /* shuffle x to loop over rows*/
+                $x = floor($x/$cols) + ($x%$cols)*$rows;
+            }
+
+            if ($x<$loop_count) {
+                $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[$x] . "</td>\n";
+            } else {
+                $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n";
+            }
+        }
+        $output .= "</tr>\n";
+    }
+    $output .= "</table>\n";
+    
+    return $output;
+}
+
+function smarty_function_html_table_cycle($name, $var, $no) {
+    if(!is_array($var)) {
+        $ret = $var;
+    } else {
+        $ret = $var[$no % count($var)];
+    }
+    
+    return ($ret) ? ' '.$ret : '';
+}
+
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.mailto.php b/include/smarty/plugins/function.mailto.php
new file mode 100644 (file)
index 0000000..64c122c
--- /dev/null
@@ -0,0 +1,163 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {mailto} function plugin
+ *
+ * Type:     function<br>
+ * Name:     mailto<br>
+ * Date:     May 21, 2002
+ * Purpose:  automate mailto address link creation, and optionally
+ *           encode them.<br>
+ * Input:<br>
+ *         - address = e-mail address
+ *         - text = (optional) text to display, default is address
+ *         - encode = (optional) can be one of:
+ *                * none : no encoding (default)
+ *                * javascript : encode with javascript
+ *                * javascript_charcode : encode with javascript charcode
+ *                * hex : encode with hexidecimal (no javascript)
+ *         - cc = (optional) address(es) to carbon copy
+ *         - bcc = (optional) address(es) to blind carbon copy
+ *         - subject = (optional) e-mail subject
+ *         - newsgroups = (optional) newsgroup(s) to post to
+ *         - followupto = (optional) address(es) to follow up to
+ *         - extra = (optional) extra tags for the href link
+ *
+ * Examples:
+ * <pre>
+ * {mailto address="me@domain.com"}
+ * {mailto address="me@domain.com" encode="javascript"}
+ * {mailto address="me@domain.com" encode="hex"}
+ * {mailto address="me@domain.com" subject="Hello to you!"}
+ * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"}
+ * {mailto address="me@domain.com" extra='class="mailto"'}
+ * </pre>
+ * @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto}
+ *          (Smarty online manual)
+ * @version  1.2
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author   credits to Jason Sweat (added cc, bcc and subject functionality)
+ * @param    array
+ * @param    Smarty
+ * @return   string
+ */
+function smarty_function_mailto($params, &$smarty)
+{
+    $extra = '';
+
+    if (empty($params['address'])) {
+        $smarty->trigger_error("mailto: missing 'address' parameter");
+        return;
+    } else {
+        $address = $params['address'];
+    }
+
+    $text = $address;
+
+    // netscape and mozilla do not decode %40 (@) in BCC field (bug?)
+    // so, don't encode it.
+    $mail_parms = array();
+    foreach ($params as $var=>$value) {
+        switch ($var) {
+            case 'cc':
+            case 'bcc':
+            case 'followupto':
+                if (!empty($value))
+                    $mail_parms[] = $var.'='.str_replace('%40','@',rawurlencode($value));
+                break;
+                
+            case 'subject':
+            case 'newsgroups':
+                $mail_parms[] = $var.'='.rawurlencode($value);
+                break;
+
+            case 'extra':
+            case 'text':
+                $$var = $value;
+
+            default:
+        }
+    }
+
+    $mail_parm_vals = '';
+    for ($i=0; $i<count($mail_parms); $i++) {
+        $mail_parm_vals .= (0==$i) ? '?' : '&';
+        $mail_parm_vals .= $mail_parms[$i];
+    }
+    $address .= $mail_parm_vals;
+
+    $encode = (empty($params['encode'])) ? 'none' : $params['encode'];
+    if (!in_array($encode,array('javascript','javascript_charcode','hex','none')) ) {
+        $smarty->trigger_error("mailto: 'encode' parameter must be none, javascript or hex");
+        return;
+    }
+
+    if ($encode == 'javascript' ) {
+        $string = 'document.write(\'<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>\');';
+
+        $js_encode = '';
+        for ($x=0; $x < strlen($string); $x++) {
+            $js_encode .= '%' . bin2hex($string[$x]);
+        }
+
+        return '<script type="text/javascript">eval(unescape(\''.$js_encode.'\'))</script>';
+
+    } elseif ($encode == 'javascript_charcode' ) {
+        $string = '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>';
+
+        for($x = 0, $y = strlen($string); $x < $y; $x++ ) {
+            $ord[] = ord($string[$x]);   
+        }
+
+        $_ret = "<script type=\"text/javascript\" language=\"javascript\">\n";
+        $_ret .= "<!--\n";
+        $_ret .= "{document.write(String.fromCharCode(";
+        $_ret .= implode(',',$ord);
+        $_ret .= "))";
+        $_ret .= "}\n";
+        $_ret .= "//-->\n";
+        $_ret .= "</script>\n";
+        
+        return $_ret;
+        
+        
+    } elseif ($encode == 'hex') {
+
+        preg_match('!^(.*)(\?.*)$!',$address,$match);
+        if(!empty($match[2])) {
+            $smarty->trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript.");
+            return;
+        }
+        $address_encode = '';
+        for ($x=0; $x < strlen($address); $x++) {
+            if(preg_match('!\w!',$address[$x])) {
+                $address_encode .= '%' . bin2hex($address[$x]);
+            } else {
+                $address_encode .= $address[$x];
+            }
+        }
+        $text_encode = '';
+        for ($x=0; $x < strlen($text); $x++) {
+            $text_encode .= '&#x' . bin2hex($text[$x]).';';
+        }
+
+        $mailto = "&#109;&#97;&#105;&#108;&#116;&#111;&#58;";
+        return '<a href="'.$mailto.$address_encode.'" '.$extra.'>'.$text_encode.'</a>';
+
+    } else {
+        // no encoding
+        return '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>';
+
+    }
+
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.math.php b/include/smarty/plugins/function.math.php
new file mode 100644 (file)
index 0000000..0439107
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {math} function plugin
+ *
+ * Type:     function<br>
+ * Name:     math<br>
+ * Purpose:  handle math computations in template<br>
+ * @link http://smarty.php.net/manual/en/language.function.math.php {math}
+ *          (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_math($params, &$smarty)
+{
+    // be sure equation parameter is present
+    if (empty($params['equation'])) {
+        $smarty->trigger_error("math: missing equation parameter");
+        return;
+    }
+
+    $equation = $params['equation'];
+
+    // make sure parenthesis are balanced
+    if (substr_count($equation,"(") != substr_count($equation,")")) {
+        $smarty->trigger_error("math: unbalanced parenthesis");
+        return;
+    }
+
+    // match all vars in equation, make sure all are passed
+    preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]+)!",$equation, $match);
+    $allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10',
+                           'max','min','pi','pow','rand','round','sin','sqrt','srand','tan');
+    
+    foreach($match[1] as $curr_var) {
+        if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) {
+            $smarty->trigger_error("math: function call $curr_var not allowed");
+            return;
+        }
+    }
+
+    foreach($params as $key => $val) {
+        if ($key != "equation" && $key != "format" && $key != "assign") {
+            // make sure value is not empty
+            if (strlen($val)==0) {
+                $smarty->trigger_error("math: parameter $key is empty");
+                return;
+            }
+            if (!is_numeric($val)) {
+                $smarty->trigger_error("math: parameter $key: is not numeric");
+                return;
+            }
+            $equation = preg_replace("/\b$key\b/",$val, $equation);
+        }
+    }
+
+    eval("\$smarty_math_result = ".$equation.";");
+
+    if (empty($params['format'])) {
+        if (empty($params['assign'])) {
+            return $smarty_math_result;
+        } else {
+            $smarty->assign($params['assign'],$smarty_math_result);
+        }
+    } else {
+        if (empty($params['assign'])){
+            printf($params['format'],$smarty_math_result);
+        } else {
+            $smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result));
+        }
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.popup.php b/include/smarty/plugins/function.popup.php
new file mode 100644 (file)
index 0000000..2ba54de
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {popup} function plugin
+ *
+ * Type:     function<br>
+ * Name:     popup<br>
+ * Purpose:  make text pop up in windows via overlib
+ * @link http://smarty.php.net/manual/en/language.function.popup.php {popup}
+ *          (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_popup($params, &$smarty)
+{
+    $append = '';
+    foreach ($params as $_key=>$_value) {
+        switch ($_key) {
+            case 'text':
+            case 'trigger':
+            case 'function':
+            case 'inarray':
+                $$_key = (string)$_value;
+                if ($_key == 'function' || $_key == 'inarray')
+                    $append .= ',' . strtoupper($_key) . ",'$_value'";
+                break;
+
+            case 'caption':
+            case 'closetext':
+            case 'status':
+                $append .= ',' . strtoupper($_key) . ",'" . str_replace("'","\'",$_value) . "'";
+                break;
+
+            case 'fgcolor':
+            case 'bgcolor':
+            case 'textcolor':
+            case 'capcolor':
+            case 'closecolor':
+            case 'textfont':
+            case 'captionfont':
+            case 'closefont':
+            case 'fgbackground':
+            case 'bgbackground':
+            case 'caparray':
+            case 'capicon':
+            case 'background':
+            case 'frame':
+                $append .= ',' . strtoupper($_key) . ",'$_value'";
+                break;
+
+            case 'textsize':
+            case 'captionsize':
+            case 'closesize':
+            case 'width':
+            case 'height':
+            case 'border':
+            case 'offsetx':
+            case 'offsety':
+            case 'snapx':
+            case 'snapy':
+            case 'fixx':
+            case 'fixy':
+            case 'padx':
+            case 'pady':
+            case 'timeout':
+            case 'delay':
+                $append .= ',' . strtoupper($_key) . ",$_value";
+                break;
+
+            case 'sticky':
+            case 'left':
+            case 'right':
+            case 'center':
+            case 'above':
+            case 'below':
+            case 'noclose':
+            case 'autostatus':
+            case 'autostatuscap':
+            case 'fullhtml':
+            case 'hauto':
+            case 'vauto':
+            case 'mouseoff':
+            case 'followmouse':
+                if ($_value) $append .= ',' . strtoupper($_key);
+                break;
+
+            default:
+                $smarty->trigger_error("[popup] unknown parameter $_key", E_USER_WARNING);
+        }
+    }
+
+    if (empty($text) && !isset($inarray) && empty($function)) {
+        $smarty->trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required");
+        return false;
+    }
+
+    if (empty($trigger)) { $trigger = "onmouseover"; }
+
+    $retval = $trigger . '="return overlib(\''.preg_replace(array("!'!","![\r\n]!"),array("\'",'\r'),$text).'\'';
+    $retval .= $append . ');"';
+    if ($trigger == 'onmouseover')
+       $retval .= ' onmouseout="nd();"';
+
+
+    return $retval;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/function.popup_init.php b/include/smarty/plugins/function.popup_init.php
new file mode 100644 (file)
index 0000000..f62c33c
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {popup_init} function plugin
+ *
+ * Type:     function<br>
+ * Name:     popup_init<br>
+ * Purpose:  initialize overlib
+ * @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init}
+ *          (Smarty online manual)
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_popup_init($params, &$smarty)
+{
+    $zindex = 1000;
+    
+    if (!empty($params['zindex'])) {
+        $zindex = $params['zindex'];
+    }
+    
+    if (!empty($params['src'])) {
+        return '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:'.$zindex.';"></div>' . "\n"
+         . '<script type="text/javascript" language="JavaScript" src="'.$params['src'].'"></script>' . "\n";
+    } else {
+        $smarty->trigger_error("popup_init: missing src parameter");
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.capitalize.php b/include/smarty/plugins/modifier.capitalize.php
new file mode 100644 (file)
index 0000000..2b9169c
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty capitalize modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     capitalize<br>
+ * Purpose:  capitalize words in the string
+ * @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE
+ *      capitalize (Smarty online manual)
+ * @param string
+ * @return string
+ */
+function smarty_modifier_capitalize($string, $uc_digits = false)
+{
+    smarty_modifier_capitalize_ucfirst(null, $uc_digits);
+    return preg_replace_callback('!\b\w+\b!', 'smarty_modifier_capitalize_ucfirst', $string);
+}
+
+function smarty_modifier_capitalize_ucfirst($string, $uc_digits = null)
+{
+    static $_uc_digits = false;
+    
+    if(isset($uc_digits)) {
+        $_uc_digits = $uc_digits;
+        return;
+    }
+    
+    if(!preg_match('!\d!',$string[0]) || $_uc_digits)
+        return ucfirst($string[0]);
+    else
+        return $string[0];
+}
+
+
+?>
diff --git a/include/smarty/plugins/modifier.cat.php b/include/smarty/plugins/modifier.cat.php
new file mode 100644 (file)
index 0000000..2e37940
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty cat modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     cat<br>
+ * Date:     Feb 24, 2003
+ * Purpose:  catenate a value to a variable
+ * Input:    string to catenate
+ * Example:  {$var|cat:"foo"}
+ * @link http://smarty.php.net/manual/en/language.modifier.cat.php cat
+ *          (Smarty online manual)
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @version 1.0
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_cat($string, $cat)
+{
+    return $string . $cat;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.count_characters.php b/include/smarty/plugins/modifier.count_characters.php
new file mode 100644 (file)
index 0000000..49ce655
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_characters modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     count_characteres<br>
+ * Purpose:  count the number of characters in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.characters.php
+ *          count_characters (Smarty online manual)
+ * @param string
+ * @param boolean include whitespace in the character count
+ * @return integer
+ */
+function smarty_modifier_count_characters($string, $include_spaces = false)
+{
+    if ($include_spaces)
+       return(strlen($string));
+
+    return preg_match_all("/[^\s]/",$string, $match);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.count_paragraphs.php b/include/smarty/plugins/modifier.count_paragraphs.php
new file mode 100644 (file)
index 0000000..6a9833c
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_paragraphs modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     count_paragraphs<br>
+ * Purpose:  count the number of paragraphs in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
+ *          count_paragraphs (Smarty online manual)
+ * @param string
+ * @return integer
+ */
+function smarty_modifier_count_paragraphs($string)
+{
+    // count \r or \n characters
+    return count(preg_split('/[\r\n]+/', $string));
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.count_sentences.php b/include/smarty/plugins/modifier.count_sentences.php
new file mode 100644 (file)
index 0000000..0c210f0
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_sentences modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     count_sentences
+ * Purpose:  count the number of sentences in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php
+ *          count_sentences (Smarty online manual)
+ * @param string
+ * @return integer
+ */
+function smarty_modifier_count_sentences($string)
+{
+    // find periods with a word before but not after.
+    return preg_match_all('/[^\s]\.(?!\w)/', $string, $match);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.count_words.php b/include/smarty/plugins/modifier.count_words.php
new file mode 100644 (file)
index 0000000..42c8a74
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty count_words modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     count_words<br>
+ * Purpose:  count the number of words in a text
+ * @link http://smarty.php.net/manual/en/language.modifier.count.words.php
+ *          count_words (Smarty online manual)
+ * @param string
+ * @return integer
+ */
+function smarty_modifier_count_words($string)
+{
+    // split text by ' ',\r,\n,\f,\t
+    $split_array = preg_split('/\s+/',$string);
+    // count matches that contain alphanumerics
+    $word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array);
+
+    return count($word_count);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.date_format.php b/include/smarty/plugins/modifier.date_format.php
new file mode 100644 (file)
index 0000000..2f36b3b
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Include the {@link shared.make_timestamp.php} plugin
+ */
+require_once $smarty->_get_plugin_filepath('shared','make_timestamp');
+/**
+ * Smarty date_format modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     date_format<br>
+ * Purpose:  format datestamps via strftime<br>
+ * Input:<br>
+ *         - string: input date string
+ *         - format: strftime format for output
+ *         - default_date: default date if $string is empty
+ * @link http://smarty.php.net/manual/en/language.modifier.date.format.php
+ *          date_format (Smarty online manual)
+ * @param string
+ * @param string
+ * @param string
+ * @return string|void
+ * @uses smarty_make_timestamp()
+ */
+function smarty_modifier_date_format($string, $format="%b %e, %Y", $default_date=null)
+{
+    if (substr(PHP_OS,0,3) == 'WIN') {
+           $_win_from = array ('%e',  '%T',       '%D');
+           $_win_to   = array ('%#d', '%H:%M:%S', '%m/%d/%y');
+           $format = str_replace($_win_from, $_win_to, $format);
+    }
+    if($string != '') {
+        return strftime($format, smarty_make_timestamp($string));
+    } elseif (isset($default_date) && $default_date != '') {
+        return strftime($format, smarty_make_timestamp($default_date));
+    } else {
+        return;
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.debug_print_var.php b/include/smarty/plugins/modifier.debug_print_var.php
new file mode 100644 (file)
index 0000000..b9bb184
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty debug_print_var modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     debug_print_var<br>
+ * Purpose:  formats variable contents for display in the console
+ * @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php
+ *          debug_print_var (Smarty online manual)
+ * @param array|object
+ * @param integer
+ * @param integer
+ * @return string
+ */
+function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40)
+{
+    $_replace = array("\n"=>'<i>&#92;n</i>', "\r"=>'<i>&#92;r</i>', "\t"=>'<i>&#92;t</i>');
+    if (is_array($var)) {
+        $results = "<b>Array (".count($var).")</b>";
+        foreach ($var as $curr_key => $curr_val) {
+            $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length);
+            $results .= "<br>".str_repeat('&nbsp;', $depth*2)."<b>".strtr($curr_key, $_replace)."</b> =&gt; $return";
+        }
+    } else if (is_object($var)) {
+        $object_vars = get_object_vars($var);
+        $results = "<b>".get_class($var)." Object (".count($object_vars).")</b>";
+        foreach ($object_vars as $curr_key => $curr_val) {
+            $return = smarty_modifier_debug_print_var($curr_val, $depth+1, $length);
+            $results .= "<br>".str_repeat('&nbsp;', $depth*2)."<b>$curr_key</b> =&gt; $return";
+        }
+    } else if (is_resource($var)) {
+        $results = '<i>'.(string)$var.'</i>';
+    } else if (empty($var) && $var != "0") {
+        $results = '<i>empty</i>';
+    } else {
+        if (strlen($var) > $length ) {
+            $results = substr($var, 0, $length-3).'...';
+        } else {
+            $results = $var;
+        }
+        $results = htmlspecialchars($results);
+        $results = strtr($results, $_replace);
+    }
+    return $results;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.default.php b/include/smarty/plugins/modifier.default.php
new file mode 100644 (file)
index 0000000..8268e39
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty default modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     default<br>
+ * Purpose:  designate default value for empty variables
+ * @link http://smarty.php.net/manual/en/language.modifier.default.php
+ *          default (Smarty online manual)
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_default($string, $default = '')
+{
+    if (!isset($string) || $string === '')
+        return $default;
+    else
+        return $string;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.escape.php b/include/smarty/plugins/modifier.escape.php
new file mode 100644 (file)
index 0000000..a32a876
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty escape modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     escape<br>
+ * Purpose:  Escape the string according to escapement type
+ * @link http://smarty.php.net/manual/en/language.modifier.escape.php
+ *          escape (Smarty online manual)
+ * @param string
+ * @param html|htmlall|url|quotes|hex|hexentity|javascript
+ * @return string
+ */
+function smarty_modifier_escape($string, $esc_type = 'html')
+{
+    switch ($esc_type) {
+        case 'html':
+            return htmlspecialchars($string, ENT_QUOTES);
+
+        case 'htmlall':
+            return htmlentities($string, ENT_QUOTES);
+
+        case 'url':
+            return rawurlencode($string);
+
+        case 'quotes':
+            // escape unescaped single quotes
+            return preg_replace("%(?<!\\\\)'%", "\\'", $string);
+
+        case 'hex':
+            // escape every character into hex
+            $return = '';
+            for ($x=0; $x < strlen($string); $x++) {
+                $return .= '%' . bin2hex($string[$x]);
+            }
+            return $return;
+            
+        case 'hexentity':
+            $return = '';
+            for ($x=0; $x < strlen($string); $x++) {
+                $return .= '&#x' . bin2hex($string[$x]) . ';';
+            }
+            return $return;
+
+        case 'decentity':
+            $return = '';
+            for ($x=0; $x < strlen($string); $x++) {
+                $return .= '&#' . ord($string[$x]) . ';';
+            }
+            return $return;
+
+        case 'javascript':
+            // escape quotes and backslashes, newlines, etc.
+            return strtr($string, array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n','</'=>'<\/'));
+            
+        case 'mail':
+            // safe way to display e-mail address on a web page
+            return str_replace(array('@', '.'),array(' [AT] ', ' [DOT] '), $string);
+            
+        case 'nonstd':
+           // escape non-standard chars, such as ms document quotes
+           $_res = '';
+           for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) {
+               $_ord = ord($string{$_i});
+               // non-standard char, escape it
+               if($_ord >= 126){
+                   $_res .= '&#' . $_ord . ';';
+               }
+               else {
+                   $_res .= $string{$_i};
+               }
+           }
+           return $_res;
+
+        default:
+            return $string;
+    }
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.indent.php b/include/smarty/plugins/modifier.indent.php
new file mode 100644 (file)
index 0000000..1642bac
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty indent modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     indent<br>
+ * Purpose:  indent lines of text
+ * @link http://smarty.php.net/manual/en/language.modifier.indent.php
+ *          indent (Smarty online manual)
+ * @param string
+ * @param integer
+ * @param string
+ * @return string
+ */
+function smarty_modifier_indent($string,$chars=4,$char=" ")
+{
+    return preg_replace('!^!m',str_repeat($char,$chars),$string);
+}
+
+?>
diff --git a/include/smarty/plugins/modifier.lower.php b/include/smarty/plugins/modifier.lower.php
new file mode 100644 (file)
index 0000000..0b4d151
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty lower modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     lower<br>
+ * Purpose:  convert string to lowercase
+ * @link http://smarty.php.net/manual/en/language.modifier.lower.php
+ *          lower (Smarty online manual)
+ * @param string
+ * @return string
+ */
+function smarty_modifier_lower($string)
+{
+    return strtolower($string);
+}
+
+?>
diff --git a/include/smarty/plugins/modifier.nl2br.php b/include/smarty/plugins/modifier.nl2br.php
new file mode 100644 (file)
index 0000000..d6fabff
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty plugin
+ *
+ * Type:     modifier<br>
+ * Name:     nl2br<br>
+ * Date:     Feb 26, 2003
+ * Purpose:  convert \r\n, \r or \n to <<br>>
+ * Input:<br>
+ *         - contents = contents to replace
+ *         - preceed_test = if true, includes preceeding break tags
+ *           in replacement
+ * Example:  {$text|nl2br}
+ * @link http://smarty.php.net/manual/en/language.modifier.nl2br.php
+ *          nl2br (Smarty online manual)
+ * @version  1.0
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @param string
+ * @return string
+ */
+function smarty_modifier_nl2br($string)
+{
+    return nl2br($string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.regex_replace.php b/include/smarty/plugins/modifier.regex_replace.php
new file mode 100644 (file)
index 0000000..7eee497
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty regex_replace modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     regex_replace<br>
+ * Purpose:  regular epxression search/replace
+ * @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php
+ *          regex_replace (Smarty online manual)
+ * @param string
+ * @param string|array
+ * @param string|array
+ * @return string
+ */
+function smarty_modifier_regex_replace($string, $search, $replace)
+{
+    if (preg_match('!\W(\w+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) {
+        /* remove eval-modifier from $search */
+        $search = substr($search, 0, -strlen($match[1])) . str_replace('e', '', $match[1]);
+    }
+    return preg_replace($search, $replace, $string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.replace.php b/include/smarty/plugins/modifier.replace.php
new file mode 100644 (file)
index 0000000..2a43515
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty replace modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     replace<br>
+ * Purpose:  simple search/replace
+ * @link http://smarty.php.net/manual/en/language.modifier.replace.php
+ *          replace (Smarty online manual)
+ * @param string
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_replace($string, $search, $replace)
+{
+    return str_replace($search, $replace, $string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.spacify.php b/include/smarty/plugins/modifier.spacify.php
new file mode 100644 (file)
index 0000000..dad057f
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty spacify modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     spacify<br>
+ * Purpose:  add spaces between characters in a string
+ * @link http://smarty.php.net/manual/en/language.modifier.spacify.php
+ *          spacify (Smarty online manual)
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_spacify($string, $spacify_char = ' ')
+{
+    return implode($spacify_char,
+                   preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY));
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.string_format.php b/include/smarty/plugins/modifier.string_format.php
new file mode 100644 (file)
index 0000000..efd6215
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty string_format modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     string_format<br>
+ * Purpose:  format strings via sprintf
+ * @link http://smarty.php.net/manual/en/language.modifier.string.format.php
+ *          string_format (Smarty online manual)
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_string_format($string, $format)
+{
+    return sprintf($format, $string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.strip.php b/include/smarty/plugins/modifier.strip.php
new file mode 100644 (file)
index 0000000..cc5c453
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty strip modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     strip<br>
+ * Purpose:  Replace all repeated spaces, newlines, tabs
+ *           with a single space or supplied replacement string.<br>
+ * Example:  {$var|strip} {$var|strip:"&nbsp;"}
+ * Date:     September 25th, 2002
+ * @link http://smarty.php.net/manual/en/language.modifier.strip.php
+ *          strip (Smarty online manual)
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @version  1.0
+ * @param string
+ * @param string
+ * @return string
+ */
+function smarty_modifier_strip($text, $replace = ' ')
+{
+    return preg_replace('!\s+!', $replace, $text);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.strip_tags.php b/include/smarty/plugins/modifier.strip_tags.php
new file mode 100644 (file)
index 0000000..45f1ec1
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty strip_tags modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     strip_tags<br>
+ * Purpose:  strip html tags from text
+ * @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php
+ *          strip_tags (Smarty online manual)
+ * @param string
+ * @param boolean
+ * @return string
+ */
+function smarty_modifier_strip_tags($string, $replace_with_space = true)
+{
+    if ($replace_with_space)
+        return preg_replace('!<[^>]*?>!', ' ', $string);
+    else
+        return strip_tags($string);
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.truncate.php b/include/smarty/plugins/modifier.truncate.php
new file mode 100644 (file)
index 0000000..15a26ba
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty truncate modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     truncate<br>
+ * Purpose:  Truncate a string to a certain length if necessary,
+ *           optionally splitting in the middle of a word, and
+ *           appending the $etc string.
+ * @link http://smarty.php.net/manual/en/language.modifier.truncate.php
+ *          truncate (Smarty online manual)
+ * @param string
+ * @param integer
+ * @param string
+ * @param boolean
+ * @return string
+ */
+function smarty_modifier_truncate($string, $length = 80, $etc = '...',
+                                  $break_words = false)
+{
+    if ($length == 0)
+        return '';
+
+    if (strlen($string) > $length) {
+        $length -= strlen($etc);
+        if (!$break_words)
+            $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1));
+      
+        return substr($string, 0, $length).$etc;
+    } else
+        return $string;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/modifier.upper.php b/include/smarty/plugins/modifier.upper.php
new file mode 100644 (file)
index 0000000..69960ae
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty upper modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     upper<br>
+ * Purpose:  convert string to uppercase
+ * @link http://smarty.php.net/manual/en/language.modifier.upper.php
+ *          upper (Smarty online manual)
+ * @param string
+ * @return string
+ */
+function smarty_modifier_upper($string)
+{
+    return strtoupper($string);
+}
+
+?>
diff --git a/include/smarty/plugins/modifier.wordwrap.php b/include/smarty/plugins/modifier.wordwrap.php
new file mode 100644 (file)
index 0000000..b9a9fe9
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty wordwrap modifier plugin
+ *
+ * Type:     modifier<br>
+ * Name:     wordwrap<br>
+ * Purpose:  wrap a string of text at a given length
+ * @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php
+ *          wordwrap (Smarty online manual)
+ * @param string
+ * @param integer
+ * @param string
+ * @param boolean
+ * @return string
+ */
+function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false)
+{
+    return wordwrap($string,$length,$break,$cut);
+}
+
+?>
diff --git a/include/smarty/plugins/outputfilter.trimwhitespace.php b/include/smarty/plugins/outputfilter.trimwhitespace.php
new file mode 100644 (file)
index 0000000..01e35e0
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+/**
+ * Smarty trimwhitespace outputfilter plugin
+ *
+ * File:     outputfilter.trimwhitespace.php<br>
+ * Type:     outputfilter<br>
+ * Name:     trimwhitespace<br>
+ * Date:     Jan 25, 2003<br>
+ * Purpose:  trim leading white space and blank lines from
+ *           template source after it gets interpreted, cleaning
+ *           up code and saving bandwidth. Does not affect
+ *           <<PRE>></PRE> and <SCRIPT></SCRIPT> blocks.<br>
+ * Install:  Drop into the plugin directory, call
+ *           <code>$smarty->load_filter('output','trimwhitespace');</code>
+ *           from application.
+ * @author   Monte Ohrt <monte at ohrt dot com>
+ * @author Contributions from Lars Noschinski <lars@usenet.noschinski.de>
+ * @version  1.3
+ * @param string
+ * @param Smarty
+ */
+function smarty_outputfilter_trimwhitespace($source, &$smarty)
+{
+    // Pull out the script blocks
+    preg_match_all("!<script[^>]+>.*?</script>!is", $source, $match);
+    $_script_blocks = $match[0];
+    $source = preg_replace("!<script[^>]+>.*?</script>!is",
+                           '@@@SMARTY:TRIM:SCRIPT@@@', $source);
+
+    // Pull out the pre blocks
+    preg_match_all("!<pre>.*?</pre>!is", $source, $match);
+    $_pre_blocks = $match[0];
+    $source = preg_replace("!<pre>.*?</pre>!is",
+                           '@@@SMARTY:TRIM:PRE@@@', $source);
+
+    // Pull out the textarea blocks
+    preg_match_all("!<textarea[^>]+>.*?</textarea>!is", $source, $match);
+    $_textarea_blocks = $match[0];
+    $source = preg_replace("!<textarea[^>]+>.*?</textarea>!is",
+                           '@@@SMARTY:TRIM:TEXTAREA@@@', $source);
+
+    // remove all leading spaces, tabs and carriage returns NOT
+    // preceeded by a php close tag.
+    $source = trim(preg_replace('/((?<!\?>)\n)[\s]+/m', '\1', $source));
+
+    // replace script blocks
+    smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source);
+
+    // replace pre blocks
+    smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source);
+
+    // replace textarea blocks
+    smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source);
+
+    return $source;
+}
+
+function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) {
+    $_len = strlen($search_str);
+    $_pos = 0;
+    for ($_i=0, $_count=count($replace); $_i<$_count; $_i++)
+        if (($_pos=strpos($subject, $search_str, $_pos))!==false)
+            $subject = substr_replace($subject, $replace[$_i], $_pos, $_len);
+        else
+            break;
+
+}
+
+?>
diff --git a/include/smarty/plugins/shared.escape_special_chars.php b/include/smarty/plugins/shared.escape_special_chars.php
new file mode 100644 (file)
index 0000000..515763a
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Smarty shared plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * escape_special_chars common function
+ *
+ * Function: smarty_function_escape_special_chars<br>
+ * Purpose:  used by other smarty functions to escape
+ *           special chars except for already escaped ones
+ * @param string
+ * @return string
+ */
+function smarty_function_escape_special_chars($string)
+{
+    if(!is_array($string)) {
+        $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string);
+        $string = htmlspecialchars($string);
+        $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string);
+    }
+    return $string;
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/smarty/plugins/shared.make_timestamp.php b/include/smarty/plugins/shared.make_timestamp.php
new file mode 100644 (file)
index 0000000..acdd777
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Smarty shared plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Function: smarty_make_timestamp<br>
+ * Purpose:  used by other smarty functions to make a timestamp
+ *           from a string.
+ * @param string
+ * @return string
+ */
+function smarty_make_timestamp($string)
+{
+    if(empty($string)) {
+        $string = "now";
+    }
+    $time = strtotime($string);
+    if (is_numeric($time) && $time != -1)
+        return $time;
+
+    // is mysql timestamp format of YYYYMMDDHHMMSS?
+    if (preg_match('/^\d{14}$/', $string)) {
+        $time = mktime(substr($string,8,2),substr($string,10,2),substr($string,12,2),
+               substr($string,4,2),substr($string,6,2),substr($string,0,4));
+
+        return $time;
+    }
+
+    // couldn't recognize it, try to return a time
+    $time = (int) $string;
+    if ($time > 0)
+        return $time;
+    else
+        return time();
+}
+
+/* vim: set expandtab: */
+
+?>
diff --git a/include/version.inc b/include/version.inc
new file mode 100644 (file)
index 0000000..b1efca8
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+/* Hard code version number */
+$version= "2.3.1";
+$cvs    = "";
+
+/* Try to evaluate if we're using CVS */
+if (is_dir("$BASE_DIR/CVS")){
+  $tmp= stat("$BASE_DIR/CVS");
+  $cvs= date ("Y-m-d/H:i:s", $tmp[9]);
+} else {
+  $cvs= "RELEASE";
+}
+
+print_red(sprintf(_("You are currently using GOsa version %s (CVS checkout from %s)"),
+      $version, $cvs));
+
+// vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
+?>