View file includes/functions_reputation.php

File size: 24.88Kb
<?php
/**
 * @package democracy
 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
 * @author Carbofos <[email protected]>
 * @author ETZel <[email protected]>
 */

if (!defined('IN_PHPBB'))
{
	die('Hacking attempt');
}

/*
 * Common images
 */
if (!empty($images))
{
	$warned_img = $lang['Warning'];
	$banned_img = $lang['reputation_ban'];
	$thumb_up_img = $lang['reputation_approve'];
	$thumb_dn_img = $lang['reputation_disapprove'];
}
$current_time = time();

/**
 * Reputation auth keys (not related to forum auth keys)
 */
$reputation_auth_keys = array('auth_view_rep', 'auth_view_warns', 'auth_add_rep', 'auth_add_rep_nonpost', 'auth_edit_rep', 'auth_delete_rep', 'auth_warn', 'auth_warn_nonpost', 'auth_ban', 'auth_ban_nonpost', 'auth_edit_warn', 'auth_delete_warn', 'auth_no_limits');

/**
 * Get required input var and (optionally) die if when isn't present.
 * @param string $required_msg Message (or $lang key) to die with when the variable is not set
 * @return mixed Request variable cast to the same type as the $default param
 */
function input_var($name, $default, $required_msg = null)
{
	global $HTTP_POST_VARS, $HTTP_GET_VARS;

	if (isset($HTTP_POST_VARS[$name]))
	{
		$var = $HTTP_POST_VARS[$name];
	}
	elseif (isset($HTTP_GET_VARS[$name]))
	{
		$var = $HTTP_GET_VARS[$name];
	}
	elseif ($required_msg)
	{
		message_die(GENERAL_ERROR, $required_msg);
	}
	else
	{
		return addslashes(is_array($default) ? $default[0] : $default);
	}

	if (is_array($default))
	{
		settype($var, gettype($default[0]));

		if (in_array($var, $default))
		{
			return $var;
		}
		return $default[0];
	}
	return settype($var, gettype($default)) ? $var : $default; // QUESTION: settype never fails?
}

/**
 * Replace censored words
 * @param boolean $html Must be set to true for messages containing html
 * @return string Censored message
 */
function censor($message, $html = false)
{
	static $orig_word = null, $replacement_word = null;

	if (is_null($orig_word))
	{
		// avoid calling obtain_word_list twice
		if (isset($GLOBALS['orig_word']) && isset($GLOBALS['replacement_word']))
		{
			$orig_word = $GLOBALS['orig_word'];
			$replacement_word = $GLOBALS['replacement_word'];
		}
		else
		{
			obtain_word_list($orig_word, $replacement_word);
		}
	}
	if ($orig_word)
	{
		return $html ? str_replace('\"', '"', substr(@preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "@preg_replace(\$orig_word, \$replacement_word, '\\0')", '>' . $message . '<'), 1, -1)) : preg_replace($orig_word, $replacement_word, $message);
	}
	return $message;
}

/**
 * Prepare message/signature for display: substitute bbcode, smilies, urls if enabled.
 * @return string Message containing HTML and ready for display
 */
function prepare_display($message, $bbcode_uid = '', $enable_html = false, $enable_smilies = true, $enable_links = true)
{
	global $board_config;

	// If the board has HTML off but the post has HTML on then we process it, else leave it alone
	if (!$board_config['allow_html'] && $enable_html)
	{
		$message = preg_replace('#(<)([\/]?.*?)(>)#is', "&lt;\\2&gt;", $message);
	}

	// Parse message and/or sig for BBCode if reqd
	if ($bbcode_uid)
	{
		if ($board_config['allow_bbcode'])
		{
			$message = bbencode_second_pass($message, $bbcode_uid);
		}
		else
		{
			$message = preg_replace('/\:[0-9a-z\:]+\]/si', ']', $message);
		}
	}

	// Make URLs clickable
	if ($enable_links)
	{
		$message = make_clickable($message);
	}

	// Parse smilies
	if ($board_config['allow_smilies'] && $enable_smilies)
	{
		$message = smilies_pass($message);
	}

	// Replace naughty words
	$message = censor($message, true);

	return nl2br($message);
}

