<?php

/**
  * BLOG:CMS: PHP/MySQL Personal Content Management System (CMS)
  * http://blogcms.com/
  * ----------------------------------------------------------------
  *
  * Copyright (C) 2003-2005 Radek HULÁN
  * http://hulan.cz/contact/
  *
  * Based on: 
  * ----------------------------------------------------------------
  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) 
  * Copyright (C) 2002-2003 The Nucleus Group
  *
  * ----------------------------------------------------------------
  * 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.
**/

global $nucleus, $CONF, $DIR_LIBS, $DIR_LANG, $manager, $member;

/****************************************
 security check for register_globals=on
****************************************/
global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_SESSION_VARS;
$aVarsToCheck = array('DIR_LIBS', 'CONF', 'DIR_LANG', 'DIR_PLUGINS', 'manager', 'nucleus', 'SQL_HOST', 'SQL_USER', 'SQL_PASSWORD', 'SQL_DATABASE');
foreach ($aVarsToCheck as $varName) {
	if (  isset($HTTP_GET_VARS[$varName])
		|| isset($HTTP_POST_VARS[$varName])
		|| isset($HTTP_COOKIE_VARS[$varName])
		|| isset($HTTP_ENV_VARS[$varName])
		|| isset($HTTP_SESSION_VARS[$varName])
		|| isset($HTTP_POST_FILES[$varName])
	)
    die('System is not configured properly - globalfunctions.php / 1.');
}
if (!is_dir($DIR_LIBS)) die('System is not configured properly - globalfunctions.php / 2.');
if (!is_dir($DIR_LANG)) die('System is not configured properly - globalfunctions.php / 3.');

/****************************************
 Fix for IIS, which doesn't set REQUEST_URI
****************************************/
if ( !isset( $_SERVER['REQUEST_URI'] ) ) {
	$_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'];
	if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
		$_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING'];
	}
}

/****************************************
  Fix for PHP as CGI hosts that set 
  SCRIPT_FILENAME to something ending in php.cgi 
  for all requests
****************************************/
if ( strpos($_SERVER['SCRIPT_FILENAME'], 'php.cgi') == strlen($_SERVER['SCRIPT_FILENAME']) - 7 )
	$_SERVER['SCRIPT_FILENAME'] = $_SERVER['PATH_TRANSLATED'];

/****************************************
 Fix for Dreamhost and other PHP as CGI hosts
****************************************/
if ( strstr( $_SERVER['SCRIPT_NAME'], 'php.cgi' ) )
	unset($_SERVER['PATH_INFO']);


$nucleus['version'] = '4.2.1f';

if (!isset($CONF))
	$CONF = array();
$CONF['debug'] = 0;

if (isset($CONF['Self'])) {
	$CONF['ItemURL'] = $CONF['Self'];
	$CONF['ArchiveURL'] = $CONF['Self'];
	$CONF['ArchiveListURL'] = $CONF['Self'];
	$CONF['MemberURL'] = $CONF['Self'];
	$CONF['SearchURL'] = $CONF['Self'];
	$CONF['BlogURL'] = $CONF['Self'];
	$CONF['CategoryURL'] = $CONF['Self'];
}

if (getNucleusPatchLevel() > 0)	
	$nucleus['version'].='/'.getNucleusPatchLevel();

/****************************************
  this document is in UTF-8 encoding !
****************************************/ 
global $global_utf,$global_asc; 

/* czech, greek, german and russian characters to ASCII */
$global_utf=explode(',',"á,č,ď,é,ě,í,ĺ,ľ,ň,ó,ř,ŕ,š,ť,ú,ů,ý,ž,ä,ë,ö,ü,Á,Č,Ď,É,Ě,Í,Ĺ,Ľ,Ň,Ó,Ř,Š,Ť,Ú,Ů,Ü,Ý,Ž,Ä,Ë,Ö,α,ά,β,γ,δ,ε,έ,ζ,η,ή,θ,ι,ί,κ,λ,μ,ν,ξ,ο,ό,π,ρ,σ,ς,τ,υ,ύ,φ,χ,ψ,ω,ώ,Α,Ά,Β,Γ,Δ,Ε,Έ,Ζ,Η,Ή,Θ,Ι,Ί,Κ,Λ,Μ,Ν,Ξ,Ο,Ό,Π,Ρ,Σ,Τ,Υ,Ύ,Φ,Χ,Ψ,Ω,Ώ,КВ,кв,КС,кс,Б,б,Ц,ц,Д,д,Э,Е,е,Ф,ф,Г,г,Х,х,И,и,Й,й,К,к,Л,л,М,м,Н,н,П,п,Ы,ы,З,з,Ч ,ч ,Ш ,ш ,Щ  ,щ  ,Ж ,ж ,я ,ь,ю ,Ю ");
$global_asc=explode(',',"a,c,d,e,e,i,l,l,n,o,r,r,s,t,u,u,y,z,a,e,o,u,A,C,D,E,E,I,L,L,N,O,R,S,T,U,U,U,Y,Z,A,E,O,a,a,v,c,d,e,e,z,i,i,t,i,i,k,l,m,n,x,o,o,p,r,s,s,t,i,i,f,x,x,o,o,A,A,V,C,D,E,E,Z,I,I,T,I,I,K,L,M,N,X,O,O,P,R,S,T,I,I,F,X,X,O,O,Q ,q ,X ,x ,B,b,C,c,D,d,E,E,e,F,f,G,g,H,h,I,i,J,j,K,k,L,l,M,m,N,n,P,p,Y,y,Z,z,Ch,ch,Sh,sh,Sht,sht,Zh,zh,ja,j,ju,Ju");

/* some more russian characters - uncomment these if you need it */
// $global_utf=array_merge($global_utf,explode(',',"Р,р,С,с,Т,т,У,у,В,в,В,в,");
// $global_asc=array_merge($global_asc,explode(',',"R,r,S,s,T,t,U,u,V,v,W,w,");

/*
	Indicates when BLOG:CMS should display startup errors. Set to 1 if you want
	the error enabled (default), false otherwise

	alertOnHeadersSent
		Displays an error when visiting a public Nucleus page and headers have
		been sent out to early. This usually indicates an error in either a
		configuration file or a language file, and could cause Nucleus to
		malfunction
	alertOnSecurityRisk
		Displays an error only when visiting the admin area, and when one or
		more of the installation files (install.php, install.sql, upgrades/
		directory) are still on the server.
*/
$CONF['alertOnHeadersSent'] = 0;
$CONF['alertOnSecurityRisk'] = 1;

/**
  * returns the currently used version (100 = 1.00, 101 = 1.01, etc...)
  */
function getNucleusVersion() {
	return 400;
}

/**
 * power users can install patches in between nucleus releases. These patches
 * usually add new functionality in the plugin API and allow those to
 * be tested without having to install CVS.
 */
function getNucleusPatchLevel() {
  return 0;
}

if ($CONF['debug'])
	error_reporting(E_ALL & ~E_NOTICE);	// report almost all errors except uninitialused variables!
else
	error_reporting(E_ERROR | E_WARNING | E_PARSE);

// include DB layer
if (!is_callable('sql_connect')) 
	include_once($DIR_LIBS . 'db.php');

// we will use postVar, getVar, ... methods instead of HTTP_GET_VARS or _GET
if (!is_callable('postVar')) {
	if (phpversion() >= '4.1.0')
		include_once($DIR_LIBS . 'vars4.1.0.php');
	else
		include_once($DIR_LIBS . 'vars4.0.6.php');
}


function intPostVar($name) { return intval(postVar($name));}
function intGetVar($name) { return intval(getVar($name));}
function intRequestVar($name) { return intval(requestVar($name)); }
function intCookieVar($name) { return intval(cookieVar($name)); }

// get all variables that can come from the request and put them in the global scope
$blogid			= intRequestVar('blogid');
$itemid			= intRequestVar('itemid');
$catid			= intRequestVar('catid');
$memberid		= intRequestVar('memberid');
$archivelist	= requestVar('archivelist');
$imagepopup		= requestVar('imagepopup');
$archive 		= requestVar('archive');

$skinid			= intRequestVar('skinid');

$query			= requestVar('query');
$highlight		= requestVar('highlight');

$amount			= intRequestVar('amount');
$action			= htmlspecialchars(requestVar('action'));
$nextaction		= htmlspecialchars(requestVar('nextaction'));

$maxresults     = intRequestVar('maxresults');
$startpos       = intRequestVar('startpos');

// generator header
if (!headers_sent()) header('Generator: BLOG:CMS ' . $nucleus['version']);

// include core classes that are needed for login & plugin handling
include($DIR_LIBS . 'MEMBER.php');
include($DIR_LIBS . 'ACTIONLOG.php');
include($DIR_LIBS . 'MANAGER.php');
include($DIR_LIBS . 'PLUGIN.php');

$manager =& MANAGER::instance();

// make sure there's no unnecessary escaping:
set_magic_quotes_runtime(0);

// only needed when updating logs
if ($CONF['UsingAdminArea']) {
	include($DIR_LIBS . 'xmlrpc.inc.php');	// XML-RPC client classes
	include_once($DIR_LIBS . 'ADMIN.php');
}

// connect to sql
sql_connect(true);

// makes sure database connection gets closed on script termination
register_shutdown_function('sql_disconnect');

// read config
getConfig();

