#!/usr/bin/perl
use lib '/home/erealms/ethereal/mgmt/perl';

################################################################################
# Created       : Martin Foster
# Modified      : 01-Jan-2007
################################################################################
#
# Gateway - Script part of Ethereal Realms designed to authenticate, leading 
#           users to various aspects of the site.
# Copyright (C) 2000-2007  Martin Foster
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# Author of this script can be contacted at the following:
#       E-Mail  : martin@ethereal-realms.org
#       Address : 3-3456 Wolfe Cres
#                 Halifax, Nova Scotia
#                 B3L 3S2
#
#################################################################################

use CGI;							# Common gateway interface
use CGI::Carp qw(fatalsToBrowser);				# CGI Error logs
use Digest::MD5 qw(md5_hex);					# MD5 digest cryptographic algorithm
use strict;							# Strict variable enforcement

use Ethereal::Audit;						# Auditing handle
use Ethereal::Database;						# Database handler
use Ethereal::Login;						# Login functionality
use Ethereal::Menu;						# Consistent menu
use Ethereal::Param;						# Parameter control
use Ethereal::Rotate;						# Code rotation
use Ethereal::Template;						# Template handler
use Ethereal::Weather;						# Weather handler
use Ethereal::Who;						# Who is on

#################################################################################
# Gobal override
#################################################################################
$CGI::POST_MAX=1024 * 50;					# Maximum posts
$CGI::DISABLE_UPLOADS = 1;					# Disable uploads

################################################################################
# Data Members
################################################################################
my $cgi;							# Common gateway interface handle
my $database;							# Database handle
my $login;							# Login handle
my $menu;							# Menu handle
my $param;							# Parameter hash
my $tmpl;							# Template handle

my $scriptname;							# Simply the script name
my $scriptpara;							# Scripted parameters
my $puppet;							# Puppet name

my %portal;							# Portal hash

################################################################################
# Program Area
################################################################################

	# Initial handles
	$cgi      = new CGI;
	$database = new Ethereal::Database();

	# Connect and fetch
	$database->Connect($cgi);

	# Set title
	$database->{'TITLE'} = $database->{'SYS'}{'TitPortal'};

	# Parameter handling
	$param    = new Ethereal::Param($database, $cgi);
	$param->GetParam();

	# Link with hash
	$database->GetHashPortal(\%portal);

	# Create instances
	$tmpl  = new Ethereal::Template(\%portal);
	$menu  = new Ethereal::Menu($database, $param);

	# Pull script name
	$scriptname = $cgi->url(-relative=>1);


	# Round about way
	if ((length($scriptname) < 2)
	 || ($scriptname =~ /\.(shtml|html)$/i))
	{
		# Assume this is not a real script name
		# Get name and only end
		$scriptname = $0;
		$scriptname =~ s/.*\/(.*)$/$1/gs;
	}

	# Regular operation
	unless ($scriptname =~ /^static/si)
	{
		# Login and template instance
		$login = new Ethereal::Login($database, $cgi, $param, $menu);

		# Authenthication
		if ($login->GetVerificationPortal())
		{
			# Quick launch
			if ($scriptname =~ /^go/si)
			{
				# Pull script name
				$scriptname = $cgi->url(-full=>1);
				$scriptpara = $cgi->url(-path_info=>1);

				# Determine need
				# Escape
				$scriptname = quotemeta($scriptname);

				# Truncate
				$scriptpara =~ s/^$scriptname\///;
				$scriptpara =~ s/\/$//;


				# Warp config
				# Need exists
				if (length($scriptpara) > 3)
				{
					# Unescape
					$scriptpara = $cgi->unescape($scriptpara);

					# Parameter assignment
					$param->{'ROOM'} = $scriptpara;
					$param->{'THIRDCHAPTER'} = 'True';
				}
			}


	
			# Otherwise open gateway
			if (defined($param->{'THIRDCHAPTER'}))
			{ 
				# Verification
				# Puppet is defined?
				($puppet) = $database->DataGetPuppetExistence($param->{'CHAR'}, $param->{'USER'});

				# Look for default
				($puppet) = $database->DataGetDefault($param->{'USER'})
				  unless (defined($puppet)); 


				# Gateway to realms
				if (defined($puppet))
				{
					# Safety first
					$param->{'CHAR'} = $puppet;

					# List realm splash and weather
					ThirdChapter($database, $cgi, $param, $tmpl, $menu, \%portal); 
				}

				else
				{
					# Cleanup
					$param->Cleanup('THIRDCHAPTER');

					# List realms, puppets and links
					SecondChapter($database, $cgi, $param, $tmpl, $menu, \%portal);
				}
			}

			# Portal is default
			else
			{
				# List realms, puppets and links
				SecondChapter($database, $cgi, $param, $tmpl, $menu, \%portal);
			}
		}
	}

	# Static/Non Interactive/SSI handler
	else
	{
		# Pointless but needed
		print $cgi->header();

		# Call for operation
		DescriptionStatic($database, $cgi, $tmpl, \%portal);
	}

################################################################################
# Sub-Routines
################################################################################

