<?php
/*========================================================================*\
|| ###################################################################### ||
|| # vBulletin 5.5.2
|| # ------------------------------------------------------------------ # ||
|| # Copyright 2000-2019 MH Sub I, LLC dba vBulletin. All Rights Reserved.  # ||
|| # This file may not be redistributed in whole or significant part.   # ||
|| # ----------------- VBULLETIN IS NOT FREE SOFTWARE ----------------- # ||
|| # http://www.vbulletin.com | http://www.vbulletin.com/license.html   # ||
|| ###################################################################### ||
\*========================================================================*/

error_reporting(E_ALL & ~E_NOTICE);

//we want this to work from a couple of different locations/urls which makes
//figuring out where some of the other files live tricky.  Especially since
//we can't necesarily assume that bburl is set correctly in the config.
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT);
$toplevel = empty($trace);

define('VERSION', '5.5.2');



$parts = parse_url($_SERVER['REQUEST_URI'] );
define('THIS_SCRIPT', $parts['path']);


define('VB_AREA', 'tools');
define('VB_ENTRY', 1);


$core = realpath(dirname(__FILE__) . '/../');
if (file_exists($core . '/includes/init.php'))
{ // need to go up a single directory, we must be in includes / admincp / modcp / install
	chdir($core);
}
else
{
	die('Please place this file within the "core/admincp" or "core/install" folder');
}

$success = false;
if(@include_once( './install/includes/class_upgrade.php'))
{
	$success = @include_once('./install/init.php');
}

if (!$success)
{
	die('The core/install function is required for tools.php.  Please upload that directory from your vBulletin download package.');
}

require_once(DIR . '/includes/functions.php');
require_once(DIR . '/includes/adminfunctions.php');

$vb5_config =& vB::getConfig();
$options = vB::getDatastore()->getValue('options');

if ($toplevel)
{
	$base_url = '../..';
}
else
{
	$base_url = '..';
}

$type = $vbulletin->input->clean_gpc('r', 'type', vB_Cleaner::TYPE_STR);

try
{
	vB_Upgrade::createAdminSession();
}
catch (Exception $e)
{
}

#####################################
# phrases for import systems
#####################################
$vbphrase['importing_language'] = 'Importing Language';
$vbphrase['importing_style'] = 'Importing Style';
$vbphrase['importing_admin_help'] = 'Importing Admin Help';
$vbphrase['importing_settings'] = 'Importing Setting';
$vbphrase['please_wait'] = 'Please Wait';
$vbphrase['language'] = 'Language';
$vbphrase['master_language'] = 'Master Language';
$vbphrase['admin_help'] = 'Admin Help';
$vbphrase['style'] = 'Style';
$vbphrase['styles'] = 'Styles';
$vbphrase['settings'] = 'Settings';
$vbphrase['master_style'] = 'MASTER STYLE';
$vbphrase['templates'] = 'Templates';
$vbphrase['css'] = 'CSS';
$vbphrase['stylevars'] = 'Stylevars';
$vbphrase['replacement_variables'] = 'Replacement Variables';
$vbphrase['controls'] = 'Controls';
$vbphrase['rebuild_style_information'] = 'Rebuild Style Information';
$vbphrase['updating_style_information_for_each_style'] = 'Updating style information for each style';
$vbphrase['updating_styles_with_no_parents'] = 'Updating style sets with no parent information';
$vbphrase['updated_x_styles'] = 'Updated %1$s Styles';
$vbphrase['no_styles_needed_updating'] = 'No Styles Needed Updating';
$vbphrase['processing_complete_proceed'] = 'Processing Complete - Proceed';

?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
	<title>vBulletin Tools</title>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
	<link rel="stylesheet" href="<?php echo $base_url;?>/core/cpstyles/vBulletin_5_Default/controlpanel.css" />
	<script type="text/javascript">
		var SESSIONHASH = "";
		var toggleAllCheckboxesInForm = function(ctrl)
		{
			var i, el;
			for (i = 0; i < ctrl.form.elements.length; i++)
			{
				el = ctrl.form.elements[i];
				if (el.type == 'checkbox' && el != ctrl)
				{
					el.checked = ctrl.checked;
				}
			}
		};

	</script>
</head>
<body style="margin:0px">
<div class="acp-content-wrapper">
<h2 class="pagetitle" style="text-align:center">vBulletin 5 Tools</h2>
<!-- END CONTROL PANEL HEADER -->
<?php