// ****************************************
// normal URLs - formatted like Fancy ones
// ****************************************
$d=requestVar('item');
if ( !empty($d) ) {
  $d=unicode_decode($d);
  if (is_numeric($d))
	$itemid=intval($d);
  else {
	$query  = sql_query("SELECT iblog, inumber FROM ".sql_table('item')." WHERE iurltitle='".sql_escape($d)."'");
	if ($r = sql_fetch_object($query)){
	  $blogid = intval($r->iblog);
	  $itemid = intval($r->inumber);
	} else {
	  $q=sql_query("SELECT inumber FROM ".sql_table('plugin_fancierurl')." WHERE iurltitle='".sql_escape($d)."'");
	  if ($r = sql_fetch_object($q)) $itemid = $r->inumber;
	  unset($q);
	}
  }
}
$d=requestVar('category');
if ( !empty($d) ) {
  $d=unicode_decode($d);
  if (is_numeric($d))
	$catid=intval($d);
  else {
	$q=sql_query("select catid, cblog from ".sql_table("category")." where iurltitle='".sql_escape($d)."'");
	if ($r=sql_fetch_object($q)) {
		$catid = intval($r->catid);
		$blogid = intval($r->cblog);
	}
	unset($q);
  }
}
$d=requestVar('member');
if ( !empty($d) ) {
  $d=unicode_decode($d);
  if (is_numeric($d))
	$memberid=intval($d);
  else {
	$q=sql_query("select mnumber from ".sql_table("member")." where mname='".sql_escape($d)."'");
	if ($r=sql_fetch_object($q)) $memberid = intval($r->mnumber);
	unset($q);
  }
}
$d=requestVar('blog');
if ( !empty($d) ) {
  $d=unicode_decode($d);
  if (is_numeric($d))
	$blogid=intval($d);
  else {
	$q=sql_query("select bnumber from ".sql_table("blog")." where bshortname='".sql_escape($d)."'");
	if ($r=sql_fetch_object($q)) $blogid = intval($r->bnumber);
	unset($q);
  }
}
$d=requestVar('archives');
if ( !empty($d) ) {
  $d=unicode_decode($d);
  if (is_numeric($d))
	$archivelist=intval($d);
  else {
	$q=sql_query("select bnumber from ".sql_table("blog")." where bshortname='".sql_escape($d)."'");
	if ($r=sql_fetch_object($q)) $archivelist = intval($r->bnumber);
	unset($q);
  }
}

// ****************************************
// FancyURLs URLs?
// ****************************************
if ($CONF['URLMode'] != 'numeric') 
	setGlobalVariables('index');

// automatically use simpler toolbar for mozilla
if ( ($CONF['DisableJsTools'] == 0) 
	&& strstr(serverVar('HTTP_USER_AGENT'),'Mozilla/5.0') 
	&& strstr(serverVar('HTTP_USER_AGENT'),'Gecko') 
   )
	$CONF['DisableJsTools'] = 2;

// login if cookies set
$member =& new MEMBER();

// login/logout when required or renew cookies
if ($action == 'login') {
	// Form Authentication
	$login 	= postVar('login');
	$pw 	= postVar('password');
	$shared	= intPostVar('shared');	// shared computer or not

	if ($member->login($login,$pw)) {

		$member->newCookieKey();
		$member->setCookies($shared);

		// allows direct access to parts of the admin area after logging in
		if ($nextaction)
			$action = $nextaction;

		$manager->notify('LoginSuccess',array('member' => &$member));
		ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
	} else {
		$manager->notify('LoginFailed',array('username' => $login));
		ACTIONLOG::add(INFO, 'Login failed for ' . $login);
	}
} elseif (serverVar('PHP_AUTH_USER') && serverVar('PHP_AUTH_PW')) {
	// HTTP Authentication
    $login  = serverVar('PHP_AUTH_USER');
    $pw     = serverVar('PHP_AUTH_PW');
    if ($member->login($login,$pw)) {
		$manager->notify('LoginSuccess',array('member' => &$member));
        ACTIONLOG::add(INFO, "HTTP authentication successful for $login");
    } else {
		$manager->notify('LoginFailed',array('username' => $login));
        ACTIONLOG::add(INFO, 'HTTP authentication failed for ' . $login);
        //Since bad credentials, generate an apropriate error page
        header("WWW-Authenticate: Basic realm=\"BLOG:CMS {$nucleus['version']}\"");
        header('HTTP/1.0 401 Unauthorized');
        echo 'Invalid username or password';
        exit;
    }
} elseif (($action == 'logout') && (!headers_sent()) && cookieVar($CONF['CookiePrefix'].'user')){
	// remove cookies on logout
	setcookie($CONF['CookiePrefix'] .'user','',(time()-2592000),$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
	setcookie($CONF['CookiePrefix'] .'loginkey','',(time()-2592000),$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
	$manager->notify('Logout',array('username' => cookieVar($CONF['CookiePrefix'] .'user')));
} elseif (cookieVar($CONF['CookiePrefix'] .'user')) {
	// Cookie Authentication
	$res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] .'user'), cookieVar($CONF['CookiePrefix'] .'loginkey'));

	// renew cookies when not on a shared computer
	if ($res && (cookieVar($CONF['CookiePrefix'] .'sharedpc') != 1) && (!headers_sent()))
		$member->setCookies();
}

// login completed
$manager->notify('PostAuthentication',array('loginOk' => $member->isLoggedIn()));

// load other classes
include($DIR_LIBS . 'PARSER.php');
include($DIR_LIBS . 'SKIN.php');
include($DIR_LIBS . 'TEMPLATE.php');
include($DIR_LIBS . 'BLOG.php');
include($DIR_LIBS . 'COMMENTS.php');
include($DIR_LIBS . 'COMMENT.php');
//include($DIR_LIBS . 'ITEM.php');
include($DIR_LIBS . 'NOTIFICATION.php');
include($DIR_LIBS . 'BAN.php');
include($DIR_LIBS . 'PAGEFACTORY.php');
include($DIR_LIBS . 'SEARCH.php');


