<?php 
	if (!defined('PmWiki') || !defined ('PhpbbRootPath')) {
		exit ();
	}

	$RecipeInfo['AuthPhpbb2Sso']['Version'] = '080401';

	$phpbb_root_path = PhpbbRootPath;

	// Include the required phpBB files
	define('IN_PHPBB', true);                                       // Or the phpBB scripts will report a "hacking attempt"
	include_once ($phpbb_root_path . '/extension.inc');             // Necessary to get the php file extension
	require_once ($phpbb_root_path . "/config.$phpEx");             // Get all db related information
	require_once ($phpbb_root_path . "/includes/db.$phpEx");        // Define and instantiate the $db object
	require_once ($phpbb_root_path . "/includes/constants.$phpEx"); // Get constants for table names etc.
	require_once ($phpbb_root_path . "/includes/sessions.$phpEx");  // Functions for sessions

	// Read the config table into the board_config array
	$board_config = GetBoardConfig();

	// To start a session we need the IP address of the client
	$user_ip   = encode_ip(( !empty($HTTP_SERVER_VARS['REMOTE_ADDR']) ) ? $HTTP_SERVER_VARS['REMOTE_ADDR'] : ( ( !empty($HTTP_ENV_VARS['REMOTE_ADDR']) ) ? $HTTP_ENV_VARS['REMOTE_ADDR'] : getenv('REMOTE_ADDR') ));

	// Now start a phpBB session
	// Registered page number in the sessions table is -20. phpBB2 itself uses 0 till -11
	$userdata = session_pagestart($user_ip, -20);

	// We now have the $userdata array to play with, as per phpBB2. The array contains the user and session 
	// information from phpBB.


	// Restrict admin pages to phpBB Administrators
	SDV($PhpbbAdminGroup, 'siteadmin');
	$DefaultPasswords['admin'] = '@' . $PhpbbAdminGroup;

	// Suffix for group moderator groups
	SDV ($PhpbbGroupModSuffix, 'Moderator');

	// Set the author name as used by PMwiki. Author name will be set to 'anonymous' if the
	// user is not signed in.
	$Author = $userdata['username'];	

	// Populate variables for AuthUser. Only if the login succeeded, or the user
	// will appear to AuthUser as an authenticated used named "anonymous".
	if ($userdata['session_logged_in'] == 1) {
		$AuthId = $userdata['username'];
		AddPhpbbGroups($userdata['user_id']);

		if ($userdata['user_level'] == 1) {
			$AuthList ['@' . $PhpbbAdminGroup] = 1;
		}
	}

	// Include AuthUser for authorization
	require_once ("scripts/authuser.php");

	// Set some variables that can be used in the PmWiki templates to visually integrate PmWiki and phpBB:
	$SiteUrl         = (($board_config['cookie_secure'] ) ? 'https://' : 'http://')
	                   . trim($board_config['server_name']) 
	                   . (( $board_config['server_port'] <> 80 ) ? ':' . trim($board_config['server_port']) : '');
	$PhpbbUrl        = $SiteUrl . '/' . preg_replace('/^\/?(.*?)\/?$/', "\\1", trim($board_config['script_path']));
	$PhpbbStyleName  = PhpbbStyleInfo('style_name');
	$PhpbbTemplate   = PhpbbStyleInfo('template_name');
	$PhpbbStylesheet = PhpbbStyleInfo('head_stylesheet');

	// Inherit compression setting from phpBB
	InheritGzip ();

	// Handle clients with disabled cookies 
	if (append_sid('') != '') {
		// Buffer the page and append the "sid=" parameter to all local urls after 
		// the page is complete. Contents of the page are passed through the 
		// AddSid() function before being send to the client.
		ob_start('AddSid');

		// Append sid to redirect URL after editing a page. This is passed through
		// a header("Location ..."), which cannot be altered by the output buffering 
		// function AddSid().
		$EditRedirectFmt = append_sid('$FullName');
	}


	// ------------------------------------------------------------------------------------------
	//Functions

	// Get and set time settings from phpBB:
	// * Time and date format
	// * Timezone
	// * Set format of new entries in the RecentChanges page so new entries are localizable.
	function UsePhpbbDateSettings () {
		global $TimeFmt, $board_config, $userdata, $RecentChangesFmt;

		// Time format, convert from date() to strfdate()
		$dateformatcnv = array('d' => '%d', 'D' => '%a', 'j' => '%e', 'l' => '%A', 'N' => '%u', 
		                       'w' => '%w', 'W' => '%V', 'F' => '%B', 'm' => '%I', 'M' => '%b',
		                       'n' => '%e', 'o' => '%G', 'Y' => '%Y', 'y' => '%y', 'a' => '%p', 
		                       'A' => '%p', 'g' => '%I', 'G' => '%H', 'h' => '%I', 'H' => '%H', 
		                       'i' => '%M', 's' => '%S', 'c' => '%Y-%I-%dT%H:%M:%S', 
		                       'r' => '%a, %e %b %Y %H:%M:%S');

		if ($userdata['user_dateformat'] != '') {
			$TimeFmt = strtr($userdata['user_dateformat'], $dateformatcnv);
		}
		else {
			$TimeFmt = strtr($board_config['default_dateformat'], $dateformatcnv);
		}

		// Timezone
		$timezone = -1 * $userdata['user_timezone'];

		if ($timezone > 0) {
			$timezone = "+$timezone";
		}

		putenv("TZ=Etc/GMT$timezone");

		// Localizable new entries in RecentChanges pages.
		$RecentChangesFmt['$SiteGroup.AllRecentChanges'] = 
			'* [[{$Group}.{$Name}]]  . . . {(ftime when="@' . time() . '")} $[by] $AuthorLink: [=$ChangeSummary=]';
		$RecentChangesFmt['$Group.RecentChanges'] =
			'* [[{$Group}/{$Name}]]  . . . {(ftime when="@' . time() . '")} $[by] $AuthorLink: [=$ChangeSummary=]';
		$DraftRecentChangesFmt['$Group.RecentDraftChanges'] =
			'* [[{$Group}/{$Name}]]  . . . {(ftime when="@' . time() . '")} $[by] $AuthorLink: [=$ChangeSummary=]';
	}


	// Returns information about the theme to be used.
	function PhpbbStyleInfo($item) {
		global $db, $userdata, $board_config;
		static $row;

		if (!is_array ($row)) {
			if ($userdata['session_logged_in'] == 1) {
				$themes_id = $userdata['user_style'];
			}
			else {
				$themes_id = $board_config['default_style'];
			}

			$sql = "SELECT template_name, head_stylesheet, style_name FROM " . THEMES_TABLE . " WHERE themes_id = $themes_id";
			
			$rowset = $db->sql_query($sql);
			$row    = $db->sql_fetchrow($rowset) or die ("Error retrieving theme name");
		}
		
		return $row[$item];
	}


	// Read the board cofiguration from the database and pass back
	// as an array.
	function GetBoardConfig() {
		global $db;

		$sql = "SELECT * FROM " . CONFIG_TABLE;

		$rowset = $db->sql_query($sql);
		while ( $row = $db->sql_fetchrow($rowset) ) {
			$board_config[$row['config_name']] = $row['config_value'];
		}
		return $board_config;
	}


	// Function to create a link to the members profile in the forum on wiki pages.
	//
	// This can be used with the [[~username]] markup. To activate, add the following line 
	// to your PmWiki local/config.php:
	//    Markup ('[[~', '<links','/\\[\\[~(.*?)\\]\\]/e', "PhpbbUserProfile('$1')");	
	function PhpbbUserProfile ($username) {
		global $db, $PhpbbUrl, $phpEx;

		// Double quotes are passed escaped (\"), but these are stored as "&quot;" in the database
		$username = str_replace('\"', '&quot;', $username);

		$sql = "SELECT user_id
		        FROM   " . USERS_TABLE . "
		        WHERE  username = \"$username\"";

		$rowset = $db->sql_query($sql);	

		if ($row = $db->sql_fetchrow($rowset)) {
			// Found the userID, now pass PmWiki link markup for further processing.
			return  "[[$PhpbbUrl/profile.$phpEx?mode=viewprofile&amp;u=" . $row['user_id'] . " | $username]]";
		}
		else {
			// If no member was found, just return the name.
			return $username;
		}
	}


	// Adds the phpBB group memberships to the $AuthList array
	function AddPhpbbGroups($UserId) {
		global $db, $AuthList, $PhpbbGroupModSuffix;

		$result = array();

		$sql = "SELECT g.group_name
		        ,      g.group_moderator
		        FROM " . GROUPS_TABLE     . " g
		        ,    " . USER_GROUP_TABLE . " ug
		        WHERE  ug.group_id         = g.group_id  
		        AND    ug.user_id          = $UserId 
		        AND    g.group_single_user = 0
		        AND    user_pending        = 0";

		$rowset = $db->sql_query($sql);
		while ( $row = $db->sql_fetchrow($rowset) ) {
			$AuthList['@' . $row['group_name']] = 1;
			if ($row['group_moderator'] == $UserId) {
				$AuthList['@' . $row['group_name'] . $PhpbbGroupModSuffix] = 1;
			}
		}	
	}


	// Output Buffer processor for clients with disabled cookies.
	// Add the sesion identifier (sid=) to all links pointing to the local site.
	// If the client disabled cookies, this function is called through the
	// ob_start() function after the page is complete. The $content variable 
	// will contain the entire page.
	function AddSid ($content) {
		global $SiteUrl;

		if ((strpos($content, "<meta http-equiv='Refresh'")) === FALSE) {			
			// Regular page, replace all links
			$content = ProcessTag ($content, '<a ', "href='");
			$content = ProcessTag ($content, '<form ', "action='");
		}
		else {
			// Page from the Redirect() function, replace the link. The header
			// will already be sent, this is handled by the $EditRedirectFmt var.
			$content   = ProcessTag ($content, "<meta http-equiv='Refresh'", 'URL=');
		}
		return $content;
	}

	// Process a specified tag to add the session identifier
	function ProcessTag ($content, $tag, $parameter) {
		global $SiteUrl;
		// Split the page into an array, each element starting with the tag
		$links = explode($tag, $content);
	
		// Now process the array
		for ($i = 0; $i < count($links); $i++)
		{
			$parstart = strpos($links[$i], $parameter);
			if (! ($parstart === FALSE)) {
				// Found a link
				$linkstart = $parstart + strlen($parameter);
				$linkend   = strpos($links[$i], '\'', $linkstart);
				$thelink   = substr($links[$i], $linkstart, ($linkend - $linkstart) );
				
				// Only replace links starting with our own URL
				if (strpos($thelink, $SiteUrl) === 0 ) {
					$links[$i] = substr($links[$i], 0, $linkstart) . append_sid($thelink) . substr($links[$i], $linkend);
				}
			}
		}
		
		// And implode back
		return implode ($links, $tag);
	}


	// Inherit Gzip compression if set in phpBB.
	// Code copied from phpbb: includes/page_header.php
	function InheritGzip () {
		global $board_config;

		if ( $board_config['gzip_compress'] )
		{
			$phpver = phpversion();

			$useragent = (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) ? $HTTP_SERVER_VARS['HTTP_USER_AGENT'] : getenv('HTTP_USER_AGENT');

			if ( $phpver >= '4.0.4pl1' && ( strstr($useragent,'compatible') || strstr($useragent,'Gecko') ) )
			{
				if ( extension_loaded('zlib') )
				{
					ob_start('ob_gzhandler');
				}
			}
			else if ( $phpver > '4.0' )
			{
				if ( strstr($HTTP_SERVER_VARS['HTTP_ACCEPT_ENCODING'], 'gzip') )
				{
					if ( extension_loaded('zlib') )
					{
						ob_start();
						ob_implicit_flush(0);

						header('Content-Encoding: gzip');
					}
				}
			}
		}
	}


	// Sets the $AuthPromptFmt variable, which is displayed when an attempt is made to access
	// a page for which the client is not authorized. This function distinguishes between 
	// anonimous users and users signed in.
	function RedirectOnDeny () {
		global $userdata, $AuthPromptFmt, $PageStartFmt, $PageEndFmt, $PhpbbUrl
		,      $PhpbbUrl, $phpEx, $AuthPromptMemberFmt, $AuthPromptAnonymousFmt;

		SDV ($AuthPromptMemberFmt, array(&$PageStartFmt, "<br><p>You are not authorized to access this page.</p><br>", &$PageEndFmt));
		SDV ($AuthPromptAnonymousFmt, "<html><head>
			<meta http-equiv='Refresh' Content='0; URL=$PhpbbUrl/login.$phpEx' />
			<title>Redirect</title>
			</head><body></body></html>");

		if ($userdata['session_logged_in'] == 1) {
			$AuthPromptFmt = $AuthPromptMemberFmt;
		}
		else {
			$AuthPromptFmt = $AuthPromptAnonymousFmt;
		}
	}


	// ------------------------------------------------------------------------------------------
	// Functions hi-jacked from the phpBB includes/functions.php file.
	// We cannot include the file itself, because it contains a function "redirect", which
	// is already defined by pmWiki.

	// Simplified message_die
	function message_die($msg_code, $msg_text = '', $msg_title = '', $err_line = '', $err_file = '', $sql = '')
	{
		die ($msg_text);
	}

	// Encode an IP address to hex
	function encode_ip($dotquad_ip)
	{
		$ip_sep = explode('.', $dotquad_ip);
		return sprintf('%02x%02x%02x%02x', $ip_sep[0], $ip_sep[1], $ip_sep[2], $ip_sep[3]);
	}

	// Decode an IP address from hex
	function decode_ip($int_ip)
	{
		$hexipbang = explode('.', chunk_split($int_ip, 2, '.'));
		return hexdec($hexipbang[0]). '.' . hexdec($hexipbang[1]) . '.' . hexdec($hexipbang[2]) . '.' . hexdec($hexipbang[3]);
	}

	// Randomiser as used by the sessions.php script
	function dss_rand()
	{
		global $db, $board_config, $dss_seeded;

		$val = $board_config['rand_seed'] . microtime();
		$val = md5($val);
		$board_config['rand_seed'] = md5($board_config['rand_seed'] . $val . 'a');

		if($dss_seeded !== true)
		{
			$sql = "UPDATE " . CONFIG_TABLE . " SET
				config_value = '" . $board_config['rand_seed'] . "'
				WHERE config_name = 'rand_seed'";

			if( !$db->sql_query($sql) )
			{
				message_die(GENERAL_ERROR, "Unable to reseed PRNG", "", __LINE__, __FILE__, $sql);
			}

			$dss_seeded = true;
		}

		return substr($val, 4, 16);
	}