/**
 * Generates template variables for user information buttons seen around post or review (www/email/profile/etc).
 * @param array $userdata Row from the users table
 * @param boolean $is_mod Generate buttons as they are viewed by moderator (affects emails display)
 * @return array Array of template variables wich can be readily feed to $template->assign_vars()
 */
function user_buttons_tpl($userdata, $is_mod = false)
{
	global $lang, $phpEx, $images, $board_config;
	static $cache = array();

	$poster_id = isset($userdata['voter_id']) ? $userdata['voter_id'] : $userdata['poster_id']; // posts have poster_id and reviews have voter_id

	if (isset($cache[$poster_id]))
	{
		return $cache[$poster_id];
	}

	$email_img = $email = $icq_status_img = $icq_img = $icq = '';

	$temp_url = append_sid("profile.$phpEx?mode=viewprofile&amp;" . POST_USERS_URL . '=' . $poster_id);
	$profile_img = '<a href="' . $temp_url . '">' . $lang['Read_profile'] . '</a>';
	$profile = '<a href="' . $temp_url . '" title="' . $lang['Read_profile'] . '">' . $lang['Profile'] . '</a>';

	$temp_url = append_sid("privmsg.$phpEx?mode=post&amp;" . POST_USERS_URL . '=' . $poster_id);
	$pm_img = '<a href="' . $temp_url . '">' . $lang['Send_private_message'] . '</a>';
	$pm = '<a href="' . $temp_url . '" title="' . $lang['Send_private_message'] . '">' . $lang['Private_Message'] . '</a>';

	if (!empty($userdata['user_viewemail']) || $is_mod)
	{
		$email_uri = $board_config['board_email_form'] ? append_sid("profile.$phpEx?mode=email&amp;" . POST_USERS_URL .'=' . $poster_id) : 'mailto:' . $userdata['user_email'];

		$email_img = '<a href="' . $email_uri . '"><img src="' . $images['icon_email'] . '" alt="' . $lang['Send_email'] . '" title="' . $lang['Send_email'] . '" border="0" /></a>';
		$email = '<a href="' . $email_uri . '" title="' . $lang['Send_email'] . '">' . $lang['Email'] . '</a>';
	}

	$www_img = $userdata['user_website'] ? '<a href="' . $userdata['user_website'] . '" target="_userwww"><img src="' . $images['icon_www'] . '" alt="' . $lang['Visit_website'] . '" title="' . $lang['Visit_website'] . '" border="0" /></a>' : '';
	$www = $userdata['user_website'] ? '<a href="' . $userdata['user_website'] . '" target="_userwww" title="' . $lang['Visit_website'] . '">WWW</a>' : '';

	if (!empty($userdata['user_icq']))
	{
		$icq_status_img = '<a href="http://wwp.icq.com/' . $userdata['user_icq'] . '#pager"><img src="http://web.icq.com/whitepages/online?icq=' . $userdata['user_icq'] . '&img=5" width="18" height="18" border="0" /></a>';
		$icq_img = '<a href="http://wwp.icq.com/scripts/search.dll?to=' . $userdata['user_icq'] . '"><img src="' . $images['icon_icq'] . '" alt="' . $lang['ICQ'] . '" title="' . $lang['ICQ'] . '" border="0" /></a>';
		$icq = '<a href="http://wwp.icq.com/scripts/search.dll?to=' . $userdata['user_icq'] . '">ICQ</a>';
	}

	$aim_img = $userdata['user_aim'] ? '<a href="aim:goim?screenname=' . $userdata['user_aim'] . '&amp;message=Hello+Are+you+there?"><img src="' . $images['icon_aim'] . '" alt="' . $lang['AIM'] . '" title="' . $lang['AIM'] . '" border="0" /></a>' : '';
	$aim = $userdata['user_aim'] ? '<a href="aim:goim?screenname=' . $userdata['user_aim'] . '&amp;message=Hello+Are+you+there?">AIM</a>' : '';

	$temp_url = append_sid("profile.$phpEx?mode=viewprofile&amp;" . POST_USERS_URL . '=' . $poster_id);
	$msn_img = $userdata['user_msnm'] ? '<a href="' . $temp_url . '"><img src="' . $images['icon_msnm'] . '" alt="' . $lang['MSNM'] . '" title="' . $lang['MSNM'] . '" border="0" /></a>' : '';
	$msn = $userdata['user_msnm'] ? '<a href="' . $temp_url . '">MSNM</a>' : '';

	$yim_img = $userdata['user_yim'] ? '<a href="http://edit.yahoo.com/config/send_webmesg?.target=' . $userdata['user_yim'] . '&amp;.src=pg"><img src="' . $images['icon_yim'] . '" alt="' . $lang['YIM'] . '" title="' . $lang['YIM'] . '" border="0" /></a>' : '';
	$yim = $userdata['user_yim'] ? '<a href="http://edit.yahoo.com/config/send_webmesg?.target=' . $userdata['user_yim'] . '&amp;.src=pg">YIM</a>' : '';

	$temp_url = append_sid("search.$phpEx?search_author=" . urlencode($userdata['username']) . "&amp;showresults=posts");
	$search_img = '<a href="' . $temp_url . '"><img src="' . $images['icon_search'] . '" alt="' . $lang['Search_user_posts'] . '" title="' . sprintf($lang['Search_user_posts'], $userdata['username']) . '" border="0" /></a>';
	$search = '<a href="' . $temp_url . '">' . sprintf($lang['Search_user_posts'], $userdata['username']) . '</a>';

	return $cache[$poster_id] = array(
		'PROFILE_IMG' => $profile_img,
		'PROFILE' => $profile,
		'SEARCH_IMG' => $search_img,
		'SEARCH' => $search,
		'PM_IMG' => $pm_img,
		'PM' => $pm,
		'EMAIL_IMG' => $email_img,
		'EMAIL' => $email,
		'WWW_IMG' => $www_img,
		'WWW' => $www,
		'ICQ_STATUS_IMG' => $icq_status_img,
		'ICQ_IMG' => $icq_img,
		'ICQ' => $icq,
		'AIM_IMG' => $aim_img,
		'AIM' => $aim,
		'MSN_IMG' => $msn_img,
		'MSN' => $msn,
		'YIM_IMG' => $yim_img,
		'YIM' => $yim,
	);
}