#####################
# Collect Forum
#
# Will generate a list of all system forums and the amount of entires within
# as to guide people and generate interest.

sub CollectForum
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# CGI handle
	my $param    = shift;					# Parameters
	my $tmpl     = shift;					# Template handler
	my $portal   = shift;					# Portal hash
	my $js       = shift;					# Javascript code

	my $statement;						# Database statement
	my $res;						# Results
	
	my $count;						# Proper entries
	my $link;						# Bio link
	my $line;						# Generated line

	#####################
	# Program area
	
	# Initiate line
	$line = '';
	
	# Generate only if necessary
	if ($database->{'SYS'}{'SetPortalForum'} =~ /^1/)
	{
		# Prepare query
		$database->Pull(\$statement, "SELECT
			  t.BoardTopic        AS \"Topic\",
			  b.BoardTopic        AS \"Check\",
  			  COUNT(*)            AS \"Posts\"
			FROM Board b
			RIGHT OUTER JOIN BoardTopic t
			   ON (t.RealmName=b.RealmName AND t.BoardTopic=b.BoardTopic)
			WHERE t.RealmName='system'
			GROUP BY t.BoardTopic, b.boardTopic
			ORDER BY b.BoardTopic");

		# Run through and execute
		while ($res = $statement->fetchrow_hashref())
		{
			# Get count
			$count = (defined($res->{'Check'}))
			  ? $res->{'Posts'}
			  : 0;
			
			# Generate Inline
			$link = $param->EmbedInline(
				USER  => $param->{'USER'},
				CRYPT => $param->{'CRYPT'},
				ROOM  => 'system',
				TOPIC => $res->{'Topic'}
			 );

			# Append to line
			$line = $line . $tmpl->Pass('TmplForumItem',
				MTOPIC => $res->{'Topic'},
				MPOSTS => $count,
				LTOPIC => $database->{'SYS'}{'LnkIntForum'} . $link,
				LJSTGT => $js
			 );
		}
	
		# Finish query
		$statement->finish();
	}

	# Return value
	return $line;
}

#####################
# Collect News
#
# Will generate a list of the last three news items to catch more attention
# from those that are entering exclusively through the portal.

sub CollectNews
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# CGI handle
	my $param    = shift;					# Parameters
	my $tmpl     = shift;					# Template handler
	my $portal   = shift;					# Portal hash

	my $statement;						# Database statement
	my $res;						# Results
	
	my $bio;						# Bio link
	my $post;						# Post link
	my $topc;						# Topic link

	my $line;						# Current line
	my $order;						# order sequence


	#####################
	# Program area
	
	
	# Only generate if required
	if ($database->{'SYS'}{'SetPortalNews'} =~ /^1/)
	{
		# Safety
		$order = ($database->{'SYS'}{'SetPortalNewsItems'} =~ /^\d$/) ? $database->{'SYS'}{'SetPortalNewsItems'} : 0;

		# Adjust query
		$order = ($order > 0)
		  ? "ORDER BY LogIDNumber DESC LIMIT $order"
		  : "HAVING getNew(LogTimestamp) > 0 ORDER BY LogIDNumber DESC";
		
		# Prepare query
		$database->Pull(\$statement, "SELECT
			  LogIDNumber AS \"LogIDNumber\",
			  PuppetName  AS \"PuppetName\",
			  LogTitle    AS \"LogTitle\",
			  LogTopic    AS \"LogTopic\",
			  LogPost     AS \"LogPost\",
			  getDate(LogTimestamp) AS \"LogTimestamp\"
			FROM Weblog
		        GROUP BY LogIdNumber,
			  PuppetName,
		  	  LogTitle,
			  LogTopic,
			  LogPost,
			  LogTimeStamp
			$order");

		# Check for entries
		if ($res = $statement->fetchrow_hashref())
		{
			# Initiate line
			$line = '';

			# Pull all entries
			do
			{
				# Biographical link
				$bio  = $database->{'SYS'}{'LnkIntBio'}  . $param->Crypt(BCHAR => $res->{'PuppetName'}, BPOOL => 'system');
				$post = $database->{'SYS'}{'LnkIntNews'} . $param->Crypt(WID   => $res->{'LogIDNumber'});
				$topc = $database->{'SYS'}{'LnkIntNews'} . $param->Crypt(FIL   => uc($res->{'LogTopic'}));


				# Generate line
				$line .= $tmpl->Pass('TmplNewsItem',
					MLOGID => $res->{'LogIDNumber'},
					MNAME  => $res->{'PuppetName'},
			 		MTITLE => $res->{'LogTitle'},
					MTOPIC => uc($res->{'LogTopic'}),
					MDATE  => $res->{'LogTimestamp'},
					LBIO   => $bio,
					LPOST  => $post,
					LTOPC  => $topc
				 );
			}
			while ($res = $statement->fetchrow_hashref());
		}

		# Display no news attribute
		else
		{
			# Nothing to see here
			$line = $portal->{'TagNewsNIL'};
		}

		# Finish query
		$statement->finish();
	}

	# Return value
	return $line;
}