// set lastVisit cookie (if allowed)
if (!headers_sent()) {
	if ($CONF['LastVisit'])
		setcookie($CONF['CookiePrefix'] .'lastVisit',time(),time()+2592000,$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
	else
		setcookie($CONF['CookiePrefix'] .'lastVisit','',(time()-2592000),$CONF['CookiePath'],$CONF['CookieDomain'],$CONF['CookieSecure']);
}

// read language file, only after user has been initialized
$language = getLanguageName();
include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');

function sendContentType($contenttype, $pagetype = '', $charset = _CHARSET) {
	global $manager, $CONF;
  $accept=false;
	if ($contenttype == 'application/xhtml+xml') {
    if(stristr(serverVar("HTTP_ACCEPT"),"application/xhtml+xml")) {
       if(preg_match("/application\/xhtml\+xml;q=0(\.[1-9]+)/i",serverVar("HTTP_ACCEPT"), $matches)) {
          $xhtml_q = $matches[1];
          if(preg_match("/text\/html;q=0(\.[1-9]+)/i",serverVar("HTTP_ACCEPT"), $matches)) {
             $html_q = $matches[1];
             if($xhtml_q >= $html_q) $accept=true;
          }
       } else
          $accept=true;
    }
    if (stristr(serverVar("HTTP_USER_AGENT"),"W3C_Validator")) $accept=true;
  }
  // cannot accept xhtml+xml
  if (!$accept && ($contenttype == 'application/xhtml+xml')) $contenttype='text/html';
  // admin area fix
	if (	($CONF['UsingAdminArea'] && !$CONF['debug']) ) $contenttype = 'text/html';
	// notification
	if (!headers_sent())
		$manager->notify(
			'PreSendContentType',
			array(
				'contentType' => &$contenttype,
				'charset' => &$charset,
				'pageType' => $pagetype
			)
		);
	// xml
	if($contenttype == "application/xhtml+xml")
    $CONF['application-xhtml-xml']=true;
  else
    $CONF['application-xhtml-xml']=false;
	// content type
	header('Vary: Accept');
	header('Content-Type: ' . $contenttype . '; charset=' . _CHARSET);
}

/**
 * Errors before the database connection has been made
 */
function startUpError($msg, $title) {
	?>
	<html xmlns="http://www.w3.org/1999/xhtml">
		<head><title><?php echo htmlspecialchars($title)?></title></head>
		<body>
			<h1><?php echo htmlspecialchars($title)?></h1>
			<?php echo $msg?>
		</body>
	</html>
	<?php	exit;
}

/**
 * Highlights a specific query in a given HTML text (not within HTML tags) and returns it
 *
 * @param $text
 *		text to be highlighted
 * @param $expression
 *		regular expression to be matched (can be an array of expressions as well)
 * @param $highlight
 *		highlight to be used (use \\0 to indicate the matched expression)
 *
 */
function highlight($text, $expression, $highlight) {
	if (!$highlight || !$expression) return $text;
	if (is_array($expression) && (count($expression) == 0))
		return $text;

	// add a tag in front (is needed for preg_match_all to work correct)
	$text = '<!--h-->'.$text;

	// split the HTML up so we have HTML tags
	// $matches[0][i] = HTML + text
	// $matches[1][i] = HTML
	// $matches[2][i] = text
	preg_match_all('/(<[^>]+>)([^<>]*)/', $text, $matches);

	// throw it all together again while applying the highlight to the text pieces
	$result = '';
	for ($i = 0; $i < sizeof($matches[2]); $i++) {
		if ($i != 0) $result .= $matches[1][$i];

		if (is_array($expression)) {
			foreach ($expression as $regex)
				if ($regex)
					$matches[2][$i] = @eregi_replace($regex,$highlight,$matches[2][$i]);
			$result .= $matches[2][$i];
		} else {
			$result .= @eregi_replace($expression,$highlight,$matches[2][$i]);
		}
	}

	return $result;
}

/**
 * Parses a query into an array of expressions that can be passed on to the highlight method
 */
function parseHighlight($query) {
	// TODO: add more intelligent splitting logic

	// get rid of quotes
	$query = preg_replace('/\'|"/','',$query);

	if (!query) return array();

	$aHighlight = explode(' ', $query);

	for ($i = 0; $i<count($aHighlight); $i++) {
		$aHighlight[$i] = trim($aHighlight[$i]);
		if (strlen($aHighlight[$i]) < 3)
			unset($aHighlight[$i]);
	}

	if (count($aHighlight) == 1)
		return $aHighlight[0];
	else
		return $aHighlight;
}

/**
  * Checks if email address is valid
  */
function isValidMailAddress($address) {
	if (preg_match('/^[a-zA-Z0-9\._-]+@[a-zA-Z0-9\._-]+\.[A-Za-z]{2,5}$/', $address))
		return 1;
	else
		return 0;
}

// some helper functions
function getBlogIDFromName($name) {
	return quickQuery('SELECT bnumber as result FROM '.sql_table('blog').' WHERE bshortname="'.sql_escape($name).'"');
}
function getBlogNameFromID($id) {
  return quickQuery('SELECT bname as result FROM '.sql_table('blog').' WHERE bnumber='.intval($id));
}
function getBlogIDFromItemID($itemid) {
  return quickQuery('SELECT iblog as result FROM '.sql_table('item').' WHERE inumber='.intval($itemid));
}
function getBlogIDFromCommentID($commentid) {
	return quickQuery('SELECT cblog as result FROM '.sql_table('comment').' WHERE cnumber='.intval($commentid));
}
function getBlogIDFromCatID($catid) {
	return quickQuery('SELECT cblog as result FROM '.sql_table('category').' WHERE catid='.intval($catid));
}
function getCatIDFromName($name) {
  return quickQuery('SELECT catid as result FROM '.sql_table('category').' WHERE cname="'.sql_escape($name).'"');
}
function quickQuery($query) {
	$r = sql_query($query);
	if ($obj = sql_fetch_object($r))
	  return $obj->result;
	else
	  return '';
}

function getPluginNameFromPid($pid) {
	$query =  sql_query('SELECT pfile FROM '.sql_table('plugin').' WHERE pid='.intval($pid));
	$obj = sql_fetch_object($query);
	return $obj->pfile;
}

function selector() {
	global $itemid, $blogid, $memberid, $query, $amount, $archivelist, $maxresults;
	global $archive, $skinid, $blog, $memberinfo, $CONF, $member;
	global $imagepopup, $catid;
	global $manager;

	// first, let's see if the site is disabled or not
	if ($CONF['DisableSite'] && !$member->isAdmin()) {
		header('Expires: 0');
		header('Pragma: no-cache');
		header('Location: ' . $CONF['DisableSiteURL']);
		exit;
	}

	// show error when headers already sent out
	if (headers_sent() && $CONF['alertOnHeadersSent']) {

		// try to get line number/filename (extra headers_sent params only exists in PHP 4.3+)
		if (function_exists('version_compare') && version_compare('4.3.0', phpversion(), '<=')) {
			headers_sent($hsFile, $hsLine);
			$extraInfo = ' in <code>'.$hsFile.'</code> line <code>'.$hsLine.'</code>';
		} else {
			$extraInfo = '';
		}


		startUpError(
			'<p>The page headers have already been sent out'.$extraInfo.'. This could cause BLOG:CMS not to work in the expected way.</p><p>Usually, this is caused by spaces or newlines at the end of the <code>cfg.php</code> file, at the end of the language file or at the end of a plugin file. Please check this and try again.</p><p>If you don\'t want to see this error message again, without solving the problem, set <code>$CONF[\'alertOnHeadersSent\']</code> in <code>globalfunctions.php</code> to <code>0</code></p>',
			'Page headers already sent'
		);
		exit;
	}

	// make is so ?archivelist without blogname or blogid shows the archivelist
	// for the default weblog
	if (serverVar('QUERY_STRING') == 'archivelist')
		$archivelist = $CONF['DefaultBlog'];

	// now decide which type of skin we need
	if ($itemid) {
		// itemid given -> only show that item
		$type = 'item';
		if (!$manager->existsItem($itemid,0,0))
			doError(_ERROR_NOSUCHITEM);


		global $itemidprev, $itemidnext, $catid, $itemtitlenext, $itemtitleprev;

		// 1. get timestamp and blogid for item
		$query = 'SELECT itime, iblog FROM '.sql_table('item').' WHERE inumber=' . intval($itemid);
		$res = sql_query($query);
		$obj = sql_fetch_object($res);

		// if a different blog id has been set through the request or selectBlog(),
		// deny access
		if ($blogid && (intval($blogid) != $obj->iblog))
			doError(_ERROR_NOSUCHITEM);

		$blogid = $obj->iblog;
		$timestamp = strtotime($obj->itime);

		$b =& $manager->getBlog($blogid);
		if ($b->isValidCategory($catid))
			$catextra = ' and icat=' . $catid;

		// get previous itemid and title
		$query = 'SELECT inumber, ititle FROM '.sql_table('item').' WHERE UNIX_TIMESTAMP(itime)<' . $timestamp . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime DESC LIMIT 1';
		$res = sql_query($query);
		$obj = sql_fetch_object($res);
		if ($obj) {
			$itemidprev = intval($obj->inumber);
			$itemtitleprev = $obj->ititle;
    		}

		// get next itemid and title
		$query = 'SELECT inumber, ititle FROM '.sql_table('item').' WHERE UNIX_TIMESTAMP(itime)>' . $timestamp . ' and itime <= ' . mysqldate(time()) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime ASC LIMIT 1';
		$res = sql_query($query);
		$obj = sql_fetch_object($res);
		if ($obj) {
			$itemidnext = intval($obj->inumber);
			$itemtitlenext = $obj->ititle;
		}

	} elseif ($archive) {
		// show archive
		$type = 'archive';

		// get next and prev month links
		global $archivenext, $archiveprev, $archivetype;

		sscanf($archive,'%d-%d-%d',$y,$m,$d);
		if ($d != 0) {
			$archivetype = _ARCHIVETYPE_DAY;
			$t = mktime(0,0,0,$m,$d,$y);
			$archiveprev = strftime('%Y-%m-%d',$t - (24*60*60));
			$archivenext = strftime('%Y-%m-%d',$t + (24*60*60));

		} else {
			$archivetype = _ARCHIVETYPE_MONTH;
			$t = mktime(0,0,0,$m,1,$y);
			$archiveprev = strftime('%Y-%m',$t - (1*24*60*60));
			$archivenext = strftime('%Y-%m',$t + (32*24*60*60));
		}


	} elseif ($archivelist) {
		$type = 'archivelist';
		if (intval($archivelist) != 0)
			$blogid = $archivelist;
		else
			$blogid = getBlogIDFromName($archivelist);
		if (!$blogid) doError(_ERROR_NOSUCHBLOG);
	} elseif ($query) {
	    global $startpos;
		$type = 'search';
		$query = sql_unescape($query);
		if (intval($blogid)==0)
			$blogid = getBlogIDFromName($blogid);
		if (!$blogid) doError(_ERROR_NOSUCHBLOG);
	} elseif ($memberid) {
		$type = 'member';
		if (!MEMBER::existsID($memberid))
			doError(_ERROR_NOSUCHMEMBER);
		$memberinfo = MEMBER::createFromID($memberid);

	} elseif ($imagepopup) {
		// media object (images etc.)
		$type = 'imagepopup';

		// TODO: check if media-object exists
		// TODO: set some vars?
	} else {
		// show regular index page
	    global $startpos;
		$type = 'index';
	}

	// decide which blog should be displayed
	if (!$blogid)
		$blogid = $CONF['DefaultBlog'];

	if (!$manager->existsBlogID($blogid))
		doError(_ERROR_NOSUCHBLOG);

	$b =& $manager->getBlog($blogid);
	$blog = $b;	// references can't be placed in global variables?

	// set catid if necessary
	if ($catid)
		$blog->setSelectedCategory($catid);

	// decide which skin should be used
	if ($skinid != '' && ($skinid == 0))
		selectSkin($skinid);
	if (!$skinid)
		$skinid = $blog->getDefaultSkin();

	$skin =& new SKIN($skinid);
	if (!$skin->isValid) doError(_ERROR_NOSUCHSKIN);

	// parse the skin
	$skin->parse($type);
}

/**
  * Show error skin with given message. An optional skin-object to use can be given
  */
function doError($msg, $skin = '') {
	global $errormessage, $CONF, $skinid, $blogid, $manager;

	if ($skin == '') {
		if (SKIN::existsID($skinid)) {
			$skin =& new SKIN($skinid);
		} elseif ($manager->existsBlogID($blogid)) {
			$blog =& $manager->getBlog($blogid);
			$skin =& new SKIN($blog->getDefaultSkin());
		} elseif ($CONF['DefaultBlog']) {
			$blog =& $manager->getBlog($CONF['DefaultBlog']);
			$skin =& new SKIN($blog->getDefaultSkin());
		} else {
			// this statement should actually never be executed
			$skin =& new SKIN($CONF['BaseSkin']);
		}
	}

	$errormessage = $msg;
	$skin->parse('error');
	exit;
}

function getConfig() {
	global $CONF;
	$res = sql_query('SELECT * FROM '.sql_table('config'));
	while ($obj = sql_fetch_object($res)) $CONF[$obj->name] = $obj->value;
}

// some checks for names of blogs, categories, templates, members, ...
function isValidShortName($name) {		return eregi('^[a-z0-9]+$', $name); }
function isValidDisplayName($name) {	return eregi('^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$', $name); }
function isValidCategoryName($name) {	return 1; }
function isValidTemplateName($name) {	return eregi('^[a-z0-9/]+$', $name); }
function isValidSkinName($name) {		return eregi('^[a-z0-9/]+$', $name); }

// add and remove linebreaks
function addBreaks($var) { 				return nl2br($var); }
function removeBreaks($var) {			return preg_replace("/<br \/>([\r\n])/","$1",$var); }

/**
  * Generate a 'pronouncable' password
  * (http://www.zend.com/codex.php?id=215&single=1)
  */
function genPassword($length){
    srand((double)microtime()*1000000);
    $vowels = array('a', 'e', 'i', 'o', 'u');
    $cons = array('b', 'c', 'd', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'u', 'v', 'w', 'tr','cr', 'br', 'fr', 'th', 'dr', 'ch', 'ph', 'wr', 'st', 'sp', 'sw', 'pr', 'sl', 'cl');
    $num_vowels = count($vowels);
    $num_cons = count($cons);
    for($i = 0; $i < $length; $i++) $password .= $cons[rand(0, $num_cons - 1)] . $vowels[rand(0, $num_vowels - 1)];
    return substr($password, 0, $length);
}

// shortens a text string to maxlength ($toadd) is what needs to be added
// at the end (end length is <= $maxlength)
function shorten($text, $maxlength, $toadd) {
	// 1. remove entities...
	$trans = get_html_translation_table(HTML_ENTITIES);
	$trans = array_flip($trans);
	$text = strtr($text, $trans);
	// 2. the actual shortening
	$text.=" ";
 	if (strlen($text) > $maxlength) {
 	  $pos=strpos(substr($text,$maxlength)," ");
 	  if ($pos===false) $pos=0;
    $text = substr($text,0,$maxlength+$pos).$toadd;
  }
	return $text;
}

/**
  * Converts a unix timestamp to a mysql DATETIME format, and places
  * quotes around it.
  */
function mysqldate($timestamp) {
	return '"' . date('Y-m-d H:i:s',$timestamp) . '"';
}

/**
  * functions for use in index.php
  */
function selectBlog($shortname) {
	global $blogid, $archivelist;
	$blogid = getBlogIDFromName($shortname);
	// also force archivelist variable, if it is set
	if ($archivelist) $archivelist = $blogid;
}

function selectSkin($skinname) {
	global $skinid;
	$skinid = SKIN::getIdFromName($skinname);
}

/**
 * Can take either a category ID or a category name (be aware that
 * multiple categories can have the same name)
 */
function selectCategory($cat) {
	global $catid;
	if (is_numeric($cat))
		$catid = intval($cat);
	else
		$catid = getCatIDFromName($cat);
}

function selectItem($id){
	global $itemid;
	$itemid = intval($id);
}

// force the use of a language file (warning: can cause warnings)
function selectLanguage($language) {
	global $DIR_LANG;
	include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
}

function parseFile($filename) {
	$handler =& new ACTIONS('fileparser');
	$parser =& new PARSER(SKIN::getAllowedActionsForType('fileparser'), $handler);
	$handler->parser =& $parser;

	if (!file_exists($filename)) doError('A file is missing');

	$fsize = filesize($filename);
	if ($fsize <= 0)
		return;

	// read file
	$fd = fopen ($filename, 'r');
	$contents = fread ($fd, $fsize);
	fclose ($fd);

	// parse file contents
	$parser->parse($contents);
}

/**
  * Outputs a debug message
  */
function debug($msg) {
	echo '<p><b>' . $msg . "</b></p>\n";
}

// shortcut
function addToLog($level, $msg) { ACTIONLOG::add($level, $msg); }

// shows a link to help file
function help($id) {
	echo helpHtml($id);
}

function helpHtml($id) {
	return helplink($id) . '<img src="documentation/action_go.gif" alt="'._HELP_TT.'"/></a>';
}

function helplink($id) {
	return '<a href="documentation/help.html#'. $id . '" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); return help(this.href);">';
}

function getMailFooter() {
	$message = "\n\n-----------------------------";
	$message .=  "\n   Powered by BLOG:CMS";
	$message .=  "\n(http://blogcms.com/)";
	return $message;
}

/**
  * Returns the name of the language to use
  * preference priority: member - site
  * defaults to english when no good language found
  *
  * checks if file exists, etc...
  */
function getLanguageName() {
	global $CONF, $member;

	if ($member) {
		// try to use members language
		$memlang = $member->getLanguage();

		if (($memlang != '') && (checkLanguage($memlang)))
			return $memlang;
	}

	// use default language
	if (checkLanguage($CONF['Language']))
		return $CONF['Language'];
	else
		return 'english';
}

/**
  * Includes a PHP file. This method can be called while parsing templates and skins
  */
function includephp($filename) {
	// make predefined variables global, so most simple scripts can be used here

	// apache (names taken from PHP doc)
	global $GATEWAY_INTERFACE, $SERVER_NAME, $SERVER_SOFTWARE, $SERVER_PROTOCOL;
	global $REQUEST_METHOD, $QUERY_STRING, $DOCUMENT_ROOT, $HTTP_ACCEPT;
	global $HTTP_ACCEPT_CHARSET, $HTTP_ACCEPT_ENCODING, $HTTP_ACCEPT_LANGUAGE;
	global $HTTP_CONNECTION, $HTTP_HOST, $HTTP_REFERER, $HTTP_USER_AGENT;
	global $REMOTE_ADDR, $REMOTE_PORT, $SCRIPT_FILENAME, $SERVER_ADMIN;
	global $SERVER_PORT, $SERVER_SIGNATURE, $PATH_TRANSLATED, $SCRIPT_NAME;
	global $REQUEST_URI;

	// php (taken from PHP doc)
	global $argv, $argc, $PHP_SELF, $HTTP_COOKIE_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS;
	global $HTTP_POST_FILES, $HTTP_ENV_VARS, $HTTP_SERVER_VARS, $HTTP_SESSION_VARS;

	// other
	global $PATH_INFO, $HTTPS, $HTTP_RAW_POST_DATA, $HTTP_X_FORWARDED_FOR;

  if (file_exists($filename)) include($filename);
}

/**
  * Checks if a certain language/plugin exists
  */
function checkLanguage($lang) {
	global $DIR_LANG ;
	return file_exists($DIR_LANG . ereg_replace( '[\\|/]', '', $lang) . '.php');
}
function checkPlugin($plug) {
	global $DIR_PLUGINS;
	return file_exists($DIR_PLUGINS . ereg_replace( '[\\|/]', '', $plug) . '.php');
}


if (!isset($CONF['Self']))
	$CONF['Self']=$CONF['IndexURL'];
	
$CONF['ItemURL'] = $CONF['Self'];
$CONF['ArchiveURL'] = $CONF['Self'];
$CONF['ArchiveListURL'] = $CONF['Self'];
$CONF['MemberURL'] = $CONF['Self'];
$CONF['SearchURL'] = $CONF['Self'];
$CONF['BlogURL'] = $CONF['Self'];
$CONF['CategoryURL'] = $CONF['Self'];

/**
  * Centralisation of the functions that generate links
  */
function createItemLink($itemid, $extra = '') {
	global $CONF;
	$link=fancyLink($itemid);
	return addLinkParams($link, $extra);
}
function createMemberLink($memberid, $extra = '') {
	global $CONF;
	switch ($CONF['URLMode']) {
		case 'pathinfo':
			$query=sql_query("select mname from ".sql_table("member")." where mnumber=".intval($memberid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->mname) ) 
				$link = $CONF['MemberURL'] . '/member/' . sql_unescape($row->mname);
			else
				$link = $CONF['MemberURL'] . '/member/' . $memberid;
			break;
		case 'normal':
			$query=sql_query("select mname from ".sql_table("member")." where mnumber=".intval($memberid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->mname) )
				$link = $CONF['MemberURL'] . '?member=' . sql_unescape($row->mname);
			else
				$link = $CONF['MemberURL'] . '?memberid=' . $memberid;
			break;
		case 'numeric':
			$link = $CONF['MemberURL'] . '?memberid=' . $memberid;
			break;
	}
	return addLinkParams($link, $extra);
}
function createCategoryLink($catid, $extra = '') {
	global $CONF;
	switch ($CONF['URLMode']) {
		case 'pathinfo':
			$query=sql_query("select iurltitle from ".sql_table("category")." where catid=".strval($catid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->iurltitle) ) 
				$link = $CONF['CategoryURL'] . '/category/' . sql_unescape($row->iurltitle);
			else
				$link = $CONF['CategoryURL'] . '/catid/' . $catid;
			break;
		case 'normal':
			$query=sql_query("select iurltitle from ".sql_table("category")." where catid=".strval($catid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->iurltitle) )
				$link = $CONF['CategoryURL'] . '?category=' . sql_unescape($row->iurltitle);
			else
				$link = $CONF['CategoryURL'] . '?catid=' . $catid;
			break;
		case 'numeric':
			$link = $CONF['CategoryURL'] . '?catid=' . $catid;
			break;
	}
	return addLinkParams($link, $extra);
}
function createArchiveListLink($blogid = '', $extra = '') {
	global $CONF;
	if (!$blogid) $blogid = $CONF['DefaultBlog'];
	switch ($CONF['URLMode']) {
		case 'pathinfo':
			$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($blogid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) )
				$link = $CONF['ArchiveListURL'] . '/archives/' . sql_unescape($row->bshortname);
			else
				$link = $CONF['ArchiveListURL'] . '/archives/' . $blogid;
			break;
		case 'normal':
			$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($blogid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) )
				$link = $CONF['ArchiveListURL'] . '?archives=' . sql_unescape($row->bshortname);
			else
				$link = $CONF['ArchiveListURL'] . '?archivelist=' . $blogid;
			break;
		case 'numeric':
			$link = $CONF['ArchiveListURL'] . '?archivelist=' . $blogid;
			break;
	}
	return addLinkParams($link, $extra);
}
function createArchiveLink($blogid, $archive, $extra = '') {
	global $CONF;
	switch ($CONF['URLMode']) {
		case 'pathinfo':
			$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($blogid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) )
				$link = $CONF['ArchiveURL'] . '/archive/'.$row->bshortname.'/' . $archive;
			else
				$link = $CONF['ArchiveURL'] . '/archive/'.$blogid.'/' . $archive;
			break;
		case 'normal':
			$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($blogid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) )
				$link = $CONF['ArchiveURL'] . '?blog='.$row->bshortname.'&amp;archive=' . $archive;
			else
				$link = $CONF['ArchiveURL'] . '?blogid='.$blogid.'&amp;archive=' . $archive;
			break;
		case 'numeric':
			$link = $CONF['ArchiveURL'] . '?blogid='.$blogid.'&amp;archive=' . $archive;
			break;
	}
	return addLinkParams($link, $extra);
}
function createBlogLink($url, $params) {
	return addLinkParams($url . '?', $params);
}
function createBlogidLink($blogid, $params = '') {
	global $CONF;
	switch ($CONF['URLMode']) {
		case 'pathinfo':
			$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($blogid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) )
				$link = $CONF['BlogURL'] . '/blog/' . sql_unescape($row->bshortname);
			else
				$link  = $CONF['BlogURL'] . '/blog/' . $blogid;
			break;
		case 'normal':
			$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($blogid));
			if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) ) 
				$link = $CONF['BlogURL'] . '?blog=' . sql_unescape($row->bshortname);
			else
				$link = $CONF['BlogURL'] . '?blogid=' . $blogid;
			break;
		case 'numeric':
			$link = $CONF['BlogURL'] . '?blogid=' . $blogid;
			break;
	}
	return addLinkParams($link, $params);
}