// #############################################################################
if (empty($_REQUEST['do']))
{
	$style_xml = getXmlVersion('vbulletin-style.xml', 256, '#vbversion="(.*?)"#');
	$language_xml = getXmlVersion('vbulletin-language.xml', 256, '#vbversion="(.*?)"#');
	$settings_xml = getXmlVersion('vbulletin-settings.xml', 300, '#<defaultvalue>(.*?)</defaultvalue>#');

	$language = $db->query_read('SELECT title FROM ' . TABLE_PREFIX . 'language WHERE languageid = ' . intval($options['languageid']));
	if ($db->num_rows($language) == 1)
	{
		$language = $db->fetch_array($language);
		$language = $language['title'];
	}
	else
	{
		$language = 'Unknown';
	}

	$xml_block_actions = array(
		'Style' => array('do' => 'xml', 'type' => 'style', 'description' => "This will take the latest style from ./install/vbulletin-style.xml<dfn>Version: <b>$style_xml</b></dfn>"),
		'Settings' => array('do' => 'xml', 'type' => 'settings', 'description' => "This will take the latest settings from ./install/vbulletin-settings.xml<dfn>Version: <b>$settings_xml</b></dfn>"),
		'Language' => array('do' => 'xml', 'type' => 'language', 'description' => "This will take the latest language from ./install/vbulletin-language.xml<dfn>Version: <b>$language_xml</b></dfn>"),
		'Admin Help' => array('do' => 'xml', 'type' => 'adminhelp', 'description' => 'This will take the latest admin help from ./install/vbulletin-adminhelp.xml'),
	);

	$datastore_block_actions = array(
		'Usergroup / Channel Cache' => array('do' => 'cache', 'type' => 'channel', 'description' => 'Update the channel and usergroup cache'),
		'Options Cache' => array('do' => 'cache', 'type' => 'options', 'description' => 'Update the options cache from the setting table'),
		'Bitfield Cache' => array('do' => 'bitfields', 'description' => 'Update the bitfields cache from the xml/bitfields_<em>???</em>.xml files'),
		'Password Schemes' => array('do' => 'pwschemes', 'description' => 'Update the password schemes from the xml/pwschemes_<em>???</em>.xml files'),
	);

	$options['cookiedomain'] = $options['cookiedomain'] == '' ? ' ( blank ) ' : '<b>' . htmlspecialchars_uni($options['cookiedomain']) . '</b>';
	$options['cookiepath'] = $options['cookiepath'] == '' ? ' ( blank ) ' : '<b>' . htmlspecialchars_uni($options['cookiepath']) . '</b>';

	$cookie_block_actions = array(
		'Cookie Prefix' => array('description' => '<b>' . htmlspecialchars_uni(COOKIE_PREFIX) . '</b> (<em>set in includes/config.php</em>)'),
		'Reset Cookie Domain' => array('do' => 'cookie', 'type' => 'domain', 'description' => 'Reset the cookie domain to be blank<dfn>Currently: ' . $options['cookiedomain'] . '</dfn>'),
		'Reset Cookie Path' => array('do' => 'cookie', 'type' => 'path', 'description' => 'Reset the cookie path to be <b>/</b><dfn>Currently: ' . $options['cookiepath'] . '</dfn>'),
	);

	$mysql_block_actions = array(
		'Run Query' => array('do' => 'mysql', 'type' => 'query', 'description' => 'This allows you to run alter and update queries on the database'),
		'Repair Tables' => array('do' => 'mysql', 'type' => 'repair', 'description' => 'You can select tables that need repaired here'),
		'Reset Admin Access' => array('do' => 'user', 'type' => 'access', 'description' => 'Reset admin access for a user'),
		'Scan Content Tables' => array('do' => 'scancontent', 'description' => 'Scan & Repair node, closure, and content tables. You should only do this if vBulletin Technical Support Staff advises you to do so, and make sure you have a back up first.'),
		'Restore Pages' => array('do' => 'pages', 'description' => 'This allows you to revert pages to their default configuration. This modifies the route, page, pagetemplate, and widgets for the page. You should only use this if vBulletin Technical Support Staff advises you to do so, and after backing up your database first.'),
//		'Repair Routes' => array('do' => 'routefix', 'description' => '<b>Do not run this unless you have been instructed to do so by vBulletin support. This tool can make irreversible changes. Always back up your database before running this tool.</b><br/><br/>This runs a repair of all channel and conversation routes. vBulletin requires a specific relationship between channels, routes and pages, and if for some reason this becomes invalid this script will attempt to fix. It sometimes is a good idea to run a second or third time if you have to do it at all. Expect this to take a minute or more- longer if you have many damaged routes.'),
		'Fix Poll Option Cache' => array('do' => 'fixpolls', 'description' => 'Regenerate the poll option cache if it is out of sync.'),
	);

	$randnumb = vbrand(0, 100000000);

	$onoffforum = ($options['bbactive'] ? 'Turn Off Forum' : 'Turn On Forum');
	$onoffcss = ($options['storecssasfile'] ? 'Turn Off Css As Files' : 'Turn On Css As Files');
	$onofftemplates = ($options['cache_templates_as_files'] ? 'Turn Off Templates As Files' : 'Turn On Templates As Files');

	$other_block_actions = array(
		$onoffforum => array('do' => 'togglesetting', 'type' => 'bbactive', 'description' =>  'Your forum is <b>' . ($options['bbactive'] ? 'On' : 'Off') . '</b>'),
		$onoffcss => array('do' => 'togglesetting', 'type' => 'storecssasfile', 'description' =>  'Css As Files is <b>' . ($options['storecssasfile'] ? 'On' : 'Off') . '</b>'),
		$onofftemplates => array('do' => 'togglesetting', 'type' => 'cache_templates_as_files', 'description' =>  'Templates As Files is <b>' . ($options['cache_templates_as_files'] ? 'On' : 'Off') . '</b>'),
		'Rebuild Styles' => array('do' => 'rebuildstyles', 'description' => 'Rebuild the internal Style Rollup values <dfn>This will rebuild the css cache on disk if Css As Files is on</dfn>'),
		'Rebuild Template Cache' => array('do' => 'rebuildtemplatecache', 'description' => 'Rebuild the template cache on disk. <dfn>This only has an effect if TemplatesAs Files is on</dfn>'),
		'Default Language' => array('do' => 'language', 'description' => 'Reset board default language.<dfn>Currently: <b>' . htmlspecialchars($language) . '</b></dfn>'),
		'Location of Website' => array('do' => 'bburl', 'description' => 'Change location of site. (This is the vboptions[frontendurl] setting) <br /><dfn>Currently: <b>' . htmlspecialchars($options['frontendurl']) . '</b></dfn>'),
	);

	try
	{
		$userdate = vbdate('r T');
	}
	catch(Exception $e)
	{
		$userdate = '';
	}

	$info_block_actions = array(
		'System Time' => array('description' => $systemdate = date('r T')),
		'Your Time' => array('description' => $userdate),
	);

	//actually print out the form
	print_form_header();

	tools_print_block('Import XML Files', $xml_block_actions);
	print_table_break();

	tools_print_block('Datastore Cache', $datastore_block_actions);
	print_table_break();

	tools_print_block('Cookies', $cookie_block_actions);
	print_table_break();

	tools_print_block('MySQL', $mysql_block_actions);
	print_table_break();

	tools_print_block('Other Tools', $other_block_actions);
	print_table_break();

	tools_print_block('Time', $info_block_actions);

	print_table_footer();
}
// #############################################################################
else if ($_REQUEST['do'] == 'xml')
{
	switch ($vbulletin->GPC['type'])
	{
		case 'style':
			require_once('./includes/adminfunctions_template.php');

			if (!($xml = file_read('./install/vbulletin-style.xml')))
			{
				echo '<p>Uh oh, ./install/vbulletin-style.xml doesn\'t appear to exist! Upload it and refresh the page.</p>';
				print_cp_footer();
			}

			echo '<p>Importing vbulletin-style.xml</p>';

			$startat = $vbulletin->input->clean_gpc('r', 'startat', vB_Cleaner::TYPE_UINT);

			$vbphrase['go_back'] = 'Go Back';
			$vbphrase['template_group_x'] = 'Template Group: %1$s';

			$perpage = 10;
			$imported = xml_import_style($xml, -1, -1, '', false, 1, false, $startat, $perpage);

			if (!$imported['done'])
			{
				//build the next page url;
				$startat = $startat + $perpage;
				$redirect = THIS_SCRIPT . '?do=xml&type=style&startat=' . $startat;
				print_cp_redirect_old($redirect, 2);
			}
			// define those phrases that are used for the import
			$vbphrase['style'] = 'Style';
			$vbphrase['please_wait'] = 'Please Wait';

			build_all_styles(0, 1);
			print_cp_redirect_old(THIS_SCRIPT . '?do=templatemerge', 2);
		break;
		case 'settings':
			require_once('./includes/adminfunctions_options.php');

			if (!($xml = file_read('./install/vbulletin-settings.xml')))
			{
				echo '<p>Uh oh, ./install/vbulletin-settings.xml doesn\'t appear to exist! Upload it and refresh the page.</p>';
				print_cp_footer();
			}

			echo '<p>Importing vbulletin-settings.xml';
			xml_import_settings($xml);
			echo '<br /><span class="smallfont"><b>Okay</b></span></p>';
		break;
		case 'language':
			require_once('./includes/adminfunctions_language.php');

			if (!($xml = file_read('./install/vbulletin-language.xml')))
			{
				echo '<p>Uh oh, ./install/vbulletin-language.xml doesn\'t appear to exist! Upload it and refresh the page.</p>';
				print_cp_footer();
			}

			echo '<p>Importing vbulletin-language.xml';
			xml_import_language($xml);
			build_language();
			echo '<br /><span class="smallfont"><b>Okay</b></span></p>';
		break;
		case 'adminhelp':
			require_once('./includes/adminfunctions_help.php');

			if (!($xml = file_read('./install/vbulletin-adminhelp.xml')))
			{
				echo '<p>Uh oh, ./install/vbulletin-adminhelp.xml doesn\'t appear to exist! Upload it and refresh the page.</p>';
				print_cp_footer();
			}

			echo '<p>Importing vbulletin-adminhelp.xml';
			xml_import_help_topics($xml);
			echo "<br /><span class=\"smallfont\"><b>Okay</b></span></p>";
		break;
	}
	define('SCRIPT_REDIRECT', true);
}
// #############################################################################
else if ($_REQUEST['do'] == 'templatemerge') // after importing style
{
	$vbulletin->input->clean_array_gpc('r', array(
		'startat' => vB_Cleaner::TYPE_UINT,
	));

	require_once(DIR . '/includes/class_template_merge.php');

	$merge_data = new vB_Template_Merge_Data($vbulletin);
	$merge_data->start_offset = $vbulletin->GPC['startat'];
	$merge_data->add_condition("tnewmaster.product IN ('', 'vbulletin')");

	$merge = new vB_Template_Merge($vbulletin);
	$merge->time_limit = 5;
	$completed = $merge->merge_templates($merge_data, $output);

	if ($completed)
	{
		// completed
		$vbphrase['style'] = 'Style';
		$vbphrase['please_wait'] = 'Please Wait';

		build_all_styles();

		define('SCRIPT_REDIRECT', true);
	}
	else
	{
		// more templates to merge
		print_cp_redirect2('tools', array('do' => 'templatemerge', 'startat' => ($merge_data->start_offset + $merge->fetch_processed_count())), 1,  substr(THIS_SCRIPT, 0, -4));
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'cache')
{
	switch ($vbulletin->GPC['type'])
	{
		case 'channel':
			vB_Library::instance('usergroup')->buildDatastore();
			vB::getUserContext()->rebuildGroupAccess();
			define('SCRIPT_REDIRECT', true);
		break;
		case 'options':
			vB::getDatastore()->build_options();
			define('SCRIPT_REDIRECT', true);
		break;
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'cookie')
{
	switch ($vbulletin->GPC['type'])
	{
		case 'domain':
			tools_update_setting($db, 'cookiedomain', '');
			define('SCRIPT_REDIRECT', true);
		break;
		case 'path':
			tools_update_setting($db, 'cookiepath', '/');
			define('SCRIPT_REDIRECT', true);
		break;
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'bitfields')
{
	require_once(DIR . '/includes/class_bitfield_builder.php');
	vB_Bitfield_Builder::save($db);
	vB_Library::instance('usergroup')->buildDatastore();
	vB::getUserContext()->rebuildGroupAccess();
	define('SCRIPT_REDIRECT', true);
}
// #############################################################################
else if ($_REQUEST['do'] == 'pwschemes')
{
	try
	{
		vB_Library::instance('login')->importPasswordSchemes();
		define('SCRIPT_REDIRECT', true);
	}
	catch(vB_Exception_Api $e)
	{
		$errors = $e->get_errors();
		print_stop_message2($errors[0]);
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'mysql')
{
	$vbulletin->input->clean_array_gpc('p', array('query' => vB_Cleaner::TYPE_STR, 'tables' => vB_Cleaner::TYPE_ARRAY));

	switch ($vbulletin->GPC['type'])
	{
		case 'query':
			if (empty($vbulletin->GPC['query']) OR !preg_match('#^(Alter|Update)#si', $vbulletin->GPC['query']))
			{
				print_form_header(substr(THIS_SCRIPT, 0, -4), 'mysql',false, true, 'cpform', '100%', '',
					true, 'post', 0, false, '', false, array('skipAdmincp' => true));
				construct_hidden_code('type', 'query');
				print_table_header('Please paste alter / update query below');
				print_textarea_row('Query to run', 'query','', 6, 60, 0, 0);
				print_submit_row('Run', '');
			}
			else
			{
				$db->query_write($vbulletin->GPC['query']);
				define('SCRIPT_REDIRECT', true);
			}
			break;
		case 'repair':
			if (empty($vbulletin->GPC['tables']))
			{
				print_form_header(substr(THIS_SCRIPT, 0, -4), 'mysql',false, true, 'cpform', '100%', '',
					true, 'post', 0, false, '', false, array('skipAdmincp' => true));
				construct_hidden_code('type', 'repair');
				print_table_header('Please select tables to repair');
				print_label_row('Table', "<label><input type=\"checkbox\" name=\"allbox\" title=\"Check All\" onclick=\"toggleAllCheckboxesInForm(this);\" />Check All</label>", 'thead');
				$result = $db->query_write("SHOW TABLE STATUS");
				while ($currow = $db->fetch_array($result, vB_Database::DBARRAY_NUM))
				{
					if (!in_array(strtolower($currow[1]), array('heap', 'memory')))
					{
						print_checkbox_row($currow[0], "tables[$currow[0]]", 0);
					}
				}
				print_submit_row('Repair', '');
			}
			else
			{
				echo '<ul>';
				foreach($vbulletin->GPC['tables'] AS $key => $val)
				{
					if ($val == 1)
					{
						echo "<li>Repairing <b>$key</b>... ";
						flush();
						$db->query_write("REPAIR TABLE $key");
						echo "Repair Complete</li>\n";
					}
				}
				echo '</ul>';
				echo "<p>Overall Repair complete</p><br />";
				define('SCRIPT_REDIRECT', true);
			}
		break;
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'user')
{
	$vbulletin->input->clean_array_gpc('p', array('user' => vB_Cleaner::TYPE_STR));

	switch ($vbulletin->GPC['type'])
	{
		case 'access':
		if (empty($vbulletin->GPC['user']))
		{
			print_form_header(substr(THIS_SCRIPT, 0, -4), 'user',false, true, 'cpform', '100%', '',
				true, 'post', 0, false, '', false, array('skipAdmincp' => true));
			construct_hidden_code('type', 'access');
			print_table_header('Enter username to restore access to');
			print_input_row('User Name', 'user', '');
			print_submit_row('Submit', '');
		}
		else
		{
			$userid = $db->query_first("
				SELECT userid, usergroupid
				FROM " . TABLE_PREFIX . "user
				WHERE username = '" . $db->escape_string(htmlspecialchars_uni($vbulletin->GPC['user'])) . "'
			");

			if (empty($userid['userid']))
			{
				echo '<p align="center">Invalid username</p>';
			}
			else
			{
				// let's check that usergroupid 6 is still admin
				$bf_ugp_adminpermissions = vB::getDatastore()->get_value('bf_ugp_adminpermissions');
				$ugroup = $db->query_first("SELECT * FROM " . TABLE_PREFIX . "usergroup WHERE usergroupid = 6 AND (adminpermissions & " . $bf_ugp_adminpermissions['cancontrolpanel'] . ")");
				if (empty($ugroup['usergroupid']))
				{
					// lets give them admin permissions again
					$db->query_write("UPDATE " . TABLE_PREFIX . "usergroup SET adminpermissions = 3 WHERE usergroupid = 6");
					vB_Library::instance('usergroup')->buildDatastore();
					vB::getUserContext()->rebuildGroupAccess();
				}

				/*insert query*/
				$db->query_write("REPLACE INTO " . TABLE_PREFIX . "administrator
					(userid, adminpermissions)
				VALUES
					($userid[userid], " . (array_sum($bf_ugp_adminpermissions) - 3) . ")
				");
				$db->query_write("UPDATE " . TABLE_PREFIX . "user SET usergroupid = 6 WHERE userid = $userid[userid]");
				define('SCRIPT_REDIRECT', true);

				vB_Cache::instance(vB_Cache::CACHE_FAST)->event('perms_changed');
				vB_Cache::instance(vB_Cache::CACHE_FAST)->event('userChg_' . $userid['userid']);
				vB_Cache::instance(vB_Cache::CACHE_LARGE)->event('userChg_' . $userid['userid']);
				vB::getUserContext()->rebuildGroupAccess();
			}
		}
		break;
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'togglesetting')
{
	$setting = $vbulletin->GPC['type'];
	$value = ($options[$setting] ? 0 : 1);

	//toggle the setting
	tools_update_setting($db, $setting, $value);


	//side effects.  These duplicate what happens in save_settings in adminfunction_options
	//we don't call that here because we need to refactor it to avoid checking permissions
	//or require a login.  This is a bit ugly since we're trying to get away from
	//a seperate action per setting but there is only so much we can do.
	if ($setting == 'storecssasfile')
	{
		require_once(DIR . '/includes/adminfunctions_template.php');
		print_rebuild_style(-1, '', 1, 0, 0, 0);
	}
	else if($setting == 'cache_templates_as_files')
	{
		$library = vB_Library::instance('template');
		if ($value)
		{
			$library->saveAllTemplatesToFile();
		}
		else
		{
			$library->deleteAllTemplateFiles();
		}
	}

	define('SCRIPT_REDIRECT', true);
}
// #############################################################################
else if ($_REQUEST['do'] == 'rebuildstyles')
{
	require_once(DIR . '/includes/adminfunctions_template.php');
	print_rebuild_style(-1);
	define('SCRIPT_REDIRECT', true);
}
// #############################################################################
else if ($_REQUEST['do'] == 'rebuildtemplatecache')
{
	if($options['cache_templates_as_files'])
	{
		$library = vB_Library::instance('template');
		$library->deleteAllTemplateFiles();
		$library->saveAllTemplatesToFile();
	}
	define('SCRIPT_REDIRECT', true);
}

// #############################################################################
else if ($_REQUEST['do'] == 'language')
{
	$vbulletin->input->clean_array_gpc('p', array('languageid' => vB_Cleaner::TYPE_UINT));

	require_once(DIR . '/includes/adminfunctions_language.php');

	$languages = $db->query_read('SELECT * FROM ' . TABLE_PREFIX . 'language');
	if ($db->num_rows($languages) == 0)
	{
		// this is just taken from install.php
		$db->query_write("INSERT INTO " . TABLE_PREFIX . "language (title, languagecode, charset, decimalsep, thousandsep) VALUES ('English (US)', 'en', 'ISO-8859-1', '.', ',')");
		$_languageid = $db->insert_id();

		$db->query_write("
			UPDATE " . TABLE_PREFIX . "setting
			SET value = " . $_languageid . "
			WHERE varname = 'languageid'
		");

		$db->query_write("
			UPDATE " . TABLE_PREFIX . "user
			SET languageid = 0
		");
		vB::getDatastore()->build_options();
		build_language($_languageid);
		build_language_datastore();
		define('SCRIPT_REDIRECT', true);
	}
	else
	{
		$sellanguages = array();
		while ($language = $db->fetch_array($languages))
		{
			$sellanguages[$language['languageid']] = $language['title'];
		}

		$languageids = implode(',', array_keys($sellanguages));

		$db->query_write("
			UPDATE " . TABLE_PREFIX . "user
			SET languageid = 0
			WHERE languageid NOT IN ($languageids)
		");

		if (empty($vbulletin->GPC['languageid']))
		{
			print_form_header(substr(THIS_SCRIPT, 0, -4), 'language',false, true, 'cpform', '100%', '',
				true, 'post', 0, false, '', false, array('skipAdmincp' => true));
			print_table_header('Select the new default language');
			print_select_row('Language', 'languageid', $sellanguages, $options['languageid']);
			print_submit_row('Submit', '');
		}
		else
		{
			vB_Api::instanceInternal('language')->setDefault($vbulletin->GPC['languageid']);
			define('SCRIPT_REDIRECT', true);
		}
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'bburl')
{
	$vbulletin->input->clean_array_gpc('p', array('frontendurl' => vB_Cleaner::TYPE_STR, 'changebburl' => vB_Cleaner::TYPE_BOOL));

	if (empty($vbulletin->GPC['frontendurl']))
	{
		print_form_header(substr(THIS_SCRIPT, 0, -4), 'bburl',false, true, 'cpform', '100%', '', true,
			'post', 0, false, '', false, array('skipAdmincp' => true));
		print_table_header('Enter the new website location (bburl)');
		print_input_row('Website url (frontendurl).<br />Note: do not add a trailing slash. (\'/\')',
			'frontendurl', htmlspecialchars($options['frontendurl']));
		print_checkbox_row('Also change the core directory (bburl) to {frontend}/core', 'changebburl');
		print_submit_row('Submit', '');
	}
	else
	{
		$db->query_write("
			UPDATE " . TABLE_PREFIX . "setting
			SET value = '" . $db->escape_string($vbulletin->GPC['frontendurl']) . "'
			WHERE varname IN('frontendurl', 'frontendurl_login')
		");

		if($vbulletin->GPC['changebburl'])
		{
			$bburl = $vbulletin->GPC['frontendurl'] . '/core';
			$db->query_write("
				UPDATE " . TABLE_PREFIX . "setting
				SET value = '" . $db->escape_string($bburl) . "'
				WHERE varname = 'bburl'
			");
		}

		vB::getDatastore()->build_options();
		define('SCRIPT_REDIRECT', true);
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'scancontent')
{
	if (!isset($_REQUEST['perpage']))
	{
		print_form_header(substr(THIS_SCRIPT, 0, -4), 'scancontent',false, true, 'cpform', '100%', '', true, 'post', 0, false, '', false, array('skipAdmincp' => true));
		print_table_header('Don\'t do this without a good reason, and don\'t do it without a backup.' );
		print_input_row('Enter the number of records to process in a step. (\'/\')', 'perpage', 50000);
		print_submit_row('Submit', '');
	}
	else
	{
		//First get the parameters.
		$params = vB::getCleaner()->cleanArray($_REQUEST, array('perpage' => vB_Cleaner::TYPE_UINT,
			'startat' => vB_Cleaner::TYPE_UINT, 'step' => vB_Cleaner::TYPE_UINT ));

		if (empty($params['perpage']) OR !is_numeric($params['perpage']))
		{
			$params['perpage'] = 50000;
		}

		if (empty($params['startat']) OR !is_numeric($params['startat']))
		{
			$params['startat'] = 1;
		}

		if (!isset($params['step']))
		{
			$params['step'] = 0;
		}
		//First step is content-type by contenttype.  So we need to get the types available.
		//Last step is scannning the closure table.

		$assertor = vB::getDbAssertor();
		$contentTypes = $assertor->getRows('vBAdmincp:getContentTypes', array());
		$maxId = $assertor->getRow('vBAdmincp:getMaxId', array());
		$maxId = $maxId['maxid'];

		if ($params['step'] == count($contentTypes))
		{
			echo sprintf('Scanning %s nodes %u through %u for invalid records.', 'closure', $params['startat'],
				$params['startat'] + $params['perpage'])."<br />\n";

			//scanning closure table
			$missing1 = $assertor->getColumn('vBAdmincp:getMissingClosureParents', 'nodeid', array('start' => $params['startat'],
				'end' => $params['startat'] + $params['perpage']));
			$missing2 = $assertor->getColumn('vBAdmincp:getMissingClosureSelf', 'nodeid', array('start' => $params['startat'],
				'end' => $params['startat'] + $params['perpage']));

			if (!empty($missing1) OR !empty($missing2))
			{
				$missing = array_merge($missing1, $missing2);
				$assertor->assertQuery('vBAdmincp:insertMissingClosureSelf', array('nodeid' => $missing));
				$assertor->assertQuery('vBAdmincp:insertMissingClosureParent', array('nodeid' => $missing));
			}
			$params['startat'] += $params['perpage'];
		}
		else if ($params['step'] > count($contentTypes))
		{
			print_stop_message2('completed_content_table_scan', 'tools');
		}
		else
		{
			//We can skip ahead to the next record of this content type, and save some steps
			$contenttypeid = $contentTypes[$params['step']]['contenttypeid'];
			$contentLib = vB_Library_Content::getContentLib($contenttypeid);
			while ($contentLib->getCannotDelete())
			{
				$params['step']++;

				if ($params['step'] >= count($contentTypes))
				{
					break;
				}
				$contenttypeid = $contentTypes[$params['step']]['contenttypeid'];
				$contentLib = vB_Library_Content::getContentLib($contenttypeid);
				$params['startat'] = 1;
			}

			if ($params['step'] < count($contentTypes))
			{
				$nextIdQry = $assertor->assertQuery('vBAdmincp:getNextNode', array('start' => $params['startat'],
					'contenttypeid' => $contenttypeid));

				if ($nextIdQry->valid() AND ($nextId = $nextIdQry->current()) AND (!empty($nextId['nextid'])))
				{
					$nextId = $nextId['nextid'];

					echo sprintf('Scanning %s nodes %u through %u for invalid records.',
							vB_Types::instance()->getContentTypeClass($contenttypeid),
							$nextId, $nextId + $params['perpage'])."<br />\n";
					vbflush();

					$damaged = $assertor->assertQuery('vBAdmincp:getDamagedNodes', array('start' => $nextId,
						'end' => $nextId + $params['perpage'],'contenttypeid' => $contenttypeid));

					//If we found anything, time to fix it.
					if ($damaged->valid())
					{
						$contentLib->setDoIncompleteNodeCleanup(true);
						foreach($damaged AS $node)
						{
							if (!empty($node['nodeid']))
							{
								echo sprintf('Found defective node %u- fixing now.', $node['nodeid'])."<br />\n";
								vbflush();
								//The next line forces a call to checkContent and incompleteNodeCleanup
								// because doIncompleteNodeCleanup has been turned on
								$node = $contentLib->getFullContent($node['nodeid']);
							}
						}
						$contentLib->setDoIncompleteNodeCleanup(false);
					}
					$params['startat'] = $nextId + $params['perpage'];
				}
				else
				{
					//we're done with this type
					$params['startat'] = $maxId + 1;
				}
			}
		}

		if ($params['startat'] > $maxId)
		{
			$params['step']++;
			$params['startat'] = 1;

			if ($params['step'] > count($contentTypes))
			{
				print_stop_message2('completed_content_table_scan', 'tools');
			}
		}
		$params['do'] = 'scancontent';
		$connector = '?';
		$redirect = THIS_SCRIPT;
		foreach($params AS $param => $value)
		{
			$redirect .= $connector . $param . '=' . $value;
			 $connector = '&';
		}
		print_cp_redirect_old($redirect, 2);
	}
}
// #############################################################################
else if ($_REQUEST['do'] == 'pages')
{
	$vbulletin->input->clean_array_gpc('p', array(
		'action'   => vB_Cleaner::TYPE_STR,
		'pageguid' => vB_Cleaner::TYPE_ARRAY_STR,
	));

	$xmldir = str_replace('\\', '/', DIR) . (empty($vb5_config['Misc']['debug']) ? '/includes/xml' : '/install');

	$pageRestore = new vB_Utility_PageRestore($xmldir);

	if ($vbulletin->GPC['action'] == 'confirm' AND !empty($vbulletin->GPC['pageguid']))
	{
		?>
		<style>
		.alt1 {
			border-bottom: 1px solid #AAA;
		}
		</style>
		<?php
		$cols = 5;
		print_form_header(substr(THIS_SCRIPT, 0, -4), 'pages',false, true, 'cpform', '100%', '', true, 'post', 0, false, '', false, array('skipAdmincp' => true));
		construct_hidden_code('action', 'revert');
		print_table_header('Revert pages to their default settings', $cols);
		print_description_row('<br />The following page(s) will be reverted. <b>This cannot be undone. Ensure you have a database backup before proceeding.</b><br /><br />', false, $cols);
		print_cells_row(array('', 'Title', 'URL', 'PageTemplate', 'Page GUID'), true);

		$xmlpages = $pageRestore->getPagesFromXml();

		foreach ($vbulletin->GPC['pageguid'] AS $pageguid)
		{
			$xmlpage = $xmlpages[$pageguid];
			$xmlroute = $pageRestore->getXmlRouteByPageGuid($xmlpage['guid']);
			$xmlpagetemplate = $pageRestore->getXmlPageTemplateByPageGuid($xmlpage['guid']);
			$dbpage = $pageRestore->getMatchingPageFromDbByXmlGuid($xmlpage['guid']);
			$dbroute = $pageRestore->getDbRouteByRouteId($dbpage['routeid']);
			$dbpagetemplate = $pageRestore->getDbPageTemplateByPageTemplateId($dbpage['pagetemplateid']);

			print_cells_row(array(
				'<b>Current:</b>',
				$pageRestore->getPageTitleByGuid($dbpage['guid']),
				'<code>&lt;site&gt;/' . $dbroute['prefix'] . '</code>',
				$dbpagetemplate['title'],
				$dbpage['guid'],
			));

			print_cells_row(array(
				'<b>Default:</b>',
				$xmlpage['title'],
				'<code>&lt;site&gt;/' . $xmlroute['prefix'] . '</code>',
				$xmlpagetemplate['title'],
				$xmlpage['guid'],
			), false);

			// can't use construct_hidden_code(), since the name will overwrite
			// a previous element with the same name
			echo "<input type=\"hidden\" name=\"pageguid[]\" value=\"$pageguid\" />\n";
		}

		print_submit_row('Permanently Revert These Pages', '', $cols, 'Cancel');

	}
	else if ($vbulletin->GPC['action'] == 'revert' AND !empty($vbulletin->GPC['pageguid']))
	{
		set_time_limit(60 * 3);
		echo '<div><b>Restoring pages...</b></div>';
		echo '<ul>';
		foreach ($vbulletin->GPC['pageguid'] AS $pageguid)
		{
			echo '<li>';
			$pageRestore->restorePage($pageguid, true);
			echo '</li>';
			vbflush();
		}
		echo '</ul>';
		echo '<div><b>Done.</b></div>';
		define('SCRIPT_REDIRECT', true);

	}
	else // select pages to revert
	{
		$cols = 5;
		print_form_header(substr(THIS_SCRIPT, 0, -4), 'pages',false, true, 'cpform', '100%', '', true, 'post', 0, false, '', false, array('skipAdmincp' => true));
		construct_hidden_code('action', 'confirm');
		print_table_header('Revert pages to their default settings', $cols);
		print_description_row('Select one or more pages to revert to default vBulletin settings. <br /><br /><div class="warning"><b>WARNING</b>: This will this will completely revert the selected pages, including page, route, page template, and module information. Remember that the page template may be in use by another page. This will remove all customizations for the page(s) and cannot be reversed. <b>Please ensure you have a database backup before proceeding</b>.</div><br />Pages will be restored to their default configuration from the XML files. Reading files from: <code>' . htmlspecialchars($xmldir) . '</code><br /><ul><li>' . implode('</li><li>', $pageRestore->getFileVersions()) . '</li></ul>', false, $cols);
		print_cells_row(array('Title', 'URL', 'PageTemplate', 'Page GUID', '<label><input type="checkbox" name="selectall" id="selectall" /> Select All</label>'), true);

		$xmlpages = $pageRestore->getPagesFromXml();
		foreach ($xmlpages AS $guid => $xmlpage)
		{
			$xmlroute = $pageRestore->getXmlRouteByPageGuid($xmlpage['guid']);
			$xmlpagetemplate = $pageRestore->getXmlPageTemplateByPageGuid($xmlpage['guid']);

			print_cells_row(array(
				$xmlpage['title'],
				'<code>&lt;site&gt;/' . $xmlroute['prefix'] . '</code>',
				$xmlpagetemplate['title'],
				$xmlpage['guid'],
				'<label><input type="checkbox" class="guidcheckbox" name="pageguid[]" value="' . $xmlpage['guid'] . '" /> Revert</label>',
			));
		}

		print_submit_row('Revert Selected Pages', '', $cols);

		?>
		<script>
		(function()
		{
			var selall = document.getElementById('selectall');
			selall.onchange = function()
			{
				var i, boxes = document.querySelectorAll('.guidcheckbox');
				for (i in boxes)
				{
					boxes[i].checked = this.checked;
				}
			};

		})();
		</script>
		<?php

	}

}

// #############################################################################
else if ($_REQUEST['do'] == 'routefix')
{
	echo '<h3>Check and Repair Route/Node Capability</h3>';

	$routeFixer = vB_Library::instance('RouteFix');
	set_time_limit (300);
	$messages = $routeFixer->fixRoutes();
	print_table_start();
	print_table_header('Route Updates and Issues', 2);

	foreach ($messages AS $message)
	{
		print_cells_row($message);
	}
	print_table_footer(2, '', '', false);
	define('SCRIPT_REDIRECT', true);
}
else if ($_REQUEST['do'] == 'fixpolls')
{
	$vbulletin->input->clean_array_gpc('r', array(
		'startat' => vB_Cleaner::TYPE_UINT,
	));


	$startat = $vbulletin->GPC['startat'];

	$assertor = vB::getDbAssertor();
	$set = $assertor->assertQuery('vBForum:poll',
		array(
			vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT,
			vB_dB_Query::CONDITIONS_KEY => array(
				array('field' => 'nodeid', 'value' => $startat, 'operator' =>  vB_dB_Query::OPERATOR_GT)
			),
			vB_dB_Query::PARAM_LIMIT => 500,
			vB_dB_Query::COLUMNS_KEY => array('nodeid'),
		)
	);

	$nextstart = $startat;
	$library = vB_Library::instance('content_poll');
	foreach($set AS $row)
	{
		$nextstart = $row['nodeid'];
		$library->updatePollCache($row['nodeid']);
	}

	if ($nextstart == $startat)
	{
		define('SCRIPT_REDIRECT', true);
	}
	else
	{
		// more polls to update
		print_cp_redirect2('tools', array(
			'do' => 'fixpolls',
			'startat' => $nextstart
		));
	}
}

// END OF ACTIONS #############################################################################

if (defined('SCRIPT_REDIRECT'))
{
	$vbphrase['redirecting'] = empty($vbphrase['redirecting']) ? 'Redirecting' : $vbphrase['redirecting'];
	echo '<p align="center" class="smallfont"><a href="./tools.php" onclick="javascript:clearTimeout(timerID);">' . $vbphrase['processing_complete_proceed'] . '</a></p>';
	echo '<p align="center">' . $vbphrase['redirecting'] . '... (<b id="countdown"></b>) <a href="#" onclick="javascript:clearTimeout(timerID);return false;">Stop Redirect</a></p>';
	echo "\n<script type=\"text/javascript\">\n";
	echo "myvar = \"\";
	timeout = " . (5) . ";
	function exec_refresh()
	{
		document.getElementById('countdown').innerHTML = timeout;
		window.status=\"" . $vbphrase['redirecting'] . "\" + myvar;
		myvar = myvar + \" .\";
		timerID = setTimeout(\"exec_refresh();\", 1000);
		if (timeout > 0)
		{
			timeout -= 1;
		}
		else
		{
			clearTimeout(timerID);
			window.status=\"\";
			window.location=\"tools.php\";
		}
	}
	exec_refresh();";
	echo "\n</script>\n";
}

?>
<!-- START CONTROL PANEL FOOTER -->
<p align="center" class="smallfont">vBulletin <?php echo VERSION; ?>, Copyright &copy;2000-<?php echo date('Y'); ?>, MH Sub I, LLC dba vBulletin.</p>

</div> <!-- acp-content-wrapper -->
</body>
</html>
<?php




//########### Helper Functions #######################

function tools_update_setting($db, $option, $value)
{
	$db->query_write("
		UPDATE " . TABLE_PREFIX . "setting
		SET value = '" . $db->escape_string($value) . "'
		WHERE varname = '" . $db->escape_string($option) . "'
	");
	vB::getDatastore()->build_options();
}

function getXmlVersion($file, $read, $regex)
{
	// Get versions of .xml files for header diagnostics
	if ($fp = @fopen('./install/' . $file, 'rb'))
	{
		$data = fread($fp, $read);
		if (preg_match($regex, $data, $matches))
		{
			$version = $matches[1];
		}
		else
		{
			$version = 'Unknown';
		}
		fclose($fp);
	}
	else
	{
		$version = 'N/A';
	}

	return $version;
}

function tools_print_block($header, $actions)
{
	print_table_header($header);
	print_column_style_code(array('width:30%'));

	foreach ($actions AS $name => $action)
	{
		$label = $name;

		//if we don't have a "do" then this is informational and doesn't actually have a link
		if(isset($action['do']))
		{
			$url = THIS_SCRIPT . '?do=' . $action['do'];
			if(isset($action['type']))
			{
				$url .= '&type=' . $action['type'];
			}

			$label = construct_link_code($label, htmlspecialchars($url), false, '', false, false);
		}

		print_label_row($label, $action['description']);
	}
}


/*======================================================================*\
|| ####################################################################
|| # NulleD By - prowebber.ru
|| # CVS: $RCSfile$ - $Revision: 100289 $
|| ####################################################################
\*======================================================================*/