/**
 * Determine user's rank
 * @return array First element will contain user's rank and second will contain a corrsponding rank image. Both are always returned but can be empty strings.
 */
function user_rank($userdata)
{
	global $db;
	static $ranks = null, $special_ranks = null, $cache = array();

	if (isset($cache[$userdata['user_id']]))
	{
		return $cache[$userdata['user_id']];
	}

	if (is_null($ranks))
	{
		if (isset($GLOBALS['ranksrow']))
		{
			$ranks = $GLOBALS['ranksrow'];
		}
		else
		{
			$result = db_query('SELECT * FROM {RANKS_TABLE} ORDER BY rank_min DESC');

			$ranks = $special_ranks = array();
			while ($row = $db->sql_fetchrow($result))
			{
				if ($row['rank_special'])
				{
					$special_ranks[$row['rank_id']] = $row;
				}
				else
				{
					$ranks[] = $row;
				}
			}
			$ranks[] = array('rank_min' => 0, 'rank_title' => '', 'rank_image' => '');
			$db->sql_freeresult($result);
		}
	}

	if ($userdata['user_rank'])
	{
		$row = $special_ranks[$userdata['user_rank']];
	}
	else
	{
		for ($i = 0; $userdata['user_posts'] < $ranks[$i]['rank_min']; $i++);
		$row = $ranks[$i];
	}

	return $cache[$userdata['user_id']] = array(
		$row['rank_title'],
		$row['rank_image'] ? '<img src="' . $row['rank_image'] . '" alt="' . $row['rank_title'] . '" title="' . $row['rank_title'] . '" border="0" /><br />' : ''
	);
}

/**
 * Return path to user's avatar or an empty string if the user has no avatar
 */
function user_avatar($userdata, $url_only = false)
{
	global $board_config;

	if ($userdata['user_avatar_type'] && $userdata['user_allowavatar'])
	{
		switch ($userdata['user_avatar_type'])
		{
			case USER_AVATAR_UPLOAD:
				$avatar = $board_config['allow_avatar_upload'] ? $board_config['avatar_path'] . '/' . $userdata['user_avatar'] : '';
				break;
			case USER_AVATAR_REMOTE:
				$avatar = $board_config['allow_avatar_remote'] ? $userdata['user_avatar'] : '';
				break;
			case USER_AVATAR_GALLERY:
				$avatar = $board_config['allow_avatar_local'] ? $board_config['avatar_gallery_path'] . '/' . $userdata['user_avatar'] : '';
				break;
		}
		return $url_only ? $avatar : ('<img src="' . $avatar . '" alt="" />');
	}
	return '';
}