#####################
# Collect Puppets
#
# Will generate the lists for both puppets and change behaviour
# based on what has been pulled if the need for a widget is desired over
# a list based format.

sub CollectPuppets
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# CGI handle
	my $param    = shift;					# Parameters
	my $tmpl     = shift;					# Template handler
	my $portal   = shift;					# Portal hash
	my $def      = shift;					# Default puppet

	my $line;						# Current line
	my $puppet;						# Singular puppet
	my $widget;						# Generated widget

	my @puppets;						# List of puppets


	#####################
	# Program area

	# Safety catch
	if (defined($def))
	{
		# Fetch list of puppets for system
		$database->GroupList(\@puppets, 'restricted', $param->{'USER'}, 'system');


		# Formatting of options
		# Normal behaviour
		unless (defined($database->{'DEFAULT'}))
		{
			# Legacy generation
			if ($database->{'SYS'}{'SetPortalPuppet'} =~ /^0/)
			{
				# Generate legacy widget
				$line = $cgi->scrolling_list(
				  -name    => 'CHAR',
				  -values  => \@puppets,
				  -default => $def,
				  -size    => 10,
				  -class   => 'CHAR'
				 );
			}

			# Popup widget
			elsif ($database->{'SYS'}{'SetPortalPuppet'} =~ /^1/)
			{
				# Generate legacy widget
				$line = $cgi->popup_menu(
				  -name    => 'CHAR',
				  -values  => \@puppets,
				  -default => $def,
				  -class   => 'CHAR'
				 );
			}

			# List formatting
			else
			{
				# Initial formatting
				$line = '';
			
				# Loop and handle appropriatly
				foreach $puppet (@puppets)
				{
					# Nothing to do
					next if ($puppet eq '');
	
					# Title
					if ($puppet =~ /^--.+--$/)
					{
						# Insert title widget
						$line = $line . $tmpl->Pass('TmplPuppetTitle',
							MNAME => $puppet
						 );
					}
	
					# Handle names
					else
					{
						# generate widget
						$widget = ($puppet eq $def)
							? "<INPUT TYPE=\"radio\" NAME=\"CHAR\" VALUE=\"$puppet\" CHECKED \/>"
							: "<INPUT TYPE=\"radio\" NAME=\"CHAR\" VALUE=\"$puppet\" \/>";
					
						# Create line
						$line = $line . $tmpl->Pass('TmplPuppetItem',
							MNAME => $puppet,
							WSLCT => $widget
						 );
					}
				}
			}
		}

		# Lock-down mode
		else
		{
			# Pretty straight and simple
			$line = $cgi->hidden('CHAR', $database->{'DEFAULT'});
		}
	}

	# Ensure definition
	$line = (defined($line))
	  ? $line
	  : '';

	# Return value
	return $line;
}


#####################
# Collect Realms
#
# Will generate the lists for both realms and change behaviour
# based on what has been pulled if the need for a widget is desired over
# a list based format.

