<?php
/*========================================================================*\
|| ###################################################################### ||
|| # vBulletin 6.2.3 - Licence Number L3138846
|| # ------------------------------------------------------------------ # ||
|| # Copyright 2000-2026 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   # ||
|| ###################################################################### ||
\*========================================================================*/

// ######################## SET PHP ENVIRONMENT ###########################

// ##################### DEFINE IMPORTANT CONSTANTS #######################
define('CVS_REVISION', '$RCSfile$ - $Revision: 122851 $');

// #################### PRE-CACHE TEMPLATES AND DATA ######################
global $phrasegroups, $specialtemplates, $vbphrase, $vbulletin;
$phrasegroups = ['cpuser', 'cpoption'];
$specialtemplates = [];

// ########################## REQUIRE BACK-END ############################
require_once(dirname(__FILE__) . '/global.php');
require_once(DIR . '/includes/adminfunctions_options.php');

// ######################## CHECK ADMIN PERMISSIONS #######################
if (!can_administer('canadminsettings'))
{
	print_cp_no_permission();
}

// ############################# LOG ACTION ###############################
$vbulletin->input->clean_array_gpc('r', [
	'questionid' => vB_Cleaner::TYPE_UINT,
	'answerid'   => vB_Cleaner::TYPE_UINT,
]);
log_admin_action(!empty($vbulletin->GPC['questionid']) ? 'question id = ' . $vbulletin->GPC['questionid'] : '');

// ########################################################################
// ######################### START MAIN SCRIPT ############################
// ########################################################################

print_cp_header($vbphrase['human_verification_manager_gcpuser'], [
	get_admincp_script_tag('vbulletin_hv.js'),
]);

if (empty($_REQUEST['do']))
{
	$_REQUEST['do'] = 'intro';
}

// ###################### Intro Screen #######################
if ($_REQUEST['do'] == 'intro')
{
	// we should probably split up the options so that we only load the ones we'll use for the current type
	$globalsettings = [
		'hv_type',
		'hvcheck',
	];

	$type_map = [
		'Disabled' => [
			'typesettings' => [],
		],
		'Image' => [
			'phrase' => 'image_verification_options',
			'typesettings' => [
				'regimagetype',
				'regimageoption',
			],
		],
		'Question' => [
			'phrase' => 'question_verification_options',
			'typesettings' => [],
			'extra' => question_display(...),
		],
		'Recaptcha2' => [
			'phrase' => 'recaptcha_verification_options',
			'typesettings' => [
				'hv_recaptcha_publickey',
				'hv_recaptcha_privatekey',
				'hv_recaptcha2_theme',
			],
		],
		'Recaptcha3' => [
			'phrase' => 'recaptcha_verification_options',
			'typesettings' => [
				'hv_recaptcha3_publickey',
				'hv_recaptcha3_privatekey',
				'hv_recaptcha3_threshold_post',
				'hv_recaptcha3_threshold_contactus',
				'hv_recaptcha3_threshold_lostpw',
				'hv_recaptcha3_threshold_register',
			],
		],
		'Turnstile' => [
			'phrase' => 'turnstile_verification_options',
			'typesettings' => [
				'hv_turnstile_sitekey',
				'hv_turnstile_secretkey',
			],
		],
	];

	$type = vB::getDatastore()->getOption('hv_type');
	$typedata = $type_map[$type] ?? $type_map['Disabled'];

	$settingnames = array_merge($globalsettings, $typedata['typesettings']);

	$settingphrase = get_setting_phrases($settingnames);
	$settingrecords = get_settings_list($settingnames);

	// There has to be a better way to do this.
	$columnStyles = ['width:60%', 'width:40%; white-space:nowrap'];

	$globalrecords = get_allowed_settings($globalsettings, $settingrecords);
	if ($globalrecords)
	{
		print_form_header2('admincp/verify', 'updateoptions');
		print_table_start2();
		print_column_style_code($columnStyles);

		print_table_header($vbphrase['human_verification_options']);
		foreach ($globalrecords AS $record)
		{
			print_setting_row($record, $settingphrase);
		}
		print_table_default_footer($vbphrase['save']);
	}

	if ($typedata['typesettings'])
	{
		print_form_header2('admincp/verify', 'updateoptions');
		print_table_start2();
		print_column_style_code($columnStyles);
		print_table_header($vbphrase[$typedata['phrase']]);

		$typerecords = get_allowed_settings($typedata['typesettings'], $settingrecords);
		foreach ($typerecords AS $record)
		{
			print_setting_row($record, $settingphrase);
		}

		print_table_default_footer($vbphrase['save']);
	}

	if (isset($typedata['extra']))
	{
		$typedata['extra']($vbphrase);
	}
}

