page.php 27 KB
Newer Older
Scott committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

	File: qa-include/qa-page.php
	Description: Routing and utility functions for page requests


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

23 24 25 26 27 28 29 30 31 32 33 34 35 36
if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
	header('Location: ../');
	exit;
}

require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
require_once QA_INCLUDE_DIR . 'app/options.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';


/**
 * Standard database failure handler function which bring up the install/repair/upgrade page
Scott committed
37 38 39 40 41
 * @param $type
 * @param int $errno
 * @param string $error
 * @param string $query
 * @return mixed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
 */
function qa_page_db_fail_handler($type, $errno = null, $error = null, $query = null)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	$pass_failure_type = $type;
	$pass_failure_errno = $errno;
	$pass_failure_error = $error;
	$pass_failure_query = $query;

	require_once QA_INCLUDE_DIR . 'qa-install.php';

	qa_exit('error');
}


/**
 * Queue any pending requests which are required independent of which page will be shown
 */
function qa_page_queue_pending()
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	qa_preload_options();
	$loginuserid = qa_get_logged_in_userid();

	if (isset($loginuserid)) {
		if (!QA_FINAL_EXTERNAL_USERS)
			qa_db_queue_pending_select('loggedinuser', qa_db_user_account_selectspec($loginuserid, true));

		qa_db_queue_pending_select('notices', qa_db_user_notices_selectspec($loginuserid));
		qa_db_queue_pending_select('favoritenonqs', qa_db_user_favorite_non_qs_selectspec($loginuserid));
		qa_db_queue_pending_select('userlimits', qa_db_user_limits_selectspec($loginuserid));
		qa_db_queue_pending_select('userlevels', qa_db_user_levels_selectspec($loginuserid, true));
Scott committed
76 77
	}

78 79 80 81
	qa_db_queue_pending_select('iplimits', qa_db_ip_limits_selectspec(qa_remote_ip_address()));
	qa_db_queue_pending_select('navpages', qa_db_pages_selectspec(array('B', 'M', 'O', 'F')));
	qa_db_queue_pending_select('widgets', qa_db_widgets_selectspec());
}
Scott committed
82 83


84 85 86 87 88 89
/**
 * Check the page state parameter and then remove it from the $_GET array
 */
function qa_load_state()
{
	global $qa_state;
Scott committed
90

91 92 93
	$qa_state = qa_get('state');
	unset($_GET['state']); // to prevent being passed through on forms
}
Scott committed
94 95


96 97 98 99 100 101 102
/**
 * If no user is logged in, call through to the login modules to see if they want to log someone in
 */
function qa_check_login_modules()
{
	if (!QA_FINAL_EXTERNAL_USERS && !qa_is_logged_in()) {
		$loginmodules = qa_load_modules_with('login', 'check_login');
Scott committed
103

104 105 106 107
		foreach ($loginmodules as $loginmodule) {
			$loginmodule->check_login();
			if (qa_is_logged_in()) // stop and reload page if it worked
				qa_redirect(qa_request(), $_GET);
Scott committed
108 109
		}
	}
110
}
Scott committed
111 112


113 114 115 116 117 118 119
/**
 * React to any of the common buttons on a page for voting, favorites and closing a notice
 * If the user has Javascript on, these should come through Ajax rather than here.
 */
function qa_check_page_clicks()
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
120

121
	global $qa_page_error_html;
Scott committed
122