sub CollectRealms
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# CGI handle
	my $param    = shift;					# Parameters
	my $tmpl     = shift;					# Template handler
	my $portal   = shift;					# Portal hash
	my $def      = shift;					# Default realms

	my $statement;						# Database statement
	my $res;						# Database results
	my $who;						# Who is on handle
	
	my $check;						# Vefification check
	my $confirmed;						# Realm is in fact valid
	my $default;						# True default realm

	my $display;						# Display attributes
	my $line;						# Current line
	my $mangle;						# Mangled name

	my @realms;						# Realm public list
	my @ver;						# Verified realms

	my %realms;						# Hash of realms


	#####################
	# Program area

	# Create instance
	$who    = new Ethereal::Who($database, $cgi, undef, $param);

	# List of all publis crealms
	$database->GetListPublicRealms(\@realms);	

	# Verified realms
	if ($database->{'USR'}{'Verified'} eq 'yes')
	{
		# Pull list
		$database->GetListVerifiedRealms(\@ver);

		# Consolidate, consolidate, consolidate
		@realms = sort(@realms, @ver);
	}

	
	# Final mangling
	$mangle = $who->Portal($def, \@realms, \%realms);


	# Legacy widget formatting
	# Widget Formatting
	if (($database->{'SYS'}{'SetPortalRealm'} =~ /^0/)
	 || ($database->{'USR'}{'Javascript'} ne 'yes')
 	 || ($database->{'USR'}{'Legacy'} eq 'legacy'))
	{
		# Javascript aware
		if ($database->{'USR'}{'Javascript'} eq 'yes')
		{
			# Generate widget
			$line = $cgi->scrolling_list(
			  -name     => 'ROOM',
			  -values   => \@realms,
			  -default  => $mangle,
			  -size     => 10,
			  -class    => 'ROOM',
			  -onchange => 'showList()'
			 );

			# Display attributes
			$display = $portal->{'TmplRealmDescription'}; 
		}

		# Ignorant of javascript
		# To avoid any error messages
		else
		{
			# Generate widget
			$line = $cgi->scrolling_list(
			  -name     => 'ROOM',
			  -values   => \@realms,
			  -default  => $mangle,
			  -size     => 10,
			  -class    => 'ROOM'
			 );

			# Display attributes
			$display = '';
		}
	}

	# List formatting
	else
	{
		# Additional vars
		my $count;					# Counter
		my $forum;					# Forum handling
		my $homepage;					# Homepage icon
		my $pers;					# Personnel
		my $verified;					# Verified realm

		my $escaped;					# Proper escaped code
		my $cssid;					# CSS id identigier

		my $jslnko;					# Javascript link open
		my $jslnkc;					# Javascript link close
		my $jshidden;					# Hidden field

		my $modern;					# Modern widget
		my $original;					# Original widget
		my $rows;					# Rows entry
		
		my $inline;					# Inline parameters


		# Generate inline
		$inline = $param->EmbedInline(
			USER  => $param->{'USER'},
			CRYPT => $param->{'CRYPT'},
		 );


		# Javascript link
		$jslnkc = '</SPAN>';

		# Initial formatting
		$modern = '';

		# Additional check on display
		$check = ($database->{'USR'}{'Verified'} eq 'yes')
		  ? "OR RealmVerified=\'yes\' "
		  : "";

		# Cycle through realms
		# Prepare and execute
		$database->Pull(\$statement, "SELECT
			 RealmName        AS \"RealmName\",
			 RealmRating      AS \"RealmRating\",
			 RealmGenre       AS \"RealmGenre\",
			 RealmHomepage    AS \"RealmHomepage\",
			 RealmVerified    AS \"RealmVerified\"
			FROM Realm
			WHERE RealmPublic=\'yes\' $check
			ORDER BY RealmName");

		# Initialize
		$count = 0;
		
		# Loop and generate lines
		while ($res = $statement->fetchrow_hashref())
		{
			# Set the true default
			$default = $res->{'RealmName'} if ($count == 0);
				
			# Is default realm valid
			$confirmed = '0' if ($res->{'RealmName'} eq $def);
				
				
			# Define variable macros
			# Verified realms
			$verified = ($res->{'RealmVerified'} eq 'yes')
		       	  ? $portal->{'TagRealmVerified'}
			  : $portal->{'TagRealmPublic'}; 
				
			# Personnel correction
			$pers = (defined($realms{$res->{'RealmName'}}))
		       	  ? $realms{$res->{'RealmName'}} 
			  : 0;

			# Homepage available
			$homepage = ($res->{'RealmHomepage'} =~ /^http:\/\/.+/i)
		       	  ? $tmpl->Pass('TagRealmHomeExists', MLINK=>$res->{'RealmHomepage'})
			  : $portal->{'TagRealmHomeMissing'};

			# Forum
			$forum    = $tmpl->Pass('TagRealmForum', MLINK=>$database->{'SYS'}{'LnkIntBoard'} . $inline . '&ROOM=' . $cgi->escape($res->{'RealmName'}));


			# Handling of javascript
			$escaped =  $res->{'RealmName'};
			$escaped =~ s/'/\\'/gs;

			# Handling of CSS identifier
			$cssid   =  $res->{'RealmName'};
			$cssid   =~ s/\W//gs;
			$cssid   = "ID=\"$cssid\" CLASS=\"UNSELECT\""; 


			# Javascript handling
			$jslnko   =  "\<SPAN CLASS=\"ROOMS\" ONCLICK=\"updateContent('$escaped'); return false;\" ONMOUSEOVER=\"window.status=\'Select $escaped\'; return true;\" ONMOUSEOUT=\"window.status=\'\';\"\>\n";
				
			# Search and replace
			$rows = $tmpl->Pass('TmplRealmItem',
				CSSID => $cssid,
				JLNKO => $jslnko,
				JLNKC => $jslnkc,
				MGENR => $res->{'RealmGenre'},
				MNAME => $res->{'RealmName'},
				MRATE => $res->{'RealmRating'},
				MHOME => $homepage,
				MFORM => $forum, 
				MVERI => $verified,
				MPERS => $pers
			 );

			# Adjust rows
			$rows =~ s/(\n|\r)//gs;
			$rows =~ s/\s{2,}//gs;
			$rows =~ s/'/\\'/gs;

			# Maintain escape beyond application
			$rows =~ s/\\\\/\\\\\\/gs; 

			# Fix row
			$modern .= $tmpl->Pass('TmplRealmSelect',
			      MNAME => $res->{'RealmName'},
		      	      MROWS => $rows
			 );	      
				
			# Increment
			$count++;
		}

		# Finish statement
		$statement->finish();


		# Generate hidden field
		$jshidden = (defined($confirmed))
		  ? $cgi->hidden('ROOM', $def)
		  : $cgi->hidden('ROOM', $default);

		# Generate fallback original widget
		$original = $cgi->scrolling_list(
		  -name     => 'ROOM',
		  -values   => \@realms,
		  -default  => $mangle,
		  -size     => 10,
		  -class    => 'ROOM'
		 );

		# Generate final template
		$line = $tmpl->Pass('TmplRealmModern',
			LSTMODERN   => $modern,
			LSTORIGINAL => $original,
			WHIDDEN     => $jshidden
		 );

		# Display attributes
		$display = $portal->{'TmplRealmDescription'}
	}

	# Ensure definition
	$line = (defined($line)) ? $line : '';

	# Return line
	return $line, $display;
}


	
#####################
# Description Handler
#
# If javascript is enabled, this function will be called.   Once that is done
# the necessary components will be filled in as to allow for use of the 
# javascript descriptions.

