[SUCS Devel] site r640 - in branches/sucs-site: components lib lib/blog templates

arthur at sucs.org arthur at sucs.org
Fri Jan 30 17:08:06 GMT 2015


Author: arthur
Date: 2015-01-30 17:08:05 +0000 (Fri, 30 Jan 2015)
New Revision: 640

Added:
   branches/sucs-site/components/blogadmin.php
   branches/sucs-site/components/blogcomment.php
   branches/sucs-site/components/blogfeed.php
   branches/sucs-site/components/blogs.php
   branches/sucs-site/components/planet.php
   branches/sucs-site/components/planetconfig.php
   branches/sucs-site/components/planetposts.php
   branches/sucs-site/lib/blog/
   branches/sucs-site/lib/blog/admin.lib.php
   branches/sucs-site/lib/blog/blog.lib.php
   branches/sucs-site/lib/blog/miscfunctions.lib.php
   branches/sucs-site/lib/blog/validation.lib.php
   branches/sucs-site/templates/planetconfig.tpl
   branches/sucs-site/templates/planetposts.tpl
Removed:
   branches/sucs-site/lib/blog/admin.lib.php
   branches/sucs-site/lib/blog/blog.lib.php
   branches/sucs-site/lib/blog/miscfunctions.lib.php
   branches/sucs-site/lib/blog/validation.lib.php
Modified:
   branches/sucs-site/components/front.php
   branches/sucs-site/components/members.php
   branches/sucs-site/components/options.php
   branches/sucs-site/templates/members.tpl
   branches/sucs-site/templates/options.tpl
Log:
Replace all the addslashes with parameterised queries, and attempt to spot anywhere else that failed to escape queries properly



Copied: branches/sucs-site/components/blogadmin.php (from rev 635, branches/sucs-site/components/blogadmin.php)
===================================================================
--- branches/sucs-site/components/blogadmin.php	                        (rev 0)
+++ branches/sucs-site/components/blogadmin.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,129 @@
+<?php
+	//include our admin functions
+	include("../lib/blog/admin.lib.php");
+	$admin = new admin();
+
+	//make our command list from the path
+	$request=$pathlist;
+array_shift($request);
+array_shift($request);
+array_shift($request);
+
+$smarty->assign("title", "Blog Admin");
+
+	if ($session->loggedin) $admin->menu(); else {
+		header("Location: {$admin->httpPath}");
+		exit;
+	}
+
+ob_start();
+		//alter the debuging state on request
+		if ($request[0] == "debug") {
+			$_SESSION[debug] = $request[1];
+		}
+		//if logged in
+		if($session->loggedin && blogger($session->username)) {
+				//call appropriate functions..
+				switch (array_shift($request)) {
+					case "newentry":
+						$admin->printEntryForm() ;
+						$smarty->assign("subselect", _("Write new entry"));
+						if ($admin->blog->editor) $smarty->assign("action", "edit");
+						break;
+					case "Settings":
+						if ($_REQUEST['submit'] == "Save Settings") {
+							$admin->updateSettings();
+						} else {
+							$admin->printSettingsForm() ;
+						}
+						$smarty->assign("subselect", _("Settings"));
+						break;
+					case "postentry":
+						$admin->postEntry() ;
+						break;
+					case "postupdate":
+						$admin->updateEntry(array_shift($request)) ;
+						break;
+					case "update":
+						$admin->updateForm(array_shift($request)) ;
+						$smarty->assign("subselect", _("Edit entries"));
+						if ($admin->blog->editor) $smarty->assign("action", "edit");
+						break;
+					case "showentries":
+						$admin->printEntries() ;
+						$smarty->assign("subselect", _("Edit entries"));
+						break;
+					case "deleteentry":
+						$admin->deleteEntry(array_shift($request)) ;
+						break;
+					case "confirmdeleteentries":
+						$admin->confirmDeleteEntries();
+						break;
+					case "deleteentries":
+						$admin->deleteEntries();
+						break;
+					case "moderatecomments":
+						$admin->printComments();
+						$admin->printAuthorisedUsers();
+						$comments=_("Comments");
+						$result = $BlogDB->GetOne("SELECT count(comments.id) from comments join entries on comments.post = entries.id where moderated = false and entries.user_id = ".$admin->id.";");
+						if($result){
+							$comments .= " (".$result[0].")";
+						}
+						$smarty->assign("subselect", $comments);
+						break;
+					case "updatecomments":
+						$admin->updateComments();
+						break;
+					case "deletecomments":
+						$admin->deleteComments(array_shift($request));
+						break;
+					case "updateauthusers":
+						$admin->updateAuthorisedUsers();
+						break;
+					default:
+						$admin->mainPage();
+				}
+		}
+		else {
+			//run appropriate functions
+			switch (array_shift($request)) {
+				case "signup":
+					$admin->addUserForm();
+					$smarty->assign("subselect", _("Start a Blog"));
+					break;
+				case "adduser":
+					$admin->addUser();
+					break;
+				//or offer login box
+				default:
+					$admin->addUserForm();
+					$smarty->assign("subselect", _("Start a Blog"));
+					break;
+			}
+		}
+
+	?>
+    <div id="bottompanel">
+	<p><? echo _("Validate"); ?> : <a href="http://validator.w3.org/check?uri=referer">XHTML</a> / <a href="http://jigsaw.w3.org/css-validator/check/referer/">CSS</a></p>
+    </div>
+<?php
+$page = ob_get_contents();
+ob_end_clean();
+
+$smarty->assign("body", $page);
+$smarty->assign("extra_styles", "/css/blog.css");
+
+
+	//if we are in debug mode display a bunch of stuff
+	if($_SESSION[debug]){
+		echo "<div class=\"debug\"><h2>"._("Debug Info")."</h2><pre>\n";
+		echo "**"._("Session")."**\n";
+		print_r($_SESSION);
+		echo "**"._("Request")."**\n";
+		print_r($_REQUEST);
+		echo "**"._("Class")."**\n";
+		print_r($admin);
+		echo "</pre></div>";
+	}
+?>

Copied: branches/sucs-site/components/blogcomment.php (from rev 635, branches/sucs-site/components/blogcomment.php)
===================================================================
--- branches/sucs-site/components/blogcomment.php	                        (rev 0)
+++ branches/sucs-site/components/blogcomment.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,28 @@
+<?php
+/*
+ * Comment posting AJAX service
+ */
+
+// don't output the site template
+$no_template = TRUE;
+
+// don't output anything before we've returned status
+ob_start();
+require_once("../lib/blog/blog.lib.php");
+
+$blogid = $_POST['blog'];
+$postid = $_POST['post'];
+$blog = new blogs($blogid);
+
+$ret = $blog->newComment($postid, FALSE);
+
+
+if($ret[0]) {
+	        echo "<split>OK";
+} else {
+	        echo "<split>ERROR<split>".$ret[1];
+}
+
+ob_end_flush();
+
+?>

Copied: branches/sucs-site/components/blogfeed.php (from rev 635, branches/sucs-site/components/blogfeed.php)
===================================================================
--- branches/sucs-site/components/blogfeed.php	                        (rev 0)
+++ branches/sucs-site/components/blogfeed.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,157 @@
+<?php
+/*
+ * feed script - outputs an feed. Currently supports both RSS 2.0 and ATOM
+ */
+
+// We're outputting raw XML, so want to turn the templating off
+$no_template = TRUE;
+
+//include the blog lib, and thus everything else we need
+include("../lib/blog/blog.lib.php");
+
+//setup our path and from that get the feed type and usernae
+$request = explode('/', substr($_SERVER['PATH_INFO'], 1));
+array_shift($request);
+array_shift($request);
+//default to rss (so old links and existing feed readers still work, would be nice to ditch this at some point)
+$feedtype = 'rss';
+if ($request[0] == 'rss' or $request[0] == 'atom'){
+	$feedtype = array_shift($request);
+}
+//grab the username
+$user = array('username'=> array_shift($request));
+//check the user is sane
+if(!safeuname($user['username'])){
+	error(1,"Invalid username");
+}
+//check the user exists
+$row = $BlogDB->GetRow("SELECT username, id, name, title, description FROM users WHERE username=? AND enabled=true;", array($user['username']));
+if(!$row){
+	error(1, "No such user");
+}
+else {
+	//fetch the users info from the db
+	$user = $row;
+	if(substr(dirname($_SERVER['SCRIPT_NAME']), -1)=="/"){
+		$user['link'] = "http://".$_SERVER['HTTP_HOST']."/blogs/".$user['username']."/";
+		$user['feed'] = "http://".$_SERVER['HTTP_HOST']."/blog/feed/".$feedtype."/".$user['username']."";
+	}
+	else {
+		$user['link'] = "http://".$_SERVER['HTTP_HOST']."/blogs/".$user['username']."/";
+		$user['feed'] = "http://".$_SERVER['HTTP_HOST']."/blog/feed/".$feedtype."/".$user['username']."";
+	}
+}
+
+$query = "SELECT subject, body, timestamp, shortsubject FROM entries WHERE user_id=?";
+$params = array( $user['id'] );
+//check to see if we are only interested in one category
+switch(array_shift($request)){
+	case "category":
+		$query .= " AND category=?";
+		$params[] = (int)array_shift($request);
+		break;
+}
+$query .= " ORDER BY timestamp DESC LIMIT 15;";
+
+//grab the first 15 entires
+$result = $BlogDB->GetAll($query, $params);
+
+//if we have relivent entrys fetch them
+if (count($result) > 0) {
+	$row = array_shift($result);
+	//set the publish dates in the required format
+	if($feedtype=='rss') {
+		$pubdate = date("r",strtotime($row['timestamp']));
+	}
+	if($feedtype=='atom') {
+		//this should be a date type c when we are on php5, untill then, this nasty hack should work.
+		$pubdate = preg_replace('/ /', 'T', $row['timestamp']).":00";
+	}
+	$entries = "";
+	//output this entry
+	if ($feedtype=='rss') {
+		do {
+			$entrydate = date("r",strtotime($row['timestamp']));
+			$entries .= "\t\t<item>\n";
+			$entries .= "\t\t\t<guid>".$user['link']."entry/".$row['shortsubject']."</guid>\n";
+			$entries .= "\t\t\t<title>" . $row['subject'] . "</title>\n";
+			$entries .= "\t\t\t<description><![CDATA[" . substr(strip_tags($row['body']),0,150) . " [...]]]></description>\n";
+			$entries .= "\t\t\t<link>".$user['link']."entry/".$row['shortsubject']."</link>\n";
+			$entries .= "\t\t\t<pubDate>" . $entrydate . "</pubDate>\n";
+			$entries .= "\t\t\t<dc:creator>".$user['name']."</dc:creator>\n";
+			$entries .= "\t\t\t<content:encoded><![CDATA[" . str_replace("'", "’", $row['body']) . "]]></content:encoded>\n";
+			$entries .= "\t\t</item>\n";
+			//and ever other 
+		} while ($row = array_shift($result));
+	}
+	if($feedtype=='atom') {
+		do {
+			$entrydate = preg_replace('/ /', 'T', $row['timestamp']).":00";
+			$entries .= "\t<entry>\n";
+			$entries .= "\t\t<title>".htmlentities($row['subject'])."</title>\n";
+			$entries .= "\t\t<link rel=\"alternate\" type=\"text/html\" href=\"".$user['link']."entry/".$row['shortsubject']."\"/>\n";
+			$entries .= "\t\t<id>".$user['link']."entry/".$row['shortsubject']."</id>\n";
+			$entries .= "\t\t<updated>".$entrydate."</updated>\n";
+			$entries .= "\t\t<content type=\"xhtml\" xml:lang=\"en\" xml:base=\"".$user['link']."entry/"."\">\n";
+			$entries .= "\t\t<div xmlns=\"http://www.w3.org/1999/xhtml\">\n";
+			//just passing though the raw body will cause the feed to fail if the code isnt valid, perhaps we should chuck everything though tidy on its way in (or even out) once we're on php5
+			$config = array('output-xhtml' => true, 'show-body-only' => true, 'wrap' => false);
+			$tidy = new tidy;
+			$tidy->parseString($row['body'], $config, 'utf8');
+			$tidy->cleanRepair();
+			$entries .= $tidy;
+			$entries .= "\t\t</div>\n";
+			$entries .= "\t\t</content>\n";
+			$entries .= "\t</entry>\n";
+		} while ($row = array_shift($result));
+	}
+}
+
+if($feedtype=='rss') {
+	//tell the client its xml and utf8 encoded (which it should be)
+	header("Content-type: application/rss+xml; charset=utf-8");
+	echo "<?xml version=\"1.0\" ?>\n";
+?>
+<rss version="2.0" 
+	xmlns:content="http://purl.org/rss/1.0/modules/content/"
+	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
+	xmlns:dc="http://purl.org/dc/elements/1.1/"
+>
+	<channel>
+		<title><?php print $user['title']?></title>
+		<description><?php print $user['description']?></description>
+		<link><?php print $user['link']?></link>
+		<pubDate><?php echo $pubdate; ?></pubDate>
+		<generator>SUCS Blogs - http://sucs.org/blogs/</generator>
+		<language>en</language>
+		<?php 
+		// add our entrys here
+		echo $entries; ?>
+	</channel>
+</rss>
+<?
+}
+if($feedtype=='atom') {
+	//tell the client its xml and utf8 encoded (which it should be)
+	header("Content-type: application/atom+xml; charset=utf-8");
+	echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+	?>
+	<feed xmlns="http://www.w3.org/2005/Atom">
+		<title type="text"><?php print $user['title']?></title>
+		<subtitle type="text"><?php print $user['description']?></subtitle>
+		<updated><?php print $pubdate;?></updated>
+		<id><?php print $user['link']?></id>
+		<link rel="alternate" type="text/html" hreflang="en" href="<?php print $user['link']?>"/>
+		<link rel="self" type="application/atom+xml" href="<?php print $user['feed']?>"/>
+		<rights>Copyright (c) <? echo date("Y",strtotime($row['timestamp'])).", ".$user['name'] ?></rights>
+		<author>
+			<name><? echo $user['name'] ?></name>
+		</author>
+		<generator uri="http://sucs.org/blogs/" version="1.0">SUCS Blogs</generator>
+<?
+		echo $entries; 
+?>
+	</feed>
+<?
+}
+?>

Copied: branches/sucs-site/components/blogs.php (from rev 635, branches/sucs-site/components/blogs.php)
===================================================================
--- branches/sucs-site/components/blogs.php	                        (rev 0)
+++ branches/sucs-site/components/blogs.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,102 @@
+<?php
+	//include our blog functions
+	require_once("../lib/blog/blog.lib.php");
+	//make our command list
+	$request=explode('/',substr($_SERVER['PATH_INFO'], 1));
+
+//bodge - fix this
+array_shift($request);
+
+	//if we have something which might be a username start a blogs instance
+	if ($request[0] != "" and $request[0] != "list"){
+		$blogsingle = new blogs(array_shift($request));
+	} 
+	//otherwise, or if there was no such user, start a bloglist instance
+	if (!isset($blogsingle) || !isset($blogsingle->id)) {
+		$bloglist = new bloglist();
+		$request = array("list");
+	}
+
+
+	$blog = isset($bloglist) ? $bloglist : $blogsingle;
+
+	if (isset($blog->userName)) {
+		if ($session->username==$blog->userName) $smarty->assign("subselect", _("My Blog"));
+		else $smarty->assign("subselect", $blog->userName._("'s Blog"));
+	}
+	
+	ob_start();
+
+$smarty->assign("title", $blog->title);
+$smarty->assign("extra_scripts", array("<script type=\"text/javascript\" src=\"$baseurl/js/xmlhttp.js\"></script>"));
+	//check we have a valid username before offering a RSS feed
+	if($blog->userName) {
+		$smarty->assign("rss_url", "http://{$_SERVER['HTTP_HOST']}{$blog->httpPath}feed/rss/{$blog->userName}".(($request[0]=="category") ? "/category/".(int)$request[1]:""));
+		$smarty->assign("atom_url", "http://{$_SERVER['HTTP_HOST']}{$blog->httpPath}feed/atom/{$blog->userName}".(($request[0]=="category") ? "/category/".(int)$request[1]:""));
+//		echo "    <link rel=\"alternate\" type=\"application/rss+xml\" title=\"{$blog->title}\" href=\"$rss_url\"/>\n";
+//		echo "    <link rel=\"alternate\" type=\"application/atom+xml\" title=\"{$blog->title}\" href=\"$atom_url\"/>\n";
+	}
+
+ob_start();
+    
+$blog->menu();
+
+		// if there was an error, print it here
+		if (isset($blogsingle) && !isset($blogsingle->id)) {
+			error_exc($blogsingle);
+		}
+	    	//run the appropriate command
+		switch (array_shift($request)) {
+			case "entry":
+				$blog->printEntryAndComments(array_shift($request));
+				break;
+			case "category":
+				$blog->printEntries(0,15,'and category = '.(int)array_shift($request)); 
+				break;
+			case "postcomment":
+				$blog->newComment((int)array_shift($request)) ; 
+				break;
+			case "Archive":
+				$blog->printArchive($request);
+				if ($session->username == $blog->userName) $smarty->assign("subselect", _("My Archive"));
+				else $smarty->assign("subselect", $blog->userName._("'s Archive"));
+				break;
+			case "list":
+				$blog->listBlogs();
+				break;
+			default:
+				$blog->printEntries(); 
+		}
+	     ?>
+    <div id="bottompanel">
+	<p><? echo _("Validate"); ?> : <a href="http://validator.w3.org/check?uri=referer">XHTML</a> / <a href="http://jigsaw.w3.org/css-validator/check/referer/">CSS</a> / 
+<?
+	if($blog->userName) {
+		echo "<a href=\"http://feedvalidator.org/check.cgi?url=$rss_url\">RSS</a> / <a href=\"http://feedvalidator.org/check.cgi?url=$atom_url\">ATOM</a>";
+	}
+	else {
+		echo "RSS / ATOM";
+	}
+?>
+	</p>
+    </div>
+<?php
+$page = ob_get_contents();
+ob_end_clean();
+
+$smarty->assign("body", $page);
+$smarty->assign("extra_styles", "/css/blog.css");
+
+	//display debuing info as required
+	if($_SESSION[debug]){
+		echo "<div class=\"debug\"><h2>"._("Debug Info")."</h2><pre>\n";
+		echo "**"._("Session")."**\n";
+		print_r($_SESSION);
+		echo "**"._("Request")."**\n";
+		print_r($_REQUEST);
+		echo "**"._("Class")."**\n";
+		print_r($blog);
+		echo "</pre></div>";
+	}
+
+?>

Modified: branches/sucs-site/components/front.php
===================================================================
--- branches/sucs-site/components/front.php	2015-01-30 16:57:12 UTC (rev 639)
+++ branches/sucs-site/components/front.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -14,6 +14,8 @@
 //$output .= $result;
 include('electionreminder.php');
 $output .= $result;
+include('planetposts.php');
+$output .= $result;
 
 }
 

Modified: branches/sucs-site/components/members.php
===================================================================
--- branches/sucs-site/components/members.php	2015-01-30 16:57:12 UTC (rev 639)
+++ branches/sucs-site/components/members.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -31,7 +31,7 @@
 		// Redirect if we have found a valid single user
 		if (count($usernames) == 1) {
 			$smarty->assign('who', $usernames[0]['uid']);
-			// Add banana widget to the sidebar
+			// Add banana widget to the sidebar 
 			$who = $usernames[0]['uid'];
 			include("../lib/banana-admin.php");
 			// Needs Redirection
@@ -53,33 +53,42 @@
 				if (file_exists( $usernames[0]['homedir'] . '/.plan')) {
 					$usernames[0]['plan'] = file_get_contents($usernames[0]['homedir'] . '/.plan');
 				}
-				// Website
+				// Website	
 				if ( file_exists( $usernames[0]['homedir'] . '/public_html') &&
 				     !file_exists( $usernames[0]['homedir'] . '/public_html/robots.txt'))  {
 					$usernames[0]['website'] = true;
 				}
+				// Blog
+				require_once("/usr/share/php/adodb/adodb.inc.php");
+				$BlogDB = NewADOConnection('postgres8');
+				$BlogDB->Connect('dbname=blogs user=apache');
+				$BlogDB->SetFetchMode(ADODB_FETCH_ASSOC);
+				require_once('../lib/blog/validation.lib.php');
+				if (blogger($usernames[0]['uid'])) {
+					$usernames[0]['blog'] = $BlogDB->GetOne("select title from users where username='".$usernames[0]['uid']."'");
+				}
 				// Bananas stuff
 				$bananasql = "SELECT *, date_trunc('second', whn) FROM awards ";
 				$bananasql .= "WHERE username ~* ? ORDER BY WHN DESC";
 				$awards = $DB->GetAll($bananasql, array("^".$usernames[0]['uid']."$"));
-
+				
 				// arrange by academic year, calculate sums as we go
 				foreach ($awards as $award) {
 					$acyear = academicYear(strtotime($award['whn']));
 					$awards_by_year[$acyear]['awards'][] = $award;
-					$awards_by_year[$acyear]['sum'] += $award['score'];
+					$awards_by_year[$acyear]['sum'] += $award['score']; 
 					$bananasum += $award['score'];
-				}
-
-				$usernames[0]['awardsbyyear'] = &$awards_by_year;
+				} 
+				
+				$usernames[0]['awardsbyyear'] = &$awards_by_year; 
 				$usernames[0]['bananascore'] = $bananasum;
 			}
 		}
 		$smarty->assign('results', $usernames);
-
+	
 	} else {
 	// generate fun data to put on index page
-
+		
 		// top 5
 		$stats['top'] = $DB->GetAll("SELECT username, sum(score) as sum FROM awards GROUP BY username ORDER BY sum DESC LIMIT 5");
 

Modified: branches/sucs-site/components/options.php
===================================================================
--- branches/sucs-site/components/options.php	2015-01-30 16:57:12 UTC (rev 639)
+++ branches/sucs-site/components/options.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -180,6 +180,34 @@
 	return FALSE;
 }
 
+function changeBlogFeed($type, $feed, $syndicate) {
+	global $sucsDB, $session, $smarty;
+	if ($type == "sucs") {
+		$feed="http://sucs.org/blog/feed/atom/".$session->username;
+	}
+	
+	if ($syndicate=="on") {
+		$syndicate = "t";
+	} else {
+		$syndicate = "f";
+	}
+
+	// try to read up to 100KB of the provided feed uri
+	if (@file_get_contents($feed,FALSE,null,0,100000) == FALSE) {
+		trigger_error("Unable to read from provided blog feed URL", E_USER_WARNING);
+		return FALSE;
+	}
+
+	if ($sucsDB->Execute("UPDATE members SET blogfeed=?,syndicateblog=? WHERE username=?", 
+		array($feed, $syndicate, $session->username)) == FALSE) {
+		return FALSE;
+		}	
+
+
+	include("planetconfig.php"); 
+	return TRUE;
+}
+
 function updateRenew() {
 	global $sucsDB, $session, $error;
 	global $paydate;
@@ -255,6 +283,13 @@
 					message_flash('Hackergotchi Cleared');
 				}
 				break;
+			case 'changeblogfeed' :
+				if (changeBlogFeed($_POST['blogtype'], $_POST['bloguri'], $_POST['syndicateblog'])){
+					message_flash("Blog Feed Updated");
+				} else {
+					trigger_error("Blog Feed has not been updated", E_USER_NOTICE);
+				}
+				break;
 			case 'renew' :
 				if (updateRenew()) {
 					message_flash('Account renewed');
@@ -286,6 +321,28 @@
 
 $smarty->assign('member', $member);
 
+// connect to Blog DB to see if user has a SUCS blog	
+	require_once("/usr/share/php/adodb/adodb.inc.php");
+	$BlogDB = NewADOConnection('postgres8');
+	$BlogDB->Connect('dbname=blogs user=apache');
+	$BlogDB->SetFetchMode(ADODB_FETCH_ASSOC); 
+	require_once('../lib/blog/validation.lib.php');
+	if (blogger($session->username)) {
+		$smarty->assign("sucsblogger", TRUE);
+		$feed="http://sucs.org/blog/feed/atom/".$session->username;
+		if ($member['blogfeed'] == $feed) {
+			$smarty->assign("sucsblogfeed", TRUE);
+		}
+	}
+
+	// change postgresql boolean to PHP boolean
+	if ($member['syndicateblog'] == 't') {
+		$member['syndicateblog'] = true;
+	} else {
+		$member['syndicateblog'] = false;
+	}
+	$smarty->assign('member', $member);
+
 }
 
 $smarty->assign('url', $component['path']);

Copied: branches/sucs-site/components/planet.php (from rev 635, branches/sucs-site/components/planet.php)
===================================================================
--- branches/sucs-site/components/planet.php	                        (rev 0)
+++ branches/sucs-site/components/planet.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,10 @@
+<?php
+
+$smarty->assign("title", "Planet SUCS");
+$smarty->assign("rss_url", "http://planet.sucs.org/rss20.xml");
+$smarty->assign("atom_url", "http://planet.sucs.org/atom.xml");
+// Read planet output from where (we hope) Planet wrote it
+$body = file_get_contents($base."static/Community/Planet.txt");
+$smarty->assign("body", $body);
+
+?>

Copied: branches/sucs-site/components/planetconfig.php (from rev 635, branches/sucs-site/components/planetconfig.php)
===================================================================
--- branches/sucs-site/components/planetconfig.php	                        (rev 0)
+++ branches/sucs-site/components/planetconfig.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,38 @@
+<?php
+// component to dynamically generate a configuration file for the Planet feed aggregator
+
+global $base;
+
+// where to put the generated config file?
+$outputfile = $base."lib/venus/sucs/generatedconfig.ini";
+
+// Where Planet should output its generated files to
+$planetoutputdir = $base."htdocs/planet";
+
+$sucsdbname = "sucs";
+$hackergotchipath = "/var/www/sucssite/htdocs/pictures/people/";
+
+// open connection to sucs database
+$sucsDB = NewADOConnection('postgres8');
+$sucsDB->Connect('dbname='.$sucsdbname.' user=apache');
+$sucsDB->SetFetchMode(ADODB_FETCH_ASSOC);
+
+// fetch blogroll
+$blogroll = $sucsDB->GetAll("SELECT username, blogfeed AS feeduri FROM members WHERE syndicateblog=TRUE");
+
+// figure out whether each user has a hackergotchi picture
+foreach($blogroll as &$blog) {
+	if (is_file($hackergotchipath.$blog['username'].".png")) {
+		$blog['hackergotchi'] = TRUE;
+	} else {
+		$blog['hackergotchi'] = FALSE;
+	}
+}
+
+$smarty->assign("blogroll", $blogroll);
+$smarty->assign("planetoutputdir", $planetoutputdir);
+$config = $smarty->fetch("planetconfig.tpl");
+file_put_contents($outputfile, $config);
+
+
+?>