123 124 125 126
	if (qa_is_http_post()) {
		foreach ($_POST as $field => $value) {
			if (strpos($field, 'vote_') === 0) { // voting...
				@list($dummy, $postid, $vote, $anchor) = explode('_', $field);
Scott committed
127

128 129 130
				if (isset($postid) && isset($vote)) {
					if (!qa_check_form_security_code('vote', qa_post_text('code')))
						$qa_page_error_html = qa_lang_html('misc/form_security_again');
Scott committed
131

132 133 134
					else {
						require_once QA_INCLUDE_DIR . 'app/votes.php';
						require_once QA_INCLUDE_DIR . 'db/selects.php';
Scott committed
135

136
						$userid = qa_get_logged_in_userid();
Scott committed
137

138 139
						$post = qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $postid));
						$qa_page_error_html = qa_vote_error_html($post, $vote, $userid, qa_request());
Scott committed
140

141 142 143
						if (!$qa_page_error_html) {
							qa_vote_set($post, $userid, qa_get_logged_in_handle(), qa_cookie_get(), $vote);
							qa_redirect(qa_request(), $_GET, null, null, $anchor);
Scott committed
144
						}
145
						break;
Scott committed
146
					}
147
				}
Scott committed
148

149 150
			} elseif (strpos($field, 'favorite_') === 0) { // favorites...
				@list($dummy, $entitytype, $entityid, $favorite) = explode('_', $field);
Scott committed
151

152 153 154
				if (isset($entitytype) && isset($entityid) && isset($favorite)) {
					if (!qa_check_form_security_code('favorite-' . $entitytype . '-' . $entityid, qa_post_text('code')))
						$qa_page_error_html = qa_lang_html('misc/form_security_again');
Scott committed
155

156 157
					else {
						require_once QA_INCLUDE_DIR . 'app/favorites.php';
Scott committed
158

159 160
						qa_user_favorite_set(qa_get_logged_in_userid(), qa_get_logged_in_handle(), qa_cookie_get(), $entitytype, $entityid, $favorite);
						qa_redirect(qa_request(), $_GET);
Scott committed
161
					}
162
				}
Scott committed
163

164 165
			} elseif (strpos($field, 'notice_') === 0) { // notices...
				@list($dummy, $noticeid) = explode('_', $field);
Scott committed
166

167 168 169
				if (isset($noticeid)) {
					if (!qa_check_form_security_code('notice-' . $noticeid, qa_post_text('code')))
						$qa_page_error_html = qa_lang_html('misc/form_security_again');
Scott committed
170

171 172 173
					else {
						if ($noticeid == 'visitor')
							setcookie('qa_noticed', 1, time() + 86400 * 3650, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true);
Scott committed
174

175 176 177
						elseif ($noticeid == 'welcome') {
							require_once QA_INCLUDE_DIR . 'db/users.php';
							qa_db_user_set_flag(qa_get_logged_in_userid(), QA_USER_FLAGS_WELCOME_NOTICE, false);
Scott committed
178

179 180 181
						} else {
							require_once QA_INCLUDE_DIR . 'db/notices.php';
							qa_db_usernotice_delete(qa_get_logged_in_userid(), $noticeid);
Scott committed
182
						}
183 184

						qa_redirect(qa_request(), $_GET);
Scott committed
185 186 187
					}
				}
			}
188
		}
Scott committed
189
	}
190
}
Scott committed
191 192


193 194 195 196 197 198
/**
 *	Run the appropriate qa-page-*.php file for this request and return back the $qa_content it passed
 */
function qa_get_request_content()
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
199

200 201 202 203
	$requestlower = strtolower(qa_request());
	$requestparts = qa_request_parts();
	$firstlower = strtolower($requestparts[0]);
	$routing = qa_page_routing();
Scott committed
204

205 206 207
	if (isset($routing[$requestlower])) {
		qa_set_template($firstlower);
		$qa_content = require QA_INCLUDE_DIR . $routing[$requestlower];
Scott committed
208

209 210 211
	} elseif (isset($routing[$firstlower . '/'])) {
		qa_set_template($firstlower);
		$qa_content = require QA_INCLUDE_DIR . $routing[$firstlower . '/'];
Scott committed
212

213 214 215
	} elseif (is_numeric($requestparts[0])) {
		qa_set_template('question');
		$qa_content = require QA_INCLUDE_DIR . 'pages/question.php';
Scott committed
216

217 218 219 220
	} else {
		qa_set_template(strlen($firstlower) ? $firstlower : 'qa'); // will be changed later
		$qa_content = require QA_INCLUDE_DIR . 'pages/default.php'; // handles many other pages, including custom pages and page modules
	}
Scott committed
221

222 223 224 225
	if ($firstlower == 'admin') {
		$_COOKIE['qa_admin_last'] = $requestlower; // for navigation tab now...
		setcookie('qa_admin_last', $_COOKIE['qa_admin_last'], 0, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true); // ...and in future
	}
Scott committed
226

227 228
	if (isset($qa_content))
		qa_set_form_security_key();
Scott committed
229

230 231
	return $qa_content;
}
Scott committed
232 233


234
/**
Scott committed
235 236 237
 *    Output the $qa_content via the theme class after doing some pre-processing, mainly relating to Javascript
 * @param $qa_content
 * @return mixed
238 239 240 241
 */
function qa_output_content($qa_content)
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
Scott committed
242

243
	global $qa_template;
Scott committed
244

245
	$requestlower = strtolower(qa_request());
