# HG changeset patch # User Dan # Date 1226258523 18000 # Node ID 904fbf10f11299777753586853fdd3f6c56a2dd5 # Parent 331e009416d58e2bb5e0726db1b898d8b01baa74# Parent e5f638c216f7901d28b0df4d7712307bad5ab26c Merging branches diff -r 331e009416d5 -r 904fbf10f112 ajax.php --- a/ajax.php Mon Sep 29 08:24:26 2008 -0400 +++ b/ajax.php Sun Nov 09 14:22:03 2008 -0500 @@ -469,6 +469,7 @@ break; case "preview": require_once(ENANO_ROOT.'/includes/pageutils.php'); + $template->init_vars(); echo PageUtils::genPreview($_POST['text']); break; case "pagediff": diff -r 331e009416d5 -r 904fbf10f112 includes/clientside/static/editor.js --- a/includes/clientside/static/editor.js Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/clientside/static/editor.js Sun Nov 09 14:22:03 2008 -0500 @@ -162,7 +162,7 @@ } // Draft notice - if ( response.have_draft ) + if ( response.have_draft && !readonly ) { var dn = document.createElement('div'); dn.className = 'warning-box'; diff -r 331e009416d5 -r 904fbf10f112 includes/clientside/static/login.js --- a/includes/clientside/static/login.js Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/clientside/static/login.js Sun Nov 09 14:22:03 2008 -0500 @@ -72,6 +72,7 @@ var AJAX_STATUS_GENERATING_KEY = 2; var AJAX_STATUS_LOGGING_IN = 3; var AJAX_STATUS_SUCCESS = 4; +var AJAX_STATUS_ERROR = 5; var AJAX_STATUS_DESTROY = 65535; /** @@ -297,6 +298,53 @@ logindata.mb_inner.innerHTML = ''; logindata.mb_inner.appendChild(div); + break; + + case AJAX_STATUS_ERROR: + // Create the status div + var div = document.createElement('div'); + div.id = 'ajax_login_status'; + div.style.marginTop = '10px'; + div.style.textAlign = 'center'; + + // The circly ball ajaxy image + status message + var status_msg = $lang.get('user_login_ajax_err_crypto'); + + // Insert the status message + div.appendChild(document.createTextNode(status_msg)); + + // Append a br or two to space things properly + div.appendChild(document.createElement('br')); + div.appendChild(document.createElement('br')); + + var img = document.createElement('img'); + img.src = ( ajax_login_successimg_path ) ? ajax_login_successimg_path : scriptPath + '/images/checkbad.png'; + div.appendChild(img); + + // Append a br or two to space things properly + div.appendChild(document.createElement('br')); + div.appendChild(document.createElement('br')); + + // The circly ball ajaxy image + status message + var detail_msg = $lang.get('user_login_ajax_err_crypto_details'); + var full_link = $lang.get('user_login_ajax_err_crypto_link'); + var link = document.createElement('a'); + link.href = makeUrlNS('Special', 'Login/' + title); + link.appendChild(document.createTextNode(full_link)); + var span = document.createElement('span'); + span.style.fontSize = 'smaller'; + + // Insert the message + span.appendChild(document.createTextNode(detail_msg + ' ')); + span.appendChild(link); + div.appendChild(span); + + // Insert the entire message into the login window + logindata.mb_inner.innerHTML = ''; + logindata.mb_inner.appendChild(div); + + break; + case AJAX_STATUS_DESTROY: case null: case undefined: @@ -588,6 +636,14 @@ lbl_dh.innerHTML = $lang.get('user_login_ajax_check_dh_ie'); form.appendChild(lbl_dh); } + else if ( !data.allow_diffiehellman ) + { + // create hidden control - server requested that DiffieHellman be disabled (usually means not supported) + var check_dh = document.createElement('input'); + check_dh.type = 'hidden'; + check_dh.id = 'ajax_login_field_dh'; + form.appendChild(check_dh); + } else { var lbl_dh = document.createElement('label'); @@ -744,6 +800,7 @@ return false; } } + if ( !username ) { var username = document.getElementById('ajax_login_field_username').value; @@ -757,6 +814,9 @@ var captcha = document.getElementById('ajax_login_field_captcha').value; } + try + { + if ( do_dh ) { ajaxLoginSetStatus(AJAX_STATUS_GENERATING_KEY); @@ -836,6 +896,14 @@ remember: remember_session } } + } + catch(e) + { + ajaxLoginSetStatus(AJAX_STATUS_ERROR); + console.error('Exception caught in login process; backtrace follows'); + console.debug(e); + return false; + } ajaxLoginPerformRequest(json_packet); } diff -r 331e009416d5 -r 904fbf10f112 includes/clientside/static/userpage.js --- a/includes/clientside/static/userpage.js Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/clientside/static/userpage.js Sun Nov 09 14:22:03 2008 -0500 @@ -7,6 +7,9 @@ var wrapper = document.getElementById('userpage_wrap'); var links = document.getElementById('userpage_links'); + if ( !wrapper ) + return false; + wrapper.className = 'userpage_wrap'; links.className = 'userpage_links'; diff -r 331e009416d5 -r 904fbf10f112 includes/common.php --- a/includes/common.php Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/common.php Sun Nov 09 14:22:03 2008 -0500 @@ -170,6 +170,10 @@ global $timezone; $timezone = 0; +// DST settings +global $dst_params; +$dst_params = array(0, 0, 0, 0, 60); + // Divert to CLI loader if running from CLI if ( isset($argc) && isset($argv) ) { @@ -390,7 +394,7 @@ // One quick security check... if ( !is_valid_ip($_SERVER['REMOTE_ADDR']) ) { - die('SECURITY: spoofed IP address'); + die('SECURITY: spoofed IP address: ' . htmlspecialchars($_SERVER['REMOTE_ADDR'])); } // All checks passed! Start the main components up. diff -r 331e009416d5 -r 904fbf10f112 includes/constants.php --- a/includes/constants.php Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/constants.php Sun Nov 09 14:22:03 2008 -0500 @@ -92,6 +92,12 @@ define('TOKEN_PARENTHRIGHT', 4); define('TOKEN_NOT', 5); +// DST constants +define('FIRST_SUNDAY', 1); +define('SECOND_SUNDAY', 2); +define('THIRD_SUNDAY', 3); +define('LAST_SUNDAY', 4); + // // User types - don't touch these // @@ -617,3 +623,12 @@ 0xFE => "COM", 0x01 => "TEM", 0x02 => "RES", ); +// DST profiles +global $dst_profiles; +$dst_profiles = array( + 'off' => '0;0;0;0;60', + 'usa' => '3;' . SECOND_SUNDAY . ';11;' . FIRST_SUNDAY . ';60', + 'europe' => '3;' . LAST_SUNDAY . ';10;' . LAST_SUNDAY . ';60', + 'australia' => '10;' . LAST_SUNDAY . ';3;' . LAST_SUNDAY . ';60', + 'tasmania' => '10;' . FIRST_SUNDAY . ';3;' . LAST_SUNDAY . ';60' + ); diff -r 331e009416d5 -r 904fbf10f112 includes/functions.php --- a/includes/functions.php Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/functions.php Sun Nov 09 14:22:03 2008 -0500 @@ -271,31 +271,117 @@ if ( !is_int($timestamp) && !is_double($timestamp) && strval(intval($timestamp)) !== $timestamp ) $timestamp = time(); - /* - // List of valid characters for date() - $date_chars = 'dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZFcrU'; - // Split them into an array - $date_chars = enano_str_split($date_chars); - // Emulate date() formatting by replacing date characters with their - // percentage-signed counterparts, but not escaped characters which - // shouldn't be parsed. - foreach ( $date_chars as $char ) - { - $string = str_replace($char, "%$char", $string); - $string = str_replace("\\%$char", $char, $string); - } - */ - // perform timestamp offset global $timezone; // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp $timestamp = $timestamp + ( $timezone * 60 ); + // are we in DST? + global $dst_params; + if ( check_timestamp_dst($timestamp, $dst_params[0], $dst_params[1], $dst_params[2], $dst_params[3]) ) + { + // offset for DST + $timestamp += ( $dst_params[4] * 60 ); + } + // Let PHP do the work for us =) return gmdate($string, $timestamp); } /** + * Determine if a timestamp is within DST. + * @param int Timestamp + * @param int Start month (1-12) of DST + * @param int Which Sunday DST starts on (*_SUNDAY constants) + * @param int End month of DST + * @param int Which Sunday DST ends on + * @return bool + */ + +function check_timestamp_dst($time, $start_month, $start_sunday, $end_month, $end_sunday) +{ + static $sundays = array(FIRST_SUNDAY, SECOND_SUNDAY, THIRD_SUNDAY, LAST_SUNDAY); + + // perform timestamp offset + global $timezone; + // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp + $time = $time + ( $timezone * 60 ); + $year = intval(gmdate('Y', $time)); + + // one-pass validation + if ( !in_array($start_sunday, $sundays) || !in_array($end_sunday, $sundays) || + $start_month < 1 || $start_month > 12 || $end_month < 1 || $end_month > 12 ) + return false; + + // get timestamp of the selected sunday (start) + $dst_start = get_sunday_timestamp($start_month, $start_sunday, $year); + $dst_end = get_sunday_timestamp($end_month, $end_sunday, $year); + + if ( $dst_start > $dst_end ) + { + // start time is past the end time, this means we're in the southern hemisphere + // as a result, if we're within the range, DST is NOT in progress. + return !( $time >= $dst_start && $time <= $dst_end ); + } + + return $time >= $dst_start && $time <= $dst_end; +} + +/** + * Returns a timestamp for the given *_SUNDAY index. + * @param int Month + * @param int Which Sunday (FIRST, SECOND, THIRD, or LAST) + * @param int Year that we're doing our calculations in + * @return int + */ + +function get_sunday_timestamp($month, $sunday, $year) +{ + $days_in_month = array( + 1 => 31, + 2 => $year % 4 == 0 && ( $year % 100 != 0 || ( $year % 100 == 0 && $year % 400 == 0 ) ) ? 29 : 28, + 3 => 31, + 4 => 30, + 5 => 31, + 6 => 30, + 7 => 31, + 8 => 31, + 9 => 30, + 10 => 31, + 11 => 30, + 12 => 31 + ); + + $result = mktime(0, 0, 0, $month, 1, $year); + + // hack. allows a specific day of the month to be set instead of a sunday. not a good place to do this. + if ( is_string($sunday) && substr($sunday, -1) === 'd' ) + { + $result += 86400 * ( intval($sunday) - 1); + return $result; + } + + $tick = 0; + $days_remaining = $days_in_month[$month]; + while ( true ) + { + if ( date('D', $result) == 'Sun' ) + { + $tick++; + if ( ( $tick == 1 && $sunday == FIRST_SUNDAY ) || + ( $tick == 2 && $sunday == SECOND_SUNDAY ) || + ( $tick == 3 && $sunday == THIRD_SUNDAY ) || + ( $sunday == LAST_SUNDAY && $days_remaining < 7 ) ) + break; + } + $days_remaining--; + $result += 86400; + } + + return $result; +} + +/** * Tells you the title for the given page ID string * @param string Page ID string (ex: Special:Administration) * @param bool Optional. If true, and if the namespace turns out to be something other than Article, the namespace prefix will be prepended to the return value. @@ -2851,9 +2937,9 @@ function is_valid_ip($ip) { - // These came from phpBB3. + // This next one came from phpBB3. $ipv4 = '(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])'; - $ipv6 = '(?:(?:(?:[\dA-F]{1,4}:){6}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:::(?:[\dA-F]{1,4}:){5}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:):(?:[\dA-F]{1,4}:){4}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,2}:(?:[\dA-F]{1,4}:){3}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,3}:(?:[\dA-F]{1,4}:){2}(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,4}:(?:[\dA-F]{1,4}:)(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,5}:(?:[\dA-F]{1,4}:[\dA-F]{1,4}|(?:(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.){3}(?:\d{1,2}|1\d\d|2[0-4]\d|25[0-5])))|(?:(?:[\dA-F]{1,4}:){1,6}:[\dA-F]{1,4})|(?:(?:[\dA-F]{1,4}:){1,7}:))'; + $ipv6 = '(?:[a-f0-9]{0,4}):(?:[a-f0-9]{0,4}):(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{0,4}:|:)?(?:[a-f0-9]{1,4})'; if ( preg_match("/^{$ipv4}$/", $ip) || preg_match("/^{$ipv6}$/", $ip) ) return true; diff -r 331e009416d5 -r 904fbf10f112 includes/render.php --- a/includes/render.php Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/render.php Sun Nov 09 14:22:03 2008 -0500 @@ -145,6 +145,7 @@ $p = 'Notice: RenderMan::getTemplate(): Parameter '.$m.' is not set'; } $text = str_replace('(_'.$m.'_)', $p, $text); + $text = str_replace('{{' . ( $m + 1 ) . '}}', $p, $text); } $text = RenderMan::include_templates($text); return $text; @@ -252,7 +253,7 @@ $text = preg_replace('/(.*?)<\/nodisplay>/is', '', $text); } - preg_match_all('/([\w\W]+?)<\/lang>/', $text, $langmatch); + preg_match_all('/([\w\W]+?)<\/lang>/', $text, $langmatch); foreach ( $langmatch[0] as $i => $match ) { if ( $langmatch[1][$i] == $lang->lang_code ) @@ -271,6 +272,17 @@ eval($cmd); } + //$template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is"; + $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU"; + $i = 0; + while ( preg_match($template_regex, $text) ) + { + $i++; + if ( $i == 5 ) + break; + $text = RenderMan::include_templates($text); + } + if ( !$plaintext ) { // Process images @@ -287,17 +299,6 @@ } } - //$template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is"; - $template_regex = "/\{\{(.+)((\n|\|[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU"; - $i = 0; - while ( preg_match($template_regex, $text) ) - { - $i++; - if ( $i == 5 ) - break; - $text = RenderMan::include_templates($text); - } - // Before shipping it out to the renderer, replace spaces in between headings and paragraphs: $text = preg_replace('/<\/(h[0-9]|div|p)>([\s]+)<(h[0-9]|div|p)( .+?)?>/i', '<\\3\\4>', $text); @@ -495,9 +496,18 @@ foreach ( $matches[0] as $i => $match ) { list($page_id, $namespace) = RenderMan::strToPageID($matches[1][$i]); + if ( ($pos = strrpos($page_id, '#')) !== false ) + { + $hash = substr($page_id, $pos); + $page_id = substr($page_id, 0, $pos); + } + else + { + $hash = ''; + } $pid_clean = $paths->nslist[$namespace] . sanitize_page_id($page_id); - $url = makeUrl($pid_clean, false, true); + $url = makeUrl($pid_clean, false, true) . $hash; $inner_text = $matches[2][$i]; $quot = '"'; $exists = ( isPage($pid_clean) ) ? '' : ' class="wikilink-nonexistent"'; @@ -564,54 +574,43 @@ * [bar] => dolor sit amet */ - public static function parse_template_vars($input) + public static function parse_template_vars($input, $newlinemode = true) { - if ( !preg_match('/^(\|[ ]*([A-z0-9_]+)([ ]*)=([ ]*)(.+?))*$/is', trim($input)) ) + $parms = array(); + $input = trim($input); + if ( $newlinemode ) { - $using_pipes = false; - $input = explode("\n", trim( $input )); + $result = preg_match_all('/ + (?:^|[\s]*)\|? # start of parameter - string start or series of spaces + [ ]* + (?: + ([A-z0-9_]+) # variable name + [ ]* = [ ]* # assignment + )? # this is optional - if the parameter name is not given, a numerical index is assigned + (.+) # value + /x', trim($input), $matches); } else { - $using_pipes = true; - $input = substr($input, 1); - $input = explode("|", trim( $input )); - } - $parms = Array(); - $current_line = ''; - $current_parm = ''; - foreach ( $input as $num => $line ) + $result = preg_match_all('/ + (?:^|[ ]*)\| # start of parameter - string start or series of spaces + [ ]* + (?: + ([A-z0-9_]+) # variable name + [ ]* = [ ]* # assignment + )? # name section is optional - if the parameter name is not given, a numerical index is assigned + ([^\|]+|.+?\n[ ]*\|) # value + /x', trim($input), $matches); + } + if ( $result ) { - if ( preg_match('/^[ ]*([A-z0-9_]+)([ ]*)=([ ]*)(.+?)$/is', $line, $matches) ) + $pi = 0; + for ( $i = 0; $i < count($matches[0]); $i++ ) { - $parm =& $matches[1]; - $text =& $matches[4]; - if ( $parm == $current_parm ) - { - $current_line .= $text; - } - else - { - // New parameter - if ( $current_parm != '' ) - $parms[$current_parm] = $current_line; - $current_line = $text; - $current_parm = $parm; - } + $matches[1][$i] = trim($matches[1][$i]); + $parmname = !empty($matches[1][$i]) ? $matches[1][$i] : strval(++$pi); + $parms[ $parmname ] = $matches[2][$i]; } - else if ( $num == 0 ) - { - // Syntax error - return false; - } - else - { - $current_line .= "\n$line"; - } - } - if ( !empty($current_parm) && !empty($current_line) ) - { - $parms[$current_parm] = $current_line; } return $parms; } @@ -624,8 +623,8 @@ * @example * $text = '{{Template - parm1 = Foo - parm2 = Bar + | parm1 = Foo + | parm2 = Bar }}'; $text = RenderMan::include_templates($text); * @@ -635,17 +634,26 @@ { global $db, $session, $paths, $template, $plugins; // Common objects // $template_regex = "/\{\{([^\]]+?)((\n([ ]*?)[A-z0-9]+([ ]*?)=([ ]*?)(.+?))*)\}\}/is"; - $template_regex = "/\{\{(.+)(((\n|[ ]*\|)[ ]*([A-z0-9]+)[ ]*=[ ]*(.+))*)\}\}/isU"; + // matches: + // 1 - template name + // 2 - parameter section + $template_regex = "/ + \{\{ # opening + ([^\n\t\a\r]+) # template name + ((?:(?:[\s]+\|?)[ ]*(?:[A-z0-9_]+)[ ]*=[ ]*?(?:.+))*) # parameters + \}\} # closing + /isxU"; if ( $count = preg_match_all($template_regex, $text, $matches) ) { //die('
' . print_r($matches, true) . '
'); for ( $i = 0; $i < $count; $i++ ) { $matches[1][$i] = sanitize_page_id($matches[1][$i]); + $newlinemode = ( substr($matches[2][$i], 0, 1) == "\n" ); $parmsection = trim($matches[2][$i]); if ( !empty($parmsection) ) { - $parms = RenderMan::parse_template_vars($parmsection); + $parms = RenderMan::parse_template_vars($parmsection, $newlinemode); if ( !is_array($parms) ) // Syntax error $parms = array(); diff -r 331e009416d5 -r 904fbf10f112 includes/sessions.php --- a/includes/sessions.php Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/sessions.php Sun Nov 09 14:22:03 2008 -0500 @@ -473,7 +473,15 @@ } } $user = true; + + // set timezone params $GLOBALS['timezone'] = $userdata['user_timezone']; + $GLOBALS['dst_params'] = explode(';', $userdata['user_dst']); + foreach ( $GLOBALS['dst_params'] as &$parm ) + { + if ( substr($parm, -1) != 'd' ) + $parm = intval($parm); + } // Set language if ( !defined('ENANO_ALLOW_LOAD_NOLANG') ) @@ -1038,7 +1046,7 @@ // using a normal call to $db->sql_query to avoid failing on errors here $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,' . "\n" . ' u.reg_time,u.account_active,u.activation_key,u.user_lang,u.user_title,k.source_ip,k.time,k.auth_level,k.key_type,COUNT(p.message_id) AS num_pms,' . "\n" - . ' u.user_timezone, x.* FROM '.table_prefix.'session_keys AS k' . "\n" + . ' u.user_timezone, u.user_dst, x.* FROM '.table_prefix.'session_keys AS k' . "\n" . ' LEFT JOIN '.table_prefix.'users AS u' . "\n" . ' ON ( u.user_id=k.user_id )' . "\n" . ' LEFT JOIN '.table_prefix.'users_extra AS x' . "\n" @@ -1051,7 +1059,7 @@ if ( !$query && ( defined('IN_ENANO_INSTALL') or defined('IN_ENANO_UPGRADE') ) ) { - $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k + $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, \'0;0;0;0;60\' AS user_dst, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k LEFT JOIN '.table_prefix.'users AS u ON ( u.user_id=k.user_id ) LEFT JOIN '.table_prefix.'privmsgs AS p @@ -2707,7 +2715,8 @@ if ( !$q ) $db->_die(); - $groups = array(); + // The l10n engine takes care of this later. + $groups = array(1 => 'Everyone'); if ( $row = $db->fetchrow() ) { @@ -2983,7 +2992,7 @@ { if ( isset($perm2[$i]) ) { - if ( $is_everyone && !$defaults_used[$i] ) + if ( $is_everyone && isset($defaults_used[$i]) && $defaults_used[$i] === false ) continue; // Decide precedence if ( isset($defaults_used[$i]) ) @@ -3396,17 +3405,20 @@ global $db, $session, $paths, $template, $plugins; // Common objects // Setup EnanoMath and Diffie-Hellman - require_once(ENANO_ROOT.'/includes/math.php'); - global $dh_supported; - $dh_supported = true; - try + if ( !function_exists('dh_gen_private') ) { - require_once(ENANO_ROOT . '/includes/diffiehellman.php'); - } - catch ( Exception $e ) - { - $dh_supported = false; + require_once(ENANO_ROOT.'/includes/math.php'); + + $dh_supported = true; + try + { + require_once(ENANO_ROOT . '/includes/diffiehellman.php'); + } + catch ( Exception $e ) + { + $dh_supported = false; + } } global $_math; diff -r 331e009416d5 -r 904fbf10f112 includes/template.php --- a/includes/template.php Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/template.php Sun Nov 09 14:22:03 2008 -0500 @@ -2051,84 +2051,59 @@ /** * Fetches the contents of both sidebars. - * @return array - key 0 is left, key 1 is right + * @return array - key 0 is left, key 1 is right, key 2 is the HTML that makes up an empty sidebar * @example list($left, $right) = $template->fetch_sidebar(); */ function fetch_sidebar() { global $db, $session, $paths, $template, $plugins; // Common objects - global $cache; + // first, check the cache + if ( $result = $this->fetch_cached_sidebar() ) + { + return $result; + } + + profiler_log('Started sidebar parsing'); + + // init our block contents $left = ''; $right = ''; + $min = ''; - // check the cache - if ( !$session->user_logged_in && $data = $cache->fetch('anon_sidebar') ) - { - if ( @$data['_theme_'] === $this->theme ) - { - unset($data['_theme_']); - foreach ( $data as &$md ) - { - $md = str_replace('$USERNAME$', $session->username, $md); - $md = str_replace('$PAGEID$', $paths->page, $md); - $md = str_replace('$MAIN_PAGE$', getConfig('main_page'), $md); - } - return $data; - } - } - + // also might want the links block if ( !$this->fetch_block('Links') ) $this->initLinksWidget(); - $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar' . "\n" - . ' WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;'); - if(!$q) $db->_die('The sidebar text data could not be selected.'); - + // templates to work with $vars = $this->extract_vars('elements.tpl'); - if(isset($vars['sidebar_top'])) + // sidebar_top and sidebar_bottom are HTML that is prepended/appended to sidebar content. Themes can + // choose whether or not to display a sidebar depending on whether the sidebar is empty ( $left == $min ) + // or not using the sidebar_left and sidebar_right template booleans (the oxygen theme does this). + if ( isset($vars['sidebar_top']) ) { $top = $this->parse($vars['sidebar_top']); $left .= $top; $right .= $top; + $min .= $top; } - while($row = $db->fetchrow()) + // grab the blocks from the DB + $q = $db->sql_query('SELECT item_id,sidebar_id,block_name,block_type,block_content FROM '.table_prefix.'sidebar' . "\n" + . ' WHERE item_enabled=1 ORDER BY sidebar_id ASC, item_order ASC;'); + if ( !$q ) + $db->_die('The sidebar text data could not be selected.'); + + // explicitly specify $q in case a plugin or PHP block makes a query + while ( $row = $db->fetchrow($q) ) { - switch($row['block_type']) - { - case BLOCK_WIKIFORMAT: - default: - $parser = $this->makeParserText($vars['sidebar_section']); - $c = RenderMan::render($row['block_content']); - break; - case BLOCK_TEMPLATEFORMAT: - $parser = $this->makeParserText($vars['sidebar_section']); - $c = $this->tplWikiFormat($row['block_content']); - break; - case BLOCK_HTML: - $parser = $this->makeParserText($vars['sidebar_section_raw']); - $c = $row['block_content']; - break; - case BLOCK_PHP: - $parser = $this->makeParserText($vars['sidebar_section_raw']); - ob_start(); - @eval($row['block_content']); - $c = ob_get_contents(); - ob_end_clean(); - break; - case BLOCK_PLUGIN: - $parser = $this->makeParserText('{CONTENT}'); - $c = '' . (gettype($this->fetch_block($row['block_content'])) == 'string') ? - $this->fetch_block($row['block_content']) : - // This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. - ''; - break; - } + // format the block + $block_content = $this->format_sidebar_block($row, $vars, $parser); + // is there a {restrict} or {hideif} block? - if ( preg_match('/\{(restrict|hideif) ([a-z0-9_\(\)\|&! ]+)\}/', $c, $match) ) + if ( preg_match('/\{(restrict|hideif) ([a-z0-9_\(\)\|&! ]+)\}/', $block_content, $match) ) { // we have one, check the condition $type =& $match[1]; @@ -2140,53 +2115,253 @@ continue; } // didn't get a match, so hide the conditional logic - $c = str_replace_once($match[0], '', $c); + // FIXME: this needs to be verbose about syntax errors + $block_content = str_replace_once($match[0], '', $block_content); } - $parser->assign_vars(Array( 'TITLE'=>$this->tplWikiFormat($row['block_name']), 'CONTENT'=>$c )); - $run = $parser->run(); + // if we made it here, this block definitely needs to be displayed. send it to the + // parser (set by format_sidebar_block) and decide where to append it (but not in that order ;)) + $appender = false; + + if ( $row['sidebar_id'] == SIDEBAR_LEFT ) + { + $appender =& $left; + } + else if ( $row['sidebar_id'] == SIDEBAR_RIGHT ) + { + $appender =& $right; + } + else + { + // uhoh, block_id isn't valid. maybe a plugin wants to put this block somewhere else? + $code = $plugins->setHook('sidebar_block_id'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + // if $appender wasn't set by a plugin, don't parse this block to save some CPU cycles + if ( !$appender ) + { + continue; + } + } + + // assign variables to parser + $block_name = $this->tplWikiFormat($row['block_name']); + $parser->assign_vars(array( + // be nice and format the title (FIXME, does this use a lot of CPU time? still needs l10n in some cases though) + 'TITLE' => $block_name, + 'CONTENT' => $block_content + )); + $parsed = $parser->run(); + + // plugins are parsed earlier due to the way disabled/missing plugins that add sidebar blocks are + // handled, so the {TITLE} var won't be replaced until now. this allows completely eliminating a + // block if it's not available if ( $row['block_type'] == BLOCK_PLUGIN ) { - $run = str_replace('{TITLE}', $this->tplWikiFormat($row['block_name']), $run); + $parsed = str_replace('{TITLE}', $block_name, $parsed); } - if ($row['sidebar_id'] == SIDEBAR_LEFT ) $left .= $run; - elseif($row['sidebar_id'] == SIDEBAR_RIGHT) $right .= $run; - unset($parser); + + // done parsing - append and continue + $appender .= $parsed; + + // we're done with this - unset it because it's a reference and we don't want it overwritten. + // also free the parser to get some RAM back + unset($appender, $parser); } - $db->free_result(); + + // lastly, append any footer HTML if(isset($vars['sidebar_bottom'])) { $bottom = $this->parse($vars['sidebar_bottom']); $left .= $bottom; $right .= $bottom; + $min .= $bottom; } - $min = ''; - if(isset($vars['sidebar_top'])) + + $return = array($left, $right, $min); + + // allow any plugins to append what they want to the return + $code = $plugins->setHook('sidebar_fetch_return'); + foreach ( $code as $cmd ) { - $min .= $top; + eval($cmd); } - if(isset($vars['sidebar_bottom'])) - { - $min .= $bottom; - } - $return = Array($left, $right, $min); - if ( getConfig('cache_thumbs') == '1' && !$session->user_logged_in ) + + // cache the result if appropriate + $this->cache_compiled_sidebar($return); + + profiler_log('Finished sidebar parsing'); + + return $return; + } + + /** + * Runs the appropriate formatting routine on a sidebar row. + * @param array Row in sidebar table + * @param array Template variable set from elements.tpl + * @param null Pass by reference, will be filled with the parser according to the block's type (sidebar_section or sidebar_section_raw) + * @return string HTML + directives like {restrict} or {hideif} + */ + + function format_sidebar_block($row, $vars, &$parser) + { + // import globals in case a PHP block wants to call the Enano API + global $db, $session, $paths, $template, $plugins; // Common objects + + $parser = null; + + switch($row['block_type']) { - $cachestore = enano_json_encode($return); - $cachestore = str_replace($session->username, '$USERNAME$', $cachestore); - $cachestore = str_replace($paths->page, '$PAGEID$', $cachestore); - $cachestore = str_replace('__STATICLINK__', $paths->page, $cachestore); - $cachestore = str_replace('__MAINPAGELINK__', '$MAIN_PAGE$', $cachestore); - $cachestore = enano_json_decode($cachestore); - $cachestore['_theme_'] = $this->theme; - $cache->store('anon_sidebar', $cachestore, 10); - - foreach ( $return as &$el ) + case BLOCK_WIKIFORMAT: + $parser = $this->makeParserText($vars['sidebar_section']); + $c = RenderMan::render($row['block_content']); + break; + + case BLOCK_TEMPLATEFORMAT: + $parser = $this->makeParserText($vars['sidebar_section']); + $c = $this->tplWikiFormat($row['block_content']); + break; + + case BLOCK_HTML: + $parser = $this->makeParserText($vars['sidebar_section_raw']); + $c = $row['block_content']; + break; + + case BLOCK_PHP: + // PHP blocks need to be sent directly to eval() + $parser = $this->makeParserText($vars['sidebar_section_raw']); + ob_start(); + @eval($row['block_content']); + $c = ob_get_contents(); + ob_end_clean(); + break; + + case BLOCK_PLUGIN: + $parser = $this->makeParserText('{CONTENT}'); + $c = '' . (gettype($this->fetch_block($row['block_content'])) == 'string') ? + $this->fetch_block($row['block_content']) : + // This used to say "can't find plugin block" but I think it's more friendly to just silently hide it. + ''; + break; + default: + // unknown block type - can a plugin handle it? + $code = $plugins->setHook('format_sidebar_block'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + if ( !isset($c) ) + { + // default to wiki formatting (this was going to be straight HTML but this is done for backwards compatibility reasons) + $c = RenderMan::render($row['block_content']); + } + if ( !$parser ) + { + // no parser defined, use the "raw" section by default (plugins are more likely to want raw content + // rather than a list of links, and they can set the parser to use sidebar_section if they want) + $parser = $this->makeParserText($vars['sidebar_section_raw']); + } + + break; + } + + return $c; + } + + /** + * Returns the list of things that should not be cached (sorry, I was listening to "The Thing That Should Not Be" by Metallica when I + * wrote this routine. You should get a copy of Master of Puppets, it's a damn good album.) + * @return array + */ + + function get_cache_replacements() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + return array( + '$LOGIN_LINK$' => $this->tpl_strings['LOGIN_LINK'], + '$MAIN_PAGE$' => $this->tpl_strings['MAIN_PAGE'], + '$USERNAME$' => $session->username + ); + } + + /** + * Attempts to load a cached compiled sidebar. + * @return array Same format as fetch_sidebar() + */ + + function fetch_cached_sidebar() + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $cache; + + $cached = false; + if ( ($result = $cache->fetch('anon_sidebar')) && !$session->user_logged_in ) + { + if ( isset($result[$this->theme]) ) { - $el = str_replace('__STATICLINK__', $paths->page, $el); + $cached = $result[$this->theme]; } } - return $return; + + // if we haven't been able to fetch yet, see if a plugin wants to give us something + if ( !$cached ) + { + $code = $plugins->setHook('fetch_cached_sidebar'); + foreach ( $code as $cmd ) + { + eval($cmd); + } + } + + if ( is_array($cached) ) + { + // fetch certain variables that can't be stored in the cache and quickly substitute + $replace = $this->get_cache_replacements(); + foreach ( $cached as &$val ) + { + $val = strtr($val, $replace); + } + + // done processing, send it back + return $cached; + } + + return false; + } + + /** + * Caches a completely compiled sidebar, if appropriate + * @param array Effectively, return from fetch_sidebar() + */ + + function cache_compiled_sidebar($sidebar) + { + global $db, $session, $paths, $template, $plugins; // Common objects + global $cache; + + // check if conditions are right + if ( !$session->user_logged_in && getConfig('cache_thumbs') === '1' ) + { + // load any existing cache to make sure other themes' cached sidebars aren't discarded + $cached = ( $_ = $cache->fetch('anon_sidebar') ) ? $_ : array(); + + // replace variables + $replace = array_flip($this->get_cache_replacements()); + + foreach ( $sidebar as &$section ) + { + $section = strtr($section, $replace); + } + + // compile + $cached[$this->theme] = $sidebar; + + // store + $cache->store('anon_sidebar', $cached, 15); + } } function initLinksWidget() diff -r 331e009416d5 -r 904fbf10f112 includes/wikiengine/Render/Xhtml/Wikilink.php --- a/includes/wikiengine/Render/Xhtml/Wikilink.php Mon Sep 29 08:24:26 2008 -0400 +++ b/includes/wikiengine/Render/Xhtml/Wikilink.php Sun Nov 09 14:22:03 2008 -0500 @@ -56,6 +56,11 @@ function token($options) { + ## + ## THIS IS NOT WHAT YOU ARE LOOKING FOR!! + ## All of this code is deprecated. Patch RenderMan::parse_internal_links() instead! + ## + global $session; if ( $session->sid_super ) { @@ -120,16 +125,8 @@ // the HREF. we support both the old form where // the page always comes at the end, and the new // form that uses %s for sprintf() - $href = $this->getConf('view_url'); - - if (strpos($href, '%s') === false) { - // use the old form (page-at-end) - $href = $href . $page . $anchor; - } else { - // use the new form (sprintf format string) - $href = sprintf($href, $page . $anchor); - } - + $href = makeUrl($page, false, true); + // get the CSS class and generate output $css = $this->formatConf(' class="%s"', 'css'); @@ -143,22 +140,13 @@ // the HREF. we support both the old form where // the page always comes at the end, and the new // form that uses %s for sprintf() - $href = $this->getConf('view_url'); - - if (strpos($href, '%s') === false) { - // use the old form (page-at-end) - $href = $href . $page . $anchor; - } else { - // use the new form (sprintf format string) - $href = sprintf($href, $page . $anchor); - } + $href = makeUrl($page, false, true); // get the CSS class and generate output $css = $this->formatConf(' class="%s"', 'css'); - $start = ''; + $start = ''; $end = ''; - } if (!strlen($text)) { $start .= $this->textEncode($options['page']); diff -r 331e009416d5 -r 904fbf10f112 install/schemas/mysql_stage2.sql --- a/install/schemas/mysql_stage2.sql Mon Sep 29 08:24:26 2008 -0400 +++ b/install/schemas/mysql_stage2.sql Sun Nov 09 14:22:03 2008 -0500 @@ -115,6 +115,7 @@ user_timezone int(12) UNSIGNED NOT NULL DEFAULT 0, user_title varchar(64) DEFAULT NULL, user_group mediumint(5) NOT NULL DEFAULT 1, + user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60', PRIMARY KEY (user_id) ) CHARACTER SET `utf8` COLLATE `utf8_bin`; diff -r 331e009416d5 -r 904fbf10f112 install/schemas/postgresql_stage2.sql --- a/install/schemas/postgresql_stage2.sql Mon Sep 29 08:24:26 2008 -0400 +++ b/install/schemas/postgresql_stage2.sql Sun Nov 09 14:22:03 2008 -0500 @@ -115,6 +115,7 @@ user_timezone int NOT NULL DEFAULT 0, user_title varchar(64) DEFAULT NULL, user_group int NOT NULL DEFAULT 1, + user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60', CHECK (avatar_type IN ('jpg', 'png', 'gif', 'grv')), PRIMARY KEY (user_id) ); diff -r 331e009416d5 -r 904fbf10f112 install/schemas/upgrade/1.1.4-1.1.5-mysql.sql --- a/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql Mon Sep 29 08:24:26 2008 -0400 +++ b/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql Sun Nov 09 14:22:03 2008 -0500 @@ -1,2 +1,3 @@ ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type tinyint(1) NOT NULL DEFAULT 0; UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2; +ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60'; diff -r 331e009416d5 -r 904fbf10f112 install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql --- a/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql Mon Sep 29 08:24:26 2008 -0400 +++ b/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql Sun Nov 09 14:22:03 2008 -0500 @@ -1,3 +1,4 @@ ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type smallint NOT NULL DEFAULT 0; UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2; +ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60'; diff -r 331e009416d5 -r 904fbf10f112 language/english/core.json --- a/language/english/core.json Mon Sep 29 08:24:26 2008 -0400 +++ b/language/english/core.json Sun Nov 09 14:22:03 2008 -0500 @@ -692,7 +692,14 @@ title_13: '[UTC + 13] Tonga Time, Phoenix Islands Time', title_14: '[UTC + 14] Line Island Time', // This is a JSON string that lists all the timezones that are defined here. - list: '{"n12":-12,"n11":-11,"n10":-10,"n9p5":-9.5,"n9":-9,"n8":-8,"n7":-7,"n6":-6,"n5":-5,"n4":-4,"n3p5":-3.5,"n3":-3,"n2":-2,"n1":-1,"0":0,"1":1,"2":2,"3":3,"3p5":3.5,"4":4,"4p5":4.5,"5":5,"5p5":5.5,"5p75":5.75,"6":6,"6p5":6.5,"7":7,"8":8,"8p75":8.75,"9":9,"9p5":9.5,"10":10,"10p5":10.5,"11":11,"11p5":11.5,"12":12,"12p75":12.75,"13":13,"14":14}' + list: '{"n12":-12,"n11":-11,"n10":-10,"n9p5":-9.5,"n9":-9,"n8":-8,"n7":-7,"n6":-6,"n5":-5,"n4":-4,"n3p5":-3.5,"n3":-3,"n2":-2,"n1":-1,"0":0,"1":1,"2":2,"3":3,"3p5":3.5,"4":4,"4p5":4.5,"5":5,"5p5":5.5,"5p75":5.75,"6":6,"6p5":6.5,"7":7,"8":8,"8p75":8.75,"9":9,"9p5":9.5,"10":10,"10p5":10.5,"11":11,"11p5":11.5,"12":12,"12p75":12.75,"13":13,"14":14}', + + // DST profiles + dst_off: 'My region doesn\'t use DST', + dst_usa: 'United States: second Sunday of March to first Sunday of November', + dst_europe: 'Europe: last Sunday of March to last Sunday of October', + dst_australia: 'Australia (except Tasmania): last Sunday of October to last Sunday of March', + dst_tasmania: 'Tasmania: first Sunday of October to last Sunday of March' }, etc: { redirect_title: 'Redirecting...', diff -r 331e009416d5 -r 904fbf10f112 language/english/user.json --- a/language/english/user.json Mon Sep 29 08:24:26 2008 -0400 +++ b/language/english/user.json Sun Nov 09 14:22:03 2008 -0500 @@ -75,6 +75,9 @@ login_ajax_check_dh_ie: 'Use a standards-compliant browser to help protect your password. Learn more', login_ajax_check_remember: 'Keep me logged in on this computer for %session_length% %length_units% unless I log out', login_ajax_check_remember_infinite: 'Keep me logged in on this computer until I log out', + login_ajax_err_crypto: 'Encryption failed.', + login_ajax_err_crypto_details: 'Details available on console.', + login_ajax_err_crypto_link: 'Use full login form', err_login_generic_title: 'There was an error in the login process', 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.', @@ -308,6 +311,7 @@ publicinfo_field_changetheme: 'Change my theme...', publicinfo_field_timezone: 'Time zone:', publicinfo_field_timezone_hint: 'Select the time zone you live in and when Daylight Savings Time occurs, if at all.', + publicinfo_field_dst: 'Daylight saving time:', publicinfo_field_usertitle_title: 'User title:', publicinfo_field_usertitle_hint: 'This can be some text that will be displayed underneath your username.', publicinfo_th_im: 'Instant messenger contact information', diff -r 331e009416d5 -r 904fbf10f112 plugins/SpecialAdmin.php --- a/plugins/SpecialAdmin.php Mon Sep 29 08:24:26 2008 -0400 +++ b/plugins/SpecialAdmin.php Sun Nov 09 14:22:03 2008 -0500 @@ -44,8 +44,26 @@ )); } +$plugins->attachHook('session_started', 'SpecialAdmin_theme_init();'); $plugins->attachHook('common_post', 'SpecialAdmin_include();'); +function SpecialAdmin_theme_init() +{ + global $db, $session, $paths, $template, $plugins; // Common objects + + // Admin pages that were too enormous to be in this file were split off into the plugins/admin/ directory in 1.0.1. + // Only load these files if we're looking to load the admin panel + list($pid, $ns) = RenderMan::strToPageID($paths->get_pageid_from_url()); + if ( $ns == 'Admin' || ( $pid == 'Administration' && $ns == 'Special' ) ) + { + // Set the theme + $session->theme = 'admin'; + $session->style = 'default'; + + $template->add_header(''); + } +} + function SpecialAdmin_include() { global $db, $session, $paths, $template, $plugins; // Common objects @@ -66,12 +84,6 @@ require(ENANO_ROOT . '/plugins/admin/ThemeManager.php'); require(ENANO_ROOT . '/plugins/admin/PluginManager.php'); require(ENANO_ROOT . '/plugins/admin/CacheManager.php'); - - // Set the theme - $session->theme = 'admin'; - $session->style = 'default'; - - $template->add_header(''); } } @@ -2093,7 +2105,7 @@ onclick: function() { var tigraentry = document.getElementById('i_div0_0').parentNode; - var tigraobj = $(tigraentry); + var tigraobj = $dynano(tigraentry); var div = document.createElement('div'); div.style.backgroundColor = '#FFFFFF'; domObjChangeOpac(70, div); diff -r 331e009416d5 -r 904fbf10f112 plugins/SpecialUserPrefs.php --- a/plugins/SpecialUserPrefs.php Mon Sep 29 08:24:26 2008 -0400 +++ b/plugins/SpecialUserPrefs.php Sun Nov 09 14:22:03 2008 -0500 @@ -652,6 +652,22 @@ get('usercp_publicinfo_field_timezone'); ?>
get('usercp_publicinfo_field_timezone_hint'); ?> + + get('usercp_publicinfo_field_dst'); ?> + + + + get_permissions('custom_user_title') ): ?>