Copied: branches/sucs-site/components/planetposts.php (from rev 635, branches/sucs-site/components/planetposts.php)
===================================================================
--- branches/sucs-site/components/planetposts.php	                        (rev 0)
+++ branches/sucs-site/components/planetposts.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,33 @@
+<?php
+
+// number of recent planet entries we want to return
+$num_entries = 5;
+
+unset($result);
+$planetposts = array();
+
+$xmldata = @file_get_contents("../htdocs/planet/atom.xml");
+
+if (!$xmldata) {
+	trigger_error("No planet atom.xml data loaded", E_USER_WARNING);
+	return;
+} 
+
+$simplexml = simplexml_load_string($xmldata);
+$xml = $simplexml->children('http://www.w3.org/2005/Atom');
+
+foreach ($xml->entry as $entry) {
+	$planetposts[] = array(
+		"post" => $entry->title, 
+		"post_uri" => $entry->link->attributes()->href, 
+		"user" => $entry->author->name,
+		"user_uri" => $entry->author->uri
+		);
+}
+
+$planetposts = array_slice($planetposts, 0, $num_entries);
+
+$smarty->assign('planetposts', $planetposts);
+$result = $smarty->fetch('planetposts.tpl');
+
+?>

Deleted: branches/sucs-site/lib/blog/admin.lib.php
===================================================================
--- branches/sucs-site/lib/blog/admin.lib.php	2015-01-21 12:59:01 UTC (rev 635)
+++ branches/sucs-site/lib/blog/admin.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -1,1001 +0,0 @@
-<?php
-/*
- * blogs class - provides functions for blogs
- */
-
-// Some useful validation functions
-require_once("validation.lib.php");
-// random other functions that aren't validation or db related
-require_once("miscfunctions.lib.php");
-//stuff from blog.lib will be useful
-require_once("blog.lib.php");
-
-//Our Blogs Class
-class admin {
-	//Blog ID
-	var $id;
-	//Blogger's Details
-	var $userName;
-	var $realName;
-	//Errors
-	var $error;
-	//Date formats
-	var $shortDateFormat;
-	var $longDateFormat;
-	//Paths
-	var $httpPath;
-	var $adminPath;
-	var $blogPath;
-	var $basePath;
-	//[temporary] holder for instance of blog class
-	var $blog;
-			
-	//Constructor - checks we've been given a valid username, and pulls in generic blog info
-	function admin() 
-	{
-		global $session, $BlogDB, $baseurl;
-
-		//set the error string first, so we dont wipe out any errors
-		$this->error = '';
-		//set the locale
-		setlocale(LC_ALL, 'en_GB');
-		//pull in the session stuff
-		$this->startSession();
-		//setup our environment
-		$this->userName = $session->username;
-		$this->realName = $session->fullname;
-
-		$this->id = $BlogDB->GetOne("select id from users where username='".$this->userName."'");
-
-		$this->shortDateFormat = "Y-m-d";
-		$this->longDateFormat = "r";
-		$this->httpPath = $baseurl."/Blogs/";
-		$this->adminPath = $this->httpPath."Admin/";
-		$this->basePath = $baseurl."/Blogs/";
-		if($this->httpPath[strlen($this->httpPath)-1]!="/") {
-			$this->httpPath .= "/";
-		}
-		//if we are logged in start a blog instance, and setup the blog path
-		if ($this->userName) {
-			$this->blog = new blogs($this->userName);
-			$this->blogPath = $this->basePath.$this->userName."/";
-		}
-	}
-	
-	//start / check our session
-	function startSession() 
-	{
-		//set the session time out in seconds
-		$maxSessionAge = 10800; //1 hour
-		//setup the session stuff
-		session_name("BlogSession");
-		session_set_cookie_params($maxSessionAge,dirname($_SERVER['SCRIPT_NAME'])."/");
-		session_start();
-		//if we dont have a session, start one
-		if (!$_SESSION[time]) {
-			$_SESSION[time] = time();
-		}
-		//close the session if its too old
-		elseif ((time()-$_SESSION[time]) > $maxSessionAge) {
-			session_unset();
-			$this->error =_("Session Expired");
-			$this->startSession();
-		}
-		//else we are happy, and we just update the session time
-		else {
-			$_SESSION[oldTime] = $_SESSION[time];
-			$_SESSION[time] = time();
-		}
-	}
-	
-	//logs people in
-	function login() 
-	{		
-		global $BlogDB, $smarty;
-		$username = "";
-		$password = "";
-		//sanitise username
-		if (isset($_POST['username']) && trim($_POST['username']) != "" && safeuname(trim($_POST['username']))) {
-			$username = trim($_POST['username']);
-		} 
-		else {
-			$this->error = _("Please check the username field");
-		}
-		//sanitise password
-		if (isset($_POST['password']) && trim($_POST['password']) != "") {
-			$password = trim($_POST['password']);
-		} 
-		else {
-			$this->error = _("Please check the password field");
-		}
-		//no errors?
-		if(!$this->error)
-		{
-			//try to pull in the users details
-			$sqlRow = $BlogDB->GetRow("SELECT id, name, password from users where enabled = true and username = '".$username."' limit 1;");
-
-			//check we returned a user
-			if (!$sqlRow) {
-				$this->error =_("Invalid Username or Password");
-			}
-			else	{
-				//check the password the user gave us agaisnt the one in the database
-				if ($sqlRow['password']!=crypt($password, $sqlRow['password'])) {
-					$this->error =_("Invalid Username or Password");				
-				}
-				else {
-					//if everything matches dump some persistant details into the session
-					$_SESSION['id'] = $sqlRow['id'];
-					$_SESSION['userName'] = $username;
-					$_SESSION['realName'] = $sqlRow['name'];
-					$this->id = $_SESSION['id'];
-					$this->userName = $_SESSION['userName'];
-					$this->realName = $_SESSION['realName'];
-				}
-			}
-		}
-		//return a state to indicate wether login was successful
-		if ($this->error) {
-			return false;
-		}
-		else {
-			return true;
-		}
-	}
-	
-	//admin menu
-	function menu() {
-		global $BlogDB, $smarty, $session;
-
-		$submenu = array();
-		if (blogger($session->username)) {
-			$submenu[_("My blog")] = $this->blogPath;
-			$submenu[_("Write new entry")] = $this->adminPath."newentry";
-			$submenu[_("Edit entries")] = $this->adminPath."showentries";
-			$submenu[_("Settings")] = $this->adminPath."Settings";
-
-			$comments = _("Comments");
-			$result = $BlogDB->GetOne("SELECT count(comments.id) from comments join entries on comments.post = entries.id where moderated = false and entries.user_id = ".$this->id.";");
-			if($result){
-				$comments .= " (".$result.")";
-				}
-			$submenu[$comments] = $this->adminPath."moderatecomments";
-		} else {
-			$submenu[_("Start a Blog")] = $this->adminPath."signup";
-		}
-
-		$menu = $smarty->get_template_vars("menu");
-		$menu[Blogs] = $submenu;
-		$smarty->assign("menu", $menu);
-	}
-	
-	//destroys the session
-	function logout () 
-	{
-		session_unset();
-		header("Location: ".$this->blogPath);
-	}
-	
-	//prints a login form
-	function printLoginForm() 
-	{
-		echo "The Login Form display function has been called. This should not happen.";
-	}
-
-	// post an entry to the db
-	function postEntry()
-	{
-		global $BlogDB;
-		$category = '';
-		$subject = '';
-		$body = '';
-		//sanitise category (make sure it IS a number!)
-		if (isset($_POST['category']) && (int)$_POST['category'] != "" && (int)$_POST['category'] != 0) {
-			$category = (int)$_POST['category'];
-		} else {
-			$this->error = _("Undefined Category!");
-		}
-		//sanitise subject
-		if (isset($_POST['subject']) && trim($_POST['subject']) != "") {
-			//complain if the subject contains html or html like things rather than dumping it without warning
-			if (strip_tags($_POST['subject']) != $_POST['subject']) {
-				$this->error = _("HTML is not allowed in the subject!");			
-			}
-			else {
-				$subject = addslashes(trim($_POST['subject']));
-			}
-		} else {
-			$this->error = _("No entry subject!");
-		}		
-		//sanitise body
-		if (isset($_POST['body']) && trim($_POST['body']) != "") {
-			$body = trim($_POST['body']);
-			//we dont want to use nl2br if peeps are useing tinymce
-			if (!$this->blog->editor) {
-				$body = nl2br($body);
-			}
-			$body = addslashes($body);
-		} else {
-			$this->error = _("No entry body!");
-		}
-		//no errors, so continue..
-		if (!$this->error) {
-			//first we make our short subject
-			$shortsubject = $this->blog->makeCleanString($subject,true);
-			//need to check if there are any short titles like this one already
-			$sql = $BlogDB->GetAll("SELECT shortsubject FROM entries WHERE user_id = {$this->id} AND shortsubject ~ '{$shortsubject}(_[0-9]{1,3}$|$)' ORDER BY char_length(shortsubject) DESC, shortsubject DESC LIMIT 1;");
-			//if so we grab the last one, and add 1 to it..
-			if (count($sql) != 0) {
-				$sqlRow = array_shift($sql);
-				// Put the matched _number into $matches[0] if there is one
-				if (preg_match("/\_[0-9]{1,3}$/",$sqlRow['shortsubject'],$matches)) {
-					// Remove the _ to get the number, add 1 and append
-					$shortsubject .= '_' . ((int)substr($matches[0],1) + 1);
-				} else {
-					$shortsubject .= '_1';
-				}
-			}
-			//shortsubject is now safe..
-			//insert our new entry
-			$sql = $BlogDB->Execute("INSERT INTO entries (category, subject, body, user_id, shortsubject) VALUES ({$category},'{$subject}','{$body}','{$this->id}','{$shortsubject}')");
-			if (!$sql) {
-				error(2,_("Database commit failed")." - ".$BlogDB->ErrorMsg());
-			} 
-			else {
-				// $row = db_last($sql, "entries");
-				$row = $BlogDB->GetRow("SELECT * FROM entries WHERE user_id = {$this->id} AND shortsubject='".$shortsubject."'");
-				$this->blog->printEntry($row,false,false);
-			}
-		}
-		//re-display entry form if there are errors
-		else {
-			$this->printEntryForm($_POST,true);
-		}	
-	}
-	
-	//update an entry in the db
-	function updateEntry($shortSubject)
-	{		
-		global $BlogDB;
-		$category = '';
-		$subject = '';
-		$body = '';		
-		//sanitise and check for existance of a short subject
-		$shortSubject = $this->blog->makeCleanString($shortSubject);
-		if (!$shortSubject) {
-			error(4,_("If you dont give me a post how do you expect me to update it"));
-		}
-		//sanitise category (make sure it IS a number!)
-		if (isset($_POST['category']) && (int)$_POST['category'] != "" && (int)$_POST['category'] != 0) {
-			$category = (int)$_POST['category'];
-		} else {
-			$this->error = _("Undefined Category!");
-		}
-		//sanitise subject
-		if (isset($_POST['subject']) && trim($_POST['subject']) != "") {
-			//complain if the subject contains html or html like things rather than dumping it without warning
-			if (strip_tags($_POST['subject']) != $_POST['subject']) {
-				$this->error = _("HTML is not allowed in the subject!");			
-			}
-			else {
-				$subject = addslashes(trim($_POST['subject']));
-			}
-		} else {
-			$this->error = _("No entry subject!");
-		}		
-		//sanitise body
-		if (isset($_POST['body']) && trim($_POST['body']) != "") {
-			$body = trim($_POST['body']);
-			//we dont want to use nl2br if peeps are useing tinymce
-			if (!$this->blog->editor) {
-				$body = nl2br($body);
-			}
-			$body = addslashes($body);
-		} else {
-			$this->error = _("No entry body!");
-		}
-
-		//no errors, so continue..
-		if (!$this->error) {
-			//check to see this post exists
-			$sql = $BlogDB->GetRow("SELECT id from entries where shortsubject = '".$shortSubject."' AND user_id='".$this->id."';");
-			//yes?, we can update it then..
-			if ($sql) { 
-				$sql = $BlogDB->Execute("UPDATE entries SET category = {$category}, subject = '{$subject}', body = '{$body}' WHERE shortsubject = '{$shortSubject}' AND user_id = '".$this->id."';");
-				if (!$sql) {
-					error(2,_("Database commit failed - ").$BlogDB->ErrorMsg());
-				} 
-				else {
-					echo "<div class=\"updateinfo\">"._("Updated!")."</div>\n";
-					$this->updateForm($shortSubject);
-				}
-			}
-			//cant update non-existant entrys
-			else {
-				 error(2,_("Cannot update entry, as it does not exist.".$BlogDB->ErrorMsg()));
-			}
-		}
-		//redisplay entry form if there are errors
-		else {
-			$this->updateForm($shortSubject);
-		}
-	}
-
-	//update form
-	function updateForm($shortSubject)
-	{
-		global $BlogDB;
-		//sanitise and check the short subject
-		$shortSubject = $this->blog->makeCleanString($shortSubject);
-		if (!$shortSubject) {
-			error(4,_("If you dont give me a post how do you expect me to decide which one you want to edit?"));
-		}
-		//try to grab the post
-		$row = $BlogDB->GetRow("SELECT subject, category, body, shortsubject from entries where shortsubject = '".$shortSubject."' AND user_id = '".$this->id."';");
-		//if it exists we can do stuff with it
-		if ($row) { 
-			$this->printEntryForm($row,true,true);
-		} 
-		//else give an error
-		else {
-			error(2, _("Could not find the requested entry."));
-		}
-	}
-/*	currently not used.. if we dont want to bring back the delete link in printEntry from blog.lib we can get rid of this entirely
-	
-	//delete an entry
-	function deleteEntry($shortSubject)
-	{
-		//sanitise the short subject
-		$shortSubject = $this->blog->makeCleanString($shortSubject);
-		if (!$shortSubject) {
-			error(4,_("If you dont give me a post how do you expect me to delete it"));
-		}
-		//check to see this post exists
-		$sql = db_query("SELECT id from entries where shortsubject = '".$shortSubject."' AND user_id='".$this->id."';");
-		$sqlNum = db_num_rows($sql);
-		//yes?, we can delete it then..
-		if ($sqlNum == 1) { 
-			db_query("DELETE FROM entries WHERE shortsubject = '{$shortSubject}' AND user_id = '".$this->id."';");			
-			echo "<p>"._("Entry deleted.")."</p>";
-		}
-		//can't delete non-existant entries
-		else {
-			 error(2,_("Cannot delete entry, as it does not exist.".db_error()));
-		}
-	}
-*/
-	//update settings
-	function updateSettings()
-	{
-		global $BlogDB;
-		$name = '';
-		$title = '';
-		$description = '';
-		$css = 'blog.css';
-		$password = "";
-		//sanitise name
-		if (isset($_POST['name']) && trim($_POST['name']) != "") {
-			$name = addslashes(trim(strip_tags($_POST['name'])));
-		} 
-		else {
-			$this->error = _("Bad Input - Realname");
-		}
-		//sanitise title
-		if (isset($_POST['btitle']) && trim($_POST['btitle']) != "") {
-			//complain if the title contains html or html like things rather than dumping it without warning
-			if (strip_tags($_POST['btitle']) != $_POST['btitle']) {
-				$this->error = _("HTML is not allowed in the title!");			
-			}
-			else {
-				$title = addslashes(trim($_POST['btitle']));
-			}
-		} 
-		else {
-			$this->error = _("Bad Input - Title");
-		}
-		//sanitise description
-		if (isset($_POST['description']) && trim($_POST['description']) != "") {
-			//complain if the description contains html or html like things rather than dumping it without warning
-			if (strip_tags($_POST['description']) != $_POST['description']) {
-				$this->error = _("HTML is not allowed in the description!");			
-			}
-			else {
-				$description = addslashes(trim($_POST['description']));
-			}
-		}
-		else {
-			$this->error = _("Bad Input - Description");
-		}
-		//sanitise css
-		if (isset($_POST['css'])) { // if its not set its defaulted...
-// It's no use checking if the css file exists in this version at present
-//			if (trim($_POST['css']) != "" && is_file($_POST['css'])) {
-			if (trim($_POST['css']) != "") {
-				$css = $_POST['css'];
-			} 
-			else {
-				$this->error = _("Bad Input - CSS location");
-			}
-		}
-		//sanitise password and encrypt
-		if ($_POST['pass1']) {
-			if ((isset($_POST['pass1']) && trim($_POST['pass1']) != "") && ($_POST['pass1']==$_POST['pass2'])) {
-				$password = crypt($_POST['pass1']);
-			} 
-			else {
-				$this->error = _("Bad Input - Password");
-			}
-		}
-		// checkbox for comment moderation, either is or isnt
-		if ($_POST['moderate'] != "") {
-			$moderate = "true";
-		}
-		else {
-			$moderate = "false";
-		}	
-		// checkbox for editor, either is or isnt
-		if ($_POST['editor'] != "") {
-			$editor = "true";
-		} 
-		else {
-			$editor = "false";
-		}
-		//if there are no errors
-		if (!$this->error) {
-			//construct the query
-			$query = "UPDATE USERS SET name='{$name}', title='{$title}', description='{$description}', css='{$css}', moderate={$moderate}, editor={$editor}";
-			//if the password is set add that too
-			if ($password) {
-				$query .= ", password='{$password}'";
-			}
-			$query .= " WHERE username='{$this->userName}';";
-			//execute query
-			if (!$BlogDB->Execute($query)) {
-				error(2,_("Database Insertion failed."));
-			} 
-			//it it worked report sucsess
-			else {
-				echo "<div class=\"updateinfo\">"._("Blog settings updated.")."</div>\n";
-			}
-		} 
-		//return the form, this also returns the errors if they exist
-		$this->printSettingsForm();
-	}
-	
-	//print the blog Entry form...
-	//used for both new and edit
-	function printEntryForm($row='',$show=false,$edit=false)
-	{
-		global $BlogDB;
-		echo "<div class=\"entry\">\n";
-		if ($this->error) {
-			echo "<div class=\"errorinfo\">Error : " . $this->error . "</div>\n";
-		}
-		echo "<h2>".((!$edit) ?_("Write Entry") : _("Edit Entry"))."</h2>\n";
-		echo "<form action=\"".$this->adminPath.((!$edit) ? "postentry" : "postupdate/{$row['shortsubject']}")."\" method=\"post\" id=\"entryform\">\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"subject\">"._(Subject)."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"subject\" id=\"subject\" value=\"" . (($show) ? htmlentities(strip_tags(trim($row['subject']))) : "") . "\" style=\"width: 100%;\" maxlength=\"100\" tabindex=\"1\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"category\">"._("Category")."</label>\n";
-		echo "<span class=\"textinput\"><select name=\"category\" id=\"category\" tabindex=\"2\">";
-		//pull in the list of catogories from the database
-		$sql = $BlogDB->GetAll("SELECT id, name FROM categories ORDER BY name ASC;");
-		while ($sqlRow = array_shift($sql)) {
-			echo "<option value=\"{$sqlRow['id']}\"".(((int)$row['category'] == $sqlRow['id']) ? " selected=\"selected\"" : "").">{$sqlRow['name']}</option>\n";
-		}
-		echo "</select></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"body\">Body</label>\n";
-		echo "<span class=\"textinput\"><textarea name=\"body\" id=\"body\" tabindex=\"3\" style=\"width: 100%; height: 30em;\">";
-		if ($show) {
-		//we dont want to use br2nl if peeps are using tinymce
-			if (!$this->blog->editor) {
-				echo "<![CDATA[".br2nl($row['body'])."]]>";
-			}
-			else {
-				echo htmlentities($row['body'], ENT_QUOTES, "UTF-8");
-			}
-		}
-		echo "</textarea></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\"Submit Entry\" /></span>\n";
-		echo "</div>\n<div class=\"clear\"></div>\n";
-		echo "</form>\n";
-		echo "</div>\n";
-	}
-
-	//print the blog settings form...
-	function printSettingsForm()
-	{
-		global $BlogDB;
-		//pull in user's current settings from the database
-		$settings = $BlogDB->GetRow("SELECT name, title, description, css, moderate, editor FROM users WHERE username='" . $this->userName . "'");
-		echo "<div class=\"entry\">\n";
-		if ($this->error) {
-			echo "<div class=\"errorinfo\">Error : " . $this->error . "</div>\n";
-		}
-		echo "<h2>"._("Blog Settings")."</h2>\n";
-		echo "<form action=\"".$this->adminPath."Settings\" method=\"post\" id=\"settingsform\">\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"name\">"._("Real name")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"name\" id=\"name\" value=\"" . $settings['name'] . "\" size=\"30\" maxlength=\"60\" tabindex=\"1\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"btitle\">"._("Title")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"btitle\" id=\"btitle\" value=\"" . $settings['title'] . "\" size=\"30\" maxlength=\"60\" tabindex=\"2\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"description\">"._("Description")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"description\" id=\"description\" value=\"" . $settings['description'] . "\" size=\"30\" maxlength=\"60\" tabindex=\"3\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"css\">"._("CSS")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"css\" id=\"css\" value=\"" . $settings['css'] . "\" size=\"30\" maxlength=\"255\" tabindex=\"4\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"moderate\">"._("Moderate new comments")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"checkbox\" name=\"moderate\" id=\"moderate\" ".(($settings['moderate']=="t") ? "checked=\"checked\"" : "")." /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"editor\">"._("Enable HTML editor")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"checkbox\" name=\"editor\" id=\"editor\" ".(($settings['editor']=="t") ? "checked=\"checked\"" : "")." /></span>\n";
-		echo "</div>\n";
-/*		echo "<div class=\"row\">\n";
-		echo "<label for=\"pass1\">"._("Password")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"password\" name=\"pass1\" id=\"pass1\" value=\"\" size=\"15\" maxlength=\"16\" tabindex=\"5\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"pass2\">"._("Again")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"password\" name=\"pass2\" id=\"pass2\" value=\"\" size=\"15\" maxlength=\"16\" tabindex=\"6\" /></span>\n";
-		echo "</div>\n"; */
-		echo "<div class=\"row\">\n";
-		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\"Save Settings\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"clear\"></div>\n";
-		echo "</form>\n";
-		echo "</div>\n";	
-	}
-	//shows unmoderated comments
-	function printComments() {
-		global $BlogDB;
-		//grab all unmoderated comments
-		$result = $BlogDB->GetAll("SELECT comments.*, entries.shortsubject from comments join entries on comments.post = entries.id where moderated = false and entries.user_id = ".$this->id." ORDER BY entries.subject ASC;");
-		if(count($result)==0) {
-			return;
-		}
-		echo "<div class=\"entry\">\n";
-		echo "<h2>Comments Pending Approval</h2>\n";
-		echo "<p>The comments in red are probably spam. They are premarked to be deleted for your convience.</p>\n";
-echo "<p><strong>Because of the large amount of spam and limited use the Blog system currently gets, all comments are defaulted to spam at present. <span style=\"color: red;\">Exercise caution</span></strong></p>\n";
-		echo "<form action=\"{$this->adminPath}updatecomments/\" method=\"post\">\n";
-		echo "<table class=\"td\">\n";
-		$post = '';		
-		$count = 0;
-
-		echo "<tfoot>\n\t<tr>\n\t\t<td></td>\n\t\t<td></td>\n\t\t<td></td>\n\t\t<td colspan=\"2\"><input type=\"submit\" value=\"Commit\" name=\"submit\" /></td>\n\t</tr>\n</tfoot>\n";
-		echo "<tbody>\n";
-		//for each comment
-		while($r = array_shift($result)) {
-			//if the post has changed
-			if ($post != $r['shortsubject']) {
-				//grab the post, display it and the subject then some headers
-				$internalR = $BlogDB->GetRow("SELECT subject, body from entries where shortsubject = '".$r['shortsubject']."' and user_id = ".$this->id." limit 1;");
-				echo "\t<tr>\n";
-				echo "\t\t<th colspan=\"4\"><a href=\"{$this->blogPath}entry/{$r['shortsubject']}\">". htmlentities($internalR['subject']) ."</a></th>\n";
-				echo "\t</tr>\n";
-				echo "\t<tr>\n";
-				echo "\t\t<td colspan=\"4\">{$internalR['body']}</td>\n";
-				echo "\t</tr>\n";
-				echo "\t<tr>\n";
-				echo "\t\t<th>Author</th>\n";
-				echo "\t\t<th>Body</th>\n";
-				echo "\t\t<th>Approve</th>\n";
-				echo "\t\t<th>Delete</th>\n";
-				echo "\t</tr>\n";
-				$post = $r['shortsubject'];
-			}
-			//how display each of the comments
-			if ($r['spam'] == 't') { 
-				echo "\t<tr class=\"errorinfo\">\n";
-			} else {
-				echo "\t<tr>\n";
-			}
-			echo "\t\t<td><a href=\"mailto:{$r['email']}\" title=\"IP: {$r['host']}\">{$r['name']}</a></td>\n";
-			echo "\t\t<td>".htmlentities($r['body'], ENT_COMPAT, 'UTF-8')."</td>\n";
-			echo "\t\t<td><input type=\"radio\" name=\"group[$count]\" value=\"a:{$r['id']}\" /></td>\n";
-//			if ($r['spam'] == 't') { 
-				echo "\t\t<td><input type=\"radio\" name=\"group[".$count++."]\" value=\"d:{$r['id']}\" checked=\"checked\"/></td>\n";
-//			} else {
-//				echo "\t\t<td><input type=\"radio\" name=\"group[".$count++."]\" value=\"d:{$r['id']}\" /></td>\n";
-//			}
-			echo "\t</tr>\n";
-		}
-
-		echo "</tbody>\n</table>\n";
-		echo "</form>\n";
-		echo "</div>\n";
-	}
-	// approve or delete comments
-	function updateComments() {
-		global $BlogDB;
-		if (count($_POST['group'])==0) {
-			error(2, _("No comments selected for approval/deletion."));
-			return;
-		}
-		$check = "";
-		$approved = "";
-		$acount = 0;
-		$deleted = "";
-		$dcount = 0;
-		//get the comment numbers and requested actions.
-		foreach($_POST['group'] as $comment) {
-			$c = explode(":", $comment);
-			if ($c[0] == "a") {
-				$approved .= (int)$c[1].", ";
-				$acount++;
-			} elseif ($c[0] == "d") {
-				$deleted .= (int)$c[1].", ";
-				$dcount++;
-			} else {
-				error(1, _("Malformed input."));
-				return;
-			}
-		}
-		$approved = substr($approved, 0, -2);
-		$deleted = substr($deleted, 0, -2);
-		//construct a list of comments to check
-		if ($approved and $deleted) {
-			$check = $deleted.", ".$approved;
-		} else {
-			$check = $deleted.$approved;
-		}
-		//check the comments exist and blong to the user
-		$result = $BlogDB->GetRow("SELECT count(comments.id) from comments join entries on comments.post = entries.id where entries.user_id = ".$this->id." and comments.id IN($check);");
-		if($result[count] != ($acount + $dcount)) {
-			error(1,_("Cant find the requested comments, maybe they have already been deleted."));
-			return;
-		}
-		//delete comments
-		if($deleted!="") {
-			$BlogDB->Execute("DELETE FROM comments WHERE id IN ($deleted);");
-		}
-		//set moderated flag on comments
-		if($approved!="") {
-			$BlogDB->Execute("UPDATE comments SET moderated=true WHERE id IN ($approved);");
-		}
-		//reprint the form
-		echo "<div class=\"updateinfo\">$acount "._("comments approved").", $dcount "._("comments deleted").".</div>\n";
-		$this->printComments();
-		$this->printAuthorisedUsers();
-	}
-
-	//Delete moderated comments from (a single post)
-	function deleteComments($entry) {
-		global $BlogDB;
-		if(isset($_POST['submit'])) {
-			if(count($_POST['comment'])==0){
-				error(5, _("No comments selected for deletion."));
-				echo "<a href=\"{$this->blogPath}entry/$entry\">"._("Return to blog entry")."</a>\n";
-			} else {
-				$del = "(";
-				foreach($_POST['comment'] as $c) {
-					$del .= "comments.id = ".(int)$c." OR ";
-				}
-				$del = substr($del, 0, -4).")";
-				//check the comments exist and blong to the user
-				$result = $BlogDB->GetOne("SELECT count(comments.id) from comments join entries on comments.post = entries.id where entries.user_id = ".$this->id." and $del;");
-				if($result[0] != count($_POST['comment'])) {
-					error(1,_("Cant find the requested comments, maybe they have already been deleted."));
-					return;
-				}
-				//delete the comments
-				$sql = "DELETE FROM comments WHERE $del";
-				if(!$BlogDB->Execute($sql)) {
-					error(2, _("Database commit error."));
-				} else {
-					echo "<div class=\"updateinfo\">".count($_POST['comment'])._(" comment(s) deleted.")."</div>\n";
-					echo "<a href=\"{$this->blogPath}entry/$entry\">"._("Return to blog entry")."</a>\n";
-				}
-			}
-		}
-	}
-	//prints a form populated with email addresses that can avoid moderation on comments
-	function printAuthorisedUsers() {
-		global $BlogDB;
-		echo "<div class=\"entry\">\n";
-		echo "<a name=\"emails\"></a>\n";
-		echo "<h2>"._("Known Users")."</h2>\n";
-		//if comment moderation is off tell the user its a bit daft
-		if(!$this->blog->comment_moderation) {
-			echo "<p>"._("Comment moderation is turned off on your blog - anyone can post comments. To turn comment moderation on, visit the")." <a href=\"".$this->adminPath."Settings\">"._("settings page")."</a>.</p>\n";
-			echo "</div>";
-			return;
-		}
-		echo "<p>"._("Comments posted to your blog with an e-mail address that appears in the list below avoid the moderation queue and appear on your blog immediately.")."</p>\n";
-		echo "<p>"._("To turn off comment moderation, visit the")." <a href=\"{$this->adminPath}Settings\">"._("settings page")."</a>.</p>\n";
-		echo "<form name=\"emailform\" id=\"emailform\" action=\"".$this->adminPath."updateauthusers\" method=\"post\">\n";
-		echo "<select multiple=\"multiple\" name=\"emaillist[]\" size=\"10\">\n";
-		$result = $BlogDB->GetAll("SELECT name,email FROM authorised_emails WHERE user_id=".$this->id." ORDER BY email ASC");
-		while($r = array_shift($result)) {
-			echo "\t<option value=\"{$r['email']}\">{$r['email']} ({$r['name']})</option>\n";
-		}
-		echo "</select><br />\n";
-		echo "<input type=\"submit\" name=\"delete\" value=\"Delete selected\" />\n";
-		echo "</form>\n";
-		//close and start a new form, so pressing enter in the 2nd bit of the form submits with addnew rather than delete
-		echo "<form name=\"emailform\" id=\"emailform\" action=\"".$this->adminPath."updateauthusers\" method=\"post\">\n";
-		echo "<h3>"._("Add Address")."</h3>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"name\"> "._("Name (not displayed anywhere but here)")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"name\" id=\"name\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"email\"> "._("E-mail address")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"email\" id=\"email\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<span class=\"textinput\"><input type=\"submit\" name=\"addnew\" value=\"Add address\" /></span>\n";
-		echo "</div>\n<div class=\"clear\"></div>\n";
-		echo "</form>\n";
-		echo "</div>\n";
-	}
-	//udates the list of authorised users.
-	function updateAuthorisedUsers($quiet=FALSE) {
-		global $BlogDB;
-		//hack so we get error returned from validEmail
-		global $error;
-		//if we have a delete action
-		if(isset($_POST['delete'])) {
-			if (count($_POST['emaillist'])==0) {
-				error(5,_("No addresses selected for deletion."));
-			} else {
-				$del = "(";
-				foreach($_POST['emaillist'] as $addr) {
-					if(validEmail($addr)) {
-						$del .= "email='$addr' OR ";
-					} else {
-						error(2,_("Invalid email address : ".$error));
-						return;
-					}
-				}
-				$del = substr($del, 0, -4).")";
-				$sql = "DELETE FROM authorised_emails WHERE $del AND user_id={$this->id}";
-				$ret = $BlogDB->Execute($sql);
-				if(!$ret) {
-					error(2, _("Database commit error: ").$BlogDB->ErrorMsg());
-				} else {
-					echo "<div class=\"updateinfo\">"._("Address(es) deleted")."</div>\n";
-				}
-			}
-		} 
-		//if we have an add action
-		elseif(isset($_POST['addnew'])) {
-			if(trim($_POST['name'])=="" or !preg_match("/^([a-z0-9]+([:space:][a-z0-9]*))$/i",trim($_POST['name']))) {
-				$this->error = _("Check name");
-			}
-			if(!validEmail($_POST['email'])) {
-				$this->error = _("Invalid e-mail address : ".$error);
-			}
-			if($this->error==""){
-				$name = addslashes(trim($_POST['name']));
-				$email = addslashes(trim($_POST['email']));
-				$ret = $BlogDB->Execute("INSERT INTO authorised_emails (user_id, name, email) VALUES ('{$this->id}', '{$name}', '{$email}');");
-				if(!$ret){
-					error(2, $BlogDB->ErrorMsg());
-				} else {
-					echo "<div class=\"updateinfo\">"._("Address added")."</div>\n";
-				}
-			}
-			else {
-				error(3,$this->error);
-			}
-		}
-		if(!$quiet){
-			$this->printComments();
-			$this->printAuthorisedUsers();
-		}
-	}
-	//prints a list of entries for the admin front page.
-	function printEntries($amount=0, $title=TRUE) {
-		global $BlogDB;
-		$limit = ($amount > 0) ? " LIMIT $amount" : "";
-		$result = $BlogDB->GetAll("SELECT shortsubject,timestamp,subject FROM entries WHERE user_id = '".$this->id."' ORDER BY timestamp DESC $limit;");
-		if(count($result)==0){
-			error(5, _("No entries found."));
-		} else {
-			if($title){
-				echo "<div class=\"entry\"><h2>"._("Edit Entries")."</h2>\n";
-			}
-			echo "<form action=\"{$this->adminPath}confirmdeleteentries/\" method=\"post\">\n<table class=\"td\">\n\t<tr>\n\t\t<th width=\"38%\">Date</th>\n\t\t<th>Title</th>\n\t\t<th width=\"5%\">Delete</th>\n\t</tr>\n";
-			$rownum = 0;
-			while($row = array_shift($result)){
-				echo "\t<tr>\n";
-				echo "\t\t<td>".strftime($this->blog->longDateFormat, strtotime($row['timestamp']))."</td>\n";
-				echo "\t\t<td><a href=\"".$this->adminPath."update/".$row['shortsubject']."\">".htmlentities($row['subject'])."</a></td>\n";
-				echo "\t\t<td><input type=\"checkbox\" name=\"entry[".$rownum++."]\" value=\"{$row['shortsubject']}\" /></td>\n";
-				echo "\t</tr>\n";
-			}
-			echo "\t<tr>\n";
-			echo "\t\t<td colspan=\"3\" align=\"right\"><input type=\"submit\" name=\"submit\" value=\""._("Delete Selected")."\" /></td>\n";
-			echo "\t</tr>\n";
-			echo "</table>\n";
-			echo "</form>\n";
-			if($title) {
-				echo "</div>\n";
-			}
-		}
-	}
-	//confirm entry deletion
-	function confirmDeleteEntries() {
-		echo "<form action=\"{$this->adminPath}deleteentries/\" method=\"post\">\n";
-		echo "<p>"._("Are you sure you want to delete the following entries?")."</p>\n<ul>\n";
-		$rownum = 0;
-		foreach ($_REQUEST[entry] as $entry) {
-			$entry = $this->blog->makeCleanString($entry);
-			echo "<input type=\"hidden\" name=\"entry[".$rownum++."]\" value=\"{$entry}\" />";
-			echo "<li>".$entry."</li>\n";
-		}
-		echo "</ul>\n";
-		echo "<p><input type=\"submit\" name=\"submit\" value=\""._("Yes")."\" />\n<input type=\"submit\" name=\"submit\" value=\""._("No")."\" /></p>\n";
-		echo "</form>\n";
-	}
-	//deletes entries
-	function deleteEntries() {
-		global $BlogDB;
-		if (count($_POST['entry'])==0) {
-			error(4, _("No entries marked for deletion."));
-		} else {
-			if ($_REQUEST[submit]==_("Yes")) {
-				$sql = "DELETE FROM entries WHERE (";
-				foreach($_POST['entry'] as $id) {
-					$sql .= "shortsubject = '".$this->blog->makeCleanString($id)."' OR ";
-				}
-				$sql = substr($sql, 0, -4);
-				$sql .= ") AND user_id = {$this->id};";
-				$BlogDB->Execute($sql);
-				echo $BlogDB->Affected_Rows()._(" post(s) deleted");
-			} else {
-				error(4, _("Entries not deleted."));
-			}
-		}
-	}
-	//constructs the main page
-	function mainPage() {
-		//Should display blog entries here
-		echo "<div class=\"entry\">\n";
-		echo "<h2>"._("Blog Management")."</h2>\n";
-		echo "<div class=\"td\">\n";
-		echo "<p>"._("Use the links on the left to manage your blog, or choose a recent entry to edit:")."</p>\n";
-		$this->printEntries(5, FALSE);
-		echo "<a href=\"".$this->adminPath."showentries\">show all entries...</a></div>\n";
-		echo "</div>\n";
-	}
-	//adds a user
-	function addUser() {
-		global $BlogDB, $session;
-		$username = '';
-		$password = makePassword();
-		$name = '';
-		$title = '';
-		$description = '';
-		//sanitise username
-		if (trim($session->username) != "") {
-			if (safeuname($session->username)) {
-				$username = $session->username;
-			} else {
-				$this->error = _("Invalid Username Provided");
-			}
-		} else {
-			$this->error = _("No Username Provided");
-		}
-
-		//sanitise name, perhaps a bit too strict?
-		if (trim($session->fullname)) {
-//			if (eregi("^([a-z]+([:space:][a-z]*))$",trim($session->fullname))) {
-// Not working, so changed to something that does work
-
-		if (isset($session->fullname)) {
-
-				$name = trim($session->fullname);
-			}
-			else {
-				$this->error = _("Invalid Name Provided");
-			}
-		} else {
-			$this->error = _("No Real Name Provided");
-		}
-		//sanitise title, regexp? ^([a-z0-9]+([:space:][a-z0-9]*))$ as a base form and '\', '-', '.', ',', ':', ';', '?', '!'
-		if (isset($_POST['btitle']) && trim($_POST['btitle']) != "") {
-			$title = addslashes(trim(strip_tags($_POST['btitle'])));
-		} else {
-			$this->error = _("No Title Provided");
-		}
-		//sanitise description, same check as title gets
-		if (isset($_POST['description']) && trim($_POST['description']) != "") {
-			$description = addslashes(trim(strip_tags($_POST['description'])));
-		} else {
-			$this->error = _("No Description Provided");
-		}
-		//check the user doesn't already exist
-		$sql = $BlogDB->GetAll("SELECT username from users where username = '".$username."';");
-		if (count($sql) != 0) {
-			$this->error = _("Username already in use!");
-		}
-		//check there is a system user with this name (ie if they are a sucs member)
-		if(!posix_getpwnam($username)) {
-			$this->error = _("You need to be a SUCS member to sign up for a blog here!");
-		} else {
-			//check the user is a member of the users, staff or societies groups
-			$posixInfo = posix_getpwnam($username);
-			if ($posixInfo[gid] != 100 && $posixInfo[gid] != 1060 && $posixInfo[gid] != 1130) {
-				$this->error = _("Err, no, you're not really a system user now are you?");
-			}
-		}
-		//if we dont have any errors
-		if (!$this->error) {
-			//encrypt the password
-			$cryptPassword = crypt($password);
-			//add to the database
-			$sql = ("INSERT into USERS (username,password,name,title,description) VALUES ('{$username}','{$cryptPassword}','{$name}','{$title}','{$description}');");
-			//error if that failed
-			if (!$BlogDB->Execute($sql)) {
-				error(2,_("Database Insertion failed - ").$BlogDB->ErrorMsg());
-			} else {
-				//else mail the password to the user and report sucsess
-				mail(
-					"{$username}@sucs.org",
-					_("Blog Password"),
-					_("Welcome to SUCS Blogs")."\n\n"._("The multi-user web log system created by SUCS members for SUCS members.")."\n\n"._("You Blog Password is : ").$password."\n"._("Please login and change it at ")."http://".$_SERVER["SERVER_NAME"].$this->adminPath,
-					"From: \"Blog Admin\" <blogadmin at sucs.org>"
-				);
-				echo _("Account Added!<br />Your password has been sent to your SUCS email account");
-				//bodge it so the username is filled in
-				$session->username = $username;
-			}
-		} else {
-			//return to the form
-			$this->addUserForm();
-		}
-	}
-	//this should take all the input and post it to addUser, passing in the current user and stuff... i think...
-	function addUserForm() {
-		global $session;
-		echo "<div class=\"entry\">\n";
-		if ($this->error != "") {
-			echo "<div class=\"errorinfo\">"._("Error")." : " . $this->error . "</div>\n";
-		}
-		echo "<h2>"._("Register for a Blog")."</h2>\n";
-		echo "<div class=\"td\">\n";
-		echo "<form action=\"".$this->adminPath."adduser\" method=\"post\" id=\"adduserform\">\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"username\">"._("Username")."</label>\n";
-//		echo "<span class=\"textinput\"><input type=\"text\" name=\"username\" id=\"username\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['username'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"1\" /></span>\n";
-		echo "<span class=\"textinput\">{$session->username}</span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"name\">"._("Real name")."</label>\n";
-//		echo "<span class=\"textinput\"><input type=\"text\" name=\"name\" id=\"name\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['name'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"2\" /></span>\n";
-		echo "<span class=\"textinput\">{$session->fullname}</span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"btitle\">"._("Title")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"btitle\" id=\"btitle\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['btitle'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"3\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"title\">"._("Description")."</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"description\" id=\"description\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['description'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"4\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\""._("Sign Up")."\" /></span>\n";
-		echo "</div>\n<div class=\"clear\"></div>\n";
-		echo "</form>\n";
-		echo "<p>"._("You need to be a member of ")."<a href=\"http://sucs.org/\">SUCS</a>"._(" to register")."<br />"._("The normal ")."<a href=\"http://sucs.org/About/Conditions\">"._("Terms and Conditions")."</a>"._(" apply")."</p>\n";
-		echo "</div>\n";
-		echo "</div>\n";
-	}
-}