Scott committed
246

247
	// Set appropriate selected flags for navigation (not done in qa_content_prepare() since it also applies to sub-navigation)
Scott committed
248

249 250 251 252
	foreach ($qa_content['navigation'] as $navtype => $navigation) {
		if (!is_array($navigation) || $navtype == 'cat') {
			continue;
		}
Scott committed
253

254 255 256 257 258 259 260
		foreach ($navigation as $navprefix => $navlink) {
			$selected =& $qa_content['navigation'][$navtype][$navprefix]['selected'];
			if (isset($navlink['selected_on'])) {
				// match specified paths
				foreach ($navlink['selected_on'] as $path) {
					if (strpos($requestlower . '$', $path) === 0)
						$selected = true;
Scott committed
261
				}
262 263 264
			} elseif ($requestlower === $navprefix || $requestlower . '$' === $navprefix) {
				// exact match for array key
				$selected = true;
Scott committed
265 266
			}
		}
267
	}
Scott committed
268

269
	// Slide down notifications
Scott committed
270

271
	if (!empty($qa_content['notices'])) {
272 273 274 275
		foreach ($qa_content['notices'] as $notice) {
			$qa_content['script_onloads'][] = array(
				"qa_reveal(document.getElementById(" . qa_js($notice['id']) . "), 'notice');",
			);
Scott committed
276
		}
277
	}
Scott committed
278

279
	// Handle maintenance mode
Scott committed
280

281 282
	if (qa_opt('site_maintenance') && ($requestlower != 'login')) {
		if (qa_get_logged_in_level() >= QA_USER_LEVEL_ADMIN) {
283
			if (!isset($qa_content['error'])) {
284 285
				$qa_content['error'] = strtr(qa_lang_html('admin/maintenance_admin_only'), array(
					'^1' => '<a href="' . qa_path_html('admin/general') . '">',
Scott committed
286 287
					'^2' => '</a>',
				));
288
			}
289 290 291
		} else {
			$qa_content = qa_content_prepare();
			$qa_content['error'] = qa_lang_html('misc/site_in_maintenance');
Scott committed
292
		}
293
	}
Scott committed
294

295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
	// Handle new users who must confirm their email now, or must be approved before continuing

	$userid = qa_get_logged_in_userid();
	if (isset($userid) && $requestlower != 'confirm' && $requestlower != 'account') {
		$flags = qa_get_logged_in_flags();

		if (($flags & QA_USER_FLAGS_MUST_CONFIRM) && !($flags & QA_USER_FLAGS_EMAIL_CONFIRMED) && qa_opt('confirm_user_emails')) {
			$qa_content = qa_content_prepare();
			$qa_content['title'] = qa_lang_html('users/confirm_title');
			$qa_content['error'] = strtr(qa_lang_html('users/confirm_required'), array(
				'^1' => '<a href="' . qa_path_html('confirm') . '">',
				'^2' => '</a>',
			));

		} elseif (($flags & QA_USER_FLAGS_MUST_APPROVE) && qa_get_logged_in_level() < QA_USER_LEVEL_APPROVED && qa_opt('moderate_users')) {
			$qa_content = qa_content_prepare();
			$qa_content['title'] = qa_lang_html('users/approve_title');
			$qa_content['error'] = strtr(qa_lang_html('users/approve_required'), array(
				'^1' => '<a href="' . qa_path_html('account') . '">',
				'^2' => '</a>',
			));
Scott committed
316
		}
317
	}
Scott committed
318

319
	// Combine various Javascript elements in $qa_content into single array for theme layer
Scott committed
320

321
	$script = array('<script>');
Scott committed
322

323 324
	if (isset($qa_content['script_var'])) {
		foreach ($qa_content['script_var'] as $var => $value) {
325
			$script[] = 'var ' . $var . ' = ' . qa_js($value) . ';';
326 327
		}
	}
Scott committed
328

329
	if (isset($qa_content['script_lines'])) {
330 331 332
		foreach ($qa_content['script_lines'] as $scriptlines) {
			$script[] = '';
			$script = array_merge($script, $scriptlines);
Scott committed
333
		}
334
	}
Scott committed
335

336
	$script[] = '</script>';
Scott committed
337

338 339 340 341 342
	if (isset($qa_content['script_rel'])) {
		$uniquerel = array_unique($qa_content['script_rel']); // remove any duplicates
		foreach ($uniquerel as $script_rel)
			$script[] = '<script src="' . qa_html(qa_path_to_root() . $script_rel) . '"></script>';
	}