function addLinkParams($link, $params) {
	global $CONF;
	if (is_array($params)) {
		// fancy urls for normal mode
		if (!$CONF['UsingAdminArea'] && ($CONF['URLMode'] != 'numeric') ) {
			foreach ($params as $param => $value) {
				switch ($param) {
					case 'blogid':
					case 'blog':
						if (is_numeric($value)) {
							$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($value));
							if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) ) {
								unset($params[$param]);
								$params['blog']=sql_unescape($row->bshortname);
							}
						}
						break;
					case 'archivelist':
					case 'archive':
						if (is_numeric($value)) {
							$query=sql_query('select bshortname from '.sql_table('blog').' where bnumber='.intval($value));
							if ( ($row=sql_fetch_object($query)) && !empty($row->bshortname) ) {
								unset($params[$param]);
								$params['archives']=sql_unescape($row->bshortname);
							}
						}
						break;
					case 'itemid':
					case 'item':
						if (is_numeric($value)) {
							$query=sql_query('select iurltitle from '.sql_table('item').' where inumber='.intval($value));
							if ( ($row=sql_fetch_object($query)) && !empty($row->iurltitle) ) {
								unset($params[$param]);
								$params['item']=sql_unescape($row->iurltitle);
							}
						}
						break;
					case 'catid':
					case 'category':
						if (is_numeric($value)) {
							$query=sql_query('select iurltitle from '.sql_table('category').' where catid='.intval($value));
							if ( ($row=sql_fetch_object($query)) && !empty($row->iurltitle) ) {
								unset($params[$param]);
								$params['category']=sql_unescape($row->iurltitle);
							}
						}
						break;
					case 'memberid':
					case 'member':
						if (is_numeric($value)) {
							$query=sql_query('select mname from '.sql_table('category').' where mnumber='.intval($value));
							if ( ($row=sql_fetch_object($query)) && !empty($row->mname) ) {
								unset($params[$param]);
								$params['member']=sql_unescape($row->mname);
							}
						}
						break;
				}
			}
		}
		// merge it together
		if ($CONF['URLMode'] == 'pathinfo')
			foreach ($params as $param => $value) $link .= '/' . $param . '/' . urlencode($value);
		else
			foreach ($params as $param => $value) $link .= '&amp;' . $param . '=' . urlencode($value);
	}
	return $link;
}

