From d42ee06575d440a6ff53e483506288505b6ed57c Mon Sep 17 00:00:00 2001
From: "Ralf S. Engelschall" Enter your announcement here.
\\n
\\n/Administrator",
+ 'Default rules' => 'Enter your rules here.',
+ 'Default category name' => 'Test category',
+ 'Default forum name' => 'Test forum',
+Index: lang/English/admin_reindex.php
+===================================================================
+--- lang/English/admin_reindex.php (revision 1168)
++++ lang/English/admin_reindex.php (revision 1655)
+@@ -14,8 +14,8 @@
+ 'Starting post info' => 'The post ID to start rebuilding at. The default value is the first available ID in the database. Normally you would not want to change this.',
+ 'Empty index' => 'Empty index',
+ 'Empty index info' => 'Empty search index before rebuilding (see below).',
+-'Rebuilding index title' => 'Rebuilding search index …',
+-'Rebuilding index' => 'Rebuilding index … This might be a good time to put on some coffee :-)',
++'Rebuilding index title' => 'Rebuilding search index…',
++'Rebuilding index' => 'Rebuilding index… This might be a good time to put on some coffee :-)',
+ 'Processing post' => 'Processing post %s in topic %s.',
+ 'Javascript redirect' => 'JavaScript redirect unsuccessful.',
+ 'Click to continue' => 'Click here to continue',
+Index: lang/English/admin_settings.php
+===================================================================
+--- lang/English/admin_settings.php (revision 1168)
++++ lang/English/admin_settings.php (revision 1655)
+@@ -51,7 +51,7 @@
+ 'Setup links legend' => 'Menu items',
+ 'Enter links label' => 'Enter your links',
+ 'Error no board title' => 'You must enter a board title.',
+-'Error timeout value' => 'The value of "Timeout online" must be smaller than the value of "Timeout visit".',
++'Error timeout value' => 'The value of "Online timeout" must be smaller than the value of "Visit timeout".',
+
+
+ // Features section
+@@ -164,7 +164,7 @@
+ 'Allow form e-mail label' => 'Hide e-mail address but allow e-mail via the forum.',
+ 'Disallow form e-mail label' => 'Hide e-mail address and disallow e-mail via the forum.',
+ 'Registration rules' => 'Forum rules (enable and compose forum rules)',
+-'Registration rules info' => 'You may require new users to agree to a set of rules when registering. The rules will always be available through a link in the navigation table at the top of every page. You may enable the use of rules and then compose your rules below.',
++'Registration rules info' => 'You may require new users to agree to a set of rules when registering. The rules will always be available through a link in the navigation menu at the top of every page. You may enable the use of rules and then compose your rules below.',
+ 'Registration rules legend' => 'Forum rules',
+ 'Require rules' => 'Use rules',
+ 'Require rules label' => 'Users must agree to forum rules before registering.',
+@@ -196,7 +196,7 @@
+
+ // Maintenance section
+ 'Maintenance head' => 'Setup maintenance message and activate maintenance mode',
+-'Maintenance mode info' => 'IMPORTANT! Putting the board into maintenance mode means it will only be available to administrators. This should be used if the board needs to taken down temporarily for maintenance.',
++'Maintenance mode info' => 'IMPORTANT! Putting the board into maintenance mode means it will only be available to administrators. This should be used if the board needs to be taken down temporarily for maintenance.',
+ 'Maintenance mode warn' => 'WARNING! DO NOT LOGOUT when the board is in maintenance mode. You will not be able to login again.',
+ 'Maintenance legend' => 'Maintenance',
+ 'Maintenance mode' => 'Maintenance mode',
+Index: lang/English/common.php
+===================================================================
+--- lang/English/common.php (revision 1168)
++++ lang/English/common.php (revision 1655)
+@@ -87,6 +87,8 @@
+ 'Info separator' => ' ', // e.g. 1 Page | 10 Topics
+ 'Powered by' => 'Powered by %s, supported by %s.',
+ 'Maintenance' => 'Maintenance',
++'Installed extension' => 'The %s official extension is installed. Copyright © 2003–2009 PunBB.',
++'Installed extensions' => 'Currently installed %s official extensions. Copyright © 2003–2009 PunBB.',
+
+ // CSRF confirmation form
+ 'Confirm' => 'Confirm', // Button
+Index: include/dblayer/common_db.php
+===================================================================
+--- include/dblayer/common_db.php (revision 1168)
++++ include/dblayer/common_db.php (revision 1655)
+@@ -32,10 +32,18 @@
+ case 'mysql':
+ require FORUM_ROOT.'include/dblayer/mysql.php';
+ break;
++
++ case 'mysql_innodb':
++ require FORUM_ROOT.'include/dblayer/mysql_innodb.php';
++ break;
+
+ case 'mysqli':
+ require FORUM_ROOT.'include/dblayer/mysqli.php';
+ break;
++
++ case 'mysqli_innodb':
++ require FORUM_ROOT.'include/dblayer/mysqli_innodb.php';
++ break;
+
+ case 'pgsql':
+ require FORUM_ROOT.'include/dblayer/pgsql.php';
+Index: include/dblayer/mysql_innodb.php
+===================================================================
+--- include/dblayer/mysql_innodb.php (revision 0)
++++ include/dblayer/mysql_innodb.php (revision 1655)
+@@ -0,0 +1,363 @@
++ 'INT(10) UNSIGNED AUTO_INCREMENT'
++ );
++
++
++ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $p_connect)
++ {
++ $this->prefix = $db_prefix;
++
++ if ($p_connect)
++ $this->link_id = @mysql_pconnect($db_host, $db_username, $db_password);
++ else
++ $this->link_id = @mysql_connect($db_host, $db_username, $db_password);
++
++ if ($this->link_id)
++ {
++ if (!@mysql_select_db($db_name, $this->link_id))
++ error('Unable to select database. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
++ }
++ else
++ error('Unable to connect to MySQL server. MySQL reported: '.mysql_error(), __FILE__, __LINE__);
++
++ // Setup the client-server character set (UTF-8)
++ if (!defined('FORUM_NO_SET_NAMES'))
++ $this->set_names('utf8');
++
++ return $this->link_id;
++ }
++
++
++ function start_transaction()
++ {
++ ++$this->in_transaction;
++
++ mysql_query('START TRANSACTION', $this->link_id);
++ return;
++ }
++
++
++ function end_transaction()
++ {
++ --$this->in_transaction;
++
++ mysql_query('COMMIT', $this->link_id);
++ return;
++ }
++
++
++ function query($sql, $unbuffered = false)
++ {
++ if (strlen($sql) > 140000)
++ exit('Insane query. Aborting.');
++
++ if (defined('FORUM_SHOW_QUERIES'))
++ $q_start = get_microtime();
++
++ if ($unbuffered)
++ $this->query_result = @mysql_unbuffered_query($sql, $this->link_id);
++ else
++ $this->query_result = @mysql_query($sql, $this->link_id);
++
++ if ($this->query_result)
++ {
++ if (defined('FORUM_SHOW_QUERIES'))
++ $this->saved_queries[] = array($sql, sprintf('%.5f', get_microtime() - $q_start));
++
++ ++$this->num_queries;
++
++ return $this->query_result;
++ }
++ else
++ {
++ if (defined('FORUM_SHOW_QUERIES'))
++ $this->saved_queries[] = array($sql, 0);
++
++ // Rollback transaction
++ if ($this->in_transaction)
++ mysql_query('ROLLBACK', $this->link_id);
++
++ --$this->in_transaction;
++
++ return false;
++ }
++ }
++
++
++ function result($query_id = 0, $row = 0, $col = 0)
++ {
++ return ($query_id) ? @mysql_result($query_id, $row, $col) : false;
++ }
++
++
++ function fetch_assoc($query_id = 0)
++ {
++ return ($query_id) ? @mysql_fetch_assoc($query_id) : false;
++ }
++
++
++ function fetch_row($query_id = 0)
++ {
++ return ($query_id) ? @mysql_fetch_row($query_id) : false;
++ }
++
++
++ function num_rows($query_id = 0)
++ {
++ return ($query_id) ? @mysql_num_rows($query_id) : false;
++ }
++
++
++ function affected_rows()
++ {
++ return ($this->link_id) ? @mysql_affected_rows($this->link_id) : false;
++ }
++
++
++ function insert_id()
++ {
++ return ($this->link_id) ? @mysql_insert_id($this->link_id) : false;
++ }
++
++
++ function get_num_queries()
++ {
++ return $this->num_queries;
++ }
++
++
++ function get_saved_queries()
++ {
++ return $this->saved_queries;
++ }
++
++
++ function free_result($query_id = false)
++ {
++ return ($query_id) ? @mysql_free_result($query_id) : false;
++ }
++
++
++ function escape($str)
++ {
++ if (is_array($str))
++ return '';
++ else if (function_exists('mysql_real_escape_string'))
++ return mysql_real_escape_string($str, $this->link_id);
++ else
++ return mysql_escape_string($str);
++ }
++
++
++ function error()
++ {
++ $result['error_sql'] = @current(@end($this->saved_queries));
++ $result['error_no'] = @mysql_errno($this->link_id);
++ $result['error_msg'] = @mysql_error($this->link_id);
++
++ return $result;
++ }
++
++
++ function close()
++ {
++ if ($this->link_id)
++ {
++ if ($this->query_result)
++ @mysql_free_result($this->query_result);
++
++ return @mysql_close($this->link_id);
++ }
++ else
++ return false;
++ }
++
++
++ function set_names($names)
++ {
++ return $this->query('SET NAMES \''.$this->escape($names).'\'');
++ }
++
++
++ function get_version()
++ {
++ $result = $this->query('SELECT VERSION()');
++
++ return array(
++ 'name' => 'MySQL Standard (InnoDB)',
++ 'version' => preg_replace('/^([^-]+).*$/', '\\1', $this->result($result))
++ );
++ }
++
++
++ function table_exists($table_name, $no_prefix = false)
++ {
++ $result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
++ return $this->num_rows($result) > 0;
++ }
++
++
++ function field_exists($table_name, $field_name, $no_prefix = false)
++ {
++ $result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
++ return $this->num_rows($result) > 0;
++ }
++
++
++ function index_exists($table_name, $index_name, $no_prefix = false)
++ {
++ $exists = false;
++
++ $result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
++ while ($cur_index = $this->fetch_assoc($result))
++ {
++ if ($cur_index['Key_name'] == ($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name)
++ {
++ $exists = true;
++ break;
++ }
++ }
++
++ return $exists;
++ }
++
++
++ function create_table($table_name, $schema, $no_prefix = false)
++ {
++ if ($this->table_exists($table_name, $no_prefix))
++ return;
++
++ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
++
++ // Go through every schema element and add it to the query
++ foreach ($schema['FIELDS'] as $field_name => $field_data)
++ {
++ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
++
++ $query .= $field_name.' '.$field_data['datatype'];
++
++ if (isset($field_data['collation']))
++ $query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
++
++ if (!$field_data['allow_null'])
++ $query .= ' NOT NULL';
++
++ if (isset($field_data['default']))
++ $query .= ' DEFAULT '.$field_data['default'];
++
++ $query .= ",\n";
++ }
++
++ // If we have a primary key, add it
++ if (isset($schema['PRIMARY KEY']))
++ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
++
++ // Add unique keys
++ if (isset($schema['UNIQUE KEYS']))
++ {
++ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
++ $query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
++ }
++
++ // Add indexes
++ if (isset($schema['INDEXES']))
++ {
++ foreach ($schema['INDEXES'] as $index_name => $index_fields)
++ $query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
++ }
++
++ // We remove the last two characters (a newline and a comma) and add on the ending
++ $query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'InnoDB').' CHARACTER SET utf8';
++
++ $this->query($query) or error(__FILE__, __LINE__);
++ }
++
++
++ function drop_table($table_name, $no_prefix = false)
++ {
++ if (!$this->table_exists($table_name, $no_prefix))
++ return;
++
++ $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or error(__FILE__, __LINE__);
++ }
++
++
++ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
++ {
++ if ($this->field_exists($table_name, $field_name, $no_prefix))
++ return;
++
++ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
++
++ if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
++ $default_value = '\''.$this->escape($default_value).'\'';
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
++ }
++
++
++ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
++ {
++ if (!$this->field_exists($table_name, $field_name, $no_prefix))
++ return;
++
++ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
++
++ if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
++ $default_value = '\''.$this->escape($default_value).'\'';
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
++ }
++
++
++ function drop_field($table_name, $field_name, $no_prefix = false)
++ {
++ if (!$this->field_exists($table_name, $field_name, $no_prefix))
++ return;
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) or error(__FILE__, __LINE__);
++ }
++
++
++ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
++ {
++ if ($this->index_exists($table_name, $index_name, $no_prefix))
++ return;
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') or error(__FILE__, __LINE__);
++ }
++
++
++ function drop_index($table_name, $index_name, $no_prefix = false)
++ {
++ if (!$this->index_exists($table_name, $index_name, $no_prefix))
++ return;
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error(__FILE__, __LINE__);
++ }
++}
+Index: include/dblayer/sqlite.php
+===================================================================
+--- include/dblayer/sqlite.php (revision 1168)
++++ include/dblayer/sqlite.php (revision 1655)
+@@ -579,7 +579,8 @@
+ if (!empty($table['indices']))
+ {
+ foreach ($table['indices'] as $cur_index)
+- $this->query($cur_index) or error(__FILE__, __LINE__);
++ if (!preg_match('#\(.*'.$field_name.'.*\)#', $cur_index))
++ $this->query($cur_index) or error(__FILE__, __LINE__);
+ }
+
+ //Copy content back
+Index: include/dblayer/mysqli_innodb.php
+===================================================================
+--- include/dblayer/mysqli_innodb.php (revision 0)
++++ include/dblayer/mysqli_innodb.php (revision 1655)
+@@ -0,0 +1,363 @@
++ 'INT(10) UNSIGNED AUTO_INCREMENT'
++ );
++
++
++ function DBLayer($db_host, $db_username, $db_password, $db_name, $db_prefix, $foo)
++ {
++ $this->prefix = $db_prefix;
++
++ // Was a custom port supplied with $db_host?
++ if (strpos($db_host, ':') !== false)
++ list($db_host, $db_port) = explode(':', $db_host);
++
++ if (isset($db_port))
++ $this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name, $db_port);
++ else
++ $this->link_id = @mysqli_connect($db_host, $db_username, $db_password, $db_name);
++
++ if (!$this->link_id)
++ error('Unable to connect to MySQL and select database. MySQL reported: '.mysqli_connect_error(), __FILE__, __LINE__);
++
++ // Setup the client-server character set (UTF-8)
++ if (!defined('FORUM_NO_SET_NAMES'))
++ $this->set_names('utf8');
++
++ return $this->link_id;
++ }
++
++
++ function start_transaction()
++ {
++ ++$this->in_transaction;
++
++ mysqli_query($this->link_id, 'START TRANSACTION');
++ return;
++ }
++
++
++ function end_transaction()
++ {
++ --$this->in_transaction;
++
++ mysqli_query($this->link_id, 'COMMIT');
++ return;
++ }
++
++
++ function query($sql, $unbuffered = false)
++ {
++ if (strlen($sql) > 140000)
++ exit('Insane query. Aborting.');
++
++ if (defined('FORUM_SHOW_QUERIES'))
++ $q_start = get_microtime();
++
++ $this->query_result = @mysqli_query($this->link_id, $sql);
++
++ if ($this->query_result)
++ {
++ if (defined('FORUM_SHOW_QUERIES'))
++ $this->saved_queries[] = array($sql, sprintf('%.5f', get_microtime() - $q_start));
++
++ ++$this->num_queries;
++
++ return $this->query_result;
++ }
++ else
++ {
++ if (defined('FORUM_SHOW_QUERIES'))
++ $this->saved_queries[] = array($sql, 0);
++
++ // Rollback transaction
++ if ($this->in_transaction)
++ mysqli_query($this->link_id, 'ROLLBACK');
++
++ --$this->in_transaction;
++
++ return false;
++ }
++ }
++
++
++ function result($query_id = 0, $row = 0, $col = 0)
++ {
++ if ($query_id)
++ {
++ if ($row)
++ @mysqli_data_seek($query_id, $row);
++
++ $cur_row = @mysqli_fetch_row($query_id);
++ return $cur_row[$col];
++ }
++ else
++ return false;
++ }
++
++
++ function fetch_assoc($query_id = 0)
++ {
++ return ($query_id) ? @mysqli_fetch_assoc($query_id) : false;
++ }
++
++
++ function fetch_row($query_id = 0)
++ {
++ return ($query_id) ? @mysqli_fetch_row($query_id) : false;
++ }
++
++
++ function num_rows($query_id = 0)
++ {
++ return ($query_id) ? @mysqli_num_rows($query_id) : false;
++ }
++
++
++ function affected_rows()
++ {
++ return ($this->link_id) ? @mysqli_affected_rows($this->link_id) : false;
++ }
++
++
++ function insert_id()
++ {
++ return ($this->link_id) ? @mysqli_insert_id($this->link_id) : false;
++ }
++
++
++ function get_num_queries()
++ {
++ return $this->num_queries;
++ }
++
++
++ function get_saved_queries()
++ {
++ return $this->saved_queries;
++ }
++
++
++ function free_result($query_id = false)
++ {
++ return ($query_id) ? @mysqli_free_result($query_id) : false;
++ }
++
++
++ function escape($str)
++ {
++ return is_array($str) ? '' : mysqli_real_escape_string($this->link_id, $str);
++ }
++
++
++ function error()
++ {
++ $result['error_sql'] = @current(@end($this->saved_queries));
++ $result['error_no'] = @mysqli_errno($this->link_id);
++ $result['error_msg'] = @mysqli_error($this->link_id);
++
++ return $result;
++ }
++
++
++ function close()
++ {
++ if ($this->link_id)
++ {
++ if ($this->query_result)
++ @mysqli_free_result($this->query_result);
++
++ return @mysqli_close($this->link_id);
++ }
++ else
++ return false;
++ }
++
++
++ function set_names($names)
++ {
++ return $this->query('SET NAMES \''.$this->escape($names).'\'');
++ }
++
++
++ function get_version()
++ {
++ $result = $this->query('SELECT VERSION()');
++
++ return array(
++ 'name' => 'MySQL Improved (InnoDB)',
++ 'version' => preg_replace('/^([^-]+).*$/', '\\1', $this->result($result))
++ );
++ }
++
++
++ function table_exists($table_name, $no_prefix = false)
++ {
++ $result = $this->query('SHOW TABLES LIKE \''.($no_prefix ? '' : $this->prefix).$this->escape($table_name).'\'');
++ return $this->num_rows($result) > 0;
++ }
++
++
++ function field_exists($table_name, $field_name, $no_prefix = false)
++ {
++ $result = $this->query('SHOW COLUMNS FROM '.($no_prefix ? '' : $this->prefix).$table_name.' LIKE \''.$this->escape($field_name).'\'');
++ return $this->num_rows($result) > 0;
++ }
++
++
++ function index_exists($table_name, $index_name, $no_prefix = false)
++ {
++ $exists = false;
++
++ $result = $this->query('SHOW INDEX FROM '.($no_prefix ? '' : $this->prefix).$table_name);
++ while ($cur_index = $this->fetch_assoc($result))
++ {
++ if ($cur_index['Key_name'] == ($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name)
++ {
++ $exists = true;
++ break;
++ }
++ }
++
++ return $exists;
++ }
++
++
++ function create_table($table_name, $schema, $no_prefix = false)
++ {
++ if ($this->table_exists($table_name, $no_prefix))
++ return;
++
++ $query = 'CREATE TABLE '.($no_prefix ? '' : $this->prefix).$table_name." (\n";
++
++ // Go through every schema element and add it to the query
++ foreach ($schema['FIELDS'] as $field_name => $field_data)
++ {
++ $field_data['datatype'] = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_data['datatype']);
++
++ $query .= $field_name.' '.$field_data['datatype'];
++
++ if (isset($field_data['collation']))
++ $query .= 'CHARACTER SET utf8 COLLATE utf8_'.$field_data['collation'];
++
++ if (!$field_data['allow_null'])
++ $query .= ' NOT NULL';
++
++ if (isset($field_data['default']))
++ $query .= ' DEFAULT '.$field_data['default'];
++
++ $query .= ",\n";
++ }
++
++ // If we have a primary key, add it
++ if (isset($schema['PRIMARY KEY']))
++ $query .= 'PRIMARY KEY ('.implode(',', $schema['PRIMARY KEY']).'),'."\n";
++
++ // Add unique keys
++ if (isset($schema['UNIQUE KEYS']))
++ {
++ foreach ($schema['UNIQUE KEYS'] as $key_name => $key_fields)
++ $query .= 'UNIQUE KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$key_name.'('.implode(',', $key_fields).'),'."\n";
++ }
++
++ // Add indexes
++ if (isset($schema['INDEXES']))
++ {
++ foreach ($schema['INDEXES'] as $index_name => $index_fields)
++ $query .= 'KEY '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.'('.implode(',', $index_fields).'),'."\n";
++ }
++
++ // We remove the last two characters (a newline and a comma) and add on the ending
++ $query = substr($query, 0, strlen($query) - 2)."\n".') ENGINE = '.(isset($schema['ENGINE']) ? $schema['ENGINE'] : 'InnoDB').' CHARACTER SET utf8';
++
++ $this->query($query) or error(__FILE__, __LINE__);
++ }
++
++
++ function drop_table($table_name, $no_prefix = false)
++ {
++ if (!$this->table_exists($table_name, $no_prefix))
++ return;
++
++ $this->query('DROP TABLE '.($no_prefix ? '' : $this->prefix).$table_name) or error(__FILE__, __LINE__);
++ }
++
++
++ function add_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
++ {
++ if ($this->field_exists($table_name, $field_name, $no_prefix))
++ return;
++
++ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
++
++ if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
++ $default_value = '\''.$this->escape($default_value).'\'';
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
++ }
++
++
++ function alter_field($table_name, $field_name, $field_type, $allow_null, $default_value = null, $after_field = null, $no_prefix = false)
++ {
++ if (!$this->field_exists($table_name, $field_name, $no_prefix))
++ return;
++
++ $field_type = preg_replace(array_keys($this->datatype_transformations), array_values($this->datatype_transformations), $field_type);
++
++ if ($default_value !== null && !is_int($default_value) && !is_float($default_value))
++ $default_value = '\''.$this->escape($default_value).'\'';
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' MODIFY '.$field_name.' '.$field_type.($allow_null ? ' ' : ' NOT NULL').($default_value !== null ? ' DEFAULT '.$default_value : ' ').($after_field != null ? ' AFTER '.$after_field : '')) or error(__FILE__, __LINE__);
++ }
++
++
++ function drop_field($table_name, $field_name, $no_prefix = false)
++ {
++ if (!$this->field_exists($table_name, $field_name, $no_prefix))
++ return;
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP '.$field_name) or error(__FILE__, __LINE__);
++ }
++
++
++ function add_index($table_name, $index_name, $index_fields, $unique = false, $no_prefix = false)
++ {
++ if ($this->index_exists($table_name, $index_name, $no_prefix))
++ return;
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' ADD '.($unique ? 'UNIQUE ' : '').'INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name.' ('.implode(',', $index_fields).')') or error(__FILE__, __LINE__);
++ }
++
++
++ function drop_index($table_name, $index_name, $no_prefix = false)
++ {
++ if (!$this->index_exists($table_name, $index_name, $no_prefix))
++ return;
++
++ $this->query('ALTER TABLE '.($no_prefix ? '' : $this->prefix).$table_name.' DROP INDEX '.($no_prefix ? '' : $this->prefix).$table_name.'_'.$index_name) or error(__FILE__, __LINE__);
++ }
++}
+Index: include/parser.php
+===================================================================
+--- include/parser.php (revision 1168)
++++ include/parser.php (revision 1655)
+@@ -44,11 +44,11 @@
+ if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
+ {
+ list($inside, $outside) = split_text($text, '[code]', '[/code]', $errors);
+- $text = implode("\0", $outside);
++ $text = implode("\xc1", $outside);
+ }
+
+ // Tidy up lists
+- $pattern = array('/\[list(?:=([1a\*]))?\]((?>(?:(?!\[list(?:=(?:[1a\*]))\]|\[\/list\]).+?)|(?R))*)\[\/list\]/ems');
++ $pattern = array('%\[list(?:=([1a*]))?+\]((?:(?>.*?(?=\[list(?:=[1a*])?+\]|\[/list\]))|(?R))*)\[/list\]%ise');
+ $replace = array('preparse_list_tag(\'$2\', \'$1\', $errors)');
+ $text = preg_replace($pattern, $replace, $text);
+
+@@ -60,7 +60,7 @@
+ // If we split up the message before we have to concatenate it together again (code tags)
+ if (isset($inside))
+ {
+- $outside = explode("\0", $text);
++ $outside = explode("\xc1", $text);
+ $text = '';
+
+ $num_tokens = count($outside);
+@@ -520,7 +520,7 @@
+
+ if (strpos($content,'[list') !== false)
+ {
+- $pattern = array('/\[list(?:=([1a\*]))?\]((?>(?:(?!\[list(?:=(?:[1a\*]))\]|\[\/list\]).+?)|(?R))*)\[\/list\]/ems');
++ $pattern = array('%\[list(?:=([1a*]))?+\]((?:(?>.*?(?=\[list(?:=[1a*])?+\]|\[/list\]))|(?R))*)\[/list\]%ise');
+ $replace = array('preparse_list_tag(\'$2\', \'$1\', $errors)');
+ $content = preg_replace($pattern, $replace, $content);
+ }
+@@ -592,7 +592,7 @@
+
+ // Ok, not very pretty :-)
+ if (!$bbcode)
+- $link = ($link == '' || $link == $url) ? ((utf8_strlen($url) > 55) ? utf8_substr($url, 0 , 39).'
'.utf8_substr($url, -10) : $url) : stripslashes($link);
++ $link = ($link == '' || $link == $url) ? ((utf8_strlen($url) > 55) ? utf8_substr($url, 0 , 39).' … '.utf8_substr($url, -10) : $url) : stripslashes($link);
+
+ $return = ($hook = get_hook('ps_handle_url_tag_end')) ? eval($hook) : null;
+ if ($return != null)
+@@ -649,7 +649,7 @@
+
+ if (strpos($content,'[list') !== false)
+ {
+- $pattern = array('/\[list(?:=([1a\*]))?\]((?>(?:(?!\[list(?:=(?:[1a\*]))\]|\[\/list\]).+?)|(?R))*)\[\/list\]/ems');
++ $pattern = array('%\[list(?:=([1a*]))?+\]((?:(?>.*?(?=\[list(?:=[1a*])?+\]|\[/list\]))|(?R))*)\[/list\]%ise');
+ $replace = array('handle_list_tag(\'$2\', \'$1\')');
+ $content = preg_replace($pattern, $replace, $content);
+ }
+@@ -688,7 +688,7 @@
+
+ if (!$is_signature)
+ {
+- $pattern[] = '/\[list(?:=([1a\*]))?\]((?>(?:(?!\[list(?:=(?:[1a\*]))\]|\[\/list\]).+?)|(?R))*)\[\/list\]/ems';
++ $pattern[] = '%\[list(?:=([1a*]))?+\]((?:(?>.*?(?=\[list(?:=[1a*])?+\]|\[/list\]))|(?R))*)\[/list\]%ise';
+ $replace[] = 'handle_list_tag(\'$2\', \'$1\')';
+ }
+
+@@ -752,7 +752,7 @@
+ {
+ $text = ' '.$text;
+
+- $text = preg_replace('#(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(https?|ftp|news){1}://([\w\-]+\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-]?)?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])#ie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5://$6\', \'$5://$6\', true).stripslashes(\'$4$10$11$12\')', $text);
++ $text = preg_replace('#(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(https?|ftp|news){1}://([\w\-]+\.([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])#ie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5://$6\', \'$5://$6\', true).stripslashes(\'$4$10$11$12\')', $text);
+ $text = preg_replace('#(?<=[\s\]\)])(<)?(\[)?(\()?([\'"]?)(www|ftp)\.(([\w\-]+\.)*[\w]+(:[0-9]+)?(/[^\s\[]*[^\s.,?!\[;:-])?)\4(?(3)(\)))(?(2)(\]))(?(1)(>))(?![^\s]*\[/(?:url|img)\])#ie', 'stripslashes(\'$1$2$3$4\').handle_url_tag(\'$5.$6\', \'$5.$6\', true).stripslashes(\'$4$10$11$12\')', $text);
+
+ return substr($text, 1);
+@@ -813,7 +813,7 @@
+ if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false)
+ {
+ list($inside, $outside) = split_text($text, '[code]', '[/code]', $errors);
+- $text = implode("\0", $outside);
++ $text = implode("\xc1", $outside);
+ }
+
+ $return = ($hook = get_hook('ps_parse_message_post_split')) ? eval($hook) : null;
+@@ -842,7 +842,7 @@
+ // If we split up the message before we have to concatenate it together again (code tags)
+ if (isset($inside))
+ {
+- $outside = explode("\0", $text);
++ $outside = explode("\xc1", $text);
+ $text = '';
+
+ $num_tokens = count($outside);
+Index: include/cache.php
+===================================================================
+--- include/cache.php (revision 1168)
++++ include/cache.php (revision 1655)
+@@ -297,7 +297,7 @@
+ $output = array();
+ while ($cur_hook = $forum_db->fetch_assoc($result))
+ {
+- $load_ext_info = '$ext_info_stack[] = array('."\n".
++ $load_ext_info = '$GLOBALS[\'ext_info_stack\'][] = array('."\n".
+ '\'id\' => \''.$cur_hook['extension_id'].'\','."\n".
+ '\'path\' => FORUM_ROOT.\'extensions/'.$cur_hook['extension_id'].'\','."\n".
+ '\'url\' => $GLOBALS[\'base_url\'].\'/extensions/'.$cur_hook['extension_id'].'\','."\n".
+@@ -316,8 +316,8 @@
+ '\'url\' => $GLOBALS[\'base_url\'].\'/extensions/'.$cur_dependency.'\'),'."\n";
+ }
+
+- $load_ext_info .= ')'."\n".');'."\n".'$ext_info = $ext_info_stack[count($ext_info_stack) - 1];';
+- $unload_ext_info = 'array_pop($ext_info_stack);'."\n".'$ext_info = empty($ext_info_stack) ? array() : $ext_info_stack[count($ext_info_stack) - 1];';
++ $load_ext_info .= ')'."\n".');'."\n".'$ext_info = $GLOBALS[\'ext_info_stack\'][count($GLOBALS[\'ext_info_stack\']) - 1];';
++ $unload_ext_info = 'array_pop($GLOBALS[\'ext_info_stack\']);'."\n".'$ext_info = empty($GLOBALS[\'ext_info_stack\']) ? array() : $GLOBALS[\'ext_info_stack\'][count($GLOBALS[\'ext_info_stack\']) - 1];';
+
+ $output[$cur_hook['id']][] = $load_ext_info."\n\n".$cur_hook['code']."\n\n".$unload_ext_info."\n";
+ }
+Index: include/functions.php
+===================================================================
+--- include/functions.php (revision 1168)
++++ include/functions.php (revision 1655)
+@@ -404,6 +404,8 @@
+ if ($type == FORUM_FT_DATETIME || $type == FORUM_FT_TIME)
+ $formatted_time .= gmdate($time_format, $timestamp);
+
++ ($hook = get_hook('fn_format_time_end')) ? eval($hook) : null;
++
+ return $formatted_time;
+ }
+
+@@ -749,7 +751,7 @@
+ global $forum_config, $forum_user;
+ static $lang_url_replace, $forum_reserved_strings;
+
+- if (!isset($lang_replace))
++ if (!isset($lang_url_replace))
+ require FORUM_ROOT.'lang/'.$forum_user['language'].'/url_replace.php';
+
+ if (!isset($forum_reserved_strings))
+@@ -772,6 +774,8 @@
+ foreach ($forum_reserved_strings as $match => $replace)
+ if ($str == $match)
+ return $replace;
++ else if ($match != '')
++ $str = str_replace($match, $replace, $str);
+
+ return $str;
+ }
+@@ -1457,6 +1461,9 @@
+ if ($cur_ban['username'] != '' && utf8_strtolower($forum_user['username']) == utf8_strtolower($cur_ban['username']))
+ $is_banned = true;
+
++ if ($cur_ban['email'] != '' && $forum_user['email'] == $cur_ban['email'])
++ $is_banned = true;
++
+ if ($cur_ban['ip'] != '')
+ {
+ $cur_ban_ips = explode(' ', $cur_ban['ip']);
+@@ -1539,7 +1546,7 @@
+ else
+ {
+ // If the entry is older than "o_timeout_visit", update last_visit for the user in question, then delete him/her from the online list
+- if ($cur_user['idle'] != '0')
++ if ($cur_user['logged'] < ($now - $forum_config['o_timeout_visit']))
+ {
+ $query = array(
+ 'UPDATE' => 'users',
+@@ -2777,15 +2784,10 @@
+
+
+ // START SUBST -
++
+ ob_start();
+
+-?>
+-
+-
++
++
+
+