Scott committed
343

344 345 346 347 348
	if (isset($qa_content['script_src'])) {
		$uniquesrc = array_unique($qa_content['script_src']); // remove any duplicates
		foreach ($uniquesrc as $script_src)
			$script[] = '<script src="' . qa_html($script_src) . '"></script>';
	}
Scott committed
349

350 351 352 353
	if (isset($qa_content['focusid'])) {
		$qa_content['script_onloads'][] = array(
			'$(' . qa_js('#' . $qa_content['focusid']) . ').focus();',
		);
Scott committed
354 355
	}

356
	// JS onloads must come after jQuery is loaded
Scott committed
357

358 359 360 361 362 363 364
	$script[] = '<script>';
	if (isset($qa_content['script_onloads'])) {
		$script[] = '$(window).load(function() {';

		foreach ($qa_content['script_onloads'] as $scriptonload) {
			foreach ((array)$scriptonload as $scriptline)
				$script[] = "\t" . $scriptline;
Scott committed
365 366
		}

367
		$script[] = '});';
Scott committed
368
	}
369
	$script[] = '</script>';
Scott committed
370

371 372 373 374 375
	if (!isset($qa_content['script'])) {
		$qa_content['script'] = array();
	}

	$qa_content['script'] = array_merge($qa_content['script'], $script);
Scott committed
376

377
	// Load the appropriate theme class and output the page
Scott committed
378

379 380 381
	$tmpl = substr($qa_template, 0, 7) == 'custom-' ? 'custom' : $qa_template;
	$themeclass = qa_load_theme_class(qa_get_site_theme(), $tmpl, $qa_content, qa_request());
	$themeclass->initialize();
Scott committed
382

383
	header('Content-type: ' . $qa_content['content_type']);
Scott committed
384

385 386 387 388
	$themeclass->doctype();
	$themeclass->html();
	$themeclass->finish();
}
Scott committed
389 390


391 392
/**
 * Update any statistics required by the fields in $qa_content, and return true if something was done
Scott committed
393 394
 * @param $qa_content
 * @return bool
395 396 397 398 399 400 401 402
 */
function qa_do_content_stats($qa_content)
{
	if (isset($qa_content['inc_views_postid'])) {
		require_once QA_INCLUDE_DIR . 'db/hotness.php';
		qa_db_hotness_update($qa_content['inc_views_postid'], null, true);
		return true;
	}
Scott committed
403

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
	return false;
}


// Other functions which might be called from anywhere

/**
 * Return an array of the default Q2A requests and which qa-page-*.php file implements them
 * If the key of an element ends in /, it should be used for any request with that key as its prefix
 */
function qa_page_routing()
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	return array(
		'account' => 'pages/account.php',
		'activity/' => 'pages/activity.php',
		'admin/' => 'pages/admin/admin-default.php',
		'admin/approve' => 'pages/admin/admin-approve.php',
		'admin/categories' => 'pages/admin/admin-categories.php',
		'admin/flagged' => 'pages/admin/admin-flagged.php',
		'admin/hidden' => 'pages/admin/admin-hidden.php',
		'admin/layoutwidgets' => 'pages/admin/admin-widgets.php',
		'admin/moderate' => 'pages/admin/admin-moderate.php',
		'admin/pages' => 'pages/admin/admin-pages.php',
		'admin/plugins' => 'pages/admin/admin-plugins.php',
		'admin/points' => 'pages/admin/admin-points.php',
		'admin/recalc' => 'pages/admin/admin-recalc.php',
		'admin/stats' => 'pages/admin/admin-stats.php',
		'admin/userfields' => 'pages/admin/admin-userfields.php',
		'admin/usertitles' => 'pages/admin/admin-usertitles.php',
		'answers/' => 'pages/answers.php',
		'ask' => 'pages/ask.php',
		'categories/' => 'pages/categories.php',
		'comments/' => 'pages/comments.php',
		'confirm' => 'pages/confirm.php',
		'favorites' => 'pages/favorites.php',
		'favorites/questions' => 'pages/favorites-list.php',
		'favorites/users' => 'pages/favorites-list.php',
		'favorites/tags' => 'pages/favorites-list.php',
		'feedback' => 'pages/feedback.php',
		'forgot' => 'pages/forgot.php',
		'hot/' => 'pages/hot.php',
		'ip/' => 'pages/ip.php',
		'login' => 'pages/login.php',
		'logout' => 'pages/logout.php',
		'messages/' => 'pages/messages.php',
		'message/' => 'pages/message.php',
		'questions/' => 'pages/questions.php',
		'register' => 'pages/register.php',
		'reset' => 'pages/reset.php',
		'search' => 'pages/search.php',
		'tag/' => 'pages/tag.php',
		'tags' => 'pages/tags.php',
		'unanswered/' => 'pages/unanswered.php',
		'unsubscribe' => 'pages/unsubscribe.php',
		'updates' => 'pages/updates.php',
		'user/' => 'pages/user.php',
		'users' => 'pages/users.php',
		'users/blocked' => 'pages/users-blocked.php',
		'users/new' => 'pages/users-newest.php',
		'users/special' => 'pages/users-special.php',
	);
}