/**
 * @param $querystr
 *		querystring to alter (e.g. foo=1&bar=2&x=y)
 * @param $param
 *		name of parameter to change (e.g. 'foo')
 * @param $value
 *		New value for that parameter (e.g. 3)
 * @result
 *		altered query string (for the examples above: foo=3&bar=2&x=y)
 */
function alterQueryStr($querystr, $param, $value) {
    $vars = explode("&", $querystr);
    $set  = false;
    for ($i=0;$i<count($vars);$i++) {
        $v = explode('=',$vars[$i]);
        if ($v[0] == $param) {
            $v[1]     = $value;
            $vars[$i] = implode('=', $v);
            $set      = true;
            break;
        }
    }
    if (!$set) {$vars[] = $param . '=' . $value;}
    return ltrim(implode('&', $vars), '&');
}

// passes one variable as hidden input field (multiple fields for arrays)
// @see passRequestVars in varsx.x.x.php
function passVar($key, $value) {
	// array ?
	if (is_array($value)) {
		for ($i=0;$i<sizeof($value);$i++)
			passVar($key.'['.$i.']',$value[$i]);
			return;
	}

	// other values: do sql_unescape if needed
	?><input type="hidden" name="<?php echo htmlspecialchars($key)?>" value="<?php echo htmlspecialchars(undoMagic($value))?>" /><?php
}

/*
	Date format functions (to be used from [%date(..)%] skinvars
*/
function formatDate($format, $timestamp, $defaultFormat) {
	if ($format == 'rfc822') {
		return date('r', $timestamp);
	} else if ($format == 'rfc822GMT') {
		return gmdate('r', $timestamp);
	} else if ($format == 'utc') {
		return gmdate('Y-m-d\TH:i:s\Z', $timestamp);
	} else if ($format == 'iso8601') {
       	$tz = date('O', $timestamp);
        $tz = substr($tz, 0, 3) . ':' . substr($tz, 3, 2);
		return gmdate('Y-m-d\TH:i:s', $timestamp) . $tz;
	} else {
		return strftime($format ? $format : $defaultFormat,$timestamp);
	}

}

/*
  These functions create a FancierURL item link, needs NP_FancierURL plugin
  installed. I put it here, to make it possible for all plugins to support
  FancierURL functionality.
*/

/* create a FancierURL link from ID */
function fancyLink($id) {
	global $catid, $CONF;
	// no id specified?
	if (!isset($id) || intval($id)<1) 
		return htmlspecialchars("http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
		switch ($CONF['URLMode']) {
		case 'pathinfo':
			if ( strrchr($CONF['ItemURL'],'/') =='/' ) $CONF['ItemURL']=substr($CONF['ItemURL'],0,-1);
			$query = sql_query('SELECT iurltitle FROM '.sql_table('item').' WHERE inumber='.strval(intval($id)));
			if ($obj = sql_fetch_object($query)) 
				return fancyTitle($id,$obj->iurltitle);
			else
				return $CONF['ItemURL'].'/';
			break;
		case 'normal':
			$query = sql_query('SELECT iurltitle FROM '.sql_table('item').' WHERE inumber='.strval(intval($id)));
			$link=$CONF['ItemURL'];
			if ($obj = sql_fetch_object($query)) $link=$CONF['ItemURL'].'?item='.$obj->iurltitle;
			if (intval($catid)>0) {
				$query=sql_query('select iurltitle from '.sql_table('category').' where catid='.intval($catid));
				if ( ($row=sql_fetch_object($query)) && !empty($row->iurltitle) )
					$link.='&category='.$row->iurltitle;
				else
					$link.='&catid='.$catid;
			}
			return htmlspecialchars($link);
			break;
		case 'numeric':
			$link=$CONF['ItemURL'].'?itemid='.$id;
			if (intval($catid)>0) $link.='&catid='.$catid;
			return htmlspecialchars($link);
			break;
  }
}

/* format a FancierURL link */
function fancyTitle($id,$title,$date='') {
	global $catid, $CONF;
	// no id specified?
	if (!isset($id) || intval($id)<1) 
		return htmlspecialchars("http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
		switch ($CONF['URLMode']) {
		case 'pathinfo':
			if ( strrchr($CONF['ItemURL'],'/') =='/' ) $CONF['ItemURL']=substr($CONF['ItemURL'],0,-1);
			$link = $CONF['ItemURL'].'/item/'.$title;
			if (intval($catid)>0) {
			  $query=sql_query("select iurltitle from ".sql_table("category")." where catid=".strval(intval($catid)));
			  if ( ($row=sql_fetch_object($query)) && (!empty($row->iurltitle)) )
				$link.='/category/'.$row->iurltitle;
			  else
				$link.='/category/'.$catid;
			}
			return htmlspecialchars($link);
			break;
		case 'normal':
			$link=$CONF['ItemURL'].'?item='.$title;
			if (intval($catid)>0) {
				$query=sql_query('select iurltitle from '.sql_table('category').' where catid='.intval($catid));
				if ( ($row=sql_fetch_object($query)) && !empty($row->iurltitle) )
					$link.='&category='.$row->iurltitle;
				else
					$link.='&catid='.$catid;
			}
			return htmlspecialchars($link);
			break;
		case 'numeric':
			$link=$CONF['ItemURL'].'?itemid='.$id;
			if (intval($catid)>0) $link.='&catid='.$catid;
			return htmlspecialchars($link);
			break;
  }
}

// debug array
function debugArray($arr){
  $s="";
  while (list ($key, $val) = each ($arr)) echo $s.="<strong>$key</strong> => $val<br />";
  return $s;
}

/* get current blog id */
function getCurrentBlogId(){
   global $manager, $blog, $CONF;
   if ($blog) $b =& $blog; else $b =& $manager->getBlog($CONF['DefaultBlog']);
   $id=$b->getID();
   if (!isset($id)) $id=1;
   if ($id<1) $id=1;
   return $id;
}

/* this function will parse an extraskin named $skinname */
function doParse($skinname,$skinType) {
  $skinname=sql_escape(sql_unescape($skinname));
  $query=sql_query("select tableid, skin from ".sql_table('plug_extra_skin')." where title='$skinname'");
  if ($row=sql_fetch_object($query)) {
    global $CONF, $blogid, $manager, $blog;
  	$blogid = $CONF['DefaultBlog'];
  	$b =& $manager->getBlog($blogid);
  	$blog = $b;
  	$skinid = $blog->getDefaultSkin();
  	$skin = new SKIN($skinid);
    $handler = new ACTIONS($skinType);
    $parser = new PARSER(SKIN::getAllowedActionsForType($skinType), $handler);
    $parser->setProperty('IncludeMode',$skin->getIncludeMode());
    $parser->setProperty('IncludePrefix',$skin->getIncludePrefix());
    $handler->setSkin($skin);
    $handler->parser =& $parser;
    $temp = sql_unescape($row->skin);
    $parser->parse($temp);
  }
}

function doParseRemote($skinname,$skinType = 'index') {
	$query=sql_query("select tableid, skin from ".sql_table('plug_extra_skin')." where title='$skinname'");
	if ($row=sql_fetch_object($query)) {
		global $CONF, $blogid, $manager, $blog;
		if (!isset($blogid))
			$blogid = $CONF['DefaultBlog'];
		if (!$manager) 
			$manager = new MANAGER();
		if (!$blog)
			$blog = new BLOG($blogid);
		$skinid = $blog->getDefaultSkin();
		$skin = new SKIN($skinid);
		$handler = new ACTIONS($skinType);
		$parser = new PARSER(SKIN::getAllowedActionsForType($skinType), $handler);
		$parser->setProperty('IncludeMode',$skin->getIncludeMode());
		$parser->setProperty('IncludePrefix',$skin->getIncludePrefix());
		$handler->setSkin($skin);
		$handler->parser =& $parser;
		$parser->parse(sql_unescape($row->skin));
	}
}

// line breaks into properly formatted paragraphs
function paragraph($text, $br = false) {
  $text=trim($text);
  $text = str_replace("\r",'',$text);
  $text = preg_replace('/&([^#])(?![a-z]{1,8};)/', '&amp;$1', $text);
  if ($text=="") return "";
  $text = $text . "\n"; // just to make things a little easier, pad the end
  $text = preg_replace('|<br/>\s*<br/>|', "\n\n", $text);
  $text = preg_replace('!(<(?:table|ul|ol|li|pre|form|blockquote|h[1-6])[^>]*>)!', "\n$1", $text); // Space things out a little
  $text = preg_replace('!(</(?:table|ul|ol|li|pre|form|blockquote|h[1-6])>)!', "$1\n", $text); // Space things out a little
  $text = preg_replace("/(\r\n|\r)/", "\n", $text); // cross-platform newlines
  $text = preg_replace("/\n\n+/", "\n\n", $text); // take care of duplicates
  $text = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "\t<p>$1</p>\n", $text); // make paragraphs, including one at the end
  $text = preg_replace('|<p>\s*?</p>|', '', $text); // under certain strange conditions it could create a P of entirely whitespace
  $text = preg_replace("|<p>(<li.+?)</p>|", "$1", $text); // problem with nested lists
  // blockquote
  $text = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $text);
  $text = str_replace('</blockquote></p>', '</p></blockquote>', $text);
  // now the hard work
  $text = preg_replace('!<p>\s*(</?(?:table|tr|td|th|div|ul|ol|li|pre|select|form|blockquote|p|h[1-6])[^>]*>)!', "$1", $text);
  $text = preg_replace('!(</?(?:table|tr|td|th|div|ul|ol|li|pre|select|form|blockquote|p|h[1-6])[^>]*>)\s*</p>|</div>"!', "$1", $text);
  if ($br) {
    // optionally make line breaks
    $text = preg_replace('/>\s+</','><',$text); // remove spaces between list items
    $text = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $text);
  }
  $text = preg_replace('!(</?(?:table|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|blockquote|p|h[1-6])[^>]*>)\s*<br/>!', "$1", $text);
  $text = preg_replace('!<br/>(\s*</?(?:p|li|div|th|pre|td|ul|ol)>)!', '$1', $text);
  // some cleanup
  $text = str_replace('</p><br />','</p>',$text);
  $text = str_replace("<br />\n</p>",'</p>',$text);
  return $text;
}

