rename incubator Horde_Form to hatchery Horde_Model
authorChuck Hagenbuch <chuck@horde.org>
Mon, 23 Feb 2009 16:17:27 +0000 (11:17 -0500)
committerChuck Hagenbuch <chuck@horde.org>
Mon, 23 Feb 2009 19:40:59 +0000 (14:40 -0500)
54 files changed:
framework/Form/lib/Horde/Form.php [deleted file]
framework/Form/lib/Horde/Form/Renderer.php [deleted file]
framework/Form/lib/Horde/Form/Renderer/Xhtml.php [deleted file]
framework/Form/lib/Horde/Form/Type.php [deleted file]
framework/Form/lib/Horde/Form/Type/Boolean.php [deleted file]
framework/Form/lib/Horde/Form/Type/Color.php [deleted file]
framework/Form/lib/Horde/Form/Type/CreditCard.php [deleted file]
framework/Form/lib/Horde/Form/Type/Date.php [deleted file]
framework/Form/lib/Horde/Form/Type/DateTime.php [deleted file]
framework/Form/lib/Horde/Form/Type/Email.php [deleted file]
framework/Form/lib/Horde/Form/Type/Enum.php [deleted file]
framework/Form/lib/Horde/Form/Type/Int.php [deleted file]
framework/Form/lib/Horde/Form/Type/Invalid.php [deleted file]
framework/Form/lib/Horde/Form/Type/Number.php [deleted file]
framework/Form/lib/Horde/Form/Type/Octal.php [deleted file]
framework/Form/lib/Horde/Form/Type/Password.php [deleted file]
framework/Form/lib/Horde/Form/Type/Phone.php [deleted file]
framework/Form/lib/Horde/Form/Type/Phone/Mobile.php [deleted file]
framework/Form/lib/Horde/Form/Type/Set.php [deleted file]
framework/Form/lib/Horde/Form/Type/String.php [deleted file]
framework/Form/lib/Horde/Form/Type/Time.php [deleted file]
framework/Form/lib/Horde/Form/VarRenderer.php [deleted file]
framework/Form/lib/Horde/Form/VarRenderer/Xhtml.php [deleted file]
framework/Form/www/js/maxlength.js [deleted file]
framework/Form/www/test.php [deleted file]
framework/Form/www/themes/form.css [deleted file]
framework/Form/www/themes/graphics/required.png [deleted file]
framework/Model/lib/Horde/Form.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Renderer.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Renderer/Xhtml.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Boolean.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Color.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/CreditCard.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Date.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/DateTime.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Email.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Enum.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Int.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Invalid.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Number.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Octal.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Password.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Phone.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Phone/Mobile.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Set.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/String.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/Type/Time.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/VarRenderer.php [new file with mode: 0644]
framework/Model/lib/Horde/Form/VarRenderer/Xhtml.php [new file with mode: 0644]
framework/Model/www/js/maxlength.js [new file with mode: 0644]
framework/Model/www/test.php [new file with mode: 0644]
framework/Model/www/themes/form.css [new file with mode: 0644]
framework/Model/www/themes/graphics/required.png [new file with mode: 0644]

diff --git a/framework/Form/lib/Horde/Form.php b/framework/Form/lib/Horde/Form.php
deleted file mode 100644 (file)
index 37bdd9a..0000000
+++ /dev/null
@@ -1,3946 +0,0 @@
-<?php
-/**
- * @package Horde_Form
- */
-
-/** String */
-include_once 'Horde/String.php';
-
-/**
- * Horde_Form Master Class.
- *
- * The Horde_Form:: package provides form rendering, validation, and
- * other functionality for the Horde Application Framework.
- *
- * $Horde: incubator/Horde_Form/Horde/Form.php,v 1.19 2008/08/26 15:32:55 selsky Exp $
- *
- * Copyright 2001-2007 Robert E. Coyle <robertecoyle@hotmail.com>
- * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author  Robert E. Coyle <robertecoyle@hotmail.com>
- * @author  Chuck Hagenbuch <chuck@horde.org>
- * @since   Horde 3.0
- * @package Horde_Form
- */
-class Horde_Form {
-
-    protected $_name = '';
-    protected $_title = '';
-    protected $_vars;
-    protected $_errors = array();
-    protected $_submitted = null;
-    protected $_sections = array();
-    protected $_open_section = null;
-    protected $_currentSection = array();
-    protected $_variables = array();
-    protected $_hiddenVariables = array();
-    protected $_useFormToken = true;
-    protected $_autofilled = false;
-    protected $_help = false;
-
-    public function __construct($vars, $title = '', $name = null)
-    {
-        if (is_null($name)) {
-            $name = String::lower(get_class($this));
-        }
-
-        $this->_vars = $vars;
-        $this->_title = $title;
-        $this->_name = $name;
-    }
-
-    public function setVars($vars)
-    {
-        $this->_vars = $vars;
-    }
-
-    public function getVars()
-    {
-        return $this->_vars;
-    }
-
-    public function getTitle()
-    {
-        return $this->_title;
-    }
-
-    public function setTitle($title)
-    {
-        $this->_title = $title;
-    }
-
-    public function getName()
-    {
-        return $this->_name;
-    }
-
-    /**
-     * Sets or gets whether the form should be verified by tokens.
-     * Tokens are used to verify that a form is only submitted once.
-     *
-     * @param boolean $token  If specified, sets whether to use form tokens.
-     *
-     * @return boolean  Whether form tokens are being used.
-     */
-    public function useToken($token = null)
-    {
-        if (!is_null($token)) {
-            $this->_useFormToken = $token;
-        }
-        return $this->_useFormToken;
-    }
-
-    /**
-     * Get the renderer for this form, either a custom renderer or the
-     * standard one.
-     *
-     * To use a custom form renderer, your form class needs to
-     * override this function:
-     * <code>
-     * function getRenderer()
-     * {
-     *     return new CustomFormRenderer();
-     * }
-     * </code>
-     *
-     * ... where CustomFormRenderer is the classname of the custom
-     * renderer class, which should extend Horde_Form_Renderer.
-     *
-     * @param array $params  A hash of renderer-specific parameters.
-     *
-     * @return object Horde_Form_Renderer  The form renderer.
-     */
-    function getRenderer($params = array())
-    {
-        return new Horde_Form_Renderer_Xhtml($params);
-    }
-
-    function getType($type, $params = array())
-    {
-        $type_class = 'Horde_Form_Type_' . $type;
-        if (!class_exists($type_class)) {
-            Horde::fatal(PEAR::raiseError(sprintf('Nonexistant class "%s" for field type "%s"', $type_class, $type)), __FILE__, __LINE__);
-        }
-        $type_ob = new $type_class();
-        call_user_func_array(array(&$type_ob, 'init'), $params);
-        return $type_ob;
-    }
-
-    public function setSection($section = '', $desc = '', $image = '', $expanded = true)
-    {
-        $this->_currentSection = $section;
-        if (!count($this->_sections) && !$this->getOpenSection()) {
-            $this->setOpenSection($section);
-        }
-        $this->_sections[$section]['desc'] = $desc;
-        $this->_sections[$section]['expanded'] = $expanded;
-        $this->_sections[$section]['image'] = $image;
-    }
-
-    public function getSections()
-    {
-        return $this->_sections;
-    }
-
-    public function getSectionDesc($section)
-    {
-        return $this->_sections[$section]['desc'];
-    }
-
-    public function getSectionImage($section)
-    {
-        return $this->_sections[$section]['image'];
-    }
-
-    public function setOpenSection($section)
-    {
-        $this->_vars->set('__formOpenSection', $section);
-    }
-
-    public function getOpenSection()
-    {
-        return $this->_vars->get('__formOpenSection');
-    }
-
-    public function getSectionExpandedState($section, $boolean = false)
-    {
-        if ($boolean) {
-            /* Only the boolean value is required. */
-            return $this->_sections[$section]['expanded'];
-        }
-
-        /* Need to return the values for use in styles. */
-        if ($this->_sections[$section]['expanded']) {
-            return 'block';
-        } else {
-            return 'none';
-        }
-    }
-
-    /**
-     * TODO
-     */
-    public function addVariable($humanName, $varName, $type, $required,
-                                $readonly = false, $description = null,
-                                $params = array())
-    {
-        return $this->insertVariableBefore(null, $humanName, $varName, $type,
-                                           $required, $readonly, $description,
-                                           $params);
-    }
-
-    /**
-     * TODO
-     */
-    public function insertVariableBefore($before, $humanName, $varName, $type,
-                                         $required, $readonly = false,
-                                         $description = null, $params = array())
-    {
-        $type = $this->getType($type, $params);
-        $var = new Horde_Form_Variable($humanName, $varName, $type,
-                                       $required, $readonly, $description);
-
-        /* Set the form object reference in the var. */
-        $var->setFormOb($this);
-
-        if ($var->getType() instanceof Horde_Form_Type_enum &&
-            count($var->getValues()) == 1) {
-            $vals = array_keys($var->getValues());
-            $this->_vars->add($var->varName, $vals[0]);
-            $var->_autofilled = true;
-        }
-        if (empty($this->_currentSection)) {
-            $this->_currentSection = '__base';
-        }
-
-        if (is_null($before)) {
-            $this->_variables[$this->_currentSection][] = &$var;
-        } else {
-            $num = 0;
-            while (isset($this->_variables[$this->_currentSection][$num]) &&
-                   $this->_variables[$this->_currentSection][$num]->getVarName() != $before) {
-                $num++;
-            }
-            if (!isset($this->_variables[$this->_currentSection][$num])) {
-                $this->_variables[$this->_currentSection][] = &$var;
-            } else {
-                $this->_variables[$this->_currentSection] = array_merge(
-                    array_slice($this->_variables[$this->_currentSection], 0, $num),
-                    array(&$var),
-                    array_slice($this->_variables[$this->_currentSection], $num));
-            }
-        }
-
-        return $var;
-    }
-
-    /**
-     * Removes a variable from the form.
-     *
-     * As only variables can be passed by reference, you need to call this
-     * method this way if want to pass a variable name:
-     * <code>
-     * $form->removeVariable($var = 'varname');
-     * </code>
-     *
-     * @param Horde_Form_Variable|string $var  Either the variable's name or
-     *                                         the variable to remove from the
-     *                                         form.
-     *
-     * @return boolean  True if the variable was found (and deleted).
-     */
-    public function removeVariable(&$var)
-    {
-        foreach (array_keys($this->_variables) as $section) {
-            foreach (array_keys($this->_variables[$section]) as $i) {
-                if ((is_a($var, 'Horde_Form_Variable') && $this->_variables[$section][$i] === $var) ||
-                    ($this->_variables[$section][$i]->getVarName() == $var)) {
-                    // Slice out the variable to be removed.
-                    $this->_variables[$this->_currentSection] = array_merge(
-                        array_slice($this->_variables[$this->_currentSection], 0, $i),
-                        array_slice($this->_variables[$this->_currentSection], $i + 1));
-
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * TODO
-     */
-    public function addHidden($varName, $type, $required, $params = array())
-    {
-        $type = $this->getType($type, $params);
-        $var = new Horde_Form_Variable('', $varName, $type, $required);
-        $var->hide();
-        $this->_hiddenVariables[] = &$var;
-        return $var;
-    }
-
-    public function getVariables($flat = true, $withHidden = false)
-    {
-        if ($flat) {
-            $vars = array();
-            foreach ($this->_variables as $section) {
-                foreach ($section as $var) {
-                    $vars[] = $var;
-                }
-            }
-            if ($withHidden) {
-                foreach ($this->_hiddenVariables as $var) {
-                    $vars[] = $var;
-                }
-            }
-            return $vars;
-        } else {
-            return $this->_variables;
-        }
-    }
-
-    public function getHiddenVariables()
-    {
-        return $this->_hiddenVariables;
-    }
-
-    /**
-     * Preserve the variables/values from another Horde_Form object.
-     */
-    public function preserve(Horde_Form $form)
-    {
-        /* OLD IMPLEMENTATION
-        if ($this->_useFormToken) {
-            $this->_preserveVarByPost($this->_name . '_formToken', Horde_Token::generateId($this->_name));
-        }
-
-        $variables = $this->getVariables();
-        foreach ($variables as $var) {
-            $varname = $var->getVarName();
-
-            switch (get_class($var->getType()) {
-            case 'passwordconfirm':
-            case 'emailconfirm':
-                $this->preserveVarByPost($this->_vars, $varname . '[original]');
-                $this->preserveVarByPost($this->_vars, $varname . '[confirm]');
-                break;
-
-            case 'monthyear':
-                $this->preserveVarByPost($this->_vars, $varname . '[month]');
-                $this->preserveVarByPost($this->_vars, $varname . '[year]');
-                break;
-
-            case 'monthdayyear':
-                $this->preserveVarByPost($this->_vars, $varname . '[month]');
-                $this->preserveVarByPost($this->_vars, $varname . '[day]');
-                $this->preserveVarByPost($this->_vars, $varname . '[year]');
-                break;
-            }
-
-            $this->preserveVarByPost($this->_vars, $varname);
-        }
-        foreach ($this->_hiddenVariables as $var) {
-            $this->preserveVarByPost($this->_vars, $var->getVarName());
-        }
-        */
-    }
-
-    /**
-     * Does the action of validating the form, checking if it really has been
-     * submitted by calling isSubmitted() and if true does any onSubmit()
-     * calls for var types in the form. The _submitted var is then rechecked.
-     *
-     * @param boolean         $canAutofill  Can the form be valid without
-     *                                      being submitted?
-     *
-     * @return boolean  True if the form is valid.
-     */
-    public function validate($canAutoFill = false)
-    {
-        /* Get submitted status. */
-        if ($this->isSubmitted() || $canAutoFill) {
-            /* Form was submitted or can autofill; check for any variable
-             * types' onSubmit(). */
-            $this->onSubmit($this->_vars);
-
-            /* Recheck submitted status. */
-            if (!$this->isSubmitted() && !$canAutoFill) {
-                return false;
-            }
-        } else {
-            /* Form has not been submitted; return false. */
-            return false;
-        }
-
-        $message = '';
-        $this->_autofilled = true;
-
-        if ($this->_useFormToken) {
-            global $conf;
-            if (isset($conf['token'])) {
-                /* If there is a configured token system, set it up. */
-                $tokenSource = Horde_Token::factory($conf['token']['driver'], Horde::getDriverConfig('token', $conf['token']['driver']));
-            } else {
-                /* Default to the file system if no config. */
-                $tokenSource = Horde_Token::factory('file');
-            }
-            if (!$tokenSource->verify($this->_vars->get($this->_name . '_formToken'))) {
-                $this->_errors['_formToken'] = _("This form has already been processed.");
-            }
-        }
-
-        foreach ($this->getVariables() as $var) {
-            $this->_autofilled = $var->_autofilled && $this->_autofilled;
-            if (!$var->validate($this->_vars, $message)) {
-                $this->_errors[$var->getVarName()] = $message;
-            }
-        }
-
-        if ($this->_autofilled) {
-            unset($this->_errors['_formToken']);
-        }
-
-        foreach ($this->_hiddenVariables as $var) {
-            if (!$var->validate($this->_vars, $message)) {
-                $this->_errors[$var->getVarName()] = $message;
-            }
-        }
-
-        return $this->isValid();
-    }
-
-    public function clearValidation()
-    {
-        $this->_errors = array();
-    }
-
-    public function getError($var)
-    {
-        if (is_a($var, 'Horde_Form_Variable')) {
-            $name = $var->getVarName();
-        } else {
-            $name = $var;
-        }
-        return isset($this->_errors[$name]) ? $this->_errors[$name] : null;
-    }
-
-    public function setError($var, $message)
-    {
-        if (is_a($var, 'Horde_Form_Variable')) {
-            $name = $var->getVarName();
-        } else {
-            $name = $var;
-        }
-        $this->_errors[$name] = $message;
-    }
-
-    public function clearError($var)
-    {
-        if (is_a($var, 'Horde_Form_Variable')) {
-            $name = $var->getVarName();
-        } else {
-            $name = $var;
-        }
-        unset($this->_errors[$name]);
-    }
-
-    public function isValid()
-    {
-        return ($this->_autofilled || !count($this->_errors));
-    }
-
-    public function execute()
-    {
-        throw new Horde_Form_Exception('Subclass must overide execute()');
-    }
-
-    /**
-     * Fetch the field values of the submitted form.
-     *
-     * @param array $info      Array to be filled with the submitted field
-     *                         values.
-     */
-    public function getInfo(&$info)
-    {
-        $this->_getInfoFromVariables($this->getVariables(), $info);
-        $this->_getInfoFromVariables($this->_hiddenVariables, $info);
-    }
-
-    /**
-     * Fetch the field values from a given array of variables.
-     *
-     * @access private
-     *
-     * @param array  $variables  An array of Horde_Form_Variable objects to
-     *                           fetch from.
-     * @param array  $info       The array to be filled with the submitted
-     *                           field values.
-     */
-    protected function _getInfoFromVariables($variables, &$info)
-    {
-        foreach ($variables as $var) {
-            if ($var->isArrayVal()) {
-                $var->getInfo($this->_vars, $values);
-                if (is_array($values)) {
-                    $varName = str_replace('[]', '', $var->getVarName());
-                    foreach ($values as $i => $val) {
-                        $info[$i][$varName] = $val;
-                    }
-                }
-            } else {
-                if (Horde_Array::getArrayParts($var->getVarName(), $base, $keys)) {
-                    if (!isset($info[$base])) {
-                        $info[$base] = array();
-                    }
-                    $pointer = &$info[$base];
-                    while (count($keys)) {
-                        $key = array_shift($keys);
-                        if (!isset($pointer[$key])) {
-                            $pointer[$key] = array();
-                        }
-                        $pointer = &$pointer[$key];
-                    }
-                    $var->getInfo($this->_vars, $pointer);
-                } else {
-                    $var->getInfo($this->_vars, $info[$var->getVarName()]);
-                }
-            }
-        }
-    }
-
-    public function hasHelp()
-    {
-        return $this->_help;
-    }
-
-    /**
-     * Determines if this form has been submitted or not. If the class
-     * var _submitted is null then it will check for the presence of
-     * the formname in the form variables.
-     *
-     * Other events can explicitly set the _submitted variable to
-     * false to indicate a form submit but not for actual posting of
-     * data (eg. onChange events to update the display of fields).
-     *
-     * @return boolean  True or false indicating if the form has been
-     *                  submitted.
-     */
-    public function isSubmitted()
-    {
-        if (is_null($this->_submitted)) {
-            if ($this->_vars->get('formname') == $this->getName()) {
-                $this->_submitted = true;
-            } else {
-                $this->_submitted = false;
-            }
-        }
-
-        return $this->_submitted;
-    }
-
-    /**
-     * Checks if there is anything to do on the submission of the form by
-     * looping through each variable's onSubmit() function.
-     */
-    public function onSubmit()
-    {
-        /* Loop through all vars and check if there's anything to do on
-         * submit. */
-        $variables = $this->getVariables();
-        foreach ($variables as $var) {
-            $var->type->onSubmit($var, $this->_vars);
-            /* If changes to var being tracked don't register the form as
-             * submitted if old value and new value differ. */
-            if ($var->getOption('trackchange')) {
-                $varname = $var->getVarName();
-                if (!is_null($this->_vars->get('formname')) &&
-                    $this->_vars->get($varname) != $this->_vars->get('__old_' . $varname)) {
-                    $this->_submitted = false;
-                }
-            }
-        }
-    }
-
-    /**
-     * Explicitly sets the state of the form submit.
-     *
-     * An event can override the automatic determination of the submit state
-     * in the isSubmitted() function.
-     *
-     * @param boolean $state  Whether to set the state of the form as being
-     *                        submitted.
-     */
-    public function setSubmitted($state = true)
-    {
-        $this->_submitted = $state;
-    }
-
-}
-
-/**
- * Horde_Form_Type Class
- *
- * @author  Robert E. Coyle <robertecoyle@hotmail.com>
- * @package Horde_Form
- */
-class Horde_Form_Type {
-
-    protected function __get($property)
-    {
-        $prop = '_' . $property;
-        return isset($this->$prop) ? $this->$prop : null;
-    }
-
-    protected function __set($property, $value)
-    {
-        $prop = '_' . $property;
-        $this->$prop = $value;
-    }
-
-    protected function __isset($property)
-    {
-        $prop = '_' . $property;
-        return isset($this->$prop);
-    }
-
-    protected function __unset($property)
-    {
-        $prop = '_' . $property;
-        unset($this->$prop);
-    }
-
-    public function init()
-    {
-    }
-
-    public function onSubmit()
-    {
-    }
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        $message = '<strong>Error:</strong> Horde_Form_Type::isValid() called - should be overridden<br />';
-        return false;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        $info = $var->getValue($vars);
-    }
-
-}
-
-class Horde_Form_Type_number extends Horde_Form_Type {
-
-    var $_fraction;
-
-    function init($fraction = null)
-    {
-        $this->_fraction = $fraction;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && empty($value) && ((string)(double)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        } elseif (empty($value)) {
-            return true;
-        }
-
-        /* If matched, then this is a correct numeric value. */
-        if (preg_match($this->_getValidationPattern(), $value)) {
-            return true;
-        }
-
-        $message = _("This field must be a valid number.");
-        return false;
-    }
-
-    function _getValidationPattern()
-    {
-        static $pattern = '';
-        if (!empty($pattern)) {
-            return $pattern;
-        }
-
-        /* Get current locale information. */
-        $linfo = NLS::getLocaleInfo();
-
-        /* Build the pattern. */
-        $pattern = '(-)?';
-
-        /* Only check thousands separators if locale has any. */
-        if (!empty($linfo['mon_thousands_sep'])) {
-            /* Regex to check for correct thousands separators (if any). */
-            $pattern .= '((\d+)|((\d{0,3}?)([' . $linfo['mon_thousands_sep'] . ']\d{3})*?))';
-        } else {
-            /* No locale thousands separator, check for only digits. */
-            $pattern .= '(\d+)';
-        }
-        /* If no decimal point specified default to dot. */
-        if (empty($linfo['mon_decimal_point'])) {
-            $linfo['mon_decimal_point'] = '.';
-        }
-        /* Regex to check for correct decimals (if any). */
-        if (empty($this->_fraction)) {
-            $fraction = '*';
-        } else {
-            $fraction = '{0,' . $this->_fraction . '}';
-        }
-        $pattern .= '([' . $linfo['mon_decimal_point'] . '](\d' . $fraction . '))?';
-
-        /* Put together the whole regex pattern. */
-        $pattern = '/^' . $pattern . '$/';
-
-        return $pattern;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        $value = $vars->get($var->getVarName());
-        $linfo = NLS::getLocaleInfo();
-        $value = str_replace($linfo['mon_thousands_sep'], '', $value);
-        $info = str_replace($linfo['mon_decimal_point'], '.', $value);
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Number"));
-    }
-
-}
-
-class Horde_Form_Type_int extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && empty($value) && ((string)(int)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^[0-9]+$/', $value)) {
-            return true;
-        }
-
-        $message = _("This field may only contain integers.");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Integer"));
-    }
-
-}
-
-class Horde_Form_Type_octal extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && empty($value) && ((string)(int)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^[0-7]+$/', $value)) {
-            return true;
-        }
-
-        $message = _("This field may only contain octal values.");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Octal"));
-    }
-
-}
-
-class Horde_Form_Type_intlist extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if (empty($value) && $var->isRequired()) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^[0-9 ,]+$/', $value)) {
-            return true;
-        }
-
-        $message = _("This field must be a comma or space separated list of integers");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Integer list"));
-    }
-
-}
-
-class Horde_Form_Type_text extends Horde_Form_Type {
-
-    var $_regex;
-    var $_size;
-    var $_maxlength;
-
-    /**
-     * The initialisation function for the text variable type.
-     *
-     * @access private
-     *
-     * @param string $regex       Any valid PHP PCRE pattern syntax that
-     *                            needs to be matched for the field to be
-     *                            considered valid. If left empty validity
-     *                            will be checked only for required fields
-     *                            whether they are empty or not.
-     *                            If using this regex test it is advisable
-     *                            to enter a description for this field to
-     *                            warn the user what is expected, as the
-     *                            generated error message is quite generic
-     *                            and will not give any indication where
-     *                            the regex failed.
-     * @param integer $size       The size of the input field.
-     * @param integer $maxlength  The max number of characters.
-     */
-    function init($regex = '', $size = 40, $maxlength = null)
-    {
-        $this->_regex     = $regex;
-        $this->_size      = $size;
-        $this->_maxlength = $maxlength;
-    }
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if (!empty($this->_maxlength) && String::length($value) > $this->_maxlength) {
-            $valid = false;
-            $message = sprintf(_("Value is over the maximum length of %s."), $this->_maxlength);
-        } elseif ($var->isRequired() && empty($this->_regex)) {
-            if (!($valid = strlen(trim($value)) > 0)) {
-                $message = _("This field is required.");
-            }
-        } elseif (strlen($this->_regex)) {
-            if (!($valid = preg_match($this->_regex, $value))) {
-                $message = _("You must enter a valid value.");
-            }
-        }
-
-        return $valid;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Text"),
-            'params' => array(
-                'regex'     => array('label' => _("Regex"),
-                                     'type'  => 'text'),
-                'size'      => array('label' => _("Size"),
-                                     'type'  => 'int'),
-                'maxlength' => array('label' => _("Maximum length"),
-                                     'type'  => 'int')));
-    }
-
-}
-
-class Horde_Form_Type_stringlist extends Horde_Form_Type_text {
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("String list"),
-            'params' => array(
-                'regex'     => array('label' => _("Regex"),
-                                     'type'  => 'text'),
-                'size'      => array('label' => _("Size"),
-                                     'type'  => 'int'),
-                'maxlength' => array('label' => _("Maximum length"),
-                                     'type'  => 'int')),
-        );
-    }
-
-}
-
-class Horde_Form_Type_phone extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if ($var->isRequired()) {
-            $valid = strlen(trim($value)) > 0;
-            if (!$valid) {
-                $message = _("This field is required.");
-            }
-        } else {
-            $valid = preg_match('/^\+?[\d()\-\/ ]*$/', $value);
-            if (!$valid) {
-                $message = _("You must enter a valid phone number, digits only with an optional '+' for the international dialing prefix.");
-            }
-        }
-
-        return $valid;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Phone number"));
-    }
-
-}
-
-class Horde_Form_Type_cellphone extends Horde_Form_Type_phone {
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Mobile phone number"));
-    }
-
-}
-
-class Horde_Form_Type_ipaddress extends Horde_Form_Type_text {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if (strlen(trim($value)) > 0) {
-            $ip = explode('.', $value);
-            $valid = (count($ip) == 4);
-            if ($valid) {
-                foreach ($ip as $part) {
-                    if (!is_numeric($part) ||
-                        $part > 255 ||
-                        $part < 0) {
-                        $valid = false;
-                        break;
-                    }
-                }
-            }
-
-            if (!$valid) {
-                $message = _("Please enter a valid IP address.");
-            }
-        } elseif ($var->isRequired()) {
-            $valid = false;
-            $message = _("This field is required.");
-        }
-
-        return $valid;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("IP address"));
-    }
-
-}
-
-class Horde_Form_Type_longtext extends Horde_Form_Type_text {
-
-    var $_rows;
-    var $_cols;
-    var $_helper = array();
-
-    function init($rows = 8, $cols = 80, $helper = array())
-    {
-        if (!is_array($helper)) {
-            $helper = array($helper);
-        }
-
-        $this->_rows = $rows;
-        $this->_cols = $cols;
-        $this->_helper = $helper;
-    }
-
-    function hasHelper($option = '')
-    {
-        if (empty($option)) {
-            /* No option specified, check if any helpers have been
-             * activated. */
-            return !empty($this->_helper);
-        } elseif (empty($this->_helper)) {
-            /* No helpers activated at all, return false. */
-            return false;
-        } else {
-            /* Check if given helper has been activated. */
-            return in_array($option, $this->_helper);
-        }
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Long text"),
-            'params' => array(
-                'rows'   => array('label' => _("Number of rows"),
-                                  'type'  => 'int'),
-                'cols'   => array('label' => _("Number of columns"),
-                                  'type'  => 'int'),
-                'helper' => array('label' => _("Helper?"),
-                                  'type'  => 'boolean')));
-    }
-
-}
-
-class Horde_Form_Type_countedtext extends Horde_Form_Type_longtext {
-
-    var $_chars;
-
-    function init($rows = null, $cols = null, $chars = 1000)
-    {
-        parent::init($rows, $cols);
-        $this->_chars = $chars;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        $length = String::length(trim($value));
-
-        if ($var->isRequired() && $length <= 0) {
-            $valid = false;
-            $message = _("This field is required.");
-        } elseif ($length > $this->_chars) {
-            $valid = false;
-            $message = sprintf(_("There are too many characters in this field. You have entered %s characters; you must enter less than %s."), String::length(trim($value)), $this->_chars);
-        }
-
-        return $valid;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Counted text"),
-            'params' => array(
-                'rows'  => array('label' => _("Number of rows"),
-                                 'type'  => 'int'),
-                'cols'  => array('label' => _("Number of columns"),
-                                 'type'  => 'int'),
-                'chars' => array('label' => _("Number of characters"),
-                                 'type'  => 'int')));
-    }
-
-}
-
-class Horde_Form_Type_address extends Horde_Form_Type_longtext {
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Address"),
-            'params' => array(
-                'rows' => array('label' => _("Number of rows"),
-                                'type'  => 'int'),
-                'cols' => array('label' => _("Number of columns"),
-                                'type'  => 'int')));
-    }
-
-}
-
-class Horde_Form_Type_addresslink extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-}
-
-class Horde_Form_Type_file extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired()) {
-            $uploaded = Horde_Browser::wasFileUploaded($var->getVarName());
-            if (is_a($uploaded, 'PEAR_Error')) {
-                $message = $uploaded->getMessage();
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        $name = $var->getVarName();
-        $uploaded = Horde_Browser::wasFileUploaded($name);
-        if ($uploaded === true) {
-            $info['name'] = $_FILES[$name]['name'];
-            $info['type'] = $_FILES[$name]['type'];
-            $info['tmp_name'] = $_FILES[$name]['tmp_name'];
-            $info['file'] = $_FILES[$name]['tmp_name'];
-            $info['error'] = $_FILES[$name]['error'];
-            $info['size'] = $_FILES[$name]['size'];
-        }
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("File upload"));
-    }
-
-}
-
-class Horde_Form_Type_image extends Horde_Form_Type {
-
-    /**
-     * Has a file been uploaded on this form submit?
-     *
-     * @var boolean
-     */
-    var $_uploaded = null;
-
-    /**
-     * Show the upload button?
-     *
-     * @var boolean
-     */
-    var $_show_upload = true;
-
-    /**
-     * Show the option to upload also original non-modified image?
-     *
-     * @var boolean
-     */
-    var $_show_keeporig = false;
-
-    /**
-     * Limit the file size?
-     *
-     * @var integer
-     */
-    var $_max_filesize = null;
-
-    /**
-     * Hash containing the previously uploaded image info.
-     *
-     * @var array
-     */
-    var $_img = array();
-
-    function init($show_upload = true, $show_keeporig = false, $max_filesize = null)
-    {
-        $this->_show_upload   = $show_upload;
-        $this->_show_keeporig = $show_keeporig;
-        $this->_max_filesize  = $max_filesize;
-    }
-
-    function onSubmit($var, $vars)
-    {
-        /* Get the upload. */
-        $this->_getUpload($vars, $var);
-
-        /* If this was done through the upload button override the submitted
-         * value of the form. */
-        if ($vars->get('_do_' . $var->getVarName())) {
-            $var->form->setSubmitted(false);
-        }
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $field = $vars->get($var->getVarName());
-
-        /* Get the upload. */
-        $this->_getUpload($vars, $var);
-
-        /* The upload generated a PEAR Error. */
-        if (is_a($this->_uploaded, 'PEAR_Error')) {
-            /* Not required and no image upload attempted. */
-            if (!$var->isRequired() && empty($field['img']) &&
-                $this->_uploaded->getCode() == UPLOAD_ERR_NO_FILE) {
-                return true;
-            }
-
-            if (($this->_uploaded->getCode() == UPLOAD_ERR_NO_FILE) &&
-                empty($field['img'])) {
-                /* Nothing uploaded and no older upload. */
-                $message = _("This field is required.");
-                return false;
-            } elseif (!empty($field['img'])) {
-                /* Nothing uploaded but older upload present. */
-                return true;
-            } else {
-                /* Some other error message. */
-                $message = $this->_uploaded->getMessage();
-                return false;
-            }
-        } elseif ($this->_max_filesize &&
-                  $this->_img['size'] > $this->_max_filesize) {
-            $message = sprintf(_("The image file was larger than the maximum allowed size (%d bytes)."), $this->_max_filesize);
-            return false;
-        }
-
-        return true;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        /* Get the upload. */
-        $this->_getUpload($vars, $var);
-
-        /* Get image params stored in the hidden field. */
-        $value = $var->getValue($vars);
-        $info = $this->_img;
-        if (empty($info['file'])) {
-            unset($info['file']);
-            return;
-        }
-        if ($this->_show_keeporig) {
-            $info['keep_orig'] = !empty($value['keep_orig']);
-        }
-
-        /* Set the uploaded value (either true or PEAR_Error). */
-        $info['uploaded'] = &$this->_uploaded;
-
-        /* If a modified file exists move it over the original. */
-        if ($this->_show_keeporig && $info['keep_orig']) {
-            /* Requested the saving of original file also. */
-            $info['orig_file'] = Horde::getTempDir() . '/' . $info['file'];
-            $info['file'] = Horde::getTempDir() . '/mod_' . $info['file'];
-            /* Check if a modified file actually exists. */
-            if (!file_exists($info['file'])) {
-                $info['file'] = $info['orig_file'];
-                unset($info['orig_file']);
-            }
-        } else {
-            /* Saving of original not required. */
-            $mod_file = Horde::getTempDir() . '/mod_' . $info['file'];
-            $info['file'] = Horde::getTempDir() . '/' . $info['file'];
-
-            if (file_exists($mod_file)) {
-                /* Unlink first (has to be done on Windows machines?) */
-                unlink($info['file']);
-                rename($mod_file, $info['file']);
-            }
-        }
-    }
-
-    /**
-     * Gets the upload and sets up the upload data array. Either
-     * fetches an upload done with this submit or retries stored
-     * upload info.
-     */
-    function _getUpload($vars, $var)
-    {
-        /* Don't bother with this function if already called and set
-         * up vars. */
-        if (!empty($this->_img)) {
-            return true;
-        }
-
-        /* Check if file has been uploaded. */
-        $varname = $var->getVarName();
-        $this->_uploaded = Horde_Browser::wasFileUploaded($varname . '[new]');
-
-        if ($this->_uploaded === true) {
-            /* A file has been uploaded on this submit. Save to temp dir for
-             * preview work. */
-            $this->_img['type'] = $this->getUploadedFileType($varname . '[new]');
-
-            /* Get the other parts of the upload. */
-            Horde_Array::getArrayParts($varname . '[new]', $base, $keys);
-
-            /* Get the temporary file name. */
-            $keys_path = array_merge(array($base, 'tmp_name'), $keys);
-            $this->_img['file'] = Horde_Array::getElement($_FILES, $keys_path);
-
-            /* Get the actual file name. */
-            $keys_path= array_merge(array($base, 'name'), $keys);
-            $this->_img['name'] = Horde_Array::getElement($_FILES, $keys_path);
-
-            /* Get the file size. */
-            $keys_path= array_merge(array($base, 'size'), $keys);
-            $this->_img['size'] = Horde_Array::getElement($_FILES, $keys_path);
-
-            /* Get any existing values for the image upload field. */
-            $upload = $vars->get($var->getVarName());
-            $upload['img'] = @unserialize($upload['img']);
-
-            /* Get the temp file if already one uploaded, otherwise create a
-             * new temporary file. */
-            if (!empty($upload['img']['file'])) {
-                $tmp_file = Horde::getTempDir() . '/' . $upload['img']['file'];
-            } else {
-                $tmp_file = Horde::getTempFile('Horde', false);
-            }
-
-            /* Move the browser created temp file to the new temp file. */
-            move_uploaded_file($this->_img['file'], $tmp_file);
-            $this->_img['file'] = basename($tmp_file);
-
-            /* Store the uploaded image file data to the hidden field. */
-            $upload['img'] = serialize($this->_img);
-            $vars->set($var->getVarName(), $upload);
-        } elseif ($this->_uploaded) {
-            /* File has not been uploaded. */
-            $upload = $vars->get($var->getVarName());
-            if ($this->_uploaded->getCode() == 4 && !empty($upload['img'])) {
-                $this->_img = @unserialize($upload['img']);
-            }
-        }
-    }
-
-    function getUploadedFileType($field)
-    {
-        /* Get any index on the field name. */
-        $index = Horde_Array::getArrayParts($field, $base, $keys);
-
-        if ($index) {
-            /* Index present, fetch the mime type var to check. */
-            $keys_path = array_merge(array($base, 'type'), $keys);
-            $type = Horde_Array::getElement($_FILES, $keys_path);
-            $keys_path= array_merge(array($base, 'tmp_name'), $keys);
-            $tmp_name = Horde_Array::getElement($_FILES, $keys_path);
-        } else {
-            /* No index, simple set up of vars to check. */
-            $type = $_FILES[$field]['type'];
-            $tmp_name = $_FILES[$field]['tmp_name'];
-        }
-
-        if (empty($type) || ($type == 'application/octet-stream')) {
-            /* Type wasn't set on upload, try analising the upload. */
-            global $conf;
-            require_once 'Horde/MIME/Magic.php';
-            if (!($type = MIME_Magic::analyzeFile($tmp_name, isset($conf['mime']['magic_db']) ? $conf['mime']['magic_db'] : null))) {
-                if ($index) {
-                    /* Get the name value. */
-                    $keys_path = array_merge(array($base, 'name'), $keys);
-                    $name = Horde_Array::getElement($_FILES, $keys_path);
-
-                    /* Work out the type from the file name. */
-                    $type = MIME_Magic::filenameToMIME($name);
-
-                    /* Set the type. */
-                    $keys_path = array_merge(array($base, 'type'), $keys);
-                    Horde_Array::getElement($_FILES, $keys_path, $type);
-                } else {
-                    /* Work out the type from the file name. */
-                    $type = MIME_Magic::filenameToMIME($_FILES[$field]['name']);
-
-                    /* Set the type. */
-                    $_FILES[$field]['type'] = MIME_Magic::filenameToMIME($_FILES[$field]['name']);
-                }
-            }
-        }
-
-        return $type;
-    }
-
-    /**
-     * Loads any existing image data into the image field. Requires that the
-     * array $image passed to it contains the structure:
-     *   $image['load']['file'] - the filename of the image;
-     *   $image['load']['data'] - the raw image data.
-     *
-     * @param array $image  The image array.
-     */
-    function loadImageData(&$image)
-    {
-        /* No existing image data to load. */
-        if (!isset($image['load'])) {
-            return;
-        }
-
-        /* Save the data to the temp dir. */
-        $tmp_file = Horde::getTempDir() . '/' . $image['load']['file'];
-        if ($fd = fopen($tmp_file, 'w')) {
-            fwrite($fd, $image['load']['data']);
-            fclose($fd);
-        }
-
-        $image['img'] = serialize(array('file' => $image['load']['file']));
-        unset($image['load']);
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Image upload"),
-            'params' => array(
-                'show_upload'   => array('label' => _("Show upload?"),
-                                         'type'  => 'boolean'),
-                'show_keeporig' => array('label' => _("Show option to keep original?"),
-                                         'type'  => 'boolean'),
-                'max_filesize'  => array('label' => _("Maximum file size in bytes"),
-                                         'type'  => 'int')));
-    }
-
-}
-
-class Horde_Form_Type_boolean extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        $info = String::lower($vars->get($var->getVarName())) == 'on';
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("True or false"));
-    }
-
-}
-
-class Horde_Form_Type_link extends Horde_Form_Type {
-
-    /**
-     * List of hashes containing link parameters. Possible keys: 'url', 'text',
-     * 'target', 'onclick', 'title', 'accesskey'.
-     *
-     * @var array
-     */
-    var $values;
-
-    function init($values)
-    {
-        $this->values = $values;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Link"),
-            'params' => array(
-                'url' => array(
-                    'label' => _("Link URL"),
-                    'type' => 'text'),
-                'text' => array(
-                    'label' => _("Link text"),
-                    'type' => 'text'),
-                'target' => array(
-                    'label' => _("Link target"),
-                    'type' => 'text'),
-                'onclick' => array(
-                    'label' => _("Onclick event"),
-                    'type' => 'text'),
-                'title' => array(
-                    'label' => _("Link title attribute"),
-                    'type' => 'text'),
-                'accesskey' => array(
-                    'label' => _("Link access key"),
-                    'type' => 'text')));
-    }
-
-}
-
-class Horde_Form_Type_email extends Horde_Form_Type {
-
-    var $_allow_multi = false;
-    var $_strip_domain = false;
-    var $_link_compose = false;
-    var $_check_smtp = false;
-    var $_link_name;
-
-    /**
-     * A string containing valid delimiters (default is just comma).
-     *
-     * @var string
-     */
-    var $_delimiters = ',';
-
-    function init($allow_multi = false, $strip_domain = false,
-                  $link_compose = false, $link_name = null,
-                  $delimiters = ',')
-    {
-        $this->_allow_multi = $allow_multi;
-        $this->_strip_domain = $strip_domain;
-        $this->_link_compose = $link_compose;
-        $this->_link_name = $link_name;
-        $this->_delimiters = $delimiters;
-    }
-
-    /**
-     */
-    function isValid($var, $vars, $value, &$message)
-    {
-        // Split into individual addresses.
-        $emails = $this->splitEmailAddresses($value);
-
-        // Check for too many.
-        if (!$this->_allow_multi && count($emails) > 1) {
-            $message = _("Only one email address is allowed.");
-            return false;
-        }
-
-        // Check for all valid and at least one non-empty.
-        $nonEmpty = 0;
-        foreach ($emails as $email) {
-            if (!strlen($email)) {
-                continue;
-            }
-            if (!$this->validateEmailAddress($email)) {
-                $message = sprintf(_("\"%s\" is not a valid email address."), $email);
-                return false;
-            }
-            ++$nonEmpty;
-        }
-
-        if (!$nonEmpty && $var->isRequired()) {
-            if ($this->_allow_multi) {
-                $message = _("You must enter at least one email address.");
-            } else {
-                $message = _("You must enter an email address.");
-            }
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Explodes an RFC 2822 string, ignoring a delimiter if preceded
-     * by a "\" character, or if the delimiter is inside single or
-     * double quotes.
-     *
-     * @param string $string     The RFC 822 string.
-     *
-     * @return array  The exploded string in an array.
-     */
-    function splitEmailAddresses($string)
-    {
-        $quotes = array('"', "'");
-        $emails = array();
-        $pos = 0;
-        $in_quote = null;
-        $in_group = false;
-        $prev = null;
-
-        if (!strlen($string)) {
-            return array();
-        }
-
-        $char = $string[0];
-        if (in_array($char, $quotes)) {
-            $in_quote = $char;
-        } elseif ($char == ':') {
-            $in_group = true;
-        } elseif (strpos($this->_delimiters, $char) !== false) {
-            $emails[] = '';
-            $pos = 1;
-        }
-
-        for ($i = 1, $iMax = strlen($string); $i < $iMax; ++$i) {
-            $char = $string[$i];
-            if (in_array($char, $quotes)) {
-                if ($prev !== '\\') {
-                    if ($in_quote === $char) {
-                        $in_quote = null;
-                    } elseif (is_null($in_quote)) {
-                        $in_quote = $char;
-                    }
-                }
-            } elseif ($in_group) {
-                if ($char == ';') {
-                    $emails[] = substr($string, $pos, $i - $pos + 1);
-                    $pos = $i + 1;
-                    $in_group = false;
-                }
-            } elseif ($char == ':') {
-                $in_group = true;
-            } elseif (strpos($this->_delimiters, $char) !== false &&
-                      $prev !== '\\' &&
-                      is_null($in_quote)) {
-                $emails[] = substr($string, $pos, $i - $pos);
-                $pos = $i + 1;
-            }
-            $prev = $char;
-        }
-
-        if ($pos != $i) {
-            /* The string ended without a delimiter. */
-            $emails[] = substr($string, $pos, $i - $pos);
-        }
-
-        return $emails;
-    }
-
-    /**
-     * RFC(2)822 Email Parser.
-     *
-     * By Cal Henderson <cal@iamcal.com>
-     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
-     * http://creativecommons.org/licenses/by-sa/2.5/
-     *
-     * http://code.iamcal.com/php/rfc822/
-     *
-     * http://iamcal.com/publish/articles/php/parsing_email
-     *
-     * Revision 4
-     *
-     * @param string $email An individual email address to validate.
-     *
-     * @return boolean
-     */
-    function validateEmailAddress($email)
-    {
-        static $comment_regexp, $email_regexp;
-        if ($comment_regexp === null) {
-            $this->_defineValidationRegexps($comment_regexp, $email_regexp);
-        }
-
-        // We need to strip comments first (repeat until we can't find
-        // any more).
-        while (true) {
-            $new = preg_replace("!$comment_regexp!", '', $email);
-            if (strlen($new) == strlen($email)){
-                break;
-            }
-            $email = $new;
-        }
-
-        // Now match what's left.
-        $result = (bool)preg_match("!^$email_regexp$!", $email);
-        if ($result && $this->_check_smtp) {
-            $result = $this->validateEmailAddressSmtp($email);
-        }
-
-        return $result;
-    }
-
-    /**
-     * Attempt partial delivery of mail to an address to validate it.
-     *
-     * @param string $email An individual email address to validate.
-     *
-     * @return boolean
-     */
-    function validateEmailAddressSmtp($email)
-    {
-        list(, $maildomain) = explode('@', $email, 2);
-
-        // Try to get the real mailserver from MX records.
-        if (function_exists('getmxrr') &&
-            @getmxrr($maildomain, $mxhosts, $mxpriorities)) {
-            // MX record found.
-            array_multisort($mxpriorities, $mxhosts);
-            $mailhost = $mxhosts[0];
-        } else {
-            // No MX record found, try the root domain as the mail
-            // server.
-            $mailhost = $maildomain;
-        }
-
-        $fp = @fsockopen($mailhost, 25, $errno, $errstr, 5);
-        if (!$fp) {
-            return false;
-        }
-
-        // Read initial response.
-        fgets($fp, 4096);
-
-        // HELO
-        fputs($fp, "HELO $mailhost\r\n");
-        fgets($fp, 4096);
-
-        // MAIL FROM
-        fputs($fp, "MAIL FROM: <root@example.com>\r\n");
-        fgets($fp, 4096);
-
-        // RCPT TO - gets the result we want.
-        fputs($fp, "RCPT TO: <$email>\r\n");
-        $result = trim(fgets($fp, 4096));
-
-        // QUIT
-        fputs($fp, "QUIT\r\n");
-        fgets($fp, 4096);
-        fclose($fp);
-
-        return substr($result, 0, 1) == '2';
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Email"),
-            'params' => array(
-                'allow_multi' => array('label' => _("Allow multiple addresses?"),
-                                       'type'  => 'boolean'),
-                'strip_domain' => array('label' => _("Protect address from spammers?"),
-                                        'type' => 'boolean'),
-                'link_compose' => array('label' => _("Link the email address to the compose page when displaying?"),
-                                        'type' => 'boolean'),
-                'link_name' => array('label' => _("The name to use when linking to the compose page"),
-                                     'type' => 'text'),
-                'delimiters' => array('label' => _("Character to split multiple addresses with"),
-                                      'type' => 'text'),
-            ),
-        );
-    }
-
-    /**
-     * RFC(2)822 Email Parser.
-     *
-     * By Cal Henderson <cal@iamcal.com>
-     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
-     * http://creativecommons.org/licenses/by-sa/2.5/
-     *
-     * http://code.iamcal.com/php/rfc822/
-     *
-     * http://iamcal.com/publish/articles/php/parsing_email
-     *
-     * Revision 4
-     *
-     * @param string &$comment The regexp for comments.
-     * @param string &$addr_spec The regexp for email addresses.
-     */
-    function _defineValidationRegexps(&$comment, &$addr_spec)
-    {
-        /**
-         * NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
-         *                         %d11 /          ;  that do not include the
-         *                         %d12 /          ;  carriage return, line feed,
-         *                         %d14-31 /       ;  and white space characters
-         *                         %d127
-         * ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
-         * DIGIT          =  %x30-39
-         */
-        $no_ws_ctl  = "[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]";
-        $alpha      = "[\\x41-\\x5a\\x61-\\x7a]";
-        $digit      = "[\\x30-\\x39]";
-        $cr         = "\\x0d";
-        $lf         = "\\x0a";
-        $crlf       = "($cr$lf)";
-
-        /**
-         * obs-char        =       %d0-9 / %d11 /          ; %d0-127 except CR and
-         *                         %d12 / %d14-127         ;  LF
-         * obs-text        =       *LF *CR *(obs-char *LF *CR)
-         * text            =       %d1-9 /         ; Characters excluding CR and LF
-         *                         %d11 /
-         *                         %d12 /
-         *                         %d14-127 /
-         *                         obs-text
-         * obs-qp          =       "\" (%d0-127)
-         * quoted-pair     =       ("\" text) / obs-qp
-         */
-        $obs_char       = "[\\x00-\\x09\\x0b\\x0c\\x0e-\\x7f]";
-        $obs_text       = "($lf*$cr*($obs_char$lf*$cr*)*)";
-        $text           = "([\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f]|$obs_text)";
-        $obs_qp         = "(\\x5c[\\x00-\\x7f])";
-        $quoted_pair    = "(\\x5c$text|$obs_qp)";
-
-        /**
-         * obs-FWS         =       1*WSP *(CRLF 1*WSP)
-         * FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
-         *                         obs-FWS
-         * ctext           =       NO-WS-CTL /     ; Non white space controls
-         *                         %d33-39 /       ; The rest of the US-ASCII
-         *                         %d42-91 /       ;  characters not including "(",
-         *                         %d93-126        ;  ")", or "\"
-         * ccontent        =       ctext / quoted-pair / comment
-         * comment         =       "(" *([FWS] ccontent) [FWS] ")"
-         * CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
-         *
-         * @note: We translate ccontent only partially to avoid an
-         * infinite loop. Instead, we'll recursively strip comments
-         * before processing the input.
-         */
-        $wsp        = "[\\x20\\x09]";
-        $obs_fws    = "($wsp+($crlf$wsp+)*)";
-        $fws        = "((($wsp*$crlf)?$wsp+)|$obs_fws)";
-        $ctext      = "($no_ws_ctl|[\\x21-\\x27\\x2A-\\x5b\\x5d-\\x7e])";
-        $ccontent   = "($ctext|$quoted_pair)";
-        $comment    = "(\\x28($fws?$ccontent)*$fws?\\x29)";
-        $cfws       = "(($fws?$comment)*($fws?$comment|$fws))";
-        $cfws       = "$fws*";
-
-        /**
-         * atext           =       ALPHA / DIGIT / ; Any character except controls,
-         *                         "!" / "#" /     ;  SP, and specials.
-         *                         "$" / "%" /     ;  Used for atoms
-         *                         "&" / "'" /
-         *                         "*" / "+" /
-         *                         "-" / "/" /
-         *                         "=" / "?" /
-         *                         "^" / "_" /
-         *                         "`" / "{" /
-         *                         "|" / "}" /
-         *                         "~"
-         * atom            =       [CFWS] 1*atext [CFWS]
-         */
-        $atext      = "($alpha|$digit|[\\x21\\x23-\\x27\\x2a\\x2b\\x2d\\x2e\\x3d\\x3f\\x5e\\x5f\\x60\\x7b-\\x7e])";
-        $atom       = "($cfws?$atext+$cfws?)";
-
-        /**
-         * qtext           =       NO-WS-CTL /     ; Non white space controls
-         *                         %d33 /          ; The rest of the US-ASCII
-         *                         %d35-91 /       ;  characters not including "\"
-         *                         %d93-126        ;  or the quote character
-         * qcontent        =       qtext / quoted-pair
-         * quoted-string   =       [CFWS]
-         *                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
-         *                         [CFWS]
-         * word            =       atom / quoted-string
-         */
-        $qtext      = "($no_ws_ctl|[\\x21\\x23-\\x5b\\x5d-\\x7e])";
-        $qcontent   = "($qtext|$quoted_pair)";
-        $quoted_string  = "($cfws?\\x22($fws?$qcontent)*$fws?\\x22$cfws?)";
-        $word       = "($atom|$quoted_string)";
-
-        /**
-         * obs-local-part  =       word *("." word)
-         * obs-domain      =       atom *("." atom)
-         */
-        $obs_local_part = "($word(\\x2e$word)*)";
-        $obs_domain = "($atom(\\x2e$atom)*)";
-
-        /**
-         * dot-atom-text   =       1*atext *("." 1*atext)
-         * dot-atom        =       [CFWS] dot-atom-text [CFWS]
-         */
-        $dot_atom_text  = "($atext+(\\x2e$atext+)*)";
-        $dot_atom   = "($cfws?$dot_atom_text$cfws?)";
-
-        /**
-         * domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
-         * dcontent        =       dtext / quoted-pair
-         * dtext           =       NO-WS-CTL /     ; Non white space controls
-         *
-         *                         %d33-90 /       ; The rest of the US-ASCII
-         *                         %d94-126        ;  characters not including "[",
-         *                                         ;  "]", or "\"
-         */
-        $dtext      = "($no_ws_ctl|[\\x21-\\x5a\\x5e-\\x7e])";
-        $dcontent   = "($dtext|$quoted_pair)";
-        $domain_literal = "($cfws?\\x5b($fws?$dcontent)*$fws?\\x5d$cfws?)";
-
-        /**
-         * local-part      =       dot-atom / quoted-string / obs-local-part
-         * domain          =       dot-atom / domain-literal / obs-domain
-         * addr-spec       =       local-part "@" domain
-         */
-        $local_part = "($dot_atom|$quoted_string|$obs_local_part)";
-        $domain     = "($dot_atom|$domain_literal|$obs_domain)";
-        $addr_spec  = "($local_part\\x40$domain)";
-    }
-
-}
-
-class Horde_Form_Type_matrix extends Horde_Form_Type {
-
-    var $_cols;
-    var $_rows;
-    var $_matrix;
-    var $_new_input;
-
-    /**
-     * Initializes the variable.
-     *
-     * @example
-     * init(array('Column A', 'Column B'),
-     *      array(1 => 'Row One', 2 => 'Row 2', 3 => 'Row 3'),
-     *      array(array(true, true, false),
-     *            array(true, false, true),
-     *            array(fasle, true, false)),
-     *      array('Row 4', 'Row 5'));
-     *
-     * @param array $cols               A list of column headers.
-     * @param array $rows               A hash with row IDs as the keys and row
-     *                                  labels as the values.
-     * @param array $matrix             A two dimensional hash with the field
-     *                                  values.
-     * @param boolean|array $new_input  If true, a free text field to add a new
-     *                                  row is displayed on the top, a select
-     *                                  box if this parameter is a value.
-     */
-    function init($cols, $rows = array(), $matrix = array(), $new_input = false)
-    {
-        $this->_cols       = $cols;
-        $this->_rows       = $rows;
-        $this->_matrix     = $matrix;
-        $this->_new_input  = $new_input;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        $values = $vars->get($var->getVarName());
-        if (!empty($values['n']['r']) && isset($values['n']['v'])) {
-            $new_row = $values['n']['r'];
-            $values['r'][$new_row] = $values['n']['v'];
-            unset($values['n']);
-        }
-
-        $info = (isset($values['r']) ? $values['r'] : array());
-    }
-
-    function about()
-    {
-        return array(
-            'name' => _("Field matrix"),
-            'params' => array(
-                'cols' => array('label' => _("Column titles"),
-                                'type'  => 'stringlist')));
-    }
-
-}
-
-class Horde_Form_Type_emailConfirm extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && empty($value['original'])) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if ($value['original'] != $value['confirm']) {
-            $message = _("Email addresses must match.");
-            return false;
-        } else {
-            $parser = new Mail_RFC822();
-            $parsed_email = $parser->parseAddressList($value['original'], false, true);
-
-            if (count($parsed_email) > 1) {
-                $message = _("Only one email address allowed.");
-                return false;
-            }
-            if (empty($parsed_email[0]->mailbox)) {
-                $message = _("You did not enter a valid email address.");
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Email with confirmation"));
-    }
-
-}
-
-class Horde_Form_Type_password extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if ($var->isRequired()) {
-            $valid = strlen(trim($value)) > 0;
-
-            if (!$valid) {
-                $message = _("This field is required.");
-            }
-        }
-
-        return $valid;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Password"));
-    }
-
-}
-
-class Horde_Form_Type_passwordconfirm extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && empty($value['original'])) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if ($value['original'] != $value['confirm']) {
-            $message = _("Passwords must match.");
-            return false;
-        }
-
-        return true;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        $value = $vars->get($var->getVarName());
-        $info = $value['original'];
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Password with confirmation"));
-    }
-
-}
-
-class Horde_Form_Type_enum extends Horde_Form_Type {
-
-    var $_values;
-    var $_prompt;
-
-    function init($values, $prompt = null)
-    {
-        $this->_values = $values;
-
-        if ($prompt === true) {
-            $this->_prompt = _("-- select --");
-        } else {
-            $this->_prompt = $prompt;
-        }
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && $value == '' && !isset($this->_values[$value])) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (count($this->_values) == 0 || isset($this->_values[$value]) ||
-            ($this->_prompt && empty($value))) {
-            return true;
-        }
-
-        $message = _("Invalid data.");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Drop down list"),
-            'params' => array(
-                'values' => array('label' => _("Values to select from"),
-                                  'type'  => 'stringlist'),
-                'prompt' => array('label' => _("Prompt text"),
-                                  'type'  => 'text')));
-    }
-
-}
-
-class Horde_Form_Type_mlenum extends Horde_Form_Type {
-
-    var $_values;
-    var $_prompts;
-
-    function init(&$values, $prompts = null)
-    {
-        $this->_values = &$values;
-
-        if ($prompts === true) {
-            $this->_prompts = array(_("-- select --"), _("-- select --"));
-        } elseif (!is_array($prompts)) {
-            $this->_prompts = array($prompts, $prompts);
-        } else {
-            $this->_prompts = $prompts;
-        }
-    }
-
-    function onSubmit($var, $vars)
-    {
-        $varname = $var->getVarName();
-        $value = $vars->get($varname);
-
-        if ($value['1'] != $value['old']) {
-            $var->form->setSubmitted(false);
-        }
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && (empty($value['1']) || empty($value['2']))) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (!count($this->_values) || isset($this->_values[$value['1']]) ||
-            (!empty($this->_prompts) && empty($value['1']))) {
-            return true;
-        }
-
-        $message = _("Invalid data.");
-        return false;
-    }
-
-    function getInfo($vars, &$var, &$info)
-    {
-        $info = $vars->get($var->getVarName());
-        return $info['2'];
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Multi-level drop down lists"),
-            'params' => array(
-                'values' => array('label' => _("Values to select from"),
-                                  'type'  => 'stringlist'),
-                'prompt' => array('label' => _("Prompt text"),
-                                  'type'  => 'text')));
-    }
-
-}
-
-class Horde_Form_Type_multienum extends Horde_Form_Type_enum {
-
-    var $size = 5;
-
-    function init($values, $size = null)
-    {
-        if (!is_null($size)) {
-            $this->size = (int)$size;
-        }
-
-        parent::init($values);
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if (is_array($value)) {
-            foreach ($value as $val) {
-                if (!$this->isValid($var, $vars, $val, $message)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        if (empty($value) && ((string)(int)$value !== $value)) {
-            if ($var->isRequired()) {
-                $message = _("This field is required.");
-                return false;
-            } else {
-                return true;
-            }
-        }
-
-        if (count($this->_values) == 0 || isset($this->_values[$value])) {
-            return true;
-        }
-
-        $message = _("Invalid data.");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Multiple selection"),
-            'params' => array(
-                'values' => array('label' => _("Values"),
-                                  'type'  => 'stringlist'),
-                'size'   => array('label' => _("Size"),
-                                  'type'  => 'int'))
-        );
-    }
-
-}
-
-class Horde_Form_Type_keyval_multienum extends Horde_Form_Type_multienum {
-
-    function getInfo($vars, $var, &$info)
-    {
-        $value = $vars->get($var->getVarName());
-        $info = array();
-        foreach ($value as $key) {
-            $info[$key] = $this->_values[$key];
-        }
-    }
-
-}
-
-class Horde_Form_Type_radio extends Horde_Form_Type_enum {
-
-    /* Entirely implemented by Horde_Form_Type_enum; just a different
-     * view. */
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Radio selection"),
-            'params' => array(
-                'values' => array('label' => _("Values"),
-                                  'type'  => 'stringlist')));
-    }
-
-}
-
-class Horde_Form_Type_set extends Horde_Form_Type {
-
-    var $_values;
-    var $_checkAll = false;
-
-    function init(&$values, $checkAll = false)
-    {
-        $this->_values = $values;
-        $this->_checkAll = $checkAll;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if (count($this->_values) == 0 || count($value) == 0) {
-            return true;
-        }
-        foreach ($value as $item) {
-            if (!isset($this->_values[$item])) {
-                $error = true;
-                break;
-            }
-        }
-        if (!isset($error)) {
-            return true;
-        }
-
-        $message = _("Invalid data.");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Set"),
-            'params' => array(
-                'values' => array('label' => _("Values"),
-                                  'type'  => 'stringlist')));
-    }
-
-}
-
-class Horde_Form_Type_date extends Horde_Form_Type {
-
-    var $_format;
-
-    function init($format = '%a %d %B')
-    {
-        $this->_format = $format;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if ($var->isRequired()) {
-            $valid = strlen(trim($value)) > 0;
-
-            if (!$valid) {
-                $message = sprintf(_("%s is required"), $var->getHumanName());
-            }
-        }
-
-        return $valid;
-    }
-
-    /**
-     * @static
-     */
-    function getAgo($timestamp)
-    {
-        if ($timestamp === null) {
-            return '';
-        }
-
-        $diffdays = Date_Calc::dateDiff(date('j', $timestamp),
-                                        date('n', $timestamp),
-                                        date('Y', $timestamp),
-                                        date('j'), date('n'), date('Y'));
-
-        /* An error occured. */
-        if ($diffdays == -1) {
-            return;
-        }
-
-        $ago = $diffdays * Date_Calc::compareDates(date('j', $timestamp),
-                                                   date('n', $timestamp),
-                                                   date('Y', $timestamp),
-                                                   date('j'), date('n'),
-                                                   date('Y'));
-        if ($ago < -1) {
-            return sprintf(_(" (%s days ago)"), $diffdays);
-        } elseif ($ago == -1) {
-            return _(" (yesterday)");
-        } elseif ($ago == 0) {
-            return _(" (today)");
-        } elseif ($ago == 1) {
-            return _(" (tomorrow)");
-        } else {
-            return sprintf(_(" (in %s days)"), $diffdays);
-        }
-    }
-
-    function getFormattedTime($timestamp, $format = null, $showago = true)
-    {
-        if (empty($format)) {
-            $format = $this->_format;
-        }
-        if (!empty($timestamp)) {
-            return strftime($format, $timestamp) . ($showago ? Horde_Form_Type_date::getAgo($timestamp) : '');
-        } else {
-            return '';
-        }
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Date"));
-    }
-
-}
-
-class Horde_Form_Type_time extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && empty($value) && ((string)(double)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^[0-2]?[0-9]:[0-5][0-9]$/', $value)) {
-            return true;
-        }
-
-        $message = _("This field may only contain numbers and the colon.");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Time"));
-    }
-
-}
-
-class Horde_Form_Type_hourminutesecond extends Horde_Form_Type {
-
-    var $_show_seconds;
-
-    function init($show_seconds = false)
-    {
-        $this->_show_seconds = $show_seconds;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $time = $vars->get($var->getVarName());
-        if (!$this->_show_seconds && !isset($time['second'])) {
-            $time['second'] = 0;
-        }
-
-        if (!$this->emptyTimeArray($time) && !$this->checktime($time['hour'], $time['minute'], $time['second'])) {
-            $message = _("Please enter a valid time.");
-            return false;
-        } elseif ($this->emptyTimeArray($time) && $var->isRequired()) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        return true;
-    }
-
-    function checktime($hour, $minute, $second)
-    {
-        if (!isset($hour) || $hour == '' || ($hour < 0 || $hour > 23)) {
-            return false;
-        }
-        if (!isset($minute) || $minute == '' || ($minute < 0 || $minute > 60)) {
-            return false;
-        }
-        if (!isset($second) || $second === '' || ($second < 0 || $second > 60)) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Return the time supplied as a Horde_Date object.
-     *
-     * @param string $time_in  Date in one of the three formats supported by
-     *                         Horde_Form and Horde_Date (ISO format
-     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS and
-     *                         UNIX epoch).
-     *
-     * @return Date  The time object.
-     */
-    function getTimeOb($time_in)
-    {
-        if (is_array($time_in)) {
-            if (!$this->emptyTimeArray($time_in)) {
-                $time_in = sprintf('1970-01-01 %02d:%02d:%02d', $time_in['hour'], $time_in['minute'], $this->_show_seconds ? $time_in['second'] : 0);
-            }
-        }
-
-        return new Horde_Date($time_in);
-    }
-
-    /**
-     * Return the time supplied split up into an array.
-     *
-     * @param string $time_in  Time in one of the three formats supported by
-     *                         Horde_Form and Horde_Date (ISO format
-     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS and
-     *                         UNIX epoch).
-     *
-     * @return array  Array with three elements - hour, minute and seconds.
-     */
-    function getTimeParts($time_in)
-    {
-        if (is_array($time_in)) {
-            /* This is probably a failed isValid input so just return the
-             * parts as they are. */
-            return $time_in;
-        } elseif (empty($time_in)) {
-            /* This is just an empty field so return empty parts. */
-            return array('hour' => '', 'minute' => '', 'second' => '');
-        }
-        $time = $this->getTimeOb($time_in);
-        return array('hour' => $time->hour,
-                     'minute' => $time->min,
-                     'second' => $time->sec);
-    }
-
-    function emptyTimeArray($time)
-    {
-        return (is_array($time) && empty($time['hour']) && empty($time['minute']) && empty($time['second']));
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Time selection"),
-            'params' => array(
-                'seconds' => array('label' => _("Show seconds?"),
-                                  'type'  => 'boolean')));
-    }
-
-}
-
-class Horde_Form_Type_monthyear extends Horde_Form_Type {
-
-    var $_start_year;
-    var $_end_year;
-
-    function init($start_year = null, $end_year = null)
-    {
-        if (empty($start_year)) {
-            $start_year = 1920;
-        }
-        if (empty($end_year)) {
-            $end_year = date('Y');
-        }
-
-        $this->_start_year = $start_year;
-        $this->_end_year = $end_year;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if (!$var->isRequired()) {
-            return true;
-        }
-
-        if (!$vars->get($this->getMonthVar($var)) ||
-            !$vars->get($this->getYearVar($var))) {
-            $message = _("Please enter a month and a year.");
-            return false;
-        }
-
-        return true;
-    }
-
-    function getMonthVar($var)
-    {
-        return $var->getVarName() . '[month]';
-    }
-
-    function getYearVar($var)
-    {
-        return $var->getVarName() . '[year]';
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Month and year"),
-                     'params' => array(
-                         'start_year' => array('label' => _("Start year"),
-                                               'type'  => 'int'),
-                         'end_year'   => array('label' => _("End year"),
-                                               'type'  => 'int')));
-    }
-
-}
-
-class Horde_Form_Type_monthdayyear extends Horde_Form_Type {
-
-    var $_start_year;
-    var $_end_year;
-    var $_picker;
-    var $_format_in = null;
-    var $_format_out = '%x';
-
-    /**
-     * Return the date supplied as a Horde_Date object.
-     *
-     * @param integer $start_year  The first available year for input.
-     * @param integer $end_year    The last available year for input.
-     * @param boolean $picker      Do we show the DHTML calendar?
-     * @param integer $format_in   The format to use when sending the date
-     *                             for storage. Defaults to Unix epoch.
-     *                             Similar to the strftime() function.
-     * @param integer $format_out  The format to use when displaying the
-     *                             date. Similar to the strftime() function.
-     */
-    function init($start_year = '', $end_year = '', $picker = true,
-                  $format_in = null, $format_out = '%x')
-    {
-        if (empty($start_year)) {
-            $start_year = date('Y');
-        }
-        if (empty($end_year)) {
-            $end_year = date('Y') + 10;
-        }
-
-        $this->_start_year = $start_year;
-        $this->_end_year = $end_year;
-        $this->_picker = $picker;
-        $this->_format_in = $format_in;
-        $this->_format_out = $format_out;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        $date = $vars->get($var->getVarName());
-        $empty = $this->emptyDateArray($date);
-
-        if ($empty == 1 && $var->isRequired()) {
-            $message = _("This field is required.");
-            return false;
-        } elseif ($empty == 0 && !checkdate($date['month'], $date['day'], $date['year'])) {
-            $message = _("Please enter a valid date, check the number of days in the month.");
-            return false;
-        } elseif ($empty == -1) {
-            $message = _("Select all date components.");
-            return false;
-        }
-
-        return true;
-    }
-
-    function emptyDateArray($date)
-    {
-        if (!is_array($date)) {
-            return empty($date);
-        }
-
-        $empty = 0;
-        /* Check each date array component. */
-        foreach ($date as $key => $val) {
-            if (empty($val)) {
-                $empty++;
-            }
-        }
-
-        /* Check state of empty. */
-        if ($empty == 0) {
-            /* If no empty parts return 0. */
-            return 0;
-        } elseif ($empty == count($date)) {
-            /* If all empty parts return 1. */
-            return 1;
-        } else {
-            /* If some empty parts return -1. */
-            return -1;
-        }
-    }
-
-    /**
-     * Return the date supplied split up into an array.
-     *
-     * @param string $date_in  Date in one of the three formats supported by
-     *                         Horde_Form and Horde_Date (ISO format
-     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS
-     *                         and UNIX epoch) plus the fourth YYYY-MM-DD.
-     *
-     * @return array  Array with three elements - year, month and day.
-     */
-    function getDateParts($date_in)
-    {
-        if (is_array($date_in)) {
-            /* This is probably a failed isValid input so just return
-             * the parts as they are. */
-            return $date_in;
-        } elseif (empty($date_in)) {
-            /* This is just an empty field so return empty parts. */
-            return array('year' => '', 'month' => '', 'day' => '');
-        }
-
-        $date = $this->getDateOb($date_in);
-        return array('year' => $date->year,
-                     'month' => $date->month,
-                     'day' => $date->mday);
-    }
-
-    /**
-     * Return the date supplied as a Horde_Date object.
-     *
-     * @param string $date_in  Date in one of the three formats supported by
-     *                         Horde_Form and Horde_Date (ISO format
-     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS
-     *                         and UNIX epoch) plus the fourth YYYY-MM-DD.
-     *
-     * @return Date  The date object.
-     */
-    function getDateOb($date_in)
-    {
-        if (is_array($date_in)) {
-            /* If passed an array change it to the ISO format. */
-            if ($this->emptyDateArray($date_in) == 0) {
-                $date_in = sprintf('%04d-%02d-%02d 00:00:00',
-                                   $date_in['year'],
-                                   $date_in['month'],
-                                   $date_in['day']);
-            }
-        } elseif (preg_match('/^\d{4}-?\d{2}-?\d{2}$/', $date_in)) {
-            /* Fix the date if it is the shortened ISO. */
-            $date_in = $date_in . ' 00:00:00';
-        }
-
-        return new Horde_Date($date_in);
-    }
-
-    /**
-     * Return the date supplied as a Horde_Date object.
-     *
-     * @param string $date  Either an already set up Horde_Date object or a
-     *                      string date in one of the three formats supported
-     *                      by Horde_Form and Horde_Date (ISO format
-     *                      YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS and
-     *                      UNIX epoch) plus the fourth YYYY-MM-DD.
-     *
-     * @return string  The date formatted according to the $format_out
-     *                 parameter when setting up the monthdayyear field.
-     */
-    function formatDate($date)
-    {
-        if (!is_a($date, 'Date')) {
-            $date = $this->getDateOb($date);
-        }
-
-        return $date->strftime($this->_format_out);
-    }
-
-    /**
-     * Insert the date input through the form into $info array, in the format
-     * specified by the $format_in parameter when setting up monthdayyear
-     * field.
-     */
-    function getInfo($vars, &$var, &$info)
-    {
-        $info = $this->_validateAndFormat($var->getValue($vars), $var);
-    }
-
-    /**
-     * Validate/format a date submission.
-     */
-    function _validateAndFormat($value, $var)
-    {
-        /* If any component is empty consider it a bad date and return the
-         * default. */
-        if ($this->emptyDateArray($value) == 1) {
-            return $var->getDefault();
-        } else {
-            $date = $this->getDateOb($value);
-            if ($this->_format_in === null) {
-                return $date->timestamp();
-            } else {
-                return $date->strftime($this->_format_in);
-            }
-        }
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Date selection"),
-            'params' => array(
-                'start_year' => array('label' => _("Start year"),
-                                      'type'  => 'int'),
-                'end_year'   => array('label' => _("End year"),
-                                      'type'  => 'int'),
-                'picker'     => array('label' => _("Show picker?"),
-                                      'type'  => 'boolean'),
-                'format_in'  => array('label' => _("Storage format"),
-                                      'type'  => 'text'),
-                'format_out' => array('label' => _("Display format"),
-                                      'type'  => 'text')));
-    }
-
-}
-
-/**
- * @since Horde 3.2
- */
-class Horde_Form_Type_datetime extends Horde_Form_Type {
-
-    var $_mdy;
-    var $_hms;
-
-    /**
-     * Return the date supplied as a Horde_Date object.
-     *
-     * @param integer $start_year  The first available year for input.
-     * @param integer $end_year    The last available year for input.
-     * @param boolean $picker      Do we show the DHTML calendar?
-     * @param integer $format_in   The format to use when sending the date
-     *                             for storage. Defaults to Unix epoch.
-     *                             Similar to the strftime() function.
-     * @param integer $format_out  The format to use when displaying the
-     *                             date. Similar to the strftime() function.
-     * @param boolean $show_seconds Include a form input for seconds.
-     */
-    function init($start_year = '', $end_year = '', $picker = true,
-                  $format_in = null, $format_out = '%x', $show_seconds = false)
-    {
-        $this->_mdy = new Horde_Form_Type_monthdayyear();
-        $this->_mdy->init($start_year, $end_year, $picker, $format_in, $format_out);
-
-        $this->_hms = new Horde_Form_Type_hourminutesecond();
-        $this->_hms->init($show_seconds);
-    }
-
-    function isValid(&$var, &$vars, $value, &$message)
-    {
-        if ($var->isRequired()) {
-            return $this->_mdy->isValid($var, $vars, $value, $message) &&
-                $this->_hms->isValid($var, $vars, $value, $message);
-        }
-        return true;
-    }
-
-    function getInfo(&$vars, &$var, &$info)
-    {
-        /* If any component is empty consider it a bad date and return the
-         * default. */
-        $value = $var->getValue($vars);
-        if ($this->emptyDateArray($value) == 1 || $this->emptyTimeArray($value)) {
-            $info = $var->getDefault();
-            return;
-        }
-
-        $date = $this->getDateOb($value);
-        $time = $this->getTimeOb($value);
-        $date->hour = $time->hour;
-        $date->min = $time->min;
-        $date->sec = $time->sec;
-        if (is_null($this->format_in)) {
-            $info = $date->timestamp();
-        } else {
-            $info = $date->strftime($this->format_in);
-        }
-    }
-
-    function __get($property)
-    {
-        if ($property == 'show_seconds') {
-            return $this->_hms->$property;
-        } else {
-            return $this->_mdy->$property;
-        }
-    }
-
-    function __set($property, $value)
-    {
-        if ($property == 'show_seconds') {
-            $this->_hms->$property = $value;
-        } else {
-            $this->_mdy->$property = $value;
-        }
-    }
-
-    function checktime($hour, $minute, $second)
-    {
-        return $this->_hms->checktime($hour, $minute, $second);
-    }
-
-    function getTimeOb($time_in)
-    {
-        return $this->_hms->getTimeOb($time_in);
-    }
-
-    function getTimeParts($time_in)
-    {
-        return $this->_hms->getTimeParts($time_in);
-    }
-
-    function emptyTimeArray($time)
-    {
-        return $this->_hms->emptyTimeArray($time);
-    }
-
-    function emptyDateArray($date)
-    {
-        return $this->_mdy->emptyDateArray($date);
-    }
-
-    function getDateParts($date_in)
-    {
-        return $this->_mdy->getDateParts($date_in);
-    }
-
-    function getDateOb($date_in)
-    {
-        return $this->_mdy->getDateOb($date_in);
-    }
-
-    function formatDate($date)
-    {
-        if ($date === null) {
-            return '';
-        }
-        return $this->_mdy->formatDate($date);
-    }
-
-    function about()
-    {
-        return array(
-            'name' => _("Date and time selection"),
-            'params' => array(
-                'start_year' => array('label' => _("Start year"),
-                                      'type'  => 'int'),
-                'end_year'   => array('label' => _("End year"),
-                                      'type'  => 'int'),
-                'picker'     => array('label' => _("Show picker?"),
-                                      'type'  => 'boolean'),
-                'format_in'  => array('label' => _("Storage format"),
-                                      'type'  => 'text'),
-                'format_out' => array('label' => _("Display format"),
-                                      'type'  => 'text'),
-                'seconds'    => array('label' => _("Show seconds?"),
-                                      'type'  => 'boolean')));
-    }
-
-}
-
-class Horde_Form_Type_colorpicker extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->isRequired() && empty($value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^#([0-9a-z]){6}$/i', $value)) {
-            return true;
-        }
-
-        $message = _("This field must contain a color code in the RGB Hex format, for example '#1234af'.");
-        return false;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Colour selection"));
-    }
-
-}
-
-class Horde_Form_Type_sorter extends Horde_Form_Type {
-
-    var $_instance;
-    var $_values;
-    var $_size;
-    var $_header;
-
-    function init($values, $size = 8, $header = '')
-    {
-        static $horde_sorter_instance = 0;
-
-        /* Get the next progressive instance count for the horde
-         * sorter so that multiple sorters can be used on one page. */
-        $horde_sorter_instance++;
-        $this->_instance = 'horde_sorter_' . $horde_sorter_instance;
-        $this->_values = $values;
-        $this->_size   = $size;
-        $this->_header = $header;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    function getOptions($keys = null)
-    {
-        $html = '';
-        if ($this->_header) {
-            $html .= '<option value="">' . htmlspecialchars($this->_header) . '</option>';
-        }
-
-        if (empty($keys)) {
-            $keys = array_keys($this->_values);
-        } else {
-            $keys = explode("\t", $keys['array']);
-        }
-        foreach ($keys as $sl_key) {
-            $html .= '<option value="' . $sl_key . '">' . htmlspecialchars($this->_values[$sl_key]) . '</option>';
-        }
-
-        return $html;
-    }
-
-    function getInfo($vars, &$var, &$info)
-    {
-        $value = $vars->get($var->getVarName());
-        $info = explode("\t", $value['array']);
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Sort order selection"),
-            'params' => array(
-                'values' => array('label' => _("Values"),
-                                  'type'  => 'stringlist'),
-                'size'   => array('label' => _("Size"),
-                                  'type'  => 'int'),
-                'header' => array('label' => _("Header"),
-                                  'type'  => 'text')));
-    }
-
-}
-
-class Horde_Form_Type_selectfiles extends Horde_Form_Type {
-
-    /**
-     * The text to use in the link.
-     *
-     * @var string
-     */
-    var $_link_text;
-
-    /**
-     * The style to use for the link.
-     *
-     * @var string
-     */
-    var $_link_style;
-
-    /**
-     *  Create the link with an icon instead of text?
-     *
-     * @var boolean
-     */
-    var $_icon;
-
-    /**
-     * Contains gollem selectfile selectionID
-     *
-     * @var string
-     */
-    var $_selectid;
-
-    function init($selectid, $link_text = null, $link_style = '',
-                  $icon = false)
-    {
-        $this->_selectid = $selectid;
-        if (is_null($link_text)) {
-            $link_text = _("Select Files");
-        }
-        $this->_link_text = $link_text;
-        $this->_link_style = $link_style;
-        $this->_icon = $icon;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    function getInfo($var, &$vars, &$info)
-    {
-        $value = $vars->getValue($var);
-        $info = $GLOBALS['registry']->call('files/selectlistResults', array($value));
-    }
-
-    function about()
-    {
-        return array(
-            'name' => _("File selection"),
-            'params' => array(
-                'selectid'   => array('label' => _("Id"),
-                                      'type' => 'text'),
-                'link_text'  => array('label' => _("Link text"),
-                                      'type' => 'text'),
-                'link_style' => array('label' => _("Link style"),
-                                      'type' => 'text'),
-                'icon'       => array('label' => _("Show icon?"),
-                                      'type' => 'boolean')));
-    }
-
-}
-
-class Horde_Form_Type_assign extends Horde_Form_Type {
-
-    var $_leftValues;
-    var $_rightValues;
-    var $_leftHeader;
-    var $_rightHeader;
-    var $_size;
-    var $_width;
-
-    function init($leftValues, $rightValues, $leftHeader = '',
-                  $rightHeader = '', $size = 8, $width = '200px')
-    {
-        $this->_leftValues = $leftValues;
-        $this->_rightValues = $rightValues;
-        $this->_leftHeader = $leftHeader;
-        $this->_rightHeader = $rightHeader;
-        $this->_size = $size;
-        $this->_width = $width;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    function setValues($side, $values)
-    {
-        if ($side) {
-            $this->_rightValues = $values;
-        } else {
-            $this->_leftValues = $values;
-        }
-    }
-
-    function getHeader($side)
-    {
-        return $side ? $this->_rightHeader : $this->_leftHeader;
-    }
-
-    function getOptions($side, $formname, $varname)
-    {
-        $html = '';
-        $headers = false;
-        if ($side) {
-            $values = $this->_rightValues;
-            if (!empty($this->_rightHeader)) {
-                $values = array('' => $this->_rightHeader) + $values;
-                $headers = true;
-            }
-        } else {
-            $values = $this->_leftValues;
-            if (!empty($this->_leftHeader)) {
-                $values = array('' => $this->_leftHeader) + $values;
-                $headers = true;
-            }
-        }
-
-        foreach ($values as $key => $val) {
-            $html .= '<option value="' . htmlspecialchars($key) . '"';
-            if ($headers) {
-                $headers = false;
-            } else {
-                $html .= ' ondblclick="Horde_Form_Assign.move(\'' . $formname . '\', \'' . $varname . '\', ' . (int)$side . ');"';
-            }
-            $html .= '>' . htmlspecialchars($val) . '</option>';
-        }
-
-        return $html;
-    }
-
-    function getInfo($vars, &$var, &$info)
-    {
-        $value = $vars->get($var->getVarName() . '__values');
-        if (strpos($value, "\t\t") === false) {
-            $left = $value;
-            $right = '';
-        } else {
-            list($left, $right) = explode("\t\t", $value);
-        }
-        if (empty($left)) {
-            $info['left'] = array();
-        } else {
-            $info['left'] = explode("\t", $left);
-        }
-        if (empty($right)) {
-            $info['right'] = array();
-        } else {
-            $info['right'] = explode("\t", $right);
-        }
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Assignment columns"),
-            'params' => array(
-                'leftValues'  => array('label' => _("Left values"),
-                                       'type'  => 'stringlist'),
-                'rightValues' => array('label' => _("Right values"),
-                                       'type'  => 'stringlist'),
-                'leftHeader'  => array('label' => _("Left header"),
-                                       'type'  => 'text'),
-                'rightHeader' => array('label' => _("Right header"),
-                                       'type'  => 'text'),
-                'size'        => array('label' => _("Size"),
-                                       'type'  => 'int'),
-                'width'       => array('label' => _("Width in CSS units"),
-                                       'type'  => 'text')));
-    }
-
-}
-
-class Horde_Form_Type_creditcard extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if (empty($value) && $var->isRequired()) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (!empty($value)) {
-            /* getCardType() will also verify the checksum. */
-            $type = $this->getCardType($value);
-            if ($type === false || $type == 'unknown') {
-                $message = _("This does not seem to be a valid card number.");
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    function getChecksum($ccnum)
-    {
-        $len = strlen($ccnum);
-        if (!is_long($len / 2)) {
-            $weight = 2;
-            $digit = $ccnum[0];
-        } elseif (is_long($len / 2)) {
-            $weight = 1;
-            $digit = $ccnum[0] * 2;
-        }
-        if ($digit > 9) {
-            $digit = $digit - 9;
-        }
-        $i = 1;
-        $checksum = $digit;
-        while ($i < $len) {
-            if ($ccnum[$i] != ' ') {
-                $digit = $ccnum[$i] * $weight;
-                $weight = ($weight == 1) ? 2 : 1;
-                if ($digit > 9) {
-                    $digit = $digit - 9;
-                }
-                $checksum += $digit;
-            }
-            $i++;
-        }
-
-        return $checksum;
-    }
-
-    function getCardType($ccnum)
-    {
-        $sum = $this->getChecksum($ccnum);
-        $l = strlen($ccnum);
-
-        // Screen checksum.
-        if (($sum % 10) != 0) {
-            return false;
-        }
-
-        // Check for Visa.
-        if ((($l == 16) || ($l == 13)) &&
-            ($ccnum[0] == 4)) {
-            return 'visa';
-        }
-
-        // Check for MasterCard.
-        if (($l == 16) &&
-            ($ccnum[0] == 5) &&
-            ($ccnum[1] >= 1) &&
-            ($ccnum[1] <= 5)) {
-            return 'mastercard';
-        }
-
-        // Check for Amex.
-        if (($l == 15) &&
-            ($ccnum[0] == 3) &&
-            (($ccnum[1] == 4) || ($ccnum[1] == 7))) {
-            return 'amex';
-        }
-
-        // Check for Discover (Novus).
-        if (strlen($ccnum) == 16 &&
-            substr($ccnum, 0, 4) == '6011') {
-            return 'discover';
-        }
-
-        // If we got this far, then no card matched.
-        return 'unknown';
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Credit card number"));
-    }
-
-}
-
-class Horde_Form_Type_obrowser extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array('name' => _("Relationship browser"));
-    }
-
-}
-
-class Horde_Form_Type_dblookup extends Horde_Form_Type_enum {
-
-    function init($dsn, $sql, $prompt = null)
-    {
-        $values = array();
-        $db = DB::connect($dsn);
-        if (!is_a($db, 'PEAR_Error')) {
-            // Set DB portability options.
-            switch ($db->phptype) {
-            case 'mssql':
-                $db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
-                break;
-            default:
-                $db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
-            }
-
-            $col = $db->getCol($sql);
-            if (!is_a($col, 'PEAR_Error')) {
-                $values = Horde_Array::combine($col, $col);
-            }
-        }
-        parent::init($values, $prompt);
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Database lookup"),
-            'params' => array(
-                'dsn' => array('label' => _("DSN (see http://pear.php.net/manual/en/package.database.db.intro-dsn.php)"),
-                               'type'  => 'text'),
-                'sql' => array('label' => _("SQL statement for value lookups"),
-                               'type'  => 'text'),
-                'prompt' => array('label' => _("Prompt text"),
-                                  'type'  => 'text'))
-            );
-    }
-
-}
-
-class Horde_Form_Type_figlet extends Horde_Form_Type {
-
-    var $_text;
-    var $_font;
-
-    function init($text, $font)
-    {
-        $this->_text = $text;
-        $this->_font = $font;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if (empty($value) && $var->isRequired()) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (String::lower($value) != String::lower($this->_text)) {
-            $message = _("The text you entered did not match the text on the screen.");
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Return info about field type.
-     */
-    function about()
-    {
-        return array(
-            'name' => _("Figlet CAPTCHA"),
-            'params' => array(
-                'text' => array('label' => _("Text"),
-                                'type'  => 'text'),
-                'font' => array('label' => _("Figlet font"),
-                                'type'  => 'text'))
-            );
-    }
-
-}
-
-class Horde_Form_Type_invalid extends Horde_Form_Type {
-
-    var $message;
-
-    function init($message)
-    {
-        $this->message = $message;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return false;
-    }
-
-}
-
-/**
- * This class represents a single form variable that may be rendered as one or
- * more form fields.
- *
- * @author  Robert E. Coyle <robertecoyle@hotmail.com>
- * @package Horde_Form
- */
-class Horde_Form_Variable {
-
-    /**
-     * The form instance this variable is assigned to.
-     *
-     * @var Horde_Form
-     */
-    var $form;
-
-    /**
-     * A short description of this variable's purpose.
-     *
-     * @var string
-     */
-    var $humanName;
-
-    /**
-     * The internally used name.
-     *
-     * @var string
-     */
-    var $varName;
-
-    /**
-     * A {@link Horde_Form_Type} instance.
-     *
-     * @var Horde_Form_Type
-     */
-    var $type;
-
-    /**
-     * Whether this is a required variable.
-     *
-     * @var boolean
-     */
-    var $required;
-
-    /**
-     * Whether this is a readonly variable.
-     *
-     * @var boolean
-     */
-    var $readonly;
-
-    /**
-     * A long description of the variable's purpose, special instructions, etc.
-     *
-     * @var string
-     */
-    var $description;
-
-    /**
-     * The variable help text.
-     *
-     * @var string
-     */
-    var $help;
-
-    /**
-     * Whether this is an array variable.
-     *
-     * @var boolean
-     */
-    var $_arrayVal;
-
-    /**
-     * The default value.
-     *
-     * @var mixed
-     */
-    var $_defValue = null;
-
-    /**
-     * A {@link Horde_Form_Action} instance.
-     *
-     * @var Horde_Form_Action
-     */
-    var $_action;
-
-    /**
-     * Whether this variable is disabled.
-     *
-     * @var boolean
-     */
-    var $_disabled = false;
-
-    /**
-     * TODO
-     *
-     * @var boolean
-     */
-    var $_autofilled = false;
-
-    /**
-     * Whether this is a hidden variable.
-     *
-     * @var boolean
-     */
-    var $_hidden = false;
-
-    /**
-     * TODO
-     *
-     * @var array
-     */
-    var $_options = array();
-
-    /**
-     * Variable constructor.
-     *
-     * @param string $humanName      A short description of the variable's
-     *                               purpose.
-     * @param string $varName        The internally used name.
-     * @param Horde_Form_Type $type  A {@link Horde_Form_Type} instance.
-     * @param boolean $required      Whether this is a required variable.
-     * @param boolean $readonly      Whether this is a readonly variable.
-     * @param string $description    A long description of the variable's
-     *                               purpose, special instructions, etc.
-     */
-    function Horde_Form_Variable($humanName, $varName, $type, $required,
-                                 $readonly = false, $description = null)
-    {
-        $this->humanName   = $humanName;
-        $this->varName     = $varName;
-        $this->type        = $type;
-        $this->required    = $required;
-        $this->readonly    = $readonly;
-        $this->description = $description;
-        $this->_arrayVal   = (strpos($varName, '[]') !== false);
-    }
-
-    /**
-     * Assign this variable to the specified form.
-     *
-     * @param Horde_Form $form  The form instance to assign this variable to.
-     */
-    function setFormOb($form)
-    {
-        $this->form = $form;
-    }
-
-    /**
-     * Sets a default value for this variable.
-     *
-     * @param mixed $value  A variable value.
-     */
-    function setDefault($value)
-    {
-        $this->_defValue = $value;
-    }
-
-    /**
-     * Returns this variable's default value.
-     *
-     * @return mixed  This variable's default value.
-     */
-    function getDefault()
-    {
-        return $this->_defValue;
-    }
-
-    /**
-     * Assigns an action to this variable.
-     *
-     * Example:
-     * <code>
-     * $v = $form->addVariable('My Variable', 'var1', 'text', false);
-     * $action = new Horde_Form_Action_submit;
-     * $v->setAction($action);
-     * </code>
-     *
-     * @param Horde_Form_Action $action  A {@link Horde_Form_Action} instance.
-     */
-    function setAction($action)
-    {
-        $this->_action = $action;
-    }
-
-    /**
-     * Returns whether this variable has an attached action.
-     *
-     * @return boolean  True if this variable has an attached action.
-     */
-    function hasAction()
-    {
-        return !is_null($this->_action);
-    }
-
-    /**
-     * Makes this a hidden variable.
-     */
-    function hide()
-    {
-        $this->_hidden = true;
-    }
-
-    /**
-     * Returns whether this is a hidden variable.
-     *
-     * @return boolean  True if this a hidden variable.
-     */
-    function isHidden()
-    {
-        return $this->_hidden;
-    }
-
-    /**
-     * Disables this variable.
-     */
-    function disable()
-    {
-        $this->_disabled = true;
-    }
-
-    /**
-     * Returns whether this variable is disabled.
-     *
-     * @return boolean  True if this variable is disabled.
-     */
-    function isDisabled()
-    {
-        return $this->_disabled;
-    }
-
-    /**
-     * Return the short description of this variable.
-     *
-     * @return string  A short description
-     */
-    function getHumanName()
-    {
-        return $this->humanName;
-    }
-
-    /**
-     * Returns the internally used variable name.
-     *
-     * @return string  This variable's internal name.
-     */
-    function getVarName()
-    {
-        return $this->varName;
-    }
-
-    /**
-     * Returns this variable's type.
-     *
-     * @return Horde_Form_Type  This variable's {@link Horde_Form_Type}
-     *                          instance.
-     */
-    function getType()
-    {
-        return $this->type;
-    }
-
-    /**
-     * Returns whether this is a required variable.
-     *
-     * @return boolean  True if this is a required variable.
-     */
-    function isRequired()
-    {
-        return $this->required;
-    }
-
-    /**
-     * Returns whether this is a readonly variable.
-     *
-     * @return boolean  True if this a readonly variable.
-     */
-    function isReadonly()
-    {
-        return $this->readonly;
-    }
-
-    /**
-     * Returns the possible values of this variable.
-     *
-     * @return array  The possible values of this variable or null.
-     */
-    function getValues()
-    {
-        return $this->type->values;
-    }
-
-    /**
-     * Returns whether this variable has a long description.
-     *
-     * @return boolean  True if this variable has a long description.
-     */
-    function hasDescription()
-    {
-        return !empty($this->description);
-    }
-
-    /**
-     * Returns this variable's long description.
-     *
-     * @return string  This variable's long description.
-     */
-    function getDescription()
-    {
-        return $this->description;
-    }
-
-    /**
-     * Returns whether this is an array variable.
-     *
-     * @return boolean  True if this an array variable.
-     */
-    function isArrayVal()
-    {
-        return $this->_arrayVal;
-    }
-
-    /**
-     * Returns whether this variable is to upload a file.
-     *
-     * @return boolean  True if variable is to upload a file.
-     */
-    function isUpload()
-    {
-        return ($this->type instanceof Horde_Form_Type_file);
-    }
-
-    /**
-     * Assigns a help text to this variable.
-     *
-     * @param string $help  The variable help text.
-     */
-    function setHelp($help)
-    {
-        $this->form->_help = true;
-        $this->help = $help;
-    }
-
-    /**
-     * Returns whether this variable has some help text assigned.
-     *
-     * @return boolean  True if this variable has a help text.
-     */
-    function hasHelp()
-    {
-        return !empty($this->help);
-    }
-
-    /**
-     * Returns the help text of this variable.
-     *
-     * @return string  This variable's help text.
-     */
-    function getHelp()
-    {
-        return $this->help;
-    }
-
-    /**
-     * Sets a variable option.
-     *
-     * @param string $option  The option name.
-     * @param mixed $val      The option's value.
-     */
-    function setOption($option, $val)
-    {
-        $this->_options[$option] = $val;
-    }
-
-    /**
-     * Returns a variable option's value.
-     *
-     * @param string $option  The option name.
-     *
-     * @return mixed          The option's value.
-     */
-    function getOption($option)
-    {
-        return isset($this->_options[$option]) ? $this->_options[$option] : null;
-    }
-
-    /**
-     * Processes the submitted value of this variable according to the rules of
-     * the variable type.
-     *
-     * @param Variables $vars  The {@link Variables} instance of the submitted
-     *                         form.
-     * @param mixed $info      A variable passed by reference that will be
-     *                         assigned the processed value of the submitted
-     *                         variable value.
-     *
-     * @return mixed  Depending on the variable type.
-     */
-    function getInfo($vars, &$info)
-    {
-        return $this->type->getInfo($vars, $this, $info);
-    }
-
-    /**
-     * Returns whether this variable if it had the "trackchange" option set
-     * has actually been changed.
-     *
-     * @param Variables $vars  The {@link Variables} instance of the submitted
-     *                         form.
-     *
-     * @return boolean  Null if this variable doesn't have the "trackchange"
-     *                  option set or the form wasn't submitted yet. A boolean
-     *                  indicating whether the variable was changed otherwise.
-     */
-    function wasChanged($vars)
-    {
-        if (!$this->getOption('trackchange')) {
-            return null;
-        }
-        $old = $vars->get('__old_' . $this->getVarName());
-        if (is_null($old)) {
-            return null;
-        }
-        return $old != $vars->get($this->getVarName());
-    }
-
-    /**
-     * Validates this variable.
-     *
-     * @param Variables $vars  The {@link Variables} instance of the submitted
-     *                         form.
-     * @param string $message  A variable passed by reference that will be
-     *                         assigned a descriptive error message if
-     *                         validation failed.
-     *
-     * @return boolean  True if the variable validated.
-     */
-    function validate($vars, &$message)
-    {
-        if ($this->_arrayVal) {
-            $vals = $this->getValue($vars);
-            if (!is_array($vals)) {
-                if ($this->required) {
-                    $message = _("This field is required.");
-                    return false;
-                } else {
-                    return true;
-                }
-            }
-            foreach ($vals as $i => $value) {
-                if ($value === null && $this->required) {
-                    $message = _("This field is required.");
-                    return false;
-                } else {
-                    if (!$this->type->isValid($this, $vars, $value, $message)) {
-                        return false;
-                    }
-                }
-            }
-        } else {
-            $value = $this->getValue($vars);
-            return $this->type->isValid($this, $vars, $value, $message);
-        }
-
-        return true;
-    }
-
-    /**
-     * Returns the submitted or default value of this variable.
-     * If an action is attached to this variable, the value will get passed to
-     * the action object.
-     *
-     * @param Variables $vars  The {@link Variables} instance of the submitted
-     *                         form.
-     * @param integer $index   If the variable is an array variable, this
-     *                         specifies the array element to return.
-     *
-     * @return mixed  The variable or element value.
-     */
-    function getValue($vars, $index = null)
-    {
-        if ($this->_arrayVal) {
-            $name = str_replace('[]', '', $this->varName);
-        } else {
-            $name = $this->varName;
-        }
-        $value = $vars->getExists($name, $wasset);
-
-        if (!$wasset) {
-            $value = $this->getDefault();
-        }
-
-        if ($this->_arrayVal && !is_null($index)) {
-            if (!$wasset && !is_array($value)) {
-                $return = $value;
-            } else {
-                $return = isset($value[$index]) ? $value[$index] : null;
-            }
-        } else {
-            $return = $value;
-        }
-
-        if ($this->hasAction()) {
-            $this->_action->setValues($vars, $return, $this->_arrayVal);
-        }
-
-        return $return;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Renderer.php b/framework/Form/lib/Horde/Form/Renderer.php
deleted file mode 100644 (file)
index 867f114..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-/**
- * @package Horde_Form
- */
-
-/**
- * The Horde_Form_Renderer class provides HTML and other renderings of
- * forms for the Horde_Form:: package.
- *
- * $Horde: incubator/Horde_Form/Horde/Form/Renderer.php,v 1.7 2007/09/16 19:51:08 chuck Exp $
- *
- * Copyright 2001-2007 Robert E. Coyle <robertecoyle@hotmail.com>
- * Copyright 2005-2007 Matt Warden <mwarden@gmail.com>
- *
- * See the enclosed file COPYING for license information (LGPL). If you
- * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
- *
- * @author  Robert E. Coyle <robertecoyle@hotmail.com>
- * @author  Matt Warden <mwarden@gmail.com>
- * @package Horde_Form
- */
-abstract class Horde_Form_Renderer {
-
-    var $_name;
-    var $_requiredLegend = false;
-    var $_helpMarker = '?';
-    var $_onLoadJS = array();
-    var $_showHeader = true;
-    var $_cols = 2;
-    var $_varRenderer = null;
-    var $_firstField = null;
-    var $_stripedRows = true;
-
-    protected $_submit = array();
-    protected $_reset = false;
-
-    /**
-     * Does the title of the form contain HTML? If so, you are responsible for
-     * doing any needed escaping/sanitization yourself. Otherwise the title
-     * will be run through htmlspecialchars() before being output.
-     *
-     * @var boolean
-     */
-    var $_encodeTitle = true;
-
-    /**
-     * Construct a new Horde_Form_Renderer::.
-     *
-     * @param array $params  This is a hash of renderer-specific parameters.
-     *                       Possible keys:<code>
-     *                       'encode_title': @see $_encodeTitle</code>
-     */
-    function __construct($params = array())
-    {
-        if (isset($params['encode_title'])) {
-            $this->encodeTitle($params['encode_title']);
-        }
-
-        $this->_varRenderer = new Horde_Form_VarRenderer_Xhtml;
-    }
-
-    abstract public function renderActive($form, $action, $method = 'get', $enctype = null, $focus = true);
-
-    public function setButtons($submit, $reset = false)
-    {
-        if ($submit === true || is_null($submit) || empty($submit)) {
-            /* Default to 'Submit'. */
-            $submit = array(_("Submit"));
-        } elseif (!is_array($submit)) {
-            /* Default to array if not passed. */
-            $submit = array($submit);
-        }
-        /* Only if $reset is strictly true insert default 'Reset'. */
-        if ($reset === true) {
-            $reset = _("Reset");
-        }
-
-        $this->_submit = $submit;
-        $this->_reset = $reset;
-
-        return $this;
-    }
-
-    public function addButtons($buttons)
-    {
-        if (!is_array($buttons)) {
-            $buttons = array($buttons);
-        }
-
-        $this->_submit = array_merge($this->_submit, $buttons);
-    }
-
-    public function showHeader($bool)
-    {
-        $this->_showHeader = $bool;
-    }
-
-    /**
-     * Sets or returns whether the form title should be encoded with
-     * htmlspecialchars().
-     *
-     * @param boolean $encode  If true, the form title gets encoded.  If false
-     *                         the title can contain HTML, but the class user
-     *                         is responsible to encode any special characters.
-     *
-     * @return boolean  Whether the form title should be encoded.
-     */
-    function encodeTitle($encode = null)
-    {
-        if (!is_null($encode)) {
-            $this->_encodeTitle = $encode;
-        }
-        return $this->_encodeTitle = $encode;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Renderer/Xhtml.php b/framework/Form/lib/Horde/Form/Renderer/Xhtml.php
deleted file mode 100644 (file)
index 3caac34..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-<?php
-/**
- */
-class Horde_Form_Renderer_Xhtml extends Horde_Form_Renderer {
-
-    protected $_enctype = 'multipart/form-data';
-
-    function _renderSectionTabs($form)
-    {
-        /* If javascript is not available, do not render tabs. */
-        if (!$GLOBALS['browser']->hasFeature('javascript')) {
-            return;
-        }
-
-        $open_section = $form->getOpenSection();
-
-        /* Add the javascript for the toggling the sections. */
-        Horde::addScriptFile('form_sections.js', 'horde', true);
-        echo '<script type="text/javascript">' . "\n" .
-            sprintf('var sections_%1$s = new Horde_Form_Sections(\'%1$s\', \'%2$s\');',
-                    $form->getName(),
-                    $open_section) .
-            '</script>';
-
-        /* Loop through the sections and print out a tab for each. */
-        echo "<div class=\"tabset\">\n";
-        $js = array();
-        foreach ($form->_sections as $section => $val) {
-            $class = ($section == $open_section) ? ' class="activeTab"' : '';
-            $tabid = htmlspecialchars($form->getName() . '_tab_' . $section);
-            $js[$linkid] = sprintf('sections_%s.toggle(\'%s\'); return false;"',
-                                   $form->getName(),
-                                   $section);
-            printf('<div%s id="%s"><a href="#" id="%s">%s%s</a></div>' . "\n",
-                   $class,
-                   $tabid,
-                   '_tablink_' . $section,
-                   $form->getSectionImage($section),
-                   $form->getSectionDesc($section));
-        }
-        echo "</div>\n";
-
-        // This doesn't help a whole lot now, but if there is a way to
-        // buffer output of JS, then we can keep JS separated from
-        // markup, whereas before the onclicks were assigned as an
-        // HTML attribute.
-        echo '<script type="text/javascript">' . "\n";
-        echo 'if (document.getElementById) {' . "\n";
-        echo '    addEvent(window, \'load\', function() {' . "\n";
-        foreach ($js as $id => $onclick) {
-            $line = '
-if (document.getElementById(%1$s)){
-    document.getElementById(%1$s).onclick = function() {
-        %2$s
-    };
-}';
-            printf($line, $id, $onclick);
-        }
-        echo '    });}</script>' . "\n";
-    }
-
-    function _renderSectionBegin($form, $section)
-    {
-        // Stripe alternate rows if that option is turned on.
-        if ($this->_stripedRows) {
-            Horde::addScriptFile('stripe.js', 'horde', true);
-            $class = 'striped';
-        } else {
-            $class = '';
-        }
-
-        $open_section = $form->getOpenSection();
-        if (empty($open_section)) {
-            $open_section = '__base';
-        }
-
-        // include a general class name for styling purposes. also helps select
-        // ULs, which only get a className currently if they are striped.
-        printf('<fieldset id="%s" class="%s form-section %s">',
-               htmlspecialchars($form->getName() . '_section_' . $section),
-               ($open_section == $section ? 'form-sectionshown' : 'form-sectionhidden'),
-               $class);
-    }
-
-    function _renderSectionEnd()
-    {
-        echo '</fieldset>';
-    }
-
-    function preserveVarByPost($vars, $varname, $alt_varname = '')
-    {
-        $value = $vars->getExists($varname, $wasset);
-
-        if ($alt_varname) {
-            $varname = $alt_varname;
-        }
-
-        if ($wasset) {
-            $this->_preserveVarByPost($varname, $value);
-        }
-    }
-
-    function _preserveVarByPost($varname, $value)
-    {
-        if (is_array($value)) {
-            foreach ($value as $id => $val) {
-                $this->_preserveVarByPost($varname . '[' . $id . ']', $val);
-            }
-        } else {
-            $varname = htmlspecialchars($varname);
-            $value = htmlspecialchars($value);
-            printf('<input type="hidden" id="%1$s" name="%1$s" value="%2$s" />'."\n",
-                   $varname,
-                   $value);
-        }
-    }
-
-    function listFormVars($form)
-    {
-        $variables = $form->getVariables(true, true);
-        $vars = array();
-        if ($variables) {
-            foreach ($variables as $var) {
-                if (is_object($var)) {
-                    if (!$var->isReadonly()) {
-                        $vars[$var->getVarName()] = 1;
-                    }
-                } else {
-                    $vars[$var] = 1;
-                }
-            }
-        }
-        require_once 'Horde/NLS.php';
-        echo '<input type="hidden" name="_formvars" value="'
-            . htmlspecialchars(serialize($vars), ENT_QUOTES, NLS::getCharset())
-            . '" />';
-    }
-
-    public function renderActive($form, $action, $method = 'get', $enctype = null, $focus = true)
-    {
-        $this->_name = $form->getName();
-
-        echo "<form class=\"horde-form\" action=\"$action\" method=\"$method\""
-            . (empty($this->_name) ? '' : ' id="' . $this->_name. '"')
-            . (is_null($this->_enctype) ? '' : ' enctype="' . $this->_enctype . '"')
-            . ">\n";
-        echo Util::formInput();
-
-        $this->listFormVars($form);
-
-        if (!empty($this->_name)) {
-            $this->_preserveVarByPost('formname', $this->_name);
-        }
-
-        if ($form->useToken()) {
-            $this->_preserveVarByPost($this->_name . '_formToken', Horde_Token::generateId($this->_name));
-        }
-
-        if (count($form->getSections())) {
-            $this->_preserveVarByPost('__formOpenSection', $form->getOpenSection());
-        }
-
-        $vars = $form->getVars();
-
-        $variables = $form->getVariables();
-        foreach ($variables as $var) {
-            if ($var->getOption('trackchange')) {
-                $varname = $var->getVarName();
-                $this->preserveVarByPost($vars, $varname, '__old_' . $varname);
-            }
-        }
-
-        foreach ($form->getHiddenVariables() as $var) {
-            $this->preserveVarByPost($vars, $var->getVarName());
-        }
-
-        $this->_renderBeginActive($form->getTitle());
-        $this->_renderForm($form, true);
-        $this->submit($this->_submit, $this->_reset);
-
-        echo "\n</fieldset>\n</form>\n";
-        if ($focus && !empty($this->_firstField)) {
-            echo '<script type="text/javascript">
-try {
-    document.getElementById("'. $this->_firstField .'").focus();
-} catch (e) {}
-</script>
-';
-        }
-    }
-
-    function renderInactive($form)
-    {
-        $this->_name = $form->getName();
-        $this->_renderBeginInactive($form->getTitle());
-        $this->_renderForm($form, false);
-    }
-
-    function _renderForm($form, $active)
-    {
-        $vars = $form->getVars();
-
-        /* If help is present 3 columns are needed. */
-        $this->_cols = $form->hasHelp() ? 3 : 2;
-
-        $variables = $form->getVariables(false);
-
-        /* Check for a form token error. */
-        if (($tokenError = $form->getError('_formToken')) !== null) {
-            printf('<p class="form-error">%s</p>'."\n", $tokenError);
-        }
-
-        $error_section = null;
-        reset($variables);
-        if (count($variables) > 1 || key($variables) != '__base') {
-            $this->_renderSectionTabs($form);
-        }
-
-        foreach ($variables as $section_id => $section) {
-            $this->_renderSectionBegin($form, $section_id);
-            foreach ($section as $var) {
-                switch (get_class($var->type)) {
-                case 'Horde_Form_Type_header':
-                    $this->_renderHeader($var->getHumanName(), $form->getError($var->getVarName()));
-                    break;
-
-                case 'Horde_Form_Type_description':
-                    $this->_renderDescription($var->getHumanName());
-                    break;
-
-                case 'Horde_Form_Type_spacer':
-                    $this->_renderSpacer();
-                    break;
-
-                default:
-                    $isInput = ($active && !$var->isReadonly());
-                    $format = $isInput ? 'Input' : 'Display';
-                    $begin = "_renderVar${format}Begin";
-                    $end = "_renderVar${format}End";
-
-                    $this->$begin($form, $var);
-                    echo $this->_varRenderer->render($form, $var, $vars, $isInput);
-                    $this->$end($form, $var);
-
-                    /* Print any javascript if actions present. */
-                    if ($var->hasAction()) {
-                        $var->_action->printJavaScript();
-                    }
-
-                    /* Keep first field. */
-                    if ($active && empty($this->_firstField) && !$var->isReadonly()
-                        && !$var->isHidden()) {
-                        $this->_firstField = $var->getVarName();
-                    }
-
-                    /* Keep section with first error. */
-                    if (is_null($error_section) && $form->getError($var)) {
-                        $error_section = $section_id;
-                    }
-                }
-            }
-
-            $this->_renderSectionEnd();
-        }
-
-        if (!is_null($error_section)) {
-            echo '<script type="text/javascript">' .
-                "\n" . sprintf('sections_%s.toggle(\'%s\');',
-                               $form->getName(),
-                               $error_section) .
-                "\n</script>\n";
-        }
-
-        echo '</fieldset>' . $this->_varRenderer->renderEnd();
-    }
-
-    function submit($submit = null, $reset = false)
-    {
-        if (is_null($submit) || empty($submit)) {
-            $submit = _("Submit");
-        }
-        if ($reset === true) {
-            $reset = _("Reset");
-        }
-        $this->_renderSubmit($submit, $reset);
-    }
-
-    /**
-     * Implementation specific begin function.
-     */
-    function _renderBeginActive($name)
-    {
-        echo '<fieldset class="horde-form" id="fieldset_' . htmlspecialchars($this->_name) . '">'."\n";
-        if ($this->_showHeader) {
-            $this->_renderSectionHeader($name);
-        }
-        if ($this->_requiredLegend) {
-            echo '<div class="form-error-example">' . $this->_requiredMarker
-                . ' &#61; ' . _("Required Field") . '</div>'."\n";
-        }
-    }
-
-    /**
-     * Implementation specific begin function.
-     */
-    function _renderBeginInactive($name)
-    {
-        echo '<fieldset class="horde-form" id="fieldset_' . htmlspecialchars($this->_name) . '">';
-        if ($this->_showHeader) {
-            $this->_renderSectionHeader($name);
-        }
-    }
-
-    function _renderHeader($header, $error = '')
-    {
-        echo '<div class="form-header">'. $header . '</div>';
-        if (!empty($error)) {
-            echo '<div class="form-error">'. $error . '</div>';
-        }
-    }
-
-    function _renderDescription($description)
-    {
-        echo '<div class="form-description">'. $description . '</div>';
-    }
-
-    function _renderSpacer()
-    {
-        // TODO: fix this later so we're not inserting nonsemantic elements just for spacing
-        // ... maybe append form-spacer to class of next or previous element
-        echo '<div class="form-spacer">&nbsp;</div>';
-    }
-
-    function _renderSubmit($submit, $reset)
-    {
-        echo '<fieldset class="form-buttons">'."\n";
-        if (!is_array($submit)) $submit = array($submit);
-        foreach ($submit as $submitbutton) {
-            echo '<input class="button" name="submitbutton" type="submit"';
-            // allow for default-value submit buttons (e.g. _renderSubmit(""))
-            if (!empty($submitbutton)) {
-                echo ' value="'. $submitbutton .'"';
-            }
-            echo ' />'."\n";
-        }
-        if (!empty($reset)) {
-            echo '<input class="button" name="resetbutton" type="reset"
-                value="'. $reset .'" />'."\n";
-        }
-    }
-
-    /**
-     * Renders the beginning of an writeable form entry, including the label
-     * and any form error related to this variable.
-     *
-     * @access private
-     * @author Matt Warden <mwarden@gmail.com>
-     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
-     */
-    function _renderVarInputBegin($form, $var, $readonly = false)
-    {
-        // get error message for variable, if any
-        $message = $form->getError($var);
-        // if no message, then no error
-        $isvalid = empty($message);
-
-        $classnames = 'form-input'
-            . (!$isvalid ? ' form-error' : '')
-            . ($var->isRequired() ? ' form-required' : '');
-
-        echo '<div class="', $classnames, '">';
-
-        if (!$isvalid) {
-            echo '<p class="form-error">', $message, '</p>', "\n";
-        }
-
-        printf('<label%s>%s</label>',
-            ($readonly ? '' : ' for="'. $var->getVarName() .'"'),
-            $var->getHumanName());
-    }
-
-    /**
-     * Renders the end of an writeable form entry, including any form notes
-     * and help info.
-     *
-     * @access private
-     * @author Matt Warden <mwarden@gmail.com>
-     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
-     */
-    function _renderVarInputEnd($form, $var)
-    {
-        /* Display any help for the field. */
-        if ($var->hasHelp()) {
-            global $registry;
-            if (isset($registry) && is_a($registry, 'Registry')) {
-                $help = Help::link($GLOBALS['registry']->getApp(), $var->getHelp());
-            } else {
-                $help = @htmlspecialchars($var->getHelp());
-            }
-            echo '<p class="form-hint">', $help, '</p>';
-        }
-
-        /* Display any description for the field. */
-        if ($var->hasDescription()) {
-            echo '<div class="form-note"><p>', $var->getDescription(), '</p></div>';
-        } else {
-            echo '<br class="clear" />';
-        }
-
-        echo '</div>';
-    }
-
-    /**
-     * Renders the beginning of a readonly form entry.
-     *
-     * @access private
-     * @author Matt Warden <mwarden@gmail.com>
-     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
-     */
-    function _renderVarDisplayBegin($form, $var)
-    {
-        return $this->_renderVarInputBegin($form, $var, true);
-    }
-
-    /**
-     * Renders the end of a readonly form entry. Help and notes are not
-     * applicable.
-     *
-     * @access private
-     * @author Matt Warden <mwarden@gmail.com>
-     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
-     */
-    function _renderVarDisplayEnd()
-    {
-        echo '</div>';
-    }
-
-    /**
-     * Renders the header for the section.
-     *
-     * @access private
-     * @author Matt Warden <mwarden@gmail.com>
-     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
-     * @param string $title section header title
-     */
-    function _renderSectionHeader($title)
-    {
-        if (!empty($title)) {
-            echo "\n".'<legend>';
-            echo $this->_encodeTitle ? htmlspecialchars($title) : $title;
-            echo '</legend>'."\n";
-        }
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type.php b/framework/Form/lib/Horde/Form/Type.php
deleted file mode 100644 (file)
index 707bb71..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-/**
- * Horde_Form_Type Class
- *
- * @author  Robert E. Coyle <robertecoyle@hotmail.com>
- * @package Horde_Form
- */
-abstract class Horde_Form_Type {
-
-    protected $_properties = array();
-
-    /**
-     * Type constructor. Takes a hash of key/value parameters.
-     *
-     * @param array $properties Any type properties to initialize.
-     */
-    public function __construct($properties = array())
-    {
-        $this->_properties = array();
-        $vars = array_keys(get_object_vars($this));
-        foreach ($vars as $var) {
-            $this->_properties[] = substr($var, 1);
-        }
-
-        if ($this->_properties && $properties) {
-            $properties = array_combine(array_slice($this->_properties, 0, count($properties)), $properties);
-            foreach ($properties as $property => $value) {
-                $this->__set($property, $value);
-            }
-        }
-    }
-
-    /**
-     */
-    abstract public function isValid($var, $vars, $value, &$message);
-
-    /**
-     */
-    function getInfo($vars, $var, &$info)
-    {
-        $info = $var->getValue($vars);
-    }
-
-    /**
-     */
-    public function onSubmit()
-    {
-    }
-
-    /**
-     * To get the 'escape' property of a type:
-     *   $escape = $type->escape;
-     * If the property is not set this will return null.
-     *
-     * @param string $property The property to retrieve.
-     */
-    protected function __get($property)
-    {
-        if (in_array($property, $this->_properties)) {
-            $prop = '_' . $property;
-            return $this->$prop;
-        }
-
-        return null;
-    }
-
-    /**
-     * To set the 'escape' property of a type to true:
-     *   $type->escape = true;
-     *
-     * @param string $property The property name to set.
-     * @param mixed $value The property value.
-     */
-    protected function __set($property, $value)
-    {
-        if (in_array($property, $this->_properties)) {
-            $prop = '_' . $property;
-            $this->$prop = $value;
-        }
-    }
-
-    /**
-     * To check if a type has a property named 'escape':
-     *  if (isset($type->escape)) { ... }
-     *
-     * @param string $property Property name to check existance of.
-     */
-    protected function __isset($property)
-    {
-        $prop = '_' . $property;
-        return isset($this->$prop);
-    }
-
-    /**
-     * To unset a Type property named 'escape':
-     *   unset($type->escape);
-     *
-     * @param string $property Property name to unset.
-     */
-    protected function __unset($property)
-    {
-        $prop = '_' . $property;
-        unset($this->$prop);
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Boolean.php b/framework/Form/lib/Horde/Form/Type/Boolean.php
deleted file mode 100644 (file)
index 9ae0e86..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * An on/off value
- */
-class Horde_Form_Type_Boolean extends Horde_Form_Type {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        return true;
-    }
-
-    public function getInfo($vars, $var, &$info)
-    {
-        $info = String::lower($vars->get($var->name)) == 'on';
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Color.php b/framework/Form/lib/Horde/Form/Type/Color.php
deleted file mode 100644 (file)
index 383a16a..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-/**
- * Color
- */
-class Horde_Form_Type_Color extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && empty($value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^#([0-9a-z]){6}$/i', $value)) {
-            return true;
-        }
-
-        $message = _("This field must contain a color code in the RGB Hex format, for example '#1234af'.");
-        return false;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/CreditCard.php b/framework/Form/lib/Horde/Form/Type/CreditCard.php
deleted file mode 100644 (file)
index 294834c..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-/**
- * Credit card number
- */
-class Horde_Form_Type_creditcard extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if (empty($value) && $var->required) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (!empty($value)) {
-            /* getCardType() will also verify the checksum. */
-            $type = $this->getCardType($value);
-            if ($type === false || $type == 'unknown') {
-                $message = _("This does not seem to be a valid card number.");
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    function getChecksum($ccnum)
-    {
-        $len = strlen($ccnum);
-        if (!is_long($len / 2)) {
-            $weight = 2;
-            $digit = $ccnum[0];
-        } elseif (is_long($len / 2)) {
-            $weight = 1;
-            $digit = $ccnum[0] * 2;
-        }
-        if ($digit > 9) {
-            $digit = $digit - 9;
-        }
-        $i = 1;
-        $checksum = $digit;
-        while ($i < $len) {
-            if ($ccnum[$i] != ' ') {
-                $digit = $ccnum[$i] * $weight;
-                $weight = ($weight == 1) ? 2 : 1;
-                if ($digit > 9) {
-                    $digit = $digit - 9;
-                }
-                $checksum += $digit;
-            }
-            $i++;
-        }
-
-        return $checksum;
-    }
-
-    function getCardType($ccnum)
-    {
-        $sum = $this->getChecksum($ccnum);
-        $l = strlen($ccnum);
-
-        // Screen checksum.
-        if (($sum % 10) != 0) {
-            return false;
-        }
-
-        // Check for Visa.
-        if ((($l == 16) || ($l == 13)) &&
-            ($ccnum[0] == 4)) {
-            return 'visa';
-        }
-
-        // Check for MasterCard.
-        if (($l == 16) &&
-            ($ccnum[0] == 5) &&
-            ($ccnum[1] >= 1) &&
-            ($ccnum[1] <= 5)) {
-            return 'mastercard';
-        }
-
-        // Check for Amex.
-        if (($l == 15) &&
-            ($ccnum[0] == 3) &&
-            (($ccnum[1] == 4) || ($ccnum[1] == 7))) {
-            return 'amex';
-        }
-
-        // Check for Discover (Novus).
-        if (strlen($ccnum) == 16 &&
-            substr($ccnum, 0, 4) == '6011') {
-            return 'discover';
-        }
-
-        // If we got this far, then no card matched.
-        return 'unknown';
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Date.php b/framework/Form/lib/Horde/Form/Type/Date.php
deleted file mode 100644 (file)
index c4415e7..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-/**
- * Date
- */
-class Horde_Form_Type_Date extends Horde_Form_Type {
-
-    var $_format = '%a %d %B';
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if ($var->required) {
-            $valid = strlen(trim($value)) > 0;
-
-            if (!$valid) {
-                $message = _("This field is required.");
-            }
-        }
-
-        return $valid;
-    }
-
-    public static function getAgo($timestamp)
-    {
-        if ($timestamp === null) {
-            return '';
-        }
-
-        $diffdays = Date_Calc::dateDiff(date('j', $timestamp),
-                                        date('n', $timestamp),
-                                        date('Y', $timestamp),
-                                        date('j'), date('n'), date('Y'));
-
-        /* An error occured. */
-        if ($diffdays == -1) {
-            return;
-        }
-
-        $ago = $diffdays * Date_Calc::compareDates(date('j', $timestamp),
-                                                   date('n', $timestamp),
-                                                   date('Y', $timestamp),
-                                                   date('j'), date('n'),
-                                                   date('Y'));
-        if ($ago < -1) {
-            return sprintf(_(" (%s days ago)"), $diffdays);
-        } elseif ($ago == -1) {
-            return _(" (yesterday)");
-        } elseif ($ago == 0) {
-            return _(" (today)");
-        } elseif ($ago == 1) {
-            return _(" (tomorrow)");
-        } else {
-            return sprintf(_(" (in %s days)"), $diffdays);
-        }
-    }
-
-    public function getFormattedTime($timestamp, $format = null, $showago = true)
-    {
-        if (empty($format)) {
-            $format = $this->_format;
-        }
-        if (!empty($timestamp)) {
-            return strftime($format, $timestamp) . ($showago ? self::getAgo($timestamp) : '');
-        } else {
-            return '';
-        }
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/DateTime.php b/framework/Form/lib/Horde/Form/Type/DateTime.php
deleted file mode 100644 (file)
index 98adaa0..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-/**
- * Date and time selection
- */
-class Horde_Form_Type_DateTime extends Horde_Form_Type {
-
-    var $_date;
-    var $_time;
-
-    /**
-     * Return the date supplied as a Horde_Date object.
-     *
-     * @param integer $start_year  The first available year for input.
-     * @param integer $end_year    The last available year for input.
-     * @param boolean $picker      Do we show the DHTML calendar?
-     * @param integer $format_in   The format to use when sending the date
-     *                             for storage. Defaults to Unix epoch.
-     *                             Similar to the strftime() function.
-     * @param integer $format_out  The format to use when displaying the
-     *                             date. Similar to the strftime() function.
-     * @param boolean $show_seconds Include a form input for seconds.
-     */
-    function init($start_year = '', $end_year = '', $picker = true,
-                  $format_in = null, $format_out = '%x', $show_seconds = false)
-    {
-        $this->_date = new Horde_Form_Type_Date();
-        $this->_date->init($start_year, $end_year, $picker, $format_in, $format_out);
-
-        $this->_time = new Horde_Form_Type_Time();
-        $this->_time->init($show_seconds);
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required) {
-            return $this->_date->isValid($var, $vars, $value, $message) &&
-                $this->_time->isValid($var, $vars, $value, $message);
-        }
-        return true;
-    }
-
-    function getInfo(&$vars, &$var, &$info)
-    {
-        /* If any component is empty consider it a bad date and return the
-         * default. */
-        $value = $var->getValue($vars);
-        if ($this->emptyDateArray($value) == 1 || $this->emptyTimeArray($value)) {
-            $info = $var->getDefault();
-            return;
-        }
-
-        $date = $this->getDateOb($value);
-        $time = $this->getTimeOb($value);
-        $date->hour = $time->hour;
-        $date->min = $time->min;
-        $date->sec = $time->sec;
-        if (is_null($this->format_in)) {
-            $info = $date->timestamp();
-        } else {
-            $info = $date->strftime($this->format_in);
-        }
-    }
-
-    function __get($property)
-    {
-        if ($property == 'show_seconds') {
-            return $this->_time->$property;
-        } else {
-            return $this->_date->$property;
-        }
-    }
-
-    function __set($property, $value)
-    {
-        if ($property == 'show_seconds') {
-            $this->_time->$property = $value;
-        } else {
-            $this->_date->$property = $value;
-        }
-    }
-
-    function checktime($hour, $minute, $second)
-    {
-        return $this->_time->checktime($hour, $minute, $second);
-    }
-
-    function getTimeOb($time_in)
-    {
-        return $this->_time->getTimeOb($time_in);
-    }
-
-    function getTimeParts($time_in)
-    {
-        return $this->_time->getTimeParts($time_in);
-    }
-
-    function emptyTimeArray($time)
-    {
-        return $this->_time->emptyTimeArray($time);
-    }
-
-    function emptyDateArray($date)
-    {
-        return $this->_date->emptyDateArray($date);
-    }
-
-    function getDateParts($date_in)
-    {
-        return $this->_date->getDateParts($date_in);
-    }
-
-    function getDateOb($date_in)
-    {
-        return $this->_date->getDateOb($date_in);
-    }
-
-    function formatDate($date)
-    {
-        if ($date === null) {
-            return '';
-        }
-        return $this->_date->formatDate($date);
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Email.php b/framework/Form/lib/Horde/Form/Type/Email.php
deleted file mode 100644 (file)
index 96cf756..0000000
+++ /dev/null
@@ -1,452 +0,0 @@
-<?php
-/**
- * Email
- */
-class Horde_Form_Type_Email extends Horde_Form_Type {
-
-    /**
-     * Allow multiple addresses?
-     *
-     * @type boolean
-     * @var boolean
-    */
-    var $_allow_multi = false;
-
-    /**
-     * Strip domain from the address?
-     *
-     * @type boolean
-     * @var boolean
-     */
-    var $_strip_domain = false;
-
-    /**
-     * Make displayed email addresses clickable?
-     *
-     * @type boolean
-     * @var boolean
-     */
-    var $_link_compose = false;
-
-    /**
-     * The compose name to use
-     *
-     * @type text
-     * @var boolean
-     */
-    var $_link_name;
-
-    /**
-     * The character to separate multiple email addresses
-     *
-     * @type text
-     * @var string
-     */
-    var $_delimiters = ',';
-
-    /**
-     * Contact the target mail server to see if the email address is deliverable?
-     *
-     * @type boolean
-     * @var boolean
-     */
-    var $_check_smtp = false;
-
-    /**
-     */
-    public function init($allow_multi = false, $strip_domain = false,
-                  $link_compose = false, $link_name = null,
-                  $delimiters = ',')
-    {
-        $this->_allow_multi = $allow_multi;
-        $this->_strip_domain = $strip_domain;
-        $this->_link_compose = $link_compose;
-        $this->_link_name = $link_name;
-        $this->_delimiters = $delimiters;
-    }
-
-    /**
-     */
-    public function isValid($var, $vars, $value, &$message)
-    {
-        // Split into individual addresses.
-        $emails = $this->splitEmailAddresses($value);
-
-        // Check for too many.
-        if (!$this->_allow_multi && count($emails) > 1) {
-            $message = _("Only one email address is allowed.");
-            return false;
-        }
-
-        // Check for all valid and at least one non-empty.
-        $nonEmpty = 0;
-        foreach ($emails as $email) {
-            if (!strlen($email)) {
-                continue;
-            }
-            if (!$this->validateEmailAddress($email)) {
-                $message = sprintf(_("\"%s\" is not a valid email address."), $email);
-                return false;
-            }
-            ++$nonEmpty;
-        }
-
-        if (!$nonEmpty && $var->required) {
-            if ($this->_allow_multi) {
-                $message = _("You must enter at least one email address.");
-            } else {
-                $message = _("You must enter an email address.");
-            }
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Explodes an RFC 2822 string, ignoring a delimiter if preceded
-     * by a "\" character, or if the delimiter is inside single or
-     * double quotes.
-     *
-     * @param string $string     The RFC 822 string.
-     *
-     * @return array  The exploded string in an array.
-     */
-    public function splitEmailAddresses($string)
-    {
-        $quotes = array('"', "'");
-        $emails = array();
-        $pos = 0;
-        $in_quote = null;
-        $in_group = false;
-        $prev = null;
-
-        if (!strlen($string)) {
-            return array();
-        }
-
-        $char = $string[0];
-        if (in_array($char, $quotes)) {
-            $in_quote = $char;
-        } elseif ($char == ':') {
-            $in_group = true;
-        } elseif (strpos($this->_delimiters, $char) !== false) {
-            $emails[] = '';
-            $pos = 1;
-        }
-
-        for ($i = 1, $iMax = strlen($string); $i < $iMax; ++$i) {
-            $char = $string[$i];
-            if (in_array($char, $quotes)) {
-                if ($prev !== '\\') {
-                    if ($in_quote === $char) {
-                        $in_quote = null;
-                    } elseif (is_null($in_quote)) {
-                        $in_quote = $char;
-                    }
-                }
-            } elseif ($in_group) {
-                if ($char == ';') {
-                    $emails[] = substr($string, $pos, $i - $pos + 1);
-                    $pos = $i + 1;
-                    $in_group = false;
-                }
-            } elseif ($char == ':') {
-                $in_group = true;
-            } elseif (strpos($this->_delimiters, $char) !== false &&
-                      $prev !== '\\' &&
-                      is_null($in_quote)) {
-                $emails[] = substr($string, $pos, $i - $pos);
-                $pos = $i + 1;
-            }
-            $prev = $char;
-        }
-
-        if ($pos != $i) {
-            /* The string ended without a delimiter. */
-            $emails[] = substr($string, $pos, $i - $pos);
-        }
-
-        return $emails;
-    }
-
-    /**
-     * RFC(2)822 Email Parser.
-     *
-     * By Cal Henderson <cal@iamcal.com>
-     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
-     * http://creativecommons.org/licenses/by-sa/2.5/
-     *
-     * http://code.iamcal.com/php/rfc822/
-     *
-     * http://iamcal.com/publish/articles/php/parsing_email
-     *
-     * Revision 4
-     *
-     * @param string $email An individual email address to validate.
-     *
-     * @return boolean
-     */
-    public function validateEmailAddress($email)
-    {
-        static $comment_regexp, $email_regexp;
-        if ($comment_regexp === null) {
-            $this->_defineValidationRegexps($comment_regexp, $email_regexp);
-        }
-
-        // We need to strip comments first (repeat until we can't find
-        // any more).
-        while (true) {
-            $new = preg_replace("!$comment_regexp!", '', $email);
-            if (strlen($new) == strlen($email)){
-                break;
-            }
-            $email = $new;
-        }
-
-        // Now match what's left.
-        $result = (bool)preg_match("!^$email_regexp$!", $email);
-        if ($result && $this->_check_smtp) {
-            $result = $this->validateEmailAddressSmtp($email);
-        }
-
-        return $result;
-    }
-
-    /**
-     * Attempt partial delivery of mail to an address to validate it.
-     *
-     * @param string $email An individual email address to validate.
-     *
-     * @return boolean
-     */
-    public function validateEmailAddressSmtp($email)
-    {
-        list(, $maildomain) = explode('@', $email, 2);
-
-        // Try to get the real mailserver from MX records.
-        if (function_exists('getmxrr') &&
-            @getmxrr($maildomain, $mxhosts, $mxpriorities)) {
-            // MX record found.
-            array_multisort($mxpriorities, $mxhosts);
-            $mailhost = $mxhosts[0];
-        } else {
-            // No MX record found, try the root domain as the mail
-            // server.
-            $mailhost = $maildomain;
-        }
-
-        $fp = @fsockopen($mailhost, 25, $errno, $errstr, 5);
-        if (!$fp) {
-            return false;
-        }
-
-        // Read initial response.
-        fgets($fp, 4096);
-
-        // HELO
-        fputs($fp, "HELO $mailhost\r\n");
-        fgets($fp, 4096);
-
-        // MAIL FROM
-        fputs($fp, "MAIL FROM: <root@example.com>\r\n");
-        fgets($fp, 4096);
-
-        // RCPT TO - gets the result we want.
-        fputs($fp, "RCPT TO: <$email>\r\n");
-        $result = trim(fgets($fp, 4096));
-
-        // QUIT
-        fputs($fp, "QUIT\r\n");
-        fgets($fp, 4096);
-        fclose($fp);
-
-        return substr($result, 0, 1) == '2';
-    }
-
-    /**
-     * RFC(2)822 Email Parser.
-     *
-     * By Cal Henderson <cal@iamcal.com>
-     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
-     * http://creativecommons.org/licenses/by-sa/2.5/
-     *
-     * http://code.iamcal.com/php/rfc822/
-     *
-     * http://iamcal.com/publish/articles/php/parsing_email
-     *
-     * Revision 4
-     *
-     * @param string &$comment The regexp for comments.
-     * @param string &$addr_spec The regexp for email addresses.
-     */
-    protected function _defineValidationRegexps(&$comment, &$addr_spec)
-    {
-        /**
-         * NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
-         *                         %d11 /          ;  that do not include the
-         *                         %d12 /          ;  carriage return, line feed,
-         *                         %d14-31 /       ;  and white space characters
-         *                         %d127
-         * ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
-         * DIGIT          =  %x30-39
-         */
-        $no_ws_ctl  = "[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]";
-        $alpha      = "[\\x41-\\x5a\\x61-\\x7a]";
-        $digit      = "[\\x30-\\x39]";
-        $cr         = "\\x0d";
-        $lf         = "\\x0a";
-        $crlf       = "($cr$lf)";
-
-        /**
-         * obs-char        =       %d0-9 / %d11 /          ; %d0-127 except CR and
-         *                         %d12 / %d14-127         ;  LF
-         * obs-text        =       *LF *CR *(obs-char *LF *CR)
-         * text            =       %d1-9 /         ; Characters excluding CR and LF
-         *                         %d11 /
-         *                         %d12 /
-         *                         %d14-127 /
-         *                         obs-text
-         * obs-qp          =       "\" (%d0-127)
-         * quoted-pair     =       ("\" text) / obs-qp
-         */
-        $obs_char       = "[\\x00-\\x09\\x0b\\x0c\\x0e-\\x7f]";
-        $obs_text       = "($lf*$cr*($obs_char$lf*$cr*)*)";
-        $text           = "([\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f]|$obs_text)";
-        $obs_qp         = "(\\x5c[\\x00-\\x7f])";
-        $quoted_pair    = "(\\x5c$text|$obs_qp)";
-
-        /**
-         * obs-FWS         =       1*WSP *(CRLF 1*WSP)
-         * FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
-         *                         obs-FWS
-         * ctext           =       NO-WS-CTL /     ; Non white space controls
-         *                         %d33-39 /       ; The rest of the US-ASCII
-         *                         %d42-91 /       ;  characters not including "(",
-         *                         %d93-126        ;  ")", or "\"
-         * ccontent        =       ctext / quoted-pair / comment
-         * comment         =       "(" *([FWS] ccontent) [FWS] ")"
-         * CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
-         *
-         * @note: We translate ccontent only partially to avoid an
-         * infinite loop. Instead, we'll recursively strip comments
-         * before processing the input.
-         */
-        $wsp        = "[\\x20\\x09]";
-        $obs_fws    = "($wsp+($crlf$wsp+)*)";
-        $fws        = "((($wsp*$crlf)?$wsp+)|$obs_fws)";
-        $ctext      = "($no_ws_ctl|[\\x21-\\x27\\x2A-\\x5b\\x5d-\\x7e])";
-        $ccontent   = "($ctext|$quoted_pair)";
-        $comment    = "(\\x28($fws?$ccontent)*$fws?\\x29)";
-        $cfws       = "(($fws?$comment)*($fws?$comment|$fws))";
-        $cfws       = "$fws*";
-
-        /**
-         * atext           =       ALPHA / DIGIT / ; Any character except controls,
-         *                         "!" / "#" /     ;  SP, and specials.
-         *                         "$" / "%" /     ;  Used for atoms
-         *                         "&" / "'" /
-         *                         "*" / "+" /
-         *                         "-" / "/" /
-         *                         "=" / "?" /
-         *                         "^" / "_" /
-         *                         "`" / "{" /
-         *                         "|" / "}" /
-         *                         "~"
-         * atom            =       [CFWS] 1*atext [CFWS]
-         */
-        $atext      = "($alpha|$digit|[\\x21\\x23-\\x27\\x2a\\x2b\\x2d\\x2e\\x3d\\x3f\\x5e\\x5f\\x60\\x7b-\\x7e])";
-        $atom       = "($cfws?$atext+$cfws?)";
-
-        /**
-         * qtext           =       NO-WS-CTL /     ; Non white space controls
-         *                         %d33 /          ; The rest of the US-ASCII
-         *                         %d35-91 /       ;  characters not including "\"
-         *                         %d93-126        ;  or the quote character
-         * qcontent        =       qtext / quoted-pair
-         * quoted-string   =       [CFWS]
-         *                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
-         *                         [CFWS]
-         * word            =       atom / quoted-string
-         */
-        $qtext      = "($no_ws_ctl|[\\x21\\x23-\\x5b\\x5d-\\x7e])";
-        $qcontent   = "($qtext|$quoted_pair)";
-        $quoted_string  = "($cfws?\\x22($fws?$qcontent)*$fws?\\x22$cfws?)";
-        $word       = "($atom|$quoted_string)";
-
-        /**
-         * obs-local-part  =       word *("." word)
-         * obs-domain      =       atom *("." atom)
-         */
-        $obs_local_part = "($word(\\x2e$word)*)";
-        $obs_domain = "($atom(\\x2e$atom)*)";
-
-        /**
-         * dot-atom-text   =       1*atext *("." 1*atext)
-         * dot-atom        =       [CFWS] dot-atom-text [CFWS]
-         */
-        $dot_atom_text  = "($atext+(\\x2e$atext+)*)";
-        $dot_atom   = "($cfws?$dot_atom_text$cfws?)";
-
-        /**
-         * domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
-         * dcontent        =       dtext / quoted-pair
-         * dtext           =       NO-WS-CTL /     ; Non white space controls
-         *
-         *                         %d33-90 /       ; The rest of the US-ASCII
-         *                         %d94-126        ;  characters not including "[",
-         *                                         ;  "]", or "\"
-         */
-        $dtext      = "($no_ws_ctl|[\\x21-\\x5a\\x5e-\\x7e])";
-        $dcontent   = "($dtext|$quoted_pair)";
-        $domain_literal = "($cfws?\\x5b($fws?$dcontent)*$fws?\\x5d$cfws?)";
-
-        /**
-         * local-part      =       dot-atom / quoted-string / obs-local-part
-         * domain          =       dot-atom / domain-literal / obs-domain
-         * addr-spec       =       local-part "@" domain
-         */
-        $local_part = "($dot_atom|$quoted_string|$obs_local_part)";
-        $domain     = "($dot_atom|$domain_literal|$obs_domain)";
-        $addr_spec  = "($local_part\\x40$domain)";
-    }
-
-}
-
-/**
- * Email with confirmation
- */
-class Horde_Form_Type_EmailConfirm extends Horde_Form_Type {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && empty($value['original'])) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if ($value['original'] != $value['confirm']) {
-            $message = _("Email addresses must match.");
-            return false;
-        } else {
-            require_once 'Horde/MIME.php';
-            $parsed_email = MIME::parseAddressList($value['original'], false,
-                                                   true);
-            if (is_a($parsed_email, 'PEAR_Error')) {
-                $message = $parsed_email->getMessage();
-                return false;
-            }
-            if (count($parsed_email) > 1) {
-                $message = _("Only one email address allowed.");
-                return false;
-            }
-            if (empty($parsed_email[0]->mailbox)) {
-                $message = _("You did not enter a valid email address.");
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Enum.php b/framework/Form/lib/Horde/Form/Type/Enum.php
deleted file mode 100644 (file)
index c5e638e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * Choose one from a list of values
- */
-class Horde_Form_Type_Enum extends Horde_Form_Type {
-
-    /**
-     * List of values to choose from
-     *
-     * @type stringlist
-     * @var array
-     */
-    protected $_values = array();
-
-    /**
-     * Initial prompt value, if any
-     *
-     * @type text
-     * @var string
-     */
-    protected $_prompt;
-
-    /**
-     */
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && $value == '' && !isset($this->_values[$value])) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (count($this->_values) == 0 || isset($this->_values[$value]) ||
-            ($this->_prompt && empty($value))) {
-            return true;
-        }
-
-        $message = _("Invalid data.");
-        return false;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Int.php b/framework/Form/lib/Horde/Form/Type/Int.php
deleted file mode 100644 (file)
index 31375a7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-/**
- * Integer
- */
-class Horde_Form_Type_Int extends Horde_Form_Type {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && empty($value) && ((string)(int)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^[0-9]+$/', $value)) {
-            return true;
-        }
-
-        $message = _("This field may only contain integers.");
-        return false;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Invalid.php b/framework/Form/lib/Horde/Form/Type/Invalid.php
deleted file mode 100644 (file)
index 20ee3c3..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-class Horde_Form_Type_invalid extends Horde_Form_Type {
-
-    var $message;
-
-    function init($message)
-    {
-        $this->message = $message;
-    }
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        return false;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Number.php b/framework/Form/lib/Horde/Form/Type/Number.php
deleted file mode 100644 (file)
index 6b58fd6..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
- * Number
- */
-class Horde_Form_Type_Number extends Horde_Form_Type {
-
-    /**
-     */
-    protected $_fraction;
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && empty($value) && ((string)(double)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        } elseif (empty($value)) {
-            return true;
-        }
-
-        /* If matched, then this is a correct numeric value. */
-        if (preg_match($this->_getValidationPattern(), $value)) {
-            return true;
-        }
-
-        $message = _("This field must be a valid number.");
-        return false;
-    }
-
-    /**
-     */
-    public function getInfo($vars, $var, &$info)
-    {
-        $value = $vars->get($var->name);
-        $linfo = NLS::getLocaleInfo();
-        $value = str_replace($linfo['mon_thousands_sep'], '', $value);
-        $info = str_replace($linfo['mon_decimal_point'], '.', $value);
-    }
-
-    /**
-     */
-    protected function _getValidationPattern()
-    {
-        static $pattern = '';
-        if (!empty($pattern)) {
-            return $pattern;
-        }
-
-        /* Get current locale information. */
-        $linfo = NLS::getLocaleInfo();
-
-        /* Build the pattern. */
-        $pattern = '(-)?';
-
-        /* Only check thousands separators if locale has any. */
-        if (!empty($linfo['mon_thousands_sep'])) {
-            /* Regex to check for correct thousands separators (if any). */
-            $pattern .= '((\d+)|((\d{0,3}?)([' . $linfo['mon_thousands_sep'] . ']\d{3})*?))';
-        } else {
-            /* No locale thousands separator, check for only digits. */
-            $pattern .= '(\d+)';
-        }
-        /* If no decimal point specified default to dot. */
-        if (empty($linfo['mon_decimal_point'])) {
-            $linfo['mon_decimal_point'] = '.';
-        }
-        /* Regex to check for correct decimals (if any). */
-        if (empty($this->_fraction)) {
-            $fraction = '*';
-        } else {
-            $fraction = '{0,' . $this->_fraction . '}';
-        }
-        $pattern .= '([' . $linfo['mon_decimal_point'] . '](\d' . $fraction . '))?';
-
-        /* Put together the whole regex pattern. */
-        $pattern = '/^' . $pattern . '$/';
-
-        return $pattern;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Octal.php b/framework/Form/lib/Horde/Form/Type/Octal.php
deleted file mode 100644 (file)
index 111cdb7..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-/**
- * Octal
- */
-class Horde_Form_Type_Octal extends Horde_Form_Type {
-
-    function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && empty($value) && ((string)(int)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^[0-7]+$/', $value)) {
-            return true;
-        }
-
-        $message = _("This field may only contain octal values.");
-        return false;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Password.php b/framework/Form/lib/Horde/Form/Type/Password.php
deleted file mode 100644 (file)
index a47a178..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-/**
- * Password
- */
-class Horde_Form_Type_Password extends Horde_Form_Type {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if ($var->required) {
-            $valid = strlen(trim($value)) > 0;
-
-            if (!$valid) {
-                $message = _("This field is required.");
-            }
-        }
-
-        return $valid;
-    }
-
-}
-
-
-/**
- * Password with confirmation
- */
-class Horde_Form_Type_passwordConfirm extends Horde_Form_Type {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && empty($value['original'])) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if ($value['original'] != $value['confirm']) {
-            $message = _("Passwords must match.");
-            return false;
-        }
-
-        return true;
-    }
-
-    function getInfo($vars, $var, &$info)
-    {
-        $value = $vars->get($var->name);
-        $info = $value['original'];
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Phone.php b/framework/Form/lib/Horde/Form/Type/Phone.php
deleted file mode 100644 (file)
index 488fa57..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-/**
- * Phone number
- */
-class Horde_Form_Type_Phone extends Horde_Form_Type {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if ($var->required) {
-            $valid = strlen(trim($value)) > 0;
-            if (!$valid) {
-                $message = _("This field is required.");
-            }
-        } else {
-            $valid = preg_match('/^\+?[\d()\-\/ ]*$/', $value);
-            if (!$valid) {
-                $message = _("You must enter a valid phone number, digits only with an optional '+' for the international dialing prefix.");
-            }
-        }
-
-        return $valid;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Phone/Mobile.php b/framework/Form/lib/Horde/Form/Type/Phone/Mobile.php
deleted file mode 100644 (file)
index 5c97969..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-<?php
-/**
- * Mobile Phone Number
- */
-class Horde_Form_Type_Phone_Mobile extends Horde_Form_Type_Phone {}
diff --git a/framework/Form/lib/Horde/Form/Type/Set.php b/framework/Form/lib/Horde/Form/Type/Set.php
deleted file mode 100644 (file)
index db805ad..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-/**
- * Set of values
- */
-class Horde_Form_Type_Set extends Horde_Form_Type {
-
-    /**
-     * Values
-     *
-     * @type stringlist
-     * @var string
-     */
-    protected $_values;
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if (count($this->_values) == 0 || count($value) == 0) {
-            return true;
-        }
-        foreach ($value as $item) {
-            if (!isset($this->_values[$item])) {
-                $error = true;
-                break;
-            }
-        }
-        if (!isset($error)) {
-            return true;
-        }
-
-        $message = _("Invalid data.");
-        return false;
-    }
-
-}
-
-class Horde_Form_Type_multienum extends Horde_Form_Type_enum {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if (is_array($value)) {
-            foreach ($value as $val) {
-                if (!$this->isValid($var, $vars, $val, $message)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        if (empty($value) && ((string)(int)$value !== $value)) {
-            if ($var->required) {
-                $message = _("This field is required.");
-                return false;
-            } else {
-                return true;
-            }
-        }
-
-        if (count($this->_values) == 0 || isset($this->_values[$value])) {
-            return true;
-        }
-
-        $message = _("Invalid data.");
-        return false;
-    }
-
-}
-
-class Horde_Form_Type_keyval_multienum extends Horde_Form_Type_multienum {
-
-    function getInfo($vars, $var, &$info)
-    {
-        $value = $vars->get($var->name);
-        $info = array();
-        foreach ($value as $key) {
-            $info[$key] = $this->_values[$key];
-        }
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/String.php b/framework/Form/lib/Horde/Form/Type/String.php
deleted file mode 100644 (file)
index 276f541..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-/**
- * String
- */
-class Horde_Form_Type_String extends Horde_Form_Type {
-
-    /**
-     * Validation regex
-     *
-     * @type string
-     * @var string
-     */
-    protected $_regex;
-
-    /**
-     * Maximum length
-     *
-     * @type int
-     * @var integer
-     */
-    protected $_maxlength;
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        $valid = true;
-
-        if (!empty($this->_maxlength) && String::length($value) > $this->_maxlength) {
-            $valid = false;
-            $message = sprintf(_("Value is over the maximum length of %s."), $this->_maxlength);
-        } elseif ($var->required && empty($this->_regex)) {
-            if (!($valid = strlen(trim($value)) > 0)) {
-                $message = _("This field is required.");
-            }
-        } elseif (strlen($this->_regex)) {
-            if (!($valid = preg_match($this->_regex, $value))) {
-                $message = _("You must enter a valid value.");
-            }
-        }
-
-        return $valid;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/Type/Time.php b/framework/Form/lib/Horde/Form/Type/Time.php
deleted file mode 100644 (file)
index 3b26133..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-/**
- * Time
- */
-class Horde_Form_Type_Time extends Horde_Form_Type {
-
-    public function isValid($var, $vars, $value, &$message)
-    {
-        if ($var->required && empty($value) && ((string)(double)$value !== $value)) {
-            $message = _("This field is required.");
-            return false;
-        }
-
-        if (empty($value) || preg_match('/^[0-2]?[0-9]:[0-5][0-9]$/', $value)) {
-            return true;
-        }
-
-        $message = _("This field may only contain numbers and the colon.");
-        return false;
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/VarRenderer.php b/framework/Form/lib/Horde/Form/VarRenderer.php
deleted file mode 100644 (file)
index 60947ba..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
- * The Horde_Form_VarRenderer:: class provides base functionality for
- * other Horde_Form elements.
- *
- * $Horde: incubator/Horde_Form/Horde/Form/VarRenderer.php,v 1.8 2008/01/02 11:12:48 jan Exp $
- *
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
- * Copyright 2005-2007 Matt Warden <mwarden@gmail.com>
- *
- * See the enclosed file LICENSE for license information (LGPL).
- *
- * @author  Jason M. Felice <jason.m.felice@gmail.com>
- * @package Horde_Form
- */
-class Horde_Form_VarRenderer {
-
-    /**
-     * Renders a variable.
-     *
-     * @param Horde_Form $form            Reference to a Horde_Form instance,
-     *                                    or null if none is available.
-     * @param Horde_Form_Variable $var    Reference to a Horde_Form_Variable.
-     * @param Variables $vars             A Variables instance.
-     * @param boolean $isInput            Whether this is an input field.
-     */
-    public function render($form, $var, $vars, $isInput = false)
-    {
-        if ($isInput) {
-            $state = 'Input';
-        } else {
-            $state = 'Display';
-        }
-        $method = "_renderVar${state}_" . str_replace('Horde_Form_Type_', '', get_class($var->type));
-        if (!method_exists($this, $method)) {
-            $method = "_renderVar${state}Default";
-        }
-        return $this->$method($form, $var, $vars);
-    }
-
-    /**
-     * Finishes rendering after all fields are output.
-     */
-    public function renderEnd()
-    {
-        return '';
-    }
-
-}
diff --git a/framework/Form/lib/Horde/Form/VarRenderer/Xhtml.php b/framework/Form/lib/Horde/Form/VarRenderer/Xhtml.php
deleted file mode 100644 (file)
index 312a217..0000000
+++ /dev/null
@@ -1,1541 +0,0 @@
-<?php
-/**
- * The Horde_Form_VarRenderer_Xhtml:: class renders variables as Xhtml.
- *
- * $Horde: incubator/Horde_Form/Horde/Form/VarRenderer/Xhtml.php,v 1.14 2008/01/02 11:12:48 jan Exp $
- *
- * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
- * Copyright 2005 Matt Warden <mwarden@gmail.com>
- *
- * See the enclosed file LICENSE for license information (LGPL).
- *
- * @author  Jason M. Felice <jason.m.felice@gmail.com>
- * @package Horde_Form
- */
-class Horde_Form_VarRenderer_Xhtml extends Horde_Form_VarRenderer {
-
-    protected $_onLoadJS = array();
-
-    /**
-     * Handles the end of rendering of variables; writes onload JavaScript.
-     *
-     * @access public
-     * @author ?
-     * @return string the javascript to execute, and its container script tags,
-     *            or and empty string if there is nothing to execute onload
-     */
-    public function renderEnd()
-    {
-        if (count($this->_onLoadJS)) {
-            return "<script type=\"text/javascript\">" .
-                "<!--\n" .  implode("\n", $this->_onLoadJS) . "\n// -->\n" .
-                "</script>";
-        } else {
-            return '';
-        }
-    }
-
-    function _renderVarInputDefault($form, $var, $vars)
-    {
-        throw new Horde_Form_Exception('Unknown variable type:' . get_class($var->type));
-    }
-
-    function _renderVarInput_number($form, $var, $vars)
-    {
-        $value = $var->getValue($vars);
-        if ($var->type->fraction) {
-            $value = sprintf('%01.' . $var->type->fraction . 'f', $value);
-        }
-        $linfo = NLS::getLocaleInfo();
-        /* Only if there is a mon_decimal_point do the
-         * substitution. */
-        if (!empty($linfo['mon_decimal_point'])) {
-            $value = str_replace('.', $linfo['mon_decimal_point'], $value);
-        }
-        return sprintf('    <input type="text" class="form-input-number" name="%1$s" id="%1$s" value="%2$s"%3$s />',
-                       $var->getVarName(),
-                       $value,
-                       $this->_getActionScripts($form, $var)
-               );
-    }
-
-    function _renderVarInput_int($form, $var, $vars)
-    {
-        return sprintf('    <input type="text" class="form-input-int" name="%1$s" id="%1$s" value="%2$s"%3$s />',
-                       $var->getVarName(),
-                       $value = $var->getValue($vars),
-                       $this->_getActionScripts($form, $var)
-               );
-    }
-
-    function _renderVarInput_octal($form, $var, $vars)
-    {
-        return sprintf('<input type="text" class="form-input-octal" name="%1$s" id="%1$s" value="%2$s"%3$s />',
-                       $var->getVarName(),
-                       sprintf('0%o', octdec($var->getValue($vars))),
-                       $this->_getActionScripts($form, $var)
-               );
-    }
-
-    function _renderVarInput_intlist($form, $var, $vars)
-    {
-        return sprintf('<input type="text" class="form-input-intlist" name="%1$s" id="%1$s" value="%2$s"%3$s />',
-                       $var->getVarName(),
-                       $value = $var->getValue($vars),
-                       $this->_getActionScripts($form, $var)
-               );
-    }
-
-    function _renderVarInput_text($form, $var, $vars)
-    {
-        return sprintf(
-            '<input type="text" class="form-input-text%1$s" name="%2$s" '
-            . 'id="%2$s" value="%3$s"%4$s%5$s%6$s />',
-            ($var->isDisabled() ? ' form-input-disabled" ' : ''),
-            $var->getVarName(),
-            htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()),
-            ($var->isDisabled() ? ' disabled="disabled" ' : ''),
-            ($var->type->maxlength ? ' maxlength="' . $var->type->maxlength . '"' : ''),
-            $this->_getActionScripts($form, $var)
-        );
-    }
-
-    function _renderVarInput_stringlist($form, $var, $vars)
-    {
-        return sprintf(
-            '<input type="text" class="form-input-stringlist" name="%s" value="%s"%s />',
-            $var->getVarName(),
-            $value = $var->getValue($vars),
-            $this->_getActionScripts($form, $var)
-        );
-    }
-
-    function _renderVarInput_phone($form, $var, $vars)
-    {
-        return sprintf(
-            '<input type="text" class="form-input-phone" name="%1$s" id="%1$s" value="%2$s" %3$s%4$s />',
-            $var->getVarName(),
-            htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()),
-            ($var->isDisabled() ? ' disabled="disabled" ' : ''),
-            $this->_getActionScripts($form, $var)
-        );
-    }
-
-    function _renderVarInput_cellphone($form, $var, $vars)
-    {
-        return $this->_renderVarInput_phone($form, $var, $vars);
-    }
-
-    function _renderVarInput_ipaddress($form, $var, $vars)
-    {
-        return sprintf('    <input type="text" class="form-input-ipaddress" name="%1$s" id="%1$s" value="%2$s" %3$s%4$s />',
-                       $var->getVarName(),
-                       htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()),
-                       $var->isDisabled() ? ' disabled="disabled" ' : '',
-                       $this->_getActionScripts($form, $var)
-               );
-    }
-
-    function _renderVarInput_file($form, $var, $vars)
-    {
-        $file = $var->getValue($vars);
-        return sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s"%2$s />',
-                       $var->getVarName(),
-                       $this->_getActionScripts($form, $var));
-    }
-
-    /**
-     * @todo Show image dimensions in the width/height boxes.
-     */
-    function _renderVarInput_image($form, $var, $vars)
-    {
-        $varname = $var->getVarName();
-        $image = $var->getValue($vars);
-
-        /* Check if existing image data is being loaded. */
-        $var->type->loadImageData($image);
-
-        Horde::addScriptFile('image.js', 'horde', true);
-        $graphics_dir = $GLOBALS['registry']->getImageDir('horde');
-        $img_dir = $graphics_dir . '/image';
-
-        $html = '';
-
-        /* Check if there is existing img information stored. */
-        if (isset($image['img'])) {
-            /* Hidden tag to store the preview image filename. */
-            $html = sprintf('    <input type="hidden" name="%1$s" id="%1$s" value="%2$s" />',
-                   $varname . '[img]',
-                   htmlspecialchars($image['img'], ENT_QUOTES, NLS::getCharset()));
-
-            /* Unserialize the img information to get the full array. */
-            $image['img'] = @unserialize($image['img']);
-        }
-
-        /* Output the input tag. */
-        if (empty($image['img'])) {
-            $js = "
-var p = document.getElementById('" . $varname . "[preview]');
-o = '\\\\'; a = '/';
-tmp = '' + document.getElementById('" . $varname . "[new]').value;
-if (tmp) {
-    while (tmp.indexOf(o) > -1) {
-        pos = tmp.indexOf(o);
-        tmp = '' + (tmp.substring(0, pos) + a + tmp.substring((pos + o.length), tmp.length));
-    }
-    p.src = 'file:///' + tmp;
-    p.alt = '" . addslashes(_("If you see this message but no image, the image you want to upload can't be displayed by your browser.")) . "';
-}";
-            $browser = Horde_Browser::singleton();
-            if ($browser->isBrowser('msie')) {
-                $html .= sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s" onchange="%2$s" />',
-                             $varname . '[new]',
-                             $js);
-            } else {
-                $html .= sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s"
-                        onclick="window.setTimeout(\'document.getElementById(\\\'%1$s\\\').blur();\', 5);"
-                        onblur="%2$s" />',
-                             $varname . '[new]',
-                             $js);
-            }
-        } else {
-            $html .= sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s" />',
-                             $varname . '[new]');
-        }
-
-        /* Output the button to upload/reset the image. */
-        if ($var->type->show_upload) {
-            $html .= '&nbsp;';
-            $html .= sprintf('    <input class="form-button-upload" name="%1$s" id="%1$s" type="submit" value="%2$s" /> ',
-                         '_do_' . $varname,
-                         _("Upload"));
-        }
-
-        if (empty($image['img'])) {
-            /* No image information stored yet, show a blank
-             * preview. */
-            $html .= Horde::img('tree/blank.png', _("Preview"),
-                    'class="form-image-preview-blank" id="' . $varname . '[preview]"',
-                    $graphics_dir);
-        } else {
-            /* Image information stored, show preview, add buttons for
-             * image manipulation. */
-            $html .= '<br />';
-            $img = Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/images/view.php');
-            if (isset($image['img']['vfs_id'])) {
-                /* Calling an image from VFS. */
-                $img = Util::addParameter($img, array('f' => $image['img']['vfs_id'],
-                                                      's' => 'vfs',
-                                                      'p' => $image['img']['vfs_path']));
-            } else {
-                /* Calling an image from a tmp directory (uploads). */
-                $img = Util::addParameter($img, 'f', $image['img']['file']);
-            }
-
-            // TODO: possible to change to unobtrusive JS?
-            /* Rotate 270. */
-            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, array('a' => 'rotate', 'v' => '270')) . '\', \'_p_' . $varname . '\', true);') . Horde::img('rotate-270.png', _("Rotate Left"), '', $img_dir) . '</a>';
-
-            /* Rotate 180. */
-            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, array('a' => 'rotate', 'v' => '180')) . '\', \'_p_' . $varname . '\', true);') . Horde::img('rotate-180.png', _("Rotate 180"), '', $img_dir) . '</a>';
-
-            /* Rotate 90. */
-            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, array('a' => 'rotate', 'v' => '90')) . '\', \'_p_' . $varname . '\', true);') . Horde::img('rotate-90.png', _("Rotate Right"), '', $img_dir) . '</a>';
-
-            /* Flip image. */
-            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, 'a', 'flip') . '\', \'_p_' . $varname . '\', true);') . Horde::img('flip.png', _("Flip"), '', $img_dir) . '</a>';
-
-            /* Mirror image. */
-            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, 'a', 'mirror') . '\', \'_p_' . $varname . '\', true);') . Horde::img('mirror.png', _("Mirror"), '', $img_dir) . '</a>';
-
-            /* Apply grayscale. */
-            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, 'a', 'grayscale') . '\', \'_p_' . $varname . '\', true);') . Horde::img('grayscale.png', _("Grayscale"), '', $img_dir) . '</a>';
-
-            /* Resize width. */
-            $html .= sprintf('%s    <input type="text" class="form-input-resize" onchange="src=getResizeSrc(\'%s\', \'%s\');showImage(src, \'_p_%s\', true);" %s />',
-                   _("w:"),
-                   Util::addParameter($img, 'a', 'resize'),
-                   $varname,
-                   $varname,
-                   '_w_'. $varname);
-
-            /* Resize height. */
-            $html .= sprintf('%s    <input type="text" class="form-input-resize" onchange="src=getResizeSrc(\'%s\', \'%s\');showImage(src, \'_p_%s\', true);" %s />',
-                   _("h:"),
-                   Util::addParameter($img, 'a', 'resize'),
-                   $varname,
-                   $varname,
-                   '_h_'. $varname);
-
-            /* Apply fixed ratio resize. */
-            $html .= Horde::link('#', '', '', '', 'src=getResizeSrc(\'' . Util::addParameter($img, 'a', 'resize') . '\', \'' . $varname . '\', \'1\');showImage(src, \'_p_' . $varname . '\', true);') . Horde::img('ratio.png', _("Fix ratio"), '', $img_dir) . '</a>';
-
-            /* Keep also original if it has been requested. */
-            if ($var->type->show_keeporig) {
-                $html .= sprintf('    <input type="checkbox" class="form-input-checkbox" name="%s"%s />%s' . "\n",
-                       $varname . '[keep_orig]',
-                       !empty($image['keep_orig']) ? ' checked="checked"' : '',
-                       _("Keep original?"));
-            }
-
-            /* The preview image element. */
-            $html .= '<br /><img src="' . $img . '" id="_p_' . $varname .'" />'."\n";
-        }
-
-        return $html;
-    }
-
-    function _renderVarInput_longtext($form, $var, $vars)
-    {
-        global $browser;
-
-        $html = sprintf('<textarea class="form-input-longtext" id="%1$s" name="%1$s" '
-                            .'cols="%2$s" rows="%3$s"%4$s%5$s>%6$s</textarea>',
-                        $var->getVarName(),
-                        $var->type->cols,
-                        $var->type->rows,
-                        $this->_getActionScripts($form, $var),
-                        $var->isDisabled() ? ' disabled="disabled"' : '',
-                        htmlspecialchars($var->getValue($vars)));
-
-        if ($var->type->hasHelper('rte') && $browser->hasFeature('rte')) {
-            $editor = Horde_Editor::factory('Xinha', array('id' => $var->getVarName()));
-        }
-
-        if ($var->type->hasHelper() && $browser->hasFeature('javascript')) {
-            $html .= '<div class="form-html-helper">';
-            Horde::addScriptFile('open_html_helper.js', 'horde');
-            $imgId = $var->getVarName() . 'ehelper';
-            if ($var->type->hasHelper('emoticons')) {
-                $html .= Horde::link('#', _("Emoticons"), '', '', 'openHtmlHelper(\'emoticons\', \'' . $var->getVarName() . '\'); return false;')
-                    . Horde::img('smile.png', _("Emoticons"), 'id="' . $imgId . '" align="middle"', $GLOBALS['registry']->getImageDir('horde') . '/emoticons')
-                    . '</a>'."\n";
-            }
-            $html .= '</div><div id="htmlhelper_' . $var->getVarName()
-                    . '" class="form-control"></div>'."\n";
-        }
-
-        return $html;
-    }
-
-    function _renderVarInput_countedtext($form, $var, $vars)
-    {
-        return sprintf('<textarea class="form-input-countedtext" id="%1$s" name="%1$s" '
-                        .'cols="%2$s" rows="%3$s"%4$s%5$s>%6$s</textarea>',
-                       $var->getVarName(),
-                       $var->type->cols,
-                       $var->type->rows,
-                       $this->_getActionScripts($form, $var),
-                       $var->isDisabled() ? ' disabled="disabled"' : '',
-                       $var->getValue($vars));
-    }
-
-    function _renderVarInput_address($form, $var, $vars)
-    {
-        return sprintf('<textarea class="form-input-address" id="%1$s" name="%1$s" '
-                        .'cols="%2$s" rows="%3$s"%4$s%5$s>%6$s</textarea>',
-                       $var->getVarName(),
-                       $var->type->cols,
-                       $var->type->rows,
-                       $this->_getActionScripts($form, $var),
-                       $var->isDisabled() ? ' disabled="disabled"' : '',
-                       $var->getValue($vars));
-    }
-
-    function _renderVarInput_date($form, $var, $vars)
-    {
-        return sprintf('    <input type="text" class="form-input-date" name="%1$s" id="%1$s" '
-                            .'value="%2$s"%3$s />',
-                        $var->getVarName(),
-                        $value = $var->getValue($vars),
-                        $this->_getActionScripts($form, $var));
-    }
-
-    function _renderVarInput_time($form, $var, $vars)
-    {
-        return sprintf('    <input type="text" class="form-input-time" name="%1$s" id="%1$s" '
-                            .'value="%2$s"%3$s />',
-                       $var->getVarName(),
-                       $value = $var->getValue($vars),
-                       $this->_getActionScripts($form, $var));
-    }
-
-    function _renderVarInput_hourminutesecond($form, $var, $vars)
-    {
-        $varname = $var->getVarName();
-        $time = $var->type->getTimeParts($var->getValue($vars));
-
-        /* Output hours. */
-        $hours = array('' => _("hh"));
-        for ($i = 0; $i <= 23; $i++) {
-            $hours[sprintf('%02d', $i)] = $i;
-        }
-        $html = sprintf('<select name="%1$s[hour]" id="%1$s[hour]"%2$s>%3$s    </select>',
-                        $varname,
-                        $this->_selectOptions($hours, $time['hour']),
-                        $this->_getActionScripts($form, $var));
-
-        /* Output minutes. */
-        $minutes = array('' => _("mm"));
-        for ($i = 0; $i <= 59; $i++) {
-            $minutes[sprintf('%02d', $i)] = $i;
-        }
-        $html .= sprintf('<select name="%1$s[minute]" id="%1$s[minute]"%2$s>%3$s    </select>',
-                         $varname,
-                         $this->_selectOptions($minutes, $time['minute']),
-                         $this->_getActionScripts($form, $var));
-
-        /* Return if seconds are not required. */
-        if ($var->type->show_seconds) {
-            /* Output seconds. */
-            $seconds = array('' => _("ss"));
-            for ($i = 0; $i <= 59; $i++) {
-                $seconds[sprintf('%02d', $i)] = $i;
-            }
-            $html .= sprintf('<select name="%1$s[second]" id="%1$s[second]"%2$s>%3$s    </select>',
-                            $varname,
-                            $this->_getActionScripts($form, $var),
-                            $this->_selectOptions($seconds, $time['second']));
-        }
-
-        return $html;
-    }
-
-    function _renderVarInput_monthyear($form, $var, $vars)
-    {
-        $dates = array();
-        $dates['month'] = array('' => _("MM"),
-                                1 => _("January"),
-                                2 => _("February"),
-                                3 => _("March"),
-                                4 => _("April"),
-                                5 => _("May"),
-                                6 => _("June"),
-                                7 => _("July"),
-                                8 => _("August"),
-                                9 => _("September"),
-                                10 => _("October"),
-                                11 => _("November"),
-                                12 => _("December"));
-        $dates['year'] = array('' => _("YYYY"));
-        if ($var->type->start_year > $var->type->end_year) {
-            for ($i = $var->type->start_year; $i >= $var->type->end_year; $i--) {
-                $dates['year'][$i] = $i;
-            }
-        } else {
-            for ($i = $var->type->start_year; $i <= $var->type->end_year; $i++) {
-                $dates['year'][$i] = $i;
-            }
-        }
-        $html = sprintf('<select name="%1$s" id="%1$s"%2$s>%3$s    </select>',
-               $var->type->getMonthVar($var),
-               $this->_getActionScripts($form, $var),
-               $this->_selectOptions($dates['month'], $vars->get($var->type->getMonthVar($var))));
-
-        $html .= sprintf('<select name="%1$s" id="%1$s"%2$s>%3$s    </select>',
-               $var->type->getYearVar($var),
-               $this->_getActionScripts($form, $var),
-               $this->_selectOptions($dates['year'], $vars->get($var->type->getYearVar($var))));
-
-        return $html;
-    }
-
-    function _renderVarInput_monthdayyear($form, $var, $vars)
-    {
-        $dates = array();
-        $dates['month'] = array(''   => _("MM"),
-                                '1'  => _("January"),
-                                '2'  => _("February"),
-                                '3'  => _("March"),
-                                '4'  => _("April"),
-                                '5'  => _("May"),
-                                '6'  => _("June"),
-                                '7'  => _("July"),
-                                '8'  => _("August"),
-                                '9'  => _("September"),
-                                '10' => _("October"),
-                                '11' => _("November"),
-                                '12' => _("December"));
-        $dates['day'] = array('' => _("DD"));
-        for ($i = 1; $i <= 31; $i++) {
-            $dates['day'][$i] = $i;
-        }
-        $dates['year'] = array('' => _("YYYY"));
-        if ($var->type->start_year > $var->type->end_year) {
-            for ($i = $var->type->start_year; $i >= $var->type->end_year; $i--) {
-                $dates['year'][$i] = $i;
-            }
-        } else {
-            for ($i = $var->type->start_year; $i <= $var->type->end_year; $i++) {
-                $dates['year'][$i] = $i;
-            }
-        }
-        $date = $var->type->getDateParts($var->getValue($vars));
-
-        // TODO: use NLS to get the order right for the Rest Of The
-        // World.
-        $html = '';
-        $date_parts = array('month', 'day', 'year');
-        foreach ($date_parts as $part) {
-            $varname = $var->getVarName() . '[' . $part . ']';
-            $html .= sprintf('<select name="%1$s" id="%1$s"%2$s>%3$s    </select>',
-                             $varname,
-                             $this->_getActionScripts($form, $var),
-                             $this->_selectOptions($dates[$part], $date[$part]));
-        }
-
-        if ($var->type->picker && $GLOBALS['browser']->hasFeature('javascript')) {
-            Horde::addScriptFile('open_calendar.js', 'horde');
-            $imgId = $var->getVarName() .'goto';
-            $html .= '<div id="goto"></div>';
-            $html .= Horde::link('#', _("Select a date"), '', '', 'openCalendar(\'' . $imgId . '\', \'' . $var->getVarName() . '\'); return false;')
-                . Horde::img('calendar.png', _("Calendar"), 'id="' . $imgId . '" ', $GLOBALS['registry']->getImageDir('horde'))
-                . '</a>';
-        }
-
-        return $html;
-    }
-
-    function _renderVarInput_datetime($form, $var, $vars)
-    {
-        return parent::_renderVarInput_monthdayyear($form, $var, $vars) .
-            parent::_renderVarInput_hourminutesecond($form, $var, $vars);
-    }
-
-    function _renderVarInput_colorpicker($form, $var, $vars)
-    {
-        $html = '<div class="form-colorpicker">'
-            . '<input type="text" maxlength="7" name="'
-            . $var->getVarName() . '" id="' . $var->getVarName()
-            . '" value="' . $var->getValue($vars) . '" />';
-
-        if ($GLOBALS['browser']->hasFeature('javascript')) {
-            Horde::addScriptFile('open_colorpicker.js', 'horde', true);
-            $html .= Horde::img('blank.gif', '', array('class' => 'form-colorpicker-preview',
-                                                       'id' => 'colordemo_' . $var->getVarName(),
-                                                       'style' => 'background:' . $var->getValue($vars)), $GLOBALS['registry']->getImageDir('horde'))
-                . Horde::link('#', _("Color Picker"), '', '', 'openColorPicker(\''. $var->getVarName() .'\'); return false;')
-                . Horde::img('colorpicker.png', _("Color Picker"), '', $GLOBALS['registry']->getImageDir('horde')) . '</a>'
-                . '<div id="colorpicker_' . $var->getVarName() . '" class="form-colorpicker-palette"></div>';
-        }
-
-        return $html . '</div>';
-    }
-
-    function _renderVarInput_sorter($form, $var, $vars)
-    {
-        global $registry;
-
-        $varname = $var->getVarName();
-        $instance = $var->type->instance;
-
-        Horde::addScriptFile('sorter.js', 'horde', true);
-
-        return '    <input type="hidden" name="'. $varname
-            . '[array]" value="" id="'. $varname .'-array-" />'."\n"
-            . '    <select class="leftFloat" multiple="multiple" size="'
-            . $var->type->size . '" name="' . $varname
-            . '[list]" onchange="' . $instance . '.deselectHeader();" '
-            . ' id="'. $varname . '-list-">'
-            . $var->type->getOptions($var->getValue($vars)) . '    </select><div class="leftFloat">'
-            . Horde::link('#', _("Move up"), '', '', $instance . '.moveColumnUp(); return false;')
-                . Horde::img('nav/up.png', _("Move up"), '', $registry->getImageDir('horde'))
-                . '</a><br />'
-            . Horde::link('#', _("Move up"), '', '', $instance . '.moveColumnDown(); return false;')
-                . Horde::img('nav/down.png', _("Move down"), '', $registry->getImageDir('horde'))
-                . '</a></div>'
-            . '<script type="text/javascript">' . "\n"
-            . sprintf('%1$s = new Horde_Form_Sorter(\'%1$s\', \'%2$s\', \'%3$s\');' . "\n",
-                    $instance, $varname, $var->type->header)
-            . sprintf("%s.setHidden();\n</script>\n", $instance);
-    }
-
-    function _renderVarInput_assign($form, $var, $vars)
-    {
-        global $registry;
-
-        Horde::addScriptFile('form_assign.js', 'horde', true);
-
-        $name = $var->getVarName();
-        $fname = $form->getName() . '.' . $name;
-        $width = $var->type->width;
-        $lhdr = (bool)$var->type->getHeader(0);
-        $rhdr = (bool)$var->type->getHeader(1);
-        $this->_onLoadJS[] = 'Horde_Form_Assign.setField(\'' . $fname . '\');';
-
-        $html = '<div class="form-input-assign">'
-             . '    <input type="hidden" name="' . $name . '__values" id="' . $name . '__values" />'
-             . sprintf('    <select name="%1$s__left" id="%1$s__left" multiple="multiple" '
-                         .'size="%2$d" style="width:%3$s"%4$s>',
-                     $name, $var->type->size, $width,
-                     $lhdr ? ' onchange="Horde_Form_Assign.deselectHeaders(\'' . $fname . '\', 0);"' : '')
-             . $var->type->getOptions(0, $fname)
-             . '    </select>'
-             . '<div><a href="" onclick="Horde_Form_Assign.move(\''. $fname .'\', 0); return false;">'
-             . Horde::img('rhand.png', _("Add column"), null, $registry->getImageDir('horde'))
-             . '</a><br /><a href="" onclick="Horde_Form_Assign.move(\''
-             . $fname . '\', 1); return false;">'
-             . Horde::img('lhand.png', _("Remove column"), null, $registry->getImageDir('horde'))
-             . '</a></div>'
-             . sprintf('    <select name="%s__right" multiple="multiple" size="%d" style="width:%s"%s>',
-                     $name, $size, $width,
-                     $rhdr ? ' onchange="Horde_Form_Assign.deselectHeaders(\'' . $fname . '\', 1);"' : '')
-             . $var->type->getOptions(1, $fname)
-             . '    </select></div>';
-
-        return $html;
-    }
-
-    function _renderVarInput_invalid($form, $var, $vars)
-    {
-        return $this->_renderVarDisplay_invalid($form, $var, $vars);
-    }
-
-    function _renderVarInput_enum($form, $var, $vars)
-    {
-        $values = $var->getValues();
-        $prompt = $var->type->prompt;
-        $htmlchars = $var->getOption('htmlchars');
-        if ($prompt) {
-            $prompt = '<option value="">' . ($htmlchars ? htmlspecialchars($prompt, ENT_QUOTES, NLS::getCharset()) : $prompt) . '</option>';
-        }
-        return sprintf('    <select name="%1$s" id="%1$s"%2$s>%3$s%4$s    </select>',
-               $var->getVarName(),
-               $this->_getActionScripts($form, $var),
-               $prompt,
-               $this->_selectOptions($values, $var->getValue($vars), $htmlchars));
-    }
-
-    function _renderVarInput_mlenum($form, $var, $vars)
-    {
-        $varname = $var->getVarName();
-        $values = $var->getValues();
-        $prompts = $var->type->prompts;
-        $selected = $var->getValue($vars);
-
-        /* If passing a non-array value need to get the keys. */
-        if (!is_array($selected)) {
-            foreach ($values as $key_1 => $values_2) {
-                if (isset($values_2[$selected])) {
-                    $selected = array('1' => $key_1, '2' => $selected);
-                    break;
-                }
-            }
-        }
-
-        /* Hidden tag to store the current first level. */
-        $html = sprintf('    <input type="hidden" name="%1$s[old]" id="%1$s[old]" value="%2$s" />',
-                        $varname,
-                        htmlspecialchars($selected['1'], ENT_QUOTES, NLS::getCharset()));
-
-        /* First level. */
-        $values_1 = Horde_Array::valuesToKeys(array_keys($values));
-        $html .= sprintf('    <select id="%1$s[1]" name="%1$s[1]" onchange="%2$s"%3$s>',
-                         $varname,
-                         'if (this.value) { document.' . $form->getName() . '.formname.value=\'\';' . 'document.' . $form->getName() . '.submit() }',
-                         ($var->hasAction() ? ' ' . $this->_genActionScript($form, $var->_action, $varname) : ''));
-        if (!empty($prompts)) {
-            $html .= '<option value="">' . htmlspecialchars($prompts[0], ENT_QUOTES, NLS::getCharset()) . '</option>';
-        }
-        $html .= $this->_selectOptions($values_1, $selected['1']);
-        $html .= '    </select>';
-
-        /* Second level. */
-        $html .= sprintf('    <select id="%1$s[2]" name="%1$s[2]"%2$s>',
-                         $varname,
-                         ($var->hasAction() ? ' ' . $this->_genActionScript($form, $var->_action, $varname) : ''));
-        if (!empty($prompts)) {
-            $html .= '<option value="">' . htmlspecialchars($prompts[1], ENT_QUOTES, NLS::getCharset()) . '</option>';
-        }
-        $values_2 = array();
-        if (!empty($selected['1'])) {
-            $values_2 = $values[$selected['1']];
-        }
-        return $html . $this->_selectOptions($values_2, $selected['2']) . '    </select>';
-    }
-
-    function _renderVarInput_multienum($form, $var, $vars)
-    {
-        $values = $var->getValues();
-        $selected = $vars->getExists($var->getVarName(), $wasset);
-        if (!$wasset) {
-            $selected = $var->getDefault();
-        }
-        $html = sprintf('    <select multiple="multiple" size="%1$s" name="%2$s[]" id="%2$s[]" %3$s>%4$s    </select>',
-                        $var->type->size,
-                        $var->getVarName(),
-                        $this->_getActionScripts($form, $var),
-                        $this->_multiSelectOptions($values, $selected));
-        return $html . '<p class="form-hint">'
-            . _("To select multiple items, hold down the Control (PC) or Command (Mac) key while clicking.")
-            . "</p>\n";
-    }
-
-    function _renderVarInput_keyval_multienum($form, $var, $vars)
-    {
-        return $this->_renderVarInput_multienum($form, $var, $vars);
-    }
-
-    function _renderVarInput_radio($form, $var, $vars)
-    {
-        return $this->_radioButtons($var->getVarName(),
-                                    $var->getValues(),
-                                    $var->getValue($vars),
-                                    $this->_getActionScripts($form, $var));
-    }
-
-    function _renderVarInput_set($form, $var, $vars)
-    {
-        $html = $this->_checkBoxes($var->getVarName(),
-                                   $var->getValues(),
-                                   $var->getValue($vars),
-                                   $this->_getActionScripts($form, $var));
-
-        if ($var->type->checkAll) {
-            $form_name = $form->getName();
-            $var_name = $var->getVarName() . '[]';
-            $function_name = 'select'  . $form_name . $var->getVarName();
-            $enable = _("Select all");
-            $disable = _("Select none");
-            $invert = _("Invert selection");
-            $html .= <<<EOT
-<script type="text/javascript">
-function $function_name()
-{
-    for (var i = 0; i < document.$form_name.elements.length; i++) {
-        f = document.$form_name.elements[i];
-        if (f.name != '$var_name') {
-            continue;
-        }
-        if (arguments.length) {
-            f.checked = arguments[0];
-        } else {
-            f.checked = !f.checked;
-        }
-    }
-}
-</script>
-<a href="#" onclick="$function_name(true); return false;">$enable</a>,
-<a href="#" onclick="$function_name(false); return false;">$disable</a>,
-<a href="#" onclick="$function_name(); return false;">$invert</a>
-EOT;
-        }
-
-        return $html;
-    }
-
-    function _renderVarInput_link($form, $var, $vars)
-    {
-        return $this->_renderVarDisplay_link($form, $var, $vars);
-    }
-
-    function _renderVarInput_html($form, $var, $vars)
-    {
-        return $this->_renderVarDisplay_html($form, $var, $vars);
-    }
-
-    function _renderVarInput_email($form, $var, $vars)
-    {
-        return sprintf('    <input type="text" id="%1$s" name="%1$s" value="%2$s"%3$s />',
-               $var->getVarName(),
-               $value = $var->getValue($vars),
-               $this->_getActionScripts($form, $var));
-    }
-
-    function _renderVarInput_matrix($form, $var, $vars)
-    {
-        $varname   = $var->getVarName();
-        $var_array = $var->getValue($vars);
-        $cols      = $var->type->cols;
-        $rows      = $var->type->rows;
-        $matrix    = $var->type->matrix;
-        $new_input = $var->type->new_input;
-
-        $html = '<table cellspacing="0"><tr>';
-
-        $html .= '<td align="right" width="20%"></td>';
-        foreach ($cols as $col_title) {
-            $html .= sprintf('<td align="center" width="1%%">%s</td>', $col_title);
-        }
-        $html .= '<td align="right" width="60%"></td></tr>';
-
-        /* Offer a new row of data to be added to the matrix? */
-        if ($new_input) {
-            $html .= '<tr><td>'."\n";
-            if (is_array($new_input)) {
-                $html .= sprintf('    <select%s name="%s[n][r]"><option value="">%s</option>%s    </select><br />'."\n",
-                       ' id="'. $varname .'-n--r-"',
-                       $varname,
-                       _("-- select --"),
-                       $this->_selectOptions($new_input, $var_array['n']['r']));
-            } elseif ($new_input == true) {
-                $html .= sprintf('    <input%s type="text" name="%s[n][r]" value="%s" />',
-                       ' id="'. $varname .'-n--r-',
-                       $varname,
-                       $var_array['n']['r']);
-            }
-            $html .= ' </td>';
-            foreach ($cols as $col_id => $col_title) {
-                $html .= sprintf('<td align="center"><input type="checkbox" class="checkbox" name="%s[n][v][%s]" /></td>', $varname, $col_id);
-            }
-            $html .= '<td>&nbsp;</td></tr>'."\n";
-        }
-
-        /* Loop through the rows and create checkboxes for each column. */
-        foreach ($rows as $row_id => $row_title) {
-            $html .= sprintf('<tr><td>%s</td>', $row_title);
-            foreach ($cols as $col_id => $col_title) {
-                $html .= sprintf('<td align="center"><input type="checkbox" class="checkbox" name="%s[r][%s][%s]"%s /></td>', $varname, $row_id, $col_id, (!empty($matrix[$row_id][$col_id]) ? ' checked="checked"' : ''));
-            }
-            $html .= '<td>&nbsp;</td></tr>'."\n";
-        }
-
-        $html .= '</table>'."\n";
-        return $html;
-    }
-
-    function _renderVarInput_password($form, $var, $vars)
-    {
-        return sprintf('<input type="password" id="%1$s" name="%1$s" value="%2$s"%3$s />',
-               $var->getVarName(),
-               $value = $var->getValue($vars),
-               $this->_getActionScripts($form, $var));
-    }
-
-    function _renderVarInput_emailconfirm($form, $var, $vars)
-    {
-        $email = $var->getValue($vars);
-        return '<ul><li>' . sprintf('<input type="text" class="form-input-emailconfirm"' .
-                                    ' id="%1$s" name="%1$s[original]" value="%2$s"%3$s />',
-                                    $var->getVarName(),
-                                    $value = $email['original'],
-                                    $this->_getActionScripts($form, $var)) . '</li><li>' .
-            sprintf('<input type="text" class="form-input-emailconfirm"' .
-                    ' id="%1$s-confirm-" name="%1$s[confirm]" value="%2$s"%3$s />',
-                    $var->getVarName(),
-                    $value = $email['confirm'],
-                    $this->_getActionScripts($form, $var)) . '</li></ul>';
-    }
-
-    function _renderVarInput_passwordconfirm($form, $var, $vars)
-    {
-        $password = $var->getValue($vars);
-        return '<ul><li>' . sprintf('<input type="password" class="form-input-passwordconfirm"'
-                                    .' id="%1$s" name="%1$s[original]" value="%2$s"%3$s />',
-                                    $var->getVarName(),
-                                    $value = $password['original'],
-                                    $this->_getActionScripts($form, $var)) . '</li><li>' .
-            sprintf('<input type="password" class="form-input-passwordconfirm"'
-                    .' id="%1$s-confirm-" name="%1$s[confirm]" value="%2$s"%3$s />',
-                    $var->getVarName(),
-                    $value = $password['confirm'],
-                    $this->_getActionScripts($form, $var)) . '</li></ul>';
-    }
-
-    function _renderVarInput_boolean($form, $var, $vars)
-    {
-        $varName = $var->getVarName();
-
-        $html = '    <input type="checkbox" class="form-input-checkbox" id="' .  $varName . '"'
-            .  ' name="' .  $varName . '"'
-            . ($var->getValue($vars) ? ' checked="checked"' : '');
-        if ($var->hasAction()) {
-            $html .= $this->_genActionScript($form, $var->_action,
-                                             $var->getVarName());
-        }
-        $html .= ' />';
-        return $html;
-    }
-
-    function _renderVarInput_creditcard($form, $var, $vars)
-    {
-        $varName = $var->getVarName();
-
-        $html = '    <input type="text" class="form-input-creditcard" id="' .  $varName . '"'
-            .  ' name="' .  $varName . '"'
-            .$var->getValue($vars);
-        if ($var->hasAction()) {
-            $html .= $this->_genActionScript($form, $var->_action,
-                                             $var->getVarName());
-        }
-
-        return $html . ' />';
-    }
-
-    function _renderVarInput_obrowser($form, $var, $vars)
-    {
-        $varname = $var->getVarName();
-        $varvalue = $vars->get($varname);
-        $fieldId = 'obrowser_' . hash('md5', uniqid(rand(), true));
-        $html = '
-            <script type="text/javascript">
-            var obrowserWindowName;
-            function obrowserCallback(name, oid)
-            {
-                if (name == obrowserWindowName) {
-                    document.getElementById(\'' . $fieldId . '\').value = oid;
-                    return false;
-                } else {
-                    return "Invalid window name supplied";
-                }
-            }
-            </script>
-            ';
-        $html .= sprintf('<input type="hidden" name="%s" id="%s"%s value="%s" />',
-                         $varname,
-                         $fieldId,
-                         $this->_getActionScripts($form, $var),
-                         $varvalue);
-        if (!empty($varvalue)) {
-            $html .= $varvalue;
-        }
-
-        if ($GLOBALS['browser']->hasFeature('javascript')) {
-            Horde::addScriptFile('popup.js', 'horde', true);
-            $imgId = $varname .'goto';
-            $html .= '<div id="goto" class="headerbox"
-                    style="position:absolute;visibility:hidden;padding:0"></div>';
-            $html .= Horde::link('#', _("Select an object"), '', '', 'obrowserWindow = popup(\'' . $GLOBALS['registry']->get('webroot', 'horde') . '/services/obrowser/' . '\'); obrowserWindowName = obrowserWindow.name; return false;') . Horde::img('tree/leaf.png', _("Object"), 'id="' . $imgId . '" align="middle"', $GLOBALS['registry']->getImageDir('horde')) . "</a>\n";
-        }
-
-        return $html;
-    }
-
-    function _renderVarInput_dblookup($form, $var, $vars)
-    {
-        return $this->_renderVarInput_enum($form, $var, $vars);
-    }
-
-    function _renderVarInput_figlet($form, $var, $vars)
-    {
-        return sprintf('    <input type="text" class="form-input-figlet" id="%1$s" name="%1$s" size="%2$s" value="%3$s" />',
-                       $var->getVarName(),
-                       strlen($var->type->text),
-                       htmlspecialchars($var->getValue($vars))) .
-            '<p class="form-input-figlet">' . _("Enter the letters below:") . '</p>' .
-            $this->_renderVarDisplay_figlet($form, $var, $vars);
-    }
-
-    function _renderVarDisplayDefault($form, $var, $vars)
-    {
-        return nl2br(htmlspecialchars($var->getValue($vars), ENT_QUOTES,
-            NLS::getCharset()));
-    }
-
-    function _renderVarDisplay_html($form, $var, $vars)
-    {
-        return $var->getValue($vars);
-    }
-
-    function _renderVarDisplay_email($form, $var, $vars)
-    {
-        $display_email = $email = $var->getValue($vars);
-
-        if ($var->type->strip_domain && strpos($email, '@') !== false) {
-            $display_email = str_replace(array('@', '.'),
-                                         array(' (at) ', ' (dot) '),
-                                         $email);
-        }
-
-        if ($var->type->link_compose) {
-            $email_val = trim($email);
-
-            // Format the address according to RFC822.
-            $mailbox_host = explode('@', $email_val);
-            if (!isset($mailbox_host[1])) {
-                $mailbox_host[1] = '';
-            }
-
-            $name = $var->type->link_name;
-
-            require_once 'Horde/MIME.php';
-            $address = MIME::rfc822WriteAddress($mailbox_host[0], $mailbox_host[1], $name);
-
-            // Get rid of the trailing @ (when no host is included in
-            // the email address).
-            $address = str_replace('@>', '>', $address);
-            $mail_link = $GLOBALS['registry']->call('mail/compose', array(array('to' => addslashes($address))));
-            if (is_a($mail_link, 'PEAR_Error')) {
-                $mail_link = 'mailto:' . urlencode($address);
-            }
-
-            return Horde::link($mail_link, $email_val)
-                . htmlspecialchars($display_email) . '</a>';
-        } else {
-            return nl2br(htmlspecialchars($display_email, ENT_QUOTES, NLS::getCharset()));
-        }
-    }
-
-    function _renderVarDisplay_password($form, $var, $vars)
-    {
-        return '********';
-    }
-
-    function _renderVarDisplay_passwordconfirm($form, $var, $vars)
-    {
-        return '********';
-    }
-
-    function _renderVarDisplay_octal($form, $var, $vars)
-    {
-        return sprintf('0%o', octdec($var->getValue($vars)));
-    }
-
-    function _renderVarDisplay_boolean($form, $var, $vars)
-    {
-        return $var->getValue($vars) ? _("Yes") : _("No");
-    }
-
-    function _renderVarDisplay_enum($form, $var, $vars)
-    {
-        $values = $var->getValues();
-        $value = $var->getValue($vars);
-        if (count($values) == 0) {
-            return _("No values");
-        } elseif (isset($values[$value]) && $value != '') {
-            return htmlspecialchars($values[$value], ENT_QUOTES, NLS::getCharset());
-        }
-    }
-
-    function _renderVarDisplay_radio($form, $var, $vars)
-    {
-        $values = $var->getValues();
-        if (count($values) == 0) {
-            return _("No values");
-        } elseif (isset($values[$var->getValue($vars)])) {
-            return htmlspecialchars($values[$var->getValue($vars)], ENT_QUOTES, NLS::getCharset());
-        }
-    }
-
-    function _renderVarDisplay_multienum($form, $var, $vars)
-    {
-        $values = $var->getValues();
-        $on = $var->getValue($vars);
-        if (!count($values) || !count($on)) {
-            return _("No values");
-        } else {
-            $display = array();
-            foreach ($values as $value => $name) {
-                if (in_array($value, $on)) {
-                    $display[] = $name;
-                }
-            }
-            return htmlspecialchars(implode(', ', $display), ENT_QUOTES, NLS::getCharset());
-        }
-    }
-
-    function _renderVarDisplay_set($form, $var, $vars)
-    {
-        $values = $var->getValues();
-        $on = $var->getValue($vars);
-        if (!count($values) || !count($on)) {
-            return _("No values");
-        } else {
-            $display = array();
-            foreach ($values as $value => $name) {
-                if (in_array($value, $on)) {
-                    $display[] = $name;
-                }
-            }
-            return htmlspecialchars(implode(', ', $display), ENT_QUOTES, NLS::getCharset());
-        }
-    }
-
-    function _renderVarDisplay_image($form, $var, $vars)
-    {
-        $img_params = $var->getValue($vars);
-        $img_url = Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/images/view.php');
-        $img_url = Util::addParameter($img_url, $img_params);
-
-        return Horde::img($img_url, isset($img_params['f']) ? $img_params['f'] : '', '', '');
-    }
-
-    function _renderVarDisplay_phone($form, &$var, &$vars)
-    {
-        global $registry;
-
-        $number = $var->getValue($vars);
-        $html = htmlspecialchars($number, ENT_QUOTES, $this->_charset);
-
-        if ($number && $registry->hasMethod('telephony/dial')) {
-            $url = $registry->call('telephony/dial', array($number));
-            $label = sprintf(_("Dial %s"), $number);
-            $html .= ' ' . Horde::link($url, $label) . Horde::img('phone.png', $label, '', $registry->getImageDir('horde')) . '</a>';
-        }
-
-        return $html;
-    }
-
-    function _renderVarDisplay_cellphone($form, &$var, &$vars)
-    {
-        global $registry;
-
-        $html = $this->_renderVarDisplay_phone($form, $var, $vars);
-
-        $number = $var->getValue($vars);
-        if ($number && $registry->hasMethod('sms/compose')) {
-            $url = $registry->link('sms/compose', array('to' => $number));
-            $html .= ' ' . Horde::link($url, _("Send SMS")) . Horde::img('mobile.png', _("Send SMS"), '', $registry->getImageDir('horde')) . '</a>';
-        }
-
-        return $html;
-    }
-
-    function _renderVarDisplay_address($form, $var, $vars)
-    {
-        global $registry;
-
-        $address = $var->getValue($vars);
-
-        if (preg_match('/((?:A[BL]|B[ABDHLNRST]?|C[ABFHMORTVW]|D[ADEGHLNTY]|E[CHNX]?|F[KY]|G[LUY]?|H[ADGPRSUX]|I[GMPV]|JE|K[ATWY]|L[ADELNSU]?|M[EKL]?|N[EGNPRW]?|O[LX]|P[AEHLOR]|R[GHM]|S[AEGKLMNOPRSTWY]?|T[ADFNQRSW]|UB|W[ACDFNRSV]?|YO|ZE)\d(?:\d|[A-Z])? \d[A-Z]{2})/', $address, $postcode)) {
-            /* UK postcode detected. */
-            /* Multimap.co.uk generated map */
-            $mapurl = 'http://www.multimap.com/map/browse.cgi?pc=' . urlencode($postcode[1]);
-            $desc = _("Multimap UK map");
-            $icon = 'map.png';
-        } elseif (preg_match('/ACT|NSW|NT|QLD|SA|TAS|VIC|WA/', $address)) {
-            /* Australian state detected. */
-            /* Whereis.com.au generated map */
-            $mapurl = 'http://www.whereis.com.au/whereis/mapping/geocodeAddress.do?';
-            $desc = _("Whereis Australia map");
-            $icon = 'map.png';
-            /* Split out the address, line-by-line. */
-            $addressLines = explode("\n", $address);
-            for ($i = 0; $i < count($addressLines); $i++) {
-                /* See if it's the street number & name. */
-                if (preg_match('/(\d+\s*\/\s*)?(\d+|\d+[a-zA-Z])\s+([a-zA-Z ]*)/', $addressLines[$i], $lineParts)) {
-                    $mapurl .= '&streetNumber=' . urlencode($lineParts[2]);
-                    $mapurl .= '&streetName=' . urlencode($lineParts[3]);
-                }
-                /* Look for "Suburb, State". */
-                if (preg_match('/([a-zA-Z ]*),?\s+' . $aus_state_regexp . '/', $addressLines[$i], $lineParts)) {
-                    $mapurl .= '&suburb=' . urlencode($lineParts[1]);
-                }
-                /* Look for "State <4 digit postcode>". */
-                if (preg_match('/(' . $aus_state_regexp . ')\s+(\d{4})/', $addressLines[$i], $lineParts)) {
-                    $mapurl .= '&state=' . urlencode($lineParts[1]);
-                }
-            }
-        } elseif (preg_match('/(.*)\n(.*)\s*,\s*(\w+)\.?\s+(\d+|[a-zA-Z]\d[a-zA-Z]\s?\d[a-zA-Z]\d)/', $address, $addressParts)) {
-            /* American/Canadian address style. */
-            /* Mapquest generated map */
-            $mapurl = 'http://www.mapquest.com/maps/map.adp?size=big&zoom=7';
-            $desc = _("MapQuest map");
-            $icon = 'map.png';
-            $country = null;
-            if (!empty($addressParts[4]) && preg_match('|[a-zA-Z]\d[a-zA-Z]\s?\d[a-zA-Z]\d|', $addressParts[4])) {
-                $country = 'CA';
-            }
-            if (!empty($addressParts[1])) {
-                $mapurl .= '&address=' . urlencode($addressParts[1]);
-            }
-            if (!empty($addressParts[2])) {
-                $mapurl .= '&city=' . urlencode($addressParts[2]);
-            }
-            if (!empty($addressParts[3])) {
-                $mapurl .= '&state=' . urlencode($addressParts[3]);
-            }
-            if (!empty($addressParts[4])) {
-                if ($country == 'CA') {
-                    $mapurl .= '&country=CA';
-                }
-                $mapurl .= '&zipcode=' . urlencode($addressParts[4]);
-            }
-
-            /* Yahoo! generated map. */
-            $mapurl2 = 'http://us.rd.yahoo.com/maps/home/submit_a/*-http://maps.yahoo.com/maps?srchtype=a&getmap=Get+Map&';
-            $desc2 = _("Yahoo! map");
-            $icon2 = 'map.png';
-            if (!empty($addressParts[1])) {
-                $mapurl2 .= '&addr=' . urlencode($addressParts[1]);
-            }
-            /* Give precedence to zipcode over city/state */
-            if (empty($addressParts[4]) && !empty($addressParts[2]) && !empty($addressParts[3])) {
-                $mapurl2 .= '&csz=' . urlencode($addressParts[2] . ' ' . $addressParts[3]);
-            }
-            if (!empty($addressParts[4])) {
-                if (preg_match('|([a-zA-Z]\d[a-zA-Z])\s?(\d[a-zA-Z]\d)|', $addressParts[4], $pcParts)) {
-                    $mapurl2 .= '&country=ca';
-                    /* make sure the postal-code has a space */
-                    $addressParts[4] = $pcParts[1] . ' ' . $pcParts[2];
-                }
-                $mapurl2 .= '&csz=' . urlencode($addressParts[4]);
-            }
-
-            /* Google generated map. */
-            $mapurl3 = 'http://maps.google.com/maps?q=' . urlencode($addressParts[0]) . '&hl=en';
-            $desc3 = _("Google Maps");
-            $icon3 = 'map.png';
-
-        } elseif (preg_match('/(.*?)\r?\n([A-Z]{1,3})-(\d{5})\s+(.*)/i', $address, $addressParts)) {
-            /* European address style. */
-            include 'Horde/NLS/carsigns.php';
-            $country = array_search(String::upper($addressParts[2]), $carsigns);
-
-            /* Map24 generated map. */
-            if (in_array($country, array('al', 'ad', 'am', 'az', 'be', 'ba',
-                                         'bg', 'de', 'dk', 'ee', 'fo', 'fi',
-                                         'fr', 'ge', 'gr', 'gb', 'ie', 'is',
-                                         'it', 'hr', 'lv', 'li', 'lt', 'lu',
-                                         'mt', 'mk', 'md', 'mc', 'nl', 'no',
-                                         'pl', 'pt', 'ro', 'ru', 'se', 'ch',
-                                         'cs', 'sk', 'si', 'es', 'cz', 'tr',
-                                         'ua', 'hu', 'by', 'cy', 'at'))) {
-                if (in_array($country, array('at', 'be', 'ch', 'de', 'dk',
-                                             'es', 'fi', 'fr', 'it', 'nl',
-                                             'no', 'se'))) {
-                    $mirror = $country;
-                } else {
-                    $mirror = 'uk';
-                }
-                $mapurl = 'http://www.' . $mirror . '.map24.com/source/address/v2.0.0/cnt_nav_maplet.php?cid=validateaddr&country=' . $country;
-                $desc = _("Map24 map");
-                $icon = 'map_eu.png';
-                if (!empty($addressParts[1])) {
-                    $mapurl .= '&street=' . urlencode($addressParts[1]);
-                }
-                if (!empty($addressParts[3])) {
-                    $mapurl .= '&zip=' . urlencode($addressParts[3]);
-                }
-                if (!empty($addressParts[4])) {
-                    $mapurl .= '&city=' . urlencode($addressParts[4]);
-                }
-            }
-
-            /* Mapquest generated map. */
-            $mapurl2 = 'http://www.mapquest.com/maps/map.adp?country=' . String::upper($country);
-            $desc2 = _("MapQuest map");
-            $icon2 = 'map_eu.png';
-            if (!empty($addressParts[1])) {
-                $mapurl2 .= '&address=' . urlencode($addressParts[1]);
-            }
-            if (!empty($addressParts[3])) {
-                $mapurl2 .= '&zipcode=' . urlencode($addressParts[3]);
-            }
-            if (!empty($addressParts[4])) {
-                $mapurl2 .= '&city=' . urlencode($addressParts[4]);
-            }
-        }
-
-        $html = nl2br(htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()));
-        if (!empty($mapurl)) {
-            $html .= '&nbsp;&nbsp;' . Horde::link(Horde::externalUrl($mapurl), $desc, null, '_blank') . Horde::img($icon, $desc, '', $registry->getImageDir('horde')) . '</a>';
-        }
-        if (!empty($mapurl2)) {
-            $html .= '&nbsp;' . Horde::link(Horde::externalUrl($mapurl2), $desc2, null, '_blank') . Horde::img($icon2, $desc2, '', $registry->getImageDir('horde')) . '</a>';
-        }
-        if (!empty($mapurl3)) {
-            $html .= '&nbsp;' . Horde::link(Horde::externalUrl($mapurl3), $desc3, null, '_blank') . Horde::img($icon3, $desc3, '', $registry->getImageDir('horde')) . '</a>';
-        }
-
-        return $html;
-    }
-
-    function _renderVarDisplay_date($form, $var, $vars)
-    {
-        return $var->type->getFormattedTime($var->getValue($vars));
-    }
-
-    function _renderVarDisplay_monthyear($form, $var, $vars)
-    {
-        return $vars->get($var->getVarName() . '[month]') . ', ' . $vars->get($var->getVarName() . '[year]');
-    }
-
-    function _renderVarDisplay_monthdayyear($form, $var, $vars)
-    {
-        $date = $var->getValue($vars);
-        if ((is_array($date) && !empty($date['year']) &&
-             !empty($date['month']) && !empty($date['day']))
-            || (!is_array($date) && !empty($date))) {
-            return $var->type->formatDate($date);
-        }
-        return '';
-    }
-
-    function _renderVarDisplay_invalid($form, $var, $vars)
-    {
-        return '<p class="form-error form-inline">'
-                . htmlspecialchars($var->type->message, ENT_QUOTES, NLS::getCharset())
-                . '</p>';
-    }
-
-    function _renderVarDisplay_link($form, $var, $vars)
-    {
-        $values = $var->getValues();
-        if (!isset($values[0])) {
-            $values = array($values);
-        }
-
-
-        $count = count($values);
-        $html = '';
-        for ($i = 0; $i < $count; $i++) {
-            if (empty($values[$i]['url']) || empty($values[$i]['text'])) {
-                continue;
-            }
-            if (!isset($values[$i]['target'])) {
-                $values[$i]['target'] = '';
-            }
-            if (!isset($values[$i]['onclick'])) {
-                $values[$i]['onclick'] = '';
-            }
-            if (!isset($values[$i]['title'])) {
-                $values[$i]['title'] = '';
-            }
-            if (!isset($values[$i]['accesskey'])) {
-                $values[$i]['accesskey'] = '';
-            }
-            if ($i > 0) {
-                $html .= ' | ';
-            }
-            $html .= Horde::link($values[$i]['url'], $values[$i]['text'],
-                        'widget', $values[$i]['target'], $values[$i]['onclick'],
-                        $values[$i]['title'], $values[$i]['accesskey'])
-                    . $values[$i]['text'] . '</a>';
-        }
-
-        return $html;
-    }
-
-    function _renderVarDisplay_dblookup($form, $var, $vars)
-    {
-        return $this->_renderVarDisplay_enum($form, $var, $vars);
-    }
-
-    function _renderVarDisplay_figlet($form, $var, $vars)
-    {
-        $figlet = new Text_Figlet();
-        $result = $figlet->loadFont($var->type->font);
-        if (is_a($result, 'PEAR_Error')) {
-            return $result->getMessage();
-        }
-
-        return '<pre>' . $figlet->lineEcho($var->type->text) . '</pre>';
-    }
-
-    function _renderVarInput_selectFiles($form, $var, $vars)
-    {
-        /* Needed for gollem js calls */
-        $html = sprintf('<input type="hidden" id="%1$s" name="%1$s" value="%2$s" />',
-                        'selectlist_selectid',
-                        $var->type->selectid)
-            . sprintf('<input type="hidden" id="%1$s" name="%1$s" />', 'actionID');
-
-        /* Form field. */
-        $html .= sprintf('<input type="hidden" id="%1$s" name="%1$s" value="%2$s" />',
-                         $var->getVarName(),
-                         $var->type->selectid);
-
-        /* Open window link. */
-        $param = array($var->type->link_text,
-                       $var->type->link_style,
-                       $form->getName(),
-                       $var->type->icon,
-                       $var->type->selectid);
-        $html .= "<p>\n" . $GLOBALS['registry']->call('files/selectlistLink', $param) . "</p>\n";
-
-        if ($var->type->selectid) {
-            $param = array($var->type->selectid);
-            $files = $GLOBALS['registry']->call('files/selectlistResults', $param);
-            if ($files) {
-                $html .= '<ol>';
-                foreach ($files as $id => $file) {
-                    $dir = key($file);
-                    $filename = current($file);
-                    if ($GLOBALS['registry']->hasMethod('files/getViewLink')) {
-                        $filename = basename($filename);
-                        $url = $GLOBALS['registry']->call('files/getViewLink', array($dir, $filename));
-                        $filename = Horde::link($url, _("Preview"), null, 'form_file_view') . htmlspecialchars(Util::realPath($dir . '/' . $filename), ENT_QUOTES, $this->_charset) . '</a>';
-                    } else {
-                        if (!empty($dir) && ($dir != '.')) {
-                            $filename = $dir . '/' . $filename;
-                        }
-                        $filename = htmlspecialchars($filename, ENT_QUOTES, $this->_charset);
-                    }
-                    $html .= '<li>' . $filename . "</li>\n";
-                }
-                $html .= '</ol>';
-            }
-        }
-
-        return $html;
-    }
-
-    function _selectOptions($values, $selectedValue = false, $htmlchars = true)
-    {
-        $result = '';
-        $sel = false;
-        foreach ($values as $value => $display) {
-            if (!is_null($selectedValue) && !$sel && $value == $selectedValue
-                && strlen($value) == strlen($selectedValue)) {
-                $selected = ' selected="selected"';
-                $sel = true;
-            } else {
-                $selected = '';
-            }
-            $result .= '        <option value="';
-            $result .= ($htmlchars) ? htmlspecialchars($value, ENT_QUOTES, NLS::getCharset()) : $value;
-            $result .= '"' . $selected . '>';
-            $result .= ($htmlchars) ? htmlspecialchars($display) : $display;
-            $result .= "</option>\n";
-        }
-
-        return $result;
-    }
-
-    function _multiSelectOptions($values, $selectedValues)
-    {
-        $result = '';
-        $sel = false;
-        foreach ($values as $value => $display) {
-            if (@in_array($value, $selectedValues)) {
-                $selected = ' selected="selected"';
-            } else {
-                $selected = '';
-            }
-            $result .= " <option value=\""
-                . htmlspecialchars($value, ENT_QUOTES, NLS::getCharset())
-                . "\"$selected>" . htmlspecialchars($display) . "</option>\n";
-        }
-
-        return $result;
-    }
-
-    function _checkBoxes($name, $values, $checkedValues, $actions = '')
-    {
-        $result = '';
-        if (!is_array($checkedValues)) {
-            $checkedValues = array();
-        }
-
-        if (count($values) > 0) {
-            $result .= "    <ul>\n";
-        }
-
-        $i = 0;
-        foreach ($values as $value => $display) {
-            $checked = in_array($value, $checkedValues) ? ' checked="checked"' : '';
-            $result .= sprintf('        <li>'
-                                .'<input id="%1$s%2$s" type="checkbox"'
-                                    .' class="form-input-checkbox" name="%1$s[]"'
-                                    .' value="%3$s"%4$s%5$s />'
-                                .'&nbsp;<label class="form-inline" for="%1$s%2$s">'
-                                    .'%6$s</label></li>'."\n",
-                            $name,
-                            $i,
-                            $value,
-                            $checked,
-                            $actions,
-                            $display);
-            $i++;
-        }
-
-        if (count($values) > 0) {
-            $result .= "    </ul>";
-        }
-
-
-        return $result;
-    }
-
-    function _radioButtons($name, $values, $checkedValue = null, $actions = '')
-    {
-        $result = '';
-
-        if (count($values) > 0) {
-            $result .= "    <ul>\n";
-        }
-
-        $i = 0;
-        foreach ($values as $value => $display) {
-            $checked = (!is_null($checkedValue) && $value == $checkedValue) ? ' checked="checked"' : '';
-            $result .= sprintf('        <li>'
-                                .'<input id="%1$s%2$s" type="radio"'
-                                    .' class="form-input-checkbox" name="%1$s"'
-                                    .' value="%3$s"%4$s%5$s />'
-                                .'&nbsp;<label class="form-inline" for="%1$s%2$s">'
-                                    .'%6$s</label></li>'."\n",
-                            $name,
-                            $i,
-                            $value,
-                            $checked,
-                            $actions,
-                            $display);
-            $i++;
-        }
-
-        if (count($values) > 0) {
-            $result .= "    </ul>";
-        }
-
-        return $result;
-    }
-
-    /**
-     *
-     * @access private
-     * @author ?
-     * @deprecated
-     */
-    function _genID($name, $fulltag = true)
-    {
-        return $fulltag ? 'id="' . htmlspecialchars($name) . '"' : $name;
-    }
-
-    /**
-     * Returns script for an rendered variable. TODO: make this unobtrusive.
-     *
-     * @access private
-     * @author ?
-     * @return string html representing an attribute with action script as value,
-     *         or and empty string, if the action is to happen window.onload
-     */
-    function _genActionScript($form, $action, $varname)
-    {
-        $html = '';
-        $triggers = $action->getTrigger();
-        if (!is_array($triggers)) {
-            $triggers = array($triggers);
-        }
-        $js = $action->getActionScript($form, $this, $varname);
-        foreach ($triggers as $trigger) {
-            if ($trigger == 'onload') {
-                $this->_onLoadJS[] = $js;
-            } else {
-                $html .= ' ' . $trigger . '="' . $js . '"';
-            }
-        }
-        return $html;
-    }
-
-    /**
-     * Returns scripts for an rendered variable. TODO: make this unobtrusive.
-     *
-     * @access private
-     * @author ?
-     * @return string html representing attributes with action script as values,
-     *         or and empty string, if the actions are all to happen window.onload
-     */
-    function _getActionScripts($form, $var)
-    {
-        $actions = '';
-        if ($var->hasAction()) {
-            $varname = $var->getVarName();
-            $action = &$var->_action;
-            $triggers = $action->getTrigger();
-            if (!is_array($triggers)) {
-                $triggers = array($triggers);
-            }
-            $js = $action->getActionScript($form, $this, $varname);
-            foreach ($triggers as $trigger) {
-                if ($trigger == 'onload') {
-                    $this->_onLoadJS[] = $js;
-                } else {
-                    $actions .= ' ' . $trigger . '="' . $js . '"';
-                }
-            }
-        }
-        return $actions;
-    }
-
-}
diff --git a/framework/Form/www/js/maxlength.js b/framework/Form/www/js/maxlength.js
deleted file mode 100644 (file)
index 200ab8e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* http://www.quirksmode.org/dom/maxlength.html */
-
-/*
-<textarea id="text" name="text" maxlength="1500"></textarea>
-*/
-
-
-function setMaxLength()
-{
-       var x = document.getElementsByTagName('textarea');
-       var counter = document.createElement('div');
-       counter.className = 'counter';
-       for (var i=0;i<x.length;i++)
-       {
-               if (x[i].getAttribute('maxlength'))
-               {
-                       var counterClone = counter.cloneNode(true);
-                       counterClone.relatedElement = x[i];
-                       counterClone.innerHTML = '<span>0</span>/'+x[i].getAttribute('maxlength');
-                       x[i].parentNode.insertBefore(counterClone,x[i].nextSibling);
-                       x[i].relatedElement = counterClone.getElementsByTagName('span')[0];
-
-                       x[i].onkeyup = x[i].onchange = checkMaxLength;
-                       x[i].onkeyup();
-               }
-       }
-}
-
-function checkMaxLength()
-{
-       var maxLength = this.getAttribute('maxlength');
-       var currentLength = this.value.length;
-       if (currentLength > maxLength)
-               this.relatedElement.className = 'toomuch';
-       else
-               this.relatedElement.className = '';
-       this.relatedElement.firstChild.nodeValue = currentLength;
-       // not innerHTML
-}
diff --git a/framework/Form/www/test.php b/framework/Form/www/test.php
deleted file mode 100644 (file)
index 8267f25..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-/**
- * Incubator Horde_Form rewrite example page.
- *
- * The initial Horde_Form xhtml rewrite was supported by Google SoC
- * 2005.
- *
- * $Horde: incubator/Horde_Form/test.php,v 1.25 2008/09/02 17:43:09 chuck Exp $
- */
-
-@define('HORDE_BASE', dirname(__FILE__) . '/../..');
-@define('INCUBATOR_BASE', dirname(__FILE__));
-
-require_once HORDE_BASE . '/lib/core.php';
-require_once 'Horde/Variables.php';
-require_once 'Horde/Autoloader.php';
-Horde_Autoloader::addClassPath(dirname(__FILE__));
-$registry = Registry::singleton();
-$vars = Variables::getDefaultVariables();
-
-$vars->set('example_bar', 'text with a beginning and an end');
-$form = new Horde_Form($vars, 'Horde_Form Test');
-
-$choices = array('big' => 'BIG',
-                 'small' => 'small',
-                 'other' => 'Other');
-$form->add('condchoices', 'Enum', _("Select something"), '', true, false, array($choices, true));
-
-$o = $form->add('other_text', 'String', _("If other, please describe"), '', false);
-$params = array('target' => 'condchoices',
-                'enabled' => true,
-                'values' => array('other'));
-$o->setAction(new Horde_Form_Action_ConditionalEnable($params));
-
-$form->add('color', 'Color', _("Color"), null, false);
-
-$vars->set('form', 'add');
-$enum = array('' => _("Select:"),
-              1 => _("Yes"),
-              0 => _("No"));
-$form->add('opciones', 'Enum', _("Simple description"), '', true, false, array($enum));
-$form->add('bool', 'Boolean', _("Boolean"));
-$form->add('number', 'Int', _("Integer"));
-$form->add('mybday', 'date', _("A Date"), '', false);
-$form->addHidden('form', 'String', true);
-$unamevar = $form->add('user_name', 'String', _("Username"));
-$form->add('password', 'password', _("Password"));
-$form->addHidden('example_hidden', 'int', false);
-$form->add('some_text', 'String', _("Insert some text"), _("Insert some text in this box"), false);
-$choices = array('big' => 'BIG',
-                 'small' => 'small',
-                 'mixed' => 'mIxED');
-$form->add('choices', 'enum', _("Select something2"), 'Use the selection box to make your choice', true, false, array($choices, true));
-$form->add('email_address', 'email', _("Email"));
-$form->add('email_address2', 'emailconfirm', _("Email2"));
-$form->add('a_creditcard', 'creditcard', _("Credit Card"));
-$form->add('a_password', 'password', _("Password"));
-$form->add('a_password2', 'passwordconfirm', _("Password with confirmation"), _("type the password twice to confirm"));
-$form->add('a_octal', 'Octal', _("Octal"), false);
-$form->add('a_radiogroup', 'set', _("Radio Group"), '', true, false, array($choices));
-
-$t = $form->add('example_bar', 'String', _("Bar field"), _("You have to fill in some long text here"), true, false, array(4, 40));
-$t->setAction(new Horde_Form_Action_setcursorpos(array(4)));
-
-$form->add('a_checkboxgroup', 'set', _("Checkbox Group"), '', false, false, array($choices));
-//$form->add('a_obrowser', 'obrowser', _("obrowser"));
-
-?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-<title>Incubator Horde_Form Test</title>
-<link rel="stylesheet" type="text/css" href="themes/form.css" />
-<script type="text/javascript" src="<?=$registry->get('jsuri', 'horde')?>/horde.js"></script>
-<script type="text/javascript" src="<?=$registry->get('jsuri', 'horde')?>/form_helpers.js"></script>
-</head>
-<body>
-<?php
-if ($form->validate()) {
-    $form->getInfo($info);
-    echo 'You have submitted:<br /><pre>';
-    var_dump($info);
-    echo '</pre>';
-}
-
-/* Render the form. */
-$renderer = new Horde_Form_Renderer_Xhtml;
-$renderer->setButtons(_("Add user"), _("Reset"));
-$renderer->renderActive($form, 'test.php', 'post');
-
-?>
-</body>
-</html>
diff --git a/framework/Form/www/themes/form.css b/framework/Form/www/themes/form.css
deleted file mode 100644 (file)
index 0c3ae39..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-form.horde-form {
-    font-size: 100%;
-    font-weight: normal;
-}
-
-form.horde-form input[type="text"], form.horde-form input[type="password"],
-form.horde-form select, form.horde-form textarea {
-    width: 130px;
-    margin: .2em 0 .1em .1em;
-}
-
-form.horde-form input[type="text"], form.horde-form input[type="password"], form.horde-form textarea {
-    padding: .1em;
-}
-
-.clear {
-    clear: both;
-}
-
-.horde-form fieldset {
-    padding: .5em;
-    margin: 0;
-    border: 1px solid #ccc;
-}
-
-.horde-form fieldset.form-buttons {
-    color: #000;
-    background: #ccc;
-    border: 1px solid #aaa;
-}
-
-fieldset legend {
-    color: #000;
-    background: #ccc;
-    padding: .5em;
-    margin-bottom: -1em;
-    border: 1px solid #999;
-    border-bottom: none;
-    font-weight: bold;
-}
-
-fieldset.form-section {
-    padding: .5em;
-    margin: .5em 0;
-}
-
-.form-button, .form-button-upload {
-    font-size: 90%;
-}
-
-.form-colorpicker {
-    float: left;
-}
-.form-colorpicker img {
-    border: 0;
-    padding: 0;
-    margin: 2px;
-    height: 16px;
-    width: 16px;
-}
-.form-colorpicker input {
-    width: 100px;
-    clear: none;
-}
-.form-colorpicker-palette {
-    display: none;
-    margin: 2px;
-}
-
-.form-description {
-    padding: 8px;
-}
-
-.form-error, .form-error-example {
-    color: #f00;
-}
-
-p.form-error {
-    background-color: #f00;
-    color: #fff;
-    padding: 3px;
-    border: 1px solid #000;
-    margin: auto 70px;
-}
-
-div.form-error {
-    background-color: #ffffe1;
-    background-image: url("graphics/required.png");
-    background-repeat: no-repeat;
-    background-position: top left;
-    color: #000;
-}
-
-.form-hint {
-    display: block;
-    margin: 0 0 5px 142px;
-    padding: 1px 3px;
-    font-size: 88%;
-}
-
-.form-header {
-    vertical-align: bottom;
-    font-weight: bold;
-}
-
-.form-image-preview-blank {
-    width: 50px;
-    height: 40px;
-    vertical-align: top;
-}
-
-.form-inline {
-    display: inline;
-}
-
-.form-input {
-    vertical-align: top;
-    clear: both;
-    padding: 4px;
-    margin: 2px 0;
-}
-
-.form-input label {
-    vertical-align: top;
-    text-align: right;
-    float: left;
-    clear: left;
-    display: block;
-    width: 10em;
-    padding: 0.3em;
-}
-
-.form-input label.form-inline {
-    float: none;
-    width: auto;
-    display: inline;
-}
-
-.form-input ul, .form-input ol {
-    list-style-type: none;
-    display: block;
-    float: left;
-}
-
-.form-input ul, .form-input ol, .form-input li {
-    margin-top: 0;
-    margin-left: 0;
-    padding-top: 0;
-    padding-left: 0;
-}
-.form-input ul {
-    margin-bottom: .5em;
-}
-
-.form-input-address {
-}
-
-.form-input-assign {
-}
-
-.form-input-assign select, .form-input-assign div {
-    display: inline;
-    clear: none;
-}
-
-.form-input-checkbox {
-    border: 0;
-    height: 14px;
-    width: 14px;
-    background: transparent;
-}
-
-.form-input-text, .form-input-intlist, .form-input-octal, .form-input-int,
-.form-input-number, .form-input-phone, .form-input-file {
-    width: 100px;
-}
-
-.form-input-resize {
-    width: 25px;
-}
-
-.form-input-stringlist {
-    width: 150px;
-}
-
-.form-input-time {
-    width: 30px;
-}
-
-.form-note {
-    clear: left;
-    width: 130px;
-    height: auto;
-    padding: .3em;
-    margin: 0 0 0 10.7em;
-    border: 1px solid #666;
-    background-color: #ffc;
-}
-.form-note p {
-    margin: 0;
-    padding: 0;
-    font-style: italic;
-    font-size: 70%;
-}
-
-.form-required {
-    background: url("graphics/required.png") .5em .5em no-repeat;
-}
-
-.form-required label {
-    font-weight: bold;
-}
-
-.form-sectionhidden {
-    position: absolute;
-    left: 0;
-    top: -500px;
-    width: 1px;
-    height: 1px;
-    overflow: hidden;
-    display: block;
-}
-
-.form-sectionshown {
-    display: block;
-}
-
-.form-spacer {
-    padding: .9em;
-}
-
-.rowEven {
-    background-color: #eef;
-}
-.rowOdd {
-    background-color: #fff;
-}
-
-/* Form styles. */
-.htmlarea .statusBar .statusBarTree a {
-    font: inherit;
-}
-.htmlarea table {
-    width: auto;
-}
-input, select {
-}
-input {
-    padding: 1px;
-}
-option {
-    padding: 0 5px 0 3px;
-}
-
-.button {
-    font-size: 90%;
-}
-a.button {
-    padding: 2px;
-    font-weight: normal;
-    text-decoration: none;
-}
diff --git a/framework/Form/www/themes/graphics/required.png b/framework/Form/www/themes/graphics/required.png
deleted file mode 100644 (file)
index 1756362..0000000
Binary files a/framework/Form/www/themes/graphics/required.png and /dev/null differ
diff --git a/framework/Model/lib/Horde/Form.php b/framework/Model/lib/Horde/Form.php
new file mode 100644 (file)
index 0000000..37bdd9a
--- /dev/null
@@ -0,0 +1,3946 @@
+<?php
+/**
+ * @package Horde_Form
+ */
+
+/** String */
+include_once 'Horde/String.php';
+
+/**
+ * Horde_Form Master Class.
+ *
+ * The Horde_Form:: package provides form rendering, validation, and
+ * other functionality for the Horde Application Framework.
+ *
+ * $Horde: incubator/Horde_Form/Horde/Form.php,v 1.19 2008/08/26 15:32:55 selsky Exp $
+ *
+ * Copyright 2001-2007 Robert E. Coyle <robertecoyle@hotmail.com>
+ * Copyright 2001-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+ * @author  Chuck Hagenbuch <chuck@horde.org>
+ * @since   Horde 3.0
+ * @package Horde_Form
+ */
+class Horde_Form {
+
+    protected $_name = '';
+    protected $_title = '';
+    protected $_vars;
+    protected $_errors = array();
+    protected $_submitted = null;
+    protected $_sections = array();
+    protected $_open_section = null;
+    protected $_currentSection = array();
+    protected $_variables = array();
+    protected $_hiddenVariables = array();
+    protected $_useFormToken = true;
+    protected $_autofilled = false;
+    protected $_help = false;
+
+    public function __construct($vars, $title = '', $name = null)
+    {
+        if (is_null($name)) {
+            $name = String::lower(get_class($this));
+        }
+
+        $this->_vars = $vars;
+        $this->_title = $title;
+        $this->_name = $name;
+    }
+
+    public function setVars($vars)
+    {
+        $this->_vars = $vars;
+    }
+
+    public function getVars()
+    {
+        return $this->_vars;
+    }
+
+    public function getTitle()
+    {
+        return $this->_title;
+    }
+
+    public function setTitle($title)
+    {
+        $this->_title = $title;
+    }
+
+    public function getName()
+    {
+        return $this->_name;
+    }
+
+    /**
+     * Sets or gets whether the form should be verified by tokens.
+     * Tokens are used to verify that a form is only submitted once.
+     *
+     * @param boolean $token  If specified, sets whether to use form tokens.
+     *
+     * @return boolean  Whether form tokens are being used.
+     */
+    public function useToken($token = null)
+    {
+        if (!is_null($token)) {
+            $this->_useFormToken = $token;
+        }
+        return $this->_useFormToken;
+    }
+
+    /**
+     * Get the renderer for this form, either a custom renderer or the
+     * standard one.
+     *
+     * To use a custom form renderer, your form class needs to
+     * override this function:
+     * <code>
+     * function getRenderer()
+     * {
+     *     return new CustomFormRenderer();
+     * }
+     * </code>
+     *
+     * ... where CustomFormRenderer is the classname of the custom
+     * renderer class, which should extend Horde_Form_Renderer.
+     *
+     * @param array $params  A hash of renderer-specific parameters.
+     *
+     * @return object Horde_Form_Renderer  The form renderer.
+     */
+    function getRenderer($params = array())
+    {
+        return new Horde_Form_Renderer_Xhtml($params);
+    }
+
+    function getType($type, $params = array())
+    {
+        $type_class = 'Horde_Form_Type_' . $type;
+        if (!class_exists($type_class)) {
+            Horde::fatal(PEAR::raiseError(sprintf('Nonexistant class "%s" for field type "%s"', $type_class, $type)), __FILE__, __LINE__);
+        }
+        $type_ob = new $type_class();
+        call_user_func_array(array(&$type_ob, 'init'), $params);
+        return $type_ob;
+    }
+
+    public function setSection($section = '', $desc = '', $image = '', $expanded = true)
+    {
+        $this->_currentSection = $section;
+        if (!count($this->_sections) && !$this->getOpenSection()) {
+            $this->setOpenSection($section);
+        }
+        $this->_sections[$section]['desc'] = $desc;
+        $this->_sections[$section]['expanded'] = $expanded;
+        $this->_sections[$section]['image'] = $image;
+    }
+
+    public function getSections()
+    {
+        return $this->_sections;
+    }
+
+    public function getSectionDesc($section)
+    {
+        return $this->_sections[$section]['desc'];
+    }
+
+    public function getSectionImage($section)
+    {
+        return $this->_sections[$section]['image'];
+    }
+
+    public function setOpenSection($section)
+    {
+        $this->_vars->set('__formOpenSection', $section);
+    }
+
+    public function getOpenSection()
+    {
+        return $this->_vars->get('__formOpenSection');
+    }
+
+    public function getSectionExpandedState($section, $boolean = false)
+    {
+        if ($boolean) {
+            /* Only the boolean value is required. */
+            return $this->_sections[$section]['expanded'];
+        }
+
+        /* Need to return the values for use in styles. */
+        if ($this->_sections[$section]['expanded']) {
+            return 'block';
+        } else {
+            return 'none';
+        }
+    }
+
+    /**
+     * TODO
+     */
+    public function addVariable($humanName, $varName, $type, $required,
+                                $readonly = false, $description = null,
+                                $params = array())
+    {
+        return $this->insertVariableBefore(null, $humanName, $varName, $type,
+                                           $required, $readonly, $description,
+                                           $params);
+    }
+
+    /**
+     * TODO
+     */
+    public function insertVariableBefore($before, $humanName, $varName, $type,
+                                         $required, $readonly = false,
+                                         $description = null, $params = array())
+    {
+        $type = $this->getType($type, $params);
+        $var = new Horde_Form_Variable($humanName, $varName, $type,
+                                       $required, $readonly, $description);
+
+        /* Set the form object reference in the var. */
+        $var->setFormOb($this);
+
+        if ($var->getType() instanceof Horde_Form_Type_enum &&
+            count($var->getValues()) == 1) {
+            $vals = array_keys($var->getValues());
+            $this->_vars->add($var->varName, $vals[0]);
+            $var->_autofilled = true;
+        }
+        if (empty($this->_currentSection)) {
+            $this->_currentSection = '__base';
+        }
+
+        if (is_null($before)) {
+            $this->_variables[$this->_currentSection][] = &$var;
+        } else {
+            $num = 0;
+            while (isset($this->_variables[$this->_currentSection][$num]) &&
+                   $this->_variables[$this->_currentSection][$num]->getVarName() != $before) {
+                $num++;
+            }
+            if (!isset($this->_variables[$this->_currentSection][$num])) {
+                $this->_variables[$this->_currentSection][] = &$var;
+            } else {
+                $this->_variables[$this->_currentSection] = array_merge(
+                    array_slice($this->_variables[$this->_currentSection], 0, $num),
+                    array(&$var),
+                    array_slice($this->_variables[$this->_currentSection], $num));
+            }
+        }
+
+        return $var;
+    }
+
+    /**
+     * Removes a variable from the form.
+     *
+     * As only variables can be passed by reference, you need to call this
+     * method this way if want to pass a variable name:
+     * <code>
+     * $form->removeVariable($var = 'varname');
+     * </code>
+     *
+     * @param Horde_Form_Variable|string $var  Either the variable's name or
+     *                                         the variable to remove from the
+     *                                         form.
+     *
+     * @return boolean  True if the variable was found (and deleted).
+     */
+    public function removeVariable(&$var)
+    {
+        foreach (array_keys($this->_variables) as $section) {
+            foreach (array_keys($this->_variables[$section]) as $i) {
+                if ((is_a($var, 'Horde_Form_Variable') && $this->_variables[$section][$i] === $var) ||
+                    ($this->_variables[$section][$i]->getVarName() == $var)) {
+                    // Slice out the variable to be removed.
+                    $this->_variables[$this->_currentSection] = array_merge(
+                        array_slice($this->_variables[$this->_currentSection], 0, $i),
+                        array_slice($this->_variables[$this->_currentSection], $i + 1));
+
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * TODO
+     */
+    public function addHidden($varName, $type, $required, $params = array())
+    {
+        $type = $this->getType($type, $params);
+        $var = new Horde_Form_Variable('', $varName, $type, $required);
+        $var->hide();
+        $this->_hiddenVariables[] = &$var;
+        return $var;
+    }
+
+    public function getVariables($flat = true, $withHidden = false)
+    {
+        if ($flat) {
+            $vars = array();
+            foreach ($this->_variables as $section) {
+                foreach ($section as $var) {
+                    $vars[] = $var;
+                }
+            }
+            if ($withHidden) {
+                foreach ($this->_hiddenVariables as $var) {
+                    $vars[] = $var;
+                }
+            }
+            return $vars;
+        } else {
+            return $this->_variables;
+        }
+    }
+
+    public function getHiddenVariables()
+    {
+        return $this->_hiddenVariables;
+    }
+
+    /**
+     * Preserve the variables/values from another Horde_Form object.
+     */
+    public function preserve(Horde_Form $form)
+    {
+        /* OLD IMPLEMENTATION
+        if ($this->_useFormToken) {
+            $this->_preserveVarByPost($this->_name . '_formToken', Horde_Token::generateId($this->_name));
+        }
+
+        $variables = $this->getVariables();
+        foreach ($variables as $var) {
+            $varname = $var->getVarName();
+
+            switch (get_class($var->getType()) {
+            case 'passwordconfirm':
+            case 'emailconfirm':
+                $this->preserveVarByPost($this->_vars, $varname . '[original]');
+                $this->preserveVarByPost($this->_vars, $varname . '[confirm]');
+                break;
+
+            case 'monthyear':
+                $this->preserveVarByPost($this->_vars, $varname . '[month]');
+                $this->preserveVarByPost($this->_vars, $varname . '[year]');
+                break;
+
+            case 'monthdayyear':
+                $this->preserveVarByPost($this->_vars, $varname . '[month]');
+                $this->preserveVarByPost($this->_vars, $varname . '[day]');
+                $this->preserveVarByPost($this->_vars, $varname . '[year]');
+                break;
+            }
+
+            $this->preserveVarByPost($this->_vars, $varname);
+        }
+        foreach ($this->_hiddenVariables as $var) {
+            $this->preserveVarByPost($this->_vars, $var->getVarName());
+        }
+        */
+    }
+
+    /**
+     * Does the action of validating the form, checking if it really has been
+     * submitted by calling isSubmitted() and if true does any onSubmit()
+     * calls for var types in the form. The _submitted var is then rechecked.
+     *
+     * @param boolean         $canAutofill  Can the form be valid without
+     *                                      being submitted?
+     *
+     * @return boolean  True if the form is valid.
+     */
+    public function validate($canAutoFill = false)
+    {
+        /* Get submitted status. */
+        if ($this->isSubmitted() || $canAutoFill) {
+            /* Form was submitted or can autofill; check for any variable
+             * types' onSubmit(). */
+            $this->onSubmit($this->_vars);
+
+            /* Recheck submitted status. */
+            if (!$this->isSubmitted() && !$canAutoFill) {
+                return false;
+            }
+        } else {
+            /* Form has not been submitted; return false. */
+            return false;
+        }
+
+        $message = '';
+        $this->_autofilled = true;
+
+        if ($this->_useFormToken) {
+            global $conf;
+            if (isset($conf['token'])) {
+                /* If there is a configured token system, set it up. */
+                $tokenSource = Horde_Token::factory($conf['token']['driver'], Horde::getDriverConfig('token', $conf['token']['driver']));
+            } else {
+                /* Default to the file system if no config. */
+                $tokenSource = Horde_Token::factory('file');
+            }
+            if (!$tokenSource->verify($this->_vars->get($this->_name . '_formToken'))) {
+                $this->_errors['_formToken'] = _("This form has already been processed.");
+            }
+        }
+
+        foreach ($this->getVariables() as $var) {
+            $this->_autofilled = $var->_autofilled && $this->_autofilled;
+            if (!$var->validate($this->_vars, $message)) {
+                $this->_errors[$var->getVarName()] = $message;
+            }
+        }
+
+        if ($this->_autofilled) {
+            unset($this->_errors['_formToken']);
+        }
+
+        foreach ($this->_hiddenVariables as $var) {
+            if (!$var->validate($this->_vars, $message)) {
+                $this->_errors[$var->getVarName()] = $message;
+            }
+        }
+
+        return $this->isValid();
+    }
+
+    public function clearValidation()
+    {
+        $this->_errors = array();
+    }
+
+    public function getError($var)
+    {
+        if (is_a($var, 'Horde_Form_Variable')) {
+            $name = $var->getVarName();
+        } else {
+            $name = $var;
+        }
+        return isset($this->_errors[$name]) ? $this->_errors[$name] : null;
+    }
+
+    public function setError($var, $message)
+    {
+        if (is_a($var, 'Horde_Form_Variable')) {
+            $name = $var->getVarName();
+        } else {
+            $name = $var;
+        }
+        $this->_errors[$name] = $message;
+    }
+
+    public function clearError($var)
+    {
+        if (is_a($var, 'Horde_Form_Variable')) {
+            $name = $var->getVarName();
+        } else {
+            $name = $var;
+        }
+        unset($this->_errors[$name]);
+    }
+
+    public function isValid()
+    {
+        return ($this->_autofilled || !count($this->_errors));
+    }
+
+    public function execute()
+    {
+        throw new Horde_Form_Exception('Subclass must overide execute()');
+    }
+
+    /**
+     * Fetch the field values of the submitted form.
+     *
+     * @param array $info      Array to be filled with the submitted field
+     *                         values.
+     */
+    public function getInfo(&$info)
+    {
+        $this->_getInfoFromVariables($this->getVariables(), $info);
+        $this->_getInfoFromVariables($this->_hiddenVariables, $info);
+    }
+
+    /**
+     * Fetch the field values from a given array of variables.
+     *
+     * @access private
+     *
+     * @param array  $variables  An array of Horde_Form_Variable objects to
+     *                           fetch from.
+     * @param array  $info       The array to be filled with the submitted
+     *                           field values.
+     */
+    protected function _getInfoFromVariables($variables, &$info)
+    {
+        foreach ($variables as $var) {
+            if ($var->isArrayVal()) {
+                $var->getInfo($this->_vars, $values);
+                if (is_array($values)) {
+                    $varName = str_replace('[]', '', $var->getVarName());
+                    foreach ($values as $i => $val) {
+                        $info[$i][$varName] = $val;
+                    }
+                }
+            } else {
+                if (Horde_Array::getArrayParts($var->getVarName(), $base, $keys)) {
+                    if (!isset($info[$base])) {
+                        $info[$base] = array();
+                    }
+                    $pointer = &$info[$base];
+                    while (count($keys)) {
+                        $key = array_shift($keys);
+                        if (!isset($pointer[$key])) {
+                            $pointer[$key] = array();
+                        }
+                        $pointer = &$pointer[$key];
+                    }
+                    $var->getInfo($this->_vars, $pointer);
+                } else {
+                    $var->getInfo($this->_vars, $info[$var->getVarName()]);
+                }
+            }
+        }
+    }
+
+    public function hasHelp()
+    {
+        return $this->_help;
+    }
+
+    /**
+     * Determines if this form has been submitted or not. If the class
+     * var _submitted is null then it will check for the presence of
+     * the formname in the form variables.
+     *
+     * Other events can explicitly set the _submitted variable to
+     * false to indicate a form submit but not for actual posting of
+     * data (eg. onChange events to update the display of fields).
+     *
+     * @return boolean  True or false indicating if the form has been
+     *                  submitted.
+     */
+    public function isSubmitted()
+    {
+        if (is_null($this->_submitted)) {
+            if ($this->_vars->get('formname') == $this->getName()) {
+                $this->_submitted = true;
+            } else {
+                $this->_submitted = false;
+            }
+        }
+
+        return $this->_submitted;
+    }
+
+    /**
+     * Checks if there is anything to do on the submission of the form by
+     * looping through each variable's onSubmit() function.
+     */
+    public function onSubmit()
+    {
+        /* Loop through all vars and check if there's anything to do on
+         * submit. */
+        $variables = $this->getVariables();
+        foreach ($variables as $var) {
+            $var->type->onSubmit($var, $this->_vars);
+            /* If changes to var being tracked don't register the form as
+             * submitted if old value and new value differ. */
+            if ($var->getOption('trackchange')) {
+                $varname = $var->getVarName();
+                if (!is_null($this->_vars->get('formname')) &&
+                    $this->_vars->get($varname) != $this->_vars->get('__old_' . $varname)) {
+                    $this->_submitted = false;
+                }
+            }
+        }
+    }
+
+    /**
+     * Explicitly sets the state of the form submit.
+     *
+     * An event can override the automatic determination of the submit state
+     * in the isSubmitted() function.
+     *
+     * @param boolean $state  Whether to set the state of the form as being
+     *                        submitted.
+     */
+    public function setSubmitted($state = true)
+    {
+        $this->_submitted = $state;
+    }
+
+}
+
+/**
+ * Horde_Form_Type Class
+ *
+ * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+ * @package Horde_Form
+ */
+class Horde_Form_Type {
+
+    protected function __get($property)
+    {
+        $prop = '_' . $property;
+        return isset($this->$prop) ? $this->$prop : null;
+    }
+
+    protected function __set($property, $value)
+    {
+        $prop = '_' . $property;
+        $this->$prop = $value;
+    }
+
+    protected function __isset($property)
+    {
+        $prop = '_' . $property;
+        return isset($this->$prop);
+    }
+
+    protected function __unset($property)
+    {
+        $prop = '_' . $property;
+        unset($this->$prop);
+    }
+
+    public function init()
+    {
+    }
+
+    public function onSubmit()
+    {
+    }
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        $message = '<strong>Error:</strong> Horde_Form_Type::isValid() called - should be overridden<br />';
+        return false;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        $info = $var->getValue($vars);
+    }
+
+}
+
+class Horde_Form_Type_number extends Horde_Form_Type {
+
+    var $_fraction;
+
+    function init($fraction = null)
+    {
+        $this->_fraction = $fraction;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && empty($value) && ((string)(double)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        } elseif (empty($value)) {
+            return true;
+        }
+
+        /* If matched, then this is a correct numeric value. */
+        if (preg_match($this->_getValidationPattern(), $value)) {
+            return true;
+        }
+
+        $message = _("This field must be a valid number.");
+        return false;
+    }
+
+    function _getValidationPattern()
+    {
+        static $pattern = '';
+        if (!empty($pattern)) {
+            return $pattern;
+        }
+
+        /* Get current locale information. */
+        $linfo = NLS::getLocaleInfo();
+
+        /* Build the pattern. */
+        $pattern = '(-)?';
+
+        /* Only check thousands separators if locale has any. */
+        if (!empty($linfo['mon_thousands_sep'])) {
+            /* Regex to check for correct thousands separators (if any). */
+            $pattern .= '((\d+)|((\d{0,3}?)([' . $linfo['mon_thousands_sep'] . ']\d{3})*?))';
+        } else {
+            /* No locale thousands separator, check for only digits. */
+            $pattern .= '(\d+)';
+        }
+        /* If no decimal point specified default to dot. */
+        if (empty($linfo['mon_decimal_point'])) {
+            $linfo['mon_decimal_point'] = '.';
+        }
+        /* Regex to check for correct decimals (if any). */
+        if (empty($this->_fraction)) {
+            $fraction = '*';
+        } else {
+            $fraction = '{0,' . $this->_fraction . '}';
+        }
+        $pattern .= '([' . $linfo['mon_decimal_point'] . '](\d' . $fraction . '))?';
+
+        /* Put together the whole regex pattern. */
+        $pattern = '/^' . $pattern . '$/';
+
+        return $pattern;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        $value = $vars->get($var->getVarName());
+        $linfo = NLS::getLocaleInfo();
+        $value = str_replace($linfo['mon_thousands_sep'], '', $value);
+        $info = str_replace($linfo['mon_decimal_point'], '.', $value);
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Number"));
+    }
+
+}
+
+class Horde_Form_Type_int extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && empty($value) && ((string)(int)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^[0-9]+$/', $value)) {
+            return true;
+        }
+
+        $message = _("This field may only contain integers.");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Integer"));
+    }
+
+}
+
+class Horde_Form_Type_octal extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && empty($value) && ((string)(int)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^[0-7]+$/', $value)) {
+            return true;
+        }
+
+        $message = _("This field may only contain octal values.");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Octal"));
+    }
+
+}
+
+class Horde_Form_Type_intlist extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if (empty($value) && $var->isRequired()) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^[0-9 ,]+$/', $value)) {
+            return true;
+        }
+
+        $message = _("This field must be a comma or space separated list of integers");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Integer list"));
+    }
+
+}
+
+class Horde_Form_Type_text extends Horde_Form_Type {
+
+    var $_regex;
+    var $_size;
+    var $_maxlength;
+
+    /**
+     * The initialisation function for the text variable type.
+     *
+     * @access private
+     *
+     * @param string $regex       Any valid PHP PCRE pattern syntax that
+     *                            needs to be matched for the field to be
+     *                            considered valid. If left empty validity
+     *                            will be checked only for required fields
+     *                            whether they are empty or not.
+     *                            If using this regex test it is advisable
+     *                            to enter a description for this field to
+     *                            warn the user what is expected, as the
+     *                            generated error message is quite generic
+     *                            and will not give any indication where
+     *                            the regex failed.
+     * @param integer $size       The size of the input field.
+     * @param integer $maxlength  The max number of characters.
+     */
+    function init($regex = '', $size = 40, $maxlength = null)
+    {
+        $this->_regex     = $regex;
+        $this->_size      = $size;
+        $this->_maxlength = $maxlength;
+    }
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if (!empty($this->_maxlength) && String::length($value) > $this->_maxlength) {
+            $valid = false;
+            $message = sprintf(_("Value is over the maximum length of %s."), $this->_maxlength);
+        } elseif ($var->isRequired() && empty($this->_regex)) {
+            if (!($valid = strlen(trim($value)) > 0)) {
+                $message = _("This field is required.");
+            }
+        } elseif (strlen($this->_regex)) {
+            if (!($valid = preg_match($this->_regex, $value))) {
+                $message = _("You must enter a valid value.");
+            }
+        }
+
+        return $valid;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Text"),
+            'params' => array(
+                'regex'     => array('label' => _("Regex"),
+                                     'type'  => 'text'),
+                'size'      => array('label' => _("Size"),
+                                     'type'  => 'int'),
+                'maxlength' => array('label' => _("Maximum length"),
+                                     'type'  => 'int')));
+    }
+
+}
+
+class Horde_Form_Type_stringlist extends Horde_Form_Type_text {
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("String list"),
+            'params' => array(
+                'regex'     => array('label' => _("Regex"),
+                                     'type'  => 'text'),
+                'size'      => array('label' => _("Size"),
+                                     'type'  => 'int'),
+                'maxlength' => array('label' => _("Maximum length"),
+                                     'type'  => 'int')),
+        );
+    }
+
+}
+
+class Horde_Form_Type_phone extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if ($var->isRequired()) {
+            $valid = strlen(trim($value)) > 0;
+            if (!$valid) {
+                $message = _("This field is required.");
+            }
+        } else {
+            $valid = preg_match('/^\+?[\d()\-\/ ]*$/', $value);
+            if (!$valid) {
+                $message = _("You must enter a valid phone number, digits only with an optional '+' for the international dialing prefix.");
+            }
+        }
+
+        return $valid;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Phone number"));
+    }
+
+}
+
+class Horde_Form_Type_cellphone extends Horde_Form_Type_phone {
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Mobile phone number"));
+    }
+
+}
+
+class Horde_Form_Type_ipaddress extends Horde_Form_Type_text {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if (strlen(trim($value)) > 0) {
+            $ip = explode('.', $value);
+            $valid = (count($ip) == 4);
+            if ($valid) {
+                foreach ($ip as $part) {
+                    if (!is_numeric($part) ||
+                        $part > 255 ||
+                        $part < 0) {
+                        $valid = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!$valid) {
+                $message = _("Please enter a valid IP address.");
+            }
+        } elseif ($var->isRequired()) {
+            $valid = false;
+            $message = _("This field is required.");
+        }
+
+        return $valid;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("IP address"));
+    }
+
+}
+
+class Horde_Form_Type_longtext extends Horde_Form_Type_text {
+
+    var $_rows;
+    var $_cols;
+    var $_helper = array();
+
+    function init($rows = 8, $cols = 80, $helper = array())
+    {
+        if (!is_array($helper)) {
+            $helper = array($helper);
+        }
+
+        $this->_rows = $rows;
+        $this->_cols = $cols;
+        $this->_helper = $helper;
+    }
+
+    function hasHelper($option = '')
+    {
+        if (empty($option)) {
+            /* No option specified, check if any helpers have been
+             * activated. */
+            return !empty($this->_helper);
+        } elseif (empty($this->_helper)) {
+            /* No helpers activated at all, return false. */
+            return false;
+        } else {
+            /* Check if given helper has been activated. */
+            return in_array($option, $this->_helper);
+        }
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Long text"),
+            'params' => array(
+                'rows'   => array('label' => _("Number of rows"),
+                                  'type'  => 'int'),
+                'cols'   => array('label' => _("Number of columns"),
+                                  'type'  => 'int'),
+                'helper' => array('label' => _("Helper?"),
+                                  'type'  => 'boolean')));
+    }
+
+}
+
+class Horde_Form_Type_countedtext extends Horde_Form_Type_longtext {
+
+    var $_chars;
+
+    function init($rows = null, $cols = null, $chars = 1000)
+    {
+        parent::init($rows, $cols);
+        $this->_chars = $chars;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        $length = String::length(trim($value));
+
+        if ($var->isRequired() && $length <= 0) {
+            $valid = false;
+            $message = _("This field is required.");
+        } elseif ($length > $this->_chars) {
+            $valid = false;
+            $message = sprintf(_("There are too many characters in this field. You have entered %s characters; you must enter less than %s."), String::length(trim($value)), $this->_chars);
+        }
+
+        return $valid;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Counted text"),
+            'params' => array(
+                'rows'  => array('label' => _("Number of rows"),
+                                 'type'  => 'int'),
+                'cols'  => array('label' => _("Number of columns"),
+                                 'type'  => 'int'),
+                'chars' => array('label' => _("Number of characters"),
+                                 'type'  => 'int')));
+    }
+
+}
+
+class Horde_Form_Type_address extends Horde_Form_Type_longtext {
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Address"),
+            'params' => array(
+                'rows' => array('label' => _("Number of rows"),
+                                'type'  => 'int'),
+                'cols' => array('label' => _("Number of columns"),
+                                'type'  => 'int')));
+    }
+
+}
+
+class Horde_Form_Type_addresslink extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+}
+
+class Horde_Form_Type_file extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired()) {
+            $uploaded = Horde_Browser::wasFileUploaded($var->getVarName());
+            if (is_a($uploaded, 'PEAR_Error')) {
+                $message = $uploaded->getMessage();
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        $name = $var->getVarName();
+        $uploaded = Horde_Browser::wasFileUploaded($name);
+        if ($uploaded === true) {
+            $info['name'] = $_FILES[$name]['name'];
+            $info['type'] = $_FILES[$name]['type'];
+            $info['tmp_name'] = $_FILES[$name]['tmp_name'];
+            $info['file'] = $_FILES[$name]['tmp_name'];
+            $info['error'] = $_FILES[$name]['error'];
+            $info['size'] = $_FILES[$name]['size'];
+        }
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("File upload"));
+    }
+
+}
+
+class Horde_Form_Type_image extends Horde_Form_Type {
+
+    /**
+     * Has a file been uploaded on this form submit?
+     *
+     * @var boolean
+     */
+    var $_uploaded = null;
+
+    /**
+     * Show the upload button?
+     *
+     * @var boolean
+     */
+    var $_show_upload = true;
+
+    /**
+     * Show the option to upload also original non-modified image?
+     *
+     * @var boolean
+     */
+    var $_show_keeporig = false;
+
+    /**
+     * Limit the file size?
+     *
+     * @var integer
+     */
+    var $_max_filesize = null;
+
+    /**
+     * Hash containing the previously uploaded image info.
+     *
+     * @var array
+     */
+    var $_img = array();
+
+    function init($show_upload = true, $show_keeporig = false, $max_filesize = null)
+    {
+        $this->_show_upload   = $show_upload;
+        $this->_show_keeporig = $show_keeporig;
+        $this->_max_filesize  = $max_filesize;
+    }
+
+    function onSubmit($var, $vars)
+    {
+        /* Get the upload. */
+        $this->_getUpload($vars, $var);
+
+        /* If this was done through the upload button override the submitted
+         * value of the form. */
+        if ($vars->get('_do_' . $var->getVarName())) {
+            $var->form->setSubmitted(false);
+        }
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $field = $vars->get($var->getVarName());
+
+        /* Get the upload. */
+        $this->_getUpload($vars, $var);
+
+        /* The upload generated a PEAR Error. */
+        if (is_a($this->_uploaded, 'PEAR_Error')) {
+            /* Not required and no image upload attempted. */
+            if (!$var->isRequired() && empty($field['img']) &&
+                $this->_uploaded->getCode() == UPLOAD_ERR_NO_FILE) {
+                return true;
+            }
+
+            if (($this->_uploaded->getCode() == UPLOAD_ERR_NO_FILE) &&
+                empty($field['img'])) {
+                /* Nothing uploaded and no older upload. */
+                $message = _("This field is required.");
+                return false;
+            } elseif (!empty($field['img'])) {
+                /* Nothing uploaded but older upload present. */
+                return true;
+            } else {
+                /* Some other error message. */
+                $message = $this->_uploaded->getMessage();
+                return false;
+            }
+        } elseif ($this->_max_filesize &&
+                  $this->_img['size'] > $this->_max_filesize) {
+            $message = sprintf(_("The image file was larger than the maximum allowed size (%d bytes)."), $this->_max_filesize);
+            return false;
+        }
+
+        return true;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        /* Get the upload. */
+        $this->_getUpload($vars, $var);
+
+        /* Get image params stored in the hidden field. */
+        $value = $var->getValue($vars);
+        $info = $this->_img;
+        if (empty($info['file'])) {
+            unset($info['file']);
+            return;
+        }
+        if ($this->_show_keeporig) {
+            $info['keep_orig'] = !empty($value['keep_orig']);
+        }
+
+        /* Set the uploaded value (either true or PEAR_Error). */
+        $info['uploaded'] = &$this->_uploaded;
+
+        /* If a modified file exists move it over the original. */
+        if ($this->_show_keeporig && $info['keep_orig']) {
+            /* Requested the saving of original file also. */
+            $info['orig_file'] = Horde::getTempDir() . '/' . $info['file'];
+            $info['file'] = Horde::getTempDir() . '/mod_' . $info['file'];
+            /* Check if a modified file actually exists. */
+            if (!file_exists($info['file'])) {
+                $info['file'] = $info['orig_file'];
+                unset($info['orig_file']);
+            }
+        } else {
+            /* Saving of original not required. */
+            $mod_file = Horde::getTempDir() . '/mod_' . $info['file'];
+            $info['file'] = Horde::getTempDir() . '/' . $info['file'];
+
+            if (file_exists($mod_file)) {
+                /* Unlink first (has to be done on Windows machines?) */
+                unlink($info['file']);
+                rename($mod_file, $info['file']);
+            }
+        }
+    }
+
+    /**
+     * Gets the upload and sets up the upload data array. Either
+     * fetches an upload done with this submit or retries stored
+     * upload info.
+     */
+    function _getUpload($vars, $var)
+    {
+        /* Don't bother with this function if already called and set
+         * up vars. */
+        if (!empty($this->_img)) {
+            return true;
+        }
+
+        /* Check if file has been uploaded. */
+        $varname = $var->getVarName();
+        $this->_uploaded = Horde_Browser::wasFileUploaded($varname . '[new]');
+
+        if ($this->_uploaded === true) {
+            /* A file has been uploaded on this submit. Save to temp dir for
+             * preview work. */
+            $this->_img['type'] = $this->getUploadedFileType($varname . '[new]');
+
+            /* Get the other parts of the upload. */
+            Horde_Array::getArrayParts($varname . '[new]', $base, $keys);
+
+            /* Get the temporary file name. */
+            $keys_path = array_merge(array($base, 'tmp_name'), $keys);
+            $this->_img['file'] = Horde_Array::getElement($_FILES, $keys_path);
+
+            /* Get the actual file name. */
+            $keys_path= array_merge(array($base, 'name'), $keys);
+            $this->_img['name'] = Horde_Array::getElement($_FILES, $keys_path);
+
+            /* Get the file size. */
+            $keys_path= array_merge(array($base, 'size'), $keys);
+            $this->_img['size'] = Horde_Array::getElement($_FILES, $keys_path);
+
+            /* Get any existing values for the image upload field. */
+            $upload = $vars->get($var->getVarName());
+            $upload['img'] = @unserialize($upload['img']);
+
+            /* Get the temp file if already one uploaded, otherwise create a
+             * new temporary file. */
+            if (!empty($upload['img']['file'])) {
+                $tmp_file = Horde::getTempDir() . '/' . $upload['img']['file'];
+            } else {
+                $tmp_file = Horde::getTempFile('Horde', false);
+            }
+
+            /* Move the browser created temp file to the new temp file. */
+            move_uploaded_file($this->_img['file'], $tmp_file);
+            $this->_img['file'] = basename($tmp_file);
+
+            /* Store the uploaded image file data to the hidden field. */
+            $upload['img'] = serialize($this->_img);
+            $vars->set($var->getVarName(), $upload);
+        } elseif ($this->_uploaded) {
+            /* File has not been uploaded. */
+            $upload = $vars->get($var->getVarName());
+            if ($this->_uploaded->getCode() == 4 && !empty($upload['img'])) {
+                $this->_img = @unserialize($upload['img']);
+            }
+        }
+    }
+
+    function getUploadedFileType($field)
+    {
+        /* Get any index on the field name. */
+        $index = Horde_Array::getArrayParts($field, $base, $keys);
+
+        if ($index) {
+            /* Index present, fetch the mime type var to check. */
+            $keys_path = array_merge(array($base, 'type'), $keys);
+            $type = Horde_Array::getElement($_FILES, $keys_path);
+            $keys_path= array_merge(array($base, 'tmp_name'), $keys);
+            $tmp_name = Horde_Array::getElement($_FILES, $keys_path);
+        } else {
+            /* No index, simple set up of vars to check. */
+            $type = $_FILES[$field]['type'];
+            $tmp_name = $_FILES[$field]['tmp_name'];
+        }
+
+        if (empty($type) || ($type == 'application/octet-stream')) {
+            /* Type wasn't set on upload, try analising the upload. */
+            global $conf;
+            require_once 'Horde/MIME/Magic.php';
+            if (!($type = MIME_Magic::analyzeFile($tmp_name, isset($conf['mime']['magic_db']) ? $conf['mime']['magic_db'] : null))) {
+                if ($index) {
+                    /* Get the name value. */
+                    $keys_path = array_merge(array($base, 'name'), $keys);
+                    $name = Horde_Array::getElement($_FILES, $keys_path);
+
+                    /* Work out the type from the file name. */
+                    $type = MIME_Magic::filenameToMIME($name);
+
+                    /* Set the type. */
+                    $keys_path = array_merge(array($base, 'type'), $keys);
+                    Horde_Array::getElement($_FILES, $keys_path, $type);
+                } else {
+                    /* Work out the type from the file name. */
+                    $type = MIME_Magic::filenameToMIME($_FILES[$field]['name']);
+
+                    /* Set the type. */
+                    $_FILES[$field]['type'] = MIME_Magic::filenameToMIME($_FILES[$field]['name']);
+                }
+            }
+        }
+
+        return $type;
+    }
+
+    /**
+     * Loads any existing image data into the image field. Requires that the
+     * array $image passed to it contains the structure:
+     *   $image['load']['file'] - the filename of the image;
+     *   $image['load']['data'] - the raw image data.
+     *
+     * @param array $image  The image array.
+     */
+    function loadImageData(&$image)
+    {
+        /* No existing image data to load. */
+        if (!isset($image['load'])) {
+            return;
+        }
+
+        /* Save the data to the temp dir. */
+        $tmp_file = Horde::getTempDir() . '/' . $image['load']['file'];
+        if ($fd = fopen($tmp_file, 'w')) {
+            fwrite($fd, $image['load']['data']);
+            fclose($fd);
+        }
+
+        $image['img'] = serialize(array('file' => $image['load']['file']));
+        unset($image['load']);
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Image upload"),
+            'params' => array(
+                'show_upload'   => array('label' => _("Show upload?"),
+                                         'type'  => 'boolean'),
+                'show_keeporig' => array('label' => _("Show option to keep original?"),
+                                         'type'  => 'boolean'),
+                'max_filesize'  => array('label' => _("Maximum file size in bytes"),
+                                         'type'  => 'int')));
+    }
+
+}
+
+class Horde_Form_Type_boolean extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        $info = String::lower($vars->get($var->getVarName())) == 'on';
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("True or false"));
+    }
+
+}
+
+class Horde_Form_Type_link extends Horde_Form_Type {
+
+    /**
+     * List of hashes containing link parameters. Possible keys: 'url', 'text',
+     * 'target', 'onclick', 'title', 'accesskey'.
+     *
+     * @var array
+     */
+    var $values;
+
+    function init($values)
+    {
+        $this->values = $values;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Link"),
+            'params' => array(
+                'url' => array(
+                    'label' => _("Link URL"),
+                    'type' => 'text'),
+                'text' => array(
+                    'label' => _("Link text"),
+                    'type' => 'text'),
+                'target' => array(
+                    'label' => _("Link target"),
+                    'type' => 'text'),
+                'onclick' => array(
+                    'label' => _("Onclick event"),
+                    'type' => 'text'),
+                'title' => array(
+                    'label' => _("Link title attribute"),
+                    'type' => 'text'),
+                'accesskey' => array(
+                    'label' => _("Link access key"),
+                    'type' => 'text')));
+    }
+
+}
+
+class Horde_Form_Type_email extends Horde_Form_Type {
+
+    var $_allow_multi = false;
+    var $_strip_domain = false;
+    var $_link_compose = false;
+    var $_check_smtp = false;
+    var $_link_name;
+
+    /**
+     * A string containing valid delimiters (default is just comma).
+     *
+     * @var string
+     */
+    var $_delimiters = ',';
+
+    function init($allow_multi = false, $strip_domain = false,
+                  $link_compose = false, $link_name = null,
+                  $delimiters = ',')
+    {
+        $this->_allow_multi = $allow_multi;
+        $this->_strip_domain = $strip_domain;
+        $this->_link_compose = $link_compose;
+        $this->_link_name = $link_name;
+        $this->_delimiters = $delimiters;
+    }
+
+    /**
+     */
+    function isValid($var, $vars, $value, &$message)
+    {
+        // Split into individual addresses.
+        $emails = $this->splitEmailAddresses($value);
+
+        // Check for too many.
+        if (!$this->_allow_multi && count($emails) > 1) {
+            $message = _("Only one email address is allowed.");
+            return false;
+        }
+
+        // Check for all valid and at least one non-empty.
+        $nonEmpty = 0;
+        foreach ($emails as $email) {
+            if (!strlen($email)) {
+                continue;
+            }
+            if (!$this->validateEmailAddress($email)) {
+                $message = sprintf(_("\"%s\" is not a valid email address."), $email);
+                return false;
+            }
+            ++$nonEmpty;
+        }
+
+        if (!$nonEmpty && $var->isRequired()) {
+            if ($this->_allow_multi) {
+                $message = _("You must enter at least one email address.");
+            } else {
+                $message = _("You must enter an email address.");
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Explodes an RFC 2822 string, ignoring a delimiter if preceded
+     * by a "\" character, or if the delimiter is inside single or
+     * double quotes.
+     *
+     * @param string $string     The RFC 822 string.
+     *
+     * @return array  The exploded string in an array.
+     */
+    function splitEmailAddresses($string)
+    {
+        $quotes = array('"', "'");
+        $emails = array();
+        $pos = 0;
+        $in_quote = null;
+        $in_group = false;
+        $prev = null;
+
+        if (!strlen($string)) {
+            return array();
+        }
+
+        $char = $string[0];
+        if (in_array($char, $quotes)) {
+            $in_quote = $char;
+        } elseif ($char == ':') {
+            $in_group = true;
+        } elseif (strpos($this->_delimiters, $char) !== false) {
+            $emails[] = '';
+            $pos = 1;
+        }
+
+        for ($i = 1, $iMax = strlen($string); $i < $iMax; ++$i) {
+            $char = $string[$i];
+            if (in_array($char, $quotes)) {
+                if ($prev !== '\\') {
+                    if ($in_quote === $char) {
+                        $in_quote = null;
+                    } elseif (is_null($in_quote)) {
+                        $in_quote = $char;
+                    }
+                }
+            } elseif ($in_group) {
+                if ($char == ';') {
+                    $emails[] = substr($string, $pos, $i - $pos + 1);
+                    $pos = $i + 1;
+                    $in_group = false;
+                }
+            } elseif ($char == ':') {
+                $in_group = true;
+            } elseif (strpos($this->_delimiters, $char) !== false &&
+                      $prev !== '\\' &&
+                      is_null($in_quote)) {
+                $emails[] = substr($string, $pos, $i - $pos);
+                $pos = $i + 1;
+            }
+            $prev = $char;
+        }
+
+        if ($pos != $i) {
+            /* The string ended without a delimiter. */
+            $emails[] = substr($string, $pos, $i - $pos);
+        }
+
+        return $emails;
+    }
+
+    /**
+     * RFC(2)822 Email Parser.
+     *
+     * By Cal Henderson <cal@iamcal.com>
+     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
+     * http://creativecommons.org/licenses/by-sa/2.5/
+     *
+     * http://code.iamcal.com/php/rfc822/
+     *
+     * http://iamcal.com/publish/articles/php/parsing_email
+     *
+     * Revision 4
+     *
+     * @param string $email An individual email address to validate.
+     *
+     * @return boolean
+     */
+    function validateEmailAddress($email)
+    {
+        static $comment_regexp, $email_regexp;
+        if ($comment_regexp === null) {
+            $this->_defineValidationRegexps($comment_regexp, $email_regexp);
+        }
+
+        // We need to strip comments first (repeat until we can't find
+        // any more).
+        while (true) {
+            $new = preg_replace("!$comment_regexp!", '', $email);
+            if (strlen($new) == strlen($email)){
+                break;
+            }
+            $email = $new;
+        }
+
+        // Now match what's left.
+        $result = (bool)preg_match("!^$email_regexp$!", $email);
+        if ($result && $this->_check_smtp) {
+            $result = $this->validateEmailAddressSmtp($email);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Attempt partial delivery of mail to an address to validate it.
+     *
+     * @param string $email An individual email address to validate.
+     *
+     * @return boolean
+     */
+    function validateEmailAddressSmtp($email)
+    {
+        list(, $maildomain) = explode('@', $email, 2);
+
+        // Try to get the real mailserver from MX records.
+        if (function_exists('getmxrr') &&
+            @getmxrr($maildomain, $mxhosts, $mxpriorities)) {
+            // MX record found.
+            array_multisort($mxpriorities, $mxhosts);
+            $mailhost = $mxhosts[0];
+        } else {
+            // No MX record found, try the root domain as the mail
+            // server.
+            $mailhost = $maildomain;
+        }
+
+        $fp = @fsockopen($mailhost, 25, $errno, $errstr, 5);
+        if (!$fp) {
+            return false;
+        }
+
+        // Read initial response.
+        fgets($fp, 4096);
+
+        // HELO
+        fputs($fp, "HELO $mailhost\r\n");
+        fgets($fp, 4096);
+
+        // MAIL FROM
+        fputs($fp, "MAIL FROM: <root@example.com>\r\n");
+        fgets($fp, 4096);
+
+        // RCPT TO - gets the result we want.
+        fputs($fp, "RCPT TO: <$email>\r\n");
+        $result = trim(fgets($fp, 4096));
+
+        // QUIT
+        fputs($fp, "QUIT\r\n");
+        fgets($fp, 4096);
+        fclose($fp);
+
+        return substr($result, 0, 1) == '2';
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Email"),
+            'params' => array(
+                'allow_multi' => array('label' => _("Allow multiple addresses?"),
+                                       'type'  => 'boolean'),
+                'strip_domain' => array('label' => _("Protect address from spammers?"),
+                                        'type' => 'boolean'),
+                'link_compose' => array('label' => _("Link the email address to the compose page when displaying?"),
+                                        'type' => 'boolean'),
+                'link_name' => array('label' => _("The name to use when linking to the compose page"),
+                                     'type' => 'text'),
+                'delimiters' => array('label' => _("Character to split multiple addresses with"),
+                                      'type' => 'text'),
+            ),
+        );
+    }
+
+    /**
+     * RFC(2)822 Email Parser.
+     *
+     * By Cal Henderson <cal@iamcal.com>
+     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
+     * http://creativecommons.org/licenses/by-sa/2.5/
+     *
+     * http://code.iamcal.com/php/rfc822/
+     *
+     * http://iamcal.com/publish/articles/php/parsing_email
+     *
+     * Revision 4
+     *
+     * @param string &$comment The regexp for comments.
+     * @param string &$addr_spec The regexp for email addresses.
+     */
+    function _defineValidationRegexps(&$comment, &$addr_spec)
+    {
+        /**
+         * NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
+         *                         %d11 /          ;  that do not include the
+         *                         %d12 /          ;  carriage return, line feed,
+         *                         %d14-31 /       ;  and white space characters
+         *                         %d127
+         * ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
+         * DIGIT          =  %x30-39
+         */
+        $no_ws_ctl  = "[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]";
+        $alpha      = "[\\x41-\\x5a\\x61-\\x7a]";
+        $digit      = "[\\x30-\\x39]";
+        $cr         = "\\x0d";
+        $lf         = "\\x0a";
+        $crlf       = "($cr$lf)";
+
+        /**
+         * obs-char        =       %d0-9 / %d11 /          ; %d0-127 except CR and
+         *                         %d12 / %d14-127         ;  LF
+         * obs-text        =       *LF *CR *(obs-char *LF *CR)
+         * text            =       %d1-9 /         ; Characters excluding CR and LF
+         *                         %d11 /
+         *                         %d12 /
+         *                         %d14-127 /
+         *                         obs-text
+         * obs-qp          =       "\" (%d0-127)
+         * quoted-pair     =       ("\" text) / obs-qp
+         */
+        $obs_char       = "[\\x00-\\x09\\x0b\\x0c\\x0e-\\x7f]";
+        $obs_text       = "($lf*$cr*($obs_char$lf*$cr*)*)";
+        $text           = "([\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f]|$obs_text)";
+        $obs_qp         = "(\\x5c[\\x00-\\x7f])";
+        $quoted_pair    = "(\\x5c$text|$obs_qp)";
+
+        /**
+         * obs-FWS         =       1*WSP *(CRLF 1*WSP)
+         * FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
+         *                         obs-FWS
+         * ctext           =       NO-WS-CTL /     ; Non white space controls
+         *                         %d33-39 /       ; The rest of the US-ASCII
+         *                         %d42-91 /       ;  characters not including "(",
+         *                         %d93-126        ;  ")", or "\"
+         * ccontent        =       ctext / quoted-pair / comment
+         * comment         =       "(" *([FWS] ccontent) [FWS] ")"
+         * CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
+         *
+         * @note: We translate ccontent only partially to avoid an
+         * infinite loop. Instead, we'll recursively strip comments
+         * before processing the input.
+         */
+        $wsp        = "[\\x20\\x09]";
+        $obs_fws    = "($wsp+($crlf$wsp+)*)";
+        $fws        = "((($wsp*$crlf)?$wsp+)|$obs_fws)";
+        $ctext      = "($no_ws_ctl|[\\x21-\\x27\\x2A-\\x5b\\x5d-\\x7e])";
+        $ccontent   = "($ctext|$quoted_pair)";
+        $comment    = "(\\x28($fws?$ccontent)*$fws?\\x29)";
+        $cfws       = "(($fws?$comment)*($fws?$comment|$fws))";
+        $cfws       = "$fws*";
+
+        /**
+         * atext           =       ALPHA / DIGIT / ; Any character except controls,
+         *                         "!" / "#" /     ;  SP, and specials.
+         *                         "$" / "%" /     ;  Used for atoms
+         *                         "&" / "'" /
+         *                         "*" / "+" /
+         *                         "-" / "/" /
+         *                         "=" / "?" /
+         *                         "^" / "_" /
+         *                         "`" / "{" /
+         *                         "|" / "}" /
+         *                         "~"
+         * atom            =       [CFWS] 1*atext [CFWS]
+         */
+        $atext      = "($alpha|$digit|[\\x21\\x23-\\x27\\x2a\\x2b\\x2d\\x2e\\x3d\\x3f\\x5e\\x5f\\x60\\x7b-\\x7e])";
+        $atom       = "($cfws?$atext+$cfws?)";
+
+        /**
+         * qtext           =       NO-WS-CTL /     ; Non white space controls
+         *                         %d33 /          ; The rest of the US-ASCII
+         *                         %d35-91 /       ;  characters not including "\"
+         *                         %d93-126        ;  or the quote character
+         * qcontent        =       qtext / quoted-pair
+         * quoted-string   =       [CFWS]
+         *                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
+         *                         [CFWS]
+         * word            =       atom / quoted-string
+         */
+        $qtext      = "($no_ws_ctl|[\\x21\\x23-\\x5b\\x5d-\\x7e])";
+        $qcontent   = "($qtext|$quoted_pair)";
+        $quoted_string  = "($cfws?\\x22($fws?$qcontent)*$fws?\\x22$cfws?)";
+        $word       = "($atom|$quoted_string)";
+
+        /**
+         * obs-local-part  =       word *("." word)
+         * obs-domain      =       atom *("." atom)
+         */
+        $obs_local_part = "($word(\\x2e$word)*)";
+        $obs_domain = "($atom(\\x2e$atom)*)";
+
+        /**
+         * dot-atom-text   =       1*atext *("." 1*atext)
+         * dot-atom        =       [CFWS] dot-atom-text [CFWS]
+         */
+        $dot_atom_text  = "($atext+(\\x2e$atext+)*)";
+        $dot_atom   = "($cfws?$dot_atom_text$cfws?)";
+
+        /**
+         * domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
+         * dcontent        =       dtext / quoted-pair
+         * dtext           =       NO-WS-CTL /     ; Non white space controls
+         *
+         *                         %d33-90 /       ; The rest of the US-ASCII
+         *                         %d94-126        ;  characters not including "[",
+         *                                         ;  "]", or "\"
+         */
+        $dtext      = "($no_ws_ctl|[\\x21-\\x5a\\x5e-\\x7e])";
+        $dcontent   = "($dtext|$quoted_pair)";
+        $domain_literal = "($cfws?\\x5b($fws?$dcontent)*$fws?\\x5d$cfws?)";
+
+        /**
+         * local-part      =       dot-atom / quoted-string / obs-local-part
+         * domain          =       dot-atom / domain-literal / obs-domain
+         * addr-spec       =       local-part "@" domain
+         */
+        $local_part = "($dot_atom|$quoted_string|$obs_local_part)";
+        $domain     = "($dot_atom|$domain_literal|$obs_domain)";
+        $addr_spec  = "($local_part\\x40$domain)";
+    }
+
+}
+
+class Horde_Form_Type_matrix extends Horde_Form_Type {
+
+    var $_cols;
+    var $_rows;
+    var $_matrix;
+    var $_new_input;
+
+    /**
+     * Initializes the variable.
+     *
+     * @example
+     * init(array('Column A', 'Column B'),
+     *      array(1 => 'Row One', 2 => 'Row 2', 3 => 'Row 3'),
+     *      array(array(true, true, false),
+     *            array(true, false, true),
+     *            array(fasle, true, false)),
+     *      array('Row 4', 'Row 5'));
+     *
+     * @param array $cols               A list of column headers.
+     * @param array $rows               A hash with row IDs as the keys and row
+     *                                  labels as the values.
+     * @param array $matrix             A two dimensional hash with the field
+     *                                  values.
+     * @param boolean|array $new_input  If true, a free text field to add a new
+     *                                  row is displayed on the top, a select
+     *                                  box if this parameter is a value.
+     */
+    function init($cols, $rows = array(), $matrix = array(), $new_input = false)
+    {
+        $this->_cols       = $cols;
+        $this->_rows       = $rows;
+        $this->_matrix     = $matrix;
+        $this->_new_input  = $new_input;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        $values = $vars->get($var->getVarName());
+        if (!empty($values['n']['r']) && isset($values['n']['v'])) {
+            $new_row = $values['n']['r'];
+            $values['r'][$new_row] = $values['n']['v'];
+            unset($values['n']);
+        }
+
+        $info = (isset($values['r']) ? $values['r'] : array());
+    }
+
+    function about()
+    {
+        return array(
+            'name' => _("Field matrix"),
+            'params' => array(
+                'cols' => array('label' => _("Column titles"),
+                                'type'  => 'stringlist')));
+    }
+
+}
+
+class Horde_Form_Type_emailConfirm extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && empty($value['original'])) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if ($value['original'] != $value['confirm']) {
+            $message = _("Email addresses must match.");
+            return false;
+        } else {
+            $parser = new Mail_RFC822();
+            $parsed_email = $parser->parseAddressList($value['original'], false, true);
+
+            if (count($parsed_email) > 1) {
+                $message = _("Only one email address allowed.");
+                return false;
+            }
+            if (empty($parsed_email[0]->mailbox)) {
+                $message = _("You did not enter a valid email address.");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Email with confirmation"));
+    }
+
+}
+
+class Horde_Form_Type_password extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if ($var->isRequired()) {
+            $valid = strlen(trim($value)) > 0;
+
+            if (!$valid) {
+                $message = _("This field is required.");
+            }
+        }
+
+        return $valid;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Password"));
+    }
+
+}
+
+class Horde_Form_Type_passwordconfirm extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && empty($value['original'])) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if ($value['original'] != $value['confirm']) {
+            $message = _("Passwords must match.");
+            return false;
+        }
+
+        return true;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        $value = $vars->get($var->getVarName());
+        $info = $value['original'];
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Password with confirmation"));
+    }
+
+}
+
+class Horde_Form_Type_enum extends Horde_Form_Type {
+
+    var $_values;
+    var $_prompt;
+
+    function init($values, $prompt = null)
+    {
+        $this->_values = $values;
+
+        if ($prompt === true) {
+            $this->_prompt = _("-- select --");
+        } else {
+            $this->_prompt = $prompt;
+        }
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && $value == '' && !isset($this->_values[$value])) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (count($this->_values) == 0 || isset($this->_values[$value]) ||
+            ($this->_prompt && empty($value))) {
+            return true;
+        }
+
+        $message = _("Invalid data.");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Drop down list"),
+            'params' => array(
+                'values' => array('label' => _("Values to select from"),
+                                  'type'  => 'stringlist'),
+                'prompt' => array('label' => _("Prompt text"),
+                                  'type'  => 'text')));
+    }
+
+}
+
+class Horde_Form_Type_mlenum extends Horde_Form_Type {
+
+    var $_values;
+    var $_prompts;
+
+    function init(&$values, $prompts = null)
+    {
+        $this->_values = &$values;
+
+        if ($prompts === true) {
+            $this->_prompts = array(_("-- select --"), _("-- select --"));
+        } elseif (!is_array($prompts)) {
+            $this->_prompts = array($prompts, $prompts);
+        } else {
+            $this->_prompts = $prompts;
+        }
+    }
+
+    function onSubmit($var, $vars)
+    {
+        $varname = $var->getVarName();
+        $value = $vars->get($varname);
+
+        if ($value['1'] != $value['old']) {
+            $var->form->setSubmitted(false);
+        }
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && (empty($value['1']) || empty($value['2']))) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (!count($this->_values) || isset($this->_values[$value['1']]) ||
+            (!empty($this->_prompts) && empty($value['1']))) {
+            return true;
+        }
+
+        $message = _("Invalid data.");
+        return false;
+    }
+
+    function getInfo($vars, &$var, &$info)
+    {
+        $info = $vars->get($var->getVarName());
+        return $info['2'];
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Multi-level drop down lists"),
+            'params' => array(
+                'values' => array('label' => _("Values to select from"),
+                                  'type'  => 'stringlist'),
+                'prompt' => array('label' => _("Prompt text"),
+                                  'type'  => 'text')));
+    }
+
+}
+
+class Horde_Form_Type_multienum extends Horde_Form_Type_enum {
+
+    var $size = 5;
+
+    function init($values, $size = null)
+    {
+        if (!is_null($size)) {
+            $this->size = (int)$size;
+        }
+
+        parent::init($values);
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if (is_array($value)) {
+            foreach ($value as $val) {
+                if (!$this->isValid($var, $vars, $val, $message)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        if (empty($value) && ((string)(int)$value !== $value)) {
+            if ($var->isRequired()) {
+                $message = _("This field is required.");
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        if (count($this->_values) == 0 || isset($this->_values[$value])) {
+            return true;
+        }
+
+        $message = _("Invalid data.");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Multiple selection"),
+            'params' => array(
+                'values' => array('label' => _("Values"),
+                                  'type'  => 'stringlist'),
+                'size'   => array('label' => _("Size"),
+                                  'type'  => 'int'))
+        );
+    }
+
+}
+
+class Horde_Form_Type_keyval_multienum extends Horde_Form_Type_multienum {
+
+    function getInfo($vars, $var, &$info)
+    {
+        $value = $vars->get($var->getVarName());
+        $info = array();
+        foreach ($value as $key) {
+            $info[$key] = $this->_values[$key];
+        }
+    }
+
+}
+
+class Horde_Form_Type_radio extends Horde_Form_Type_enum {
+
+    /* Entirely implemented by Horde_Form_Type_enum; just a different
+     * view. */
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Radio selection"),
+            'params' => array(
+                'values' => array('label' => _("Values"),
+                                  'type'  => 'stringlist')));
+    }
+
+}
+
+class Horde_Form_Type_set extends Horde_Form_Type {
+
+    var $_values;
+    var $_checkAll = false;
+
+    function init(&$values, $checkAll = false)
+    {
+        $this->_values = $values;
+        $this->_checkAll = $checkAll;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if (count($this->_values) == 0 || count($value) == 0) {
+            return true;
+        }
+        foreach ($value as $item) {
+            if (!isset($this->_values[$item])) {
+                $error = true;
+                break;
+            }
+        }
+        if (!isset($error)) {
+            return true;
+        }
+
+        $message = _("Invalid data.");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Set"),
+            'params' => array(
+                'values' => array('label' => _("Values"),
+                                  'type'  => 'stringlist')));
+    }
+
+}
+
+class Horde_Form_Type_date extends Horde_Form_Type {
+
+    var $_format;
+
+    function init($format = '%a %d %B')
+    {
+        $this->_format = $format;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if ($var->isRequired()) {
+            $valid = strlen(trim($value)) > 0;
+
+            if (!$valid) {
+                $message = sprintf(_("%s is required"), $var->getHumanName());
+            }
+        }
+
+        return $valid;
+    }
+
+    /**
+     * @static
+     */
+    function getAgo($timestamp)
+    {
+        if ($timestamp === null) {
+            return '';
+        }
+
+        $diffdays = Date_Calc::dateDiff(date('j', $timestamp),
+                                        date('n', $timestamp),
+                                        date('Y', $timestamp),
+                                        date('j'), date('n'), date('Y'));
+
+        /* An error occured. */
+        if ($diffdays == -1) {
+            return;
+        }
+
+        $ago = $diffdays * Date_Calc::compareDates(date('j', $timestamp),
+                                                   date('n', $timestamp),
+                                                   date('Y', $timestamp),
+                                                   date('j'), date('n'),
+                                                   date('Y'));
+        if ($ago < -1) {
+            return sprintf(_(" (%s days ago)"), $diffdays);
+        } elseif ($ago == -1) {
+            return _(" (yesterday)");
+        } elseif ($ago == 0) {
+            return _(" (today)");
+        } elseif ($ago == 1) {
+            return _(" (tomorrow)");
+        } else {
+            return sprintf(_(" (in %s days)"), $diffdays);
+        }
+    }
+
+    function getFormattedTime($timestamp, $format = null, $showago = true)
+    {
+        if (empty($format)) {
+            $format = $this->_format;
+        }
+        if (!empty($timestamp)) {
+            return strftime($format, $timestamp) . ($showago ? Horde_Form_Type_date::getAgo($timestamp) : '');
+        } else {
+            return '';
+        }
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Date"));
+    }
+
+}
+
+class Horde_Form_Type_time extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && empty($value) && ((string)(double)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^[0-2]?[0-9]:[0-5][0-9]$/', $value)) {
+            return true;
+        }
+
+        $message = _("This field may only contain numbers and the colon.");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Time"));
+    }
+
+}
+
+class Horde_Form_Type_hourminutesecond extends Horde_Form_Type {
+
+    var $_show_seconds;
+
+    function init($show_seconds = false)
+    {
+        $this->_show_seconds = $show_seconds;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $time = $vars->get($var->getVarName());
+        if (!$this->_show_seconds && !isset($time['second'])) {
+            $time['second'] = 0;
+        }
+
+        if (!$this->emptyTimeArray($time) && !$this->checktime($time['hour'], $time['minute'], $time['second'])) {
+            $message = _("Please enter a valid time.");
+            return false;
+        } elseif ($this->emptyTimeArray($time) && $var->isRequired()) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        return true;
+    }
+
+    function checktime($hour, $minute, $second)
+    {
+        if (!isset($hour) || $hour == '' || ($hour < 0 || $hour > 23)) {
+            return false;
+        }
+        if (!isset($minute) || $minute == '' || ($minute < 0 || $minute > 60)) {
+            return false;
+        }
+        if (!isset($second) || $second === '' || ($second < 0 || $second > 60)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Return the time supplied as a Horde_Date object.
+     *
+     * @param string $time_in  Date in one of the three formats supported by
+     *                         Horde_Form and Horde_Date (ISO format
+     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS and
+     *                         UNIX epoch).
+     *
+     * @return Date  The time object.
+     */
+    function getTimeOb($time_in)
+    {
+        if (is_array($time_in)) {
+            if (!$this->emptyTimeArray($time_in)) {
+                $time_in = sprintf('1970-01-01 %02d:%02d:%02d', $time_in['hour'], $time_in['minute'], $this->_show_seconds ? $time_in['second'] : 0);
+            }
+        }
+
+        return new Horde_Date($time_in);
+    }
+
+    /**
+     * Return the time supplied split up into an array.
+     *
+     * @param string $time_in  Time in one of the three formats supported by
+     *                         Horde_Form and Horde_Date (ISO format
+     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS and
+     *                         UNIX epoch).
+     *
+     * @return array  Array with three elements - hour, minute and seconds.
+     */
+    function getTimeParts($time_in)
+    {
+        if (is_array($time_in)) {
+            /* This is probably a failed isValid input so just return the
+             * parts as they are. */
+            return $time_in;
+        } elseif (empty($time_in)) {
+            /* This is just an empty field so return empty parts. */
+            return array('hour' => '', 'minute' => '', 'second' => '');
+        }
+        $time = $this->getTimeOb($time_in);
+        return array('hour' => $time->hour,
+                     'minute' => $time->min,
+                     'second' => $time->sec);
+    }
+
+    function emptyTimeArray($time)
+    {
+        return (is_array($time) && empty($time['hour']) && empty($time['minute']) && empty($time['second']));
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Time selection"),
+            'params' => array(
+                'seconds' => array('label' => _("Show seconds?"),
+                                  'type'  => 'boolean')));
+    }
+
+}
+
+class Horde_Form_Type_monthyear extends Horde_Form_Type {
+
+    var $_start_year;
+    var $_end_year;
+
+    function init($start_year = null, $end_year = null)
+    {
+        if (empty($start_year)) {
+            $start_year = 1920;
+        }
+        if (empty($end_year)) {
+            $end_year = date('Y');
+        }
+
+        $this->_start_year = $start_year;
+        $this->_end_year = $end_year;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if (!$var->isRequired()) {
+            return true;
+        }
+
+        if (!$vars->get($this->getMonthVar($var)) ||
+            !$vars->get($this->getYearVar($var))) {
+            $message = _("Please enter a month and a year.");
+            return false;
+        }
+
+        return true;
+    }
+
+    function getMonthVar($var)
+    {
+        return $var->getVarName() . '[month]';
+    }
+
+    function getYearVar($var)
+    {
+        return $var->getVarName() . '[year]';
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Month and year"),
+                     'params' => array(
+                         'start_year' => array('label' => _("Start year"),
+                                               'type'  => 'int'),
+                         'end_year'   => array('label' => _("End year"),
+                                               'type'  => 'int')));
+    }
+
+}
+
+class Horde_Form_Type_monthdayyear extends Horde_Form_Type {
+
+    var $_start_year;
+    var $_end_year;
+    var $_picker;
+    var $_format_in = null;
+    var $_format_out = '%x';
+
+    /**
+     * Return the date supplied as a Horde_Date object.
+     *
+     * @param integer $start_year  The first available year for input.
+     * @param integer $end_year    The last available year for input.
+     * @param boolean $picker      Do we show the DHTML calendar?
+     * @param integer $format_in   The format to use when sending the date
+     *                             for storage. Defaults to Unix epoch.
+     *                             Similar to the strftime() function.
+     * @param integer $format_out  The format to use when displaying the
+     *                             date. Similar to the strftime() function.
+     */
+    function init($start_year = '', $end_year = '', $picker = true,
+                  $format_in = null, $format_out = '%x')
+    {
+        if (empty($start_year)) {
+            $start_year = date('Y');
+        }
+        if (empty($end_year)) {
+            $end_year = date('Y') + 10;
+        }
+
+        $this->_start_year = $start_year;
+        $this->_end_year = $end_year;
+        $this->_picker = $picker;
+        $this->_format_in = $format_in;
+        $this->_format_out = $format_out;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        $date = $vars->get($var->getVarName());
+        $empty = $this->emptyDateArray($date);
+
+        if ($empty == 1 && $var->isRequired()) {
+            $message = _("This field is required.");
+            return false;
+        } elseif ($empty == 0 && !checkdate($date['month'], $date['day'], $date['year'])) {
+            $message = _("Please enter a valid date, check the number of days in the month.");
+            return false;
+        } elseif ($empty == -1) {
+            $message = _("Select all date components.");
+            return false;
+        }
+
+        return true;
+    }
+
+    function emptyDateArray($date)
+    {
+        if (!is_array($date)) {
+            return empty($date);
+        }
+
+        $empty = 0;
+        /* Check each date array component. */
+        foreach ($date as $key => $val) {
+            if (empty($val)) {
+                $empty++;
+            }
+        }
+
+        /* Check state of empty. */
+        if ($empty == 0) {
+            /* If no empty parts return 0. */
+            return 0;
+        } elseif ($empty == count($date)) {
+            /* If all empty parts return 1. */
+            return 1;
+        } else {
+            /* If some empty parts return -1. */
+            return -1;
+        }
+    }
+
+    /**
+     * Return the date supplied split up into an array.
+     *
+     * @param string $date_in  Date in one of the three formats supported by
+     *                         Horde_Form and Horde_Date (ISO format
+     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS
+     *                         and UNIX epoch) plus the fourth YYYY-MM-DD.
+     *
+     * @return array  Array with three elements - year, month and day.
+     */
+    function getDateParts($date_in)
+    {
+        if (is_array($date_in)) {
+            /* This is probably a failed isValid input so just return
+             * the parts as they are. */
+            return $date_in;
+        } elseif (empty($date_in)) {
+            /* This is just an empty field so return empty parts. */
+            return array('year' => '', 'month' => '', 'day' => '');
+        }
+
+        $date = $this->getDateOb($date_in);
+        return array('year' => $date->year,
+                     'month' => $date->month,
+                     'day' => $date->mday);
+    }
+
+    /**
+     * Return the date supplied as a Horde_Date object.
+     *
+     * @param string $date_in  Date in one of the three formats supported by
+     *                         Horde_Form and Horde_Date (ISO format
+     *                         YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS
+     *                         and UNIX epoch) plus the fourth YYYY-MM-DD.
+     *
+     * @return Date  The date object.
+     */
+    function getDateOb($date_in)
+    {
+        if (is_array($date_in)) {
+            /* If passed an array change it to the ISO format. */
+            if ($this->emptyDateArray($date_in) == 0) {
+                $date_in = sprintf('%04d-%02d-%02d 00:00:00',
+                                   $date_in['year'],
+                                   $date_in['month'],
+                                   $date_in['day']);
+            }
+        } elseif (preg_match('/^\d{4}-?\d{2}-?\d{2}$/', $date_in)) {
+            /* Fix the date if it is the shortened ISO. */
+            $date_in = $date_in . ' 00:00:00';
+        }
+
+        return new Horde_Date($date_in);
+    }
+
+    /**
+     * Return the date supplied as a Horde_Date object.
+     *
+     * @param string $date  Either an already set up Horde_Date object or a
+     *                      string date in one of the three formats supported
+     *                      by Horde_Form and Horde_Date (ISO format
+     *                      YYYY-MM-DD HH:MM:SS, timestamp YYYYMMDDHHMMSS and
+     *                      UNIX epoch) plus the fourth YYYY-MM-DD.
+     *
+     * @return string  The date formatted according to the $format_out
+     *                 parameter when setting up the monthdayyear field.
+     */
+    function formatDate($date)
+    {
+        if (!is_a($date, 'Date')) {
+            $date = $this->getDateOb($date);
+        }
+
+        return $date->strftime($this->_format_out);
+    }
+
+    /**
+     * Insert the date input through the form into $info array, in the format
+     * specified by the $format_in parameter when setting up monthdayyear
+     * field.
+     */
+    function getInfo($vars, &$var, &$info)
+    {
+        $info = $this->_validateAndFormat($var->getValue($vars), $var);
+    }
+
+    /**
+     * Validate/format a date submission.
+     */
+    function _validateAndFormat($value, $var)
+    {
+        /* If any component is empty consider it a bad date and return the
+         * default. */
+        if ($this->emptyDateArray($value) == 1) {
+            return $var->getDefault();
+        } else {
+            $date = $this->getDateOb($value);
+            if ($this->_format_in === null) {
+                return $date->timestamp();
+            } else {
+                return $date->strftime($this->_format_in);
+            }
+        }
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Date selection"),
+            'params' => array(
+                'start_year' => array('label' => _("Start year"),
+                                      'type'  => 'int'),
+                'end_year'   => array('label' => _("End year"),
+                                      'type'  => 'int'),
+                'picker'     => array('label' => _("Show picker?"),
+                                      'type'  => 'boolean'),
+                'format_in'  => array('label' => _("Storage format"),
+                                      'type'  => 'text'),
+                'format_out' => array('label' => _("Display format"),
+                                      'type'  => 'text')));
+    }
+
+}
+
+/**
+ * @since Horde 3.2
+ */
+class Horde_Form_Type_datetime extends Horde_Form_Type {
+
+    var $_mdy;
+    var $_hms;
+
+    /**
+     * Return the date supplied as a Horde_Date object.
+     *
+     * @param integer $start_year  The first available year for input.
+     * @param integer $end_year    The last available year for input.
+     * @param boolean $picker      Do we show the DHTML calendar?
+     * @param integer $format_in   The format to use when sending the date
+     *                             for storage. Defaults to Unix epoch.
+     *                             Similar to the strftime() function.
+     * @param integer $format_out  The format to use when displaying the
+     *                             date. Similar to the strftime() function.
+     * @param boolean $show_seconds Include a form input for seconds.
+     */
+    function init($start_year = '', $end_year = '', $picker = true,
+                  $format_in = null, $format_out = '%x', $show_seconds = false)
+    {
+        $this->_mdy = new Horde_Form_Type_monthdayyear();
+        $this->_mdy->init($start_year, $end_year, $picker, $format_in, $format_out);
+
+        $this->_hms = new Horde_Form_Type_hourminutesecond();
+        $this->_hms->init($show_seconds);
+    }
+
+    function isValid(&$var, &$vars, $value, &$message)
+    {
+        if ($var->isRequired()) {
+            return $this->_mdy->isValid($var, $vars, $value, $message) &&
+                $this->_hms->isValid($var, $vars, $value, $message);
+        }
+        return true;
+    }
+
+    function getInfo(&$vars, &$var, &$info)
+    {
+        /* If any component is empty consider it a bad date and return the
+         * default. */
+        $value = $var->getValue($vars);
+        if ($this->emptyDateArray($value) == 1 || $this->emptyTimeArray($value)) {
+            $info = $var->getDefault();
+            return;
+        }
+
+        $date = $this->getDateOb($value);
+        $time = $this->getTimeOb($value);
+        $date->hour = $time->hour;
+        $date->min = $time->min;
+        $date->sec = $time->sec;
+        if (is_null($this->format_in)) {
+            $info = $date->timestamp();
+        } else {
+            $info = $date->strftime($this->format_in);
+        }
+    }
+
+    function __get($property)
+    {
+        if ($property == 'show_seconds') {
+            return $this->_hms->$property;
+        } else {
+            return $this->_mdy->$property;
+        }
+    }
+
+    function __set($property, $value)
+    {
+        if ($property == 'show_seconds') {
+            $this->_hms->$property = $value;
+        } else {
+            $this->_mdy->$property = $value;
+        }
+    }
+
+    function checktime($hour, $minute, $second)
+    {
+        return $this->_hms->checktime($hour, $minute, $second);
+    }
+
+    function getTimeOb($time_in)
+    {
+        return $this->_hms->getTimeOb($time_in);
+    }
+
+    function getTimeParts($time_in)
+    {
+        return $this->_hms->getTimeParts($time_in);
+    }
+
+    function emptyTimeArray($time)
+    {
+        return $this->_hms->emptyTimeArray($time);
+    }
+
+    function emptyDateArray($date)
+    {
+        return $this->_mdy->emptyDateArray($date);
+    }
+
+    function getDateParts($date_in)
+    {
+        return $this->_mdy->getDateParts($date_in);
+    }
+
+    function getDateOb($date_in)
+    {
+        return $this->_mdy->getDateOb($date_in);
+    }
+
+    function formatDate($date)
+    {
+        if ($date === null) {
+            return '';
+        }
+        return $this->_mdy->formatDate($date);
+    }
+
+    function about()
+    {
+        return array(
+            'name' => _("Date and time selection"),
+            'params' => array(
+                'start_year' => array('label' => _("Start year"),
+                                      'type'  => 'int'),
+                'end_year'   => array('label' => _("End year"),
+                                      'type'  => 'int'),
+                'picker'     => array('label' => _("Show picker?"),
+                                      'type'  => 'boolean'),
+                'format_in'  => array('label' => _("Storage format"),
+                                      'type'  => 'text'),
+                'format_out' => array('label' => _("Display format"),
+                                      'type'  => 'text'),
+                'seconds'    => array('label' => _("Show seconds?"),
+                                      'type'  => 'boolean')));
+    }
+
+}
+
+class Horde_Form_Type_colorpicker extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->isRequired() && empty($value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^#([0-9a-z]){6}$/i', $value)) {
+            return true;
+        }
+
+        $message = _("This field must contain a color code in the RGB Hex format, for example '#1234af'.");
+        return false;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Colour selection"));
+    }
+
+}
+
+class Horde_Form_Type_sorter extends Horde_Form_Type {
+
+    var $_instance;
+    var $_values;
+    var $_size;
+    var $_header;
+
+    function init($values, $size = 8, $header = '')
+    {
+        static $horde_sorter_instance = 0;
+
+        /* Get the next progressive instance count for the horde
+         * sorter so that multiple sorters can be used on one page. */
+        $horde_sorter_instance++;
+        $this->_instance = 'horde_sorter_' . $horde_sorter_instance;
+        $this->_values = $values;
+        $this->_size   = $size;
+        $this->_header = $header;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    function getOptions($keys = null)
+    {
+        $html = '';
+        if ($this->_header) {
+            $html .= '<option value="">' . htmlspecialchars($this->_header) . '</option>';
+        }
+
+        if (empty($keys)) {
+            $keys = array_keys($this->_values);
+        } else {
+            $keys = explode("\t", $keys['array']);
+        }
+        foreach ($keys as $sl_key) {
+            $html .= '<option value="' . $sl_key . '">' . htmlspecialchars($this->_values[$sl_key]) . '</option>';
+        }
+
+        return $html;
+    }
+
+    function getInfo($vars, &$var, &$info)
+    {
+        $value = $vars->get($var->getVarName());
+        $info = explode("\t", $value['array']);
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Sort order selection"),
+            'params' => array(
+                'values' => array('label' => _("Values"),
+                                  'type'  => 'stringlist'),
+                'size'   => array('label' => _("Size"),
+                                  'type'  => 'int'),
+                'header' => array('label' => _("Header"),
+                                  'type'  => 'text')));
+    }
+
+}
+
+class Horde_Form_Type_selectfiles extends Horde_Form_Type {
+
+    /**
+     * The text to use in the link.
+     *
+     * @var string
+     */
+    var $_link_text;
+
+    /**
+     * The style to use for the link.
+     *
+     * @var string
+     */
+    var $_link_style;
+
+    /**
+     *  Create the link with an icon instead of text?
+     *
+     * @var boolean
+     */
+    var $_icon;
+
+    /**
+     * Contains gollem selectfile selectionID
+     *
+     * @var string
+     */
+    var $_selectid;
+
+    function init($selectid, $link_text = null, $link_style = '',
+                  $icon = false)
+    {
+        $this->_selectid = $selectid;
+        if (is_null($link_text)) {
+            $link_text = _("Select Files");
+        }
+        $this->_link_text = $link_text;
+        $this->_link_style = $link_style;
+        $this->_icon = $icon;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    function getInfo($var, &$vars, &$info)
+    {
+        $value = $vars->getValue($var);
+        $info = $GLOBALS['registry']->call('files/selectlistResults', array($value));
+    }
+
+    function about()
+    {
+        return array(
+            'name' => _("File selection"),
+            'params' => array(
+                'selectid'   => array('label' => _("Id"),
+                                      'type' => 'text'),
+                'link_text'  => array('label' => _("Link text"),
+                                      'type' => 'text'),
+                'link_style' => array('label' => _("Link style"),
+                                      'type' => 'text'),
+                'icon'       => array('label' => _("Show icon?"),
+                                      'type' => 'boolean')));
+    }
+
+}
+
+class Horde_Form_Type_assign extends Horde_Form_Type {
+
+    var $_leftValues;
+    var $_rightValues;
+    var $_leftHeader;
+    var $_rightHeader;
+    var $_size;
+    var $_width;
+
+    function init($leftValues, $rightValues, $leftHeader = '',
+                  $rightHeader = '', $size = 8, $width = '200px')
+    {
+        $this->_leftValues = $leftValues;
+        $this->_rightValues = $rightValues;
+        $this->_leftHeader = $leftHeader;
+        $this->_rightHeader = $rightHeader;
+        $this->_size = $size;
+        $this->_width = $width;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    function setValues($side, $values)
+    {
+        if ($side) {
+            $this->_rightValues = $values;
+        } else {
+            $this->_leftValues = $values;
+        }
+    }
+
+    function getHeader($side)
+    {
+        return $side ? $this->_rightHeader : $this->_leftHeader;
+    }
+
+    function getOptions($side, $formname, $varname)
+    {
+        $html = '';
+        $headers = false;
+        if ($side) {
+            $values = $this->_rightValues;
+            if (!empty($this->_rightHeader)) {
+                $values = array('' => $this->_rightHeader) + $values;
+                $headers = true;
+            }
+        } else {
+            $values = $this->_leftValues;
+            if (!empty($this->_leftHeader)) {
+                $values = array('' => $this->_leftHeader) + $values;
+                $headers = true;
+            }
+        }
+
+        foreach ($values as $key => $val) {
+            $html .= '<option value="' . htmlspecialchars($key) . '"';
+            if ($headers) {
+                $headers = false;
+            } else {
+                $html .= ' ondblclick="Horde_Form_Assign.move(\'' . $formname . '\', \'' . $varname . '\', ' . (int)$side . ');"';
+            }
+            $html .= '>' . htmlspecialchars($val) . '</option>';
+        }
+
+        return $html;
+    }
+
+    function getInfo($vars, &$var, &$info)
+    {
+        $value = $vars->get($var->getVarName() . '__values');
+        if (strpos($value, "\t\t") === false) {
+            $left = $value;
+            $right = '';
+        } else {
+            list($left, $right) = explode("\t\t", $value);
+        }
+        if (empty($left)) {
+            $info['left'] = array();
+        } else {
+            $info['left'] = explode("\t", $left);
+        }
+        if (empty($right)) {
+            $info['right'] = array();
+        } else {
+            $info['right'] = explode("\t", $right);
+        }
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Assignment columns"),
+            'params' => array(
+                'leftValues'  => array('label' => _("Left values"),
+                                       'type'  => 'stringlist'),
+                'rightValues' => array('label' => _("Right values"),
+                                       'type'  => 'stringlist'),
+                'leftHeader'  => array('label' => _("Left header"),
+                                       'type'  => 'text'),
+                'rightHeader' => array('label' => _("Right header"),
+                                       'type'  => 'text'),
+                'size'        => array('label' => _("Size"),
+                                       'type'  => 'int'),
+                'width'       => array('label' => _("Width in CSS units"),
+                                       'type'  => 'text')));
+    }
+
+}
+
+class Horde_Form_Type_creditcard extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if (empty($value) && $var->isRequired()) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (!empty($value)) {
+            /* getCardType() will also verify the checksum. */
+            $type = $this->getCardType($value);
+            if ($type === false || $type == 'unknown') {
+                $message = _("This does not seem to be a valid card number.");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    function getChecksum($ccnum)
+    {
+        $len = strlen($ccnum);
+        if (!is_long($len / 2)) {
+            $weight = 2;
+            $digit = $ccnum[0];
+        } elseif (is_long($len / 2)) {
+            $weight = 1;
+            $digit = $ccnum[0] * 2;
+        }
+        if ($digit > 9) {
+            $digit = $digit - 9;
+        }
+        $i = 1;
+        $checksum = $digit;
+        while ($i < $len) {
+            if ($ccnum[$i] != ' ') {
+                $digit = $ccnum[$i] * $weight;
+                $weight = ($weight == 1) ? 2 : 1;
+                if ($digit > 9) {
+                    $digit = $digit - 9;
+                }
+                $checksum += $digit;
+            }
+            $i++;
+        }
+
+        return $checksum;
+    }
+
+    function getCardType($ccnum)
+    {
+        $sum = $this->getChecksum($ccnum);
+        $l = strlen($ccnum);
+
+        // Screen checksum.
+        if (($sum % 10) != 0) {
+            return false;
+        }
+
+        // Check for Visa.
+        if ((($l == 16) || ($l == 13)) &&
+            ($ccnum[0] == 4)) {
+            return 'visa';
+        }
+
+        // Check for MasterCard.
+        if (($l == 16) &&
+            ($ccnum[0] == 5) &&
+            ($ccnum[1] >= 1) &&
+            ($ccnum[1] <= 5)) {
+            return 'mastercard';
+        }
+
+        // Check for Amex.
+        if (($l == 15) &&
+            ($ccnum[0] == 3) &&
+            (($ccnum[1] == 4) || ($ccnum[1] == 7))) {
+            return 'amex';
+        }
+
+        // Check for Discover (Novus).
+        if (strlen($ccnum) == 16 &&
+            substr($ccnum, 0, 4) == '6011') {
+            return 'discover';
+        }
+
+        // If we got this far, then no card matched.
+        return 'unknown';
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Credit card number"));
+    }
+
+}
+
+class Horde_Form_Type_obrowser extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array('name' => _("Relationship browser"));
+    }
+
+}
+
+class Horde_Form_Type_dblookup extends Horde_Form_Type_enum {
+
+    function init($dsn, $sql, $prompt = null)
+    {
+        $values = array();
+        $db = DB::connect($dsn);
+        if (!is_a($db, 'PEAR_Error')) {
+            // Set DB portability options.
+            switch ($db->phptype) {
+            case 'mssql':
+                $db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+                break;
+            default:
+                $db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+            }
+
+            $col = $db->getCol($sql);
+            if (!is_a($col, 'PEAR_Error')) {
+                $values = Horde_Array::combine($col, $col);
+            }
+        }
+        parent::init($values, $prompt);
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Database lookup"),
+            'params' => array(
+                'dsn' => array('label' => _("DSN (see http://pear.php.net/manual/en/package.database.db.intro-dsn.php)"),
+                               'type'  => 'text'),
+                'sql' => array('label' => _("SQL statement for value lookups"),
+                               'type'  => 'text'),
+                'prompt' => array('label' => _("Prompt text"),
+                                  'type'  => 'text'))
+            );
+    }
+
+}
+
+class Horde_Form_Type_figlet extends Horde_Form_Type {
+
+    var $_text;
+    var $_font;
+
+    function init($text, $font)
+    {
+        $this->_text = $text;
+        $this->_font = $font;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if (empty($value) && $var->isRequired()) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (String::lower($value) != String::lower($this->_text)) {
+            $message = _("The text you entered did not match the text on the screen.");
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Return info about field type.
+     */
+    function about()
+    {
+        return array(
+            'name' => _("Figlet CAPTCHA"),
+            'params' => array(
+                'text' => array('label' => _("Text"),
+                                'type'  => 'text'),
+                'font' => array('label' => _("Figlet font"),
+                                'type'  => 'text'))
+            );
+    }
+
+}
+
+class Horde_Form_Type_invalid extends Horde_Form_Type {
+
+    var $message;
+
+    function init($message)
+    {
+        $this->message = $message;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return false;
+    }
+
+}
+
+/**
+ * This class represents a single form variable that may be rendered as one or
+ * more form fields.
+ *
+ * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+ * @package Horde_Form
+ */
+class Horde_Form_Variable {
+
+    /**
+     * The form instance this variable is assigned to.
+     *
+     * @var Horde_Form
+     */
+    var $form;
+
+    /**
+     * A short description of this variable's purpose.
+     *
+     * @var string
+     */
+    var $humanName;
+
+    /**
+     * The internally used name.
+     *
+     * @var string
+     */
+    var $varName;
+
+    /**
+     * A {@link Horde_Form_Type} instance.
+     *
+     * @var Horde_Form_Type
+     */
+    var $type;
+
+    /**
+     * Whether this is a required variable.
+     *
+     * @var boolean
+     */
+    var $required;
+
+    /**
+     * Whether this is a readonly variable.
+     *
+     * @var boolean
+     */
+    var $readonly;
+
+    /**
+     * A long description of the variable's purpose, special instructions, etc.
+     *
+     * @var string
+     */
+    var $description;
+
+    /**
+     * The variable help text.
+     *
+     * @var string
+     */
+    var $help;
+
+    /**
+     * Whether this is an array variable.
+     *
+     * @var boolean
+     */
+    var $_arrayVal;
+
+    /**
+     * The default value.
+     *
+     * @var mixed
+     */
+    var $_defValue = null;
+
+    /**
+     * A {@link Horde_Form_Action} instance.
+     *
+     * @var Horde_Form_Action
+     */
+    var $_action;
+
+    /**
+     * Whether this variable is disabled.
+     *
+     * @var boolean
+     */
+    var $_disabled = false;
+
+    /**
+     * TODO
+     *
+     * @var boolean
+     */
+    var $_autofilled = false;
+
+    /**
+     * Whether this is a hidden variable.
+     *
+     * @var boolean
+     */
+    var $_hidden = false;
+
+    /**
+     * TODO
+     *
+     * @var array
+     */
+    var $_options = array();
+
+    /**
+     * Variable constructor.
+     *
+     * @param string $humanName      A short description of the variable's
+     *                               purpose.
+     * @param string $varName        The internally used name.
+     * @param Horde_Form_Type $type  A {@link Horde_Form_Type} instance.
+     * @param boolean $required      Whether this is a required variable.
+     * @param boolean $readonly      Whether this is a readonly variable.
+     * @param string $description    A long description of the variable's
+     *                               purpose, special instructions, etc.
+     */
+    function Horde_Form_Variable($humanName, $varName, $type, $required,
+                                 $readonly = false, $description = null)
+    {
+        $this->humanName   = $humanName;
+        $this->varName     = $varName;
+        $this->type        = $type;
+        $this->required    = $required;
+        $this->readonly    = $readonly;
+        $this->description = $description;
+        $this->_arrayVal   = (strpos($varName, '[]') !== false);
+    }
+
+    /**
+     * Assign this variable to the specified form.
+     *
+     * @param Horde_Form $form  The form instance to assign this variable to.
+     */
+    function setFormOb($form)
+    {
+        $this->form = $form;
+    }
+
+    /**
+     * Sets a default value for this variable.
+     *
+     * @param mixed $value  A variable value.
+     */
+    function setDefault($value)
+    {
+        $this->_defValue = $value;
+    }
+
+    /**
+     * Returns this variable's default value.
+     *
+     * @return mixed  This variable's default value.
+     */
+    function getDefault()
+    {
+        return $this->_defValue;
+    }
+
+    /**
+     * Assigns an action to this variable.
+     *
+     * Example:
+     * <code>
+     * $v = $form->addVariable('My Variable', 'var1', 'text', false);
+     * $action = new Horde_Form_Action_submit;
+     * $v->setAction($action);
+     * </code>
+     *
+     * @param Horde_Form_Action $action  A {@link Horde_Form_Action} instance.
+     */
+    function setAction($action)
+    {
+        $this->_action = $action;
+    }
+
+    /**
+     * Returns whether this variable has an attached action.
+     *
+     * @return boolean  True if this variable has an attached action.
+     */
+    function hasAction()
+    {
+        return !is_null($this->_action);
+    }
+
+    /**
+     * Makes this a hidden variable.
+     */
+    function hide()
+    {
+        $this->_hidden = true;
+    }
+
+    /**
+     * Returns whether this is a hidden variable.
+     *
+     * @return boolean  True if this a hidden variable.
+     */
+    function isHidden()
+    {
+        return $this->_hidden;
+    }
+
+    /**
+     * Disables this variable.
+     */
+    function disable()
+    {
+        $this->_disabled = true;
+    }
+
+    /**
+     * Returns whether this variable is disabled.
+     *
+     * @return boolean  True if this variable is disabled.
+     */
+    function isDisabled()
+    {
+        return $this->_disabled;
+    }
+
+    /**
+     * Return the short description of this variable.
+     *
+     * @return string  A short description
+     */
+    function getHumanName()
+    {
+        return $this->humanName;
+    }
+
+    /**
+     * Returns the internally used variable name.
+     *
+     * @return string  This variable's internal name.
+     */
+    function getVarName()
+    {
+        return $this->varName;
+    }
+
+    /**
+     * Returns this variable's type.
+     *
+     * @return Horde_Form_Type  This variable's {@link Horde_Form_Type}
+     *                          instance.
+     */
+    function getType()
+    {
+        return $this->type;
+    }
+
+    /**
+     * Returns whether this is a required variable.
+     *
+     * @return boolean  True if this is a required variable.
+     */
+    function isRequired()
+    {
+        return $this->required;
+    }
+
+    /**
+     * Returns whether this is a readonly variable.
+     *
+     * @return boolean  True if this a readonly variable.
+     */
+    function isReadonly()
+    {
+        return $this->readonly;
+    }
+
+    /**
+     * Returns the possible values of this variable.
+     *
+     * @return array  The possible values of this variable or null.
+     */
+    function getValues()
+    {
+        return $this->type->values;
+    }
+
+    /**
+     * Returns whether this variable has a long description.
+     *
+     * @return boolean  True if this variable has a long description.
+     */
+    function hasDescription()
+    {
+        return !empty($this->description);
+    }
+
+    /**
+     * Returns this variable's long description.
+     *
+     * @return string  This variable's long description.
+     */
+    function getDescription()
+    {
+        return $this->description;
+    }
+
+    /**
+     * Returns whether this is an array variable.
+     *
+     * @return boolean  True if this an array variable.
+     */
+    function isArrayVal()
+    {
+        return $this->_arrayVal;
+    }
+
+    /**
+     * Returns whether this variable is to upload a file.
+     *
+     * @return boolean  True if variable is to upload a file.
+     */
+    function isUpload()
+    {
+        return ($this->type instanceof Horde_Form_Type_file);
+    }
+
+    /**
+     * Assigns a help text to this variable.
+     *
+     * @param string $help  The variable help text.
+     */
+    function setHelp($help)
+    {
+        $this->form->_help = true;
+        $this->help = $help;
+    }
+
+    /**
+     * Returns whether this variable has some help text assigned.
+     *
+     * @return boolean  True if this variable has a help text.
+     */
+    function hasHelp()
+    {
+        return !empty($this->help);
+    }
+
+    /**
+     * Returns the help text of this variable.
+     *
+     * @return string  This variable's help text.
+     */
+    function getHelp()
+    {
+        return $this->help;
+    }
+
+    /**
+     * Sets a variable option.
+     *
+     * @param string $option  The option name.
+     * @param mixed $val      The option's value.
+     */
+    function setOption($option, $val)
+    {
+        $this->_options[$option] = $val;
+    }
+
+    /**
+     * Returns a variable option's value.
+     *
+     * @param string $option  The option name.
+     *
+     * @return mixed          The option's value.
+     */
+    function getOption($option)
+    {
+        return isset($this->_options[$option]) ? $this->_options[$option] : null;
+    }
+
+    /**
+     * Processes the submitted value of this variable according to the rules of
+     * the variable type.
+     *
+     * @param Variables $vars  The {@link Variables} instance of the submitted
+     *                         form.
+     * @param mixed $info      A variable passed by reference that will be
+     *                         assigned the processed value of the submitted
+     *                         variable value.
+     *
+     * @return mixed  Depending on the variable type.
+     */
+    function getInfo($vars, &$info)
+    {
+        return $this->type->getInfo($vars, $this, $info);
+    }
+
+    /**
+     * Returns whether this variable if it had the "trackchange" option set
+     * has actually been changed.
+     *
+     * @param Variables $vars  The {@link Variables} instance of the submitted
+     *                         form.
+     *
+     * @return boolean  Null if this variable doesn't have the "trackchange"
+     *                  option set or the form wasn't submitted yet. A boolean
+     *                  indicating whether the variable was changed otherwise.
+     */
+    function wasChanged($vars)
+    {
+        if (!$this->getOption('trackchange')) {
+            return null;
+        }
+        $old = $vars->get('__old_' . $this->getVarName());
+        if (is_null($old)) {
+            return null;
+        }
+        return $old != $vars->get($this->getVarName());
+    }
+
+    /**
+     * Validates this variable.
+     *
+     * @param Variables $vars  The {@link Variables} instance of the submitted
+     *                         form.
+     * @param string $message  A variable passed by reference that will be
+     *                         assigned a descriptive error message if
+     *                         validation failed.
+     *
+     * @return boolean  True if the variable validated.
+     */
+    function validate($vars, &$message)
+    {
+        if ($this->_arrayVal) {
+            $vals = $this->getValue($vars);
+            if (!is_array($vals)) {
+                if ($this->required) {
+                    $message = _("This field is required.");
+                    return false;
+                } else {
+                    return true;
+                }
+            }
+            foreach ($vals as $i => $value) {
+                if ($value === null && $this->required) {
+                    $message = _("This field is required.");
+                    return false;
+                } else {
+                    if (!$this->type->isValid($this, $vars, $value, $message)) {
+                        return false;
+                    }
+                }
+            }
+        } else {
+            $value = $this->getValue($vars);
+            return $this->type->isValid($this, $vars, $value, $message);
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the submitted or default value of this variable.
+     * If an action is attached to this variable, the value will get passed to
+     * the action object.
+     *
+     * @param Variables $vars  The {@link Variables} instance of the submitted
+     *                         form.
+     * @param integer $index   If the variable is an array variable, this
+     *                         specifies the array element to return.
+     *
+     * @return mixed  The variable or element value.
+     */
+    function getValue($vars, $index = null)
+    {
+        if ($this->_arrayVal) {
+            $name = str_replace('[]', '', $this->varName);
+        } else {
+            $name = $this->varName;
+        }
+        $value = $vars->getExists($name, $wasset);
+
+        if (!$wasset) {
+            $value = $this->getDefault();
+        }
+
+        if ($this->_arrayVal && !is_null($index)) {
+            if (!$wasset && !is_array($value)) {
+                $return = $value;
+            } else {
+                $return = isset($value[$index]) ? $value[$index] : null;
+            }
+        } else {
+            $return = $value;
+        }
+
+        if ($this->hasAction()) {
+            $this->_action->setValues($vars, $return, $this->_arrayVal);
+        }
+
+        return $return;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Renderer.php b/framework/Model/lib/Horde/Form/Renderer.php
new file mode 100644 (file)
index 0000000..867f114
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+/**
+ * @package Horde_Form
+ */
+
+/**
+ * The Horde_Form_Renderer class provides HTML and other renderings of
+ * forms for the Horde_Form:: package.
+ *
+ * $Horde: incubator/Horde_Form/Horde/Form/Renderer.php,v 1.7 2007/09/16 19:51:08 chuck Exp $
+ *
+ * Copyright 2001-2007 Robert E. Coyle <robertecoyle@hotmail.com>
+ * Copyright 2005-2007 Matt Warden <mwarden@gmail.com>
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+ * @author  Matt Warden <mwarden@gmail.com>
+ * @package Horde_Form
+ */
+abstract class Horde_Form_Renderer {
+
+    var $_name;
+    var $_requiredLegend = false;
+    var $_helpMarker = '?';
+    var $_onLoadJS = array();
+    var $_showHeader = true;
+    var $_cols = 2;
+    var $_varRenderer = null;
+    var $_firstField = null;
+    var $_stripedRows = true;
+
+    protected $_submit = array();
+    protected $_reset = false;
+
+    /**
+     * Does the title of the form contain HTML? If so, you are responsible for
+     * doing any needed escaping/sanitization yourself. Otherwise the title
+     * will be run through htmlspecialchars() before being output.
+     *
+     * @var boolean
+     */
+    var $_encodeTitle = true;
+
+    /**
+     * Construct a new Horde_Form_Renderer::.
+     *
+     * @param array $params  This is a hash of renderer-specific parameters.
+     *                       Possible keys:<code>
+     *                       'encode_title': @see $_encodeTitle</code>
+     */
+    function __construct($params = array())
+    {
+        if (isset($params['encode_title'])) {
+            $this->encodeTitle($params['encode_title']);
+        }
+
+        $this->_varRenderer = new Horde_Form_VarRenderer_Xhtml;
+    }
+
+    abstract public function renderActive($form, $action, $method = 'get', $enctype = null, $focus = true);
+
+    public function setButtons($submit, $reset = false)
+    {
+        if ($submit === true || is_null($submit) || empty($submit)) {
+            /* Default to 'Submit'. */
+            $submit = array(_("Submit"));
+        } elseif (!is_array($submit)) {
+            /* Default to array if not passed. */
+            $submit = array($submit);
+        }
+        /* Only if $reset is strictly true insert default 'Reset'. */
+        if ($reset === true) {
+            $reset = _("Reset");
+        }
+
+        $this->_submit = $submit;
+        $this->_reset = $reset;
+
+        return $this;
+    }
+
+    public function addButtons($buttons)
+    {
+        if (!is_array($buttons)) {
+            $buttons = array($buttons);
+        }
+
+        $this->_submit = array_merge($this->_submit, $buttons);
+    }
+
+    public function showHeader($bool)
+    {
+        $this->_showHeader = $bool;
+    }
+
+    /**
+     * Sets or returns whether the form title should be encoded with
+     * htmlspecialchars().
+     *
+     * @param boolean $encode  If true, the form title gets encoded.  If false
+     *                         the title can contain HTML, but the class user
+     *                         is responsible to encode any special characters.
+     *
+     * @return boolean  Whether the form title should be encoded.
+     */
+    function encodeTitle($encode = null)
+    {
+        if (!is_null($encode)) {
+            $this->_encodeTitle = $encode;
+        }
+        return $this->_encodeTitle = $encode;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Renderer/Xhtml.php b/framework/Model/lib/Horde/Form/Renderer/Xhtml.php
new file mode 100644 (file)
index 0000000..3caac34
--- /dev/null
@@ -0,0 +1,455 @@
+<?php
+/**
+ */
+class Horde_Form_Renderer_Xhtml extends Horde_Form_Renderer {
+
+    protected $_enctype = 'multipart/form-data';
+
+    function _renderSectionTabs($form)
+    {
+        /* If javascript is not available, do not render tabs. */
+        if (!$GLOBALS['browser']->hasFeature('javascript')) {
+            return;
+        }
+
+        $open_section = $form->getOpenSection();
+
+        /* Add the javascript for the toggling the sections. */
+        Horde::addScriptFile('form_sections.js', 'horde', true);
+        echo '<script type="text/javascript">' . "\n" .
+            sprintf('var sections_%1$s = new Horde_Form_Sections(\'%1$s\', \'%2$s\');',
+                    $form->getName(),
+                    $open_section) .
+            '</script>';
+
+        /* Loop through the sections and print out a tab for each. */
+        echo "<div class=\"tabset\">\n";
+        $js = array();
+        foreach ($form->_sections as $section => $val) {
+            $class = ($section == $open_section) ? ' class="activeTab"' : '';
+            $tabid = htmlspecialchars($form->getName() . '_tab_' . $section);
+            $js[$linkid] = sprintf('sections_%s.toggle(\'%s\'); return false;"',
+                                   $form->getName(),
+                                   $section);
+            printf('<div%s id="%s"><a href="#" id="%s">%s%s</a></div>' . "\n",
+                   $class,
+                   $tabid,
+                   '_tablink_' . $section,
+                   $form->getSectionImage($section),
+                   $form->getSectionDesc($section));
+        }
+        echo "</div>\n";
+
+        // This doesn't help a whole lot now, but if there is a way to
+        // buffer output of JS, then we can keep JS separated from
+        // markup, whereas before the onclicks were assigned as an
+        // HTML attribute.
+        echo '<script type="text/javascript">' . "\n";
+        echo 'if (document.getElementById) {' . "\n";
+        echo '    addEvent(window, \'load\', function() {' . "\n";
+        foreach ($js as $id => $onclick) {
+            $line = '
+if (document.getElementById(%1$s)){
+    document.getElementById(%1$s).onclick = function() {
+        %2$s
+    };
+}';
+            printf($line, $id, $onclick);
+        }
+        echo '    });}</script>' . "\n";
+    }
+
+    function _renderSectionBegin($form, $section)
+    {
+        // Stripe alternate rows if that option is turned on.
+        if ($this->_stripedRows) {
+            Horde::addScriptFile('stripe.js', 'horde', true);
+            $class = 'striped';
+        } else {
+            $class = '';
+        }
+
+        $open_section = $form->getOpenSection();
+        if (empty($open_section)) {
+            $open_section = '__base';
+        }
+
+        // include a general class name for styling purposes. also helps select
+        // ULs, which only get a className currently if they are striped.
+        printf('<fieldset id="%s" class="%s form-section %s">',
+               htmlspecialchars($form->getName() . '_section_' . $section),
+               ($open_section == $section ? 'form-sectionshown' : 'form-sectionhidden'),
+               $class);
+    }
+
+    function _renderSectionEnd()
+    {
+        echo '</fieldset>';
+    }
+
+    function preserveVarByPost($vars, $varname, $alt_varname = '')
+    {
+        $value = $vars->getExists($varname, $wasset);
+
+        if ($alt_varname) {
+            $varname = $alt_varname;
+        }
+
+        if ($wasset) {
+            $this->_preserveVarByPost($varname, $value);
+        }
+    }
+
+    function _preserveVarByPost($varname, $value)
+    {
+        if (is_array($value)) {
+            foreach ($value as $id => $val) {
+                $this->_preserveVarByPost($varname . '[' . $id . ']', $val);
+            }
+        } else {
+            $varname = htmlspecialchars($varname);
+            $value = htmlspecialchars($value);
+            printf('<input type="hidden" id="%1$s" name="%1$s" value="%2$s" />'."\n",
+                   $varname,
+                   $value);
+        }
+    }
+
+    function listFormVars($form)
+    {
+        $variables = $form->getVariables(true, true);
+        $vars = array();
+        if ($variables) {
+            foreach ($variables as $var) {
+                if (is_object($var)) {
+                    if (!$var->isReadonly()) {
+                        $vars[$var->getVarName()] = 1;
+                    }
+                } else {
+                    $vars[$var] = 1;
+                }
+            }
+        }
+        require_once 'Horde/NLS.php';
+        echo '<input type="hidden" name="_formvars" value="'
+            . htmlspecialchars(serialize($vars), ENT_QUOTES, NLS::getCharset())
+            . '" />';
+    }
+
+    public function renderActive($form, $action, $method = 'get', $enctype = null, $focus = true)
+    {
+        $this->_name = $form->getName();
+
+        echo "<form class=\"horde-form\" action=\"$action\" method=\"$method\""
+            . (empty($this->_name) ? '' : ' id="' . $this->_name. '"')
+            . (is_null($this->_enctype) ? '' : ' enctype="' . $this->_enctype . '"')
+            . ">\n";
+        echo Util::formInput();
+
+        $this->listFormVars($form);
+
+        if (!empty($this->_name)) {
+            $this->_preserveVarByPost('formname', $this->_name);
+        }
+
+        if ($form->useToken()) {
+            $this->_preserveVarByPost($this->_name . '_formToken', Horde_Token::generateId($this->_name));
+        }
+
+        if (count($form->getSections())) {
+            $this->_preserveVarByPost('__formOpenSection', $form->getOpenSection());
+        }
+
+        $vars = $form->getVars();
+
+        $variables = $form->getVariables();
+        foreach ($variables as $var) {
+            if ($var->getOption('trackchange')) {
+                $varname = $var->getVarName();
+                $this->preserveVarByPost($vars, $varname, '__old_' . $varname);
+            }
+        }
+
+        foreach ($form->getHiddenVariables() as $var) {
+            $this->preserveVarByPost($vars, $var->getVarName());
+        }
+
+        $this->_renderBeginActive($form->getTitle());
+        $this->_renderForm($form, true);
+        $this->submit($this->_submit, $this->_reset);
+
+        echo "\n</fieldset>\n</form>\n";
+        if ($focus && !empty($this->_firstField)) {
+            echo '<script type="text/javascript">
+try {
+    document.getElementById("'. $this->_firstField .'").focus();
+} catch (e) {}
+</script>
+';
+        }
+    }
+
+    function renderInactive($form)
+    {
+        $this->_name = $form->getName();
+        $this->_renderBeginInactive($form->getTitle());
+        $this->_renderForm($form, false);
+    }
+
+    function _renderForm($form, $active)
+    {
+        $vars = $form->getVars();
+
+        /* If help is present 3 columns are needed. */
+        $this->_cols = $form->hasHelp() ? 3 : 2;
+
+        $variables = $form->getVariables(false);
+
+        /* Check for a form token error. */
+        if (($tokenError = $form->getError('_formToken')) !== null) {
+            printf('<p class="form-error">%s</p>'."\n", $tokenError);
+        }
+
+        $error_section = null;
+        reset($variables);
+        if (count($variables) > 1 || key($variables) != '__base') {
+            $this->_renderSectionTabs($form);
+        }
+
+        foreach ($variables as $section_id => $section) {
+            $this->_renderSectionBegin($form, $section_id);
+            foreach ($section as $var) {
+                switch (get_class($var->type)) {
+                case 'Horde_Form_Type_header':
+                    $this->_renderHeader($var->getHumanName(), $form->getError($var->getVarName()));
+                    break;
+
+                case 'Horde_Form_Type_description':
+                    $this->_renderDescription($var->getHumanName());
+                    break;
+
+                case 'Horde_Form_Type_spacer':
+                    $this->_renderSpacer();
+                    break;
+
+                default:
+                    $isInput = ($active && !$var->isReadonly());
+                    $format = $isInput ? 'Input' : 'Display';
+                    $begin = "_renderVar${format}Begin";
+                    $end = "_renderVar${format}End";
+
+                    $this->$begin($form, $var);
+                    echo $this->_varRenderer->render($form, $var, $vars, $isInput);
+                    $this->$end($form, $var);
+
+                    /* Print any javascript if actions present. */
+                    if ($var->hasAction()) {
+                        $var->_action->printJavaScript();
+                    }
+
+                    /* Keep first field. */
+                    if ($active && empty($this->_firstField) && !$var->isReadonly()
+                        && !$var->isHidden()) {
+                        $this->_firstField = $var->getVarName();
+                    }
+
+                    /* Keep section with first error. */
+                    if (is_null($error_section) && $form->getError($var)) {
+                        $error_section = $section_id;
+                    }
+                }
+            }
+
+            $this->_renderSectionEnd();
+        }
+
+        if (!is_null($error_section)) {
+            echo '<script type="text/javascript">' .
+                "\n" . sprintf('sections_%s.toggle(\'%s\');',
+                               $form->getName(),
+                               $error_section) .
+                "\n</script>\n";
+        }
+
+        echo '</fieldset>' . $this->_varRenderer->renderEnd();
+    }
+
+    function submit($submit = null, $reset = false)
+    {
+        if (is_null($submit) || empty($submit)) {
+            $submit = _("Submit");
+        }
+        if ($reset === true) {
+            $reset = _("Reset");
+        }
+        $this->_renderSubmit($submit, $reset);
+    }
+
+    /**
+     * Implementation specific begin function.
+     */
+    function _renderBeginActive($name)
+    {
+        echo '<fieldset class="horde-form" id="fieldset_' . htmlspecialchars($this->_name) . '">'."\n";
+        if ($this->_showHeader) {
+            $this->_renderSectionHeader($name);
+        }
+        if ($this->_requiredLegend) {
+            echo '<div class="form-error-example">' . $this->_requiredMarker
+                . ' &#61; ' . _("Required Field") . '</div>'."\n";
+        }
+    }
+
+    /**
+     * Implementation specific begin function.
+     */
+    function _renderBeginInactive($name)
+    {
+        echo '<fieldset class="horde-form" id="fieldset_' . htmlspecialchars($this->_name) . '">';
+        if ($this->_showHeader) {
+            $this->_renderSectionHeader($name);
+        }
+    }
+
+    function _renderHeader($header, $error = '')
+    {
+        echo '<div class="form-header">'. $header . '</div>';
+        if (!empty($error)) {
+            echo '<div class="form-error">'. $error . '</div>';
+        }
+    }
+
+    function _renderDescription($description)
+    {
+        echo '<div class="form-description">'. $description . '</div>';
+    }
+
+    function _renderSpacer()
+    {
+        // TODO: fix this later so we're not inserting nonsemantic elements just for spacing
+        // ... maybe append form-spacer to class of next or previous element
+        echo '<div class="form-spacer">&nbsp;</div>';
+    }
+
+    function _renderSubmit($submit, $reset)
+    {
+        echo '<fieldset class="form-buttons">'."\n";
+        if (!is_array($submit)) $submit = array($submit);
+        foreach ($submit as $submitbutton) {
+            echo '<input class="button" name="submitbutton" type="submit"';
+            // allow for default-value submit buttons (e.g. _renderSubmit(""))
+            if (!empty($submitbutton)) {
+                echo ' value="'. $submitbutton .'"';
+            }
+            echo ' />'."\n";
+        }
+        if (!empty($reset)) {
+            echo '<input class="button" name="resetbutton" type="reset"
+                value="'. $reset .'" />'."\n";
+        }
+    }
+
+    /**
+     * Renders the beginning of an writeable form entry, including the label
+     * and any form error related to this variable.
+     *
+     * @access private
+     * @author Matt Warden <mwarden@gmail.com>
+     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+     */
+    function _renderVarInputBegin($form, $var, $readonly = false)
+    {
+        // get error message for variable, if any
+        $message = $form->getError($var);
+        // if no message, then no error
+        $isvalid = empty($message);
+
+        $classnames = 'form-input'
+            . (!$isvalid ? ' form-error' : '')
+            . ($var->isRequired() ? ' form-required' : '');
+
+        echo '<div class="', $classnames, '">';
+
+        if (!$isvalid) {
+            echo '<p class="form-error">', $message, '</p>', "\n";
+        }
+
+        printf('<label%s>%s</label>',
+            ($readonly ? '' : ' for="'. $var->getVarName() .'"'),
+            $var->getHumanName());
+    }
+
+    /**
+     * Renders the end of an writeable form entry, including any form notes
+     * and help info.
+     *
+     * @access private
+     * @author Matt Warden <mwarden@gmail.com>
+     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+     */
+    function _renderVarInputEnd($form, $var)
+    {
+        /* Display any help for the field. */
+        if ($var->hasHelp()) {
+            global $registry;
+            if (isset($registry) && is_a($registry, 'Registry')) {
+                $help = Help::link($GLOBALS['registry']->getApp(), $var->getHelp());
+            } else {
+                $help = @htmlspecialchars($var->getHelp());
+            }
+            echo '<p class="form-hint">', $help, '</p>';
+        }
+
+        /* Display any description for the field. */
+        if ($var->hasDescription()) {
+            echo '<div class="form-note"><p>', $var->getDescription(), '</p></div>';
+        } else {
+            echo '<br class="clear" />';
+        }
+
+        echo '</div>';
+    }
+
+    /**
+     * Renders the beginning of a readonly form entry.
+     *
+     * @access private
+     * @author Matt Warden <mwarden@gmail.com>
+     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+     */
+    function _renderVarDisplayBegin($form, $var)
+    {
+        return $this->_renderVarInputBegin($form, $var, true);
+    }
+
+    /**
+     * Renders the end of a readonly form entry. Help and notes are not
+     * applicable.
+     *
+     * @access private
+     * @author Matt Warden <mwarden@gmail.com>
+     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+     */
+    function _renderVarDisplayEnd()
+    {
+        echo '</div>';
+    }
+
+    /**
+     * Renders the header for the section.
+     *
+     * @access private
+     * @author Matt Warden <mwarden@gmail.com>
+     * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+     * @param string $title section header title
+     */
+    function _renderSectionHeader($title)
+    {
+        if (!empty($title)) {
+            echo "\n".'<legend>';
+            echo $this->_encodeTitle ? htmlspecialchars($title) : $title;
+            echo '</legend>'."\n";
+        }
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type.php b/framework/Model/lib/Horde/Form/Type.php
new file mode 100644 (file)
index 0000000..707bb71
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Horde_Form_Type Class
+ *
+ * @author  Robert E. Coyle <robertecoyle@hotmail.com>
+ * @package Horde_Form
+ */
+abstract class Horde_Form_Type {
+
+    protected $_properties = array();
+
+    /**
+     * Type constructor. Takes a hash of key/value parameters.
+     *
+     * @param array $properties Any type properties to initialize.
+     */
+    public function __construct($properties = array())
+    {
+        $this->_properties = array();
+        $vars = array_keys(get_object_vars($this));
+        foreach ($vars as $var) {
+            $this->_properties[] = substr($var, 1);
+        }
+
+        if ($this->_properties && $properties) {
+            $properties = array_combine(array_slice($this->_properties, 0, count($properties)), $properties);
+            foreach ($properties as $property => $value) {
+                $this->__set($property, $value);
+            }
+        }
+    }
+
+    /**
+     */
+    abstract public function isValid($var, $vars, $value, &$message);
+
+    /**
+     */
+    function getInfo($vars, $var, &$info)
+    {
+        $info = $var->getValue($vars);
+    }
+
+    /**
+     */
+    public function onSubmit()
+    {
+    }
+
+    /**
+     * To get the 'escape' property of a type:
+     *   $escape = $type->escape;
+     * If the property is not set this will return null.
+     *
+     * @param string $property The property to retrieve.
+     */
+    protected function __get($property)
+    {
+        if (in_array($property, $this->_properties)) {
+            $prop = '_' . $property;
+            return $this->$prop;
+        }
+
+        return null;
+    }
+
+    /**
+     * To set the 'escape' property of a type to true:
+     *   $type->escape = true;
+     *
+     * @param string $property The property name to set.
+     * @param mixed $value The property value.
+     */
+    protected function __set($property, $value)
+    {
+        if (in_array($property, $this->_properties)) {
+            $prop = '_' . $property;
+            $this->$prop = $value;
+        }
+    }
+
+    /**
+     * To check if a type has a property named 'escape':
+     *  if (isset($type->escape)) { ... }
+     *
+     * @param string $property Property name to check existance of.
+     */
+    protected function __isset($property)
+    {
+        $prop = '_' . $property;
+        return isset($this->$prop);
+    }
+
+    /**
+     * To unset a Type property named 'escape':
+     *   unset($type->escape);
+     *
+     * @param string $property Property name to unset.
+     */
+    protected function __unset($property)
+    {
+        $prop = '_' . $property;
+        unset($this->$prop);
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Boolean.php b/framework/Model/lib/Horde/Form/Type/Boolean.php
new file mode 100644 (file)
index 0000000..9ae0e86
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+/**
+ * An on/off value
+ */
+class Horde_Form_Type_Boolean extends Horde_Form_Type {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        return true;
+    }
+
+    public function getInfo($vars, $var, &$info)
+    {
+        $info = String::lower($vars->get($var->name)) == 'on';
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Color.php b/framework/Model/lib/Horde/Form/Type/Color.php
new file mode 100644 (file)
index 0000000..383a16a
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Color
+ */
+class Horde_Form_Type_Color extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && empty($value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^#([0-9a-z]){6}$/i', $value)) {
+            return true;
+        }
+
+        $message = _("This field must contain a color code in the RGB Hex format, for example '#1234af'.");
+        return false;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/CreditCard.php b/framework/Model/lib/Horde/Form/Type/CreditCard.php
new file mode 100644 (file)
index 0000000..294834c
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Credit card number
+ */
+class Horde_Form_Type_creditcard extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if (empty($value) && $var->required) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (!empty($value)) {
+            /* getCardType() will also verify the checksum. */
+            $type = $this->getCardType($value);
+            if ($type === false || $type == 'unknown') {
+                $message = _("This does not seem to be a valid card number.");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    function getChecksum($ccnum)
+    {
+        $len = strlen($ccnum);
+        if (!is_long($len / 2)) {
+            $weight = 2;
+            $digit = $ccnum[0];
+        } elseif (is_long($len / 2)) {
+            $weight = 1;
+            $digit = $ccnum[0] * 2;
+        }
+        if ($digit > 9) {
+            $digit = $digit - 9;
+        }
+        $i = 1;
+        $checksum = $digit;
+        while ($i < $len) {
+            if ($ccnum[$i] != ' ') {
+                $digit = $ccnum[$i] * $weight;
+                $weight = ($weight == 1) ? 2 : 1;
+                if ($digit > 9) {
+                    $digit = $digit - 9;
+                }
+                $checksum += $digit;
+            }
+            $i++;
+        }
+
+        return $checksum;
+    }
+
+    function getCardType($ccnum)
+    {
+        $sum = $this->getChecksum($ccnum);
+        $l = strlen($ccnum);
+
+        // Screen checksum.
+        if (($sum % 10) != 0) {
+            return false;
+        }
+
+        // Check for Visa.
+        if ((($l == 16) || ($l == 13)) &&
+            ($ccnum[0] == 4)) {
+            return 'visa';
+        }
+
+        // Check for MasterCard.
+        if (($l == 16) &&
+            ($ccnum[0] == 5) &&
+            ($ccnum[1] >= 1) &&
+            ($ccnum[1] <= 5)) {
+            return 'mastercard';
+        }
+
+        // Check for Amex.
+        if (($l == 15) &&
+            ($ccnum[0] == 3) &&
+            (($ccnum[1] == 4) || ($ccnum[1] == 7))) {
+            return 'amex';
+        }
+
+        // Check for Discover (Novus).
+        if (strlen($ccnum) == 16 &&
+            substr($ccnum, 0, 4) == '6011') {
+            return 'discover';
+        }
+
+        // If we got this far, then no card matched.
+        return 'unknown';
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Date.php b/framework/Model/lib/Horde/Form/Type/Date.php
new file mode 100644 (file)
index 0000000..c4415e7
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Date
+ */
+class Horde_Form_Type_Date extends Horde_Form_Type {
+
+    var $_format = '%a %d %B';
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if ($var->required) {
+            $valid = strlen(trim($value)) > 0;
+
+            if (!$valid) {
+                $message = _("This field is required.");
+            }
+        }
+
+        return $valid;
+    }
+
+    public static function getAgo($timestamp)
+    {
+        if ($timestamp === null) {
+            return '';
+        }
+
+        $diffdays = Date_Calc::dateDiff(date('j', $timestamp),
+                                        date('n', $timestamp),
+                                        date('Y', $timestamp),
+                                        date('j'), date('n'), date('Y'));
+
+        /* An error occured. */
+        if ($diffdays == -1) {
+            return;
+        }
+
+        $ago = $diffdays * Date_Calc::compareDates(date('j', $timestamp),
+                                                   date('n', $timestamp),
+                                                   date('Y', $timestamp),
+                                                   date('j'), date('n'),
+                                                   date('Y'));
+        if ($ago < -1) {
+            return sprintf(_(" (%s days ago)"), $diffdays);
+        } elseif ($ago == -1) {
+            return _(" (yesterday)");
+        } elseif ($ago == 0) {
+            return _(" (today)");
+        } elseif ($ago == 1) {
+            return _(" (tomorrow)");
+        } else {
+            return sprintf(_(" (in %s days)"), $diffdays);
+        }
+    }
+
+    public function getFormattedTime($timestamp, $format = null, $showago = true)
+    {
+        if (empty($format)) {
+            $format = $this->_format;
+        }
+        if (!empty($timestamp)) {
+            return strftime($format, $timestamp) . ($showago ? self::getAgo($timestamp) : '');
+        } else {
+            return '';
+        }
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/DateTime.php b/framework/Model/lib/Horde/Form/Type/DateTime.php
new file mode 100644 (file)
index 0000000..98adaa0
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+/**
+ * Date and time selection
+ */
+class Horde_Form_Type_DateTime extends Horde_Form_Type {
+
+    var $_date;
+    var $_time;
+
+    /**
+     * Return the date supplied as a Horde_Date object.
+     *
+     * @param integer $start_year  The first available year for input.
+     * @param integer $end_year    The last available year for input.
+     * @param boolean $picker      Do we show the DHTML calendar?
+     * @param integer $format_in   The format to use when sending the date
+     *                             for storage. Defaults to Unix epoch.
+     *                             Similar to the strftime() function.
+     * @param integer $format_out  The format to use when displaying the
+     *                             date. Similar to the strftime() function.
+     * @param boolean $show_seconds Include a form input for seconds.
+     */
+    function init($start_year = '', $end_year = '', $picker = true,
+                  $format_in = null, $format_out = '%x', $show_seconds = false)
+    {
+        $this->_date = new Horde_Form_Type_Date();
+        $this->_date->init($start_year, $end_year, $picker, $format_in, $format_out);
+
+        $this->_time = new Horde_Form_Type_Time();
+        $this->_time->init($show_seconds);
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required) {
+            return $this->_date->isValid($var, $vars, $value, $message) &&
+                $this->_time->isValid($var, $vars, $value, $message);
+        }
+        return true;
+    }
+
+    function getInfo(&$vars, &$var, &$info)
+    {
+        /* If any component is empty consider it a bad date and return the
+         * default. */
+        $value = $var->getValue($vars);
+        if ($this->emptyDateArray($value) == 1 || $this->emptyTimeArray($value)) {
+            $info = $var->getDefault();
+            return;
+        }
+
+        $date = $this->getDateOb($value);
+        $time = $this->getTimeOb($value);
+        $date->hour = $time->hour;
+        $date->min = $time->min;
+        $date->sec = $time->sec;
+        if (is_null($this->format_in)) {
+            $info = $date->timestamp();
+        } else {
+            $info = $date->strftime($this->format_in);
+        }
+    }
+
+    function __get($property)
+    {
+        if ($property == 'show_seconds') {
+            return $this->_time->$property;
+        } else {
+            return $this->_date->$property;
+        }
+    }
+
+    function __set($property, $value)
+    {
+        if ($property == 'show_seconds') {
+            $this->_time->$property = $value;
+        } else {
+            $this->_date->$property = $value;
+        }
+    }
+
+    function checktime($hour, $minute, $second)
+    {
+        return $this->_time->checktime($hour, $minute, $second);
+    }
+
+    function getTimeOb($time_in)
+    {
+        return $this->_time->getTimeOb($time_in);
+    }
+
+    function getTimeParts($time_in)
+    {
+        return $this->_time->getTimeParts($time_in);
+    }
+
+    function emptyTimeArray($time)
+    {
+        return $this->_time->emptyTimeArray($time);
+    }
+
+    function emptyDateArray($date)
+    {
+        return $this->_date->emptyDateArray($date);
+    }
+
+    function getDateParts($date_in)
+    {
+        return $this->_date->getDateParts($date_in);
+    }
+
+    function getDateOb($date_in)
+    {
+        return $this->_date->getDateOb($date_in);
+    }
+
+    function formatDate($date)
+    {
+        if ($date === null) {
+            return '';
+        }
+        return $this->_date->formatDate($date);
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Email.php b/framework/Model/lib/Horde/Form/Type/Email.php
new file mode 100644 (file)
index 0000000..96cf756
--- /dev/null
@@ -0,0 +1,452 @@
+<?php
+/**
+ * Email
+ */
+class Horde_Form_Type_Email extends Horde_Form_Type {
+
+    /**
+     * Allow multiple addresses?
+     *
+     * @type boolean
+     * @var boolean
+    */
+    var $_allow_multi = false;
+
+    /**
+     * Strip domain from the address?
+     *
+     * @type boolean
+     * @var boolean
+     */
+    var $_strip_domain = false;
+
+    /**
+     * Make displayed email addresses clickable?
+     *
+     * @type boolean
+     * @var boolean
+     */
+    var $_link_compose = false;
+
+    /**
+     * The compose name to use
+     *
+     * @type text
+     * @var boolean
+     */
+    var $_link_name;
+
+    /**
+     * The character to separate multiple email addresses
+     *
+     * @type text
+     * @var string
+     */
+    var $_delimiters = ',';
+
+    /**
+     * Contact the target mail server to see if the email address is deliverable?
+     *
+     * @type boolean
+     * @var boolean
+     */
+    var $_check_smtp = false;
+
+    /**
+     */
+    public function init($allow_multi = false, $strip_domain = false,
+                  $link_compose = false, $link_name = null,
+                  $delimiters = ',')
+    {
+        $this->_allow_multi = $allow_multi;
+        $this->_strip_domain = $strip_domain;
+        $this->_link_compose = $link_compose;
+        $this->_link_name = $link_name;
+        $this->_delimiters = $delimiters;
+    }
+
+    /**
+     */
+    public function isValid($var, $vars, $value, &$message)
+    {
+        // Split into individual addresses.
+        $emails = $this->splitEmailAddresses($value);
+
+        // Check for too many.
+        if (!$this->_allow_multi && count($emails) > 1) {
+            $message = _("Only one email address is allowed.");
+            return false;
+        }
+
+        // Check for all valid and at least one non-empty.
+        $nonEmpty = 0;
+        foreach ($emails as $email) {
+            if (!strlen($email)) {
+                continue;
+            }
+            if (!$this->validateEmailAddress($email)) {
+                $message = sprintf(_("\"%s\" is not a valid email address."), $email);
+                return false;
+            }
+            ++$nonEmpty;
+        }
+
+        if (!$nonEmpty && $var->required) {
+            if ($this->_allow_multi) {
+                $message = _("You must enter at least one email address.");
+            } else {
+                $message = _("You must enter an email address.");
+            }
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Explodes an RFC 2822 string, ignoring a delimiter if preceded
+     * by a "\" character, or if the delimiter is inside single or
+     * double quotes.
+     *
+     * @param string $string     The RFC 822 string.
+     *
+     * @return array  The exploded string in an array.
+     */
+    public function splitEmailAddresses($string)
+    {
+        $quotes = array('"', "'");
+        $emails = array();
+        $pos = 0;
+        $in_quote = null;
+        $in_group = false;
+        $prev = null;
+
+        if (!strlen($string)) {
+            return array();
+        }
+
+        $char = $string[0];
+        if (in_array($char, $quotes)) {
+            $in_quote = $char;
+        } elseif ($char == ':') {
+            $in_group = true;
+        } elseif (strpos($this->_delimiters, $char) !== false) {
+            $emails[] = '';
+            $pos = 1;
+        }
+
+        for ($i = 1, $iMax = strlen($string); $i < $iMax; ++$i) {
+            $char = $string[$i];
+            if (in_array($char, $quotes)) {
+                if ($prev !== '\\') {
+                    if ($in_quote === $char) {
+                        $in_quote = null;
+                    } elseif (is_null($in_quote)) {
+                        $in_quote = $char;
+                    }
+                }
+            } elseif ($in_group) {
+                if ($char == ';') {
+                    $emails[] = substr($string, $pos, $i - $pos + 1);
+                    $pos = $i + 1;
+                    $in_group = false;
+                }
+            } elseif ($char == ':') {
+                $in_group = true;
+            } elseif (strpos($this->_delimiters, $char) !== false &&
+                      $prev !== '\\' &&
+                      is_null($in_quote)) {
+                $emails[] = substr($string, $pos, $i - $pos);
+                $pos = $i + 1;
+            }
+            $prev = $char;
+        }
+
+        if ($pos != $i) {
+            /* The string ended without a delimiter. */
+            $emails[] = substr($string, $pos, $i - $pos);
+        }
+
+        return $emails;
+    }
+
+    /**
+     * RFC(2)822 Email Parser.
+     *
+     * By Cal Henderson <cal@iamcal.com>
+     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
+     * http://creativecommons.org/licenses/by-sa/2.5/
+     *
+     * http://code.iamcal.com/php/rfc822/
+     *
+     * http://iamcal.com/publish/articles/php/parsing_email
+     *
+     * Revision 4
+     *
+     * @param string $email An individual email address to validate.
+     *
+     * @return boolean
+     */
+    public function validateEmailAddress($email)
+    {
+        static $comment_regexp, $email_regexp;
+        if ($comment_regexp === null) {
+            $this->_defineValidationRegexps($comment_regexp, $email_regexp);
+        }
+
+        // We need to strip comments first (repeat until we can't find
+        // any more).
+        while (true) {
+            $new = preg_replace("!$comment_regexp!", '', $email);
+            if (strlen($new) == strlen($email)){
+                break;
+            }
+            $email = $new;
+        }
+
+        // Now match what's left.
+        $result = (bool)preg_match("!^$email_regexp$!", $email);
+        if ($result && $this->_check_smtp) {
+            $result = $this->validateEmailAddressSmtp($email);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Attempt partial delivery of mail to an address to validate it.
+     *
+     * @param string $email An individual email address to validate.
+     *
+     * @return boolean
+     */
+    public function validateEmailAddressSmtp($email)
+    {
+        list(, $maildomain) = explode('@', $email, 2);
+
+        // Try to get the real mailserver from MX records.
+        if (function_exists('getmxrr') &&
+            @getmxrr($maildomain, $mxhosts, $mxpriorities)) {
+            // MX record found.
+            array_multisort($mxpriorities, $mxhosts);
+            $mailhost = $mxhosts[0];
+        } else {
+            // No MX record found, try the root domain as the mail
+            // server.
+            $mailhost = $maildomain;
+        }
+
+        $fp = @fsockopen($mailhost, 25, $errno, $errstr, 5);
+        if (!$fp) {
+            return false;
+        }
+
+        // Read initial response.
+        fgets($fp, 4096);
+
+        // HELO
+        fputs($fp, "HELO $mailhost\r\n");
+        fgets($fp, 4096);
+
+        // MAIL FROM
+        fputs($fp, "MAIL FROM: <root@example.com>\r\n");
+        fgets($fp, 4096);
+
+        // RCPT TO - gets the result we want.
+        fputs($fp, "RCPT TO: <$email>\r\n");
+        $result = trim(fgets($fp, 4096));
+
+        // QUIT
+        fputs($fp, "QUIT\r\n");
+        fgets($fp, 4096);
+        fclose($fp);
+
+        return substr($result, 0, 1) == '2';
+    }
+
+    /**
+     * RFC(2)822 Email Parser.
+     *
+     * By Cal Henderson <cal@iamcal.com>
+     * This code is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
+     * http://creativecommons.org/licenses/by-sa/2.5/
+     *
+     * http://code.iamcal.com/php/rfc822/
+     *
+     * http://iamcal.com/publish/articles/php/parsing_email
+     *
+     * Revision 4
+     *
+     * @param string &$comment The regexp for comments.
+     * @param string &$addr_spec The regexp for email addresses.
+     */
+    protected function _defineValidationRegexps(&$comment, &$addr_spec)
+    {
+        /**
+         * NO-WS-CTL       =       %d1-8 /         ; US-ASCII control characters
+         *                         %d11 /          ;  that do not include the
+         *                         %d12 /          ;  carriage return, line feed,
+         *                         %d14-31 /       ;  and white space characters
+         *                         %d127
+         * ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
+         * DIGIT          =  %x30-39
+         */
+        $no_ws_ctl  = "[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]";
+        $alpha      = "[\\x41-\\x5a\\x61-\\x7a]";
+        $digit      = "[\\x30-\\x39]";
+        $cr         = "\\x0d";
+        $lf         = "\\x0a";
+        $crlf       = "($cr$lf)";
+
+        /**
+         * obs-char        =       %d0-9 / %d11 /          ; %d0-127 except CR and
+         *                         %d12 / %d14-127         ;  LF
+         * obs-text        =       *LF *CR *(obs-char *LF *CR)
+         * text            =       %d1-9 /         ; Characters excluding CR and LF
+         *                         %d11 /
+         *                         %d12 /
+         *                         %d14-127 /
+         *                         obs-text
+         * obs-qp          =       "\" (%d0-127)
+         * quoted-pair     =       ("\" text) / obs-qp
+         */
+        $obs_char       = "[\\x00-\\x09\\x0b\\x0c\\x0e-\\x7f]";
+        $obs_text       = "($lf*$cr*($obs_char$lf*$cr*)*)";
+        $text           = "([\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f]|$obs_text)";
+        $obs_qp         = "(\\x5c[\\x00-\\x7f])";
+        $quoted_pair    = "(\\x5c$text|$obs_qp)";
+
+        /**
+         * obs-FWS         =       1*WSP *(CRLF 1*WSP)
+         * FWS             =       ([*WSP CRLF] 1*WSP) /   ; Folding white space
+         *                         obs-FWS
+         * ctext           =       NO-WS-CTL /     ; Non white space controls
+         *                         %d33-39 /       ; The rest of the US-ASCII
+         *                         %d42-91 /       ;  characters not including "(",
+         *                         %d93-126        ;  ")", or "\"
+         * ccontent        =       ctext / quoted-pair / comment
+         * comment         =       "(" *([FWS] ccontent) [FWS] ")"
+         * CFWS            =       *([FWS] comment) (([FWS] comment) / FWS)
+         *
+         * @note: We translate ccontent only partially to avoid an
+         * infinite loop. Instead, we'll recursively strip comments
+         * before processing the input.
+         */
+        $wsp        = "[\\x20\\x09]";
+        $obs_fws    = "($wsp+($crlf$wsp+)*)";
+        $fws        = "((($wsp*$crlf)?$wsp+)|$obs_fws)";
+        $ctext      = "($no_ws_ctl|[\\x21-\\x27\\x2A-\\x5b\\x5d-\\x7e])";
+        $ccontent   = "($ctext|$quoted_pair)";
+        $comment    = "(\\x28($fws?$ccontent)*$fws?\\x29)";
+        $cfws       = "(($fws?$comment)*($fws?$comment|$fws))";
+        $cfws       = "$fws*";
+
+        /**
+         * atext           =       ALPHA / DIGIT / ; Any character except controls,
+         *                         "!" / "#" /     ;  SP, and specials.
+         *                         "$" / "%" /     ;  Used for atoms
+         *                         "&" / "'" /
+         *                         "*" / "+" /
+         *                         "-" / "/" /
+         *                         "=" / "?" /
+         *                         "^" / "_" /
+         *                         "`" / "{" /
+         *                         "|" / "}" /
+         *                         "~"
+         * atom            =       [CFWS] 1*atext [CFWS]
+         */
+        $atext      = "($alpha|$digit|[\\x21\\x23-\\x27\\x2a\\x2b\\x2d\\x2e\\x3d\\x3f\\x5e\\x5f\\x60\\x7b-\\x7e])";
+        $atom       = "($cfws?$atext+$cfws?)";
+
+        /**
+         * qtext           =       NO-WS-CTL /     ; Non white space controls
+         *                         %d33 /          ; The rest of the US-ASCII
+         *                         %d35-91 /       ;  characters not including "\"
+         *                         %d93-126        ;  or the quote character
+         * qcontent        =       qtext / quoted-pair
+         * quoted-string   =       [CFWS]
+         *                         DQUOTE *([FWS] qcontent) [FWS] DQUOTE
+         *                         [CFWS]
+         * word            =       atom / quoted-string
+         */
+        $qtext      = "($no_ws_ctl|[\\x21\\x23-\\x5b\\x5d-\\x7e])";
+        $qcontent   = "($qtext|$quoted_pair)";
+        $quoted_string  = "($cfws?\\x22($fws?$qcontent)*$fws?\\x22$cfws?)";
+        $word       = "($atom|$quoted_string)";
+
+        /**
+         * obs-local-part  =       word *("." word)
+         * obs-domain      =       atom *("." atom)
+         */
+        $obs_local_part = "($word(\\x2e$word)*)";
+        $obs_domain = "($atom(\\x2e$atom)*)";
+
+        /**
+         * dot-atom-text   =       1*atext *("." 1*atext)
+         * dot-atom        =       [CFWS] dot-atom-text [CFWS]
+         */
+        $dot_atom_text  = "($atext+(\\x2e$atext+)*)";
+        $dot_atom   = "($cfws?$dot_atom_text$cfws?)";
+
+        /**
+         * domain-literal  =       [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS]
+         * dcontent        =       dtext / quoted-pair
+         * dtext           =       NO-WS-CTL /     ; Non white space controls
+         *
+         *                         %d33-90 /       ; The rest of the US-ASCII
+         *                         %d94-126        ;  characters not including "[",
+         *                                         ;  "]", or "\"
+         */
+        $dtext      = "($no_ws_ctl|[\\x21-\\x5a\\x5e-\\x7e])";
+        $dcontent   = "($dtext|$quoted_pair)";
+        $domain_literal = "($cfws?\\x5b($fws?$dcontent)*$fws?\\x5d$cfws?)";
+
+        /**
+         * local-part      =       dot-atom / quoted-string / obs-local-part
+         * domain          =       dot-atom / domain-literal / obs-domain
+         * addr-spec       =       local-part "@" domain
+         */
+        $local_part = "($dot_atom|$quoted_string|$obs_local_part)";
+        $domain     = "($dot_atom|$domain_literal|$obs_domain)";
+        $addr_spec  = "($local_part\\x40$domain)";
+    }
+
+}
+
+/**
+ * Email with confirmation
+ */
+class Horde_Form_Type_EmailConfirm extends Horde_Form_Type {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && empty($value['original'])) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if ($value['original'] != $value['confirm']) {
+            $message = _("Email addresses must match.");
+            return false;
+        } else {
+            require_once 'Horde/MIME.php';
+            $parsed_email = MIME::parseAddressList($value['original'], false,
+                                                   true);
+            if (is_a($parsed_email, 'PEAR_Error')) {
+                $message = $parsed_email->getMessage();
+                return false;
+            }
+            if (count($parsed_email) > 1) {
+                $message = _("Only one email address allowed.");
+                return false;
+            }
+            if (empty($parsed_email[0]->mailbox)) {
+                $message = _("You did not enter a valid email address.");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Enum.php b/framework/Model/lib/Horde/Form/Type/Enum.php
new file mode 100644 (file)
index 0000000..c5e638e
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Choose one from a list of values
+ */
+class Horde_Form_Type_Enum extends Horde_Form_Type {
+
+    /**
+     * List of values to choose from
+     *
+     * @type stringlist
+     * @var array
+     */
+    protected $_values = array();
+
+    /**
+     * Initial prompt value, if any
+     *
+     * @type text
+     * @var string
+     */
+    protected $_prompt;
+
+    /**
+     */
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && $value == '' && !isset($this->_values[$value])) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (count($this->_values) == 0 || isset($this->_values[$value]) ||
+            ($this->_prompt && empty($value))) {
+            return true;
+        }
+
+        $message = _("Invalid data.");
+        return false;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Int.php b/framework/Model/lib/Horde/Form/Type/Int.php
new file mode 100644 (file)
index 0000000..31375a7
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Integer
+ */
+class Horde_Form_Type_Int extends Horde_Form_Type {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && empty($value) && ((string)(int)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^[0-9]+$/', $value)) {
+            return true;
+        }
+
+        $message = _("This field may only contain integers.");
+        return false;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Invalid.php b/framework/Model/lib/Horde/Form/Type/Invalid.php
new file mode 100644 (file)
index 0000000..20ee3c3
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+class Horde_Form_Type_invalid extends Horde_Form_Type {
+
+    var $message;
+
+    function init($message)
+    {
+        $this->message = $message;
+    }
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        return false;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Number.php b/framework/Model/lib/Horde/Form/Type/Number.php
new file mode 100644 (file)
index 0000000..6b58fd6
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Number
+ */
+class Horde_Form_Type_Number extends Horde_Form_Type {
+
+    /**
+     */
+    protected $_fraction;
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && empty($value) && ((string)(double)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        } elseif (empty($value)) {
+            return true;
+        }
+
+        /* If matched, then this is a correct numeric value. */
+        if (preg_match($this->_getValidationPattern(), $value)) {
+            return true;
+        }
+
+        $message = _("This field must be a valid number.");
+        return false;
+    }
+
+    /**
+     */
+    public function getInfo($vars, $var, &$info)
+    {
+        $value = $vars->get($var->name);
+        $linfo = NLS::getLocaleInfo();
+        $value = str_replace($linfo['mon_thousands_sep'], '', $value);
+        $info = str_replace($linfo['mon_decimal_point'], '.', $value);
+    }
+
+    /**
+     */
+    protected function _getValidationPattern()
+    {
+        static $pattern = '';
+        if (!empty($pattern)) {
+            return $pattern;
+        }
+
+        /* Get current locale information. */
+        $linfo = NLS::getLocaleInfo();
+
+        /* Build the pattern. */
+        $pattern = '(-)?';
+
+        /* Only check thousands separators if locale has any. */
+        if (!empty($linfo['mon_thousands_sep'])) {
+            /* Regex to check for correct thousands separators (if any). */
+            $pattern .= '((\d+)|((\d{0,3}?)([' . $linfo['mon_thousands_sep'] . ']\d{3})*?))';
+        } else {
+            /* No locale thousands separator, check for only digits. */
+            $pattern .= '(\d+)';
+        }
+        /* If no decimal point specified default to dot. */
+        if (empty($linfo['mon_decimal_point'])) {
+            $linfo['mon_decimal_point'] = '.';
+        }
+        /* Regex to check for correct decimals (if any). */
+        if (empty($this->_fraction)) {
+            $fraction = '*';
+        } else {
+            $fraction = '{0,' . $this->_fraction . '}';
+        }
+        $pattern .= '([' . $linfo['mon_decimal_point'] . '](\d' . $fraction . '))?';
+
+        /* Put together the whole regex pattern. */
+        $pattern = '/^' . $pattern . '$/';
+
+        return $pattern;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Octal.php b/framework/Model/lib/Horde/Form/Type/Octal.php
new file mode 100644 (file)
index 0000000..111cdb7
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Octal
+ */
+class Horde_Form_Type_Octal extends Horde_Form_Type {
+
+    function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && empty($value) && ((string)(int)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^[0-7]+$/', $value)) {
+            return true;
+        }
+
+        $message = _("This field may only contain octal values.");
+        return false;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Password.php b/framework/Model/lib/Horde/Form/Type/Password.php
new file mode 100644 (file)
index 0000000..a47a178
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Password
+ */
+class Horde_Form_Type_Password extends Horde_Form_Type {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if ($var->required) {
+            $valid = strlen(trim($value)) > 0;
+
+            if (!$valid) {
+                $message = _("This field is required.");
+            }
+        }
+
+        return $valid;
+    }
+
+}
+
+
+/**
+ * Password with confirmation
+ */
+class Horde_Form_Type_passwordConfirm extends Horde_Form_Type {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && empty($value['original'])) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if ($value['original'] != $value['confirm']) {
+            $message = _("Passwords must match.");
+            return false;
+        }
+
+        return true;
+    }
+
+    function getInfo($vars, $var, &$info)
+    {
+        $value = $vars->get($var->name);
+        $info = $value['original'];
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Phone.php b/framework/Model/lib/Horde/Form/Type/Phone.php
new file mode 100644 (file)
index 0000000..488fa57
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+/**
+ * Phone number
+ */
+class Horde_Form_Type_Phone extends Horde_Form_Type {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if ($var->required) {
+            $valid = strlen(trim($value)) > 0;
+            if (!$valid) {
+                $message = _("This field is required.");
+            }
+        } else {
+            $valid = preg_match('/^\+?[\d()\-\/ ]*$/', $value);
+            if (!$valid) {
+                $message = _("You must enter a valid phone number, digits only with an optional '+' for the international dialing prefix.");
+            }
+        }
+
+        return $valid;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Phone/Mobile.php b/framework/Model/lib/Horde/Form/Type/Phone/Mobile.php
new file mode 100644 (file)
index 0000000..5c97969
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+/**
+ * Mobile Phone Number
+ */
+class Horde_Form_Type_Phone_Mobile extends Horde_Form_Type_Phone {}
diff --git a/framework/Model/lib/Horde/Form/Type/Set.php b/framework/Model/lib/Horde/Form/Type/Set.php
new file mode 100644 (file)
index 0000000..db805ad
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Set of values
+ */
+class Horde_Form_Type_Set extends Horde_Form_Type {
+
+    /**
+     * Values
+     *
+     * @type stringlist
+     * @var string
+     */
+    protected $_values;
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if (count($this->_values) == 0 || count($value) == 0) {
+            return true;
+        }
+        foreach ($value as $item) {
+            if (!isset($this->_values[$item])) {
+                $error = true;
+                break;
+            }
+        }
+        if (!isset($error)) {
+            return true;
+        }
+
+        $message = _("Invalid data.");
+        return false;
+    }
+
+}
+
+class Horde_Form_Type_multienum extends Horde_Form_Type_enum {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if (is_array($value)) {
+            foreach ($value as $val) {
+                if (!$this->isValid($var, $vars, $val, $message)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        if (empty($value) && ((string)(int)$value !== $value)) {
+            if ($var->required) {
+                $message = _("This field is required.");
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        if (count($this->_values) == 0 || isset($this->_values[$value])) {
+            return true;
+        }
+
+        $message = _("Invalid data.");
+        return false;
+    }
+
+}
+
+class Horde_Form_Type_keyval_multienum extends Horde_Form_Type_multienum {
+
+    function getInfo($vars, $var, &$info)
+    {
+        $value = $vars->get($var->name);
+        $info = array();
+        foreach ($value as $key) {
+            $info[$key] = $this->_values[$key];
+        }
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/String.php b/framework/Model/lib/Horde/Form/Type/String.php
new file mode 100644 (file)
index 0000000..276f541
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * String
+ */
+class Horde_Form_Type_String extends Horde_Form_Type {
+
+    /**
+     * Validation regex
+     *
+     * @type string
+     * @var string
+     */
+    protected $_regex;
+
+    /**
+     * Maximum length
+     *
+     * @type int
+     * @var integer
+     */
+    protected $_maxlength;
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        $valid = true;
+
+        if (!empty($this->_maxlength) && String::length($value) > $this->_maxlength) {
+            $valid = false;
+            $message = sprintf(_("Value is over the maximum length of %s."), $this->_maxlength);
+        } elseif ($var->required && empty($this->_regex)) {
+            if (!($valid = strlen(trim($value)) > 0)) {
+                $message = _("This field is required.");
+            }
+        } elseif (strlen($this->_regex)) {
+            if (!($valid = preg_match($this->_regex, $value))) {
+                $message = _("You must enter a valid value.");
+            }
+        }
+
+        return $valid;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/Type/Time.php b/framework/Model/lib/Horde/Form/Type/Time.php
new file mode 100644 (file)
index 0000000..3b26133
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Time
+ */
+class Horde_Form_Type_Time extends Horde_Form_Type {
+
+    public function isValid($var, $vars, $value, &$message)
+    {
+        if ($var->required && empty($value) && ((string)(double)$value !== $value)) {
+            $message = _("This field is required.");
+            return false;
+        }
+
+        if (empty($value) || preg_match('/^[0-2]?[0-9]:[0-5][0-9]$/', $value)) {
+            return true;
+        }
+
+        $message = _("This field may only contain numbers and the colon.");
+        return false;
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/VarRenderer.php b/framework/Model/lib/Horde/Form/VarRenderer.php
new file mode 100644 (file)
index 0000000..60947ba
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/**
+ * The Horde_Form_VarRenderer:: class provides base functionality for
+ * other Horde_Form elements.
+ *
+ * $Horde: incubator/Horde_Form/Horde/Form/VarRenderer.php,v 1.8 2008/01/02 11:12:48 jan Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2005-2007 Matt Warden <mwarden@gmail.com>
+ *
+ * See the enclosed file LICENSE for license information (LGPL).
+ *
+ * @author  Jason M. Felice <jason.m.felice@gmail.com>
+ * @package Horde_Form
+ */
+class Horde_Form_VarRenderer {
+
+    /**
+     * Renders a variable.
+     *
+     * @param Horde_Form $form            Reference to a Horde_Form instance,
+     *                                    or null if none is available.
+     * @param Horde_Form_Variable $var    Reference to a Horde_Form_Variable.
+     * @param Variables $vars             A Variables instance.
+     * @param boolean $isInput            Whether this is an input field.
+     */
+    public function render($form, $var, $vars, $isInput = false)
+    {
+        if ($isInput) {
+            $state = 'Input';
+        } else {
+            $state = 'Display';
+        }
+        $method = "_renderVar${state}_" . str_replace('Horde_Form_Type_', '', get_class($var->type));
+        if (!method_exists($this, $method)) {
+            $method = "_renderVar${state}Default";
+        }
+        return $this->$method($form, $var, $vars);
+    }
+
+    /**
+     * Finishes rendering after all fields are output.
+     */
+    public function renderEnd()
+    {
+        return '';
+    }
+
+}
diff --git a/framework/Model/lib/Horde/Form/VarRenderer/Xhtml.php b/framework/Model/lib/Horde/Form/VarRenderer/Xhtml.php
new file mode 100644 (file)
index 0000000..312a217
--- /dev/null
@@ -0,0 +1,1541 @@
+<?php
+/**
+ * The Horde_Form_VarRenderer_Xhtml:: class renders variables as Xhtml.
+ *
+ * $Horde: incubator/Horde_Form/Horde/Form/VarRenderer/Xhtml.php,v 1.14 2008/01/02 11:12:48 jan Exp $
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ * Copyright 2005 Matt Warden <mwarden@gmail.com>
+ *
+ * See the enclosed file LICENSE for license information (LGPL).
+ *
+ * @author  Jason M. Felice <jason.m.felice@gmail.com>
+ * @package Horde_Form
+ */
+class Horde_Form_VarRenderer_Xhtml extends Horde_Form_VarRenderer {
+
+    protected $_onLoadJS = array();
+
+    /**
+     * Handles the end of rendering of variables; writes onload JavaScript.
+     *
+     * @access public
+     * @author ?
+     * @return string the javascript to execute, and its container script tags,
+     *            or and empty string if there is nothing to execute onload
+     */
+    public function renderEnd()
+    {
+        if (count($this->_onLoadJS)) {
+            return "<script type=\"text/javascript\">" .
+                "<!--\n" .  implode("\n", $this->_onLoadJS) . "\n// -->\n" .
+                "</script>";
+        } else {
+            return '';
+        }
+    }
+
+    function _renderVarInputDefault($form, $var, $vars)
+    {
+        throw new Horde_Form_Exception('Unknown variable type:' . get_class($var->type));
+    }
+
+    function _renderVarInput_number($form, $var, $vars)
+    {
+        $value = $var->getValue($vars);
+        if ($var->type->fraction) {
+            $value = sprintf('%01.' . $var->type->fraction . 'f', $value);
+        }
+        $linfo = NLS::getLocaleInfo();
+        /* Only if there is a mon_decimal_point do the
+         * substitution. */
+        if (!empty($linfo['mon_decimal_point'])) {
+            $value = str_replace('.', $linfo['mon_decimal_point'], $value);
+        }
+        return sprintf('    <input type="text" class="form-input-number" name="%1$s" id="%1$s" value="%2$s"%3$s />',
+                       $var->getVarName(),
+                       $value,
+                       $this->_getActionScripts($form, $var)
+               );
+    }
+
+    function _renderVarInput_int($form, $var, $vars)
+    {
+        return sprintf('    <input type="text" class="form-input-int" name="%1$s" id="%1$s" value="%2$s"%3$s />',
+                       $var->getVarName(),
+                       $value = $var->getValue($vars),
+                       $this->_getActionScripts($form, $var)
+               );
+    }
+
+    function _renderVarInput_octal($form, $var, $vars)
+    {
+        return sprintf('<input type="text" class="form-input-octal" name="%1$s" id="%1$s" value="%2$s"%3$s />',
+                       $var->getVarName(),
+                       sprintf('0%o', octdec($var->getValue($vars))),
+                       $this->_getActionScripts($form, $var)
+               );
+    }
+
+    function _renderVarInput_intlist($form, $var, $vars)
+    {
+        return sprintf('<input type="text" class="form-input-intlist" name="%1$s" id="%1$s" value="%2$s"%3$s />',
+                       $var->getVarName(),
+                       $value = $var->getValue($vars),
+                       $this->_getActionScripts($form, $var)
+               );
+    }
+
+    function _renderVarInput_text($form, $var, $vars)
+    {
+        return sprintf(
+            '<input type="text" class="form-input-text%1$s" name="%2$s" '
+            . 'id="%2$s" value="%3$s"%4$s%5$s%6$s />',
+            ($var->isDisabled() ? ' form-input-disabled" ' : ''),
+            $var->getVarName(),
+            htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()),
+            ($var->isDisabled() ? ' disabled="disabled" ' : ''),
+            ($var->type->maxlength ? ' maxlength="' . $var->type->maxlength . '"' : ''),
+            $this->_getActionScripts($form, $var)
+        );
+    }
+
+    function _renderVarInput_stringlist($form, $var, $vars)
+    {
+        return sprintf(
+            '<input type="text" class="form-input-stringlist" name="%s" value="%s"%s />',
+            $var->getVarName(),
+            $value = $var->getValue($vars),
+            $this->_getActionScripts($form, $var)
+        );
+    }
+
+    function _renderVarInput_phone($form, $var, $vars)
+    {
+        return sprintf(
+            '<input type="text" class="form-input-phone" name="%1$s" id="%1$s" value="%2$s" %3$s%4$s />',
+            $var->getVarName(),
+            htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()),
+            ($var->isDisabled() ? ' disabled="disabled" ' : ''),
+            $this->_getActionScripts($form, $var)
+        );
+    }
+
+    function _renderVarInput_cellphone($form, $var, $vars)
+    {
+        return $this->_renderVarInput_phone($form, $var, $vars);
+    }
+
+    function _renderVarInput_ipaddress($form, $var, $vars)
+    {
+        return sprintf('    <input type="text" class="form-input-ipaddress" name="%1$s" id="%1$s" value="%2$s" %3$s%4$s />',
+                       $var->getVarName(),
+                       htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()),
+                       $var->isDisabled() ? ' disabled="disabled" ' : '',
+                       $this->_getActionScripts($form, $var)
+               );
+    }
+
+    function _renderVarInput_file($form, $var, $vars)
+    {
+        $file = $var->getValue($vars);
+        return sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s"%2$s />',
+                       $var->getVarName(),
+                       $this->_getActionScripts($form, $var));
+    }
+
+    /**
+     * @todo Show image dimensions in the width/height boxes.
+     */
+    function _renderVarInput_image($form, $var, $vars)
+    {
+        $varname = $var->getVarName();
+        $image = $var->getValue($vars);
+
+        /* Check if existing image data is being loaded. */
+        $var->type->loadImageData($image);
+
+        Horde::addScriptFile('image.js', 'horde', true);
+        $graphics_dir = $GLOBALS['registry']->getImageDir('horde');
+        $img_dir = $graphics_dir . '/image';
+
+        $html = '';
+
+        /* Check if there is existing img information stored. */
+        if (isset($image['img'])) {
+            /* Hidden tag to store the preview image filename. */
+            $html = sprintf('    <input type="hidden" name="%1$s" id="%1$s" value="%2$s" />',
+                   $varname . '[img]',
+                   htmlspecialchars($image['img'], ENT_QUOTES, NLS::getCharset()));
+
+            /* Unserialize the img information to get the full array. */
+            $image['img'] = @unserialize($image['img']);
+        }
+
+        /* Output the input tag. */
+        if (empty($image['img'])) {
+            $js = "
+var p = document.getElementById('" . $varname . "[preview]');
+o = '\\\\'; a = '/';
+tmp = '' + document.getElementById('" . $varname . "[new]').value;
+if (tmp) {
+    while (tmp.indexOf(o) > -1) {
+        pos = tmp.indexOf(o);
+        tmp = '' + (tmp.substring(0, pos) + a + tmp.substring((pos + o.length), tmp.length));
+    }
+    p.src = 'file:///' + tmp;
+    p.alt = '" . addslashes(_("If you see this message but no image, the image you want to upload can't be displayed by your browser.")) . "';
+}";
+            $browser = Horde_Browser::singleton();
+            if ($browser->isBrowser('msie')) {
+                $html .= sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s" onchange="%2$s" />',
+                             $varname . '[new]',
+                             $js);
+            } else {
+                $html .= sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s"
+                        onclick="window.setTimeout(\'document.getElementById(\\\'%1$s\\\').blur();\', 5);"
+                        onblur="%2$s" />',
+                             $varname . '[new]',
+                             $js);
+            }
+        } else {
+            $html .= sprintf('    <input type="file" class="form-input-file" name="%1$s" id="%1$s" />',
+                             $varname . '[new]');
+        }
+
+        /* Output the button to upload/reset the image. */
+        if ($var->type->show_upload) {
+            $html .= '&nbsp;';
+            $html .= sprintf('    <input class="form-button-upload" name="%1$s" id="%1$s" type="submit" value="%2$s" /> ',
+                         '_do_' . $varname,
+                         _("Upload"));
+        }
+
+        if (empty($image['img'])) {
+            /* No image information stored yet, show a blank
+             * preview. */
+            $html .= Horde::img('tree/blank.png', _("Preview"),
+                    'class="form-image-preview-blank" id="' . $varname . '[preview]"',
+                    $graphics_dir);
+        } else {
+            /* Image information stored, show preview, add buttons for
+             * image manipulation. */
+            $html .= '<br />';
+            $img = Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/images/view.php');
+            if (isset($image['img']['vfs_id'])) {
+                /* Calling an image from VFS. */
+                $img = Util::addParameter($img, array('f' => $image['img']['vfs_id'],
+                                                      's' => 'vfs',
+                                                      'p' => $image['img']['vfs_path']));
+            } else {
+                /* Calling an image from a tmp directory (uploads). */
+                $img = Util::addParameter($img, 'f', $image['img']['file']);
+            }
+
+            // TODO: possible to change to unobtrusive JS?
+            /* Rotate 270. */
+            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, array('a' => 'rotate', 'v' => '270')) . '\', \'_p_' . $varname . '\', true);') . Horde::img('rotate-270.png', _("Rotate Left"), '', $img_dir) . '</a>';
+
+            /* Rotate 180. */
+            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, array('a' => 'rotate', 'v' => '180')) . '\', \'_p_' . $varname . '\', true);') . Horde::img('rotate-180.png', _("Rotate 180"), '', $img_dir) . '</a>';
+
+            /* Rotate 90. */
+            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, array('a' => 'rotate', 'v' => '90')) . '\', \'_p_' . $varname . '\', true);') . Horde::img('rotate-90.png', _("Rotate Right"), '', $img_dir) . '</a>';
+
+            /* Flip image. */
+            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, 'a', 'flip') . '\', \'_p_' . $varname . '\', true);') . Horde::img('flip.png', _("Flip"), '', $img_dir) . '</a>';
+
+            /* Mirror image. */
+            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, 'a', 'mirror') . '\', \'_p_' . $varname . '\', true);') . Horde::img('mirror.png', _("Mirror"), '', $img_dir) . '</a>';
+
+            /* Apply grayscale. */
+            $html .= Horde::link('#', '', '', '', 'showImage(\'' . Util::addParameter($img, 'a', 'grayscale') . '\', \'_p_' . $varname . '\', true);') . Horde::img('grayscale.png', _("Grayscale"), '', $img_dir) . '</a>';
+
+            /* Resize width. */
+            $html .= sprintf('%s    <input type="text" class="form-input-resize" onchange="src=getResizeSrc(\'%s\', \'%s\');showImage(src, \'_p_%s\', true);" %s />',
+                   _("w:"),
+                   Util::addParameter($img, 'a', 'resize'),
+                   $varname,
+                   $varname,
+                   '_w_'. $varname);
+
+            /* Resize height. */
+            $html .= sprintf('%s    <input type="text" class="form-input-resize" onchange="src=getResizeSrc(\'%s\', \'%s\');showImage(src, \'_p_%s\', true);" %s />',
+                   _("h:"),
+                   Util::addParameter($img, 'a', 'resize'),
+                   $varname,
+                   $varname,
+                   '_h_'. $varname);
+
+            /* Apply fixed ratio resize. */
+            $html .= Horde::link('#', '', '', '', 'src=getResizeSrc(\'' . Util::addParameter($img, 'a', 'resize') . '\', \'' . $varname . '\', \'1\');showImage(src, \'_p_' . $varname . '\', true);') . Horde::img('ratio.png', _("Fix ratio"), '', $img_dir) . '</a>';
+
+            /* Keep also original if it has been requested. */
+            if ($var->type->show_keeporig) {
+                $html .= sprintf('    <input type="checkbox" class="form-input-checkbox" name="%s"%s />%s' . "\n",
+                       $varname . '[keep_orig]',
+                       !empty($image['keep_orig']) ? ' checked="checked"' : '',
+                       _("Keep original?"));
+            }
+
+            /* The preview image element. */
+            $html .= '<br /><img src="' . $img . '" id="_p_' . $varname .'" />'."\n";
+        }
+
+        return $html;
+    }
+
+    function _renderVarInput_longtext($form, $var, $vars)
+    {
+        global $browser;
+
+        $html = sprintf('<textarea class="form-input-longtext" id="%1$s" name="%1$s" '
+                            .'cols="%2$s" rows="%3$s"%4$s%5$s>%6$s</textarea>',
+                        $var->getVarName(),
+                        $var->type->cols,
+                        $var->type->rows,
+                        $this->_getActionScripts($form, $var),
+                        $var->isDisabled() ? ' disabled="disabled"' : '',
+                        htmlspecialchars($var->getValue($vars)));
+
+        if ($var->type->hasHelper('rte') && $browser->hasFeature('rte')) {
+            $editor = Horde_Editor::factory('Xinha', array('id' => $var->getVarName()));
+        }
+
+        if ($var->type->hasHelper() && $browser->hasFeature('javascript')) {
+            $html .= '<div class="form-html-helper">';
+            Horde::addScriptFile('open_html_helper.js', 'horde');
+            $imgId = $var->getVarName() . 'ehelper';
+            if ($var->type->hasHelper('emoticons')) {
+                $html .= Horde::link('#', _("Emoticons"), '', '', 'openHtmlHelper(\'emoticons\', \'' . $var->getVarName() . '\'); return false;')
+                    . Horde::img('smile.png', _("Emoticons"), 'id="' . $imgId . '" align="middle"', $GLOBALS['registry']->getImageDir('horde') . '/emoticons')
+                    . '</a>'."\n";
+            }
+            $html .= '</div><div id="htmlhelper_' . $var->getVarName()
+                    . '" class="form-control"></div>'."\n";
+        }
+
+        return $html;
+    }
+
+    function _renderVarInput_countedtext($form, $var, $vars)
+    {
+        return sprintf('<textarea class="form-input-countedtext" id="%1$s" name="%1$s" '
+                        .'cols="%2$s" rows="%3$s"%4$s%5$s>%6$s</textarea>',
+                       $var->getVarName(),
+                       $var->type->cols,
+                       $var->type->rows,
+                       $this->_getActionScripts($form, $var),
+                       $var->isDisabled() ? ' disabled="disabled"' : '',
+                       $var->getValue($vars));
+    }
+
+    function _renderVarInput_address($form, $var, $vars)
+    {
+        return sprintf('<textarea class="form-input-address" id="%1$s" name="%1$s" '
+                        .'cols="%2$s" rows="%3$s"%4$s%5$s>%6$s</textarea>',
+                       $var->getVarName(),
+                       $var->type->cols,
+                       $var->type->rows,
+                       $this->_getActionScripts($form, $var),
+                       $var->isDisabled() ? ' disabled="disabled"' : '',
+                       $var->getValue($vars));
+    }
+
+    function _renderVarInput_date($form, $var, $vars)
+    {
+        return sprintf('    <input type="text" class="form-input-date" name="%1$s" id="%1$s" '
+                            .'value="%2$s"%3$s />',
+                        $var->getVarName(),
+                        $value = $var->getValue($vars),
+                        $this->_getActionScripts($form, $var));
+    }
+
+    function _renderVarInput_time($form, $var, $vars)
+    {
+        return sprintf('    <input type="text" class="form-input-time" name="%1$s" id="%1$s" '
+                            .'value="%2$s"%3$s />',
+                       $var->getVarName(),
+                       $value = $var->getValue($vars),
+                       $this->_getActionScripts($form, $var));
+    }
+
+    function _renderVarInput_hourminutesecond($form, $var, $vars)
+    {
+        $varname = $var->getVarName();
+        $time = $var->type->getTimeParts($var->getValue($vars));
+
+        /* Output hours. */
+        $hours = array('' => _("hh"));
+        for ($i = 0; $i <= 23; $i++) {
+            $hours[sprintf('%02d', $i)] = $i;
+        }
+        $html = sprintf('<select name="%1$s[hour]" id="%1$s[hour]"%2$s>%3$s    </select>',
+                        $varname,
+                        $this->_selectOptions($hours, $time['hour']),
+                        $this->_getActionScripts($form, $var));
+
+        /* Output minutes. */
+        $minutes = array('' => _("mm"));
+        for ($i = 0; $i <= 59; $i++) {
+            $minutes[sprintf('%02d', $i)] = $i;
+        }
+        $html .= sprintf('<select name="%1$s[minute]" id="%1$s[minute]"%2$s>%3$s    </select>',
+                         $varname,
+                         $this->_selectOptions($minutes, $time['minute']),
+                         $this->_getActionScripts($form, $var));
+
+        /* Return if seconds are not required. */
+        if ($var->type->show_seconds) {
+            /* Output seconds. */
+            $seconds = array('' => _("ss"));
+            for ($i = 0; $i <= 59; $i++) {
+                $seconds[sprintf('%02d', $i)] = $i;
+            }
+            $html .= sprintf('<select name="%1$s[second]" id="%1$s[second]"%2$s>%3$s    </select>',
+                            $varname,
+                            $this->_getActionScripts($form, $var),
+                            $this->_selectOptions($seconds, $time['second']));
+        }
+
+        return $html;
+    }
+
+    function _renderVarInput_monthyear($form, $var, $vars)
+    {
+        $dates = array();
+        $dates['month'] = array('' => _("MM"),
+                                1 => _("January"),
+                                2 => _("February"),
+                                3 => _("March"),
+                                4 => _("April"),
+                                5 => _("May"),
+                                6 => _("June"),
+                                7 => _("July"),
+                                8 => _("August"),
+                                9 => _("September"),
+                                10 => _("October"),
+                                11 => _("November"),
+                                12 => _("December"));
+        $dates['year'] = array('' => _("YYYY"));
+        if ($var->type->start_year > $var->type->end_year) {
+            for ($i = $var->type->start_year; $i >= $var->type->end_year; $i--) {
+                $dates['year'][$i] = $i;
+            }
+        } else {
+            for ($i = $var->type->start_year; $i <= $var->type->end_year; $i++) {
+                $dates['year'][$i] = $i;
+            }
+        }
+        $html = sprintf('<select name="%1$s" id="%1$s"%2$s>%3$s    </select>',
+               $var->type->getMonthVar($var),
+               $this->_getActionScripts($form, $var),
+               $this->_selectOptions($dates['month'], $vars->get($var->type->getMonthVar($var))));
+
+        $html .= sprintf('<select name="%1$s" id="%1$s"%2$s>%3$s    </select>',
+               $var->type->getYearVar($var),
+               $this->_getActionScripts($form, $var),
+               $this->_selectOptions($dates['year'], $vars->get($var->type->getYearVar($var))));
+
+        return $html;
+    }
+
+    function _renderVarInput_monthdayyear($form, $var, $vars)
+    {
+        $dates = array();
+        $dates['month'] = array(''   => _("MM"),
+                                '1'  => _("January"),
+                                '2'  => _("February"),
+                                '3'  => _("March"),
+                                '4'  => _("April"),
+                                '5'  => _("May"),
+                                '6'  => _("June"),
+                                '7'  => _("July"),
+                                '8'  => _("August"),
+                                '9'  => _("September"),
+                                '10' => _("October"),
+                                '11' => _("November"),
+                                '12' => _("December"));
+        $dates['day'] = array('' => _("DD"));
+        for ($i = 1; $i <= 31; $i++) {
+            $dates['day'][$i] = $i;
+        }
+        $dates['year'] = array('' => _("YYYY"));
+        if ($var->type->start_year > $var->type->end_year) {
+            for ($i = $var->type->start_year; $i >= $var->type->end_year; $i--) {
+                $dates['year'][$i] = $i;
+            }
+        } else {
+            for ($i = $var->type->start_year; $i <= $var->type->end_year; $i++) {
+                $dates['year'][$i] = $i;
+            }
+        }
+        $date = $var->type->getDateParts($var->getValue($vars));
+
+        // TODO: use NLS to get the order right for the Rest Of The
+        // World.
+        $html = '';
+        $date_parts = array('month', 'day', 'year');
+        foreach ($date_parts as $part) {
+            $varname = $var->getVarName() . '[' . $part . ']';
+            $html .= sprintf('<select name="%1$s" id="%1$s"%2$s>%3$s    </select>',
+                             $varname,
+                             $this->_getActionScripts($form, $var),
+                             $this->_selectOptions($dates[$part], $date[$part]));
+        }
+
+        if ($var->type->picker && $GLOBALS['browser']->hasFeature('javascript')) {
+            Horde::addScriptFile('open_calendar.js', 'horde');
+            $imgId = $var->getVarName() .'goto';
+            $html .= '<div id="goto"></div>';
+            $html .= Horde::link('#', _("Select a date"), '', '', 'openCalendar(\'' . $imgId . '\', \'' . $var->getVarName() . '\'); return false;')
+                . Horde::img('calendar.png', _("Calendar"), 'id="' . $imgId . '" ', $GLOBALS['registry']->getImageDir('horde'))
+                . '</a>';
+        }
+
+        return $html;
+    }
+
+    function _renderVarInput_datetime($form, $var, $vars)
+    {
+        return parent::_renderVarInput_monthdayyear($form, $var, $vars) .
+            parent::_renderVarInput_hourminutesecond($form, $var, $vars);
+    }
+
+    function _renderVarInput_colorpicker($form, $var, $vars)
+    {
+        $html = '<div class="form-colorpicker">'
+            . '<input type="text" maxlength="7" name="'
+            . $var->getVarName() . '" id="' . $var->getVarName()
+            . '" value="' . $var->getValue($vars) . '" />';
+
+        if ($GLOBALS['browser']->hasFeature('javascript')) {
+            Horde::addScriptFile('open_colorpicker.js', 'horde', true);
+            $html .= Horde::img('blank.gif', '', array('class' => 'form-colorpicker-preview',
+                                                       'id' => 'colordemo_' . $var->getVarName(),
+                                                       'style' => 'background:' . $var->getValue($vars)), $GLOBALS['registry']->getImageDir('horde'))
+                . Horde::link('#', _("Color Picker"), '', '', 'openColorPicker(\''. $var->getVarName() .'\'); return false;')
+                . Horde::img('colorpicker.png', _("Color Picker"), '', $GLOBALS['registry']->getImageDir('horde')) . '</a>'
+                . '<div id="colorpicker_' . $var->getVarName() . '" class="form-colorpicker-palette"></div>';
+        }
+
+        return $html . '</div>';
+    }
+
+    function _renderVarInput_sorter($form, $var, $vars)
+    {
+        global $registry;
+
+        $varname = $var->getVarName();
+        $instance = $var->type->instance;
+
+        Horde::addScriptFile('sorter.js', 'horde', true);
+
+        return '    <input type="hidden" name="'. $varname
+            . '[array]" value="" id="'. $varname .'-array-" />'."\n"
+            . '    <select class="leftFloat" multiple="multiple" size="'
+            . $var->type->size . '" name="' . $varname
+            . '[list]" onchange="' . $instance . '.deselectHeader();" '
+            . ' id="'. $varname . '-list-">'
+            . $var->type->getOptions($var->getValue($vars)) . '    </select><div class="leftFloat">'
+            . Horde::link('#', _("Move up"), '', '', $instance . '.moveColumnUp(); return false;')
+                . Horde::img('nav/up.png', _("Move up"), '', $registry->getImageDir('horde'))
+                . '</a><br />'
+            . Horde::link('#', _("Move up"), '', '', $instance . '.moveColumnDown(); return false;')
+                . Horde::img('nav/down.png', _("Move down"), '', $registry->getImageDir('horde'))
+                . '</a></div>'
+            . '<script type="text/javascript">' . "\n"
+            . sprintf('%1$s = new Horde_Form_Sorter(\'%1$s\', \'%2$s\', \'%3$s\');' . "\n",
+                    $instance, $varname, $var->type->header)
+            . sprintf("%s.setHidden();\n</script>\n", $instance);
+    }
+
+    function _renderVarInput_assign($form, $var, $vars)
+    {
+        global $registry;
+
+        Horde::addScriptFile('form_assign.js', 'horde', true);
+
+        $name = $var->getVarName();
+        $fname = $form->getName() . '.' . $name;
+        $width = $var->type->width;
+        $lhdr = (bool)$var->type->getHeader(0);
+        $rhdr = (bool)$var->type->getHeader(1);
+        $this->_onLoadJS[] = 'Horde_Form_Assign.setField(\'' . $fname . '\');';
+
+        $html = '<div class="form-input-assign">'
+             . '    <input type="hidden" name="' . $name . '__values" id="' . $name . '__values" />'
+             . sprintf('    <select name="%1$s__left" id="%1$s__left" multiple="multiple" '
+                         .'size="%2$d" style="width:%3$s"%4$s>',
+                     $name, $var->type->size, $width,
+                     $lhdr ? ' onchange="Horde_Form_Assign.deselectHeaders(\'' . $fname . '\', 0);"' : '')
+             . $var->type->getOptions(0, $fname)
+             . '    </select>'
+             . '<div><a href="" onclick="Horde_Form_Assign.move(\''. $fname .'\', 0); return false;">'
+             . Horde::img('rhand.png', _("Add column"), null, $registry->getImageDir('horde'))
+             . '</a><br /><a href="" onclick="Horde_Form_Assign.move(\''
+             . $fname . '\', 1); return false;">'
+             . Horde::img('lhand.png', _("Remove column"), null, $registry->getImageDir('horde'))
+             . '</a></div>'
+             . sprintf('    <select name="%s__right" multiple="multiple" size="%d" style="width:%s"%s>',
+                     $name, $size, $width,
+                     $rhdr ? ' onchange="Horde_Form_Assign.deselectHeaders(\'' . $fname . '\', 1);"' : '')
+             . $var->type->getOptions(1, $fname)
+             . '    </select></div>';
+
+        return $html;
+    }
+
+    function _renderVarInput_invalid($form, $var, $vars)
+    {
+        return $this->_renderVarDisplay_invalid($form, $var, $vars);
+    }
+
+    function _renderVarInput_enum($form, $var, $vars)
+    {
+        $values = $var->getValues();
+        $prompt = $var->type->prompt;
+        $htmlchars = $var->getOption('htmlchars');
+        if ($prompt) {
+            $prompt = '<option value="">' . ($htmlchars ? htmlspecialchars($prompt, ENT_QUOTES, NLS::getCharset()) : $prompt) . '</option>';
+        }
+        return sprintf('    <select name="%1$s" id="%1$s"%2$s>%3$s%4$s    </select>',
+               $var->getVarName(),
+               $this->_getActionScripts($form, $var),
+               $prompt,
+               $this->_selectOptions($values, $var->getValue($vars), $htmlchars));
+    }
+
+    function _renderVarInput_mlenum($form, $var, $vars)
+    {
+        $varname = $var->getVarName();
+        $values = $var->getValues();
+        $prompts = $var->type->prompts;
+        $selected = $var->getValue($vars);
+
+        /* If passing a non-array value need to get the keys. */
+        if (!is_array($selected)) {
+            foreach ($values as $key_1 => $values_2) {
+                if (isset($values_2[$selected])) {
+                    $selected = array('1' => $key_1, '2' => $selected);
+                    break;
+                }
+            }
+        }
+
+        /* Hidden tag to store the current first level. */
+        $html = sprintf('    <input type="hidden" name="%1$s[old]" id="%1$s[old]" value="%2$s" />',
+                        $varname,
+                        htmlspecialchars($selected['1'], ENT_QUOTES, NLS::getCharset()));
+
+        /* First level. */
+        $values_1 = Horde_Array::valuesToKeys(array_keys($values));
+        $html .= sprintf('    <select id="%1$s[1]" name="%1$s[1]" onchange="%2$s"%3$s>',
+                         $varname,
+                         'if (this.value) { document.' . $form->getName() . '.formname.value=\'\';' . 'document.' . $form->getName() . '.submit() }',
+                         ($var->hasAction() ? ' ' . $this->_genActionScript($form, $var->_action, $varname) : ''));
+        if (!empty($prompts)) {
+            $html .= '<option value="">' . htmlspecialchars($prompts[0], ENT_QUOTES, NLS::getCharset()) . '</option>';
+        }
+        $html .= $this->_selectOptions($values_1, $selected['1']);
+        $html .= '    </select>';
+
+        /* Second level. */
+        $html .= sprintf('    <select id="%1$s[2]" name="%1$s[2]"%2$s>',
+                         $varname,
+                         ($var->hasAction() ? ' ' . $this->_genActionScript($form, $var->_action, $varname) : ''));
+        if (!empty($prompts)) {
+            $html .= '<option value="">' . htmlspecialchars($prompts[1], ENT_QUOTES, NLS::getCharset()) . '</option>';
+        }
+        $values_2 = array();
+        if (!empty($selected['1'])) {
+            $values_2 = $values[$selected['1']];
+        }
+        return $html . $this->_selectOptions($values_2, $selected['2']) . '    </select>';
+    }
+
+    function _renderVarInput_multienum($form, $var, $vars)
+    {
+        $values = $var->getValues();
+        $selected = $vars->getExists($var->getVarName(), $wasset);
+        if (!$wasset) {
+            $selected = $var->getDefault();
+        }
+        $html = sprintf('    <select multiple="multiple" size="%1$s" name="%2$s[]" id="%2$s[]" %3$s>%4$s    </select>',
+                        $var->type->size,
+                        $var->getVarName(),
+                        $this->_getActionScripts($form, $var),
+                        $this->_multiSelectOptions($values, $selected));
+        return $html . '<p class="form-hint">'
+            . _("To select multiple items, hold down the Control (PC) or Command (Mac) key while clicking.")
+            . "</p>\n";
+    }
+
+    function _renderVarInput_keyval_multienum($form, $var, $vars)
+    {
+        return $this->_renderVarInput_multienum($form, $var, $vars);
+    }
+
+    function _renderVarInput_radio($form, $var, $vars)
+    {
+        return $this->_radioButtons($var->getVarName(),
+                                    $var->getValues(),
+                                    $var->getValue($vars),
+                                    $this->_getActionScripts($form, $var));
+    }
+
+    function _renderVarInput_set($form, $var, $vars)
+    {
+        $html = $this->_checkBoxes($var->getVarName(),
+                                   $var->getValues(),
+                                   $var->getValue($vars),
+                                   $this->_getActionScripts($form, $var));
+
+        if ($var->type->checkAll) {
+            $form_name = $form->getName();
+            $var_name = $var->getVarName() . '[]';
+            $function_name = 'select'  . $form_name . $var->getVarName();
+            $enable = _("Select all");
+            $disable = _("Select none");
+            $invert = _("Invert selection");
+            $html .= <<<EOT
+<script type="text/javascript">
+function $function_name()
+{
+    for (var i = 0; i < document.$form_name.elements.length; i++) {
+        f = document.$form_name.elements[i];
+        if (f.name != '$var_name') {
+            continue;
+        }
+        if (arguments.length) {
+            f.checked = arguments[0];
+        } else {
+            f.checked = !f.checked;
+        }
+    }
+}
+</script>
+<a href="#" onclick="$function_name(true); return false;">$enable</a>,
+<a href="#" onclick="$function_name(false); return false;">$disable</a>,
+<a href="#" onclick="$function_name(); return false;">$invert</a>
+EOT;
+        }
+
+        return $html;
+    }
+
+    function _renderVarInput_link($form, $var, $vars)
+    {
+        return $this->_renderVarDisplay_link($form, $var, $vars);
+    }
+
+    function _renderVarInput_html($form, $var, $vars)
+    {
+        return $this->_renderVarDisplay_html($form, $var, $vars);
+    }
+
+    function _renderVarInput_email($form, $var, $vars)
+    {
+        return sprintf('    <input type="text" id="%1$s" name="%1$s" value="%2$s"%3$s />',
+               $var->getVarName(),
+               $value = $var->getValue($vars),
+               $this->_getActionScripts($form, $var));
+    }
+
+    function _renderVarInput_matrix($form, $var, $vars)
+    {
+        $varname   = $var->getVarName();
+        $var_array = $var->getValue($vars);
+        $cols      = $var->type->cols;
+        $rows      = $var->type->rows;
+        $matrix    = $var->type->matrix;
+        $new_input = $var->type->new_input;
+
+        $html = '<table cellspacing="0"><tr>';
+
+        $html .= '<td align="right" width="20%"></td>';
+        foreach ($cols as $col_title) {
+            $html .= sprintf('<td align="center" width="1%%">%s</td>', $col_title);
+        }
+        $html .= '<td align="right" width="60%"></td></tr>';
+
+        /* Offer a new row of data to be added to the matrix? */
+        if ($new_input) {
+            $html .= '<tr><td>'."\n";
+            if (is_array($new_input)) {
+                $html .= sprintf('    <select%s name="%s[n][r]"><option value="">%s</option>%s    </select><br />'."\n",
+                       ' id="'. $varname .'-n--r-"',
+                       $varname,
+                       _("-- select --"),
+                       $this->_selectOptions($new_input, $var_array['n']['r']));
+            } elseif ($new_input == true) {
+                $html .= sprintf('    <input%s type="text" name="%s[n][r]" value="%s" />',
+                       ' id="'. $varname .'-n--r-',
+                       $varname,
+                       $var_array['n']['r']);
+            }
+            $html .= ' </td>';
+            foreach ($cols as $col_id => $col_title) {
+                $html .= sprintf('<td align="center"><input type="checkbox" class="checkbox" name="%s[n][v][%s]" /></td>', $varname, $col_id);
+            }
+            $html .= '<td>&nbsp;</td></tr>'."\n";
+        }
+
+        /* Loop through the rows and create checkboxes for each column. */
+        foreach ($rows as $row_id => $row_title) {
+            $html .= sprintf('<tr><td>%s</td>', $row_title);
+            foreach ($cols as $col_id => $col_title) {
+                $html .= sprintf('<td align="center"><input type="checkbox" class="checkbox" name="%s[r][%s][%s]"%s /></td>', $varname, $row_id, $col_id, (!empty($matrix[$row_id][$col_id]) ? ' checked="checked"' : ''));
+            }
+            $html .= '<td>&nbsp;</td></tr>'."\n";
+        }
+
+        $html .= '</table>'."\n";
+        return $html;
+    }
+
+    function _renderVarInput_password($form, $var, $vars)
+    {
+        return sprintf('<input type="password" id="%1$s" name="%1$s" value="%2$s"%3$s />',
+               $var->getVarName(),
+               $value = $var->getValue($vars),
+               $this->_getActionScripts($form, $var));
+    }
+
+    function _renderVarInput_emailconfirm($form, $var, $vars)
+    {
+        $email = $var->getValue($vars);
+        return '<ul><li>' . sprintf('<input type="text" class="form-input-emailconfirm"' .
+                                    ' id="%1$s" name="%1$s[original]" value="%2$s"%3$s />',
+                                    $var->getVarName(),
+                                    $value = $email['original'],
+                                    $this->_getActionScripts($form, $var)) . '</li><li>' .
+            sprintf('<input type="text" class="form-input-emailconfirm"' .
+                    ' id="%1$s-confirm-" name="%1$s[confirm]" value="%2$s"%3$s />',
+                    $var->getVarName(),
+                    $value = $email['confirm'],
+                    $this->_getActionScripts($form, $var)) . '</li></ul>';
+    }
+
+    function _renderVarInput_passwordconfirm($form, $var, $vars)
+    {
+        $password = $var->getValue($vars);
+        return '<ul><li>' . sprintf('<input type="password" class="form-input-passwordconfirm"'
+                                    .' id="%1$s" name="%1$s[original]" value="%2$s"%3$s />',
+                                    $var->getVarName(),
+                                    $value = $password['original'],
+                                    $this->_getActionScripts($form, $var)) . '</li><li>' .
+            sprintf('<input type="password" class="form-input-passwordconfirm"'
+                    .' id="%1$s-confirm-" name="%1$s[confirm]" value="%2$s"%3$s />',
+                    $var->getVarName(),
+                    $value = $password['confirm'],
+                    $this->_getActionScripts($form, $var)) . '</li></ul>';
+    }
+
+    function _renderVarInput_boolean($form, $var, $vars)
+    {
+        $varName = $var->getVarName();
+
+        $html = '    <input type="checkbox" class="form-input-checkbox" id="' .  $varName . '"'
+            .  ' name="' .  $varName . '"'
+            . ($var->getValue($vars) ? ' checked="checked"' : '');
+        if ($var->hasAction()) {
+            $html .= $this->_genActionScript($form, $var->_action,
+                                             $var->getVarName());
+        }
+        $html .= ' />';
+        return $html;
+    }
+
+    function _renderVarInput_creditcard($form, $var, $vars)
+    {
+        $varName = $var->getVarName();
+
+        $html = '    <input type="text" class="form-input-creditcard" id="' .  $varName . '"'
+            .  ' name="' .  $varName . '"'
+            .$var->getValue($vars);
+        if ($var->hasAction()) {
+            $html .= $this->_genActionScript($form, $var->_action,
+                                             $var->getVarName());
+        }
+
+        return $html . ' />';
+    }
+
+    function _renderVarInput_obrowser($form, $var, $vars)
+    {
+        $varname = $var->getVarName();
+        $varvalue = $vars->get($varname);
+        $fieldId = 'obrowser_' . hash('md5', uniqid(rand(), true));
+        $html = '
+            <script type="text/javascript">
+            var obrowserWindowName;
+            function obrowserCallback(name, oid)
+            {
+                if (name == obrowserWindowName) {
+                    document.getElementById(\'' . $fieldId . '\').value = oid;
+                    return false;
+                } else {
+                    return "Invalid window name supplied";
+                }
+            }
+            </script>
+            ';
+        $html .= sprintf('<input type="hidden" name="%s" id="%s"%s value="%s" />',
+                         $varname,
+                         $fieldId,
+                         $this->_getActionScripts($form, $var),
+                         $varvalue);
+        if (!empty($varvalue)) {
+            $html .= $varvalue;
+        }
+
+        if ($GLOBALS['browser']->hasFeature('javascript')) {
+            Horde::addScriptFile('popup.js', 'horde', true);
+            $imgId = $varname .'goto';
+            $html .= '<div id="goto" class="headerbox"
+                    style="position:absolute;visibility:hidden;padding:0"></div>';
+            $html .= Horde::link('#', _("Select an object"), '', '', 'obrowserWindow = popup(\'' . $GLOBALS['registry']->get('webroot', 'horde') . '/services/obrowser/' . '\'); obrowserWindowName = obrowserWindow.name; return false;') . Horde::img('tree/leaf.png', _("Object"), 'id="' . $imgId . '" align="middle"', $GLOBALS['registry']->getImageDir('horde')) . "</a>\n";
+        }
+
+        return $html;
+    }
+
+    function _renderVarInput_dblookup($form, $var, $vars)
+    {
+        return $this->_renderVarInput_enum($form, $var, $vars);
+    }
+
+    function _renderVarInput_figlet($form, $var, $vars)
+    {
+        return sprintf('    <input type="text" class="form-input-figlet" id="%1$s" name="%1$s" size="%2$s" value="%3$s" />',
+                       $var->getVarName(),
+                       strlen($var->type->text),
+                       htmlspecialchars($var->getValue($vars))) .
+            '<p class="form-input-figlet">' . _("Enter the letters below:") . '</p>' .
+            $this->_renderVarDisplay_figlet($form, $var, $vars);
+    }
+
+    function _renderVarDisplayDefault($form, $var, $vars)
+    {
+        return nl2br(htmlspecialchars($var->getValue($vars), ENT_QUOTES,
+            NLS::getCharset()));
+    }
+
+    function _renderVarDisplay_html($form, $var, $vars)
+    {
+        return $var->getValue($vars);
+    }
+
+    function _renderVarDisplay_email($form, $var, $vars)
+    {
+        $display_email = $email = $var->getValue($vars);
+
+        if ($var->type->strip_domain && strpos($email, '@') !== false) {
+            $display_email = str_replace(array('@', '.'),
+                                         array(' (at) ', ' (dot) '),
+                                         $email);
+        }
+
+        if ($var->type->link_compose) {
+            $email_val = trim($email);
+
+            // Format the address according to RFC822.
+            $mailbox_host = explode('@', $email_val);
+            if (!isset($mailbox_host[1])) {
+                $mailbox_host[1] = '';
+            }
+
+            $name = $var->type->link_name;
+
+            require_once 'Horde/MIME.php';
+            $address = MIME::rfc822WriteAddress($mailbox_host[0], $mailbox_host[1], $name);
+
+            // Get rid of the trailing @ (when no host is included in
+            // the email address).
+            $address = str_replace('@>', '>', $address);
+            $mail_link = $GLOBALS['registry']->call('mail/compose', array(array('to' => addslashes($address))));
+            if (is_a($mail_link, 'PEAR_Error')) {
+                $mail_link = 'mailto:' . urlencode($address);
+            }
+
+            return Horde::link($mail_link, $email_val)
+                . htmlspecialchars($display_email) . '</a>';
+        } else {
+            return nl2br(htmlspecialchars($display_email, ENT_QUOTES, NLS::getCharset()));
+        }
+    }
+
+    function _renderVarDisplay_password($form, $var, $vars)
+    {
+        return '********';
+    }
+
+    function _renderVarDisplay_passwordconfirm($form, $var, $vars)
+    {
+        return '********';
+    }
+
+    function _renderVarDisplay_octal($form, $var, $vars)
+    {
+        return sprintf('0%o', octdec($var->getValue($vars)));
+    }
+
+    function _renderVarDisplay_boolean($form, $var, $vars)
+    {
+        return $var->getValue($vars) ? _("Yes") : _("No");
+    }
+
+    function _renderVarDisplay_enum($form, $var, $vars)
+    {
+        $values = $var->getValues();
+        $value = $var->getValue($vars);
+        if (count($values) == 0) {
+            return _("No values");
+        } elseif (isset($values[$value]) && $value != '') {
+            return htmlspecialchars($values[$value], ENT_QUOTES, NLS::getCharset());
+        }
+    }
+
+    function _renderVarDisplay_radio($form, $var, $vars)
+    {
+        $values = $var->getValues();
+        if (count($values) == 0) {
+            return _("No values");
+        } elseif (isset($values[$var->getValue($vars)])) {
+            return htmlspecialchars($values[$var->getValue($vars)], ENT_QUOTES, NLS::getCharset());
+        }
+    }
+
+    function _renderVarDisplay_multienum($form, $var, $vars)
+    {
+        $values = $var->getValues();
+        $on = $var->getValue($vars);
+        if (!count($values) || !count($on)) {
+            return _("No values");
+        } else {
+            $display = array();
+            foreach ($values as $value => $name) {
+                if (in_array($value, $on)) {
+                    $display[] = $name;
+                }
+            }
+            return htmlspecialchars(implode(', ', $display), ENT_QUOTES, NLS::getCharset());
+        }
+    }
+
+    function _renderVarDisplay_set($form, $var, $vars)
+    {
+        $values = $var->getValues();
+        $on = $var->getValue($vars);
+        if (!count($values) || !count($on)) {
+            return _("No values");
+        } else {
+            $display = array();
+            foreach ($values as $value => $name) {
+                if (in_array($value, $on)) {
+                    $display[] = $name;
+                }
+            }
+            return htmlspecialchars(implode(', ', $display), ENT_QUOTES, NLS::getCharset());
+        }
+    }
+
+    function _renderVarDisplay_image($form, $var, $vars)
+    {
+        $img_params = $var->getValue($vars);
+        $img_url = Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/images/view.php');
+        $img_url = Util::addParameter($img_url, $img_params);
+
+        return Horde::img($img_url, isset($img_params['f']) ? $img_params['f'] : '', '', '');
+    }
+
+    function _renderVarDisplay_phone($form, &$var, &$vars)
+    {
+        global $registry;
+
+        $number = $var->getValue($vars);
+        $html = htmlspecialchars($number, ENT_QUOTES, $this->_charset);
+
+        if ($number && $registry->hasMethod('telephony/dial')) {
+            $url = $registry->call('telephony/dial', array($number));
+            $label = sprintf(_("Dial %s"), $number);
+            $html .= ' ' . Horde::link($url, $label) . Horde::img('phone.png', $label, '', $registry->getImageDir('horde')) . '</a>';
+        }
+
+        return $html;
+    }
+
+    function _renderVarDisplay_cellphone($form, &$var, &$vars)
+    {
+        global $registry;
+
+        $html = $this->_renderVarDisplay_phone($form, $var, $vars);
+
+        $number = $var->getValue($vars);
+        if ($number && $registry->hasMethod('sms/compose')) {
+            $url = $registry->link('sms/compose', array('to' => $number));
+            $html .= ' ' . Horde::link($url, _("Send SMS")) . Horde::img('mobile.png', _("Send SMS"), '', $registry->getImageDir('horde')) . '</a>';
+        }
+
+        return $html;
+    }
+
+    function _renderVarDisplay_address($form, $var, $vars)
+    {
+        global $registry;
+
+        $address = $var->getValue($vars);
+
+        if (preg_match('/((?:A[BL]|B[ABDHLNRST]?|C[ABFHMORTVW]|D[ADEGHLNTY]|E[CHNX]?|F[KY]|G[LUY]?|H[ADGPRSUX]|I[GMPV]|JE|K[ATWY]|L[ADELNSU]?|M[EKL]?|N[EGNPRW]?|O[LX]|P[AEHLOR]|R[GHM]|S[AEGKLMNOPRSTWY]?|T[ADFNQRSW]|UB|W[ACDFNRSV]?|YO|ZE)\d(?:\d|[A-Z])? \d[A-Z]{2})/', $address, $postcode)) {
+            /* UK postcode detected. */
+            /* Multimap.co.uk generated map */
+            $mapurl = 'http://www.multimap.com/map/browse.cgi?pc=' . urlencode($postcode[1]);
+            $desc = _("Multimap UK map");
+            $icon = 'map.png';
+        } elseif (preg_match('/ACT|NSW|NT|QLD|SA|TAS|VIC|WA/', $address)) {
+            /* Australian state detected. */
+            /* Whereis.com.au generated map */
+            $mapurl = 'http://www.whereis.com.au/whereis/mapping/geocodeAddress.do?';
+            $desc = _("Whereis Australia map");
+            $icon = 'map.png';
+            /* Split out the address, line-by-line. */
+            $addressLines = explode("\n", $address);
+            for ($i = 0; $i < count($addressLines); $i++) {
+                /* See if it's the street number & name. */
+                if (preg_match('/(\d+\s*\/\s*)?(\d+|\d+[a-zA-Z])\s+([a-zA-Z ]*)/', $addressLines[$i], $lineParts)) {
+                    $mapurl .= '&streetNumber=' . urlencode($lineParts[2]);
+                    $mapurl .= '&streetName=' . urlencode($lineParts[3]);
+                }
+                /* Look for "Suburb, State". */
+                if (preg_match('/([a-zA-Z ]*),?\s+' . $aus_state_regexp . '/', $addressLines[$i], $lineParts)) {
+                    $mapurl .= '&suburb=' . urlencode($lineParts[1]);
+                }
+                /* Look for "State <4 digit postcode>". */
+                if (preg_match('/(' . $aus_state_regexp . ')\s+(\d{4})/', $addressLines[$i], $lineParts)) {
+                    $mapurl .= '&state=' . urlencode($lineParts[1]);
+                }
+            }
+        } elseif (preg_match('/(.*)\n(.*)\s*,\s*(\w+)\.?\s+(\d+|[a-zA-Z]\d[a-zA-Z]\s?\d[a-zA-Z]\d)/', $address, $addressParts)) {
+            /* American/Canadian address style. */
+            /* Mapquest generated map */
+            $mapurl = 'http://www.mapquest.com/maps/map.adp?size=big&zoom=7';
+            $desc = _("MapQuest map");
+            $icon = 'map.png';
+            $country = null;
+            if (!empty($addressParts[4]) && preg_match('|[a-zA-Z]\d[a-zA-Z]\s?\d[a-zA-Z]\d|', $addressParts[4])) {
+                $country = 'CA';
+            }
+            if (!empty($addressParts[1])) {
+                $mapurl .= '&address=' . urlencode($addressParts[1]);
+            }
+            if (!empty($addressParts[2])) {
+                $mapurl .= '&city=' . urlencode($addressParts[2]);
+            }
+            if (!empty($addressParts[3])) {
+                $mapurl .= '&state=' . urlencode($addressParts[3]);
+            }
+            if (!empty($addressParts[4])) {
+                if ($country == 'CA') {
+                    $mapurl .= '&country=CA';
+                }
+                $mapurl .= '&zipcode=' . urlencode($addressParts[4]);
+            }
+
+            /* Yahoo! generated map. */
+            $mapurl2 = 'http://us.rd.yahoo.com/maps/home/submit_a/*-http://maps.yahoo.com/maps?srchtype=a&getmap=Get+Map&';
+            $desc2 = _("Yahoo! map");
+            $icon2 = 'map.png';
+            if (!empty($addressParts[1])) {
+                $mapurl2 .= '&addr=' . urlencode($addressParts[1]);
+            }
+            /* Give precedence to zipcode over city/state */
+            if (empty($addressParts[4]) && !empty($addressParts[2]) && !empty($addressParts[3])) {
+                $mapurl2 .= '&csz=' . urlencode($addressParts[2] . ' ' . $addressParts[3]);
+            }
+            if (!empty($addressParts[4])) {
+                if (preg_match('|([a-zA-Z]\d[a-zA-Z])\s?(\d[a-zA-Z]\d)|', $addressParts[4], $pcParts)) {
+                    $mapurl2 .= '&country=ca';
+                    /* make sure the postal-code has a space */
+                    $addressParts[4] = $pcParts[1] . ' ' . $pcParts[2];
+                }
+                $mapurl2 .= '&csz=' . urlencode($addressParts[4]);
+            }
+
+            /* Google generated map. */
+            $mapurl3 = 'http://maps.google.com/maps?q=' . urlencode($addressParts[0]) . '&hl=en';
+            $desc3 = _("Google Maps");
+            $icon3 = 'map.png';
+
+        } elseif (preg_match('/(.*?)\r?\n([A-Z]{1,3})-(\d{5})\s+(.*)/i', $address, $addressParts)) {
+            /* European address style. */
+            include 'Horde/NLS/carsigns.php';
+            $country = array_search(String::upper($addressParts[2]), $carsigns);
+
+            /* Map24 generated map. */
+            if (in_array($country, array('al', 'ad', 'am', 'az', 'be', 'ba',
+                                         'bg', 'de', 'dk', 'ee', 'fo', 'fi',
+                                         'fr', 'ge', 'gr', 'gb', 'ie', 'is',
+                                         'it', 'hr', 'lv', 'li', 'lt', 'lu',
+                                         'mt', 'mk', 'md', 'mc', 'nl', 'no',
+                                         'pl', 'pt', 'ro', 'ru', 'se', 'ch',
+                                         'cs', 'sk', 'si', 'es', 'cz', 'tr',
+                                         'ua', 'hu', 'by', 'cy', 'at'))) {
+                if (in_array($country, array('at', 'be', 'ch', 'de', 'dk',
+                                             'es', 'fi', 'fr', 'it', 'nl',
+                                             'no', 'se'))) {
+                    $mirror = $country;
+                } else {
+                    $mirror = 'uk';
+                }
+                $mapurl = 'http://www.' . $mirror . '.map24.com/source/address/v2.0.0/cnt_nav_maplet.php?cid=validateaddr&country=' . $country;
+                $desc = _("Map24 map");
+                $icon = 'map_eu.png';
+                if (!empty($addressParts[1])) {
+                    $mapurl .= '&street=' . urlencode($addressParts[1]);
+                }
+                if (!empty($addressParts[3])) {
+                    $mapurl .= '&zip=' . urlencode($addressParts[3]);
+                }
+                if (!empty($addressParts[4])) {
+                    $mapurl .= '&city=' . urlencode($addressParts[4]);
+                }
+            }
+
+            /* Mapquest generated map. */
+            $mapurl2 = 'http://www.mapquest.com/maps/map.adp?country=' . String::upper($country);
+            $desc2 = _("MapQuest map");
+            $icon2 = 'map_eu.png';
+            if (!empty($addressParts[1])) {
+                $mapurl2 .= '&address=' . urlencode($addressParts[1]);
+            }
+            if (!empty($addressParts[3])) {
+                $mapurl2 .= '&zipcode=' . urlencode($addressParts[3]);
+            }
+            if (!empty($addressParts[4])) {
+                $mapurl2 .= '&city=' . urlencode($addressParts[4]);
+            }
+        }
+
+        $html = nl2br(htmlspecialchars($var->getValue($vars), ENT_QUOTES, NLS::getCharset()));
+        if (!empty($mapurl)) {
+            $html .= '&nbsp;&nbsp;' . Horde::link(Horde::externalUrl($mapurl), $desc, null, '_blank') . Horde::img($icon, $desc, '', $registry->getImageDir('horde')) . '</a>';
+        }
+        if (!empty($mapurl2)) {
+            $html .= '&nbsp;' . Horde::link(Horde::externalUrl($mapurl2), $desc2, null, '_blank') . Horde::img($icon2, $desc2, '', $registry->getImageDir('horde')) . '</a>';
+        }
+        if (!empty($mapurl3)) {
+            $html .= '&nbsp;' . Horde::link(Horde::externalUrl($mapurl3), $desc3, null, '_blank') . Horde::img($icon3, $desc3, '', $registry->getImageDir('horde')) . '</a>';
+        }
+
+        return $html;
+    }
+
+    function _renderVarDisplay_date($form, $var, $vars)
+    {
+        return $var->type->getFormattedTime($var->getValue($vars));
+    }
+
+    function _renderVarDisplay_monthyear($form, $var, $vars)
+    {
+        return $vars->get($var->getVarName() . '[month]') . ', ' . $vars->get($var->getVarName() . '[year]');
+    }
+
+    function _renderVarDisplay_monthdayyear($form, $var, $vars)
+    {
+        $date = $var->getValue($vars);
+        if ((is_array($date) && !empty($date['year']) &&
+             !empty($date['month']) && !empty($date['day']))
+            || (!is_array($date) && !empty($date))) {
+            return $var->type->formatDate($date);
+        }
+        return '';
+    }
+
+    function _renderVarDisplay_invalid($form, $var, $vars)
+    {
+        return '<p class="form-error form-inline">'
+                . htmlspecialchars($var->type->message, ENT_QUOTES, NLS::getCharset())
+                . '</p>';
+    }
+
+    function _renderVarDisplay_link($form, $var, $vars)
+    {
+        $values = $var->getValues();
+        if (!isset($values[0])) {
+            $values = array($values);
+        }
+
+
+        $count = count($values);
+        $html = '';
+        for ($i = 0; $i < $count; $i++) {
+            if (empty($values[$i]['url']) || empty($values[$i]['text'])) {
+                continue;
+            }
+            if (!isset($values[$i]['target'])) {
+                $values[$i]['target'] = '';
+            }
+            if (!isset($values[$i]['onclick'])) {
+                $values[$i]['onclick'] = '';
+            }
+            if (!isset($values[$i]['title'])) {
+                $values[$i]['title'] = '';
+            }
+            if (!isset($values[$i]['accesskey'])) {
+                $values[$i]['accesskey'] = '';
+            }
+            if ($i > 0) {
+                $html .= ' | ';
+            }
+            $html .= Horde::link($values[$i]['url'], $values[$i]['text'],
+                        'widget', $values[$i]['target'], $values[$i]['onclick'],
+                        $values[$i]['title'], $values[$i]['accesskey'])
+                    . $values[$i]['text'] . '</a>';
+        }
+
+        return $html;
+    }
+
+    function _renderVarDisplay_dblookup($form, $var, $vars)
+    {
+        return $this->_renderVarDisplay_enum($form, $var, $vars);
+    }
+
+    function _renderVarDisplay_figlet($form, $var, $vars)
+    {
+        $figlet = new Text_Figlet();
+        $result = $figlet->loadFont($var->type->font);
+        if (is_a($result, 'PEAR_Error')) {
+            return $result->getMessage();
+        }
+
+        return '<pre>' . $figlet->lineEcho($var->type->text) . '</pre>';
+    }
+
+    function _renderVarInput_selectFiles($form, $var, $vars)
+    {
+        /* Needed for gollem js calls */
+        $html = sprintf('<input type="hidden" id="%1$s" name="%1$s" value="%2$s" />',
+                        'selectlist_selectid',
+                        $var->type->selectid)
+            . sprintf('<input type="hidden" id="%1$s" name="%1$s" />', 'actionID');
+
+        /* Form field. */
+        $html .= sprintf('<input type="hidden" id="%1$s" name="%1$s" value="%2$s" />',
+                         $var->getVarName(),
+                         $var->type->selectid);
+
+        /* Open window link. */
+        $param = array($var->type->link_text,
+                       $var->type->link_style,
+                       $form->getName(),
+                       $var->type->icon,
+                       $var->type->selectid);
+        $html .= "<p>\n" . $GLOBALS['registry']->call('files/selectlistLink', $param) . "</p>\n";
+
+        if ($var->type->selectid) {
+            $param = array($var->type->selectid);
+            $files = $GLOBALS['registry']->call('files/selectlistResults', $param);
+            if ($files) {
+                $html .= '<ol>';
+                foreach ($files as $id => $file) {
+                    $dir = key($file);
+                    $filename = current($file);
+                    if ($GLOBALS['registry']->hasMethod('files/getViewLink')) {
+                        $filename = basename($filename);
+                        $url = $GLOBALS['registry']->call('files/getViewLink', array($dir, $filename));
+                        $filename = Horde::link($url, _("Preview"), null, 'form_file_view') . htmlspecialchars(Util::realPath($dir . '/' . $filename), ENT_QUOTES, $this->_charset) . '</a>';
+                    } else {
+                        if (!empty($dir) && ($dir != '.')) {
+                            $filename = $dir . '/' . $filename;
+                        }
+                        $filename = htmlspecialchars($filename, ENT_QUOTES, $this->_charset);
+                    }
+                    $html .= '<li>' . $filename . "</li>\n";
+                }
+                $html .= '</ol>';
+            }
+        }
+
+        return $html;
+    }
+
+    function _selectOptions($values, $selectedValue = false, $htmlchars = true)
+    {
+        $result = '';
+        $sel = false;
+        foreach ($values as $value => $display) {
+            if (!is_null($selectedValue) && !$sel && $value == $selectedValue
+                && strlen($value) == strlen($selectedValue)) {
+                $selected = ' selected="selected"';
+                $sel = true;
+            } else {
+                $selected = '';
+            }
+            $result .= '        <option value="';
+            $result .= ($htmlchars) ? htmlspecialchars($value, ENT_QUOTES, NLS::getCharset()) : $value;
+            $result .= '"' . $selected . '>';
+            $result .= ($htmlchars) ? htmlspecialchars($display) : $display;
+            $result .= "</option>\n";
+        }
+
+        return $result;
+    }
+
+    function _multiSelectOptions($values, $selectedValues)
+    {
+        $result = '';
+        $sel = false;
+        foreach ($values as $value => $display) {
+            if (@in_array($value, $selectedValues)) {
+                $selected = ' selected="selected"';
+            } else {
+                $selected = '';
+            }
+            $result .= " <option value=\""
+                . htmlspecialchars($value, ENT_QUOTES, NLS::getCharset())
+                . "\"$selected>" . htmlspecialchars($display) . "</option>\n";
+        }
+
+        return $result;
+    }
+
+    function _checkBoxes($name, $values, $checkedValues, $actions = '')
+    {
+        $result = '';
+        if (!is_array($checkedValues)) {
+            $checkedValues = array();
+        }
+
+        if (count($values) > 0) {
+            $result .= "    <ul>\n";
+        }
+
+        $i = 0;
+        foreach ($values as $value => $display) {
+            $checked = in_array($value, $checkedValues) ? ' checked="checked"' : '';
+            $result .= sprintf('        <li>'
+                                .'<input id="%1$s%2$s" type="checkbox"'
+                                    .' class="form-input-checkbox" name="%1$s[]"'
+                                    .' value="%3$s"%4$s%5$s />'
+                                .'&nbsp;<label class="form-inline" for="%1$s%2$s">'
+                                    .'%6$s</label></li>'."\n",
+                            $name,
+                            $i,
+                            $value,
+                            $checked,
+                            $actions,
+                            $display);
+            $i++;
+        }
+
+        if (count($values) > 0) {
+            $result .= "    </ul>";
+        }
+
+
+        return $result;
+    }
+
+    function _radioButtons($name, $values, $checkedValue = null, $actions = '')
+    {
+        $result = '';
+
+        if (count($values) > 0) {
+            $result .= "    <ul>\n";
+        }
+
+        $i = 0;
+        foreach ($values as $value => $display) {
+            $checked = (!is_null($checkedValue) && $value == $checkedValue) ? ' checked="checked"' : '';
+            $result .= sprintf('        <li>'
+                                .'<input id="%1$s%2$s" type="radio"'
+                                    .' class="form-input-checkbox" name="%1$s"'
+                                    .' value="%3$s"%4$s%5$s />'
+                                .'&nbsp;<label class="form-inline" for="%1$s%2$s">'
+                                    .'%6$s</label></li>'."\n",
+                            $name,
+                            $i,
+                            $value,
+                            $checked,
+                            $actions,
+                            $display);
+            $i++;
+        }
+
+        if (count($values) > 0) {
+            $result .= "    </ul>";
+        }
+
+        return $result;
+    }
+
+    /**
+     *
+     * @access private
+     * @author ?
+     * @deprecated
+     */
+    function _genID($name, $fulltag = true)
+    {
+        return $fulltag ? 'id="' . htmlspecialchars($name) . '"' : $name;
+    }
+
+    /**
+     * Returns script for an rendered variable. TODO: make this unobtrusive.
+     *
+     * @access private
+     * @author ?
+     * @return string html representing an attribute with action script as value,
+     *         or and empty string, if the action is to happen window.onload
+     */
+    function _genActionScript($form, $action, $varname)
+    {
+        $html = '';
+        $triggers = $action->getTrigger();
+        if (!is_array($triggers)) {
+            $triggers = array($triggers);
+        }
+        $js = $action->getActionScript($form, $this, $varname);
+        foreach ($triggers as $trigger) {
+            if ($trigger == 'onload') {
+                $this->_onLoadJS[] = $js;
+            } else {
+                $html .= ' ' . $trigger . '="' . $js . '"';
+            }
+        }
+        return $html;
+    }
+
+    /**
+     * Returns scripts for an rendered variable. TODO: make this unobtrusive.
+     *
+     * @access private
+     * @author ?
+     * @return string html representing attributes with action script as values,
+     *         or and empty string, if the actions are all to happen window.onload
+     */
+    function _getActionScripts($form, $var)
+    {
+        $actions = '';
+        if ($var->hasAction()) {
+            $varname = $var->getVarName();
+            $action = &$var->_action;
+            $triggers = $action->getTrigger();
+            if (!is_array($triggers)) {
+                $triggers = array($triggers);
+            }
+            $js = $action->getActionScript($form, $this, $varname);
+            foreach ($triggers as $trigger) {
+                if ($trigger == 'onload') {
+                    $this->_onLoadJS[] = $js;
+                } else {
+                    $actions .= ' ' . $trigger . '="' . $js . '"';
+                }
+            }
+        }
+        return $actions;
+    }
+
+}
diff --git a/framework/Model/www/js/maxlength.js b/framework/Model/www/js/maxlength.js
new file mode 100644 (file)
index 0000000..200ab8e
--- /dev/null
@@ -0,0 +1,39 @@
+/* http://www.quirksmode.org/dom/maxlength.html */
+
+/*
+<textarea id="text" name="text" maxlength="1500"></textarea>
+*/
+
+
+function setMaxLength()
+{
+       var x = document.getElementsByTagName('textarea');
+       var counter = document.createElement('div');
+       counter.className = 'counter';
+       for (var i=0;i<x.length;i++)
+       {
+               if (x[i].getAttribute('maxlength'))
+               {
+                       var counterClone = counter.cloneNode(true);
+                       counterClone.relatedElement = x[i];
+                       counterClone.innerHTML = '<span>0</span>/'+x[i].getAttribute('maxlength');
+                       x[i].parentNode.insertBefore(counterClone,x[i].nextSibling);
+                       x[i].relatedElement = counterClone.getElementsByTagName('span')[0];
+
+                       x[i].onkeyup = x[i].onchange = checkMaxLength;
+                       x[i].onkeyup();
+               }
+       }
+}
+
+function checkMaxLength()
+{
+       var maxLength = this.getAttribute('maxlength');
+       var currentLength = this.value.length;
+       if (currentLength > maxLength)
+               this.relatedElement.className = 'toomuch';
+       else
+               this.relatedElement.className = '';
+       this.relatedElement.firstChild.nodeValue = currentLength;
+       // not innerHTML
+}
diff --git a/framework/Model/www/test.php b/framework/Model/www/test.php
new file mode 100644 (file)
index 0000000..8267f25
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+/**
+ * Incubator Horde_Form rewrite example page.
+ *
+ * The initial Horde_Form xhtml rewrite was supported by Google SoC
+ * 2005.
+ *
+ * $Horde: incubator/Horde_Form/test.php,v 1.25 2008/09/02 17:43:09 chuck Exp $
+ */
+
+@define('HORDE_BASE', dirname(__FILE__) . '/../..');
+@define('INCUBATOR_BASE', dirname(__FILE__));
+
+require_once HORDE_BASE . '/lib/core.php';
+require_once 'Horde/Variables.php';
+require_once 'Horde/Autoloader.php';
+Horde_Autoloader::addClassPath(dirname(__FILE__));
+$registry = Registry::singleton();
+$vars = Variables::getDefaultVariables();
+
+$vars->set('example_bar', 'text with a beginning and an end');
+$form = new Horde_Form($vars, 'Horde_Form Test');
+
+$choices = array('big' => 'BIG',
+                 'small' => 'small',
+                 'other' => 'Other');
+$form->add('condchoices', 'Enum', _("Select something"), '', true, false, array($choices, true));
+
+$o = $form->add('other_text', 'String', _("If other, please describe"), '', false);
+$params = array('target' => 'condchoices',
+                'enabled' => true,
+                'values' => array('other'));
+$o->setAction(new Horde_Form_Action_ConditionalEnable($params));
+
+$form->add('color', 'Color', _("Color"), null, false);
+
+$vars->set('form', 'add');
+$enum = array('' => _("Select:"),
+              1 => _("Yes"),
+              0 => _("No"));
+$form->add('opciones', 'Enum', _("Simple description"), '', true, false, array($enum));
+$form->add('bool', 'Boolean', _("Boolean"));
+$form->add('number', 'Int', _("Integer"));
+$form->add('mybday', 'date', _("A Date"), '', false);
+$form->addHidden('form', 'String', true);
+$unamevar = $form->add('user_name', 'String', _("Username"));
+$form->add('password', 'password', _("Password"));
+$form->addHidden('example_hidden', 'int', false);
+$form->add('some_text', 'String', _("Insert some text"), _("Insert some text in this box"), false);
+$choices = array('big' => 'BIG',
+                 'small' => 'small',
+                 'mixed' => 'mIxED');
+$form->add('choices', 'enum', _("Select something2"), 'Use the selection box to make your choice', true, false, array($choices, true));
+$form->add('email_address', 'email', _("Email"));
+$form->add('email_address2', 'emailconfirm', _("Email2"));
+$form->add('a_creditcard', 'creditcard', _("Credit Card"));
+$form->add('a_password', 'password', _("Password"));
+$form->add('a_password2', 'passwordconfirm', _("Password with confirmation"), _("type the password twice to confirm"));
+$form->add('a_octal', 'Octal', _("Octal"), false);
+$form->add('a_radiogroup', 'set', _("Radio Group"), '', true, false, array($choices));
+
+$t = $form->add('example_bar', 'String', _("Bar field"), _("You have to fill in some long text here"), true, false, array(4, 40));
+$t->setAction(new Horde_Form_Action_setcursorpos(array(4)));
+
+$form->add('a_checkboxgroup', 'set', _("Checkbox Group"), '', false, false, array($choices));
+//$form->add('a_obrowser', 'obrowser', _("obrowser"));
+
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+<title>Incubator Horde_Form Test</title>
+<link rel="stylesheet" type="text/css" href="themes/form.css" />
+<script type="text/javascript" src="<?=$registry->get('jsuri', 'horde')?>/horde.js"></script>
+<script type="text/javascript" src="<?=$registry->get('jsuri', 'horde')?>/form_helpers.js"></script>
+</head>
+<body>
+<?php
+if ($form->validate()) {
+    $form->getInfo($info);
+    echo 'You have submitted:<br /><pre>';
+    var_dump($info);
+    echo '</pre>';
+}
+
+/* Render the form. */
+$renderer = new Horde_Form_Renderer_Xhtml;
+$renderer->setButtons(_("Add user"), _("Reset"));
+$renderer->renderActive($form, 'test.php', 'post');
+
+?>
+</body>
+</html>
diff --git a/framework/Model/www/themes/form.css b/framework/Model/www/themes/form.css
new file mode 100644 (file)
index 0000000..0c3ae39
--- /dev/null
@@ -0,0 +1,262 @@
+form.horde-form {
+    font-size: 100%;
+    font-weight: normal;
+}
+
+form.horde-form input[type="text"], form.horde-form input[type="password"],
+form.horde-form select, form.horde-form textarea {
+    width: 130px;
+    margin: .2em 0 .1em .1em;
+}
+
+form.horde-form input[type="text"], form.horde-form input[type="password"], form.horde-form textarea {
+    padding: .1em;
+}
+
+.clear {
+    clear: both;
+}
+
+.horde-form fieldset {
+    padding: .5em;
+    margin: 0;
+    border: 1px solid #ccc;
+}
+
+.horde-form fieldset.form-buttons {
+    color: #000;
+    background: #ccc;
+    border: 1px solid #aaa;
+}
+
+fieldset legend {
+    color: #000;
+    background: #ccc;
+    padding: .5em;
+    margin-bottom: -1em;
+    border: 1px solid #999;
+    border-bottom: none;
+    font-weight: bold;
+}
+
+fieldset.form-section {
+    padding: .5em;
+    margin: .5em 0;
+}
+
+.form-button, .form-button-upload {
+    font-size: 90%;
+}
+
+.form-colorpicker {
+    float: left;
+}
+.form-colorpicker img {
+    border: 0;
+    padding: 0;
+    margin: 2px;
+    height: 16px;
+    width: 16px;
+}
+.form-colorpicker input {
+    width: 100px;
+    clear: none;
+}
+.form-colorpicker-palette {
+    display: none;
+    margin: 2px;
+}
+
+.form-description {
+    padding: 8px;
+}
+
+.form-error, .form-error-example {
+    color: #f00;
+}
+
+p.form-error {
+    background-color: #f00;
+    color: #fff;
+    padding: 3px;
+    border: 1px solid #000;
+    margin: auto 70px;
+}
+
+div.form-error {
+    background-color: #ffffe1;
+    background-image: url("graphics/required.png");
+    background-repeat: no-repeat;
+    background-position: top left;
+    color: #000;
+}
+
+.form-hint {
+    display: block;
+    margin: 0 0 5px 142px;
+    padding: 1px 3px;
+    font-size: 88%;
+}
+
+.form-header {
+    vertical-align: bottom;
+    font-weight: bold;
+}
+
+.form-image-preview-blank {
+    width: 50px;
+    height: 40px;
+    vertical-align: top;
+}
+
+.form-inline {
+    display: inline;
+}
+
+.form-input {
+    vertical-align: top;
+    clear: both;
+    padding: 4px;
+    margin: 2px 0;
+}
+
+.form-input label {
+    vertical-align: top;
+    text-align: right;
+    float: left;
+    clear: left;
+    display: block;
+    width: 10em;
+    padding: 0.3em;
+}
+
+.form-input label.form-inline {
+    float: none;
+    width: auto;
+    display: inline;
+}
+
+.form-input ul, .form-input ol {
+    list-style-type: none;
+    display: block;
+    float: left;
+}
+
+.form-input ul, .form-input ol, .form-input li {
+    margin-top: 0;
+    margin-left: 0;
+    padding-top: 0;
+    padding-left: 0;
+}
+.form-input ul {
+    margin-bottom: .5em;
+}
+
+.form-input-address {
+}
+
+.form-input-assign {
+}
+
+.form-input-assign select, .form-input-assign div {
+    display: inline;
+    clear: none;
+}
+
+.form-input-checkbox {
+    border: 0;
+    height: 14px;
+    width: 14px;
+    background: transparent;
+}
+
+.form-input-text, .form-input-intlist, .form-input-octal, .form-input-int,
+.form-input-number, .form-input-phone, .form-input-file {
+    width: 100px;
+}
+
+.form-input-resize {
+    width: 25px;
+}
+
+.form-input-stringlist {
+    width: 150px;
+}
+
+.form-input-time {
+    width: 30px;
+}
+
+.form-note {
+    clear: left;
+    width: 130px;
+    height: auto;
+    padding: .3em;
+    margin: 0 0 0 10.7em;
+    border: 1px solid #666;
+    background-color: #ffc;
+}
+.form-note p {
+    margin: 0;
+    padding: 0;
+    font-style: italic;
+    font-size: 70%;
+}
+
+.form-required {
+    background: url("graphics/required.png") .5em .5em no-repeat;
+}
+
+.form-required label {
+    font-weight: bold;
+}
+
+.form-sectionhidden {
+    position: absolute;
+    left: 0;
+    top: -500px;
+    width: 1px;
+    height: 1px;
+    overflow: hidden;
+    display: block;
+}
+
+.form-sectionshown {
+    display: block;
+}
+
+.form-spacer {
+    padding: .9em;
+}
+
+.rowEven {
+    background-color: #eef;
+}
+.rowOdd {
+    background-color: #fff;
+}
+
+/* Form styles. */
+.htmlarea .statusBar .statusBarTree a {
+    font: inherit;
+}
+.htmlarea table {
+    width: auto;
+}
+input, select {
+}
+input {
+    padding: 1px;
+}
+option {
+    padding: 0 5px 0 3px;
+}
+
+.button {
+    font-size: 90%;
+}
+a.button {
+    padding: 2px;
+    font-weight: normal;
+    text-decoration: none;
+}
diff --git a/framework/Model/www/themes/graphics/required.png b/framework/Model/www/themes/graphics/required.png
new file mode 100644 (file)
index 0000000..1756362
Binary files /dev/null and b/framework/Model/www/themes/graphics/required.png differ