/**
 * Sets the template which should be passed to the theme class, telling it which type of page it's displaying
Scott committed
472
 * @param $template
473 474 475 476 477 478 479 480 481 482 483
 */
function qa_set_template($template)
{
	global $qa_template;
	$qa_template = $template;
}


/**
 * Start preparing theme content in global $qa_content variable, with or without $voting support,
 * in the context of the categories in $categoryids (if not null)
Scott committed
484 485 486
 * @param bool $voting
 * @param array $categoryids
 * @return array
487
 */
Scott committed
488
function qa_content_prepare($voting = false, $categoryids = null)
489 490 491 492 493 494 495 496 497
{
	if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }

	global $qa_template, $qa_page_error_html;

	if (QA_DEBUG_PERFORMANCE) {
		global $qa_usage;
		$qa_usage->mark('control');
	}
Scott committed
498

499 500 501 502
	$request = qa_request();
	$requestlower = qa_request();
	$navpages = qa_db_get_pending_result('navpages');
	$widgets = qa_db_get_pending_result('widgets');
Scott committed
503

504 505
	if (isset($categoryids) && !is_array($categoryids)) // accept old-style parameter
		$categoryids = array($categoryids);
Scott committed
506

507 508 509 510
	$lastcategoryid = count($categoryids) ? end($categoryids) : null;
	$charset = 'utf-8';
	$language = qa_opt('site_language');
	$language = empty($language) ? 'en' : qa_html($language);
Scott committed
511

512 513 514
	$qa_content = array(
		'content_type' => 'text/html; charset=' . $charset,
		'charset' => $charset,
Scott committed
515

516
		'language' => $language,
Scott committed
517

518
		'direction' => qa_opt('site_text_direction'),
Scott committed
519

520 521 522
		'options' => array(
			'minify_html' => qa_opt('minify_html'),
		),
Scott committed
523

524
		'site_title' => qa_html(qa_opt('site_title')),
Scott committed
525

526
		'html_tags' => 'lang="' . $language . '"',
Scott committed
527

528
		'head_lines' => array(),
Scott committed
529

530 531
		'navigation' => array(
			'user' => array(),
Scott committed
532

533
			'main' => array(),
Scott committed
534

535 536 537 538
			'footer' => array(
				'feedback' => array(
					'url' => qa_path_html('feedback'),
					'label' => qa_lang_html('main/nav_feedback'),
Scott committed
539 540 541
				),
			),

542
		),
Scott committed
543

544 545 546 547
		'sidebar' => qa_opt('show_custom_sidebar') ? qa_opt('custom_sidebar') : null,
		'sidepanel' => qa_opt('show_custom_sidepanel') ? qa_opt('custom_sidepanel') : null,
		'widgets' => array(),
	);
Scott committed
548

549 550 551 552
	// add meta description if we're on the home page
	if ($request === '' || $request === array_search('', qa_get_request_map())) {
		$qa_content['description'] = qa_html(qa_opt('home_description'));
	}
Scott committed
553

554 555
	if (qa_opt('show_custom_in_head'))
		$qa_content['head_lines'][] = qa_opt('custom_in_head');
Scott committed
556

557 558
	if (qa_opt('show_custom_header'))
		$qa_content['body_header'] = qa_opt('custom_header');
Scott committed
559

560 561
	if (qa_opt('show_custom_footer'))
		$qa_content['body_footer'] = qa_opt('custom_footer');
Scott committed
562

563 564
	if (isset($categoryids))
		$qa_content['categoryids'] = $categoryids;
Scott committed
565