Copied: branches/sucs-site/lib/blog/admin.lib.php (from rev 635, branches/sucs-site/lib/blog/admin.lib.php)
===================================================================
--- branches/sucs-site/lib/blog/admin.lib.php	                        (rev 0)
+++ branches/sucs-site/lib/blog/admin.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,1006 @@
+<?php
+/*
+ * blogs class - provides functions for blogs
+ */
+
+// Some useful validation functions
+require_once("validation.lib.php");
+// random other functions that aren't validation or db related
+require_once("miscfunctions.lib.php");
+//stuff from blog.lib will be useful
+require_once("blog.lib.php");
+
+//Our Blogs Class
+class admin {
+	//Blog ID
+	var $id;
+	//Blogger's Details
+	var $userName;
+	var $realName;
+	//Errors
+	var $error;
+	//Date formats
+	var $shortDateFormat;
+	var $longDateFormat;
+	//Paths
+	var $httpPath;
+	var $adminPath;
+	var $blogPath;
+	var $basePath;
+	//[temporary] holder for instance of blog class
+	var $blog;
+			
+	//Constructor - checks we've been given a valid username, and pulls in generic blog info
+	function admin() 
+	{
+		global $session, $BlogDB, $baseurl;
+
+		//set the error string first, so we dont wipe out any errors
+		$this->error = '';
+		//set the locale
+		setlocale(LC_ALL, 'en_GB');
+		//pull in the session stuff
+		$this->startSession();
+		//setup our environment
+		$this->userName = $session->username;
+		$this->realName = $session->fullname;
+
+		$this->id = $BlogDB->GetOne("select id from users where username=?", array($this->userName));
+
+		$this->shortDateFormat = "Y-m-d";
+		$this->longDateFormat = "r";
+		$this->httpPath = $baseurl."/Blogs/";
+		$this->adminPath = $this->httpPath."Admin/";
+		$this->basePath = $baseurl."/Blogs/";
+		if($this->httpPath[strlen($this->httpPath)-1]!="/") {
+			$this->httpPath .= "/";
+		}
+		//if we are logged in start a blog instance, and setup the blog path
+		if ($this->userName) {
+			$this->blog = new blogs($this->userName);
+			$this->blogPath = $this->basePath.$this->userName."/";
+		}
+	}
+	
+	//start / check our session
+	function startSession() 
+	{
+		//set the session time out in seconds
+		$maxSessionAge = 10800; //1 hour
+		//setup the session stuff
+		session_name("BlogSession");
+		session_set_cookie_params($maxSessionAge,dirname($_SERVER['SCRIPT_NAME'])."/");
+		session_start();
+		//if we dont have a session, start one
+		if (!$_SESSION[time]) {
+			$_SESSION[time] = time();
+		}
+		//close the session if its too old
+		elseif ((time()-$_SESSION[time]) > $maxSessionAge) {
+			session_unset();
+			$this->error =_("Session Expired");
+			$this->startSession();
+		}
+		//else we are happy, and we just update the session time
+		else {
+			$_SESSION[oldTime] = $_SESSION[time];
+			$_SESSION[time] = time();
+		}
+	}
+	
+	//logs people in
+	function login() 
+	{		
+		global $BlogDB, $smarty;
+		$username = "";
+		$password = "";
+		//sanitise username
+		if (isset($_POST['username']) && trim($_POST['username']) != "" && safeuname(trim($_POST['username']))) {
+			$username = trim($_POST['username']);
+		} 
+		else {
+			$this->error = _("Please check the username field");
+		}
+		//sanitise password
+		if (isset($_POST['password']) && trim($_POST['password']) != "") {
+			$password = trim($_POST['password']);
+		} 
+		else {
+			$this->error = _("Please check the password field");
+		}
+		//no errors?
+		if(!$this->error)
+		{
+			//try to pull in the users details
+			$sqlRow = $BlogDB->GetRow("SELECT id, name, password from users where enabled = true and username = ? limit 1;", array($username));
+
+			//check we returned a user
+			if (!$sqlRow) {
+				$this->error =_("Invalid Username or Password");
+			}
+			else	{
+				//check the password the user gave us agaisnt the one in the database
+				if ($sqlRow['password']!=crypt($password, $sqlRow['password'])) {
+					$this->error =_("Invalid Username or Password");				
+				}
+				else {
+					//if everything matches dump some persistant details into the session
+					$_SESSION['id'] = $sqlRow['id'];
+					$_SESSION['userName'] = $username;
+					$_SESSION['realName'] = $sqlRow['name'];
+					$this->id = $_SESSION['id'];
+					$this->userName = $_SESSION['userName'];
+					$this->realName = $_SESSION['realName'];
+				}
+			}
+		}
+		//return a state to indicate wether login was successful
+		if ($this->error) {
+			return false;
+		}
+		else {
+			return true;
+		}
+	}
+	
+	//admin menu
+	function menu() {
+		global $BlogDB, $smarty, $session;
+
+		$submenu = array();
+		if (blogger($session->username)) {
+			$submenu[_("My blog")] = $this->blogPath;
+			$submenu[_("Write new entry")] = $this->adminPath."newentry";
+			$submenu[_("Edit entries")] = $this->adminPath."showentries";
+			$submenu[_("Settings")] = $this->adminPath."Settings";
+
+			$comments = _("Comments");
+			$result = $BlogDB->GetOne("SELECT count(comments.id) from comments join entries on comments.post = entries.id where moderated = false and entries.user_id = ?;", array($this->id));
+			if($result){
+				$comments .= " (".$result.")";
+				}
+			$submenu[$comments] = $this->adminPath."moderatecomments";
+		} else {
+			$submenu[_("Start a Blog")] = $this->adminPath."signup";
+		}
+
+		$menu = $smarty->get_template_vars("menu");
+		$menu[Blogs] = $submenu;
+		$smarty->assign("menu", $menu);
+	}
+	
+	//destroys the session
+	function logout () 
+	{
+		session_unset();
+		header("Location: ".$this->blogPath);
+	}
+	
+	//prints a login form
+	function printLoginForm() 
+	{
+		echo "The Login Form display function has been called. This should not happen.";
+	}
+
+	// post an entry to the db
+	function postEntry()
+	{
+		global $BlogDB;
+		$category = '';
+		$subject = '';
+		$body = '';
+		//sanitise category (make sure it IS a number!)
+		if (isset($_POST['category']) && (int)$_POST['category'] != "" && (int)$_POST['category'] != 0) {
+			$category = (int)$_POST['category'];
+		} else {
+			$this->error = _("Undefined Category!");
+		}
+		//sanitise subject
+		if (isset($_POST['subject']) && trim($_POST['subject']) != "") {
+			//complain if the subject contains html or html like things rather than dumping it without warning
+			if (strip_tags($_POST['subject']) != $_POST['subject']) {
+				$this->error = _("HTML is not allowed in the subject!");			
+			}
+			else {
+				$subject = trim($_POST['subject']);
+			}
+		} else {
+			$this->error = _("No entry subject!");
+		}		
+		//sanitise body
+		if (isset($_POST['body']) && trim($_POST['body']) != "") {
+			$body = trim($_POST['body']);
+			//we dont want to use nl2br if peeps are useing tinymce
+			if (!$this->blog->editor) {
+				$body = nl2br($body);
+			}
+		} else {
+			$this->error = _("No entry body!");
+		}
+		//no errors, so continue..
+		if (!$this->error) {
+			//first we make our short subject
+			$shortsubject = $this->blog->makeCleanString($subject,true);
+			//need to check if there are any short titles like this one already
+			$sql = $BlogDB->GetAll("SELECT shortsubject FROM entries WHERE user_id = ? AND shortsubject ~ '{$shortsubject}(_[0-9]{1,3}$|$)' ORDER BY char_length(shortsubject) DESC, shortsubject DESC LIMIT 1;", array($this->id));
+			//if so we grab the last one, and add 1 to it..
+			if (count($sql) != 0) {
+				$sqlRow = array_shift($sql);
+				// Put the matched _number into $matches[0] if there is one
+				if (preg_match("/\_[0-9]{1,3}$/",$sqlRow['shortsubject'],$matches)) {
+					// Remove the _ to get the number, add 1 and append
+					$shortsubject .= '_' . ((int)substr($matches[0],1) + 1);
+				} else {
+					$shortsubject .= '_1';
+				}
+			}
+			//shortsubject is now safe..
+			//insert our new entry
+			$sql = $BlogDB->Execute("INSERT INTO entries (category, subject, body, user_id, shortsubject) VALUES (?,?,?,?,?)", array($category,$subject,$body,$this->id,$shortsubject));
+			if (!$sql) {
+				error(2,_("Database commit failed")." - ".$BlogDB->ErrorMsg());
+			} 
+			else {
+				// $row = db_last($sql, "entries");
+				$row = $BlogDB->GetRow("SELECT * FROM entries WHERE user_id=? AND shortsubject=?", array($this->id, $shortsubject));
+				$this->blog->printEntry($row,false,false);
+			}
+		}
+		//re-display entry form if there are errors
+		else {
+			$this->printEntryForm($_POST,true);
+		}	
+	}
+	
+	//update an entry in the db
+	function updateEntry($shortSubject)
+	{		
+		global $BlogDB;
+		$category = '';
+		$subject = '';
+		$body = '';		
+		//sanitise and check for existance of a short subject
+		$shortSubject = $this->blog->makeCleanString($shortSubject);
+		if (!$shortSubject) {
+			error(4,_("If you dont give me a post how do you expect me to update it"));
+		}
+		//sanitise category (make sure it IS a number!)
+		if (isset($_POST['category']) && (int)$_POST['category'] != "" && (int)$_POST['category'] != 0) {
+			$category = (int)$_POST['category'];
+		} else {
+			$this->error = _("Undefined Category!");
+		}
+		//sanitise subject
+		if (isset($_POST['subject']) && trim($_POST['subject']) != "") {
+			//complain if the subject contains html or html like things rather than dumping it without warning
+			if (strip_tags($_POST['subject']) != $_POST['subject']) {
+				$this->error = _("HTML is not allowed in the subject!");			
+			}
+			else {
+				$subject = trim($_POST['subject']);
+			}
+		} else {
+			$this->error = _("No entry subject!");
+		}		
+		//sanitise body
+		if (isset($_POST['body']) && trim($_POST['body']) != "") {
+			$body = trim($_POST['body']);
+			//we dont want to use nl2br if peeps are useing tinymce
+			if (!$this->blog->editor) {
+				$body = nl2br($body);
+			}
+		} else {
+			$this->error = _("No entry body!");
+		}
+
+		//no errors, so continue..
+		if (!$this->error) {
+			//check to see this post exists
+			$sql = $BlogDB->GetRow("SELECT id from entries where shortsubject=? AND user_id=?;", array($shortSubject, $this->id));
+			//yes?, we can update it then..
+			if ($sql) { 
+				$sql = $BlogDB->Execute("UPDATE entries SET category=?, subject=?, body=? WHERE shortsubject=? AND user_id=?;", array($category, $subject, $body, $shortSubject, $this->id));
+				if (!$sql) {
+					error(2,_("Database commit failed - ").$BlogDB->ErrorMsg());
+				} 
+				else {
+					echo "<div class=\"updateinfo\">"._("Updated!")."</div>\n";
+					$this->updateForm($shortSubject);
+				}
+			}
+			//cant update non-existant entrys
+			else {
+				 error(2,_("Cannot update entry, as it does not exist.".$BlogDB->ErrorMsg()));
+			}
+		}
+		//redisplay entry form if there are errors
+		else {
+			$this->updateForm($shortSubject);
+		}
+	}
+
+	//update form
+	function updateForm($shortSubject)
+	{
+		global $BlogDB;
+		//sanitise and check the short subject
+		$shortSubject = $this->blog->makeCleanString($shortSubject);
+		if (!$shortSubject) {
+			error(4,_("If you dont give me a post how do you expect me to decide which one you want to edit?"));
+		}
+		//try to grab the post
+		$row = $BlogDB->GetRow("SELECT subject, category, body, shortsubject from entries where shortsubject=? AND user_id=?;", array($shortSubject, $this->id));
+		//if it exists we can do stuff with it
+		if ($row) { 
+			$this->printEntryForm($row,true,true);
+		} 
+		//else give an error
+		else {
+			error(2, _("Could not find the requested entry."));
+		}
+	}
+/*	currently not used.. if we dont want to bring back the delete link in printEntry from blog.lib we can get rid of this entirely
+	
+	//delete an entry
+	function deleteEntry($shortSubject)
+	{
+		//sanitise the short subject
+		$shortSubject = $this->blog->makeCleanString($shortSubject);
+		if (!$shortSubject) {
+			error(4,_("If you dont give me a post how do you expect me to delete it"));
+		}
+		//check to see this post exists
+		$sql = db_query("SELECT id from entries where shortsubject = '".$shortSubject."' AND user_id='".$this->id."';");
+		$sqlNum = db_num_rows($sql);
+		//yes?, we can delete it then..
+		if ($sqlNum == 1) { 
+			db_query("DELETE FROM entries WHERE shortsubject = '{$shortSubject}' AND user_id = '".$this->id."';");			
+			echo "<p>"._("Entry deleted.")."</p>";
+		}
+		//can't delete non-existant entries
+		else {
+			 error(2,_("Cannot delete entry, as it does not exist.".db_error()));
+		}
+	}
+*/
+	//update settings
+	function updateSettings()
+	{
+		global $BlogDB;
+		$name = '';
+		$title = '';
+		$description = '';
+		$css = 'blog.css';
+		$password = "";
+		//sanitise name
+		if (isset($_POST['name']) && trim($_POST['name']) != "") {
+			$name = trim(strip_tags($_POST['name']));
+		} 
+		else {
+			$this->error = _("Bad Input - Realname");
+		}
+		//sanitise title
+		if (isset($_POST['btitle']) && trim($_POST['btitle']) != "") {
+			//complain if the title contains html or html like things rather than dumping it without warning
+			if (strip_tags($_POST['btitle']) != $_POST['btitle']) {
+				$this->error = _("HTML is not allowed in the title!");			
+			}
+			else {
+				$title = trim($_POST['btitle']);
+			}
+		} 
+		else {
+			$this->error = _("Bad Input - Title");
+		}
+		//sanitise description
+		if (isset($_POST['description']) && trim($_POST['description']) != "") {
+			//complain if the description contains html or html like things rather than dumping it without warning
+			if (strip_tags($_POST['description']) != $_POST['description']) {
+				$this->error = _("HTML is not allowed in the description!");			
+			}
+			else {
+				$description = trim($_POST['description']);
+			}
+		}
+		else {
+			$this->error = _("Bad Input - Description");
+		}
+		//sanitise css
+		if (isset($_POST['css'])) { // if its not set its defaulted...
+// It's no use checking if the css file exists in this version at present
+//			if (trim($_POST['css']) != "" && is_file($_POST['css'])) {
+			if (trim($_POST['css']) != "") {
+				$css = $_POST['css'];
+			} 
+			else {
+				$this->error = _("Bad Input - CSS location");
+			}
+		}
+		//sanitise password and encrypt
+		if ($_POST['pass1']) {
+			if ((isset($_POST['pass1']) && trim($_POST['pass1']) != "") && ($_POST['pass1']==$_POST['pass2'])) {
+				$password = crypt($_POST['pass1']);
+			} 
+			else {
+				$this->error = _("Bad Input - Password");
+			}
+		}
+		// checkbox for comment moderation, either is or isnt
+		if ($_POST['moderate'] != "") {
+			$moderate = "true";
+		}
+		else {
+			$moderate = "false";
+		}	
+		// checkbox for editor, either is or isnt
+		if ($_POST['editor'] != "") {
+			$editor = "true";
+		} 
+		else {
+			$editor = "false";
+		}
+		//if there are no errors
+		if (!$this->error) {
+			//construct the query
+			$query = "UPDATE USERS SET name=?, title=?, description=?, css=?, moderate=?, editor=?";
+			$params = array( $name, $title, $description, $css, $moderate, $editor);
+			//if the password is set add that too
+			if ($password) {
+				$query .= ", password=?";
+				$params[] = $password;
+			}
+			$query .= " WHERE username=?;";
+			$params[] = $this->userName;
+			//execute query
+			if (!$BlogDB->Execute($query, $params)) {
+				error(2,_("Database Insertion failed."));
+			} 
+			//it it worked report sucsess
+			else {
+				echo "<div class=\"updateinfo\">"._("Blog settings updated.")."</div>\n";
+			}
+		} 
+		//return the form, this also returns the errors if they exist
+		$this->printSettingsForm();
+	}
+	
+	//print the blog Entry form...
+	//used for both new and edit
+	function printEntryForm($row='',$show=false,$edit=false)
+	{
+		global $BlogDB;
+		echo "<div class=\"entry\">\n";
+		if ($this->error) {
+			echo "<div class=\"errorinfo\">Error : " . $this->error . "</div>\n";
+		}
+		echo "<h2>".((!$edit) ?_("Write Entry") : _("Edit Entry"))."</h2>\n";
+		echo "<form action=\"".$this->adminPath.((!$edit) ? "postentry" : "postupdate/{$row['shortsubject']}")."\" method=\"post\" id=\"entryform\">\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"subject\">"._(Subject)."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"subject\" id=\"subject\" value=\"" . (($show) ? htmlentities(strip_tags(trim($row['subject']))) : "") . "\" style=\"width: 100%;\" maxlength=\"100\" tabindex=\"1\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"category\">"._("Category")."</label>\n";
+		echo "<span class=\"textinput\"><select name=\"category\" id=\"category\" tabindex=\"2\">";
+		//pull in the list of catogories from the database
+		$sql = $BlogDB->GetAll("SELECT id, name FROM categories ORDER BY name ASC;");
+		while ($sqlRow = array_shift($sql)) {
+			echo "<option value=\"{$sqlRow['id']}\"".(((int)$row['category'] == $sqlRow['id']) ? " selected=\"selected\"" : "").">{$sqlRow['name']}</option>\n";
+		}
+		echo "</select></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"body\">Body</label>\n";
+		echo "<span class=\"textinput\"><textarea name=\"body\" id=\"body\" tabindex=\"3\" style=\"width: 100%; height: 30em;\">";
+		if ($show) {
+		//we dont want to use br2nl if peeps are using tinymce
+			if (!$this->blog->editor) {
+				echo "<![CDATA[".br2nl($row['body'])."]]>";
+			}
+			else {
+				echo htmlentities($row['body'], ENT_QUOTES, "UTF-8");
+			}
+		}
+		echo "</textarea></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\"Submit Entry\" /></span>\n";
+		echo "</div>\n<div class=\"clear\"></div>\n";
+		echo "</form>\n";
+		echo "</div>\n";
+	}
+
+	//print the blog settings form...
+	function printSettingsForm()
+	{
+		global $BlogDB;
+		//pull in user's current settings from the database
+		$settings = $BlogDB->GetRow("SELECT name, title, description, css, moderate, editor FROM users WHERE username=?", array($this->userName));
+		echo "<div class=\"entry\">\n";
+		if ($this->error) {
+			echo "<div class=\"errorinfo\">Error : " . $this->error . "</div>\n";
+		}
+		echo "<h2>"._("Blog Settings")."</h2>\n";
+		echo "<form action=\"".$this->adminPath."Settings\" method=\"post\" id=\"settingsform\">\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"name\">"._("Real name")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"name\" id=\"name\" value=\"" . $settings['name'] . "\" size=\"30\" maxlength=\"60\" tabindex=\"1\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"btitle\">"._("Title")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"btitle\" id=\"btitle\" value=\"" . $settings['title'] . "\" size=\"30\" maxlength=\"60\" tabindex=\"2\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"description\">"._("Description")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"description\" id=\"description\" value=\"" . $settings['description'] . "\" size=\"30\" maxlength=\"60\" tabindex=\"3\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"css\">"._("CSS")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"css\" id=\"css\" value=\"" . $settings['css'] . "\" size=\"30\" maxlength=\"255\" tabindex=\"4\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"moderate\">"._("Moderate new comments")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"checkbox\" name=\"moderate\" id=\"moderate\" ".(($settings['moderate']=="t") ? "checked=\"checked\"" : "")." /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"editor\">"._("Enable HTML editor")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"checkbox\" name=\"editor\" id=\"editor\" ".(($settings['editor']=="t") ? "checked=\"checked\"" : "")." /></span>\n";
+		echo "</div>\n";
+/*		echo "<div class=\"row\">\n";
+		echo "<label for=\"pass1\">"._("Password")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"password\" name=\"pass1\" id=\"pass1\" value=\"\" size=\"15\" maxlength=\"16\" tabindex=\"5\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"pass2\">"._("Again")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"password\" name=\"pass2\" id=\"pass2\" value=\"\" size=\"15\" maxlength=\"16\" tabindex=\"6\" /></span>\n";
+		echo "</div>\n"; */
+		echo "<div class=\"row\">\n";
+		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\"Save Settings\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"clear\"></div>\n";
+		echo "</form>\n";
+		echo "</div>\n";	
+	}
+	//shows unmoderated comments
+	function printComments() {
+		global $BlogDB;
+		//grab all unmoderated comments
+		$result = $BlogDB->GetAll("SELECT comments.*, entries.shortsubject from comments join entries on comments.post = entries.id where moderated = false and entries.user_id = ? ORDER BY entries.subject ASC;", array($this->id));
+		if(count($result)==0) {
+			return;
+		}
+		echo "<div class=\"entry\">\n";
+		echo "<h2>Comments Pending Approval</h2>\n";
+		echo "<p>The comments in red are probably spam. They are premarked to be deleted for your convience.</p>\n";
+echo "<p><strong>Because of the large amount of spam and limited use the Blog system currently gets, all comments are defaulted to spam at present. <span style=\"color: red;\">Exercise caution</span></strong></p>\n";
+		echo "<form action=\"{$this->adminPath}updatecomments/\" method=\"post\">\n";
+		echo "<table class=\"td\">\n";
+		$post = '';		
+		$count = 0;
+
+		echo "<tfoot>\n\t<tr>\n\t\t<td></td>\n\t\t<td></td>\n\t\t<td></td>\n\t\t<td colspan=\"2\"><input type=\"submit\" value=\"Commit\" name=\"submit\" /></td>\n\t</tr>\n</tfoot>\n";
+		echo "<tbody>\n";
+		//for each comment
+		while($r = array_shift($result)) {
+			//if the post has changed
+			if ($post != $r['shortsubject']) {
+				//grab the post, display it and the subject then some headers
+				$internalR = $BlogDB->GetRow("SELECT subject, body from entries where shortsubject = ? and user_id = ? limit 1;", array($r['shortsubject'], $this->id));
+				echo "\t<tr>\n";
+				echo "\t\t<th colspan=\"4\"><a href=\"{$this->blogPath}entry/{$r['shortsubject']}\">". htmlentities($internalR['subject']) ."</a></th>\n";
+				echo "\t</tr>\n";
+				echo "\t<tr>\n";
+				echo "\t\t<td colspan=\"4\">{$internalR['body']}</td>\n";
+				echo "\t</tr>\n";
+				echo "\t<tr>\n";
+				echo "\t\t<th>Author</th>\n";
+				echo "\t\t<th>Body</th>\n";
+				echo "\t\t<th>Approve</th>\n";
+				echo "\t\t<th>Delete</th>\n";
+				echo "\t</tr>\n";
+				$post = $r['shortsubject'];
+			}
+			//how display each of the comments
+			if ($r['spam'] == 't') { 
+				echo "\t<tr class=\"errorinfo\">\n";
+			} else {
+				echo "\t<tr>\n";
+			}
+			echo "\t\t<td><a href=\"mailto:{$r['email']}\" title=\"IP: {$r['host']}\">{$r['name']}</a></td>\n";
+			echo "\t\t<td>".htmlentities($r['body'], ENT_COMPAT, 'UTF-8')."</td>\n";
+			echo "\t\t<td><input type=\"radio\" name=\"group[$count]\" value=\"a:{$r['id']}\" /></td>\n";
+//			if ($r['spam'] == 't') { 
+				echo "\t\t<td><input type=\"radio\" name=\"group[".$count++."]\" value=\"d:{$r['id']}\" checked=\"checked\"/></td>\n";
+//			} else {
+//				echo "\t\t<td><input type=\"radio\" name=\"group[".$count++."]\" value=\"d:{$r['id']}\" /></td>\n";
+//			}
+			echo "\t</tr>\n";
+		}
+
+		echo "</tbody>\n</table>\n";
+		echo "</form>\n";
+		echo "</div>\n";
+	}
+	// approve or delete comments
+	function updateComments() {
+		global $BlogDB;
+		if (count($_POST['group'])==0) {
+			error(2, _("No comments selected for approval/deletion."));
+			return;
+		}
+		$check = "";
+		$approved = "";
+		$acount = 0;
+		$deleted = "";
+		$dcount = 0;
+		//get the comment numbers and requested actions.
+		foreach($_POST['group'] as $comment) {
+			$c = explode(":", $comment);
+			if ($c[0] == "a") {
+				$approved .= (int)$c[1].", ";
+				$acount++;
+			} elseif ($c[0] == "d") {
+				$deleted .= (int)$c[1].", ";
+				$dcount++;
+			} else {
+				error(1, _("Malformed input."));
+				return;
+			}
+		}
+		$approved = substr($approved, 0, -2);
+		$deleted = substr($deleted, 0, -2);
+		//construct a list of comments to check
+		if ($approved and $deleted) {
+			$check = $deleted.", ".$approved;
+		} else {
+			$check = $deleted.$approved;
+		}
+		//check the comments exist and blong to the user
+		$result = $BlogDB->GetRow("SELECT count(comments.id) from comments join entries on comments.post = entries.id where entries.user_id = ? and comments.id IN($check);", array($this->id));
+		if($result[count] != ($acount + $dcount)) {
+			error(1,_("Cant find the requested comments, maybe they have already been deleted."));
+			return;
+		}
+		//delete comments
+		if($deleted!="") {
+			$BlogDB->Execute("DELETE FROM comments WHERE id IN ($deleted);");
+		}
+		//set moderated flag on comments
+		if($approved!="") {
+			$BlogDB->Execute("UPDATE comments SET moderated=true WHERE id IN ($approved);");
+		}
+		//reprint the form
+		echo "<div class=\"updateinfo\">$acount "._("comments approved").", $dcount "._("comments deleted").".</div>\n";
+		$this->printComments();
+		$this->printAuthorisedUsers();
+	}
+
+	//Delete moderated comments from (a single post)
+	function deleteComments($entry) {
+		global $BlogDB;
+		if(isset($_POST['submit'])) {
+			if(count($_POST['comment'])==0){
+				error(5, _("No comments selected for deletion."));
+				echo "<a href=\"{$this->blogPath}entry/$entry\">"._("Return to blog entry")."</a>\n";
+			} else {
+				$del = "(";
+				foreach($_POST['comment'] as $c) {
+					$del .= "comments.id = ".(int)$c." OR ";
+				}
+				$del = substr($del, 0, -4).")";
+				//check the comments exist and blong to the user
+				$result = $BlogDB->GetOne("SELECT count(comments.id) from comments join entries on comments.post = entries.id where entries.user_id = ? and $del;", array($this->id));
+				if($result[0] != count($_POST['comment'])) {
+					error(1,_("Cant find the requested comments, maybe they have already been deleted."));
+					return;
+				}
+				//delete the comments
+				$sql = "DELETE FROM comments WHERE $del";
+				if(!$BlogDB->Execute($sql)) {
+					error(2, _("Database commit error."));
+				} else {
+					echo "<div class=\"updateinfo\">".count($_POST['comment'])._(" comment(s) deleted.")."</div>\n";
+					echo "<a href=\"{$this->blogPath}entry/$entry\">"._("Return to blog entry")."</a>\n";
+				}
+			}
+		}
+	}
+	//prints a form populated with email addresses that can avoid moderation on comments
+	function printAuthorisedUsers() {
+		global $BlogDB;
+		echo "<div class=\"entry\">\n";
+		echo "<a name=\"emails\"></a>\n";
+		echo "<h2>"._("Known Users")."</h2>\n";
+		//if comment moderation is off tell the user its a bit daft
+		if(!$this->blog->comment_moderation) {
+			echo "<p>"._("Comment moderation is turned off on your blog - anyone can post comments. To turn comment moderation on, visit the")." <a href=\"".$this->adminPath."Settings\">"._("settings page")."</a>.</p>\n";
+			echo "</div>";
+			return;
+		}
+		echo "<p>"._("Comments posted to your blog with an e-mail address that appears in the list below avoid the moderation queue and appear on your blog immediately.")."</p>\n";
+		echo "<p>"._("To turn off comment moderation, visit the")." <a href=\"{$this->adminPath}Settings\">"._("settings page")."</a>.</p>\n";
+		echo "<form name=\"emailform\" id=\"emailform\" action=\"".$this->adminPath."updateauthusers\" method=\"post\">\n";
+		echo "<select multiple=\"multiple\" name=\"emaillist[]\" size=\"10\">\n";
+		$result = $BlogDB->GetAll("SELECT name,email FROM authorised_emails WHERE user_id=? ORDER BY email ASC", array($this->id));
+		while($r = array_shift($result)) {
+			echo "\t<option value=\"{$r['email']}\">{$r['email']} ({$r['name']})</option>\n";
+		}
+		echo "</select><br />\n";
+		echo "<input type=\"submit\" name=\"delete\" value=\"Delete selected\" />\n";
+		echo "</form>\n";
+		//close and start a new form, so pressing enter in the 2nd bit of the form submits with addnew rather than delete
+		echo "<form name=\"emailform\" id=\"emailform\" action=\"".$this->adminPath."updateauthusers\" method=\"post\">\n";
+		echo "<h3>"._("Add Address")."</h3>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"name\"> "._("Name (not displayed anywhere but here)")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"name\" id=\"name\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"email\"> "._("E-mail address")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"email\" id=\"email\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<span class=\"textinput\"><input type=\"submit\" name=\"addnew\" value=\"Add address\" /></span>\n";
+		echo "</div>\n<div class=\"clear\"></div>\n";
+		echo "</form>\n";
+		echo "</div>\n";
+	}
+	//udates the list of authorised users.
+	function updateAuthorisedUsers($quiet=FALSE) {
+		global $BlogDB;
+		//hack so we get error returned from validEmail
+		global $error;
+		//if we have a delete action
+		if(isset($_POST['delete'])) {
+			if (count($_POST['emaillist'])==0) {
+				error(5,_("No addresses selected for deletion."));
+			} else {
+				$del = "(";
+				foreach($_POST['emaillist'] as $addr) {
+					if(validEmail($addr)) {
+						$del .= "email='$addr' OR ";
+					} else {
+						error(2,_("Invalid email address : ".$error));
+						return;
+					}
+				}
+				$del = substr($del, 0, -4).")";
+				$sql = "DELETE FROM authorised_emails WHERE $del AND user_id=?";
+				$ret = $BlogDB->Execute($sql, array($this->id));
+				if(!$ret) {
+					error(2, _("Database commit error: ").$BlogDB->ErrorMsg());
+				} else {
+					echo "<div class=\"updateinfo\">"._("Address(es) deleted")."</div>\n";
+				}
+			}
+		} 
+		//if we have an add action
+		elseif(isset($_POST['addnew'])) {
+			if(trim($_POST['name'])=="" or !preg_match("/^([a-z0-9]+([:space:][a-z0-9]*))$/i",trim($_POST['name']))) {
+				$this->error = _("Check name");
+			}
+			if(!validEmail($_POST['email'])) {
+				$this->error = _("Invalid e-mail address : ".$error);
+			}
+			if($this->error==""){
+				$name = trim($_POST['name']);
+				$email = trim($_POST['email']);
+				$ret = $BlogDB->Execute("INSERT INTO authorised_emails (user_id, name, email) VALUES (?,?,?);", array($this->id, $name, $email));
+				if(!$ret){
+					error(2, $BlogDB->ErrorMsg());
+				} else {
+					echo "<div class=\"updateinfo\">"._("Address added")."</div>\n";
+				}
+			}
+			else {
+				error(3,$this->error);
+			}
+		}
+		if(!$quiet){
+			$this->printComments();
+			$this->printAuthorisedUsers();
+		}
+	}
+	//prints a list of entries for the admin front page.
+	function printEntries($amount=0, $title=TRUE) {
+		global $BlogDB;
+		$limit = ($amount > 0) ? " LIMIT $amount" : "";
+		$result = $BlogDB->GetAll("SELECT shortsubject,timestamp,subject FROM entries WHERE user_id = ? ORDER BY timestamp DESC $limit;", array($this->id));
+		if(count($result)==0){
+			error(5, _("No entries found."));
+		} else {
+			if($title){
+				echo "<div class=\"entry\"><h2>"._("Edit Entries")."</h2>\n";
+			}
+			echo "<form action=\"{$this->adminPath}confirmdeleteentries/\" method=\"post\">\n<table class=\"td\">\n\t<tr>\n\t\t<th width=\"38%\">Date</th>\n\t\t<th>Title</th>\n\t\t<th width=\"5%\">Delete</th>\n\t</tr>\n";
+			$rownum = 0;
+			while($row = array_shift($result)){
+				echo "\t<tr>\n";
+				echo "\t\t<td>".strftime($this->blog->longDateFormat, strtotime($row['timestamp']))."</td>\n";
+				echo "\t\t<td><a href=\"".$this->adminPath."update/".$row['shortsubject']."\">".htmlentities($row['subject'])."</a></td>\n";
+				echo "\t\t<td><input type=\"checkbox\" name=\"entry[".$rownum++."]\" value=\"{$row['shortsubject']}\" /></td>\n";
+				echo "\t</tr>\n";
+			}
+			echo "\t<tr>\n";
+			echo "\t\t<td colspan=\"3\" align=\"right\"><input type=\"submit\" name=\"submit\" value=\""._("Delete Selected")."\" /></td>\n";
+			echo "\t</tr>\n";
+			echo "</table>\n";
+			echo "</form>\n";
+			if($title) {
+				echo "</div>\n";
+			}
+		}
+	}
+	//confirm entry deletion
+	function confirmDeleteEntries() {
+		echo "<form action=\"{$this->adminPath}deleteentries/\" method=\"post\">\n";
+		echo "<p>"._("Are you sure you want to delete the following entries?")."</p>\n<ul>\n";
+		$rownum = 0;
+		foreach ($_REQUEST[entry] as $entry) {
+			$entry = $this->blog->makeCleanString($entry);
+			echo "<input type=\"hidden\" name=\"entry[".$rownum++."]\" value=\"{$entry}\" />";
+			echo "<li>".$entry."</li>\n";
+		}
+		echo "</ul>\n";
+		echo "<p><input type=\"submit\" name=\"submit\" value=\""._("Yes")."\" />\n<input type=\"submit\" name=\"submit\" value=\""._("No")."\" /></p>\n";
+		echo "</form>\n";
+	}
+	//deletes entries
+	function deleteEntries() {
+		global $BlogDB;
+		if (count($_POST['entry'])==0) {
+			error(4, _("No entries marked for deletion."));
+		} else {
+			if ($_REQUEST[submit]==_("Yes")) {
+				$sql = "DELETE FROM entries WHERE (";
+				$params = array();
+				foreach($_POST['entry'] as $id) {
+					$sql .= "shortsubject = ? OR ";
+					$params[] = $this->blog->makeCleanString($id);
+				}
+				$sql = substr($sql, 0, -4);
+				$sql .= ") AND user_id = ?;";
+				$params[] = $this->id;
+				$BlogDB->Execute($sql, $params);
+				echo $BlogDB->Affected_Rows()._(" post(s) deleted");
+			} else {
+				error(4, _("Entries not deleted."));
+			}
+		}
+	}
+	//constructs the main page
+	function mainPage() {
+		//Should display blog entries here
+		echo "<div class=\"entry\">\n";
+		echo "<h2>"._("Blog Management")."</h2>\n";
+		echo "<div class=\"td\">\n";
+		echo "<p>"._("Use the links on the left to manage your blog, or choose a recent entry to edit:")."</p>\n";
+		$this->printEntries(5, FALSE);
+		echo "<a href=\"".$this->adminPath."showentries\">show all entries...</a></div>\n";
+		echo "</div>\n";
+	}
+	//adds a user
+	function addUser() {
+		global $BlogDB, $session;
+		$username = '';
+		$password = makePassword();
+		$name = '';
+		$title = '';
+		$description = '';
+		//sanitise username
+		if (trim($session->username) != "") {
+			if (safeuname($session->username)) {
+				$username = $session->username;
+			} else {
+				$this->error = _("Invalid Username Provided");
+			}
+		} else {
+			$this->error = _("No Username Provided");
+		}
+
+		//sanitise name, perhaps a bit too strict?
+		if (trim($session->fullname)) {
+//			if (eregi("^([a-z]+([:space:][a-z]*))$",trim($session->fullname))) {
+// Not working, so changed to something that does work
+
+		if (isset($session->fullname)) {
+
+				$name = trim($session->fullname);
+			}
+			else {
+				$this->error = _("Invalid Name Provided");
+			}
+		} else {
+			$this->error = _("No Real Name Provided");
+		}
+		//sanitise title, regexp? ^([a-z0-9]+([:space:][a-z0-9]*))$ as a base form and '\', '-', '.', ',', ':', ';', '?', '!'
+		if (isset($_POST['btitle']) && trim($_POST['btitle']) != "") {
+			$title = trim(strip_tags($_POST['btitle']));
+		} else {
+			$this->error = _("No Title Provided");
+		}
+		//sanitise description, same check as title gets
+		if (isset($_POST['description']) && trim($_POST['description']) != "") {
+			$description = trim(strip_tags($_POST['description']));
+		} else {
+			$this->error = _("No Description Provided");
+		}
+		//check the user doesn't already exist
+		$sql = $BlogDB->GetAll("SELECT username from users where username = ?", array($username));
+		if (count($sql) != 0) {
+			$this->error = _("Username already in use!");
+		}
+		//check there is a system user with this name (ie if they are a sucs member)
+		if(!posix_getpwnam($username)) {
+			$this->error = _("You need to be a SUCS member to sign up for a blog here!");
+		} else {
+			//check the user is a member of the users, staff or societies groups
+			$posixInfo = posix_getpwnam($username);
+			if ($posixInfo[gid] != 100 && $posixInfo[gid] != 1060 && $posixInfo[gid] != 1130) {
+				$this->error = _("Err, no, you're not really a system user now are you?");
+			}
+		}
+		//if we dont have any errors
+		if (!$this->error) {
+			//encrypt the password
+			$cryptPassword = crypt($password);
+			//add to the database
+			$sql = "INSERT into USERS (username,password,name,title,description) VALUES (?,?,?,?,?)";
+			$params = array($username,$cryptPassword,$name,$title,$description);
+			//error if that failed
+			if (!$BlogDB->Execute($sql, $params)) {
+				error(2,_("Database Insertion failed - ").$BlogDB->ErrorMsg());
+			} else {
+				//else mail the password to the user and report sucsess
+				mail(
+					"{$username}@sucs.org",
+					_("Blog Password"),
+					_("Welcome to SUCS Blogs")."\n\n"._("The multi-user web log system created by SUCS members for SUCS members.")."\n\n"._("You Blog Password is : ").$password."\n"._("Please login and change it at ")."http://".$_SERVER["SERVER_NAME"].$this->adminPath,
+					"From: \"Blog Admin\" <blogadmin at sucs.org>"
+				);
+				echo _("Account Added!<br />Your password has been sent to your SUCS email account");
+				//bodge it so the username is filled in
+				$session->username = $username;
+			}
+		} else {
+			//return to the form
+			$this->addUserForm();
+		}
+	}
+	//this should take all the input and post it to addUser, passing in the current user and stuff... i think...
+	function addUserForm() {
+		global $session;
+		echo "<div class=\"entry\">\n";
+		if ($this->error != "") {
+			echo "<div class=\"errorinfo\">"._("Error")." : " . $this->error . "</div>\n";
+		}
+		echo "<h2>"._("Register for a Blog")."</h2>\n";
+		echo "<div class=\"td\">\n";
+		echo "<form action=\"".$this->adminPath."adduser\" method=\"post\" id=\"adduserform\">\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"username\">"._("Username")."</label>\n";
+//		echo "<span class=\"textinput\"><input type=\"text\" name=\"username\" id=\"username\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['username'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"1\" /></span>\n";
+		echo "<span class=\"textinput\">{$session->username}</span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"name\">"._("Real name")."</label>\n";
+//		echo "<span class=\"textinput\"><input type=\"text\" name=\"name\" id=\"name\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['name'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"2\" /></span>\n";
+		echo "<span class=\"textinput\">{$session->fullname}</span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"btitle\">"._("Title")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"btitle\" id=\"btitle\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['btitle'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"3\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"title\">"._("Description")."</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"description\" id=\"description\" value=\"" . (($this->error != "") ? strip_tags(trim($_POST['description'])) : "") . "\" size=\"30\" maxlength=\"60\" tabindex=\"4\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\""._("Sign Up")."\" /></span>\n";
+		echo "</div>\n<div class=\"clear\"></div>\n";
+		echo "</form>\n";
+		echo "<p>"._("You need to be a member of ")."<a href=\"http://sucs.org/\">SUCS</a>"._(" to register")."<br />"._("The normal ")."<a href=\"http://sucs.org/About/Conditions\">"._("Terms and Conditions")."</a>"._(" apply")."</p>\n";
+		echo "</div>\n";
+		echo "</div>\n";
+	}
+}