function question_display($vbphrase)
{
	$questions = vB::getDbAssertor()->getRows('vBForum:fetchQuestions', []);

	$headers = [
		$vbphrase['question'],
		$vbphrase['answers'],
		$vbphrase['regex'],
		$vbphrase['date'],
		$vbphrase['controls']
	];

	$cols = count($headers);

	print_form_header2('admincp/verify', 'modifyquestion');
	print_table_start2();
	print_table_header($vbphrase['question_verification_options'], $cols);

	if (count($questions))
	{
		print_cells_row2($headers, 'thead', 'center');
	}
	else
	{
		print_description_row($vbphrase['not_specified_questions_no_validation'], false, $cols);
	}

	$options = [
		'modifyquestion' => $vbphrase['edit'],
		'killquestion'   => $vbphrase['delete'],
	];

	$logdateformat = vB::getDatastore()->getOption('logdateformat');
	foreach ($questions AS $question)
	{
		$cells = [
			$question['text'],
			$question['answerid'] ? $question['answers'] : 0,
			$question['regex'] ? $vbphrase['yes'] : $vbphrase['no'],
			vbdate($logdateformat, $question['dateline']),
			construct_jump_control('que', $question['questionid'], $vbphrase['go'], $options),
		];
		print_cells_row2($cells, '', 'center');
	}
	print_table_default_footer($vbphrase['add_new_question'], $cols);
}

// ###################### Edit/Add Question #######################
if ($_REQUEST['do'] == 'modifyquestion')
{
	$assertor = vB::getDbAssertor();
	print_form_header2('admincp/verify', 'updatequestion');
	print_table_start2();

	if (empty($vbulletin->GPC['questionid']))
	{
		print_table_header($vbphrase['add_new_question']);
		$question = [
			'text' => '',
			'regex' => '',
		];

		$text_label = $vbphrase['question_dfn'];
	}
	else
	{
		$question = $assertor->getRow('vBForum:fetchQuestionById', ['questionid' => $vbulletin->GPC['questionid']]);
		if (!$question)
		{
			print_stop_message(['invalid_x_specified', $vbphrase['question']]);
		}

		print_table_header(construct_phrase($vbphrase['x_y_id_z'], $vbphrase['question'], htmlspecialchars_uni($question['text']), $vbulletin->GPC['questionid']), 2, 0);
		// The JS for the jump controls below will depend on this being set.  This is a hack to get around some limitations of the jump control feature.
		// It's not a problem unless we try to seperate the answer UI to a separate page or similar.
		construct_hidden_code('questionid', $vbulletin->GPC['questionid']);

		$text_label = $vbphrase['question_dfn'] . '<dfn>' . construct_translation_link($vbphrase['translations'], 'hvquestion', 'question' . $vbulletin->GPC['questionid']) . '</dfn>';
	}

	print_input_row($text_label, 'question', $question['text']);
	print_input_row($vbphrase['regular_expression_require_match_gcpuser'], 'regex', $question['regex']);
	print_table_default_footer($vbphrase['save']);

	if (!empty($vbulletin->GPC['questionid']))
	{
		$answers = vB::getDbAssertor()->assertQuery('vBForum:hvanswer',
			[
				'questionid' => $vbulletin->GPC['questionid']
			],
			['field' => 'dateline', 'direction' => vB_dB_Query::SORT_ASC]
		);
		print_form_header2('admincp/verify', 'modifyanswer');
		print_table_start2();
		print_table_header($vbphrase['answers'], 2);
		construct_hidden_code('questionid', $vbulletin->GPC['questionid']);

		$colalign = ['left', 'center'];
		if ($answers AND $answers->valid())
		{
			print_cells_row2([$vbphrase['answer'], $vbphrase['controls']], 'thead', $colalign);
		}

		$options = [
			'modifyanswer' => $vbphrase['edit'],
			'killanswer'   => $vbphrase['delete'],
		];

		foreach ($answers AS $answer)
		{
			print_cells_row2([
				$answer['answer'],
				construct_jump_control('ans', $answer['answerid'],  $vbphrase['go'], $options),
			], '', $colalign);
		}
		print_table_default_footer($vbphrase['add_new_answer']);
	}
}