566 567 568 569
	foreach ($navpages as $page) {
		if ($page['nav'] == 'B')
			qa_navigation_add_page($qa_content['navigation']['main'], $page);
	}
Scott committed
570

571 572 573 574 575 576
	if (qa_opt('nav_home') && qa_opt('show_custom_home')) {
		$qa_content['navigation']['main']['$'] = array(
			'url' => qa_path_html(''),
			'label' => qa_lang_html('main/nav_home'),
		);
	}
Scott committed
577

578 579 580 581 582 583
	if (qa_opt('nav_activity')) {
		$qa_content['navigation']['main']['activity'] = array(
			'url' => qa_path_html('activity'),
			'label' => qa_lang_html('main/nav_activity'),
		);
	}
Scott committed
584

585
	$hascustomhome = qa_has_custom_home();
Scott committed
586

587 588 589 590 591 592
	if (qa_opt($hascustomhome ? 'nav_qa_not_home' : 'nav_qa_is_home')) {
		$qa_content['navigation']['main'][$hascustomhome ? 'qa' : '$'] = array(
			'url' => qa_path_html($hascustomhome ? 'qa' : ''),
			'label' => qa_lang_html('main/nav_qa'),
		);
	}
Scott committed
593

594 595 596 597 598 599
	if (qa_opt('nav_questions')) {
		$qa_content['navigation']['main']['questions'] = array(
			'url' => qa_path_html('questions'),
			'label' => qa_lang_html('main/nav_qs'),
		);
	}
Scott committed
600

601 602 603 604 605 606
	if (qa_opt('nav_hot')) {
		$qa_content['navigation']['main']['hot'] = array(
			'url' => qa_path_html('hot'),
			'label' => qa_lang_html('main/nav_hot'),
		);
	}
Scott committed
607

608 609 610 611 612 613
	if (qa_opt('nav_unanswered')) {
		$qa_content['navigation']['main']['unanswered'] = array(
			'url' => qa_path_html('unanswered'),
			'label' => qa_lang_html('main/nav_unanswered'),
		);
	}
Scott committed
614

615 616 617 618 619 620 621
	if (qa_using_tags() && qa_opt('nav_tags')) {
		$qa_content['navigation']['main']['tag'] = array(
			'url' => qa_path_html('tags'),
			'label' => qa_lang_html('main/nav_tags'),
			'selected_on' => array('tags$', 'tag/'),
		);
	}
Scott committed
622

623 624 625 626 627 628 629
	if (qa_using_categories() && qa_opt('nav_categories')) {
		$qa_content['navigation']['main']['categories'] = array(
			'url' => qa_path_html('categories'),
			'label' => qa_lang_html('main/nav_categories'),
			'selected_on' => array('categories$', 'categories/'),
		);
	}
Scott committed
630

631 632 633 634 635 636 637
	if (qa_opt('nav_users')) {
		$qa_content['navigation']['main']['user'] = array(
			'url' => qa_path_html('users'),
			'label' => qa_lang_html('main/nav_users'),
			'selected_on' => array('users$', 'users/', 'user/'),
		);
	}
Scott committed
638

639
	// Only the 'level' permission error prevents the menu option being shown - others reported on qa-page-ask.php
Scott committed
640

641 642 643 644
	if (qa_opt('nav_ask') && qa_user_maximum_permit_error('permit_post_q') != 'level') {
		$qa_content['navigation']['main']['ask'] = array(
			'url' => qa_path_html('ask', (qa_using_categories() && strlen($lastcategoryid)) ? array('cat' => $lastcategoryid) : null),
			'label' => qa_lang_html('main/nav_ask'),
Scott committed
645
		);
646
	}
Scott committed
647 648


649 650
	if (qa_get_logged_in_level() >= QA_USER_LEVEL_ADMIN || !qa_user_maximum_permit_error('permit_moderate') ||
		!qa_user_maximum_permit_error('permit_hide_show') || !qa_user_maximum_permit_error('permit_delete_hidden')
651 652 653 654 655
	) {
		$qa_content['navigation']['main']['admin'] = array(
			'url' => qa_path_html('admin'),
			'label' => qa_lang_html('main/nav_admin'),
			'selected_on' => array('admin/'),
Scott committed
656
		);
657
	}