sub DescriptionHandler
{
	#####################
	# Data members
	my $database = shift;					# Database handle

	my $descr;						# Description

	#####################
	# Program Area

	# Only if necessary
	if (($database->{'USR'}{'Javascript'} == 'yes')
	 && ($database->{'SYS'}{'SetPortalDescripion'} !~ /~0/))
	{
		#####################
		# Local data members
		my $res;					# Query results
		my $statement;					# Query statements

		my $macro ='';					# Generate macro replacement


		# Retreive results
		# Description
		$descr = $database->DocumentGetDescription();


		# Realms and descriptions
		$database->Pull(\$statement, "SELECT
			 RealmName        AS \"RealmName\",
			 RealmDescription AS \"RealmDescription\",
			 RealmGenre       AS \"RealmGenre\",
			 RealmRating      AS \"RealmRating\"
			FROM Realm
			WHERE (RealmPublic='yes'
			   OR RealmVerified='yes')
			  AND RealmDescription IS NOT NULL");


		# Loop and generate
		while ($res = $statement->fetchrow_hashref())
		{
			# Append to macro
			$macro = "$macro\tcase \"$res->{RealmName}\":\n\t" 
			 . " mes='$res->{RealmDescription}'\;\n\t"
			 . " rat='$res->{RealmRating}'\;\n\t"
			 . " gre='$res->{RealmGenre}'\;\n\t"
			 . " break\;\n";
		}


		# Complete query
		$statement->finish();

		
		# Replace macro
		$descr =~ s/MDESCRCASE/$macro/gs;
	}

	# Returns value for use
	return $descr;
}


#####################
# Description Static
#
# A variant of the above with purpose of displaying this to mostly
# static pages.  Meaning being used in Server Side Includes (SSI)
# et cetera.

sub DescriptionStatic
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# Common Gateway Interface
	my $tmpl     = shift;					# Template handler
	my $portal   = shift;					# Portal handler

	my $res;						# Query results
	my $statement;						# Query statements

	my $board;						# Message board link
	my $escape;						# Escaped title
	my $genre;						# Current genre
	my $title;						# Displayed title
	my $url;						# Quick access link

	my $line;						# Captured lines
	my $links;						# Generated links

	my @genres;						# List of genres


	#####################
	# Program Area

	# Realm specific
	# Retreive results
	# Realms and descriptions
	$database->Pull(\$statement, "SELECT
		 RealmName         AS \"RealmName\",
		 RealmHomepage     AS \"RealmHomepage\",
		 RealmDescription  AS \"RealmDescription\",
		 RealmGenre        AS \"RealmGenre\",
		 RealmRating       AS \"RealmRating\"
		FROM Realm
		WHERE RealmPublic <> 'no'
		  AND RealmDescription IS NOT NULL
		  AND RealmHomepage IS NOT NULL
		ORDER BY RealmGenre, RealmName");


	# Initial check
	if ($res = $statement->fetchrow_hashref())
	{
		# Initialize
		$line = '';

		# Loop through
		do
		{
			# Genre Handling
			if ((!defined($genre))
			 || ($res->{'RealmGenre'} ne $genre))
			{
				# Assign and Escape
				$genre  = $res->{'RealmGenre'};
				$escape = $cgi->escape($res->{'RealmGenre'});
	
				# Title
				$line .= $tmpl->Pass('TmplStaticGenre',
					MTITLE  => $genre,
					MANCHOR => "NAME=\"$escape\""
				 );

				# Throw onto end of array
				push(@genres, $res->{'RealmGenre'});
			}

			# Generate link
			$url   = $database->{'SYS'}{'LnkExtRealm'} . '/' . $cgi->escape($res->{'RealmName'});
			$board = $database->{'SYS'}{'LnkIntBoard'} . '/' . $cgi->escape($res->{'RealmName'});


			# Information and spacer
			$line .= $tmpl->Pass('TmplStaticListing',
			  MBOARD  => $board,
			  MDESCR  => $res->{'RealmDescription'},
			  MHOME   => $res->{'RealmHomepage'},
			  MLINK   => $url,
		 	  MRATING => $res->{'RealmRating'},
		 	  MTITLE  => $res->{'RealmName'}
			);

		# Until condition is reached
		} while ($res = $statement->fetchrow_hashref());


		# Generate nav links
		$links = QuickLink($cgi, $tmpl, \@genres);


		# Display final template
		$tmpl->Show('TmplStatic',
			LSTREALMS => $line,
			LSTLINKS  => $links
		 );
	}
}


#####################
# Quick Link
#
# Dirt simple and is used simply to clean up the static pages list of elements
# allowing for quick navigation.

sub QuickLink
{
	#####################
	# Data members
	my $cgi     = shift;					# CGI handle
	my $tmpl    = shift;					# Template handle
	my $array   = shift;					# Referenced array
	my $exclude = shift;					# Exclusion

	my $escape;						# Escaped name
	my $genre;						# Genre
	my $line;						# Generated line


	#####################
	# Program area

	# Initialize
	$line = '';
	
	# Loop and display
	foreach $genre (@{$array})
	{
		unless ((defined($exclude))
		 && ($genre eq $exclude))
		{
			# Escape link
			$escape = $cgi->escape($genre);

			# Simply display from a format
			$line .= $tmpl->Pass('TagLnkGen',
			     	MTITLE => $genre,
				MLINK  => "HREF=\"\#$escape\""
			 );
		}
	}

	# Return
	return $line;
}



#####################
# Second Chapter
#
# Unusual name given to a part of the script that will be exected once the user
# has been authenthicated.   

sub SecondChapter
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# CGI handle
	my $param    = shift;					# Parameter list
	my $tmpl     = shift;					# Template handler
	my $menu     = shift;					# Menu handler
	my $portal   = shift;					# Portal hash

	my $rotate;						# Code rotation

	my $def_pup;						# Default puppet
	my $def_realm;						# Default realm
	my $expire;						# Access expired
	my $key;						# Singular key
	my $mail;						# Mail count
	my $news;						# News entries
	my $new;						# Newness factor
	my $template;						# Actual template
	my $unread;						# Unread mail

	my $jscode;						# Javascript code

	my %keys;						# Generated keys

	#####################
	# Program area

	# Create instances
	$rotate = new Ethereal::Rotate(DB=>$database, ZONE=>'portal');


	# Javascript Options
	$keys{'GENJSCODE'} = ($database->{'USR'}{'Javascript'} ne 'no')
	  ? "ONCLICK='window.open(this.href,this.target,settings); return false'"
	  : '';


	# Retreive puppet default
	($def_pup, $def_realm) = $database->DataGetDefault($param->{'USER'}); 

	# Retreive numbers
	($mail)   = $database->DataGetPuppeteerMailCount($param->{'USER'});
	($unread) = $database->DataGetPuppeteerMailNew($param->{'USER'});
	($news, $new) = $database->DataGetWeblogEntries();

	# Expiry
	($expire) = $database->DataGetPuppeteerExpire($param->{'USER'});


	# Error message display
	$keys{'MERRMSG'}    = (defined($param->{'RMESS'}))
	  ? $tmpl->Pass('TagRealmError', MNAME=>$param->{'RMESS'}) . "\n"
	  : '';
	

	# Widget Generation
	# Offline capabilities
	$keys{'WROFFLINE'}  = $cgi->checkbox(-name=>'OFFLINE', -label=>'');
	

	# Set general macros
	# Counters
	$keys{'MMAILCOUNT'}  = $mail;
	$keys{'MMAILUNREAD'} = $unread;
	$keys{'MNEWSCOUNT'}  = $news;

	# Format and seting of recent
	$keys{'MNEWSRECENT'} = ($new != 0) ? $portal->{'TagNewness'} : '';

	# Possibly display Javascript
	$keys{'MJAVASCRIPT'} = ($database->{'USR'}{'Javascript'} eq 'yes')
	  ? $database->DocumentGetJavascript()
	  : ''; 
	
	# Create private realm
	$keys{'WPRIVREALM'}  = $cgi->textfield(
		-name      => 'ALTROOM', 
		-default   => '', 
		-size      => 20,
	        -maxlength => 30,
		-class     => 'ALTROOM');

	# Submit widget
	$keys{'WSUBMIT'}     = $cgi->submit(
		-name      => $portal->{'TxtSubmitRealms'},
	        -class     => 'WSUBMIT');

	# Create inline link
	$keys{'GENPARAM'}    = $param->EmbedInline(
		USER  => $param->{'USER'},
		CRYPT => $param->{'CRYPT'}
	 );


	# Lists
	# Listing of all realms
	($keys{'LSTREALMS'}, 
	 $keys{'MDISPLAY'}) = CollectRealms($database, $cgi, $param, $tmpl, $portal, $def_realm);

	# Listing of all puppets
	$keys{'LSTPUPPETS'}  = CollectPuppets($database, $cgi, $param, $tmpl, $portal, $def_pup);

	# Listing of all news entries
	$keys{'LSTNEWS'}     = CollectNews($database, $cgi, $param, $tmpl, $portal);

	# Listing for all forum pieces
	$keys{'LSTFORUM'}    = CollectForum($database, $cgi, $param, $tmpl, $portal, $keys{'GENJSCODE'});


	# Rotated section
	$keys{'MROTSECT'} = $rotate->Pull();


	# Start form
	$keys{'FRMOPEN'} = $cgi->start_form(-NAME=>'PORTAL') . $param->EmbedNormal($param->Flat(), THIRDCHAPTER=>'True'), "\n";

	# Close form
	$keys{'FRMCLOSE'} = $cgi->end_form(), "\n";

	
	# Fetch template
	($template) = $database->DocumentGetPortal();
	

	# Generation
	# Show descriptions
	$keys{'MDESCRIPTION'} = DescriptionHandler($database);


	# Run through keys
	foreach $key (keys(%keys))
	{
		# Replace every occurence
		$template =~ s/$key/$keys{$key}/gs;
	}

	# Final display
	print $menu->Rewrite($template, $keys{'GENPARAM'}), "\n";
}