// ###################### Save Question #######################
if ($_POST['do'] == 'updatequestion')
{
	$vbulletin->input->clean_array_gpc('p', [
		'question' => vB_Cleaner::TYPE_STR,
		'regex'    => vB_Cleaner::TYPE_STR,
	]);
	if (empty($vbulletin->GPC['question']))
	{
		print_stop_message('please_complete_required_fields');
	}

	if (empty($vbulletin->GPC['questionid']))
	{
		$questionid = vB::getDbAssertor()->assertQuery('vBForum:hvquestion', [
			vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT,
			'regex' => $vbulletin->GPC['regex'],
			'dateline' => TIMENOW
		]);
	}
	else
	{
		$questionid = $vbulletin->GPC['questionid'];
		$updateQuestion = vB::getDbAssertor()->assertQuery('vBForum:hvquestion', [
			vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_UPDATE,
			'regex' => $vbulletin->GPC['regex'],
			vB_dB_Query::CONDITIONS_KEY => [
				'questionid' => $vbulletin->GPC['questionid']
			]
		]);
	}

	/*insert_query*/
	$updatePhrase = vB::getDbAssertor()->assertQuery('replaceIntoPhrases',	[
		'text' => $vbulletin->GPC['question'],
		'fieldname' => 'hvquestion',
		'languageid' => 0,
		'varname' => "question" . $questionid,
		'product' => 'vbulletin',
		'enteredBy' => $vbulletin->userinfo['username'],
		'dateline' => TIMENOW,
		'version' => $vbulletin->options['templateversion'],
	]);

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

	print_stop_message('updated_question_successfully', get_admincp_url('verify', ['do' => 'modifyquestion', 'questionid' => $questionid]));
}

// ###################### Edit/Add Answer #######################
if ($_REQUEST['do'] == 'modifyanswer')
{
	print_form_header2('admincp/verify', 'updateanswer');
	print_table_start2();
	$question = vB::getDbAssertor()->getRow('vBForum:fetchQuestionByAnswer', ['questionid' => $vbulletin->GPC['questionid']]);

	if (!$question)
	{
		print_stop_message(['invalid_x_specified', $vbphrase['question']]);
	}

	print_table_header(construct_phrase($vbphrase['x_y_id_z'], $vbphrase['question'], htmlspecialchars_uni($question['text']), $question['questionid']), 2, 0);

	if (empty($vbulletin->GPC['answerid']))
	{
		$answer = [
			'answer' => '',
		];

		print_table_header($vbphrase['add_new_answer']);
		construct_hidden_code('questionid', $vbulletin->GPC['questionid']);
	}
	else
	{
		$answer = vB::getDbAssertor()->getRow('vBForum:hvanswer',	['answerid' => $vbulletin->GPC['answerid']]);
		construct_hidden_code('answerid', $answer['answerid']);
		construct_hidden_code('questionid', $answer['questionid']);
	}

	print_input_row($vbphrase['answer'], 'answer', $answer['answer']);
	print_submit_row($vbphrase['save']);
}

// ###################### Save Question #######################
if ($_POST['do'] == 'updateanswer')
{
	$vbulletin->input->clean_array_gpc('p', [
		'answer' => vB_Cleaner::TYPE_STR,
	]);
	if ($vbulletin->GPC['answer'] === '')
	{
		print_stop_message('please_complete_required_fields');
	}

	$question = vB::getDbAssertor()->getRow('vBForum:hvquestion', ['questionid' => $vbulletin->GPC['questionid']]);
	if (!$question)
	{
		print_stop_message(['invalid_x_specified', $vbphrase['question']]);
	}

	if (empty($vbulletin->GPC['answerid']))
	{
		$insertAnswer = vB::getDbAssertor()->assertQuery('vBForum:hvanswer', [
			vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_INSERT,
			'questionid' => $vbulletin->GPC['questionid'],
			'answer' => $vbulletin->GPC['answer'],
			'dateline' => TIMENOW
		]);
		$vbulletin->GPC['answerid'] = $db->insert_id();
	}
	else
	{
		$updateAnswer = vB::getDbAssertor()->assertQuery('vBForum:hvanswer', [
			vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_UPDATE,
			'answer' => $vbulletin->GPC['answer'],
			vB_dB_Query::CONDITIONS_KEY => [
				'answerid' => $vbulletin->GPC['answerid']
			]
		]);
	}

	print_stop_message('updated_answer_successfully', get_admincp_url('verify', ['do' => 'modifyquestion', 'questionid' => $vbulletin->GPC['questionid']]));
}