Scott committed
658

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
	$qa_content['search'] = array(
		'form_tags' => 'method="get" action="' . qa_path_html('search') . '"',
		'form_extra' => qa_path_form_html('search'),
		'title' => qa_lang_html('main/search_title'),
		'field_tags' => 'name="q"',
		'button_label' => qa_lang_html('main/search_button'),
	);

	if (!qa_opt('feedback_enabled'))
		unset($qa_content['navigation']['footer']['feedback']);

	foreach ($navpages as $page) {
		if ($page['nav'] == 'M' || $page['nav'] == 'O' || $page['nav'] == 'F') {
			$loc = ($page['nav'] == 'F') ? 'footer' : 'main';
			qa_navigation_add_page($qa_content['navigation'][$loc], $page);
		}
	}
Scott committed
676

677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
	$regioncodes = array(
		'F' => 'full',
		'M' => 'main',
		'S' => 'side',
	);

	$placecodes = array(
		'T' => 'top',
		'H' => 'high',
		'L' => 'low',
		'B' => 'bottom',
	);

	foreach ($widgets as $widget) {
		$tagstring = ',' . $widget['tags'] . ',';
692 693 694 695 696
		$showOnTmpl = strpos($tagstring, ",$qa_template,") !== false || strpos($tagstring, ',all,') !== false;
		// special case for user pages
		$showOnUser = strpos($tagstring, ',user,') !== false && preg_match('/^user(-.+)?$/', $qa_template) === 1;

		if ($showOnTmpl || $showOnUser) {
697 698 699 700 701 702 703
			// widget has been selected for display on this template
			$region = @$regioncodes[substr($widget['place'], 0, 1)];
			$place = @$placecodes[substr($widget['place'], 1, 2)];

			if (isset($region) && isset($place)) {
				// region/place codes recognized
				$module = qa_load_module('widget', $widget['title']);
704
				$allowTmpl = (substr($qa_template, 0, 7) == 'custom-') ? 'custom' : $qa_template;
705

706 707 708
				if (isset($module) &&
					method_exists($module, 'allow_template') && $module->allow_template($allowTmpl) &&
					method_exists($module, 'allow_region') && $module->allow_region($region) &&
709 710 711 712
					method_exists($module, 'output_widget')
				) {
					// if module loaded and happy to be displayed here, tell theme about it
					$qa_content['widgets'][$region][$place][] = $module;
Scott committed
713 714 715
				}
			}
		}
716
	}
Scott committed
717

718 719 720 721 722 723 724 725 726
	$logoshow = qa_opt('logo_show');
	$logourl = qa_opt('logo_url');
	$logowidth = qa_opt('logo_width');
	$logoheight = qa_opt('logo_height');

	if ($logoshow) {
		$qa_content['logo'] = '<a href="' . qa_path_html('') . '" class="qa-logo-link" title="' . qa_html(qa_opt('site_title')) . '">' .
			'<img src="' . qa_html(is_numeric(strpos($logourl, '://')) ? $logourl : qa_path_to_root() . $logourl) . '"' .
			($logowidth ? (' width="' . $logowidth . '"') : '') . ($logoheight ? (' height="' . $logoheight . '"') : '') .
Scott committed
727
			' alt="' . qa_html(qa_opt('site_title')) . '"/></a>';
728 729 730
	} else {
		$qa_content['logo'] = '<a href="' . qa_path_html('') . '" class="qa-logo-link">' . qa_html(qa_opt('site_title')) . '</a>';
	}
Scott committed
731

732
	$topath = qa_get('to'); // lets user switch between login and register without losing destination page
Scott committed
733

734
	$userlinks = qa_get_login_links(qa_path_to_root(), isset($topath) ? $topath : qa_path($request, $_GET, ''));
Scott committed
735

736
	$qa_content['navigation']['user'] = array();
Scott committed
737

