Page MenuHomePhorge

No OneTemporary

Size
75 KB
Referenced Files
None
Subscribers
None
This document is not UTF8. It was detected as ISO-8859-1 (Latin 1) and converted to UTF8 for display.
diff --git a/lib/ext/PEAR.php b/lib/ext/PEAR.php
new file mode 100644
index 0000000..f4dfd96
--- /dev/null
+++ b/lib/ext/PEAR.php
@@ -0,0 +1,1137 @@
+<?php
+/**
+ * PEAR, the PHP Extension and Application Repository
+ *
+ * PEAR class and PEAR_Error class
+ *
+ * PHP versions 4 and 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Sterling Hughes <sterling@php.net>
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V.Cox <cox@idecnet.com>
+ * @author Greg Beaver <cellog@php.net>
+ * @copyright 1997-2009 The Authors
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version CVS: $Id$
+ * @link http://pear.php.net/package/PEAR
+ * @since File available since Release 0.1
+ */
+
+/**#@+
+ * ERROR constants
+ */
+define('PEAR_ERROR_RETURN', 1);
+define('PEAR_ERROR_PRINT', 2);
+define('PEAR_ERROR_TRIGGER', 4);
+define('PEAR_ERROR_DIE', 8);
+define('PEAR_ERROR_CALLBACK', 16);
+/**
+ * WARNING: obsolete
+ * @deprecated
+ */
+define('PEAR_ERROR_EXCEPTION', 32);
+/**#@-*/
+define('PEAR_ZE2', (function_exists('version_compare') &&
+ version_compare(zend_version(), "2-dev", "ge")));
+
+if (substr(PHP_OS, 0, 3) == 'WIN') {
+ define('OS_WINDOWS', true);
+ define('OS_UNIX', false);
+ define('PEAR_OS', 'Windows');
+} else {
+ define('OS_WINDOWS', false);
+ define('OS_UNIX', true);
+ define('PEAR_OS', 'Unix'); // blatant assumption
+}
+
+$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
+$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
+$GLOBALS['_PEAR_destructor_object_list'] = array();
+$GLOBALS['_PEAR_shutdown_funcs'] = array();
+$GLOBALS['_PEAR_error_handler_stack'] = array();
+
+@ini_set('track_errors', true);
+
+/**
+ * Base class for other PEAR classes. Provides rudimentary
+ * emulation of destructors.
+ *
+ * If you want a destructor in your class, inherit PEAR and make a
+ * destructor method called _yourclassname (same name as the
+ * constructor, but with a "_" prefix). Also, in your constructor you
+ * have to call the PEAR constructor: $this->PEAR();.
+ * The destructor method will be called without parameters. Note that
+ * at in some SAPI implementations (such as Apache), any output during
+ * the request shutdown (in which destructors are called) seems to be
+ * discarded. If you need to get any debug information from your
+ * destructor, use error_log(), syslog() or something similar.
+ *
+ * IMPORTANT! To use the emulated destructors you need to create the
+ * objects by reference: $obj =& new PEAR_child;
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V. Cox <cox@idecnet.com>
+ * @author Greg Beaver <cellog@php.net>
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.9.0
+ * @link http://pear.php.net/package/PEAR
+ * @see PEAR_Error
+ * @since Class available since PHP 4.0.2
+ * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear
+ */
+class PEAR
+{
+ // {{{ properties
+
+ /**
+ * Whether to enable internal debug messages.
+ *
+ * @var bool
+ * @access private
+ */
+ var $_debug = false;
+
+ /**
+ * Default error mode for this object.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_mode = null;
+
+ /**
+ * Default error options used for this object when error mode
+ * is PEAR_ERROR_TRIGGER.
+ *
+ * @var int
+ * @access private
+ */
+ var $_default_error_options = null;
+
+ /**
+ * Default error handler (callback) for this object, if error mode is
+ * PEAR_ERROR_CALLBACK.
+ *
+ * @var string
+ * @access private
+ */
+ var $_default_error_handler = '';
+
+ /**
+ * Which class to use for error objects.
+ *
+ * @var string
+ * @access private
+ */
+ var $_error_class = 'PEAR_Error';
+
+ /**
+ * An array of expected errors.
+ *
+ * @var array
+ * @access private
+ */
+ var $_expected_errors = array();
+
+ // }}}
+
+ // {{{ constructor
+
+ /**
+ * Constructor. Registers this object in
+ * $_PEAR_destructor_object_list for destructor emulation if a
+ * destructor object exists.
+ *
+ * @param string $error_class (optional) which class to use for
+ * error objects, defaults to PEAR_Error.
+ * @access public
+ * @return void
+ */
+ function PEAR($error_class = null)
+ {
+ $classname = strtolower(get_class($this));
+ if ($this->_debug) {
+ print "PEAR constructor called, class=$classname\n";
+ }
+ if ($error_class !== null) {
+ $this->_error_class = $error_class;
+ }
+ while ($classname && strcasecmp($classname, "pear")) {
+ $destructor = "_$classname";
+ if (method_exists($this, $destructor)) {
+ global $_PEAR_destructor_object_list;
+ $_PEAR_destructor_object_list[] = &$this;
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+
+ // }}}
+ // {{{ destructor
+
+ /**
+ * Destructor (the emulated type of...). Does nothing right now,
+ * but is included for forward compatibility, so subclass
+ * destructors should always call it.
+ *
+ * See the note in the class desciption about output from
+ * destructors.
+ *
+ * @access public
+ * @return void
+ */
+ function _PEAR() {
+ if ($this->_debug) {
+ printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
+ }
+ }
+
+ // }}}
+ // {{{ getStaticProperty()
+
+ /**
+ * If you have a class that's mostly/entirely static, and you need static
+ * properties, you can use this method to simulate them. Eg. in your method(s)
+ * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
+ * You MUST use a reference, or they will not persist!
+ *
+ * @access public
+ * @param string $class The calling classname, to prevent clashes
+ * @param string $var The variable to retrieve.
+ * @return mixed A reference to the variable. If not set it will be
+ * auto initialised to NULL.
+ */
+ function &getStaticProperty($class, $var)
+ {
+ static $properties;
+ if (!isset($properties[$class])) {
+ $properties[$class] = array();
+ }
+
+ if (!array_key_exists($var, $properties[$class])) {
+ $properties[$class][$var] = null;
+ }
+
+ return $properties[$class][$var];
+ }
+
+ // }}}
+ // {{{ registerShutdownFunc()
+
+ /**
+ * Use this function to register a shutdown method for static
+ * classes.
+ *
+ * @access public
+ * @param mixed $func The function name (or array of class/method) to call
+ * @param mixed $args The arguments to pass to the function
+ * @return void
+ */
+ function registerShutdownFunc($func, $args = array())
+ {
+ // if we are called statically, there is a potential
+ // that no shutdown func is registered. Bug #6445
+ if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
+ register_shutdown_function("_PEAR_call_destructors");
+ $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
+ }
+ $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
+ }
+
+ // }}}
+ // {{{ isError()
+
+ /**
+ * Tell whether a value is a PEAR error.
+ *
+ * @param mixed $data the value to test
+ * @param int $code if $data is an error object, return true
+ * only if $code is a string and
+ * $obj->getMessage() == $code or
+ * $code is an integer and $obj->getCode() == $code
+ * @access public
+ * @return bool true if parameter is an error
+ */
+ static function isError($data, $code = null)
+ {
+ if (!is_object($data) || !is_a($data, 'PEAR_Error')) {
+ return false;
+ }
+
+ if (is_null($code)) {
+ return true;
+ } elseif (is_string($code)) {
+ return $data->getMessage() == $code;
+ }
+
+ return $data->getCode() == $code;
+ }
+
+ // }}}
+ // {{{ setErrorHandling()
+
+ /**
+ * Sets how errors generated by this object should be handled.
+ * Can be invoked both in objects and statically. If called
+ * statically, setErrorHandling sets the default behaviour for all
+ * PEAR objects. If called in an object, setErrorHandling sets
+ * the default behaviour for that object.
+ *
+ * @param int $mode
+ * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options
+ * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
+ * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ *
+ * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
+ * to be the callback function or method. A callback
+ * function is a string with the name of the function, a
+ * callback method is an array of two elements: the element
+ * at index 0 is the object, and the element at index 1 is
+ * the name of the method to call in the object.
+ *
+ * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
+ * a printf format string used when printing the error
+ * message.
+ *
+ * @access public
+ * @return void
+ * @see PEAR_ERROR_RETURN
+ * @see PEAR_ERROR_PRINT
+ * @see PEAR_ERROR_TRIGGER
+ * @see PEAR_ERROR_DIE
+ * @see PEAR_ERROR_CALLBACK
+ * @see PEAR_ERROR_EXCEPTION
+ *
+ * @since PHP 4.0.5
+ */
+
+ function setErrorHandling($mode = null, $options = null)
+ {
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $setmode = &$this->_default_error_mode;
+ $setoptions = &$this->_default_error_options;
+ } else {
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ }
+
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ }
+
+ // }}}
+ // {{{ expectError()
+
+ /**
+ * This method is used to tell which errors you expect to get.
+ * Expected errors are always returned with error mode
+ * PEAR_ERROR_RETURN. Expected error codes are stored in a stack,
+ * and this method pushes a new element onto it. The list of
+ * expected errors are in effect until they are popped off the
+ * stack with the popExpect() method.
+ *
+ * Note that this method can not be called statically
+ *
+ * @param mixed $code a single error code or an array of error codes to expect
+ *
+ * @return int the new depth of the "expected errors" stack
+ * @access public
+ */
+ function expectError($code = '*')
+ {
+ if (is_array($code)) {
+ array_push($this->_expected_errors, $code);
+ } else {
+ array_push($this->_expected_errors, array($code));
+ }
+ return sizeof($this->_expected_errors);
+ }
+
+ // }}}
+ // {{{ popExpect()
+
+ /**
+ * This method pops one element off the expected error codes
+ * stack.
+ *
+ * @return array the list of error codes that were popped
+ */
+ function popExpect()
+ {
+ return array_pop($this->_expected_errors);
+ }
+
+ // }}}
+ // {{{ _checkDelExpect()
+
+ /**
+ * This method checks unsets an error code if available
+ *
+ * @param mixed error code
+ * @return bool true if the error code was unset, false otherwise
+ * @access private
+ * @since PHP 4.3.0
+ */
+ function _checkDelExpect($error_code)
+ {
+ $deleted = false;
+
+ foreach ($this->_expected_errors AS $key => $error_array) {
+ if (in_array($error_code, $error_array)) {
+ unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
+ $deleted = true;
+ }
+
+ // clean up empty arrays
+ if (0 == count($this->_expected_errors[$key])) {
+ unset($this->_expected_errors[$key]);
+ }
+ }
+ return $deleted;
+ }
+
+ // }}}
+ // {{{ delExpect()
+
+ /**
+ * This method deletes all occurences of the specified element from
+ * the expected error codes stack.
+ *
+ * @param mixed $error_code error code that should be deleted
+ * @return mixed list of error codes that were deleted or error
+ * @access public
+ * @since PHP 4.3.0
+ */
+ function delExpect($error_code)
+ {
+ $deleted = false;
+ if ((is_array($error_code) && (0 != count($error_code)))) {
+ // $error_code is a non-empty array here;
+ // we walk through it trying to unset all
+ // values
+ foreach($error_code as $key => $error) {
+ if ($this->_checkDelExpect($error)) {
+ $deleted = true;
+ } else {
+ $deleted = false;
+ }
+ }
+ return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ } elseif (!empty($error_code)) {
+ // $error_code comes alone, trying to unset it
+ if ($this->_checkDelExpect($error_code)) {
+ return true;
+ } else {
+ return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
+ }
+ }
+
+ // $error_code is empty
+ return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
+ }
+
+ // }}}
+ // {{{ raiseError()
+
+ /**
+ * This method is a wrapper that returns an instance of the
+ * configured error class with this object's default error
+ * handling applied. If the $mode and $options parameters are not
+ * specified, the object's defaults are used.
+ *
+ * @param mixed $message a text error message or a PEAR error object
+ *
+ * @param int $code a numeric error code (it is up to your class
+ * to define these if you want to use codes)
+ *
+ * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
+ * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
+ * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
+ *
+ * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
+ * specifies the PHP-internal error level (one of
+ * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
+ * If $mode is PEAR_ERROR_CALLBACK, this
+ * parameter specifies the callback function or
+ * method. In other error modes this parameter
+ * is ignored.
+ *
+ * @param string $userinfo If you need to pass along for example debug
+ * information, this parameter is meant for that.
+ *
+ * @param string $error_class The returned error object will be
+ * instantiated from this class, if specified.
+ *
+ * @param bool $skipmsg If true, raiseError will only pass error codes,
+ * the error message parameter will be dropped.
+ *
+ * @access public
+ * @return object a PEAR error object
+ * @see PEAR::setErrorHandling
+ * @since PHP 4.0.5
+ */
+ function &raiseError($message = null,
+ $code = null,
+ $mode = null,
+ $options = null,
+ $userinfo = null,
+ $error_class = null,
+ $skipmsg = false)
+ {
+ // The error is yet a PEAR error object
+ if (is_object($message)) {
+ $code = $message->getCode();
+ $userinfo = $message->getUserInfo();
+ $error_class = $message->getType();
+ $message->error_message_prefix = '';
+ $message = $message->getMessage();
+ }
+
+ if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
+ if ($exp[0] == "*" ||
+ (is_int(reset($exp)) && in_array($code, $exp)) ||
+ (is_string(reset($exp)) && in_array($message, $exp))) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ }
+
+ // No mode given, try global ones
+ if ($mode === null) {
+ // Class error handler
+ if (isset($this) && isset($this->_default_error_mode)) {
+ $mode = $this->_default_error_mode;
+ $options = $this->_default_error_options;
+ // Global error handler
+ } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
+ $mode = $GLOBALS['_PEAR_default_error_mode'];
+ $options = $GLOBALS['_PEAR_default_error_options'];
+ }
+ }
+
+ if ($error_class !== null) {
+ $ec = $error_class;
+ } elseif (isset($this) && isset($this->_error_class)) {
+ $ec = $this->_error_class;
+ } else {
+ $ec = 'PEAR_Error';
+ }
+
+ if (intval(PHP_VERSION) < 5) {
+ // little non-eval hack to fix bug #12147
+ include 'PEAR/FixPHP5PEARWarnings.php';
+ return $a;
+ }
+
+ if ($skipmsg) {
+ $a = new $ec($code, $mode, $options, $userinfo);
+ } else {
+ $a = new $ec($message, $code, $mode, $options, $userinfo);
+ }
+
+ return $a;
+ }
+
+ // }}}
+ // {{{ throwError()
+
+ /**
+ * Simpler form of raiseError with fewer options. In most cases
+ * message, code and userinfo are enough.
+ *
+ * @param string $message
+ *
+ */
+ function &throwError($message = null,
+ $code = null,
+ $userinfo = null)
+ {
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $a = &$this->raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ }
+
+ $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
+ return $a;
+ }
+
+ // }}}
+ function staticPushErrorHandling($mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ $stack[] = array($def_mode, $def_options);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $def_mode = $mode;
+ $def_options = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $def_mode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $def_options = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ function staticPopErrorHandling()
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ $setmode = &$GLOBALS['_PEAR_default_error_mode'];
+ $setoptions = &$GLOBALS['_PEAR_default_error_options'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ switch ($mode) {
+ case PEAR_ERROR_EXCEPTION:
+ case PEAR_ERROR_RETURN:
+ case PEAR_ERROR_PRINT:
+ case PEAR_ERROR_TRIGGER:
+ case PEAR_ERROR_DIE:
+ case null:
+ $setmode = $mode;
+ $setoptions = $options;
+ break;
+
+ case PEAR_ERROR_CALLBACK:
+ $setmode = $mode;
+ // class/object method callback
+ if (is_callable($options)) {
+ $setoptions = $options;
+ } else {
+ trigger_error("invalid error callback", E_USER_WARNING);
+ }
+ break;
+
+ default:
+ trigger_error("invalid error mode", E_USER_WARNING);
+ break;
+ }
+ return true;
+ }
+
+ // {{{ pushErrorHandling()
+
+ /**
+ * Push a new error handler on top of the error handler options stack. With this
+ * you can easily override the actual error handler for some code and restore
+ * it later with popErrorHandling.
+ *
+ * @param mixed $mode (same as setErrorHandling)
+ * @param mixed $options (same as setErrorHandling)
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::setErrorHandling
+ */
+ function pushErrorHandling($mode, $options = null)
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $def_mode = &$this->_default_error_mode;
+ $def_options = &$this->_default_error_options;
+ } else {
+ $def_mode = &$GLOBALS['_PEAR_default_error_mode'];
+ $def_options = &$GLOBALS['_PEAR_default_error_options'];
+ }
+ $stack[] = array($def_mode, $def_options);
+
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $this->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ $stack[] = array($mode, $options);
+ return true;
+ }
+
+ // }}}
+ // {{{ popErrorHandling()
+
+ /**
+ * Pop the last error handler used
+ *
+ * @return bool Always true
+ *
+ * @see PEAR::pushErrorHandling
+ */
+ function popErrorHandling()
+ {
+ $stack = &$GLOBALS['_PEAR_error_handler_stack'];
+ array_pop($stack);
+ list($mode, $options) = $stack[sizeof($stack) - 1];
+ array_pop($stack);
+ if (isset($this) && is_a($this, 'PEAR')) {
+ $this->setErrorHandling($mode, $options);
+ } else {
+ PEAR::setErrorHandling($mode, $options);
+ }
+ return true;
+ }
+
+ // }}}
+ // {{{ loadExtension()
+
+ /**
+ * OS independant PHP extension load. Remember to take care
+ * on the correct extension name for case sensitive OSes.
+ *
+ * @param string $ext The extension name
+ * @return bool Success or not on the dl() call
+ */
+ function loadExtension($ext)
+ {
+ if (!extension_loaded($ext)) {
+ // if either returns true dl() will produce a FATAL error, stop that
+ if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
+ return false;
+ }
+
+ if (OS_WINDOWS) {
+ $suffix = '.dll';
+ } elseif (PHP_OS == 'HP-UX') {
+ $suffix = '.sl';
+ } elseif (PHP_OS == 'AIX') {
+ $suffix = '.a';
+ } elseif (PHP_OS == 'OSX') {
+ $suffix = '.bundle';
+ } else {
+ $suffix = '.so';
+ }
+
+ return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
+ }
+
+ return true;
+ }
+
+ // }}}
+}
+
+if (PEAR_ZE2) {
+ include_once 'PEAR5.php';
+}
+
+// {{{ _PEAR_call_destructors()
+
+function _PEAR_call_destructors()
+{
+ global $_PEAR_destructor_object_list;
+ if (is_array($_PEAR_destructor_object_list) &&
+ sizeof($_PEAR_destructor_object_list))
+ {
+ reset($_PEAR_destructor_object_list);
+ if (PEAR_ZE2) {
+ $destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo');
+ } else {
+ $destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
+ }
+
+ if ($destructLifoExists) {
+ $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
+ }
+
+ while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
+ $classname = get_class($objref);
+ while ($classname) {
+ $destructor = "_$classname";
+ if (method_exists($objref, $destructor)) {
+ $objref->$destructor();
+ break;
+ } else {
+ $classname = get_parent_class($classname);
+ }
+ }
+ }
+ // Empty the object list to ensure that destructors are
+ // not called more than once.
+ $_PEAR_destructor_object_list = array();
+ }
+
+ // Now call the shutdown functions
+ if (isset($GLOBALS['_PEAR_shutdown_funcs']) AND is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
+ foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
+ call_user_func_array($value[0], $value[1]);
+ }
+ }
+}
+
+// }}}
+/**
+ * Standard PEAR error class for PHP 4
+ *
+ * This class is supserseded by {@link PEAR_Exception} in PHP 5
+ *
+ * @category pear
+ * @package PEAR
+ * @author Stig Bakken <ssb@php.net>
+ * @author Tomas V.V. Cox <cox@idecnet.com>
+ * @author Gregory Beaver <cellog@php.net>
+ * @copyright 1997-2006 The PHP Group
+ * @license http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version Release: 1.9.0
+ * @link http://pear.php.net/manual/en/core.pear.pear-error.php
+ * @see PEAR::raiseError(), PEAR::throwError()
+ * @since Class available since PHP 4.0.2
+ */
+class PEAR_Error
+{
+ // {{{ properties
+
+ var $error_message_prefix = '';
+ var $mode = PEAR_ERROR_RETURN;
+ var $level = E_USER_NOTICE;
+ var $code = -1;
+ var $message = '';
+ var $userinfo = '';
+ var $backtrace = null;
+
+ // }}}
+ // {{{ constructor
+
+ /**
+ * PEAR_Error constructor
+ *
+ * @param string $message message
+ *
+ * @param int $code (optional) error code
+ *
+ * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN,
+ * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
+ * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
+ *
+ * @param mixed $options (optional) error level, _OR_ in the case of
+ * PEAR_ERROR_CALLBACK, the callback function or object/method
+ * tuple.
+ *
+ * @param string $userinfo (optional) additional user/debug info
+ *
+ * @access public
+ *
+ */
+ function PEAR_Error($message = 'unknown error', $code = null,
+ $mode = null, $options = null, $userinfo = null)
+ {
+ if ($mode === null) {
+ $mode = PEAR_ERROR_RETURN;
+ }
+ $this->message = $message;
+ $this->code = $code;
+ $this->mode = $mode;
+ $this->userinfo = $userinfo;
+
+ if (PEAR_ZE2) {
+ $skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace');
+ } else {
+ $skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
+ }
+
+ if (!$skiptrace) {
+ $this->backtrace = debug_backtrace();
+ if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
+ unset($this->backtrace[0]['object']);
+ }
+ }
+
+ if ($mode & PEAR_ERROR_CALLBACK) {
+ $this->level = E_USER_NOTICE;
+ $this->callback = $options;
+ } else {
+ if ($options === null) {
+ $options = E_USER_NOTICE;
+ }
+
+ $this->level = $options;
+ $this->callback = null;
+ }
+
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ } else {
+ $format = $options;
+ }
+
+ printf($format, $this->getMessage());
+ }
+
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ trigger_error($this->getMessage(), $this->level);
+ }
+
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $msg = $this->getMessage();
+ if (is_null($options) || is_int($options)) {
+ $format = "%s";
+ if (substr($msg, -1) != "\n") {
+ $msg .= "\n";
+ }
+ } else {
+ $format = $options;
+ }
+ die(sprintf($format, $msg));
+ }
+
+ if ($this->mode & PEAR_ERROR_CALLBACK) {
+ if (is_callable($this->callback)) {
+ call_user_func($this->callback, $this);
+ }
+ }
+
+ if ($this->mode & PEAR_ERROR_EXCEPTION) {
+ trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
+ eval('$e = new Exception($this->message, $this->code);throw($e);');
+ }
+ }
+
+ // }}}
+ // {{{ getMode()
+
+ /**
+ * Get the error mode from an error object.
+ *
+ * @return int error mode
+ * @access public
+ */
+ function getMode() {
+ return $this->mode;
+ }
+
+ // }}}
+ // {{{ getCallback()
+
+ /**
+ * Get the callback function/method from an error object.
+ *
+ * @return mixed callback function or object/method array
+ * @access public
+ */
+ function getCallback() {
+ return $this->callback;
+ }
+
+ // }}}
+ // {{{ getMessage()
+
+
+ /**
+ * Get the error message from an error object.
+ *
+ * @return string full error message
+ * @access public
+ */
+ function getMessage()
+ {
+ return ($this->error_message_prefix . $this->message);
+ }
+
+
+ // }}}
+ // {{{ getCode()
+
+ /**
+ * Get error code from an error object
+ *
+ * @return int error code
+ * @access public
+ */
+ function getCode()
+ {
+ return $this->code;
+ }
+
+ // }}}
+ // {{{ getType()
+
+ /**
+ * Get the name of this error/exception.
+ *
+ * @return string error/exception name (type)
+ * @access public
+ */
+ function getType()
+ {
+ return get_class($this);
+ }
+
+ // }}}
+ // {{{ getUserInfo()
+
+ /**
+ * Get additional user-supplied information.
+ *
+ * @return string user-supplied information
+ * @access public
+ */
+ function getUserInfo()
+ {
+ return $this->userinfo;
+ }
+
+ // }}}
+ // {{{ getDebugInfo()
+
+ /**
+ * Get additional debug information supplied by the application.
+ *
+ * @return string debug information
+ * @access public
+ */
+ function getDebugInfo()
+ {
+ return $this->getUserInfo();
+ }
+
+ // }}}
+ // {{{ getBacktrace()
+
+ /**
+ * Get the call backtrace from where the error was generated.
+ * Supported with PHP 4.3.0 or newer.
+ *
+ * @param int $frame (optional) what frame to fetch
+ * @return array Backtrace, or NULL if not available.
+ * @access public
+ */
+ function getBacktrace($frame = null)
+ {
+ if (defined('PEAR_IGNORE_BACKTRACE')) {
+ return null;
+ }
+ if ($frame === null) {
+ return $this->backtrace;
+ }
+ return $this->backtrace[$frame];
+ }
+
+ // }}}
+ // {{{ addUserInfo()
+
+ function addUserInfo($info)
+ {
+ if (empty($this->userinfo)) {
+ $this->userinfo = $info;
+ } else {
+ $this->userinfo .= " ** $info";
+ }
+ }
+
+ // }}}
+ // {{{ toString()
+ function __toString()
+ {
+ return $this->getMessage();
+ }
+ // }}}
+ // {{{ toString()
+
+ /**
+ * Make a string representation of this object.
+ *
+ * @return string a string with an object summary
+ * @access public
+ */
+ function toString() {
+ $modes = array();
+ $levels = array(E_USER_NOTICE => 'notice',
+ E_USER_WARNING => 'warning',
+ E_USER_ERROR => 'error');
+ if ($this->mode & PEAR_ERROR_CALLBACK) {
+ if (is_array($this->callback)) {
+ $callback = (is_object($this->callback[0]) ?
+ strtolower(get_class($this->callback[0])) :
+ $this->callback[0]) . '::' .
+ $this->callback[1];
+ } else {
+ $callback = $this->callback;
+ }
+ return sprintf('[%s: message="%s" code=%d mode=callback '.
+ 'callback=%s prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ $callback, $this->error_message_prefix,
+ $this->userinfo);
+ }
+ if ($this->mode & PEAR_ERROR_PRINT) {
+ $modes[] = 'print';
+ }
+ if ($this->mode & PEAR_ERROR_TRIGGER) {
+ $modes[] = 'trigger';
+ }
+ if ($this->mode & PEAR_ERROR_DIE) {
+ $modes[] = 'die';
+ }
+ if ($this->mode & PEAR_ERROR_RETURN) {
+ $modes[] = 'return';
+ }
+ return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
+ 'prefix="%s" info="%s"]',
+ strtolower(get_class($this)), $this->message, $this->code,
+ implode("|", $modes), $levels[$this->level],
+ $this->error_message_prefix,
+ $this->userinfo);
+ }
+
+ // }}}
+}
+
+/*
+ * Local Variables:
+ * mode: php
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/lib/ext/PEAR5.php b/lib/ext/PEAR5.php
new file mode 100644
index 0000000..4286067
--- /dev/null
+++ b/lib/ext/PEAR5.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * This is only meant for PHP 5 to get rid of certain strict warning
+ * that doesn't get hidden since it's in the shutdown function
+ */
+class PEAR5
+{
+ /**
+ * If you have a class that's mostly/entirely static, and you need static
+ * properties, you can use this method to simulate them. Eg. in your method(s)
+ * do this: $myVar = &PEAR5::getStaticProperty('myclass', 'myVar');
+ * You MUST use a reference, or they will not persist!
+ *
+ * @access public
+ * @param string $class The calling classname, to prevent clashes
+ * @param string $var The variable to retrieve.
+ * @return mixed A reference to the variable. If not set it will be
+ * auto initialised to NULL.
+ */
+ static function &getStaticProperty($class, $var)
+ {
+ static $properties;
+ if (!isset($properties[$class])) {
+ $properties[$class] = array();
+ }
+
+ if (!array_key_exists($var, $properties[$class])) {
+ $properties[$class][$var] = null;
+ }
+
+ return $properties[$class][$var];
+ }
+}
\ No newline at end of file
diff --git a/lib/ext/enriched.inc b/lib/ext/enriched.inc
new file mode 100644
index 0000000..e3abd8c
--- /dev/null
+++ b/lib/ext/enriched.inc
@@ -0,0 +1,114 @@
+<?php
+/*
+ File: read_enriched.inc
+ Author: Ryo Chijiiwa
+ License: GPL (part of IlohaMail)
+ Purpose: functions for handling text/enriched messages
+ Reference: RFC 1523, 1896
+*/
+
+
+function enriched_convert_newlines($str){
+ //remove single newlines, convert N newlines to N-1
+
+ $str = str_replace("\r\n","\n",$str);
+ $len = strlen($str);
+
+ $nl = 0;
+ $out = '';
+ for($i=0;$i<$len;$i++){
+ $c = $str[$i];
+ if (ord($c)==10) $nl++;
+ if ($nl && ord($c)!=10) $nl = 0;
+ if ($nl!=1) $out.=$c;
+ else $out.=' ';
+ }
+ return $out;
+}
+
+function enriched_convert_formatting($body){
+ $a=array('<bold>'=>'<b>','</bold>'=>'</b>','<italic>'=>'<i>',
+ '</italic>'=>'</i>','<fixed>'=>'<tt>','</fixed>'=>'</tt>',
+ '<smaller>'=>'<font size=-1>','</smaller>'=>'</font>',
+ '<bigger>'=>'<font size=+1>','</bigger>'=>'</font>',
+ '<underline>'=>'<span style="text-decoration: underline">',
+ '</underline>'=>'</span>',
+ '<flushleft>'=>'<span style="text-align:left">',
+ '</flushleft>'=>'</span>',
+ '<flushright>'=>'<span style="text-align:right">',
+ '</flushright>'=>'</span>',
+ '<flushboth>'=>'<span style="text-align:justified">',
+ '</flushboth>'=>'</span>',
+ '<indent>'=>'<span style="padding-left: 20px">',
+ '</indent>'=>'</span>',
+ '<indentright>'=>'<span style="padding-right: 20px">',
+ '</indentright>'=>'</span>');
+
+ while(list($find,$replace)=each($a)){
+ $body = preg_replace('#'.$find.'#i', $replace, $body);
+ }
+ return $body;
+}
+
+function enriched_font($body){
+ $pattern = '/(.*)\<fontfamily\>\<param\>(.*)\<\/param\>(.*)\<\/fontfamily\>(.*)/ims';
+ while(preg_match($pattern,$body,$a)){
+ //print_r($a);
+ if (count($a)!=5) continue;
+ $body=$a[1].'<span style="font-family: '.$a[2].'">'.$a[3].'</span>'.$a[4];
+ }
+
+ return $body;
+}
+
+
+function enriched_color($body){
+ $pattern = '/(.*)\<color\>\<param\>(.*)\<\/param\>(.*)\<\/color\>(.*)/ims';
+ while(preg_match($pattern,$body,$a)){
+ //print_r($a);
+ if (count($a)!=5) continue;
+
+ //extract color (either by name, or ####,####,####)
+ if (strpos($a[2],',')){
+ $rgb = explode(',',$a[2]);
+ $color ='#';
+ for($i=0;$i<3;$i++) $color.=substr($rgb[$i],0,2); //just take first 2 bytes
+ }else{
+ $color = $a[2];
+ }
+
+ //put it all together
+ $body = $a[1].'<span style="color: '.$color.'">'.$a[3].'</span>'.$a[4];
+ }
+
+ return $body;
+}
+
+function enriched_excerpt($body){
+
+ $pattern = '/(.*)\<excerpt\>(.*)\<\/excerpt\>(.*)/i';
+ while(preg_match($pattern,$body,$a)){
+ //print_r($a);
+ if (count($a)!=4) continue;
+ $quoted = '';
+ $lines = explode('<br>',$a[2]);
+ foreach($lines as $n=>$line) $quoted.='&gt;'.$line.'<br>';
+ $body=$a[1].'<span class="quotes">'.$quoted.'</span>'.$a[3];
+ }
+
+ return $body;
+}
+
+function enriched_to_html($body){
+ $body = str_replace('<<','&lt;',$body);
+ $body = enriched_convert_newlines($body);
+ $body = str_replace("\n", '<br>', $body);
+ $body = enriched_convert_formatting($body);
+ $body = enriched_color($body);
+ $body = enriched_font($body);
+ $body = enriched_excerpt($body);
+ //$body = nl2br($body);
+ return $body;
+}
+
+?>
\ No newline at end of file
diff --git a/lib/ext/html2text.php b/lib/ext/html2text.php
new file mode 100644
index 0000000..9de2e96
--- /dev/null
+++ b/lib/ext/html2text.php
@@ -0,0 +1,744 @@
+<?php
+
+/*************************************************************************
+ * *
+ * class.html2text.inc *
+ * *
+ *************************************************************************
+ * *
+ * Converts HTML to formatted plain text *
+ * *
+ * Copyright (c) 2005-2007 Jon Abernathy <jon@chuggnutt.com> *
+ * All rights reserved. *
+ * *
+ * This script is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * The GNU General Public License can be found at *
+ * http://www.gnu.org/copyleft/gpl.html. *
+ * *
+ * This script is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * Author(s): Jon Abernathy <jon@chuggnutt.com> *
+ * *
+ * Last modified: 08/08/07 *
+ * *
+ *************************************************************************/
+
+
+/**
+ * Takes HTML and converts it to formatted, plain text.
+ *
+ * Thanks to Alexander Krug (http://www.krugar.de/) to pointing out and
+ * correcting an error in the regexp search array. Fixed 7/30/03.
+ *
+ * Updated set_html() function's file reading mechanism, 9/25/03.
+ *
+ * Thanks to Joss Sanglier (http://www.dancingbear.co.uk/) for adding
+ * several more HTML entity codes to the $search and $replace arrays.
+ * Updated 11/7/03.
+ *
+ * Thanks to Darius Kasperavicius (http://www.dar.dar.lt/) for
+ * suggesting the addition of $allowed_tags and its supporting function
+ * (which I slightly modified). Updated 3/12/04.
+ *
+ * Thanks to Justin Dearing for pointing out that a replacement for the
+ * <TH> tag was missing, and suggesting an appropriate fix.
+ * Updated 8/25/04.
+ *
+ * Thanks to Mathieu Collas (http://www.myefarm.com/) for finding a
+ * display/formatting bug in the _build_link_list() function: email
+ * readers would show the left bracket and number ("[1") as part of the
+ * rendered email address.
+ * Updated 12/16/04.
+ *
+ * Thanks to Wojciech Bajon (http://histeria.pl/) for submitting code
+ * to handle relative links, which I hadn't considered. I modified his
+ * code a bit to handle normal HTTP links and MAILTO links. Also for
+ * suggesting three additional HTML entity codes to search for.
+ * Updated 03/02/05.
+ *
+ * Thanks to Jacob Chandler for pointing out another link condition
+ * for the _build_link_list() function: "https".
+ * Updated 04/06/05.
+ *
+ * Thanks to Marc Bertrand (http://www.dresdensky.com/) for
+ * suggesting a revision to the word wrapping functionality; if you
+ * specify a $width of 0 or less, word wrapping will be ignored.
+ * Updated 11/02/06.
+ *
+ * *** Big housecleaning updates below:
+ *
+ * Thanks to Colin Brown (http://www.sparkdriver.co.uk/) for
+ * suggesting the fix to handle </li> and blank lines (whitespace).
+ * Christian Basedau (http://www.movetheweb.de/) also suggested the
+ * blank lines fix.
+ *
+ * Special thanks to Marcus Bointon (http://www.synchromedia.co.uk/),
+ * Christian Basedau, Norbert Laposa (http://ln5.co.uk/),
+ * Bas van de Weijer, and Marijn van Butselaar
+ * for pointing out my glaring error in the <th> handling. Marcus also
+ * supplied a host of fixes.
+ *
+ * Thanks to Jeffrey Silverman (http://www.newtnotes.com/) for pointing
+ * out that extra spaces should be compressed--a problem addressed with
+ * Marcus Bointon's fixes but that I had not yet incorporated.
+ *
+ * Thanks to Daniel Schledermann (http://www.typoconsult.dk/) for
+ * suggesting a valuable fix with <a> tag handling.
+ *
+ * Thanks to Wojciech Bajon (again!) for suggesting fixes and additions,
+ * including the <a> tag handling that Daniel Schledermann pointed
+ * out but that I had not yet incorporated. I haven't (yet)
+ * incorporated all of Wojciech's changes, though I may at some
+ * future time.
+ *
+ * *** End of the housecleaning updates. Updated 08/08/07.
+ *
+ * @author Jon Abernathy <jon@chuggnutt.com>
+ * @version 1.0.0
+ * @since PHP 4.0.2
+ */
+class html2text
+{
+
+ /**
+ * Contains the HTML content to convert.
+ *
+ * @var string $html
+ * @access public
+ */
+ var $html;
+
+ /**
+ * Contains the converted, formatted text.
+ *
+ * @var string $text
+ * @access public
+ */
+ var $text;
+
+ /**
+ * Maximum width of the formatted text, in columns.
+ *
+ * Set this value to 0 (or less) to ignore word wrapping
+ * and not constrain text to a fixed-width column.
+ *
+ * @var integer $width
+ * @access public
+ */
+ var $width = 70;
+
+ /**
+ * List of preg* regular expression patterns to search for,
+ * used in conjunction with $replace.
+ *
+ * @var array $search
+ * @access public
+ * @see $replace
+ */
+ var $search = array(
+ "/\r/", // Non-legal carriage return
+ "/[\n\t]+/", // Newlines and tabs
+ '/<script[^>]*>.*?<\/script>/i', // <script>s -- which strip_tags supposedly has problems with
+ '/<style[^>]*>.*?<\/style>/i', // <style>s -- which strip_tags supposedly has problems with
+ '/<p[^>]*>/i', // <P>
+ '/<br[^>]*>/i', // <br>
+ '/<i[^>]*>(.*?)<\/i>/i', // <i>
+ '/<em[^>]*>(.*?)<\/em>/i', // <em>
+ '/(<ul[^>]*>|<\/ul>)/i', // <ul> and </ul>
+ '/(<ol[^>]*>|<\/ol>)/i', // <ol> and </ol>
+ '/<li[^>]*>(.*?)<\/li>/i', // <li> and </li>
+ '/<li[^>]*>/i', // <li>
+ '/<hr[^>]*>/i', // <hr>
+ '/<div[^>]*>/i', // <div>
+ '/(<table[^>]*>|<\/table>)/i', // <table> and </table>
+ '/(<tr[^>]*>|<\/tr>)/i', // <tr> and </tr>
+ '/<td[^>]*>(.*?)<\/td>/i', // <td> and </td>
+ );
+
+ /**
+ * List of pattern replacements corresponding to patterns searched.
+ *
+ * @var array $replace
+ * @access public
+ * @see $search
+ */
+ var $replace = array(
+ '', // Non-legal carriage return
+ ' ', // Newlines and tabs
+ '', // <script>s -- which strip_tags supposedly has problems with
+ '', // <style>s -- which strip_tags supposedly has problems with
+ "\n\n", // <P>
+ "\n", // <br>
+ '_\\1_', // <i>
+ '_\\1_', // <em>
+ "\n\n", // <ul> and </ul>
+ "\n\n", // <ol> and </ol>
+ "\t* \\1\n", // <li> and </li>
+ "\n\t* ", // <li>
+ "\n-------------------------\n", // <hr>
+ "<div>\n", // <div>
+ "\n\n", // <table> and </table>
+ "\n", // <tr> and </tr>
+ "\t\t\\1\n", // <td> and </td>
+ );
+
+ /**
+ * List of preg* regular expression patterns to search for,
+ * used in conjunction with $ent_replace.
+ *
+ * @var array $ent_search
+ * @access public
+ * @see $ent_replace
+ */
+ var $ent_search = array(
+ '/&(nbsp|#160);/i', // Non-breaking space
+ '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i',
+ // Double quotes
+ '/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes
+ '/&gt;/i', // Greater-than
+ '/&lt;/i', // Less-than
+ '/&(copy|#169);/i', // Copyright
+ '/&(trade|#8482|#153);/i', // Trademark
+ '/&(reg|#174);/i', // Registered
+ '/&(mdash|#151|#8212);/i', // mdash
+ '/&(ndash|minus|#8211|#8722);/i', // ndash
+ '/&(bull|#149|#8226);/i', // Bullet
+ '/&(pound|#163);/i', // Pound sign
+ '/&(euro|#8364);/i', // Euro sign
+ '/&(amp|#38);/i', // Ampersand: see _converter()
+ '/[ ]{2,}/', // Runs of spaces, post-handling
+ );
+
+ /**
+ * List of pattern replacements corresponding to patterns searched.
+ *
+ * @var array $ent_replace
+ * @access public
+ * @see $ent_search
+ */
+ var $ent_replace = array(
+ ' ', // Non-breaking space
+ '"', // Double quotes
+ "'", // Single quotes
+ '>',
+ '<',
+ '(c)',
+ '(tm)',
+ '(R)',
+ '--',
+ '-',
+ '*',
+ '£',
+ 'EUR', // Euro sign. € ?
+ '|+|amp|+|', // Ampersand: see _converter()
+ ' ', // Runs of spaces, post-handling
+ );
+
+ /**
+ * List of preg* regular expression patterns to search for
+ * and replace using callback function.
+ *
+ * @var array $callback_search
+ * @access public
+ */
+ var $callback_search = array(
+ '/<(a) [^>]*href=("|\')([^"\']+)\2[^>]*>(.*?)<\/a>/i', // <a href="">
+ '/<(h)[123456]( [^>]*)?>(.*?)<\/h[123456]>/i', // h1 - h6
+ '/<(b)( [^>]*)?>(.*?)<\/b>/i', // <b>
+ '/<(strong)( [^>]*)?>(.*?)<\/strong>/i', // <strong>
+ '/<(th)( [^>]*)?>(.*?)<\/th>/i', // <th> and </th>
+ );
+
+ /**
+ * List of preg* regular expression patterns to search for in PRE body,
+ * used in conjunction with $pre_replace.
+ *
+ * @var array $pre_search
+ * @access public
+ * @see $pre_replace
+ */
+ var $pre_search = array(
+ "/\n/",
+ "/\t/",
+ '/ /',
+ '/<pre[^>]*>/',
+ '/<\/pre>/'
+ );
+
+ /**
+ * List of pattern replacements corresponding to patterns searched for PRE body.
+ *
+ * @var array $pre_replace
+ * @access public
+ * @see $pre_search
+ */
+ var $pre_replace = array(
+ '<br>',
+ '&nbsp;&nbsp;&nbsp;&nbsp;',
+ '&nbsp;',
+ '',
+ ''
+ );
+
+ /**
+ * Contains a list of HTML tags to allow in the resulting text.
+ *
+ * @var string $allowed_tags
+ * @access public
+ * @see set_allowed_tags()
+ */
+ var $allowed_tags = '';
+
+ /**
+ * Contains the base URL that relative links should resolve to.
+ *
+ * @var string $url
+ * @access public
+ */
+ var $url;
+
+ /**
+ * Indicates whether content in the $html variable has been converted yet.
+ *
+ * @var boolean $_converted
+ * @access private
+ * @see $html, $text
+ */
+ var $_converted = false;
+
+ /**
+ * Contains URL addresses from links to be rendered in plain text.
+ *
+ * @var array $_link_list
+ * @access private
+ * @see _build_link_list()
+ */
+ var $_link_list = array();
+
+ /**
+ * Boolean flag, true if a table of link URLs should be listed after the text.
+ *
+ * @var boolean $_do_links
+ * @access private
+ * @see html2text()
+ */
+ var $_do_links = true;
+
+ /**
+ * Constructor.
+ *
+ * If the HTML source string (or file) is supplied, the class
+ * will instantiate with that source propagated, all that has
+ * to be done it to call get_text().
+ *
+ * @param string $source HTML content
+ * @param boolean $from_file Indicates $source is a file to pull content from
+ * @param boolean $do_links Indicate whether a table of link URLs is desired
+ * @param integer $width Maximum width of the formatted text, 0 for no limit
+ * @access public
+ * @return void
+ */
+ function html2text( $source = '', $from_file = false, $do_links = true, $width = 75 )
+ {
+ if ( !empty($source) ) {
+ $this->set_html($source, $from_file);
+ }
+
+ $this->set_base_url();
+ $this->_do_links = $do_links;
+ $this->width = $width;
+ }
+
+ /**
+ * Loads source HTML into memory, either from $source string or a file.
+ *
+ * @param string $source HTML content
+ * @param boolean $from_file Indicates $source is a file to pull content from
+ * @access public
+ * @return void
+ */
+ function set_html( $source, $from_file = false )
+ {
+ if ( $from_file && file_exists($source) ) {
+ $this->html = file_get_contents($source);
+ }
+ else
+ $this->html = $source;
+
+ $this->_converted = false;
+ }
+
+ /**
+ * Returns the text, converted from HTML.
+ *
+ * @access public
+ * @return string
+ */
+ function get_text()
+ {
+ if ( !$this->_converted ) {
+ $this->_convert();
+ }
+
+ return $this->text;
+ }
+
+ /**
+ * Prints the text, converted from HTML.
+ *
+ * @access public
+ * @return void
+ */
+ function print_text()
+ {
+ print $this->get_text();
+ }
+
+ /**
+ * Alias to print_text(), operates identically.
+ *
+ * @access public
+ * @return void
+ * @see print_text()
+ */
+ function p()
+ {
+ print $this->get_text();
+ }
+
+ /**
+ * Sets the allowed HTML tags to pass through to the resulting text.
+ *
+ * Tags should be in the form "<p>", with no corresponding closing tag.
+ *
+ * @access public
+ * @return void
+ */
+ function set_allowed_tags( $allowed_tags = '' )
+ {
+ if ( !empty($allowed_tags) ) {
+ $this->allowed_tags = $allowed_tags;
+ }
+ }
+
+ /**
+ * Sets a base URL to handle relative links.
+ *
+ * @access public
+ * @return void
+ */
+ function set_base_url( $url = '' )
+ {
+ if ( empty($url) ) {
+ if ( !empty($_SERVER['HTTP_HOST']) ) {
+ $this->url = 'http://' . $_SERVER['HTTP_HOST'];
+ } else {
+ $this->url = '';
+ }
+ } else {
+ // Strip any trailing slashes for consistency (relative
+ // URLs may already start with a slash like "/file.html")
+ if ( substr($url, -1) == '/' ) {
+ $url = substr($url, 0, -1);
+ }
+ $this->url = $url;
+ }
+ }
+
+ /**
+ * Workhorse function that does actual conversion (calls _converter() method).
+ *
+ * @access private
+ * @return void
+ */
+ function _convert()
+ {
+ // Variables used for building the link list
+ $this->_link_list = array();
+
+ $text = trim(stripslashes($this->html));
+
+ // Convert HTML to TXT
+ $this->_converter($text);
+
+ // Add link list
+ if (!empty($this->_link_list)) {
+ $text .= "\n\nLinks:\n------\n";
+ foreach ($this->_link_list as $idx => $url) {
+ $text .= '[' . ($idx+1) . '] ' . $url . "\n";
+ }
+ }
+
+ $this->text = $text;
+
+ $this->_converted = true;
+ }
+
+ /**
+ * Workhorse function that does actual conversion.
+ *
+ * First performs custom tag replacement specified by $search and
+ * $replace arrays. Then strips any remaining HTML tags, reduces whitespace
+ * and newlines to a readable format, and word wraps the text to
+ * $width characters.
+ *
+ * @param string Reference to HTML content string
+ *
+ * @access private
+ * @return void
+ */
+ function _converter(&$text)
+ {
+ // Convert <BLOCKQUOTE> (before PRE!)
+ $this->_convert_blockquotes($text);
+
+ // Convert <PRE>
+ $this->_convert_pre($text);
+
+ // Run our defined tags search-and-replace
+ $text = preg_replace($this->search, $this->replace, $text);
+
+ // Run our defined tags search-and-replace with callback
+ $text = preg_replace_callback($this->callback_search, array('html2text', '_preg_callback'), $text);
+
+ // Strip any other HTML tags
+ $text = strip_tags($text, $this->allowed_tags);
+
+ // Run our defined entities/characters search-and-replace
+ $text = preg_replace($this->ent_search, $this->ent_replace, $text);
+
+ // Replace known html entities
+ $text = html_entity_decode($text, ENT_COMPAT, 'UTF-8');
+
+ // Remove unknown/unhandled entities (this cannot be done in search-and-replace block)
+ $text = preg_replace('/&([a-zA-Z0-9]{2,6}|#[0-9]{2,4});/', '', $text);
+
+ // Convert "|+|amp|+|" into "&", need to be done after handling of unknown entities
+ // This properly handles situation of "&amp;quot;" in input string
+ $text = str_replace('|+|amp|+|', '&', $text);
+
+ // Bring down number of empty lines to 2 max
+ $text = preg_replace("/\n\s+\n/", "\n\n", $text);
+ $text = preg_replace("/[\n]{3,}/", "\n\n", $text);
+
+ // remove leading empty lines (can be produced by eg. P tag on the beginning)
+ $text = ltrim($text, "\n");
+
+ // Wrap the text to a readable format
+ // for PHP versions >= 4.0.2. Default width is 75
+ // If width is 0 or less, don't wrap the text.
+ if ( $this->width > 0 ) {
+ $text = wordwrap($text, $this->width);
+ }
+ }
+
+ /**
+ * Helper function called by preg_replace() on link replacement.
+ *
+ * Maintains an internal list of links to be displayed at the end of the
+ * text, with numeric indices to the original point in the text they
+ * appeared. Also makes an effort at identifying and handling absolute
+ * and relative links.
+ *
+ * @param string $link URL of the link
+ * @param string $display Part of the text to associate number with
+ * @access private
+ * @return string
+ */
+ function _build_link_list( $link, $display )
+ {
+ if (!$this->_do_links || empty($link)) {
+ return $display;
+ }
+
+ // Ignored link types
+ if (preg_match('!^(javascript:|mailto:|#)!i', $link)) {
+ return $display;
+ }
+
+ if (preg_match('!^([a-z][a-z0-9.+-]+:)!i', $link)) {
+ $url = $link;
+ }
+ else {
+ $url = $this->url;
+ if (substr($link, 0, 1) != '/') {
+ $url .= '/';
+ }
+ $url .= "$link";
+ }
+
+ if (($index = array_search($url, $this->_link_list)) === false) {
+ $index = count($this->_link_list);
+ $this->_link_list[] = $url;
+ }
+
+ return $display . ' [' . ($index+1) . ']';
+ }
+
+ /**
+ * Helper function for PRE body conversion.
+ *
+ * @param string HTML content
+ * @access private
+ */
+ function _convert_pre(&$text)
+ {
+ // get the content of PRE element
+ while (preg_match('/<pre[^>]*>(.*)<\/pre>/ismU', $text, $matches)) {
+ $this->pre_content = $matches[1];
+
+ // Run our defined tags search-and-replace with callback
+ $this->pre_content = preg_replace_callback($this->callback_search,
+ array('html2text', '_preg_callback'), $this->pre_content);
+
+ // convert the content
+ $this->pre_content = sprintf('<div><br>%s<br></div>',
+ preg_replace($this->pre_search, $this->pre_replace, $this->pre_content));
+
+ // replace the content (use callback because content can contain $0 variable)
+ $text = preg_replace_callback('/<pre[^>]*>.*<\/pre>/ismU',
+ array('html2text', '_preg_pre_callback'), $text, 1);
+
+ // free memory
+ $this->pre_content = '';
+ }
+ }
+
+ /**
+ * Helper function for BLOCKQUOTE body conversion.
+ *
+ * @param string HTML content
+ * @access private
+ */
+ function _convert_blockquotes(&$text)
+ {
+ if (preg_match_all('/<\/*blockquote[^>]*>/i', $text, $matches, PREG_OFFSET_CAPTURE)) {
+ $level = 0;
+ $diff = 0;
+ foreach ($matches[0] as $m) {
+ if ($m[0][0] == '<' && $m[0][1] == '/') {
+ $level--;
+ if ($level < 0) {
+ $level = 0; // malformed HTML: go to next blockquote
+ }
+ else if ($level > 0) {
+ // skip inner blockquote
+ }
+ else {
+ $end = $m[1];
+ $len = $end - $taglen - $start;
+ // Get blockquote content
+ $body = substr($text, $start + $taglen - $diff, $len);
+
+ // Set text width
+ $p_width = $this->width;
+ if ($this->width > 0) $this->width -= 2;
+ // Convert blockquote content
+ $body = trim($body);
+ $this->_converter($body);
+ // Add citation markers and create PRE block
+ $body = preg_replace('/((^|\n)>*)/', '\\1> ', trim($body));
+ $body = '<pre>' . htmlspecialchars($body) . '</pre>';
+ // Re-set text width
+ $this->width = $p_width;
+ // Replace content
+ $text = substr($text, 0, $start - $diff)
+ . $body . substr($text, $end + strlen($m[0]) - $diff);
+
+ $diff = $len + $taglen + strlen($m[0]) - strlen($body);
+ unset($body);
+ }
+ }
+ else {
+ if ($level == 0) {
+ $start = $m[1];
+ $taglen = strlen($m[0]);
+ }
+ $level ++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Callback function for preg_replace_callback use.
+ *
+ * @param array PREG matches
+ * @return string
+ */
+ private function _preg_callback($matches)
+ {
+ switch (strtolower($matches[1])) {
+ case 'b':
+ case 'strong':
+ return $this->_toupper($matches[3]);
+ case 'th':
+ return $this->_toupper("\t\t". $matches[3] ."\n");
+ case 'h':
+ return $this->_toupper("\n\n". $matches[3] ."\n\n");
+ case 'a':
+ // Remove spaces in URL (#1487805)
+ $url = str_replace(' ', '', $matches[3]);
+ return $this->_build_link_list($url, $matches[4]);
+ }
+ }
+
+ /**
+ * Callback function for preg_replace_callback use in PRE content handler.
+ *
+ * @param array PREG matches
+ * @return string
+ */
+ private function _preg_pre_callback($matches)
+ {
+ return $this->pre_content;
+ }
+
+ /**
+ * Strtoupper function with HTML tags and entities handling.
+ *
+ * @param string $str Text to convert
+ * @return string Converted text
+ */
+ private function _toupper($str)
+ {
+ // string can containg HTML tags
+ $chunks = preg_split('/(<[^>]*>)/', $str, null, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
+
+ // convert toupper only the text between HTML tags
+ foreach ($chunks as $idx => $chunk) {
+ if ($chunk[0] != '<') {
+ $chunks[$idx] = $this->_strtoupper($chunk);
+ }
+ }
+
+ return implode($chunks);
+ }
+
+ /**
+ * Strtoupper multibyte wrapper function with HTML entities handling.
+ *
+ * @param string $str Text to convert
+ * @return string Converted text
+ */
+ private function _strtoupper($str)
+ {
+ $str = html_entity_decode($str, ENT_COMPAT, RCMAIL_CHARSET);
+
+ if (function_exists('mb_strtoupper'))
+ $str = mb_strtoupper($str);
+ else
+ $str = strtoupper($str);
+
+ $str = htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
+
+ return $str;
+ }
+}
diff --git a/lib/ext/tnef_decoder.php b/lib/ext/tnef_decoder.php
new file mode 100644
index 0000000..28d3689
--- /dev/null
+++ b/lib/ext/tnef_decoder.php
@@ -0,0 +1,330 @@
+<?php
+/**
+ * The Horde's class allows MS-TNEF data to be displayed.
+ *
+ * The TNEF rendering is based on code by:
+ * Graham Norbury <gnorbury@bondcar.com>
+ * Original design by:
+ * Thomas Boll <tb@boll.ch>, Mark Simpson <damned@world.std.com>
+ *
+ * Copyright 2002-2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @author Jan Schneider <jan@horde.org>
+ * @author Michael Slusarz <slusarz@horde.org>
+ * @package Horde_Compress
+ */
+class tnef_decoder
+{
+ const SIGNATURE = 0x223e9f78;
+ const LVL_MESSAGE = 0x01;
+ const LVL_ATTACHMENT = 0x02;
+
+ const ASUBJECT = 0x88004;
+ const AMCLASS = 0x78008;
+ const ATTACHDATA = 0x6800f;
+ const AFILENAME = 0x18010;
+ const ARENDDATA = 0x69002;
+ const AMAPIATTRS = 0x69005;
+ const AVERSION = 0x89006;
+
+ const MAPI_NULL = 0x0001;
+ const MAPI_SHORT = 0x0002;
+ const MAPI_INT = 0x0003;
+ const MAPI_FLOAT = 0x0004;
+ const MAPI_DOUBLE = 0x0005;
+ const MAPI_CURRENCY = 0x0006;
+ const MAPI_APPTIME = 0x0007;
+ const MAPI_ERROR = 0x000a;
+ const MAPI_BOOLEAN = 0x000b;
+ const MAPI_OBJECT = 0x000d;
+ const MAPI_INT8BYTE = 0x0014;
+ const MAPI_STRING = 0x001e;
+ const MAPI_UNICODE_STRING = 0x001f;
+ const MAPI_SYSTIME = 0x0040;
+ const MAPI_CLSID = 0x0048;
+ const MAPI_BINARY = 0x0102;
+
+ const MAPI_ATTACH_LONG_FILENAME = 0x3707;
+ const MAPI_ATTACH_MIME_TAG = 0x370E;
+
+ const MAPI_NAMED_TYPE_ID = 0x0000;
+ const MAPI_NAMED_TYPE_STRING = 0x0001;
+ const MAPI_MV_FLAG = 0x1000;
+
+ /**
+ * Decompress the data.
+ *
+ * @param string $data The data to decompress.
+ * @param array $params An array of arguments needed to decompress the
+ * data.
+ *
+ * @return mixed The decompressed data.
+ */
+ public function decompress($data, $params = array())
+ {
+ $out = array();
+
+ if ($this->_geti($data, 32) == self::SIGNATURE) {
+ $this->_geti($data, 16);
+
+ while (strlen($data) > 0) {
+ switch ($this->_geti($data, 8)) {
+ case self::LVL_MESSAGE:
+ $this->_decodeMessage($data);
+ break;
+
+ case self::LVL_ATTACHMENT:
+ $this->_decodeAttachment($data, $out);
+ break;
+ }
+ }
+ }
+
+ return array_reverse($out);
+ }
+
+ /**
+ * TODO
+ *
+ * @param string &$data The data string.
+ * @param integer $bits How many bits to retrieve.
+ *
+ * @return TODO
+ */
+ protected function _getx(&$data, $bits)
+ {
+ $value = null;
+
+ if (strlen($data) >= $bits) {
+ $value = substr($data, 0, $bits);
+ $data = substr_replace($data, '', 0, $bits);
+ }
+
+ return $value;
+ }
+
+ /**
+ * TODO
+ *
+ * @param string &$data The data string.
+ * @param integer $bits How many bits to retrieve.
+ *
+ * @return TODO
+ */
+ protected function _geti(&$data, $bits)
+ {
+ $bytes = $bits / 8;
+ $value = null;
+
+ if (strlen($data) >= $bytes) {
+ $value = ord($data[0]);
+ if ($bytes >= 2) {
+ $value += (ord($data[1]) << 8);
+ }
+ if ($bytes >= 4) {
+ $value += (ord($data[2]) << 16) + (ord($data[3]) << 24);
+ }
+ $data = substr_replace($data, '', 0, $bytes);
+ }
+
+ return $value;
+ }
+
+ /**
+ * TODO
+ *
+ * @param string &$data The data string.
+ * @param string $attribute TODO
+ */
+ protected function _decodeAttribute(&$data, $attribute)
+ {
+ /* Data. */
+ $this->_getx($data, $this->_geti($data, 32));
+
+ /* Checksum. */
+ $this->_geti($data, 16);
+ }
+
+ /**
+ * TODO
+ *
+ * @param string $data The data string.
+ * @param array &$attachment_data TODO
+ */
+ protected function _extractMapiAttributes($data, &$attachment_data)
+ {
+ /* Number of attributes. */
+ $number = $this->_geti($data, 32);
+
+ while ((strlen($data) > 0) && $number--) {
+ $have_mval = false;
+ $num_mval = 1;
+ $named_id = $value = null;
+ $attr_type = $this->_geti($data, 16);
+ $attr_name = $this->_geti($data, 16);
+
+ if (($attr_type & self::MAPI_MV_FLAG) != 0) {
+ $have_mval = true;
+ $attr_type = $attr_type & ~self::MAPI_MV_FLAG;
+ }
+
+ if (($attr_name >= 0x8000) && ($attr_name < 0xFFFE)) {
+ $this->_getx($data, 16);
+ $named_type = $this->_geti($data, 32);
+
+ switch ($named_type) {
+ case self::MAPI_NAMED_TYPE_ID:
+ $named_id = $this->_geti($data, 32);
+ $attr_name = $named_id;
+ break;
+
+ case self::MAPI_NAMED_TYPE_STRING:
+ $attr_name = 0x9999;
+ $idlen = $this->_geti($data, 32);
+ $datalen = $idlen + ((4 - ($idlen % 4)) % 4);
+ $named_id = substr($this->_getx($data, $datalen), 0, $idlen);
+ break;
+ }
+ }
+
+ if ($have_mval) {
+ $num_mval = $this->_geti($data, 32);
+ }
+
+ switch ($attr_type) {
+ case self::MAPI_SHORT:
+ $value = $this->_geti($data, 16);
+ break;
+
+ case self::MAPI_INT:
+ case self::MAPI_BOOLEAN:
+ for ($i = 0; $i < $num_mval; $i++) {
+ $value = $this->_geti($data, 32);
+ }
+ break;
+
+ case self::MAPI_FLOAT:
+ case self::MAPI_ERROR:
+ $value = $this->_getx($data, 4);
+ break;
+
+ case self::MAPI_DOUBLE:
+ case self::MAPI_APPTIME:
+ case self::MAPI_CURRENCY:
+ case self::MAPI_INT8BYTE:
+ case self::MAPI_SYSTIME:
+ $value = $this->_getx($data, 8);
+ break;
+
+ case self::MAPI_STRING:
+ case self::MAPI_UNICODE_STRING:
+ case self::MAPI_BINARY:
+ case self::MAPI_OBJECT:
+ $num_vals = ($have_mval) ? $num_mval : $this->_geti($data, 32);
+ for ($i = 0; $i < $num_vals; $i++) {
+ $length = $this->_geti($data, 32);
+
+ /* Pad to next 4 byte boundary. */
+ $datalen = $length + ((4 - ($length % 4)) % 4);
+
+ if ($attr_type == self::MAPI_STRING) {
+ --$length;
+ }
+
+ /* Read and truncate to length. */
+ $value = substr($this->_getx($data, $datalen), 0, $length);
+ }
+ break;
+ }
+
+ /* Store any interesting attributes. */
+ switch ($attr_name) {
+ case self::MAPI_ATTACH_LONG_FILENAME:
+ /* Used in preference to AFILENAME value. */
+ $attachment_data[0]['name'] = preg_replace('/.*[\/](.*)$/', '\1', $value);
+ $attachment_data[0]['name'] = str_replace("\0", '', $attachment_data[0]['name']);
+ break;
+
+ case self::MAPI_ATTACH_MIME_TAG:
+ /* Is this ever set, and what is format? */
+ $attachment_data[0]['type'] = preg_replace('/^(.*)\/.*/', '\1', $value);
+ $attachment_data[0]['subtype'] = preg_replace('/.*\/(.*)$/', '\1', $value);
+ $attachment_data[0]['subtype'] = str_replace("\0", '', $attachment_data[0]['subtype']);
+ break;
+ }
+ }
+ }
+
+ /**
+ * TODO
+ *
+ * @param string &$data The data string.
+ */
+ protected function _decodeMessage(&$data)
+ {
+ $this->_decodeAttribute($data, $this->_geti($data, 32));
+ }
+
+ /**
+ * TODO
+ *
+ * @param string &$data The data string.
+ * @param array &$attachment_data TODO
+ */
+ protected function _decodeAttachment(&$data, &$attachment_data)
+ {
+ $attribute = $this->_geti($data, 32);
+
+ switch ($attribute) {
+ case self::ARENDDATA:
+ /* Marks start of new attachment. */
+ $this->_getx($data, $this->_geti($data, 32));
+
+ /* Checksum */
+ $this->_geti($data, 16);
+
+ /* Add a new default data block to hold details of this
+ attachment. Reverse order is easier to handle later! */
+ array_unshift($attachment_data, array('type' => 'application',
+ 'subtype' => 'octet-stream',
+ 'name' => 'unknown',
+ 'stream' => ''));
+ break;
+
+ case self::AFILENAME:
+ /* Strip path. */
+ $attachment_data[0]['name'] = preg_replace('/.*[\/](.*)$/', '\1', $this->_getx($data, $this->_geti($data, 32)));
+ $attachment_data[0]['name'] = str_replace("\0", '', $attachment_data[0]['name']);
+
+ /* Checksum */
+ $this->_geti($data, 16);
+ break;
+
+ case self::ATTACHDATA:
+ /* The attachment itself. */
+ $length = $this->_geti($data, 32);
+ $attachment_data[0]['size'] = $length;
+ $attachment_data[0]['stream'] = $this->_getx($data, $length);
+
+ /* Checksum */
+ $this->_geti($data, 16);
+ break;
+
+ case self::AMAPIATTRS:
+ $length = $this->_geti($data, 32);
+ $value = $this->_getx($data, $length);
+
+ /* Checksum */
+ $this->_geti($data, 16);
+ $this->_extractMapiAttributes($value, $attachment_data);
+ break;
+
+ default:
+ $this->_decodeAttribute($data, $attribute);
+ }
+ }
+
+}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Apr 19, 9:46 AM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
435808
Default Alt Text
(75 KB)

Event Timeline