// ###################### Remove Answer #######################
if ($_REQUEST['do'] == 'removeanswer')
{
	$answer = vB::getDbAssertor()->getRow('vBForum:hvanswer',	['answerid' => $vbulletin->GPC['answerid']]);

	if (!$answer)
	{
		print_stop_message(['invalid_x_specified', $vbphrase['answer']]);
	}

	print_form_header2('admincp/verify', 'killanswer');
	print_table_start2();
	construct_hidden_code('answerid', $answer['answerid']);
	print_table_header(construct_phrase($vbphrase['confirm_deletion_x'], htmlspecialchars_uni($answer['answer'])));
	print_description_row($vbphrase['are_you_sure_you_want_to_delete_this_answer']);
	print_submit_row($vbphrase['yes'], '', 2, $vbphrase['no']);
}

// ###################### Kill Answer #######################
if ($_POST['do'] == 'killanswer')
{
	$answer = vB::getDbAssertor()->getRow('vBForum:hvanswer', ['answerid' => $vbulletin->GPC['answerid']]);

	if (!$answer)
	{
		print_stop_message(['invalid_x_specified', $vbphrase['answer']]);
	}

	$deleteAnswer = vB::getDbAssertor()->assertQuery('vBForum:hvanswer', [
		vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_DELETE,
		'answerid' => $answer['answerid']
	]);

	print_stop_message('deleted_answer_successfully', get_admincp_url('verify', ['do' => 'modifyquestion', 'questionid' => $answer['questionid']]));
}

// ###################### Remove Question #######################
if ($_REQUEST['do'] == 'removequestion')
{
	$question = vB::getDbAssertor()->getRow('vBForum:fetchQuestionByPhrase', ['questionid' => $vbulletin->GPC['questionid']]);

	if (!$question)
	{
		print_stop_message(['invalid_x_specified', $vbphrase['question']]);
	}

	print_form_header2('admincp/verify', 'killquestion');
	print_table_start2();
	construct_hidden_code('questionid', $question['questionid']);
	print_table_header(construct_phrase($vbphrase['confirm_deletion_x'], htmlspecialchars_uni($question['text'])));
	print_description_row($vbphrase['are_you_sure_you_want_to_delete_this_question']);
	print_submit_row($vbphrase['yes'], '', 2, $vbphrase['no']);
}

// ###################### Kill Answer #######################
if ($_POST['do'] == 'killquestion')
{
	$question = vB::getDbAssertor()->getRow('vBForum:fetchQuestionByPhrase', ['questionid' => $vbulletin->GPC['questionid']]);

	if (!$question)
	{
		print_stop_message(['invalid_x_specified', $vbphrase['question']]);
	}

	$deleteAnswer = vB::getDbAssertor()->assertQuery('vBForum:hvanswer',
		[vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_DELETE, 'questionid' => $question['questionid']]
	);

	$deleteQuestion = vB::getDbAssertor()->assertQuery('vBForum:hvquestion',
		[vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_DELETE, 'questionid' => $question['questionid']]
	);

	$deletePhrase = vB::getDbAssertor()->assertQuery('vBForum:phrase', [
		vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_DELETE,
		'fieldname' => 'hvquestion',
		'varname' => 'question' . $question['questionid']
	]);

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

	print_stop_message('deleted_question_successfully', get_admincp_url('verify', []));
}

// ###################### Intro Screen #######################
if ($_POST['do'] == 'updateoptions')
{
	$vbulletin->input->clean_array_gpc('p', [
		'setting'  => vB_Cleaner::TYPE_ARRAY,
	]);

	save_settings($vbulletin->GPC['setting']);
	print_stop_message('saved_settings_successfully', get_admincp_url('verify', []));
}

print_cp_footer();

/*=========================================================================*\
|| #######################################################################
|| # Downloaded: 13:27, Sun Aug 30th 2026
|| # CVS: $RCSfile$ - $Revision: 122851 $
|| #######################################################################
\*=========================================================================*/