// convert protocols into links
function createLinkCode($pre, $url, $protocol = 'http') {
	$post = '';
	$aBadEntities = array('&quot;', '&gt;', '&lt;');
	foreach ($aBadEntities as $entity){
		$pos = strpos($url, $entity);
		if ($pos){
			$post = substr($url, $pos) . $post;
			$url = substr($url, 0, $pos);
		}
	}
	if (preg_match('/(&\w+;)+$/i', $url, $matches)) {
		$post = $matches[0] . $post;	// found entities (1 or more)
		$url = substr($url, 0, strlen($url) - strlen($post));
	}
	if (!ereg('^'.$protocol.'://',$url))
		$linkedUrl = $protocol . (($protocol == 'mailto') ? ':' : '://') . $url;
	else
		$linkedUrl = $url;
	if ($protocol != 'mailto')
		$displayedUrl = $linkedUrl;
	else
		$displayedUrl = $url;
	return $pre . '<a href="'.$linkedUrl.'">'.shorten($displayedUrl,30,'...').'</a>' . $post;
}

// link callback function
function hyperlink($body){
  if (strpos($body,"<a href=")!==false) return $body;
	$replaceFrom = array(
		'/([^:\/\/\w]|^)((https:\/\/)([\w\.-]+)([\/\w+\.~%&?@=_:;#,-]+))/ie',
		'/([^:\/\/\w]|^)((http:\/\/|www\.)([\w\.-]+)([\/\w+\.~%&?@=_:;#,-]+))/ie',
		'/([^:\/\/\w]|^)((ftp:\/\/|ftp\.)([\w\.-]+)([\/\w+\.~%&?@=_:;#,-]+))/ie',
		'/([^:\/\/\w]|^)(mailto:(([a-zA-Z\@\%\.\-\+_])+))/ie'
	);
	$replaceTo = array(
		'createLinkCode("\\1", "\\2","https")',
		'createLinkCode("\\1", "\\2","http")',
		'createLinkCode("\\1", "\\2","ftp")',
		'createLinkCode("\\1", "\\3","mailto")'
	);
	return preg_replace($replaceFrom, $replaceTo, $body);
}

// get global variables from URL
function setGlobalVariables($type=''){
  // **********************
  // FancyURLs (FilesMatch)
  // **********************
  $data = explode("/",serverVar('PATH_INFO')."/".serverVar('REQUEST_URI'));
  global $blogid, $catid, $itemid, $archivelist, $archive, $memberid;
  for ($i=0; $i<sizeof($data); $i++){
    /* category id */
    if ($data[$i]=='catid' || $data[$i]=='category' || ($type=='category' && $i==0) ){
	  if (intval($catid)==0) {	
		  if (is_numeric($data[$i+1]))
			$catid = intval($data[$i+1]);
		  else {
			$query=sql_query("select catid, cblog from ".sql_table("category")." where iurltitle='".sql_escape(unicode_decode($data[$i+1]))."'");
			if ($row=sql_fetch_object($query)) {
				$catid=$row->catid;
				$blogid=$row->cblog;
			} else $catid=0;
		  }
	  }
      if ($catid) $i++;
    }
    /* member id */
    if ($data[$i]=='memberid' || $data[$i]=='member' || ($type=='member' && $i==0) ){
	  if (is_numeric($data[$i+1]))
		$memberid = intval($data[$i+1]);
	  else {
		$query=sql_query("select mnumber from ".sql_table("member")." where mname='".sql_escape(unicode_decode($data[$i+1]))."'");
		if ($row=sql_fetch_object($query)) $memberid=intval($row->mnumber);
	  }
      if ($memberid) $i++;
    }
    /* blog id */
    if ($data[$i]=='blogid' || $data[$i]=='blog' || ($type=='blog' && $i==0) ){
		if (is_numeric($data[$i+1])) {
			$blogid=intval($data[$i+1]);
		} else {
			$query = sql_query("SELECT bnumber FROM ".sql_table('blog')." where bshortname='".sql_escape(unicode_decode($data[$i+1]))."'");
			if ($row = sql_fetch_object($query)) $blogid=intval($row->bnumber);
		}
        if ($blogid) $i++;
    }
    /* archivelist id */
    if ($data[$i]=='archivelist' || $data[$i]=='archives' || ($type=='archives' && $i==0) ){
		if (is_numeric($data[$i+1])) {
			$archivelist=intval($data[$i+1]);
		} else {
			$query = sql_query("SELECT bnumber FROM ".sql_table('blog')." where bshortname='".sql_escape(unicode_decode($data[$i+1]))."'");
			if ($row = sql_fetch_object($query)) $archivelist=intval($row->bnumber);
		}
        if ($archivelist) $i++;
    }
    /* item id */
    if ($data[$i]=='itemid' || $data[$i]=='item' || ($type=='item' && $i==0) ){
      if (is_numeric($data[$i+1]))
        $itemid=intval($data[$i]);
      else {
      	$query  = sql_query("SELECT iblog, inumber FROM ".sql_table('item')." WHERE iurltitle='".sql_escape(unicode_decode($data[$i+1]))."'");
      	if ($row = sql_fetch_object($query)){
      	  $blogid = $row->iblog;
      	  $itemid = $row->inumber;
      	} else {
      	  $query=sql_query("SELECT inumber FROM ".sql_table('plugin_fancierurl')." WHERE iurltitle='".sql_escape(unicode_decode($data[$i+1]))."'");
      	  if ($row = sql_fetch_object($query)) {
        	  $itemid = $row->inumber;
        	}
        }
      }
      if ($itemid) $i++;
    }
    /* archive id */
    if ($data[$i]=='archive' || ($type=='archive' && $i==0) ){
		// two possibilities: archive/yyyy-mm or archive/1/yyyy-mm (with blogid)
		if ((($i+1)<sizeof($data)) && (!strstr($data[$i+1],'-')) ) {
			if (is_numeric($data[$i+1])) {
				$blogid=intval($data[$i+1]);
			} else {
				$query = sql_query("SELECT bnumber FROM ".sql_table('blog')." where bshortname='".sql_escape(unicode_decode($data[$i+1]))."'");
				if ($row = sql_fetch_object($query)) $blogid=intval($row->bnumber);
			}
		}
		$i++;
		if ($i<sizeof($data)) $archive = $data[$i];
		$i++;
	}
  }
  // switch to default item category, if one is present
  if ( (intval($catid)>0) && (intval($itemid)>0) ) {
	    $query=sql_query('select icat from '.sql_table('item').' where inumber='.$itemid);
		if ($row=sql_fetch_object($query)) $catid=intval($row->icat);
  }
  unset($query);
}


// comment formatting
function commentformatting($text){
  //  real allowed tags into pseudo tags
  $patterns = array(
      '/\<abbr\s+title\=[\"|\']*(.*?)[\"|\']*\>(.*?)\<\/abbr\>/si',
      '/\<cite\>(.*?)\<\/cite\>/si',
      '/\<code\>(.*?)\<\/code\>/si',
      '/\<em\>(.*?)\<\/em\>/si',
      '/\<q\>(.*?)\<\/q\>/si',
      '/\<strong\>(.*?)\<\/strong\>/si',
      '/\<a\s+href\=[\"|\']*(.*?)[\"|\']*\>(.*?)\<\/a\>/si',
      '/\<li\>(.*?)\<\/li\>/si'
      );
  $replace = array(
      '[abbr title=\\1]\\2[/abbr]',
      '[cite]\\1[/cite]',
      '[code]\\1[/code]',
      '[em]\\1[/em]',
      '[q]\\1[/q]',
      '[strong]\\1[/strong]',
      '[a href=\\1]\\2[/a]',
      '[li]\\1[/li]'
      );
  $text = preg_replace( $patterns, $replace, $text);
  // strip tags
  $text = htmlspecialchars($text,ENT_QUOTES,'UTF-8');
  //  pseudo tags into real tags
  $patterns = array(
      '/\[abbr\s+title\=[\"|\']*(.*?)[\"|\']*](.*?)\[\/abbr\]/si',
      '/\[cite\](.*?)\[\/cite\]/si',
      '/\[code\](.*?)\[\/code\]/si',
      '/\[em\](.*?)\[\/em\]/si',
      '/\[q\](.*?)\[\/q\]/si',
      '/\[strong\](.*?)\[\/strong\]/si',
      '/\[a\s+href\=[\"|\']*(.*?)[\"|\']*](.*?)\[\/a\]/si',
      '/\[li\](.*?)\[\/li\]/si'
      );
  $replace = array(
      '<abbr title="\\1">\\2</abbr>',
      '<cite>\\1</cite>',
      '<code>\\1</code>',
      '<em>\\1</em>',
      '<q>\\1</q>',
      '<strong>\\1</strong>',
      '<a href="\\1">\\2</a>',
      '<li>\\1</li>'
      );
  // pseudo tags into XHTML tags
  $text = preg_replace( $patterns, $replace, $text);
  // create lists
  $text = preg_replace('/<\/li>\s+<li>/','</li><li>',$text); // remove spaces between list items
  $i=0;
  $first=true;
  while ($i<strlen($text)){
    $j=strpos(substr($text,$i),"<li>");
    if ( ($j!==false) ) {
      $i+=$j;
      if ($first) { // open this list
        $text=substr($text,0,$i)."<ul>".substr($text,$i);
        $first=false;
        $i+=4;
      }
    } else
      break;
    $j=strpos(substr($text,$i),"</li>");
    if ( ($j===false) ) break; // should never occur
    $i+=$j;
    if (substr($text,$i+5,4)=='<li>')
      $i+=5;
    else { // close this list
      $text=substr($text,0,$i)."</li></ul>".substr($text,$i+5);
      $i+=5;
      $first=true;
    }
  }
  // line breaks to paragraphs
  $text = paragraph($text,true);
  // trim and hyperlinks
  $text = hyperlink(COMMENT::prepareBody($text));
  return $text;
}