738 739 740 741 742
	if (qa_is_logged_in()) {
		$qa_content['loggedin'] = qa_lang_html_sub_split('main/logged_in_x', QA_FINAL_EXTERNAL_USERS
			? qa_get_logged_in_user_html(qa_get_logged_in_user_cache(), qa_path_to_root(), false)
			: qa_get_one_user_html(qa_get_logged_in_handle(), false)
		);
Scott committed
743

744 745 746 747
		$qa_content['navigation']['user']['updates'] = array(
			'url' => qa_path_html('updates'),
			'label' => qa_lang_html('main/nav_updates'),
		);
Scott committed
748

749
		if (!empty($userlinks['logout'])) {
750 751 752
			$qa_content['navigation']['user']['logout'] = array(
				'url' => qa_html(@$userlinks['logout']),
				'label' => qa_lang_html('main/nav_logout'),
Scott committed
753
			);
754
		}
Scott committed
755

756 757
		if (!QA_FINAL_EXTERNAL_USERS) {
			$source = qa_get_logged_in_source();
Scott committed
758

759 760
			if (strlen($source)) {
				$loginmodules = qa_load_modules_with('login', 'match_source');
Scott committed
761

762
				foreach ($loginmodules as $module) {
763 764 765 766 767
					if ($module->match_source($source) && method_exists($module, 'logout_html')) {
						ob_start();
						$module->logout_html(qa_path('logout', array(), qa_opt('site_url')));
						$qa_content['navigation']['user']['logout'] = array('label' => ob_get_clean());
					}
768
				}
Scott committed
769
			}
770
		}
Scott committed
771

772 773 774
		$notices = qa_db_get_pending_result('notices');
		foreach ($notices as $notice)
			$qa_content['notices'][] = qa_notice_form($notice['noticeid'], qa_viewer_html($notice['content'], $notice['format']), $notice);
Scott committed
775

776 777
	} else {
		require_once QA_INCLUDE_DIR . 'util/string.php';
Scott committed
778

779 780
		if (!QA_FINAL_EXTERNAL_USERS) {
			$loginmodules = qa_load_modules_with('login', 'login_html');
Scott committed
781

782 783 784 785
			foreach ($loginmodules as $tryname => $module) {
				ob_start();
				$module->login_html(isset($topath) ? (qa_opt('site_url') . $topath) : qa_path($request, $_GET, qa_opt('site_url')), 'menu');
				$label = ob_get_clean();
Scott committed
786

787 788
				if (strlen($label))
					$qa_content['navigation']['user'][implode('-', qa_string_to_words($tryname))] = array('label' => $label);
Scott committed
789
			}
790
		}
Scott committed
791

792 793 794 795 796
		if (!empty($userlinks['login'])) {
			$qa_content['navigation']['user']['login'] = array(
				'url' => qa_html(@$userlinks['login']),
				'label' => qa_lang_html('main/nav_login'),
			);
Scott committed
797 798
		}

799 800 801 802 803 804 805
		if (!empty($userlinks['register'])) {
			$qa_content['navigation']['user']['register'] = array(
				'url' => qa_html(@$userlinks['register']),
				'label' => qa_lang_html('main/nav_register'),
			);
		}
	}
Scott committed
806

807 808 809
	if (QA_FINAL_EXTERNAL_USERS || !qa_is_logged_in()) {
		if (qa_opt('show_notice_visitor') && (!isset($topath)) && (!isset($_COOKIE['qa_noticed'])))
			$qa_content['notices'][] = qa_notice_form('visitor', qa_opt('notice_visitor'));
Scott committed
810

811 812
	} else {
		setcookie('qa_noticed', 1, time() + 86400 * 3650, '/', QA_COOKIE_DOMAIN, (bool)ini_get('session.cookie_secure'), true); // don't show first-time notice if a user has logged in
Scott committed
813

Scott committed
814 815
		if (qa_opt('show_notice_welcome') && (qa_get_logged_in_flags() & QA_USER_FLAGS_WELCOME_NOTICE)) {
			if ($requestlower != 'confirm' && $requestlower != 'account') // let people finish registering in peace
816
				$qa_content['notices'][] = qa_notice_form('welcome', qa_opt('notice_welcome'));
Scott committed
817
		}
818
	}
Scott committed
819

820 821
	$qa_content['script_rel'] = array('qa-content/jquery-1.11.3.min.js');
	$qa_content['script_rel'][] = 'qa-content/qa-page.js?' . QA_VERSION;
Scott committed
822

823 824
	if ($voting)
		$qa_content['error'] = @$qa_page_error_html;
Scott committed
825

826 827 828 829
	$qa_content['script_var'] = array(
		'qa_root' => qa_path_to_root(),
		'qa_request' => $request,
	);
Scott committed
830

831 832
	return $qa_content;
}
Scott committed
833 834


835 836 837 838 839 840 841
/**
 * Get the start parameter which should be used, as constrained by the setting in qa-config.php
 */
function qa_get_start()
{
	return min(max(0, (int)qa_get('start')), QA_MAX_LIMIT_START);
}
Scott committed
842

843 844 845 846 847 848 849 850 851

/**
 * Get the state parameter which should be used, as set earlier in qa_load_state()
 */
function qa_get_state()
{
	global $qa_state;
	return $qa_state;
}