Deleted: branches/sucs-site/lib/blog/blog.lib.php
===================================================================
--- branches/sucs-site/lib/blog/blog.lib.php	2015-01-21 12:59:01 UTC (rev 635)
+++ branches/sucs-site/lib/blog/blog.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -1,858 +0,0 @@
-<?php
-/* vim: set tabstop=4: */
-/*
- * blogs class - provides functions for blogs
- */
-
-// PHP Notices are fun, but we don't really want to see them right now
-error_reporting(E_ALL ^ E_NOTICE);
-
-// Initialise the database
-require_once("/usr/share/php/adodb/adodb.inc.php");
-$BlogDB = NewADOConnection('postgres8');
-$BlogDB->Connect('dbname=blogs user=apache');
-$BlogDB->SetFetchMode(ADODB_FETCH_ASSOC);
-
-// Some useful validation functions
-require_once("validation.lib.php");
-
-// Some useful miscellaneous functions
-require_once("miscfunctions.lib.php");
-
-/* a stub of an error handler
-
-scale of 1-5, 5 being warnings, 1 being fatal errors?
-1 : fatal
-2 : dberror
-3
-4 : bad input
-5 : not found/doesnt exist etc
-*/
-function error($level, $error) {
-	echo("<p class=\"errorinfo\">"._("Level ").$level._(" error - ").$error."</p>");
-}
-//A bit of a nicer error handler, to allow errors encounterd in the construction phase to be displayed in the 'correct' place
-function error_exc($e) {
-	if (!isset($e->error) || !isset($e->errormsg)) {
-		echo("<p class=\"errorinfo\">"._("Level 0 error - no error message available")."</p>");
-	} else {
-		echo("<p class=\"errorinfo\">"._("Level ").$e->error._(" error - ").$e->errormsg."</p>");
-	}
-}
-
-//Our Blogs Class
-class blogs {
-	//Blog ID
-	var $id;
-	//Blogger's Details
-	var $userName;
-	var $realName;
-	//Blog Details
-	var $title;
-	var $description;
-	var $cssFile;
-	//Date formats
-	var $shortDateFormat;
-	var $longDateFormat;
-	//Paths
-	var $httpPath;
-	var $blogPath;
-	var $basePath;
-	var $adminPath;
-	//bools
-	var $comment_moderation;
-	var $editor; //surely this should be in admin.lib? it doesnt seem to be used in blog.lib
-	var $currentEntry;
-	//Errors
-	var $error;
-	var $errormsg;
-	//SVN Revision... the closest thing we've got to a version number
-	var $svnRevision;
-	
-	//Constructor - checks we've been given a valid username, and pulls in generic blog info
-	function blogs($user) {
-		global $BlogDB;
-		//set the error string first, so we dont wipe out any errors
-		$this->error = null;
-		$this->errormsg = null;
-		//set the locale
-		setlocale(LC_ALL, 'en_GB');
-		//check the username
-		if(!safeuname($user)) {
-			$this->error = 1;
-			$this->errormsg = "No such user";
-			return;
-		} else {
-			//check to see if the user has a blog
-			$sql = $BlogDB->GetRow("SELECT id, name, title, description, css, moderate, editor from users where username = '".$user."' and enabled = true;");
-			if (!$sql) {
-				$this->error = 1;
-				$this->errormsg = "No such user";
-				return;
-			} else {
-				//pull in the blog details
-				$this->id = $sql['id'];
-				$this->userName = $user;
-				$this->realName = $sql['name'];
-				$this->title = $sql['title'];
-				$this->description = $sql['description'];
-				$this->cssFile = $sql['css'];
-				$this->shortDateFormat = "%x %X";
-				$this->longDateFormat = "%c";
-				//set path for all http stuff.. ie images, css and so on
-				$this->httpPath = "/Blogs/";
-				//make the httpPath work nicely if we're not in a subdir
-				//if(substr($this->httpPath, -1)!="/") {
-				//	$this->httpPath .= "/";
-				//}
-				//path for the blog viewer with no user
-				$this->basePath = "/Blogs/";
-				//path to this blog
-				$this->blogPath = $this->basePath.$this->userName."/";
-				//path to the admin bits
-				$this->adminPath = $this->httpPath."Admin/";
-				$this->comment_moderation = ($sql['moderate']=='t') ? TRUE : FALSE;
-				$this->editor = ($sql['editor']=='t') ? TRUE : FALSE;
-				$this->currentEntry = "";
-				$this->svnRevision = getSVNRevision();
-				//setup the session
-				session_name("BlogSession");
-				session_start();
-			}
-		}
-	}
-
-	// print a blog entry, when provided with a database $row containing one.
-	function printEntry($row, $commentLink = true, $titleLink = true) {
-		global $pathlist;
-		echo "<div class=\"box\">\n";
-
-		echo "<div class=\"boxhead\"><h2>";
-		if ($titleLink) {
-			echo "<a href=\"{$this->blogPath}entry/". htmlentities($row['shortsubject']) ."\">". htmlentities($row['subject']) ."</a>";
-		} else {
-			echo htmlentities($row['subject']);
-		}
-		if ($pathlist[3]=="entry") {
-		// If we're displaying a single entry, hack the pathlist into shape
-			$pathlist[3]=$row['subject'];
-			unset($pathlist[4]);
-		}
-		echo "</h2></div>\n";
-		
-		echo "<div class=\"boxcontent\">\n";
-		echo $row['body'] . "\n";
-		echo "</div>\n";
-		echo "<div class=\"boxfoot\"><p>[ Entry posted at: ".strftime($this->longDateFormat,strtotime($row['timestamp']));
-		if ($commentLink) {
-			echo " | <a href=\"".$this->blogPath."entry/{$row['shortsubject']}\">Comments</a>: ".$this->commentCount($row['id']);
-		} else {
-			echo " | ".$this->commentCount($row['id'])." comment(s)...";
-		}
-		echo " | Cat: <a href=\"".$this->blogPath."category/{$row['category']}\">".$this->categoryName($row['category'])."</a> ";
-		if($this->checkSessionOwner()){
-			echo "| <a href=\"".$this->adminPath."update/{$row['shortsubject']}\">"._("Edit")."</a> ";
-			//delete link, disabled for now
-			//echo "| <a href=\"".$this->adminPath."deleteentry/{$row['shortsubject']}\">"._("Delete")."</a>";
-		}
-		echo " ]</p></div>\n";
-		echo "</div>\n";
-		
-	}
-
-	// print lots of blog entries
-	function printEntries($offset=0, $limit=15, $constraint='') {
-		global $BlogDB;
-		//get the entries from the database
-		$sql = $BlogDB->GetAll("SELECT id, category, subject, body, timestamp, shortsubject from entries where user_id = '".$this->id."' ".$constraint." order by timestamp desc limit ".$limit." offset ".$offset.";");
-		//return an error if we cant find any
-		if (count($sql) < 1) {
-			error(5,"No relevant posts");
-		} else {
-			//print each entry
-			while ($sqlRow = array_shift($sql)) {
-				$this->printEntry($sqlRow);
-			}
-			//archive link
-			echo "<div class=\"archivelink\"><a href=\"{$this->blogPath}Archive/\">"._("archived posts...")."</a></div>";
-		}
-	}
-
-	// print old entries sorted by either date (default), subject or category
-	function printArchive($request) {
-		switch(trim($request[0])) {
-			case 'category' : 
-				array_shift($request);
-				$this->printArchiveByCategory($request);
-				break;
-			case 'subject' : 
-				array_shift($request);
-				$this->printArchiveBySubject($request);
-				break;
-			case 'date' :
-				array_shift($request);
-				$this->printArchiveByDate($request);
-				break;
-			default :
-				$this->printArchiveByDate($request);
-		}
-	}
-
-	// print a list of entries by date
-	function printArchiveByDate($request) 
-	{
-		global $BlogDB;
-		$request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s
-		//get the refinements if set
-		$year = (isset($request[0]) && is_numeric($request[0])) ? $request[0] : "";
-		$month = (isset($request[1]) && is_numeric($request[1])) ? $request[1] : "";
-		$day = (isset($request[2]) && is_numeric($request[2]) ) ? $request[2] : "";
-		// Get the last request option (sort order) after the date
-		$lastIndex = count($request) - 1; 
-		$order = strtoupper($request[$lastIndex]);
-		//this ensures order is sane
-		switch($order) {
-			case 'ASC' :
-				$strOppositeOrder = 'Descending';
-				$oppositeOrder = 'DESC';
-				$strOrder = 'Ascending';
-				break;
-			case 'DESC' :
-			default :
-				$strOppositeOrder = 'Ascending';
-				$oppositeOrder = 'ASC';
-				$strOrder = 'Descending';
-				$order = 'DESC';
-		}
- 
-		if($month=="" && $day=="") {
-			$enddate = $year+1;
-		} elseif($month != "" && $day=="") {
-			$enddate = $year.(sprintf("%02d", $month+1));
-		} else {
-			$enddate = $year.$month.(sprintf("%02d", $day+1));
-		}
-
-		$sql = "SELECT shortsubject,subject,timestamp FROM entries WHERE ".((!$year)? "" : "timestamp >= $year$month$day AND timestamp < $enddate AND ") . 
-			"user_id = '".$this->id."' ORDER BY timestamp " . $order;
-		$result = $BlogDB->GetAll($sql);
-
-		$requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':'';
-	 
-		$curyear = "";
-		$curmonth = "";
-		$curday = "";
-		echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/date/\">Date</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . 
-			"Archive/date/" . $requestPath  . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . 
-			"</a> || Sort By <a href=\"" . $this->blogPath . "Archive/category\">Category</a> | <a href=\"" .
-			$this->blogPath . "Archive/subject\"> Subject </a><br />";
-		if ( count($result) >= 1 ) {
-			while($row = array_shift($result)){
-				if($curyear!=date("Y", strtotime($row['timestamp']))) {
-					$curyear = date("Y", strtotime($row['timestamp']));
-					echo "<h1><a href=\"".$this->blogPath."Archive/$curyear\">$curyear</a></h1>";
-				}
-				if($curmonth!=date("F", strtotime($row['timestamp']))) {
-					$curmonth = date("F", strtotime($row['timestamp']));
-					echo "<h2><a href=\"".$this->blogPath."Archive/".date("Y/m", strtotime($row['timestamp']))."\">$curmonth</a></h2>\n";
-				}
-				if($curday!=date("l jS", strtotime($row['timestamp']))) {
-					$curday = date("l jS", strtotime($row['timestamp']));
-					echo "<h3><a href=\"".$this->blogPath."Archive/".date("Y/m/d", strtotime($row['timestamp']))."\">$curday</a></h3>\n";
-				}
-				echo date("g:ia", strtotime($row['timestamp']))." - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n";
-			}
-		} else {
-			error(5,"No Entries Available" . ($allentries ? '' : " for $year" . ($month != '' ? "/$month":'') . ($day != '' ? "/$day":'')));
-		}
-		echo "</div>";
-	}
-
-	//print a list of entries by category
-    function printArchiveByCategory($request) 
-    {
-    		global $BlogDB;
-		// Check for a category id
-		// There must be a better way to check that it isn't $order
- 		$request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s
-		if (isset($request[0]) && (strtoupper($request[0]) != 'ASC') && (strtoupper($request[0]) != 'DESC')) {
-			$category = $this->makeCleanString($request[0]);
-			if (strlen($category) < 3)
-                		$allentries = true;
-		} else {
-			$allentries = true;
-		}
-	 
-		$lastIndex = count($request) - 1; // Get the last request option after the date
-		$order = 'ASC';
-		if (isset($request[$lastIndex]) && (($lastIndex > 0) || isset($allentries)) &&
-			(strlen($request[$lastIndex]) > 2)) {
-			$order = strtoupper($request[$lastIndex]);
-			array_pop($request);
-		}
-		switch($order) {
-			case 'DESC' :
-				$strOppositeOrder = 'Ascending';
-				$oppositeOrder = 'ASC';
-				$strOrder = 'Descending';
-				break;
-			case 'ASC' :
-			default :
-				$strOppositeOrder = 'Descending';
-				$oppositeOrder = 'DESC';
-				$strOrder = 'Ascending';
-				$order = 'ASC';
-		}
-
-		$sql = "SELECT shortsubject,subject,timestamp, name FROM entries AS e,categories AS c WHERE " . 
-			($allentries ? "" : " lower(c.name) = '" . $category . "' AND ") .
-			"e.user_id = '".$this->id."' AND e.category = c.id ORDER BY " . ($allentries? "name " . $order . " ,timestamp ASC" : "timestamp " . $order );
-		$result = $BlogDB->GetAll($sql);
-
-		$requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':'';
-		$dbCategory = '';
-		echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/category/\">Category</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . 
-			"Archive/category/" . $requestPath  . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . 
-			"</a> || Sort By <a href=\"" . $this->blogPath . "Archive/date\">Date</a> | <a href=\"" .
-			$this->blogPath . "Archive/subject\"> Subject </a><br />";
-		
-		if ( count($result) >= 1 ) {
-			while($row = array_shift($result)){
-				if($dbCategory != $row['name']) {
-					$dbCategory = $row['name'];
-					echo "<h1><a href=\"".$this->blogPath."Archive/category/$dbCategory\">$dbCategory</a></h1>";
-				}
-				echo date("d/m/Y", strtotime($row['timestamp'])) . " - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n";
-			}
-			echo "</div>";
-		} else {
-			error(5,"No Entries Available" . (isset($category) ? " in $category":''));
-		}
-	}
-
-	//print a list of entries by title
-	function printArchiveBySubject ($request) 
-	{
-		global $BlogDB;
-		// Look for a single character to show subjects by 
-		$request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s
-		if (isset($request[0]) && (preg_match('/^[a-z]$/i', $request[0]))) {
-			$letter = strtolower($request[0]);
-		} else {
-			$allentries = true;
-		}
-	
-		// Get whether it is Ascending or Descending
-		$lastIndex = count($request) - 1; // Get the last request option after the date
-		$order = 'ASC';
-		if (isset($request[$lastIndex]) && !is_numeric($request[$lastIndex])) {
-			$order = strtoupper($request[$lastIndex]);
-			array_pop($request);
-		}
-		switch($order) {
-			case 'DESC' :
-				$strOppositeOrder = 'Ascending';
-				$oppositeOrder = 'ASC';
-				$strOrder = 'Descending';
-				break;
-			case 'ASC' :
-				default :
-				$strOppositeOrder = 'Descending';
-				$oppositeOrder = 'DESC';
-				$strOrder = 'Ascending';
-				$order = 'ASC';
-		}
-
-		$requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':'';
-	 
-		// lower() exists in PG and MySQL, but given that db abstraction is wanted, is it part of the SQL standard?
-		// Should a better method be used?
-		$sql = "SELECT shortsubject,subject,timestamp FROM entries WHERE ".(($allentries)? "" : "lower(subject) LIKE '" . $letter . "%' AND ") . 
-			"user_id = '".$this->id."' ORDER BY subject " . $order;
-		$result = $BlogDB->GetAll($sql);
-
-		echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/subject/\">Subject</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . 
-			"Archive/subject/" . $requestPath  . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . 
-			"</a> || Sort By <a href=\"" . $this->blogPath . "Archive/date\">Date</a> | <a href=\"" .
-			$this->blogPath . "Archive/category\"> Category </a><br /><a href=\"" . $this->blogPath . 
-			"Archive/subject/a/$order\">a</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/b/$order\">b</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/c/$order\">c</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/d/$order\">d</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/e/$order\">e</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/f/$order\">f</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/g/$order\">g</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/h/$order\">h</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/i/$order\">i</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/j/$order\">j</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/k/$order\">k</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/l/$order\">l</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/m/$order\">m</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/n/$order\">n</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/o/$order\">o</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/p/$order\">p</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/q/$order\">q</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/r/$order\">r</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/s/$order\">s</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/t/$order\">t</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/u/$order\">u</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/v/$order\">v</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/w/$order\">w</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/x/$order\">x</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/y/$order\">y</a> | <a href=\"" . $this->blogPath . 
-			"Archive/subject/z/$order\">z</a><br />";
-		if ( count($result) >= 1 ) {
-			while($row = array_shift($result)){
-				echo date("d/m/Y", strtotime($row['timestamp'])) . " - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n";
-			}
-		} else {
-			error(5, "No Entries Available" . ($allentries ? '' : " beginning with '$letter'"));
-		}
-		echo "</div>";
-	}
-
-	//print Prev/Next nav bar
-	function printNavigationBar($id) {
-		global $BlogDB;
-		$sql = $BlogDB->GetRow("SELECT timestamp from entries WHERE id='".$id."'");
-		$prev = $BlogDB->GetAll("SELECT id, shortsubject, subject FROM entries WHERE timestamp < '".$sql['timestamp']."' AND user_id = '".$this->id."' ORDER BY timestamp DESC LIMIT 1");
-		$next = $BlogDB->GetAll("SELECT id, shortsubject, subject FROM entries WHERE timestamp > '".$sql['timestamp']."' AND user_id = '".$this->id."' ORDER BY timestamp ASC LIMIT 1;");
-		if (count($prev)>0) $prevRow=array_shift($prev);
-		if (count($next)>0) $nextRow=array_shift($next);
-
-		echo "<div class=\"navbar\"><div><div><div>\n";
-		echo "<ul class=\"blognav\">";
-		if ($prevRow['shortsubject']!="") echo "<li class=\"prev\"><a href=\"{$this->blogPath}entry/{$prevRow['shortsubject']}\">< ".htmlentities($prevRow['subject'])."</a></li>";
-		if ($nextRow['shortsubject']!="") echo "<li class=\"next\"><a href=\"{$this->blogPath}entry/{$nextRow['shortsubject']}\">".htmlentities($nextRow['subject'])." ></a></li>";
-		echo "</ul>\n";
-		echo "<br style=\"clear: both:\" /></div></div></div></div>\n";
-	}
-
-	//print one entry and its comments
-	function printEntryAndComments($shortsubject) 
-	{
-		global $BlogDB;
-		$shortsubject = $this->makeCleanString($shortsubject);
-		$sql = $BlogDB->GetRow("SELECT id, category, subject, body, timestamp, shortsubject from entries where shortsubject='".$shortsubject."' and user_id = ".$this->id." LIMIT 1;");
-		if (!$sql) {
-			error(5,"No relevant posts");
-		}
-		else	{
-			$this->currentEntry = $sql['shortsubject'];
-			$this->printNavigationBar($sql['id']);
-			$this->printEntry($sql, false, false);
-			$this->printComments($sql['id']);
-			$this->printCommentForm($sql['id']);
-		}
-	}
-
-	//print lots of comments
-	function printComments($postid, $offset=0, $limit=15) 
-	{
-		global $BlogDB;
-		$sql = $BlogDB->GetAll("SELECT timestamp, name, email, body, host, id FROM comments WHERE post = ".$postid." and moderated = true ORDER BY timestamp ASC limit ".$limit." OFFSET ".$offset.";");
-		echo "<div id=\"comments\">\n";
-		if (count($sql) > 0) {
-			$blogOwner = $this->checkSessionOwner();
-			if($blogOwner) {
-				echo "<form name=\"deletecomments\" id=\"deletecomments\" method=\"post\" action=\"{$this->adminPath}deletecomments/{$this->currentEntry}\">\n";
-			}
-			
-			$count=0;
-			while ($sqlRow = array_shift($sql)) {
-				$this->printComment($sqlRow, $blogOwner, $count++);
-			}
-
-
-			if($blogOwner) {
-				echo "<div style=\"width: 100%; text-align: right\">\n";
-				echo "<input type=\"submit\" name=\"submit\" value=\"Delete Comments\" />\n";
-				echo "</div>\n";
-				echo "</form>\n";
-			}
-		}
-		echo "</div>\n";
-	}
-
-	//print a comment
-	function printComment($row, $printCheckBox=FALSE, $checkBoxNum=0) 
-	{
-		echo "<div class=\"box\">\n";
-		echo "<div class=\"boxhead\"><h3>" . htmlentities($row['name']) . " writes:</h3></div>";
-		echo "<div class=\"boxcontent\"><p>" . nl2br(htmlentities(br2nl($row['body']))) . "</p></div>\n";
-		echo "<div class=\"boxfoot\"><p>[ " .strftime($this->longDateFormat,strtotime($row['timestamp']));
-		if($printCheckBox){
-			echo " | <input class=\"smallcheckbox\" type=\"checkbox\" id=\"comment{$checkBoxNum}\" name=\"comment[{$checkBoxNum}]\" value=\"{$row['id']}\" />\n";
-			echo "<label for=\"comment{$checkBoxNum}\">Delete</label>\n";
-		}
-		echo " ]</p></div>\n";
-		echo "</div>\n";
-	}
-	
-	//counts the number of comments 
-	function commentCount($entry) {
-		global $BlogDB;
-		$sql = $BlogDB->GetCol("SELECT count(id) from comments where post = ".$entry." and moderated = true;");		
-		return $sql[0];
-	}
-	
-	//returns a category name
-	function categoryName($category) {
-		global $BlogDB;
-		$sql = $BlogDB->GetCol("SELECT name from categories where id = ".$category.";");		
-		return $sql[0];
-	}
-	
-	//prints a form so people can comment
-	function printCommentForm($id) 
-	{
-		echo "<div class=\"entry\">\n";
-		echo "<h2>Add Comment<a id=\"cmt\"></a></h2>\n";
-		echo "<div class=\"td\">\n";
-		if ($this->commentError != "") {
-			echo "<p class=\"invalid\">*** " . $this->commentError . " ***</p>\n";
-		}
-		elseif (isset($_POST['submit'])) {
-			echo "<p>Thank you for your comment</p>\n";
-		}
-
-		// try to work out the viewer's name + email
-		//seems a bit silly to check for the existance of the session stuff in two places, its probably fair to assume if one is set, the other will be too
-		//these need the same validation checks as when we put things into the db, else people can inject what ever html they like into our pages
-		if(isset($_SESSION['realName'])) {
-			$name = $_SESSION['realName'];
-		} elseif(isset($_COOKIE['Blog_CommentRealName'])) {
-			$name = $_COOKIE['Blog_CommentRealName'];
-		} else {
-			$name = "";
-		}
-		if(isset($_SESSION['userName'])) {
-			$email = $_SESSION['userName']."@sucs.org";
-		} elseif(isset($_COOKIE['Blog_CommentEmailAddress'])) {
-			$email = $_COOKIE['Blog_CommentEmailAddress'];
-		} else {
-			$email = "";
-		}
-		echo "<form onsubmit=\"return postcomment('".$this->httpPath."', '".$this->userName."', '".$id."')\" action=\"".$this->blogPath."postcomment/".$id."\" method=\"post\" id=\"commentform\">\n";
-		echo "<div class=\"row\">\n";
-		echo "<label for=\"author\">Name (required)</label>\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"author\" id=\"author\" value=\"$name\" size=\"40\" maxlength=\"50\" tabindex=\"1\" /></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<span class=\"textinput\"><input type=\"text\" name=\"email\" id=\"email\" value=\"$email\" size=\"40\" maxlength=\"70\" tabindex=\"2\" /></span>\n";
-		echo "<label for=\"email\">E-mail (required, not displayed)</label>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<span class=\"textinput\"><textarea name=\"comment\" id=\"comment\" cols=\"50\" rows=\"10\" tabindex=\"3\">" . (($this->commentError != "") ? strip_tags($_POST['comment']) : "") . "</textarea></span>\n";
-		echo "</div>\n";
-		echo "<div class=\"row\">\n";
-		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\"Submit Comment\" /></span>";
-		echo "<img src=\"".$this->httpPath."img/spinner.gif\" alt=\"\" id=\"spinner\"/>\n";
-		echo "<label class=\"invalid\" for=\"submit\" id=\"errors\"></label>\n";
-		echo "</div>\n<div class=\"clear\"></div>";
-		echo "</form>\n";
-		echo "</div>\n";
-		echo "</div>\n";
-	}
-
-	//takes a string and strips it, making it safe to put in a URL
-	function makeCleanString($string,$externalSource=false)
-	{
-		//externalSource meaning directly inputed by a user, in most cases this should be false.. appart from starting a new post
-		$string = strtolower($string);
-		$string = preg_replace("/[^a-z0-9\- _]/i", "", $string);
-		$string = str_replace(" ", "-",trim($string));
-		if ($externalSource) {
-			$string = str_replace("_", "-",$string);
-		}
-		$string = urlencode($string);
-		return $string;
-	}
-	
-	//handles posting of comments
-	function newComment($id, $printentry=TRUE) 
-	{
-		global $BlogDB;
-		$author = "";
-		$email = "";
-		$comment = "";
-		//check the post exists, and is part of this blog
-		$row = $BlogDB->GetRow("SELECT subject, id from entries where user_id = ".$this->id." and id = '".$id."';");
-		if (!$row) {
-			error(1,_("Invalid blog entry, This entry may have been removed..?"));
-			return;
-		}
-		//pull in the unadulterated subject for later on
-		$subject = $row['subject'];
-		$postid =  $row['id'];
-		//set hostname
-		if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
-			$host = addslashes($_SERVER['HTTP_X_FORWARDED_FOR']) . " : " . addslashes($_SERVER['REMOTE_ADDR']);
-		}
-		else {
-			$host = addslashes($_SERVER['REMOTE_ADDR']);
-		}
-		//sanitise comment
-		if (isset($_POST['comment']) && trim($_POST['comment']) != "") {
-			if(strip_tags($_POST['comment']) == $_POST['comment']) {
-				$comment = addslashes(nl2br(trim($_POST['comment'])));
-			} else {
-				$this->commentError = _("HTML within comments is not allowed, Please remove all html tags and try again");
-				$element = "comment";
-			}
-		} else {
-			$this->commentError = _("Please check the comment field");
-			$element = "comment";
-		}
-		//decided if the comment is likly to be spam
-		if (checkSpam($host,$_POST['comment'])) {
-			$spam = true;
-			//force this comment though moderation
-			$this->comment_moderation = true;
-		} else {
-			$spam = false;
-		}
-		//sanitise email
-		if (isset($_POST['email']) && trim($_POST['email']) != "" && validEmail(trim($_POST['email']))) {
-			$email = addslashes(trim($_POST['email']));
-		} else {
-			$this->commentError = _("Check email address, it does not apear to be valid.");
-			$element = "email";
-		}
-		//sanitse author
-		if (isset($_POST['author']) && trim($_POST['author']) != "") {
-			if(preg_match("/^([a-z0-9]+ *)+$/i", $_POST['author'])) {
-				$author = addslashes(nl2br(trim(strip_tags($_POST['author']))));
-			} else {
-				$this->commentError = _("Invalid name. We only allow alphanumeric names!");
-				$element = "author";
-			}
-		} 
-		else {
-			$this->commentError = _("Please give us your name.");
-			$element = "author";
-		}
-		//if no errors have been raised so far commit to the db
-		if ($this->commentError == "") {
-			// do we need to set the moderated flag on this comment?
-			if(!$this->comment_moderation) {
-				$moderated = TRUE;
-			} else {
-				//check the list of 'authorised' commentors
-				if(count($BlogDB->GetAll("SELECT name FROM authorised_emails WHERE user_id={$this->id} AND email='{$email}'"))>0) {
-					$moderated = TRUE;
-				} else {
-					$moderated = FALSE;
-				}
-			}
-			//actualy insert the new comment and check it worked
-			$query = "INSERT INTO comments (post, name, email, body, host, moderated, spam) VALUES ('{$postid}','{$author}','{$email}','{$comment}','{$host}', ".(($moderated) ? "true" : "false").", ".(($spam) ? "true" : "false").")";
-			if(!$BlogDB->Execute($query)) {
-				error(2,_("Database commit failed -").$BlogDB->ErrorMsg());
-			}
-			//send out an notificaiton email if we have succeeded unless we think its spam or moderation has been bypassed
-			else {
-				if(!$spam or !$moderated) 
-					mail($this->userName . "@sucs.org", "Blog comment on \"".$subject."\"", "You've received a comment from ".$author." on your blog post \"".$subject.". The comment is:\n==========\n".$comment.(($moderated) ? "" : "\n==========\nPlease login to your blog admin page to approve or delete this comment."), "From: Your Blog <noreply at sucs.org>");
-				//inform the commentor if the message has been tagged for modderation
-				if(!$moderated) {
-					echo "<p class=\"updateinfo\">"._("Your comment has been added, but before it appears here it must be accepted by the blog owner.")."</p>";
-				} 
-				//or pass out the comment useing the standard form
-				elseif(!$printentry) {
-					$time = strftime($this->longDateFormat, time());
-					$this->printComment(array('name'=>$author, 'body'=>$comment, 'timestamp'=>$time));
-				}
-				//reprint the entire entry (for the case where we're not useing the ajax goodness)
-				if($printentry) {
-					$this->printEntryAndComments($shortSubject);
-				}
-				//if we dont have a valid session store the name & email in there own cookies
-				if(!isset($_SESSION['realName'])) {
-					setcookie("Blog_CommentRealName", $author, time()+604800);
-					setcookie("Blog_CommentEmailAddress", $email, time()+604800);
-				}
-				ob_end_flush();
-				return array(TRUE);
-			}
-		//else return our error and the status gumf for the benifit of the ajax goodness
-		} else {
-			echo $this->commentError;
-			return array(FALSE, $element);
-		}
-	}
-	
-	//reutrns the id of the message assosiated with a short subject
-	function shortSubjectToID($shortsubject)
-	{
-		global $BlogDB;
-		$sql = $BlogDB->GetRow("SELECT id from entries where user_id = ".$this->id." and shortsubject = '".$shortsubject."';");
-		if ($sql) {
-			return $sql['id'];
-		}
-		else {
-			error(3,"No such post");
-		}
-	}
-	
-	//reutrns the short subject of the message given message 
-	function IDToShortSubject($id)
-	{
-		global $BlogDB;
-		$sql = $BlogDB->GetRow("SELECT shortsubject from entries where user_id = ".$this->id." and id = '".$id."';");
-		if ($sql) {
-			return $sql['shortsubject'];
-		}
-		else {
-			error(3,"No such post");
-		}
-	}
-
-	// Blog menu
-	function menu()
-	{
-		global $smarty, $session;
-
-		$submenu = array();
-
-		if ($session->loggedin && blogger($session->username)) $submenu[_("My Blog")] = "{$this->httpPath}{$session->username}";
-
-		if ($session->username != $this->userName) $userblog = $this->userName._("'s Blog");
-		$submenu[$userblog] = $this->blogPath;
-
-		if ($session->username == $this->userName) $archiveblog = _("My Archive");
-		else $archiveblog = $this->userName._("'s Archive");
-		$submenu[$archiveblog] = "{$this->blogPath}Archive/";
-		
-		if ($this->checkSessionOwner() && blogger($session->username)){
-			$submenu[_("Blog admin")] = "{$this->adminPath}";
-		}
-
-		$menu = $smarty->get_template_vars("menu");
-		$menu[Blogs] = $submenu;
-		$smarty->assign("menu", $menu);
-	}
-
-	// Check the session to see if the user is browsing her own blog
-	function checkSessionOwner()
-	{
-		global $session;
-		$maxSessionAge = 3600;
-		
-		// if the session's expired then nuke it
-		if ($session->username != $this->userName) {
-			return FALSE;
-		} else {
-			// the time's not up and the usernames match so it's probably the right user.
-			return TRUE;
-		}
-	}
-}
-
-// a pseudo-class to list all blog users
-class bloglist {
-	var $title;
-	var $description;
-	var $httpPath;
-	var $listPath;
-	var $adminPath;
-	var $cssFile;
-	var $svnRevision;       // the SVN revision number of the currently running blog
-
-	// don't do anything apart from setting up default variables
-	function bloglist() 
-	{
-		$this->title = _("Blogs");
-		$this->description = _("Swansea University Computer Society member web logs");
-		$this->httpPath = "/Blogs/";
-		//if(substr($this->httpPath, -1)!="/") {
-		//	$this->httpPath .= "/";
-		//}
-		$this->basePath = "/Blogs/";
-		$this->adminPath = $this->httpPath."Admin/";
-		$this->cssFile = "blog.css";
-		$this->svnRevision = getSVNRevision();
-
-		// setup the session purely so we get the debug bits..
-		session_name("BlogSession");
-		session_start();
-	}
-
-	// print a nice list of blog users and when they last updated
-	function listBlogs()
-	{
-		global $BlogDB, $session;
-		$sql = $BlogDB->GetAll("SELECT max(entries.timestamp) AS ts, users.username, users.description, users.name, users.title FROM entries LEFT JOIN users ON entries.user_id = users.id GROUP BY users.username, users.name, users.title, users.description ORDER BY ts DESC;");
-		if (count($sql) > 0) {
-			echo "<div class=\"td\">\n";
-			echo "<p>"._("Welcome to SUCS Blogs - The multi-user web log system created by SUCS members for SUCS members.")."</p>\n";
-			echo "<p>"._("Browse the blogs below or use the links on the left to navigate the site. Happy blogging!")."</p>\n";
-			if ($session->loggedin && !blogger($session->username)) echo "<p>"._("Want to join the ranks of SUCS bloggers? - ")."<a href=\"{$this->adminPath}signup\">"._("Start a Blog!")."</a></p>\n";
-			echo "</div>\n";
-			echo "<div id=\"listofblogs\">\n";
-			echo "<table class=\"border\">\n";
-			echo "<tr><th class=\"bname\">"._("Name")."</th><th class=\"btitle\">"._("Blog")."</th><th class=\"bupdated\">"._("Last Updated")."</th></tr>";
-			while($row = array_shift($sql)) {
-				echo "<tr>\n";
-				echo "    <td>".$row['name']."</td>\n";
-				echo "    <td><a href=\"".$this->basePath.$row['username']."\" title=\"".$row['description']."\">".$row['title']."</a></td>\n";
-				echo "    <td>".$this->timeDiff(strtotime($row['ts']))." ago</td>\n";
-				echo "</tr>\n";
-			}
-			
-			echo "</table>\n";
-			echo "</div>\n";
-		}
-		else {
-			error(3,_("No blogs"));
-		}
-	}
-    
-	//Returns a textual diff between two time stamps
-	function timeDiff($first, $second=0)
-	{
-		if($second == 0) {
-			$second = time();
-		}
-
-		$diff = max($first, $second) - min($first, $second);
-
-		if($diff>604800) {
-			$ret = round($diff/604800);
-			return $ret.(($ret>1)? _(" weeks") : _(" week"));
-		} 
-		elseif($diff>86400) {
-			$ret = round($diff/86400);
-			return $ret.(($ret>1)? _(" days") : _(" day"));
-		} 
-		elseif($diff>3600) {
-			$ret = round($diff/3600);
-			return $ret.(($ret>1)? _(" hours") : _(" hour"));
-		} 
-		elseif($diff>60) {
-			$ret = round($diff/60);
-			return $ret.(($ret>1)? _(" minutes") : _(" minute"));
-		}
-		else {
-			return $diff.(($diff>1)? _(" seconds") : _(" second"));
-		}
-	}
-
-	// Blog menu - links displayed when the blog list is displayed
-	function menu() {
-		global $smarty, $session;
-
-		if ($session->loggedin) {
-		$submenu = array();
-			if (blogger($session->username)) {
-				$submenu[_("My Blog")] = "{$this->httpPath}{$session->username}";
-				$submenu[_("Blog admin")] = "{$this->adminPath}";
-			} else {
-				$submenu[_("Start a Blog")] = "{$this->adminPath}signup";		
-			}
-		$menu = $smarty->get_template_vars("menu");
-		$menu[Blogs] = $submenu;
-		$smarty->assign("menu", $menu);
-		}
-	}
-}