#####################
# Third Chapter
#
# Unusual name given to a part of the script that will be exected once the user  
# in his infinit wisdom has selected a puppet and realm

sub ThirdChapter
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# CGI handle
	my $param    = shift;					# Parameter list
	my $tmpl     = shift;					# Template handler
	my $menu     = shift;					# Menu handler
	my $portal   = shift;					# Portal hash

	my $who;						# Who is on handle
	my $rtmpl;						# Realm template

	my $enter;						# Entrance button
	my $info;						# Room information
	my $list;						# List of people
	my $meteo;						# Forecasting
	my $warn;						# Warning users about the mode

	my $splash;						# Splash page for release

	my $access;						# Access control
	my $alias;						# Room alias
	my $room;						# Room name
	my $pub;						# Public status
	my $rand;						# Random password
	my $search;						# Room to search from
	my $status;						# Room status
	my $ver;						# Verified requirement

	my %realm;						# Realm hash

	#####################
	# Program area

	# Cleanup
	$param->Cleanup('THIRDCHAPTER');



	# Determine need to create a room
	if ((defined($param->{'ALTROOM'}))
	 && (length($param->{'ALTROOM'}) > 2))
	{
		# Existence of password
		if ($param->{'ALTROOM'} =~ /@/)
		{
			# Seperate into password and realm
			($param->{'RPASS'}, $param->{'ALTROOM'}) = split(/@/, $param->{'ALTROOM'});

			# Meets length requirements
			$param->{'ROOM'} = (length(($param->{'ALTROOM'})) > 2) ? $param->{'ALTROOM'} : $param->{'ROOM'};
		}

		# Default
		else
		{	
			# Assign ROOM
			$param->{'ROOM'} = $param->{'ALTROOM'};
		}

		# Retreive query information
		($room, $status, $alias) = $database->DataGetRealmExistence($param->{'ROOM'});


		# Create if not found
		unless (defined($room))
		{
			# Auditing instance
			my $audit = new Ethereal::Audit($database, $cgi, $param);


			# Handle realm password
			if ((defined($param->{'RPASS'})) 
			 && (length($param->{'RPASS'}) > 2))
			{
				# Generate password
				$rand  = md5_hex(rand());
				$rand  = substr($rand, 0, 14);

				# Generated encrypted password
				$param->{'RCRYPT'} = crypt($param->{'RPASS'}, $rand);

				# Cleanup
				$param->Cleanup('RPASS');
			}
			else
			{
				# Undefine parameter
				$param->{'RCRYPT'} = undef;
			}

			# Evaluate block
			eval
			{
				# Realm creation
				$database->Write("INSERT INTO Realm 
					(RealmName,
					 RealmPassword,
					 RealmImageHeight,
					 RealmImageWidth,
					 RealmImageSize)
					VALUES(?,?,0,0,0)", 

				 $param->{'ROOM'}, 
				 $param->{'RCRYPT'} 
				);

				# Board link
				$database->Write("INSERT INTO BoardTopic
					(RealmName,
					 BoardTopic)
					VALUES (?,?)",

				 $param->{'ROOM'},
				 $portal->{'TxtDefault'}
				);

				# Record addition
				$audit->UserRealm($param->{'ROOM'}, $param->{'ROOM'});


				# Commit changes
				$database->Commit();
			};

			# If block failed
			if ($@)
			{
				# Issue warning
				warn("Transaction aborted: $@");

				# Undo incomplete changes
				$database->Rollback();


				# Re-display portal
				SecondChapter($database, $cgi, $param, $tmpl, $portal);

			 	# Return
				return 0;	
			}
		}
		

		# Realm exists
		else
		{
			# Handle alias
			$room = ($status eq 'alias')  ? $alias : $room;

			# Consistent naming
			$param->{'ROOM'} = $room;
		}
	}

	# Remove number information
	$param->{'ROOM'} =~ s/ \(\d+\)$//s;


	# Access control
	($access) = $database->DataGetRealmAccess($param->{'ROOM'});


	# Ensure puppet is defined
	if (($access eq 'restricted')
	 or (!defined($param->{'CHAR'})))
	{
		# Retreive default puppet
		($param->{'CHAR'}) = $database->DataGetDefault($param->{'USER'}, $param->{'ROOM'}, $access);
	}



	# Realms particulars
	($pub, $ver) = $database->DataGetRealmPublic($param->{'ROOM'});



	# Update default realm
	if (($pub eq 'yes')
         || ($ver eq 'yes'))
	{

		# Update default realm if public or adult
		$database->Quick("UPDATE Puppeteer
			SET PuppeteerRealm=?
			WHERE PuppeteerLogin=?",

		 $param->{'ROOM'},
		 $param->{'USER'}
		);
	}

	# Populate hash
	$database->GetHashRealm(\%realm);

	# Splash template
	$search = ($realm{'SetSplash'} eq '1')
	  ? $param->{'ROOM'} : 'system';


	# Realms mode
	# Offline realms
	if (defined($param->{'OFFLINE'}))
	{

		
		# Offline splash page
		($info) = $database->FetchOfflineInfo($param->{'ROOM'});
		($warn) = $database->FetchOfflineWarning($param->{'ROOM'});


		# Generate entrance button
		# Start with form information
		$enter = $cgi->start_form(
			-method  => 'POST',
			-action  => $database->{'SYS'}{'LnkIntOffline'},
			-enctype => 'application/x-www-form-urlencoded'
		 );

		# Append embeded information
		$enter .= $param->EmbedNormal($param->Flat());

		# Append widget
		$enter .= $cgi->submit(
			-name   => $realm{'TxtRealmEnter'},
			-value  => $realm{'TxtRealmEnter'},
			-class  => 'ENTRANCE'
		 );

		# Form end
		$enter .= $cgi->end_form(), "\n";


		# Fetch template
		($splash) = $database->FetchOfflineSplash($search);


		# Search and replace
		$splash =~ s/MINFO/$info/gs;
		$splash =~ s/MROOM/$param->{'ROOM'}/gs;
		$splash =~ s/MWARN/$warn/gs;
		$splash =~ s/WENTER/$enter/gs;
	}

	# Standard active
	else
	{
		# who is on handles
		$rtmpl = new Ethereal::Template(\%realm);
		$who   = new Ethereal::Who($database, $cgi, $rtmpl, $param);

		# Pull in components
		# Pull realms splash
	   	($info) = $database->FetchRealmInfo($param->{'ROOM'});

		# List who is on and entrance button
		($list, $enter) = $who->WhoEntrance();

		# Potential warnings
		($warn) = ($access eq 'restricted')
		  ? $database->DocumentGetCanon()
		  : '';

		# Weather forcast
		($meteo) = WeatherHandler($database, $cgi, $param, $tmpl, $portal);
	

		# Fetch template
		($splash) = $database->FetchRealmSplash($search);


		# Search and replace
		$splash =~ s/LSTWHO/$list/gs;
		$splash =~ s/MINFO/$info/gs;
		$splash =~ s/MMETEO/$meteo/gs;
		$splash =~ s/MROOM/$param->{'ROOM'}/gs;
		$splash =~ s/MWARN/$warn/gs;
		$splash =~ s/WENTER/$enter/gs;
	}

	# Adapt title
	$database->{'TITLE'} = $param->{'ROOM'};

	# Display
	print $menu->Rewrite($splash);
}