function makeSEOURL($url){
  $md=md5($url);
  $query=sql_query("select id from ".sql_table("plug_seo")." where id='$md'");
  if (sql_num_rows($query)==0) sql_query("insert into ".sql_table("plug_seo")." (id,url) values ('$md','".sql_escape($url)."')");
  global $CONF;
  return $CONF['ItemURL']."?id=".$md;
}

function SEOlink($url){
  global $manager;
  if (!$manager->pluginInstalled('NP_SEO')) return $url;
  if (strstr($url,$plug->server) ||
       ( !strstr($url,'http://') &&
         !strstr($url,'https://') &&
         !strstr($url,'ftp://') )
  )
    return $url;
   else
    return makeSEOURL($url);
}

/* converts UTF-8 string phonetically to ASCII alphabet */
function iso2ascii($title){
	if (empty($title)) return '';
	global $global_utf,$global_asc; 
	if (!isset($global_utf)) return $title;
	$i=0;
	foreach ($global_utf as $s) $title=str_replace(trim($s),trim($global_asc[$i++]),$title);
	return $title;
}

/* returns first letter of a given word in UTF-8, but converted to ASCII equivalent */
function letter2ascii($letter){
	if (preg_match("/^[a-zA-Z](.*?)/i",$letter)) return substr($letter,0,1);
	global $global_utf,$global_asc;
	if (!isset($global_utf)) return $letter;
	$i=0;
	foreach ($global_utf as $s) {
		  $s=trim($s);
		  if (substr($letter,0,strlen(trim($s)))==$s) return trim($global_asc[$i]);
		  $i++;
	}
	return '-';
}

/* returns first letter of a word which is in UTF-8 encoding */
function utf2letter($letter){
	if (preg_match("/^[a-zA-Z](.*?)/i",$letter)) return substr($letter,0,1); 
	global $global_utf;
	if (!isset($global_utf)) return $letter;
	foreach ($global_utf as $s) {
	    $s=trim($s);
		if (substr($letter,0,strlen($s))==$s) return $s;
	}
	return '-';
}

/* convert HTML entities back to their one-char representation - useful for RSS/Atom feeds */
function unhtmlentities ($string)  {
  $trans_tbl = get_html_translation_table (HTML_ENTITIES);
  $trans_tbl = array_flip ($trans_tbl);
  return strtr ($string, $trans_tbl);
}

/* decodes URL into Unicode string */
function unicode_decode($txt) {
	$txt = ereg_replace('%u0([[:alnum:]]{3})', '&#x\1;',$txt);
	$txt = ereg_replace('%([[:alnum:]]{2})', '&#x\1;',$txt);
	return urldecode($txt);
}

global $entities_named, $entities_decimal, $entities_hexadecimal;  
$entities_named       = array("&nbsp;","&iexcl;","&cent;","&pound;","&curren;","&yen;","&brvbar;","&sect;","&uml;","&copy;","&ordf;","&laquo;","&not;","&shy;","&reg;","&macr;","&deg;","&plusmn;","&sup2;","&sup3;","&acute;","&micro;","&para;","&middot;","&cedil;","&sup1;","&ordm;","&raquo;","&frac14;","&frac12;","&frac34;","&iquest;","&Agrave;","&Aacute;","&Acirc;","&Atilde;","&Auml;","&Aring;","&AElig;","&Ccedil;","&Egrave;","&Eacute;","&Ecirc;","&Euml;","&Igrave;","&Iacute;","&Icirc;","&Iuml;","&ETH;","&Ntilde;","&Ograve;","&Oacute;","&Ocirc;","&Otilde;","&Ouml;","&times;","&Oslash;","&Ugrave;","&Uacute;","&Ucirc;","&Uuml;","&Yacute;","&THORN;","&szlig;","&agrave;","&aacute;","&acirc;","&atilde;","&auml;","&aring;","&aelig;","&ccedil;","&egrave;","&eacute;","&ecirc;","&euml;","&igrave;","&iacute;","&icirc;","&iuml;","&eth;","&ntilde;","&ograve;","&oacute;","&ocirc;","&otilde;","&ouml;","&divide;","&oslash;","&ugrave;","&uacute;","&ucirc;","&uuml;","&yacute;","&thorn;","&yuml;","&fnof;","&Alpha;","&Beta;","&Gamma;","&Delta;","&Epsilon;","&Zeta;","&Eta;","&Theta;","&Iota;","&Kappa;","&Lambda;","&Mu;","&Nu;","&Xi;","&Omicron;","&Pi;","&Rho;","&Sigma;","&Tau;","&Upsilon;","&Phi;","&Chi;","&Psi;","&Omega;","&alpha;","&beta;","&gamma;","&delta;","&epsilon;","&zeta;","&eta;","&theta;","&iota;","&kappa;","&lambda;","&mu;","&nu;","&xi;","&omicron;","&pi;","&rho;","&sigmaf;","&sigma;","&tau;","&upsilon;","&phi;","&chi;","&psi;","&omega;","&thetasym;","&upsih;","&piv;","&bull;","&hellip;","&prime;","&Prime;","&oline;","&frasl;","&weierp;","&image;","&real;","&trade;","&alefsym;","&larr;","&uarr;","&rarr;","&darr;","&harr;","&crarr;","&lArr;","&uArr;","&rArr;","&dArr;","&hArr;","&forall;","&part;","&exist;","&empty;","&nabla;","&isin;","&notin;","&ni;","&prod;","&sum;","&minus;","&lowast;","&radic;","&prop;","&infin;","&ang;","&and;","&or;","&cap;","&cup;","&int;","&there4;","&sim;","&cong;","&asymp;","&ne;","&equiv;","&le;","&ge;","&sub;","&sup;","&nsub;","&sube;","&supe;","&oplus;","&otimes;","&perp;","&sdot;","&lceil;","&rceil;","&lfloor;","&rfloor;","&lang;","&rang;","&loz;","&spades;","&clubs;","&hearts;","&diams;","&quot;","&amp;","&lt;","&gt;","&OElig;","&oelig;","&Scaron;","&scaron;","&Yuml;","&circ;","&tilde;","&ensp;","&emsp;","&thinsp;","&zwnj;","&zwj;","&lrm;","&rlm;","&ndash;","&mdash;","&lsquo;","&rsquo;","&sbquo;","&ldquo;","&rdquo;","&bdquo;","&dagger;","&Dagger;","&permil;","&lsaquo;","&rsaquo;","&euro;","&apos;");
$entities_decimal     = array("&#160;","&#161;","&#162;","&#163;","&#164;","&#165;","&#166;","&#167;","&#168;","&#169;","&#170;","&#171;","&#172;","&#173;","&#174;","&#175;","&#176;","&#177;","&#178;","&#179;","&#180;","&#181;","&#182;","&#183;","&#184;","&#185;","&#186;","&#187;","&#188;","&#189;","&#190;","&#191;","&#192;","&#193;","&#194;","&#195;","&#196;","&#197;","&#198;","&#199;","&#200;","&#201;","&#202;","&#203;","&#204;","&#205;","&#206;","&#207;","&#208;","&#209;","&#210;","&#211;","&#212;","&#213;","&#214;","&#215;","&#216;","&#217;","&#218;","&#219;","&#220;","&#221;","&#222;","&#223;","&#224;","&#225;","&#226;","&#227;","&#228;","&#229;","&#230;","&#231;","&#232;","&#233;","&#234;","&#235;","&#236;","&#237;","&#238;","&#239;","&#240;","&#241;","&#242;","&#243;","&#244;","&#245;","&#246;","&#247;","&#248;","&#249;","&#250;","&#251;","&#252;","&#253;","&#254;","&#255;","&#402;","&#913;","&#914;","&#915;","&#916;","&#917;","&#918;","&#919;","&#920;","&#921;","&#922;","&#923;","&#924;","&#925;","&#926;","&#927;","&#928;","&#929;","&#931;","&#932;","&#933;","&#934;","&#935;","&#936;","&#937;","&#945;","&#946;","&#947;","&#948;","&#949;","&#950;","&#951;","&#952;","&#953;","&#954;","&#955;","&#956;","&#957;","&#958;","&#959;","&#960;","&#961;","&#962;","&#963;","&#964;","&#965;","&#966;","&#967;","&#968;","&#969;","&#977;","&#978;","&#982;","&#8226;","&#8230;","&#8242;","&#8243;","&#8254;","&#8260;","&#8472;","&#8465;","&#8476;","&#8482;","&#8501;","&#8592;","&#8593;","&#8594;","&#8595;","&#8596;","&#8629;","&#8656;","&#8657;","&#8658;","&#8659;","&#8660;","&#8704;","&#8706;","&#8707;","&#8709;","&#8711;","&#8712;","&#8713;","&#8715;","&#8719;","&#8721;","&#8722;","&#8727;","&#8730;","&#8733;","&#8734;","&#8736;","&#8743;","&#8744;","&#8745;","&#8746;","&#8747;","&#8756;","&#8764;","&#8773;","&#8776;","&#8800;","&#8801;","&#8804;","&#8805;","&#8834;","&#8835;","&#8836;","&#8838;","&#8839;","&#8853;","&#8855;","&#8869;","&#8901;","&#8968;","&#8969;","&#8970;","&#8971;","&#9001;","&#9002;","&#9674;","&#9824;","&#9827;","&#9829;","&#9830;","&#34;","&#38;","&#60;","&#62;","&#338;","&#339;","&#352;","&#353;","&#376;","&#710;","&#732;","&#8194;","&#8195;","&#8201;","&#8204;","&#8205;","&#8206;","&#8207;","&#8211;","&#8212;","&#8216;","&#8217;","&#8218;","&#8220;","&#8221;","&#8222;","&#8224;","&#8225;","&#8240;","&#8249;","&#8250;","&#8364;","&#39;");
$entities_hexadecimal = array("&#xa0;","&#xa1;","&#xa2;","&#xa3;","&#xa4;","&#xa5;","&#xa6;","&#xa7;","&#xa8;","&#xa9;","&#xaa;","&#xab;","&#xac;","&#xad;","&#xae;","&#xaf;","&#xb0;","&#xb1;","&#xb2;","&#xb3;","&#xb4;","&#xb5;","&#xb6;","&#xb7;","&#xb8;","&#xb9;","&#xba;","&#xbb;","&#xbc;","&#xbd;","&#xbe;","&#xbf;","&#xc0;","&#xc1;","&#xc2;","&#xc3;","&#xc4;","&#xc5;","&#xc6;","&#xc7;","&#xc8;","&#xc9;","&#xca;","&#xcb;","&#xcc;","&#xcd;","&#xce;","&#xcf;","&#xd0;","&#xd1;","&#xd2;","&#xd3;","&#xd4;","&#xd5;","&#xd6;","&#xd7;","&#xd8;","&#xd9;","&#xda;","&#xdb;","&#xdc;","&#xdd;","&#xde;","&#xdf;","&#xe0;","&#xe1;","&#xe2;","&#xe3;","&#xe4;","&#xe5;","&#xe6;","&#xe7;","&#xe8;","&#xe9;","&#xea;","&#xeb;","&#xec;","&#xed;","&#xee;","&#xef;","&#xf0;","&#xf1;","&#xf2;","&#xf3;","&#xf4;","&#xf5;","&#xf6;","&#xf7;","&#xf8;","&#xf9;","&#xfa;","&#xfb;","&#xfc;","&#xfd;","&#xfe;","&#xff;","&#x192;","&#x391;","&#x392;","&#x393;","&#x394;","&#x395;","&#x396;","&#x397;","&#x398;","&#x399;","&#x39a;","&#x39b;","&#x39c;","&#x39d;","&#x39e;","&#x39f;","&#x3a0;","&#x3a1;","&#x3a3;","&#x3a4;","&#x3a5;","&#x3a6;","&#x3a7;","&#x3a8;","&#x3a9;","&#x3b1;","&#x3b2;","&#x3b3;","&#x3b4;","&#x3b5;","&#x3b6;","&#x3b7;","&#x3b8;","&#x3b9;","&#x3ba;","&#x3bb;","&#x3bc;","&#x3bd;","&#x3be;","&#x3bf;","&#x3c0;","&#x3c1;","&#x3c2;","&#x3c3;","&#x3c4;","&#x3c5;","&#x3c6;","&#x3c7;","&#x3c8;","&#x3c9;","&#x3d1;","&#x3d2;","&#x3d6;","&#x2022;","&#x2026;","&#x2032;","&#x2033;","&#x203e;","&#x2044;","&#x2118;","&#x2111;","&#x211c;","&#x2122;","&#x2135;","&#x2190;","&#x2191;","&#x2192;","&#x2193;","&#x2194;","&#x21b5;","&#x21d0;","&#x21d1;","&#x21d2;","&#x21d3;","&#x21d4;","&#x2200;","&#x2202;","&#x2203;","&#x2205;","&#x2207;","&#x2208;","&#x2209;","&#x220b;","&#x220f;","&#x2211;","&#x2212;","&#x2217;","&#x221a;","&#x221d;","&#x221e;","&#x2220;","&#x2227;","&#x2228;","&#x2229;","&#x222a;","&#x222b;","&#x2234;","&#x223c;","&#x2245;","&#x2248;","&#x2260;","&#x2261;","&#x2264;","&#x2265;","&#x2282;","&#x2283;","&#x2284;","&#x2286;","&#x2287;","&#x2295;","&#x2297;","&#x22a5;","&#x22c5;","&#x2308;","&#x2309;","&#x230a;","&#x230b;","&#x2329;","&#x232a;","&#x25ca;","&#x2660;","&#x2663;","&#x2665;","&#x2666;","&#x22;","&#x26;","&#x3c;","&#x3e;","&#x152;","&#x153;","&#x160;","&#x161;","&#x178;","&#x2c6;","&#x2dc;","&#x2002;","&#x2003;","&#x2009;","&#x200c;","&#x200d;","&#x200e;","&#x200f;","&#x2013;","&#x2014;","&#x2018;","&#x2019;","&#x201a;","&#x201c;","&#x201d;","&#x201e;","&#x2020;","&#x2021;","&#x2030;","&#x2039;","&#x203a;","&#x20ac;","&#x27;");