/**
 * Generate template vars for inline post warning display
 * @param array $warning
 * @return array
 */
function reputation_warning_tpl($warning)
{
	global $lang, $images, $phpEx, $board_config, $warned_img, $banned_img;

	$issuer = '<b><a href="' . append_sid("profile.$phpEx?mode=viewprofile&amp;" . POST_USERS_URL . '=' . $warning['voter_id']) . '">' . $warning['username'] . '</a></b>';
	$temp_url = append_sid("profile.$phpEx?mode=warnings&amp;" . POST_REVIEWS_URL . '=' . $warning['id']) . '#' . $warning['id'];
	if ($warning['modification'] == REPUTATION_WARNING || $warning['modification'] == REPUTATION_WARNING_EXPIRED)
	{
		$icon = '<b>!</b>';
		$details = $lang['reputation_post_warning'];
	}
	else
	{
		$icon = '<b>#</b>';
		$details = $lang['reputation_post_ban'];
	}
	if ($warning['modification'] == REPUTATION_WARNING_EXPIRED || $warning['modification'] == REPUTATION_BAN_EXPIRED)
	{
		$expire = $lang['reputation_expired'];
	}
	else
	{
		$expire = is_null($warning['expire']) ? $lang['reputation_expire_never'] : create_date($board_config['default_dateformat'], $warning['expire'], $board_config['board_timezone']);;
	}
	$details = sprintf($details, $issuer, create_date($board_config['default_dateformat'], $warning['date'], $board_config['board_timezone']), $expire);
	$message = $warning['text'] ? prepare_display($warning['text'], $warning['bbcode_uid'], true, true) : $lang['None'];

	return array('ICON' => $icon, 'DETAILS' => $details, 'MESSAGE' => $message);
}

/**
 * Generate HTML code for displaying dropdown list. Useful for providing sorting options and such.
 * @param string $name
 * @param array $values
 * @param array $titles
 * @param string $default
 * @return string Generated HTML code for displaying the list
 */
function html_select($name, $values, $titles, $default = null)
{
	global $lang;

	$select = '<select name="' . $name . '" onchange="this.form.submit();">';

	foreach ($values as $i => $value)
	{
		$checked = ($value == $default) ? ' selected="selected"' : '';
		$select .= "<option value=\"$value\"$checked>" . htmlspecialchars($lang[$titles[$i]]) . '</option>';
	}

	$select .= '</select>';

	return $select;
}

/**
 * Generate string with user's reputation in configurable format and plus/minus buttons if appropriate.
 * @param array $userdata User data array with user_id, reputation, reputation_plus fields
 * @param array $is_auth Reputation auth array with at least auth_view_rep and auth_add_rep keys
 * @param boolean $for_post
 * @return string
 */