Copied: branches/sucs-site/lib/blog/blog.lib.php (from rev 635, branches/sucs-site/lib/blog/blog.lib.php)
===================================================================
--- branches/sucs-site/lib/blog/blog.lib.php	                        (rev 0)
+++ branches/sucs-site/lib/blog/blog.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,885 @@
+<?php
+/* vim: set tabstop=4: */
+/*
+ * blogs class - provides functions for blogs
+ */
+
+// PHP Notices are fun, but we don't really want to see them right now
+error_reporting(E_ALL ^ E_NOTICE);
+
+// Initialise the database
+require_once("/usr/share/php/adodb/adodb.inc.php");
+$BlogDB = NewADOConnection('postgres8');
+$BlogDB->Connect('dbname=blogs user=apache');
+$BlogDB->SetFetchMode(ADODB_FETCH_ASSOC);
+
+// Some useful validation functions
+require_once("validation.lib.php");
+
+// Some useful miscellaneous functions
+require_once("miscfunctions.lib.php");
+
+/* a stub of an error handler
+
+scale of 1-5, 5 being warnings, 1 being fatal errors?
+1 : fatal
+2 : dberror
+3
+4 : bad input
+5 : not found/doesnt exist etc
+*/
+function error($level, $error) {
+	echo("<p class=\"errorinfo\">"._("Level ").$level._(" error - ").$error."</p>");
+}
+//A bit of a nicer error handler, to allow errors encounterd in the construction phase to be displayed in the 'correct' place
+function error_exc($e) {
+	if (!isset($e->error) || !isset($e->errormsg)) {
+		echo("<p class=\"errorinfo\">"._("Level 0 error - no error message available")."</p>");
+	} else {
+		echo("<p class=\"errorinfo\">"._("Level ").$e->error._(" error - ").$e->errormsg."</p>");
+	}
+}
+
+//Our Blogs Class
+class blogs {
+	//Blog ID
+	var $id;
+	//Blogger's Details
+	var $userName;
+	var $realName;
+	//Blog Details
+	var $title;
+	var $description;
+	var $cssFile;
+	//Date formats
+	var $shortDateFormat;
+	var $longDateFormat;
+	//Paths
+	var $httpPath;
+	var $blogPath;
+	var $basePath;
+	var $adminPath;
+	//bools
+	var $comment_moderation;
+	var $editor; //surely this should be in admin.lib? it doesnt seem to be used in blog.lib
+	var $currentEntry;
+	//Errors
+	var $error;
+	var $errormsg;
+	//SVN Revision... the closest thing we've got to a version number
+	var $svnRevision;
+	
+	//Constructor - checks we've been given a valid username, and pulls in generic blog info
+	function blogs($user) {
+		global $BlogDB;
+		//set the error string first, so we dont wipe out any errors
+		$this->error = null;
+		$this->errormsg = null;
+		//set the locale
+		setlocale(LC_ALL, 'en_GB');
+		//check the username
+		if(!safeuname($user)) {
+			$this->error = 1;
+			$this->errormsg = "No such user";
+			return;
+		} else {
+			//check to see if the user has a blog
+			$sql = $BlogDB->GetRow("SELECT id, name, title, description, css, moderate, editor from users where username = ? and enabled = true;", array($user));
+			if (!$sql) {
+				$this->error = 1;
+				$this->errormsg = "No such user";
+				return;
+			} else {
+				//pull in the blog details
+				$this->id = $sql['id'];
+				$this->userName = $user;
+				$this->realName = $sql['name'];
+				$this->title = $sql['title'];
+				$this->description = $sql['description'];
+				$this->cssFile = $sql['css'];
+				$this->shortDateFormat = "%x %X";
+				$this->longDateFormat = "%c";
+				//set path for all http stuff.. ie images, css and so on
+				$this->httpPath = "/Blogs/";
+				//make the httpPath work nicely if we're not in a subdir
+				//if(substr($this->httpPath, -1)!="/") {
+				//	$this->httpPath .= "/";
+				//}
+				//path for the blog viewer with no user
+				$this->basePath = "/Blogs/";
+				//path to this blog
+				$this->blogPath = $this->basePath.$this->userName."/";
+				//path to the admin bits
+				$this->adminPath = $this->httpPath."Admin/";
+				$this->comment_moderation = ($sql['moderate']=='t') ? TRUE : FALSE;
+				$this->editor = ($sql['editor']=='t') ? TRUE : FALSE;
+				$this->currentEntry = "";
+				$this->svnRevision = getSVNRevision();
+				//setup the session
+				session_name("BlogSession");
+				session_start();
+			}
+		}
+	}
+
+	// print a blog entry, when provided with a database $row containing one.
+	function printEntry($row, $commentLink = true, $titleLink = true) {
+		global $pathlist;
+		echo "<div class=\"box\">\n";
+
+		echo "<div class=\"boxhead\"><h2>";
+		if ($titleLink) {
+			echo "<a href=\"{$this->blogPath}entry/". htmlentities($row['shortsubject']) ."\">". htmlentities($row['subject']) ."</a>";
+		} else {
+			echo htmlentities($row['subject']);
+		}
+		if ($pathlist[3]=="entry") {
+		// If we're displaying a single entry, hack the pathlist into shape
+			$pathlist[3]=$row['subject'];
+			unset($pathlist[4]);
+		}
+		echo "</h2></div>\n";
+		
+		echo "<div class=\"boxcontent\">\n";
+		echo $row['body'] . "\n";
+		echo "</div>\n";
+		echo "<div class=\"boxfoot\"><p>[ Entry posted at: ".strftime($this->longDateFormat,strtotime($row['timestamp']));
+		if ($commentLink) {
+			echo " | <a href=\"".$this->blogPath."entry/{$row['shortsubject']}\">Comments</a>: ".$this->commentCount($row['id']);
+		} else {
+			echo " | ".$this->commentCount($row['id'])." comment(s)...";
+		}
+		echo " | Cat: <a href=\"".$this->blogPath."category/{$row['category']}\">".$this->categoryName($row['category'])."</a> ";
+		if($this->checkSessionOwner()){
+			echo "| <a href=\"".$this->adminPath."update/{$row['shortsubject']}\">"._("Edit")."</a> ";
+			//delete link, disabled for now
+			//echo "| <a href=\"".$this->adminPath."deleteentry/{$row['shortsubject']}\">"._("Delete")."</a>";
+		}
+		echo " ]</p></div>\n";
+		echo "</div>\n";
+		
+	}
+
+	// print lots of blog entries
+	function printEntries($offset=0, $limit=15, $constraint='') {
+		global $BlogDB;
+		//get the entries from the database
+		$sql = $BlogDB->GetAll("SELECT id, category, subject, body, timestamp, shortsubject from entries where user_id = '".$this->id."' ".$constraint." order by timestamp desc limit ".$limit." offset ".$offset.";");
+		//return an error if we cant find any
+		if (count($sql) < 1) {
+			error(5,"No relevant posts");
+		} else {
+			//print each entry
+			while ($sqlRow = array_shift($sql)) {
+				$this->printEntry($sqlRow);
+			}
+			//archive link
+			echo "<div class=\"archivelink\"><a href=\"{$this->blogPath}Archive/\">"._("archived posts...")."</a></div>";
+		}
+	}
+
+	// print old entries sorted by either date (default), subject or category
+	function printArchive($request) {
+		switch(trim($request[0])) {
+			case 'category' : 
+				array_shift($request);
+				$this->printArchiveByCategory($request);
+				break;
+			case 'subject' : 
+				array_shift($request);
+				$this->printArchiveBySubject($request);
+				break;
+			case 'date' :
+				array_shift($request);
+				$this->printArchiveByDate($request);
+				break;
+			default :
+				$this->printArchiveByDate($request);
+		}
+	}
+
+	// print a list of entries by date
+	function printArchiveByDate($request) 
+	{
+		global $BlogDB;
+		$request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s
+		//get the refinements if set
+		$year = (isset($request[0]) && is_numeric($request[0])) ? $request[0] : "";
+		$month = (isset($request[1]) && is_numeric($request[1])) ? $request[1] : "";
+		$day = (isset($request[2]) && is_numeric($request[2]) ) ? $request[2] : "";
+		// Get the last request option (sort order) after the date
+		$lastIndex = count($request) - 1; 
+		$order = strtoupper($request[$lastIndex]);
+		//this ensures order is sane
+		switch($order) {
+			case 'ASC' :
+				$strOppositeOrder = 'Descending';
+				$oppositeOrder = 'DESC';
+				$strOrder = 'Ascending';
+				break;
+			case 'DESC' :
+			default :
+				$strOppositeOrder = 'Ascending';
+				$oppositeOrder = 'ASC';
+				$strOrder = 'Descending';
+				$order = 'DESC';
+		}
+ 
+		if($month=="" && $day=="") {
+			$enddate = $year+1;
+		} elseif($month != "" && $day=="") {
+			$enddate = $year.(sprintf("%02d", $month+1));
+		} else {
+			$enddate = $year.$month.(sprintf("%02d", $day+1));
+		}
+
+		$sql = "SELECT shortsubject,subject,timestamp FROM entries WHERE ";
+		$params = array();
+		if ($year) {
+				$sql .= "timestamp >= ? AND timestamp < ? AND ";
+				$params[] = "$year$month$day";
+				$params[] = $enddate;
+		}
+		$sql .= "user_id = ? ORDER BY timestamp " . $order;
+		$params[] = $this->id;
+		$result = $BlogDB->GetAll($sql, $params);
+
+		$requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':'';
+	 
+		$curyear = "";
+		$curmonth = "";
+		$curday = "";
+		echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/date/\">Date</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . 
+			"Archive/date/" . $requestPath  . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . 
+			"</a> || Sort By <a href=\"" . $this->blogPath . "Archive/category\">Category</a> | <a href=\"" .
+			$this->blogPath . "Archive/subject\"> Subject </a><br />";
+		if ( count($result) >= 1 ) {
+			while($row = array_shift($result)){
+				if($curyear!=date("Y", strtotime($row['timestamp']))) {
+					$curyear = date("Y", strtotime($row['timestamp']));
+					echo "<h1><a href=\"".$this->blogPath."Archive/$curyear\">$curyear</a></h1>";
+				}
+				if($curmonth!=date("F", strtotime($row['timestamp']))) {
+					$curmonth = date("F", strtotime($row['timestamp']));
+					echo "<h2><a href=\"".$this->blogPath."Archive/".date("Y/m", strtotime($row['timestamp']))."\">$curmonth</a></h2>\n";
+				}
+				if($curday!=date("l jS", strtotime($row['timestamp']))) {
+					$curday = date("l jS", strtotime($row['timestamp']));
+					echo "<h3><a href=\"".$this->blogPath."Archive/".date("Y/m/d", strtotime($row['timestamp']))."\">$curday</a></h3>\n";
+				}
+				echo date("g:ia", strtotime($row['timestamp']))." - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n";
+			}
+		} else {
+			error(5,"No Entries Available" . ($allentries ? '' : " for $year" . ($month != '' ? "/$month":'') . ($day != '' ? "/$day":'')));
+		}
+		echo "</div>";
+	}
+
+	//print a list of entries by category
+    function printArchiveByCategory($request) 
+    {
+    		global $BlogDB;
+		// Check for a category id
+		// There must be a better way to check that it isn't $order
+ 		$request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s
+		if (isset($request[0]) && (strtoupper($request[0]) != 'ASC') && (strtoupper($request[0]) != 'DESC')) {
+			$category = $this->makeCleanString($request[0]);
+			if (strlen($category) < 3)
+                		$allentries = true;
+		} else {
+			$allentries = true;
+		}
+	 
+		$lastIndex = count($request) - 1; // Get the last request option after the date
+		$order = 'ASC';
+		if (isset($request[$lastIndex]) && (($lastIndex > 0) || isset($allentries)) &&
+			(strlen($request[$lastIndex]) > 2)) {
+			$order = strtoupper($request[$lastIndex]);
+			array_pop($request);
+		}
+		switch($order) {
+			case 'DESC' :
+				$strOppositeOrder = 'Ascending';
+				$oppositeOrder = 'ASC';
+				$strOrder = 'Descending';
+				break;
+			case 'ASC' :
+			default :
+				$strOppositeOrder = 'Descending';
+				$oppositeOrder = 'DESC';
+				$strOrder = 'Ascending';
+				$order = 'ASC';
+		}
+
+		$sql = "SELECT shortsubject,subject,timestamp, name FROM entries AS e,categories AS c WHERE ";
+		$params = array();
+
+		if (!$allentries) {
+				$sql .= " lower(c.name) = ? AND ";
+				$params[] = $category;
+		}
+		$sql .= "e.user_id = ? AND e.category = c.id ORDER BY ";
+		$params[] = $this->id;
+	
+		if ($allentries) {
+				$sql .= "name " . $order . " ,timestamp ASC";
+		} else {
+				$sql .= "timestamp " . $order;
+		}
+		$result = $BlogDB->GetAll($sql, $params);
+
+		$requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':'';
+		$dbCategory = '';
+		echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/category/\">Category</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . 
+			"Archive/category/" . $requestPath  . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . 
+			"</a> || Sort By <a href=\"" . $this->blogPath . "Archive/date\">Date</a> | <a href=\"" .
+			$this->blogPath . "Archive/subject\"> Subject </a><br />";
+		
+		if ( count($result) >= 1 ) {
+			while($row = array_shift($result)){
+				if($dbCategory != $row['name']) {
+					$dbCategory = $row['name'];
+					echo "<h1><a href=\"".$this->blogPath."Archive/category/$dbCategory\">$dbCategory</a></h1>";
+				}
+				echo date("d/m/Y", strtotime($row['timestamp'])) . " - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n";
+			}
+			echo "</div>";
+		} else {
+			error(5,"No Entries Available" . (isset($category) ? " in $category":''));
+		}
+	}
+
+	//print a list of entries by title
+	function printArchiveBySubject ($request) 
+	{
+		global $BlogDB;
+		// Look for a single character to show subjects by 
+		$request = preg_grep('/.+/', $request); // Remove any additional silly extra elements due to additional /'s
+		if (isset($request[0]) && (preg_match('/^[a-z]$/i', $request[0]))) {
+			$letter = strtolower($request[0]);
+		} else {
+			$allentries = true;
+		}
+	
+		// Get whether it is Ascending or Descending
+		$lastIndex = count($request) - 1; // Get the last request option after the date
+		$order = 'ASC';
+		if (isset($request[$lastIndex]) && !is_numeric($request[$lastIndex])) {
+			$order = strtoupper($request[$lastIndex]);
+			array_pop($request);
+		}
+		switch($order) {
+			case 'DESC' :
+				$strOppositeOrder = 'Ascending';
+				$oppositeOrder = 'ASC';
+				$strOrder = 'Descending';
+				break;
+			case 'ASC' :
+				default :
+				$strOppositeOrder = 'Descending';
+				$oppositeOrder = 'DESC';
+				$strOrder = 'Ascending';
+				$order = 'ASC';
+		}
+
+		$requestPath = (count($request) > 0)?implode ( $request, '/' ) . '/':'';
+	 
+		// lower() exists in PG and MySQL, but given that db abstraction is wanted, is it part of the SQL standard?
+		// Should a better method be used?
+		$sql = "SELECT shortsubject,subject,timestamp FROM entries WHERE ";
+		$params = array();
+		if (!$allentries) {
+				$sql .= "lower(subject) LIKE '" . $letter . "%' AND ";
+				$params[] = $letter;
+		}
+		$sql .= "user_id = ? ORDER BY subject " . $order;
+		$params[] = $this->id;
+		$result = $BlogDB->GetAll($sql, $params);
+
+		echo "<div class=\"td\"><h2>Sorted By <a href=\"" . $this->blogPath . "Archive/subject/\">Subject</a> (" . $strOrder . ")</h2><a href=\"" . $this->blogPath . 
+			"Archive/subject/" . $requestPath  . "" . $oppositeOrder . "\"> Sort " . $strOppositeOrder . 
+			"</a> || Sort By <a href=\"" . $this->blogPath . "Archive/date\">Date</a> | <a href=\"" .
+			$this->blogPath . "Archive/category\"> Category </a><br /><a href=\"" . $this->blogPath . 
+			"Archive/subject/a/$order\">a</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/b/$order\">b</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/c/$order\">c</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/d/$order\">d</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/e/$order\">e</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/f/$order\">f</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/g/$order\">g</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/h/$order\">h</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/i/$order\">i</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/j/$order\">j</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/k/$order\">k</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/l/$order\">l</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/m/$order\">m</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/n/$order\">n</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/o/$order\">o</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/p/$order\">p</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/q/$order\">q</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/r/$order\">r</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/s/$order\">s</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/t/$order\">t</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/u/$order\">u</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/v/$order\">v</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/w/$order\">w</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/x/$order\">x</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/y/$order\">y</a> | <a href=\"" . $this->blogPath . 
+			"Archive/subject/z/$order\">z</a><br />";
+		if ( count($result) >= 1 ) {
+			while($row = array_shift($result)){
+				echo date("d/m/Y", strtotime($row['timestamp'])) . " - <a href=\"{$this->blogPath}entry/{$row['shortsubject']}\">". htmlentities($row['subject']) ."</a><br />\n";
+			}
+		} else {
+			error(5, "No Entries Available" . ($allentries ? '' : " beginning with '$letter'"));
+		}
+		echo "</div>";
+	}
+
+	//print Prev/Next nav bar
+	function printNavigationBar($id) {
+		global $BlogDB;
+		$sql = $BlogDB->GetRow("SELECT timestamp from entries WHERE id='".$id."'");
+		$prev = $BlogDB->GetAll("SELECT id, shortsubject, subject FROM entries WHERE timestamp < '".$sql['timestamp']."' AND user_id = '".$this->id."' ORDER BY timestamp DESC LIMIT 1");
+		$next = $BlogDB->GetAll("SELECT id, shortsubject, subject FROM entries WHERE timestamp > '".$sql['timestamp']."' AND user_id = '".$this->id."' ORDER BY timestamp ASC LIMIT 1;");
+		if (count($prev)>0) $prevRow=array_shift($prev);
+		if (count($next)>0) $nextRow=array_shift($next);
+
+		echo "<div class=\"navbar\"><div><div><div>\n";
+		echo "<ul class=\"blognav\">";
+		if ($prevRow['shortsubject']!="") echo "<li class=\"prev\"><a href=\"{$this->blogPath}entry/{$prevRow['shortsubject']}\">< ".htmlentities($prevRow['subject'])."</a></li>";
+		if ($nextRow['shortsubject']!="") echo "<li class=\"next\"><a href=\"{$this->blogPath}entry/{$nextRow['shortsubject']}\">".htmlentities($nextRow['subject'])." ></a></li>";
+		echo "</ul>\n";
+		echo "<br style=\"clear: both:\" /></div></div></div></div>\n";
+	}
+
+	//print one entry and its comments
+	function printEntryAndComments($shortsubject) 
+	{
+		global $BlogDB;
+		$sql = $BlogDB->GetRow("SELECT id, category, subject, body, timestamp, shortsubject from entries where shortsubject=? and user_id = ? LIMIT 1;", array($shortsubject, $this->id));
+		if (!$sql) {
+			error(5,"No relevant posts");
+		}
+		else	{
+			$this->currentEntry = $sql['shortsubject'];
+			$this->printNavigationBar($sql['id']);
+			$this->printEntry($sql, false, false);
+			$this->printComments($sql['id']);
+			$this->printCommentForm($sql['id']);
+		}
+	}
+
+	//print lots of comments
+	function printComments($postid, $offset=0, $limit=15) 
+	{
+		global $BlogDB;
+		$sql = $BlogDB->GetAll("SELECT timestamp, name, email, body, host, id FROM comments WHERE post = ? and moderated = true ORDER BY timestamp ASC limit ".$limit." OFFSET ".$offset.";", array($postid));
+		echo "<div id=\"comments\">\n";
+		if (count($sql) > 0) {
+			$blogOwner = $this->checkSessionOwner();
+			if($blogOwner) {
+				echo "<form name=\"deletecomments\" id=\"deletecomments\" method=\"post\" action=\"{$this->adminPath}deletecomments/{$this->currentEntry}\">\n";
+			}
+			
+			$count=0;
+			while ($sqlRow = array_shift($sql)) {
+				$this->printComment($sqlRow, $blogOwner, $count++);
+			}
+
+
+			if($blogOwner) {
+				echo "<div style=\"width: 100%; text-align: right\">\n";
+				echo "<input type=\"submit\" name=\"submit\" value=\"Delete Comments\" />\n";
+				echo "</div>\n";
+				echo "</form>\n";
+			}
+		}
+		echo "</div>\n";
+	}
+
+	//print a comment
+	function printComment($row, $printCheckBox=FALSE, $checkBoxNum=0) 
+	{
+		echo "<div class=\"box\">\n";
+		echo "<div class=\"boxhead\"><h3>" . htmlentities($row['name']) . " writes:</h3></div>";
+		echo "<div class=\"boxcontent\"><p>" . nl2br(htmlentities(br2nl($row['body']))) . "</p></div>\n";
+		echo "<div class=\"boxfoot\"><p>[ " .strftime($this->longDateFormat,strtotime($row['timestamp']));
+		if($printCheckBox){
+			echo " | <input class=\"smallcheckbox\" type=\"checkbox\" id=\"comment{$checkBoxNum}\" name=\"comment[{$checkBoxNum}]\" value=\"{$row['id']}\" />\n";
+			echo "<label for=\"comment{$checkBoxNum}\">Delete</label>\n";
+		}
+		echo " ]</p></div>\n";
+		echo "</div>\n";
+	}
+	
+	//counts the number of comments 
+	function commentCount($entry) {
+		global $BlogDB;
+		$sql = $BlogDB->GetCol("SELECT count(id) from comments where post = ? and moderated = true;", array($entry));		
+		return $sql[0];
+	}
+	
+	//returns a category name
+	function categoryName($category) {
+		global $BlogDB;
+		$sql = $BlogDB->GetCol("SELECT name from categories where id = ?;", array($category));		
+		return $sql[0];
+	}
+	
+	//prints a form so people can comment
+	function printCommentForm($id) 
+	{
+		echo "<div class=\"entry\">\n";
+		echo "<h2>Add Comment<a id=\"cmt\"></a></h2>\n";
+		echo "<div class=\"td\">\n";
+		if ($this->commentError != "") {
+			echo "<p class=\"invalid\">*** " . $this->commentError . " ***</p>\n";
+		}
+		elseif (isset($_POST['submit'])) {
+			echo "<p>Thank you for your comment</p>\n";
+		}
+
+		// try to work out the viewer's name + email
+		//seems a bit silly to check for the existance of the session stuff in two places, its probably fair to assume if one is set, the other will be too
+		//these need the same validation checks as when we put things into the db, else people can inject what ever html they like into our pages
+		if(isset($_SESSION['realName'])) {
+			$name = $_SESSION['realName'];
+		} elseif(isset($_COOKIE['Blog_CommentRealName'])) {
+			$name = $_COOKIE['Blog_CommentRealName'];
+		} else {
+			$name = "";
+		}
+		if(isset($_SESSION['userName'])) {
+			$email = $_SESSION['userName']."@sucs.org";
+		} elseif(isset($_COOKIE['Blog_CommentEmailAddress'])) {
+			$email = $_COOKIE['Blog_CommentEmailAddress'];
+		} else {
+			$email = "";
+		}
+		echo "<form onsubmit=\"return postcomment('".$this->httpPath."', '".$this->userName."', '".$id."')\" action=\"".$this->blogPath."postcomment/".$id."\" method=\"post\" id=\"commentform\">\n";
+		echo "<div class=\"row\">\n";
+		echo "<label for=\"author\">Name (required)</label>\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"author\" id=\"author\" value=\"$name\" size=\"40\" maxlength=\"50\" tabindex=\"1\" /></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<span class=\"textinput\"><input type=\"text\" name=\"email\" id=\"email\" value=\"$email\" size=\"40\" maxlength=\"70\" tabindex=\"2\" /></span>\n";
+		echo "<label for=\"email\">E-mail (required, not displayed)</label>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<span class=\"textinput\"><textarea name=\"comment\" id=\"comment\" cols=\"50\" rows=\"10\" tabindex=\"3\">" . (($this->commentError != "") ? strip_tags($_POST['comment']) : "") . "</textarea></span>\n";
+		echo "</div>\n";
+		echo "<div class=\"row\">\n";
+		echo "<span class=\"textinput\"><input name=\"submit\" type=\"submit\" id=\"submit\" tabindex=\"4\" value=\"Submit Comment\" /></span>";
+		echo "<img src=\"".$this->httpPath."img/spinner.gif\" alt=\"\" id=\"spinner\"/>\n";
+		echo "<label class=\"invalid\" for=\"submit\" id=\"errors\"></label>\n";
+		echo "</div>\n<div class=\"clear\"></div>";
+		echo "</form>\n";
+		echo "</div>\n";
+		echo "</div>\n";
+	}
+
+	//takes a string and strips it, making it safe to put in a URL
+	function makeCleanString($string,$externalSource=false)
+	{
+		//externalSource meaning directly inputed by a user, in most cases this should be false.. appart from starting a new post
+		$string = strtolower($string);
+		$string = preg_replace("/[^a-z0-9\- _]/i", "", $string);
+		$string = str_replace(" ", "-",trim($string));
+		if ($externalSource) {
+			$string = str_replace("_", "-",$string);
+		}
+		$string = urlencode($string);
+		return $string;
+	}
+	
+	//handles posting of comments
+	function newComment($id, $printentry=TRUE) 
+	{
+		global $BlogDB;
+		$author = "";
+		$email = "";
+		$comment = "";
+		//check the post exists, and is part of this blog
+		$row = $BlogDB->GetRow("SELECT subject, id from entries where user_id = ? and id = ?;", array($this->id, $id));
+		if (!$row) {
+			error(1,_("Invalid blog entry, This entry may have been removed..?"));
+			return;
+		}
+		//pull in the unadulterated subject for later on
+		$subject = $row['subject'];
+		$postid =  $row['id'];
+		//set hostname
+		if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+			$host = $_SERVER['HTTP_X_FORWARDED_FOR'] . " : " . $_SERVER['REMOTE_ADDR'];
+		}
+		else {
+			$host = $_SERVER['REMOTE_ADDR'];
+		}
+		//sanitise comment
+		if (isset($_POST['comment']) && trim($_POST['comment']) != "") {
+			if(strip_tags($_POST['comment']) == $_POST['comment']) {
+				$comment = nl2br(trim($_POST['comment']));
+			} else {
+				$this->commentError = _("HTML within comments is not allowed, Please remove all html tags and try again");
+				$element = "comment";
+			}
+		} else {
+			$this->commentError = _("Please check the comment field");
+			$element = "comment";
+		}
+		//decided if the comment is likly to be spam
+		if (checkSpam($host,$_POST['comment'])) {
+			$spam = true;
+			//force this comment though moderation
+			$this->comment_moderation = true;
+		} else {
+			$spam = false;
+		}
+		//sanitise email
+		if (isset($_POST['email']) && trim($_POST['email']) != "" && validEmail(trim($_POST['email']))) {
+			$email = trim($_POST['email']);
+		} else {
+			$this->commentError = _("Check email address, it does not apear to be valid.");
+			$element = "email";
+		}
+		//sanitse author
+		if (isset($_POST['author']) && trim($_POST['author']) != "") {
+			if(preg_match("/^([a-z0-9]+ *)+$/i", $_POST['author'])) {
+				$author = nl2br(trim(strip_tags($_POST['author'])));
+			} else {
+				$this->commentError = _("Invalid name. We only allow alphanumeric names!");
+				$element = "author";
+			}
+		} 
+		else {
+			$this->commentError = _("Please give us your name.");
+			$element = "author";
+		}
+		//if no errors have been raised so far commit to the db
+		if ($this->commentError == "") {
+			// do we need to set the moderated flag on this comment?
+			if(!$this->comment_moderation) {
+				$moderated = TRUE;
+			} else {
+				//check the list of 'authorised' commentors
+				if(count($BlogDB->GetAll("SELECT name FROM authorised_emails WHERE user_id=? AND email=?", array($this->id, $email))>0) {
+					$moderated = TRUE;
+				} else {
+					$moderated = FALSE;
+				}
+			}
+			//actualy insert the new comment and check it worked
+			$query = "INSERT INTO comments (post, name, email, body, host, moderated, spam) VALUES (?,?,?,?,?,?,?)";
+			$params = array( $postid, $author, $email, $comment, $host);
+			$params[] = ($moderated) ? "true" : "false";
+			$params[] = ($spam) ? "true" : "false";
+			if(!$BlogDB->Execute($query, $params)) {
+				error(2,_("Database commit failed -").$BlogDB->ErrorMsg());
+			}
+			//send out an notificaiton email if we have succeeded unless we think its spam or moderation has been bypassed
+			else {
+				if(!$spam or !$moderated) 
+					mail($this->userName . "@sucs.org", "Blog comment on \"".$subject."\"", "You've received a comment from ".$author." on your blog post \"".$subject.". The comment is:\n==========\n".$comment.(($moderated) ? "" : "\n==========\nPlease login to your blog admin page to approve or delete this comment."), "From: Your Blog <noreply at sucs.org>");
+				//inform the commentor if the message has been tagged for modderation
+				if(!$moderated) {
+					echo "<p class=\"updateinfo\">"._("Your comment has been added, but before it appears here it must be accepted by the blog owner.")."</p>";
+				} 
+				//or pass out the comment useing the standard form
+				elseif(!$printentry) {
+					$time = strftime($this->longDateFormat, time());
+					$this->printComment(array('name'=>$author, 'body'=>$comment, 'timestamp'=>$time));
+				}
+				//reprint the entire entry (for the case where we're not useing the ajax goodness)
+				if($printentry) {
+					$this->printEntryAndComments($shortSubject);
+				}
+				//if we dont have a valid session store the name & email in there own cookies
+				if(!isset($_SESSION['realName'])) {
+					setcookie("Blog_CommentRealName", $author, time()+604800);
+					setcookie("Blog_CommentEmailAddress", $email, time()+604800);
+				}
+				ob_end_flush();
+				return array(TRUE);
+			}
+		//else return our error and the status gumf for the benifit of the ajax goodness
+		} else {
+			echo $this->commentError;
+			return array(FALSE, $element);
+		}
+	}
+	
+	//reutrns the id of the message assosiated with a short subject
+	function shortSubjectToID($shortsubject)
+	{
+		global $BlogDB;
+		$sql = $BlogDB->GetRow("SELECT id from entries where user_id = ? and shortsubject = ?;", array($this->id, $shortsubject));
+		if ($sql) {
+			return $sql['id'];
+		}
+		else {
+			error(3,"No such post");
+		}
+	}
+	
+	//reutrns the short subject of the message given message 
+	function IDToShortSubject($id)
+	{
+		global $BlogDB;
+		$sql = $BlogDB->GetRow("SELECT shortsubject from entries where user_id = ? and id = ?;", array($this->id, $id));
+		if ($sql) {
+			return $sql['shortsubject'];
+		}
+		else {
+			error(3,"No such post");
+		}
+	}
+
+	// Blog menu
+	function menu()
+	{
+		global $smarty, $session;
+
+		$submenu = array();
+
+		if ($session->loggedin && blogger($session->username)) $submenu[_("My Blog")] = "{$this->httpPath}{$session->username}";
+
+		if ($session->username != $this->userName) $userblog = $this->userName._("'s Blog");
+		$submenu[$userblog] = $this->blogPath;
+
+		if ($session->username == $this->userName) $archiveblog = _("My Archive");
+		else $archiveblog = $this->userName._("'s Archive");
+		$submenu[$archiveblog] = "{$this->blogPath}Archive/";
+		
+		if ($this->checkSessionOwner() && blogger($session->username)){
+			$submenu[_("Blog admin")] = "{$this->adminPath}";
+		}
+
+		$menu = $smarty->get_template_vars("menu");
+		$menu[Blogs] = $submenu;
+		$smarty->assign("menu", $menu);
+	}
+
+	// Check the session to see if the user is browsing her own blog
+	function checkSessionOwner()
+	{
+		global $session;
+		$maxSessionAge = 3600;
+		
+		// if the session's expired then nuke it
+		if ($session->username != $this->userName) {
+			return FALSE;
+		} else {
+			// the time's not up and the usernames match so it's probably the right user.
+			return TRUE;
+		}
+	}
+}
+
+// a pseudo-class to list all blog users
+class bloglist {
+	var $title;
+	var $description;
+	var $httpPath;
+	var $listPath;
+	var $adminPath;
+	var $cssFile;
+	var $svnRevision;       // the SVN revision number of the currently running blog
+
+	// don't do anything apart from setting up default variables
+	function bloglist() 
+	{
+		$this->title = _("Blogs");
+		$this->description = _("Swansea University Computer Society member web logs");
+		$this->httpPath = "/Blogs/";
+		//if(substr($this->httpPath, -1)!="/") {
+		//	$this->httpPath .= "/";
+		//}
+		$this->basePath = "/Blogs/";
+		$this->adminPath = $this->httpPath."Admin/";
+		$this->cssFile = "blog.css";
+		$this->svnRevision = getSVNRevision();
+
+		// setup the session purely so we get the debug bits..
+		session_name("BlogSession");
+		session_start();
+	}
+
+	// print a nice list of blog users and when they last updated
+	function listBlogs()
+	{
+		global $BlogDB, $session;
+		$sql = $BlogDB->GetAll("SELECT max(entries.timestamp) AS ts, users.username, users.description, users.name, users.title FROM entries LEFT JOIN users ON entries.user_id = users.id GROUP BY users.username, users.name, users.title, users.description ORDER BY ts DESC;");
+		if (count($sql) > 0) {
+			echo "<div class=\"td\">\n";
+			echo "<p>"._("Welcome to SUCS Blogs - The multi-user web log system created by SUCS members for SUCS members.")."</p>\n";
+			echo "<p>"._("Browse the blogs below or use the links on the left to navigate the site. Happy blogging!")."</p>\n";
+			if ($session->loggedin && !blogger($session->username)) echo "<p>"._("Want to join the ranks of SUCS bloggers? - ")."<a href=\"{$this->adminPath}signup\">"._("Start a Blog!")."</a></p>\n";
+			echo "</div>\n";
+			echo "<div id=\"listofblogs\">\n";
+			echo "<table class=\"border\">\n";
+			echo "<tr><th class=\"bname\">"._("Name")."</th><th class=\"btitle\">"._("Blog")."</th><th class=\"bupdated\">"._("Last Updated")."</th></tr>";
+			while($row = array_shift($sql)) {
+				echo "<tr>\n";
+				echo "    <td>".$row['name']."</td>\n";
+				echo "    <td><a href=\"".$this->basePath.$row['username']."\" title=\"".$row['description']."\">".$row['title']."</a></td>\n";
+				echo "    <td>".$this->timeDiff(strtotime($row['ts']))." ago</td>\n";
+				echo "</tr>\n";
+			}
+			
+			echo "</table>\n";
+			echo "</div>\n";
+		}
+		else {
+			error(3,_("No blogs"));
+		}
+	}
+    
+	//Returns a textual diff between two time stamps
+	function timeDiff($first, $second=0)
+	{
+		if($second == 0) {
+			$second = time();
+		}
+
+		$diff = max($first, $second) - min($first, $second);
+
+		if($diff>604800) {
+			$ret = round($diff/604800);
+			return $ret.(($ret>1)? _(" weeks") : _(" week"));
+		} 
+		elseif($diff>86400) {
+			$ret = round($diff/86400);
+			return $ret.(($ret>1)? _(" days") : _(" day"));
+		} 
+		elseif($diff>3600) {
+			$ret = round($diff/3600);
+			return $ret.(($ret>1)? _(" hours") : _(" hour"));
+		} 
+		elseif($diff>60) {
+			$ret = round($diff/60);
+			return $ret.(($ret>1)? _(" minutes") : _(" minute"));
+		}
+		else {
+			return $diff.(($diff>1)? _(" seconds") : _(" second"));
+		}
+	}
+
+	// Blog menu - links displayed when the blog list is displayed
+	function menu() {
+		global $smarty, $session;
+
+		if ($session->loggedin) {
+		$submenu = array();
+			if (blogger($session->username)) {
+				$submenu[_("My Blog")] = "{$this->httpPath}{$session->username}";
+				$submenu[_("Blog admin")] = "{$this->adminPath}";
+			} else {
+				$submenu[_("Start a Blog")] = "{$this->adminPath}signup";		
+			}
+		$menu = $smarty->get_template_vars("menu");
+		$menu[Blogs] = $submenu;
+		$smarty->assign("menu", $menu);
+		}
+	}
+}