/* entity to unicode decimal value */
function entity_to_decimal_value($string){
	static $entities_dec = false;
	if (!is_array($entities_dec)) {
		global $entities_named,$entities_decimal;
		if (function_exists('array_combine')) 
			$entities_dec=array_combine($entities_named,$entities_decimal);
		else {
			$i=0;
			foreach ($entities_named as $_entities_named) $entities_dec[$_entities_named]=$entities_decimal[$i++];
		}
	}
	return strtr($string,$entities_dec);
}

/* retrieves preferred and/or user CSS style */
function getCSSStyle(){
	global $manager;
	if (!$manager) $manager =& MANAGER::instance();
	$plugin =& $manager->getPlugin('NP_CSS');
	if (!$plugin) return 'golf.css';
	$CSSDefaultFile = $plugin->getOption('CSSDefaultFile');
	$CSSStylesArray = explode(',',$plugin->getOption('CSSStyles'));
	$cookie = $plugin->getOption('cookie');
	$userprefs = cookieVar($cookie);
	// user selected style in cookie still exists?
	if (isset($userprefs) && in_array($userprefs,$CSSStylesArray)) return $userprefs.'.css';
	// return default style
	return $CSSDefaultFile.'.css'; 
}

// cleans np_cache for one itemid and index page
function cleanItem($itemid){
	// np_cache plugin installed?
	global $manager;
	$plugin =& $manager->getPlugin('NP_Cache');
	// cache plugin not installed
	if (!$plugin) return false;
	// installed, but not enabled
	if ($plugin->getOption('cache')!='1') return false;
	
	// get current blog
	$query=sql_query('select iblog from '.sql_table('item').' where inumber='.$itemid);
	if ($row=sql_fetch_object($query)) $currentblog=strval($row->iblog); else return false;
	$currentblog='_b'.$currentblog;
	// cache parameters
	global $DIR_PLUGINS, $DIR_MEDIA;
	include_once($DIR_PLUGINS.'cache/Lite.php');
	$url=$DIR_MEDIA.$plugin->getOption('url').'/';
	$cacheoptions = array(
	  'cacheDir' => $url,
	  'lifeTime' => 0
	);      
	// remove cache for this item page and index page
	$cache=new Cache_Lite($cacheoptions);
	$cleanArray=array( 'index', 'item_i'.strval($itemid) );
	foreach ($cleanArray as $s) $cache->clean($s.$currentblog);
	return true;
}

function smartStartGzip(){
	// output compression already started?
	if (function_exists('ob_get_level') && (ob_get_level() > 0))
		return false;
	// For some very odd reason, "Norton Internet Security" unsets this
	$_SERVER['HTTP_ACCEPT_ENCODING'] = isset($_SERVER['HTTP_ACCEPT_ENCODING']) ? $_SERVER['HTTP_ACCEPT_ENCODING'] : '';
	// Should we use gzip output compression?
	if ( extension_loaded('zlib') && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') !== false))
		return ob_start('ob_gzhandler');
	else
		return false;
}

function setBlogURLs($url){
	global $CONF;
	if (!isset($CONF))
		$CONF = array();
	if ($CONF['URLMode']=='pathinfo')
		if (substr($url,-1,1)=='/')
			$url=substr($url,0,-1);
	$CONF['Self'] = $url;
	$CONF['ItemURL'] = $CONF['Self'];
	$CONF['ArchiveURL'] = $CONF['Self'];
	$CONF['ArchiveListURL'] = $CONF['Self'];
	$CONF['MemberURL'] = $CONF['Self'];
	$CONF['SearchURL'] = $CONF['Self'];
	$CONF['BlogURL'] = $CONF['Self'];
	$CONF['CategoryURL'] = $CONF['Self'];
}

function setBlogIDURLs(){
	global $blogid;
	if (!isset($blogid))
			$blogid = $CONF['DefaultBlog'];
	$b = new BLOG($blogid);
	setBlogURLs($b->getURL());
}

function printNiceMessage($message){
	global $CONF;
	echo "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>\n";
	echo "<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>\n";
	echo "<head>\n";
	echo "<meta http-equiv='Content-Type' content='text/html; charset="._CHARSET."' />\n";
	echo "<title>Message</title>\n";
	echo "<link rel='stylesheet' type='text/css' href='".$CONF['SkinsURL'].'base/'.getCSSStyle()."' media='screen,projection,tv'/>\n";
	echo "</head><body>\n";
	echo "<div id='content'>\n";
	echo "<h1>Message</h1>\n";
	echo "<div id='items' class='full'>\n";
	echo "<h3>$message</h3>\n";
	echo "</div>\n";
	echo "<div id='footer'>\n";
	echo "<a href='http://blogcms.com/'><img src='./skins/base/logo.png' alt='blogcms.com' /></a>\n";
	echo "</div></div>\n";
	echo "</body></html>\n";
	die;
}

?>