function reputation_display($userdata, $is_auth, $for_post)
{
	global $lang, $thumb_up_img, $thumb_dn_img, $board_config, $phpEx;

	if ($is_auth['no_rep'])
	{
		return '';
	}
	if ($userdata['user_reputation'] || $userdata['user_reputation_plus'])
	{
		if ($for_post)
		{
			if ($is_auth['auth_view_rep'])
			{
				$user_reputation = '<a href="' . append_sid("profile.$phpEx?mode=reputation&amp;" . POST_USERS_URL . '=' . $userdata['user_id']) . '" title="' . $lang['reputation_search_reputation'] . '">' . $lang['Reputation'] . '</a>: ';
			}
			else
			{
				$user_reputation = $lang['Reputation'] . ': ';
			}
		}
		else
		{
			$user_reputation = '';
		}

		switch ($board_config['reputation_display'])
		{
			case REPUTATION_SUM:
				$user_reputation .= $userdata['user_reputation'];
				break;

			case REPUTATION_PLUSMINUS:
				if ($userdata['user_reputation_plus'])
				{
					$user_reputation .= '+' . $userdata['user_reputation_plus'];
				}
				if ($reputation_minus = $userdata['user_reputation_plus'] - $userdata['user_reputation'])
				{
					$user_reputation .= ($userdata['user_reputation_plus'] ? '/' : '') . '-' . $reputation_minus;
				}
				break;

			default:
				message_die(GENERAL_ERROR, 'Reputation config is damaged');
		}
	}
	else
	{
		$user_reputation = $for_post ? ($lang['Reputation'] . ': 0') : '0';
	}

	if ($is_auth['auth_add_rep'])
	{
		$url_param = $for_post ? (POST_POST_URL . '=' . $userdata['post_id']) : (POST_USERS_URL . '=' . $userdata['user_id']);

		$user_reputation .= '<br/><a href="' . append_sid("reputation.$phpEx?mode=inc&amp;$url_param") . '">+</a>';

		if (!$board_config['reputation_positive_only'])
		{
			$user_reputation .= ' | <a href="' . append_sid("reputation.$phpEx?mode=dec&amp;$url_param") . '">-</a>';
		}
	}
	return $user_reputation;
}

/**
 * TODO: write desc
 */
function reputation_warnings($userdata, $banned, $auth)
{
	global $warned_img, $banned_img, $lang, $phpEx;

	if ($userdata['user_warnings'])
	{
		$warnings = str_repeat($warned_img, $banned ? ($userdata['user_warnings'] - 1) : $userdata['user_warnings']) . ($banned ? $banned_img : '');
		$title = sprintf($lang['reputation_warnings_to'], $userdata['username']);

		if ($auth['auth_view_warns'])
		{
			return '<a href="' . append_sid("profile.$phpEx?mode=warnings&amp;" . POST_USERS_URL . '=' . $userdata['user_id']) . '" title="' . $title . '">' . $warnings . '</a>';
		}
		else
		{
			return '<span title="' . $title . '">' . $warnings . '</span>';
		}
	}
	elseif ($banned)
	{
		return '<span title="' . $lang['reputation_banned_permanently'] . '">' . $banned_img . '</span>';
	}

	return '';
}

/**
 * Writes a string to cache.
 * @param string $id Unique identifier of cached string. Alphanumeric only, please.
 * @param string $data Data to store or null to clear.
 */
function cache_set($id, $data = null)
{
	global $phpbb_root_path;

	$cache_file = $phpbb_root_path . 'cache/' . $id;

	if ($data)
	{
		if ($f = fopen($cache_file, 'wb'))
		{
			fwrite($f, serialize($data));
			fclose($f);
			return true;
		}
		return false;
	}
	elseif (file_exists($cache_file))
	{
		@unlink($cache_file);
	}
}

/**
 * Reads cached string.
 * @param string $id Unique identifier of cached string. Alphanumeric only, please.
 */
function cache_get($id)
{
	global $phpbb_root_path;

	$cache_file = $phpbb_root_path . 'cache/' . $id;

	if (is_readable($cache_file) && ($f = fopen($cache_file, 'rb')))
	{
		if ($data = fread($f, filesize($cache_file)))
		{
			$data = unserialize($data);

		}
		fclose($f);
		return $data;
	}

	return false;
}

/**
 * TODO: Write desc
 * @param mixed $forum_id_or_auth
 * @param array $userdata
 * @return array
 */
