# HG changeset patch # User Dan # Date 1198647446 18000 # Node ID c72b545f1304ef5b64de6809b6c83b68334d38f6 # Parent 32429702305e09914cbd2ed3713185f622c94be8 More localization work. Resolved major issue with JSON parser not parsing files over ~50KB. Switched JSON parser to the one from the Zend Framework (BSD licensed). Forced to split enano.json into five different files. diff -r 32429702305e -r c72b545f1304 ajax.php --- a/ajax.php Fri Dec 21 19:08:27 2007 -0500 +++ b/ajax.php Wed Dec 26 00:37:26 2007 -0500 @@ -47,7 +47,6 @@ $db->connect(); // result is sent using JSON - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $return = Array( 'mode' => 'success', 'users_real' => Array() @@ -61,7 +60,7 @@ 'mode' => 'error', 'error' => 'Invalid URI' ); - die( $json->encode($return) ); + die( enano_json_encode($return) ); } $allowanon = ( isset($_GET['allowanon']) && $_GET['allowanon'] == '1' ) ? '' : ' AND user_id > 1'; $q = $db->sql_query('SELECT username FROM '.table_prefix.'users WHERE ' . ENANO_SQLFUNC_LOWERCASE . '(username) LIKE ' . ENANO_SQLFUNC_LOWERCASE . '(\'%'.$name.'%\')' . $allowanon . ' ORDER BY username ASC;'); @@ -80,7 +79,7 @@ // all done! :-) $db->close(); - echo $json->encode( $return ); + echo enano_json_encode( $return ); exit; } @@ -285,7 +284,6 @@ die('GOOD'); break; case 'get_tags': - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $ret = array('tags' => array(), 'user_level' => $session->user_level, 'can_add' => $session->get_permissions('tag_create')); $q = $db->sql_query('SELECT t.tag_id, t.tag_name, pg.pg_target IS NOT NULL AS used_in_acl, t.user_id FROM '.table_prefix.'tags AS t @@ -321,11 +319,10 @@ ); } - echo $json->encode($ret); + echo enano_json_encode($ret); break; case 'addtag': - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); $resp = array( 'success' => false, 'error' => 'No error', @@ -337,7 +334,7 @@ if ( !$session->get_permissions('tag_create') ) { $resp['error'] = 'You are not permitted to tag pages.'; - die($json->encode($resp)); + die(enano_json_encode($resp)); } // sanitize the tag name @@ -347,7 +344,7 @@ if ( strlen($tag) < 2 ) { $resp['error'] = 'Tags must consist of at least 2 alphanumeric characters.'; - die($json->encode($resp)); + die(enano_json_encode($resp)); } // check if tag is already on page @@ -357,7 +354,7 @@ if ( $db->numrows() > 0 ) { $resp['error'] = 'This page already has this tag.'; - die($json->encode($resp)); + die(enano_json_encode($resp)); } $db->free_result(); @@ -369,7 +366,7 @@ if ( $db->numrows() > 0 && !$can_edit_acl ) { $resp['error'] = 'This tag is used in an ACL page group, and thus can\'t be added to a page by people without administrator privileges.'; - die($json->encode($resp)); + die(enano_json_encode($resp)); } $resp['in_acl'] = ( $db->numrows() > 0 ); $db->free_result(); @@ -383,7 +380,7 @@ $resp['tag'] = $tag; $resp['tag_id'] = $db->insert_id(); - echo $json->encode($resp); + echo enano_json_encode($resp); break; case 'deltag': diff -r 32429702305e -r c72b545f1304 images/pm_ajax.gif Binary file images/pm_ajax.gif has changed diff -r 32429702305e -r c72b545f1304 images/pm_star_off.png Binary file images/pm_star_off.png has changed diff -r 32429702305e -r c72b545f1304 images/pm_star_on.png Binary file images/pm_star_on.png has changed diff -r 32429702305e -r c72b545f1304 includes/clientside/css/enano-shared.css --- a/includes/clientside/css/enano-shared.css Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/clientside/css/enano-shared.css Wed Dec 26 00:37:26 2007 -0500 @@ -193,6 +193,7 @@ div.search-result span.search-result-info { color: #7777CC; } div.search-result span.search-result-url { color: green; } div.search-result span.search-term, div.search-result span.title-search-term { background-color: #FFFFC0; font-weight: bold; } +div.search-result span.url-search-term { font-weight: bold; } div.search-result span.search-result-annotation { font-size: 8pt; } div.search-hibar { border-top: 1px solid #3366CC; margin-top: 10px; color: #000; background-color: #D5DFF3; padding: 3px; vertical-align: middle; } div.search-lobar { background-color: #E5EFFF; margin: 0; padding: 5px; } @@ -526,3 +527,121 @@ font-size: 0.7em; } +/* Default private message AJAX interface styles (colors and style based on those of Gmail) */ + +div#privmsgs { + /* Neal prefers this border but I personally consider it distasteful because it detracts from the Gmail-ey look. + border: 1px solid #c0c0c0; */ + background-color: white; + color: black; +} + +span.pm_link { + color: #0000ff; + cursor: pointer; + text-decoration: underline; +} + +span.pm_link_folder { + display: block; + text-decoration: none; + padding: 3px; +} + +span.pm_link_selected { + background-color: #c3d9ff; + font-weight: bold; + text-decoration: underline; +} + +span.pm_link_selected_trash { + background-color: #d9d9db; +} + +div.pm_break { + height: 10px; +} + +div.pm_main { + background-color: #c3d9ff; + padding: 5px 5px 3px 5px; + margin-left: 12em; + min-height: 16em; +} + +div.pm_main_trash { + background-color: #d9d9db; +} + +div.pm_status { + display: table; + background-color: #cc0000; + padding: 3px; + margin: 0 auto; + color: white; +} + +div.pm_teaser { + background-color: white; + color: black; + text-align: center; + padding: 8em 1em 8em 1em; +} + +div.pm_mlist_message { + background-color: #e8eef7; + color: black; + border-bottom: 1px solid #d8d8d8; + cursor: pointer; +} + +div.pm_mlist_message span.pm_subject { + font-weight: normal; + display: inline-block; + clip: rect(0px, auto, auto, 0px); + overflow: hidden; + margin: 0 3px 0 0; +} + +div.pm_mlist_message span.pm_sender { + display: inline-block; + width: 30%; + margin: 0 10px 0% 4px; + font-weight: normal; + clip: rect(0px, auto, auto, 0px); + overflow: hidden; +} + +div.pm_mlist_message span.pm_miniclip { + color: #909090; + display: inline-block; + clip: rect(0px, auto, auto, 0px); + overflow: hidden; +} + +div.pm_messagelist_inner { + min-height: 12em; + background-color: white; +} + +div.pm_mlist_message_unread { + background-color: white; +} + +div.pm_mlist_message_unread span.pm_subject { + font-weight: bold; +} + +div.pm_mlist_message_unread span.pm_sender { + font-weight: bold; +} + +div.pm_mlist_message_selected { + background-color: #ffffcc; +} + +span.pm_toolbar_label { + color: black; + font-weight: bold; +} + diff -r 32429702305e -r c72b545f1304 includes/clientside/static/l10n.js --- a/includes/clientside/static/l10n.js Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/clientside/static/l10n.js Wed Dec 26 00:37:26 2007 -0500 @@ -18,7 +18,7 @@ return string_id; if ( typeof(this.strings[catname][string_name]) != 'string' ) return string_id; - return '[LJS] ' + this.perform_subst(this.strings[catname][string_name], subst); + return this.perform_subst(this.strings[catname][string_name], subst) + '**'; } this.perform_subst = function(str, subst) diff -r 32429702305e -r c72b545f1304 includes/clientside/static/misc.js --- a/includes/clientside/static/misc.js Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/clientside/static/misc.js Wed Dec 26 00:37:26 2007 -0500 @@ -792,3 +792,13 @@ return ( email.match(/^(?:[\w\d_-]+\.?)+@((?:(?:[\w\d_-]\-?)+\.)+\w{2,4}|localhost)$/) ) ? true : false; } +/** + * Equivalent of PHP's time() + * @return int + */ + +function unix_time() +{ + return parseInt((new Date()).getTime()/1000); +} + diff -r 32429702305e -r c72b545f1304 includes/comment.php --- a/includes/comment.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/comment.php Wed Dec 26 00:37:26 2007 -0500 @@ -80,19 +80,18 @@ function process_json($json) { global $db, $session, $paths, $template, $plugins; // Common objects - $parser = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); - $data = $parser->decode($json); + $data = enano_json_decode($json); $data = decode_unicode_array($data); if ( !isset($data['mode']) ) { $ret = Array('mode'=>'error','error'=>'No mode defined!'); - echo $parser->encode($ret); + echo enano_json_encode($ret); return $ret; } if ( getConfig('enable_comments') == '0' ) { $ret = Array('mode'=>'error','error'=>'Comments are not enabled on this site.'); - echo $parser->encode($ret); + echo enano_json_encode($ret); return $ret; } $ret = Array(); @@ -346,7 +345,7 @@ 'mode' => 'error', 'error' => 'You are not authorized to moderate comments.' ); - echo $parser->encode($ret); + echo enano_json_encode($ret); return $ret; } @@ -383,7 +382,7 @@ ); break; } - echo $parser->encode($ret); + echo enano_json_encode($ret); return $ret; } diff -r 32429702305e -r c72b545f1304 includes/common.php --- a/includes/common.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/common.php Wed Dec 26 00:37:26 2007 -0500 @@ -120,6 +120,7 @@ require_once(ENANO_ROOT.'/includes/email.php'); require_once(ENANO_ROOT.'/includes/search.php'); require_once(ENANO_ROOT.'/includes/json.php'); +require_once(ENANO_ROOT.'/includes/json2.php'); require_once(ENANO_ROOT.'/includes/wikiengine/Tables.php'); require_once(ENANO_ROOT.'/includes/pageprocess.php'); require_once(ENANO_ROOT.'/includes/tagcloud.php'); @@ -348,6 +349,14 @@ // All checks passed! Start the main components up. $session->start(); + + // This is where plugins will want to add pages from 1.1.x on out. You can still add pages at base_classes_initted but the titles won't be localized. + $code = $plugins->setHook('session_started'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + $paths->init(); // We're ready for whatever life throws us now. @@ -385,7 +394,7 @@ // A better name for this hook would be common_post. At this point // all of Enano is fully initialized and running and you're ready // to do whatever you want. - $code = $plugins->setHook('session_started'); + $code = $plugins->setHook('common_post'); foreach ( $code as $cmd ) { eval($cmd); diff -r 32429702305e -r c72b545f1304 includes/constants.php --- a/includes/constants.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/constants.php Wed Dec 26 00:37:26 2007 -0500 @@ -68,6 +68,15 @@ define('GROUP_HIDDEN', 3); define('GROUP_OPEN', 4); +// Private message flags +define('PM_UNREAD', 1); +define('PM_STARRED', 2); +define('PM_SENT', 4); +define('PM_DRAFT', 8); +define('PM_ARCHIVE', 16); +define('PM_TRASH', 32); +define('PM_DELIVERED', 64); + // Other stuff define('MAX_PMS_PER_BATCH', 7); // The maximum number of users that users can send PMs to in one go; restriction does not apply to users with mod_misc rights diff -r 32429702305e -r c72b545f1304 includes/functions.php --- a/includes/functions.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/functions.php Wed Dec 26 00:37:26 2007 -0500 @@ -3806,6 +3806,58 @@ return false; } +/** + * Generates a JSON encoder/decoder singleton. + * @return object + */ + +function enano_json_singleton() +{ + static $json_obj; + if ( !is_object($json_obj) ) + $json_obj = new Services_JSON(SERVICES_JSON_LOOSE_TYPE | SERVICES_JSON_SUPPRESS_ERRORS); + + return $json_obj; +} + +/** + * Wrapper for JSON encoding. + * @param mixed Variable to encode + * @return string JSON-encoded string + */ + +function enano_json_encode($data) +{ + /* + if ( function_exists('json_encode') ) + { + // using PHP5 with JSON support + return json_encode($data); + } + */ + + return Zend_Json::encode($data, true); +} + +/** + * Wrapper for JSON decoding. + * @param string JSON-encoded string + * @return mixed Decoded value + */ + +function enano_json_decode($data) +{ + /* + if ( function_exists('json_decode') ) + { + // using PHP5 with JSON support + return json_decode($data); + } + */ + + return Zend_Json::decode($data, Zend_Json::TYPE_ARRAY); +} + //die('
Original: 01010101010100101010100101010101011010'."\nProcessed: ".uncompress_bitfield(compress_bitfield('01010101010100101010100101010101011010')).''); ?> diff -r 32429702305e -r c72b545f1304 includes/json2.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/json2.php Wed Dec 26 00:37:26 2007 -0500 @@ -0,0 +1,1015 @@ +_cycleCheck = $cycleCheck; + } + + /** + * Use the JSON encoding scheme for the value specified + * + * @param mixed $value The value to be encoded + * @param boolean $cycleCheck Whether or not to check for possible object recursion when encoding + * @return string The encoded value + */ + public static function encode($value, $cycleCheck = false) + { + $encoder = new Zend_Json_Encoder(($cycleCheck) ? true : false); + + return $encoder->_encodeValue($value); + } + + /** + * Recursive driver which determines the type of value to be encoded + * and then dispatches to the appropriate method. $values are either + * - objects (returns from {@link _encodeObject()}) + * - arrays (returns from {@link _encodeArray()}) + * - basic datums (e.g. numbers or strings) (returns from {@link _encodeDatum()}) + * + * @param $value mixed The value to be encoded + * @return string Encoded value + */ + protected function _encodeValue(&$value) + { + if (is_object($value)) { + return $this->_encodeObject($value); + } else if (is_array($value)) { + return $this->_encodeArray($value); + } + + return $this->_encodeDatum($value); + } + + + + /** + * Encode an object to JSON by encoding each of the public properties + * + * A special property is added to the JSON object called '__className' + * that contains the name of the class of $value. This is used to decode + * the object on the client into a specific class. + * + * @param $value object + * @return string + * @throws Zend_Json_Exception If recursive checks are enabled and the object has been serialized previously + */ + protected function _encodeObject(&$value) + { + if ($this->_cycleCheck) { + if ($this->_wasVisited($value)) { + throw new Zend_Json_Exception( + 'Cycles not supported in JSON encoding, cycle introduced by ' + . 'class "' . get_class($value) . '"' + ); + } + + $this->_visited[] = $value; + } + + $props = ''; + foreach (get_object_vars($value) as $name => $propValue) { + if (isset($propValue)) { + $props .= ',' + . $this->_encodeValue($name) + . ':' + . $this->_encodeValue($propValue); + } + } + + return '{"__className":"' . get_class($value) . '"' + . $props . '}'; + } + + + /** + * Determine if an object has been serialized already + * + * @param mixed $value + * @return boolean + */ + protected function _wasVisited(&$value) + { + if (in_array($value, $this->_visited, true)) { + return true; + } + + return false; + } + + + /** + * JSON encode an array value + * + * Recursively encodes each value of an array and returns a JSON encoded + * array string. + * + * Arrays are defined as integer-indexed arrays starting at index 0, where + * the last index is (count($array) -1); any deviation from that is + * considered an associative array, and will be encoded as such. + * + * @param $array array + * @return string + */ + protected function _encodeArray(&$array) + { + $tmpArray = array(); + + // Check for associative array + if (!empty($array) && (array_keys($array) !== range(0, count($array) - 1))) { + // Associative array + $result = '{'; + foreach ($array as $key => $value) { + $key = (string) $key; + $tmpArray[] = $this->_encodeString($key) + . ':' + . $this->_encodeValue($value); + } + $result .= implode(',', $tmpArray); + $result .= '}'; + } else { + // Indexed array + $result = '['; + $length = count($array); + for ($i = 0; $i < $length; $i++) { + $tmpArray[] = $this->_encodeValue($array[$i]); + } + $result .= implode(',', $tmpArray); + $result .= ']'; + } + + return $result; + } + + + /** + * JSON encode a basic data type (string, number, boolean, null) + * + * If value type is not a string, number, boolean, or null, the string + * 'null' is returned. + * + * @param $value mixed + * @return string + */ + protected function _encodeDatum(&$value) + { + $result = 'null'; + + if (is_int($value) || is_float($value)) { + $result = (string)$value; + } elseif (is_string($value)) { + $result = $this->_encodeString($value); + } elseif (is_bool($value)) { + $result = $value ? 'true' : 'false'; + } + + return $result; + } + + + /** + * JSON encode a string value by escaping characters as necessary + * + * @param $value string + * @return string + */ + protected function _encodeString(&$string) + { + // Escape these characters with a backslash: + // " \ / \n \r \t \b \f + $search = array('\\', "\n", "\t", "\r", "\b", "\f", '"'); + $replace = array('\\\\', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'); + $string = str_replace($search, $replace, $string); + + // Escape certain ASCII characters: + // 0x08 => \b + // 0x0c => \f + $string = str_replace(array(chr(0x08), chr(0x0C)), array('\b', '\f'), $string); + + return '"' . $string . '"'; + } + + + /** + * Encode the constants associated with the ReflectionClass + * parameter. The encoding format is based on the class2 format + * + * @param $cls ReflectionClass + * @return string Encoded constant block in class2 format + */ + private static function _encodeConstants(ReflectionClass $cls) + { + $result = "constants : {"; + $constants = $cls->getConstants(); + + $tmpArray = array(); + if (!empty($constants)) { + foreach ($constants as $key => $value) { + $tmpArray[] = "$key: " . self::encode($value); + } + + $result .= implode(', ', $tmpArray); + } + + return $result . "}"; + } + + + /** + * Encode the public methods of the ReflectionClass in the + * class2 format + * + * @param $cls ReflectionClass + * @return string Encoded method fragment + * + */ + private static function _encodeMethods(ReflectionClass $cls) + { + $methods = $cls->getMethods(); + $result = 'methods:{'; + + $started = false; + foreach ($methods as $method) { + if (! $method->isPublic() || !$method->isUserDefined()) { + continue; + } + + if ($started) { + $result .= ','; + } + $started = true; + + $result .= '' . $method->getName(). ':function('; + + if ('__construct' != $method->getName()) { + $parameters = $method->getParameters(); + $paramCount = count($parameters); + $argsStarted = false; + + $argNames = "var argNames=["; + foreach ($parameters as $param) { + if ($argsStarted) { + $result .= ','; + } + + $result .= $param->getName(); + + if ($argsStarted) { + $argNames .= ','; + } + + $argNames .= '"' . $param->getName() . '"'; + + $argsStarted = true; + } + $argNames .= "];"; + + $result .= "){" + . $argNames + . 'var result = ZAjaxEngine.invokeRemoteMethod(' + . "this, '" . $method->getName() + . "',argNames,arguments);" + . 'return(result);}'; + } else { + $result .= "){}"; + } + } + + return $result . "}"; + } + + + /** + * Encode the public properties of the ReflectionClass in the class2 + * format. + * + * @param $cls ReflectionClass + * @return string Encode properties list + * + */ + private static function _encodeVariables(ReflectionClass $cls) + { + $properties = $cls->getProperties(); + $propValues = get_class_vars($cls->getName()); + $result = "variables:{"; + $cnt = 0; + + $tmpArray = array(); + foreach ($properties as $prop) { + if (! $prop->isPublic()) { + continue; + } + + $tmpArray[] = $prop->getName() + . ':' + . self::encode($propValues[$prop->getName()]); + } + $result .= implode(',', $tmpArray); + + return $result . "}"; + } + + /** + * Encodes the given $className into the class2 model of encoding PHP + * classes into JavaScript class2 classes. + * NOTE: Currently only public methods and variables are proxied onto + * the client machine + * + * @param $className string The name of the class, the class must be + * instantiable using a null constructor + * @param $package string Optional package name appended to JavaScript + * proxy class name + * @return string The class2 (JavaScript) encoding of the class + * @throws Zend_Json_Exception + */ + public static function encodeClass($className, $package = '') + { + $cls = new ReflectionClass($className); + if (! $cls->isInstantiable()) { + throw new Zend_Json_Exception("$className must be instantiable"); + } + + return "Class.create('$package$className',{" + . self::_encodeConstants($cls) ."," + . self::_encodeMethods($cls) ."," + . self::_encodeVariables($cls) .'});'; + } + + + /** + * Encode several classes at once + * + * Returns JSON encoded classes, using {@link encodeClass()}. + * + * @param array $classNames + * @param string $package + * @return string + */ + public static function encodeClasses(array $classNames, $package = '') + { + $result = ''; + foreach ($classNames as $className) { + $result .= self::encodeClass($className, $package); + } + + return $result; + } + +} + +/** + * Decode JSON encoded string to PHP variable constructs + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Decoder +{ + /** + * Parse tokens used to decode the JSON object. These are not + * for public consumption, they are just used internally to the + * class. + */ + const EOF = 0; + const DATUM = 1; + const LBRACE = 2; + const LBRACKET = 3; + const RBRACE = 4; + const RBRACKET = 5; + const COMMA = 6; + const COLON = 7; + + /** + * Use to maintain a "pointer" to the source being decoded + * + * @var string + */ + protected $_source; + + /** + * Caches the source length + * + * @var int + */ + protected $_sourceLength; + + /** + * The offset within the souce being decoded + * + * @var int + * + */ + protected $_offset; + + /** + * The current token being considered in the parser cycle + * + * @var int + */ + protected $_token; + + /** + * Flag indicating how objects should be decoded + * + * @var int + * @access protected + */ + protected $_decodeType; + + /** + * Constructor + * + * @param string $source String source to decode + * @param int $decodeType How objects should be decoded -- see + * {@link Zend_Json::TYPE_ARRAY} and {@link Zend_Json::TYPE_OBJECT} for + * valid values + * @return void + */ + protected function __construct($source, $decodeType) + { + + // eliminate comments + $source = preg_replace(array( + + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + + ), '', $source); + + // Set defaults + $this->_source = $source; + $this->_sourceLength = strlen($source); + $this->_token = self::EOF; + $this->_offset = 0; + + // Normalize and set $decodeType + if (!in_array($decodeType, array(Zend_Json::TYPE_ARRAY, Zend_Json::TYPE_OBJECT))) + { + $decodeType = Zend_Json::TYPE_ARRAY; + } + $this->_decodeType = $decodeType; + + // Set pointer at first token + $this->_getNextToken(); + } + + /** + * Decode a JSON source string + * + * Decodes a JSON encoded string. The value returned will be one of the + * following: + * - integer + * - float + * - boolean + * - null + * - StdClass + * - array + * - array of one or more of the above types + * + * By default, decoded objects will be returned as associative arrays; to + * return a StdClass object instead, pass {@link Zend_Json::TYPE_OBJECT} to + * the $objectDecodeType parameter. + * + * Throws a Zend_Json_Exception if the source string is null. + * + * @static + * @access public + * @param string $source String to be decoded + * @param int $objectDecodeType How objects should be decoded; should be + * either or {@link Zend_Json::TYPE_ARRAY} or + * {@link Zend_Json::TYPE_OBJECT}; defaults to TYPE_ARRAY + * @return mixed + * @throws Zend_Json_Exception + */ + public static function decode($source = null, $objectDecodeType = Zend_Json::TYPE_ARRAY) + { + if (null === $source) { + throw new Zend_Json_Exception('Must specify JSON encoded source for decoding'); + } elseif (!is_string($source)) { + throw new Zend_Json_Exception('Can only decode JSON encoded strings'); + } + + $decoder = new self($source, $objectDecodeType); + + return $decoder->_decodeValue(); + } + + + /** + * Recursive driving rountine for supported toplevel tops + * + * @return mixed + */ + protected function _decodeValue() + { + switch ($this->_token) { + case self::DATUM: + $result = $this->_tokenValue; + $this->_getNextToken(); + return($result); + break; + case self::LBRACE: + return($this->_decodeObject()); + break; + case self::LBRACKET: + return($this->_decodeArray()); + break; + default: + return null; + break; + } + } + + /** + * Decodes an object of the form: + * { "attribute: value, "attribute2" : value,...} + * + * If ZJsonEnoder or ZJAjax was used to encode the original object + * then a special attribute called __className which specifies a class + * name that should wrap the data contained within the encoded source. + * + * Decodes to either an array or StdClass object, based on the value of + * {@link $_decodeType}. If invalid $_decodeType present, returns as an + * array. + * + * @return array|StdClass + */ + protected function _decodeObject() + { + $members = array(); + $tok = $this->_getNextToken(); + + while ($tok && $tok != self::RBRACE) { + if ($tok != self::DATUM || ! is_string($this->_tokenValue)) { + throw new Zend_Json_Exception('Missing key in object encoding: ' . $this->_source); + } + + $key = $this->_tokenValue; + $tok = $this->_getNextToken(); + + if ($tok != self::COLON) { + throw new Zend_Json_Exception('Missing ":" in object encoding: ' . $this->_source); + } + + $tok = $this->_getNextToken(); + $members[$key] = $this->_decodeValue(); + $tok = $this->_token; + + if ($tok == self::RBRACE) { + break; + } + + if ($tok != self::COMMA) { + throw new Zend_Json_Exception('Missing "," in object encoding: ' . $this->_source); + } + + $tok = $this->_getNextToken(); + } + + switch ($this->_decodeType) { + case Zend_Json::TYPE_OBJECT: + // Create new StdClass and populate with $members + $result = new StdClass(); + foreach ($members as $key => $value) { + $result->$key = $value; + } + break; + case Zend_Json::TYPE_ARRAY: + default: + $result = $members; + break; + } + + $this->_getNextToken(); + return $result; + } + + /** + * Decodes a JSON array format: + * [element, element2,...,elementN] + * + * @return array + */ + protected function _decodeArray() + { + $result = array(); + $starttok = $tok = $this->_getNextToken(); // Move past the '[' + $index = 0; + + while ($tok && $tok != self::RBRACKET) { + $result[$index++] = $this->_decodeValue(); + + $tok = $this->_token; + + if ($tok == self::RBRACKET || !$tok) { + break; + } + + if ($tok != self::COMMA) { + throw new Zend_Json_Exception('Missing "," in array encoding: ' . $this->_source); + } + + $tok = $this->_getNextToken(); + } + + $this->_getNextToken(); + return($result); + } + + + /** + * Removes whitepsace characters from the source input + */ + protected function _eatWhitespace() + { + if (preg_match( + '/([\t\b\f\n\r ])*/s', + $this->_source, + $matches, + PREG_OFFSET_CAPTURE, + $this->_offset) + && $matches[0][1] == $this->_offset) + { + $this->_offset += strlen($matches[0][0]); + } + } + + + /** + * Retrieves the next token from the source stream + * + * @return int Token constant value specified in class definition + */ + protected function _getNextToken() + { + $this->_token = self::EOF; + $this->_tokenValue = null; + $this->_eatWhitespace(); + + if ($this->_offset >= $this->_sourceLength) { + return(self::EOF); + } + + $str = $this->_source; + $str_length = $this->_sourceLength; + $i = $this->_offset; + $start = $i; + + switch ($str{$i}) { + case '{': + $this->_token = self::LBRACE; + break; + case '}': + $this->_token = self::RBRACE; + break; + case '[': + $this->_token = self::LBRACKET; + break; + case ']': + $this->_token = self::RBRACKET; + break; + case ',': + $this->_token = self::COMMA; + break; + case ':': + $this->_token = self::COLON; + break; + case '"': + $result = ''; + do { + $i++; + if ($i >= $str_length) { + break; + } + + $chr = $str{$i}; + if ($chr == '\\') { + $i++; + if ($i >= $str_length) { + break; + } + $chr = $str{$i}; + switch ($chr) { + case '"' : + $result .= '"'; + break; + case '\\': + $result .= '\\'; + break; + case '/' : + $result .= '/'; + break; + case 'b' : + $result .= chr(8); + break; + case 'f' : + $result .= chr(12); + break; + case 'n' : + $result .= chr(10); + break; + case 'r' : + $result .= chr(13); + break; + case 't' : + $result .= chr(9); + break; + case '\'' : + $result .= '\''; + break; + default: + throw new Zend_Json_Exception("Illegal escape " + . "sequence '" . $chr . "'"); + } + } elseif ($chr == '"') { + break; + } else { + $result .= $chr; + } + } while ($i < $str_length); + + $this->_token = self::DATUM; + //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1); + $this->_tokenValue = $result; + break; + case "'": + $result = ''; + do { + $i++; + if ($i >= $str_length) { + break; + } + + $chr = $str{$i}; + if ($chr == '\\') { + $i++; + if ($i >= $str_length) { + break; + } + $chr = $str{$i}; + switch ($chr) { + case "'" : + $result .= "'"; + break; + case '\\': + $result .= '\\'; + break; + case '/' : + $result .= '/'; + break; + case 'b' : + $result .= chr(8); + break; + case 'f' : + $result .= chr(12); + break; + case 'n' : + $result .= chr(10); + break; + case 'r' : + $result .= chr(13); + break; + case 't' : + $result .= chr(9); + break; + case '"' : + $result .= '"'; + break; + default: + throw new Zend_Json_Exception("Illegal escape " + . "sequence '" . $chr . "'"); + } + } elseif ($chr == "'") { + break; + } else { + $result .= $chr; + } + } while ($i < $str_length); + + $this->_token = self::DATUM; + //$this->_tokenValue = substr($str, $start + 1, $i - $start - 1); + $this->_tokenValue = $result; + break; + case 't': + if (($i+ 3) < $str_length && substr($str, $start, 4) == "true") { + $this->_token = self::DATUM; + } + $this->_tokenValue = true; + $i += 3; + break; + case 'f': + if (($i+ 4) < $str_length && substr($str, $start, 5) == "false") { + $this->_token = self::DATUM; + } + $this->_tokenValue = false; + $i += 4; + break; + case 'n': + if (($i+ 3) < $str_length && substr($str, $start, 4) == "null") { + $this->_token = self::DATUM; + } + $this->_tokenValue = NULL; + $i += 3; + break; + case ' ': + break; + } + + if ($this->_token != self::EOF) { + $this->_offset = $i + 1; // Consume the last token character + return($this->_token); + } + + $chr = $str{$i}; + if ($chr == '-' || $chr == '.' || ($chr >= '0' && $chr <= '9')) { + if (preg_match('/-?([0-9])*(\.[0-9]*)?((e|E)((-|\+)?)[0-9]+)?/s', + $str, $matches, PREG_OFFSET_CAPTURE, $start) && $matches[0][1] == $start) { + + $datum = $matches[0][0]; + + if (is_numeric($datum)) { + if (preg_match('/^0\d+$/', $datum)) { + throw new Zend_Json_Exception("Octal notation not supported by JSON (value: $datum)"); + } else { + $val = intval($datum); + $fVal = floatval($datum); + $this->_tokenValue = ($val == $fVal ? $val : $fVal); + } + } else { + throw new Zend_Json_Exception("Illegal number format: $datum"); + } + + $this->_token = self::DATUM; + $this->_offset = $start + strlen($datum); + } + } else { + throw new Zend_Json_Exception("Illegal Token at pos $i: $chr\nContext:\n--------------------------------------------------" . substr($str, $i) . "\n--------------------------------------------------"); + } + + return($this->_token); + } +} + +/** + * 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_Json + * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + + +/** + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json_Exception extends Zend_Exception +{} + +/** + * @category Zend + * @package Zend + * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Exception extends Exception +{} + +/** + * Class for encoding to and decoding from JSON. + * + * @category Zend + * @package Zend_Json + * @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ +class Zend_Json +{ + /** + * How objects should be encoded -- arrays or as StdClass. TYPE_ARRAY is 1 + * so that it is a boolean true value, allowing it to be used with + * ext/json's functions. + */ + const TYPE_ARRAY = 1; + const TYPE_OBJECT = 0; + + /** + * @var bool + */ + public static $useBuiltinEncoderDecoder = true; + + /** + * Decodes the given $encodedValue string which is + * encoded in the JSON format + * + * Uses ext/json's json_decode if available. + * + * @param string $encodedValue Encoded in JSON format + * @param int $objectDecodeType Optional; flag indicating how to decode + * objects. See {@link ZJsonDecoder::decode()} for details. + * @return mixed + */ + public static function decode($encodedValue, $objectDecodeType = Zend_Json::TYPE_ARRAY) + { + if (function_exists('json_decode') && self::$useBuiltinEncoderDecoder !== true) { + return json_decode($encodedValue, $objectDecodeType); + } + + return Zend_Json_Decoder::decode($encodedValue, $objectDecodeType); + } + + + /** + * Encode the mixed $valueToEncode into the JSON format + * + * Encodes using ext/json's json_encode() if available. + * + * NOTE: Object should not contain cycles; the JSON format + * does not allow object reference. + * + * NOTE: Only public variables will be encoded + * + * @param mixed $valueToEncode + * @param boolean $cycleCheck Optional; whether or not to check for object recursion; off by default + * @return string JSON encoded object + */ + public static function encode($valueToEncode, $cycleCheck = false) + { + if (function_exists('json_encode') && self::$useBuiltinEncoderDecoder !== true) { + return json_encode($valueToEncode); + } + + return Zend_Json_Encoder::encode($valueToEncode, $cycleCheck); + } +} + +?> diff -r 32429702305e -r c72b545f1304 includes/lang.php --- a/includes/lang.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/lang.php Wed Dec 26 00:37:26 2007 -0500 @@ -216,8 +216,7 @@ } else { - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); - $langdata = $json->decode($contents); + $langdata = enano_json_decode($contents); if ( !is_array($langdata) ) $db->_die('lang.php - invalid language file'); @@ -299,11 +298,34 @@ $contents = preg_replace('/^([^{]+)\{/', '{', $contents); $contents = preg_replace('/\}([^}]+)$/', '}', $contents); - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); - $langdata = $json->decode($contents); + // Correct syntax to be nice to the json parser + + // eliminate comments + $contents = preg_replace(array( + // eliminate single line comments in '// ...' form + '#^\s*//(.+)$#m', + // eliminate multi-line comments in '/* ... */' form, at start of string + '#^\s*/\*(.+)\*/#Us', + // eliminate multi-line comments in '/* ... */' form, at end of string + '#/\*(.+)\*/\s*$#Us' + ), '', $contents); + + $contents = preg_replace('/([,\{\[])([\s]*?)([a-z0-9_]+)([\s]*?):/', '\\1\\2"\\3" :', $contents); + + try + { + $langdata = enano_json_decode($contents); + } + catch(Zend_Json_Exception $e) + { + $db->_die('lang.php - Exception caught by JSON parser'); + exit; + } if ( !is_array($langdata) ) - $db->_die('lang.php - invalid language file'); + { + $db->_die('lang.php - invalid or non-well-formed language file'); + } if ( !isset($langdata['categories']) || !isset($langdata['strings']) ) $db->_die('lang.php - language file does not contain the proper items'); diff -r 32429702305e -r c72b545f1304 includes/pageutils.php --- a/includes/pageutils.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/pageutils.php Wed Dec 26 00:37:26 2007 -0500 @@ -1608,10 +1608,9 @@ function getstyles() { - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); if ( !preg_match('/^([a-z0-9_-]+)$/', $_GET['id']) ) - return $json->encode(false); + return enano_json_encode(false); $dir = './themes/' . $_GET['id'] . '/css/'; $list = Array(); @@ -1631,10 +1630,10 @@ } else { - return($json->encode(Array('mode' => 'error', 'error' => $dir.' is not a dir'))); + return(enano_json_encode(Array('mode' => 'error', 'error' => $dir.' is not a dir'))); } - return $json->encode($list); + return enano_json_encode($list); } /** @@ -2188,10 +2187,9 @@ function acl_json($parms = '{ }') { global $db, $session, $paths, $template, $plugins; // Common objects - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); - $parms = $json->decode($parms); + $parms = enano_json_decode($parms); $ret = PageUtils::acl_editor($parms); - $ret = $json->encode($ret); + $ret = enano_json_encode($ret); return $ret; } diff -r 32429702305e -r c72b545f1304 includes/paths.php --- a/includes/paths.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/paths.php Wed Dec 26 00:37:26 2007 -0500 @@ -418,8 +418,16 @@ function add_page($flags) { + global $lang; $flags['urlname_nons'] = $flags['urlname']; $flags['urlname'] = $this->nslist[$flags['namespace']] . $flags['urlname']; // Applies the User:/File:/etc prefixes to the URL names + + if ( is_object($lang) ) + { + if ( preg_match('/^[a-z0-9]+_[a-z0-9_]+$/', $flags['name']) ) + $flags['name'] = $lang->get($flags['name']); + } + $pages_len = sizeof($this->pages)/2; $this->pages[$pages_len] = $flags; $this->pages[$flags['urlname']] =& $this->pages[$pages_len]; diff -r 32429702305e -r c72b545f1304 includes/search.php --- a/includes/search.php Fri Dec 21 19:08:27 2007 -0500 +++ b/includes/search.php Wed Dec 26 00:37:26 2007 -0500 @@ -112,10 +112,11 @@ * @param string Search query * @param string Will be filled with any warnings encountered whilst parsing the query * @param bool Case sensitivity - defaults to false + * @param array|reference Will be filled with the parsed list of words. * @return array */ -function perform_search($query, &$warnings, $case_sensitive = false) +function perform_search($query, &$warnings, $case_sensitive = false, &$word_list) { global $db, $session, $paths, $template, $plugins; // Common objects $warnings = array(); @@ -522,7 +523,7 @@ if ( isset($scores[$idstring]) ) { $page_data[$idstring] = array( - 'page_name' => $page['name'], + 'page_name' => highlight_search_result($page['name'], $word_list, $case_sensitive), 'page_text' => '', 'page_id' => $page['urlname_nons'], 'namespace' => $page['namespace'], @@ -592,6 +593,11 @@ // if ( $score > $divisor ) // $score = $divisor; $datum['score'] = round($score / $divisor, 2) * 100; + + // Highlight the URL + $datum['url_highlight'] = makeUrlComplete($datum['namespace'], $datum['page_id']); + $datum['url_highlight'] = preg_replace('/\?.+$/', '', $datum['url_highlight']); + $datum['url_highlight'] = highlight_search_result($datum['url_highlight'], $word_list, $case_sensitive); // Store it in our until-now-unused results array $results[] = $datum; @@ -613,6 +619,8 @@ function parse_search_query($query, &$warnings) { + global $lang; + $stopwords = get_stopwords(); $ret = array( 'any' => array(), @@ -663,7 +671,7 @@ if ( $ticker == 20 ) { - $warnings[] = 'Some of your search terms were excluded because searches are limited to 20 terms to prevent excessive server load.'; + $warnings[] = $lang->get('search_err_query_too_many_terms'); break; } @@ -672,13 +680,13 @@ $word = substr ( $atom, 2, ( strlen( $atom ) - 3 ) ); if ( strlen ( $word ) < 2 || in_array($word, $stopwords) ) { - $warnings[] = 'One or more of your search terms was excluded because either it was less than 2 characters in length or is a common word (a stopword) that is typically found on a large number of pages. Examples of stopwords include "the", "this", "which", "with", etc.'; + $warnings[] = $lang->get('search_err_query_has_stopwords'); $ticker--; continue; } if(in_array($word, $ret['req'])) { - $warnings[] = 'One or more of your search terms was excluded because duplicate terms were encountered.'; + $warnings[] = $lang->get('search_err_query_dup_terms'); $ticker--; continue; } @@ -689,13 +697,13 @@ $word = substr ( $atom, 2, ( strlen( $atom ) - 3 ) ); if ( strlen ( $word ) < 4 ) { - $warnings[] = 'One or more of your search terms was excluded because terms must be at least 4 characters in length.'; + $warnings[] = $lang->get('search_err_query_term_too_short'); $ticker--; continue; } if(in_array($word, $ret['not'])) { - $warnings[] = 'One or more of your search terms was excluded because duplicate terms were encountered.'; + $warnings[] = $lang->get('search_err_query_dup_terms'); $ticker--; continue; } @@ -706,13 +714,13 @@ $word = substr ( $atom, 1 ); if ( strlen ( $word ) < 2 || in_array($word, $stopwords) ) { - $warnings[] = 'One or more of your search terms was excluded because either it was less than 2 characters in length or is a common word (a stopword) that is typically found on a large number of pages. Examples of stopwords include "the", "this", "which", "with", etc.'; + $warnings[] = $lang->get('search_err_query_has_stopwords'); $ticker--; continue; } if(in_array($word, $ret['req'])) { - $warnings[] = 'One or more of your search terms was excluded because duplicate terms were encountered.'; + $warnings[] = $lang->get('search_err_query_dup_terms'); $ticker--; continue; } @@ -723,13 +731,13 @@ $word = substr ( $atom, 1 ); if ( strlen ( $word ) < 2 || in_array($word, $stopwords) ) { - $warnings[] = 'One or more of your search terms was excluded because either it was less than 2 characters in length or is a common word (a stopword) that is typically found on a large number of pages. Examples of stopwords include "the", "this", "which", "with", etc.'; + $warnings[] = $lang->get('search_err_query_has_stopwords'); $ticker--; continue; } if(in_array($word, $ret['not'])) { - $warnings[] = 'One or more of your search terms was excluded because duplicate terms were encountered.'; + $warnings[] = $lang->get('search_err_query_dup_terms'); $ticker--; continue; } @@ -740,13 +748,13 @@ $word = substr ( $atom, 1, ( strlen ( $atom ) - 2 ) ); if ( strlen ( $word ) < 2 || in_array($word, $stopwords) ) { - $warnings[] = 'One or more of your search terms was excluded because either it was less than 2 characters in length or is a common word (a stopword) that is typically found on a large number of pages. Examples of stopwords include "the", "this", "which", "with", etc.'; + $warnings[] = $lang->get('search_err_query_has_stopwords'); $ticker--; continue; } if(in_array($word, $ret['any'])) { - $warnings[] = 'One or more of your search terms was excluded because duplicate terms were encountered.'; + $warnings[] = $lang->get('search_err_query_dup_terms'); $ticker--; continue; } @@ -757,13 +765,13 @@ $word = $atom; if ( strlen ( $word ) < 2 || in_array($word, $stopwords) ) { - $warnings[] = 'One or more of your search terms was excluded because either it was less than 2 characters in length or is a common word (a stopword) that is typically found on a large number of pages. Examples of stopwords include "the", "this", "which", "with", etc.'; + $warnings[] = $lang->get('search_err_query_has_stopwords'); $ticker--; continue; } if(in_array($word, $ret['any'])) { - $warnings[] = 'One or more of your search terms was excluded because duplicate terms were encountered.'; + $warnings[] = $lang->get('search_err_query_dup_terms'); $ticker--; continue; } diff -r 32429702305e -r c72b545f1304 index.php --- a/index.php Fri Dec 21 19:08:27 2007 -0500 +++ b/index.php Wed Dec 26 00:37:26 2007 -0500 @@ -20,10 +20,10 @@ // Set up gzip encoding before any output is sent - $aggressive_optimize_html = false; + $aggressive_optimize_html = true; global $do_gzip; - $do_gzip = false; + $do_gzip = true; if(isset($_SERVER['PATH_INFO'])) $v = $_SERVER['PATH_INFO']; elseif(isset($_GET['title'])) $v = $_GET['title']; diff -r 32429702305e -r c72b545f1304 install.php --- a/install.php Fri Dec 21 19:08:27 2007 -0500 +++ b/install.php Wed Dec 26 00:37:26 2007 -0500 @@ -1071,8 +1071,7 @@ break; case 'langjs': header('Content-type: text/javascript'); - $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE); - $lang_js = $json->encode($lang->strings); + $lang_js = enano_json_encode($lang->strings); // use EEOF here because jEdit misinterprets "typ'eof'" echo <<
Permission types:
This website is powered by Enano, the lightweight and open source CMS that everyone can use. Enano is copyright © 2006-2007 Dan Fuhry. For legal information, along with a list of libraries that Enano uses, please see Legal Information.
The developers and maintainers of Enano strongly believe that software should not only be free to use, but free to be modified, distributed, and used to create derivative works. For more information about Free Software, check out the Wikipedia page or the Free Software Foundation\'s homepage.
', + enano_about_gpl: 'This program is Free Software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
You should have received a copy of the GNU General Public License along with this program; if not, write to:
Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor
Boston, MA 02110-1301, USA
Alternatively, you can read it online.
', + enano_about_lbl_enanoversion: 'Enano version:', + enano_about_lbl_webserver: 'Web server:', + enano_about_lbl_serverplatform: 'Server platform:', + enano_about_lbl_phpversion: 'PHP version:', + enano_about_lbl_mysqlversion: 'MySQL version:', + }, + page: { + protect_lbl_success_title: 'Page protected', + protect_lbl_success_body: 'The protection setting has been applied. Return to the page.', + protect_err_need_reason: 'Error: you must enter a reason for protecting this page.', + protect_lbl_reason: 'Reason for protecting the page:', + protect_lbl_level: 'Protecion level to be applied:', + protect_lbl_level_none: 'No protection', + protect_lbl_level_semi: 'Semi-protection', + protect_lbl_level_full: 'Full protection', + protect_btn_submit: 'Protect page', + + rename_err_need_name: 'Error: you must enter a new name for this page.', + rename_lbl: 'Please enter a new name for this page:', + rename_btn_submit: 'Rename page', + rename_success_title: 'Page renamed', + + flushlogs_warning_stern: 'Unlike deleting or editing this page, this action is not reversible! You should only do this if you are desparate for database space.
Do you really want to continue?
', + flushlogs_btn_submit: 'Flush logs', + + delvote_warning_stern: 'If you think that this page is not relavent to the content on this site, or if it looks like this page was only created in an attempt to spam the site, you can request that this page be deleted by an administrator.
After you vote, you should leave a comment explaining the reason for your vote, especially if you are the first person to vote against this page.
', + + delvote_count_zero: 'So far, no one has voted for the deletion of this page.', + delvote_count_one: 'So far, one person has voted to delete this page.', + delvote_count_plural: 'So far, %delvotes% people have voted to delete this page.', + delvote_btn_submit: 'Vote to delete this page', + delvote_reset_btn_submit: 'Reset votes', + + delete_warning_stern: 'While the deletion of the page itself is completely reversible, it is impossible to recover any comments or category information on this page. If this is a file page, the file along with all older revisions of it will be permanently deleted. Also, any custom information that this page is tagged with, such as a custom name, protection status, or additional settings such as whether to allow comments, will be permanently lost.
Are you absolutely sure that you want to continue?
You will not be asked again.
Your user account doesn\'t have the necessary permission to view this page. There are a number of possible reasons for this:
+If you would like to inquire further about this message, you may contact the %site_administration%.
', + err_access_denied_siteadmin: 'site administrator', + msg_this_is_a_redirector: 'This page is a redirector.This website is powered by Enano, the lightweight and open source CMS that everyone can use. Enano is copyright © 2006-2007 Dan Fuhry. For legal information, along with a list of libraries that Enano uses, please see Legal Information.
The developers and maintainers of Enano strongly believe that software should not only be free to use, but free to be modified, distributed, and used to create derivative works. For more information about Free Software, check out the Wikipedia page or the Free Software Foundation\'s homepage.
', - enano_about_gpl: 'This program is Free Software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
You should have received a copy of the GNU General Public License along with this program; if not, write to:
Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor
Boston, MA 02110-1301, USA
Alternatively, you can read it online.
', - enano_about_lbl_enanoversion: 'Enano version:', - enano_about_lbl_webserver: 'Web server:', - enano_about_lbl_serverplatform: 'Server platform:', - enano_about_lbl_phpversion: 'PHP version:', - enano_about_lbl_mysqlversion: 'MySQL version:', - }, - user: { - login_message_short: 'Please enter your username and password to log in.', - login_message_short_elev: 'Please re-enter your login details', - login_body: 'Logging in enables you to use your preferences and access member information. If you don\'t have a username and password here, you can create an account.', - login_body_elev: 'You are requesting that a sensitive operation be performed. To continue, please re-enter your password to confirm your identity.', - login_field_username: 'Username', - login_field_password: 'Password', - login_forgotpass_blurb: 'Forgot your password? No problem.', - login_createaccount_blurb: 'Maybe you need to create an account.', - login_field_captcha: 'Code in image', - login_nocrypt_title: 'Important note regarding cryptography:', - login_nocrypt_body: 'Some countries do not allow the import or use of cryptographic technology. If you live in one of the countries listed below, you should log in without using encryption.', - login_nocrypt_countrylist: 'This restriction applies to the following countries: Belarus, China, India, Israel, Kazakhstan, Mongolia, Pakistan, Russia, Saudi Arabia, Singapore, Tunisia, Venezuela, and Vietnam.', - login_usecrypt_title: 'Encryption is currently turned off.', - login_usecrypt_body: 'If you are not in one of the countries listed below, you should enable encryption to secure the logon process.', - login_usecrypt_countrylist: 'The cryptography restriction applies to the following countries: Belarus, China, India, Israel, Kazakhstan, Mongolia, Pakistan, Russia, Saudi Arabia, Singapore, Tunisia, Venezuela, and Vietnam.', - login_success_title: 'Login successful', - login_success_body: 'You have successfully logged into the %config.site_name% site as "%username%". Redirecting to %redir_target%...', - login_success_body_mainpage: 'the main page', - login_success_short: 'Success.', - - login_ajax_fetching_key: 'Fetching an encryption key...', - login_ajax_prompt_title: 'Please enter your username and password to continue.', - login_ajax_prompt_title_elev: 'You are requesting a sensitive operation.', - login_ajax_prompt_body_elev: 'Please re-enter your login details, to verify your identity.', - login_ajax_link_fullform: 'Trouble logging in? Try the full login form.', - login_ajax_link_forgotpass: 'Did you forget your password?', - login_ajax_loggingin: 'Logging in...', - - err_key_not_found: 'Enano couldn\'t look up the encryption key used to encrypt your password. This most often happens if a cache rotation occurred during your login attempt, or if you refreshed the login page.', - err_key_not_found_cleared: 'It seems that the list of encryption keys used for login information has reached its maximum length, thus preventing new keys from being inserted. The list has been automatically cleared. Please try logging in again; if you are still unable to log in, please contact the site administration.', - err_key_wrong_length: 'The encryption key was the wrong length.', - err_too_big_for_britches: 'You are trying to authenticate at a level that your user account does not permit.', - err_invalid_credentials: 'You have entered an invalid username or password. Please enter your login details again.', - err_invalid_credentials_lockout: ' You have used up %fails% out of %config.lockout_threshold% login attempts. After you have used up all %config.lockout_threshold% login attempts, you will be locked out from logging in for %config.lockout_duration% minutes.', - err_invalid_credentials_lockout_captcha: ' You have used up %lockout_fails% out of %config.lockout_threshold% login attempts. After you have used up all %config.lockout_threshold% login attempts, you will have to enter a visual confirmation code while logging in, effective for %config.lockout_duration% minutes.', - err_backend_fail: 'You entered the right credentials and everything was validated, but for some reason Enano couldn\'t register your session. This is an internal problem with the site and you are encouraged to contact site administration.', - err_locked_out: 'You have used up all %config.lockout_threshold% allowed login attempts. Please wait %time_rem% minute%plural% before attempting to log in again%captcha_blurb%.', - err_locked_out_captcha_blurb: ', or enter the visual confirmation code shown above in the appropriate box', - - logout_success_title: 'Logged out', - logout_success_body: 'You have been successfully logged out, and all cookies have been cleared. You will now be transferred to the main page.', - logout_confirm_title: 'Are you sure you want to log out?', - logout_confirm_body: 'If you log out, you will no longer be able to access your user preferences, your private messages, or certain areas of this site until you log in again.', - logout_confirm_title_elev: 'Are you sure you want to de-authenticate?', - logout_confirm_body_elev: 'If you de-authenticate, you will no longer be able to use the administration panel until you re-authenticate again. You may do so at any time using the Administration button on the sidebar.', - logout_err_title: 'An error occurred during the logout process.', - // Unused at this point - logout_err_not_loggedin: 'You don\'t seem to be logged in.', - - keepalive_info_title: 'About the keep-alive feature', - keepalive_info_body: 'Keep-alive is a new Enano feature that keeps your administrative session from timing out while you are using the administration panel. This feature can be useful if you are editing a large page or doing something in the administration interface that will take longer than 15 minutes.Unlike deleting or editing this page, this action is not reversible! You should only do this if you are desparate for database space.
Do you really want to continue?
', - flushlogs_btn_submit: 'Flush logs', - - delvote_warning_stern: 'If you think that this page is not relavent to the content on this site, or if it looks like this page was only created in an attempt to spam the site, you can request that this page be deleted by an administrator.
After you vote, you should leave a comment explaining the reason for your vote, especially if you are the first person to vote against this page.
', - - delvote_count_zero: 'So far, no one has voted for the deletion of this page.', - delvote_count_one: 'So far, one person has voted to delete this page.', - delvote_count_plural: 'So far, %delvotes% people have voted to delete this page.', - delvote_btn_submit: 'Vote to delete this page', - delvote_reset_btn_submit: 'Reset votes', - - delete_warning_stern: 'While the deletion of the page itself is completely reversible, it is impossible to recover any comments or category information on this page. If this is a file page, the file along with all older revisions of it will be permanently deleted. Also, any custom information that this page is tagged with, such as a custom name, protection status, or additional settings such as whether to allow comments, will be permanently lost.
Are you absolutely sure that you want to continue?
You will not be asked again.
Your user account doesn\'t have the necessary permission to view this page. There are a number of possible reasons for this:
-If you would like to inquire further about this message, you may contact the %site_administration%.
', - err_access_denied_siteadmin: 'site administrator', - msg_this_is_a_redirector: 'This page is a redirector.Permission types:
You need to log in to view your private messages.
'); + die_friendly($lang->get('etc_access_denied_short'), '' . $lang->get('privmsgs_err_need_login', array('login_link' => makeUrlNS('Special', 'Login/' . $paths->page))) . '
'); } $argv = Array(); $argv[] = $paths->getParam(0); @@ -67,7 +68,7 @@ $db->free_result(); if ( ($r['message_to'] != $session->username && $r['message_from'] != $session->username ) || $r['folder_name']=='drafts' ) { - die_friendly('Access denied', 'You are not authorized to view this message.
'); + die_friendly($lang->get('etc_access_denied_short'), '' . $lang->get('privmsgs_err_not_authorized_read') . '
'); } if ( $r['message_to'] == $session->username ) { @@ -83,17 +84,17 @@ ?>Private message from | |||
---|---|---|---|
Subject: | |||
Date: | |||
Message: | get('privmsgs_lbl_message_from', array('sender' => htmlspecialchars($r['message_from']))); ?> | ||
get('privmsgs_lbl_subject') ?> | |||
get('privmsgs_lbl_date') ?> | |||
get('privmsgs_lbl_message') ?> | '; echo RenderMan::render($r['signature']); } ?> | ||
Send reply | Delete message | Archive message | Return to inbox | |||
get('privmsgs_btn_send_reply'); ?> | Delete message | get('privmsgs_btn_archive'); ?> | get('privmsgs_btn_return_to_inbox'); ?> |
You are not authorized to alter this message.
'); + die_friendly($lang->get('etc_access_denied_short'), '' . $lang->get('privmsgs_err_not_authorized_edit') . '
'); } $fname = $argv[2]; if ( !$fname || ( $fname != 'Inbox' && $fname != 'Outbox' && $fname != 'Sent' && $fname != 'Drafts' && $fname != 'Archive' ) ) @@ -126,7 +127,7 @@ { $db->_die('The message was not successfully moved.'); } - die_friendly('Message status', 'Your message has been moved to the folder "'.$fname.'".
'); + die_friendly($lang->get('privmsgs_msg_message_status'), '' . $lang->get('privmsgs_msg_message_moved', array('folder' => $fname)) . '
' . $lang->get('privmsgs_btn_return_to_inbox') . '
'); break; case 'Delete': $id = $argv[1]; @@ -142,7 +143,7 @@ $r = $db->fetchrow(); if ( $r['message_to'] != $session->username ) { - die_friendly('Access denied', 'You are not authorized to delete this message.
'); + die_friendly($lang->get('etc_access_denied_short'), 'You are not authorized to delete this message.
'); } $q = $db->sql_query('DELETE FROM '.table_prefix.'privmsgs WHERE message_id='.$id.';'); if ( !$q ) @@ -150,55 +151,99 @@ $db->_die('The message was not successfully deleted.'); } $db->free_result(); - die_friendly('Message status', 'The message has been deleted.
'); + die_friendly($lang->get('privmsgs_msg_message_status'), '' . $lang->get('privmsgs_msg_message_deleted') . '
' . $lang->get('privmsgs_btn_return_to_inbox') . '
'); break; case 'Compose': if ( $argv[1]=='Send' && isset($_POST['_send']) ) { // Check each POST DATA parameter... - if(!isset($_POST['to']) || ( isset($_POST['to']) && $_POST['to'] == '')) die_friendly('Sending of message failed', 'Please enter the username to which you want to send your message.
'); - if(!isset($_POST['subject']) || ( isset($_POST['subject']) && $_POST['subject'] == '')) die_friendly('Sending of message failed', 'Please enter a subject for your message.
'); - if(!isset($_POST['message']) || ( isset($_POST['message']) && $_POST['message'] == '')) die_friendly('Sending of message failed', 'Please enter a message to send.
'); - $namelist = $_POST['to']; - $namelist = str_replace(', ', ',', $namelist); - $namelist = explode(',', $namelist); - foreach($namelist as $n) { $n = $db->escape($n); } - $subject = RenderMan::preprocess_text($_POST['subject']); - $message = RenderMan::preprocess_text($_POST['message']); - $base_query = 'INSERT INTO '.table_prefix.'privmsgs(message_from,message_to,date,subject,message_text,folder_name,message_read) VALUES'; - foreach($namelist as $n) + $errors = array(); + if(!isset($_POST['to']) || ( isset($_POST['to']) && $_POST['to'] == '')) + { + $errors[] = $lang->get('privmsgs_err_need_username'); + } + if(!isset($_POST['subject']) || ( isset($_POST['subject']) && $_POST['subject'] == '')) + { + $errors[] = $lang->get('privmsgs_err_need_subject'); + } + if(!isset($_POST['message']) || ( isset($_POST['message']) && $_POST['message'] == '')) + { + $errors[] = $lang->get('privmsgs_err_need_message'); + } + if ( count($errors) < 1 ) { - $base_query .= '(\''.$session->username.'\', \''.$n.'\', '.time().', \''.$subject.'\', \''.$message.'\', \'inbox\', 0),'; + $namelist = $_POST['to']; + $namelist = str_replace(', ', ',', $namelist); + $namelist = explode(',', $namelist); + foreach($namelist as $n) { $n = $db->escape($n); } + $subject = RenderMan::preprocess_text($_POST['subject']); + $message = RenderMan::preprocess_text($_POST['message']); + $base_query = 'INSERT INTO '.table_prefix.'privmsgs(message_from,message_to,date,subject,message_text,folder_name,message_read) VALUES'; + foreach($namelist as $n) + { + $base_query .= '(\''.$session->username.'\', \''.$n.'\', '.time().', \''.$subject.'\', \''.$message.'\', \'inbox\', 0),'; + } + $base_query = substr($base_query, 0, strlen($base_query)-1) . ';'; + $result = $db->sql_query($base_query); + $db->free_result(); + if ( !$result ) + { + $db->_die('The message could not be sent.'); + } + else + { + die_friendly($lang->get('privmsgs_msg_message_status'), '' . $lang->get('privmsgs_msg_message_sent', array('inbox_link' => makeUrlNS('Special', 'PrivateMessages/Folder/Inbox'))) . '
'); + } + return; } - $base_query = substr($base_query, 0, strlen($base_query)-1) . ';'; - $result = $db->sql_query($base_query); - $db->free_result(); - if(!$result) $db->_die('The message could not be sent.'); - else die_friendly('Message status', 'Your message has been sent. You may edit the message if you wish; one copy for each recipient will be in your outbox until each recipient has read it. Return to your inbox.
'); - return; - } elseif($argv[1]=='Send' && isset($_POST['_savedraft'])) { - // Check each POST DATA parameter... - if(!isset($_POST['to']) || ( isset($_POST['to']) && $_POST['to'] == '')) die_friendly('Sending of message failed', 'Please enter the username to which you want to send your message.
'); - if(!isset($_POST['subject']) || ( isset($_POST['subject']) && $_POST['subject'] == '')) die_friendly('Sending of message failed', 'Please enter a subject for your message.
'); - if(!isset($_POST['message']) || ( isset($_POST['message']) && $_POST['message'] == '')) die_friendly('Sending of message failed', 'Please enter a message to send.
'); - $namelist = $_POST['to']; - $namelist = str_replace(', ', ',', $namelist); - $namelist = explode(',', $namelist); - foreach($namelist as $n) { $n = $db->escape($n); } - if(count($namelist) > MAX_PMS_PER_BATCH && $session->get_permssions('mod_misc')) die_friendly('Limit exceeded', 'You can only send this message to a maximum of '.MAX_PMS_PER_BATCH.' users.
'); - $subject = $db->escape($_POST['subject']); - $message = RenderMan::preprocess_text($_POST['message']); - $base_query = 'INSERT INTO '.table_prefix.'privmsgs(message_from,message_to,date,subject,message_text,folder_name,message_read) VALUES'; - foreach($namelist as $n) + } + else if ( $argv[1] == 'Send' && isset($_POST['_savedraft'] ) ) + { + $errors = array(); + if ( !isset($_POST['to']) || ( isset($_POST['to']) && $_POST['to'] == '') ) + { + $errors[] = $lang->get('privmsgs_err_need_username'); + } + if ( !isset($_POST['subject']) || ( isset($_POST['subject']) && $_POST['subject'] == '') ) + { + $errors[] = $lang->get('privmsgs_err_need_subject'); + } + if ( !isset($_POST['message']) || ( isset($_POST['message']) && $_POST['message'] == '') ) + { + $errors[] = $lang->get('privmsgs_err_need_message'); + } + if ( count($errors) < 1 ) { - $base_query .= '(\''.$session->username.'\', \''.$n.'\', '.time().', \''.$subject.'\', \''.$message.'\', \'drafts\', 0),'; + $namelist = $_POST['to']; + $namelist = str_replace(', ', ',', $namelist); + $namelist = explode(',', $namelist); + foreach($namelist as $n) + { + $n = $db->escape($n); + } + if ( count($namelist) > MAX_PMS_PER_BATCH && !$session->get_permssions('mod_misc') ) + { + die_friendly($lang->get('privmsgs_err_limit_exceeded_title'), '' . $lang->get('privmsgs_err_limit_exceeded_body', array('limit' => MAX_PMS_PER_BATCH)) . '
'); + } + $subject = $db->escape($_POST['subject']); + $message = RenderMan::preprocess_text($_POST['message']); + $base_query = 'INSERT INTO '.table_prefix.'privmsgs(message_from,message_to,date,subject,message_text,folder_name,message_read) VALUES'; + foreach($namelist as $n) + { + $base_query .= '(\''.$session->username.'\', \''.$n.'\', '.time().', \''.$subject.'\', \''.$message.'\', \'drafts\', 0),'; + } + $base_query = substr($base_query, 0, strlen($base_query) - 1) . ';'; + $result = $db->sql_query($base_query); + $db->free_result(); + if ( !$result ) + { + $db->_die('The message could not be saved.'); + } } - $base_query = substr($base_query, 0, strlen($base_query)-1) . ';'; - $result = $db->sql_query($base_query); - $db->free_result(); - if(!$result) $db->_die('The message could not be saved.'); - } elseif(isset($_POST['_inbox'])) { - header('Location: '.makeUrlNS('Special', 'PrivateMessages/Folder/Inbox')); + } + else if(isset($_POST['_inbox'])) + { + redirect(makeUrlNS('Special', 'PrivateMessages/Folder/Inbox'), '', '', 0); } if($argv[1] == 'ReplyTo' && preg_match('#^([0-9]+)$#', $argv[2])) { @@ -207,12 +252,17 @@ $subj = ''; $id = $argv[2]; $q = $db->sql_query('SELECT p.message_from, p.message_to, p.subject, p.message_text, p.date, p.folder_name, u.signature FROM '.table_prefix.'privmsgs AS p LEFT JOIN '.table_prefix.'users AS u ON (p.message_from=u.username) WHERE message_id='.$id.';'); - if(!$q) $db->_die('The message data could not be selected.'); + if ( !$q ) + $db->_die('The message data could not be selected.'); + $r = $db->fetchrow(); $db->free_result(); - if( ($r['message_to'] != $session->username && $r['message_from'] != $session->username ) || $r['folder_name']=='drafts' ) die_friendly('Access denied', 'You are not authorized to view the contents of this message.
'); + if ( ($r['message_to'] != $session->username && $r['message_from'] != $session->username ) || $r['folder_name'] == 'drafts' ) + { + die_friendly($lang->get('etc_access_denied_short'), 'You are not authorized to view the contents of this message.
'); + } $subj = 'Re: ' . $r['subject']; - $text = "\n\n\nOn ".date('M j, Y G:i', $r['date']).", ".$r['message_from']." wrote:\n> ".str_replace("\n", "\n> ", $r['message_text']); // Way less complicated than using a regex ;-) + $text = "\n\n\nOn " . date('M j, Y G:i', $r['date']) . ", " . $r['message_from'] . " wrote:\n> " . str_replace("\n", "\n> ", $r['message_text']); // Way less complicated than using a regex ;-) $tbuf = $text; while( preg_match("/\n([\> ]*?)\> \>/", $text) ) @@ -224,26 +274,47 @@ } $to = $r['message_from']; - } else { - if(( $argv[1]=='to' || $argv[1]=='To' ) && $argv[2]) $to = $argv[2]; - else $to = ''; + } + else + { + if ( ( $argv[1]=='to' || $argv[1]=='To' ) && $argv[2] ) + { + $to = htmlspecialchars($argv[2]); + } + else + { + $to = ''; + } $text = ''; $subj = ''; } $template->header(); userprefs_show_menu(); - echo '