#####################
# Weather Handler
#
# The weather heandler is realm specific for which is it not listed on the
# module directly.   This will essentially show off the specific weather 
# patterns for the realm if found

sub WeatherHandler
{
	#####################
	# Data members
	my $database = shift;					# Database handle
	my $cgi      = shift;					# CGI handle
	my $param    = shift;					# Parameter list
	my $tmpl     = shift;					# Template
	my $portal   = shift;					# Portal handle

	my $for;						# Forcast handle
	my $metar;						# Coded weather forcast
	my $meteo    = '';					# Template

	my $cond;						# Weather conditions
	my $key;						# Key to check against
	my $sky;						# Sky conditions

	my %cond;						# Specific conditions


	#####################
	# Program area

	# Retreive forcast
	($metar) = $database->DataGetWeather($param->{'ROOM'});
	

	# Only complete if forcast
	if (defined($metar))
	{
		# Initialize handle
		$for = new Ethereal::Weather();

		# Parse
		$for->Parse($metar, \%cond);


		# Forcast handling
		$sky  = lc(join(", ", @{$cond{SKY}}));
		$cond = lc(join(", ", @{$cond{HUMAN}}));		

		# Conditions
		$cond = (length($cond) > 2) ? ucfirst("$cond, $sky") : ucfirst("$sky");
		$cond =~ s/,([^,.]+?)$/ and $1/s;


		# Check values
		foreach $key (keys(%cond))
		{
			# Verify conditions
			$cond{$key} = (defined($cond{$key})) ? $cond{$key} : $portal->{'TxtUnavail'};
		}

		# Simply replace template
		$meteo =  $tmpl->Pass('TmplWeather',
			MFORECAST       => $cond,
			MWIND_DIR_ENG	=> $cond{'WIND_DIR_ENG'},
			MWIND_KPH	=> $cond{'WIND_KPH'},
			MWIND_MPH	=> $cond{'WIND_MPH'},
			MC_DEW		=> $cond{'C_DEW'},
			MF_DEW		=> $cond{'F_DEW'},
			MC_TEMP		=> $cond{'C_TEMP'},
			MF_TEMP		=> $cond{'F_TEMP'},
			MVIS_KILO	=> $cond{'VIS_KILO'},
			MVIS_MILE	=> $cond{'VIS_MILE'},
			MALTI		=> $cond{'ALTI'},
			MALTK		=> $cond{'ALTK'}
		 );
	}

	# Return completed template
	return $meteo;
}