function reputation_auth($auth_or_forum_id, $userdata, $subject = null, $quick = false)
{
	global $board_config, $reputation_auth_keys;

	if (is_array($auth_or_forum_id))
	{
		$auth = $auth_or_forum_id;
	}
	elseif ($auth_or_forum_id == NO_ID)
	{
		// fake some auth values
		$auth = array('auth_read' => true, 'auth_view' => true, 'auth_mod' => ($userdata['user_level'] == MOD || $userdata['user_level'] == ADMIN));
	}
	else
	{
		$auth = auth(AUTH_ALL, $auth_or_forum_id, $userdata);
	}

	if ($auth_or_forum_id == AUTH_LIST_ALL) // NOTE: null will pass this! use NO_ID when forum auth is not available
	{
		$auth[NO_ID] = NO_ID; // nonpost warns/reviews/reports belong to phantom forum with forum_id = NO_ID.

		foreach ($auth as $forum_id => $forum_auth)
		{
			$auth[$forum_id] = reputation_auth($forum_auth, $userdata, $subject, $quick);
		}

		return $auth;
	}

	if (!isset($auth['auth_add_rep']))
	{
		$admin = ($userdata['user_id'] != ANONYMOUS) && ($userdata['user_level'] == ADMIN);
		$guest = $auth['auth_read'] && $auth['auth_view'];
		$reg = ($userdata['user_id'] != ANONYMOUS) && $guest;

		foreach ($reputation_auth_keys as $i => $key)
		{
			switch ($board_config['reputation_perms'][$i])
			{
				case AUTH_ADMIN:
					$auth[$key] = $admin;
					break;
				case AUTH_MOD:
					$auth[$key] = (bool) $auth['auth_mod'];
					break;
				case AUTH_REG:
					$auth[$key] = $reg;
					break;
				case AUTH_ALL:
					$auth[$key] = $guest;
					break;
				default:
					message_die(GENERAL_ERROR, 'Reputation config is damaged');
			}
		}
		if ($auth_or_forum_id == NO_ID)
		{
			$auth['auth_add_rep'] = $auth['auth_add_rep_nonpost'];
			$auth['auth_warn'] = $auth['auth_warn_nonpost'];
			$auth['auth_ban'] = $auth['auth_ban_nonpost'];
		}
	}

	if (!empty($subject))
	{
		reputation_auth_personal($auth, $userdata, $subject, $quick);
	}

	return $auth;
}

/**
 * TODO: Write desc
 * @return mixed Either error message or boolean false (no limitations apply)
 */
