From c53d8d026021f97075fb2f4940ba22793c38fb6e Mon Sep 17 00:00:00 2001
From: davehauenstein <davehauenstein@d4e419ec-0920-11de-bbfd-a7c1bc4c261e>
Date: Wed, 15 Apr 2009 22:06:42 +0000
Subject: added toolbar; functionality includes refresh button to get back to
 original page, print article, email a link to the article with a personal
 note

git-svn-id: http://arc90labs-readability.googlecode.com/svn/trunk@31 d4e419ec-0920-11de-bbfd-a7c1bc4c261e
---
 lib/Zend/Exception.php                         |   30 +
 lib/Zend/Filter.php                            |  115 +++
 lib/Zend/Filter/Alnum.php                      |  115 +++
 lib/Zend/Filter/Alpha.php                      |  115 +++
 lib/Zend/Filter/BaseName.php                   |   50 ++
 lib/Zend/Filter/Digits.php                     |   82 ++
 lib/Zend/Filter/Dir.php                        |   50 ++
 lib/Zend/Filter/Exception.php                  |   37 +
 lib/Zend/Filter/File/LowerCase.php             |   84 ++
 lib/Zend/Filter/File/Rename.php                |  282 +++++++
 lib/Zend/Filter/File/UpperCase.php             |   84 ++
 lib/Zend/Filter/HtmlEntities.php               |  122 +++
 lib/Zend/Filter/Inflector.php                  |  497 +++++++++++
 lib/Zend/Filter/Input.php                      |  926 +++++++++++++++++++++
 lib/Zend/Filter/Int.php                        |   50 ++
 lib/Zend/Filter/Interface.php                  |   40 +
 lib/Zend/Filter/PregReplace.php                |  156 ++++
 lib/Zend/Filter/RealPath.php                   |   50 ++
 lib/Zend/Filter/StringToLower.php              |   76 ++
 lib/Zend/Filter/StringToUpper.php              |   76 ++
 lib/Zend/Filter/StringTrim.php                 |   97 +++
 lib/Zend/Filter/StripNewlines.php              |   48 ++
 lib/Zend/Filter/StripTags.php                  |  294 +++++++
 lib/Zend/Filter/Word/CamelCaseToDash.php       |   44 +
 lib/Zend/Filter/Word/CamelCaseToSeparator.php  |   49 ++
 lib/Zend/Filter/Word/CamelCaseToUnderscore.php |   44 +
 lib/Zend/Filter/Word/DashToCamelCase.php       |   44 +
 lib/Zend/Filter/Word/DashToSeparator.php       |   42 +
 lib/Zend/Filter/Word/DashToUnderscore.php      |   45 +
 lib/Zend/Filter/Word/Separator/Abstract.php    |   76 ++
 lib/Zend/Filter/Word/SeparatorToCamelCase.php  |   52 ++
 lib/Zend/Filter/Word/SeparatorToDash.php       |   46 ++
 lib/Zend/Filter/Word/SeparatorToSeparator.php  |  129 +++
 lib/Zend/Filter/Word/UnderscoreToCamelCase.php |   44 +
 lib/Zend/Filter/Word/UnderscoreToDash.php      |   45 +
 lib/Zend/Filter/Word/UnderscoreToSeparator.php |   45 +
 lib/Zend/Loader.php                            |  263 ++++++
 lib/Zend/Loader/Exception.php                  |   35 +
 lib/Zend/Loader/PluginLoader.php               |  464 +++++++++++
 lib/Zend/Loader/PluginLoader/Exception.php     |   38 +
 lib/Zend/Loader/PluginLoader/Interface.php     |   74 ++
 lib/Zend/Mail.php                              | 1042 +++++++++++++++++++++++
 lib/Zend/Mail/Exception.php                    |   37 +
 lib/Zend/Mail/Message.php                      |  112 +++
 lib/Zend/Mail/Message/File.php                 |   96 +++
 lib/Zend/Mail/Message/Interface.php            |   55 ++
 lib/Zend/Mail/Part.php                         |  489 +++++++++++
 lib/Zend/Mail/Part/File.php                    |  198 +++++
 lib/Zend/Mail/Part/Interface.php               |  136 +++
 lib/Zend/Mail/Protocol/Abstract.php            |  385 +++++++++
 lib/Zend/Mail/Protocol/Exception.php           |   39 +
 lib/Zend/Mail/Protocol/Imap.php                |  837 +++++++++++++++++++
 lib/Zend/Mail/Protocol/Pop3.php                |  471 +++++++++++
 lib/Zend/Mail/Protocol/Smtp.php                |  443 ++++++++++
 lib/Zend/Mail/Protocol/Smtp/Auth/Crammd5.php   |  108 +++
 lib/Zend/Mail/Protocol/Smtp/Auth/Login.php     |   98 +++
 lib/Zend/Mail/Protocol/Smtp/Auth/Plain.php     |   96 +++
 lib/Zend/Mail/Storage.php                      |   39 +
 lib/Zend/Mail/Storage/Abstract.php             |  366 +++++++++
 lib/Zend/Mail/Storage/Exception.php            |   39 +
 lib/Zend/Mail/Storage/Folder.php               |  236 ++++++
 lib/Zend/Mail/Storage/Folder/Interface.php     |   60 ++
 lib/Zend/Mail/Storage/Folder/Maildir.php       |  265 ++++++
 lib/Zend/Mail/Storage/Folder/Mbox.php          |  264 ++++++
 lib/Zend/Mail/Storage/Imap.php                 |  644 +++++++++++++++
 lib/Zend/Mail/Storage/Maildir.php              |  475 +++++++++++
 lib/Zend/Mail/Storage/Mbox.php                 |  447 ++++++++++
 lib/Zend/Mail/Storage/Pop3.php                 |  328 ++++++++
 lib/Zend/Mail/Storage/Writable/Interface.php   |  108 +++
 lib/Zend/Mail/Storage/Writable/Maildir.php     | 1049 ++++++++++++++++++++++++
 lib/Zend/Mail/Transport/Abstract.php           |  350 ++++++++
 lib/Zend/Mail/Transport/Exception.php          |   39 +
 lib/Zend/Mail/Transport/Sendmail.php           |  170 ++++
 lib/Zend/Mail/Transport/Smtp.php               |  241 ++++++
 lib/Zend/Mime.php                              |  365 +++++++++
 lib/Zend/Mime/Decode.php                       |  243 ++++++
 lib/Zend/Mime/Exception.php                    |   36 +
 lib/Zend/Mime/Message.php                      |  285 +++++++
 lib/Zend/Mime/Part.php                         |  216 +++++
 lib/Zend/Registry.php                          |  207 +++++
 lib/Zend/Validate.php                          |  171 ++++
 lib/Zend/Validate/Abstract.php                 |  358 ++++++++
 lib/Zend/Validate/Alnum.php                    |  120 +++
 lib/Zend/Validate/Alpha.php                    |  120 +++
 lib/Zend/Validate/Barcode.php                  |   99 +++
 lib/Zend/Validate/Barcode/Ean13.php            |  112 +++
 lib/Zend/Validate/Barcode/UpcA.php             |  100 +++
 lib/Zend/Validate/Between.php                  |  200 +++++
 lib/Zend/Validate/Ccnum.php                    |  111 +++
 lib/Zend/Validate/Date.php                     |  235 ++++++
 lib/Zend/Validate/Digits.php                   |  100 +++
 lib/Zend/Validate/EmailAddress.php             |  247 ++++++
 lib/Zend/Validate/Exception.php                |   37 +
 lib/Zend/Validate/File/Count.php               |  275 +++++++
 lib/Zend/Validate/File/Crc32.php               |  179 ++++
 lib/Zend/Validate/File/ExcludeExtension.php    |   94 +++
 lib/Zend/Validate/File/ExcludeMimeType.php     |   91 ++
 lib/Zend/Validate/File/Exists.php              |  203 +++++
 lib/Zend/Validate/File/Extension.php           |  234 ++++++
 lib/Zend/Validate/File/FilesSize.php           |  163 ++++
 lib/Zend/Validate/File/Hash.php                |  195 +++++
 lib/Zend/Validate/File/ImageSize.php           |  370 +++++++++
 lib/Zend/Validate/File/IsCompressed.php        |  133 +++
 lib/Zend/Validate/File/IsImage.php             |  137 ++++
 lib/Zend/Validate/File/Md5.php                 |  183 +++++
 lib/Zend/Validate/File/MimeType.php            |  283 +++++++
 lib/Zend/Validate/File/NotExists.php           |   84 ++
 lib/Zend/Validate/File/Sha1.php                |  181 ++++
 lib/Zend/Validate/File/Size.php                |  404 +++++++++
 lib/Zend/Validate/File/Upload.php              |  234 ++++++
 lib/Zend/Validate/Float.php                    |   75 ++
 lib/Zend/Validate/GreaterThan.php              |  114 +++
 lib/Zend/Validate/Hex.php                      |   74 ++
 lib/Zend/Validate/Hostname.php                 |  444 ++++++++++
 lib/Zend/Validate/Hostname/At.php              |   50 ++
 lib/Zend/Validate/Hostname/Ch.php              |   50 ++
 lib/Zend/Validate/Hostname/De.php              |   58 ++
 lib/Zend/Validate/Hostname/Fi.php              |   50 ++
 lib/Zend/Validate/Hostname/Hu.php              |   50 ++
 lib/Zend/Validate/Hostname/Interface.php       |   52 ++
 lib/Zend/Validate/Hostname/Li.php              |   50 ++
 lib/Zend/Validate/Hostname/No.php              |   52 ++
 lib/Zend/Validate/Hostname/Se.php              |   50 ++
 lib/Zend/Validate/Identical.php                |  117 +++
 lib/Zend/Validate/InArray.php                  |  138 ++++
 lib/Zend/Validate/Int.php                      |   73 ++
 lib/Zend/Validate/Interface.php                |   71 ++
 lib/Zend/Validate/Ip.php                       |   71 ++
 lib/Zend/Validate/LessThan.php                 |  113 +++
 lib/Zend/Validate/NotEmpty.php                 |   70 ++
 lib/Zend/Validate/Regex.php                    |  125 +++
 lib/Zend/Validate/StringLength.php             |  223 +++++
 132 files changed, 23792 insertions(+)
 create mode 100644 lib/Zend/Exception.php
 create mode 100644 lib/Zend/Filter.php
 create mode 100644 lib/Zend/Filter/Alnum.php
 create mode 100644 lib/Zend/Filter/Alpha.php
 create mode 100644 lib/Zend/Filter/BaseName.php
 create mode 100644 lib/Zend/Filter/Digits.php
 create mode 100644 lib/Zend/Filter/Dir.php
 create mode 100644 lib/Zend/Filter/Exception.php
 create mode 100644 lib/Zend/Filter/File/LowerCase.php
 create mode 100644 lib/Zend/Filter/File/Rename.php
 create mode 100644 lib/Zend/Filter/File/UpperCase.php
 create mode 100644 lib/Zend/Filter/HtmlEntities.php
 create mode 100644 lib/Zend/Filter/Inflector.php
 create mode 100644 lib/Zend/Filter/Input.php
 create mode 100644 lib/Zend/Filter/Int.php
 create mode 100644 lib/Zend/Filter/Interface.php
 create mode 100644 lib/Zend/Filter/PregReplace.php
 create mode 100644 lib/Zend/Filter/RealPath.php
 create mode 100644 lib/Zend/Filter/StringToLower.php
 create mode 100644 lib/Zend/Filter/StringToUpper.php
 create mode 100644 lib/Zend/Filter/StringTrim.php
 create mode 100644 lib/Zend/Filter/StripNewlines.php
 create mode 100644 lib/Zend/Filter/StripTags.php
 create mode 100644 lib/Zend/Filter/Word/CamelCaseToDash.php
 create mode 100644 lib/Zend/Filter/Word/CamelCaseToSeparator.php
 create mode 100644 lib/Zend/Filter/Word/CamelCaseToUnderscore.php
 create mode 100644 lib/Zend/Filter/Word/DashToCamelCase.php
 create mode 100644 lib/Zend/Filter/Word/DashToSeparator.php
 create mode 100644 lib/Zend/Filter/Word/DashToUnderscore.php
 create mode 100644 lib/Zend/Filter/Word/Separator/Abstract.php
 create mode 100644 lib/Zend/Filter/Word/SeparatorToCamelCase.php
 create mode 100644 lib/Zend/Filter/Word/SeparatorToDash.php
 create mode 100644 lib/Zend/Filter/Word/SeparatorToSeparator.php
 create mode 100644 lib/Zend/Filter/Word/UnderscoreToCamelCase.php
 create mode 100644 lib/Zend/Filter/Word/UnderscoreToDash.php
 create mode 100644 lib/Zend/Filter/Word/UnderscoreToSeparator.php
 create mode 100644 lib/Zend/Loader.php
 create mode 100644 lib/Zend/Loader/Exception.php
 create mode 100644 lib/Zend/Loader/PluginLoader.php
 create mode 100644 lib/Zend/Loader/PluginLoader/Exception.php
 create mode 100644 lib/Zend/Loader/PluginLoader/Interface.php
 create mode 100644 lib/Zend/Mail.php
 create mode 100644 lib/Zend/Mail/Exception.php
 create mode 100644 lib/Zend/Mail/Message.php
 create mode 100644 lib/Zend/Mail/Message/File.php
 create mode 100644 lib/Zend/Mail/Message/Interface.php
 create mode 100644 lib/Zend/Mail/Part.php
 create mode 100644 lib/Zend/Mail/Part/File.php
 create mode 100644 lib/Zend/Mail/Part/Interface.php
 create mode 100644 lib/Zend/Mail/Protocol/Abstract.php
 create mode 100644 lib/Zend/Mail/Protocol/Exception.php
 create mode 100644 lib/Zend/Mail/Protocol/Imap.php
 create mode 100644 lib/Zend/Mail/Protocol/Pop3.php
 create mode 100644 lib/Zend/Mail/Protocol/Smtp.php
 create mode 100644 lib/Zend/Mail/Protocol/Smtp/Auth/Crammd5.php
 create mode 100644 lib/Zend/Mail/Protocol/Smtp/Auth/Login.php
 create mode 100644 lib/Zend/Mail/Protocol/Smtp/Auth/Plain.php
 create mode 100644 lib/Zend/Mail/Storage.php
 create mode 100644 lib/Zend/Mail/Storage/Abstract.php
 create mode 100644 lib/Zend/Mail/Storage/Exception.php
 create mode 100644 lib/Zend/Mail/Storage/Folder.php
 create mode 100644 lib/Zend/Mail/Storage/Folder/Interface.php
 create mode 100644 lib/Zend/Mail/Storage/Folder/Maildir.php
 create mode 100644 lib/Zend/Mail/Storage/Folder/Mbox.php
 create mode 100644 lib/Zend/Mail/Storage/Imap.php
 create mode 100644 lib/Zend/Mail/Storage/Maildir.php
 create mode 100644 lib/Zend/Mail/Storage/Mbox.php
 create mode 100644 lib/Zend/Mail/Storage/Pop3.php
 create mode 100644 lib/Zend/Mail/Storage/Writable/Interface.php
 create mode 100644 lib/Zend/Mail/Storage/Writable/Maildir.php
 create mode 100644 lib/Zend/Mail/Transport/Abstract.php
 create mode 100644 lib/Zend/Mail/Transport/Exception.php
 create mode 100644 lib/Zend/Mail/Transport/Sendmail.php
 create mode 100644 lib/Zend/Mail/Transport/Smtp.php
 create mode 100644 lib/Zend/Mime.php
 create mode 100644 lib/Zend/Mime/Decode.php
 create mode 100644 lib/Zend/Mime/Exception.php
 create mode 100644 lib/Zend/Mime/Message.php
 create mode 100644 lib/Zend/Mime/Part.php
 create mode 100644 lib/Zend/Registry.php
 create mode 100644 lib/Zend/Validate.php
 create mode 100644 lib/Zend/Validate/Abstract.php
 create mode 100644 lib/Zend/Validate/Alnum.php
 create mode 100644 lib/Zend/Validate/Alpha.php
 create mode 100644 lib/Zend/Validate/Barcode.php
 create mode 100644 lib/Zend/Validate/Barcode/Ean13.php
 create mode 100644 lib/Zend/Validate/Barcode/UpcA.php
 create mode 100644 lib/Zend/Validate/Between.php
 create mode 100644 lib/Zend/Validate/Ccnum.php
 create mode 100644 lib/Zend/Validate/Date.php
 create mode 100644 lib/Zend/Validate/Digits.php
 create mode 100644 lib/Zend/Validate/EmailAddress.php
 create mode 100644 lib/Zend/Validate/Exception.php
 create mode 100644 lib/Zend/Validate/File/Count.php
 create mode 100644 lib/Zend/Validate/File/Crc32.php
 create mode 100644 lib/Zend/Validate/File/ExcludeExtension.php
 create mode 100644 lib/Zend/Validate/File/ExcludeMimeType.php
 create mode 100644 lib/Zend/Validate/File/Exists.php
 create mode 100644 lib/Zend/Validate/File/Extension.php
 create mode 100644 lib/Zend/Validate/File/FilesSize.php
 create mode 100644 lib/Zend/Validate/File/Hash.php
 create mode 100644 lib/Zend/Validate/File/ImageSize.php
 create mode 100644 lib/Zend/Validate/File/IsCompressed.php
 create mode 100644 lib/Zend/Validate/File/IsImage.php
 create mode 100644 lib/Zend/Validate/File/Md5.php
 create mode 100644 lib/Zend/Validate/File/MimeType.php
 create mode 100644 lib/Zend/Validate/File/NotExists.php
 create mode 100644 lib/Zend/Validate/File/Sha1.php
 create mode 100644 lib/Zend/Validate/File/Size.php
 create mode 100644 lib/Zend/Validate/File/Upload.php
 create mode 100644 lib/Zend/Validate/Float.php
 create mode 100644 lib/Zend/Validate/GreaterThan.php
 create mode 100644 lib/Zend/Validate/Hex.php
 create mode 100644 lib/Zend/Validate/Hostname.php
 create mode 100644 lib/Zend/Validate/Hostname/At.php
 create mode 100644 lib/Zend/Validate/Hostname/Ch.php
 create mode 100644 lib/Zend/Validate/Hostname/De.php
 create mode 100644 lib/Zend/Validate/Hostname/Fi.php
 create mode 100644 lib/Zend/Validate/Hostname/Hu.php
 create mode 100644 lib/Zend/Validate/Hostname/Interface.php
 create mode 100644 lib/Zend/Validate/Hostname/Li.php
 create mode 100644 lib/Zend/Validate/Hostname/No.php
 create mode 100644 lib/Zend/Validate/Hostname/Se.php
 create mode 100644 lib/Zend/Validate/Identical.php
 create mode 100644 lib/Zend/Validate/InArray.php
 create mode 100644 lib/Zend/Validate/Int.php
 create mode 100644 lib/Zend/Validate/Interface.php
 create mode 100644 lib/Zend/Validate/Ip.php
 create mode 100644 lib/Zend/Validate/LessThan.php
 create mode 100644 lib/Zend/Validate/NotEmpty.php
 create mode 100644 lib/Zend/Validate/Regex.php
 create mode 100644 lib/Zend/Validate/StringLength.php

(limited to 'lib/Zend')

diff --git a/lib/Zend/Exception.php b/lib/Zend/Exception.php
new file mode 100644
index 0000000..599d8a0
--- /dev/null
+++ b/lib/Zend/Exception.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Exception extends Exception
+{}
+
diff --git a/lib/Zend/Filter.php b/lib/Zend/Filter.php
new file mode 100644
index 0000000..23bec21
--- /dev/null
+++ b/lib/Zend/Filter.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Filter.php 8434 2008-02-27 19:15:13Z darby $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter implements Zend_Filter_Interface
+{
+    /**
+     * Filter chain
+     *
+     * @var array
+     */
+    protected $_filters = array();
+
+    /**
+     * Adds a filter to the end of the chain
+     *
+     * @param  Zend_Filter_Interface $filter
+     * @return Zend_Filter Provides a fluent interface
+     */
+    public function addFilter(Zend_Filter_Interface $filter)
+    {
+        $this->_filters[] = $filter;
+        return $this;
+    }
+
+    /**
+     * Returns $value filtered through each filter in the chain
+     *
+     * Filters are run in the order in which they were added to the chain (FIFO)
+     *
+     * @param  mixed $value
+     * @return mixed
+     */
+    public function filter($value)
+    {
+        $valueFiltered = $value;
+        foreach ($this->_filters as $filter) {
+            $valueFiltered = $filter->filter($valueFiltered);
+        }
+        return $valueFiltered;
+    }
+
+    /**
+     * Returns a value filtered through a specified filter class, without requiring separate
+     * instantiation of the filter object.
+     *
+     * The first argument of this method is a data input value, that you would have filtered.
+     * The second argument is a string, which corresponds to the basename of the filter class,
+     * relative to the Zend_Filter namespace. This method automatically loads the class,
+     * creates an instance, and applies the filter() method to the data input. You can also pass
+     * an array of constructor arguments, if they are needed for the filter class.
+     *
+     * @param  mixed        $value
+     * @param  string       $classBaseName
+     * @param  array        $args          OPTIONAL
+     * @param  array|string $namespaces    OPTIONAL
+     * @return mixed
+     * @throws Zend_Filter_Exception
+     */
+    public static function get($value, $classBaseName, array $args = array(), $namespaces = array())
+    {
+        require_once 'Zend/Loader.php';
+        $namespaces = array_merge(array('Zend_Filter'), (array) $namespaces);
+        foreach ($namespaces as $namespace) {
+            $className = $namespace . '_' . ucfirst($classBaseName);
+            try {
+                @Zend_Loader::loadClass($className);
+            } catch (Zend_Exception $ze) {
+                continue;
+            }
+            $class = new ReflectionClass($className);
+            if ($class->implementsInterface('Zend_Filter_Interface')) {
+                if ($class->hasMethod('__construct')) {
+                    $object = $class->newInstanceArgs($args);
+                } else {
+                    $object = $class->newInstance();
+                }
+                return $object->filter($value);
+            }
+        }
+        require_once 'Zend/Filter/Exception.php';
+        throw new Zend_Filter_Exception("Filter class not found from basename '$classBaseName'");
+    }
+}
diff --git a/lib/Zend/Filter/Alnum.php b/lib/Zend/Filter/Alnum.php
new file mode 100644
index 0000000..a50cddd
--- /dev/null
+++ b/lib/Zend/Filter/Alnum.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Alnum.php 12751 2008-11-21 18:30:48Z yoshida@zend.co.jp $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+/**
+ * @see Zend_Locale
+ */
+require_once 'Zend/Locale.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Alnum implements Zend_Filter_Interface
+{
+    /**
+     * Whether to allow white space characters; off by default
+     *
+     * @var boolean
+     */
+    public $allowWhiteSpace;
+
+    /**
+     * Is PCRE is compiled with UTF-8 and Unicode support
+     *
+     * @var mixed
+     **/
+    protected static $_unicodeEnabled;
+
+    /**
+     * Locale in browser.
+     *
+     * @var Zend_Locale object
+     */
+    protected $_locale;
+
+    /**
+     * The Alphabet means english alphabet.
+     *
+     * @var boolean
+     */
+    protected static $_meansEnglishAlphabet;
+
+    /**
+     * Sets default option values for this instance
+     *
+     * @param  boolean $allowWhiteSpace
+     * @return void
+     */
+    public function __construct($allowWhiteSpace = false)
+    {
+        $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+        if (null === self::$_unicodeEnabled) {
+            self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false;
+        }
+
+        if (null === self::$_meansEnglishAlphabet) {
+            $this->_locale = new Zend_Locale('auto');
+            self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(),
+                                                    array('ja', 'ko', 'zh')
+                                                    );
+        }
+
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value, removing all but alphabetic and digit characters
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        $whiteSpace = $this->allowWhiteSpace ? '\s' : '';
+        if (!self::$_unicodeEnabled) {
+            // POSIX named classes are not supported, use alternative a-zA-Z0-9 match
+            $pattern = '/[^a-zA-Z0-9' . $whiteSpace . ']/';
+        } else if (self::$_meansEnglishAlphabet) {
+            //The Alphabet means english alphabet.
+            $pattern = '/[^a-zA-Z0-9'  . $whiteSpace . ']/u';
+        } else {
+            //The Alphabet means each language's alphabet.
+            $pattern = '/[^\p{L}\p{N}' . $whiteSpace . ']/u';
+        }
+
+        return preg_replace($pattern, '', (string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/Alpha.php b/lib/Zend/Filter/Alpha.php
new file mode 100644
index 0000000..adfaafe
--- /dev/null
+++ b/lib/Zend/Filter/Alpha.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Alpha.php 12751 2008-11-21 18:30:48Z yoshida@zend.co.jp $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+/**
+ * @see Zend_Locale
+ */
+require_once 'Zend/Locale.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Alpha implements Zend_Filter_Interface
+{
+    /**
+     * Whether to allow white space characters; off by default
+     *
+     * @var boolean
+     */
+    public $allowWhiteSpace;
+
+    /**
+     * Is PCRE is compiled with UTF-8 and Unicode support
+     *
+     * @var mixed
+     **/
+    protected static $_unicodeEnabled;
+
+    /**
+     * Locale in browser.
+     *
+     * @var Zend_Locale object
+     */
+    protected $_locale;
+
+    /**
+     * The Alphabet means english alphabet.
+     *
+     * @var boolean
+     */
+    protected static $_meansEnglishAlphabet;
+
+    /**
+     * Sets default option values for this instance
+     *
+     * @param  boolean $allowWhiteSpace
+     * @return void
+     */
+    public function __construct($allowWhiteSpace = false)
+    {
+        $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+        if (null === self::$_unicodeEnabled) {
+            self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false;
+        }
+
+        if (null === self::$_meansEnglishAlphabet) {
+            $this->_locale = new Zend_Locale('auto');
+            self::$_meansEnglishAlphabet = in_array($this->_locale->getLanguage(),
+                                                    array('ja', 'ko', 'zh')
+                                                    );
+        }
+
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value, removing all but alphabetic characters
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        $whiteSpace = $this->allowWhiteSpace ? '\s' : '';
+        if (!self::$_unicodeEnabled) {
+            // POSIX named classes are not supported, use alternative a-zA-Z match
+            $pattern = '/[^a-zA-Z' . $whiteSpace . ']/';
+        } else if (self::$_meansEnglishAlphabet) {
+            //The Alphabet means english alphabet.
+            $pattern = '/[^a-zA-Z'  . $whiteSpace . ']/u';
+        } else {
+            //The Alphabet means each language's alphabet.
+            $pattern = '/[^\p{L}' . $whiteSpace . ']/u';
+        }
+
+        return preg_replace($pattern, '', (string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/BaseName.php b/lib/Zend/Filter/BaseName.php
new file mode 100644
index 0000000..a0652ab
--- /dev/null
+++ b/lib/Zend/Filter/BaseName.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: BaseName.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_BaseName implements Zend_Filter_Interface
+{
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns basename($value)
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        return basename((string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/Digits.php b/lib/Zend/Filter/Digits.php
new file mode 100644
index 0000000..e062e1a
--- /dev/null
+++ b/lib/Zend/Filter/Digits.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Digits.php 8731 2008-03-10 15:08:03Z darby $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Digits implements Zend_Filter_Interface
+{
+    /**
+     * Is PCRE is compiled with UTF-8 and Unicode support
+     *
+     * @var mixed
+     **/
+    protected static $_unicodeEnabled;
+
+    /**
+     * Class constructor
+     *
+     * Checks if PCRE is compiled with UTF-8 and Unicode support
+     *
+     * @return void
+     */
+    public function __construct()
+    {
+        if (null === self::$_unicodeEnabled) {
+            self::$_unicodeEnabled = (@preg_match('/\pL/u', 'a')) ? true : false;
+        }
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value, removing all but digit characters
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        if (!self::$_unicodeEnabled) {
+            // POSIX named classes are not supported, use alternative 0-9 match
+            $pattern = '/[^0-9]/';
+        } else if (extension_loaded('mbstring')) {
+            // Filter for the value with mbstring
+            $pattern = '/[^[:digit:]]/';
+        } else {
+            // Filter for the value without mbstring
+            $pattern = '/[\p{^N}]/';
+        }
+
+        return preg_replace($pattern, '', (string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/Dir.php b/lib/Zend/Filter/Dir.php
new file mode 100644
index 0000000..a08534e
--- /dev/null
+++ b/lib/Zend/Filter/Dir.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Dir.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Dir implements Zend_Filter_Interface
+{
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns dirname($value)
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        return dirname((string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/Exception.php b/lib/Zend/Filter/Exception.php
new file mode 100644
index 0000000..3142c81
--- /dev/null
+++ b/lib/Zend/Filter/Exception.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Exception
+ */
+require_once 'Zend/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Exception extends Zend_Exception
+{}
diff --git a/lib/Zend/Filter/File/LowerCase.php b/lib/Zend/Filter/File/LowerCase.php
new file mode 100644
index 0000000..98abab2
--- /dev/null
+++ b/lib/Zend/Filter/File/LowerCase.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: $
+ */
+
+/**
+ * @see Zend_Filter_StringToLower
+ */
+require_once 'Zend/Filter/StringToLower.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_File_LowerCase extends Zend_Filter_StringToLower
+{
+    /**
+     * Adds options to the filter at initiation
+     *
+     * @param string $options
+     */
+    public function __construct($options = null)
+    {
+        if (!empty($options)) {
+            $this->setEncoding($options);
+        }
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Does a lowercase on the content of the given file
+     *
+     * @param  string $value Full path of file to change
+     * @return string The given $value
+     * @throws Zend_Filter_Exception
+     */
+    public function filter($value)
+    {
+        if (!file_exists($value)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("File '$value' not found");
+        }
+
+        if (!is_writable($value)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("File '$value' is not writable");
+        }
+
+        $content = file_get_contents($value);
+        if (!$content) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("Problem while reading file '$value'");
+        }
+
+        $content = parent::filter($content);
+        $result  = file_put_contents($value, $content);
+
+        if (!$result) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("Problem while writing file '$value'");
+        }
+
+        return $value;
+    }
+}
diff --git a/lib/Zend/Filter/File/Rename.php b/lib/Zend/Filter/File/Rename.php
new file mode 100644
index 0000000..718443f
--- /dev/null
+++ b/lib/Zend/Filter/File/Rename.php
@@ -0,0 +1,282 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: $
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_File_Rename implements Zend_Filter_Interface
+{
+    /**
+     * Internal array of array(source, target, overwrite)
+     */
+    protected $_files = array();
+
+    /**
+     * Class constructor
+     *
+     * Options argument may be either a string, a Zend_Config object, or an array.
+     * If an array or Zend_Config object, it accepts the following keys:
+     * 'source'    => Source filename or directory which will be renamed
+     * 'target'    => Target filename or directory, the new name of the sourcefile
+     * 'overwrite' => Shall existing files be overwritten ?
+     *
+     * @param  string|array $options Target file or directory to be renamed
+     * @param  string $target Source filename or directory (deprecated)
+     * @param  bool $overwrite Should existing files be overwritten (deprecated)
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (is_string($options)) {
+            $options = array('target' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('Invalid options argument provided to filter');
+        }
+
+        if (1 < func_num_args()) {
+            trigger_error('Support for multiple arguments is deprecated in favor of a single options array', E_USER_NOTICE);
+            $argv = func_get_args();
+            array_shift($argv);
+            $source    = array_shift($argv);
+            $overwrite = false;
+            if (!empty($argv)) {
+                $overwrite = array_shift($argv);
+            }
+            $options['source']    = $source;
+            $options['overwrite'] = $overwrite;
+        }
+
+        $this->setFile($options);
+    }
+
+    /**
+     * Returns the files to rename and their new name and location
+     *
+     * @return array
+     */
+    public function getFile()
+    {
+        return $this->_files;
+    }
+
+    /**
+     * Sets a new file or directory as target, deleting existing ones
+     *
+     * Array accepts the following keys:
+     * 'source'    => Source filename or directory which will be renamed
+     * 'target'    => Target filename or directory, the new name of the sourcefile
+     * 'overwrite' => Shall existing files be overwritten ?
+     *
+     * @param  string|array $options Old file or directory to be rewritten
+     * @return Zend_Filter_File_Rename
+     */
+    public function setFile($options)
+    {
+        $this->_files = array();
+        $this->addFile($options);
+
+        return $this;
+    }
+
+    /**
+     * Adds a new file or directory as target to the existing ones
+     *
+     * Array accepts the following keys:
+     * 'source'    => Source filename or directory which will be renamed
+     * 'target'    => Target filename or directory, the new name of the sourcefile
+     * 'overwrite' => Shall existing files be overwritten ?
+     *
+     * @param  string|array $options Old file or directory to be rewritten
+     * @return Zend_Filter_File_Rename
+     */
+    public function addFile($options)
+    {
+        if (is_string($options)) {
+            $options = array('target' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception ('Invalid options to rename filter provided');
+        }
+
+        $this->_convertOptions($options);
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Renames the file $value to the new name set before
+     * Returns the file $value, removing all but digit characters
+     *
+     * @param  string $value Full path of file to change
+     * @return string The new filename which has been set, or false when there were errors
+     */
+    public function filter($value)
+    {
+        $file = $this->_getFileName($value);
+        if ($file['source'] == $file['target']) {
+            return $value;
+        }
+
+        if (!file_exists($file['source'])) {
+            return $value;
+        }
+
+        if (($file['overwrite'] == true) and (file_exists($file['target']))) {
+            unlink($file['target']);
+        }
+
+        if (file_exists($file['target'])) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. It already exists.", $value));
+        }
+
+        $result = rename($file['source'], $file['target']);
+
+        if ($result === true) {
+            return $file['target'];
+        }
+
+        require_once 'Zend/Filter/Exception.php';
+        throw new Zend_Filter_Exception(sprintf("File '%s' could not be renamed. An error occured while processing the file.", $value));
+    }
+
+    /**
+     * Internal method for creating the file array
+     * Supports single and nested arrays
+     *
+     * @param  array $options
+     * @return array
+     */
+    protected function _convertOptions($options) {
+        $files = array();
+        foreach ($options as $key => $value) {
+            if (is_array($value)) {
+                $this->_convertOptions($value);
+                continue;
+            }
+
+            switch ($key) {
+                case "source":
+                    $files['source'] = (string) $value;
+                    break;
+
+                case 'target' :
+                    $files['target'] = (string) $value;
+                    break;
+
+                case 'overwrite' :
+                    $files['overwrite'] = (boolean) $value;
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        if (empty($files)) {
+            return $this;
+        }
+
+        if (empty($files['source'])) {
+            $files['source'] = '*';
+        }
+
+        if (empty($files['target'])) {
+            $files['target'] = '*';
+        }
+
+        if (empty($files['overwrite'])) {
+            $files['overwrite'] = false;
+        }
+
+        $found = false;
+        foreach ($this->_files as $key => $value) {
+            if ($value['source'] == $files['source']) {
+                $this->_files[$key] = $files;
+                $found              = true;
+            }
+        }
+
+        if (!$found) {
+            $count                = count($this->_files);
+            $this->_files[$count] = $files;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Internal method to resolve the requested source
+     * and return all other related parameters
+     *
+     * @param  string $file Filename to get the informations for
+     * @return array
+     */
+    protected function _getFileName($file)
+    {
+        $rename = array();
+        foreach ($this->_files as $value) {
+            if ($value['source'] == '*') {
+                if (!isset($rename['source'])) {
+                    $rename           = $value;
+                    $rename['source'] = $file;
+                }
+            }
+
+            if ($value['source'] == $file) {
+                $rename = $value;
+            }
+        }
+
+        if (!isset($rename['source'])) {
+            return $file;
+        }
+
+        if (!isset($rename['target']) or ($rename['target'] == '*')) {
+            $rename['target'] = $rename['source'];
+        }
+
+        if (is_dir($rename['target'])) {
+            $name = basename($rename['source']);
+            $last = $rename['target'][strlen($rename['target']) - 1];
+            if (($last != '/') and ($last != '\\')) {
+                $rename['target'] .= DIRECTORY_SEPARATOR;
+            }
+
+            $rename['target'] .= $name;
+        }
+
+        return $rename;
+    }
+}
diff --git a/lib/Zend/Filter/File/UpperCase.php b/lib/Zend/Filter/File/UpperCase.php
new file mode 100644
index 0000000..9501e9e
--- /dev/null
+++ b/lib/Zend/Filter/File/UpperCase.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: $
+ */
+
+/**
+ * @see Zend_Filter_StringToUpper
+ */
+require_once 'Zend/Filter/StringToUpper.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_File_UpperCase extends Zend_Filter_StringToUpper
+{
+    /**
+     * Adds options to the filter at initiation
+     *
+     * @param string $options
+     */
+    public function __construct($options = null)
+    {
+        if (!empty($options)) {
+            $this->setEncoding($options);
+        }
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Does a lowercase on the content of the given file
+     *
+     * @param  string $value Full path of file to change
+     * @return string The given $value
+     * @throws Zend_Filter_Exception
+     */
+    public function filter($value)
+    {
+        if (!file_exists($value)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("File '$value' not found");
+        }
+
+        if (!is_writable($value)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("File '$value' is not writable");
+        }
+
+        $content = file_get_contents($value);
+        if (!$content) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("Problem while reading file '$value'");
+        }
+
+        $content = parent::filter($content);
+        $result  = file_put_contents($value, $content);
+
+        if (!$result) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("Problem while writing file '$value'");
+        }
+
+        return $value;
+    }
+}
diff --git a/lib/Zend/Filter/HtmlEntities.php b/lib/Zend/Filter/HtmlEntities.php
new file mode 100644
index 0000000..e9887a2
--- /dev/null
+++ b/lib/Zend/Filter/HtmlEntities.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: HtmlEntities.php 11783 2008-10-09 17:38:54Z andries $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_HtmlEntities implements Zend_Filter_Interface
+{
+    /**
+     * Corresponds to second htmlentities() argument
+     *
+     * @var integer
+     */
+    protected $_quoteStyle;
+
+    /**
+     * Corresponds to third htmlentities() argument
+     *
+     * @var string
+     */
+    protected $_charSet;
+
+    /**
+     * Sets filter options
+     *
+     * @param  integer $quoteStyle
+     * @param  string  $charSet
+     * @return void
+     */
+    public function __construct($quoteStyle = ENT_COMPAT, $charSet = 'ISO-8859-1')
+    {
+        $this->_quoteStyle = $quoteStyle;
+        $this->_charSet    = $charSet;
+    }
+
+    /**
+     * Returns the quoteStyle option
+     *
+     * @return integer
+     */
+    public function getQuoteStyle()
+    {
+        return $this->_quoteStyle;
+    }
+
+    /**
+     * Sets the quoteStyle option
+     *
+     * @param  integer $quoteStyle
+     * @return Zend_Filter_HtmlEntities Provides a fluent interface
+     */
+    public function setQuoteStyle($quoteStyle)
+    {
+        $this->_quoteStyle = $quoteStyle;
+        return $this;
+    }
+
+    /**
+     * Returns the charSet option
+     *
+     * @return string
+     */
+    public function getCharSet()
+    {
+        return $this->_charSet;
+    }
+
+    /**
+     * Sets the charSet option
+     *
+     * @param  string $charSet
+     * @return Zend_Filter_HtmlEntities Provides a fluent interface
+     */
+    public function setCharSet($charSet)
+    {
+        $this->_charSet = $charSet;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value, converting characters to their corresponding HTML entity
+     * equivalents where they exist
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        return htmlentities((string) $value, $this->_quoteStyle, $this->_charSet);
+    }
+}
diff --git a/lib/Zend/Filter/Inflector.php b/lib/Zend/Filter/Inflector.php
new file mode 100644
index 0000000..4e7e493
--- /dev/null
+++ b/lib/Zend/Filter/Inflector.php
@@ -0,0 +1,497 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Inflector.php 12501 2008-11-10 16:28:31Z matthew $
+ */
+
+/**
+ * @see Zend_Filter
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter.php';
+
+/**
+ * @see Zend_Loader_PluginLoader
+ */
+require_once 'Zend/Loader/PluginLoader.php';
+
+/**
+ * Filter chain for string inflection
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Inflector implements Zend_Filter_Interface 
+{
+    /**
+     * @var Zend_Loader_PluginLoader_Interface
+     */
+    protected $_pluginLoader = null;
+    
+    /**
+     * @var string
+     */
+    protected $_target = null;
+        
+    /**
+     * @var bool
+     */
+    protected $_throwTargetExceptionsOn = true;
+    
+    /**
+     * @var string
+     */
+    protected $_targetReplacementIdentifier = ':';
+
+    /**
+     * @var array
+     */
+    protected $_rules = array();
+
+    /**
+     * Constructor
+     *
+     * @param string $target
+     * @param array $rules
+     */
+    public function __construct($target = null, Array $rules = array(), $throwTargetExceptionsOn = null, $targetReplacementIdentifer = null)
+    {
+        if ($target instanceof Zend_Config) {
+            $this->setConfig($target);
+        } else {
+            if ((null !== $target) && is_string($target)) {
+                $this->setTarget($target);
+            }
+
+            if (null !== $rules) {
+                $this->addRules($rules);
+            }
+            
+            if ($throwTargetExceptionsOn !== null) {
+                $this->setThrowTargetExceptionsOn($throwTargetExceptionsOn);
+            }
+            
+            if ($targetReplacementIdentifer != '') {
+                $this->setTargetReplacementIdentifier($targetReplacementIdentifer);
+            }
+        }
+    }
+    
+    /**
+     * Retreive PluginLoader
+     *
+     * @return Zend_Loader_PluginLoader_Interface
+     */
+    public function getPluginLoader()
+    {
+        if (!$this->_pluginLoader instanceof Zend_Loader_PluginLoader_Interface) {
+            $this->_pluginLoader = new Zend_Loader_PluginLoader(array('Zend_Filter_' => 'Zend/Filter/'), __CLASS__);
+        }
+        
+        return $this->_pluginLoader;
+    }
+    
+    /**
+     * Set PluginLoader
+     *
+     * @param Zend_Loader_PluginLoader_Interface $pluginLoader
+     * @return Zend_Filter_Inflector
+     */
+    public function setPluginLoader(Zend_Loader_PluginLoader_Interface $pluginLoader)
+    {
+        $this->_pluginLoader = $pluginLoader;
+        return $this;
+    }
+
+    /**
+     * Use Zend_Config object to set object state
+     * 
+     * @param  Zend_Config $config 
+     * @return Zend_Filter_Inflector
+     */
+    public function setConfig(Zend_Config $config)
+    {
+        foreach ($config as $key => $value) {
+            switch ($key) {
+                case 'target':
+                    $this->setTarget($value);
+                    break;
+                case 'filterPrefixPath':
+                    if (is_scalar($value)) {
+                        break;
+                    }
+                    $paths = $value->toArray();
+                    foreach ($paths as $prefix => $path) {
+                        $this->addFilterPrefixPath($prefix, $path);
+                    }
+                    break;
+                case 'throwTargetExceptionsOn':
+                    $this->setThrowTargetExceptionsOn($value);
+                    break;
+                case 'targetReplacementIdentifier':
+                    $this->setTargetReplacementIdentifier($value);
+                    break;
+                case 'rules':
+                    $this->addRules($value->toArray());
+                    break;
+                default:
+                    break;
+            }
+        }
+        return $this;
+    }
+    
+    /**
+     * Convienence method to add prefix and path to PluginLoader
+     *
+     * @param string $prefix
+     * @param string $path
+     * @return Zend_Filter_Inflector
+     */
+    public function addFilterPrefixPath($prefix, $path)
+    {
+        $this->getPluginLoader()->addPrefixPath($prefix, $path);
+        return $this;
+    }
+
+    /**
+     * Set Whether or not the inflector should throw an exception when a replacement
+     * identifier is still found within an inflected target.
+     *
+     * @param bool $throwTargetExceptions
+     * @return Zend_Filter_Inflector
+     */
+    public function setThrowTargetExceptionsOn($throwTargetExceptionsOn)
+    {
+        $this->_throwTargetExceptionsOn = ($throwTargetExceptionsOn == true) ? true : false;
+        return $this;
+    }
+    
+    /**
+     * Will exceptions be thrown?
+     *
+     * @return bool
+     */
+    public function isThrowTargetExceptionsOn()
+    {
+        return $this->_throwTargetExceptionsOn;
+    }
+
+    /**
+     * Set the Target Replacement Identifier, by default ':'
+     *
+     * @param string $targetReplacementIdentifier
+     * @return Zend_Filter_Inflector
+     */
+    public function setTargetReplacementIdentifier($targetReplacementIdentifier)
+    {
+        $this->_targetReplacementIdentifier = (string) $targetReplacementIdentifier;
+        return $this;
+    }
+    
+    /**
+     * Get Target Replacement Identifier
+     *
+     * @return string
+     */
+    public function getTargetReplacementIdentifier()
+    {
+        return $this->_targetReplacementIdentifier;
+    }
+    
+    /**
+     * Set a Target
+     * ex: 'scripts/:controller/:action.:suffix'
+     * 
+     * @param string
+     * @return Zend_Filter_Inflector
+     */
+    public function setTarget($target)
+    {
+        $this->_target = (string) $target;
+        return $this;
+    }
+
+    /**
+     * Retrieve target
+     * 
+     * @return string
+     */
+    public function getTarget()
+    {
+        return $this->_target;
+    }
+
+    /**
+     * Set Target Reference
+     *
+     * @param reference $target
+     * @return Zend_Filter_Inflector
+     */
+    public function setTargetReference(&$target)
+    {
+        $this->_target =& $target;
+        return $this;
+    }
+
+    /**
+     * SetRules() is the same as calling addRules() with the exception that it
+     * clears the rules before adding them.
+     *
+     * @param array $rules
+     * @return Zend_Filter_Inflector
+     */
+    public function setRules(Array $rules)
+    {
+        $this->clearRules();
+        $this->addRules($rules);
+        return $this;
+    }
+    
+    /**
+     * AddRules(): multi-call to setting filter rules.  
+     *
+     * If prefixed with a ":" (colon), a filter rule will be added.  If not 
+     * prefixed, a static replacement will be added.
+     * 
+     * ex:
+     * array(
+     *     ':controller' => array('CamelCaseToUnderscore','StringToLower'),
+     *     ':action'     => array('CamelCaseToUnderscore','StringToLower'),
+     *     'suffix'      => 'phtml'
+     *     );
+     * 
+     * @param array
+     * @return Zend_Filter_Inflector
+     */
+    public function addRules(Array $rules)
+    {
+        $keys = array_keys($rules);
+        foreach ($keys as $spec) {
+            if ($spec[0] == ':') {
+                $this->addFilterRule($spec, $rules[$spec]);
+            } else {
+                $this->setStaticRule($spec, $rules[$spec]);
+            }
+        }
+        
+        return $this;
+    }
+    
+    /**
+     * Get rules
+     *
+     * By default, returns all rules. If a $spec is provided, will return those 
+     * rules if found, false otherwise.
+     * 
+     * @param  string $spec 
+     * @return array|false
+     */
+    public function getRules($spec = null)
+    {
+        if (null !== $spec) {
+            $spec = $this->_normalizeSpec($spec);
+            if (isset($this->_rules[$spec])) {
+                return $this->_rules[$spec];
+            }
+            return false;
+        }
+
+        return $this->_rules;
+    }
+    
+    /**
+     * getRule() returns a rule set by setFilterRule(), a numeric index must be provided
+     *
+     * @param string $spec
+     * @param int $index
+     * @return Zend_Filter_Interface|false
+     */
+    public function getRule($spec, $index)
+    {
+        $spec = $this->_normalizeSpec($spec);
+        if (isset($this->_rules[$spec]) && is_array($this->_rules[$spec])) {
+            if (isset($this->_rules[$spec][$index])) {
+                return $this->_rules[$spec][$index];
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * ClearRules() clears the rules currently in the inflector
+     *
+     * @return Zend_Filter_Inflector
+     */
+    public function clearRules()
+    {
+        $this->_rules = array();
+        return $this;
+    }
+    
+    /**
+     * Set a filtering rule for a spec.  $ruleSet can be a string, Filter object
+     * or an array of strings or filter objects.
+     *
+     * @param string $spec
+     * @param array|string|Zend_Filter_Interface $ruleSet
+     * @return Zend_Filter_Inflector
+     */
+    public function setFilterRule($spec, $ruleSet)
+    {
+        $spec = $this->_normalizeSpec($spec);
+        $this->_rules[$spec] = array();
+        return $this->addFilterRule($spec, $ruleSet);
+    }
+
+    /**
+     * Add a filter rule for a spec
+     * 
+     * @param mixed $spec 
+     * @param mixed $ruleSet 
+     * @return void
+     */
+    public function addFilterRule($spec, $ruleSet)
+    {
+        $spec = $this->_normalizeSpec($spec);
+        if (!isset($this->_rules[$spec])) {
+            $this->_rules[$spec] = array();
+        }
+        if (!is_array($ruleSet)) {
+            $ruleSet = array($ruleSet);
+        }
+        foreach ($ruleSet as $rule) {
+            $this->_rules[$spec][] = $this->_getRule($rule);
+        }
+        return $this;
+    }
+    
+    /**
+     * Set a static rule for a spec.  This is a single string value
+     *
+     * @param string $name
+     * @param string $value
+     * @return Zend_Filter_Inflector
+     */
+    public function setStaticRule($name, $value)
+    {
+        $name = $this->_normalizeSpec($name);
+        $this->_rules[$name] = (string) $value;
+        return $this;
+    }
+    
+    /**
+     * Set Static Rule Reference. 
+     *
+     * This allows a consuming class to pass a property or variable
+     * in to be referenced when its time to build the output string from the 
+     * target.
+     *
+     * @param string $name
+     * @param mixed $reference
+     * @return Zend_Filter_Inflector
+     */
+    public function setStaticRuleReference($name, &$reference)
+    {
+        $name = $this->_normalizeSpec($name);
+        $this->_rules[$name] =& $reference;
+        return $this;
+    }
+
+    /**
+     * Inflect
+     *
+     * @param  string|array $source
+     * @return string
+     */
+    public function filter($source)
+    {
+        // clean source
+        foreach ( (array) $source as $sourceName => $sourceValue) {
+            $source[ltrim($sourceName, ':')] = $sourceValue;
+        }
+
+        $pregQuotedTargetReplacementIdentifier = preg_quote($this->_targetReplacementIdentifier, '#');
+        $processedParts = array();
+        
+        foreach ($this->_rules as $ruleName => $ruleValue) {
+            if (isset($source[$ruleName])) {
+                if (is_string($ruleValue)) {
+                    // overriding the set rule
+                    $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $source[$ruleName]);
+                } elseif (is_array($ruleValue)) {
+                    $processedPart = $source[$ruleName];
+                    foreach ($ruleValue as $ruleFilter) {
+                        $processedPart = $ruleFilter->filter($processedPart);
+                    }
+                    $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $processedPart);
+                }
+            } elseif (is_string($ruleValue)) {
+                $processedParts['#'.$pregQuotedTargetReplacementIdentifier.$ruleName.'#'] = str_replace('\\', '\\\\', $ruleValue);
+            }
+        }
+        
+        // all of the values of processedParts would have been str_replace('\\', '\\\\', ..)'d to disable preg_replace backreferences 
+        $inflectedTarget = preg_replace(array_keys($processedParts), array_values($processedParts), $this->_target);
+
+        if ($this->_throwTargetExceptionsOn && (preg_match('#(?='.$pregQuotedTargetReplacementIdentifier.'[A-Za-z]{1})#', $inflectedTarget) == true)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('A replacement identifier ' . $this->_targetReplacementIdentifier . ' was found inside the inflected target, perhaps a rule was not satisfied with a target source?  Unsatisfied inflected target: ' . $inflectedTarget);
+        }
+        
+        return $inflectedTarget;
+    }
+    
+    /**
+     * Normalize spec string
+     * 
+     * @param  string $spec 
+     * @return string
+     */
+    protected function _normalizeSpec($spec)
+    {
+        return ltrim((string) $spec, ':&');
+    }
+    
+    /**
+     * Resolve named filters and convert them to filter objects.
+     *
+     * @param  string $rule
+     * @return Zend_Filter_Interface
+     */
+    protected function _getRule($rule)
+    {
+        if ($rule instanceof Zend_Filter_Interface) {
+            return $rule;
+        }
+        
+        $rule = (string) $rule;
+        
+        $className  = $this->getPluginLoader()->load($rule);
+        $ruleObject = new $className();
+        if (!$ruleObject instanceof Zend_Filter_Interface) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('No class named ' . $rule . ' implementing Zend_Filter_Interface could be found');
+        }
+        
+        return $ruleObject;
+    }
+
+}
diff --git a/lib/Zend/Filter/Input.php b/lib/Zend/Filter/Input.php
new file mode 100644
index 0000000..a6782a3
--- /dev/null
+++ b/lib/Zend/Filter/Input.php
@@ -0,0 +1,926 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Input.php 8856 2008-03-16 11:28:48Z thomas $
+ */
+
+/**
+ * @see Zend_Loader
+ */
+require_once 'Zend/Loader.php';
+
+/**
+ * @see Zend_Filter
+ */
+require_once 'Zend/Filter.php';
+
+/**
+ * @see Zend_Validate
+ */
+require_once 'Zend/Validate.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Input
+{
+
+    const ALLOW_EMPTY       = 'allowEmpty';
+    const BREAK_CHAIN       = 'breakChainOnFailure';
+    const DEFAULT_VALUE     = 'default';
+    const MESSAGES          = 'messages';
+    const ESCAPE_FILTER     = 'escapeFilter';
+    const FIELDS            = 'fields';
+    const FILTER            = 'filter';
+    const FILTER_CHAIN      = 'filterChain';
+    const MISSING_MESSAGE   = 'missingMessage';
+    const INPUT_NAMESPACE   = 'inputNamespace';
+    const NOT_EMPTY_MESSAGE = 'notEmptyMessage';
+    const PRESENCE          = 'presence';
+    const PRESENCE_OPTIONAL = 'optional';
+    const PRESENCE_REQUIRED = 'required';
+    const RULE              = 'rule';
+    const RULE_WILDCARD     = '*';
+    const VALIDATE          = 'validate';
+    const VALIDATOR         = 'validator';
+    const VALIDATOR_CHAIN   = 'validatorChain';
+    const VALIDATOR_CHAIN_COUNT = 'validatorChainCount';
+
+    /**
+     * @var array Input data, before processing.
+     */
+    protected $_data = array();
+
+    /**
+     * @var array Association of rules to filters.
+     */
+    protected $_filterRules = array();
+
+    /**
+     * @var array Association of rules to validators.
+     */
+    protected $_validatorRules = array();
+
+    /**
+     * @var array After processing data, this contains mapping of valid fields
+     * to field values.
+     */
+    protected $_validFields = array();
+
+    /**
+     * @var array After processing data, this contains mapping of validation
+     * rules that did not pass validation to the array of messages returned
+     * by the validator chain.
+     */
+    protected $_invalidMessages = array();
+
+    /**
+     * @var array After processing data, this contains mapping of validation
+     * rules that did not pass validation to the array of error identifiers
+     * returned by the validator chain.
+     */
+    protected $_invalidErrors = array();
+
+    /**
+     * @var array After processing data, this contains mapping of validation
+     * rules in which some fields were missing to the array of messages
+     * indicating which fields were missing.
+     */
+    protected $_missingFields = array();
+
+    /**
+     * @var array After processing, this contains a copy of $_data elements
+     * that were not mentioned in any validation rule.
+     */
+    protected $_unknownFields = array();
+
+    /**
+     * @var Zend_Filter_Interface The filter object that is run on values
+     * returned by the getEscaped() method.
+     */
+    protected $_defaultEscapeFilter = null;
+
+    /**
+     * Plugin loaders
+     * @var array
+     */
+    protected $_loaders = array();
+
+    /**
+     * @var array Default values to use when processing filters and validators.
+     */
+    protected $_defaults = array(
+        self::ALLOW_EMPTY         => false,
+        self::BREAK_CHAIN         => false,
+        self::ESCAPE_FILTER       => 'HtmlEntities',
+        self::MISSING_MESSAGE     => "Field '%field%' is required by rule '%rule%', but the field is missing",
+        self::NOT_EMPTY_MESSAGE   => "You must give a non-empty value for field '%field%'",
+        self::PRESENCE            => self::PRESENCE_OPTIONAL
+    );
+
+    /**
+     * @var boolean Set to False initially, this is set to True after the
+     * input data have been processed.  Reset to False in setData() method.
+     */
+    protected $_processed = false;
+
+    /**
+     * @param array $filterRules
+     * @param array $validatorRules
+     * @param array $data       OPTIONAL
+     * @param array $options    OPTIONAL
+     */
+    public function __construct($filterRules, $validatorRules, array $data = null, array $options = null)
+    {
+        if ($options) {
+            $this->setOptions($options);
+        }
+
+        $this->_filterRules = (array) $filterRules;
+        $this->_validatorRules = (array) $validatorRules;
+
+        if ($data) {
+            $this->setData($data);
+        }
+    }
+
+    /**
+     * @param mixed $namespaces
+     * @return Zend_Filter_Input
+     * @deprecated since 1.5.0RC1 - use addFilterPrefixPath() or addValidatorPrefixPath instead.
+     */
+    public function addNamespace($namespaces)
+    {
+        if (!is_array($namespaces)) {
+            $namespaces = array($namespaces);
+        }
+
+        foreach ($namespaces as $namespace) {
+            $prefix = $namespace;
+            $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix);
+            $this->addFilterPrefixPath($prefix, $path);
+            $this->addValidatorPrefixPath($prefix, $path);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Add prefix path for all elements
+     *
+     * @param  string $prefix
+     * @param  string $path
+     * @return Zend_Filter_Input
+     */
+    public function addFilterPrefixPath($prefix, $path)
+    {
+        $this->getPluginLoader(self::FILTER)->addPrefixPath($prefix, $path);
+
+        return $this;
+    }
+
+    /**
+     * Add prefix path for all elements
+     *
+     * @param  string $prefix
+     * @param  string $path
+     * @return Zend_Filter_Input
+     */
+    public function addValidatorPrefixPath($prefix, $path)
+    {
+        $this->getPluginLoader(self::VALIDATE)->addPrefixPath($prefix, $path);
+
+        return $this;
+    }
+
+    /**
+     * Set plugin loaders for use with decorators and elements
+     *
+     * @param  Zend_Loader_PluginLoader_Interface $loader
+     * @param  string $type 'filter' or 'validate'
+     * @return Zend_Filter_Input
+     * @throws Zend_Filter_Exception on invalid type
+     */
+    public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type)
+    {
+        $type = strtolower($type);
+        switch ($type) {
+            case self::FILTER:
+            case self::VALIDATE:
+                $this->_loaders[$type] = $loader;
+                return $this;
+            default:
+                require_once 'Zend/Filter/Exception.php';
+                throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
+        }
+
+        return $this;
+    }
+
+    /**
+     * Retrieve plugin loader for given type
+     *
+     * $type may be one of:
+     * - filter
+     * - validator
+     *
+     * If a plugin loader does not exist for the given type, defaults are
+     * created.
+     *
+     * @param  string $type 'filter' or 'validate'
+     * @return Zend_Loader_PluginLoader_Interface
+     * @throws Zend_Filter_Exception on invalid type
+     */
+    public function getPluginLoader($type)
+    {
+        $type = strtolower($type);
+        if (!isset($this->_loaders[$type])) {
+            switch ($type) {
+                case self::FILTER:
+                    $prefixSegment = 'Zend_Filter_';
+                    $pathSegment   = 'Zend/Filter/';
+                    break;
+                case self::VALIDATE:
+                    $prefixSegment = 'Zend_Validate_';
+                    $pathSegment   = 'Zend/Validate/';
+                    break;
+                default:
+                    require_once 'Zend/Filter/Exception.php';
+                    throw new Zend_Filter_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
+            }
+
+            require_once 'Zend/Loader/PluginLoader.php';
+            $this->_loaders[$type] = new Zend_Loader_PluginLoader(
+                array($prefixSegment => $pathSegment)
+            );
+        }
+
+        return $this->_loaders[$type];
+    }
+
+    /**
+     * @return array
+     */
+    public function getMessages()
+    {
+        $this->_process();
+        return array_merge($this->_invalidMessages, $this->_missingFields);
+    }
+
+    /**
+     * @return array
+     */
+    public function getErrors()
+    {
+        $this->_process();
+        return $this->_invalidErrors;
+    }
+
+    /**
+     * @return array
+     */
+    public function getInvalid()
+    {
+        $this->_process();
+        return $this->_invalidMessages;
+    }
+
+    /**
+     * @return array
+     */
+    public function getMissing()
+    {
+        $this->_process();
+        return $this->_missingFields;
+    }
+
+    /**
+     * @return array
+     */
+    public function getUnknown()
+    {
+        $this->_process();
+        return $this->_unknownFields;
+    }
+
+    /**
+     * @param string $fieldName OPTIONAL
+     * @return mixed
+     */
+    public function getEscaped($fieldName = null)
+    {
+        $this->_process();
+        $this->_getDefaultEscapeFilter();
+
+        if ($fieldName === null) {
+            return $this->_escapeRecursive($this->_validFields);
+        }
+        if (array_key_exists($fieldName, $this->_validFields)) {
+            return $this->_escapeRecursive($this->_validFields[$fieldName]);
+        }
+        return null;
+    }
+
+    /**
+     * @param mixed $value
+     * @return mixed
+     */
+    protected function _escapeRecursive($data)
+    {
+        if (!is_array($data)) {
+            return $this->_getDefaultEscapeFilter()->filter($data);
+        }
+        foreach ($data as &$element) {
+            $element = $this->_escapeRecursive($element);
+        }
+        return $data;
+    }
+
+    /**
+     * @param string $fieldName OPTIONAL
+     * @return mixed
+     */
+    public function getUnescaped($fieldName = null)
+    {
+        $this->_process();
+        if ($fieldName === null) {
+            return $this->_validFields;
+        }
+        if (array_key_exists($fieldName, $this->_validFields)) {
+            return $this->_validFields[$fieldName];
+        }
+        return null;
+    }
+
+    /**
+     * @param string $fieldName
+     * @return mixed
+     */
+    public function __get($fieldName)
+    {
+        return $this->getEscaped($fieldName);
+    }
+
+    /**
+     * @return boolean
+     */
+    public function hasInvalid()
+    {
+        $this->_process();
+        return !(empty($this->_invalidMessages));
+    }
+
+    /**
+     * @return boolean
+     */
+    public function hasMissing()
+    {
+        $this->_process();
+        return !(empty($this->_missingFields));
+    }
+
+    /**
+     * @return boolean
+     */
+    public function hasUnknown()
+    {
+        $this->_process();
+        return !(empty($this->_unknownFields));
+    }
+
+    /**
+     * @return boolean
+     */
+    public function hasValid()
+    {
+        $this->_process();
+        return !(empty($this->_validFields));
+    }
+
+    /**
+     * @param string $fieldName
+     * @return boolean
+     */
+    public function isValid($fieldName = null)
+    {
+        $this->_process();
+        if ($fieldName === null) {
+            return !($this->hasMissing() || $this->hasInvalid());
+        }
+        return array_key_exists($fieldName, $this->_validFields);
+    }
+
+    /**
+     * @param string $fieldName
+     * @return boolean
+     */
+    public function __isset($fieldName)
+    {
+        $this->_process();
+        return isset($this->_validFields[$fieldName]);
+    }
+
+    /**
+     * @return Zend_Filter_Input
+     * @throws Zend_Filter_Exception
+     */
+    public function process()
+    {
+        $this->_process();
+        if ($this->hasInvalid()) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("Input has invalid fields");
+        }
+        if ($this->hasMissing()) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("Input has missing fields");
+        }
+
+        return $this;
+    }
+
+    /**
+     * @param array $data
+     * @return Zend_Filter_Input
+     */
+    public function setData(array $data)
+    {
+        $this->_data = $data;
+
+        /**
+         * Reset to initial state
+         */
+        $this->_validFields = array();
+        $this->_invalidMessages = array();
+        $this->_invalidErrors = array();
+        $this->_missingFields = array();
+        $this->_unknownFields = array();
+
+        $this->_processed = false;
+
+        return $this;
+    }
+
+    /**
+     * @param mixed $escapeFilter
+     * @return Zend_Filter_Interface
+     */
+    public function setDefaultEscapeFilter($escapeFilter)
+    {
+        if (is_string($escapeFilter) || is_array($escapeFilter)) {
+            $escapeFilter = $this->_getFilter($escapeFilter);
+        }
+        if (!$escapeFilter instanceof Zend_Filter_Interface) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('Escape filter specified does not implement Zend_Filter_Interface');
+        }
+        $this->_defaultEscapeFilter = $escapeFilter;
+        return $escapeFilter;
+    }
+
+    /**
+     * @param array $options
+     * @return Zend_Filter_Input
+     * @throws Zend_Filter_Exception if an unknown option is given
+     */
+    public function setOptions(array $options)
+    {
+        foreach ($options as $option => $value) {
+            switch ($option) {
+                case self::ESCAPE_FILTER:
+                    $this->setDefaultEscapeFilter($value);
+                    break;
+                case self::INPUT_NAMESPACE:
+                    $this->addNamespace($value);
+                    break;
+                case self::ALLOW_EMPTY:
+                case self::BREAK_CHAIN:
+                case self::MISSING_MESSAGE:
+                case self::NOT_EMPTY_MESSAGE:
+                case self::PRESENCE:
+                    $this->_defaults[$option] = $value;
+                    break;
+                default:
+                    require_once 'Zend/Filter/Exception.php';
+                    throw new Zend_Filter_Exception("Unknown option '$option'");
+                    break;
+            }
+        }
+
+        return $this;
+    }
+
+    /*
+     * Protected methods
+     */
+
+    /**
+     * @return void
+     */
+    protected function _filter()
+    {
+        foreach ($this->_filterRules as $ruleName => &$filterRule) {
+            /**
+             * Make sure we have an array representing this filter chain.
+             * Don't typecast to (array) because it might be a Zend_Filter object
+             */
+            if (!is_array($filterRule)) {
+                $filterRule = array($filterRule);
+            }
+
+            /**
+             * Filters are indexed by integer, metacommands are indexed by string.
+             * Pick out the filters.
+             */
+            $filterList = array();
+            foreach ($filterRule as $key => $value) {
+                if (is_int($key)) {
+                    $filterList[] = $value;
+                }
+            }
+
+            /**
+             * Use defaults for filter metacommands.
+             */
+            $filterRule[self::RULE] = $ruleName;
+            if (!isset($filterRule[self::FIELDS])) {
+                $filterRule[self::FIELDS] = $ruleName;
+            }
+
+            /**
+             * Load all the filter classes and add them to the chain.
+             */
+            if (!isset($filterRule[self::FILTER_CHAIN])) {
+                $filterRule[self::FILTER_CHAIN] = new Zend_Filter();
+                foreach ($filterList as $filter) {
+                    if (is_string($filter) || is_array($filter)) {
+                        $filter = $this->_getFilter($filter);
+                    }
+                    $filterRule[self::FILTER_CHAIN]->addFilter($filter);
+                }
+            }
+
+            /**
+             * If the ruleName is the special wildcard rule,
+             * then apply the filter chain to all input data.
+             * Else just process the field named by the rule.
+             */
+            if ($ruleName == self::RULE_WILDCARD) {
+                foreach (array_keys($this->_data) as $field)  {
+                    $this->_filterRule(array_merge($filterRule, array(self::FIELDS => $field)));
+                }
+            } else {
+                $this->_filterRule($filterRule);
+            }
+        }
+    }
+
+    /**
+     * @param array $filterRule
+     * @return void
+     */
+    protected function _filterRule(array $filterRule)
+    {
+        $field = $filterRule[self::FIELDS];
+        if (!array_key_exists($field, $this->_data)) {
+            return;
+        }
+        if (is_array($this->_data[$field])) {
+            foreach ($this->_data[$field] as $key => $value) {
+                $this->_data[$field][$key] = $filterRule[self::FILTER_CHAIN]->filter($value);
+            }
+        } else {
+            $this->_data[$field] =
+                $filterRule[self::FILTER_CHAIN]->filter($this->_data[$field]);
+        }
+    }
+
+    /**
+     * @return Zend_Filter_Interface
+     */
+    protected function _getDefaultEscapeFilter()
+    {
+        if ($this->_defaultEscapeFilter !== null) {
+            return $this->_defaultEscapeFilter;
+        }
+        return $this->setDefaultEscapeFilter($this->_defaults[self::ESCAPE_FILTER]);
+    }
+
+    /**
+     * @param string $rule
+     * @param string $field
+     * @return string
+     */
+    protected function _getMissingMessage($rule, $field)
+    {
+        $message = $this->_defaults[self::MISSING_MESSAGE];
+        $message = str_replace('%rule%', $rule, $message);
+        $message = str_replace('%field%', $field, $message);
+        return $message;
+    }
+
+    /**
+     * @return string
+     */
+    protected function _getNotEmptyMessage($rule, $field)
+    {
+        $message = $this->_defaults[self::NOT_EMPTY_MESSAGE];
+        $message = str_replace('%rule%', $rule, $message);
+        $message = str_replace('%field%', $field, $message);
+        return $message;
+    }
+
+    /**
+     * @return void
+     */
+    protected function _process()
+    {
+        if ($this->_processed === false) {
+            $this->_filter();
+            $this->_validate();
+            $this->_processed = true;
+        }
+    }
+
+    /**
+     * @return void
+     */
+    protected function _validate()
+    {
+        /**
+         * Special case: if there are no validators, treat all fields as valid.
+         */
+        if (!$this->_validatorRules) {
+            $this->_validFields = $this->_data;
+            $this->_data = array();
+            return;
+        }
+
+        foreach ($this->_validatorRules as $ruleName => &$validatorRule) {
+            /**
+             * Make sure we have an array representing this validator chain.
+             * Don't typecast to (array) because it might be a Zend_Validate object
+             */
+            if (!is_array($validatorRule)) {
+                $validatorRule = array($validatorRule);
+            }
+
+            /**
+             * Validators are indexed by integer, metacommands are indexed by string.
+             * Pick out the validators.
+             */
+            $validatorList = array();
+            foreach ($validatorRule as $key => $value) {
+                if (is_int($key)) {
+                    $validatorList[] = $value;
+                }
+            }
+
+            /**
+             * Use defaults for validation metacommands.
+             */
+            $validatorRule[self::RULE] = $ruleName;
+            if (!isset($validatorRule[self::FIELDS])) {
+                $validatorRule[self::FIELDS] = $ruleName;
+            }
+            if (!isset($validatorRule[self::BREAK_CHAIN])) {
+                $validatorRule[self::BREAK_CHAIN] = $this->_defaults[self::BREAK_CHAIN];
+            }
+            if (!isset($validatorRule[self::PRESENCE])) {
+                $validatorRule[self::PRESENCE] = $this->_defaults[self::PRESENCE];
+            }
+            if (!isset($validatorRule[self::ALLOW_EMPTY])) {
+                $validatorRule[self::ALLOW_EMPTY] = $this->_defaults[self::ALLOW_EMPTY];
+            }
+            if (!isset($validatorRule[self::MESSAGES])) {
+                $validatorRule[self::MESSAGES] = array();
+            } else if (!is_array($validatorRule[self::MESSAGES])) {
+                $validatorRule[self::MESSAGES] = array($validatorRule[self::MESSAGES]);
+            } else if (!array_intersect_key($validatorList, $validatorRule[self::MESSAGES])) {
+                $validatorRule[self::MESSAGES] = array($validatorRule[self::MESSAGES]);
+            }
+
+            /**
+             * Load all the validator classes and add them to the chain.
+             */
+            if (!isset($validatorRule[self::VALIDATOR_CHAIN])) {
+                $validatorRule[self::VALIDATOR_CHAIN] = new Zend_Validate();
+                $i = 0;
+                foreach ($validatorList as $validator) {
+
+                    if (is_string($validator) || is_array($validator)) {
+                        $validator = $this->_getValidator($validator);
+                    }
+                    if (isset($validatorRule[self::MESSAGES][$i])) {
+                        $value = $validatorRule[self::MESSAGES][$i];
+                        if (is_array($value)) {
+                            $validator->setMessages($value);
+                        } else {
+                            $validator->setMessage($value);
+                        }
+                    }
+
+                    $validatorRule[self::VALIDATOR_CHAIN]->addValidator($validator, $validatorRule[self::BREAK_CHAIN]);
+                    ++$i;
+                }
+                $validatorRule[self::VALIDATOR_CHAIN_COUNT] = $i;
+            }
+
+            /**
+             * If the ruleName is the special wildcard rule,
+             * then apply the validator chain to all input data.
+             * Else just process the field named by the rule.
+             */
+            if ($ruleName == self::RULE_WILDCARD) {
+                foreach (array_keys($this->_data) as $field)  {
+                    $this->_validateRule(array_merge($validatorRule, array(self::FIELDS => $field)));
+                }
+            } else {
+                $this->_validateRule($validatorRule);
+            }
+        }
+
+        /**
+         * Unset fields in $_data that have been added to other arrays.
+         * We have to wait until all rules have been processed because
+         * a given field may be referenced by multiple rules.
+         */
+        foreach (array_merge(array_keys($this->_missingFields), array_keys($this->_invalidMessages)) as $rule) {
+            foreach ((array) $this->_validatorRules[$rule][self::FIELDS] as $field) {
+                unset($this->_data[$field]);
+            }
+        }
+        foreach ($this->_validFields as $field => $value) {
+            unset($this->_data[$field]);
+        }
+
+        /**
+         * Anything left over in $_data is an unknown field.
+         */
+        $this->_unknownFields = $this->_data;
+    }
+
+    /**
+     * @param array $validatorRule
+     * @return void
+     */
+    protected function _validateRule(array $validatorRule)
+    {
+        /**
+         * Get one or more data values from input, and check for missing fields.
+         * Apply defaults if fields are missing.
+         */
+        $data = array();
+        foreach ((array) $validatorRule[self::FIELDS] as $field) {
+            if (array_key_exists($field, $this->_data)) {
+                $data[$field] = $this->_data[$field];
+            } else
+            if (array_key_exists(self::DEFAULT_VALUE, $validatorRule)) {
+                if (is_array($validatorRule[self::DEFAULT_VALUE])) {
+                    $key = array_search($field, (array) $validatorRule[self::FIELDS]);
+                    if (array_key_exists($key, $validatorRule[self::DEFAULT_VALUE])) {
+                        $data[$field] = $validatorRule[self::DEFAULT_VALUE][$key];
+                    }
+                } else {
+                    $data[$field] = $validatorRule[self::DEFAULT_VALUE];
+                }
+            } else
+            if ($validatorRule[self::PRESENCE] == self::PRESENCE_REQUIRED) {
+                $this->_missingFields[$validatorRule[self::RULE]][] =
+                    $this->_getMissingMessage($validatorRule[self::RULE], $field);
+            }
+        }
+
+        /**
+         * If any required fields are missing, break the loop.
+         */
+        if (isset($this->_missingFields[$validatorRule[self::RULE]]) && count($this->_missingFields[$validatorRule[self::RULE]]) > 0) {
+            return;
+        }
+
+        /**
+         * Evaluate the inputs against the validator chain.
+         */
+        if (count((array) $validatorRule[self::FIELDS]) > 1) {
+            if (!$validatorRule[self::VALIDATOR_CHAIN]->isValid($data)) {
+                $this->_invalidMessages[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getMessages();
+                $this->_invalidErrors[$validatorRule[self::RULE]] = $validatorRule[self::VALIDATOR_CHAIN]->getErrors();
+                return;
+            }
+        } else {
+            $failed = false;
+            foreach ($data as $fieldKey => $field) {
+                if (!is_array($field)) {
+                    $field = array($field);
+                }
+                foreach ($field as $value) {
+                    if (empty($value)) {
+                        if ($validatorRule[self::ALLOW_EMPTY] == true) {
+                            continue;
+                        }
+                        if ($validatorRule[self::VALIDATOR_CHAIN_COUNT] == 0) {
+                            $notEmptyValidator = $this->_getValidator('NotEmpty');
+                            $notEmptyValidator->setMessage($this->_getNotEmptyMessage($validatorRule[self::RULE], $fieldKey));
+                            $validatorRule[self::VALIDATOR_CHAIN]->addValidator($notEmptyValidator);
+                        }
+                    }
+                    if (!$validatorRule[self::VALIDATOR_CHAIN]->isValid($value)) {
+                        $this->_invalidMessages[$validatorRule[self::RULE]] =
+                            $validatorRule[self::VALIDATOR_CHAIN]->getMessages();
+                        $this->_invalidErrors[$validatorRule[self::RULE]] =
+                            $validatorRule[self::VALIDATOR_CHAIN]->getErrors();
+                        unset($this->_validFields[$fieldKey]);
+                        $failed = true;
+                        if ($validatorRule[self::BREAK_CHAIN]) {
+                            return;
+                        }
+                    }
+                }
+            }
+            if ($failed) {
+                return;
+            }
+        }
+
+        /**
+         * If we got this far, the inputs for this rule pass validation.
+         */
+        foreach ((array) $validatorRule[self::FIELDS] as $field) {
+            if (array_key_exists($field, $data)) {
+                $this->_validFields[$field] = $data[$field];
+            }
+        }
+    }
+
+    /**
+     * @param mixed $classBaseName
+     * @return Zend_Filter_Interface
+     */
+    protected function _getFilter($classBaseName)
+    {
+        return $this->_getFilterOrValidator(self::FILTER, $classBaseName);
+    }
+
+    /**
+     * @param mixed $classBaseName
+     * @return Zend_Validate_Interface
+     */
+    protected function _getValidator($classBaseName)
+    {
+        return $this->_getFilterOrValidator(self::VALIDATE, $classBaseName);
+    }
+
+    /**
+     * @param string $type
+     * @param mixed $classBaseName
+     * @return Zend_Filter_Interface|Zend_Validate_Interface
+     * @throws Zend_Filter_Exception
+     */
+    protected function _getFilterOrValidator($type, $classBaseName)
+    {
+        $args = array();
+
+        if (is_array($classBaseName)) {
+            $args = $classBaseName;
+            $classBaseName = array_shift($args);
+        }
+
+        $interfaceName = 'Zend_' . ucfirst($type) . '_Interface';
+        $className = $this->getPluginLoader($type)->load(ucfirst($classBaseName));
+
+        $class = new ReflectionClass($className);
+
+        if (!$class->implementsInterface($interfaceName)) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception("Class based on basename '$classBaseName' must implement the '$interfaceName' interface");
+        }
+
+        if ($class->hasMethod('__construct')) {
+            $object = $class->newInstanceArgs($args);
+        } else {
+            $object = $class->newInstance();
+        }
+
+        return $object;
+    }
+
+}
diff --git a/lib/Zend/Filter/Int.php b/lib/Zend/Filter/Int.php
new file mode 100644
index 0000000..39c3d6d
--- /dev/null
+++ b/lib/Zend/Filter/Int.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Int.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Int implements Zend_Filter_Interface
+{
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns (int) $value
+     *
+     * @param  string $value
+     * @return integer
+     */
+    public function filter($value)
+    {
+        return (int) ((string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/Interface.php b/lib/Zend/Filter/Interface.php
new file mode 100644
index 0000000..61a3531
--- /dev/null
+++ b/lib/Zend/Filter/Interface.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Interface.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Filter_Interface
+{
+    /**
+     * Returns the result of filtering $value
+     *
+     * @param  mixed $value
+     * @throws Zend_Filter_Exception If filtering $value is impossible
+     * @return mixed
+     */
+    public function filter($value);
+}
diff --git a/lib/Zend/Filter/PregReplace.php b/lib/Zend/Filter/PregReplace.php
new file mode 100644
index 0000000..7e6ab27
--- /dev/null
+++ b/lib/Zend/Filter/PregReplace.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: PregReplace.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_PregReplace implements Zend_Filter_Interface
+{
+    /**
+     * Pattern to match
+     * @var mixed
+     */
+    protected $_matchPattern = null;
+
+    /**
+     * Replacement pattern
+     * @var mixed
+     */
+    protected $_replacement = '';
+    
+    /**
+     * Is unicode enabled?
+     *
+     * @var bool
+     */
+    static protected $_unicodeSupportEnabled = null;
+
+    /**
+     * Is Unicode Support Enabled Utility function
+     *
+     * @return bool
+     */
+    static public function isUnicodeSupportEnabled()
+    {
+        if (self::$_unicodeSupportEnabled === null) {
+            self::_determineUnicodeSupport();
+        }
+        
+        return self::$_unicodeSupportEnabled;
+    }
+    
+    /**
+     * Method to cache the regex needed to determine if unicode support is available
+     *
+     * @return bool
+     */
+    static protected function _determineUnicodeSupport()
+    {
+        self::$_unicodeSupportEnabled = (@preg_match('/\pL/u', 'a')) ? true : false;
+    }
+    
+    /**
+     * Constructor
+     * 
+     * @param  string $match 
+     * @param  string $replace 
+     * @return void
+     */
+    public function __construct($matchPattern = null, $replacement = null)
+    {
+        if ($matchPattern) {
+            $this->setMatchPattern($matchPattern);
+        }
+        
+        if ($replacement) {
+            $this->setReplacement($replacement);
+        }
+    }
+    
+    /**
+     * Set the match pattern for the regex being called within filter()
+     *
+     * @param mixed $match - same as the first argument of preg_replace
+     * @return Zend_Filter_PregReplace
+     */
+    public function setMatchPattern($match)
+    {
+        $this->_matchPattern = $match;
+        return $this;
+    }
+
+    /**
+     * Get currently set match pattern
+     * 
+     * @return string
+     */
+    public function getMatchPattern()
+    {
+        return $this->_matchPattern;
+    }
+    
+    /**
+     * Set the Replacement pattern/string for the preg_replace called in filter
+     *
+     * @param mixed $replacement - same as the second argument of preg_replace
+     * @return Zend_Filter_PregReplace
+     */
+    public function setReplacement($replacement)
+    {
+        $this->_replacement = $replacement;
+        return $this;
+    }
+
+    /**
+     * Get currently set replacement value
+     * 
+     * @return string
+     */
+    public function getReplacement()
+    {
+        return $this->_replacement;
+    }
+    
+    /**
+     * Perform regexp replacement as filter
+     * 
+     * @param  string $value 
+     * @return string
+     */
+    public function filter($value)
+    {
+        if ($this->_matchPattern == null) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception(get_class($this) . ' does not have a valid MatchPattern set.');
+        }
+        
+        return preg_replace($this->_matchPattern, $this->_replacement, $value);    
+    }
+    
+}
diff --git a/lib/Zend/Filter/RealPath.php b/lib/Zend/Filter/RealPath.php
new file mode 100644
index 0000000..f94de32
--- /dev/null
+++ b/lib/Zend/Filter/RealPath.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: RealPath.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_RealPath implements Zend_Filter_Interface
+{
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns realpath($value)
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        return realpath((string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/StringToLower.php b/lib/Zend/Filter/StringToLower.php
new file mode 100644
index 0000000..acd91f7
--- /dev/null
+++ b/lib/Zend/Filter/StringToLower.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: StringToLower.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_StringToLower implements Zend_Filter_Interface
+{
+    /**
+     * Encoding for the input string
+     *
+     * @var string
+     */
+    protected $_encoding = null;
+
+    /**
+     * Set the input encoding for the given string
+     *
+     * @param  string $encoding
+     * @throws Zend_Filter_Exception
+     */
+    public function setEncoding($encoding = null)
+    {
+        if (!function_exists('mb_strtolower')) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('mbstring is required for this feature');
+        }
+        $this->_encoding = $encoding;
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value, converting characters to lowercase as necessary
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        if ($this->_encoding) {
+            return mb_strtolower((string) $value, $this->_encoding);
+        }
+
+        return strtolower((string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/StringToUpper.php b/lib/Zend/Filter/StringToUpper.php
new file mode 100644
index 0000000..bd68aae
--- /dev/null
+++ b/lib/Zend/Filter/StringToUpper.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: StringToUpper.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_StringToUpper implements Zend_Filter_Interface
+{
+    /**
+     * Encoding for the input string
+     *
+     * @var string
+     */
+    protected $_encoding = null;
+
+    /**
+     * Set the input encoding for the given string
+     *
+     * @param  string $encoding
+     * @throws Zend_Filter_Exception
+     */
+    public function setEncoding($encoding = null)
+    {
+        if (!function_exists('mb_strtoupper')) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('mbstring is required for this feature');
+        }
+        $this->_encoding = $encoding;
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value, converting characters to uppercase as necessary
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        if ($this->_encoding) {
+            return mb_strtoupper((string) $value, $this->_encoding);
+        }
+
+        return strtoupper((string) $value);
+    }
+}
diff --git a/lib/Zend/Filter/StringTrim.php b/lib/Zend/Filter/StringTrim.php
new file mode 100644
index 0000000..af22900
--- /dev/null
+++ b/lib/Zend/Filter/StringTrim.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: StringTrim.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_StringTrim implements Zend_Filter_Interface
+{
+    /**
+     * List of characters provided to the trim() function
+     *
+     * If this is null, then trim() is called with no specific character list,
+     * and its default behavior will be invoked, trimming whitespace.
+     *
+     * @var string|null
+     */
+    protected $_charList;
+
+    /**
+     * Sets filter options
+     *
+     * @param  string $charList
+     * @return void
+     */
+    public function __construct($charList = null)
+    {
+        $this->_charList = $charList;
+    }
+
+    /**
+     * Returns the charList option
+     *
+     * @return string|null
+     */
+    public function getCharList()
+    {
+        return $this->_charList;
+    }
+
+    /**
+     * Sets the charList option
+     *
+     * @param  string|null $charList
+     * @return Zend_Filter_StringTrim Provides a fluent interface
+     */
+    public function setCharList($charList)
+    {
+        $this->_charList = $charList;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value with characters stripped from the beginning and end
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        if (null === $this->_charList) {
+            return trim((string) $value);
+        } else {
+            return trim((string) $value, $this->_charList);
+        }
+    }
+}
diff --git a/lib/Zend/Filter/StripNewlines.php b/lib/Zend/Filter/StripNewlines.php
new file mode 100644
index 0000000..b2dd042
--- /dev/null
+++ b/lib/Zend/Filter/StripNewlines.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: $
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_StripNewlines implements Zend_Filter_Interface
+{
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns $value without newline control characters
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter ($value)
+    {
+        return str_replace(array("\n", "\r"), '', $value);
+    }
+}
diff --git a/lib/Zend/Filter/StripTags.php b/lib/Zend/Filter/StripTags.php
new file mode 100644
index 0000000..4bd907c
--- /dev/null
+++ b/lib/Zend/Filter/StripTags.php
@@ -0,0 +1,294 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: StripTags.php 14273 2009-03-10 20:00:32Z matthew $
+ */
+
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_StripTags implements Zend_Filter_Interface
+{
+    /**
+     * Unique ID prefix used for allowing comments
+     */
+    const UNIQUE_ID_PREFIX = '__Zend_Filter_StripTags__';
+
+    /**
+     * Whether comments are allowed
+     *
+     * If false (the default), then comments are removed from the input string.
+     *
+     * @var boolean
+     */
+    public $commentsAllowed;
+
+    /**
+     * Array of allowed tags and allowed attributes for each allowed tag
+     *
+     * Tags are stored in the array keys, and the array values are themselves
+     * arrays of the attributes allowed for the corresponding tag.
+     *
+     * @var array
+     */
+    protected $_tagsAllowed = array();
+
+    /**
+     * Array of allowed attributes for all allowed tags
+     *
+     * Attributes stored here are allowed for all of the allowed tags.
+     *
+     * @var array
+     */
+    protected $_attributesAllowed = array();
+
+    /**
+     * Sets the filter options
+     *
+     * @param  array|string $tagsAllowed
+     * @param  array|string $attributesAllowed
+     * @param  boolean      $allowComments
+     * @return void
+     */
+    public function __construct($tagsAllowed = null, $attributesAllowed = null, $commentsAllowed = false)
+    {
+        $this->setTagsAllowed($tagsAllowed);
+        $this->setAttributesAllowed($attributesAllowed);
+        $this->commentsAllowed = (boolean) $commentsAllowed;
+    }
+
+    /**
+     * Returns the tagsAllowed option
+     *
+     * @return array
+     */
+    public function getTagsAllowed()
+    {
+        return $this->_tagsAllowed;
+    }
+
+    /**
+     * Sets the tagsAllowed option
+     *
+     * @param  array|string $tagsAllowed
+     * @return Zend_Filter_StripTags Provides a fluent interface
+     */
+    public function setTagsAllowed($tagsAllowed)
+    {
+        if (!is_array($tagsAllowed)) {
+            $tagsAllowed = array($tagsAllowed);
+        }
+
+        foreach ($tagsAllowed as $index => $element) {
+            // If the tag was provided without attributes
+            if (is_int($index) && is_string($element)) {
+                // Canonicalize the tag name
+                $tagName = strtolower($element);
+                // Store the tag as allowed with no attributes
+                $this->_tagsAllowed[$tagName] = array();
+            }
+            // Otherwise, if a tag was provided with attributes
+            else if (is_string($index) && (is_array($element) || is_string($element))) {
+                // Canonicalize the tag name
+                $tagName = strtolower($index);
+                // Canonicalize the attributes
+                if (is_string($element)) {
+                    $element = array($element);
+                }
+                // Store the tag as allowed with the provided attributes
+                $this->_tagsAllowed[$tagName] = array();
+                foreach ($element as $attribute) {
+                    if (is_string($attribute)) {
+                        // Canonicalize the attribute name
+                        $attributeName = strtolower($attribute);
+                        $this->_tagsAllowed[$tagName][$attributeName] = null;
+                    }
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the attributesAllowed option
+     *
+     * @return array
+     */
+    public function getAttributesAllowed()
+    {
+        return $this->_attributesAllowed;
+    }
+
+    /**
+     * Sets the attributesAllowed option
+     *
+     * @param  array|string $attributesAllowed
+     * @return Zend_Filter_StripTags Provides a fluent interface
+     */
+    public function setAttributesAllowed($attributesAllowed)
+    {
+        if (!is_array($attributesAllowed)) {
+            $attributesAllowed = array($attributesAllowed);
+        }
+
+        // Store each attribute as allowed
+        foreach ($attributesAllowed as $attribute) {
+            if (is_string($attribute)) {
+                // Canonicalize the attribute name
+                $attributeName = strtolower($attribute);
+                $this->_attributesAllowed[$attributeName] = null;
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * @todo improve docblock descriptions
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        $valueCopy = (string) $value;
+
+        // If comments are allowed, then replace them with unique identifiers
+        if ($this->commentsAllowed) {
+            preg_match_all('/<\!--.*?--\s*>/s' , (string) $valueCopy, $matches);
+            $comments = array_unique($matches[0]);
+            foreach ($comments as $k => $v) {
+                $valueCopy = str_replace($v, self::UNIQUE_ID_PREFIX . $k, $valueCopy);
+            }
+        }
+
+        // Initialize accumulator for filtered data
+        $dataFiltered = '';
+        // Parse the input data iteratively as regular pre-tag text followed by a
+        // tag; either may be empty strings
+        preg_match_all('/([^<]*)(<?[^>]*>?)/', (string) $valueCopy, $matches);
+        // Iterate over each set of matches
+        foreach ($matches[1] as $index => $preTag) {
+            // If the pre-tag text is non-empty, strip any ">" characters from it
+            if (strlen($preTag)) {
+                $preTag = str_replace('>', '', $preTag);
+            }
+            // If a tag exists in this match, then filter the tag
+            $tag = $matches[2][$index];
+            if (strlen($tag)) {
+                $tagFiltered = $this->_filterTag($tag);
+            } else {
+                $tagFiltered = '';
+            }
+            // Add the filtered pre-tag text and filtered tag to the data buffer
+            $dataFiltered .= $preTag . $tagFiltered;
+        }
+
+        // If comments are allowed, then replace the unique identifiers with the corresponding comments
+        if ($this->commentsAllowed) {
+            foreach ($comments as $k => $v) {
+                $dataFiltered = str_replace(self::UNIQUE_ID_PREFIX . $k, $v, $dataFiltered);
+            }
+        }
+
+        // Return the filtered data
+        return $dataFiltered;
+    }
+
+    /**
+     * Filters a single tag against the current option settings
+     *
+     * @param  string $tag
+     * @return string
+     */
+    protected function _filterTag($tag)
+    {
+        // Parse the tag into:
+        // 1. a starting delimiter (mandatory)
+        // 2. a tag name (if available)
+        // 3. a string of attributes (if available)
+        // 4. an ending delimiter (if available)
+        $isMatch = preg_match('~(</?)(\w*)((/(?!>)|[^/>])*)(/?>)~', $tag, $matches);
+
+        // If the tag does not match, then strip the tag entirely
+        if (!$isMatch) {
+            return '';
+        }
+
+        // Save the matches to more meaningfully named variables
+        $tagStart      = $matches[1];
+        $tagName       = strtolower($matches[2]);
+        $tagAttributes = $matches[3];
+        $tagEnd        = $matches[5];
+
+        // If the tag is not an allowed tag, then remove the tag entirely
+        if (!isset($this->_tagsAllowed[$tagName])) {
+            return '';
+        }
+
+        // Trim the attribute string of whitespace at the ends
+        $tagAttributes = trim($tagAttributes);
+
+        // If there are non-whitespace characters in the attribute string
+        if (strlen($tagAttributes)) {
+            // Parse iteratively for well-formed attributes
+            preg_match_all('/(\w+)\s*=\s*(?:(")(.*?)"|(\')(.*?)\')/s', $tagAttributes, $matches);
+
+            // Initialize valid attribute accumulator
+            $tagAttributes = '';
+
+            // Iterate over each matched attribute
+            foreach ($matches[1] as $index => $attributeName) {
+                $attributeName      = strtolower($attributeName);
+                $attributeDelimiter = $matches[2][$index];
+                $attributeValue     = $matches[3][$index];
+
+                // If the attribute is not allowed, then remove it entirely
+                if (!array_key_exists($attributeName, $this->_tagsAllowed[$tagName])
+                    && !array_key_exists($attributeName, $this->_attributesAllowed)) {
+                    continue;
+                }
+                // Add the attribute to the accumulator
+                $tagAttributes .= " $attributeName=" . $attributeDelimiter
+                                . $attributeValue . $attributeDelimiter;
+            }
+        }
+
+        // Reconstruct tags ending with "/>" as backwards-compatible XHTML tag
+        if (strpos($tagEnd, '/') !== false) {
+            $tagEnd = " $tagEnd";
+        }
+
+        // Return the filtered tag
+        return $tagStart . $tagName . $tagAttributes . $tagEnd;
+    }
+}
diff --git a/lib/Zend/Filter/Word/CamelCaseToDash.php b/lib/Zend/Filter/Word/CamelCaseToDash.php
new file mode 100644
index 0000000..c4717f2
--- /dev/null
+++ b/lib/Zend/Filter/Word/CamelCaseToDash.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToDash.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Word/CamelCaseToSeparator.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_CamelCaseToDash extends Zend_Filter_Word_CamelCaseToSeparator
+{
+    /**
+     * Constructor
+     * 
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct('-');
+    }
+}
diff --git a/lib/Zend/Filter/Word/CamelCaseToSeparator.php b/lib/Zend/Filter/Word/CamelCaseToSeparator.php
new file mode 100644
index 0000000..5dfa590
--- /dev/null
+++ b/lib/Zend/Filter/Word/CamelCaseToSeparator.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToSeparator.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/Word/Separator/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_CamelCaseToSeparator extends Zend_Filter_Word_Separator_Abstract
+{
+    
+    public function filter($value)
+    {
+        if (self::isUnicodeSupportEnabled()) {
+            parent::setMatchPattern(array('#(?<=(?:\p{Lu}))(\p{Lu}\p{Ll})#','#(?<=(?:\p{Ll}))(\p{Lu})#'));
+            parent::setReplacement(array($this->_separator . '\1', $this->_separator . '\1'));
+        } else {
+            parent::setMatchPattern(array('#(?<=(?:[A-Z]))([A-Z]+)([A-Z][A-z])#', '#(?<=(?:[a-z]))([A-Z])#'));
+            parent::setReplacement(array('\1' . $this->_separator . '\2', $this->_separator . '\1'));
+        }
+
+        return parent::filter($value);
+    }
+    
+}
diff --git a/lib/Zend/Filter/Word/CamelCaseToUnderscore.php b/lib/Zend/Filter/Word/CamelCaseToUnderscore.php
new file mode 100644
index 0000000..659dfb4
--- /dev/null
+++ b/lib/Zend/Filter/Word/CamelCaseToUnderscore.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToUnderscore.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_CamelCaseToSeparator
+ */
+require_once 'Zend/Filter/Word/CamelCaseToSeparator.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_CamelCaseToUnderscore extends Zend_Filter_Word_CamelCaseToSeparator
+{
+    /**
+     * Constructor
+     * 
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct('_');
+    }
+}
diff --git a/lib/Zend/Filter/Word/DashToCamelCase.php b/lib/Zend/Filter/Word/DashToCamelCase.php
new file mode 100644
index 0000000..a1ab8e7
--- /dev/null
+++ b/lib/Zend/Filter/Word/DashToCamelCase.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToDash.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Word/SeparatorToCamelCase.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_DashToCamelCase extends Zend_Filter_Word_SeparatorToCamelCase
+{
+    /**
+     * Constructor
+     * 
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct('-');
+    }
+}
diff --git a/lib/Zend/Filter/Word/DashToSeparator.php b/lib/Zend/Filter/Word/DashToSeparator.php
new file mode 100644
index 0000000..884ba1a
--- /dev/null
+++ b/lib/Zend/Filter/Word/DashToSeparator.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToSeparator.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/Word/Separator/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_DashToSeparator extends Zend_Filter_Word_Separator_Abstract
+{
+
+    public function filter($value)
+    {
+        $this->setMatchPattern('#-#');
+        $this->setReplacement($this->_separator);
+        return parent::filter($value);
+    }
+}
diff --git a/lib/Zend/Filter/Word/DashToUnderscore.php b/lib/Zend/Filter/Word/DashToUnderscore.php
new file mode 100644
index 0000000..404598a
--- /dev/null
+++ b/lib/Zend/Filter/Word/DashToUnderscore.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToSeparator.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/Word/SeparatorToSeparator.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_DashToUnderscore extends Zend_Filter_Word_SeparatorToSeparator 
+{
+    /**
+     * Constructor
+     * 
+     * @param  string $separator Space by default
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct('-', '_');
+    }
+}
\ No newline at end of file
diff --git a/lib/Zend/Filter/Word/Separator/Abstract.php b/lib/Zend/Filter/Word/Separator/Abstract.php
new file mode 100644
index 0000000..b33b96b
--- /dev/null
+++ b/lib/Zend/Filter/Word/Separator/Abstract.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToUnderscore.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/PregReplace.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @uses       Zend_Filter_PregReplace
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Filter_Word_Separator_Abstract extends Zend_Filter_PregReplace
+{
+
+    protected $_separator = null;
+
+    /**
+     * Constructor
+     * 
+     * @param  string $separator Space by default
+     * @return void
+     */
+    public function __construct($separator = ' ')
+    {
+        $this->setSeparator($separator);
+    }
+
+    /**
+     * Sets a new seperator
+     * 
+     * @param  string  $separator  Seperator
+     * @return $this
+     */
+    public function setSeparator($separator)
+    {
+        if ($separator == null) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('"' . $separator . '" is not a valid separator.');
+        }
+        $this->_separator = $separator;
+        return $this;
+    }
+
+    /**
+     * Returns the actual set seperator
+     * 
+     * @return  string
+     */
+    public function getSeparator()
+    {
+        return $this->_separator;
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Filter/Word/SeparatorToCamelCase.php b/lib/Zend/Filter/Word/SeparatorToCamelCase.php
new file mode 100644
index 0000000..853ec1b
--- /dev/null
+++ b/lib/Zend/Filter/Word/SeparatorToCamelCase.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToSeparator.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/Word/Separator/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_SeparatorToCamelCase extends Zend_Filter_Word_Separator_Abstract
+{
+
+    public function filter($value)
+    {
+        // a unicode safe way of converting characters to \x00\x00 notation
+        $pregQuotedSeparator = preg_quote($this->_separator, '#');
+
+        if (self::isUnicodeSupportEnabled()) {
+            parent::setMatchPattern(array('#('.$pregQuotedSeparator.')(\p{L}{1})#e','#(^\p{Ll}{1})#e'));
+            parent::setReplacement(array("strtoupper('\\2')","strtoupper('\\1')"));
+        } else {
+            parent::setMatchPattern(array('#('.$pregQuotedSeparator.')([A-Z]{1})#e','#(^[a-z]{1})#e'));
+            parent::setReplacement(array("strtoupper('\\2')","strtoupper('\\1')"));
+        }
+
+        return parent::filter($value);
+    }
+
+}
diff --git a/lib/Zend/Filter/Word/SeparatorToDash.php b/lib/Zend/Filter/Word/SeparatorToDash.php
new file mode 100644
index 0000000..d5eab06
--- /dev/null
+++ b/lib/Zend/Filter/Word/SeparatorToDash.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToUnderscore.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_SeperatorToSeparator
+ */
+require_once 'Zend/Filter/Word/SeparatorToSeparator.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_SeparatorToDash extends Zend_Filter_Word_SeparatorToSeparator
+{
+    /**
+     * Constructor
+     * 
+     * @param  string  $searchSeparator  Seperator to search for change
+     * @return void
+     */
+    public function __construct($searchSeparator = ' ')
+    {
+        parent::__construct($searchSeparator, '-');
+    }
+    
+}
\ No newline at end of file
diff --git a/lib/Zend/Filter/Word/SeparatorToSeparator.php b/lib/Zend/Filter/Word/SeparatorToSeparator.php
new file mode 100644
index 0000000..e70aaf3
--- /dev/null
+++ b/lib/Zend/Filter/Word/SeparatorToSeparator.php
@@ -0,0 +1,129 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToUnderscore.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/PregReplace.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_SeparatorToSeparator extends Zend_Filter_PregReplace
+{
+
+    protected $_searchSeparator = null;
+    protected $_replacementSeparator = null;
+
+    /**
+     * Constructor
+     * 
+     * @param  string  $searchSeparator      Seperator to search for
+     * @param  string  $replacementSeperator Seperator to replace with
+     * @return void
+     */
+    public function __construct($searchSeparator = ' ', $replacementSeparator = '-')
+    {
+        $this->setSearchSeparator($searchSeparator);
+        $this->setReplacementSeparator($replacementSeparator);
+    }
+
+    /**
+     * Sets a new seperator to search for
+     * 
+     * @param  string  $separator  Seperator to search for
+     * @return $this
+     */
+    public function setSearchSeparator($separator)
+    {
+        $this->_searchSeparator = $separator;
+        return $this;
+    }
+
+    /**
+     * Returns the actual set seperator to search for
+     * 
+     * @return  string
+     */
+    public function getSearchSeparator()
+    {
+        return $this->_searchSeparator;
+    }
+
+    /**
+     * Sets a new seperator which replaces the searched one
+     * 
+     * @param  string  $separator  Seperator which replaces the searched one
+     * @return $this
+     */
+    public function setReplacementSeparator($separator)
+    {
+        $this->_replacementSeparator = $separator;
+        return $this;
+    }
+
+    /**
+     * Returns the actual set seperator which replaces the searched one
+     * 
+     * @return  string
+     */
+    public function getReplacementSeparator()
+    {
+        return $this->_replacementSeparator;
+    }
+
+    /**
+     * Defined by Zend_Filter_Interface
+     *
+     * Returns the string $value, replacing the searched seperators with the defined ones
+     *
+     * @param  string $value
+     * @return string
+     */
+    public function filter($value)
+    {
+        return $this->_separatorToSeparatorFilter($value);
+    }
+
+    /**
+     * Do the real work, replaces the seperator to search for with the replacement seperator
+     *
+     * Returns the replaced string
+     *
+     * @param  string $value
+     * @return string
+     */
+    protected function _separatorToSeparatorFilter($value)
+    {
+        if ($this->_searchSeparator == null) {
+            require_once 'Zend/Filter/Exception.php';
+            throw new Zend_Filter_Exception('You must provide a search separator for this filter to work.');
+        }
+
+        $this->setMatchPattern('#' . preg_quote($this->_searchSeparator, '#') . '#');
+        $this->setReplacement($this->_replacementSeparator);
+        return parent::filter($value);
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Filter/Word/UnderscoreToCamelCase.php b/lib/Zend/Filter/Word/UnderscoreToCamelCase.php
new file mode 100644
index 0000000..aabbba9
--- /dev/null
+++ b/lib/Zend/Filter/Word/UnderscoreToCamelCase.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToDash.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_Interface
+ */
+require_once 'Zend/Filter/Word/SeparatorToCamelCase.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_UnderscoreToCamelCase extends Zend_Filter_Word_SeparatorToCamelCase
+{
+    /**
+     * Constructor
+     * 
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct('_');
+    }
+}
diff --git a/lib/Zend/Filter/Word/UnderscoreToDash.php b/lib/Zend/Filter/Word/UnderscoreToDash.php
new file mode 100644
index 0000000..43326c4
--- /dev/null
+++ b/lib/Zend/Filter/Word/UnderscoreToDash.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToSeparator.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/Word/SeparatorToSeparator.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_UnderscoreToDash extends Zend_Filter_Word_SeparatorToSeparator
+{
+    /**
+     * Constructor
+     * 
+     * @param  string $separator Space by default
+     * @return void
+     */
+    public function __construct()
+    {
+        parent::__construct('_', '-');
+    }
+}
\ No newline at end of file
diff --git a/lib/Zend/Filter/Word/UnderscoreToSeparator.php b/lib/Zend/Filter/Word/UnderscoreToSeparator.php
new file mode 100644
index 0000000..3fba924
--- /dev/null
+++ b/lib/Zend/Filter/Word/UnderscoreToSeparator.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: UnderscoreToPathSeparator.php 6793 2007-11-09 18:10:06Z matthew $
+ */
+
+/**
+ * @see Zend_Filter_PregReplace
+ */
+require_once 'Zend/Filter/Word/SeparatorToSeparator.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Filter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Filter_Word_UnderscoreToSeparator extends Zend_Filter_Word_SeparatorToSeparator
+{
+    /**
+     * Constructor
+     * 
+     * @param  string $separator Space by default
+     * @return void
+     */
+    public function __construct($replacementSeparator = ' ')
+    {
+        parent::__construct('_', $replacementSeparator);
+    }
+}
diff --git a/lib/Zend/Loader.php b/lib/Zend/Loader.php
new file mode 100644
index 0000000..3d962a5
--- /dev/null
+++ b/lib/Zend/Loader.php
@@ -0,0 +1,263 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Loader.php 12507 2008-11-10 16:29:09Z matthew $
+ */
+
+/**
+ * Static methods for loading classes and files.
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Loader
+{
+    /**
+     * Loads a class from a PHP file.  The filename must be formatted
+     * as "$class.php".
+     *
+     * If $dirs is a string or an array, it will search the directories
+     * in the order supplied, and attempt to load the first matching file.
+     *
+     * If $dirs is null, it will split the class name at underscores to
+     * generate a path hierarchy (e.g., "Zend_Example_Class" will map
+     * to "Zend/Example/Class.php").
+     *
+     * If the file was not found in the $dirs, or if no $dirs were specified,
+     * it will attempt to load it from PHP's include_path.
+     *
+     * @param string $class      - The full class name of a Zend component.
+     * @param string|array $dirs - OPTIONAL Either a path or an array of paths
+     *                             to search.
+     * @return void
+     * @throws Zend_Exception
+     */
+    public static function loadClass($class, $dirs = null)
+    {
+        if (class_exists($class, false) || interface_exists($class, false)) {
+            return;
+        }
+
+        if ((null !== $dirs) && !is_string($dirs) && !is_array($dirs)) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception('Directory argument must be a string or an array');
+        }
+
+        // autodiscover the path from the class name
+        $file = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
+        if (!empty($dirs)) {
+            // use the autodiscovered path
+            $dirPath = dirname($file);
+            if (is_string($dirs)) {
+                $dirs = explode(PATH_SEPARATOR, $dirs);
+            }
+            foreach ($dirs as $key => $dir) {
+                if ($dir == '.') {
+                    $dirs[$key] = $dirPath;
+                } else {
+                    $dir = rtrim($dir, '\\/');
+                    $dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath;
+                }
+            }
+            $file = basename($file);
+            self::loadFile($file, $dirs, true);
+        } else {
+            self::_securityCheck($file);
+            include_once $file;
+        }
+
+        if (!class_exists($class, false) && !interface_exists($class, false)) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception("File \"$file\" does not exist or class \"$class\" was not found in the file");
+        }
+    }
+
+    /**
+     * Loads a PHP file.  This is a wrapper for PHP's include() function.
+     *
+     * $filename must be the complete filename, including any
+     * extension such as ".php".  Note that a security check is performed that
+     * does not permit extended characters in the filename.  This method is
+     * intended for loading Zend Framework files.
+     *
+     * If $dirs is a string or an array, it will search the directories
+     * in the order supplied, and attempt to load the first matching file.
+     *
+     * If the file was not found in the $dirs, or if no $dirs were specified,
+     * it will attempt to load it from PHP's include_path.
+     *
+     * If $once is TRUE, it will use include_once() instead of include().
+     *
+     * @param  string        $filename
+     * @param  string|array  $dirs - OPTIONAL either a path or array of paths
+     *                       to search.
+     * @param  boolean       $once
+     * @return boolean
+     * @throws Zend_Exception
+     */
+    public static function loadFile($filename, $dirs = null, $once = false)
+    {
+        self::_securityCheck($filename);
+
+        /**
+         * Search in provided directories, as well as include_path
+         */
+        $incPath = false;
+        if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) {
+            if (is_array($dirs)) {
+                $dirs = implode(PATH_SEPARATOR, $dirs);
+            }
+            $incPath = get_include_path();
+            set_include_path($dirs . PATH_SEPARATOR . $incPath);
+        }
+
+        /**
+         * Try finding for the plain filename in the include_path.
+         */
+        if ($once) {
+            include_once $filename;
+        } else {
+            include $filename;
+        }
+
+        /**
+         * If searching in directories, reset include_path
+         */
+        if ($incPath) {
+            set_include_path($incPath);
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns TRUE if the $filename is readable, or FALSE otherwise.
+     * This function uses the PHP include_path, where PHP's is_readable()
+     * does not.
+     *
+     * Note from ZF-2900:
+     * If you use custom error handler, please check whether return value
+     *  from error_reporting() is zero or not.
+     * At mark of fopen() can not suppress warning if the handler is used.
+     *
+     * @param string   $filename
+     * @return boolean
+     */
+    public static function isReadable($filename)
+    {
+        if (!$fh = @fopen($filename, 'r', true)) {
+            return false;
+        }
+        @fclose($fh);
+        return true;
+    }
+
+    /**
+     * spl_autoload() suitable implementation for supporting class autoloading.
+     *
+     * Attach to spl_autoload() using the following:
+     * <code>
+     * spl_autoload_register(array('Zend_Loader', 'autoload'));
+     * </code>
+     *
+     * @param string $class
+     * @return string|false Class name on success; false on failure
+     */
+    public static function autoload($class)
+    {
+        try {
+            self::loadClass($class);
+            return $class;
+        } catch (Exception $e) {
+            return false;
+        }
+    }
+
+    /**
+     * Register {@link autoload()} with spl_autoload()
+     *
+     * @param string $class (optional)
+     * @param boolean $enabled (optional)
+     * @return void
+     * @throws Zend_Exception if spl_autoload() is not found
+     * or if the specified class does not have an autoload() method.
+     */
+    public static function registerAutoload($class = 'Zend_Loader', $enabled = true)
+    {
+        if (!function_exists('spl_autoload_register')) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception('spl_autoload does not exist in this PHP installation');
+        }
+
+        self::loadClass($class);
+        $methods = get_class_methods($class);
+        if (!in_array('autoload', (array) $methods)) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
+        }
+
+        if ($enabled === true) {
+            spl_autoload_register(array($class, 'autoload'));
+        } else {
+            spl_autoload_unregister(array($class, 'autoload'));
+        }
+    }
+
+    /**
+     * Ensure that filename does not contain exploits
+     *
+     * @param  string $filename
+     * @return void
+     * @throws Zend_Exception
+     */
+    protected static function _securityCheck($filename)
+    {
+        /**
+         * Security check
+         */
+        if (preg_match('/[^a-z0-9\\/\\\\_.-]/i', $filename)) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception('Security check: Illegal character in filename');
+        }
+    }
+
+    /**
+     * Attempt to include() the file.
+     *
+     * include() is not prefixed with the @ operator because if
+     * the file is loaded and contains a parse error, execution
+     * will halt silently and this is difficult to debug.
+     *
+     * Always set display_errors = Off on production servers!
+     *
+     * @param  string  $filespec
+     * @param  boolean $once
+     * @return boolean
+     * @deprecated Since 1.5.0; use loadFile() instead
+     */
+    protected static function _includeFile($filespec, $once = false)
+    {
+        if ($once) {
+            return include_once $filespec;
+        } else {
+            return include $filespec ;
+        }
+    }
+}
diff --git a/lib/Zend/Loader/Exception.php b/lib/Zend/Loader/Exception.php
new file mode 100644
index 0000000..2c0e1e4
--- /dev/null
+++ b/lib/Zend/Loader/Exception.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: CamelCaseToUnderscore.php 6779 2007-11-08 15:10:41Z matthew $
+ */
+
+/**
+ * @see Zend_Exception
+ */
+require_once 'Zend/Exception.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Loader
+ * @uses       Zend_Exception
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Loader_Exception extends Zend_Exception 
+{}
\ No newline at end of file
diff --git a/lib/Zend/Loader/PluginLoader.php b/lib/Zend/Loader/PluginLoader.php
new file mode 100644
index 0000000..c1bd989
--- /dev/null
+++ b/lib/Zend/Loader/PluginLoader.php
@@ -0,0 +1,464 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @subpackage PluginLoader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/** Zend_Loader_PluginLoader_Interface */
+require_once 'Zend/Loader/PluginLoader/Interface.php';
+
+/** Zend_Loader */
+require_once 'Zend/Loader.php';
+
+/**
+ * Generic plugin class loader
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @subpackage PluginLoader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Loader_PluginLoader implements Zend_Loader_PluginLoader_Interface
+{
+    /**
+     * Class map cache file
+     * @var string
+     */
+    protected static $_includeFileCache;
+
+    /**
+     * Instance loaded plugin paths
+     *
+     * @var array
+     */
+    protected $_loadedPluginPaths = array();
+
+    /**
+     * Instance loaded plugins
+     *
+     * @var array
+     */
+    protected $_loadedPlugins = array();
+
+    /**
+     * Instance registry property
+     *
+     * @var array
+     */
+    protected $_prefixToPaths = array();
+
+    /**
+     * Statically loaded plugin path mappings
+     *
+     * @var array
+     */
+    protected static $_staticLoadedPluginPaths = array();
+
+    /**
+     * Statically loaded plugins
+     *
+     * @var array
+     */
+    protected static $_staticLoadedPlugins = array();
+
+    /**
+     * Static registry property
+     *
+     * @var array
+     */
+    protected static $_staticPrefixToPaths = array();
+
+    /**
+     * Whether to use a statically named registry for loading plugins
+     *
+     * @var string|null
+     */
+    protected $_useStaticRegistry = null;
+
+    /**
+     * Constructor
+     *
+     * @param array $prefixToPaths
+     * @param string $staticRegistryName OPTIONAL
+     */
+    public function __construct(Array $prefixToPaths = array(), $staticRegistryName = null)
+    {
+        if (is_string($staticRegistryName) && !empty($staticRegistryName)) {
+            $this->_useStaticRegistry = $staticRegistryName;
+            if(!isset(self::$_staticPrefixToPaths[$staticRegistryName])) {
+                self::$_staticPrefixToPaths[$staticRegistryName] = array();
+            }
+            if(!isset(self::$_staticLoadedPlugins[$staticRegistryName])) {
+                self::$_staticLoadedPlugins[$staticRegistryName] = array();
+            }
+        }
+
+        foreach ($prefixToPaths as $prefix => $path) {
+            $this->addPrefixPath($prefix, $path);
+        }
+    }
+
+    /**
+     * Format prefix for internal use
+     *
+     * @param  string $prefix
+     * @return string
+     */
+    protected function _formatPrefix($prefix)
+    {
+        return rtrim($prefix, '_') . '_';
+    }
+
+    /**
+     * Add prefixed paths to the registry of paths
+     *
+     * @param string $prefix
+     * @param string $path
+     * @return Zend_Loader_PluginLoader
+     */
+    public function addPrefixPath($prefix, $path)
+    {
+        if (!is_string($prefix) || !is_string($path)) {
+            require_once 'Zend/Loader/PluginLoader/Exception.php';
+            throw new Zend_Loader_PluginLoader_Exception('Zend_Loader_PluginLoader::addPrefixPath() method only takes strings for prefix and path.');
+        }
+
+        $prefix = $this->_formatPrefix($prefix);
+        $path   = rtrim($path, '/\\') . '/';
+
+        if ($this->_useStaticRegistry) {
+            self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix][] = $path;
+        } else {
+            $this->_prefixToPaths[$prefix][] = $path;
+        }
+        return $this;
+    }
+
+    /**
+     * Get path stack
+     *
+     * @param  string $prefix
+     * @return false|array False if prefix does not exist, array otherwise
+     */
+    public function getPaths($prefix = null)
+    {
+        if ((null !== $prefix) && is_string($prefix)) {
+            $prefix = $this->_formatPrefix($prefix);
+            if ($this->_useStaticRegistry) {
+                if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) {
+                    return self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix];
+                }
+
+                return false;
+            }
+
+            if (isset($this->_prefixToPaths[$prefix])) {
+                return $this->_prefixToPaths[$prefix];
+            }
+
+            return false;
+        }
+
+        if ($this->_useStaticRegistry) {
+            return self::$_staticPrefixToPaths[$this->_useStaticRegistry];
+        }
+
+        return $this->_prefixToPaths;
+    }
+
+    /**
+     * Clear path stack
+     *
+     * @param  string $prefix
+     * @return bool False only if $prefix does not exist
+     */
+    public function clearPaths($prefix = null)
+    {
+        if ((null !== $prefix) && is_string($prefix)) {
+            $prefix = $this->_formatPrefix($prefix);
+            if ($this->_useStaticRegistry) {
+                if (isset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix])) {
+                    unset(self::$_staticPrefixToPaths[$this->_useStaticRegistry][$prefix]);
+                    return true;
+                }
+
+                return false;
+            }
+
+            if (isset($this->_prefixToPaths[$prefix])) {
+                unset($this->_prefixToPaths[$prefix]);
+                return true;
+            }
+
+            return false;
+        }
+
+        if ($this->_useStaticRegistry) {
+            self::$_staticPrefixToPaths[$this->_useStaticRegistry] = array();
+        } else {
+            $this->_prefixToPaths = array();
+        }
+
+        return true;
+    }
+
+    /**
+     * Remove a prefix (or prefixed-path) from the registry
+     *
+     * @param string $prefix
+     * @param string $path OPTIONAL
+     * @return Zend_Loader_PluginLoader
+     */
+    public function removePrefixPath($prefix, $path = null)
+    {
+        $prefix = $this->_formatPrefix($prefix);
+        if ($this->_useStaticRegistry) {
+            $registry =& self::$_staticPrefixToPaths[$this->_useStaticRegistry];
+        } else {
+            $registry =& $this->_prefixToPaths;
+        }
+
+        if (!isset($registry[$prefix])) {
+            require_once 'Zend/Loader/PluginLoader/Exception.php';
+            throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' was not found in the PluginLoader.');
+        }
+
+        if ($path != null) {
+            $pos = array_search($path, $registry[$prefix]);
+            if ($pos === null) {
+                require_once 'Zend/Loader/PluginLoader/Exception.php';
+                throw new Zend_Loader_PluginLoader_Exception('Prefix ' . $prefix . ' / Path ' . $path . ' was not found in the PluginLoader.');
+            }
+            unset($registry[$prefix][$pos]);
+        } else {
+            unset($registry[$prefix]);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Normalize plugin name
+     *
+     * @param  string $name
+     * @return string
+     */
+    protected function _formatName($name)
+    {
+        return ucfirst((string) $name);
+    }
+
+    /**
+     * Whether or not a Plugin by a specific name is loaded
+     *
+     * @param string $name
+     * @return Zend_Loader_PluginLoader
+     */
+    public function isLoaded($name)
+    {
+        $name = $this->_formatName($name);
+        if ($this->_useStaticRegistry) {
+            return isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]);
+        }
+
+        return isset($this->_loadedPlugins[$name]);
+    }
+
+    /**
+     * Return full class name for a named plugin
+     *
+     * @param string $name
+     * @return string|false False if class not found, class name otherwise
+     */
+    public function getClassName($name)
+    {
+        $name = $this->_formatName($name);
+        if ($this->_useStaticRegistry 
+            && isset(self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name])
+        ) {
+            return self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name];
+        } elseif (isset($this->_loadedPlugins[$name])) {
+            return $this->_loadedPlugins[$name];
+        }
+
+        return false;
+    }
+
+    /**
+     * Get path to plugin class
+     * 
+     * @param  mixed $name 
+     * @return string|false False if not found
+     */
+    public function getClassPath($name)
+    {
+        $name = $this->_formatName($name);
+        if ($this->_useStaticRegistry 
+            && !empty(self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name])
+        ) {
+            return self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name];
+        } elseif (!empty($this->_loadedPluginPaths[$name])) {
+            return $this->_loadedPluginPaths[$name];
+        }
+
+        if ($this->isLoaded($name)) {
+            $class = $this->getClassName($name);
+            $r     = new ReflectionClass($class);
+            $path  = $r->getFileName();
+            if ($this->_useStaticRegistry) {
+                self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name] = $path;
+            } else {
+                $this->_loadedPluginPaths[$name] = $path;
+            }
+            return $path;
+        }
+
+        return false;
+    }
+
+    /**
+     * Load a plugin via the name provided
+     *
+     * @param  string $name
+     * @return string Class name of loaded class
+     * @throws Zend_Loader_Exception if class not found
+     */
+    public function load($name)
+    {
+        $name = $this->_formatName($name);
+        if ($this->isLoaded($name)) {
+            return $this->getClassName($name);
+        }
+
+        if ($this->_useStaticRegistry) {
+            $registry = self::$_staticPrefixToPaths[$this->_useStaticRegistry];
+        } else {
+            $registry = $this->_prefixToPaths;
+        }
+
+        $registry  = array_reverse($registry, true);
+        $found     = false;
+        $classFile = str_replace('_', DIRECTORY_SEPARATOR, $name) . '.php';
+        $incFile   = self::getIncludeFileCache();
+        foreach ($registry as $prefix => $paths) {
+            $className = $prefix . $name;
+
+            if (class_exists($className, false)) {
+                $found = true;
+                break;
+            }
+
+            $paths     = array_reverse($paths, true);
+
+            foreach ($paths as $path) {
+                $loadFile = $path . $classFile;
+                if (Zend_Loader::isReadable($loadFile)) {
+                    include_once $loadFile;
+                    if (class_exists($className, false)) {
+                        if (null !== $incFile) {
+                            self::_appendIncFile($loadFile);
+                        }
+                        $found = true;
+                        break 2;
+                    }
+                }
+            }
+        }
+
+        if (!$found) {
+            $message = "Plugin by name '$name' was not found in the registry; used paths:";
+            foreach ($registry as $prefix => $paths) {
+                $message .= "\n$prefix: " . implode(PATH_SEPARATOR, $paths);
+            }
+            require_once 'Zend/Loader/PluginLoader/Exception.php';
+            throw new Zend_Loader_PluginLoader_Exception($message);
+       }
+
+        if ($this->_useStaticRegistry) {
+            self::$_staticLoadedPlugins[$this->_useStaticRegistry][$name]     = $className;
+            self::$_staticLoadedPluginPaths[$this->_useStaticRegistry][$name] = (isset($loadFile) ? $loadFile : '');
+        } else {
+            $this->_loadedPlugins[$name]     = $className;
+            $this->_loadedPluginPaths[$name] = (isset($loadFile) ? $loadFile : '');
+        }
+        return $className;
+    }
+
+    /**
+     * Set path to class file cache
+     *
+     * Specify a path to a file that will add include_once statements for each 
+     * plugin class loaded. This is an opt-in feature for performance purposes.
+     * 
+     * @param  string $file 
+     * @return void
+     * @throws Zend_Loader_PluginLoader_Exception if file is not writeable or path does not exist
+     */
+    public static function setIncludeFileCache($file)
+    {
+        if (null === $file) {
+            self::$_includeFileCache = null;
+            return;
+        }
+
+        if (!file_exists($file) && !file_exists(dirname($file))) {
+            require_once 'Zend/Loader/PluginLoader/Exception.php';
+            throw new Zend_Loader_PluginLoader_Exception('Specified file does not exist and/or directory does not exist (' . $file . ')');
+        }
+        if (file_exists($file) && !is_writable($file)) {
+            require_once 'Zend/Loader/PluginLoader/Exception.php';
+            throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')');
+        }
+        if (!file_exists($file) && file_exists(dirname($file)) && !is_writable(dirname($file))) {
+            require_once 'Zend/Loader/PluginLoader/Exception.php';
+            throw new Zend_Loader_PluginLoader_Exception('Specified file is not writeable (' . $file . ')');
+        }
+
+        self::$_includeFileCache = $file;
+    }
+
+    /**
+     * Retrieve class file cache path
+     * 
+     * @return string|null
+     */
+    public static function getIncludeFileCache()
+    {
+        return self::$_includeFileCache;
+    }
+
+    /**
+     * Append an include_once statement to the class file cache
+     * 
+     * @param  string $incFile 
+     * @return void
+     */
+    protected static function _appendIncFile($incFile)
+    {
+        if (!file_exists(self::$_includeFileCache)) {
+            $file = '<?php';
+        } else {
+            $file = file_get_contents(self::$_includeFileCache);
+        }
+        if (!strstr($file, $incFile)) {
+            $file .= "\ninclude_once '$incFile';";
+            file_put_contents(self::$_includeFileCache, $file);
+        }
+    }
+}
diff --git a/lib/Zend/Loader/PluginLoader/Exception.php b/lib/Zend/Loader/PluginLoader/Exception.php
new file mode 100644
index 0000000..60b53a4
--- /dev/null
+++ b/lib/Zend/Loader/PluginLoader/Exception.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @subpackage PluginLoader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * @see Zend_Loader_Exception
+ */
+require_once 'Zend/Loader/Exception.php';
+
+/**
+ * Plugin class loader exceptions
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @subpackage PluginLoader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Loader_PluginLoader_Exception extends Zend_Loader_Exception
+{
+}
diff --git a/lib/Zend/Loader/PluginLoader/Interface.php b/lib/Zend/Loader/PluginLoader/Interface.php
new file mode 100644
index 0000000..50f34aa
--- /dev/null
+++ b/lib/Zend/Loader/PluginLoader/Interface.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @subpackage PluginLoader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Plugin class loader interface
+ *
+ * @category   Zend
+ * @package    Zend_Loader
+ * @subpackage PluginLoader
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Loader_PluginLoader_Interface
+{
+    /**
+     * Add prefixed paths to the registry of paths
+     *
+     * @param string $prefix
+     * @param string $path
+     * @return Zend_Loader_PluginLoader
+     */
+    public function addPrefixPath($prefix, $path);
+    
+    /**
+     * Remove a prefix (or prefixed-path) from the registry
+     *
+     * @param string $prefix
+     * @param string $path OPTIONAL
+     * @return Zend_Loader_PluginLoader
+     */
+    public function removePrefixPath($prefix, $path = null);
+    
+    /**
+     * Whether or not a Helper by a specific name
+     *
+     * @param string $name
+     * @return Zend_Loader_PluginLoader
+     */
+    public function isLoaded($name);
+
+    /**
+     * Return full class name for a named helper
+     *
+     * @param string $name
+     * @return string
+     */
+    public function getClassName($name);
+    
+    /**
+     * Load a helper via the name provided
+     *
+     * @param string $name
+     * @return string
+     */
+    public function load($name);
+}
diff --git a/lib/Zend/Mail.php b/lib/Zend/Mail.php
new file mode 100644
index 0000000..5364f22
--- /dev/null
+++ b/lib/Zend/Mail.php
@@ -0,0 +1,1042 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Mail.php 14071 2009-02-12 22:22:43Z beberlei $
+ */
+
+
+/**
+ * @see Zend_Mail_Transport_Abstract
+ */
+require_once 'Zend/Mail/Transport/Abstract.php';
+
+/**
+ * @see Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+/**
+ * @see Zend_Mime_Message
+ */
+require_once 'Zend/Mime/Message.php';
+
+/**
+ * @see Zend_Mime_Part
+ */
+require_once 'Zend/Mime/Part.php';
+
+
+/**
+ * Class for sending an email.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail extends Zend_Mime_Message
+{
+    /**#@+
+     * @access protected
+     */
+
+    /**
+     * @var Zend_Mail_Transport_Abstract
+     * @static
+     */
+    protected static $_defaultTransport = null;
+
+    /**
+     * Mail character set
+     * @var string
+     */
+    protected $_charset = null;
+
+    /**
+     * Mail headers
+     * @var array
+     */
+    protected $_headers = array();
+
+    /**
+     * Encoding of Mail headers
+     * @var string
+     */
+    protected $_headerEncoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE;
+
+    /**
+     * From: address
+     * @var string
+     */
+    protected $_from = null;
+
+    /**
+     * To: addresses
+     * @var array
+     */
+    protected $_to = array();
+
+    /**
+     * Array of all recipients
+     * @var array
+     */
+    protected $_recipients = array();
+
+    /**
+     * Return-Path header
+     * @var string
+     */
+    protected $_returnPath = null;
+
+    /**
+     * Subject: header
+     * @var string
+     */
+    protected $_subject = null;
+
+    /**
+     * Date: header
+     * @var string
+     */
+    protected $_date = null;
+
+    /**
+     * Message-ID: header
+     * @var string
+     */
+    protected $_messageId = null;
+
+    /**
+     * text/plain MIME part
+     * @var false|Zend_Mime_Part
+     */
+    protected $_bodyText = false;
+
+    /**
+     * text/html MIME part
+     * @var false|Zend_Mime_Part
+     */
+    protected $_bodyHtml = false;
+
+    /**
+     * MIME boundary string
+     * @var string
+     */
+    protected $_mimeBoundary = null;
+
+    /**
+     * Content type of the message
+     * @var string
+     */
+    protected $_type = null;
+
+    /**#@-*/
+
+    /**
+     * Flag: whether or not email has attachments
+     * @var boolean
+     */
+    public $hasAttachments = false;
+
+
+    /**
+     * Sets the default mail transport for all following uses of
+     * Zend_Mail::send();
+     *
+     * @todo Allow passing a string to indicate the transport to load
+     * @todo Allow passing in optional options for the transport to load
+     * @param  Zend_Mail_Transport_Abstract $transport
+     */
+    public static function setDefaultTransport(Zend_Mail_Transport_Abstract $transport)
+    {
+        self::$_defaultTransport = $transport;
+    }
+
+    /**
+     * Public constructor
+     *
+     * @param string $charset
+     */
+    public function __construct($charset = 'iso-8859-1')
+    {
+        $this->_charset = $charset;
+    }
+
+    /**
+     * Return charset string
+     *
+     * @return string
+     */
+    public function getCharset()
+    {
+        return $this->_charset;
+    }
+
+    /**
+     * Set content type
+     *
+     * Should only be used for manually setting multipart content types.
+     *
+     * @param  string $type Content type
+     * @return Zend_Mail Implements fluent interface
+     * @throws Zend_Mail_Exception for types not supported by Zend_Mime
+     */
+    public function setType($type)
+    {
+        $allowed = array(
+            Zend_Mime::MULTIPART_ALTERNATIVE,
+            Zend_Mime::MULTIPART_MIXED,
+            Zend_Mime::MULTIPART_RELATED,
+        );
+        if (!in_array($type, $allowed)) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Invalid content type "' . $type . '"');
+        }
+
+        $this->_type = $type;
+        return $this;
+    }
+
+    /**
+     * Get content type of the message
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        return $this->_type;
+    }
+
+    /**
+     * Set an arbitrary mime boundary for the message
+     *
+     * If not set, Zend_Mime will generate one.
+     *
+     * @param  string    $boundary
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function setMimeBoundary($boundary)
+    {
+        $this->_mimeBoundary = $boundary;
+
+        return $this;
+    }
+
+    /**
+     * Return the boundary string used for the message
+     *
+     * @return string
+     */
+    public function getMimeBoundary()
+    {
+        return $this->_mimeBoundary;
+    }
+
+    /**
+     * Return encoding of mail headers
+     *
+     * @deprecated use {@link getHeaderEncoding()} instead
+     * @return <type>
+     */
+    public function getEncodingOfHeaders()
+    {
+        return $this->getHeaderEncoding();
+    }
+
+    /**
+     * Return the encoding of mail headers
+     *
+     * Either Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64
+     *
+     * @return string
+     */
+    public function getHeaderEncoding()
+    {
+        return $this->_headerEncoding;
+    }
+
+    /**
+     * Set the encoding of mail headers
+     *
+     * @deprecated Use {@link setHeaderEncoding()} instead.
+     * @param  string $encoding
+     * @return Zend_Mail
+     */
+    public function setEncodingOfHeaders($encoding)
+    {
+        return $this->setHeaderEncoding($encoding);
+    }
+
+    /**
+     * Set the encoding of mail headers
+     *
+     * @param  string $encoding Zend_Mime::ENCODING_QUOTEDPRINTABLE or Zend_Mime::ENCODING_BASE64
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function setHeaderEncoding($encoding)
+    {
+        $allowed = array(
+            Zend_Mime::ENCODING_BASE64,
+            Zend_Mime::ENCODING_QUOTEDPRINTABLE
+        );
+        if (!in_array($encoding, $allowed)) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Invalid encoding "' . $encoding . '"');
+        }
+        $this->_headerEncoding = $encoding;
+
+        return $this;
+    }
+
+    /**
+     * Sets the text body for the message.
+     *
+     * @param  string $txt
+     * @param  string $charset
+     * @param  string $encoding
+     * @return Zend_Mail Provides fluent interface
+    */
+    public function setBodyText($txt, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
+    {
+        if ($charset === null) {
+            $charset = $this->_charset;
+        }
+
+        $mp = new Zend_Mime_Part($txt);
+        $mp->encoding = $encoding;
+        $mp->type = Zend_Mime::TYPE_TEXT;
+        $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
+        $mp->charset = $charset;
+
+        $this->_bodyText = $mp;
+
+        return $this;
+    }
+
+    /**
+     * Return text body Zend_Mime_Part or string
+     *
+     * @param  bool textOnly Whether to return just the body text content or the MIME part; defaults to false, the MIME part
+     * @return false|Zend_Mime_Part|string
+     */
+    public function getBodyText($textOnly = false)
+    {
+        if ($textOnly && $this->_bodyText) {
+            $body = $this->_bodyText;
+            return $body->getContent();
+        }
+
+        return $this->_bodyText;
+    }
+
+    /**
+     * Sets the HTML body for the message
+     *
+     * @param  string    $html
+     * @param  string    $charset
+     * @param  string    $encoding
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function setBodyHtml($html, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
+    {
+        if ($charset === null) {
+            $charset = $this->_charset;
+        }
+
+        $mp = new Zend_Mime_Part($html);
+        $mp->encoding = $encoding;
+        $mp->type = Zend_Mime::TYPE_HTML;
+        $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
+        $mp->charset = $charset;
+
+        $this->_bodyHtml = $mp;
+
+        return $this;
+    }
+
+    /**
+     * Return Zend_Mime_Part representing body HTML
+     *
+     * @param  bool $htmlOnly Whether to return the body HTML only, or the MIME part; defaults to false, the MIME part
+     * @return false|Zend_Mime_Part|string
+     */
+    public function getBodyHtml($htmlOnly = false)
+    {
+        if ($htmlOnly && $this->_bodyHtml) {
+            $body = $this->_bodyHtml;
+            return $body->getContent();
+        }
+
+        return $this->_bodyHtml;
+    }
+
+    /**
+     * Adds an existing attachment to the mail message
+     *
+     * @param  Zend_Mime_Part $attachment
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addAttachment(Zend_Mime_Part $attachment)
+    {
+        $this->addPart($attachment);
+        $this->hasAttachments = true;
+
+        return $this;
+    }
+
+    /**
+     * Creates a Zend_Mime_Part attachment
+     *
+     * Attachment is automatically added to the mail object after creation. The
+     * attachment object is returned to allow for further manipulation.
+     *
+     * @param  string         $body
+     * @param  string         $mimeType
+     * @param  string         $disposition
+     * @param  string         $encoding
+     * @param  string         $filename OPTIONAL A filename for the attachment
+     * @return Zend_Mime_Part Newly created Zend_Mime_Part object (to allow
+     * advanced settings)
+     */
+    public function createAttachment($body,
+                                     $mimeType    = Zend_Mime::TYPE_OCTETSTREAM,
+                                     $disposition = Zend_Mime::DISPOSITION_ATTACHMENT,
+                                     $encoding    = Zend_Mime::ENCODING_BASE64,
+                                     $filename    = null)
+    {
+
+        $mp = new Zend_Mime_Part($body);
+        $mp->encoding = $encoding;
+        $mp->type = $mimeType;
+        $mp->disposition = $disposition;
+        $mp->filename = $filename;
+
+        $this->addAttachment($mp);
+
+        return $mp;
+    }
+
+    /**
+     * Return a count of message parts
+     *
+     * @return integer
+     */
+    public function getPartCount()
+    {
+        return count($this->_parts);
+    }
+
+    /**
+     * Encode header fields
+     *
+     * Encodes header content according to RFC1522 if it contains non-printable
+     * characters.
+     *
+     * @param  string $value
+     * @return string
+     */
+    protected function _encodeHeader($value)
+    {
+    	if (Zend_Mime::isPrintable($value) === false) {
+            if ($this->getHeaderEncoding() === Zend_Mime::ENCODING_QUOTEDPRINTABLE) {
+                $value = Zend_Mime::encodeQuotedPrintableHeader($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
+            } else {
+                $value = Zend_Mime::encodeBase64Header($value, $this->getCharset(), Zend_Mime::LINELENGTH, Zend_Mime::LINEEND);
+            }
+        }
+
+        return $value;
+    }
+
+    /**
+     * Add a header to the message
+     *
+     * Adds a header to this message. If append is true and the header already
+     * exists, raises a flag indicating that the header should be appended.
+     *
+     * @param string  $headerName
+     * @param string  $value
+     * @param bool $append
+     */
+    protected function _storeHeader($headerName, $value, $append = false)
+    {
+        if (isset($this->_headers[$headerName])) {
+            $this->_headers[$headerName][] = $value;
+        } else {
+            $this->_headers[$headerName] = array($value);
+        }
+
+        if ($append) {
+            $this->_headers[$headerName]['append'] = true;
+        }
+
+    }
+
+    /**
+     * Clear header from the message
+     *
+     * @param string $headerName
+     */
+    protected function _clearHeader($headerName)
+    {
+        if (isset($this->_headers[$headerName])){
+            unset($this->_headers[$headerName]);
+        }
+    }
+
+    /**
+     * Helper function for adding a recipient and the corresponding header
+     *
+     * @param string $headerName
+     * @param string $email
+     * @param string $name
+     */
+    protected function _addRecipientAndHeader($headerName, $email, $name)
+    {
+        $email = $this->_filterEmail($email);
+        $name  = $this->_filterName($name);
+        // prevent duplicates
+        $this->_recipients[$email] = 1;
+        $this->_storeHeader($headerName, $this->_formatAddress($email, $name), true);
+    }
+
+    /**
+     * Adds To-header and recipient
+     *
+     * @param  string $email
+     * @param  string $name
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addTo($email, $name='')
+    {
+        $this->_addRecipientAndHeader('To', $email, $name);
+        $this->_to[] = $email;
+        return $this;
+    }
+
+    /**
+     * Adds Cc-header and recipient
+     *
+     * @param  string    $email
+     * @param  string    $name
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addCc($email, $name='')
+    {
+        $this->_addRecipientAndHeader('Cc', $email, $name);
+        return $this;
+    }
+
+    /**
+     * Adds Bcc recipient
+     *
+     * @param  string    $email
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function addBcc($email)
+    {
+        $this->_addRecipientAndHeader('Bcc', $email, '');
+        return $this;
+    }
+
+    /**
+     * Return list of recipient email addresses
+     *
+     * @return array (of strings)
+     */
+    public function getRecipients()
+    {
+        return array_keys($this->_recipients);
+    }
+
+    /**
+     * Clears list of recipient email addresses
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearRecipients()
+    {
+        $this->_recipients = array();
+        $this->_to = array();
+
+        $this->_clearHeader('To');
+        $this->_clearHeader('Cc');
+        $this->_clearHeader('Bcc');
+
+        return $this;
+    }
+
+    /**
+     * Sets From-header and sender of the message
+     *
+     * @param  string    $email
+     * @param  string    $name
+     * @return Zend_Mail Provides fluent interface
+     * @throws Zend_Mail_Exception if called subsequent times
+     */
+    public function setFrom($email, $name = null)
+    {
+        if ($this->_from === null) {
+            $email = $this->_filterEmail($email);
+            $name  = $this->_filterName($name);
+            $this->_from = $email;
+            $this->_storeHeader('From', $this->_formatAddress($email, $name), true);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('From Header set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the sender of the mail
+     *
+     * @return string
+     */
+    public function getFrom()
+    {
+        return $this->_from;
+    }
+
+    /**
+     * Clears the sender from the mail
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearFrom()
+    {
+        $this->_from = null;
+        $this->_clearHeader('From');
+
+        return $this;
+    }
+
+    /**
+     * Sets the Return-Path header of the message
+     *
+     * @param  string    $email
+     * @return Zend_Mail Provides fluent interface
+     * @throws Zend_Mail_Exception if set multiple times
+     */
+    public function setReturnPath($email)
+    {
+        if ($this->_returnPath === null) {
+            $email = $this->_filterEmail($email);
+            $this->_returnPath = $email;
+            $this->_storeHeader('Return-Path', $email, false);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Return-Path Header set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the current Return-Path address of the message
+     *
+     * If no Return-Path header is set, returns the value of {@link $_from}.
+     *
+     * @return string
+     */
+    public function getReturnPath()
+    {
+        if (null !== $this->_returnPath) {
+            return $this->_returnPath;
+        }
+
+        return $this->_from;
+    }
+
+    /**
+     * Clears the current Return-Path address from the message
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearReturnPath()
+    {
+        $this->_returnPath = null;
+        $this->_clearHeader('Return-Path');
+
+        return $this;
+    }
+
+    /**
+     * Sets the subject of the message
+     *
+     * @param   string    $subject
+     * @return  Zend_Mail Provides fluent interface
+     * @throws  Zend_Mail_Exception
+     */
+    public function setSubject($subject)
+    {
+        if ($this->_subject === null) {
+            $subject = $this->_filterOther($subject);
+            $this->_subject = $this->_encodeHeader($subject);
+            $this->_storeHeader('Subject', $this->_subject);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Subject set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the encoded subject of the message
+     *
+     * @return string
+     */
+    public function getSubject()
+    {
+        return $this->_subject;
+    }
+
+    /**
+     * Clears the encoded subject from the message
+     *
+     * @return  Zend_Mail Provides fluent interface
+     */
+    public function clearSubject()
+    {
+        $this->_subject = null;
+        $this->_clearHeader('Subject');
+
+        return $this;
+    }
+
+    /**
+     * Sets Date-header
+     *
+     * @param  string    $date
+     * @return Zend_Mail Provides fluent interface
+     * @throws Zend_Mail_Exception if called subsequent times
+     */
+    public function setDate($date = null)
+    {
+        if ($this->_date === null) {
+            if ($date === null) {
+                $date = date('r');
+            } else if (is_int($date)) {
+                $date = date('r', $date);
+            } else if (is_string($date)) {
+                $date = strtotime($date);
+                if ($date === false || $date < 0) {
+		            /**
+		             * @see Zend_Mail_Exception
+		             */
+		            require_once 'Zend/Mail/Exception.php';
+                	throw new Zend_Mail_Exception('String representations of Date Header must be ' .
+                                                  'strtotime()-compatible');
+                }
+                $date = date('r', $date);
+            } else if ($date instanceof Zend_Date) {
+                $date = $date->get(Zend_Date::RFC_2822);
+            } else {
+	            /**
+	             * @see Zend_Mail_Exception
+	             */
+	            require_once 'Zend/Mail/Exception.php';
+            	throw new Zend_Mail_Exception(__METHOD__ . ' only accepts UNIX timestamps, Zend_Date objects, ' .
+                                              ' and strtotime()-compatible strings');
+            }
+            $this->_date = $date;
+            $this->_storeHeader('Date', $date);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+        	require_once 'Zend/Mail/Exception.php';
+        	throw new Zend_Mail_Exception('Date Header set twice');
+        }
+        return $this;
+    }
+
+    /**
+     * Returns the formatted date of the message
+     *
+     * @return string
+     */
+    public function getDate()
+    {
+        return $this->_date;
+    }
+
+    /**
+     * Clears the formatted date from the message
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearDate()
+    {
+        $this->_date = null;
+        $this->_clearHeader('Date');
+
+        return $this;
+    }
+
+    /**
+     * Sets the Message-ID of the message
+     *
+     * @param   boolean|string  $id
+     * true  :Auto
+     * false :No set
+     * null  :No set
+     * string:Sets string
+     * @return  Zend_Mail Provides fluent interface
+     * @throws  Zend_Mail_Exception
+     */
+    public function setMessageId($id = true)
+    {
+    	if ($id === null || $id === false) {
+    		return $this;
+    	} elseif ($id === true) {
+            $id = $this->createMessageId();
+    	}
+
+        if ($this->_messageId === null) {
+        	$id = $this->_filterOther($id);
+            $this->_messageId = $id;
+            $this->_storeHeader('Message-Id', $this->_messageId);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Message-ID set twice');
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the Message-ID of the message
+     *
+     * @return string
+     */
+    public function getMessageId()
+    {
+        return $this->_messageId;
+    }
+
+
+    /**
+     * Clears the Message-ID from the message
+     *
+     * @return Zend_Mail Provides fluent interface
+     */
+    public function clearMessageId()
+    {
+        $this->_messageId = null;
+        $this->_clearHeader('Message-Id');
+
+        return $this;
+    }
+
+    /**
+     * Creates the Message-ID
+     *
+     * @return string
+     */
+    public function createMessageId() {
+
+        $time = time();
+
+        if ($this->_from !== null) {
+        	$user = $this->_from;
+        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
+        	$user = $_SERVER['REMOTE_ADDR'];
+        } else {
+        	$user = getmypid();
+        }
+
+    	$rand = mt_rand();
+
+    	if ($this->_recipients !== array()) {
+            $recipient = array_rand($this->_recipients);
+    	} else {
+    		$recipient = 'unknown';
+    	}
+
+    	if (isset($_SERVER["SERVER_NAME"])) {
+            $hostName = $_SERVER["SERVER_NAME"];
+        } else {
+        	$hostName = php_uname('n');
+        }
+
+        return sha1($time . $user . $rand . $recipient) . '@' . $hostName;
+    }
+
+    /**
+     * Add a custom header to the message
+     *
+     * @param  string              $name
+     * @param  string              $value
+     * @param  boolean             $append
+     * @return Zend_Mail           Provides fluent interface
+     * @throws Zend_Mail_Exception on attempts to create standard headers
+     */
+    public function addHeader($name, $value, $append = false)
+    {
+        $prohibit = array('to', 'cc', 'bcc', 'from', 'subject',
+                          'return-path', 'date', 'message-id',
+                         );
+        if (in_array(strtolower($name), $prohibit)) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('Cannot set standard header from addHeader()');
+        }
+
+        $value = $this->_filterOther($value);
+        $value = $this->_encodeHeader($value);
+        $this->_storeHeader($name, $value, $append);
+
+        return $this;
+    }
+
+    /**
+     * Return mail headers
+     *
+     * @return void
+     */
+    public function getHeaders()
+    {
+        return $this->_headers;
+    }
+
+    /**
+     * Sends this email using the given transport or a previously
+     * set DefaultTransport or the internal mail function if no
+     * default transport had been set.
+     *
+     * @param  Zend_Mail_Transport_Abstract $transport
+     * @return Zend_Mail                    Provides fluent interface
+     */
+    public function send($transport = null)
+    {
+        if ($transport === null) {
+            if (! self::$_defaultTransport instanceof Zend_Mail_Transport_Abstract) {
+                require_once 'Zend/Mail/Transport/Sendmail.php';
+                $transport = new Zend_Mail_Transport_Sendmail();
+            } else {
+                $transport = self::$_defaultTransport;
+            }
+        }
+
+        if ($this->_date === null) {
+            $this->setDate();
+        }
+
+        $transport->send($this);
+
+        return $this;
+    }
+
+    /**
+     * Filter of email data
+     *
+     * @param string $email
+     * @return string
+     */
+    protected function _filterEmail($email)
+    {
+    	$rule = array("\r" => '',
+    	              "\n" => '',
+    	              "\t" => '',
+                      '"'  => '',
+    	              ','  => '',
+                      '<'  => '',
+                      '>'  => '',
+    	);
+
+        return strtr($email, $rule);
+    }
+
+    /**
+     * Filter of name data
+     *
+     * @param string $name
+     * @return string
+     */
+    protected function _filterName($name)
+    {
+    	$rule = array("\r" => '',
+                      "\n" => '',
+                      "\t" => '',
+                      '"'  => "'",
+                      '<'  => '[',
+    	              '>'  => ']',
+    	);
+
+        return trim(strtr($name, $rule));
+    }
+
+    /**
+     * Filter of other data
+     *
+     * @param string $data
+     * @return string
+     */
+    protected function _filterOther($data)
+    {
+        $rule = array("\r" => '',
+                      "\n" => '',
+                      "\t" => '',
+        );
+
+        return strtr($data, $rule);
+    }
+
+    /**
+     * Formats e-mail address
+     *
+     * @param string $email
+     * @param string $name
+     * @return string
+     */
+    protected function _formatAddress($email, $name)
+    {
+        if ($name === '' || $name === null || $name === $email) {
+            return $email;
+        } else {
+            $encodedName = $this->_encodeHeader($name);
+            if ($encodedName === $name && strpos($name, ',') !== false) {
+                $format = '"%s" <%s>';
+            } else {
+                $format = '%s <%s>';
+            }
+            return sprintf($format, $encodedName, $email);
+        }
+    }
+
+}
diff --git a/lib/Zend/Mail/Exception.php b/lib/Zend/Mail/Exception.php
new file mode 100644
index 0000000..bab758e
--- /dev/null
+++ b/lib/Zend/Mail/Exception.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Exception
+ */
+require_once 'Zend/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Exception extends Zend_Exception
+{}
+
diff --git a/lib/Zend/Mail/Message.php b/lib/Zend/Mail/Message.php
new file mode 100644
index 0000000..787df98
--- /dev/null
+++ b/lib/Zend/Mail/Message.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Message.php 9099 2008-03-30 19:35:47Z thomas $
+ */
+
+
+/**
+ * Zend_Mail_Part
+ */
+require_once 'Zend/Mail/Part.php';
+
+/**
+ * Zend_Mail_Message_Interface
+ */
+require_once 'Zend/Mail/Message/Interface.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Message extends Zend_Mail_Part implements Zend_Mail_Message_Interface
+{
+    /**
+     * flags for this message
+     * @var array
+     */
+    protected $_flags = array();
+
+    /**
+     * Public constructor
+     *
+     * In addition to the parameters of Zend_Mail_Part::__construct() this constructor supports:
+     * - file  filename or file handle of a file with raw message content
+     * - flags array with flags for message, keys are ignored, use constants defined in Zend_Mail_Storage
+     *
+     * @param  string $rawMessage  full message with or without headers
+     * @throws Zend_Mail_Exception
+     */
+    public function __construct(array $params)
+    {
+        if (isset($params['file'])) {
+            if (!is_resource($params['file'])) {
+                $params['raw'] = @file_get_contents($params['file']);
+                if ($params['raw'] === false) {
+                    /**
+                     * @see Zend_Mail_Exception
+                     */
+                    require_once 'Zend/Mail/Exception.php';
+                    throw new Zend_Mail_Exception('could not open file');
+                }
+            } else {
+                $params['raw'] = stream_get_contents($params['file']);
+            }
+        }
+
+        if (!empty($params['flags'])) {
+            // set key and value to the same value for easy lookup
+            $this->_flags = array_combine($params['flags'], $params['flags']);
+        }
+
+        parent::__construct($params);
+    }
+
+    /**
+     * return toplines as found after headers
+     *
+     * @return string toplines
+     */
+    public function getTopLines()
+    {
+        return $this->_topLines;
+    }
+
+    /**
+     * check if flag is set
+     *
+     * @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
+     * @return bool true if set, otherwise false
+     */
+    public function hasFlag($flag)
+    {
+        return isset($this->_flags[$flag]);
+    }
+
+    /**
+     * get all set flags
+     *
+     * @return array array with flags, key and value are the same for easy lookup
+     */
+    public function getFlags()
+    {
+        return $this->_flags;
+    }
+}
diff --git a/lib/Zend/Mail/Message/File.php b/lib/Zend/Mail/Message/File.php
new file mode 100644
index 0000000..5a93449
--- /dev/null
+++ b/lib/Zend/Mail/Message/File.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Message.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * Zend_Mail_Part
+ */
+require_once 'Zend/Mail/Part/File.php';
+
+/**
+ * Zend_Mail_Message_Interface
+ */
+require_once 'Zend/Mail/Message/Interface.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Message_File extends Zend_Mail_Part_File implements Zend_Mail_Message_Interface
+{
+    /**
+     * flags for this message
+     * @var array
+     */
+    protected $_flags = array();
+
+    /**
+     * Public constructor
+     *
+     * In addition to the parameters of Zend_Mail_Part::__construct() this constructor supports:
+     * - flags array with flags for message, keys are ignored, use constants defined in Zend_Mail_Storage
+     *
+     * @param  string $rawMessage  full message with or without headers
+     * @throws Zend_Mail_Exception
+     */
+    public function __construct(array $params)
+    {
+        if (!empty($params['flags'])) {
+            // set key and value to the same value for easy lookup
+            $this->_flags = array_combine($params['flags'], $params['flags']);
+        }
+        
+        parent::__construct($params);
+    }
+
+    /**
+     * return toplines as found after headers
+     *
+     * @return string toplines
+     */
+    public function getTopLines()
+    {
+        return $this->_topLines;
+    }
+
+    /**
+     * check if flag is set
+     *
+     * @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
+     * @return bool true if set, otherwise false
+     */
+    public function hasFlag($flag)
+    {
+        return isset($this->_flags[$flag]);
+    }
+
+    /**
+     * get all set flags
+     *
+     * @return array array with flags, key and value are the same for easy lookup
+     */
+    public function getFlags()
+    {
+        return $this->_flags;
+    }
+}
diff --git a/lib/Zend/Mail/Message/Interface.php b/lib/Zend/Mail/Message/Interface.php
new file mode 100644
index 0000000..92acd49
--- /dev/null
+++ b/lib/Zend/Mail/Message/Interface.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Interface.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+interface Zend_Mail_Message_Interface
+{
+    /**
+     * return toplines as found after headers
+     *
+     * @return string toplines
+     */
+    public function getTopLines();
+
+    /**
+     * check if flag is set
+     *
+     * @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage
+     * @return bool true if set, otherwise false
+     */
+    public function hasFlag($flag);
+
+    /**
+     * get all set flags
+     *
+     * @return array array with flags, key and value are the same for easy lookup
+     */
+    public function getFlags();
+}
\ No newline at end of file
diff --git a/lib/Zend/Mail/Part.php b/lib/Zend/Mail/Part.php
new file mode 100644
index 0000000..c2f6bef
--- /dev/null
+++ b/lib/Zend/Mail/Part.php
@@ -0,0 +1,489 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Part.php 14073 2009-02-12 22:30:40Z beberlei $
+ */
+
+
+/**
+ * @see Zend_Mime_Decode
+ */
+require_once 'Zend/Mime/Decode.php';
+
+/**
+ * @see Zend_Mail_Part_Interface
+ */
+require_once 'Zend/Mail/Part/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Part implements RecursiveIterator, Zend_Mail_Part_Interface
+{
+    /**
+     * headers of part as array
+     * @var null|array
+     */
+    protected $_headers;
+
+    /**
+     * raw part body
+     * @var null|string
+     */
+    protected $_content;
+
+    /**
+     * toplines as fetched with headers
+     * @var string
+     */
+    protected $_topLines = '';
+
+    /**
+     * parts of multipart message
+     * @var array
+     */
+    protected $_parts = array();
+
+    /**
+     * count of parts of a multipart message
+     * @var null|int
+     */
+    protected $_countParts;
+
+    /**
+     * current position of iterator
+     * @var int
+     */
+    protected $_iterationPos = 1;
+
+    /**
+     * mail handler, if late fetch is active
+     * @var null|Zend_Mail_Storage_Abstract
+     */
+    protected $_mail;
+
+    /**
+     * message number for mail handler
+     * @var int
+     */
+    protected $_messageNum = 0;
+
+    /**
+     * Public constructor
+     *
+     * Zend_Mail_Part supports different sources for content. The possible params are:
+     * - handler    a instance of Zend_Mail_Storage_Abstract for late fetch
+     * - id         number of message for handler
+     * - raw        raw content with header and body as string
+     * - headers    headers as array (name => value) or string, if a content part is found it's used as toplines
+     * - noToplines ignore content found after headers in param 'headers'
+     * - content    content as string
+     *
+     * @param   array $params  full message with or without headers
+     * @throws  Zend_Mail_Exception
+     */
+    public function __construct(array $params)
+    {
+        if (isset($params['handler'])) {
+            if (!$params['handler'] instanceof Zend_Mail_Storage_Abstract) {
+                /**
+                 * @see Zend_Mail_Exception
+                 */
+                require_once 'Zend/Mail/Exception.php';
+                throw new Zend_Mail_Exception('handler is not a valid mail handler');
+            }
+            if (!isset($params['id'])) {
+                /**
+                 * @see Zend_Mail_Exception
+                 */
+                require_once 'Zend/Mail/Exception.php';
+                throw new Zend_Mail_Exception('need a message id with a handler');
+            }
+
+            $this->_mail       = $params['handler'];
+            $this->_messageNum = $params['id'];
+        }
+
+        if (isset($params['raw'])) {
+            Zend_Mime_Decode::splitMessage($params['raw'], $this->_headers, $this->_content);
+        } else if (isset($params['headers'])) {
+            if (is_array($params['headers'])) {
+                $this->_headers = $params['headers'];
+            } else {
+                if (!empty($params['noToplines'])) {
+                    Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $null);
+                } else {
+                    Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $this->_topLines);
+                }
+            }
+            if (isset($params['content'])) {
+                $this->_content = $params['content'];
+            }
+        }
+    }
+
+    /**
+     * Check if part is a multipart message
+     *
+     * @return bool if part is multipart
+     */
+    public function isMultipart()
+    {
+        try {
+            return stripos($this->contentType, 'multipart/') === 0;
+        } catch(Zend_Mail_Exception $e) {
+            return false;
+        }
+    }
+
+
+    /**
+     * Body of part
+     *
+     * If part is multipart the raw content of this part with all sub parts is returned
+     *
+     * @return string body
+     * @throws Zend_Mail_Exception
+     */
+    public function getContent()
+    {
+        if ($this->_content !== null) {
+            return $this->_content;
+        }
+
+        if ($this->_mail) {
+            return $this->_mail->getRawContent($this->_messageNum);
+        } else {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('no content');
+        }
+    }
+
+    /**
+     * Return size of part
+     *
+     * Quite simple implemented currently (not decoding). Handle with care.
+     *
+     * @return int size
+     */
+    public function getSize() {
+        return strlen($this->getContent());
+    }
+
+
+    /**
+     * Cache content and split in parts if multipart
+     *
+     * @return null
+     * @throws Zend_Mail_Exception
+     */
+    protected function _cacheContent()
+    {
+        // caching content if we can't fetch parts
+        if ($this->_content === null && $this->_mail) {
+            $this->_content = $this->_mail->getRawContent($this->_messageNum);
+        }
+
+        if (!$this->isMultipart()) {
+            return;
+        }
+
+        // split content in parts
+        $boundary = $this->getHeaderField('content-type', 'boundary');
+        if (!$boundary) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('no boundary found in content type to split message');
+        }
+        $parts = Zend_Mime_Decode::splitMessageStruct($this->_content, $boundary);
+        if ($parts === null) {
+            return;
+        }
+        $counter = 1;
+        foreach ($parts as $part) {
+            $this->_parts[$counter++] = new self(array('headers' => $part['header'], 'content' => $part['body']));
+        }
+    }
+
+    /**
+     * Get part of multipart message
+     *
+     * @param  int $num number of part starting with 1 for first part
+     * @return Zend_Mail_Part wanted part
+     * @throws Zend_Mail_Exception
+     */
+    public function getPart($num)
+    {
+        if (isset($this->_parts[$num])) {
+            return $this->_parts[$num];
+        }
+
+        if (!$this->_mail && $this->_content === null) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('part not found');
+        }
+
+        if ($this->_mail && $this->_mail->hasFetchPart) {
+            // TODO: fetch part
+            // return
+        }
+
+        $this->_cacheContent();
+
+        if (!isset($this->_parts[$num])) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('part not found');
+        }
+
+        return $this->_parts[$num];
+    }
+
+    /**
+     * Count parts of a multipart part
+     *
+     * @return int number of sub-parts
+     */
+    public function countParts()
+    {
+        if ($this->_countParts) {
+            return $this->_countParts;
+        }
+
+        $this->_countParts = count($this->_parts);
+        if ($this->_countParts) {
+            return $this->_countParts;
+        }
+
+        if ($this->_mail && $this->_mail->hasFetchPart) {
+            // TODO: fetch part
+            // return
+        }
+
+        $this->_cacheContent();
+
+        $this->_countParts = count($this->_parts);
+        return $this->_countParts;
+    }
+
+
+    /**
+     * Get all headers
+     *
+     * The returned headers are as saved internally. All names are lowercased. The value is a string or an array
+     * if a header with the same name occurs more than once.
+     *
+     * @return array headers as array(name => value)
+     */
+    public function getHeaders()
+    {
+        if ($this->_headers === null) {
+            if (!$this->_mail) {
+                $this->_headers = array();
+            } else {
+                $part = $this->_mail->getRawHeader($this->_messageNum);
+                Zend_Mime_Decode::splitMessage($part, $this->_headers, $null);
+            }
+        }
+
+        return $this->_headers;
+    }
+
+    /**
+     * Get a header in specificed format
+     *
+     * Internally headers that occur more than once are saved as array, all other as string. If $format
+     * is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim).
+     *
+     * @param  string $name   name of header, matches case-insensitive, but camel-case is replaced with dashes
+     * @param  string $format change type of return value to 'string' or 'array'
+     * @return string|array value of header in wanted or internal format
+     * @throws Zend_Mail_Exception
+     */
+    public function getHeader($name, $format = null)
+    {
+        if ($this->_headers === null) {
+            $this->getHeaders();
+        }
+
+        $lowerName = strtolower($name);
+
+        if (!isset($this->_headers[$lowerName])) {
+            $lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name));
+            if (!isset($this->_headers[$lowerName])) {
+                /**
+                 * @see Zend_Mail_Exception
+                 */
+                require_once 'Zend/Mail/Exception.php';
+                throw new Zend_Mail_Exception("no Header with Name $name found");
+            }
+        }
+        $name = $lowerName;
+
+        $header = $this->_headers[$name];
+
+        switch ($format) {
+            case 'string':
+                if (is_array($header)) {
+                    $header = implode(Zend_Mime::LINEEND, $header);
+                }
+                break;
+            case 'array':
+                $header = (array)$header;
+            default:
+                // do nothing
+        }
+
+        return $header;
+    }
+    
+    /**
+     * Get a specific field from a header like content type or all fields as array
+     *
+     * If the header occurs more than once, only the value from the first header
+     * is returned.
+     *
+     * Throws a Zend_Mail_Exception if the requested header does not exist. If
+     * the specific header field does not exist, returns null.
+     *
+     * @param  string $name       name of header, like in getHeader()
+     * @param  string $wantedPart the wanted part, default is first, if null an array with all parts is returned
+     * @param  string $firstName  key name for the first part
+     * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
+     * @throws Zend_Exception, Zend_Mail_Exception
+     */
+    public function getHeaderField($name, $wantedPart = 0, $firstName = 0) {
+        return Zend_Mime_Decode::splitHeaderField(current($this->getHeader($name, 'array')), $wantedPart, $firstName);
+    }
+
+
+    /**
+     * Getter for mail headers - name is matched in lowercase
+     *
+     * This getter is short for Zend_Mail_Part::getHeader($name, 'string')
+     *
+     * @see Zend_Mail_Part::getHeader()
+     *
+     * @param  string $name header name
+     * @return string value of header
+     * @throws Zend_Mail_Exception
+     */
+    public function __get($name)
+    {
+        return $this->getHeader($name, 'string');
+    }
+
+    /**
+     * magic method to get content of part
+     *
+     * @return string content
+     */
+    public function __toString()
+    {
+        return $this->getContent();
+    }
+
+    /**
+     * implements RecursiveIterator::hasChildren()
+     *
+     * @return bool current element has children/is multipart
+     */
+    public function hasChildren()
+    {
+        $current = $this->current();
+        return $current && $current instanceof Zend_Mail_Part && $current->isMultipart();
+    }
+
+    /**
+     * implements RecursiveIterator::getChildren()
+     *
+     * @return Zend_Mail_Part same as self::current()
+     */
+    public function getChildren()
+    {
+        return $this->current();
+    }
+
+    /**
+     * implements Iterator::valid()
+     *
+     * @return bool check if there's a current element
+     */
+    public function valid()
+    {
+        if ($this->_countParts === null) {
+            $this->countParts();
+        }
+        return $this->_iterationPos && $this->_iterationPos <= $this->_countParts;
+    }
+
+    /**
+     * implements Iterator::next()
+     *
+     * @return null
+     */
+    public function next()
+    {
+        ++$this->_iterationPos;
+    }
+
+    /**
+     * implements Iterator::key()
+     *
+     * @return string key/number of current part
+     */
+    public function key()
+    {
+        return $this->_iterationPos;
+    }
+
+    /**
+     * implements Iterator::current()
+     *
+     * @return Zend_Mail_Part current part
+     */
+    public function current()
+    {
+        return $this->getPart($this->_iterationPos);
+    }
+
+    /**
+     * implements Iterator::rewind()
+     *
+     * @return null
+     */
+    public function rewind()
+    {
+        $this->countParts();
+        $this->_iterationPos = 1;
+    }
+}
diff --git a/lib/Zend/Mail/Part/File.php b/lib/Zend/Mail/Part/File.php
new file mode 100644
index 0000000..6ff5147
--- /dev/null
+++ b/lib/Zend/Mail/Part/File.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Part.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mime_Decode
+ */
+require_once 'Zend/Mime/Decode.php';
+
+/**
+ * @see Zend_Mail_Part
+ */
+require_once 'Zend/Mail/Part.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Part_File extends Zend_Mail_Part
+{
+    protected $_contentPos = array();
+    protected $_partPos = array();
+    protected $_fh;
+
+    /**
+     * Public constructor
+     *
+     * This handler supports the following params:
+     * - file     filename or open file handler with message content (required)
+     * - startPos start position of message or part in file (default: current position)
+     * - endPos   end position of message or part in file (default: end of file)
+     *
+     * @param   array $params  full message with or without headers
+     * @throws  Zend_Mail_Exception
+     */
+    public function __construct(array $params)
+    {
+        if (empty($params['file'])) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('no file given in params');
+        }
+        
+        if (!is_resource($params['file'])) {
+            $this->_fh = fopen($params['file'], 'r');
+        } else {
+            $this->_fh = $params['file'];
+        }
+        if (!$this->_fh) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('could not open file');
+        }
+        if (isset($params['startPos'])) {
+            fseek($this->_fh, $params['startPos']);
+        }
+        $header = '';
+        $endPos = isset($params['endPos']) ? $params['endPos'] : null;
+        while (($endPos === null || ftell($this->_fh) < $endPos) && trim($line = fgets($this->_fh))) {
+            $header .= $line;
+        }
+
+        Zend_Mime_Decode::splitMessage($header, $this->_headers, $null);
+        
+        $this->_contentPos[0] = ftell($this->_fh);
+        if ($endPos !== null) {
+            $this->_contentPos[1] = $endPos;
+        } else {
+            fseek($this->_fh, 0, SEEK_END);
+            $this->_contentPos[1] = ftell($this->_fh);
+        }
+        if (!$this->isMultipart()) {
+            return;
+        }
+        
+        $boundary = $this->getHeaderField('content-type', 'boundary');
+        if (!$boundary) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('no boundary found in content type to split message');
+        }
+        
+        $part = array();
+        $pos = $this->_contentPos[0];
+        fseek($this->_fh, $pos);
+        while (!feof($this->_fh) && ($endPos === null || $pos < $endPos)) {
+            $line = fgets($this->_fh);
+            if ($line === false) {
+                if (feof($this->_fh)) {
+                    break;
+                }
+                /**
+                 * @see Zend_Mail_Exception
+                 */
+                require_once 'Zend/Mail/Exception.php';
+                throw new Zend_Mail_Exception('error reading file');
+            }
+
+            $lastPos = $pos;
+            $pos = ftell($this->_fh);
+            $line = trim($line);
+
+            if ($line == '--' . $boundary) {
+                if ($part) {
+                    // not first part
+                    $part[1] = $lastPos;
+                    $this->_partPos[] = $part;
+                }
+                $part = array($pos);
+            } else if ($line == '--' . $boundary . '--') {
+                $part[1] = $lastPos;
+                $this->_partPos[] = $part;
+                break;
+            }
+        }
+        $this->_countParts = count($this->_partPos);
+        
+    }
+
+
+    /**
+     * Body of part
+     *
+     * If part is multipart the raw content of this part with all sub parts is returned
+     *
+     * @return string body
+     * @throws Zend_Mail_Exception
+     */
+    public function getContent($stream = null)
+    {
+        fseek($this->_fh, $this->_contentPos[0]);
+        if ($stream !== null) {
+            return stream_copy_to_stream($this->_fh, $stream, $this->_contentPos[1] - $this->_contentPos[0]);    
+        }
+        $length = $this->_contentPos[1] - $this->_contentPos[0];
+        return $length < 1 ? '' : fread($this->_fh, $length);
+    }
+
+    /**
+     * Return size of part
+     *
+     * Quite simple implemented currently (not decoding). Handle with care.
+     *
+     * @return int size
+     */
+    public function getSize() {
+        return $this->_contentPos[1] - $this->_contentPos[0];
+    }
+
+    /**
+     * Get part of multipart message
+     *
+     * @param  int $num number of part starting with 1 for first part
+     * @return Zend_Mail_Part wanted part
+     * @throws Zend_Mail_Exception
+     */
+    public function getPart($num)
+    {
+        --$num;
+        if (!isset($this->_partPos[$num])) {
+            /**
+             * @see Zend_Mail_Exception
+             */
+            require_once 'Zend/Mail/Exception.php';
+            throw new Zend_Mail_Exception('part not found');
+        }
+
+        return new self(array('file' => $this->_fh, 'startPos' => $this->_partPos[$num][0], 
+                              'endPos' => $this->_partPos[$num][1]));
+    }
+}
diff --git a/lib/Zend/Mail/Part/Interface.php b/lib/Zend/Mail/Part/Interface.php
new file mode 100644
index 0000000..d1a22f1
--- /dev/null
+++ b/lib/Zend/Mail/Part/Interface.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Interface.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+interface Zend_Mail_Part_Interface extends RecursiveIterator
+{
+    /**
+     * Check if part is a multipart message
+     *
+     * @return bool if part is multipart
+     */
+    public function isMultipart();
+
+
+    /**
+     * Body of part
+     *
+     * If part is multipart the raw content of this part with all sub parts is returned
+     *
+     * @return string body
+     * @throws Zend_Mail_Exception
+     */
+    public function getContent();
+
+    /**
+     * Return size of part
+     *
+     * @return int size
+     */
+    public function getSize();
+
+    /**
+     * Get part of multipart message
+     *
+     * @param  int $num number of part starting with 1 for first part
+     * @return Zend_Mail_Part wanted part
+     * @throws Zend_Mail_Exception
+     */
+    public function getPart($num);
+
+    /**
+     * Count parts of a multipart part
+     *
+     * @return int number of sub-parts
+     */
+    public function countParts();
+
+
+    /**
+     * Get all headers
+     *
+     * The returned headers are as saved internally. All names are lowercased. The value is a string or an array
+     * if a header with the same name occurs more than once.
+     *
+     * @return array headers as array(name => value)
+     */
+    public function getHeaders();
+
+    /**
+     * Get a header in specificed format
+     *
+     * Internally headers that occur more than once are saved as array, all other as string. If $format
+     * is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim).
+     *
+     * @param  string $name   name of header, matches case-insensitive, but camel-case is replaced with dashes
+     * @param  string $format change type of return value to 'string' or 'array'
+     * @return string|array value of header in wanted or internal format
+     * @throws Zend_Mail_Exception
+     */
+    public function getHeader($name, $format = null);
+    
+    /**
+     * Get a specific field from a header like content type or all fields as array
+     *
+     * If the header occurs more than once, only the value from the first header
+     * is returned.
+     *
+     * Throws a Zend_Mail_Exception if the requested header does not exist. If
+     * the specific header field does not exist, returns null.
+     *
+     * @param  string $name       name of header, like in getHeader()
+     * @param  string $wantedPart the wanted part, default is first, if null an array with all parts is returned
+     * @param  string $firstName  key name for the first part
+     * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
+     * @throws Zend_Exception, Zend_Mail_Exception
+     */
+    public function getHeaderField($name, $wantedPart = 0, $firstName = 0);
+
+
+    /**
+     * Getter for mail headers - name is matched in lowercase
+     *
+     * This getter is short for Zend_Mail_Part::getHeader($name, 'string')
+     *
+     * @see Zend_Mail_Part::getHeader()
+     *
+     * @param  string $name header name
+     * @return string value of header
+     * @throws Zend_Mail_Exception
+     */
+    public function __get($name);
+
+    /**
+     * magic method to get content of part
+     *
+     * @return string content
+     */
+    public function __toString();
+}
\ No newline at end of file
diff --git a/lib/Zend/Mail/Protocol/Abstract.php b/lib/Zend/Mail/Protocol/Abstract.php
new file mode 100644
index 0000000..cfb1f42
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Abstract.php
@@ -0,0 +1,385 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Abstract.php 12395 2008-11-07 23:58:38Z nico $
+ */
+
+
+/**
+ * @see Zend_Validate
+ */
+require_once 'Zend/Validate.php';
+
+
+/**
+ * @see Zend_Validate_Hostname
+ */
+require_once 'Zend/Validate/Hostname.php';
+
+
+/**
+ * Zend_Mail_Protocol_Abstract
+ *
+ * Provides low-level methods for concrete adapters to communicate with a remote mail server and track requests and responses.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Abstract.php 12395 2008-11-07 23:58:38Z nico $
+ * @todo Implement proxy settings
+ */
+abstract class Zend_Mail_Protocol_Abstract
+{
+    /**
+     * Mail default EOL string
+     */
+    const EOL = "\r\n";
+
+
+    /**
+     * Default timeout in seconds for initiating session
+     */
+    const TIMEOUT_CONNECTION = 30;
+
+
+    /**
+     * Hostname or IP address of remote server
+     * @var string
+     */
+    protected $_host;
+
+
+    /**
+     * Port number of connection
+     * @var integer
+     */
+    protected $_port;
+
+
+    /**
+     * Instance of Zend_Validate to check hostnames
+     * @var Zend_Validate
+     */
+    protected $_validHost;
+
+
+    /**
+     * Socket connection resource
+     * @var resource
+     */
+    protected $_socket;
+
+
+    /**
+     * Last request sent to server
+     * @var string
+     */
+    protected $_request;
+
+
+    /**
+     * Array of server responses to last request
+     * @var array
+     */
+    protected $_response;
+
+
+    /**
+     * String template for parsing server responses using sscanf (default: 3 digit code and response string)
+     * @var resource
+     */
+    protected $_template = '%d%s';
+
+
+    /**
+     * Log of mail requests and server responses for a session
+     * @var string
+     */
+    private $_log;
+
+
+    /**
+     * Constructor.
+     *
+     * @param  string  $host OPTIONAL Hostname of remote connection (default: 127.0.0.1)
+     * @param  integer $port OPTIONAL Port number (default: null)
+     * @throws Zend_Mail_Protocol_Exception
+     * @return void
+     */
+    public function __construct($host = '127.0.0.1', $port = null)
+    {
+        $this->_validHost = new Zend_Validate();
+        $this->_validHost->addValidator(new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL));
+
+        if (!$this->_validHost->isValid($host)) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
+        }
+
+        $this->_host = $host;
+        $this->_port = $port;
+    }
+
+
+    /**
+     * Class destructor to cleanup open resources
+     *
+     * @return void
+     */
+    public function __destruct()
+    {
+        $this->_disconnect();
+    }
+
+
+    /**
+     * Create a connection to the remote host
+     *
+     * Concrete adapters for this class will implement their own unique connect scripts, using the _connect() method to create the socket resource.
+     */
+    abstract public function connect();
+
+
+    /**
+     * Retrieve the last client request
+     *
+     * @return string
+     */
+    public function getRequest()
+    {
+        return $this->_request;
+    }
+
+
+    /**
+     * Retrieve the last server response
+     *
+     * @return array
+     */
+    public function getResponse()
+    {
+        return $this->_response;
+    }
+
+
+    /**
+     * Retrieve the transaction log
+     *
+     * @return string
+     */
+    public function getLog()
+    {
+        return $this->_log;
+    }
+
+
+    /**
+     * Reset the transaction log
+     *
+     * @return void
+     */
+    public function resetLog()
+    {
+        $this->_log = '';
+    }
+
+
+    /**
+     * Connect to the server using the supplied transport and target
+     *
+     * An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222'
+     *
+     * @param  string $remote Remote
+     * @throws Zend_Mail_Protocol_Exception
+     * @return boolean
+     */
+    protected function _connect($remote)
+    {
+        $errorNum = 0;
+        $errorStr = '';
+
+        // open connection
+        $this->_socket = @stream_socket_client($remote, $errorNum, $errorStr, self::TIMEOUT_CONNECTION);
+
+        if ($this->_socket === false) {
+            if ($errorNum == 0) {
+                $errorStr = 'Could not open socket';
+            }
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception($errorStr);
+        }
+
+        if (($result = stream_set_timeout($this->_socket, self::TIMEOUT_CONNECTION)) === false) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('Could not set stream timeout');
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * Disconnect from remote host and free resource
+     *
+     * @return void
+     */
+    protected function _disconnect()
+    {
+        if (is_resource($this->_socket)) {
+            fclose($this->_socket);
+        }
+    }
+
+
+    /**
+     * Send the given request followed by a LINEEND to the server.
+     *
+     * @param  string $request
+     * @throws Zend_Mail_Protocol_Exception
+     * @return integer|boolean Number of bytes written to remote host
+     */
+    protected function _send($request)
+    {
+        if (!is_resource($this->_socket)) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
+        }
+
+        $this->_request = $request;
+
+        $result = fwrite($this->_socket, $request . self::EOL);
+
+        // Save request to internal log
+        $this->_log .= $request . self::EOL;
+
+        if ($result === false) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('Could not send request to ' . $this->_host);
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * Get a line from the stream.
+     *
+     * @var    integer $timeout Per-request timeout value if applicable
+     * @throws Zend_Mail_Protocol_Exception
+     * @return string
+     */
+    protected function _receive($timeout = null)
+    {
+        if (!is_resource($this->_socket)) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host);
+        }
+
+        // Adapters may wish to supply per-commend timeouts according to appropriate RFC
+        if ($timeout !== null) {
+           stream_set_timeout($this->_socket, $timeout);
+        }
+
+        // Retrieve response
+        $reponse = fgets($this->_socket, 1024);
+
+        // Save request to internal log
+        $this->_log .= $reponse;
+
+        // Check meta data to ensure connection is still valid
+        $info = stream_get_meta_data($this->_socket);
+
+        if (!empty($info['timed_out'])) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception($this->_host . ' has timed out');
+        }
+
+        if ($reponse === false) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('Could not read from ' . $this->_host);
+        }
+
+        return $reponse;
+    }
+
+
+    /**
+     * Parse server response for successful codes
+     *
+     * Read the response from the stream and check for expected return code.
+     * Throws a Zend_Mail_Protocol_Exception if an unexpected code is returned.
+     *
+     * @param  string|array $code One or more codes that indicate a successful response
+     * @throws Zend_Mail_Protocol_Exception
+     * @return string Last line of response string
+     */
+    protected function _expect($code, $timeout = null)
+    {
+        $this->_response = array();
+        $cmd = '';
+        $msg = '';
+
+        if (!is_array($code)) {
+            $code = array($code);
+        }
+
+        do {
+            $this->_response[] = $result = $this->_receive($timeout);
+            sscanf($result, $this->_template, $cmd, $msg);
+
+            if ($cmd === null || !in_array($cmd, $code)) {
+                /**
+                 * @see Zend_Mail_Protocol_Exception
+                 */
+                require_once 'Zend/Mail/Protocol/Exception.php';
+                throw new Zend_Mail_Protocol_Exception($result);
+            }
+
+        } while (strpos($msg, '-') === 0); // The '-' message prefix indicates an information string instead of a response string.
+
+        return $msg;
+    }
+}
diff --git a/lib/Zend/Mail/Protocol/Exception.php b/lib/Zend/Mail/Protocol/Exception.php
new file mode 100644
index 0000000..c3add11
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Exception.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Exception
+ */
+require_once 'Zend/Mail/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Exception extends Zend_Mail_Exception
+{}
+
diff --git a/lib/Zend/Mail/Protocol/Imap.php b/lib/Zend/Mail/Protocol/Imap.php
new file mode 100644
index 0000000..eec0ff3
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Imap.php
@@ -0,0 +1,837 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Imap.php 12539 2008-11-11 02:47:17Z yoshida@zend.co.jp $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Imap
+{
+    /**
+     * Default timeout in seconds for initiating session
+     */
+    const TIMEOUT_CONNECTION = 30;
+    
+    /**
+     * socket to imap server
+     * @var resource|null
+     */
+    protected $_socket;
+
+    /**
+     * counter for request tag
+     * @var int
+     */
+    protected $_tagCount = 0;
+
+    /**
+     * Public constructor
+     *
+     * @param  string   $host  hostname of IP address of IMAP server, if given connect() is called
+     * @param  int|null $port  port of IMAP server, null for default (143 or 993 for ssl)
+     * @param  bool     $ssl   use ssl? 'SSL', 'TLS' or false
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    function __construct($host = '', $port = null, $ssl = false)
+    {
+        if ($host) {
+            $this->connect($host, $port, $ssl);
+        }
+    }
+
+    /**
+     * Public destructor
+     */
+    public function __destruct()
+    {
+        $this->logout();
+    }
+
+    /**
+     * Open connection to POP3 server
+     *
+     * @param  string      $host  hostname of IP address of POP3 server
+     * @param  int|null    $port  of IMAP server, default is 143 (993 for ssl)
+     * @param  string|bool $ssl   use 'SSL', 'TLS' or false
+     * @return string welcome message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function connect($host, $port = null, $ssl = false)
+    {
+        if ($ssl == 'SSL') {
+            $host = 'ssl://' . $host;
+        }
+
+        if ($port === null) {
+            $port = $ssl === 'SSL' ? 993 : 143;
+        }
+
+        $errno  =  0;
+        $errstr = '';
+        $this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
+        if (!$this->_socket) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('cannot connect to host : ' . $errno . ' : ' . $errstr);
+        }
+
+        if (!$this->_assumedNextLine('* OK')) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('host doesn\'t allow connection');
+        }
+
+        if ($ssl === 'TLS') {
+            $result = $this->requestAndResponse('STARTTLS');
+            $result = $result && stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
+            if (!$result) {
+                /**
+                 * @see Zend_Mail_Protocol_Exception
+                 */
+                require_once 'Zend/Mail/Protocol/Exception.php';
+                throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
+            }
+        }
+    }
+
+    /**
+     * get the next line from socket with error checking, but nothing else
+     *
+     * @return string next line
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    protected function _nextLine()
+    {
+        $line = @fgets($this->_socket);
+        if ($line === false) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('cannot read - connection closed?');
+        }
+
+        return $line;
+    }
+
+    /**
+     * get next line and assume it starts with $start. some requests give a simple
+     * feedback so we can quickly check if we can go on.
+     *
+     * @param  string $start the first bytes we assume to be in the next line
+     * @return bool line starts with $start
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    protected function _assumedNextLine($start)
+    {
+        $line = $this->_nextLine();
+        return strpos($line, $start) === 0;
+    }
+
+    /**
+     * get next line and split the tag. that's the normal case for a response line
+     *
+     * @param  string $tag tag of line is returned by reference
+     * @return string next line
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    protected function _nextTaggedLine(&$tag)
+    {
+        $line = $this->_nextLine();
+
+        // seperate tag from line
+        list($tag, $line) = explode(' ', $line, 2);
+
+        return $line;
+    }
+
+    /**
+     * split a given line in tokens. a token is literal of any form or a list
+     *
+     * @param  string $line line to decode
+     * @return array tokens, literals are returned as string, lists as array
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    protected function _decodeLine($line)
+    {
+        $tokens = array();
+        $stack = array();
+
+        /*
+            We start to decode the response here. The unterstood tokens are:
+                literal
+                "literal" or also "lit\\er\"al"
+                {bytes}<NL>literal
+                (literals*)
+            All tokens are returned in an array. Literals in braces (the last unterstood
+            token in the list) are returned as an array of tokens. I.e. the following response:
+                "foo" baz {3}<NL>bar ("f\\\"oo" bar)
+            would be returned as:
+                array('foo', 'baz', 'bar', array('f\\\"oo', 'bar'));
+                
+            // TODO: add handling of '[' and ']' to parser for easier handling of response text 
+        */
+        //  replace any trailling <NL> including spaces with a single space
+        $line = rtrim($line) . ' ';
+        while (($pos = strpos($line, ' ')) !== false) {
+            $token = substr($line, 0, $pos);
+            while ($token[0] == '(') {
+                array_push($stack, $tokens);
+                $tokens = array();
+                $token = substr($token, 1);
+            }
+            if ($token[0] == '"') {
+                if (preg_match('%^"((.|\\\\|\\")*?)" *%', $line, $matches)) {
+                    $tokens[] = $matches[1];
+                    $line = substr($line, strlen($matches[0]));
+                    continue;
+                }
+            }
+            if ($token[0] == '{') {
+                $endPos = strpos($token, '}');
+                $chars = substr($token, 1, $endPos - 1);
+                if (is_numeric($chars)) {
+                    $token = '';
+                    while (strlen($token) < $chars) {
+                        $token .= $this->_nextLine();
+                    }
+                    $line = '';
+                    if (strlen($token) > $chars) {
+                        $line = substr($token, $chars);
+                        $token = substr($token, 0, $chars);
+                    } else {
+                        $line .= $this->_nextLine();
+                    }
+                    $tokens[] = $token;
+                    $line = trim($line) . ' ';
+                    continue;
+                }
+            }
+            if ($stack && $token[strlen($token) - 1] == ')') {
+                // closing braces are not seperated by spaces, so we need to count them
+                $braces = strlen($token);
+                $token = rtrim($token, ')');
+                // only count braces if more than one
+                $braces -= strlen($token) + 1;
+                // only add if token had more than just closing braces
+                if ($token) {
+                    $tokens[] = $token;
+                }
+                $token = $tokens;
+                $tokens = array_pop($stack);
+                // special handline if more than one closing brace
+                while ($braces-- > 0) {
+                    $tokens[] = $token;
+                    $token = $tokens;
+                    $tokens = array_pop($stack);
+                }
+            }
+            $tokens[] = $token;
+            $line = substr($line, $pos + 1);
+        }
+
+        // maybe the server forgot to send some closing braces
+        while ($stack) {
+            $child = $tokens;
+            $tokens = array_pop($stack);
+            $tokens[] = $child;
+        }
+
+        return $tokens;
+    }
+
+    /**
+     * read a response "line" (could also be more than one real line if response has {..}<NL>)
+     * and do a simple decode
+     *
+     * @param  array|string  $tokens    decoded tokens are returned by reference, if $dontParse
+     *                                  is true the unparsed line is returned here
+     * @param  string        $wantedTag check for this tag for response code. Default '*' is
+     *                                  continuation tag.
+     * @param  bool          $dontParse if true only the unparsed line is returned $tokens
+     * @return bool if returned tag matches wanted tag
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function readLine(&$tokens = array(), $wantedTag = '*', $dontParse = false)
+    {
+        $line = $this->_nextTaggedLine($tag);
+        if (!$dontParse) {
+            $tokens = $this->_decodeLine($line);
+        } else {
+            $tokens = $line;
+        }
+
+        // if tag is wanted tag we might be at the end of a multiline response
+        return $tag == $wantedTag;
+    }
+
+    /**
+     * read all lines of response until given tag is found (last line of response)
+     *
+     * @param  string       $tag       the tag of your request
+     * @param  string|array $filter    you can filter the response so you get only the
+     *                                 given response lines
+     * @param  bool         $dontParse if true every line is returned unparsed instead of
+     *                                 the decoded tokens
+     * @return null|bool|array tokens if success, false if error, null if bad request
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function readResponse($tag, $dontParse = false)
+    {
+        $lines = array();
+        while (!$this->readLine($tokens, $tag, $dontParse)) {
+            $lines[] = $tokens;
+        }
+
+        if ($dontParse) {
+            // last to chars are still needed for response code
+            $tokens = array(substr($tokens, 0, 2));
+        }
+        // last line has response code
+        if ($tokens[0] == 'OK') {
+            return $lines ? $lines : true;
+        } else if ($tokens[0] == 'NO'){
+            return false;
+        }
+        return null;
+    }
+
+    /**
+     * send a request
+     *
+     * @param  string $command your request command
+     * @param  array  $tokens  additional parameters to command, use escapeString() to prepare
+     * @param  string $tag     provide a tag otherwise an autogenerated is returned
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function sendRequest($command, $tokens = array(), &$tag = null)
+    {
+        if (!$tag) {
+            ++$this->_tagCount;
+            $tag = 'TAG' . $this->_tagCount;
+        }
+
+        $line = $tag . ' ' . $command;
+
+        foreach ($tokens as $token) {
+            if (is_array($token)) {
+                if (@fputs($this->_socket, $line . ' ' . $token[0] . "\r\n") === false) {
+                    /**
+                     * @see Zend_Mail_Protocol_Exception
+                     */
+                    require_once 'Zend/Mail/Protocol/Exception.php';
+                    throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
+                }
+                if (!$this->_assumedNextLine('+ ')) {
+                    /**
+                     * @see Zend_Mail_Protocol_Exception
+                     */
+                    require_once 'Zend/Mail/Protocol/Exception.php';
+                    throw new Zend_Mail_Protocol_Exception('cannot send literal string');
+                }
+                $line = $token[1];
+            } else {
+                $line .= ' ' . $token;
+            }
+        }
+
+        if (@fputs($this->_socket, $line . "\r\n") === false) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('cannot write - connection closed?');
+        }
+    }
+
+    /**
+     * send a request and get response at once
+     *
+     * @param  string $command   command as in sendRequest()
+     * @param  array  $tokens    parameters as in sendRequest()
+     * @param  bool   $dontParse if true unparsed lines are returned instead of tokens
+     * @return mixed response as in readResponse()
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function requestAndResponse($command, $tokens = array(), $dontParse = false)
+    {
+        $this->sendRequest($command, $tokens, $tag);
+        $response = $this->readResponse($tag, $dontParse);
+
+        return $response;
+    }
+
+    /**
+     * escape one or more literals i.e. for sendRequest
+     *
+     * @param  string|array $string the literal/-s
+     * @return string|array escape literals, literals with newline ar returned
+     *                      as array('{size}', 'string');
+     */
+    public function escapeString($string)
+    {
+        if (func_num_args() < 2) {
+            if (strpos($string, "\n") !== false) {
+                return array('{' . strlen($string) . '}', $string);
+            } else {
+                return '"' . str_replace(array('\\', '"'), array('\\\\', '\\"'), $string) . '"';
+            }
+        }
+        $result = array();
+        foreach (func_get_args() as $string) {
+            $result[] = $this->escapeString($string);
+        }
+        return $result;
+    }
+
+    /**
+     * escape a list with literals or lists
+     *
+     * @param  array $list list with literals or lists as PHP array
+     * @return string escaped list for imap
+     */
+    public function escapeList($list)
+    {
+        $result = array();
+        foreach ($list as $k => $v) {
+            if (!is_array($v)) {
+//              $result[] = $this->escapeString($v);
+                $result[] = $v;
+                continue;
+            }
+            $result[] = $this->escapeList($v);
+        }
+        return '(' . implode(' ', $result) . ')';
+    }
+
+    /**
+     * Login to IMAP server.
+     *
+     * @param  string $user      username
+     * @param  string $password  password
+     * @return bool success
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function login($user, $password)
+    {
+        return $this->requestAndResponse('LOGIN', $this->escapeString($user, $password), true);
+    }
+
+    /**
+     * logout of imap server
+     *
+     * @return bool success
+     */
+    public function logout()
+    {
+        $result = false;
+        if ($this->_socket) {
+            try {
+                $result = $this->requestAndResponse('LOGOUT', array(), true);
+            } catch (Zend_Mail_Protocol_Exception $e) {
+                // ignoring exception
+            }
+            fclose($this->_socket);
+            $this->_socket = null;
+        }
+        return $result;
+    }
+
+
+    /**
+     * Get capabilities from IMAP server
+     *
+     * @return array list of capabilities
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function capability()
+    {
+        $response = $this->requestAndResponse('CAPABILITY');
+
+        if (!$response) {
+            return $response;
+        }
+
+        $capabilities = array();
+        foreach ($response as $line) {
+            $capabilities = array_merge($capabilities, $line);
+        }
+        return $capabilities;
+    }
+
+    /**
+     * Examine and select have the same response. The common code for both
+     * is in this method
+     *
+     * @param  string $command can be 'EXAMINE' or 'SELECT' and this is used as command
+     * @param  string $box which folder to change to or examine
+     * @return bool|array false if error, array with returned information
+     *                    otherwise (flags, exists, recent, uidvalidity)
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function examineOrSelect($command = 'EXAMINE', $box = 'INBOX')
+    {
+        $this->sendRequest($command, array($this->escapeString($box)), $tag);
+
+        $result = array();
+        while (!$this->readLine($tokens, $tag)) {
+            if ($tokens[0] == 'FLAGS') {
+                array_shift($tokens);
+                $result['flags'] = $tokens;
+                continue;
+            }
+            switch ($tokens[1]) {
+                case 'EXISTS':
+                case 'RECENT':
+                    $result[strtolower($tokens[1])] = $tokens[0];
+                    break;
+                case '[UIDVALIDITY':
+                    $result['uidvalidity'] = (int)$tokens[2];
+                    break;
+                default:
+                    // ignore
+            }
+        }
+
+        if ($tokens[0] != 'OK') {
+            return false;
+        }
+        return $result;
+    }
+
+    /**
+     * change folder
+     *
+     * @param  string $box change to this folder
+     * @return bool|array see examineOrselect()
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function select($box = 'INBOX')
+    {
+        return $this->examineOrSelect('SELECT', $box);
+    }
+
+    /**
+     * examine folder
+     *
+     * @param  string $box examine this folder
+     * @return bool|array see examineOrselect()
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function examine($box = 'INBOX')
+    {
+        return $this->examineOrSelect('EXAMINE', $box);
+    }
+
+    /**
+     * fetch one or more items of one or more messages
+     *
+     * @param  string|array $items items to fetch from message(s) as string (if only one item)
+     *                             or array of strings
+     * @param  int          $from  message for items or start message if $to !== null
+     * @param  int|null     $to    if null only one message ($from) is fetched, else it's the
+     *                             last message, INF means last message avaible
+     * @return string|array if only one item of one message is fetched it's returned as string
+     *                      if items of one message are fetched it's returned as (name => value)
+     *                      if one items of messages are fetched it's returned as (msgno => value)
+     *                      if items of messages are fetchted it's returned as (msgno => (name => value))
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function fetch($items, $from, $to = null)
+    {
+        if (is_array($from)) {
+            $set = implode(',', $from);
+        } else if ($to === null) {
+            $set = (int)$from;
+        } else if ($to === INF) {
+            $set = (int)$from . ':*';
+        } else {
+            $set = (int)$from . ':' . (int)$to;
+        }
+
+        $items = (array)$items;
+        $itemList = $this->escapeList($items);
+
+        $this->sendRequest('FETCH', array($set, $itemList), $tag);
+
+        $result = array();
+        while (!$this->readLine($tokens, $tag)) {
+            // ignore other responses
+            if ($tokens[1] != 'FETCH') {
+                continue;
+            }
+            // ignore other messages
+            if ($to === null && !is_array($from) && $tokens[0] != $from) {
+                continue;
+            }
+            // if we only want one item we return that one directly
+            if (count($items) == 1) {
+                if ($tokens[2][0] == $items[0]) {
+                    $data = $tokens[2][1];
+                } else {
+                    // maybe the server send an other field we didn't wanted
+                    $count = count($tokens[2]);
+                    // we start with 2, because 0 was already checked
+                    for ($i = 2; $i < $count; $i += 2) {
+                        if ($tokens[2][$i] != $items[0]) {
+                            continue;
+                        }
+                        $data = $tokens[2][$i + 1];
+                        break;
+                    }
+                }
+            } else {
+                $data = array();
+                while (key($tokens[2]) !== null) {
+                    $data[current($tokens[2])] = next($tokens[2]);
+                    next($tokens[2]);
+                }
+            }
+            // if we want only one message we can ignore everything else and just return
+            if ($to === null && !is_array($from) && $tokens[0] == $from) {
+                // we still need to read all lines
+                while (!$this->readLine($tokens, $tag));
+                return $data;
+            }
+            $result[$tokens[0]] = $data;
+        }
+
+        if ($to === null && !is_array($from)) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('the single id was not found in response');
+        }
+
+        return $result;
+    }
+
+    /**
+     * get mailbox list
+     *
+     * this method can't be named after the IMAP command 'LIST', as list is a reserved keyword
+     *
+     * @param  string $reference mailbox reference for list
+     * @param  string $mailbox   mailbox name match with wildcards
+     * @return array mailboxes that matched $mailbox as array(globalName => array('delim' => .., 'flags' => ..))
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function listMailbox($reference = '', $mailbox = '*')
+    {
+        $result = array();
+        $list = $this->requestAndResponse('LIST', $this->escapeString($reference, $mailbox));
+        if (!$list || $list === true) {
+            return $result;
+        }
+
+        foreach ($list as $item) {
+            if (count($item) != 4 || $item[0] != 'LIST') {
+                continue;
+            }
+            $result[$item[3]] = array('delim' => $item[2], 'flags' => $item[1]);
+        }
+
+        return $result;
+    }
+
+    /**
+     * set flags
+     *
+     * @param  array       $flags  flags to set, add or remove - see $mode
+     * @param  int         $from   message for items or start message if $to !== null
+     * @param  int|null    $to     if null only one message ($from) is fetched, else it's the
+     *                             last message, INF means last message avaible
+     * @param  string|null $mode   '+' to add flags, '-' to remove flags, everything else sets the flags as given
+     * @param  bool        $silent if false the return values are the new flags for the wanted messages
+     * @return bool|array new flags if $silent is false, else true or false depending on success
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function store(array $flags, $from, $to = null, $mode = null, $silent = true)
+    {
+        $item = 'FLAGS';
+        if ($mode == '+' || $mode == '-') {
+            $item = $mode . $item;
+        }
+        if ($silent) {
+            $item .= '.SILENT';
+        }
+
+        $flags = $this->escapeList($flags);
+        $set = (int)$from;
+        if ($to != null) {
+            $set .= ':' . ($to == INF ? '*' : (int)$to);
+        }
+
+        $result = $this->requestAndResponse('STORE', array($set, $item, $flags), $silent);
+
+        if ($silent) {
+            return $result ? true : false;
+        }
+
+        $tokens = $result;
+        $result = array();
+        foreach ($tokens as $token) {
+            if ($token[1] != 'FETCH' || $token[2][0] != 'FLAGS') {
+                continue;
+            }
+            $result[$token[0]] = $token[2][1];
+        }
+
+        return $result;
+    }
+
+    /**
+     * append a new message to given folder
+     *
+     * @param string $folder  name of target folder
+     * @param string $message full message content
+     * @param array  $flags   flags for new message
+     * @param string $date    date for new message
+     * @return bool success
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function append($folder, $message, $flags = null, $date = null)
+    {
+        $tokens = array();
+        $tokens[] = $this->escapeString($folder);
+        if ($flags !== null) {
+            $tokens[] = $this->escapeList($flags);
+        }
+        if ($date !== null) {
+            $tokens[] = $this->escapeString($date);
+        }
+        $tokens[] = $this->escapeString($message);
+
+        return $this->requestAndResponse('APPEND', $tokens, true);
+    }
+
+    /**
+     * copy message set from current folder to other folder
+     *
+     * @param string   $folder destination folder
+     * @param int|null $to     if null only one message ($from) is fetched, else it's the
+     *                         last message, INF means last message avaible
+     * @return bool success
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function copy($folder, $from, $to = null)
+    {
+        $set = (int)$from;
+        if ($to != null) {
+            $set .= ':' . ($to == INF ? '*' : (int)$to);
+        }
+
+        return $this->requestAndResponse('COPY', array($set, $this->escapeString($folder)), true);
+    }
+
+    /**
+     * create a new folder (and parent folders if needed)
+     *
+     * @param string $folder folder name
+     * @return bool success
+     */
+    public function create($folder)
+    {
+        return $this->requestAndResponse('CREATE', array($this->escapeString($folder)), true);
+    }
+
+    /**
+     * rename an existing folder
+     *
+     * @param string $old old name
+     * @param string $new new name
+     * @return bool success
+     */
+    public function rename($old, $new)
+    {
+        return $this->requestAndResponse('RENAME', $this->escapeString($old, $new), true);
+    }
+
+    /**
+     * remove a folder
+     *
+     * @param string $folder folder name
+     * @return bool success
+     */
+    public function delete($folder)
+    {
+        return $this->requestAndResponse('DELETE', array($this->escapeString($folder)), true);
+    }
+
+    /**
+     * permanently remove messages
+     *
+     * @return bool success
+     */
+    public function expunge()
+    {
+        // TODO: parse response?
+        return $this->requestAndResponse('EXPUNGE');
+    }
+
+    /**
+     * send noop
+     *
+     * @return bool success
+     */
+    public function noop()
+    {
+        // TODO: parse response
+        return $this->requestAndResponse('NOOP');
+    }
+
+    /**
+     * do a search request
+     *
+     * This method is currently marked as internal as the API might change and is not
+     * safe if you don't take precautions.
+     *
+     * @internal
+     * @return array message ids
+     */
+    public function search(array $params)
+    {
+        $response = $this->requestAndResponse('SEARCH', $params);
+        if (!$response) {
+            return $response;
+        }
+        
+        foreach ($response as $ids) {
+            if ($ids[0] == 'SEARCH') {
+                array_shift($ids);
+                return $ids;
+            }
+        }
+        return array();
+    }
+
+}
diff --git a/lib/Zend/Mail/Protocol/Pop3.php b/lib/Zend/Mail/Protocol/Pop3.php
new file mode 100644
index 0000000..c1f968a
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Pop3.php
@@ -0,0 +1,471 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Pop3.php 12539 2008-11-11 02:47:17Z yoshida@zend.co.jp $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Pop3
+{
+    /**
+     * Default timeout in seconds for initiating session
+     */
+    const TIMEOUT_CONNECTION = 30;
+    
+    /**
+     * saves if server supports top
+     * @var null|bool
+     */
+    public $hasTop = null;
+
+    /**
+     * socket to pop3
+     * @var null|resource
+     */
+    protected $_socket;
+
+    /**
+     * greeting timestamp for apop
+     * @var null|string
+     */
+    protected $_timestamp;
+
+
+    /**
+     * Public constructor
+     *
+     * @param  string      $host  hostname of IP address of POP3 server, if given connect() is called
+     * @param  int|null    $port  port of POP3 server, null for default (110 or 995 for ssl)
+     * @param  bool|string $ssl   use ssl? 'SSL', 'TLS' or false
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function __construct($host = '', $port = null, $ssl = false)
+    {
+        if ($host) {
+            $this->connect($host, $port, $ssl);
+        }
+    }
+
+
+    /**
+     * Public destructor
+     */
+    public function __destruct()
+    {
+        $this->logout();
+    }
+
+
+    /**
+     * Open connection to POP3 server
+     *
+     * @param  string      $host  hostname of IP address of POP3 server
+     * @param  int|null    $port  of POP3 server, default is 110 (995 for ssl)
+     * @param  string|bool $ssl   use 'SSL', 'TLS' or false
+     * @return string welcome message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function connect($host, $port = null, $ssl = false)
+    {
+        if ($ssl == 'SSL') {
+            $host = 'ssl://' . $host;
+        }
+
+        if ($port === null) {
+            $port = $ssl == 'SSL' ? 995 : 110;
+        }
+
+        $errno  =  0;
+        $errstr = '';
+        $this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
+        if (!$this->_socket) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('cannot connect to host : ' . $errno . ' : ' . $errstr);
+        }
+
+        $welcome = $this->readResponse();
+
+        strtok($welcome, '<');
+        $this->_timestamp = strtok('>');
+        if (!strpos($this->_timestamp, '@')) {
+            $this->_timestamp = null;
+        } else {
+            $this->_timestamp = '<' . $this->_timestamp . '>';
+        }
+
+        if ($ssl === 'TLS') {
+            $this->request('STLS');
+            $result = stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
+            if (!$result) {
+                /**
+                 * @see Zend_Mail_Protocol_Exception
+                 */
+                require_once 'Zend/Mail/Protocol/Exception.php';
+                throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
+            }
+        }
+
+        return $welcome;
+    }
+
+
+    /**
+     * Send a request
+     *
+     * @param string $request your request without newline
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function sendRequest($request)
+    {
+        $result = @fputs($this->_socket, $request . "\r\n");
+        if (!$result) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('send failed - connection closed?');
+        }
+    }
+
+
+    /**
+     * read a response
+     *
+     * @param  boolean $multiline response has multiple lines and should be read until "<nl>.<nl>"
+     * @return string response
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function readResponse($multiline = false)
+    {
+        $result = @fgets($this->_socket);
+        if (!is_string($result)) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('read failed - connection closed?');
+        }
+
+        $result = trim($result);
+        if (strpos($result, ' ')) {
+            list($status, $message) = explode(' ', $result, 2);
+        } else {
+            $status = $result;
+            $message = '';
+        }
+
+        if ($status != '+OK') {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('last request failed');
+        }
+
+        if ($multiline) {
+            $message = '';
+            $line = fgets($this->_socket);
+            while ($line && rtrim($line, "\r\n") != '.') {
+                if ($line[0] == '.') {
+                    $line = substr($line, 1);
+                }
+                $message .= $line;
+                $line = fgets($this->_socket);
+            };
+        }
+
+        return $message;
+    }
+
+
+    /**
+     * Send request and get resposne
+     *
+     * @see sendRequest(), readResponse()
+     *
+     * @param  string $request    request
+     * @param  bool   $multiline  multiline response?
+     * @return string             result from readResponse()
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function request($request, $multiline = false)
+    {
+        $this->sendRequest($request);
+        return $this->readResponse($multiline);
+    }
+
+
+    /**
+     * End communication with POP3 server (also closes socket)
+     *
+     * @return null
+     */
+    public function logout()
+    {
+        if (!$this->_socket) {
+            return;
+        }
+
+        try {
+            $this->request('QUIT');
+        } catch (Zend_Mail_Protocol_Exception $e) {
+            // ignore error - we're closing the socket anyway
+        }
+
+        fclose($this->_socket);
+        $this->_socket = null;
+    }
+
+
+    /**
+     * Get capabilities from POP3 server
+     *
+     * @return array list of capabilities
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function capa()
+    {
+        $result = $this->request('CAPA', true);
+        return explode("\n", $result);
+    }
+
+
+    /**
+     * Login to POP3 server. Can use APOP
+     *
+     * @param  string $user      username
+     * @param  string $password  password
+     * @param  bool   $try_apop  should APOP be tried?
+     * @return void
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function login($user, $password, $tryApop = true)
+    {
+        if ($tryApop && $this->_timestamp) {
+            try {
+                $this->request("APOP $user " . md5($this->_timestamp . $password));
+                return;
+            } catch (Zend_Mail_Protocol_Exception $e) {
+                // ignore
+            }
+        }
+
+        $result = $this->request("USER $user");
+        $result = $this->request("PASS $password");
+    }
+
+
+    /**
+     * Make STAT call for message count and size sum
+     *
+     * @param  int $messages  out parameter with count of messages
+     * @param  int $octets    out parameter with size in octects of messages
+     * @return void
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function status(&$messages, &$octets)
+    {
+        $messages = 0;
+        $octets = 0;
+        $result = $this->request('STAT');
+
+        list($messages, $octets) = explode(' ', $result);
+    }
+
+
+    /**
+     * Make LIST call for size of message(s)
+     *
+     * @param  int|null $msgno number of message, null for all
+     * @return int|array size of given message or list with array(num => size)
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function getList($msgno = null)
+    {
+        if ($msgno !== null) {
+            $result = $this->request("LIST $msgno");
+
+            list(, $result) = explode(' ', $result);
+            return (int)$result;
+        }
+
+        $result = $this->request('LIST', true);
+        $messages = array();
+        $line = strtok($result, "\n");
+        while ($line) {
+            list($no, $size) = explode(' ', trim($line));
+            $messages[(int)$no] = (int)$size;
+            $line = strtok("\n");
+        }
+
+        return $messages;
+    }
+
+
+    /**
+     * Make UIDL call for getting a uniqueid
+     *
+     * @param  int|null $msgno number of message, null for all
+     * @return string|array uniqueid of message or list with array(num => uniqueid)
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function uniqueid($msgno = null)
+    {
+        if ($msgno !== null) {
+            $result = $this->request("UIDL $msgno");
+
+            list(, $result) = explode(' ', $result);
+            return $result;
+        }
+
+        $result = $this->request('UIDL', true);
+
+        $result = explode("\n", $result);
+        $messages = array();
+        foreach ($result as $line) {
+            if (!$line) {
+                continue;
+            }
+            list($no, $id) = explode(' ', trim($line), 2);
+            $messages[(int)$no] = $id;
+        }
+
+        return $messages;
+
+    }
+
+
+    /**
+     * Make TOP call for getting headers and maybe some body lines
+     * This method also sets hasTop - before it it's not known if top is supported
+     *
+     * The fallback makes normale RETR call, which retrieves the whole message. Additional
+     * lines are not removed.
+     *
+     * @param  int  $msgno    number of message
+     * @param  int  $lines    number of wanted body lines (empty line is inserted after header lines)
+     * @param  bool $fallback fallback with full retrieve if top is not supported
+     * @return string message headers with wanted body lines
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function top($msgno, $lines = 0, $fallback = false)
+    {
+        if ($this->hasTop === false) {
+            if ($fallback) {
+                return $this->retrieve($msgno);
+            } else {
+                /**
+                 * @see Zend_Mail_Protocol_Exception
+                 */
+                require_once 'Zend/Mail/Protocol/Exception.php';
+                throw new Zend_Mail_Protocol_Exception('top not supported and no fallback wanted');
+            }
+        }
+        $this->hasTop = true;
+
+        $lines = (!$lines || $lines < 1) ? 0 : (int)$lines;
+
+        try {
+            $result = $this->request("TOP $msgno $lines", true);
+        } catch (Zend_Mail_Protocol_Exception $e) {
+            $this->hasTop = false;
+            if ($fallback) {
+                $result = $this->retrieve($msgno);
+            } else {
+                throw $e;
+            }
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * Make a RETR call for retrieving a full message with headers and body
+     *
+     * @deprecated since 1.1.0; this method has a typo - please use retrieve()
+     * @param  int $msgno  message number
+     * @return string message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function retrive($msgno)
+    {
+        return $this->retrieve($msgno);
+    }
+
+
+    /**
+     * Make a RETR call for retrieving a full message with headers and body
+     *
+     * @param  int $msgno  message number
+     * @return string message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function retrieve($msgno)
+    {
+        $result = $this->request("RETR $msgno", true);
+        return $result;
+    }
+
+    /**
+     * Make a NOOP call, maybe needed for keeping the server happy
+     *
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function noop()
+    {
+        $this->request('NOOP');
+    }
+
+
+    /**
+     * Make a DELE count to remove a message
+     *
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function delete($msgno)
+    {
+        $this->request("DELE $msgno");
+    }
+
+
+    /**
+     * Make RSET call, which rollbacks delete requests
+     *
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function undelete()
+    {
+        $this->request('RSET');
+    }
+}
diff --git a/lib/Zend/Mail/Protocol/Smtp.php b/lib/Zend/Mail/Protocol/Smtp.php
new file mode 100644
index 0000000..18ac77a
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Smtp.php
@@ -0,0 +1,443 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Smtp.php 11196 2008-09-02 00:56:25Z yoshida@zend.co.jp $
+ */
+
+
+/**
+ * @see Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+
+/**
+ * @see Zend_Mail_Protocol_Abstract
+ */
+require_once 'Zend/Mail/Protocol/Abstract.php';
+
+
+/**
+ * Smtp implementation of Zend_Mail_Protocol_Abstract
+ *
+ * Minimum implementation according to RFC2821: EHLO, MAIL FROM, RCPT TO, DATA, RSET, NOOP, QUIT
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Smtp extends Zend_Mail_Protocol_Abstract
+{
+    /**
+     * The transport method for the socket
+     *
+     * @var string
+     */
+    protected $_transport = 'tcp';
+
+
+    /**
+     * Indicates that a session is requested to be secure
+     *
+     * @var string
+     */
+    protected $_secure;
+
+
+    /**
+     * Indicates an smtp session has been started by the HELO command
+     *
+     * @var boolean
+     */
+    protected $_sess = false;
+
+
+    /**
+     * Indicates the HELO command has been issues
+     *
+     * @var unknown_type
+     */
+    protected $_helo = false;
+
+
+    /**
+     * Indicates an smtp AUTH has been issued and authenticated
+     *
+     * @var unknown_type
+     */
+    protected $_auth = false;
+
+
+    /**
+     * Indicates a MAIL command has been issued
+     *
+     * @var unknown_type
+     */
+    protected $_mail = false;
+
+
+    /**
+     * Indicates one or more RCTP commands have been issued
+     *
+     * @var unknown_type
+     */
+    protected $_rcpt = false;
+
+
+    /**
+     * Indicates that DATA has been issued and sent
+     *
+     * @var unknown_type
+     */
+    protected $_data = null;
+
+
+    /**
+     * Constructor.
+     *
+     * @param  string  $host
+     * @param  integer $port
+     * @param  array   $config
+     * @return void
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function __construct($host = '127.0.0.1', $port = null, array $config = array())
+    {
+        if (isset($config['ssl'])) {
+            switch (strtolower($config['ssl'])) {
+                case 'tls':
+                    $this->_secure = 'tls';
+                    break;
+
+                case 'ssl':
+                    $this->_transport = 'ssl';
+                    $this->_secure = 'ssl';
+                    if ($port == null) {
+                        $port = 465;
+                    }
+                    break;
+
+                default:
+                    /**
+                     * @see Zend_Mail_Protocol_Exception
+                     */
+                    require_once 'Zend/Mail/Protocol/Exception.php';
+                    throw new Zend_Mail_Protocol_Exception($config['ssl'] . ' is unsupported SSL type');
+                    break;
+            }
+        }
+
+        // If no port has been specified then check the master PHP ini file. Defaults to 25 if the ini setting is null.
+        if ($port == null) {
+            if (($port = ini_get('smtp_port')) == '') {
+                $port = 25;
+            }
+        }
+
+        parent::__construct($host, $port);
+    }
+
+
+    /**
+     * Connect to the server with the parameters given in the constructor.
+     *
+     * @return boolean
+     */
+    public function connect()
+    {
+        return $this->_connect($this->_transport . '://' . $this->_host . ':'. $this->_port);
+    }
+
+
+    /**
+     * Initiate HELO/EHLO sequence and set flag to indicate valid smtp session
+     *
+     * @param  string $host The client hostname or IP address (default: 127.0.0.1)
+     * @throws Zend_Mail_Protocol_Exception
+     * @return void
+     */
+    public function helo($host = '127.0.0.1')
+    {
+        // Respect RFC 2821 and disallow HELO attempts if session is already initiated.
+        if ($this->_sess === true) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('Cannot issue HELO to existing session');
+        }
+
+        // Validate client hostname
+        if (!$this->_validHost->isValid($host)) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages()));
+        }
+
+        // Initiate helo sequence
+        $this->_expect(220, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+        $this->_ehlo($host);
+
+        // If a TLS session is required, commence negotiation
+        if ($this->_secure == 'tls') {
+            $this->_send('STARTTLS');
+            $this->_expect(220, 180);
+            if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
+                /**
+                 * @see Zend_Mail_Protocol_Exception
+                 */
+                require_once 'Zend/Mail/Protocol/Exception.php';
+                throw new Zend_Mail_Protocol_Exception('Unable to connect via TLS');
+            }
+            $this->_ehlo($host);
+        }
+
+        $this->_startSession();
+        $this->auth();
+    }
+
+
+    /**
+     * Send EHLO or HELO depending on capabilities of smtp host
+     *
+     * @param  string $host The client hostname or IP address (default: 127.0.0.1)
+     * @throws Zend_Mail_Protocol_Exception
+     * @return void
+     */
+    protected function _ehlo($host)
+    {
+        // Support for older, less-compliant remote servers. Tries multiple attempts of EHLO or HELO.
+        try {
+            $this->_send('EHLO ' . $host);
+            $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+        } catch (Zend_Mail_Protocol_Exception $e) {
+            $this->_send('HELO ' . $host);
+            $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+        } catch (Zend_Mail_Protocol_Exception $e) {
+            throw $e;
+        }
+    }
+
+
+    /**
+     * Issues MAIL command
+     *
+     * @param  string $from Sender mailbox
+     * @throws Zend_Mail_Protocol_Exception
+     * @return void
+     */
+    public function mail($from)
+    {
+        if ($this->_sess !== true) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('A valid session has not been started');
+        }
+
+        $this->_send('MAIL FROM:<' . $from . '>');
+        $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+
+        // Set mail to true, clear recipients and any existing data flags as per 4.1.1.2 of RFC 2821
+        $this->_mail = true;
+        $this->_rcpt = false;
+        $this->_data = false;
+    }
+
+
+    /**
+     * Issues RCPT command
+     *
+     * @param  string $to Receiver(s) mailbox
+     * @throws Zend_Mail_Protocol_Exception
+     * @return void
+     */
+    public function rcpt($to)
+    {
+        if ($this->_mail !== true) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('No sender reverse path has been supplied');
+        }
+
+        // Set rcpt to true, as per 4.1.1.3 of RFC 2821
+        $this->_send('RCPT TO:<' . $to . '>');
+        $this->_expect(array(250, 251), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+        $this->_rcpt = true;
+    }
+
+
+    /**
+     * Issues DATA command
+     *
+     * @param  string $data
+     * @throws Zend_Mail_Protocol_Exception
+     * @return void
+     */
+    public function data($data)
+    {
+        // Ensure recipients have been set
+        if ($this->_rcpt !== true) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('No recipient forward path has been supplied');
+        }
+
+        $this->_send('DATA');
+        $this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2
+
+        foreach (explode(Zend_Mime::LINEEND, $data) as $line) {
+            if (strpos($line, '.') === 0) {
+                // Escape lines prefixed with a '.'
+                $line = '.' . $line;
+            }
+            $this->_send($line);
+        }
+
+        $this->_send('.');
+        $this->_expect(250, 600); // Timeout set for 10 minutes as per RFC 2821 4.5.3.2
+        $this->_data = true;
+    }
+
+
+    /**
+     * Issues the RSET command end validates answer
+     *
+     * Can be used to restore a clean smtp communication state when a transaction has been cancelled or commencing a new transaction.
+     *
+     * @return void
+     */
+    public function rset()
+    {
+        $this->_send('RSET');
+        // MS ESMTP doesn't follow RFC, see [ZF-1377]
+        $this->_expect(array(250, 220));
+
+        $this->_mail = false;
+        $this->_rcpt = false;
+        $this->_data = false;
+    }
+
+
+    /**
+     * Issues the NOOP command end validates answer
+     *
+     * Not used by Zend_Mail, could be used to keep a connection alive or check if it is still open.
+     *
+     * @return void
+     */
+    public function noop()
+    {
+        $this->_send('NOOP');
+        $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+    }
+
+
+    /**
+     * Issues the VRFY command end validates answer
+     *
+     * Not used by Zend_Mail.
+     *
+     * @param  string $user User Name or eMail to verify
+     * @return void
+     */
+    public function vrfy($user)
+    {
+        $this->_send('VRFY ' . $user);
+        $this->_expect(array(250, 251, 252), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+    }
+
+
+    /**
+     * Issues the QUIT command and clears the current session
+     *
+     * @return void
+     */
+    public function quit()
+    {
+        if ($this->_sess) {
+            $this->_send('QUIT');
+            $this->_expect(221, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2
+            $this->_stopSession();
+        }
+    }
+
+
+    /**
+     * Default authentication method
+     *
+     * This default method is implemented by AUTH adapters to properly authenticate to a remote host.
+     *
+     * @throws Zend_Mail_Protocol_Exception
+     * @return void
+     */
+    public function auth()
+    {
+        if ($this->_auth === true) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('Already authenticated for this session');
+        }
+    }
+
+
+    /**
+     * Closes connection
+     *
+     * @return void
+     */
+    public function disconnect()
+    {
+        $this->_disconnect();
+    }
+
+
+    /**
+     * Start mail session
+     *
+     * @return void
+     */
+    protected function _startSession()
+    {
+        $this->_sess = true;
+    }
+
+
+    /**
+     * Stop mail session
+     *
+     * @return void
+     */
+    protected function _stopSession()
+    {
+        $this->_sess = false;
+    }
+}
diff --git a/lib/Zend/Mail/Protocol/Smtp/Auth/Crammd5.php b/lib/Zend/Mail/Protocol/Smtp/Auth/Crammd5.php
new file mode 100644
index 0000000..337c7eb
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Smtp/Auth/Crammd5.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Crammd5.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Protocol_Smtp
+ */
+require_once 'Zend/Mail/Protocol/Smtp.php';
+
+
+/**
+ * Performs CRAM-MD5 authentication
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Smtp_Auth_Crammd5 extends Zend_Mail_Protocol_Smtp
+{
+    /**
+     * Constructor.
+     *
+     * @param  string $host   (Default: 127.0.0.1)
+     * @param  int    $port   (Default: null)
+     * @param  array  $config Auth-specific parameters
+     * @return void
+     */
+    public function __construct($host = '127.0.0.1', $port = null, $config = null)
+    {
+        if (is_array($config)) {
+            if (isset($config['username'])) {
+                $this->_username = $config['username'];
+            }
+            if (isset($config['password'])) {
+                $this->_password = $config['password'];
+            }
+        }
+
+        parent::__construct($host, $port, $config);
+    }
+
+
+    /**
+     * @todo Perform CRAM-MD5 authentication with supplied credentials
+     *
+     * @return void
+     */
+    public function auth()
+    {
+        // Ensure AUTH has not already been initiated.
+        parent::auth();
+
+        $this->_send('AUTH CRAM-MD5');
+        $challenge = $this->_expect(334);
+        $challenge = base64_decode($challenge);
+        $digest = $this->_hmacMd5($this->_password, $challenge);
+        $this->_send(base64_encode($this->_username . ' ' . $digest));
+        $this->_expect(235);
+        $this->_auth = true;
+    }
+
+
+    /**
+     * Prepare CRAM-MD5 response to server's ticket
+     *
+     * @param  string $key   Challenge key (usually password)
+     * @param  string $data  Challenge data
+     * @param  string $block Length of blocks
+     * @return string
+     */
+    protected function _hmacMd5($key, $data, $block = 64)
+    {
+        if (strlen($key) > 64) {
+            $key = pack('H32', md5($key));
+        } elseif (strlen($key) < 64) {
+            $key = str_pad($key, $block, chr(0));
+        }
+
+        $k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
+        $k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
+
+        $inner = pack('H32', md5($k_ipad . $data));
+        $digest = md5($k_opad . $inner);
+
+        return $digest;
+    }
+}
diff --git a/lib/Zend/Mail/Protocol/Smtp/Auth/Login.php b/lib/Zend/Mail/Protocol/Smtp/Auth/Login.php
new file mode 100644
index 0000000..6332207
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Smtp/Auth/Login.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Login.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Protocol_Smtp
+ */
+require_once 'Zend/Mail/Protocol/Smtp.php';
+
+
+/**
+ * Performs LOGIN authentication
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Smtp_Auth_Login extends Zend_Mail_Protocol_Smtp
+{
+    /**
+     * LOGIN username
+     *
+     * @var string
+     */
+    protected $_username;
+
+
+    /**
+     * LOGIN password
+     *
+     * @var string
+     */
+    protected $_password;
+
+
+    /**
+     * Constructor.
+     *
+     * @param  string $host   (Default: 127.0.0.1)
+     * @param  int    $port   (Default: null)
+     * @param  array  $config Auth-specific parameters
+     * @return void
+     */
+    public function __construct($host = '127.0.0.1', $port = null, $config = null)
+    {
+        if (is_array($config)) {
+            if (isset($config['username'])) {
+                $this->_username = $config['username'];
+            }
+            if (isset($config['password'])) {
+                $this->_password = $config['password'];
+            }
+        }
+
+        parent::__construct($host, $port, $config);
+    }
+
+
+    /**
+     * Perform LOGIN authentication with supplied credentials
+     *
+     * @return void
+     */
+    public function auth()
+    {
+        // Ensure AUTH has not already been initiated.
+        parent::auth();
+
+        $this->_send('AUTH LOGIN');
+        $this->_expect(334);
+        $this->_send(base64_encode($this->_username));
+        $this->_expect(334);
+        $this->_send(base64_encode($this->_password));
+        $this->_expect(235);
+        $this->_auth = true;
+    }
+}
diff --git a/lib/Zend/Mail/Protocol/Smtp/Auth/Plain.php b/lib/Zend/Mail/Protocol/Smtp/Auth/Plain.php
new file mode 100644
index 0000000..cb8d019
--- /dev/null
+++ b/lib/Zend/Mail/Protocol/Smtp/Auth/Plain.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Plain.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Protocol_Smtp
+ */
+require_once 'Zend/Mail/Protocol/Smtp.php';
+
+
+/**
+ * Performs PLAIN authentication
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Smtp_Auth_Plain extends Zend_Mail_Protocol_Smtp
+{
+    /**
+     * PLAIN username
+     *
+     * @var string
+     */
+    protected $_username;
+
+
+    /**
+     * PLAIN password
+     *
+     * @var string
+     */
+    protected $_password;
+
+
+    /**
+     * Constructor.
+     *
+     * @param  string $host   (Default: 127.0.0.1)
+     * @param  int    $port   (Default: null)
+     * @param  array  $config Auth-specific parameters
+     * @return void
+     */
+    public function __construct($host = '127.0.0.1', $port = null, $config = null)
+    {
+        if (is_array($config)) {
+            if (isset($config['username'])) {
+                $this->_username = $config['username'];
+            }
+            if (isset($config['password'])) {
+                $this->_password = $config['password'];
+            }
+        }
+
+        parent::__construct($host, $port, $config);
+    }
+
+
+    /**
+     * Perform PLAIN authentication with supplied credentials
+     *
+     * @return void
+     */
+    public function auth()
+    {
+        // Ensure AUTH has not already been initiated.
+        parent::auth();
+
+        $this->_send('AUTH PLAIN');
+        $this->_expect(334);
+        $this->_send(base64_encode(chr(0) . $this->_username . chr(0) . $this->_password));
+        $this->_expect(235);
+        $this->_auth = true;
+    }
+}
diff --git a/lib/Zend/Mail/Storage.php b/lib/Zend/Mail/Storage.php
new file mode 100644
index 0000000..227f496
--- /dev/null
+++ b/lib/Zend/Mail/Storage.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Storage.php 9099 2008-03-30 19:35:47Z thomas $
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage
+{
+    // maildir and IMAP flags, using IMAP names, where possible to be able to distinguish between IMAP
+    // system flags and other flags
+    const FLAG_PASSED   = 'Passed';
+    const FLAG_SEEN     = '\Seen';
+    const FLAG_ANSWERED = '\Answered';
+    const FLAG_FLAGGED  = '\Flagged';
+    const FLAG_DELETED  = '\Deleted';
+    const FLAG_DRAFT    = '\Draft';
+    const FLAG_RECENT   = '\Recent';
+}
diff --git a/lib/Zend/Mail/Storage/Abstract.php b/lib/Zend/Mail/Storage/Abstract.php
new file mode 100644
index 0000000..9e84d93
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Abstract.php
@@ -0,0 +1,366 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Abstract.php 9099 2008-03-30 19:35:47Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Mail_Storage_Abstract implements Countable, ArrayAccess, SeekableIterator
+{
+    /**
+     * class capabilities with default values
+     * @var array
+     */
+    protected $_has = array('uniqueid'  => true,
+                            'delete'    => false,
+                            'create'    => false,
+                            'top'       => false,
+                            'fetchPart' => true,
+                            'flags'     => false);
+
+    /**
+     * current iteration position
+     * @var int
+     */
+    protected $_iterationPos = 0;
+
+    /**
+     * maximum iteration position (= message count)
+     * @var null|int
+     */
+    protected $_iterationMax = null;
+
+    /**
+     * used message class, change it in an extened class to extend the returned message class
+     * @var string
+     */
+    protected $_messageClass = 'Zend_Mail_Message';
+
+    /**
+     * Getter for has-properties. The standard has properties
+     * are: hasFolder, hasUniqueid, hasDelete, hasCreate, hasTop
+     *
+     * The valid values for the has-properties are:
+     *   - true if a feature is supported
+     *   - false if a feature is not supported
+     *   - null is it's not yet known or it can't be know if a feature is supported
+     *
+     * @param  string $var  property name
+     * @return bool         supported or not
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __get($var)
+    {
+        if (strpos($var, 'has') === 0) {
+            $var = strtolower(substr($var, 3));
+            return isset($this->_has[$var]) ? $this->_has[$var] : null;
+        }
+        
+        /**
+         * @see Zend_Mail_Storage_Exception
+         */
+        require_once 'Zend/Mail/Storage/Exception.php';
+        throw new Zend_Mail_Storage_Exception($var . ' not found');
+    }
+
+
+    /**
+     * Get a full list of features supported by the specific mail lib and the server
+     *
+     * @return array list of features as array(featurename => true|false[|null])
+     */
+    public function getCapabilities()
+    {
+        return $this->_has;
+    }
+
+
+    /**
+     * Count messages messages in current box/folder
+     *
+     * @return int number of messages
+     * @throws Zend_Mail_Storage_Exception
+     */
+    abstract public function countMessages();
+
+
+    /**
+     * Get a list of messages with number and size
+     *
+     * @param  int $id  number of message
+     * @return int|array size of given message of list with all messages as array(num => size)
+     */
+    abstract public function getSize($id = 0);
+
+
+    /**
+     * Get a message with headers and body
+     *
+     * @param  $id int number of message
+     * @return Zend_Mail_Message
+     */
+    abstract public function getMessage($id);
+
+
+    /**
+     * Get raw header of message or part
+     *
+     * @param  int               $id       number of message
+     * @param  null|array|string $part     path to part or null for messsage header
+     * @param  int               $topLines include this many lines with header (after an empty line)
+     * @return string raw header
+     */
+    abstract public function getRawHeader($id, $part = null, $topLines = 0);
+
+    /**
+     * Get raw content of message or part
+     *
+     * @param  int               $id   number of message
+     * @param  null|array|string $part path to part or null for messsage content
+     * @return string raw content
+     */
+    abstract public function getRawContent($id, $part = null);
+
+    /**
+     * Create instance with parameters
+     *
+     * @param  array $params mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     */
+    abstract public function __construct($params);
+
+
+    /**
+     * Destructor calls close() and therefore closes the resource.
+     */
+    public function __destruct()
+    {
+        $this->close();
+    }
+
+
+    /**
+     * Close resource for mail lib. If you need to control, when the resource
+     * is closed. Otherwise the destructor would call this.
+     *
+     * @return null
+     */
+    abstract public function close();
+
+
+    /**
+     * Keep the resource alive.
+     *
+     * @return null
+     */
+    abstract public function noop();
+
+    /**
+     * delete a message from current box/folder
+     *
+     * @return null
+     */
+    abstract public function removeMessage($id);
+
+    /**
+     * get unique id for one or all messages
+     *
+     * if storage does not support unique ids it's the same as the message number
+     *
+     * @param int|null $id message number
+     * @return array|string message number for given message or all messages as array
+     * @throws Zend_Mail_Storage_Exception
+     */
+    abstract public function getUniqueId($id = null);
+
+    /**
+     * get a message number from a unique id
+     *
+     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
+     * as parameter and use this method to translate it to message number right before calling removeMessage()
+     *
+     * @param string $id unique id
+     * @return int message number
+     * @throws Zend_Mail_Storage_Exception
+     */
+    abstract public function getNumberByUniqueId($id);
+
+    // interface implementations follows
+
+    /**
+     * Countable::count()
+     *
+     * @return   int
+     */
+     public function count()
+     {
+        return $this->countMessages();
+     }
+
+
+     /**
+      * ArrayAccess::offsetExists()
+      *
+      * @param    int     $id
+      * @return   boolean
+      */
+     public function offsetExists($id)
+     {
+        try {
+            if ($this->getMessage($id)) {
+                return true;
+            }
+        } catch(Zend_Mail_Storage_Exception $e) {}
+
+        return false;
+     }
+
+
+     /**
+      * ArrayAccess::offsetGet()
+      *
+      * @param    int $id
+      * @return   Zend_Mail_Message message object
+      */
+     public function offsetGet($id)
+     {
+        return $this->getMessage($id);
+     }
+
+
+     /**
+      * ArrayAccess::offsetSet()
+      *
+      * @param    id     $id
+      * @param    mixed  $value
+      * @throws   Zend_Mail_Storage_Exception
+      * @return   void
+      */
+     public function offsetSet($id, $value)
+     {
+        /**
+         * @see Zend_Mail_Storage_Exception
+         */
+        require_once 'Zend/Mail/Storage/Exception.php';
+        throw new Zend_Mail_Storage_Exception('cannot write mail messages via array access');
+     }
+
+
+     /**
+      * ArrayAccess::offsetUnset()
+      *
+      * @param    int   $id
+      * @return   boolean success
+      */
+     public function offsetUnset($id)
+     {
+        return $this->removeMessage($id);
+     }
+
+
+     /**
+      * Iterator::rewind()
+      *
+      * Rewind always gets the new count from the storage. Thus if you use
+      * the interfaces and your scripts take long you should use reset()
+      * from time to time.
+      *
+      * @return   void
+      */
+     public function rewind()
+     {
+        $this->_iterationMax = $this->countMessages();
+        $this->_iterationPos = 1;
+     }
+
+
+     /**
+      * Iterator::current()
+      *
+      * @return   Zend_Mail_Message current message
+      */
+     public function current()
+     {
+        return $this->getMessage($this->_iterationPos);
+     }
+
+
+     /**
+      * Iterator::key()
+      *
+      * @return   int id of current position
+      */
+     public function key()
+     {
+        return $this->_iterationPos;
+     }
+
+
+     /**
+      * Iterator::next()
+      *
+      * @return   void
+      */
+     public function next()
+     {
+        ++$this->_iterationPos;
+     }
+
+
+     /**
+      * Iterator::valid()
+      *
+      * @return   boolean
+      */
+     public function valid()
+     {
+        if ($this->_iterationMax === null) {
+          $this->_iterationMax = $this->countMessages();
+        }
+        return $this->_iterationPos && $this->_iterationPos <= $this->_iterationMax;
+     }
+
+
+     /**
+      * SeekableIterator::seek()
+      *
+      * @param  int $pos
+      * @return void
+      * @throws OutOfBoundsException
+      */
+     public function seek($pos)
+     {
+        if ($this->_iterationMax === null) {
+          $this->_iterationMax = $this->countMessages();
+        }
+
+        if ($pos > $this->_iterationMax) {
+            throw new OutOfBoundsException('this position does not exist');
+        }
+        $this->_iterationPos = $pos;
+     }
+
+}
diff --git a/lib/Zend/Mail/Storage/Exception.php b/lib/Zend/Mail/Storage/Exception.php
new file mode 100644
index 0000000..1aea4f9
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Exception.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Exception
+ */
+require_once 'Zend/Mail/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Exception extends Zend_Mail_Exception
+{}
+
diff --git a/lib/Zend/Mail/Storage/Folder.php b/lib/Zend/Mail/Storage/Folder.php
new file mode 100644
index 0000000..6ee9abe
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Folder.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Folder.php 9099 2008-03-30 19:35:47Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Folder implements RecursiveIterator
+{
+    /**
+     * subfolders of folder array(localName => Zend_Mail_Storage_Folder folder)
+     * @var array
+     */
+    protected $_folders;
+
+    /**
+     * local name (name of folder in parent folder)
+     * @var string
+     */
+    protected $_localName;
+
+    /**
+     * global name (absolute name of folder)
+     * @var string
+     */
+    protected $_globalName;
+
+    /**
+     * folder is selectable if folder is able to hold messages, else it's just a parent folder
+     * @var bool
+     */
+    protected $_selectable = true;
+
+    /**
+     * create a new mail folder instance
+     *
+     * @param string $localName  name of folder in current subdirectory
+     * @param string $globalName absolute name of folder
+     * @param bool   $selectable if true folder holds messages, if false it's just a parent for subfolders
+     * @param array  $folders    init with given instances of Zend_Mail_Storage_Folder as subfolders
+     */
+    public function __construct($localName, $globalName = '', $selectable = true, array $folders = array())
+    {
+        $this->_localName  = $localName;
+        $this->_globalName = $globalName ? $globalName : $localName;
+        $this->_selectable = $selectable;
+        $this->_folders    = $folders;
+    }
+
+    /**
+     * implements RecursiveIterator::hasChildren()
+     *
+     * @return bool current element has children
+     */
+    public function hasChildren()
+    {
+        $current = $this->current();
+        return $current && $current instanceof Zend_Mail_Storage_Folder && !$current->isLeaf();
+    }
+
+    /**
+     * implements RecursiveIterator::getChildren()
+     *
+     * @return Zend_Mail_Storage_Folder same as self::current()
+     */
+    public function getChildren()
+    {
+        return $this->current();
+    }
+
+    /**
+     * implements Iterator::valid()
+     *
+     * @return bool check if there's a current element
+     */
+    public function valid()
+    {
+        return key($this->_folders) !== null;
+    }
+
+    /**
+     * implements Iterator::next()
+     *
+     * @return null
+     */
+    public function next()
+    {
+        next($this->_folders);
+    }
+
+    /**
+     * implements Iterator::key()
+     *
+     * @return string key/local name of current element
+     */
+    public function key()
+    {
+        return key($this->_folders);
+    }
+
+    /**
+     * implements Iterator::current()
+     *
+     * @return Zend_Mail_Storage_Folder current folder
+     */
+    public function current()
+    {
+        return current($this->_folders);
+    }
+
+    /**
+     * implements Iterator::rewind()
+     *
+     * @return null
+     */
+    public function rewind()
+    {
+        reset($this->_folders);
+    }
+
+    /**
+     * get subfolder named $name
+     *
+     * @param  string $name wanted subfolder
+     * @return Zend_Mail_Storage_Folder folder named $folder
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __get($name)
+    {
+        if (!isset($this->_folders[$name])) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception("no subfolder named $name");
+        }
+
+        return $this->_folders[$name];
+    }
+
+    /**
+     * add or replace subfolder named $name
+     *
+     * @param string $name local name of subfolder
+     * @param Zend_Mail_Storage_Folder $folder instance for new subfolder
+     * @return null
+     */
+    public function __set($name, Zend_Mail_Storage_Folder $folder)
+    {
+        $this->_folders[$name] = $folder;
+    }
+
+    /**
+     * remove subfolder named $name
+     *
+     * @param string $name local name of subfolder
+     * @return null
+     */
+    public function __unset($name)
+    {
+        unset($this->_folders[$name]);
+    }
+
+    /**
+     * magic method for easy output of global name
+     *
+     * @return string global name of folder
+     */
+    public function __toString()
+    {
+        return (string)$this->getGlobalName();
+    }
+
+    /**
+     * get local name
+     *
+     * @return string local name
+     */
+    public function getLocalName()
+    {
+        return $this->_localName;
+    }
+
+    /**
+     * get global name
+     *
+     * @return string global name
+     */
+    public function getGlobalName()
+    {
+        return $this->_globalName;
+    }
+
+    /**
+     * is this folder selectable?
+     *
+     * @return bool selectable
+     */
+    public function isSelectable()
+    {
+        return $this->_selectable;
+    }
+
+    /**
+     * check if folder has no subfolder
+     *
+     * @return bool true if no subfolders
+     */
+    public function isLeaf()
+    {
+        return empty($this->_folders);
+    }
+}
diff --git a/lib/Zend/Mail/Storage/Folder/Interface.php b/lib/Zend/Mail/Storage/Folder/Interface.php
new file mode 100644
index 0000000..cb148b7
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Folder/Interface.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Interface.php 9098 2008-03-30 19:29:10Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Mail_Storage_Folder_Interface
+{
+    /**
+     * get root folder or given folder
+     *
+     * @param string $rootFolder get folder structure for given folder, else root
+     * @return Zend_Mail_Storage_Folder root or wanted folder
+     */
+    public function getFolders($rootFolder = null);
+
+    /**
+     * select given folder
+     *
+     * folder must be selectable!
+     *
+     * @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function selectFolder($globalName);
+
+
+    /**
+     * get Zend_Mail_Storage_Folder instance for current folder
+     *
+     * @return Zend_Mail_Storage_Folder instance of current folder
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getCurrentFolder();
+}
diff --git a/lib/Zend/Mail/Storage/Folder/Maildir.php b/lib/Zend/Mail/Storage/Folder/Maildir.php
new file mode 100644
index 0000000..30b31aa
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Folder/Maildir.php
@@ -0,0 +1,265 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Maildir.php 9098 2008-03-30 19:29:10Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Storage_Folder
+ */
+require_once 'Zend/Mail/Storage/Folder.php';
+
+/**
+ * @see Zend_Mail_Storage_Folder_Interface
+ */
+require_once 'Zend/Mail/Storage/Folder/Interface.php';
+
+/**
+ * @see Zend_Mail_Storage_Maildir
+ */
+require_once 'Zend/Mail/Storage/Maildir.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Folder_Maildir extends Zend_Mail_Storage_Maildir implements Zend_Mail_Storage_Folder_Interface
+{
+    /**
+     * Zend_Mail_Storage_Folder root folder for folder structure
+     * @var Zend_Mail_Storage_Folder
+     */
+    protected $_rootFolder;
+
+    /**
+     * rootdir of folder structure
+     * @var string
+     */
+    protected $_rootdir;
+
+    /**
+     * name of current folder
+     * @var string
+     */
+    protected $_currentFolder;
+
+    /**
+     * delim char for subfolders
+     * @var string
+     */
+    protected $_delim;
+
+    /**
+     * Create instance with parameters
+     * Supported parameters are:
+     *   - dirname rootdir of maildir structure
+     *   - delim   delim char for folder structur, default is '.'
+     *   - folder intial selected folder, default is 'INBOX'
+     *
+     * @param  $params array mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __construct($params)
+    {
+        if (is_array($params)) {
+            $params = (object)$params;
+        }
+
+        if (!isset($params->dirname) || !is_dir($params->dirname)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
+        }
+
+        $this->_rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
+
+        $this->_delim = isset($params->delim) ? $params->delim : '.';
+
+        $this->_buildFolderTree();
+        $this->selectFolder(!empty($params->folder) ? $params->folder : 'INBOX');
+        $this->_has['top'] = true;
+        $this->_has['flags'] = true;
+    }
+
+    /**
+     * find all subfolders and mbox files for folder structure
+     *
+     * Result is save in Zend_Mail_Storage_Folder instances with the root in $this->_rootFolder.
+     * $parentFolder and $parentGlobalName are only used internally for recursion.
+     *
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    protected function _buildFolderTree()
+    {
+        $this->_rootFolder = new Zend_Mail_Storage_Folder('/', '/', false);
+        $this->_rootFolder->INBOX = new Zend_Mail_Storage_Folder('INBOX', 'INBOX', true);
+
+        $dh = @opendir($this->_rootdir);
+        if (!$dh) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception("can't read folders in maildir");
+        }
+        $dirs = array();
+        while (($entry = readdir($dh)) !== false) {
+            // maildir++ defines folders must start with .
+            if ($entry[0] != '.' || $entry == '.' || $entry == '..') {
+                continue;
+            }
+            if ($this->_isMaildir($this->_rootdir . $entry)) {
+                $dirs[] = $entry;
+            }
+        }
+        closedir($dh);
+
+        sort($dirs);
+        $stack = array(null);
+        $folderStack = array(null);
+        $parentFolder = $this->_rootFolder;
+        $parent = '.';
+
+        foreach ($dirs as $dir) {
+            do {
+                if (strpos($dir, $parent) === 0) {
+                    $local = substr($dir, strlen($parent));
+                    if (strpos($local, $this->_delim) !== false) {
+                        /**
+                         * @see Zend_Mail_Storage_Exception
+                         */
+                        require_once 'Zend/Mail/Storage/Exception.php';
+                        throw new Zend_Mail_Storage_Exception('error while reading maildir');
+                    }
+                    array_push($stack, $parent);
+                    $parent = $dir . $this->_delim;
+                    $folder = new Zend_Mail_Storage_Folder($local, substr($dir, 1), true);
+                    $parentFolder->$local = $folder;
+                    array_push($folderStack, $parentFolder);
+                    $parentFolder = $folder;
+                    break;
+                } else if ($stack) {
+                    $parent = array_pop($stack);
+                    $parentFolder = array_pop($folderStack);
+                }
+            } while ($stack);
+            if (!$stack) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('error while reading maildir');
+            }
+        }
+    }
+
+    /**
+     * get root folder or given folder
+     *
+     * @param string $rootFolder get folder structure for given folder, else root
+     * @return Zend_Mail_Storage_Folder root or wanted folder
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getFolders($rootFolder = null)
+    {
+        if (!$rootFolder || $rootFolder == 'INBOX') {
+            return $this->_rootFolder;
+        }
+
+        // rootdir is same as INBOX in maildir
+        if (strpos($rootFolder, 'INBOX' . $this->_delim) === 0) {
+            $rootFolder = substr($rootFolder, 6);
+        }
+        $currentFolder = $this->_rootFolder;
+        $subname = trim($rootFolder, $this->_delim);
+        while ($currentFolder) {
+            @list($entry, $subname) = @explode($this->_delim, $subname, 2);
+            $currentFolder = $currentFolder->$entry;
+            if (!$subname) {
+                break;
+            }
+        }
+
+        if ($currentFolder->getGlobalName() != rtrim($rootFolder, $this->_delim)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception("folder $rootFolder not found");
+        }
+        return $currentFolder;
+    }
+
+    /**
+     * select given folder
+     *
+     * folder must be selectable!
+     *
+     * @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function selectFolder($globalName)
+    {
+        $this->_currentFolder = (string)$globalName;
+
+        // getting folder from folder tree for validation
+        $folder = $this->getFolders($this->_currentFolder);
+
+        try {
+            $this->_openMaildir($this->_rootdir . '.' . $folder->getGlobalName());
+        } catch(Zend_Mail_Storage_Exception $e) {
+            // check what went wrong
+            if (!$folder->isSelectable()) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception("{$this->_currentFolder} is not selectable");
+            }
+            // seems like file has vanished; rebuilding folder tree - but it's still an exception
+            $this->_buildFolderTree($this->_rootdir);
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('seems like the maildir has vanished, I\'ve rebuild the ' .
+                                                         'folder tree, search for an other folder and try again');
+        }
+    }
+
+    /**
+     * get Zend_Mail_Storage_Folder instance for current folder
+     *
+     * @return Zend_Mail_Storage_Folder instance of current folder
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getCurrentFolder()
+    {
+        return $this->_currentFolder;
+    }
+}
diff --git a/lib/Zend/Mail/Storage/Folder/Mbox.php b/lib/Zend/Mail/Storage/Folder/Mbox.php
new file mode 100644
index 0000000..797148d
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Folder/Mbox.php
@@ -0,0 +1,264 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Mbox.php 9098 2008-03-30 19:29:10Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Storage_Folder
+ */
+require_once 'Zend/Mail/Storage/Folder.php';
+
+/**
+ * @see Zend_Mail_Storage_Folder_Interface
+ */
+require_once 'Zend/Mail/Storage/Folder/Interface.php';
+
+/**
+ * @see Zend_Mail_Storage_Mbox
+ */
+require_once 'Zend/Mail/Storage/Mbox.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Folder_Mbox extends Zend_Mail_Storage_Mbox implements Zend_Mail_Storage_Folder_Interface
+{
+    /**
+     * Zend_Mail_Storage_Folder root folder for folder structure
+     * @var Zend_Mail_Storage_Folder
+     */
+    protected $_rootFolder;
+
+    /**
+     * rootdir of folder structure
+     * @var string
+     */
+    protected $_rootdir;
+
+    /**
+     * name of current folder
+     * @var string
+     */
+    protected $_currentFolder;
+
+    /**
+     * Create instance with parameters
+     *
+     * Disallowed parameters are:
+     *   - filename use Zend_Mail_Storage_Mbox for a single file
+     * Supported parameters are:
+     *   - dirname rootdir of mbox structure
+     *   - folder intial selected folder, default is 'INBOX'
+     *
+     * @param  $params array mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __construct($params)
+    {
+        if (is_array($params)) {
+            $params = (object)$params;
+        }
+
+        if (isset($params->filename)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('use Zend_Mail_Storage_Mbox for a single file');
+        }
+
+        if (!isset($params->dirname) || !is_dir($params->dirname)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
+        }
+
+        $this->_rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
+
+        $this->_buildFolderTree($this->_rootdir);
+        $this->selectFolder(!empty($params->folder) ? $params->folder : 'INBOX');
+        $this->_has['top']      = true;
+        $this->_has['uniqueid'] = false;
+    }
+
+    /**
+     * find all subfolders and mbox files for folder structure
+     *
+     * Result is save in Zend_Mail_Storage_Folder instances with the root in $this->_rootFolder.
+     * $parentFolder and $parentGlobalName are only used internally for recursion.
+     *
+     * @param string $currentDir call with root dir, also used for recursion.
+     * @param Zend_Mail_Storage_Folder|null $parentFolder used for recursion
+     * @param string $parentGlobalName used for rescursion
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    protected function _buildFolderTree($currentDir, $parentFolder = null, $parentGlobalName = '')
+    {
+        if (!$parentFolder) {
+            $this->_rootFolder = new Zend_Mail_Storage_Folder('/', '/', false);
+            $parentFolder = $this->_rootFolder;
+        }
+
+        $dh = @opendir($currentDir);
+        if (!$dh) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception("can't read dir $currentDir");
+        }
+        while (($entry = readdir($dh)) !== false) {
+            // ignore hidden files for mbox
+            if ($entry[0] == '.') {
+                continue;
+            }
+            $absoluteEntry = $currentDir . $entry;
+            $globalName = $parentGlobalName . DIRECTORY_SEPARATOR . $entry;
+            if (is_file($absoluteEntry) && $this->_isMboxFile($absoluteEntry)) {
+                $parentFolder->$entry = new Zend_Mail_Storage_Folder($entry, $globalName);
+                continue;
+            }
+            if (!is_dir($absoluteEntry) /* || $entry == '.' || $entry == '..' */) {
+                continue;
+            }
+            $folder = new Zend_Mail_Storage_Folder($entry, $globalName, false);
+            $parentFolder->$entry = $folder;
+            $this->_buildFolderTree($absoluteEntry . DIRECTORY_SEPARATOR, $folder, $globalName);
+        }
+
+        closedir($dh);
+    }
+
+    /**
+     * get root folder or given folder
+     *
+     * @param string $rootFolder get folder structure for given folder, else root
+     * @return Zend_Mail_Storage_Folder root or wanted folder
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getFolders($rootFolder = null)
+    {
+        if (!$rootFolder) {
+            return $this->_rootFolder;
+        }
+
+        $currentFolder = $this->_rootFolder;
+        $subname = trim($rootFolder, DIRECTORY_SEPARATOR);
+        while ($currentFolder) {
+            @list($entry, $subname) = @explode(DIRECTORY_SEPARATOR, $subname, 2);
+            $currentFolder = $currentFolder->$entry;
+            if (!$subname) {
+                break;
+            }
+        }
+
+        if ($currentFolder->getGlobalName() != DIRECTORY_SEPARATOR . trim($rootFolder, DIRECTORY_SEPARATOR)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception("folder $rootFolder not found");
+        }
+        return $currentFolder;
+    }
+
+    /**
+     * select given folder
+     *
+     * folder must be selectable!
+     *
+     * @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function selectFolder($globalName)
+    {
+        $this->_currentFolder = (string)$globalName;
+
+        // getting folder from folder tree for validation
+        $folder = $this->getFolders($this->_currentFolder);
+
+        try {
+            $this->_openMboxFile($this->_rootdir . $folder->getGlobalName());
+        } catch(Zend_Mail_Storage_Exception $e) {
+            // check what went wrong
+            if (!$folder->isSelectable()) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception("{$this->_currentFolder} is not selectable");
+            }
+            // seems like file has vanished; rebuilding folder tree - but it's still an exception
+            $this->_buildFolderTree($this->_rootdir);
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('seems like the mbox file has vanished, I\'ve rebuild the ' .
+                                                         'folder tree, search for an other folder and try again');
+        }
+    }
+
+    /**
+     * get Zend_Mail_Storage_Folder instance for current folder
+     *
+     * @return Zend_Mail_Storage_Folder instance of current folder
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getCurrentFolder()
+    {
+        return $this->_currentFolder;
+    }
+
+    /**
+     * magic method for serialize()
+     *
+     * with this method you can cache the mbox class
+     *
+     * @return array name of variables
+     */
+    public function __sleep()
+    {
+        return array_merge(parent::__sleep(), array('_currentFolder', '_rootFolder', '_rootdir'));
+    }
+
+    /**
+     * magic method for unserialize()
+     *
+     * with this method you can cache the mbox class
+     *
+     * @return null
+     */
+    public function __wakeup()
+    {
+        // if cache is stall selectFolder() rebuilds the tree on error
+        parent::__wakeup();
+    }
+}
diff --git a/lib/Zend/Mail/Storage/Imap.php b/lib/Zend/Mail/Storage/Imap.php
new file mode 100644
index 0000000..f4051f9
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Imap.php
@@ -0,0 +1,644 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Imap.php 12519 2008-11-10 18:41:24Z alexander $
+ */
+
+
+/**
+ * @see Zend_Mail_Storage_Abstract
+ */
+require_once 'Zend/Mail/Storage/Abstract.php';
+
+/**
+ * @see Zend_Mail_Protocol_Imap
+ */
+require_once 'Zend/Mail/Protocol/Imap.php';
+
+/**
+ * @see Zend_Mail_Storage_Writable_Interface
+ */
+require_once 'Zend/Mail/Storage/Writable/Interface.php';
+
+/**
+ * @see Zend_Mail_Storage_Folder_Interface
+ */
+require_once 'Zend/Mail/Storage/Folder/Interface.php';
+
+/**
+ * @see Zend_Mail_Storage_Folder
+ */
+require_once 'Zend/Mail/Storage/Folder.php';
+
+/**
+ * @see Zend_Mail_Message
+ */
+require_once 'Zend/Mail/Message.php';
+
+/**
+ * @see Zend_Mail_Storage
+ */
+require_once 'Zend/Mail/Storage.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Imap extends Zend_Mail_Storage_Abstract
+                             implements Zend_Mail_Storage_Folder_Interface, Zend_Mail_Storage_Writable_Interface
+{
+    // TODO: with an internal cache we could optimize this class, or create an extra class with
+    // such optimizations. Especially the various fetch calls could be combined to one cache call
+
+    /**
+     * protocol handler
+     * @var null|Zend_Mail_Protocol_Imap
+     */
+    protected $_protocol;
+
+    /**
+     * name of current folder
+     * @var string
+     */
+    protected $_currentFolder = '';
+
+    /**
+     * imap flags to constants translation
+     * @var array
+     */
+    protected static $_knownFlags = array('\Passed'   => Zend_Mail_Storage::FLAG_PASSED,
+                                          '\Answered' => Zend_Mail_Storage::FLAG_ANSWERED,
+                                          '\Seen'     => Zend_Mail_Storage::FLAG_SEEN,
+                                          '\Deleted'  => Zend_Mail_Storage::FLAG_DELETED,
+                                          '\Draft'    => Zend_Mail_Storage::FLAG_DRAFT,
+                                          '\Flagged'  => Zend_Mail_Storage::FLAG_FLAGGED);
+
+    /**
+     * map flags to search criterias
+     * @var array
+     */
+    protected static $_searchFlags = array('\Recent'   => 'RECENT',
+                                           '\Answered' => 'ANSWERED',
+                                           '\Seen'     => 'SEEN',
+                                           '\Deleted'  => 'DELETED',
+                                           '\Draft'    => 'DRAFT',
+                                           '\Flagged'  => 'FLAGGED');
+
+    /**
+     * Count messages all messages in current box
+     *
+     * @return int number of messages
+     * @throws Zend_Mail_Storage_Exception
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function countMessages($flags = null)
+    {
+        if (!$this->_currentFolder) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('No selected folder to count');
+        }
+
+        if ($flags === null) {
+            return count($this->_protocol->search(array('ALL')));
+        }
+    
+        $params = array();
+        foreach ((array)$flags as $flag) {
+            if (isset(self::$_searchFlags[$flag])) {
+                $params[] = self::$_searchFlags[$flag];
+            } else {
+                $params[] = 'KEYWORD';
+                $params[] = $this->_protocol->escapeString($flag);
+            }
+        }
+        return count($this->_protocol->search($params));
+    }
+
+    /**
+     * get a list of messages with number and size
+     *
+     * @param int $id number of message
+     * @return int|array size of given message of list with all messages as array(num => size)
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function getSize($id = 0)
+    {
+        if ($id) {
+            return $this->_protocol->fetch('RFC822.SIZE', $id);
+        }
+        return $this->_protocol->fetch('RFC822.SIZE', 1, INF);
+    }
+
+    /**
+     * Fetch a message
+     *
+     * @param int $id number of message
+     * @return Zend_Mail_Message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function getMessage($id)
+    {
+        $data = $this->_protocol->fetch(array('FLAGS', 'RFC822.HEADER'), $id);
+        $header = $data['RFC822.HEADER'];
+
+        $flags = array();
+        foreach ($data['FLAGS'] as $flag) {
+            $flags[] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
+        }
+
+        return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $header, 'flags' => $flags));
+    }
+
+    /*
+     * Get raw header of message or part
+     *
+     * @param  int               $id       number of message
+     * @param  null|array|string $part     path to part or null for messsage header
+     * @param  int               $topLines include this many lines with header (after an empty line)
+     * @param  int $topLines include this many lines with header (after an empty line)
+     * @return string raw header
+     * @throws Zend_Mail_Protocol_Exception
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawHeader($id, $part = null, $topLines = 0)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+
+        // TODO: toplines
+        return $this->_protocol->fetch('RFC822.HEADER', $id);
+    }
+
+    /*
+     * Get raw content of message or part
+     *
+     * @param  int               $id   number of message
+     * @param  null|array|string $part path to part or null for messsage content
+     * @return string raw content
+     * @throws Zend_Mail_Protocol_Exception
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawContent($id, $part = null)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+
+        return $this->_protocol->fetch('RFC822.TEXT', $id);
+    }
+
+    /**
+     * create instance with parameters
+     * Supported paramters are
+     *   - user username
+     *   - host hostname or ip address of IMAP server [optional, default = 'localhost']
+     *   - password password for user 'username' [optional, default = '']
+     *   - port port for IMAP server [optional, default = 110]
+     *   - ssl 'SSL' or 'TLS' for secure sockets
+     *   - folder select this folder [optional, default = 'INBOX']
+     *
+     * @param  array $params mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function __construct($params)
+    {
+        if (is_array($params)) {
+            $params = (object)$params;
+        }
+
+        $this->_has['flags'] = true;
+
+        if ($params instanceof Zend_Mail_Protocol_Imap) {
+            $this->_protocol = $params;
+            try {
+                $this->selectFolder('INBOX');
+            } catch(Zend_Mail_Storage_Exception $e) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('cannot select INBOX, is this a valid transport?');
+            }
+            return;
+        }
+
+        if (!isset($params->user)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('need at least user in params');
+        }
+
+        $host     = isset($params->host)     ? $params->host     : 'localhost';
+        $password = isset($params->password) ? $params->password : '';
+        $port     = isset($params->port)     ? $params->port     : null;
+        $ssl      = isset($params->ssl)      ? $params->ssl      : false;
+
+        $this->_protocol = new Zend_Mail_Protocol_Imap();
+        $this->_protocol->connect($host, $port, $ssl);
+        if (!$this->_protocol->login($params->user, $password)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot login, user or password wrong');
+        }
+        $this->selectFolder(isset($params->folder) ? $params->folder : 'INBOX');
+    }
+
+    /**
+     * Close resource for mail lib. If you need to control, when the resource
+     * is closed. Otherwise the destructor would call this.
+     *
+     * @return null
+     */
+    public function close()
+    {
+        $this->_currentFolder = '';
+        $this->_protocol->logout();
+    }
+
+    /**
+     * Keep the server busy.
+     *
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function noop()
+    {
+        if (!$this->_protocol->noop()) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('could not do nothing');
+        }
+    }
+
+    /**
+     * Remove a message from server. If you're doing that from a web enviroment
+     * you should be careful and use a uniqueid as parameter if possible to
+     * identify the message.
+     *
+     * @param   int $id number of message
+     * @return  null
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    public function removeMessage($id)
+    {
+        if (!$this->_protocol->store(array(Zend_Mail_Storage::FLAG_DELETED), $id, null, '+')) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot set deleted flag');
+        }
+        // TODO: expunge here or at close? we can handle an error here better and are more fail safe
+        if (!$this->_protocol->expunge()) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('message marked as deleted, but could not expunge');
+        }
+    }
+
+    /**
+     * get unique id for one or all messages
+     *
+     * if storage does not support unique ids it's the same as the message number
+     *
+     * @param int|null $id message number
+     * @return array|string message number for given message or all messages as array
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getUniqueId($id = null)
+    {
+        if ($id) {
+            return $this->_protocol->fetch('UID', $id);
+        }
+
+        return $this->_protocol->fetch('UID', 1, INF);
+    }
+
+    /**
+     * get a message number from a unique id
+     *
+     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
+     * as parameter and use this method to translate it to message number right before calling removeMessage()
+     *
+     * @param string $id unique id
+     * @return int message number
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getNumberByUniqueId($id)
+    {
+        // TODO: use search to find number directly
+        $ids = $this->getUniqueId();
+        foreach ($ids as $k => $v) {
+            if ($v == $id) {
+                return $k;
+            }
+        }
+
+        /**
+         * @see Zend_Mail_Storage_Exception
+         */
+        require_once 'Zend/Mail/Storage/Exception.php';
+        throw new Zend_Mail_Storage_Exception('unique id not found');
+    }
+
+
+    /**
+     * get root folder or given folder
+     *
+     * @param  string $rootFolder get folder structure for given folder, else root
+     * @return Zend_Mail_Storage_Folder root or wanted folder
+     * @throws Zend_Mail_Storage_Exception
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function getFolders($rootFolder = null)
+    {
+        $folders = $this->_protocol->listMailbox((string)$rootFolder);
+        if (!$folders) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('folder not found');
+        }
+
+        ksort($folders, SORT_STRING);
+        $root = new Zend_Mail_Storage_Folder('/', '/', false);
+        $stack = array(null);
+        $folderStack = array(null);
+        $parentFolder = $root;
+        $parent = '';
+
+        foreach ($folders as $globalName => $data) {
+            do {
+                if (!$parent || strpos($globalName, $parent) === 0) {
+                    $pos = strrpos($globalName, $data['delim']);
+                    if ($pos === false) {
+                        $localName = $globalName;
+                    } else {
+                        $localName = substr($globalName, $pos + 1);
+                    }
+                    $selectable = !$data['flags'] || !in_array('\\Noselect', $data['flags']);
+
+                    array_push($stack, $parent);
+                    $parent = $globalName . $data['delim'];
+                    $folder = new Zend_Mail_Storage_Folder($localName, $globalName, $selectable);
+                    $parentFolder->$localName = $folder;
+                    array_push($folderStack, $parentFolder);
+                    $parentFolder = $folder;
+                    break;
+                } else if ($stack) {
+                    $parent = array_pop($stack);
+                    $parentFolder = array_pop($folderStack);
+                }
+            } while ($stack);
+            if (!$stack) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('error while constructing folder tree');
+            }
+        }
+
+        return $root;
+    }
+
+    /**
+     * select given folder
+     *
+     * folder must be selectable!
+     *
+     * @param  Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function selectFolder($globalName)
+    {
+        $this->_currentFolder = $globalName;
+        if (!$this->_protocol->select($this->_currentFolder)) {
+            $this->_currentFolder = '';
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot change folder, maybe it does not exist');
+        }
+    }
+
+
+    /**
+     * get Zend_Mail_Storage_Folder instance for current folder
+     *
+     * @return Zend_Mail_Storage_Folder instance of current folder
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getCurrentFolder()
+    {
+        return $this->_currentFolder;
+    }
+
+    /**
+     * create a new folder
+     *
+     * This method also creates parent folders if necessary. Some mail storages may restrict, which folder
+     * may be used as parent or which chars may be used in the folder name
+     *
+     * @param  string                          $name         global name of folder, local name if $parentFolder is set
+     * @param  string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function createFolder($name, $parentFolder = null)
+    {
+        // TODO: we assume / as the hierarchy delim - need to get that from the folder class!
+        if ($parentFolder instanceof Zend_Mail_Storage_Folder) {
+            $folder = $parentFolder->getGlobalName() . '/' . $name;
+        } else if ($parentFolder != null) {
+            $folder = $parentFolder . '/' . $name;
+        } else {
+            $folder = $name;
+        }
+
+        if (!$this->_protocol->create($folder)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot create folder');
+        }
+    }
+
+    /**
+     * remove a folder
+     *
+     * @param  string|Zend_Mail_Storage_Folder $name      name or instance of folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function removeFolder($name)
+    {
+        if ($name instanceof Zend_Mail_Storage_Folder) {
+            $name = $name->getGlobalName();
+        }
+
+        if (!$this->_protocol->delete($name)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot delete folder');
+        }
+    }
+
+    /**
+     * rename and/or move folder
+     *
+     * The new name has the same restrictions as in createFolder()
+     *
+     * @param  string|Zend_Mail_Storage_Folder $oldName name or instance of folder
+     * @param  string                          $newName new global name of folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function renameFolder($oldName, $newName)
+    {
+        if ($oldName instanceof Zend_Mail_Storage_Folder) {
+            $oldName = $oldName->getGlobalName();
+        }
+
+        if (!$this->_protocol->rename($oldName, $newName)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot rename folder');
+        }
+    }
+
+    /**
+     * append a new message to mail storage
+     *
+     * @param  string                                     $message message as string or instance of message class
+     * @param  null|string|Zend_Mail_Storage_Folder       $folder  folder for new message, else current folder is taken
+     * @param  null|array                                 $flags   set flags for new message, else a default set is used
+     * @throws Zend_Mail_Storage_Exception
+     */
+     // not yet * @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
+    public function appendMessage($message, $folder = null, $flags = null)
+    {
+        if ($folder === null) {
+            $folder = $this->_currentFolder;
+        }
+
+        if ($flags === null) {
+            $flags = array(Zend_Mail_Storage::FLAG_SEEN);
+        }
+
+        // TODO: handle class instances for $message
+        if (!$this->_protocol->append($folder, $message, $flags)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot create message, please check if the folder exists and your flags');
+        }
+    }
+
+    /**
+     * copy an existing message
+     *
+     * @param  int                             $id     number of message
+     * @param  string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function copyMessage($id, $folder)
+    {
+        if (!$this->_protocol->copy($folder, $id)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot copy message, does the folder exist?');
+        }
+    }
+
+    /**
+     * move an existing message
+     *
+     * NOTE: imap has no native move command, thus it's emulated with copy and delete
+     *
+     * @param  int                             $id     number of message
+     * @param  string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function moveMessage($id, $folder) {
+        $this->copyMessage($id, $folder);
+        $this->removeMessage($id);
+    }
+
+    /**
+     * set flags for message
+     *
+     * NOTE: this method can't set the recent flag.
+     *
+     * @param  int   $id    number of message
+     * @param  array $flags new flags for message
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function setFlags($id, $flags)
+    {
+        if (!$this->_protocol->store($flags, $id)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot set flags, have you tried to set the recent flag or special chars?');
+        }
+    }
+}
+
diff --git a/lib/Zend/Mail/Storage/Maildir.php b/lib/Zend/Mail/Storage/Maildir.php
new file mode 100644
index 0000000..429636a
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Maildir.php
@@ -0,0 +1,475 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Maildir.php 12519 2008-11-10 18:41:24Z alexander $
+ */
+
+
+/**
+ * @see Zend_Mail_Storage_Abstract
+ */
+require_once 'Zend/Mail/Storage/Abstract.php';
+
+/**
+ * @see Zend_Mail_Message_File
+ */
+require_once 'Zend/Mail/Message/File.php';
+
+/**
+ * @see Zend_Mail_Storage
+ */
+require_once 'Zend/Mail/Storage.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Maildir extends Zend_Mail_Storage_Abstract
+{
+    /**
+     * used message class, change it in an extened class to extend the returned message class
+     * @var string
+     */
+    protected $_messageClass = 'Zend_Mail_Message_File';
+
+    /**
+     * data of found message files in maildir dir
+     * @var array
+     */
+    protected $_files = array();
+
+    /**
+     * known flag chars in filenames
+     *
+     * This list has to be in alphabetical order for setFlags()
+     *
+     * @var array
+     */
+    protected static $_knownFlags = array('D' => Zend_Mail_Storage::FLAG_DRAFT,
+                                          'F' => Zend_Mail_Storage::FLAG_FLAGGED,
+                                          'P' => Zend_Mail_Storage::FLAG_PASSED,
+                                          'R' => Zend_Mail_Storage::FLAG_ANSWERED,
+                                          'S' => Zend_Mail_Storage::FLAG_SEEN,
+                                          'T' => Zend_Mail_Storage::FLAG_DELETED);
+                                          
+    // TODO: getFlags($id) for fast access if headers are not needed (i.e. just setting flags)?
+
+    /**
+     * Count messages all messages in current box
+     *
+     * @return int number of messages
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function countMessages($flags = null)
+    {
+        if ($flags === null) {
+            return count($this->_files);
+        }
+
+        $count = 0;                
+        if (!is_array($flags)) {
+            foreach ($this->_files as $file) {
+                if (isset($file['flaglookup'][$flags])) {
+                    ++$count;
+                }
+            }
+            return $count;
+        }
+        
+        $flags = array_flip($flags);
+           foreach ($this->_files as $file) {
+               foreach ($flags as $flag => $v) {
+                   if (!isset($file['flaglookup'][$flag])) {
+                       continue 2;
+                   }
+               }
+               ++$count;
+           }
+           return $count;
+    }
+
+    /**
+     * Get one or all fields from file structure. Also checks if message is valid
+     *
+     * @param  int         $id    message number
+     * @param  string|null $field wanted field
+     * @return string|array wanted field or all fields as array
+     * @throws Zend_Mail_Storage_Exception
+     */
+    protected function _getFileData($id, $field = null)
+    {
+        if (!isset($this->_files[$id - 1])) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('id does not exist');
+        }
+
+        if (!$field) {
+            return $this->_files[$id - 1];
+        }
+
+        if (!isset($this->_files[$id - 1][$field])) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('field does not exist');
+        }
+
+        return $this->_files[$id - 1][$field];
+    }
+
+    /**
+     * Get a list of messages with number and size
+     *
+     * @param  int|null $id number of message or null for all messages
+     * @return int|array size of given message of list with all messages as array(num => size)
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getSize($id = null)
+    {
+        if ($id !== null) {
+            $filedata = $this->_getFileData($id);
+            return isset($filedata['size']) ? $filedata['size'] : filesize($filedata['filename']);
+        }
+
+        $result = array();
+        foreach ($this->_files as $num => $data) {
+            $result[$num + 1] = isset($data['size']) ? $data['size'] : filesize($data['filename']);
+        }
+
+        return $result;
+    }
+
+
+
+    /**
+     * Fetch a message
+     *
+     * @param  int $id number of message
+     * @return Zend_Mail_Message_File
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getMessage($id)
+    {
+        // TODO that's ugly, would be better to let the message class decide
+        if (strtolower($this->_messageClass) == 'zend_mail_message_file' || is_subclass_of($this->_messageClass, 'zend_mail_message_file')) {
+            return new $this->_messageClass(array('file'  => $this->_getFileData($id, 'filename'),
+                                                  'flags' => $this->_getFileData($id, 'flags')));
+        }
+        
+        return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $this->getRawHeader($id),
+                                              'flags'   => $this->_getFileData($id, 'flags')));
+    }
+
+    /*
+     * Get raw header of message or part
+     *
+     * @param  int               $id       number of message
+     * @param  null|array|string $part     path to part or null for messsage header
+     * @param  int               $topLines include this many lines with header (after an empty line)
+     * @return string raw header
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawHeader($id, $part = null, $topLines = 0)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+
+        $fh = fopen($this->_getFileData($id, 'filename'), 'r');
+
+        $content = '';
+        while (!feof($fh)) {
+            $line = fgets($fh);
+            if (!trim($line)) {
+                break;
+            }
+            $content .= $line;
+        }
+
+        fclose($fh);
+        return $content;
+    }
+
+    /*
+     * Get raw content of message or part
+     *
+     * @param  int               $id   number of message
+     * @param  null|array|string $part path to part or null for messsage content
+     * @return string raw content
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawContent($id, $part = null)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+
+        $fh = fopen($this->_getFileData($id, 'filename'), 'r');
+
+        while (!feof($fh)) {
+            $line = fgets($fh);
+            if (!trim($line)) {
+                break;
+            }
+        }
+
+        $content = stream_get_contents($fh);
+        fclose($fh);
+        return $content;
+    }
+
+    /**
+     * Create instance with parameters
+     * Supported parameters are:
+     *   - dirname dirname of mbox file
+     *
+     * @param  $params array mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __construct($params)
+    {
+        if (is_array($params)) {
+            $params = (object)$params;
+        }
+
+        if (!isset($params->dirname) || !is_dir($params->dirname)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
+        }
+
+        if (!$this->_isMaildir($params->dirname)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('invalid maildir given');
+        }
+
+        $this->_has['top'] = true;
+        $this->_has['flags'] = true;
+        $this->_openMaildir($params->dirname);
+    }
+
+    /**
+     * check if a given dir is a valid maildir
+     *
+     * @param string $dirname name of dir
+     * @return bool dir is valid maildir
+     */
+    protected function _isMaildir($dirname)
+    {
+        if (file_exists($dirname . '/new') && !is_dir($dirname . '/new')) {
+            return false;
+        }
+        if (file_exists($dirname . '/tmp') && !is_dir($dirname . '/tmp')) {
+            return false;
+        }
+        return is_dir($dirname . '/cur');
+    }
+
+    /**
+     * open given dir as current maildir
+     *
+     * @param string $dirname name of maildir
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    protected function _openMaildir($dirname)
+    {
+        if ($this->_files) {
+            $this->close();
+        }
+
+        $dh = @opendir($dirname . '/cur/');
+        if (!$dh) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot open maildir');
+        }
+        $this->_getMaildirFiles($dh, $dirname . '/cur/');
+        closedir($dh);
+
+        $dh = @opendir($dirname . '/new/');
+        if ($dh) {
+            $this->_getMaildirFiles($dh, $dirname . '/new/', array(Zend_Mail_Storage::FLAG_RECENT));
+            closedir($dh);
+        } else if (file_exists($dirname . '/new/')) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot read recent mails in maildir');
+        }
+    }
+
+    /**
+     * find all files in opened dir handle and add to maildir files
+     *
+     * @param resource $dh            dir handle used for search
+     * @param string   $dirname       dirname of dir in $dh
+     * @param array    $default_flags default flags for given dir
+     * @return null
+     */
+    protected function _getMaildirFiles($dh, $dirname, $default_flags = array())
+    {
+        while (($entry = readdir($dh)) !== false) {
+            if ($entry[0] == '.' || !is_file($dirname . $entry)) {
+                continue;
+            }
+
+            @list($uniq, $info) = explode(':', $entry, 2);
+            @list(,$size) = explode(',', $uniq, 2);
+            if ($size && $size[0] == 'S' && $size[1] == '=') {
+                $size = substr($size, 2);
+            }
+            if (!ctype_digit($size)) {
+                $size = null;
+            }
+            @list($version, $flags) = explode(',', $info, 2);
+            if ($version != 2) {
+                $flags = '';
+            }
+
+            $named_flags = $default_flags;
+            $length = strlen($flags);
+            for ($i = 0; $i < $length; ++$i) {
+                $flag = $flags[$i];
+                $named_flags[$flag] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
+            }
+
+            $data = array('uniq'       => $uniq,
+                          'flags'      => $named_flags,
+                          'flaglookup' => array_flip($named_flags),
+                          'filename'   => $dirname . $entry);
+            if ($size !== null) {
+                $data['size'] = (int)$size;
+            }
+            $this->_files[] = $data;
+        }
+    }
+
+
+    /**
+     * Close resource for mail lib. If you need to control, when the resource
+     * is closed. Otherwise the destructor would call this.
+     *
+     * @return void
+     */
+    public function close()
+    {
+        $this->_files = array();
+    }
+
+
+    /**
+     * Waste some CPU cycles doing nothing.
+     *
+     * @return void
+     */
+    public function noop()
+    {
+        return true;
+    }
+
+
+    /**
+     * stub for not supported message deletion
+     *
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function removeMessage($id)
+    {
+        /**
+         * @see Zend_Mail_Storage_Exception
+         */
+        require_once 'Zend/Mail/Storage/Exception.php';
+        throw new Zend_Mail_Storage_Exception('maildir is (currently) read-only');
+    }
+
+    /**
+     * get unique id for one or all messages
+     *
+     * if storage does not support unique ids it's the same as the message number
+     *
+     * @param int|null $id message number
+     * @return array|string message number for given message or all messages as array
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getUniqueId($id = null)
+    {
+        if ($id) {
+            return $this->_getFileData($id, 'uniq');
+        }
+
+        $ids = array();
+        foreach ($this->_files as $num => $file) {
+            $ids[$num + 1] = $file['uniq'];
+        }
+        return $ids;
+    }
+
+    /**
+     * get a message number from a unique id
+     *
+     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
+     * as parameter and use this method to translate it to message number right before calling removeMessage()
+     *
+     * @param string $id unique id
+     * @return int message number
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getNumberByUniqueId($id)
+    {
+        foreach ($this->_files as $num => $file) {
+            if ($file['uniq'] == $id) {
+                return $num + 1;
+            }
+        }
+
+        /**
+         * @see Zend_Mail_Storage_Exception
+         */
+        require_once 'Zend/Mail/Storage/Exception.php';
+        throw new Zend_Mail_Storage_Exception('unique id not found');
+    }
+}
diff --git a/lib/Zend/Mail/Storage/Mbox.php b/lib/Zend/Mail/Storage/Mbox.php
new file mode 100644
index 0000000..8be42d8
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Mbox.php
@@ -0,0 +1,447 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Mbox.php 12519 2008-11-10 18:41:24Z alexander $
+ */
+
+
+/**
+ * @see Zend_Loader
+ * May be used in constructor, but commented out for now
+ */
+// require_once 'Zend/Loader.php';
+
+/**
+ * @see Zend_Mail_Storage_Abstract
+ */
+require_once 'Zend/Mail/Storage/Abstract.php';
+
+/**
+ * @see Zend_Mail_Message_File
+ */
+require_once 'Zend/Mail/Message/File.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Mbox extends Zend_Mail_Storage_Abstract
+{
+    /**
+     * file handle to mbox file
+     * @var null|resource
+     */
+    protected $_fh;
+
+    /**
+     * filename of mbox file for __wakeup
+     * @var string
+     */
+    protected $_filename;
+
+    /**
+     * modification date of mbox file for __wakeup
+     * @var int
+     */
+    protected $_filemtime;
+
+    /**
+     * start and end position of messages as array('start' => start, 'seperator' => headersep, 'end' => end)
+     * @var array
+     */
+    protected $_positions;
+
+    /**
+     * used message class, change it in an extened class to extend the returned message class
+     * @var string
+     */
+    protected $_messageClass = 'Zend_Mail_Message_File';
+
+    /**
+     * Count messages all messages in current box
+     *
+     * @return int number of messages
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function countMessages()
+    {
+        return count($this->_positions);
+    }
+
+
+    /**
+     * Get a list of messages with number and size
+     *
+     * @param  int|null $id  number of message or null for all messages
+     * @return int|array size of given message of list with all messages as array(num => size)
+     */
+    public function getSize($id = 0)
+    {
+        if ($id) {
+            $pos = $this->_positions[$id - 1];
+            return $pos['end'] - $pos['start'];
+        }
+
+        $result = array();
+        foreach ($this->_positions as $num => $pos) {
+            $result[$num + 1] = $pos['end'] - $pos['start'];
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * Get positions for mail message or throw exeption if id is invalid
+     *
+     * @param int $id number of message
+     * @return array positions as in _positions
+     * @throws Zend_Mail_Storage_Exception
+     */
+    protected function _getPos($id)
+    {
+        if (!isset($this->_positions[$id - 1])) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('id does not exist');
+        }
+
+        return $this->_positions[$id - 1];
+    }
+
+
+    /**
+     * Fetch a message
+     *
+     * @param  int $id number of message
+     * @return Zend_Mail_Message_File
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getMessage($id)
+    {
+        // TODO that's ugly, would be better to let the message class decide
+        if (strtolower($this->_messageClass) == 'zend_mail_message_file' || is_subclass_of($this->_messageClass, 'zend_mail_message_file')) {
+            // TODO top/body lines
+            $messagePos = $this->_getPos($id);
+            return new $this->_messageClass(array('file' => $this->_fh, 'startPos' => $messagePos['start'],
+                                                  'endPos' => $messagePos['end']));
+        }
+
+        $bodyLines = 0; // TODO: need a way to change that
+
+        $message = $this->getRawHeader($id);
+        // file pointer is after headers now
+        if ($bodyLines) {
+            $message .= "\n";
+            while ($bodyLines-- && ftell($this->_fh) < $this->_positions[$id - 1]['end']) {
+                $message .= fgets($this->_fh);
+            }
+        }
+
+        return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $message));
+    }
+
+    /*
+     * Get raw header of message or part
+     *
+     * @param  int               $id       number of message
+     * @param  null|array|string $part     path to part or null for messsage header
+     * @param  int               $topLines include this many lines with header (after an empty line)
+     * @return string raw header
+     * @throws Zend_Mail_Protocol_Exception
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawHeader($id, $part = null, $topLines = 0)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+        $messagePos = $this->_getPos($id);
+        // TODO: toplines
+        return stream_get_contents($this->_fh, $messagePos['separator'] - $messagePos['start'], $messagePos['start']);
+    }
+
+    /*
+     * Get raw content of message or part
+     *
+     * @param  int               $id   number of message
+     * @param  null|array|string $part path to part or null for messsage content
+     * @return string raw content
+     * @throws Zend_Mail_Protocol_Exception
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawContent($id, $part = null)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+        $messagePos = $this->_getPos($id);
+        return stream_get_contents($this->_fh, $messagePos['end'] - $messagePos['separator'], $messagePos['separator']);
+    }
+
+    /**
+     * Create instance with parameters
+     * Supported parameters are:
+     *   - filename filename of mbox file
+     *
+     * @param  $params array mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __construct($params)
+    {
+        if (is_array($params)) {
+            $params = (object)$params;
+        }
+    
+        if (!isset($params->filename) /* || Zend_Loader::isReadable($params['filename']) */) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('no valid filename given in params');
+        }
+
+        $this->_openMboxFile($params->filename);
+        $this->_has['top']      = true;
+        $this->_has['uniqueid'] = false;
+    }
+
+    /**
+     * check if given file is a mbox file
+     *
+     * if $file is a resource its file pointer is moved after the first line
+     *
+     * @param  resource|string $file stream resource of name of file
+     * @param  bool $fileIsString file is string or resource
+     * @return bool file is mbox file
+     */
+    protected function _isMboxFile($file, $fileIsString = true)
+    {
+        if ($fileIsString) {
+            $file = @fopen($file, 'r');
+            if (!$file) {
+                return false;
+            }
+        } else {
+            fseek($file, 0);
+        }
+
+        $result = false;
+
+        $line = fgets($file);
+        if (strpos($line, 'From ') === 0) {
+            $result = true;
+        }
+
+        if ($fileIsString) {
+            @fclose($file);
+        }
+
+        return $result;
+    }
+
+    /**
+     * open given file as current mbox file
+     *
+     * @param  string $filename filename of mbox file
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    protected function _openMboxFile($filename)
+    {
+        if ($this->_fh) {
+            $this->close();
+        }
+
+        $this->_fh = @fopen($filename, 'r');
+        if (!$this->_fh) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot open mbox file');
+        }
+        $this->_filename = $filename;
+        $this->_filemtime = filemtime($this->_filename);
+
+        if (!$this->_isMboxFile($this->_fh, false)) {
+            @fclose($this->_fh);
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('file is not a valid mbox format');
+        }
+
+        $messagePos = array('start' => ftell($this->_fh), 'separator' => 0, 'end' => 0);
+        while (($line = fgets($this->_fh)) !== false) {
+            if (strpos($line, 'From ') === 0) {
+                $messagePos['end'] = ftell($this->_fh) - strlen($line) - 2; // + newline
+                if (!$messagePos['separator']) {
+                    $messagePos['separator'] = $messagePos['end'];
+                }
+                $this->_positions[] = $messagePos;
+                $messagePos = array('start' => ftell($this->_fh), 'separator' => 0, 'end' => 0);
+            }
+            if (!$messagePos['separator'] && !trim($line)) {
+                $messagePos['separator'] = ftell($this->_fh);
+            }
+        }
+
+        $messagePos['end'] = ftell($this->_fh);
+        if (!$messagePos['separator']) {
+            $messagePos['separator'] = $messagePos['end'];
+        }
+        $this->_positions[] = $messagePos;
+    }
+
+    /**
+     * Close resource for mail lib. If you need to control, when the resource
+     * is closed. Otherwise the destructor would call this.
+     *
+     * @return void
+     */
+    public function close()
+    {
+        @fclose($this->_fh);
+        $this->_positions = array();
+    }
+
+
+    /**
+     * Waste some CPU cycles doing nothing.
+     *
+     * @return void
+     */
+    public function noop()
+    {
+        return true;
+    }
+
+
+    /**
+     * stub for not supported message deletion
+     *
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function removeMessage($id)
+    {
+        /**
+         * @see Zend_Mail_Storage_Exception
+         */
+        require_once 'Zend/Mail/Storage/Exception.php';
+        throw new Zend_Mail_Storage_Exception('mbox is read-only');
+    }
+
+    /**
+     * get unique id for one or all messages
+     *
+     * Mbox does not support unique ids (yet) - it's always the same as the message number.
+     * That shouldn't be a problem, because we can't change mbox files. Therefor the message
+     * number is save enough.
+     *
+     * @param int|null $id message number
+     * @return array|string message number for given message or all messages as array
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getUniqueId($id = null)
+    {
+        if ($id) {
+            // check if id exists
+            $this->_getPos($id);
+            return $id;
+        }
+
+        $range = range(1, $this->countMessages());
+        return array_combine($range, $range);
+    }
+
+    /**
+     * get a message number from a unique id
+     *
+     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
+     * as parameter and use this method to translate it to message number right before calling removeMessage()
+     *
+     * @param string $id unique id
+     * @return int message number
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getNumberByUniqueId($id)
+    {
+        // check if id exists
+        $this->_getPos($id);
+        return $id;
+    }
+
+    /**
+     * magic method for serialize()
+     *
+     * with this method you can cache the mbox class
+     *
+     * @return array name of variables
+     */
+    public function __sleep()
+    {
+        return array('_filename', '_positions', '_filemtime');
+    }
+
+    /**
+     * magic method for unserialize()
+     *
+     * with this method you can cache the mbox class
+     * for cache validation the mtime of the mbox file is used
+     *
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __wakeup()
+    {
+        if ($this->_filemtime != @filemtime($this->_filename)) {
+            $this->close();
+            $this->_openMboxFile($this->_filename);
+        } else {
+            $this->_fh = @fopen($this->_filename, 'r');
+            if (!$this->_fh) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('cannot open mbox file');
+            }
+        }
+    }
+
+}
diff --git a/lib/Zend/Mail/Storage/Pop3.php b/lib/Zend/Mail/Storage/Pop3.php
new file mode 100644
index 0000000..693384d
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Pop3.php
@@ -0,0 +1,328 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Pop3.php 9099 2008-03-30 19:35:47Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Storage_Abstract
+ */
+require_once 'Zend/Mail/Storage/Abstract.php';
+
+/**
+ * @see Zend_Mail_Protocol_Pop3
+ */
+require_once 'Zend/Mail/Protocol/Pop3.php';
+
+/**
+ * @see Zend_Mail_Message
+ */
+require_once 'Zend/Mail/Message.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Pop3 extends Zend_Mail_Storage_Abstract
+{
+    /**
+     * protocol handler
+     * @var null|Zend_Mail_Protocol_Pop3
+     */
+    protected $_protocol;
+
+
+    /**
+     * Count messages all messages in current box
+     *
+     * @return int number of messages
+     * @throws Zend_Mail_Storage_Exception
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function countMessages()
+    {
+        $this->_protocol->status($count, $null);
+        return (int)$count;
+    }
+
+    /**
+     * get a list of messages with number and size
+     *
+     * @param int $id number of message
+     * @return int|array size of given message of list with all messages as array(num => size)
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function getSize($id = 0)
+    {
+        $id = $id ? $id : null;
+        return $this->_protocol->getList($id);
+    }
+
+    /**
+     * Fetch a message
+     *
+     * @param int $id number of message
+     * @return Zend_Mail_Message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function getMessage($id)
+    {
+        $bodyLines = 0;
+        $message = $this->_protocol->top($id, $bodyLines, true);
+
+        return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $message,
+                                              'noToplines' => $bodyLines < 1));
+    }
+
+    /*
+     * Get raw header of message or part
+     *
+     * @param  int               $id       number of message
+     * @param  null|array|string $part     path to part or null for messsage header
+     * @param  int               $topLines include this many lines with header (after an empty line)
+     * @return string raw header
+     * @throws Zend_Mail_Protocol_Exception
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawHeader($id, $part = null, $topLines = 0)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+
+        return $this->_protocol->top($id, 0, true);
+    }
+
+    /*
+     * Get raw content of message or part
+     *
+     * @param  int               $id   number of message
+     * @param  null|array|string $part path to part or null for messsage content
+     * @return string raw content
+     * @throws Zend_Mail_Protocol_Exception
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getRawContent($id, $part = null)
+    {
+        if ($part !== null) {
+            // TODO: implement
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('not implemented');
+        }
+
+        $content = $this->_protocol->retrieve($id);
+        // TODO: find a way to avoid decoding the headers
+        Zend_Mime_Decode::splitMessage($content, $null, $body);
+        return $body;
+    }
+
+    /**
+     * create instance with parameters
+     * Supported paramters are
+     *   - host hostname or ip address of POP3 server
+     *   - user username
+     *   - password password for user 'username' [optional, default = '']
+     *   - port port for POP3 server [optional, default = 110]
+     *   - ssl 'SSL' or 'TLS' for secure sockets
+     *
+     * @param  $params array  mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function __construct($params)
+    {
+        if (is_array($params)) {
+            $params = (object)$params;
+        }
+
+        $this->_has['fetchPart'] = false;
+        $this->_has['top']       = null;
+        $this->_has['uniqueid']  = null;
+
+        if ($params instanceof Zend_Mail_Protocol_Pop3) {
+            $this->_protocol = $params;
+            return;
+        }
+
+        if (!isset($params->user)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('need at least user in params');
+        }
+
+        $host     = isset($params->host)     ? $params->host     : 'localhost';
+        $password = isset($params->password) ? $params->password : '';
+        $port     = isset($params->port)     ? $params->port     : null;
+        $ssl      = isset($params->ssl)      ? $params->ssl      : false;
+
+        $this->_protocol = new Zend_Mail_Protocol_Pop3();
+        $this->_protocol->connect($host, $port, $ssl);
+        $this->_protocol->login($params->user, $password);
+    }
+
+    /**
+     * Close resource for mail lib. If you need to control, when the resource
+     * is closed. Otherwise the destructor would call this.
+     *
+     * @return null
+     */
+    public function close()
+    {
+        $this->_protocol->logout();
+    }
+
+    /**
+     * Keep the server busy.
+     *
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function noop()
+    {
+        return $this->_protocol->noop();
+    }
+
+    /**
+     * Remove a message from server. If you're doing that from a web enviroment
+     * you should be careful and use a uniqueid as parameter if possible to
+     * identify the message.
+     *
+     * @param  int $id number of message
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function removeMessage($id)
+    {
+        $this->_protocol->delete($id);
+    }
+
+    /**
+     * get unique id for one or all messages
+     *
+     * if storage does not support unique ids it's the same as the message number
+     *
+     * @param int|null $id message number
+     * @return array|string message number for given message or all messages as array
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getUniqueId($id = null)
+    {
+        if (!$this->hasUniqueid) {
+            if ($id) {
+                return $id;
+            }
+            $count = $this->countMessages();
+            if ($count < 1) {
+                return array(); 
+            }
+            $range = range(1, $count);
+            return array_combine($range, $range);
+        }
+
+        return $this->_protocol->uniqueid($id);
+    }
+
+    /**
+     * get a message number from a unique id
+     *
+     * I.e. if you have a webmailer that supports deleting messages you should use unique ids
+     * as parameter and use this method to translate it to message number right before calling removeMessage()
+     *
+     * @param string $id unique id
+     * @return int message number
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function getNumberByUniqueId($id)
+    {
+        if (!$this->hasUniqueid) {
+            return $id;
+        }
+
+        $ids = $this->getUniqueId();
+        foreach ($ids as $k => $v) {
+            if ($v == $id) {
+                return $k;
+            }
+        }
+
+        /**
+         * @see Zend_Mail_Storage_Exception
+         */
+        require_once 'Zend/Mail/Storage/Exception.php';
+        throw new Zend_Mail_Storage_Exception('unique id not found');
+    }
+
+    /**
+     * Special handling for hasTop and hasUniqueid. The headers of the first message is
+     * retrieved if Top wasn't needed/tried yet.
+     *
+     * @see Zend_Mail_Storage_Abstract:__get()
+     * @param  string $var
+     * @return string
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __get($var)
+    {
+        $result = parent::__get($var);
+        if ($result !== null) {
+            return $result;
+        }
+
+        if (strtolower($var) == 'hastop') {
+            if ($this->_protocol->hasTop === null) {
+                // need to make a real call, because not all server are honest in their capas
+                try {
+                    $this->_protocol->top(1, 0, false);
+                } catch(Zend_Mail_Exception $e) {
+                    // ignoring error
+                }
+            }
+            $this->_has['top'] = $this->_protocol->hasTop;
+            return $this->_protocol->hasTop;
+        }
+
+        if (strtolower($var) == 'hasuniqueid') {
+            $id = null;
+            try {
+                $id = $this->_protocol->uniqueid(1);
+            } catch(Zend_Mail_Exception $e) {
+                // ignoring error
+            }
+            $this->_has['uniqueid'] = $id ? true : false;
+            return $this->_has['uniqueid'];
+        }
+
+        return $result;
+    }
+}
diff --git a/lib/Zend/Mail/Storage/Writable/Interface.php b/lib/Zend/Mail/Storage/Writable/Interface.php
new file mode 100644
index 0000000..b49fc8e
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Writable/Interface.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Interface.php 9098 2008-03-30 19:29:10Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+interface Zend_Mail_Storage_Writable_Interface
+{
+    /**
+     * create a new folder
+     *
+     * This method also creates parent folders if necessary. Some mail storages may restrict, which folder
+     * may be used as parent or which chars may be used in the folder name
+     *
+     * @param string                          $name         global name of folder, local name if $parentFolder is set
+     * @param string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function createFolder($name, $parentFolder = null);
+
+    /**
+     * remove a folder
+     *
+     * @param string|Zend_Mail_Storage_Folder $name      name or instance of folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function removeFolder($name);
+
+    /**
+     * rename and/or move folder
+     *
+     * The new name has the same restrictions as in createFolder()
+     *
+     * @param string|Zend_Mail_Storage_Folder $oldName name or instance of folder
+     * @param string                          $newName new global name of folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function renameFolder($oldName, $newName);
+
+    /**
+     * append a new message to mail storage
+     *
+     * @param  string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
+     * @param  null|string|Zend_Mail_Storage_Folder       $folder  folder for new message, else current folder is taken
+     * @param  null|array                                 $flags   set flags for new message, else a default set is used
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function appendMessage($message, $folder = null, $flags = null);
+
+    /**
+     * copy an existing message
+     *
+     * @param  int                             $id     number of message
+     * @param  string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function copyMessage($id, $folder);
+
+    /**
+     * move an existing message
+     *
+     * @param  int                             $id     number of message
+     * @param  string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function moveMessage($id, $folder);
+
+    /**
+     * set flags for message
+     *
+     * NOTE: this method can't set the recent flag.
+     *
+     * @param  int   $id    number of message
+     * @param  array $flags new flags for message
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function setFlags($id, $flags);
+}
\ No newline at end of file
diff --git a/lib/Zend/Mail/Storage/Writable/Maildir.php b/lib/Zend/Mail/Storage/Writable/Maildir.php
new file mode 100644
index 0000000..9ba7573
--- /dev/null
+++ b/lib/Zend/Mail/Storage/Writable/Maildir.php
@@ -0,0 +1,1049 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Maildir.php 12519 2008-11-10 18:41:24Z alexander $
+ */
+
+
+/**
+ * @see Zend_Mail_Storage_Folder_Maildir
+ */
+require_once 'Zend/Mail/Storage/Folder/Maildir.php';
+
+/**
+ * @see Zend_Mail_Storage_Writable_Interface
+ */
+require_once 'Zend/Mail/Storage/Writable/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Storage
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Storage_Writable_Maildir extends    Zend_Mail_Storage_Folder_Maildir
+                                         implements Zend_Mail_Storage_Writable_Interface
+{
+    // TODO: init maildir (+ constructor option create if not found)
+
+    /**
+     * use quota and size of quota if given
+     * @var bool|int
+     */
+    protected $_quota;
+    
+    /**
+     * create a new maildir
+     *
+     * If the given dir is already a valid maildir this will not fail.
+     *
+     * @param string $dir directory for the new maildir (may already exist)
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public static function initMaildir($dir)
+    {
+        if (file_exists($dir)) {
+            if (!is_dir($dir)) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('maildir must be a directory if already exists');
+            }
+        } else {
+            if (!mkdir($dir)) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                $dir = dirname($dir);
+                if (!file_exists($dir)) {
+                    throw new Zend_Mail_Storage_Exception("parent $dir not found");
+                } else if (!is_dir($dir)) {
+                    throw new Zend_Mail_Storage_Exception("parent $dir not a directory");
+                } else {
+                    throw new Zend_Mail_Storage_Exception('cannot create maildir');
+                }
+            }
+        }
+        
+        foreach (array('cur', 'tmp', 'new') as $subdir) {
+            if (!@mkdir($dir . DIRECTORY_SEPARATOR . $subdir)) {
+                // ignore if dir exists (i.e. was already valid maildir or two processes try to create one)
+                if (!file_exists($dir . DIRECTORY_SEPARATOR . $subdir)) {
+                    /**
+                     * @see Zend_Mail_Storage_Exception
+                     */
+                    require_once 'Zend/Mail/Storage/Exception.php';
+                    throw new Zend_Mail_Storage_Exception('could not create subdir ' . $subdir);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Create instance with parameters
+     * Additional parameters are (see parent for more):
+     *   - create if true a new maildir is create if none exists
+     *
+     * @param  $params array mail reader specific parameters
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function __construct($params) {
+        if (is_array($params)) {
+            $params = (object)$params;
+        }
+        
+        if (!empty($params->create) && isset($params->dirname) && !file_exists($params->dirname . DIRECTORY_SEPARATOR . 'cur')) {
+            self::initMaildir($params->dirname);
+        }
+        
+        parent::__construct($params);
+    }
+
+    /**
+     * create a new folder
+     *
+     * This method also creates parent folders if necessary. Some mail storages may restrict, which folder
+     * may be used as parent or which chars may be used in the folder name
+     *
+     * @param   string                          $name         global name of folder, local name if $parentFolder is set
+     * @param   string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
+     * @return  string only used internally (new created maildir)
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    public function createFolder($name, $parentFolder = null)
+    {
+        if ($parentFolder instanceof Zend_Mail_Storage_Folder) {
+            $folder = $parentFolder->getGlobalName() . $this->_delim . $name;
+        } else if ($parentFolder != null) {
+            $folder = rtrim($parentFolder, $this->_delim) . $this->_delim . $name;
+        } else {
+            $folder = $name;
+        }
+
+        $folder = trim($folder, $this->_delim);
+
+        // first we check if we try to create a folder that does exist
+        $exists = null;
+        try {
+            $exists = $this->getFolders($folder);
+        } catch (Zend_Mail_Exception $e) {
+            // ok
+        }
+        if ($exists) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('folder already exists');
+        }
+
+        if (strpos($folder, $this->_delim . $this->_delim) !== false) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('invalid name - folder parts may not be empty');
+        }
+
+        if (strpos($folder, 'INBOX' . $this->_delim) === 0) {
+            $folder = substr($folder, 6);
+        }
+
+        $fulldir = $this->_rootdir . '.' . $folder;
+
+        // check if we got tricked and would create a dir outside of the rootdir or not as direct child
+        if (strpos($folder, DIRECTORY_SEPARATOR) !== false || strpos($folder, '/') !== false
+            || dirname($fulldir) . DIRECTORY_SEPARATOR != $this->_rootdir) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('invalid name - no directory seprator allowed in folder name');
+        }
+
+        // has a parent folder?
+        $parent = null;
+        if (strpos($folder, $this->_delim)) {
+            // let's see if the parent folder exists
+            $parent = substr($folder, 0, strrpos($folder, $this->_delim));
+            try {
+                $this->getFolders($parent);
+            } catch (Zend_Mail_Exception $e) {
+                // does not - create parent folder
+                $this->createFolder($parent);
+            }
+        }
+
+        if (!@mkdir($fulldir) || !@mkdir($fulldir . DIRECTORY_SEPARATOR . 'cur')) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('error while creating new folder, may be created incompletly');
+        }
+
+        mkdir($fulldir . DIRECTORY_SEPARATOR . 'new');
+        mkdir($fulldir . DIRECTORY_SEPARATOR . 'tmp');
+
+        $localName = $parent ? substr($folder, strlen($parent) + 1) : $folder;
+        $this->getFolders($parent)->$localName = new Zend_Mail_Storage_Folder($localName, $folder, true);
+
+        return $fulldir;
+    }
+
+    /**
+     * remove a folder
+     *
+     * @param   string|Zend_Mail_Storage_Folder $name      name or instance of folder
+     * @return  null
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    public function removeFolder($name)
+    {
+        // TODO: This could fail in the middle of the task, which is not optimal.
+        // But there is no defined standard way to mark a folder as removed and there is no atomar fs-op
+        // to remove a directory. Also moving the folder to a/the trash folder is not possible, as
+        // all parent folders must be created. What we could do is add a dash to the front of the
+        // directory name and it should be ignored as long as other processes obey the standard.
+
+        if ($name instanceof Zend_Mail_Storage_Folder) {
+            $name = $name->getGlobalName();
+        }
+
+        $name = trim($name, $this->_delim);
+        if (strpos($name, 'INBOX' . $this->_delim) === 0) {
+            $name = substr($name, 6);
+        }
+
+        // check if folder exists and has no children
+        if (!$this->getFolders($name)->isLeaf()) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('delete children first');
+        }
+
+        if ($name == 'INBOX' || $name == DIRECTORY_SEPARATOR || $name == '/') {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('wont delete INBOX');
+        }
+
+        if ($name == $this->getCurrentFolder()) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('wont delete selected folder');
+        }
+
+        foreach (array('tmp', 'new', 'cur', '.') as $subdir) {
+            $dir = $this->_rootdir . '.' . $name . DIRECTORY_SEPARATOR . $subdir;
+            if (!file_exists($dir)) {
+                continue;
+            }
+            $dh = opendir($dir);
+            if (!$dh) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception("error opening $subdir");
+            }
+            while (($entry = readdir($dh)) !== false) {
+                if ($entry == '.' || $entry == '..') {
+                    continue;
+                }
+                if (!unlink($dir . DIRECTORY_SEPARATOR . $entry)) {
+                    /**
+                     * @see Zend_Mail_Storage_Exception
+                     */
+                    require_once 'Zend/Mail/Storage/Exception.php';
+                    throw new Zend_Mail_Storage_Exception("error cleaning $subdir");
+                }
+            }
+            closedir($dh);
+            if ($subdir !== '.') {
+                if (!rmdir($dir)) {
+                    /**
+                     * @see Zend_Mail_Storage_Exception
+                     */
+                    require_once 'Zend/Mail/Storage/Exception.php';
+                    throw new Zend_Mail_Storage_Exception("error removing $subdir");
+                }
+            }
+        }
+
+        if (!rmdir($this->_rootdir . '.' . $name)) {
+            // at least we should try to make it a valid maildir again
+            mkdir($this->_rootdir . '.' . $name . DIRECTORY_SEPARATOR . 'cur');
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception("error removing maindir");
+        }
+
+        $parent = strpos($name, $this->_delim) ? substr($name, 0, strrpos($name, $this->_delim)) : null;
+        $localName = $parent ? substr($name, strlen($parent) + 1) : $name;
+        unset($this->getFolders($parent)->$localName);
+    }
+
+    /**
+     * rename and/or move folder
+     *
+     * The new name has the same restrictions as in createFolder()
+     *
+     * @param   string|Zend_Mail_Storage_Folder $oldName name or instance of folder
+     * @param   string                          $newName new global name of folder
+     * @return  null
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    public function renameFolder($oldName, $newName)
+    {
+        // TODO: This is also not atomar and has similar problems as removeFolder()
+
+        if ($oldName instanceof Zend_Mail_Storage_Folder) {
+            $oldName = $oldName->getGlobalName();
+        }
+
+        $oldName = trim($oldName, $this->_delim);
+        if (strpos($oldName, 'INBOX' . $this->_delim) === 0) {
+            $oldName = substr($oldName, 6);
+        }
+
+        $newName = trim($newName, $this->_delim);
+        if (strpos($newName, 'INBOX' . $this->_delim) === 0) {
+            $newName = substr($newName, 6);
+        }
+
+        if (strpos($newName, $oldName . $this->_delim) === 0) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('new folder cannot be a child of old folder');
+        }
+
+        // check if folder exists and has no children
+        $folder = $this->getFolders($oldName);
+
+        if ($oldName == 'INBOX' || $oldName == DIRECTORY_SEPARATOR || $oldName == '/') {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('wont rename INBOX');
+        }
+
+        if ($oldName == $this->getCurrentFolder()) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('wont rename selected folder');
+        }
+
+        $newdir = $this->createFolder($newName);
+
+        if (!$folder->isLeaf()) {
+            foreach ($folder as $k => $v) {
+                $this->renameFolder($v->getGlobalName(), $newName . $this->_delim . $k);
+            }
+        }
+
+        $olddir = $this->_rootdir . '.' . $folder;
+        foreach (array('tmp', 'new', 'cur') as $subdir) {
+            $subdir = DIRECTORY_SEPARATOR . $subdir;
+            if (!file_exists($olddir . $subdir)) {
+                continue;
+            }
+            // using copy or moving files would be even better - but also much slower
+            if (!rename($olddir . $subdir, $newdir . $subdir)) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('error while moving ' . $subdir);
+            }
+        }
+        // create a dummy if removing fails - otherwise we can't read it next time
+        mkdir($olddir . DIRECTORY_SEPARATOR . 'cur');
+        $this->removeFolder($oldName);
+    }
+
+    /**
+     * create a uniqueid for maildir filename
+     *
+     * This is nearly the format defined in the maildir standard. The microtime() call should already
+     * create a uniqueid, the pid is for multicore/-cpu machine that manage to call this function at the
+     * exact same time, and uname() gives us the hostname for multiple machines accessing the same storage.
+     *
+     * If someone disables posix we create a random number of the same size, so this method should also
+     * work on Windows - if you manage to get maildir working on Windows.
+     * Microtime could also be disabled, altough I've never seen it.
+     *
+     * @return string new uniqueid
+     */
+    protected function _createUniqueId()
+    {
+        $id = '';
+        $id .= function_exists('microtime') ? microtime(true) : (time() . ' ' . rand(0, 100000));
+        $id .= '.' . (function_exists('posix_getpid') ? posix_getpid() : rand(50, 65535));
+        $id .= '.' . php_uname('n');
+
+        return $id;
+    }
+
+    /**
+     * open a temporary maildir file
+     *
+     * makes sure tmp/ exists and create a file with a unique name
+     * you should close the returned filehandle!
+     *
+     * @param   string $folder name of current folder without leading .
+     * @return  array array('dirname' => dir of maildir folder, 'uniq' => unique id, 'filename' => name of create file
+     *                     'handle'  => file opened for writing)
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    protected function _createTmpFile($folder = 'INBOX')
+    {
+        if ($folder == 'INBOX') {
+            $tmpdir = $this->_rootdir . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
+        } else {
+            $tmpdir = $this->_rootdir . '.' . $folder . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR;
+        }
+        if (!file_exists($tmpdir)) {
+            if (!mkdir($tmpdir)) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('problems creating tmp dir');
+            }
+        }
+
+        // we should retry to create a unique id if a file with the same name exists
+        // to avoid a script timeout we only wait 1 second (instead of 2) and stop
+        // after a defined retry count
+        // if you change this variable take into account that it can take up to $max_tries seconds
+        // normally we should have a valid unique name after the first try, we're just following the "standard" here
+        $max_tries = 5;
+        for ($i = 0; $i < $max_tries; ++$i) {
+            $uniq = $this->_createUniqueId();
+            if (!file_exists($tmpdir . $uniq)) {
+                // here is the race condition! - as defined in the standard
+                // to avoid having a long time between stat()ing the file and creating it we're opening it here
+                // to mark the filename as taken
+                $fh = fopen($tmpdir . $uniq, 'w');
+                if (!$fh) {
+                    /**
+                     * @see Zend_Mail_Storage_Exception
+                     */
+                    require_once 'Zend/Mail/Storage/Exception.php';
+                    throw new Zend_Mail_Storage_Exception('could not open temp file');
+                }
+                break;
+            }
+            sleep(1);
+        }
+
+        if (!$fh) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception("tried $max_tries unique ids for a temp file, but all were taken"
+                                                . ' - giving up');
+        }
+
+        return array('dirname' => $this->_rootdir . '.' . $folder, 'uniq' => $uniq, 'filename' => $tmpdir . $uniq,
+                     'handle' => $fh);
+    }
+
+    /**
+     * create an info string for filenames with given flags
+     *
+     * @param   array $flags wanted flags, with the reference you'll get the set flags with correct key (= char for flag)
+     * @return  string info string for version 2 filenames including the leading colon
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    protected function _getInfoString(&$flags)
+    {
+        // accessing keys is easier, faster and it removes duplicated flags
+        $wanted_flags = array_flip($flags);
+        if (isset($wanted_flags[Zend_Mail_Storage::FLAG_RECENT])) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('recent flag may not be set');
+        }
+
+        $info = ':2,';
+        $flags = array();
+        foreach (Zend_Mail_Storage_Maildir::$_knownFlags as $char => $flag) {
+            if (!isset($wanted_flags[$flag])) {
+                continue;
+            }
+            $info .= $char;
+            $flags[$char] = $flag;
+            unset($wanted_flags[$flag]);
+        }
+
+        if (!empty($wanted_flags)) {
+            $wanted_flags = implode(', ', array_keys($wanted_flags));
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('unknown flag(s): ' . $wanted_flags);
+        }
+
+        return $info;
+    }
+
+    /**
+     * append a new message to mail storage
+     *
+     * @param   string|stream                              $message message as string or stream resource
+     * @param   null|string|Zend_Mail_Storage_Folder       $folder  folder for new message, else current folder is taken
+     * @param   null|array                                 $flags   set flags for new message, else a default set is used
+     * @param   bool                                       $recent  handle this mail as if recent flag has been set,
+     *                                                              should only be used in delivery
+     * @throws  Zend_Mail_Storage_Exception
+     */
+     // not yet * @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
+
+    public function appendMessage($message, $folder = null, $flags = null, $recent = false)
+    {
+        if ($this->_quota && $this->checkQuota()) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('storage is over quota!');            
+        }
+
+        if ($folder === null) {
+            $folder = $this->_currentFolder;
+        }
+
+        if (!($folder instanceof Zend_Mail_Storage_Folder)) {
+            $folder = $this->getFolders($folder);
+        }
+
+        if ($flags === null) {
+            $flags = array(Zend_Mail_Storage::FLAG_SEEN);
+        }
+        $info = $this->_getInfoString($flags);
+        $temp_file = $this->_createTmpFile($folder->getGlobalName());
+
+        // TODO: handle class instances for $message
+        if (is_resource($message) && get_resource_type($message) == 'stream') {
+            stream_copy_to_stream($message, $temp_file['handle']);
+        } else {
+            fputs($temp_file['handle'], $message);
+        }
+        fclose($temp_file['handle']);
+
+        // we're adding the size to the filename for maildir++
+        $size = filesize($temp_file['filename']);
+        if ($size !== false) {
+            $info = ',S=' . $size . $info;
+        }
+        $new_filename = $temp_file['dirname'] . DIRECTORY_SEPARATOR;
+        $new_filename .= $recent ? 'new' : 'cur';
+        $new_filename .= DIRECTORY_SEPARATOR . $temp_file['uniq'] . $info;
+
+        // we're throwing any exception after removing our temp file and saving it to this variable instead
+        $exception = null;
+
+        if (!link($temp_file['filename'], $new_filename)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            $exception = new Zend_Mail_Storage_Exception('cannot link message file to final dir');
+        }
+        @unlink($temp_file['filename']);
+
+        if ($exception) {
+            throw $exception;
+        }
+
+        $this->_files[] = array('uniq'     => $temp_file['uniq'],
+                                'flags'    => $flags,
+                                'filename' => $new_filename);
+        if ($this->_quota) {
+            $this->_addQuotaEntry((int)$size, 1);
+        }
+    }
+
+    /**
+     * copy an existing message
+     *
+     * @param   int                             $id     number of message
+     * @param   string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
+     * @return  null
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    public function copyMessage($id, $folder)
+    {
+        if ($this->_quota && $this->checkQuota()) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('storage is over quota!');            
+        }
+    
+        if (!($folder instanceof Zend_Mail_Storage_Folder)) {
+            $folder = $this->getFolders($folder);
+        }
+
+        $filedata = $this->_getFileData($id);
+        $old_file = $filedata['filename'];
+        $flags = $filedata['flags'];
+
+        // copied message can't be recent
+        while (($key = array_search(Zend_Mail_Storage::FLAG_RECENT, $flags)) !== false) {
+            unset($flags[$key]);
+        }
+        $info = $this->_getInfoString($flags);
+
+        // we're creating the copy as temp file before moving to cur/
+        $temp_file = $this->_createTmpFile($folder->getGlobalName());
+        // we don't write directly to the file
+        fclose($temp_file['handle']);
+
+        // we're adding the size to the filename for maildir++
+        $size = filesize($old_file);
+        if ($size !== false) {
+            $info = ',S=' . $size . $info;
+        }
+
+        $new_file = $temp_file['dirname'] . DIRECTORY_SEPARATOR . 'cur' . DIRECTORY_SEPARATOR . $temp_file['uniq'] . $info;
+
+        // we're throwing any exception after removing our temp file and saving it to this variable instead
+        $exception = null;
+
+        if (!copy($old_file, $temp_file['filename'])) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            $exception = new Zend_Mail_Storage_Exception('cannot copy message file');
+        } else if (!link($temp_file['filename'], $new_file)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            $exception = new Zend_Mail_Storage_Exception('cannot link message file to final dir');
+        }
+        @unlink($temp_file['filename']);
+
+        if ($exception) {
+            throw $exception;
+        }
+
+        if ($folder->getGlobalName() == $this->_currentFolder
+            || ($this->_currentFolder == 'INBOX' && $folder->getGlobalName() == '/')) {
+            $this->_files[] = array('uniq'     => $temp_file['uniq'],
+                                    'flags'    => $flags,
+                                    'filename' => $new_file);
+        }
+        
+        if ($this->_quota) {
+            $this->_addQuotaEntry((int)$size, 1);
+        }
+    }
+
+    /**
+     * move an existing message
+     *
+     * @param  int                             $id     number of message
+     * @param  string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
+     * @return null
+     * @throws Zend_Mail_Storage_Exception
+     */
+    public function moveMessage($id, $folder) {
+        if (!($folder instanceof Zend_Mail_Storage_Folder)) {
+            $folder = $this->getFolders($folder);
+        }
+        
+        if ($folder->getGlobalName() == $this->_currentFolder
+            || ($this->_currentFolder == 'INBOX' && $folder->getGlobalName() == '/')) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('target is current folder');
+        }
+        
+        $filedata = $this->_getFileData($id);
+        $old_file = $filedata['filename'];
+        $flags = $filedata['flags'];
+
+        // moved message can't be recent
+        while (($key = array_search(Zend_Mail_Storage::FLAG_RECENT, $flags)) !== false) {
+            unset($flags[$key]);
+        }
+        $info = $this->_getInfoString($flags);
+
+        // reserving a new name
+        $temp_file = $this->_createTmpFile($folder->getGlobalName());
+        fclose($temp_file['handle']);
+
+        // we're adding the size to the filename for maildir++
+        $size = filesize($old_file);
+        if ($size !== false) {
+            $info = ',S=' . $size . $info;
+        }
+
+        $new_file = $temp_file['dirname'] . DIRECTORY_SEPARATOR . 'cur' . DIRECTORY_SEPARATOR . $temp_file['uniq'] . $info;
+
+        // we're throwing any exception after removing our temp file and saving it to this variable instead
+        $exception = null;
+
+        if (!rename($old_file, $new_file)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            $exception = new Zend_Mail_Storage_Exception('cannot move message file');
+        }
+        @unlink($temp_file['filename']);
+
+        if ($exception) {
+            throw $exception;
+        }
+
+        unset($this->_files[$id - 1]);
+        // remove the gap
+        $this->_files = array_values($this->_files);
+    }
+
+
+    /**
+     * set flags for message
+     *
+     * NOTE: this method can't set the recent flag.
+     *
+     * @param   int   $id    number of message
+     * @param   array $flags new flags for message
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    public function setFlags($id, $flags)
+    {
+        $info = $this->_getInfoString($flags);
+        $filedata = $this->_getFileData($id);
+
+        // NOTE: double dirname to make sure we always move to cur. if recent flag has been set (message is in new) it will be moved to cur.
+        $new_filename = dirname(dirname($filedata['filename'])) . DIRECTORY_SEPARATOR . 'cur' . DIRECTORY_SEPARATOR . "$filedata[uniq]$info";
+
+        if (!@rename($filedata['filename'], $new_filename)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot rename file');
+        }
+
+        $filedata['flags']    = $flags;
+        $filedata['filename'] = $new_filename;
+
+        $this->_files[$id - 1] = $filedata;
+    }
+
+
+    /**
+     * stub for not supported message deletion
+     *
+     * @return  null
+     * @throws  Zend_Mail_Storage_Exception
+     */
+    public function removeMessage($id)
+    {
+        $filename = $this->_getFileData($id, 'filename');
+        
+        if ($this->_quota) {
+            $size = filesize($filename);
+        }
+        
+        if (!@unlink($filename)) {
+            /**
+             * @see Zend_Mail_Storage_Exception
+             */
+            require_once 'Zend/Mail/Storage/Exception.php';
+            throw new Zend_Mail_Storage_Exception('cannot remove message');
+        }
+        unset($this->_files[$id - 1]);
+        // remove the gap
+        $this->_files = array_values($this->_files);
+        if ($this->_quota) {
+            $this->_addQuotaEntry(0 - (int)$size, -1);
+        }
+    }
+    
+    /**
+     * enable/disable quota and set a quota value if wanted or needed
+     *
+     * You can enable/disable quota with true/false. If you don't have
+     * a MDA or want to enforce a quota value you can also set this value
+     * here. Use array('size' => SIZE_QUOTA, 'count' => MAX_MESSAGE) do
+     * define your quota. Order of these fields does matter!
+     *
+     * @param bool|array $value new quota value
+     * @return null
+     */
+    public function setQuota($value) {
+        $this->_quota = $value;
+    }
+    
+    /**
+     * get currently set quota
+     *
+     * @see Zend_Mail_Storage_Writable_Maildir::setQuota()
+     *
+     * @return bool|array
+     */
+    public function getQuota($fromStorage = false) {
+        if ($fromStorage) {
+            $fh = @fopen($this->_rootdir . 'maildirsize', 'r');
+            if (!$fh) {
+                /**
+                 * @see Zend_Mail_Storage_Exception
+                 */
+                require_once 'Zend/Mail/Storage/Exception.php';
+                throw new Zend_Mail_Storage_Exception('cannot open maildirsize');
+            }
+            $definition = fgets($fh);
+            fclose($fh);
+            $definition = explode(',', trim($definition));
+            $quota = array();
+            foreach ($definition as $member) {
+                $key = $member[strlen($member) - 1];
+                if ($key == 'S' || $key == 'C') {
+                    $key = $key == 'C' ? 'count' : 'size';
+                }
+                $quota[$key] = substr($member, 0, -1);
+            }
+            return $quota;
+        }
+        
+        return $this->_quota;
+    }
+    
+    /**
+     * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating maildirsize"
+     */
+    protected function _calculateMaildirsize() {
+        $timestamps = array();
+        $messages = 0;
+        $total_size = 0;
+
+        if (is_array($this->_quota)) {
+            $quota = $this->_quota;
+        } else {
+            try {
+                $quota = $this->getQuota(true);
+            } catch (Zend_Mail_Storage_Exception $e) {
+                throw new Zend_Mail_Storage_Exception('no quota defintion found');
+            }
+        }
+        
+        $folders = new RecursiveIteratorIterator($this->getFolders(), RecursiveIteratorIterator::SELF_FIRST);
+        foreach ($folders as $folder) {
+            $subdir = $folder->getGlobalName();
+            if ($subdir == 'INBOX') {
+                $subdir = '';
+            } else {
+                $subdir = '.' . $subdir;
+            }
+            if ($subdir == 'Trash') {
+                continue;
+            }
+            
+            foreach (array('cur', 'new') as $subsubdir) {
+                $dirname = $this->_rootdir . $subdir . DIRECTORY_SEPARATOR . $subsubdir . DIRECTORY_SEPARATOR;
+                if (!file_exists($dirname)) {
+                    continue;
+                }
+                // NOTE: we are using mtime instead of "the latest timestamp". The latest would be atime
+                // and as we are accessing the directory it would make the whole calculation useless.    
+                $timestamps[$dirname] = filemtime($dirname);
+
+                $dh = opendir($dirname);
+                // NOTE: Should have been checked in constructor. Not throwing an exception here, quotas will 
+                // therefore not be fully enforeced, but next request will fail anyway, if problem persists.
+                if (!$dh) {
+                    continue;
+                }
+                
+                                
+                while (($entry = readdir()) !== false) {
+                    if ($entry[0] == '.' || !is_file($dirname . $entry)) {
+                        continue;
+                    }
+                    
+                    if (strpos($entry, ',S=')) {
+                        strtok($entry, '=');
+                        $filesize = strtok(':');
+                        if (is_numeric($filesize)) {
+                            $total_size += $filesize;
+                            ++$messages;
+                            continue;
+                        }
+                    }
+                    $size = filesize($dirname . $entry);
+                    if ($size === false) {
+                        // ignore, as we assume file got removed
+                        continue;
+                    }
+                    $total_size += $size;
+                    ++$messages;
+                }
+            }
+        }
+        
+        $tmp = $this->_createTmpFile();
+        $fh = $tmp['handle'];
+        $definition = array();
+        foreach ($quota as $type => $value) {
+            if ($type == 'size' || $type == 'count') {
+                $type = $type == 'count' ? 'C' : 'S';
+            }
+            $definition[] = $value . $type;
+        }
+        $definition = implode(',', $definition);
+        fputs($fh, "$definition\n");
+        fputs($fh, "$total_size $messages\n");
+        fclose($fh);
+        rename($tmp['filename'], $this->_rootdir . 'maildirsize');
+        foreach ($timestamps as $dir => $timestamp) {
+            if ($timestamp < filemtime($dir)) {
+                unlink($this->_rootdir . 'maildirsize');
+                break;
+            }
+        }
+        
+        return array('size' => $total_size, 'count' => $messages, 'quota' => $quota);
+    }
+    
+    /**
+     * @see http://www.inter7.com/courierimap/README.maildirquota.html "Calculating the quota for a Maildir++"
+     */
+    protected function _calculateQuota($forceRecalc = false) {
+        $fh = null;
+        $total_size = 0;
+        $messages   = 0;
+        $maildirsize = '';
+        if (!$forceRecalc && file_exists($this->_rootdir . 'maildirsize') && filesize($this->_rootdir . 'maildirsize') < 5120) {
+            $fh = fopen($this->_rootdir . 'maildirsize', 'r');
+        }
+        if ($fh) {
+            $maildirsize = fread($fh, 5120);
+            if (strlen($maildirsize) >= 5120) {
+                fclose($fh);
+                $fh = null;
+                $maildirsize = '';
+            }
+        }
+        if (!$fh) {
+            $result = $this->_calculateMaildirsize();
+            $total_size = $result['size'];
+            $messages   = $result['count'];
+            $quota      = $result['quota'];
+        } else {
+            $maildirsize = explode("\n", $maildirsize);
+            if (is_array($this->_quota)) {
+                $quota = $this->_quota;
+            } else {
+                $definition = explode(',', $maildirsize[0]);
+                $quota = array();
+                foreach ($definition as $member) {
+                    $key = $member[strlen($member) - 1];
+                    if ($key == 'S' || $key == 'C') {
+                        $key = $key == 'C' ? 'count' : 'size';
+                    }
+                    $quota[$key] = substr($member, 0, -1);
+                }
+            }
+            unset($maildirsize[0]);
+            foreach ($maildirsize as $line) {
+                list($size, $count) = explode(' ', trim($line));
+                $total_size += $size;
+                $messages   += $count;
+            }
+        }
+        
+        $over_quota = false;
+        $over_quota = $over_quota || (isset($quota['size'])  && $total_size > $quota['size']); 
+        $over_quota = $over_quota || (isset($quota['count']) && $messages   > $quota['count']);
+        // NOTE: $maildirsize equals false if it wasn't set (AKA we recalculated) or it's only
+        // one line, because $maildirsize[0] gets unsetted.
+        // Also we're using local time to calculate the 15 minute offset. Touching a file just for known the
+        // local time of the file storage isn't worth the hassle.
+        if ($over_quota && ($maildirsize || filemtime($this->_rootdir . 'maildirsize') > time() - 900)) {
+            $result = $this->_calculateMaildirsize();
+            $total_size = $result['size'];
+            $messages   = $result['count'];
+            $quota      = $result['quota'];
+            $over_quota = false;
+            $over_quota = $over_quota || (isset($quota['size'])  && $total_size > $quota['size']); 
+            $over_quota = $over_quota || (isset($quota['count']) && $messages   > $quota['count']);
+        }
+        
+        if ($fh) {
+            // TODO is there a safe way to keep the handle open for writing?
+            fclose($fh);
+        }
+        
+        return array('size' => $total_size, 'count' => $messages, 'quota' => $quota, 'over_quota' => $over_quota);
+    }
+    
+    protected function _addQuotaEntry($size, $count = 1) {
+        if (!file_exists($this->_rootdir . 'maildirsize')) {
+            // TODO: should get file handler from _calculateQuota
+        }
+        $size = (int)$size;
+        $count = (int)$count;
+        file_put_contents($this->_rootdir . 'maildirsize', "$size $count\n", FILE_APPEND);
+    }
+    
+    /**
+     * check if storage is currently over quota
+     *
+     * @param bool $detailedResponse return known data of quota and current size and message count @see _calculateQuota()
+     * @return bool|array over quota state or detailed response
+     */
+    public function checkQuota($detailedResponse = false, $forceRecalc = false) {
+        $result = $this->_calculateQuota($forceRecalc);
+        return $detailedResponse ? $result : $result['over_quota'];
+    }
+}
diff --git a/lib/Zend/Mail/Transport/Abstract.php b/lib/Zend/Mail/Transport/Abstract.php
new file mode 100644
index 0000000..603411a
--- /dev/null
+++ b/lib/Zend/Mail/Transport/Abstract.php
@@ -0,0 +1,350 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Abstract.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+
+/**
+ * Abstract for sending eMails through different
+ * ways of transport
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Mail_Transport_Abstract 
+{
+    /**
+     * Mail body
+     * @var string
+     * @access public
+     */
+    public $body = '';
+
+    /**
+     * MIME boundary
+     * @var string
+     * @access public
+     */
+    public $boundary = '';
+
+    /**
+     * Mail header string
+     * @var string
+     * @access public
+     */
+    public $header = '';
+
+    /**
+     * Array of message headers
+     * @var array
+     * @access protected
+     */
+    protected $_headers = array();
+
+    /**
+     * Message is a multipart message
+     * @var boolean
+     * @access protected
+     */
+    protected $_isMultipart = false;
+
+    /**
+     * Zend_Mail object
+     * @var false|Zend_Mail
+     * @access protected
+     */
+    protected $_mail = false;
+
+    /**
+     * Array of message parts
+     * @var array
+     * @access protected
+     */
+    protected $_parts = array();
+
+    /**
+     * Recipients string
+     * @var string
+     * @access public
+     */
+    public $recipients = '';
+
+    /**
+     * EOL character string used by transport
+     * @var string
+     * @access public
+     */
+    public $EOL = "\r\n";
+
+    /**
+     * Send an email independent from the used transport
+     *
+     * The requisite information for the email will be found in the following
+     * properties:
+     *
+     * - {@link $recipients} - list of recipients (string)
+     * - {@link $header} - message header
+     * - {@link $body} - message body
+     */
+    abstract protected function _sendMail();
+
+    /**
+     * Return all mail headers as an array
+     *
+     * If a boundary is given, a multipart header is generated with a
+     * Content-Type of either multipart/alternative or multipart/mixed depending
+     * on the mail parts present in the {@link $_mail Zend_Mail object} present.
+     *
+     * @param string $boundary
+     * @return array
+     */
+    protected function _getHeaders($boundary)
+    {
+        if (null !== $boundary) {
+            // Build multipart mail
+            $type = $this->_mail->getType();
+            if (!$type) {
+                if ($this->_mail->hasAttachments) {
+                    $type = Zend_Mime::MULTIPART_MIXED;
+                } elseif ($this->_mail->getBodyText() && $this->_mail->getBodyHtml()) {
+                    $type = Zend_Mime::MULTIPART_ALTERNATIVE;
+                } else {
+                    $type = Zend_Mime::MULTIPART_MIXED;
+                }
+            }
+
+            $this->_headers['Content-Type'] = array(
+                $type . '; charset="' . $this->_mail->getCharset() . '";'
+                . $this->EOL
+                . " " . 'boundary="' . $boundary . '"'
+            );
+            $this->_headers['MIME-Version'] = array('1.0');
+
+            $this->boundary = $boundary;
+        }
+
+        return $this->_headers;
+    }
+
+    /**
+     * Prepend header name to header value
+     *
+     * @param string $item
+     * @param string $key
+     * @param string $prefix
+     * @static
+     * @access protected
+     * @return void
+     */
+    protected static function _formatHeader(&$item, $key, $prefix)
+    {
+        $item = $prefix . ': ' . $item;
+    }
+
+    /**
+     * Prepare header string for use in transport
+     *
+     * Prepares and generates {@link $header} based on the headers provided.
+     *
+     * @param mixed $headers
+     * @access protected
+     * @return void
+     * @throws Zend_Mail_Transport_Exception if any header lines exceed 998
+     * characters
+     */
+    protected function _prepareHeaders($headers)
+    {
+        if (!$this->_mail) {
+            /**
+             * @see Zend_Mail_Transport_Exception
+             */
+            require_once 'Zend/Mail/Transport/Exception.php';
+            throw new Zend_Mail_Transport_Exception('Missing Zend_Mail object in _mail property');
+        }
+
+        $this->header = '';
+
+        foreach ($headers as $header => $content) {
+            if (isset($content['append'])) {
+                unset($content['append']);
+                $value = implode(',' . $this->EOL . ' ', $content);
+                $this->header .= $header . ': ' . $value . $this->EOL;
+            } else {
+                array_walk($content, array(get_class($this), '_formatHeader'), $header);
+                $this->header .= implode($this->EOL, $content) . $this->EOL;
+            }
+        }
+
+        // Sanity check on headers -- should not be > 998 characters
+        $sane = true;
+        foreach (explode($this->EOL, $this->header) as $line) {
+            if (strlen(trim($line)) > 998) {
+                $sane = false;
+                break;
+            }
+        }
+        if (!$sane) {
+            /**
+             * @see Zend_Mail_Transport_Exception
+             */
+            require_once 'Zend/Mail/Transport/Exception.php';
+            throw new Zend_Mail_Exception('At least one mail header line is too long');
+        }
+    }
+
+    /**
+     * Generate MIME compliant message from the current configuration
+     *
+     * If both a text and HTML body are present, generates a
+     * multipart/alternative Zend_Mime_Part containing the headers and contents
+     * of each. Otherwise, uses whichever of the text or HTML parts present.
+     *
+     * The content part is then prepended to the list of Zend_Mime_Parts for
+     * this message.
+     *
+     * @return void
+     */
+    protected function _buildBody()
+    {
+        if (($text = $this->_mail->getBodyText())
+            && ($html = $this->_mail->getBodyHtml()))
+        {
+            // Generate unique boundary for multipart/alternative
+            $mime = new Zend_Mime(null);
+            $boundaryLine = $mime->boundaryLine($this->EOL);
+            $boundaryEnd  = $mime->mimeEnd($this->EOL);
+
+            $text->disposition = false;
+            $html->disposition = false;
+
+            $body = $boundaryLine
+                  . $text->getHeaders($this->EOL)
+                  . $this->EOL
+                  . $text->getContent($this->EOL)
+                  . $this->EOL
+                  . $boundaryLine
+                  . $html->getHeaders($this->EOL)
+                  . $this->EOL
+                  . $html->getContent($this->EOL)
+                  . $this->EOL
+                  . $boundaryEnd;
+
+            $mp           = new Zend_Mime_Part($body);
+            $mp->type     = Zend_Mime::MULTIPART_ALTERNATIVE;
+            $mp->boundary = $mime->boundary();
+
+            $this->_isMultipart = true;
+
+            // Ensure first part contains text alternatives
+            array_unshift($this->_parts, $mp);
+
+            // Get headers
+            $this->_headers = $this->_mail->getHeaders();
+            return;
+        }
+
+        // If not multipart, then get the body
+        if (false !== ($body = $this->_mail->getBodyHtml())) {
+            array_unshift($this->_parts, $body);
+        } elseif (false !== ($body = $this->_mail->getBodyText())) {
+            array_unshift($this->_parts, $body);
+        }
+
+        if (!$body) {
+            /**
+             * @see Zend_Mail_Transport_Exception
+             */
+            require_once 'Zend/Mail/Transport/Exception.php';
+            throw new Zend_Mail_Transport_Exception('No body specified');
+        }
+
+        // Get headers
+        $this->_headers = $this->_mail->getHeaders();
+        $headers = $body->getHeadersArray($this->EOL);
+        foreach ($headers as $header) {
+            // Headers in Zend_Mime_Part are kept as arrays with two elements, a
+            // key and a value
+            $this->_headers[$header[0]] = array($header[1]);
+        }
+    }
+
+    /**
+     * Send a mail using this transport
+     *
+     * @param  Zend_Mail $mail
+     * @access public
+     * @return void
+     * @throws Zend_Mail_Transport_Exception if mail is empty
+     */
+    public function send(Zend_Mail $mail)
+    {
+        $this->_isMultipart = false;
+        $this->_mail        = $mail;
+        $this->_parts       = $mail->getParts();
+        $mime               = $mail->getMime();
+
+        // Build body content
+        $this->_buildBody();
+
+        // Determine number of parts and boundary
+        $count    = count($this->_parts);
+        $boundary = null;
+        if ($count < 1) {
+            /**
+             * @see Zend_Mail_Transport_Exception
+             */
+            require_once 'Zend/Mail/Transport/Exception.php';
+            throw new Zend_Mail_Transport_Exception('Empty mail cannot be sent');
+        }
+
+        if ($count > 1) {
+            // Multipart message; create new MIME object and boundary
+            $mime     = new Zend_Mime($this->_mail->getMimeBoundary());
+            $boundary = $mime->boundary();
+        } elseif ($this->_isMultipart) {
+            // multipart/alternative -- grab boundary
+            $boundary = $this->_parts[0]->boundary;
+        }
+
+        // Determine recipients, and prepare headers
+        $this->recipients = implode(',', $mail->getRecipients());
+        $this->_prepareHeaders($this->_getHeaders($boundary));
+
+        // Create message body
+        // This is done so that the same Zend_Mail object can be used in
+        // multiple transports
+        $message = new Zend_Mime_Message();
+        $message->setParts($this->_parts);
+        $message->setMime($mime);
+        $this->body = $message->generateMessage($this->EOL);
+
+        // Send to transport!
+        $this->_sendMail();
+    }
+}
diff --git a/lib/Zend/Mail/Transport/Exception.php b/lib/Zend/Mail/Transport/Exception.php
new file mode 100644
index 0000000..16ef240
--- /dev/null
+++ b/lib/Zend/Mail/Transport/Exception.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Exception
+ */
+require_once 'Zend/Mail/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Transport_Exception extends Zend_Mail_Exception
+{}
+
diff --git a/lib/Zend/Mail/Transport/Sendmail.php b/lib/Zend/Mail/Transport/Sendmail.php
new file mode 100644
index 0000000..651df3c
--- /dev/null
+++ b/lib/Zend/Mail/Transport/Sendmail.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Sendmail.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Mail_Transport_Abstract
+ */
+require_once 'Zend/Mail/Transport/Abstract.php';
+
+
+/**
+ * Class for sending eMails via the PHP internal mail() function
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Transport_Sendmail extends Zend_Mail_Transport_Abstract
+{
+    /**
+     * Subject
+     * @var string
+     * @access public
+     */
+    public $subject = null;
+
+
+    /**
+     * Config options for sendmail parameters
+     *
+     * @var string
+     */
+    public $parameters;
+
+
+    /**
+     * EOL character string
+     * @var string
+     * @access public
+     */
+    public $EOL = PHP_EOL;
+
+
+    /**
+     * Constructor.
+     *
+     * @param  string $parameters OPTIONAL (Default: null)
+     * @return void
+     */
+    public function __construct($parameters = null)
+    {
+        $this->parameters = $parameters;
+    }
+
+
+    /**
+     * Send mail using PHP native mail()
+     *
+     * @access public
+     * @return void
+     * @throws Zend_Mail_Transport_Exception on mail() failure
+     */
+    public function _sendMail()
+    {
+        if ($this->parameters === null) {
+            $result = mail(
+                $this->recipients,
+                $this->_mail->getSubject(),
+                $this->body,
+                $this->header);
+        } else {
+            $result = mail(
+                $this->recipients,
+                $this->_mail->getSubject(),
+                $this->body,
+                $this->header,
+                $this->parameters);
+        }
+        if (!$result) {
+            /**
+             * @see Zend_Mail_Transport_Exception
+             */
+            require_once 'Zend/Mail/Transport/Exception.php';
+            throw new Zend_Mail_Transport_Exception('Unable to send mail');
+        }
+    }
+
+
+    /**
+     * Format and fix headers
+     *
+     * mail() uses its $to and $subject arguments to set the To: and Subject:
+     * headers, respectively. This method strips those out as a sanity check to
+     * prevent duplicate header entries.
+     *
+     * @access  protected
+     * @param   array $headers
+     * @return  void
+     * @throws  Zend_Mail_Transport_Exception
+     */
+    protected function _prepareHeaders($headers)
+    {
+        if (!$this->_mail) {
+            /**
+             * @see Zend_Mail_Transport_Exception
+             */
+            require_once 'Zend/Mail/Transport/Exception.php';
+            throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object');
+        }
+
+        // mail() uses its $to parameter to set the To: header, and the $subject
+        // parameter to set the Subject: header. We need to strip them out.
+        if (0 === strpos(PHP_OS, 'WIN')) {
+            // If the current recipients list is empty, throw an error
+            if (empty($this->recipients)) {
+                /**
+                 * @see Zend_Mail_Transport_Exception
+                 */
+                require_once 'Zend/Mail/Transport/Exception.php';
+                throw new Zend_Mail_Transport_Exception('Missing To addresses');
+            }
+        } else {
+            // All others, simply grab the recipients and unset the To: header
+            if (!isset($headers['To'])) {
+                /**
+                 * @see Zend_Mail_Transport_Exception
+                 */
+                require_once 'Zend/Mail/Transport/Exception.php';
+                throw new Zend_Mail_Transport_Exception('Missing To header');
+            }
+
+            unset($headers['To']['append']);
+            $this->recipients = implode(',', $headers['To']);
+        }
+
+        // Remove recipient header
+        unset($headers['To']);
+
+        // Remove subject header, if present
+        if (isset($headers['Subject'])) {
+            unset($headers['Subject']);
+        }
+
+        // Prepare headers
+        parent::_prepareHeaders($headers);
+    }
+
+}
+
diff --git a/lib/Zend/Mail/Transport/Smtp.php b/lib/Zend/Mail/Transport/Smtp.php
new file mode 100644
index 0000000..714266e
--- /dev/null
+++ b/lib/Zend/Mail/Transport/Smtp.php
@@ -0,0 +1,241 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ * 
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Smtp.php 12519 2008-11-10 18:41:24Z alexander $
+ */
+
+
+/**
+ * @see Zend_Loader
+ */
+require_once 'Zend/Loader.php';
+
+/**
+ * @see Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+/**
+ * @see Zend_Mail_Protocol_Smtp
+ */
+require_once 'Zend/Mail/Protocol/Smtp.php';
+
+/**
+ * @see Zend_Mail_Transport_Abstract
+ */
+require_once 'Zend/Mail/Transport/Abstract.php';
+
+
+/**
+ * SMTP connection object
+ *
+ * Loads an instance of Zend_Mail_Protocol_Smtp and forwards smtp transactions
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Transport
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Transport_Smtp extends Zend_Mail_Transport_Abstract
+{
+    /**
+     * EOL character string used by transport
+     * @var string
+     * @access public
+     */
+    public $EOL = "\n";
+
+    /**
+     * Remote smtp hostname or i.p.
+     *
+     * @var string
+     */
+    protected $_host;
+
+
+    /**
+     * Port number
+     *
+     * @var integer|null
+     */
+    protected $_port;
+
+
+    /**
+     * Local client hostname or i.p.
+     *
+     * @var string
+     */
+    protected $_name = 'localhost';
+
+
+    /**
+     * Authentication type OPTIONAL
+     *
+     * @var string
+     */
+    protected $_auth;
+
+
+    /**
+     * Config options for authentication
+     *
+     * @var array
+     */
+    protected $_config;
+
+
+    /**
+     * Instance of Zend_Mail_Protocol_Smtp
+     *
+     * @var Zend_Mail_Protocol_Smtp
+     */
+    protected $_connection;
+
+
+    /**
+     * Constructor.
+     *
+     * @param  string $host OPTIONAL (Default: 127.0.0.1)
+     * @param  array|null $config OPTIONAL (Default: null)
+     * @return void
+     */
+    public function __construct($host = '127.0.0.1', Array $config = array())
+    {
+        if (isset($config['name'])) {
+            $this->_name = $config['name'];
+        }
+        if (isset($config['port'])) {
+            $this->_port = $config['port'];
+        }
+        if (isset($config['auth'])) {
+            $this->_auth = $config['auth'];
+        }
+
+        $this->_host = $host;
+        $this->_config = $config;
+    }
+
+
+    /**
+     * Class destructor to ensure all open connections are closed
+     *
+     * @return void
+     */
+    public function __destruct()
+    {
+        if ($this->_connection instanceof Zend_Mail_Protocol_Smtp) {
+            try {
+                $this->_connection->quit();
+            } catch (Zend_Mail_Protocol_Exception $e) {
+                // ignore
+            }
+            $this->_connection->disconnect();
+        }
+    }
+
+
+    /**
+     * Sets the connection protocol instance
+     *
+     * @param Zend_Mail_Protocol_Abstract $client
+     *
+     * @return void
+     */
+    public function setConnection(Zend_Mail_Protocol_Abstract $connection)
+    {
+        $this->_connection = $connection;
+    }
+
+
+    /**
+     * Gets the connection protocol instance
+     *
+     * @return Zend_Mail_Protocol|null
+     */
+    public function getConnection()
+    {
+        return $this->_connection;
+    }
+
+    /**
+     * Send an email via the SMTP connection protocol
+     *
+     * The connection via the protocol adapter is made just-in-time to allow a
+     * developer to add a custom adapter if required before mail is sent.
+     *
+     * @return void
+     */
+    public function _sendMail()
+    {
+        // If sending multiple messages per session use existing adapter
+        if (!($this->_connection instanceof Zend_Mail_Protocol_Smtp)) {
+            // Check if authentication is required and determine required class
+            $connectionClass = 'Zend_Mail_Protocol_Smtp';
+            if ($this->_auth) {
+                $connectionClass .= '_Auth_' . ucwords($this->_auth);
+            }
+            Zend_Loader::loadClass($connectionClass);
+            $this->setConnection(new $connectionClass($this->_host, $this->_port, $this->_config));
+            $this->_connection->connect();
+            $this->_connection->helo($this->_name);
+        } else {
+            // Reset connection to ensure reliable transaction
+            $this->_connection->rset();
+        }
+
+        // Set mail return path from sender email address
+        $this->_connection->mail($this->_mail->getReturnPath());
+
+        // Set recipient forward paths
+        foreach ($this->_mail->getRecipients() as $recipient) {
+            $this->_connection->rcpt($recipient);
+        }
+
+        // Issue DATA command to client
+        $this->_connection->data($this->header . Zend_Mime::LINEEND . $this->body);
+    }
+
+    /**
+     * Format and fix headers
+     *
+     * Some SMTP servers do not strip BCC headers. Most clients do it themselves as do we.
+     *
+     * @access  protected
+     * @param   array $headers
+     * @return  void
+     * @throws  Zend_Transport_Exception
+     */
+    protected function _prepareHeaders($headers)
+    {
+        if (!$this->_mail) {
+            /**
+             * @see Zend_Mail_Transport_Exception
+             */
+            require_once 'Zend/Mail/Transport/Exception.php';
+            throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object');
+        }
+
+        unset($headers['Bcc']);
+
+        // Prepare headers
+        parent::_prepareHeaders($headers);
+    }
+}
diff --git a/lib/Zend/Mime.php b/lib/Zend/Mime.php
new file mode 100644
index 0000000..414e541
--- /dev/null
+++ b/lib/Zend/Mime.php
@@ -0,0 +1,365 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * Support class for MultiPart Mime Messages
+ *
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mime
+{
+    const TYPE_OCTETSTREAM = 'application/octet-stream';
+    const TYPE_TEXT = 'text/plain';
+    const TYPE_HTML = 'text/html';
+    const ENCODING_7BIT = '7bit';
+    const ENCODING_8BIT = '8bit';
+    const ENCODING_QUOTEDPRINTABLE = 'quoted-printable';
+    const ENCODING_BASE64 = 'base64';
+    const DISPOSITION_ATTACHMENT = 'attachment';
+    const DISPOSITION_INLINE = 'inline';
+    const LINELENGTH = 72;
+    const LINEEND = "\n";
+    const MULTIPART_ALTERNATIVE = 'multipart/alternative';
+    const MULTIPART_MIXED = 'multipart/mixed';
+    const MULTIPART_RELATED = 'multipart/related';
+
+    protected $_boundary;
+    protected static $makeUnique = 0;
+
+    // lookup-Tables for QuotedPrintable
+    public static $qpKeys = array(
+        "\x00","\x01","\x02","\x03","\x04","\x05","\x06","\x07",
+        "\x08","\x09","\x0A","\x0B","\x0C","\x0D","\x0E","\x0F",
+        "\x10","\x11","\x12","\x13","\x14","\x15","\x16","\x17",
+        "\x18","\x19","\x1A","\x1B","\x1C","\x1D","\x1E","\x1F",
+        "\x7F","\x80","\x81","\x82","\x83","\x84","\x85","\x86",
+        "\x87","\x88","\x89","\x8A","\x8B","\x8C","\x8D","\x8E",
+        "\x8F","\x90","\x91","\x92","\x93","\x94","\x95","\x96",
+        "\x97","\x98","\x99","\x9A","\x9B","\x9C","\x9D","\x9E",
+        "\x9F","\xA0","\xA1","\xA2","\xA3","\xA4","\xA5","\xA6",
+        "\xA7","\xA8","\xA9","\xAA","\xAB","\xAC","\xAD","\xAE",
+        "\xAF","\xB0","\xB1","\xB2","\xB3","\xB4","\xB5","\xB6",
+        "\xB7","\xB8","\xB9","\xBA","\xBB","\xBC","\xBD","\xBE",
+        "\xBF","\xC0","\xC1","\xC2","\xC3","\xC4","\xC5","\xC6",
+        "\xC7","\xC8","\xC9","\xCA","\xCB","\xCC","\xCD","\xCE",
+        "\xCF","\xD0","\xD1","\xD2","\xD3","\xD4","\xD5","\xD6",
+        "\xD7","\xD8","\xD9","\xDA","\xDB","\xDC","\xDD","\xDE",
+        "\xDF","\xE0","\xE1","\xE2","\xE3","\xE4","\xE5","\xE6",
+        "\xE7","\xE8","\xE9","\xEA","\xEB","\xEC","\xED","\xEE",
+        "\xEF","\xF0","\xF1","\xF2","\xF3","\xF4","\xF5","\xF6",
+        "\xF7","\xF8","\xF9","\xFA","\xFB","\xFC","\xFD","\xFE",
+        "\xFF"
+        );
+
+    public static $qpReplaceValues = array(
+        "=00","=01","=02","=03","=04","=05","=06","=07",
+        "=08","=09","=0A","=0B","=0C","=0D","=0E","=0F",
+        "=10","=11","=12","=13","=14","=15","=16","=17",
+        "=18","=19","=1A","=1B","=1C","=1D","=1E","=1F",
+        "=7F","=80","=81","=82","=83","=84","=85","=86",
+        "=87","=88","=89","=8A","=8B","=8C","=8D","=8E",
+        "=8F","=90","=91","=92","=93","=94","=95","=96",
+        "=97","=98","=99","=9A","=9B","=9C","=9D","=9E",
+        "=9F","=A0","=A1","=A2","=A3","=A4","=A5","=A6",
+        "=A7","=A8","=A9","=AA","=AB","=AC","=AD","=AE",
+        "=AF","=B0","=B1","=B2","=B3","=B4","=B5","=B6",
+        "=B7","=B8","=B9","=BA","=BB","=BC","=BD","=BE",
+        "=BF","=C0","=C1","=C2","=C3","=C4","=C5","=C6",
+        "=C7","=C8","=C9","=CA","=CB","=CC","=CD","=CE",
+        "=CF","=D0","=D1","=D2","=D3","=D4","=D5","=D6",
+        "=D7","=D8","=D9","=DA","=DB","=DC","=DD","=DE",
+        "=DF","=E0","=E1","=E2","=E3","=E4","=E5","=E6",
+        "=E7","=E8","=E9","=EA","=EB","=EC","=ED","=EE",
+        "=EF","=F0","=F1","=F2","=F3","=F4","=F5","=F6",
+        "=F7","=F8","=F9","=FA","=FB","=FC","=FD","=FE",
+        "=FF"
+        );
+
+    public static $qpKeysString =
+         "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
+
+    /**
+     * Check if the given string is "printable"
+     *
+     * Checks that a string contains no unprintable characters. If this returns
+     * false, encode the string for secure delivery.
+     *
+     * @param string $str
+     * @return boolean
+     */
+    public static function isPrintable($str)
+    {
+        return (strcspn($str, self::$qpKeysString) == strlen($str));
+    }
+
+    /**
+     * Encode a given string with the QUOTED_PRINTABLE mechanism and wrap the lines.
+     *
+     * @param string $str
+     * @param int $lineLength Defaults to {@link LINELENGTH}
+     * @param int $lineEnd Defaults to {@link LINEEND}
+     * @return string
+     */
+    public static function encodeQuotedPrintable($str,
+        $lineLength = self::LINELENGTH,
+        $lineEnd = self::LINEEND)
+    {
+        $out = '';
+        $str = self::_encodeQuotedPrintable($str);
+
+        // Split encoded text into separate lines
+        while ($str) {
+            $ptr = strlen($str);
+            if ($ptr > $lineLength) {
+                $ptr = $lineLength;
+            }
+
+            // Ensure we are not splitting across an encoded character
+            $pos = strrpos(substr($str, 0, $ptr), '=');
+            if ($pos !== false && $pos >= $ptr - 2) {
+                $ptr = $pos;
+            }
+
+            // Check if there is a space at the end of the line and rewind
+            if ($ptr > 0 && $str[$ptr - 1] == ' ') {
+                --$ptr;
+            }
+
+            // Add string and continue
+            $out .= substr($str, 0, $ptr) . '=' . $lineEnd;
+            $str = substr($str, $ptr);
+        }
+
+        $out = rtrim($out, $lineEnd);
+        $out = rtrim($out, '=');
+        return $out;
+    }
+
+    /**
+     * Converts a string into quoted printable format.
+     *
+     * @param  string $str
+     * @return string
+     */
+    private static function _encodeQuotedPrintable($str)
+    {
+        $str = str_replace('=', '=3D', $str);
+        $str = str_replace(self::$qpKeys, self::$qpReplaceValues, $str);
+        $str = rtrim($str);
+        return $str;
+    }
+
+    /**
+     * Encode a given string with the QUOTED_PRINTABLE mechanism for Mail Headers.
+     *
+     * Mail headers depend on an extended quoted printable algorithm otherwise
+     * a range of bugs can occur.
+     *
+     * @param string $str
+     * @param string $charset
+     * @param int $lineLength Defaults to {@link LINELENGTH}
+     * @param int $lineEnd Defaults to {@link LINEEND}
+     * @return string
+     */
+    public static function encodeQuotedPrintableHeader($str, $charset,
+        $lineLength = self::LINELENGTH,
+        $lineEnd = self::LINEEND)
+    {
+        // Reduce line-length by the length of the required delimiter, charsets and encoding
+        $prefix = sprintf('=?%s?Q?', $charset);
+        $lineLength = $lineLength-strlen($prefix)-3;
+
+        $str = self::_encodeQuotedPrintable($str);
+
+        // Mail-Header required chars have to be encoded also:
+        $str = str_replace(array('?', ' ', '_'), array('=3F', '=20', '=5F'), $str);
+
+        // initialize first line, we need it anyways
+        $lines = array(0 => "");
+
+        // Split encoded text into separate lines
+        $tmp = "";
+        while(strlen($str) > 0) {
+            $currentLine = max(count($lines)-1, 0);
+            $token       = self::getNextQuotedPrintableToken($str);
+            $str         = substr($str, strlen($token));
+
+            $tmp .= $token;
+            if( (strlen($token) == 1 && strpbrk($token, '!%,.:;<>'))
+                || in_array($token, array("=3F", "=20", "=5F")) ) {
+                // only if we have a single char token or space, we can append the
+                // tempstring it to the current line or start a new line if necessary.
+                if(strlen($lines[$currentLine].$tmp) > $lineLength) {
+                    $lines[$currentLine+1] = $tmp;
+                } else {
+                    $lines[$currentLine] .= $tmp;
+                }
+                $tmp = "";
+            }
+            // don't forget to append the rest to the last line
+            if(strlen($str) == 0) {
+                $lines[$currentLine] .= $tmp;
+            }
+        }
+
+        // assemble the lines together by pre- and appending delimiters, charset, encoding.
+        for($i = 0; $i < count($lines); $i++) {
+            $lines[$i] = " ".$prefix.$lines[$i]."?=";
+        }
+        $str = trim(implode($lineEnd, $lines));
+        return $str;
+    }
+
+    /**
+     * Retrieves the first token from a quoted printable string.
+     *
+     * @param  string $str
+     * @return string
+     */
+    private static function getNextQuotedPrintableToken($str)
+    {
+        if(substr($str, 0, 1) == "=") {
+            $token = substr($str, 0, 3);
+        } else {
+            $token = substr($str, 0, 1);
+        }
+        return $token;
+    }
+
+    /**
+     * Encode a given string in mail header compatible base64 encoding.
+     *
+     * @param string $str
+     * @param string $charset
+     * @param int $lineLength Defaults to {@link LINELENGTH}
+     * @param int $lineEnd Defaults to {@link LINEEND}
+     * @return string
+     */
+    public static function encodeBase64Header($str,
+        $charset,
+        $lineLength = self::LINELENGTH,
+        $lineEnd = self::LINEEND)
+    {
+        $prefix = '=?' . $charset . '?B?';
+        $suffix = '?=';
+        $remainingLength = $lineLength - strlen($prefix) - strlen($suffix);
+
+        $encodedValue = self::encodeBase64($str, $remainingLength, $lineEnd);
+        $encodedValue = str_replace($lineEnd, $suffix . $lineEnd . ' ' . $prefix, $encodedValue);
+        $encodedValue = $prefix . $encodedValue . $suffix;
+        return $encodedValue;
+    }
+
+    /**
+     * Encode a given string in base64 encoding and break lines
+     * according to the maximum linelength.
+     *
+     * @param string $str
+     * @param int $lineLength Defaults to {@link LINELENGTH}
+     * @param int $lineEnd Defaults to {@link LINEEND}
+     * @return string
+     */
+    public static function encodeBase64($str,
+        $lineLength = self::LINELENGTH,
+        $lineEnd = self::LINEEND)
+    {
+        return rtrim(chunk_split(base64_encode($str), $lineLength, $lineEnd));
+    }
+
+    /**
+     * Constructor
+     *
+     * @param null|string $boundary
+     * @access public
+     * @return void
+     */
+    public function __construct($boundary = null)
+    {
+        // This string needs to be somewhat unique
+        if ($boundary === null) {
+            $this->_boundary = '=_' . md5(microtime(1) . self::$makeUnique++);
+        } else {
+            $this->_boundary = $boundary;
+        }
+    }
+
+    /**
+     * Encode the given string with the given encoding.
+     *
+     * @param string $str
+     * @param string $encoding
+     * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
+     * @return string
+     */
+    public static function encode($str, $encoding, $EOL = self::LINEEND)
+    {
+        switch ($encoding) {
+            case self::ENCODING_BASE64:
+                return self::encodeBase64($str, self::LINELENGTH, $EOL);
+
+            case self::ENCODING_QUOTEDPRINTABLE:
+                return self::encodeQuotedPrintable($str, self::LINELENGTH, $EOL);
+
+            default:
+                /**
+                 * @todo 7Bit and 8Bit is currently handled the same way.
+                 */
+                return $str;
+        }
+    }
+
+    /**
+     * Return a MIME boundary
+     *
+     * @access public
+     * @return string
+     */
+    public function boundary()
+    {
+        return $this->_boundary;
+    }
+
+    /**
+     * Return a MIME boundary line
+     *
+     * @param mixed $EOL Defaults to {@link LINEEND}
+     * @access public
+     * @return string
+     */
+    public function boundaryLine($EOL = self::LINEEND)
+    {
+        return $EOL . '--' . $this->_boundary . $EOL;
+    }
+
+    /**
+     * Return MIME ending
+     *
+     * @access public
+     * @return string
+     */
+    public function mimeEnd($EOL = self::LINEEND)
+    {
+        return $EOL . '--' . $this->_boundary . '--' . $EOL;
+    }
+}
diff --git a/lib/Zend/Mime/Decode.php b/lib/Zend/Mime/Decode.php
new file mode 100644
index 0000000..cc4de8b
--- /dev/null
+++ b/lib/Zend/Mime/Decode.php
@@ -0,0 +1,243 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * @see Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mime_Decode
+{
+    /**
+     * Explode MIME multipart string into seperate parts
+     *
+     * Parts consist of the header and the body of each MIME part.
+     *
+     * @param  string $body     raw body of message
+     * @param  string $boundary boundary as found in content-type
+     * @return array parts with content of each part, empty if no parts found
+     * @throws Zend_Exception
+     */
+    public static function splitMime($body, $boundary)
+    {
+        // TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
+        $body = str_replace("\r", '', $body);
+
+        $start = 0;
+        $res = array();
+        // find every mime part limiter and cut out the
+        // string before it.
+        // the part before the first boundary string is discarded:
+        $p = strpos($body, '--' . $boundary . "\n", $start);
+        if ($p === false) {
+            // no parts found!
+            return array();
+        }
+
+        // position after first boundary line
+        $start = $p + 3 + strlen($boundary);
+
+        while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
+            $res[] = substr($body, $start, $p-$start);
+            $start = $p + 3 + strlen($boundary);
+        }
+
+        // no more parts, find end boundary
+        $p = strpos($body, '--' . $boundary . '--', $start);
+        if ($p===false) {
+            throw new Zend_Exception('Not a valid Mime Message: End Missing');
+        }
+
+        // the remaining part also needs to be parsed:
+        $res[] = substr($body, $start, $p-$start);
+        return $res;
+    }
+
+    /**
+     * decodes a mime encoded String and returns a
+     * struct of parts with header and body
+     *
+     * @param  string $message  raw message content
+     * @param  string $boundary boundary as found in content-type
+     * @param  string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
+     * @return array|null parts as array('header' => array(name => value), 'body' => content), null if no parts found
+     * @throws Zend_Exception
+     */
+    public static function splitMessageStruct($message, $boundary, $EOL = Zend_Mime::LINEEND)
+    {
+        $parts = self::splitMime($message, $boundary);
+        if (count($parts) <= 0) {
+            return null;
+        }
+        $result = array();
+        foreach ($parts as $part) {
+            self::splitMessage($part, $headers, $body, $EOL);
+            $result[] = array('header' => $headers,
+                              'body'   => $body    );
+        }
+        return $result;
+    }
+
+    /**
+     * split a message in header and body part, if no header or an
+     * invalid header is found $headers is empty
+     *
+     * The charset of the returned headers depend on your iconv settings.
+     *
+     * @param  string $message raw message with header and optional content
+     * @param  array  $headers output param, array with headers as array(name => value)
+     * @param  string $body    output param, content of message
+     * @param  string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
+     * @return null
+     */
+    public static function splitMessage($message, &$headers, &$body, $EOL = Zend_Mime::LINEEND)
+    {
+        // check for valid header at first line
+        $firstline = strtok($message, "\n");
+        if (!preg_match('%^[^\s]+[^:]*:%', $firstline)) {
+            $headers = array();
+            // TODO: we're ignoring \r for now - is this function fast enough and is it safe to asume noone needs \r?
+            $body = str_replace(array("\r", "\n"), array('', $EOL), $message);
+            return;
+        }
+
+        // find an empty line between headers and body
+        // default is set new line
+        if (strpos($message, $EOL . $EOL)) {
+            list($headers, $body) = explode($EOL . $EOL, $message, 2);
+        // next is the standard new line
+        } else if ($EOL != "\r\n" && strpos($message, "\r\n\r\n")) {
+            list($headers, $body) = explode("\r\n\r\n", $message, 2);
+        // next is the other "standard" new line
+        } else if ($EOL != "\n" && strpos($message, "\n\n")) {
+            list($headers, $body) = explode("\n\n", $message, 2);
+        // at last resort find anything that looks like a new line
+        } else {
+            @list($headers, $body) = @preg_split("%([\r\n]+)\\1%U", $message, 2);
+        }
+
+        $headers = iconv_mime_decode_headers($headers, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
+
+        if ($headers === false ) {
+            // an error occurs during the decoding
+            return;
+        }
+
+        // normalize header names
+        foreach ($headers as $name => $header) {
+            $lower = strtolower($name);
+            if ($lower == $name) {
+                continue;
+            }
+            unset($headers[$name]);
+            if (!isset($headers[$lower])) {
+                $headers[$lower] = $header;
+                continue;
+            }
+            if (is_array($headers[$lower])) {
+                $headers[$lower][] = $header;
+                continue;
+            }
+            $headers[$lower] = array($headers[$lower], $header);
+        }
+    }
+
+    /**
+     * split a content type in its different parts
+     *
+     * @param  string $type       content-type
+     * @param  string $wantedPart the wanted part, else an array with all parts is returned
+     * @return string|array wanted part or all parts as array('type' => content-type, partname => value)
+     */
+    public static function splitContentType($type, $wantedPart = null)
+    {
+        return self::splitHeaderField($type, $wantedPart, 'type');
+    }
+
+    /**
+     * split a header field like content type in its different parts
+     *
+     * @param  string $type       header field
+     * @param  string $wantedPart the wanted part, else an array with all parts is returned
+     * @param  string $firstName  key name for the first part
+     * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value)
+     * @throws Zend_Exception
+     */
+    public static function splitHeaderField($field, $wantedPart = null, $firstName = 0)
+    {
+        $wantedPart = strtolower($wantedPart);
+        $firstName = strtolower($firstName);
+
+        // special case - a bit optimized
+        if ($firstName === $wantedPart) {
+            $field = strtok($field, ';');
+            return $field[0] == '"' ? substr($field, 1, -1) : $field;
+        }
+
+        $field = $firstName . '=' . $field;
+        if (!preg_match_all('%([^=\s]+)\s*=\s*("[^"]+"|[^;]+)(;\s*|$)%', $field, $matches)) {
+            throw new Zend_Exception('not a valid header field');
+        }
+
+        if ($wantedPart) {
+            foreach ($matches[1] as $key => $name) {
+                if (strcasecmp($name, $wantedPart)) {
+                    continue;
+                }
+                if ($matches[2][$key][0] != '"') {
+                    return $matches[2][$key];
+                }
+                return substr($matches[2][$key], 1, -1);
+            }
+            return null;
+        }
+
+        $split = array();
+        foreach ($matches[1] as $key => $name) {
+            $name = strtolower($name);
+            if ($matches[2][$key][0] == '"') {
+                $split[$name] = substr($matches[2][$key], 1, -1);
+            } else {
+                $split[$name] = $matches[2][$key];
+            }
+        }
+
+        return $split;
+    }
+
+    /**
+     * decode a quoted printable encoded string
+     *
+     * The charset of the returned string depends on your iconv settings.
+     *
+     * @param  string encoded string
+     * @return string decoded string
+     */
+    public static function decodeQuotedPrintable($string)
+    {
+        return iconv_mime_decode($string, ICONV_MIME_DECODE_CONTINUE_ON_ERROR);
+    }
+}
diff --git a/lib/Zend/Mime/Exception.php b/lib/Zend/Mime/Exception.php
new file mode 100644
index 0000000..2c22e9b
--- /dev/null
+++ b/lib/Zend/Mime/Exception.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * Zend_Exception
+ */
+require_once 'Zend/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mime_Exception extends Zend_Exception
+{}
+
diff --git a/lib/Zend/Mime/Message.php b/lib/Zend/Mime/Message.php
new file mode 100644
index 0000000..613be1d
--- /dev/null
+++ b/lib/Zend/Mime/Message.php
@@ -0,0 +1,285 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+
+/**
+ * Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+/**
+ * Zend_Mime_Part
+ */
+require_once 'Zend/Mime/Part.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mime_Message
+{
+
+    protected $_parts = array();
+    protected $_mime = null;
+
+    /**
+     * Returns the list of all Zend_Mime_Parts in the message
+     *
+     * @return array of Zend_Mime_Part
+     */
+    public function getParts()
+    {
+        return $this->_parts;
+    }
+
+    /**
+     * Sets the given array of Zend_Mime_Parts as the array for the message
+     *
+     * @param array $parts
+     */
+    public function setParts($parts)
+    {
+        $this->_parts = $parts;
+    }
+
+    /**
+     * Append a new Zend_Mime_Part to the current message
+     *
+     * @param Zend_Mime_Part $part
+     */
+    public function addPart(Zend_Mime_Part $part)
+    {
+        /**
+         * @todo check for duplicate object handle
+         */
+        $this->_parts[] = $part;
+    }
+
+    /**
+     * Check if message needs to be sent as multipart
+     * MIME message or if it has only one part.
+     *
+     * @return boolean
+     */
+    public function isMultiPart()
+    {
+        return (count($this->_parts) > 1);
+    }
+
+    /**
+     * Set Zend_Mime object for the message
+     *
+     * This can be used to set the boundary specifically or to use a subclass of
+     * Zend_Mime for generating the boundary.
+     *
+     * @param Zend_Mime $mime
+     */
+    public function setMime(Zend_Mime $mime)
+    {
+        $this->_mime = $mime;
+    }
+
+    /**
+     * Returns the Zend_Mime object in use by the message
+     *
+     * If the object was not present, it is created and returned. Can be used to
+     * determine the boundary used in this message.
+     *
+     * @return Zend_Mime
+     */
+    public function getMime()
+    {
+        if ($this->_mime === null) {
+            $this->_mime = new Zend_Mime();
+        }
+
+        return $this->_mime;
+    }
+
+    /**
+     * Generate MIME-compliant message from the current configuration
+     *
+     * This can be a multipart message if more than one MIME part was added. If
+     * only one part is present, the content of this part is returned. If no
+     * part had been added, an empty string is returned.
+     *
+     * Parts are seperated by the mime boundary as defined in Zend_Mime. If
+     * {@link setMime()} has been called before this method, the Zend_Mime
+     * object set by this call will be used. Otherwise, a new Zend_Mime object
+     * is generated and used.
+     *
+     * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
+     * @return string
+     */
+    public function generateMessage($EOL = Zend_Mime::LINEEND)
+    {
+        if (! $this->isMultiPart()) {
+            $body = array_shift($this->_parts);
+            $body = $body->getContent($EOL);
+        } else {
+            $mime = $this->getMime();
+
+            $boundaryLine = $mime->boundaryLine($EOL);
+            $body = 'This is a message in Mime Format.  If you see this, '
+                  . "your mail reader does not support this format." . $EOL;
+
+            foreach (array_keys($this->_parts) as $p) {
+                $body .= $boundaryLine
+                       . $this->getPartHeaders($p, $EOL)
+                       . $EOL
+                       . $this->getPartContent($p, $EOL);
+            }
+
+            $body .= $mime->mimeEnd($EOL);
+        }
+
+        return trim($body);
+    }
+
+    /**
+     * Get the headers of a given part as an array
+     *
+     * @param int $partnum
+     * @return array
+     */
+    public function getPartHeadersArray($partnum)
+    {
+        return $this->_parts[$partnum]->getHeadersArray();
+    }
+
+    /**
+     * Get the headers of a given part as a string
+     *
+     * @param int $partnum
+     * @return string
+     */
+    public function getPartHeaders($partnum, $EOL = Zend_Mime::LINEEND)
+    {
+        return $this->_parts[$partnum]->getHeaders($EOL);
+    }
+
+    /**
+     * Get the (encoded) content of a given part as a string
+     *
+     * @param int $partnum
+     * @return string
+     */
+    public function getPartContent($partnum, $EOL = Zend_Mime::LINEEND)
+    {
+        return $this->_parts[$partnum]->getContent($EOL);
+    }
+
+    /**
+     * Explode MIME multipart string into seperate parts
+     *
+     * Parts consist of the header and the body of each MIME part.
+     *
+     * @param string $body
+     * @param string $boundary
+     * @return array
+     */
+    protected static function _disassembleMime($body, $boundary)
+    {
+        $start = 0;
+        $res = array();
+        // find every mime part limiter and cut out the
+        // string before it.
+        // the part before the first boundary string is discarded:
+        $p = strpos($body, '--'.$boundary."\n", $start);
+        if ($p === false) {
+            // no parts found!
+            return array();
+        }
+
+        // position after first boundary line
+        $start = $p + 3 + strlen($boundary);
+
+        while (($p = strpos($body, '--' . $boundary . "\n", $start)) !== false) {
+            $res[] = substr($body, $start, $p-$start);
+            $start = $p + 3 + strlen($boundary);
+        }
+
+        // no more parts, find end boundary
+        $p = strpos($body, '--' . $boundary . '--', $start);
+        if ($p===false) {
+            throw new Zend_Exception('Not a valid Mime Message: End Missing');
+        }
+
+        // the remaining part also needs to be parsed:
+        $res[] = substr($body, $start, $p-$start);
+        return $res;
+    }
+
+    /**
+     * Decodes a MIME encoded string and returns a Zend_Mime_Message object with
+     * all the MIME parts set according to the given string
+     *
+     * @param string $message
+     * @param string $boundary
+     * @param string $EOL EOL string; defaults to {@link Zend_Mime::LINEEND}
+     * @return Zend_Mime_Message
+     */
+    public static function createFromMessage($message, $boundary, $EOL = Zend_Mime::LINEEND)
+    {
+        require_once 'Zend/Mime/Decode.php';
+        $parts = Zend_Mime_Decode::splitMessageStruct($message, $boundary, $EOL);
+
+        $res = new self();
+        foreach ($parts as $part) {
+            // now we build a new MimePart for the current Message Part:
+            $newPart = new Zend_Mime_Part($part['body']);
+            foreach ($part['header'] as $key => $value) {
+                /**
+                 * @todo check for characterset and filename
+                 */
+                switch(strtolower($key)) {
+                    case 'content-type':
+                        $newPart->type = $value;
+                        break;
+                    case 'content-transfer-encoding':
+                        $newPart->encoding = $value;
+                        break;
+                    case 'content-id':
+                        $newPart->id = trim($value,'<>');
+                        break;
+                    case 'content-disposition':
+                        $newPart->disposition = $value;
+                        break;
+                    case 'content-description':
+                        $newPart->description = $value;
+                        break;
+                    case 'content-location':
+                        $newPart->location = $value;
+                        break;
+                    case 'content-language':
+                        $newPart->language = $value;
+                        break;
+                    default:
+                        throw new Zend_Exception('Unknown header ignored for MimePart:' . $key);
+                }
+            }
+            $res->addPart($newPart);
+        }
+        return $res;
+    }
+}
diff --git a/lib/Zend/Mime/Part.php b/lib/Zend/Mime/Part.php
new file mode 100644
index 0000000..a3e261b
--- /dev/null
+++ b/lib/Zend/Mime/Part.php
@@ -0,0 +1,216 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * Zend_Mime
+ */
+require_once 'Zend/Mime.php';
+
+/**
+ * Class representing a MIME part.
+ *
+ * @category   Zend
+ * @package    Zend_Mime
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mime_Part {
+
+    public $type = Zend_Mime::TYPE_OCTETSTREAM;
+    public $encoding = Zend_Mime::ENCODING_8BIT;
+    public $id;
+    public $disposition;
+    public $filename;
+    public $description;
+    public $charset;
+    public $boundary;
+    public $location;
+    public $language;
+    protected $_content;
+    protected $_isStream = false;
+
+
+    /**
+     * create a new Mime Part.
+     * The (unencoded) content of the Part as passed
+     * as a string or stream
+     *
+     * @param mixed $content  String or Stream containing the content
+     */
+    public function __construct($content)
+    {
+        $this->_content = $content;
+        if (is_resource($content)) {
+            $this->_isStream = true;
+        }
+    }
+
+    /**
+     * @todo setters/getters
+     * @todo error checking for setting $type
+     * @todo error checking for setting $encoding
+     */
+
+    /**
+     * check if this part can be read as a stream.
+     * if true, getEncodedStream can be called, otherwise
+     * only getContent can be used to fetch the encoded
+     * content of the part
+     *
+     * @return bool
+     */
+    public function isStream()
+    {
+      return $this->_isStream;
+    }
+
+    /**
+     * if this was created with a stream, return a filtered stream for
+     * reading the content. very useful for large file attachments.
+     *
+     * @return stream
+     * @throws Zend_Mime_Exception if not a stream or unable to append filter
+     */
+    public function getEncodedStream()
+    {
+        if (!$this->_isStream) {
+            require_once 'Zend/Mime/Exception.php';
+            throw new Zend_Mime_Exception('Attempt to get a stream from a string part');
+        }
+
+        //stream_filter_remove(); // ??? is that right?
+        switch ($this->encoding) {
+            case Zend_Mime::ENCODING_QUOTEDPRINTABLE:
+                $filter = stream_filter_append(
+                    $this->_content,
+                    'convert.quoted-printable-encode',
+                    STREAM_FILTER_READ,
+                    array(
+                        'line-length'      => 76,
+                        'line-break-chars' => Zend_Mime::LINEEND
+                    )
+                );
+                if (!is_resource($filter)) {
+                    require_once 'Zend/Mime/Exception.php';
+                    throw new Zend_Mime_Exception('Failed to append quoted-printable filter');
+                }
+                break;
+            case Zend_Mime::ENCODING_BASE64:
+                $filter = stream_filter_append(
+                    $this->_content,
+                    'convert.base64-encode',
+                    STREAM_FILTER_READ,
+                    array(
+                        'line-length'      => 76,
+                        'line-break-chars' => Zend_Mime::LINEEND
+                    )
+                );
+                if (!is_resource($filter)) {
+                    require_once 'Zend/Mime/Exception.php';
+                    throw new Zend_Mime_Exception('Failed to append base64 filter');
+                }
+                break;
+            default:
+        }
+        return $this->_content;
+    }
+
+    /**
+     * Get the Content of the current Mime Part in the given encoding.
+     *
+     * @return String
+     */
+    public function getContent($EOL = Zend_Mime::LINEEND)
+    {
+        if ($this->_isStream) {
+            return stream_get_contents($this->getEncodedStream());
+        } else {
+            return Zend_Mime::encode($this->_content, $this->encoding, $EOL);
+        }
+    }
+
+    /**
+     * Create and return the array of headers for this MIME part
+     *
+     * @access public
+     * @return array
+     */
+    public function getHeadersArray($EOL = Zend_Mime::LINEEND)
+    {
+        $headers = array();
+
+        $contentType = $this->type;
+        if ($this->charset) {
+            $contentType .= '; charset="' . $this->charset . '"';
+        }
+
+        if ($this->boundary) {
+            $contentType .= ';' . $EOL
+                          . " boundary=\"" . $this->boundary . '"';
+        }
+
+        $headers[] = array('Content-Type', $contentType);
+
+        if ($this->encoding) {
+            $headers[] = array('Content-Transfer-Encoding', $this->encoding);
+        }
+
+        if ($this->id) {
+            $headers[]  = array('Content-ID', '<' . $this->id . '>');
+        }
+
+        if ($this->disposition) {
+            $disposition = $this->disposition;
+            if ($this->filename) {
+                $disposition .= '; filename="' . $this->filename . '"';
+            }
+            $headers[] = array('Content-Disposition', $disposition);
+        }
+
+        if ($this->description) {
+            $headers[] = array('Content-Description', $this->description);
+        }
+
+        if ($this->location) {
+            $headers[] = array('Content-Location', $this->location);
+        }
+
+        if ($this->language){
+            $headers[] = array('Content-Language', $this->language);
+        }
+
+        return $headers;
+    }
+
+    /**
+     * Return the headers for this part as a string
+     *
+     * @return String
+     */
+    public function getHeaders($EOL = Zend_Mime::LINEEND)
+    {
+        $res = '';
+        foreach ($this->getHeadersArray($EOL) as $header) {
+            $res .= $header[0] . ': ' . $header[1] . $EOL;
+        }
+
+        return $res;
+    }
+}
diff --git a/lib/Zend/Registry.php b/lib/Zend/Registry.php
new file mode 100644
index 0000000..2bc8814
--- /dev/null
+++ b/lib/Zend/Registry.php
@@ -0,0 +1,207 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Registry
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Registry.php 12065 2008-10-21 20:56:32Z doctorrock83 $
+ */
+
+/**
+ * Generic storage class helps to manage global data.
+ *
+ * @category   Zend
+ * @package    Zend_Registry
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Registry extends ArrayObject
+{
+    /**
+     * Class name of the singleton registry object.
+     * @var string
+     */
+    private static $_registryClassName = 'Zend_Registry';
+
+    /**
+     * Registry object provides storage for shared objects.
+     * @var Zend_Registry
+     */
+    private static $_registry = null;
+
+    /**
+     * Retrieves the default registry instance.
+     *
+     * @return Zend_Registry
+     */
+    public static function getInstance()
+    {
+        if (self::$_registry === null) {
+            self::init();
+        }
+
+        return self::$_registry;
+    }
+
+    /**
+     * Set the default registry instance to a specified instance.
+     *
+     * @param Zend_Registry $registry An object instance of type Zend_Registry,
+     *   or a subclass.
+     * @return void
+     * @throws Zend_Exception if registry is already initialized.
+     */
+    public static function setInstance(Zend_Registry $registry)
+    {
+        if (self::$_registry !== null) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception('Registry is already initialized');
+        }
+
+        self::setClassName(get_class($registry));
+        self::$_registry = $registry;
+    }
+
+    /**
+     * Initialize the default registry instance.
+     *
+     * @return void
+     */
+    protected static function init()
+    {
+        self::setInstance(new self::$_registryClassName());
+    }
+
+    /**
+     * Set the class name to use for the default registry instance.
+     * Does not affect the currently initialized instance, it only applies
+     * for the next time you instantiate.
+     *
+     * @param string $registryClassName
+     * @return void
+     * @throws Zend_Exception if the registry is initialized or if the
+     *   class name is not valid.
+     */
+    public static function setClassName($registryClassName = 'Zend_Registry')
+    {
+        if (self::$_registry !== null) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception('Registry is already initialized');
+        }
+
+        if (!is_string($registryClassName)) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception("Argument is not a class name");
+        }
+
+        /**
+         * @see Zend_Loader
+         */
+        require_once 'Zend/Loader.php';
+        Zend_Loader::loadClass($registryClassName);
+
+        self::$_registryClassName = $registryClassName;
+    }
+
+    /**
+     * Unset the default registry instance.
+     * Primarily used in tearDown() in unit tests.
+     * @returns void
+     */
+    public static function _unsetInstance()
+    {
+        self::$_registry = null;
+    }
+
+    /**
+     * getter method, basically same as offsetGet().
+     *
+     * This method can be called from an object of type Zend_Registry, or it
+     * can be called statically.  In the latter case, it uses the default
+     * static instance stored in the class.
+     *
+     * @param string $index - get the value associated with $index
+     * @return mixed
+     * @throws Zend_Exception if no entry is registerd for $index.
+     */
+    public static function get($index)
+    {
+        $instance = self::getInstance();
+
+        if (!$instance->offsetExists($index)) {
+            require_once 'Zend/Exception.php';
+            throw new Zend_Exception("No entry is registered for key '$index'");
+        }
+
+        return $instance->offsetGet($index);
+    }
+
+    /**
+     * setter method, basically same as offsetSet().
+     *
+     * This method can be called from an object of type Zend_Registry, or it
+     * can be called statically.  In the latter case, it uses the default
+     * static instance stored in the class.
+     *
+     * @param string $index The location in the ArrayObject in which to store
+     *   the value.
+     * @param mixed $value The object to store in the ArrayObject.
+     * @return void
+     */
+    public static function set($index, $value)
+    {
+        $instance = self::getInstance();
+        $instance->offsetSet($index, $value);
+    }
+
+    /**
+     * Returns TRUE if the $index is a named value in the registry,
+     * or FALSE if $index was not found in the registry.
+     *
+     * @param  string $index
+     * @return boolean
+     */
+    public static function isRegistered($index)
+    {
+        if (self::$_registry === null) {
+            return false;
+        }
+        return self::$_registry->offsetExists($index);
+    }
+
+    /**
+     * Constructs a parent ArrayObject with default
+     * ARRAY_AS_PROPS to allow acces as an object
+     *
+     * @param array $array data array
+     * @param integer $flags ArrayObject flags
+     */
+    public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS)
+    {
+        parent::__construct($array, $flags);
+    }
+
+    /**
+     * @param string $index
+     * @returns mixed
+     *
+     * Workaround for http://bugs.php.net/bug.php?id=40442 (ZF-960).
+     */
+    public function offsetExists($index)
+    {
+        return array_key_exists($index, $this);
+    }
+
+}
diff --git a/lib/Zend/Validate.php b/lib/Zend/Validate.php
new file mode 100644
index 0000000..b57930a
--- /dev/null
+++ b/lib/Zend/Validate.php
@@ -0,0 +1,171 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Validate.php 8729 2008-03-10 11:44:10Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Interface
+ */
+require_once 'Zend/Validate/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate implements Zend_Validate_Interface
+{
+    /**
+     * Validator chain
+     *
+     * @var array
+     */
+    protected $_validators = array();
+
+    /**
+     * Array of validation failure messages
+     *
+     * @var array
+     */
+    protected $_messages = array();
+
+    /**
+     * Array of validation failure message codes
+     *
+     * @var array
+     * @deprecated Since 1.5.0
+     */
+    protected $_errors = array();
+
+    /**
+     * Adds a validator to the end of the chain
+     *
+     * If $breakChainOnFailure is true, then if the validator fails, the next validator in the chain,
+     * if one exists, will not be executed.
+     *
+     * @param  Zend_Validate_Interface $validator
+     * @param  boolean                 $breakChainOnFailure
+     * @return Zend_Validate Provides a fluent interface
+     */
+    public function addValidator(Zend_Validate_Interface $validator, $breakChainOnFailure = false)
+    {
+        $this->_validators[] = array(
+            'instance' => $validator,
+            'breakChainOnFailure' => (boolean) $breakChainOnFailure
+            );
+        return $this;
+    }
+
+    /**
+     * Returns true if and only if $value passes all validations in the chain
+     *
+     * Validators are run in the order in which they were added to the chain (FIFO).
+     *
+     * @param  mixed $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_messages = array();
+        $this->_errors   = array();
+        $result = true;
+        foreach ($this->_validators as $element) {
+            $validator = $element['instance'];
+            if ($validator->isValid($value)) {
+                continue;
+            }
+            $result = false;
+            $messages = $validator->getMessages();
+            $this->_messages = array_merge($this->_messages, $messages);
+            $this->_errors   = array_merge($this->_errors,   array_keys($messages));
+            if ($element['breakChainOnFailure']) {
+                break;
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns array of validation failure messages
+     *
+     * @return array
+     */
+    public function getMessages()
+    {
+        return $this->_messages;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns array of validation failure message codes
+     *
+     * @return array
+     * @deprecated Since 1.5.0
+     */
+    public function getErrors()
+    {
+        return $this->_errors;
+    }
+
+    /**
+     * @param  mixed    $value
+     * @param  string   $classBaseName
+     * @param  array    $args          OPTIONAL
+     * @param  mixed    $namespaces    OPTIONAL
+     * @return boolean
+     * @throws Zend_Validate_Exception
+     */
+    public static function is($value, $classBaseName, array $args = array(), $namespaces = array())
+    {
+        $namespaces = array_merge(array('Zend_Validate'), (array) $namespaces);
+        foreach ($namespaces as $namespace) {
+            $className = $namespace . '_' . ucfirst($classBaseName);
+            try {
+                require_once 'Zend/Loader.php';
+                @Zend_Loader::loadClass($className);
+                if (class_exists($className, false)) {
+                    $class = new ReflectionClass($className);
+                    if ($class->implementsInterface('Zend_Validate_Interface')) {
+                        if ($class->hasMethod('__construct')) {
+                            $object = $class->newInstanceArgs($args);
+                        } else {
+                            $object = $class->newInstance();
+                        }
+                        return $object->isValid($value);
+                    }
+                }
+            } catch (Zend_Validate_Exception $ze) {
+                // if there is an exception while validating throw it
+                throw $ze;
+            } catch (Zend_Exception $ze) {
+                // fallthrough and continue for missing validation classes
+            }
+        }
+        require_once 'Zend/Validate/Exception.php';
+        throw new Zend_Validate_Exception("Validate class not found from basename '$classBaseName'");
+    }
+
+}
diff --git a/lib/Zend/Validate/Abstract.php b/lib/Zend/Validate/Abstract.php
new file mode 100644
index 0000000..66566a9
--- /dev/null
+++ b/lib/Zend/Validate/Abstract.php
@@ -0,0 +1,358 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Abstract.php 13351 2008-12-18 15:26:14Z alexander $
+ */
+
+
+/**
+ * @see Zend_Validate_Interface
+ */
+require_once 'Zend/Validate/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Validate_Abstract implements Zend_Validate_Interface
+{
+    /**
+     * The value to be validated
+     *
+     * @var mixed
+     */
+    protected $_value;
+
+    /**
+     * Additional variables available for validation failure messages
+     *
+     * @var array
+     */
+    protected $_messageVariables = array();
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array();
+
+    /**
+     * Array of validation failure messages
+     *
+     * @var array
+     */
+    protected $_messages = array();
+
+    /**
+     * Flag indidcating whether or not value should be obfuscated in error
+     * messages
+     * @var bool
+     */
+    protected $_obscureValue = false;
+
+    /**
+     * Array of validation failure message codes
+     *
+     * @var array
+     * @deprecated Since 1.5.0
+     */
+    protected $_errors = array();
+
+    /**
+     * Translation object
+     * @var Zend_Translate
+     */
+    protected $_translator;
+
+    /**
+     * Default translation object for all validate objects
+     * @var Zend_Translate
+     */
+    protected static $_defaultTranslator;
+
+    /**
+     * Returns array of validation failure messages
+     *
+     * @return array
+     */
+    public function getMessages()
+    {
+        return $this->_messages;
+    }
+
+    /**
+     * Returns an array of the names of variables that are used in constructing validation failure messages
+     *
+     * @return array
+     */
+    public function getMessageVariables()
+    {
+        return array_keys($this->_messageVariables);
+    }
+
+    /**
+     * Sets the validation failure message template for a particular key
+     *
+     * @param  string $messageString
+     * @param  string $messageKey     OPTIONAL
+     * @return Zend_Validate_Abstract Provides a fluent interface
+     * @throws Zend_Validate_Exception
+     */
+    public function setMessage($messageString, $messageKey = null)
+    {
+        if ($messageKey === null) {
+            $keys = array_keys($this->_messageTemplates);
+            $messageKey = current($keys);
+        }
+        if (!isset($this->_messageTemplates[$messageKey])) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("No message template exists for key '$messageKey'");
+        }
+        $this->_messageTemplates[$messageKey] = $messageString;
+        return $this;
+    }
+
+    /**
+     * Sets validation failure message templates given as an array, where the array keys are the message keys,
+     * and the array values are the message template strings.
+     *
+     * @param  array $messages
+     * @return Zend_Validate_Abstract
+     */
+    public function setMessages(array $messages)
+    {
+        foreach ($messages as $key => $message) {
+            $this->setMessage($message, $key);
+        }
+        return $this;
+    }
+
+    /**
+     * Magic function returns the value of the requested property, if and only if it is the value or a
+     * message variable.
+     *
+     * @param  string $property
+     * @return mixed
+     * @throws Zend_Validate_Exception
+     */
+    public function __get($property)
+    {
+        if ($property == 'value') {
+            return $this->_value;
+        }
+        if (array_key_exists($property, $this->_messageVariables)) {
+            return $this->{$this->_messageVariables[$property]};
+        }
+        /**
+         * @see Zend_Validate_Exception
+         */
+        require_once 'Zend/Validate/Exception.php';
+        throw new Zend_Validate_Exception("No property exists by the name '$property'");
+    }
+
+    /**
+     * Constructs and returns a validation failure message with the given message key and value.
+     *
+     * Returns null if and only if $messageKey does not correspond to an existing template.
+     *
+     * If a translator is available and a translation exists for $messageKey,
+     * the translation will be used.
+     *
+     * @param  string $messageKey
+     * @param  string $value
+     * @return string
+     */
+    protected function _createMessage($messageKey, $value)
+    {
+        if (!isset($this->_messageTemplates[$messageKey])) {
+            return null;
+        }
+
+        $message = $this->_messageTemplates[$messageKey];
+
+        if (null !== ($translator = $this->getTranslator())) {
+            if ($translator->isTranslated($message)) {
+                $message = $translator->translate($message);
+            } elseif ($translator->isTranslated($messageKey)) {
+                $message = $translator->translate($messageKey);
+            }
+        }
+
+        if (is_object($value)) {
+        	if (!in_array('__toString', get_class_methods($value))) {
+        		$value = get_class($value) . ' object';
+        	} else {
+        		$value = $value->__toString();
+        	}
+        } else {
+        	$value = (string)$value;
+        }
+
+        if ($this->getObscureValue()) {
+            $value = str_repeat('*', strlen($value));
+        }
+
+        $message = str_replace('%value%', (string) $value, $message);
+        foreach ($this->_messageVariables as $ident => $property) {
+            $message = str_replace("%$ident%", (string) $this->$property, $message);
+        }
+        return $message;
+    }
+
+    /**
+     * @param  string $messageKey OPTIONAL
+     * @param  string $value      OPTIONAL
+     * @return void
+     */
+    protected function _error($messageKey = null, $value = null)
+    {
+        if ($messageKey === null) {
+            $keys = array_keys($this->_messageTemplates);
+            $messageKey = current($keys);
+        }
+        if ($value === null) {
+            $value = $this->_value;
+        }
+        $this->_errors[]              = $messageKey;
+        $this->_messages[$messageKey] = $this->_createMessage($messageKey, $value);
+    }
+
+    /**
+     * Sets the value to be validated and clears the messages and errors arrays
+     *
+     * @param  mixed $value
+     * @return void
+     */
+    protected function _setValue($value)
+    {
+        $this->_value    = $value;
+        $this->_messages = array();
+        $this->_errors   = array();
+    }
+
+    /**
+     * Returns array of validation failure message codes
+     *
+     * @return array
+     * @deprecated Since 1.5.0
+     */
+    public function getErrors()
+    {
+        return $this->_errors;
+    }
+
+    /**
+     * Set flag indicating whether or not value should be obfuscated in messages
+     *
+     * @param  bool $flag
+     * @return Zend_Validate_Abstract
+     */
+    public function setObscureValue($flag)
+    {
+        $this->_obscureValue = (bool) $flag;
+        return $this;
+    }
+
+    /**
+     * Retrieve flag indicating whether or not value should be obfuscated in
+     * messages
+     *
+     * @return bool
+     */
+    public function getObscureValue()
+    {
+        return $this->_obscureValue;
+    }
+
+    /**
+     * Set translation object
+     *
+     * @param  Zend_Translate|Zend_Translate_Adapter|null $translator
+     * @return Zend_Validate_Abstract
+     */
+    public function setTranslator($translator = null)
+    {
+        if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) {
+            $this->_translator = $translator;
+        } elseif ($translator instanceof Zend_Translate) {
+            $this->_translator = $translator->getAdapter();
+        } else {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('Invalid translator specified');
+        }
+        return $this;
+    }
+
+    /**
+     * Return translation object
+     *
+     * @return Zend_Translate_Adapter|null
+     */
+    public function getTranslator()
+    {
+        if (null === $this->_translator) {
+            return self::getDefaultTranslator();
+        }
+
+        return $this->_translator;
+    }
+
+    /**
+     * Set default translation object for all validate objects
+     *
+     * @param  Zend_Translate|Zend_Translate_Adapter|null $translator
+     * @return void
+     */
+    public static function setDefaultTranslator($translator = null)
+    {
+        if ((null === $translator) || ($translator instanceof Zend_Translate_Adapter)) {
+            self::$_defaultTranslator = $translator;
+        } elseif ($translator instanceof Zend_Translate) {
+            self::$_defaultTranslator = $translator->getAdapter();
+        } else {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('Invalid translator specified');
+        }
+    }
+
+    /**
+     * Get default translation object for all validate objects
+     *
+     * @return Zend_Translate_Adapter|null
+     */
+    public static function getDefaultTranslator()
+    {
+        if (null === self::$_defaultTranslator) {
+            require_once 'Zend/Registry.php';
+            if (Zend_Registry::isRegistered('Zend_Translate')) {
+                $translator = Zend_Registry::get('Zend_Translate');
+                if ($translator instanceof Zend_Translate_Adapter) {
+                    return $translator;
+                } elseif ($translator instanceof Zend_Translate) {
+                    return $translator->getAdapter();
+                }
+            }
+        }
+        return self::$_defaultTranslator;
+    }
+}
diff --git a/lib/Zend/Validate/Alnum.php b/lib/Zend/Validate/Alnum.php
new file mode 100644
index 0000000..36b0adc
--- /dev/null
+++ b/lib/Zend/Validate/Alnum.php
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Alnum.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Alnum extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value contains non-alphabetic or non-digit characters
+     */
+    const NOT_ALNUM = 'notAlnum';
+
+    /**
+     * Validation failure message key for when the value is an empty string
+     */
+    const STRING_EMPTY = 'stringEmpty';
+
+    /**
+     * Whether to allow white space characters; off by default
+     *
+     * @var boolean
+     */
+    public $allowWhiteSpace;
+
+    /**
+     * Alphanumeric filter used for validation
+     *
+     * @var Zend_Filter_Alnum
+     */
+    protected static $_filter = null;
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_ALNUM    => "'%value%' has not only alphabetic and digit characters",
+        self::STRING_EMPTY => "'%value%' is an empty string"
+    );
+
+    /**
+     * Sets default option values for this instance
+     *
+     * @param  boolean $allowWhiteSpace
+     * @return void
+     */
+    public function __construct($allowWhiteSpace = false)
+    {
+        $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value contains only alphabetic and digit characters
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        if ('' === $valueString) {
+            $this->_error(self::STRING_EMPTY);
+            return false;
+        }
+
+        if (null === self::$_filter) {
+            /**
+             * @see Zend_Filter_Alnum
+             */
+            require_once 'Zend/Filter/Alnum.php';
+            self::$_filter = new Zend_Filter_Alnum();
+        }
+
+        self::$_filter->allowWhiteSpace = $this->allowWhiteSpace;
+
+        if ($valueString !== self::$_filter->filter($valueString)) {
+            $this->_error(self::NOT_ALNUM);
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Alpha.php b/lib/Zend/Validate/Alpha.php
new file mode 100644
index 0000000..0f2298e
--- /dev/null
+++ b/lib/Zend/Validate/Alpha.php
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Alpha.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Alpha extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value contains non-alphabetic characters
+     */
+    const NOT_ALPHA = 'notAlpha';
+
+    /**
+     * Validation failure message key for when the value is an empty string
+     */
+    const STRING_EMPTY = 'stringEmpty';
+
+    /**
+     * Whether to allow white space characters; off by default
+     *
+     * @var boolean
+     */
+    public $allowWhiteSpace;
+
+    /**
+     * Alphabetic filter used for validation
+     *
+     * @var Zend_Filter_Alpha
+     */
+    protected static $_filter = null;
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_ALPHA    => "'%value%' has not only alphabetic characters",
+        self::STRING_EMPTY => "'%value%' is an empty string"
+    );
+
+    /**
+     * Sets default option values for this instance
+     *
+     * @param  boolean $allowWhiteSpace
+     * @return void
+     */
+    public function __construct($allowWhiteSpace = false)
+    {
+        $this->allowWhiteSpace = (boolean) $allowWhiteSpace;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value contains only alphabetic characters
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        if ('' === $valueString) {
+            $this->_error(self::STRING_EMPTY);
+            return false;
+        }
+
+        if (null === self::$_filter) {
+            /**
+             * @see Zend_Filter_Alpha
+             */
+            require_once 'Zend/Filter/Alpha.php';
+            self::$_filter = new Zend_Filter_Alpha();
+        }
+
+        self::$_filter->allowWhiteSpace = $this->allowWhiteSpace;
+
+        if ($valueString !== self::$_filter->filter($valueString)) {
+            $this->_error(self::NOT_ALPHA);
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Barcode.php b/lib/Zend/Validate/Barcode.php
new file mode 100644
index 0000000..d51f11b
--- /dev/null
+++ b/lib/Zend/Validate/Barcode.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Barcode.php 8211 2008-02-20 14:29:24Z darby $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Barcode extends Zend_Validate_Abstract
+{
+    /**
+     * Barcode validator
+     *
+     * @var Zend_Validate_Abstract
+     */
+    protected $_barcodeValidator;
+
+    /**
+     * Generates the standard validator object
+     *
+     * @param  string $barcodeType - Barcode validator to use
+     * @return void
+     * @throws Zend_Validate_Exception
+     */
+    public function __construct($barcodeType)
+    {
+        $this->setType($barcodeType);
+    }
+
+    /**
+     * Sets a new barcode validator
+     *
+     * @param  string $barcodeType - Barcode validator to use
+     * @return void
+     * @throws Zend_Validate_Exception
+     */
+    public function setType($barcodeType)
+    {
+        switch (strtolower($barcodeType)) {
+            case 'upc':
+            case 'upc-a':
+                $className = 'UpcA';
+                break;
+            case 'ean13':
+            case 'ean-13':
+                $className = 'Ean13';
+                break;
+            default:
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception("Barcode type '$barcodeType' is not supported'");
+                break;
+        }
+
+        require_once 'Zend/Validate/Barcode/' . $className . '.php';
+
+        $class = 'Zend_Validate_Barcode_' . $className;
+        $this->_barcodeValidator = new $class;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value contains a valid barcode
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        return call_user_func(array($this->_barcodeValidator, 'isValid'), $value);
+    }
+}
diff --git a/lib/Zend/Validate/Barcode/Ean13.php b/lib/Zend/Validate/Barcode/Ean13.php
new file mode 100644
index 0000000..393091d
--- /dev/null
+++ b/lib/Zend/Validate/Barcode/Ean13.php
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Ean13.php 11791 2008-10-09 18:19:13Z andries $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Barcode_Ean13 extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value is
+     * an invalid barcode
+     */
+    const INVALID = 'invalid';
+
+    /**
+     * Validation failure message key for when the value is
+     * not 13 characters long
+     */
+    const INVALID_LENGTH = 'invalidLength';
+
+    /**
+     * Validation failure message key for when the value
+     * does not only contain numeric characters
+     */
+    const NOT_NUMERIC = 'ean13NotNumeric';
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::INVALID        => "'%value%' is an invalid EAN-13 barcode",
+        self::INVALID_LENGTH => "'%value%' should be 13 characters",
+        self::NOT_NUMERIC    => "'%value%' should contain only numeric characters",
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value contains a valid barcode
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        if (false === ctype_digit($value)) {
+            $this->_error(self::NOT_NUMERIC);
+            return false;
+        }
+
+        $valueString = (string) $value;
+        $this->_setValue($valueString);
+
+        if (strlen($valueString) !== 13) {
+            $this->_error(self::INVALID_LENGTH);
+            return false;
+        }
+
+        $barcode = strrev(substr($valueString, 0, -1));
+        $oddSum  = 0;
+        $evenSum = 0;
+
+        for ($i = 0; $i < 12; $i++) {
+            if ($i % 2 === 0) {
+                $oddSum += $barcode[$i] * 3;
+            } elseif ($i % 2 === 1) {
+                $evenSum += $barcode[$i];
+            }
+        }
+
+        $calculation = ($oddSum + $evenSum) % 10;
+        $checksum    = ($calculation === 0) ? 0 : 10 - $calculation;
+
+        if ($valueString[12] != $checksum) {
+            $this->_error(self::INVALID);
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/lib/Zend/Validate/Barcode/UpcA.php b/lib/Zend/Validate/Barcode/UpcA.php
new file mode 100644
index 0000000..c584e81
--- /dev/null
+++ b/lib/Zend/Validate/Barcode/UpcA.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: UpcA.php 8210 2008-02-20 14:09:05Z andries $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Barcode_UpcA extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value is
+     * an invalid barcode
+     */
+    const INVALID = 'invalid';
+
+    /**
+     * Validation failure message key for when the value is
+     * not 12 characters long
+     */
+    const INVALID_LENGTH = 'invalidLength';
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::INVALID        => "'%value%' is an invalid UPC-A barcode",
+        self::INVALID_LENGTH => "'%value%' should be 12 characters",
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value contains a valid barcode
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+        $this->_setValue($valueString);
+
+        if (strlen($valueString) !== 12) {
+            $this->_error(self::INVALID_LENGTH);
+            return false;
+        }
+
+        $barcode = substr($valueString, 0, -1);
+        $oddSum  = 0;
+        $evenSum = 0;
+
+        for ($i = 0; $i < 11; $i++) {
+            if ($i % 2 === 0) {
+                $oddSum += $barcode[$i] * 3;
+            } elseif ($i % 2 === 1) {
+                $evenSum += $barcode[$i];
+            }
+        }
+
+        $calculation = ($oddSum + $evenSum) % 10;
+        $checksum    = ($calculation === 0) ? 0 : 10 - $calculation;
+
+        if ($valueString[11] != $checksum) {
+            $this->_error(self::INVALID);
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/lib/Zend/Validate/Between.php b/lib/Zend/Validate/Between.php
new file mode 100644
index 0000000..bb0b726
--- /dev/null
+++ b/lib/Zend/Validate/Between.php
@@ -0,0 +1,200 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Between.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Between extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value is not between the min and max, inclusively
+     */
+    const NOT_BETWEEN        = 'notBetween';
+
+    /**
+     * Validation failure message key for when the value is not strictly between the min and max
+     */
+    const NOT_BETWEEN_STRICT = 'notBetweenStrict';
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_BETWEEN        => "'%value%' is not between '%min%' and '%max%', inclusively",
+        self::NOT_BETWEEN_STRICT => "'%value%' is not strictly between '%min%' and '%max%'"
+    );
+
+    /**
+     * Additional variables available for validation failure messages
+     *
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'min' => '_min',
+        'max' => '_max'
+    );
+
+    /**
+     * Minimum value
+     *
+     * @var mixed
+     */
+    protected $_min;
+
+    /**
+     * Maximum value
+     *
+     * @var mixed
+     */
+    protected $_max;
+
+    /**
+     * Whether to do inclusive comparisons, allowing equivalence to min and/or max
+     *
+     * If false, then strict comparisons are done, and the value may equal neither
+     * the min nor max options
+     *
+     * @var boolean
+     */
+    protected $_inclusive;
+
+    /**
+     * Sets validator options
+     *
+     * @param  mixed   $min
+     * @param  mixed   $max
+     * @param  boolean $inclusive
+     * @return void
+     */
+    public function __construct($min, $max, $inclusive = true)
+    {
+        $this->setMin($min)
+             ->setMax($max)
+             ->setInclusive($inclusive);
+    }
+
+    /**
+     * Returns the min option
+     *
+     * @return mixed
+     */
+    public function getMin()
+    {
+        return $this->_min;
+    }
+
+    /**
+     * Sets the min option
+     *
+     * @param  mixed $min
+     * @return Zend_Validate_Between Provides a fluent interface
+     */
+    public function setMin($min)
+    {
+        $this->_min = $min;
+        return $this;
+    }
+
+    /**
+     * Returns the max option
+     *
+     * @return mixed
+     */
+    public function getMax()
+    {
+        return $this->_max;
+    }
+
+    /**
+     * Sets the max option
+     *
+     * @param  mixed $max
+     * @return Zend_Validate_Between Provides a fluent interface
+     */
+    public function setMax($max)
+    {
+        $this->_max = $max;
+        return $this;
+    }
+
+    /**
+     * Returns the inclusive option
+     *
+     * @return boolean
+     */
+    public function getInclusive()
+    {
+        return $this->_inclusive;
+    }
+
+    /**
+     * Sets the inclusive option
+     *
+     * @param  boolean $inclusive
+     * @return Zend_Validate_Between Provides a fluent interface
+     */
+    public function setInclusive($inclusive)
+    {
+        $this->_inclusive = $inclusive;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is between min and max options, inclusively
+     * if inclusive option is true.
+     *
+     * @param  mixed $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_setValue($value);
+
+        if ($this->_inclusive) {
+            if ($this->_min > $value || $value > $this->_max) {
+                $this->_error(self::NOT_BETWEEN);
+                return false;
+            }
+        } else {
+            if ($this->_min >= $value || $value >= $this->_max) {
+                $this->_error(self::NOT_BETWEEN_STRICT);
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Ccnum.php b/lib/Zend/Validate/Ccnum.php
new file mode 100644
index 0000000..227a4ec
--- /dev/null
+++ b/lib/Zend/Validate/Ccnum.php
@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Ccnum.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Ccnum extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value is not of valid length
+     */
+    const LENGTH   = 'ccnumLength';
+
+    /**
+     * Validation failure message key for when the value fails the mod-10 checksum
+     */
+    const CHECKSUM = 'ccnumChecksum';
+
+    /**
+     * Digits filter for input
+     *
+     * @var Zend_Filter_Digits
+     */
+    protected static $_filter = null;
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::LENGTH   => "'%value%' must contain between 13 and 19 digits",
+        self::CHECKSUM => "Luhn algorithm (mod-10 checksum) failed on '%value%'"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value follows the Luhn algorithm (mod-10 checksum)
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_setValue($value);
+
+        if (null === self::$_filter) {
+            /**
+             * @see Zend_Filter_Digits
+             */
+            require_once 'Zend/Filter/Digits.php';
+            self::$_filter = new Zend_Filter_Digits();
+        }
+
+        $valueFiltered = self::$_filter->filter($value);
+
+        $length = strlen($valueFiltered);
+
+        if ($length < 13 || $length > 19) {
+            $this->_error(self::LENGTH);
+            return false;
+        }
+
+        $sum    = 0;
+        $weight = 2;
+
+        for ($i = $length - 2; $i >= 0; $i--) {
+            $digit = $weight * $valueFiltered[$i];
+            $sum += floor($digit / 10) + $digit % 10;
+            $weight = $weight % 2 + 1;
+        }
+
+        if ((10 - $sum % 10) % 10 != $valueFiltered[$length - 1]) {
+            $this->_error(self::CHECKSUM, $valueFiltered);
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Date.php b/lib/Zend/Validate/Date.php
new file mode 100644
index 0000000..156c584
--- /dev/null
+++ b/lib/Zend/Validate/Date.php
@@ -0,0 +1,235 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Date.php 13687 2009-01-18 15:33:52Z thomas $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Date extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value does not follow the YYYY-MM-DD format
+     */
+    const NOT_YYYY_MM_DD = 'dateNotYYYY-MM-DD';
+
+    /**
+     * Validation failure message key for when the value does not appear to be a valid date
+     */
+    const INVALID        = 'dateInvalid';
+
+    /**
+     * Validation failure message key for when the value does not fit the given dateformat or locale
+     */
+    const FALSEFORMAT    = 'dateFalseFormat';
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_YYYY_MM_DD => "'%value%' is not of the format YYYY-MM-DD",
+        self::INVALID        => "'%value%' does not appear to be a valid date",
+        self::FALSEFORMAT    => "'%value%' does not fit given date format"
+    );
+
+    /**
+     * Optional format
+     *
+     * @var string|null
+     */
+    protected $_format;
+
+    /**
+     * Optional locale
+     *
+     * @var string|Zend_Locale|null
+     */
+    protected $_locale;
+
+    /**
+     * Sets validator options
+     *
+     * @param  string             $format OPTIONAL
+     * @param  string|Zend_Locale $locale OPTIONAL
+     * @return void
+     */
+    public function __construct($format = null, $locale = null)
+    {
+        $this->setFormat($format);
+        if ($locale !== null) {
+            $this->setLocale($locale);
+        }
+    }
+
+    /**
+     * Returns the locale option
+     *
+     * @return string|Zend_Locale|null
+     */
+    public function getLocale()
+    {
+        return $this->_locale;
+    }
+
+    /**
+     * Sets the locale option
+     *
+     * @param  string|Zend_Locale $locale
+     * @return Zend_Validate_Date provides a fluent interface
+     */
+    public function setLocale($locale = null)
+    {
+        require_once 'Zend/Locale.php';
+        $this->_locale = Zend_Locale::findLocale($locale);
+        return $this;
+    }
+
+    /**
+     * Returns the locale option
+     *
+     * @return string|null
+     */
+    public function getFormat()
+    {
+        return $this->_format;
+    }
+
+    /**
+     * Sets the format option
+     *
+     * @param  string $format
+     * @return Zend_Validate_Date provides a fluent interface
+     */
+    public function setFormat($format = null)
+    {
+        $this->_format = $format;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if $value is a valid date of the format YYYY-MM-DD
+     * If optional $format or $locale is set the date format is checked
+     * according to Zend_Date, see Zend_Date::isDate()
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        if (($this->_format !== null) or ($this->_locale !== null)) {
+            require_once 'Zend/Date.php';
+            if (!Zend_Date::isDate($value, $this->_format, $this->_locale)) {
+                if ($this->_checkFormat($value) === false) {
+                    $this->_error(self::FALSEFORMAT);
+                } else {
+                    $this->_error(self::INVALID);
+                }
+                return false;
+            }
+        } else {
+            if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $valueString)) {
+                $this->_error(self::NOT_YYYY_MM_DD);
+                return false;
+            }
+
+            list($year, $month, $day) = sscanf($valueString, '%d-%d-%d');
+
+            if (!checkdate($month, $day, $year)) {
+                $this->_error(self::INVALID);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Check if the given date fits the given format
+     *
+     * @param  string $value  Date to check
+     * @return boolean False when date does not fit the format
+     */
+    private function _checkFormat($value)
+    {
+        try {
+            require_once 'Zend/Locale/Format.php';
+            $parsed = Zend_Locale_Format::getDate($value, array(
+                                                  'date_format' => $this->_format, 'format_type' => 'iso',
+                                                  'fix_date' => false));
+            if (isset($parsed['year']) and ((strpos(strtoupper($this->_format), 'YY') !== false) and
+                (strpos(strtoupper($this->_format), 'YYYY') === false))) {
+                $parsed['year'] = Zend_Date::getFullYear($parsed['year']);
+            }
+        } catch (Exception $e) {
+            // Date can not be parsed
+            return false;
+        }
+
+        if (((strpos($this->_format, 'Y') !== false) or (strpos($this->_format, 'y') !== false)) and
+            (!isset($parsed['year']))) {
+            // Year expected but not found
+            return false;
+        }
+
+        if ((strpos($this->_format, 'M') !== false) and (!isset($parsed['month']))) {
+            // Month expected but not found
+            return false;
+        }
+
+        if ((strpos($this->_format, 'd') !== false) and (!isset($parsed['day']))) {
+            // Day expected but not found
+            return false;
+        }
+
+        if (((strpos($this->_format, 'H') !== false) or (strpos($this->_format, 'h') !== false)) and
+            (!isset($parsed['hour']))) {
+            // Hour expected but not found
+            return false;
+        }
+
+        if ((strpos($this->_format, 'm') !== false) and (!isset($parsed['minute']))) {
+            // Minute expected but not found
+            return false;
+        }
+
+        if ((strpos($this->_format, 's') !== false) and (!isset($parsed['second']))) {
+            // Second expected  but not found
+            return false;
+        }
+
+        // Date fits the format
+        return true;
+    }
+}
diff --git a/lib/Zend/Validate/Digits.php b/lib/Zend/Validate/Digits.php
new file mode 100644
index 0000000..c42ec0a
--- /dev/null
+++ b/lib/Zend/Validate/Digits.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Digits.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Digits extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value contains non-digit characters
+     */
+    const NOT_DIGITS = 'notDigits';
+
+    /**
+     * Validation failure message key for when the value is an empty string
+     */
+    const STRING_EMPTY = 'stringEmpty';
+
+    /**
+     * Digits filter used for validation
+     *
+     * @var Zend_Filter_Digits
+     */
+    protected static $_filter = null;
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_DIGITS   => "'%value%' contains not only digit characters",
+        self::STRING_EMPTY => "'%value%' is an empty string"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value only contains digit characters
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        if ('' === $valueString) {
+            $this->_error(self::STRING_EMPTY);
+            return false;
+        }
+
+        if (null === self::$_filter) {
+            /**
+             * @see Zend_Filter_Digits
+             */
+            require_once 'Zend/Filter/Digits.php';
+            self::$_filter = new Zend_Filter_Digits();
+        }
+
+        if ($valueString !== self::$_filter->filter($valueString)) {
+            $this->_error(self::NOT_DIGITS);
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/EmailAddress.php b/lib/Zend/Validate/EmailAddress.php
new file mode 100644
index 0000000..82ed91b
--- /dev/null
+++ b/lib/Zend/Validate/EmailAddress.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: EmailAddress.php 13253 2008-12-14 20:28:06Z thomas $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @see Zend_Validate_Hostname
+ */
+require_once 'Zend/Validate/Hostname.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_EmailAddress extends Zend_Validate_Abstract
+{
+    const INVALID            = 'emailAddressInvalid';
+    const INVALID_HOSTNAME   = 'emailAddressInvalidHostname';
+    const INVALID_MX_RECORD  = 'emailAddressInvalidMxRecord';
+    const DOT_ATOM           = 'emailAddressDotAtom';
+    const QUOTED_STRING      = 'emailAddressQuotedString';
+    const INVALID_LOCAL_PART = 'emailAddressInvalidLocalPart';
+    const LENGTH_EXCEEDED    = 'emailAddressLengthExceeded';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::INVALID            => "'%value%' is not a valid email address in the basic format local-part@hostname",
+        self::INVALID_HOSTNAME   => "'%hostname%' is not a valid hostname for email address '%value%'",
+        self::INVALID_MX_RECORD  => "'%hostname%' does not appear to have a valid MX record for the email address '%value%'",
+        self::DOT_ATOM           => "'%localPart%' not matched against dot-atom format",
+        self::QUOTED_STRING      => "'%localPart%' not matched against quoted-string format",
+        self::INVALID_LOCAL_PART => "'%localPart%' is not a valid local part for email address '%value%'",
+        self::LENGTH_EXCEEDED    => "'%value%' exceeds the allowed length"
+    );
+
+    /**
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'hostname'  => '_hostname',
+        'localPart' => '_localPart'
+    );
+
+    /**
+     * Local object for validating the hostname part of an email address
+     *
+     * @var Zend_Validate_Hostname
+     */
+    public $hostnameValidator;
+
+    /**
+     * Whether we check for a valid MX record via DNS
+     *
+     * @var boolean
+     */
+    protected $_validateMx = false;
+
+    /**
+     * @var string
+     */
+    protected $_hostname;
+
+    /**
+     * @var string
+     */
+    protected $_localPart;
+
+    /**
+     * Instantiates hostname validator for local use
+     *
+     * You can pass a bitfield to determine what types of hostnames are allowed.
+     * These bitfields are defined by the ALLOW_* constants in Zend_Validate_Hostname
+     * The default is to allow DNS hostnames only
+     *
+     * @param integer                $allow             OPTIONAL
+     * @param bool                   $validateMx        OPTIONAL
+     * @param Zend_Validate_Hostname $hostnameValidator OPTIONAL
+     * @return void
+     */
+    public function __construct($allow = Zend_Validate_Hostname::ALLOW_DNS, $validateMx = false, Zend_Validate_Hostname $hostnameValidator = null)
+    {
+        $this->setValidateMx($validateMx);
+        $this->setHostnameValidator($hostnameValidator, $allow);
+    }
+
+    /**
+     * @param Zend_Validate_Hostname $hostnameValidator OPTIONAL
+     * @param int                    $allow             OPTIONAL
+     * @return void
+     */
+    public function setHostnameValidator(Zend_Validate_Hostname $hostnameValidator = null, $allow = Zend_Validate_Hostname::ALLOW_DNS)
+    {
+        if ($hostnameValidator === null) {
+            $hostnameValidator = new Zend_Validate_Hostname($allow);
+        }
+        $this->hostnameValidator = $hostnameValidator;
+    }
+
+    /**
+     * Whether MX checking via dns_get_mx is supported or not
+     *
+     * This currently only works on UNIX systems
+     *
+     * @return boolean
+     */
+    public function validateMxSupported()
+    {
+        return function_exists('dns_get_mx');
+    }
+
+    /**
+     * Set whether we check for a valid MX record via DNS
+     *
+     * This only applies when DNS hostnames are validated
+     *
+     * @param boolean $allowed Set allowed to true to validate for MX records, and false to not validate them
+     */
+    public function setValidateMx($allowed)
+    {
+        $this->_validateMx = (bool) $allowed;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is a valid email address
+     * according to RFC2822
+     *
+     * @link   http://www.ietf.org/rfc/rfc2822.txt RFC2822
+     * @link   http://www.columbia.edu/kermit/ascii.html US-ASCII characters
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+        $matches     = array();
+        $length      = true;
+
+        $this->_setValue($valueString);
+
+        // Split email address up and disallow '..'
+        if ((strpos($valueString, '..') !== false) or
+            (!preg_match('/^(.+)@([^@]+)$/', $valueString, $matches))) {
+            $this->_error(self::INVALID);
+            return false;
+        }
+
+        $this->_localPart = $matches[1];
+        $this->_hostname  = $matches[2];
+
+        if ((strlen($this->_localPart) > 64) || (strlen($this->_hostname) > 255)) {
+            $length = false;
+            $this->_error(self::LENGTH_EXCEEDED);
+        }
+
+        // Match hostname part
+        $hostnameResult = $this->hostnameValidator->setTranslator($this->getTranslator())
+                               ->isValid($this->_hostname);
+        if (!$hostnameResult) {
+            $this->_error(self::INVALID_HOSTNAME);
+
+            // Get messages and errors from hostnameValidator
+            foreach ($this->hostnameValidator->getMessages() as $code => $message) {
+                $this->_messages[$code] = $message;
+            }
+            foreach ($this->hostnameValidator->getErrors() as $error) {
+                $this->_errors[] = $error;
+            }
+        } else if ($this->_validateMx) {
+            // MX check on hostname via dns_get_record()
+            if ($this->validateMxSupported()) {
+                $result = dns_get_mx($this->_hostname, $mxHosts);
+                if (count($mxHosts) < 1) {
+                    $hostnameResult = false;
+                    $this->_error(self::INVALID_MX_RECORD);
+                }
+            } else {
+                /**
+                 * MX checks are not supported by this system
+                 * @see Zend_Validate_Exception
+                 */
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception('Internal error: MX checking not available on this system');
+            }
+        }
+
+        // First try to match the local part on the common dot-atom format
+        $localResult = false;
+
+        // Dot-atom characters are: 1*atext *("." 1*atext)
+        // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*",
+        //        "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~"
+        $atext = 'a-zA-Z0-9\x21\x23\x24\x25\x26\x27\x2a\x2b\x2d\x2f\x3d\x3f\x5e\x5f\x60\x7b\x7c\x7d';
+        if (preg_match('/^[' . $atext . ']+(\x2e+[' . $atext . ']+)*$/', $this->_localPart)) {
+            $localResult = true;
+        } else {
+            // Try quoted string format
+
+            // Quoted-string characters are: DQUOTE *([FWS] qtext/quoted-pair) [FWS] DQUOTE
+            // qtext: Non white space controls, and the rest of the US-ASCII characters not
+            //   including "\" or the quote character
+            $noWsCtl    = '\x01-\x08\x0b\x0c\x0e-\x1f\x7f';
+            $qtext      = $noWsCtl . '\x21\x23-\x5b\x5d-\x7e';
+            $ws         = '\x20\x09';
+            if (preg_match('/^\x22([' . $ws . $qtext . '])*[$ws]?\x22$/', $this->_localPart)) {
+                $localResult = true;
+            } else {
+                $this->_error(self::DOT_ATOM);
+                $this->_error(self::QUOTED_STRING);
+                $this->_error(self::INVALID_LOCAL_PART);
+            }
+        }
+
+        // If both parts valid, return true
+        if ($localResult && $hostnameResult && $length) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/lib/Zend/Validate/Exception.php b/lib/Zend/Validate/Exception.php
new file mode 100644
index 0000000..a38077e
--- /dev/null
+++ b/lib/Zend/Validate/Exception.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Exception.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Exception
+ */
+require_once 'Zend/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Exception extends Zend_Exception
+{}
diff --git a/lib/Zend/Validate/File/Count.php b/lib/Zend/Validate/File/Count.php
new file mode 100644
index 0000000..97667ab
--- /dev/null
+++ b/lib/Zend/Validate/File/Count.php
@@ -0,0 +1,275 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator for counting all given files
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Count extends Zend_Validate_Abstract
+{
+    /**#@+
+     * @const string Error constants
+     */
+    const TOO_MUCH = 'fileCountTooMuch';
+    const TOO_LESS = 'fileCountTooLess';
+    /**#@-*/
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::TOO_MUCH => "Too much files, maximum '%max%' are allowed but '%count%' are given",
+        self::TOO_LESS => "Too less files, minimum '%min%' are expected but '%count%' are given"
+    );
+
+    /**
+     * @var array Error message template variables
+     */
+    protected $_messageVariables = array(
+        'min'   => '_min',
+        'max'   => '_max',
+        'count' => '_count'
+    );
+
+    /**
+     * Minimum file count
+     *
+     * If null, there is no minimum file count
+     *
+     * @var integer
+     */
+    protected $_min;
+
+    /**
+     * Maximum file count
+     *
+     * If null, there is no maximum file count
+     *
+     * @var integer|null
+     */
+    protected $_max;
+
+    /**
+     * Actual filecount
+     *
+     * @var integer
+     */
+    protected $_count;
+
+    /**
+     * Internal file array
+     * @var array
+     */
+    protected $_files;
+
+    /**
+     * Sets validator options
+     *
+     * Min limits the file count, when used with max=null it is the maximum file count
+     * It also accepts an array with the keys 'min' and 'max'
+     *
+     * If $options is a integer, it will be used as maximum file count
+     * As Array is accepts the following keys:
+     * 'min': Minimum filecount
+     * 'max': Maximum filecount
+     *
+     * @param  integer|array $options Options for the adapter
+     * @param  integer $max (Deprecated) Maximum value (implies $options is the minimum)
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (is_string($options) || is_numeric($options)) {
+            $options = array('max' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        if (1 < func_num_args()) {
+            trigger_error('Multiple arguments are deprecated in favor of an array of named arguments', E_USER_NOTICE);
+            $options['min'] = func_get_arg(0);
+            $options['max'] = func_get_arg(1);
+        }
+
+        if (isset($options['min'])) {
+            $this->setMin($options);
+        }
+
+        if (isset($options['max'])) {
+            $this->setMax($options);
+        }
+    }
+
+    /**
+     * Returns the minimum file count
+     *
+     * @return integer
+     */
+    public function getMin()
+    {
+        return $this->_min;
+    }
+
+    /**
+     * Sets the minimum file count
+     *
+     * @param  integer|array $min The minimum file count
+     * @return Zend_Validate_File_Count Provides a fluent interface
+     * @throws Zend_Validate_Exception When min is greater than max
+     */
+    public function setMin($min)
+    {
+        if (is_array($min) and isset($min['min'])) {
+            $min = $min['min'];
+        }
+
+        if (!is_string($min) and !is_numeric($min)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        $min = (integer) $min;
+        if (($this->_max !== null) && ($min > $this->_max)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum file count, but $min >"
+                                            . " {$this->_max}");
+        }
+
+        $this->_min = $min;
+        return $this;
+    }
+
+    /**
+     * Returns the maximum file count
+     *
+     * @return integer
+     */
+    public function getMax()
+    {
+        return $this->_max;
+    }
+
+    /**
+     * Sets the maximum file count
+     *
+     * @param  integer|array $max The maximum file count
+     * @return Zend_Validate_StringLength Provides a fluent interface
+     * @throws Zend_Validate_Exception When max is smaller than min
+     */
+    public function setMax($max)
+    {
+        if (is_array($max) and isset($max['max'])) {
+            $max = $max['max'];
+        }
+
+        if (!is_string($max) and !is_numeric($max)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        $max = (integer) $max;
+        if (($this->_min !== null) && ($max < $this->_min)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum file count, but "
+                                            . "$max < {$this->_min}");
+        }
+
+        $this->_max = $max;
+        return $this;
+    }
+
+    /**
+     * Adds a file for validation
+     *
+     * @param string|array $file
+     */
+    public function addFile($file)
+    {
+        if (is_string($file)) {
+            $file = array($file);
+        }
+
+        if (is_array($file)) {
+            foreach ($file as $name) {
+                if (!isset($this->_files[$name])) {
+                    $this->_files[$name] = $name;
+                }
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the file count of all checked files is at least min and
+     * not bigger than max (when max is not null). Attention: When checking with set min you
+     * must give all files with the first call, otherwise you will get an false.
+     *
+     * @param  string|array $value Filenames to check for count
+     * @param  array        $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        $this->addFile($value);
+        $this->_count = count($this->_files);
+        if (($this->_max !== null) && ($this->_count > $this->_max)) {
+            return $this->_throw($file, self::TOO_MUCH);
+        }
+
+        if (($this->_min !== null) && ($this->_count < $this->_min)) {
+            return $this->_throw($file, self::TOO_LESS);
+        }
+
+        return true;
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if ($file !== null) {
+            $this->_value = $file['name'];
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/File/Crc32.php b/lib/Zend/Validate/File/Crc32.php
new file mode 100644
index 0000000..47ace9d
--- /dev/null
+++ b/lib/Zend/Validate/File/Crc32.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_Hash
+ */
+require_once 'Zend/Validate/File/Hash.php';
+
+/**
+ * Validator for the crc32 hash of given files
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Crc32 extends Zend_Validate_File_Hash
+{
+    /**
+     * @const string Error constants
+     */
+    const DOES_NOT_MATCH = 'fileCrc32DoesNotMatch';
+    const NOT_DETECTED   = 'fileCrc32NotDetected';
+    const NOT_FOUND      = 'fileCrc32NotFound';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::DOES_NOT_MATCH => "The file '%value%' does not match the given crc32 hashes",
+        self::NOT_DETECTED   => "There was no crc32 hash detected for the given file",
+        self::NOT_FOUND      => "The file '%value%' could not be found"
+    );
+
+    /**
+     * Hash of the file
+     *
+     * @var string
+     */
+    protected $_hash;
+
+    /**
+     * Sets validator options
+     *
+     * @param  string|array $options
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (is_scalar($options)) {
+            $options = array('hash1' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('Invalid options to validator provided');
+        }
+
+        $this->setCrc32($options);
+    }
+
+    /**
+     * Returns all set crc32 hashes
+     *
+     * @return array
+     */
+    public function getCrc32()
+    {
+        return $this->getHash();
+    }
+
+    /**
+     * Sets the crc32 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function setHash($options)
+    {
+        if (!is_array($options)) {
+            $options = array($options);
+        }
+
+        $options['algorithm'] = 'crc32';
+        parent::setHash($options);
+        return $this;
+    }
+
+    /**
+     * Sets the crc32 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function setCrc32($options)
+    {
+        $this->setHash($options);
+        return $this;
+    }
+
+    /**
+     * Adds the crc32 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function addHash($options)
+    {
+        if (!is_array($options)) {
+            $options = array($options);
+        }
+
+        $options['algorithm'] = 'crc32';
+        parent::addHash($options);
+        return $this;
+    }
+
+    /**
+     * Adds the crc32 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function addCrc32($options)
+    {
+        $this->addHash($options);
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the given file confirms the set hash
+     *
+     * @param  string $value Filename to check for hash
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_FOUND);
+        }
+
+        $hashes = array_unique(array_keys($this->_hash));
+        $filehash = hash_file('crc32', $value);
+        if ($filehash === false) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        foreach($hashes as $hash) {
+            if ($filehash === $hash) {
+                return true;
+            }
+        }
+
+        return $this->_throw($file, self::DOES_NOT_MATCH);
+    }
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/File/ExcludeExtension.php b/lib/Zend/Validate/File/ExcludeExtension.php
new file mode 100644
index 0000000..2a442ab
--- /dev/null
+++ b/lib/Zend/Validate/File/ExcludeExtension.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/File/Extension.php';
+
+/**
+ * Validator for the excluding file extensions
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_ExcludeExtension extends Zend_Validate_File_Extension
+{
+    /**
+     * @const string Error constants
+     */
+    const FALSE_EXTENSION = 'fileExcludeExtensionFalse';
+    const NOT_FOUND       = 'fileExcludeExtensionNotFound';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::FALSE_EXTENSION => "The file '%value%' has a false extension",
+        self::NOT_FOUND       => "The file '%value%' was not found"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the fileextension of $value is not included in the
+     * set extension list
+     *
+     * @param  string  $value Real file to check for extension
+     * @param  array   $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_FOUND);
+        }
+
+        if ($file !== null) {
+            $info['extension'] = substr($file['name'], strrpos($file['name'], '.') + 1);
+        } else {
+            $info = pathinfo($value);
+        }
+
+        $extensions = $this->getExtension();
+
+        if ($this->_case and (!in_array($info['extension'], $extensions))) {
+            return true;
+        } else if (!$this->_case) {
+            $found = false;
+            foreach ($extensions as $extension) {
+                if (strtolower($extension) == strtolower($info['extension'])) {
+                    $found = true;
+                }
+            }
+
+            if (!$found) {
+                return true;
+            }
+        }
+
+        return $this->_throw($file, self::FALSE_EXTENSION);
+    }
+}
diff --git a/lib/Zend/Validate/File/ExcludeMimeType.php b/lib/Zend/Validate/File/ExcludeMimeType.php
new file mode 100644
index 0000000..d69dc06
--- /dev/null
+++ b/lib/Zend/Validate/File/ExcludeMimeType.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_MimeType
+ */
+require_once 'Zend/Validate/File/MimeType.php';
+
+/**
+ * Validator for the mime type of a file
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_ExcludeMimeType extends Zend_Validate_File_MimeType
+{
+    const FALSE_TYPE   = 'fileExcludeMimeTypeFalse';
+    const NOT_DETECTED = 'fileExcludeMimeTypeNotDetected';
+    const NOT_READABLE = 'fileExcludeMimeTypeNotReadable';
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if the mimetype of the file does not matche the given ones. Also parts
+     * of mimetypes can be checked. If you give for example "image" all image
+     * mime types will not be accepted like "image/gif", "image/jpeg" and so on.
+     *
+     * @param  string $value Real file to check for mimetype
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_READABLE);
+        }
+
+        if ($file !== null) {
+            if (class_exists('finfo', false) && defined('MAGIC')) {
+                $mime = new finfo(FILEINFO_MIME);
+                $this->_type = $mime->file($value);
+                unset($mime);
+            } elseif (function_exists('mime_content_type') && ini_get('mime_magic.magicfile')) {
+                $this->_type = mime_content_type($value);
+            } else {
+                $this->_type = $file['type'];
+            }
+        }
+
+        if (empty($this->_type)) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        $mimetype = $this->getMimeType(true);
+        if (in_array($this->_type, $mimetype)) {
+            return $this->_throw($file, self::FALSE_TYPE);
+        }
+
+        $types = explode('/', $this->_type);
+        $types = array_merge($types, explode('-', $this->_type));
+        foreach($mimetype as $mime) {
+            if (in_array($mime, $types)) {
+                return $this->_throw($file, self::FALSE_TYPE);
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/lib/Zend/Validate/File/Exists.php b/lib/Zend/Validate/File/Exists.php
new file mode 100644
index 0000000..cf509aa
--- /dev/null
+++ b/lib/Zend/Validate/File/Exists.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator which checks if the file already exists in the directory
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Exists extends Zend_Validate_Abstract
+{
+    /**
+     * @const string Error constants
+     */
+    const DOES_NOT_EXIST = 'fileExistsDoesNotExist';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::DOES_NOT_EXIST => "The file '%value%' does not exist"
+    );
+
+    /**
+     * Internal list of directories
+     * @var string
+     */
+    protected $_directory = '';
+
+    /**
+     * @var array Error message template variables
+     */
+    protected $_messageVariables = array(
+        'directory' => '_directory'
+    );
+
+    /**
+     * Sets validator options
+     *
+     * @param  string|array $directory
+     * @return void
+     */
+    public function __construct($directory = array())
+    {
+        if ($directory instanceof Zend_Config) {
+            $directory = $directory->toArray();
+        } else if (is_string($directory)) {
+            $directory = explode(',', $directory);
+        } else if (!is_array($directory)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        $this->setDirectory($directory);
+    }
+
+    /**
+     * Returns the set file directories which are checked
+     *
+     * @param  boolean $asArray Returns the values as array, when false an concated string is returned
+     * @return string
+     */
+    public function getDirectory($asArray = false)
+    {
+        $asArray   = (bool) $asArray;
+        $directory = (string) $this->_directory;
+        if ($asArray) {
+            $directory = explode(',', $directory);
+        }
+
+        return $directory;
+    }
+
+    /**
+     * Sets the file directory which will be checked
+     *
+     * @param  string|array $directory The directories to validate
+     * @return Zend_Validate_File_Extension Provides a fluent interface
+     */
+    public function setDirectory($directory)
+    {
+        $this->_directory = null;
+        $this->addDirectory($directory);
+        return $this;
+    }
+
+    /**
+     * Adds the file directory which will be checked
+     *
+     * @param  string|array $directory The directory to add for validation
+     * @return Zend_Validate_File_Extension Provides a fluent interface
+     */
+    public function addDirectory($directory)
+    {
+        $directories = $this->getDirectory(true);
+
+        if (is_string($directory)) {
+            $directory = explode(',', $directory);
+        } else if (!is_array($directory)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        foreach ($directory as $content) {
+            if (empty($content) || !is_string($content)) {
+                continue;
+            }
+
+            $directories[] = trim($content);
+        }
+        $directories = array_unique($directories);
+
+        // Sanity check to ensure no empty values
+        foreach ($directories as $key => $dir) {
+            if (empty($dir)) {
+                unset($directories[$key]);
+            }
+        }
+
+        $this->_directory = implode(',', $directories);
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the file already exists in the set directories
+     *
+     * @param  string  $value Real file to check for existance
+     * @param  array   $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        $directories = $this->getDirectory(true);
+        if (($file !== null) and (!empty($file['destination']))) {
+            $directories[] = $file['destination'];
+        } else if (!isset($file['name'])) {
+            $file['name'] = $value;
+        }
+
+        $check = false;
+        foreach ($directories as $directory) {
+            if (empty($directory)) {
+                continue;
+            }
+
+            $check = true;
+            if (!file_exists($directory . DIRECTORY_SEPARATOR . $file['name'])) {
+                return $this->_throw($file, self::DOES_NOT_EXIST);
+            }
+        }
+
+        if (!$check) {
+            return $this->_throw($file, self::DOES_NOT_EXIST);
+        }
+
+        return true;
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if ($file !== null) {
+            $this->_value = $file['name'];
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/File/Extension.php b/lib/Zend/Validate/File/Extension.php
new file mode 100644
index 0000000..49411b3
--- /dev/null
+++ b/lib/Zend/Validate/File/Extension.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator for the file extension of a file
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Extension extends Zend_Validate_Abstract
+{
+    /**
+     * @const string Error constants
+     */
+    const FALSE_EXTENSION = 'fileExtensionFalse';
+    const NOT_FOUND       = 'fileExtensionNotFound';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::FALSE_EXTENSION => "The file '%value%' has a false extension",
+        self::NOT_FOUND       => "The file '%value%' was not found"
+    );
+
+    /**
+     * Internal list of extensions
+     * @var string
+     */
+    protected $_extension = '';
+
+    /**
+     * Validate case sensitive
+     *
+     * @var boolean
+     */
+    protected $_case = false;
+
+    /**
+     * @var array Error message template variables
+     */
+    protected $_messageVariables = array(
+        'extension' => '_extension'
+    );
+
+    /**
+     * Sets validator options
+     *
+     * @param  string|array $extension
+     * @param  boolean      $case      If true validation is done case sensitive
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        }
+
+        if (1 < func_num_args()) {
+            trigger_error('Multiple arguments to constructor are deprecated in favor of options array', E_USER_NOTICE);
+            $case = func_get_arg(1);
+            $this->setCase($case);
+        }
+
+        if (is_array($options) and isset($options['case'])) {
+            $this->setCase($options['case']);
+            unset($options['case']);
+        }
+
+        $this->setExtension($options);
+    }
+
+    /**
+     * Returns the case option
+     *
+     * @return boolean
+     */
+    public function getCase()
+    {
+        return $this->_case;
+    }
+
+    /**
+     * Sets the case to use
+     *
+     * @param  boolean $case
+     * @return Zend_Validate_File_Extension Provides a fluent interface
+     */
+    public function setCase($case)
+    {
+        $this->_case = (boolean) $case;
+        return $this;
+    }
+
+    /**
+     * Returns the set file extension
+     *
+     * @return array
+     */
+    public function getExtension()
+    {
+        $extension = explode(',', $this->_extension);
+
+        return $extension;
+    }
+
+    /**
+     * Sets the file extensions
+     *
+     * @param  string|array $extension The extensions to validate
+     * @return Zend_Validate_File_Extension Provides a fluent interface
+     */
+    public function setExtension($extension)
+    {
+        $this->_extension = null;
+        $this->addExtension($extension);
+        return $this;
+    }
+
+    /**
+     * Adds the file extensions
+     *
+     * @param  string|array $extension The extensions to add for validation
+     * @return Zend_Validate_File_Extension Provides a fluent interface
+     */
+    public function addExtension($extension)
+    {
+        $extensions = $this->getExtension();
+        if (is_string($extension)) {
+            $extension = explode(',', $extension);
+        }
+
+        foreach ($extension as $content) {
+            if (empty($content) || !is_string($content)) {
+                continue;
+            }
+
+            $extensions[] = trim($content);
+        }
+        $extensions = array_unique($extensions);
+
+        // Sanity check to ensure no empty values
+        foreach ($extensions as $key => $ext) {
+            if (empty($ext)) {
+                unset($extensions[$key]);
+            }
+        }
+
+        $this->_extension = implode(',', $extensions);
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the fileextension of $value is included in the
+     * set extension list
+     *
+     * @param  string  $value Real file to check for extension
+     * @param  array   $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_FOUND);
+        }
+
+        if ($file !== null) {
+            $info['extension'] = substr($file['name'], strrpos($file['name'], '.') + 1);
+        } else {
+            $info = pathinfo($value);
+        }
+
+        $extensions = $this->getExtension();
+
+        if ($this->_case && (in_array($info['extension'], $extensions))) {
+            return true;
+        } else if (!$this->getCase()) {
+            foreach ($extensions as $extension) {
+                if (strtolower($extension) == strtolower($info['extension'])) {
+                    return true;
+                }
+            }
+        }
+
+        return $this->_throw($file, self::FALSE_EXTENSION);
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if (null !== $file) {
+            $this->_value = $file['name'];
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/File/FilesSize.php b/lib/Zend/Validate/File/FilesSize.php
new file mode 100644
index 0000000..ea8d085
--- /dev/null
+++ b/lib/Zend/Validate/File/FilesSize.php
@@ -0,0 +1,163 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_Size
+ */
+require_once 'Zend/Validate/File/Size.php';
+
+/**
+ * Validator for the size of all files which will be validated in sum
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_FilesSize extends Zend_Validate_File_Size
+{
+    /**
+     * @const string Error constants
+     */
+    const TOO_BIG      = 'fileFilesSizeTooBig';
+    const TOO_SMALL    = 'fileFilesSizeTooSmall';
+    const NOT_READABLE = 'fileFilesSizeNotReadable';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::TOO_BIG      => "All files in sum should have a maximum size of '%max%' but '%size%' were detected",
+        self::TOO_SMALL    => "All files in sum should have a minimum size of '%min%' but '%size%' were detected",
+        self::NOT_READABLE => "One or more files can not be read"
+    );
+
+    /**
+     * Internal file array
+     *
+     * @var array
+     */
+    protected $_files;
+
+    /**
+     * Sets validator options
+     *
+     * Min limits the used diskspace for all files, when used with max=null it is the maximum filesize
+     * It also accepts an array with the keys 'min' and 'max'
+     *
+     * @param  integer|array $min        Minimum diskspace for all files
+     * @param  integer       $max        Maximum diskspace for all files (deprecated)
+     * @param  boolean       $bytestring Use bytestring or real size ? (deprecated)
+     * @return void
+     */
+    public function __construct($options)
+    {
+        $this->_files = array();
+        $this->_setSize(0);
+
+        if (1 < func_num_args()) {
+            trigger_error('Multiple constructor options are deprecated in favor of a single options array', E_USER_NOTICE);
+            if ($options instanceof Zend_Config) {
+                $options = $options->toArray();
+            } elseif (is_scalar($options)) {
+                $options = array('min' => $options);
+            } elseif (!is_array($options)) {
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception('Invalid options to validator provided');
+            }
+
+            $argv = func_get_args();
+            array_shift($argv);
+            $options['max'] = array_shift($argv);
+            if (!empty($argv)) {
+                $options['bytestring'] = array_shift($argv);
+            }
+        }
+
+        parent::__construct($options);
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the disk usage of all files is at least min and
+     * not bigger than max (when max is not null).
+     *
+     * @param  string|array $value Real file to check for size
+     * @param  array        $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        require_once 'Zend/Loader.php';
+        if (is_string($value)) {
+            $value = array($value);
+        }
+
+        $min  = $this->getMin(true);
+        $max  = $this->getMax(true);
+        $size = $this->_getSize();
+        foreach ($value as $files) {
+            // Is file readable ?
+            if (!Zend_Loader::isReadable($files)) {
+                $this->_throw($file, self::NOT_READABLE);
+                continue;
+            }
+
+            if (!isset($this->_files[$files])) {
+                $this->_files[$files] = $files;
+            } else {
+                // file already counted... do not count twice
+                continue;
+            }
+
+            // limited to 2GB files
+            $size += @filesize($files);
+            $this->_setSize($size);
+            if (($max !== null) && ($max < $size)) {
+                if ($this->useByteString()) {
+                    $this->setMax($this->_toByteString($max));
+                    $this->_throw($file, self::TOO_BIG);
+                    $this->setMax($max);
+                } else {
+                    $this->_throw($file, self::TOO_BIG);
+                }
+            }
+        }
+
+        // Check that aggregate files are >= minimum size
+        if (($min !== null) && ($size < $min)) {
+            if ($this->useByteString()) {
+                $this->setMin($this->_toByteString($min));
+                $this->_throw($file, self::TOO_SMALL);
+                $this->setMin($min);
+            } else {
+                $this->_throw($file, self::TOO_SMALL);
+            }
+        }
+
+        if (count($this->_messages) > 0) {
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/lib/Zend/Validate/File/Hash.php b/lib/Zend/Validate/File/Hash.php
new file mode 100644
index 0000000..1702593
--- /dev/null
+++ b/lib/Zend/Validate/File/Hash.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator for the hash of given files
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Hash extends Zend_Validate_Abstract
+{
+    /**
+     * @const string Error constants
+     */
+    const DOES_NOT_MATCH = 'fileHashDoesNotMatch';
+    const NOT_DETECTED   = 'fileHashHashNotDetected';
+    const NOT_FOUND      = 'fileHashNotFound';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::DOES_NOT_MATCH => "The file '%value%' does not match the given hashes",
+        self::NOT_DETECTED   => "There was no hash detected for the given file",
+        self::NOT_FOUND      => "The file '%value%' could not be found"
+    );
+
+    /**
+     * Hash of the file
+     *
+     * @var string
+     */
+    protected $_hash;
+
+    /**
+     * Sets validator options
+     *
+     * @param  string|array $options
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (is_scalar($options)) {
+            $options = array('hash1' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('Invalid options to validator provided');
+        }
+
+        if (1 < func_num_args()) {
+            trigger_error('Multiple constructor options are deprecated in favor of a single options array', E_USER_NOTICE);
+            $options['algorithm'] = func_get_arg(1);
+        }
+
+        $this->setHash($options);
+    }
+
+    /**
+     * Returns the set hash values as array, the hash as key and the algorithm the value
+     *
+     * @return array
+     */
+    public function getHash()
+    {
+        return $this->_hash;
+    }
+
+    /**
+     * Sets the hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function setHash($options)
+    {
+        $this->_hash  = null;
+        $this->addHash($options);
+
+        return $this;
+    }
+
+    /**
+     * Adds the hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function addHash($options)
+    {
+        if (is_string($options)) {
+            $options = array($options);
+        } else if (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("False parameter given");
+        }
+
+        $known = hash_algos();
+        if (!isset($options['algorithm'])) {
+            $algorithm = 'crc32';
+        } else {
+            $algorithm = $options['algorithm'];
+            unset($options['algorithm']);
+        }
+
+        if (!in_array($algorithm, $known)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("Unknown algorithm '{$algorithm}'");
+        }
+
+        foreach ($options as $value) {
+            $this->_hash[$value] = $algorithm;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the given file confirms the set hash
+     *
+     * @param  string $value Filename to check for hash
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_FOUND);
+        }
+
+        $algos  = array_unique(array_values($this->_hash));
+        $hashes = array_unique(array_keys($this->_hash));
+        foreach ($algos as $algorithm) {
+            $filehash = hash_file($algorithm, $value);
+            if ($filehash === false) {
+                return $this->_throw($file, self::NOT_DETECTED);
+            }
+
+            foreach($hashes as $hash) {
+                if ($filehash === $hash) {
+                    return true;
+                }
+            }
+        }
+
+        return $this->_throw($file, self::DOES_NOT_MATCH);
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if ($file !== null) {
+            $this->_value = $file['name'];
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/File/ImageSize.php b/lib/Zend/Validate/File/ImageSize.php
new file mode 100644
index 0000000..ada8bd3
--- /dev/null
+++ b/lib/Zend/Validate/File/ImageSize.php
@@ -0,0 +1,370 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator for the image size of a image file
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_ImageSize extends Zend_Validate_Abstract
+{
+    /**
+     * @const string Error constants
+     */
+    const WIDTH_TOO_BIG    = 'fileImageSizeWidthTooBig';
+    const WIDTH_TOO_SMALL  = 'fileImageSizeWidthTooSmall';
+    const HEIGHT_TOO_BIG   = 'fileImageSizeHeightTooBig';
+    const HEIGHT_TOO_SMALL = 'fileImageSizeHeightTooSmall';
+    const NOT_DETECTED     = 'fileImageSizeNotDetected';
+    const NOT_READABLE     = 'fileImageSizeNotReadable';
+
+    /**
+     * @var array Error message template
+     */
+    protected $_messageTemplates = array(
+        self::WIDTH_TOO_BIG    => "Maximum allowed width for image '%value%' should be '%maxwidth%' but '%width%' detected",
+        self::WIDTH_TOO_SMALL  => "Minimum expected width for image '%value%' should be '%minwidth%' but '%width%' detected",
+        self::HEIGHT_TOO_BIG   => "Maximum allowed height for image '%value%' should be '%maxheight%' but '%height%' detected",
+        self::HEIGHT_TOO_SMALL => "Minimum expected height for image '%value%' should be '%minheight%' but '%height%' detected",
+        self::NOT_DETECTED     => "The size of image '%value%' could not be detected",
+        self::NOT_READABLE     => "The image '%value%' can not be read"
+    );
+
+    /**
+     * @var array Error message template variables
+     */
+    protected $_messageVariables = array(
+        'minwidth'  => '_minwidth',
+        'maxwidth'  => '_maxwidth',
+        'minheight' => '_minheight',
+        'maxheight' => '_maxheight',
+        'width'     => '_width',
+        'height'    => '_height'
+    );
+
+    /**
+     * Minimum image width
+     *
+     * @var integer
+     */
+    protected $_minwidth;
+
+    /**
+     * Maximum image width
+     *
+     * @var integer
+     */
+    protected $_maxwidth;
+
+    /**
+     * Minimum image height
+     *
+     * @var integer
+     */
+    protected $_minheight;
+
+    /**
+     * Maximum image height
+     *
+     * @var integer
+     */
+    protected $_maxheight;
+
+    /**
+     * Detected width
+     *
+     * @var integer
+     */
+    protected $_width;
+
+    /**
+     * Detected height
+     *
+     * @var integer
+     */
+    protected $_height;
+
+    /**
+     * Sets validator options
+     *
+     * Accepts the following option keys:
+     * - minheight
+     * - minwidth
+     * - maxheight
+     * - maxwidth
+     *
+     * @param  Zend_Config|array $options
+     * @return void
+     */
+    public function __construct($options)
+    {
+        $minwidth  = 0;
+        $minheight = 0;
+        $maxwidth  = null;
+        $maxheight = null;
+
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (1 < func_num_args()) {
+            trigger_error('Multiple constructor options are deprecated in favor of a single options array', E_USER_NOTICE);
+            if (!is_array($options)) {
+                $options = array('minwidth' => $options);
+            }
+            $argv = func_get_args();
+            array_shift($argv);
+            $options['minheight'] = array_shift($argv);
+            if (!empty($argv)) {
+                $options['maxwidth'] = array_shift($argv);
+                if (!empty($argv)) {
+                    $options['maxheight'] = array_shift($argv);
+                }
+            }
+        } else if (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        if (isset($options['minheight']) || isset($options['minwidth'])) {
+            $this->setImageMin($options);
+        }
+
+        if (isset($options['maxheight']) || isset($options['maxwidth'])) {
+            $this->setImageMax($options);
+        }
+    }
+
+    /**
+     * Returns the set minimum image sizes
+     *
+     * @return array
+     */
+    public function getImageMin()
+    {
+        return array('minwidth' => $this->_minwidth, 'minheight' => $this->_minheight);
+    }
+
+    /**
+     * Returns the set maximum image sizes
+     *
+     * @return array
+     */
+    public function getImageMax()
+    {
+        return array('maxwidth' => $this->_maxwidth, 'maxheight' => $this->_maxheight);
+    }
+
+    /**
+     * Returns the set image width sizes
+     *
+     * @return array
+     */
+    public function getImageWidth()
+    {
+        return array('minwidth' => $this->_minwidth, 'maxwidth' => $this->_maxwidth);
+    }
+
+    /**
+     * Returns the set image height sizes
+     *
+     * @return array
+     */
+    public function getImageHeight()
+    {
+        return array('minheight' => $this->_minheight, 'maxheight' => $this->_maxheight);
+    }
+
+    /**
+     * Sets the minimum image size
+     *
+     * @param  array $options               The minimum image dimensions
+     * @throws Zend_Validate_Exception      When minwidth is greater than maxwidth
+     * @throws Zend_Validate_Exception      When minheight is greater than maxheight
+     * @return Zend_Validate_File_ImageSize Provides a fluent interface
+     */
+    public function setImageMin($options)
+    {
+        if (isset($options['minwidth'])) {
+            if (($this->_maxwidth !== null) and ($options['minwidth'] > $this->_maxwidth)) {
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception("The minimum image width must be less than or equal to the "
+                    . " maximum image width, but {$options['minwidth']} > {$this->_maxwidth}");
+            }
+        }
+
+        if (isset($options['maxheight'])) {
+            if (($this->_maxheight !== null) and ($options['minheight'] > $this->_maxheight)) {
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception("The minimum image height must be less than or equal to the "
+                    . " maximum image height, but {$options['minheight']} > {$this->_maxheight}");
+            }
+        }
+
+        if (isset($options['minwidth'])) {
+            $this->_minwidth  = (int) $options['minwidth'];
+        }
+
+        if (isset($options['minheight'])) {
+            $this->_minheight = (int) $options['minheight'];
+        }
+
+        return $this;
+    }
+
+    /**
+     * Sets the maximum image size
+     *
+     * @param  array $options          The maximum image dimensions
+     * @throws Zend_Validate_Exception When maxwidth is smaller than minwidth
+     * @throws Zend_Validate_Exception When maxheight is smaller than minheight
+     * @return Zend_Validate_StringLength Provides a fluent interface
+     */
+    public function setImageMax($options)
+    {
+        if (isset($options['maxwidth'])) {
+            if (($this->_minwidth !== null) and ($options['maxwidth'] < $this->_minwidth)) {
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception("The maximum image width must be greater than or equal to the "
+                    . "minimum image width, but {$options['maxwidth']} < {$this->_minwidth}");
+            }
+        }
+
+        if (isset($options['maxheight'])) {
+            if (($this->_minheight !== null) and ($options['maxheight'] < $this->_minheight)) {
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception("The maximum image height must be greater than or equal to the "
+                    . "minimum image height, but {$options['maxheight']} < {$this->_minwidth}");
+            }
+        }
+
+        if (isset($options['maxwidth'])) {
+            $this->_maxwidth  = (int) $options['maxwidth'];
+        }
+
+        if (isset($options['maxheight'])) {
+            $this->_maxheight = (int) $options['maxheight'];
+        }
+
+        return $this;
+    }
+
+    /**
+     * Sets the mimimum and maximum image width
+     *
+     * @param  array $options               The image width dimensions
+     * @return Zend_Validate_File_ImageSize Provides a fluent interface
+     */
+    public function setImageWidth($options)
+    {
+        $this->setImageMin($options);
+        $this->setImageMax($options);
+
+        return $this;
+    }
+
+    /**
+     * Sets the mimimum and maximum image height
+     *
+     * @param  array $options               The image height dimensions
+     * @return Zend_Validate_File_ImageSize Provides a fluent interface
+     */
+    public function setImageHeight($options)
+    {
+        $this->setImageMin($options);
+        $this->setImageMax($options);
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the imagesize of $value is at least min and
+     * not bigger than max
+     *
+     * @param  string $value Real file to check for image size
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_READABLE);
+        }
+
+        $size = @getimagesize($value);
+        $this->_setValue($file);
+
+        if (empty($size) or ($size[0] === 0) or ($size[1] === 0)) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        $this->_width  = $size[0];
+        $this->_height = $size[1];
+        if ($this->_width < $this->_minwidth) {
+            $this->_throw($file, self::WIDTH_TOO_SMALL);
+        }
+
+        if (($this->_maxwidth !== null) and ($this->_maxwidth < $this->_width)) {
+            $this->_throw($file, self::WIDTH_TOO_BIG);
+        }
+
+        if ($this->_height < $this->_minheight) {
+            $this->_throw($file, self::HEIGHT_TOO_SMALL);
+        }
+
+        if (($this->_maxheight !== null) and ($this->_maxheight < $this->_height)) {
+            $this->_throw($file, self::HEIGHT_TOO_BIG);
+        }
+
+        if (count($this->_messages) > 0) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if ($file !== null) {
+            $this->_value = $file['name'];
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/File/IsCompressed.php b/lib/Zend/Validate/File/IsCompressed.php
new file mode 100644
index 0000000..050eb1c
--- /dev/null
+++ b/lib/Zend/Validate/File/IsCompressed.php
@@ -0,0 +1,133 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_MimeType
+ */
+require_once 'Zend/Validate/File/MimeType.php';
+
+/**
+ * Validator which checks if the file already exists in the directory
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_IsCompressed extends Zend_Validate_File_MimeType
+{
+    /**
+     * @const string Error constants
+     */
+    const FALSE_TYPE   = 'fileIsCompressedFalseType';
+    const NOT_DETECTED = 'fileIsCompressedNotDetected';
+    const NOT_READABLE = 'fileIsCompressedNotReadable';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::FALSE_TYPE   => "The file '%value%' is not compressed, '%type%' detected",
+        self::NOT_DETECTED => "The mimetype of file '%value%' has not been detected",
+        self::NOT_READABLE => "The file '%value%' can not be read"
+    );
+
+    /**
+     * Sets validator options
+     *
+     * @param  string|array $compression
+     * @return void
+     */
+    public function __construct($mimetype = array())
+    {
+        if (empty($mimetype)) {
+            $mimetype = array(
+                'application/x-tar',
+                'application/x-cpio',
+                'application/x-debian-package',
+                'application/x-archive',
+                'application/x-arc',
+                'application/x-arj',
+                'application/x-lharc',
+                'application/x-lha',
+                'application/x-rar',
+                'application/zip',
+                'application/zoo',
+                'application/x-eet',
+                'application/x-java-pack200',
+                'application/x-compress',
+                'application/x-gzip',
+                'application/x-bzip2'
+            );
+        }
+
+        $this->setMimeType($mimetype);
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the file is compression with the set compression types
+     *
+     * @param  string  $value Real file to check for compression
+     * @param  array   $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_READABLE);
+        }
+
+        if ($file !== null) {
+            if (class_exists('finfo', false) && defined('MAGIC')) {
+                $mime = new finfo(FILEINFO_MIME);
+                $this->_type = $mime->file($value);
+                unset($mime);
+            } elseif (function_exists('mime_content_type') && ini_get('mime_magic.magicfile')) {
+                $this->_type = mime_content_type($value);
+            } else {
+                $this->_type = $file['type'];
+            }
+        }
+
+        if (empty($this->_type)) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        $compressions = $this->getMimeType(true);
+        if (in_array($this->_type, $compressions)) {
+            return true;
+        }
+
+        $types = explode('/', $this->_type);
+        $types = array_merge($types, explode('-', $this->_type));
+        foreach ($compressions as $mime) {
+            if (in_array($mime, $types)) {
+                return true;
+            }
+        }
+
+        return $this->_throw($file, self::FALSE_TYPE);
+    }
+}
diff --git a/lib/Zend/Validate/File/IsImage.php b/lib/Zend/Validate/File/IsImage.php
new file mode 100644
index 0000000..045c7fe
--- /dev/null
+++ b/lib/Zend/Validate/File/IsImage.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_MimeType
+ */
+require_once 'Zend/Validate/File/MimeType.php';
+
+/**
+ * Validator which checks if the file already exists in the directory
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_IsImage extends Zend_Validate_File_MimeType
+{
+    /**
+     * @const string Error constants
+     */
+    const FALSE_TYPE   = 'fileIsImageFalseType';
+    const NOT_DETECTED = 'fileIsImageNotDetected';
+    const NOT_READABLE = 'fileIsImageNotReadable';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::FALSE_TYPE   => "The file '%value%' is no image, '%type%' detected",
+        self::NOT_DETECTED => "The mimetype of file '%value%' has not been detected",
+        self::NOT_READABLE => "The file '%value%' can not be read"
+    );
+
+    /**
+     * Sets validator options
+     *
+     * @param  string|array $mimetype
+     * @return void
+     */
+    public function __construct($mimetype = array())
+    {
+        if (empty($mimetype)) {
+            $mimetype = array(
+                'image/x-quicktime',
+                'image/jp2',
+                'image/x-xpmi',
+                'image/x-portable-bitmap',
+                'image/x-portable-greymap',
+                'image/x-portable-pixmap',
+                'image/x-niff',
+                'image/tiff',
+                'image/png',
+                'image/x-unknown',
+                'image/gif',
+                'image/x-ms-bmp',
+                'application/dicom',
+                'image/vnd.adobe.photoshop',
+                'image/vnd.djvu',
+                'image/x-cpi',
+                'image/jpeg',
+                'image/x-ico',
+                'image/x-coreldraw',
+                'image/svg+xml'
+            );
+        }
+
+        $this->setMimeType($mimetype);
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the file is compression with the set compression types
+     *
+     * @param  string  $value Real file to check for compression
+     * @param  array   $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_READABLE);
+        }
+
+        if ($file !== null) {
+            if (class_exists('finfo', false) && defined('MAGIC')) {
+                $mime = new finfo(FILEINFO_MIME);
+                $this->_type = $mime->file($value);
+                unset($mime);
+            } elseif (function_exists('mime_content_type') && ini_get('mime_magic.magicfile')) {
+                $this->_type = mime_content_type($value);
+            } else {
+                $this->_type = $file['type'];
+            }
+        }
+
+        if (empty($this->_type)) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        $compressions = $this->getMimeType(true);
+        if (in_array($this->_type, $compressions)) {
+            return true;
+        }
+
+        $types = explode('/', $this->_type);
+        $types = array_merge($types, explode('-', $this->_type));
+        foreach($compressions as $mime) {
+            if (in_array($mime, $types)) {
+                return true;
+            }
+        }
+
+        return $this->_throw($file, self::FALSE_TYPE);
+    }
+}
diff --git a/lib/Zend/Validate/File/Md5.php b/lib/Zend/Validate/File/Md5.php
new file mode 100644
index 0000000..4b612d0
--- /dev/null
+++ b/lib/Zend/Validate/File/Md5.php
@@ -0,0 +1,183 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_Hash
+ */
+require_once 'Zend/Validate/File/Hash.php';
+
+/**
+ * Validator for the md5 hash of given files
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Md5 extends Zend_Validate_File_Hash
+{
+    /**
+     * @const string Error constants
+     */
+    const DOES_NOT_MATCH = 'fileMd5DoesNotMatch';
+    const NOT_DETECTED   = 'fileMd5NotDetected';
+    const NOT_FOUND      = 'fileMd5NotFound';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::DOES_NOT_MATCH => "The file '%value%' does not match the given md5 hashes",
+        self::NOT_DETECTED   => "There was no md5 hash detected for the given file",
+        self::NOT_FOUND      => "The file '%value%' could not be found"
+    );
+
+    /**
+     * Hash of the file
+     *
+     * @var string
+     */
+    protected $_hash;
+
+    /**
+     * Sets validator options
+     *
+     * $hash is the hash we accept for the file $file
+     *
+     * @param  string|array $options
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (is_scalar($options)) {
+            $options = array('hash1' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('Invalid options to validator provided');
+        }
+
+        $this->setMd5($options);
+    }
+
+    /**
+     * Returns all set md5 hashes
+     *
+     * @return array
+     */
+    public function getMd5()
+    {
+        return $this->getHash();
+    }
+
+    /**
+     * Sets the md5 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @param  string       $algorithm (Deprecated) Algorithm to use, fixed to md5
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function setHash($options)
+    {
+        if (!is_array($options)) {
+            $options = (array) $options;
+        }
+
+        $options['algorithm'] = 'md5';
+        parent::setHash($options);
+        return $this;
+    }
+
+    /**
+     * Sets the md5 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function setMd5($options)
+    {
+        $this->setHash($options);
+        return $this;
+    }
+
+    /**
+     * Adds the md5 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @param  string       $algorithm (Depreciated) Algorithm to use, fixed to md5
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function addHash($options)
+    {
+        if (!is_array($options)) {
+            $options = (array) $options;
+        }
+
+        $options['algorithm'] = 'md5';
+        parent::addHash($options);
+        return $this;
+    }
+
+    /**
+     * Adds the md5 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function addMd5($options)
+    {
+        $this->addHash($options);
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the given file confirms the set hash
+     *
+     * @param  string $value Filename to check for hash
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_FOUND);
+        }
+
+        $hashes = array_unique(array_keys($this->_hash));
+        $filehash = hash_file('md5', $value);
+        if ($filehash === false) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        foreach($hashes as $hash) {
+            if ($filehash === $hash) {
+                return true;
+            }
+        }
+
+        return $this->_throw($file, self::DOES_NOT_MATCH);
+    }
+}
diff --git a/lib/Zend/Validate/File/MimeType.php b/lib/Zend/Validate/File/MimeType.php
new file mode 100644
index 0000000..1605dad
--- /dev/null
+++ b/lib/Zend/Validate/File/MimeType.php
@@ -0,0 +1,283 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator for the mime type of a file
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_MimeType extends Zend_Validate_Abstract
+{
+    /**#@+
+     * @const Error type constants
+     */
+    const FALSE_TYPE   = 'fileMimeTypeFalse';
+    const NOT_DETECTED = 'fileMimeTypeNotDetected';
+    const NOT_READABLE = 'fileMimeTypeNotReadable';
+    /**#@-*/
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::FALSE_TYPE   => "The file '%value%' has a false mimetype of '%type%'",
+        self::NOT_DETECTED => "The mimetype of file '%value%' could not been detected",
+        self::NOT_READABLE => "The file '%value%' can not be read"
+    );
+
+    /**
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'type' => '_type'
+    );
+
+    /**
+     * @var string
+     */
+    protected $_type;
+
+    /**
+     * Mimetypes
+     *
+     * If null, there is no mimetype
+     *
+     * @var string|null
+     */
+    protected $_mimetype;
+
+    /**
+     * Magicfile to use
+     *
+     * @var string|null
+     */
+    protected $_magicfile;
+
+    /**
+     * Sets validator options
+     *
+     * Mimetype to accept
+     *
+     * @param  string|array $mimetype MimeType
+     * @return void
+     */
+    public function __construct($mimetype)
+    {
+        if ($mimetype instanceof Zend_Config) {
+            $mimetype = $mimetype->toArray();
+        } elseif (is_string($mimetype)) {
+            $mimetype = explode(',', $mimetype);
+        } elseif (!is_array($mimetype)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("Invalid options to validator provided");
+        }
+
+        if (isset($mimetype['magicfile'])) {
+            $this->setMagicFile($mimetype['magicfile']);
+        }
+
+        $this->setMimeType($mimetype);
+    }
+
+    /**
+     * Returna the actual set magicfile
+     *
+     * @return string
+     */
+    public function getMagicFile()
+    {
+        return $this->_magicfile;
+    }
+
+    /**
+     * Sets the magicfile to use
+     * if null, the MAGIC constant from php is used
+     *
+     * @param  string $file
+     * @return Zend_Validate_File_MimeType Provides fluid interface
+     */
+    public function setMagicFile($file)
+    {
+        if (empty($file)) {
+            $this->_magicfile = null;
+        } else if (!is_readable($file)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('The given magicfile can not be read');
+        } else {
+            $this->_magicfile = (string) $file;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the set mimetypes
+     *
+     * @param  boolean $asArray Returns the values as array, when false an concated string is returned
+     * @return string|array
+     */
+    public function getMimeType($asArray = false)
+    {
+        $asArray   = (bool) $asArray;
+        $mimetype = (string) $this->_mimetype;
+        if ($asArray) {
+            $mimetype = explode(',', $mimetype);
+        }
+
+        return $mimetype;
+    }
+
+    /**
+     * Sets the mimetypes
+     *
+     * @param  string|array $mimetype The mimetypes to validate
+     * @return Zend_Validate_File_Extension Provides a fluent interface
+     */
+    public function setMimeType($mimetype)
+    {
+        $this->_mimetype = null;
+        $this->addMimeType($mimetype);
+        return $this;
+    }
+
+    /**
+     * Adds the mimetypes
+     *
+     * @param  string|array $mimetype The mimetypes to add for validation
+     * @return Zend_Validate_File_Extension Provides a fluent interface
+     */
+    public function addMimeType($mimetype)
+    {
+        $mimetypes = $this->getMimeType(true);
+
+        if (is_string($mimetype)) {
+            $mimetype = explode(',', $mimetype);
+        } elseif (!is_array($mimetype)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("Invalid options to validator provided");
+        }
+
+        if (isset($mimetype['magicfile'])) {
+            unset($mimetype['magicfile']);
+        }
+
+        foreach ($mimetype as $content) {
+            if (empty($content) || !is_string($content)) {
+                continue;
+            }
+            $mimetypes[] = trim($content);
+        }
+        $mimetypes = array_unique($mimetypes);
+
+        // Sanity check to ensure no empty values
+        foreach ($mimetypes as $key => $mt) {
+            if (empty($mt)) {
+                unset($mimetypes[$key]);
+            }
+        }
+
+        $this->_mimetype = implode(',', $mimetypes);
+
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if the mimetype of the file matches the given ones. Also parts
+     * of mimetypes can be checked. If you give for example "image" all image
+     * mime types will be accepted like "image/gif", "image/jpeg" and so on.
+     *
+     * @param  string $value Real file to check for mimetype
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_READABLE);
+        }
+
+        if ($file !== null) {
+            $mimefile = $this->getMagicFile();
+            if (class_exists('finfo', false) && ((!empty($mimefile)) or (defined('MAGIC')))) {
+                if (!empty($mimefile)) {
+                    $mime = new finfo(FILEINFO_MIME, $mimefile);
+                } else {
+                    $mime = new finfo(FILEINFO_MIME);
+                }
+
+                $this->_type = $mime->file($value);
+                unset($mime);
+            } elseif (function_exists('mime_content_type') && ini_get('mime_magic.magicfile')) {
+                $this->_type = mime_content_type($value);
+            } else {
+                $this->_type = $file['type'];
+            }
+        }
+
+        if (empty($this->_type)) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        $mimetype = $this->getMimeType(true);
+        if (in_array($this->_type, $mimetype)) {
+            return true;
+        }
+
+        $types = explode('/', $this->_type);
+        $types = array_merge($types, explode('-', $this->_type));
+        foreach($mimetype as $mime) {
+            if (in_array($mime, $types)) {
+                return true;
+            }
+        }
+
+        return $this->_throw($file, self::FALSE_TYPE);
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if ($file !== null) {
+            $this->_value = $file['name'];
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/File/NotExists.php b/lib/Zend/Validate/File/NotExists.php
new file mode 100644
index 0000000..8aeef9f
--- /dev/null
+++ b/lib/Zend/Validate/File/NotExists.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_Exists
+ */
+require_once 'Zend/Validate/File/Exists.php';
+
+/**
+ * Validator which checks if the destination file does not exist
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_NotExists extends Zend_Validate_File_Exists
+{
+    /**
+     * @const string Error constants
+     */
+    const DOES_EXIST = 'fileNotExistsDoesExist';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::DOES_EXIST => "The file '%value%' does exist"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the file does not exist in the set destinations
+     *
+     * @param  string  $value Real file to check for
+     * @param  array   $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        $directories = $this->getDirectory(true);
+        if (($file !== null) and (!empty($file['destination']))) {
+            $directories[] = $file['destination'];
+        } else if (!isset($file['name'])) {
+            $file['name'] = $value;
+        }
+
+        foreach ($directories as $directory) {
+            if (empty($directory)) {
+                continue;
+            }
+
+            $check = true;
+            if (file_exists($directory . DIRECTORY_SEPARATOR . $file['name'])) {
+                return $this->_throw($file, self::DOES_EXIST);
+            }
+        }
+
+        if (!isset($check)) {
+            return $this->_throw($file, self::DOES_EXIST);
+        }
+
+        return true;
+    }
+}
diff --git a/lib/Zend/Validate/File/Sha1.php b/lib/Zend/Validate/File/Sha1.php
new file mode 100644
index 0000000..b02a837
--- /dev/null
+++ b/lib/Zend/Validate/File/Sha1.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_File_Hash
+ */
+require_once 'Zend/Validate/File/Hash.php';
+
+/**
+ * Validator for the sha1 hash of given files
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Sha1 extends Zend_Validate_File_Hash
+{
+    /**
+     * @const string Error constants
+     */
+    const DOES_NOT_MATCH = 'fileSha1DoesNotMatch';
+    const NOT_DETECTED   = 'fileSha1NotDetected';
+    const NOT_FOUND      = 'fileSha1NotFound';
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::DOES_NOT_MATCH => "The file '%value%' does not match the given sha1 hashes",
+        self::NOT_DETECTED   => "There was no sha1 hash detected for the given file",
+        self::NOT_FOUND      => "The file '%value%' could not be found"
+    );
+
+    /**
+     * Hash of the file
+     *
+     * @var string
+     */
+    protected $_hash;
+
+    /**
+     * Sets validator options
+     *
+     * $hash is the hash we accept for the file $file
+     *
+     * @param  string|array $options
+     * @return void
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (is_scalar($options)) {
+            $options = array('hash1' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('Invalid options to validator provided');
+        }
+
+        $this->setHash($options);
+    }
+
+    /**
+     * Returns all set sha1 hashes
+     *
+     * @return array
+     */
+    public function getSha1()
+    {
+        return $this->getHash();
+    }
+
+    /**
+     * Sets the sha1 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function setHash($options)
+    {
+        if (!is_array($options)) {
+            $options = (array) $options;
+        }
+
+        $options['algorithm'] = 'sha1';
+        parent::setHash($options);
+        return $this;
+    }
+
+    /**
+     * Sets the sha1 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function setSha1($options)
+    {
+        $this->setHash($options);
+        return $this;
+    }
+
+    /**
+     * Adds the sha1 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function addHash($options)
+    {
+        if (!is_array($options)) {
+            $options = (array) $options;
+        }
+
+        $options['algorithm'] = 'sha1';
+        parent::addHash($options);
+        return $this;
+    }
+
+    /**
+     * Adds the sha1 hash for one or multiple files
+     *
+     * @param  string|array $options
+     * @return Zend_Validate_File_Hash Provides a fluent interface
+     */
+    public function addSha1($options)
+    {
+        $this->addHash($options);
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the given file confirms the set hash
+     *
+     * @param  string $value Filename to check for hash
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_FOUND);
+        }
+
+        $hashes = array_unique(array_keys($this->_hash));
+        $filehash = hash_file('sha1', $value);
+        if ($filehash === false) {
+            return $this->_throw($file, self::NOT_DETECTED);
+        }
+
+        foreach ($hashes as $hash) {
+            if ($filehash === $hash) {
+                return true;
+            }
+        }
+
+        return $this->_throw($file, self::DOES_NOT_MATCH);
+    }
+}
diff --git a/lib/Zend/Validate/File/Size.php b/lib/Zend/Validate/File/Size.php
new file mode 100644
index 0000000..a52d499
--- /dev/null
+++ b/lib/Zend/Validate/File/Size.php
@@ -0,0 +1,404 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator for the maximum size of a file up to a max of 2GB
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Size extends Zend_Validate_Abstract
+{
+    /**#@+
+     * @const string Error constants
+     */
+    const TOO_BIG   = 'fileSizeTooBig';
+    const TOO_SMALL = 'fileSizeTooSmall';
+    const NOT_FOUND = 'fileSizeNotFound';
+    /**#@-*/
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::TOO_BIG   => "Maximum allowed size for file '%value%' is '%max%' but '%size%' detected",
+        self::TOO_SMALL => "Minimum expected size for file '%value%' is '%min%' but '%size%' detected",
+        self::NOT_FOUND => "The file '%value%' could not be found"
+    );
+
+    /**
+     * @var array Error message template variables
+     */
+    protected $_messageVariables = array(
+        'min'  => '_min',
+        'max'  => '_max',
+        'size' => '_size',
+    );
+
+    /**
+     * Minimum filesize
+     * @var integer
+     */
+    protected $_min;
+
+    /**
+     * Maximum filesize
+     *
+     * If null, there is no maximum filesize
+     *
+     * @var integer|null
+     */
+    protected $_max;
+
+    /**
+     * Detected size
+     *
+     * @var integer
+     */
+    protected $_size;
+
+    /**
+     * Use bytestring ?
+     *
+     * @var boolean
+     */
+    protected $_useByteString = true;
+
+    /**
+     * Sets validator options
+     *
+     * If $options is a integer, it will be used as maximum filesize
+     * As Array is accepts the following keys:
+     * 'min': Minimum filesize
+     * 'max': Maximum filesize
+     * 'bytestring': Use bytestring or real size for messages
+     *
+     * @param  integer|array $options Options for the adapter
+     */
+    public function __construct($options)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (is_string($options) || is_numeric($options)) {
+            $options = array('max' => $options);
+        } elseif (!is_array($options)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        if (1 < func_num_args()) {
+            trigger_error('Multiple constructor options are deprecated in favor of a single options array', E_USER_NOTICE);
+            $argv = func_get_args();
+            array_shift($argv);
+            $options['max'] = array_shift($argv);
+            if (!empty($argv)) {
+                $options['bytestring'] = array_shift($argv);
+            }
+        }
+
+        if (isset($options['bytestring'])) {
+            $this->setUseByteString($options['bytestring']);
+        }
+
+        if (isset($options['min'])) {
+            $this->setMin($options['min']);
+        }
+
+        if (isset($options['max'])) {
+            $this->setMax($options['max']);
+        }
+    }
+
+    /**
+     * Returns the minimum filesize
+     *
+     * @param  boolean $byteString Use bytestring ?
+     * @return integer
+     */
+    public function setUseByteString($byteString = true)
+    {
+        $this->_useByteString = (bool) $byteString;
+        return $this;
+    }
+
+    /**
+     * Will bytestring be used?
+     *
+     * @return boolean
+     */
+    public function useByteString()
+    {
+        return $this->_useByteString;
+    }
+
+    /**
+     * Returns the minimum filesize
+     *
+     * @param  bool $raw Whether or not to force return of the raw value (defaults off)
+     * @return integer|string
+     */
+    public function getMin($raw = false)
+    {
+        $min = $this->_min;
+        if (!$raw && $this->useByteString()) {
+            $min = $this->_toByteString($min);
+        }
+
+        return $min;
+    }
+
+    /**
+     * Sets the minimum filesize
+     *
+     * @param  integer $min The minimum filesize
+     * @throws Zend_Validate_Exception When min is greater than max
+     * @return Zend_Validate_File_Size Provides a fluent interface
+     */
+    public function setMin($min)
+    {
+        if (!is_string($min) and !is_numeric($min)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        $min = (integer) $this->_fromByteString($min);
+        $max = $this->getMax(true);
+        if (($max !== null) && ($min > $max)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum filesize, but $min >"
+                                            . " $max");
+        }
+
+        $this->_min = $min;
+        return $this;
+    }
+
+    /**
+     * Returns the maximum filesize
+     *
+     * @param  bool $raw Whether or not to force return of the raw value (defaults off)
+     * @return integer|string
+     */
+    public function getMax($raw = false)
+    {
+        $max = $this->_max;
+        if (!$raw && $this->useByteString()) {
+            $max = $this->_toByteString($max);
+        }
+
+        return $max;
+    }
+
+    /**
+     * Sets the maximum filesize
+     *
+     * @param  integer $max The maximum filesize
+     * @throws Zend_Validate_Exception When max is smaller than min
+     * @return Zend_Validate_StringLength Provides a fluent interface
+     */
+    public function setMax($max)
+    {
+        if (!is_string($max) && !is_numeric($max)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception ('Invalid options to validator provided');
+        }
+
+        $max = (integer) $this->_fromByteString($max);
+        $min = $this->getMin(true);
+        if (($min !== null) && ($max < $min)) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum filesize, but "
+                                            . "$max < $min");
+        }
+
+        $this->_max = $max;
+        return $this;
+    }
+
+    /**
+     * Retrieve current detected file size
+     *
+     * @return int
+     */
+    protected function _getSize()
+    {
+        return $this->_size;
+    }
+
+    /**
+     * Set current size
+     *
+     * @param  int $size
+     * @return Zend_Validate_File_Size
+     */
+    protected function _setSize($size)
+    {
+        $this->_size = $size;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the filesize of $value is at least min and
+     * not bigger than max (when max is not null).
+     *
+     * @param  string $value Real file to check for size
+     * @param  array  $file  File data from Zend_File_Transfer
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        // Is file readable ?
+        require_once 'Zend/Loader.php';
+        if (!Zend_Loader::isReadable($value)) {
+            return $this->_throw($file, self::NOT_FOUND);
+        }
+
+        // limited to 4GB files
+        $size = sprintf("%u", @filesize($value));
+
+        // Check to see if it's smaller than min size
+        $min = $this->getMin(true);
+        $max = $this->getMax(true);
+        if (($min !== null) && ($size < $min)) {
+            if ($this->useByteString()) {
+                $this->_min  = $this->_toByteString($min);
+                $this->_size = $this->_toByteString($size);
+                $this->_throw($file, self::TOO_SMALL);
+                $this->_min  = $min;
+                $this->_size = $size;
+            } else {
+                $this->_throw($file, self::TOO_SMALL);
+            }
+        }
+
+        // Check to see if it's larger than max size
+        if (($max !== null) && ($max < $size)) {
+            if ($this->useByteString()) {
+                $this->_max  = $this->_toByteString($max);
+                $this->_size = $this->_toByteString($size);
+                $this->_throw($file, self::TOO_BIG);
+                $this->_max  = $max;
+                $this->_size = $size;
+            } else {
+                $this->_throw($file, self::TOO_BIG);
+            }
+        }
+
+        if (count($this->_messages) > 0) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the formatted size
+     *
+     * @param  integer $size
+     * @return string
+     */
+    protected function _toByteString($size)
+    {
+        $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
+        for ($i=0; $size >= 1024 && $i < 9; $i++) {
+            $size /= 1024;
+        }
+
+        return round($size, 2) . $sizes[$i];
+    }
+
+    /**
+     * Returns the unformatted size
+     *
+     * @param  string $size
+     * @return integer
+     */
+    protected function _fromByteString($size)
+    {
+        if (is_numeric($size)) {
+            return (integer) $size;
+        }
+
+        $type  = trim(substr($size, -2, 1));
+
+        $value = substr($size, 0, -1);
+        if (!is_numeric($value)) {
+            $value = substr($value, 0, -1);
+        }
+
+        switch (strtoupper($type)) {
+            case 'Y':
+                $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024);
+                break;
+            case 'Z':
+                $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024);
+                break;
+            case 'E':
+                $value *= (1024 * 1024 * 1024 * 1024 * 1024 * 1024);
+                break;
+            case 'P':
+                $value *= (1024 * 1024 * 1024 * 1024 * 1024);
+                break;
+            case 'T':
+                $value *= (1024 * 1024 * 1024 * 1024);
+                break;
+            case 'G':
+                $value *= (1024 * 1024 * 1024);
+                break;
+            case 'M':
+                $value *= (1024 * 1024);
+                break;
+            case 'K':
+                $value *= 1024;
+                break;
+            default:
+                break;
+        }
+
+        return $value;
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if ($file !== null) {
+            $this->_value = $file['name'];
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/File/Upload.php b/lib/Zend/Validate/File/Upload.php
new file mode 100644
index 0000000..ddeb328
--- /dev/null
+++ b/lib/Zend/Validate/File/Upload.php
@@ -0,0 +1,234 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ * @version   $Id: $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * Validator for the maximum size of a file up to a max of 2GB
+ *
+ * @category  Zend
+ * @package   Zend_Validate
+ * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license   http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_File_Upload extends Zend_Validate_Abstract
+{
+    /**@#+
+     * @const string Error constants
+     */
+    const INI_SIZE       = 'fileUploadErrorIniSize';
+    const FORM_SIZE      = 'fileUploadErrorFormSize';
+    const PARTIAL        = 'fileUploadErrorPartial';
+    const NO_FILE        = 'fileUploadErrorNoFile';
+    const NO_TMP_DIR     = 'fileUploadErrorNoTmpDir';
+    const CANT_WRITE     = 'fileUploadErrorCantWrite';
+    const EXTENSION      = 'fileUploadErrorExtension';
+    const ATTACK         = 'fileUploadErrorAttack';
+    const FILE_NOT_FOUND = 'fileUploadErrorFileNotFound';
+    const UNKNOWN        = 'fileUploadErrorUnknown';
+    /**@#-*/
+
+    /**
+     * @var array Error message templates
+     */
+    protected $_messageTemplates = array(
+        self::INI_SIZE       => "The file '%value%' exceeds the defined ini size",
+        self::FORM_SIZE      => "The file '%value%' exceeds the defined form size",
+        self::PARTIAL        => "The file '%value%' was only partially uploaded",
+        self::NO_FILE        => "The file '%value%' was not uploaded",
+        self::NO_TMP_DIR     => "No temporary directory was found for the file '%value%'",
+        self::CANT_WRITE     => "The file '%value%' can't be written",
+        self::EXTENSION      => "The extension returned an error while uploading the file '%value%'",
+        self::ATTACK         => "The file '%value%' was illegal uploaded, possible attack",
+        self::FILE_NOT_FOUND => "The file '%value%' was not found",
+        self::UNKNOWN        => "Unknown error while uploading the file '%value%'"
+    );
+
+    /**
+     * Internal array of files
+     * @var array
+     */
+    protected $_files = array();
+
+    /**
+     * Sets validator options
+     *
+     * The array $files must be given in syntax of Zend_File_Transfer to be checked
+     * If no files are given the $_FILES array will be used automatically.
+     * NOTE: This validator will only work with HTTP POST uploads!
+     *
+     * @param  array $files Array of files in syntax of Zend_File_Transfer
+     * @return void
+     */
+    public function __construct($files = array())
+    {
+        $this->setFiles($files);
+    }
+
+    /**
+     * Returns the array of set files
+     *
+     * @param  string $files (Optional) The file to return in detail
+     * @return array
+     * @throws Zend_Validate_Exception If file is not found
+     */
+    public function getFiles($file = null)
+    {
+        if ($file !== null) {
+            $return = array();
+            foreach ($this->_files as $name => $content) {
+                if ($name === $file) {
+                    $return[$file] = $this->_files[$name];
+                }
+
+                if ($content['name'] === $file) {
+                    $return[$name] = $this->_files[$name];
+                }
+            }
+
+            if (count($return) === 0) {
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception("The file '$file' was not found");
+            }
+
+            return $return;
+        }
+
+        return $this->_files;
+    }
+
+    /**
+     * Sets the minimum filesize
+     *
+     * @param  array $files The files to check in syntax of Zend_File_Transfer
+     * @return Zend_Validate_File_Upload Provides a fluent interface
+     */
+    public function setFiles($files = array())
+    {
+        if (count($files) === 0) {
+            $this->_files = $_FILES;
+        } else {
+            $this->_files = $files;
+        }
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the file was uploaded without errors
+     *
+     * @param  string $value Single file to check for upload errors, when giving null the $_FILES array
+     *                       from initialization will be used
+     * @return boolean
+     */
+    public function isValid($value, $file = null)
+    {
+        if (array_key_exists($value, $this->_files)) {
+            $files[$value] = $this->_files[$value];
+        } else {
+            foreach ($this->_files as $file => $content) {
+                if ($content['name'] === $value) {
+                    $files[$file] = $this->_files[$file];
+                }
+
+                if ($content['tmp_name'] === $value) {
+                    $files[$file] = $this->_files[$file];
+                }
+            }
+        }
+
+        if (empty($files)) {
+            return $this->_throw($file, self::FILE_NOT_FOUND);
+        }
+
+        foreach ($files as $file => $content) {
+            $this->_value = $file;
+            switch($content['error']) {
+                case 0:
+                    if (!is_uploaded_file($content['tmp_name'])) {
+                        $this->_throw($file, self::ATTACK);
+                    }
+                    break;
+
+                case 1:
+                    $this->_throw($file, self::INI_SIZE);
+                    break;
+
+                case 2:
+                    $this->_throw($file, self::FORM_SIZE);
+                    break;
+
+                case 3:
+                    $this->_throw($file, self::PARTIAL);
+                    break;
+
+                case 4:
+                    $this->_throw($file, self::NO_FILE);
+                    break;
+
+                case 6:
+                    $this->_throw($file, self::NO_TMP_DIR);
+                    break;
+
+                case 7:
+                    $this->_throw($file, self::CANT_WRITE);
+                    break;
+
+                case 8:
+                    $this->_throw($file, self::EXTENSION);
+                    break;
+
+                default:
+                    $this->_throw($file, self::UNKNOWN);
+                    break;
+            }
+        }
+
+        if (count($this->_messages) > 0) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Throws an error of the given type
+     *
+     * @param  string $file
+     * @param  string $errorType
+     * @return false
+     */
+    protected function _throw($file, $errorType)
+    {
+        if ($file !== null) {
+            if (is_array($file) and !empty($file['name'])) {
+                $this->_value = $file['name'];
+            }
+        }
+
+        $this->_error($errorType);
+        return false;
+    }
+}
diff --git a/lib/Zend/Validate/Float.php b/lib/Zend/Validate/Float.php
new file mode 100644
index 0000000..0405161
--- /dev/null
+++ b/lib/Zend/Validate/Float.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Float.php 8714 2008-03-09 20:03:45Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Float extends Zend_Validate_Abstract
+{
+
+    const NOT_FLOAT = 'notFloat';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_FLOAT => "'%value%' does not appear to be a float"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is a floating-point value
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        $locale = localeconv();
+
+        $valueFiltered = str_replace($locale['thousands_sep'], '', $valueString);
+        $valueFiltered = str_replace($locale['decimal_point'], '.', $valueFiltered);
+
+        if (strval(floatval($valueFiltered)) != $valueFiltered) {
+            $this->_error();
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/GreaterThan.php b/lib/Zend/Validate/GreaterThan.php
new file mode 100644
index 0000000..35e658c
--- /dev/null
+++ b/lib/Zend/Validate/GreaterThan.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: GreaterThan.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_GreaterThan extends Zend_Validate_Abstract
+{
+
+    const NOT_GREATER = 'notGreaterThan';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_GREATER => "'%value%' is not greater than '%min%'"
+    );
+
+    /**
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'min' => '_min'
+    );
+
+    /**
+     * Minimum value
+     *
+     * @var mixed
+     */
+    protected $_min;
+
+    /**
+     * Sets validator options
+     *
+     * @param  mixed $min
+     * @return void
+     */
+    public function __construct($min)
+    {
+        $this->setMin($min);
+    }
+
+    /**
+     * Returns the min option
+     *
+     * @return mixed
+     */
+    public function getMin()
+    {
+        return $this->_min;
+    }
+
+    /**
+     * Sets the min option
+     *
+     * @param  mixed $min
+     * @return Zend_Validate_GreaterThan Provides a fluent interface
+     */
+    public function setMin($min)
+    {
+        $this->_min = $min;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is greater than min option
+     *
+     * @param  mixed $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_setValue($value);
+
+        if ($this->_min >= $value) {
+            $this->_error();
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Hex.php b/lib/Zend/Validate/Hex.php
new file mode 100644
index 0000000..9512eda
--- /dev/null
+++ b/lib/Zend/Validate/Hex.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Hex.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hex extends Zend_Validate_Abstract
+{
+    /**
+     * Validation failure message key for when the value contains characters other than hexadecimal digits
+     */
+    const NOT_HEX = 'notHex';
+
+    /**
+     * Validation failure message template definitions
+     *
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_HEX => "'%value%' has not only hexadecimal digit characters"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value contains only hexadecimal digit characters
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        if (!ctype_xdigit($valueString)) {
+            $this->_error();
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Hostname.php b/lib/Zend/Validate/Hostname.php
new file mode 100644
index 0000000..61b0b23
--- /dev/null
+++ b/lib/Zend/Validate/Hostname.php
@@ -0,0 +1,444 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Hostname.php 12274 2008-11-03 12:50:50Z yoshida@zend.co.jp $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @see Zend_Loader
+ */
+require_once 'Zend/Loader.php';
+
+/**
+ * @see Zend_Validate_Ip
+ */
+require_once 'Zend/Validate/Ip.php';
+
+/**
+ * Please note there are two standalone test scripts for testing IDN characters due to problems
+ * with file encoding.
+ *
+ * The first is tests/Zend/Validate/HostnameTestStandalone.php which is designed to be run on
+ * the command line.
+ *
+ * The second is tests/Zend/Validate/HostnameTestForm.php which is designed to be run via HTML
+ * to allow users to test entering UTF-8 characters in a form.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname extends Zend_Validate_Abstract
+{
+
+    const IP_ADDRESS_NOT_ALLOWED  = 'hostnameIpAddressNotAllowed';
+    const UNKNOWN_TLD             = 'hostnameUnknownTld';
+    const INVALID_DASH            = 'hostnameDashCharacter';
+    const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema';
+    const UNDECIPHERABLE_TLD      = 'hostnameUndecipherableTld';
+    const INVALID_HOSTNAME        = 'hostnameInvalidHostname';
+    const INVALID_LOCAL_NAME      = 'hostnameInvalidLocalName';
+    const LOCAL_NAME_NOT_ALLOWED  = 'hostnameLocalNameNotAllowed';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::IP_ADDRESS_NOT_ALLOWED  => "'%value%' appears to be an IP address, but IP addresses are not allowed",
+        self::UNKNOWN_TLD             => "'%value%' appears to be a DNS hostname but cannot match TLD against known list",
+        self::INVALID_DASH            => "'%value%' appears to be a DNS hostname but contains a dash (-) in an invalid position",
+        self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
+        self::UNDECIPHERABLE_TLD      => "'%value%' appears to be a DNS hostname but cannot extract TLD part",
+        self::INVALID_HOSTNAME        => "'%value%' does not match the expected structure for a DNS hostname",
+        self::INVALID_LOCAL_NAME      => "'%value%' does not appear to be a valid local network name",
+        self::LOCAL_NAME_NOT_ALLOWED  => "'%value%' appears to be a local network name but local network names are not allowed"
+    );
+
+    /**
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'tld' => '_tld'
+    );
+
+    /**
+     * Allows Internet domain names (e.g., example.com)
+     */
+    const ALLOW_DNS   = 1;
+
+    /**
+     * Allows IP addresses
+     */
+    const ALLOW_IP    = 2;
+
+    /**
+     * Allows local network names (e.g., localhost, www.localdomain)
+     */
+    const ALLOW_LOCAL = 4;
+
+    /**
+     * Allows all types of hostnames
+     */
+    const ALLOW_ALL   = 7;
+
+    /**
+     * Whether IDN domains are validated
+     *
+     * @var boolean
+     */
+    private $_validateIdn = true;
+
+    /**
+     * Whether TLDs are validated against a known list
+     *
+     * @var boolean
+     */
+    private $_validateTld = true;
+
+    /**
+     * Bit field of ALLOW constants; determines which types of hostnames are allowed
+     *
+     * @var integer
+     */
+    protected $_allow;
+
+    /**
+     * Bit field of CHECK constants; determines what additional hostname checks to make
+     *
+     * @var unknown_type
+     */
+    // protected $_check;
+
+    /**
+     * Array of valid top-level-domains
+     *
+     * @var array
+     * @see ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt  List of all TLDs by domain
+     */
+    protected $_validTlds = array(
+        'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao',
+        'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb',
+        'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bm', 'bn', 'bo',
+        'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd',
+        'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop',
+        'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do',
+        'dz', 'ec', 'edu', 'ee', 'eg', 'er', 'es', 'et', 'eu', 'fi', 'fj',
+        'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh',
+        'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu',
+        'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il',
+        'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm',
+        'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw',
+        'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu',
+        'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm',
+        'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv',
+        'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng',
+        'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe',
+        'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt',
+        'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd',
+        'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr',
+        'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj',
+        'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw',
+        'tz', 'ua', 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've',
+        'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm',
+        'zw'
+        );
+
+    /**
+     * @var string
+     */
+    protected $_tld;
+
+    /**
+     * Sets validator options
+     *
+     * @param integer          $allow       OPTIONAL Set what types of hostname to allow (default ALLOW_DNS)
+     * @param boolean          $validateIdn OPTIONAL Set whether IDN domains are validated (default true)
+     * @param boolean          $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true)
+     * @param Zend_Validate_Ip $ipValidator OPTIONAL
+     * @return void
+     * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm  Technical Specifications for ccTLDs
+     */
+    public function __construct($allow = self::ALLOW_DNS, $validateIdn = true, $validateTld = true, Zend_Validate_Ip $ipValidator = null)
+    {
+        // Set allow options
+        $this->setAllow($allow);
+
+        // Set validation options
+        $this->_validateIdn = $validateIdn;
+        $this->_validateTld = $validateTld;
+
+        $this->setIpValidator($ipValidator);
+    }
+
+    /**
+     * @param Zend_Validate_Ip $ipValidator OPTIONAL
+     * @return void;
+     */
+    public function setIpValidator(Zend_Validate_Ip $ipValidator = null)
+    {
+        if ($ipValidator === null) {
+            $ipValidator = new Zend_Validate_Ip();
+        }
+        $this->_ipValidator = $ipValidator;
+    }
+
+    /**
+     * Returns the allow option
+     *
+     * @return integer
+     */
+    public function getAllow()
+    {
+        return $this->_allow;
+    }
+
+    /**
+     * Sets the allow option
+     *
+     * @param  integer $allow
+     * @return Zend_Validate_Hostname Provides a fluent interface
+     */
+    public function setAllow($allow)
+    {
+        $this->_allow = $allow;
+        return $this;
+    }
+
+    /**
+     * Set whether IDN domains are validated
+     *
+     * This only applies when DNS hostnames are validated
+     *
+     * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them
+     */
+    public function setValidateIdn ($allowed)
+    {
+        $this->_validateIdn = (bool) $allowed;
+    }
+
+    /**
+     * Set whether the TLD element of a hostname is validated
+     *
+     * This only applies when DNS hostnames are validated
+     *
+     * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them
+     */
+    public function setValidateTld ($allowed)
+    {
+        $this->_validateTld = (bool) $allowed;
+    }
+
+    /**
+     * Sets the check option
+     *
+     * @param  integer $check
+     * @return Zend_Validate_Hostname Provides a fluent interface
+     */
+    /*
+    public function setCheck($check)
+    {
+        $this->_check = $check;
+        return $this;
+    }
+     */
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the $value is a valid hostname with respect to the current allow option
+     *
+     * @param  string $value
+     * @throws Zend_Validate_Exception if a fatal error occurs for validation process
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        // Check input against IP address schema
+        if ($this->_ipValidator->setTranslator($this->getTranslator())->isValid($valueString)) {
+            if (!($this->_allow & self::ALLOW_IP)) {
+                $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
+                return false;
+            } else{
+                return true;
+            }
+        }
+
+        // Check input against DNS hostname schema
+        $domainParts = explode('.', $valueString);
+        if ((count($domainParts) > 1) && (strlen($valueString) >= 4) && (strlen($valueString) <= 254)) {
+            $status = false;
+
+            do {
+                // First check TLD
+                if (preg_match('/([a-z]{2,10})$/i', end($domainParts), $matches)) {
+
+                    reset($domainParts);
+
+                    // Hostname characters are: *(label dot)(label dot label); max 254 chars
+                    // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
+                    // id-prefix: alpha / digit
+                    // ldh: alpha / digit / dash
+
+                    // Match TLD against known list
+                    $this->_tld = strtolower($matches[1]);
+                    if ($this->_validateTld) {
+                        if (!in_array($this->_tld, $this->_validTlds)) {
+                            $this->_error(self::UNKNOWN_TLD);
+                            $status = false;
+                            break;
+                        }
+                    }
+
+                    /**
+                     * Match against IDN hostnames
+                     * @see Zend_Validate_Hostname_Interface
+                     */
+                    $labelChars = 'a-z0-9';
+                    $utf8 = false;
+                    $classFile = 'Zend/Validate/Hostname/' . ucfirst($this->_tld) . '.php';
+                    if ($this->_validateIdn) {
+                        if (Zend_Loader::isReadable($classFile)) {
+
+                            // Load additional characters
+                            $className = 'Zend_Validate_Hostname_' . ucfirst($this->_tld);
+                            Zend_Loader::loadClass($className);
+                            $labelChars .= call_user_func(array($className, 'getCharacters'));
+                            $utf8 = true;
+                        }
+                    }
+
+                    // Keep label regex short to avoid issues with long patterns when matching IDN hostnames
+                    $regexLabel = '/^[' . $labelChars . '\x2d]{1,63}$/i';
+                    if ($utf8) {
+                        $regexLabel .= 'u';
+                    }
+
+                    // Check each hostname part
+                    $valid = true;
+                    foreach ($domainParts as $domainPart) {
+
+                        // Check dash (-) does not start, end or appear in 3rd and 4th positions
+                        if (strpos($domainPart, '-') === 0 ||
+                        (strlen($domainPart) > 2 && strpos($domainPart, '-', 2) == 2 && strpos($domainPart, '-', 3) == 3) ||
+                        strrpos($domainPart, '-') === strlen($domainPart) - 1) {
+
+                            $this->_error(self::INVALID_DASH);
+                            $status = false;
+                            break 2;
+                        }
+
+                        // Check each domain part
+                        $status = @preg_match($regexLabel, $domainPart);
+                        if ($status === false) {
+                            /**
+                             * Regex error
+                             * @see Zend_Validate_Exception
+                             */
+                            require_once 'Zend/Validate/Exception.php';
+                            throw new Zend_Validate_Exception('Internal error: DNS validation failed');
+                        } elseif ($status === 0) {
+                            $valid = false;
+                        }
+                    }
+
+                    // If all labels didn't match, the hostname is invalid
+                    if (!$valid) {
+                        $this->_error(self::INVALID_HOSTNAME_SCHEMA);
+                        $status = false;
+                    }
+
+                } else {
+                    // Hostname not long enough
+                    $this->_error(self::UNDECIPHERABLE_TLD);
+                    $status = false;
+                }
+            } while (false);
+
+            // If the input passes as an Internet domain name, and domain names are allowed, then the hostname
+            // passes validation
+            if ($status && ($this->_allow & self::ALLOW_DNS)) {
+                return true;
+            }
+        } else {
+            $this->_error(self::INVALID_HOSTNAME);
+        }
+
+        // Check input against local network name schema; last chance to pass validation
+        $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}){1,254}$/';
+        $status = @preg_match($regexLocal, $valueString);
+        if (false === $status) {
+            /**
+             * Regex error
+             * @see Zend_Validate_Exception
+             */
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception('Internal error: local network name validation failed');
+        }
+
+        // If the input passes as a local network name, and local network names are allowed, then the
+        // hostname passes validation
+        $allowLocal = $this->_allow & self::ALLOW_LOCAL;
+        if ($status && $allowLocal) {
+            return true;
+        }
+
+        // If the input does not pass as a local network name, add a message
+        if (!$status) {
+            $this->_error(self::INVALID_LOCAL_NAME);
+        }
+
+        // If local network names are not allowed, add a message
+        if ($status && !$allowLocal) {
+            $this->_error(self::LOCAL_NAME_NOT_ALLOWED);
+        }
+
+        return false;
+    }
+
+    /**
+     * Throws an exception if a regex for $type does not exist
+     *
+     * @param  string $type
+     * @throws Zend_Validate_Exception
+     * @return Zend_Validate_Hostname Provides a fluent interface
+     */
+    /*
+    protected function _checkRegexType($type)
+    {
+        if (!isset($this->_regex[$type])) {
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("'$type' must be one of ('" . implode(', ', array_keys($this->_regex))
+                                            . "')");
+        }
+        return $this;
+    }
+     */
+
+}
diff --git a/lib/Zend/Validate/Hostname/At.php b/lib/Zend/Validate/Hostname/At.php
new file mode 100644
index 0000000..fff6bf2
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/At.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: At.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_At implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see http://www.nic.at/en/service/technical_information/idn/charset_converter/ Austria (.AT)
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return '\x{00EO}-\x{00F6}\x{00F8}-\x{00FF}\x{0153}\x{0161}\x{017E}';
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Hostname/Ch.php b/lib/Zend/Validate/Hostname/Ch.php
new file mode 100644
index 0000000..72fae7b
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/Ch.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Ch.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_Ch implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 Switzerland (.CH)
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return '\x{00EO}-\x{00F6}\x{00F8}-\x{00FF}\x{0153}';
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Hostname/De.php b/lib/Zend/Validate/Hostname/De.php
new file mode 100644
index 0000000..cfea068
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/De.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: De.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_De implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see http://www.denic.de/en/domains/idns/liste.html Germany (.DE) alllowed characters
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return  '\x{00E1}\x{00E0}\x{0103}\x{00E2}\x{00E5}\x{00E4}\x{00E3}\x{0105}\x{0101}\x{00E6}\x{0107}' .
+                '\x{0109}\x{010D}\x{010B}\x{00E7}\x{010F}\x{0111}\x{00E9}\x{00E8}\x{0115}\x{00EA}\x{011B}' .
+                '\x{00EB}\x{0117}\x{0119}\x{0113}\x{011F}\x{011D}\x{0121}\x{0123}\x{0125}\x{0127}\x{00ED}' .
+                '\x{00EC}\x{012D}\x{00EE}\x{00EF}\x{0129}\x{012F}\x{012B}\x{0131}\x{0135}\x{0137}\x{013A}' .
+                '\x{013E}\x{013C}\x{0142}\x{0144}\x{0148}\x{00F1}\x{0146}\x{014B}\x{00F3}\x{00F2}\x{014F}' .
+                '\x{00F4}\x{00F6}\x{0151}\x{00F5}\x{00F8}\x{014D}\x{0153}\x{0138}\x{0155}\x{0159}\x{0157}' .
+                '\x{015B}\x{015D}\x{0161}\x{015F}\x{0165}\x{0163}\x{0167}\x{00FA}\x{00F9}\x{016D}\x{00FB}' .
+                '\x{016F}\x{00FC}\x{0171}\x{0169}\x{0173}\x{016B}\x{0175}\x{00FD}\x{0177}\x{00FF}\x{017A}' .
+                '\x{017E}\x{017C}\x{00F0}\x{00FE}';
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Hostname/Fi.php b/lib/Zend/Validate/Hostname/Fi.php
new file mode 100644
index 0000000..a28ba56
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/Fi.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Fi.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_Fi implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html Finland (.FI)
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return '\x{00E5}\x{00E4}\x{00F6}';
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Hostname/Hu.php b/lib/Zend/Validate/Hostname/Hu.php
new file mode 100644
index 0000000..e6f9795
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/Hu.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Hu.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_Hu implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see http://www.domain.hu/domain/English/szabalyzat.html Hungary (.HU)
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return '\x{00E1}\x{00E9}\x{00ED}\x{00F3}\x{00F6}\x{0151}\x{00FA}\x{00FC}\x{0171}';
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Hostname/Interface.php b/lib/Zend/Validate/Hostname/Interface.php
new file mode 100644
index 0000000..4426d8b
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/Interface.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Interface.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * UTF-8 characters should be written as four character hex codes \x{XXXX}
+     * For example é (lowercase e with acute) is represented by the hex code \x{00E9}
+     *
+     * You only need to include lower-case equivalents of characters since the hostname
+     * check is case-insensitive
+     *
+     * Please document the supported TLDs in the documentation file at:
+     * manual/en/module_specs/Zend_Validate-Hostname.xml
+     *
+     * @see http://en.wikipedia.org/wiki/Internationalized_domain_name
+     * @see http://www.iana.org/cctld/ Country-Code Top-Level Domains (TLDs)
+     * @see http://www.columbia.edu/kermit/utf8-t1.html UTF-8 characters
+     * @return string
+     */
+    static function getCharacters();
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Hostname/Li.php b/lib/Zend/Validate/Hostname/Li.php
new file mode 100644
index 0000000..0739c93
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/Li.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Li.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_Li implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1 Liechtenstein (.LI)
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return '\x{00EO}-\x{00F6}\x{00F8}-\x{00FF}\x{0153}';
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Hostname/No.php b/lib/Zend/Validate/Hostname/No.php
new file mode 100644
index 0000000..d0d4c67
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/No.php
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: No.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_No implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html Norway (.NO)
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return  '\x00E1\x00E0\x00E4\x010D\x00E7\x0111\x00E9\x00E8\x00EA\x\x014B' .
+                '\x0144\x00F1\x00F3\x00F2\x00F4\x00F6\x0161\x0167\x00FC\x017E\x00E6' .
+                '\x00F8\x00E5';
+    }
+
+}
diff --git a/lib/Zend/Validate/Hostname/Se.php b/lib/Zend/Validate/Hostname/Se.php
new file mode 100644
index 0000000..6f181cb
--- /dev/null
+++ b/lib/Zend/Validate/Hostname/Se.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Se.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Hostname_Interface
+ */
+require_once 'Zend/Validate/Hostname/Interface.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Hostname_Se implements Zend_Validate_Hostname_Interface
+{
+
+    /**
+     * Returns UTF-8 characters allowed in DNS hostnames for the specified Top-Level-Domain
+     *
+     * @see http://www.iis.se/english/IDN_campaignsite.shtml?lang=en Sweden (.SE)
+     * @return string
+     */
+    static function getCharacters()
+    {
+        return '\x{00E5}\x{00E4}\x{00F6}\x{00FC}\x{00E9}';
+    }
+
+}
\ No newline at end of file
diff --git a/lib/Zend/Validate/Identical.php b/lib/Zend/Validate/Identical.php
new file mode 100644
index 0000000..02a5366
--- /dev/null
+++ b/lib/Zend/Validate/Identical.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Identical.php 8118 2008-02-18 16:10:32Z matthew $
+ */
+
+/** Zend_Validate_Abstract */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Identical extends Zend_Validate_Abstract
+{
+    /**#@+
+     * Error codes
+     * @const string
+     */
+    const NOT_SAME      = 'notSame';
+    const MISSING_TOKEN = 'missingToken';
+    /**#@-*/
+
+    /**
+     * Error messages
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_SAME      => 'Tokens do not match',
+        self::MISSING_TOKEN => 'No token was provided to match against',
+    );
+
+    /**
+     * Original token against which to validate
+     * @var string
+     */
+    protected $_token;
+
+    /**
+     * Sets validator options
+     *
+     * @param  string $token
+     * @return void
+     */
+    public function __construct($token = null)
+    {
+        if (null !== $token) {
+            $this->setToken($token);
+        }
+    }
+
+    /**
+     * Set token against which to compare
+     * 
+     * @param  string $token 
+     * @return Zend_Validate_Identical
+     */
+    public function setToken($token)
+    {
+        $this->_token = (string) $token;
+        return $this;
+    }
+
+    /**
+     * Retrieve token
+     * 
+     * @return string
+     */
+    public function getToken()
+    {
+        return $this->_token;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if a token has been set and the provided value 
+     * matches that token.
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_setValue($value);
+        $token = $this->getToken();
+
+        if (empty($token)) {
+            $this->_error(self::MISSING_TOKEN);
+            return false;
+        }
+
+        if ($value !== $token)  {
+            $this->_error(self::NOT_SAME);
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/lib/Zend/Validate/InArray.php b/lib/Zend/Validate/InArray.php
new file mode 100644
index 0000000..1c7725a
--- /dev/null
+++ b/lib/Zend/Validate/InArray.php
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: InArray.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_InArray extends Zend_Validate_Abstract
+{
+
+    const NOT_IN_ARRAY = 'notInArray';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_IN_ARRAY => "'%value%' was not found in the haystack"
+    );
+
+    /**
+     * Haystack of possible values
+     *
+     * @var array
+     */
+    protected $_haystack;
+
+    /**
+     * Whether a strict in_array() invocation is used
+     *
+     * @var boolean
+     */
+    protected $_strict;
+
+    /**
+     * Sets validator options
+     *
+     * @param  array   $haystack
+     * @param  boolean $strict
+     * @return void
+     */
+    public function __construct(array $haystack, $strict = false)
+    {
+        $this->setHaystack($haystack)
+             ->setStrict($strict);
+    }
+
+    /**
+     * Returns the haystack option
+     *
+     * @return mixed
+     */
+    public function getHaystack()
+    {
+        return $this->_haystack;
+    }
+
+    /**
+     * Sets the haystack option
+     *
+     * @param  mixed $haystack
+     * @return Zend_Validate_InArray Provides a fluent interface
+     */
+    public function setHaystack(array $haystack)
+    {
+        $this->_haystack = $haystack;
+        return $this;
+    }
+
+    /**
+     * Returns the strict option
+     *
+     * @return boolean
+     */
+    public function getStrict()
+    {
+        return $this->_strict;
+    }
+
+    /**
+     * Sets the strict option
+     *
+     * @param  boolean $strict
+     * @return Zend_Validate_InArray Provides a fluent interface
+     */
+    public function setStrict($strict)
+    {
+        $this->_strict = $strict;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is contained in the haystack option. If the strict
+     * option is true, then the type of $value is also checked.
+     *
+     * @param  mixed $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_setValue($value);
+        if (!in_array($value, $this->_haystack, $this->_strict)) {
+            $this->_error();
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Int.php b/lib/Zend/Validate/Int.php
new file mode 100644
index 0000000..1fa0744
--- /dev/null
+++ b/lib/Zend/Validate/Int.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Int.php 12336 2008-11-06 19:11:46Z thomas $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Int extends Zend_Validate_Abstract
+{
+    const NOT_INT = 'notInt';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_INT => "'%value%' does not appear to be an integer"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is a valid integer
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+        $this->_setValue($valueString);
+        if (is_bool($value)) {
+            $this->_error();
+            return false;
+        }
+
+        $locale        = localeconv();
+        $valueFiltered = str_replace($locale['decimal_point'], '.', $valueString);
+        $valueFiltered = str_replace($locale['thousands_sep'], '', $valueFiltered);
+
+        if (strval(intval($valueFiltered)) != $valueFiltered) {
+            $this->_error();
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Interface.php b/lib/Zend/Validate/Interface.php
new file mode 100644
index 0000000..4fcd525
--- /dev/null
+++ b/lib/Zend/Validate/Interface.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Interface.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Validate_Interface
+{
+    /**
+     * Returns true if and only if $value meets the validation requirements
+     *
+     * If $value fails validation, then this method returns false, and
+     * getMessages() will return an array of messages that explain why the
+     * validation failed.
+     *
+     * @param  mixed $value
+     * @return boolean
+     * @throws Zend_Valid_Exception If validation of $value is impossible
+     */
+    public function isValid($value);
+
+    /**
+     * Returns an array of messages that explain why the most recent isValid()
+     * call returned false. The array keys are validation failure message identifiers,
+     * and the array values are the corresponding human-readable message strings.
+     *
+     * If isValid() was never called or if the most recent isValid() call
+     * returned true, then this method returns an empty array.
+     *
+     * @return array
+     */
+    public function getMessages();
+
+    /**
+     * Returns an array of message codes that explain why a previous isValid() call
+     * returned false.
+     *
+     * If isValid() was never called or if the most recent isValid() call
+     * returned true, then this method returns an empty array.
+     *
+     * This is now the same as calling array_keys() on the return value from getMessages().
+     *
+     * @return array
+     * @deprecated Since 1.5.0
+     */
+    public function getErrors();
+
+}
diff --git a/lib/Zend/Validate/Ip.php b/lib/Zend/Validate/Ip.php
new file mode 100644
index 0000000..67dc95f
--- /dev/null
+++ b/lib/Zend/Validate/Ip.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Ip.php 13289 2008-12-15 23:18:58Z tjohns $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Ip extends Zend_Validate_Abstract
+{
+    const NOT_IP_ADDRESS = 'notIpAddress';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_IP_ADDRESS => "'%value%' does not appear to be a valid IP address"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is a valid IP address
+     *
+     * @param  mixed $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        if ((ip2long($valueString) === false) || (long2ip(ip2long($valueString)) !== $valueString)) {
+            if (!function_exists('inet_pton')) {
+                $this->_error();
+                return false;
+            } else if ((@inet_pton($value) === false) ||(inet_ntop(@inet_pton($value)) !== $valueString)) {
+                $this->_error();
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/LessThan.php b/lib/Zend/Validate/LessThan.php
new file mode 100644
index 0000000..9f7b72c
--- /dev/null
+++ b/lib/Zend/Validate/LessThan.php
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: LessThan.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_LessThan extends Zend_Validate_Abstract
+{
+
+    const NOT_LESS = 'notLessThan';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_LESS => "'%value%' is not less than '%max%'"
+    );
+
+    /**
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'max' => '_max'
+    );
+
+    /**
+     * Maximum value
+     *
+     * @var mixed
+     */
+    protected $_max;
+
+    /**
+     * Sets validator options
+     *
+     * @param  mixed $max
+     * @return void
+     */
+    public function __construct($max)
+    {
+        $this->setMax($max);
+    }
+
+    /**
+     * Returns the max option
+     *
+     * @return mixed
+     */
+    public function getMax()
+    {
+        return $this->_max;
+    }
+
+    /**
+     * Sets the max option
+     *
+     * @param  mixed $max
+     * @return Zend_Validate_LessThan Provides a fluent interface
+     */
+    public function setMax($max)
+    {
+        $this->_max = $max;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is less than max option
+     *
+     * @param  mixed $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_setValue($value);
+        if ($this->_max <= $value) {
+            $this->_error();
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/NotEmpty.php b/lib/Zend/Validate/NotEmpty.php
new file mode 100644
index 0000000..ce5b1d3
--- /dev/null
+++ b/lib/Zend/Validate/NotEmpty.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: NotEmpty.php 13249 2008-12-14 19:29:40Z thomas $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_NotEmpty extends Zend_Validate_Abstract
+{
+    const IS_EMPTY = 'isEmpty';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::IS_EMPTY => "Value is required and can't be empty"
+    );
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value is not an empty value.
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $this->_setValue((string) $value);
+
+        if (is_string($value)
+            && (('' === $value)
+                || preg_match('/^\s+$/s', $value))
+        ) {
+            $this->_error();
+            return false;
+        } elseif (!is_string($value) && empty($value)) {
+            $this->_error();
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/Regex.php b/lib/Zend/Validate/Regex.php
new file mode 100644
index 0000000..1566f07
--- /dev/null
+++ b/lib/Zend/Validate/Regex.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Regex.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_Regex extends Zend_Validate_Abstract
+{
+
+    const NOT_MATCH = 'regexNotMatch';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::NOT_MATCH => "'%value%' does not match against pattern '%pattern%'"
+    );
+
+    /**
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'pattern' => '_pattern'
+    );
+
+    /**
+     * Regular expression pattern
+     *
+     * @var string
+     */
+    protected $_pattern;
+
+    /**
+     * Sets validator options
+     *
+     * @param  string $pattern
+     * @return void
+     */
+    public function __construct($pattern)
+    {
+        $this->setPattern($pattern);
+    }
+
+    /**
+     * Returns the pattern option
+     *
+     * @return string
+     */
+    public function getPattern()
+    {
+        return $this->_pattern;
+    }
+
+    /**
+     * Sets the pattern option
+     *
+     * @param  string $pattern
+     * @return Zend_Validate_Regex Provides a fluent interface
+     */
+    public function setPattern($pattern)
+    {
+        $this->_pattern = (string) $pattern;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if $value matches against the pattern option
+     *
+     * @param  string $value
+     * @throws Zend_Validate_Exception if there is a fatal error in pattern matching
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+
+        $this->_setValue($valueString);
+
+        $status = @preg_match($this->_pattern, $valueString);
+        if (false === $status) {
+            /**
+             * @see Zend_Validate_Exception
+             */
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("Internal error matching pattern '$this->_pattern' against value '$valueString'");
+        }
+        if (!$status) {
+            $this->_error();
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/lib/Zend/Validate/StringLength.php b/lib/Zend/Validate/StringLength.php
new file mode 100644
index 0000000..caf3d4d
--- /dev/null
+++ b/lib/Zend/Validate/StringLength.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: StringLength.php 13278 2008-12-15 19:55:17Z thomas $
+ */
+
+/**
+ * @see Zend_Validate_Abstract
+ */
+require_once 'Zend/Validate/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Validate
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Validate_StringLength extends Zend_Validate_Abstract
+{
+    const TOO_SHORT = 'stringLengthTooShort';
+    const TOO_LONG  = 'stringLengthTooLong';
+
+    /**
+     * @var array
+     */
+    protected $_messageTemplates = array(
+        self::TOO_SHORT => "'%value%' is less than %min% characters long",
+        self::TOO_LONG  => "'%value%' is greater than %max% characters long"
+    );
+
+    /**
+     * @var array
+     */
+    protected $_messageVariables = array(
+        'min' => '_min',
+        'max' => '_max'
+    );
+
+    /**
+     * Minimum length
+     *
+     * @var integer
+     */
+    protected $_min;
+
+    /**
+     * Maximum length
+     *
+     * If null, there is no maximum length
+     *
+     * @var integer|null
+     */
+    protected $_max;
+
+    /**
+     * Encoding to use
+     *
+     * @var string|null
+     */
+    protected $_encoding;
+
+    /**
+     * Sets validator options
+     *
+     * @param  integer $min
+     * @param  integer $max
+     * @return void
+     */
+    public function __construct($min = 0, $max = null, $encoding = null)
+    {
+        $this->setMin($min);
+        $this->setMax($max);
+        $this->setEncoding($encoding);
+    }
+
+    /**
+     * Returns the min option
+     *
+     * @return integer
+     */
+    public function getMin()
+    {
+        return $this->_min;
+    }
+
+    /**
+     * Sets the min option
+     *
+     * @param  integer $min
+     * @throws Zend_Validate_Exception
+     * @return Zend_Validate_StringLength Provides a fluent interface
+     */
+    public function setMin($min)
+    {
+        if (null !== $this->_max && $min > $this->_max) {
+            /**
+             * @see Zend_Validate_Exception
+             */
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("The minimum must be less than or equal to the maximum length, but $min >"
+                                            . " $this->_max");
+        }
+        $this->_min = max(0, (integer) $min);
+        return $this;
+    }
+
+    /**
+     * Returns the max option
+     *
+     * @return integer|null
+     */
+    public function getMax()
+    {
+        return $this->_max;
+    }
+
+    /**
+     * Sets the max option
+     *
+     * @param  integer|null $max
+     * @throws Zend_Validate_Exception
+     * @return Zend_Validate_StringLength Provides a fluent interface
+     */
+    public function setMax($max)
+    {
+        if (null === $max) {
+            $this->_max = null;
+        } else if ($max < $this->_min) {
+            /**
+             * @see Zend_Validate_Exception
+             */
+            require_once 'Zend/Validate/Exception.php';
+            throw new Zend_Validate_Exception("The maximum must be greater than or equal to the minimum length, but "
+                                            . "$max < $this->_min");
+        } else {
+            $this->_max = (integer) $max;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Returns the actual encoding
+     *
+     * @return string
+     */
+    public function getEncoding()
+    {
+        return $this->_encoding;
+    }
+
+    /**
+     * Sets a new encoding to use
+     *
+     * @param string $encoding
+     * @return Zend_Validate_StringLength
+     */
+    public function setEncoding($encoding = null)
+    {
+        if ($encoding !== null) {
+            $orig   = iconv_get_encoding('internal_encoding');
+            $result = iconv_set_encoding('internal_encoding', $encoding);
+            if (!$result) {
+                require_once 'Zend/Validate/Exception.php';
+                throw new Zend_Validate_Exception('Given encoding not supported on this OS!');
+            }
+
+            iconv_set_encoding('internal_encoding', $orig);
+        }
+
+        $this->_encoding = $encoding;
+        return $this;
+    }
+
+    /**
+     * Defined by Zend_Validate_Interface
+     *
+     * Returns true if and only if the string length of $value is at least the min option and
+     * no greater than the max option (when the max option is not null).
+     *
+     * @param  string $value
+     * @return boolean
+     */
+    public function isValid($value)
+    {
+        $valueString = (string) $value;
+        $this->_setValue($valueString);
+        if ($this->_encoding !== null) {
+            $length = iconv_strlen($valueString, $this->_encoding);
+        } else {
+            $length = iconv_strlen($valueString);
+        }
+
+        if ($length < $this->_min) {
+            $this->_error(self::TOO_SHORT);
+        }
+
+        if (null !== $this->_max && $this->_max < $length) {
+            $this->_error(self::TOO_LONG);
+        }
+
+        if (count($this->_messages)) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+}
-- 
cgit v1.2.3