Deleted: branches/sucs-site/lib/blog/miscfunctions.lib.php
===================================================================
--- branches/sucs-site/lib/blog/miscfunctions.lib.php	2015-01-21 12:59:01 UTC (rev 635)
+++ branches/sucs-site/lib/blog/miscfunctions.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -1,300 +0,0 @@
-<?php
-// does the opposite of PHP's nl2br()
-function br2nl($string) {
-	$string = preg_replace("/(\r\n|\n|\r)/", "", $string);
-	$string = preg_replace("/<br *\/?>/i", "\n", $string);
-	return $string;
-}
-
-// generate a pseudo-word random password
-function makePassword($length=8)
-{
-	$password = "";
-	$vowels = "aeiouy";
-	$consonants = "bcdfghjklmnprst";
-	$cn = strlen($consonants)-1;
-	$vn = strlen($vowels)-1;
-	// Start on cons or vowel
-	$alt = mt_rand(0, 1);
-	// How many numbers
-	$len = mt_rand($length-3,$length);
-	//add the letters
-	for ($i = 0; $i < $len; $i++)
-	{
-		if ($alt == 1)	{
-			$password .= $consonants[ mt_rand(0,$cn) ];
-			$alt = 0;
-		}
-		else	{
-			$password .= $vowels[ mt_rand(0,$vn) ];
-			$alt = 1;
-		}
-	}
-	//add the numbers
-	for ($i = 0; $i < $length-$len; $i++)
-	{
-		$password .= mt_rand(0,9);
-	}
-	return $password;
-}
-
-$revision = "unknown";
-function startElement($parser, $name, $attrs)
-{
-	global $revision;
-	if($name=="ENTRY" && $attrs['NAME']=="") {
-		$revision = $attrs['REVISION'];
-	}
-}
-
-function endElement($parser, $name){}
-
-function getSVNRevision()
-{
-	global $revision;
-	$xml_parser = xml_parser_create();
-	xml_set_element_handler($xml_parser, "startElement", "endElement");
-	if (!($fp = fopen(".svn/entries", "r"))) {
-		return "unknown - couldn't open SVN XML file.";
-	}
-	while(($data = fread($fp, 1024)) && $revision=="unknown") {
-		if (!xml_parse($xml_parser, $data, feof($fp))) {
-			return "unknown - couldn't parse SVN XML file";
-		}
-	}
-	xml_parser_free($xml_parser);
-	return $revision;
-}
-
-/*
- *
- * Spam Checks
- *
- */
-//Check the Spam URI Realtime Blocklist
-function checkSpamURLs($text) {
-	$spam = false;
-	//find urls, ugly but works
-	while (preg_match("/http://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/",$text,$match)) {
-		$matches[] = $match[0];
-		$text = preg_replace("/".$match[0]."/","",$text); //Can this be replaced with str_replace?
-	}
-	//pull in list of two level tlds, make an array from them. from http://spamcheck.freeapp.net/two-level-tlds
-	$twoLevelTLD = file("/var/www/sucssite/lib/blog/two-level-tlds");
-	foreach($twoLevelTLD as $TLD) {
-		$two_level_tlds[trim($TLD)] = true;
-	}
-	if (!$matches)
-		return;
-	//for each url
-	foreach ($matches as $url) {
-		//break it down
-		$urlBits = explode(".",substr($url, 7));
-		//reverse the oder
-		$bitsURL = array_reverse($urlBits);
-		//if its a two level tld, we want the first 3 bits of the url.. if not just the first 2
-		if ($two_level_tlds[($bitsURL[1].".".$bitsURL[0])]) {
-			$URLstoTest[] = ($bitsURL[2].".".$bitsURL[1].".".$bitsURL[0]);
-		} else {
-			$URLstoTest[] = ($bitsURL[1].".".$bitsURL[0]);
-		}
-	}
-	if (!$URLstoTest)
-		return;
-	//actualy test each of he domains against the surbl
-	foreach($URLstoTest as $url) {
-		$result = gethostbyname($url.'.multi.surbl.org');
-		if ($result != $url.'.multi.surbl.org') {
-			$spam = true;
-		}
-		elseif ($url == "blogspot.com") {
-			$spam = true;
-		}
-	}
-	return $spam;
-}
-//feeds a message body though LinkSleeve (http://www.linksleeve.org/) which at the time of testing seems quite good.
-function checkSpamLinkSleeve ($text) {
-	// Include the Pear XML-RPC Client Package
-	require_once 'XML/RPC.php';
-	// Build the XML-RPC message
-	$params = array(new XML_RPC_Value($text, 'string'));
-	$msg = new XML_RPC_Message('slv', $params);
-	//Send the XML-RPC message
-	$cli = new XML_RPC_Client('/slv.php', 'http://www.linksleeve.org');
-	$resp = $cli->send($msg);
-	//Check for a responce
-	if (!$resp) {
-		echo 'Communication error: ' . $cli->errstr;
-		return false;
-	}
-	//spam?
-	if (!$resp->faultCode()) {
-		$val = $resp->value();
-		if($val->scalarval()=='1') {
-			$spam = false;
-		}
-		else {
-			$spam = true;
-		}
-	} 
-	//Handle Errors
-	else {
-		 echo 'Fault Code: ' . $resp->faultCode() . "\n";
-		 echo 'Fault Reason: ' . $resp->faultString() . "\n";
-	}
-	return $spam;
-}
-
-//checks an ip in several blacklists returns true if its present
-function checkSpamIP($ip) {
-	$spam = false;
-	//reverse the ip
-	$ip = implode('.',array_reverse(explode('.',$ip)));
-	//look up in various rbls
-	$rbl = gethostbyname($ip.'.rbl-plus.mail-abuse.ja.net');
-	$scbl = gethostbynamel($ip.'.bl.spamcop.net');
-	$sorbs = gethostbynamel($ip.'.dnsbl.sorbs.net');
-	$sbl = gethostbynamel($ip.'.sbl.spamhaus.org');
-	$njabl = gethostbynamel($ip.'.dnsbl.njabl.org');
-	$opm = gethostbyname($ip.'.opm.blitzed.org');
-	$cbl = gethostbynamel($ip.'.cbl.abuseat.org');
-
-	//CBL 
-	if ($cbl) {
-		$spam = true;
-	}
-	
-	//OPM
-	if ($opm != $ip.".opm.blitzed.org") {
-		//this bl uses a decimal to represent one catagory of spam source
-		$code = decbin(ip2long($opm));
-		//check for WinGate
-		if ($code[30])
-			$spam = true;
-		//check for SOCKS
-		if ($code[29])
-			$spam = true;
-		//check for HTTP CONNECT
-		if ($code[28])
-			$spam = true;
-		//check for Router
-		if ($code[27])
-			$spam = true;
-		//check for HTTP POST
-		if ($code[26])
-			$spam = true;
-	}
-
-	//RBL+
-	if ($rbl != $ip.".rbl-plus.mail-abuse.ja.net") 	{
-		$code = decbin(ip2long($rbl));
-		//check for rbl
-		if ($code[30])
-			$spam = true;
-		//check for dul
-		if ($code[29])
-			//we dont care about dul
-		//check for rss
-		if ($code[28])
-			$spam = true;
-		//check for ops
-		if ($code[27])
-			$spam = true;
-	}
-	
-	//SpamCop
-	if ($scbl) {
-		$spam = true;
-	}
-	
-	//SORBS
-	if ($sorbs) {
-		foreach($sorbs as $result) {
-			$result = explode('.',$result);
-			//check for http
-			if ($result[3] == 2)
-				$spam = true;
-			//check for socks
-			if ($result[3] == 3)
-				$spam = true;
-			//check for misc
-			if ($result[3] == 4)
-				$spam = true;
-			//check for smtp
-			if ($result[3] == 5)
-				$spam = true;
-			//check for spam
-			if ($result[3] == 6)
-				$spam = true;
-			//check for web
-			if ($result[3] == 7)
-				$spam = true;
-			//check for block
-			if ($result[3] == 8)
-				$spam = true;
-			//check for zombie
-			if ($result[3] == 9)
-				$spam = true;
-			//check for dul
-			if ($result[3] == 10)
-				//dont care about dul
-			//check for badconf
-			if ($result[3] == 11)
-				$spam = true;
-			//check for nomail
-			if ($result[3] == 12)
-				$spam = true;
-		}
-	}
-
-	//NJABL
-	if ($njabl) {
-		foreach($njabl as $result) {
-			$result = explode('.',$result);
-			//check for relay
-			if ($result[3] == 2)
-				$spam = true;
-			//check for dul
-			if ($result[3] == 3) {
-				//dont care about dul
-			}
-			//check for spam
-			if ($result[3] == 4)
-				$spam = true;
-			//check for relay
-			if ($result[3] == 5)
-				$spam = true;
-			//check for web
-			if ($result[3] == 8)
-				$spam = true;
-			//check for proxy
-			if ($result[3] == 9)
-				$spam = true;
-		}
-	}
-
-	//SBL
-	if($sbl) {
-		$spam = true;
-	}
-	return $spam;
-}
-
-# General spam function combining all checks
-function checkSpam($ip, $text) {
-	//Check LinkSleeve first, its a collaborative statistical thing, and will benefit from seeing all messages, spam or not
-	if (checkSpamLinkSleeve($text)) {
-		$spam = true;
-	//Check any URL's the Spam URL Black List
-	} elseif (checkSpamURLs($text)) {
-		$spam = true;
-	//If all else fails lookup the posting IP in all the normal IP Black Lists
-	} elseif (checkSpamIP($ip)) {
-		$spam = true;
-	//Decide its probably not spam
-	} else {
-		$spam = false;
-	}
-	return $spam;
-}