function reputation_check_limits($actor, $subject, $quick = false)
{
	global $db, $board_config, $lang, $current_time;

	if ($actor['user_posts'] < $board_config['reputation_posts_req'])
	{
		return $lang['reputation_limits_apply'];
	}
	if (($current_time - $actor['user_regdate']) < $board_config['reputation_days_req'] * 86400)
	{
		return $lang['reputation_limits_apply'];
	}
	if ($actor['user_warnings'] > $board_config['reputation_warnings_req'])
	{
		return $lang['reputation_limits_apply'];
	}
	if ($actor['user_reputation'] < $board_config['reputation_points_req'])
	{
		return $lang['reputation_limits_apply'];
	}

	// The complex thing: time & rotation limits
	if (!$quick && ($board_config['reputation_time_limit'] || $board_config['reputation_rotation_limit']))
	{
		$result = db_query('SELECT id, date FROM {REPUTATION_TABLE}
			WHERE voter_id = %d AND user_id = %d
				AND (modification = {REPUTATION_INC} OR modification = {REPUTATION_DEC})
			ORDER BY id DESC
			LIMIT 1', $actor['user_id'], empty($subject['voter_id']) ? $subject['user_id'] : $subject['voter_id']);
		if ($row = $db->sql_fetchrow($result))
		{
			if ($board_config['reputation_time_limit'] && ($current_time < $row['date'] + $board_config['reputation_time_limit'] * 60))
			{
				return sprintf($lang['reputation_time_limit'], $board_config['reputation_time_limit']);
			}
			if ($board_config['reputation_rotation_limit'])
			{
				$result = db_query('SELECT COUNT(*) AS cnt FROM {REPUTATION_TABLE}
					WHERE voter_id = %d AND id > %d
						AND (modification = {REPUTATION_INC} OR modification = {REPUTATION_DEC})
					GROUP BY voter_id',
					$actor['user_id'], $row['id']);

				if (!($row = $db->sql_fetchrow($result)) || $row['cnt'] < $board_config['reputation_rotation_limit'])
				{
					return sprintf($lang['reputation_rotation_limit'], $board_config['reputation_rotation_limit']);
				}
			}
		}
	}

	return false;
}

/**
 * Adjusts $auth array takin into account that $actor is performing some reputation-related action towards $subject.
 * For all changed values error message is provided in the form of $auth['auth_add_rep_msg'] ('_msg' added to auth key)
 * @access private
 */
function reputation_auth_personal(&$auth, $actor, $subject, $quick)
{
/* TODO: rearchitect personalized auth system
			add_rep		edit/delete_rep			add_warn/ban			edit/delete_warn/ban
USER1		!self		self					0						0
MOD1		!self		self && !(mod2,admin2)	!self && !(mod2,admin2)	self && !(mod2,admin2)
ADMIN1		!self		1						!self && !(mod2,admin2)	1

*/
	global $db, $lang, $board_config;

	static $cache = array();
	$subject_id = empty($subject['voter_id']) ? $subject['user_id'] : $subject['voter_id']; // voter_id have priopity because reviews may have user_id too
	$pair_id = $actor['user_id'] . ',' . $subject_id;

	if (isset($cache[$pair_id]))
	{
		$fix = $cache[$pair_id];
	}
	else
	{
		$subject_is_mod = ($subject['user_level'] == ADMIN || $subject['user_level'] == MOD);

		// not quite the right place to put applicability checks...
		$fix = array(
			'no_rep' => ($subject['user_id'] == ANONYMOUS || $subject['user_level'] == MOD && $board_config['reputation_mod_norep'] || $subject['user_level'] == ADMIN && $board_config['reputation_admin_norep']),
			'no_warn' => ($subject_id == ANONYMOUS || $subject_is_mod),
		);

		if ($subject_id == ANONYMOUS)
		{
			$fix['auth_view_rep'] = $fix['auth_add_rep'] = $fix['auth_warn'] = $lang['reputation_anonymous_no_reputation'];
		}
		elseif ($actor['user_id'] == $subject_id)
		{
			$fix['auth_add_rep'] = $fix['auth_warn'] = $fix['auth_ban'] = $lang['reputation_self_no_modify'];
		}
		else
		{
			if ($fix['no_rep'])
			{
				$fix['auth_view_rep'] = $fix['auth_add_rep'] = $lang['reputation_not_applicable'];
			}
			elseif (!$auth['auth_no_limits'])
			{
				if ($message = reputation_check_limits($actor, $subject, $quick))
				{
					$fix['auth_add_rep'] = $message;
				}
			}

			if ($subject_is_mod)
			{
				$fix['auth_view_warns'] = $fix['auth_warn'] = $fix['auth_ban'] = $lang['reputation_cant_warn_mods'];
			}

			if ($actor['user_level'] == MOD)
			{
				/*if ($subject_is_mod)
				{
					$fix['auth_edit_rep'] = $fix['auth_delete_rep'] = $lang['reputation_other_mods_no_edit'];
				}*/
			}
			elseif ($actor['user_level'] != ADMIN)
			{
				$fix['auth_edit_rep'] = $fix['auth_delete_rep'] = $lang['reputation_others_no_edit'];
			}
		}

		/*if ($subject_is_mod)
		{
			if ($actor['user_level'] == MOD) // admins are unconstrained, users never have warning perms
			{
				$fix['auth_edit_warn'] = $fix['auth_delete_warn'] = false;
			}
		}*/

		$cache[$pair_id] = $fix;
	}

	foreach ($fix as $key => $value)
	{
		if (!empty($auth[$key]))
		{
			$auth[$key] = false;
			if ($value)
			{
				$auth[$key . '_msg'] = $value;
			}
		}
	}
	$auth['no_rep'] = $fix['no_rep']; $auth['no_warn'] = $fix['no_warn'];
}

function server_url()
{
	global $board_config, $phpEx;

	if ($script_name = preg_replace('/^\/?(.*?)\/?$/', '\1', trim($board_config['script_path'])))
	{
		$script_name .= '/';
	}

	$server_port = ($board_config['server_port'] != 80) ? (':' . trim($board_config['server_port']) . '/') : '/';

	return ($board_config['cookie_secure'] ? 'https://' : 'http://') . trim($board_config['server_name']) . $server_port . $script_name;
}

/*
 * Some reputation options are kept together in comma-separated lists for compactness.
 */
$board_config['reputation_perms'] = explode(',', $board_config['reputation_perms']);
$board_config['reputation_warning_expire'] = $board_config['reputation_warning_expire'] ? explode(',', $board_config['reputation_warning_expire']) : array();
$board_config['reputation_ban_expire'] = $board_config['reputation_ban_expire'] ? explode(',', $board_config['reputation_ban_expire']) : array();

?>