Copied: branches/sucs-site/lib/blog/miscfunctions.lib.php (from rev 635, branches/sucs-site/lib/blog/miscfunctions.lib.php)
===================================================================
--- branches/sucs-site/lib/blog/miscfunctions.lib.php	                        (rev 0)
+++ branches/sucs-site/lib/blog/miscfunctions.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,300 @@
+<?php
+// does the opposite of PHP's nl2br()
+function br2nl($string) {
+	$string = preg_replace("/(\r\n|\n|\r)/", "", $string);
+	$string = preg_replace("/<br *\/?>/i", "\n", $string);
+	return $string;
+}
+
+// generate a pseudo-word random password
+function makePassword($length=8)
+{
+	$password = "";
+	$vowels = "aeiouy";
+	$consonants = "bcdfghjklmnprst";
+	$cn = strlen($consonants)-1;
+	$vn = strlen($vowels)-1;
+	// Start on cons or vowel
+	$alt = mt_rand(0, 1);
+	// How many numbers
+	$len = mt_rand($length-3,$length);
+	//add the letters
+	for ($i = 0; $i < $len; $i++)
+	{
+		if ($alt == 1)	{
+			$password .= $consonants[ mt_rand(0,$cn) ];
+			$alt = 0;
+		}
+		else	{
+			$password .= $vowels[ mt_rand(0,$vn) ];
+			$alt = 1;
+		}
+	}
+	//add the numbers
+	for ($i = 0; $i < $length-$len; $i++)
+	{
+		$password .= mt_rand(0,9);
+	}
+	return $password;
+}
+
+$revision = "unknown";
+function startElement($parser, $name, $attrs)
+{
+	global $revision;
+	if($name=="ENTRY" && $attrs['NAME']=="") {
+		$revision = $attrs['REVISION'];
+	}
+}
+
+function endElement($parser, $name){}
+
+function getSVNRevision()
+{
+	global $revision;
+	$xml_parser = xml_parser_create();
+	xml_set_element_handler($xml_parser, "startElement", "endElement");
+	if (!($fp = fopen(".svn/entries", "r"))) {
+		return "unknown - couldn't open SVN XML file.";
+	}
+	while(($data = fread($fp, 1024)) && $revision=="unknown") {
+		if (!xml_parse($xml_parser, $data, feof($fp))) {
+			return "unknown - couldn't parse SVN XML file";
+		}
+	}
+	xml_parser_free($xml_parser);
+	return $revision;
+}
+
+/*
+ *
+ * Spam Checks
+ *
+ */
+//Check the Spam URI Realtime Blocklist
+function checkSpamURLs($text) {
+	$spam = false;
+	//find urls, ugly but works
+	while (preg_match("/http://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}/",$text,$match)) {
+		$matches[] = $match[0];
+		$text = preg_replace("/".$match[0]."/","",$text); //Can this be replaced with str_replace?
+	}
+	//pull in list of two level tlds, make an array from them. from http://spamcheck.freeapp.net/two-level-tlds
+	$twoLevelTLD = file("/var/www/sucssite/lib/blog/two-level-tlds");
+	foreach($twoLevelTLD as $TLD) {
+		$two_level_tlds[trim($TLD)] = true;
+	}
+	if (!$matches)
+		return;
+	//for each url
+	foreach ($matches as $url) {
+		//break it down
+		$urlBits = explode(".",substr($url, 7));
+		//reverse the oder
+		$bitsURL = array_reverse($urlBits);
+		//if its a two level tld, we want the first 3 bits of the url.. if not just the first 2
+		if ($two_level_tlds[($bitsURL[1].".".$bitsURL[0])]) {
+			$URLstoTest[] = ($bitsURL[2].".".$bitsURL[1].".".$bitsURL[0]);
+		} else {
+			$URLstoTest[] = ($bitsURL[1].".".$bitsURL[0]);
+		}
+	}
+	if (!$URLstoTest)
+		return;
+	//actualy test each of he domains against the surbl
+	foreach($URLstoTest as $url) {
+		$result = gethostbyname($url.'.multi.surbl.org');
+		if ($result != $url.'.multi.surbl.org') {
+			$spam = true;
+		}
+		elseif ($url == "blogspot.com") {
+			$spam = true;
+		}
+	}
+	return $spam;
+}
+//feeds a message body though LinkSleeve (http://www.linksleeve.org/) which at the time of testing seems quite good.
+function checkSpamLinkSleeve ($text) {
+	// Include the Pear XML-RPC Client Package
+	require_once 'XML/RPC.php';
+	// Build the XML-RPC message
+	$params = array(new XML_RPC_Value($text, 'string'));
+	$msg = new XML_RPC_Message('slv', $params);
+	//Send the XML-RPC message
+	$cli = new XML_RPC_Client('/slv.php', 'http://www.linksleeve.org');
+	$resp = $cli->send($msg);
+	//Check for a responce
+	if (!$resp) {
+		echo 'Communication error: ' . $cli->errstr;
+		return false;
+	}
+	//spam?
+	if (!$resp->faultCode()) {
+		$val = $resp->value();
+		if($val->scalarval()=='1') {
+			$spam = false;
+		}
+		else {
+			$spam = true;
+		}
+	} 
+	//Handle Errors
+	else {
+		 echo 'Fault Code: ' . $resp->faultCode() . "\n";
+		 echo 'Fault Reason: ' . $resp->faultString() . "\n";
+	}
+	return $spam;
+}
+
+//checks an ip in several blacklists returns true if its present
+function checkSpamIP($ip) {
+	$spam = false;
+	//reverse the ip
+	$ip = implode('.',array_reverse(explode('.',$ip)));
+	//look up in various rbls
+	$rbl = gethostbyname($ip.'.rbl-plus.mail-abuse.ja.net');
+	$scbl = gethostbynamel($ip.'.bl.spamcop.net');
+	$sorbs = gethostbynamel($ip.'.dnsbl.sorbs.net');
+	$sbl = gethostbynamel($ip.'.sbl.spamhaus.org');
+	$njabl = gethostbynamel($ip.'.dnsbl.njabl.org');
+	$opm = gethostbyname($ip.'.opm.blitzed.org');
+	$cbl = gethostbynamel($ip.'.cbl.abuseat.org');
+
+	//CBL 
+	if ($cbl) {
+		$spam = true;
+	}
+	
+	//OPM
+	if ($opm != $ip.".opm.blitzed.org") {
+		//this bl uses a decimal to represent one catagory of spam source
+		$code = decbin(ip2long($opm));
+		//check for WinGate
+		if ($code[30])
+			$spam = true;
+		//check for SOCKS
+		if ($code[29])
+			$spam = true;
+		//check for HTTP CONNECT
+		if ($code[28])
+			$spam = true;
+		//check for Router
+		if ($code[27])
+			$spam = true;
+		//check for HTTP POST
+		if ($code[26])
+			$spam = true;
+	}
+
+	//RBL+
+	if ($rbl != $ip.".rbl-plus.mail-abuse.ja.net") 	{
+		$code = decbin(ip2long($rbl));
+		//check for rbl
+		if ($code[30])
+			$spam = true;
+		//check for dul
+		if ($code[29])
+			//we dont care about dul
+		//check for rss
+		if ($code[28])
+			$spam = true;
+		//check for ops
+		if ($code[27])
+			$spam = true;
+	}
+	
+	//SpamCop
+	if ($scbl) {
+		$spam = true;
+	}
+	
+	//SORBS
+	if ($sorbs) {
+		foreach($sorbs as $result) {
+			$result = explode('.',$result);
+			//check for http
+			if ($result[3] == 2)
+				$spam = true;
+			//check for socks
+			if ($result[3] == 3)
+				$spam = true;
+			//check for misc
+			if ($result[3] == 4)
+				$spam = true;
+			//check for smtp
+			if ($result[3] == 5)
+				$spam = true;
+			//check for spam
+			if ($result[3] == 6)
+				$spam = true;
+			//check for web
+			if ($result[3] == 7)
+				$spam = true;
+			//check for block
+			if ($result[3] == 8)
+				$spam = true;
+			//check for zombie
+			if ($result[3] == 9)
+				$spam = true;
+			//check for dul
+			if ($result[3] == 10)
+				//dont care about dul
+			//check for badconf
+			if ($result[3] == 11)
+				$spam = true;
+			//check for nomail
+			if ($result[3] == 12)
+				$spam = true;
+		}
+	}
+
+	//NJABL
+	if ($njabl) {
+		foreach($njabl as $result) {
+			$result = explode('.',$result);
+			//check for relay
+			if ($result[3] == 2)
+				$spam = true;
+			//check for dul
+			if ($result[3] == 3) {
+				//dont care about dul
+			}
+			//check for spam
+			if ($result[3] == 4)
+				$spam = true;
+			//check for relay
+			if ($result[3] == 5)
+				$spam = true;
+			//check for web
+			if ($result[3] == 8)
+				$spam = true;
+			//check for proxy
+			if ($result[3] == 9)
+				$spam = true;
+		}
+	}
+
+	//SBL
+	if($sbl) {
+		$spam = true;
+	}
+	return $spam;
+}
+
+# General spam function combining all checks
+function checkSpam($ip, $text) {
+	//Check LinkSleeve first, its a collaborative statistical thing, and will benefit from seeing all messages, spam or not
+	if (checkSpamLinkSleeve($text)) {
+		$spam = true;
+	//Check any URL's the Spam URL Black List
+	} elseif (checkSpamURLs($text)) {
+		$spam = true;
+	//If all else fails lookup the posting IP in all the normal IP Black Lists
+	} elseif (checkSpamIP($ip)) {
+		$spam = true;
+	//Decide its probably not spam
+	} else {
+		$spam = false;
+	}
+	return $spam;
+}

Deleted: branches/sucs-site/lib/blog/validation.lib.php
===================================================================
--- branches/sucs-site/lib/blog/validation.lib.php	2015-01-21 12:59:01 UTC (rev 635)
+++ branches/sucs-site/lib/blog/validation.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -1,18 +0,0 @@
-<?
-//check for a safe username
-function safeuname($name)
-{
-	if (strlen($name) < 2) return FALSE;
-	return preg_match("/^[a-z][a-z0-9_]*$/i", $name);
-}
-
-// Find out if a given user has a blog
-function blogger ($user) {
-	global $BlogDB;
-	$result = $BlogDB->GetAll("select username from users where username='". $user ."'");
-	if (count($result)>0) return true;
-	else return false;
-}
-
-require_once($base."/lib/validation.php");
-?>

Copied: branches/sucs-site/lib/blog/validation.lib.php (from rev 635, branches/sucs-site/lib/blog/validation.lib.php)
===================================================================
--- branches/sucs-site/lib/blog/validation.lib.php	                        (rev 0)
+++ branches/sucs-site/lib/blog/validation.lib.php	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,18 @@
+<?
+//check for a safe username
+function safeuname($name)
+{
+	if (strlen($name) < 2) return FALSE;
+	return preg_match("/^[a-z][a-z0-9_]*$/i", $name);
+}
+
+// Find out if a given user has a blog
+function blogger ($user) {
+	global $BlogDB;
+	$result = $BlogDB->GetAll("select username from users where username=?;", array($user));
+	if (count($result)>0) return true;
+	else return false;
+}
+
+require_once($base."/lib/validation.php");
+?>

Modified: branches/sucs-site/templates/members.tpl
===================================================================
--- branches/sucs-site/templates/members.tpl	2015-01-30 16:57:12 UTC (rev 639)
+++ branches/sucs-site/templates/members.tpl	2015-01-30 17:08:05 UTC (rev 640)
@@ -26,6 +26,10 @@
 	<dt>Website</dt>
 	<dd><a href="http://sucs.org/~{$member.uid|escape:'url'}/">http://sucs.org/~{$member.uid|escape:'url'}/</a></dd>
 {/if}
+{if isset($member.blog) }
+	<dt>Blog</dt>
+	<dd><a href="/Blogs/{$member.uid|escape:'url'}">{$member.blog}</a></dd>
+{/if}
 {if isset($member.project) }
 	<dt>Project</dt>
 	<dd id="project">{$member.project|escape:'htmlall'}</dd>

Modified: branches/sucs-site/templates/options.tpl
===================================================================
--- branches/sucs-site/templates/options.tpl	2015-01-30 16:57:12 UTC (rev 639)
+++ branches/sucs-site/templates/options.tpl	2015-01-30 17:08:05 UTC (rev 640)
@@ -164,7 +164,45 @@
 {/if}
 	</fieldset>
 	</form>
+	<form method="post" action="{$baseurl}{$path}">
+	<input type="hidden" name="action" value="changeblogfeed" />
+	<fieldset>
+	<legend>Blog Feed</legend>
 
+{* if the member has a SUCS blog, offer this *}
+{if $sucsblogger}
+	<div class="row">
+	<label for="blogtype">My SUCS Blog:</label>
+	<span class="textinput">
+		<input type="radio" name="blogtype" value="sucs" {if $sucsblogfeed}checked="checked"{/if} />
+	</span>
+	</div>
+{/if}
+	<div class="row">
+		<label for="bloguri">RSS/Atom feed:</label>
+		<span class="textinput">
+		{if $sucsblogger} 
+			<input type="radio" name="blogtype" value="custom" {if not $sucsblogfeed}checked="checked"{/if} />
+		{/if}
+			<input type="text" name="bloguri" id="bloguri" style="width:90%;" {if $member.blogfeed}value="{$member.blogfeed}"{/if} />
+		</span>
+	</div>
+	<div class="row">
+		<label for="syndicateblog">Display on Planet SUCS:</label>
+		<span class="textinput">
+			<input type="checkbox" name="syndicateblog" id="syndicateblog" {if $member.syndicateblog}checked="checked"{/if} />
+			<div class="note">Tick this box if you wish to have your blog syndicated on <a href="http://sucs.org/Community/Planet">Planet SUCS</a>. We'd like to keep the Planet free of needlessly offensive/illegal/liable-to-melt-eyeballs material, and may decide to remove feeds which don't comply with this policy. Consider setting up a category and separate feed for posts you'd like to appear on Planet if you feel your blog may otherwise be unsuitable.
+			</div>
+		</span>
+	</div>
+	<div class="row">
+		<input type="submit" value="Change" />
+	</div>
+
+
+	</fieldset>
+	</form>
+
 {if ($member.type == 1 || $member.type == 2) && $member.paid != $paydate}
 	<form method="post" action="{$baseurl}{$path}">
 	<fieldset>

Copied: branches/sucs-site/templates/planetconfig.tpl (from rev 635, branches/sucs-site/templates/planetconfig.tpl)
===================================================================
--- branches/sucs-site/templates/planetconfig.tpl	                        (rev 0)
+++ branches/sucs-site/templates/planetconfig.tpl	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,67 @@
+# Planet configuration file
+
+[Planet]
+name = Planet SUCS
+link = http://www.sucs.org/planet
+owner_name = SUCS Admin
+owner_email = admin at sucs.org
+
+# cache_directory: Where cached feeds are stored
+# new_feed_items: Number of items to take from new feeds
+# log_level: One of DEBUG, INFO, WARNING, ERROR or CRITICAL
+# feed_timeout: number of seconds to wait for any given feed
+cache_directory = cache
+new_feed_items = 2
+log_level = ERROR
+feed_timeout = 20
+
+# template_files: Space-separated list of output template files
+template_files = sucs/Planet.txt.tmpl sucs/atom.xml.tmpl sucs/rss20.xml.tmpl sucs/rss10.xml.tmpl sucs/opml.xml.tmpl sucs/foafroll.xml.tmpl
+
+output_dir = {$planetoutputdir}
+items_per_page = 50
+days_per_page = 0
+date_format = %b %d, %Y at %I:%M %p
+new_date_format = %B %d, %Y
+encoding = utf-8
+# locale = C
+
+# To define a different value for a particular template you may create
+# a section with the same name as the template file's filename (as given
+# in template_files).
+
+# If non-zero, all feeds which have not been updated in the indicated
+# number of days will be marked as inactive
+activity_threshold = 0
+
+# Options placed in the [DEFAULT] section provide defaults for the feed
+# sections.  Placing a default here means you only need to override the
+# special cases later.
+#[DEFAULT]
+# Hackergotchi default size.
+# If we want to put a face alongside a feed, and it's this size, we
+# can omit these variables.
+#facewidth = 65
+#faceheight = 85
+
+# Any other section defines a feed to subscribe to.  The section title
+# (in the []s) is the URI of the feed itself.  A section can also be
+# have any of the following options:
+# 
+# name: Name of the feed (defaults to the title found in the feed)
+
+
+#blogroll pulled from the database
+{foreach from=$blogroll item=blog}
+[{$blog.feeduri}]
+name = {$blog.username}
+{if $blog.hackergotchi}
+face = {$blog.username}.png
+{/if}
+
+{/foreach}
+
+#static entries 
+
+[http://sucs.org/blog/feed/atom/vote]
+name = Election 2009

Copied: branches/sucs-site/templates/planetposts.tpl (from rev 635, branches/sucs-site/templates/planetposts.tpl)
===================================================================
--- branches/sucs-site/templates/planetposts.tpl	                        (rev 0)
+++ branches/sucs-site/templates/planetposts.tpl	2015-01-30 17:08:05 UTC (rev 640)
@@ -0,0 +1,19 @@
+{if count($planetposts) > 0 }
+<div class="cbb">
+
+<h3><a href="/planet/">Recent Blog entries</a></h3>
+
+<table width="100%" class="border">
+<tr>
+<th>Subject</th>
+<th>by</th>
+</tr>
+{foreach name=planetposts from=$planetposts item=post}
+<tr>
+	<td><a href="{$post.post_uri}">{$post.post}</a></td>
+	<td><a href="{$post.user_uri}">{$post.user}</a></td>
+</tr>
+{/foreach}
+</table>
+</div>
+{/if}




More information about the Devel mailing list