#!/usr/bin/perl --

# Location of config file
###### CHANGE THIS ######
$::configfile="album.cfg";
###### CHANGE THIS ######
# Make sure the config file is readable to the web server

# Program Version
$::ver="6.1";
######################## START OF SETUP ########################

# Show all script errors to the browser, for easier debugging
use CGI::Carp qw(fatalsToBrowser);

#use strict;
use CGI;

use POSIX qw(ceil floor);
use Cwd;

# Set debug level:
#	0 = None
#	1 = Special - Nothing has this code, so you can add a ,1 to any debug statement to make it stand out on it's own
#	2 = Standard - No recursive info or detailed file info. Usually just startup info.
#	3 = Detailed - Some recursive and detailed info.
#	4 = Overwhelming - Everything that ever had a debug turned on.
$::debug=0;

# Write output immediately
$|=1;

my $query=new CGI;
my $form=new CGI;

$::html_header=<<HTML;
Content-Type: text/html


<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
<html>
HTML

# Display Images direcly (for shrouding)
if ($form->param('image'))
{
	readConfig($::configfile);
	print shroudPic($form->param('image'));
	exit(0);
}

# Get browser cookie info
getCookie();

# Check to see if a configfile override was passed in
#if ($form->param('configfile'))
#{
#	$::configfile=$form->param('configfile');
#	$::configfilepassed=1;
#}

# Load this down into a variable, so we can modify it
$::function=$form->param('function');

debug("\$::function=$::function",2,__LINE__);

# Read configuration file settings
readConfig($::configfile);

# Was a debug value passed in from the web?
#if (!$::debug)
#{
#	$::debug=$form->param($::debug_code);
#}

# Print HTML Page Header when debugging
#if ($::debug)
#{
#	print $::html_header;
#}


### Some items that were removed from the config file are defined here now.
### zorz, hack for authentication
@albumuser = split(/\//, $::cgi_dir);

# Set to 1 to strip out comments from the final HTML. Saves bandwidth, but makes debugging a pain.
$::strip_comments=0;

# Name for the root album in the descriptions file. This allows the "root" album to be given a title and description.
$::rootalbumname="Root";

# Descriptions file delimiter. Used to separate description entries in $::descname.
$::desc_delim="~";

# Code used to initiate an update check
$::checkupdate="";

# Code used to display the user login screen. No need to change this.
$::login_code="login";

# Display the photo upload page, or the "uploads not allowed" page, as per your settings. No need to change this one, as it's not a threat - you *want* people to get to your upload page, right?
$::upload="upload";

# Code to display the rating form. No need to change this.
$::rating_form="rating_form";

# Set the size of the "enter description" box
$::enterdesc_rows=5;
$::enterdesc_cols=50;

# *** Temporary measure to fix usebuttons problem/bug
$::usebuttons=1;

# File path to photo icon
$::file_photo_icon="$::cgi_dir/$::img_dir/$::photo_icon";

# File path to movie icon
$::file_movie_icon="$::cgi_dir/$::img_dir/$::movie_icon";

# File path to album icon
$::file_album_icon="$::cgi_dir/$::img_dir/$::album_icon";

# Web delimiter - should be ; for standardization, but might have to be & on some systems
$::webdelim=";";

# Release "name" - not really used for anything, just wanted to add it
$::release="Mufti [3]";
# Next up: Palindrome, Arquebus

# Native Cookie field names
$::albumcookieusername="albumusername";
$::albumcookiepassword="albumpassword";

# Hide ratings in album view, if also hiding titles
if ($::descloc == 2)
{
	$::rating_location=0;
}

debug("Starting execution, debugging is on ($::debug)...",2,__LINE__);

# Pull off web vars for lcoal use
$::localconfig=$form->param('album');
$::photo_width=$form->param('photo_width');
$::photo_height=$form->param('photo_height');

# Pull off more web vars
$::searchstring=$form->param('searchstring');
$::searchfilenames=$form->param('searchfilenames');
$::searchdescriptions=$form->param('searchdescriptions');
$::searchcomments=$form->param('searchcomments');
$::searchowners=$form->param('searchowners');

if (!$::localconfig)
{
	$::localconfig=$form->param('photo');

	# Change all \'s to /'s
	$::localconfig=~s/\\/\//g;

	# Drop the filename
	$::localconfig=~s/(.*\/).*/$1/;
}

# Read localized configuration file settings for this album
readConfig("$::album_dir/$::localconfig/album.cfg",1);

# Use default_size (esp when told to), unless a size has been specified
if ($::photo_width || $::photo_height || $::photo_width eq -1 || $::photo_height eq -1)
{
	$::default_size=0;
}

# Set default photo size (small)
if ($::default_size == 1)
{
	$::photo_width=$::small_width;
	$::photo_height=$::small_height;
}

# Set default photo size (medium)
if ($::default_size == 2)
{
	$::photo_width=$::medium_width;
	$::photo_height=$::medium_height;
}

# Set default photo size (large)
if ($::default_size == 3)
{
	$::photo_width=$::large_width;
	$::photo_height=$::large_height;
}

# Dump contents of cookie
showCookie();

$::cwd=cwd;

debug("Home directory is $::cwd",3,__LINE__);

# Add full path to the stringtable, depending on if this is the first startup or not...
#if ($::newconfig eq "true")
#{
#	$::cgi_dir=$::cwd;
#}

$::stringtable="$::cgi_dir/$::stringtable";

debug("\$::stringtable is now $::stringtable",3,__LINE__);

# Check some basic stuff to make sure the environment is safe
sanityTest();

# Check for command-line parameter to set static mode
#if ($ARGV[0] eq "static")
#{
#	$::create_html_flag=10;
#}

# Check for command-line parameter to set debug mode
#if ($ARGV[0] eq "debug")
#{
#	$::debug=$ARGV[1];

	# If none passed as 2nd paramater, set debug level 4
#	if (!$::debug)
#	{
#		$::debug=4;
#	}
#}

# Was static mode passed from the web?
#if ($form->param('static'))
#{
#	$::create_html_flag=1;
#}

# $::create_html_flag has the following values:
# 0 - No static HTML
# 1 - Build static HTML for current album/photo only (called from the web)
# 2 - Build static HTML, don't display results using HTML (called from the command line)

# Explicitly turn off buttons, jump station and multi-paging if creating static HTML
if ($::create_html_flag)
{
	# *** Temporary action to remove icons, jump menu, buttons and legend for static html... (notify is OK)
	$::usebuttons=$::jump_to=$::icons=$::legend=$::notify=$::photos_per_page=0;
}

# Set up default admins with comma seperators at either end
$::default_admins=",$::default_admins,";

# Ditto for guests
$::default_guests=",$::default_guests,";

if (!$::authentication_type)
{
	$::protect_album=0;
}

# Show at least one upload field
if (!$::concurrent_uploads)
{
	$::concurrent_uploads=1;
}

# Don't constrain thumbnails if we're using Image Magick - create them!
if ($::imagemagick)
{
	$::constrain_thumbs=0;
}

# Load these down into a variable, so we can modify them
$::username=$form->param('username');
$::password=$form->param('password');
$::fullscreen=$form->param('fullscreen');
$::randompic=$form->param('random');
$::ssi=$form->param('ssi');
$::popular_flag=$form->param('popular');
#$::upute_flag=$form->param('upute');

debug("\$::popular_flag is set to: [$::popular_flag], to show $::most_popular max",4,__LINE__);

# If we're entering descriptions, turn off the slideshow!
if ($::function eq $::enter_desc)
{
	$::slide_timer=0;
	$::slide_timer_passed=1;
}

# Was a slideshow timer value passed in from the web?
if ($form->param('slideshow'))
{
	# Were we asked to turn off the slide show?
	if ($form->param('slideshow') eq -1 && $::fullscreen ne $::S{263})
	{
		$::slide_timer=$::fullscreen=0;
	}
	else
	{
		$::slide_timer=$form->param('slideshow');

		# Are we just turning the slideshow on?
		if ($form->param('oldslideshow'))
		{
			# Set timer when converting to fullscreen mode
			$::slide_timer=$form->param('oldslideshow');

			# Go fullscreen!
			$::temp="$::albumprog?full=1".passVars(0).$::webdelim."photo=".$form->param('photo').$::webdelim."photo_width=";

			printHTMLHeader();
			print <<HTML;
<script type="text/javascript" language="JavaScript">
<!--
windowprops = "top=0,left=0,resizable=no" + ",width=" + screen.width +
",height=" + screen.height + ",fullscreen=yes" + ",scrollbars=auto";
picwidth=screen.width-40;
window.open("$::temp"+picwidth, "popupPage", windowprops);
//-->
</script>
HTML
			# Change back
			$::slide_timer=$::fullscreen=0;
		}
	}

	# Set flag to keep the slide timer in the URL...
	$::slide_timer_passed=1;
}

# Load this down into a variable, so we can modify it
$::page=$form->param('page');

# Set default page
if (!$::page)
{
	$::page=1;
}

# Are we displaying the config screen?
#if ($::function eq $::config)
#{
#	printHTMLHeader();
#	$authenticated = Authenticate();

#	if ($authenticated == 1)
#	{
#		showConfig();
#	} else {
#		print "<script language=\"Javascript\">alert(\"Not authorized or wrong password!!! Please click login button at the main menu.\")</script>";
#	}
#}

# Are we actually updating the configuration?
#if ($::function eq $::updateconfig)
#{
#	printHTMLHeader();
#	updateConfig();
#}

# Add full path to template files
$::album_template="$::template_dir/$::album_template";
$::photo_template="$::template_dir/$::photo_template";
$::object_template="$::template_dir/$::object_template";
$::upload_template="$::template_dir/$::upload_template";
$::login_template="$::template_dir/$::login_template";
$::upute_template="$::template_dir/$::upute_template";

debug("\$::album_template is now $::album_template",4,__LINE__);
debug("\$::photo_template is now $::photo_template",4,__LINE__);
debug("\$::object_template is now $::object_template",4,__LINE__);
debug("\$::upload_template is now $::upload_template",4,__LINE__);
debug("\$::login_template is now $::login_template",4,__LINE__);

# Add full path to icon/button files
$::photo_icon="$::img_dir/$::photo_icon";
$::movie_icon="$::img_dir/$::movie_icon";
$::album_icon="images/$::album_icon";
$::album_folder_icon="$::img_dir/$::album_folder_icon";
$::login_button="$::img_dir/$::login_button";
$::home_button="$::img_dir/$::home_button";
$::search_button="$::img_dir/$::search_button";
$::random_button="$::img_dir/$::random_button";
$::upload_button="$::img_dir/$::upload_button";
$::recent_button="$::img_dir/$::recent_button";
$::rate_button="$::img_dir/$::rate_button";
$::email_button="$::img_dir/$::email_button";
$::small_button="$::img_dir/$::small_button";
$::medium_button="$::img_dir/$::medium_button";
$::large_button="$::img_dir/$::large_button";
$::fullsize_button="$::img_dir/$::fullsize_button";
$::fullscreen_button="$::img_dir/$::fullscreen_button";
$::edit_button="$::img_dir_new/$::edit_button";
$::delete_button="$::img_dir_new/$::delete_button";
$::move_button="$::img_dir_new/$::move_button";
$::config_button="$::img_dir/$::config_button";
$::create_button="$::img_dir/$::create_button";
$::titles_button="$::img_dir/$::titles_button";
$::updates_button="$::img_dir/$::updates_button";
$::adminupload_button="$::img_dir/$::adminupload_button";
$::thumb_button="$::img_dir/$::thumb_button";
$::popular_button="$::img_dir/$::popular_button";

# If album_web is not set, then we are performing image shrouding
if (!$::album_web)
{
	$::album_web=$::albumprog."?image=";
}

# Set recent upload tag to be used as the album
$::recent_upload_album=":recent";

# Are we creating an album?
if ($form->param('admincreate') && $form->param('album')!~/$::recent_upload_album$/)
{
	printHTMLHeader();

	# Actually create the album
	if ($form->param('albumname'))
	{
		
		if (createAlbum($form->param('album'),$form->param('albumname'),$form->param('title'),$form->param('description'),$::owner,1))
		{
			error(__LINE__,"upload_dir",$form->param('albumname'))
		}
		else
		{
			$::album=$::album_dir."/".$form->param('album')."/".$form->param('albumname');
			$::function="";
		}
	}
	else
	# Just display the form
	{
		$::shortdesc=$::S{49};
		display(buildTemplate());
		exit(0);
	}
}

# Check to see we're creating static HTML files
if ($::create_html_flag gt 1)
{

	$::static_time=time();

	# *** Copy CSS into root photo album and reference it from there
#	copy(x,"$::album_dir$::style_sheet");

	if ($::create_html_flag le 1)
	{
		print "<head><title>";
	}
	print "album.pl - ";
	print $::S{1};
	if ($::create_html_flag le 1)
	{
		print "</title>";
	}

	if ($::create_html_flag le 1)
	{
		$::object=printHeader();
		print <<HTML;
$::object
<h1>
HTML
	}
	print $::S{2};
	print "\n\n";
	if ($::create_html_flag le 1)
	{
		print "</h1><p>";
	}
	print $::S{3};
	print "\n\n";
	if ($::create_html_flag le 1)
	{
		print "<p>";
	}
	print $::S{4};
	print "\n\n";
	if ($::create_html_flag le 1)
	{
		print "<p>";
	}

	print $::S{5};
	print "\n\n";
	if ($::create_html_flag le 1)
	{
		print "<p>";
	}
	print "$::album_dir...\n";
	if ($::create_html_flag le 1)
	{
		print "<br>";
	}

	debug("Calling photoAlbum($::album_dir)",4,__LINE__);
	photoAlbum($::album_dir);
	debug("Back from photoAlbum($::album_dir) call",4,__LINE__);
	debug("Calling recursiveScan($::album_dir)",4,__LINE__);
	recursiveScan($::album_dir);
	debug("Back from recursiveScan($::album_dir) call",4,__LINE__);

	$::static_time_taken=time()-$::static_time;

	if ($::create_html_flag le 1)
	{
		print "<p>";
	}
	print $::S{6};
	print " $::static_photos_done ";
	print $::S{7};

	# Any movies?
	if ($::static_movies_done)
	{
		print " ";
		print $::S{8};
		print " $::static_movies_done ";
		print $::S{9};
	}

	# Add 1 to account for the root album
	$::static_albums_done++;

	print " ";
	print $::S{10};
	print " $::static_albums_done ";
	print $::S{11};
	print "\n";

	# Count thumbnails
	if ($::static_photos_thumb)
	{
		if ($::create_html_flag le 1)
		{
			print "<p>";
		}
		print "$::static_photos_thumb ";
		print $::S{12};
		print " ";
		print $::S{15};
		print "\n";
	}
	if ($::static_movies_thumb)
	{
		if ($::create_html_flag le 1)
		{
			print "<p>";
		}
		print "$::static_movies_thumb ";
		print $::S{13};
		print " ";
		print $::S{15};
		print "\n";
	}
	if ($::static_albums_thumb)
	{
		if ($::create_html_flag le 1)
		{
			print "<p>";
		}
		print "$::static_albums_thumb ";
		print $::S{14};
		print " ";
		print $::S{15};
		print "\n";
	}

	# Count descriptions
	if ($::totalphotodesc)
	{
		if ($::create_html_flag le 1)
		{
			print "<p>";
		}
		print "$::totalphotodesc ";
		print $::S{12};
		print " ";
		print $::S{205};
		print "\n";
	}
	if ($::totalmoviedesc)
	{
		if ($::create_html_flag le 1)
		{
			print "<p>";
		}
		print "$::totalmoviedesc ";
		print $::S{13};
		print " ";
		print $::S{205};
		print "\n";
	}
	if ($::totalalbumdesc)
	{
		if ($::create_html_flag le 1)
		{
			print "<p>";
		}
		print "$::totalalbumdesc ";
		print $::S{14};
		print " ";
		print $::S{205};

		# Average
		print "\n$::S{269} ".int($::static_photos_done/$::static_albums_done)." $::S{270}";

		print "\n\n";
	}
	if ($::create_html_flag le 1)
	{
		print "<p><p>";
	}
	print $::S{265};
	$::static_minutes=int($::static_time_taken/60);
	$::static_hours=int($::static_minutes/60);
	$::static_seconds=$::static_time_taken-($::static_minutes*60);
	$::static_minutes=$::static_minutes-($::static_hours*60);
	if ($::static_hours)
	{
		print " $::static_hours $::S{268}";
	}
	if ($::static_minutes)
	{
		print " $::static_minutes $::S{267}";
	}
	print " $::static_seconds $::S{266}\n";

}
else
{

	# Authenticate user
	$::authenticated=Authenticate();

	if (!$::debug)
	{
		printHTMLHeader();
	}

	# Clear manual override
	$::manual_override="";

	# Are we doing random pics?
	if ($::randompic)
	{
#		$::randompic=0;
		$::manual_override=randomizer();

		# SSI Random Pic
		if ($::ssi)
		{
			$::album=$::manual_override;
			$::album=~s/(.*)\/.*/$1/;
			display(showObject($::manual_override));
			exit(0);
		}
	}

	# Bypass login form for function=about
	if ($::function eq "about")
	{
		$::authenticated=1;
	}

	# Show Login Screen if not already logged in
	if ((($::album_password && !$::authenticated) && ($::password ne $::album_password)) || ($::protect_album && !$::authenticated))
	{
		debug("\$::function=$::login_code for one of the following reasons:",2,__LINE__);
		debug("\	1. \$::album_password required ($::album_password). (\$::password = $::password)",2,__LINE__);
		debug("\	2. \$::protect_album required ($::protect_album). (\$::authenticated = $::authenticated)",2,__LINE__);
		debug("\	3. Not logged in (\$::loggedin = $::loggedin)",2,__LINE__);
		$::function=$::login_code;

		# Manually reset the album to the root album, to avoid users passing in sub albums or photos
		$::manual_override=$::album_dir;
	}

	photoAlbum($::manual_override);
}

######################## END OF MAIN ########################

################### START OF SUBROUTINES ####################


##############################################################

=head3 photoAlbum()

 photoAlbum($manual_override);

 $manual_override - Start in this album or with this photo (optional)

Does the majority of the processing for the photo album

=cut

sub photoAlbum
{
my $manual_override=shift;

	debug("Entering subroutine: photoAlbum($manual_override)<p>",4,__LINE__);

	if ($manual_override)
	{
		debug("\$manual_override=$manual_override",2,__LINE__);
	}

	# Localize some vars
	{
	my $key;
	my @keys;
		# Read web environment variables
		@keys=keys %ENV;
		debug("---- BEGIN Web environment variables ----",3,__LINE__);
		foreach $key (@keys)
		{
			debug("$key: $ENV{$key}",3,__LINE__);
		}
		debug("---- END Web environment variables ----",3,__LINE__);
	}

	# Check to see if we're being called with function=$::upload
	if ($::function eq "$::upload")
	{
		$authenticated = Authenticate();

		if ($authenticated == 1) {
			uploadPhoto();
			exit(0);
		} else {
			print "<script language=\"Javascript\">var answer = confirm (\"Not authorized or wrong password!!! Please click login button at the main menu\")if (answer) window.location=\"http://www.yahoo.com/\"</script>";
		}
	}

	# Check to see if the user is updating a description
	if ($::function eq "$::update_desc")
	{
		updateDesc($form->param('object'),$form->param('desc_file_loc'),$form->param('title'),$form->param('description'),$form->param('owner'));
		if (!$form->param('advance.x'))
		{
			$manual_override=$form->param('photo2');
		}
	}

	# Check to see if the user is adding a rating
	if ($::function eq $::rating_form)
	{
	my $temp=$form->param('rating_file_loc');
		openDescfile("$::album_dir/$temp/");
		getDescription($form->param('object'));
		$::shortdesc="$::S{229} ".$::shortdesc;
		display(buildTemplate());
		exit(0);
	}

	# Check to see if the user is adding a rating
	if ($::function eq "$::update_rating")
	{
		if ($form->param('comments'))
		{
			$::object="$::S{203} ";
			if ($form->param('name'))
			{
				$::object.=$form->param('name');
			}
			else
			{
				$::object.="$::S{204}";
			}
			$::object.=": ".$form->param('comments');
		}

		updateRating($form->param('object'),$form->param('rating_file_loc'),$form->param('rating'),$::object);
	}

	# Have we been told to stop adding descriptions?
	if ($form->param('stop_add_desc') eq "stop")
	{
		$::function="";
	}

	# Translate into shorter variable names
	if ($form->param('album') && !$::album)
	{
		$::album=$::album_dir."/".$form->param('album');
		debug("\$::album has been set to $::album (from the web form var)",2,__LINE__);
	}

	if ($form->param('photo'))
	{
		$::photo=$form->param('photo');

		# Change all \'s to /'s
		$::photo=~s/\\/\//g;

		debug("\$::photo has been set to $::photo (from the web form var)",2,__LINE__);
	}

	if ($::album)
	{
		# Change all \'s to /'s
		$::album=~s/\\/\//g;
	}

	# Are we checking for updates?
#	if ($::function eq $::checkupdate)
#	{
#		checkUpdate();
#	}

	# Override album (for creating static HTML)
	if ($manual_override || $::create_html_flag)
	{
		debug("Manual Override is [$manual_override]",2,__LINE__);
		if (isAPhoto($manual_override))
		{
			$::photo=$manual_override;
			debug("Setting photo to [$::photo]",2,__LINE__);
			$::static_filename_to_use="$::full_directory.html";
			$::album="";
		}
		else
		{
			if (isAMovie($manual_override))
			{
				$::album=$manual_override;

				# Change all \'s to /'s
				$::album=~s/\\/\//g;

				$::album=~s/(.*)\/(.*)/$1/;

				$::album="$::album_dir/$::album";
			}
			else
			{
				$::album=$manual_override;
			}
			debug("Setting album to [$::album]",2,__LINE__);
			if ($::full_directory)
			{
				# For photo albums to be scanned
				$::static_filename_to_use="$::full_directory/$::static_html_filename";
			}
			else
			{
				# For root photo album
				$::static_filename_to_use="$::album_dir/$::static_html_filename";
			}
			$::photo="";
		}
	}

	# Is this the top level?
	if (!($::photo || $::album))
	{
		$::album="$::album_dir";
	}

	if ($::album)
	{
		$::middle=$::album;
	}

	if ($::photo)
	{
		$::middle=$::photo;
	}

	if ($::middle=~/^$::album_dir$/i)
	{
		$::middle="";
	}
	else
	{
		# Change all \'s to /'s
		$::middle=~s/\\/\//g;
		$::middle=~s/$::album_dir\/(.*)/$1/;
	}

	# Open static HTML file...
	if ($::create_html_flag)
	{
		# Open the static HTML file
		open(STATIC,">$::static_filename_to_use") || error(__LINE__,"not_writable","$::static_filename_to_use");
		debug("Creating static HTML file at [$::static_filename_to_use]",2,__LINE__);
	}

	debug("The album is: $::album",2,__LINE__);
	debug("The middle bit is: $::middle<p>",2,__LINE__);

	$::goback=$::middle;

	# Change all \'s to /'s
	$::goback=~s/\\/\//g;

	# Drop the filename
	$::goback=~s/(.*)\/.*/$1/;

	if ($::goback eq $::middle)
	{
		$::goback="";
	}

	# Keep a copy, so you don't have all the funny web stuff when you do a compare
	$::realgoback=$::goback;

	debug("GoBack: $::goback",2,__LINE__);

	if ($::photo)
	{
		$::descfile=$::album_dir."/";
		if ($::goback)
		{
			$::descfile.=$::goback."/";
		}
	}

	if ($::album)
	{
		#$::shortalbum=$::album_dir."/".$::album;
		$::shortalbum=$::album;
		if ($::realgoback)
		{
			$::shortalbum=~s/(.*\/).*/$1/;
		}
		else
		{
			$::shortalbum=$::album_dir;
		}
		$::shortalbum=$::shortalbum."/";

		debug("ShortAlbum: $::shortalbum<p>",2,__LINE__);

		# If you're updating descriptions, this is the file you want.
		$::desc_to_update="$::shortalbum";

		openDescfile($::shortalbum);

		if ($::album=~/^$::album_dir$/i)
		{
			$::shortalbum="$::rootalbumname";
		}
		else
		{
			if ($::realgoback)
			{
				$::shortalbum=$::middle;
				$::shortalbum=~s/(.*)$::realgoback\//$1/;
			}
			else
			{
				$::shortalbum=$::middle;
			}
		}

		debug("ShortAlbum: $::shortalbum<p>",2,__LINE__);

		$::shortobject=$::shortalbum;

		getDescription($::shortalbum);

		# Set album thumbnail
		if ($form->param('setthumb'))
		{
		use File::Copy;
		my $ext;
		my $temp2;
		my $temp;

			$::shortalbum=$form->param('album');
			$ext=$form->param('setthumb');

			$temp="$::album_dir/$::shortalbum/$ext";

			# Change all \'s to /'s
			$::shortalbum=~s/\\/\//g;

			# Pull out path
			$::shortalbum=~s/.*\/(.*)/$1/;

			$ext=~s/.*\.(.*)/$1/;

			$temp2="$::album_dir/".$form->param('album')."/../$::thumbprefix$::shortalbum.$ext";
			debug("Copying album thimbnail: $temp --> $temp2",2,__LINE__);

			# Make sure source thumb is readable, and that we are authorized to do this
			if (-r $temp && ($::function eq $::admin || (($::owner eq $::loggedin || $::default_admins=~/(.*,)*$::loggedin(,.*)*/) && $::loggedin)))
			{
				unlink($temp2);
				copy($temp,$temp2);
			}
		}


		# Keep count for static
		if ($::founddesc)
		{
			$::totalalbumdesc++;
		}

		close(DESC);

		# Set the description to pass as a default for editing
		$::existing_shortdesc=$::shortdesc;

		if (!$::shortdesc)
		{
			if ($::shortalbum eq $::rootalbumname)
			{
				$::shortdesc="$::S{87}";
			}
			else
			{
				$::shortdesc=$::shortalbum;
			}
		}

		$::descfile="$::album_dir/$::middle/";
	}

	# Select directory to read all entries from
	if ($::album)
	{
		$::dir_to_read="$::album_dir/$::goback";
	}

	# This is the spot that causes the bug.
	if (!$::usebuttons)
	{
	my $temp=passVars(0);
		if ($temp)
		{
			$::goback.="?".$temp;
		}
	}

	if ($::photo)
	{
		$::dir_to_read="$::descfile";
		$::shortphoto=$::photo;
		$::shortphoto=~s/^$::realgoback\/(.*)/$1/;
	}

	# Are we deleting an object? If so, confirm.
	if ($form->param('deleteobject'))
	{
		$::shortdesc=$::S{183};
		$::longdesc="";
		display(buildTemplate());
		exit(0);
	}

	# Have we confirmed the delete?
	if ($form->param('confirmdeleteobject') && $form->param('yes'))
	{
		debug("Calling deleteObject(confirmdeleteobject)",3,__LINE__);
		deleteObject($form->param('confirmdeleteobject'));
	}

	# Are we moving an object? If so, confirm.
	if ($form->param('moveobject'))
	{
		display(buildTemplate());
		exit(0);
	}

	# Have we confirmed the move?
	if ($form->param('confirmmoveobject') && $form->param('yes'))
	{
		debug("Calling moveObject(confirmmoveobject)",3,__LINE__);
		moveObject($form->param('confirmmoveobject'),0,$form->param('category'));
	}

	# Show Recent Uploads
	if ($form->param('album')=~/$::recent_upload_album$/)
	{
		$::album=$::recent_upload_album;
		display(buildTemplate());
		exit(0);
	}

	# Show search screen, or the search results
	if ($form->param('searchstart') || $::searchstring)
	{
		$::shortdesc=$::S{280};
		$::longdesc="";
		display(buildTemplate());
		exit(0);
	}


	# Show Most Popular screen
	if ($::popular_flag && $::most_popular)
	{
		$::shortdesc="$::most_popular $::S{271}";
		$::longdesc="";
		display(buildTemplate());
		exit(0);
	}

	# Find next and previous pictures/albums as appropriate
	debug("Looking for next and previous objects in [$::dir_to_read]...",2,__LINE__);

	@::file_list=readDirectory($::dir_to_read);

	debug("Done Directory Scan, comparing for $::shortphoto or $::shortalbum...",3,__LINE__);

	# clear re-used vars
	$::prev_obj_desc="";
	$::next_obj_desc="";

	$::next_obj="";

	# Prep the "jump station" for the footer
	if ($::jump_to && $::middle && $::album && $::contains_dir)
	{
		$::jump_station.="<form method=\"post\" action=\"$::albumprog\">\n";
		$::jump_station.=passVars(1);
		$::jump_station.=$::S{16};
		$::jump_station.=" <SELECT name=album>\n";
		# Save vars
		$::temp_shortdesc=$::shortdesc;
		$::temp_longdesc=$::longdesc;
		openDescfile($::desc_to_update);
	}

	@::file_list=sortObjects(1);

	my $this_is_it=0;

	foreach $::object (@::file_list)
	{
		my $justtemp;

		debug("Current object is [$::object]",4,__LINE__);
		if ($this_is_it)
		{
			$justtemp="$::album_dir/";
			if ($::goback)
			{
				$justtemp.="$::goback/";
			}
			$justtemp.=$::object;

			debug("Is this an album: $justtemp",4,__LINE__);
			debug("\$::photo: $::photo",4,__LINE__);
			debug("\$::album: $::album",4,__LINE__);

			# This is cheap... if $::goback="" then we get "$::album_dir//$::object" which works, but is not clean
	#		if (($::photo && isAPhoto($::object)) || ($::album && -d $justtemp))
			if (isAPhoto($::object) || -d $justtemp ||isAMovie($::object))
			{
				$::next_obj=$::object;
				debug("Setting \$::next_obj to $::next_obj...",3,__LINE__);
			}
		}
		$this_is_it=0;
		if (($::photo && ($::object eq $::shortphoto)) || ($::album && ($::object eq $::shortalbum)))
		{
			$::prev_obj=$::prev_object;
			$this_is_it=1;
			debug("Setting \$::prev_obj to $::prev_obj...",3,__LINE__);
		}
		$::prev_object=$::object;

		# Prep the "jump station" for the footer
		if ($::jump_to && $::middle && $::album && $::contains_dir && (-d "$::album_dir/$::goback/$::object"))
		{
			$::founddesc=0;
			getDescription($::object);
			$::jump_station.="<OPTION value=\"";
			if ($::goback)
			{
				$::jump_station.="$::goback/";
			}
			$::jump_station.="$::object\"";
			if ($::object eq $::shortalbum)
			{
				$::jump_station.=" SELECTED";
			}
			$::jump_station.=">";
			if ($::usedesc && $::shortdesc)
			{
				$::jump_station.="$::shortdesc";
			}
			else
			{
				$::jump_station.="$::object";
			}
			$::jump_station.="</OPTION>\n";
		}
	}

	# Prep the "jump station" for the footer
	if ($::jump_to && $::middle && $::album && $::contains_dir)
	{
		# Restore vars
		$::shortdesc=$::temp_shortdesc;
		$::longdesc=$::temp_longdesc;
		close(DESC);
		$::jump_station.="</SELECT> <input type=\"submit\" value=\"$::S{17}\" name=\"submit\" class=\"button\"></form>\n";
	}

	# Cache descriptions, to be restored later
	$::temp_shortdesc=$::shortdesc;
	$::temp_longdesc=$::longdesc;

	$::shortdesc=$::longdesc="";

	# strip off last album, to get descriptions for the current album, next album and previous album
	$::back_descfile=$::descfile;
	$::back_descfile=~s/(.*\/).*\/.*/$1/;

	if ($::album)
	{
		openDescfile($::back_descfile);
	}

	if ($::photo)
	{
		openDescfile($::descfile);
	}

	# Get description for the next object
	if ($::next_obj)
	{
		getDescription($::next_obj);
		if ($::founddesc)
		{
			$::next_obj_desc=$::shortdesc;
		}
	}

	# Get description for the previous object
	if ($::prev_obj)
	{
		getDescription($::prev_obj);
		if ($::founddesc)
		{
			$::prev_obj_desc=$::shortdesc;
		}
	}
	close(DESC);

	# Restore original descriptions
	$::shortdesc=$::temp_shortdesc;
	$::longdesc=$::temp_longdesc;

	debug("Next Object: $::next_obj [$::next_obj_desc]",3,__LINE__);
	debug("Previous Object: $::prev_obj [$::prev_obj_desc]",3,__LINE__);

	# clear array of photos, to save a lot of work later
	@::file_list="";

	if ($::album)
	{
		# Re-load the list of files from the current album directory
		@::file_list=readDirectory($::album);
		debug("Found objects in this album: @::file_list",3,__LINE__);
	}

	debug("Finished looking for next and previous objects...",2,__LINE__);

	# If the current object is an album, you have to go up one more
	if ($::album && ($::middle=~/\//))
	{
		$::back_descfile=~s/(.*\/).*\/.*/$1/;
	}

	# Get description of current object's album
	openDescfile($::back_descfile);
	$::temp_shortdesc=$::shortdesc;
	$::temp_longdesc=$::longdesc;
	$::shortdesc=$::longdesc="";
	if (!$::realgoback)
	{
		$::object=$::rootalbumname;
	}
	else
	{
		$::object=$::realgoback;
		if ($::object=~/\//)
		{
			$::object=~s/.*\/(.*)/$1/;
		}
	}
	getDescription($::object);
	$::back_desc=$::shortdesc;
	$::shortdesc=$::temp_shortdesc;
	$::longdesc=$::temp_longdesc;
	debug("Desc for object's parent album is: $::back_desc",4,__LINE__);
	close(DESC);

	# clear re-used vars
	$::prev_object="";

	# Remove any web variables, if present
	$::descfile=~s/(.*)\&.*/$1\//;

	openDescfile($::descfile);

	if ($::photo)
	{

		debug("ShortPhoto: $::shortphoto<p>",2,__LINE__);

		$::shortobject=$::shortphoto;

		$::shortdesc="";
		$::longdesc="";
		getDescription($::shortphoto);

		if (isAMovie($::shortphoto))
		{
			$::totalmoviedesc+=$::founddesc;
		}
		else
		{
			$::totalphotodesc+=$::founddesc;
		}

		# Set the description to pass as a default for editing
		$::existing_shortdesc=$::shortdesc;

		if (!$::shortdesc)
		{
			$::shortdesc=$::shortphoto;
		}

		# If you're updating descriptions, this is the file you want.
		$::desc_to_update="$::descfile";
	}

	debug("ShortObject: $::shortobject",2,__LINE__);

	# Make a "text" (not html) version of the long description
	$::textlongdesc=$::longdesc;
	$::textlongdesc=~s/<br \/>//g;
	$::textlongdesc=~s/<br>//g;
	$::textlongdesc=~s/\r//g;
	$::textlongdesc=~s/\n+$//g;

	# Build the "next photo" url
	if ($::create_html_flag)
	{
		$::next_photo_link="$::next_obj.html";
	}
	else
	{
		$::next_photo_link="$::albumprog?photo=$::realgoback/$::next_obj";
	}

	$::next_photo_link.=passVars(0);

	# Build navigation buttons/links
	$::nav_footer=buildNavFooter();

	# When a photo is displayed, it is in an HTML page, with a reference to the actual photo.
	# The short description is the photo's title, and the long description is displayed below it.
	# Description information is read out of $::descfile file, in the photo album.

	# Save off descriptions
	$::temp_shortdesc=$::shortdesc;
	$::temp_longdesc=$::longdesc;

	# Only build object if it's real.
	if (($::photo && -e "$::album_dir/$::photo") || ($::album && -e "$::album"))
	{
		$::actual_object=buildObject(0);
		$::actual_objecta=buildObject(1);
	}
	else
	{
		$::actual_object=$::S{294};
	}

	# Restoredescriptions
	$::shortdesc=$::temp_shortdesc;
	$::longdesc=$::temp_longdesc;

	$::template=buildTemplate();

	# Translate funny web chars like spaces --> %20 (not if static though)
	if (!$::create_html_flag)
	{
		$::template=parseLinks($::template);
	}

	debug("Object template is built! [$::template]",4,__LINE__);

	# Remove comments
	if ($::strip_comments)
	{
		$::template=~s/<!--([^>]|\n)*>//g;
	}

	display("$::template");

	# Scan for files and directories under the root directory. Each directory is considered an album.
	# Each photo file (.bmp, .gif or .jpg) is considered an photo.

	# Display an HTML page listing all albums and photos in given directory.

	# Each album's link will call album.pl with the name of the album as an environment variable.
	# (album=01 - The Beginning)

	# Each picture's link will call album.pl with the name of the photo file as an environment variable.
	# Each picture's short description is displayed as the link text.
	# (photo=001.jpg)

	if ($::usedesc)
	{
		close(DESC);
	}

	if ($::create_html_flag)
	{
		close(STATIC);
	}

	debug("Leaving subroutine: photoAlbum($manual_override)<p>",4,__LINE__);

}


##########################################################################

=head3 error()

 error($line,$error_code,$extra_info);

 $line - Line number, where error occurred.
 $error_code - Pre-defined error code that prints a canned message.
 $extra_info - Additional information that can be passed in

Displayes the error message associated with $error_code along with the $extra_info. Then halts execution.

=cut

sub error
{
my $error;
my $error_header;
my $errstring;
my @error_fields;
my $line=shift;

	# Pull error code and error fields
	($error,@error_fields)=@_;

	printHTMLHeader();

	$error_header="<head><title>album.pl - $::S{18}</title>\n";
	$error_header.=printHeader();
	$error_header.="<h1>$::S{19} $line</h1><br>\n";

	# Print error header
	display($error_header);

	# Build error info, depending on error code
	if ($error eq "not_readable")
	{
		$errstring="$::S{20} <b>@error_fields</b>\n";
	}
	elsif ($error eq "tempdesc_not_writable")
	{
		$errstring="$::S{21} <b>@error_fields</b><p>\n$::S{22}";
	}
	elsif ($error eq "not_writable")
	{
		$errstring="$::S{23} <b>@error_fields</b>\n";
	}
	elsif ($error eq "stringtable")
	{
		$errstring="String table is not found! Cannot continue execution. <b>@error_fields</b>\n";
	}
	elsif ($error eq "sanity")
	{
		$errstring="$::S{24} <b>@error_fields</b>\n";
	}
	elsif ($error eq "upload_error")
	{
		$errstring="$::S{25} <b>@error_fields</b>\n";
	}
	elsif ($error eq "open_db")
	{
		$errstring="$::S{26} <b>@error_fields</b>\n";
	}
	elsif ($error eq "short_stringtable")
	{
		$errstring="Your string table ($::stringtable) is too short: <b>@error_fields</b>\n";
	}
	elsif ($error eq "cant_append")
	{
		$errstring="$::S{27} <b>@error_fields</b>\n";
	}
	elsif ($error eq "upload_dir")
	{
		$errstring="$::S{28} <b>@error_fields</b>\n";
	}
	elsif ($error eq "reg_error")
	{
		$errstring="$::S{30} <b>@error_fields</b>\n";
	}
	elsif ($error eq "no_config")
	{
		$errstring="$::S{31} (@error_fields).\n<p>$::S{32} <b>$0</b> $::S{33}\n";
	}
	elsif ($error eq "cant_fork")
	{
		$errstring="Cannot fork: @error_fields.\n";
	}
	else
	{
		# Handle error codes not listed above
		$errstring="$::S{34} $error (@error_fields)<p>\n$::S{35}\n";
	}

	# Print error info
	display("$errstring<p>\n");
	display("<hr>\n");

	# Strip out any HTML for js popup
	$errstring=~s/<([^>]|\n)*>//g;

	# Put up a javascript popup
	display(javaAlert($errstring));

	# Print error footer
	showFooter(1);

	# End of error
	exit(0);
}


##########################################################################

=head3 display()

 display($display_message);

 $display_message - String to print (to STDOUT or to static file)

Prints a message to the designated output steam

=cut

sub display
{
#	print {$::create_html_flag ? "STATIC" : "STDOUT" } "@_"; # pre strict
	print {$::create_html_flag ? "STATIC" : \*STDOUT } "@_";

#	if ($::debug || ($::create_html_flag eq 1))
	if ($::create_html_flag eq 1)
	{
		print "@_";
	}
}


##########################################################################

=head3 debug()

 debug($debug_message,$debug_level,$line);

 $debug_message - String to print if debugging is on
 $debug_level - Only pring string if current debug level is $debug_level or higher (current debug level is set by $debug)
 $line - The line number of the debug statement.

Prints a message, if $::debug has a value.

=cut

sub debug
{
my $debug_message=shift;
my $debug_level=shift;
my $line=shift;

	if (($debug_level le $::debug) && $::debug)
	{
		# Entering subroutine
		if ($debug_message=~/^Entering subroutine:/i)
		{
			display("<ul>");
		}
		display("<pre>");
		if ($line)
		{
			display("$line: ");
		}
		display("$debug_message</pre>\n");

		# Leaving subroutine
		if ($debug_message=~/^Leaving subroutine:/i)
		{
			display("</ul>");
		}
	}
}


##########################################################################

=head3 setDate()

 $datestr=setDate($convtime,$return_seconds);

 $datestr        - date and time
 $convtime       - unixtime value which is used to set $datestr (optional)
 $return_seconds - 1=YYYY/MM/DD HH:MM:SS, 0=YYYY/MM/DD HH:MM

Converts $convtime into a human readable format and returns it as $datestring.
If $convtime is not provided, the current time is returned. If $return_seconds
has a value, then the time includes seconds.

=cut

sub setDate
{
my $convtime=shift;
my $return_seconds=shift;
my $year;
my $mon;
my $hour;
my $min;
my $sec;
my $sysdate;
my $mday;
my $wday;
my $yday;
my $isdst;

	$convtime=time if (!$convtime);

	debug("Convtime: [$convtime]",2,__LINE__);

	($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($convtime);
	$year+=1900;
	$mon++;
	$mday = "0$mday" if ($mday < 10);
	$mon  = "0$mon"  if ($mon < 10);
	$hour = "0$hour" if ($hour < 10);
	$min  = "0$min"  if ($min < 10);
	$sec  = "0$sec"  if ($sec < 10);
	$sysdate="$year/$mon/$mday $hour:$min";

	$sysdate.=":$sec" if ($return_seconds);

	debug("Sysdate: [$sysdate]",2,__LINE__);
	return($sysdate);
}


##########################################################################

=head3 sanityTest()

 sanityTest();

Runs some basic tests to make sure the environment is clean and secure before the script starts.

=cut

sub sanityTest
{
my $data;
my $errstr="";
my $count=1;
my $stuff;
my $confopen;
my @funccodes;
my $funccode;
my $prevcode;
my $couldbe=$0;

	debug("Loading string table from $::stringtable...",2,__LINE__);

	# Trying to open the provided config file
	if (open(STRINGTABLE,"$::stringtable"))
	{
		debug("Opened string table at $::stringtable",2,__LINE__);
		$confopen=1;
	}
	else
	{
		$confopen=0;
	}

	# Nope. Try just album_strings.txt
	if (!$confopen)
	{
		debug("Trying to read string table information from album_strings.txt...",2,__LINE__);
		if (open(STRINGTABLE,"album_strings.txt"))
		{
			debug("Opened string table at album_strings.txt",2,__LINE__);
			$confopen=1;
			$::stringtable="album_strings.txt";
		}
		else
		{
			$confopen=0;
		}
	}

	# Nope. Try the same directory as album.pl explicitly
	if (!$confopen)
	{
		# Change all \'s to /'s
		$couldbe=~s/\\/\//g;

		# Drop the filename
		$couldbe=~s/(.*\/).*/$1/;

		$couldbe.="album_strings.txt";
		debug("Trying to read string table information from $couldbe...",2,__LINE__);
		if (open(STRINGTABLE,"$couldbe"))
		{
			debug("Opened string table file at $couldbe",2,__LINE__);
			$confopen=1;
			$::stringtable=$couldbe;
		}
		else
		{
			$confopen=0;
		}
	}

	# Just couldn't find the bloody thing!
	if (!$confopen)
	{
		error(__LINE__,"stringtable","$::stringtable: $!");
	}

	# Read all values from stringtable
	while ($data=<STRINGTABLE>)
	{
		chomp($data);
		$data=~s/\n//g;
		$data=~s/\r//g;
		# Use just @S because I'm going to type this variable name a million times, and I'm lazy.
		$::S{$count}=$data;
		$stuff=$::S{$count};
#		debug("\$::S{$count} = [$::S{$count}]",4,__LINE__);
		$count++;
	}
	close(STRINGTABLE);

	# Check for security holes

	# Relative paths
	if ($form->param('album')=~/^\\*\./)
	{
		$errstr="$::S{84} $::S{14}.";
	}
	if ($form->param('photo')=~/^\\*\./)
	{
		$errstr="$::S{84} $::S{12}.";
	}
	if ($form->param('album')=~/^\/*\./)
	{
		$errstr="$::S{84} $::S{14}.";
	}
	if ($form->param('photo')=~/^\/*\./)
	{
		$errstr="$::S{84} $::S{12}.";
	}

	# Special chars
	if ($form->param('album')=~/[|><]/)
	{
		$errstr="$::S{85} $::S{14} $::S{86}.";
	}
	if ($form->param('photo')=~/[|><]/)
	{
		$errstr="$::S{85} $::S{12} $::S{86}.";
	}

	# Check for function codes that are the same...
	push @funccodes,$::admin;
	push @funccodes,$::config;
	push @funccodes,$::updateconfig;
	push @funccodes,$::enter_desc;
	push @funccodes,$::update_desc;
	push @funccodes,$::update_rating;
	push @funccodes,$::debug_code;

	@funccodes=sort @funccodes;

	$prevcode="";

	foreach $funccode (@funccodes)
	{
		if ($funccode eq $prevcode)
		{
			$::warning.=$::S{292}."<br>";
		}
		$prevcode=$funccode;
	}
	@funccodes="";

	if ($errstr)
	{
		error(__LINE__,"sanity","$errstr");
	}
}


##########################################################################

=head3 readDirectory()

 @myfile_list=readDirectory($scan_directory);

 @myfile_list - Returned list of files in this directory
 $scan_directory - Directory to read all values from

Reads all entries in specified directory, returns as list

=cut

sub readDirectory
{
my @myfile_list;
my @final_file_list;
my $scan_directory=shift;
my $shortfile;

	# Clear arrays, because otherwise they appear to have a null element, which really buggers things up
	while (@final_file_list)
	{
		shift @final_file_list;
	}
	while (@myfile_list)
	{
		shift @myfile_list;
	}
	while (@::album_list)
	{
		shift @::album_list;
	}
	while (@::photo_list)
	{
		shift @::photo_list;
	}
	while (@::movie_list)
	{
		shift @::movie_list;
	}

	debug("Attempting to read entries in [$scan_directory]<p>",2,__LINE__);
	opendir(ENTRIES,"$scan_directory") or error(__LINE__,"not_readable","$scan_directory");

	# Change Grep
	@myfile_list=grep !/^\.\.?$/,readdir ENTRIES;
	close(ENTRIES);

	# clear directory flag
	$::contains_dir=$::temp_quota_total=$::numfiles=$::filenum=0;

	foreach $shortfile (@myfile_list)
	{
		# Check to see if it's a movie, picture or album
		debug("Checking to see if $scan_directory/$shortfile is a photo/movie/album...",4,__LINE__);
		if (isAPhoto($shortfile) || isAMovie($shortfile) || (-d "$scan_directory/$shortfile"))
		{
			# Load photo, movie and album arrays
			if (isAPhoto($shortfile))
			{
				debug("It's a photo ($shortfile)...",4,__LINE__);
				push @::photo_list,$shortfile;

				# For pic randomizer
				if ($::doing_upload==2)
				{
				my $tempstuff="$scan_directory/$shortfile";
					$tempstuff=~s/^$::album_dir\///;
					push @::total_photo_list,$tempstuff;
					debug("Randomization: Adding $tempstuff list of random objects",4,__LINE__);
				}
			}
			if (isAMovie($shortfile))
			{
				debug("It's a movie...",4,__LINE__);
				push @::movie_list,$shortfile;
			}
			if (-d "$scan_directory/$shortfile")
			{
				debug("It's an album ($shortfile)...",4,__LINE__);
				push @::album_list,$shortfile;
			}
			push @final_file_list,$shortfile;

			# Keep count
			$::numfiles++;

			if ($shortfile eq $::shortphoto)
			{
				$::filenum=$::numfiles;
			}

			# Set the flag if we've seen at least one dir
			if (!$::contains_dir && (-d "$scan_directory/$shortfile"))
			{
				$::contains_dir=1;
			}

			# Update quota information
			if ($::quota && $::per_member_upload)
			{
				@::allinfo=stat("$scan_directory/$shortfile");
				$::temp_quota_total+=$::allinfo[7];
				debug("New quota total: $::temp_quota_total",3,__LINE__);
			}
		}
	}

	debug("Final quota total: $::temp_quota_total bytes from $::numfiles files.",3,__LINE__);

	# Here's where to add in different sorting options
	@final_file_list=sort(@final_file_list);

	debug("All Entries:<p>@final_file_list",4,__LINE__);

	return (wantarray) ? @final_file_list : shift(@final_file_list);

}


##########################################################################

=head3 recursiveScan()

 recursiveScan($scan_directory,$already_scanned);

 $scan_directory - Directory to search recursively
 $already_scanned - Path of directories above this one (optional)

Walks the directory tree recursively

=cut

sub recursiveScan
{
my @all_dirs;
my $single_directory;
my $photo_filename;
my $directory_only;
my $filename_only;
my $scan_directory=shift;
my $already_scanned=shift;

	debug("Entering subroutine: recursiveScan($scan_directory,$already_scanned)",4,__LINE__);

	debug("Performing recursive scan of $scan_directory...",2,__LINE__);
	debug("\$already_scanned=$already_scanned",2,__LINE__);

	@all_dirs=readDirectory($scan_directory);

	# Add root directory
	if ($::doing_upload==1 && !$already_scanned)
	{
		# Get description
		openDescfile("$::album_dir/");
		getDescription($::rootalbumname);
		close(DESC);

		debug("Checking for existance of $::album_dir/no_upload.txt",4,__LINE__);

		# If no_upload.txt file is present in this dir, don't show it on the upload menu
		if (!-e "$::album_dir/no_upload.txt" || isAdmin())
		{
			$::object.="<option value=\"\">";

			if (!$::shortdesc)
			{
				$::object.="$::S{87}";
			}
			else
			{
				$::object.="$::shortdesc";
			}

			$::object.="</option>\n";
		}
		else
		{
			debug("Skipping $::album_dir because no_upload.txt was found.",3,__LINE__);
		}

		# Search
		if ($::searchstring)
		{
			# Description/owner search
			if ($::searchdescriptions || $::searchowners)
			{
				debug("Searching descriptions/owners in $single_directory for $::searchstring",4,__LINE__);
				openDescfile("$::album_dir/");

				# Pass in object of parent dir as parameter
				getDescription("./",1);
			}

			# Ratings serch
			if ($::searchcomments)
			{
				debug("Searching ratings in $single_directory for $::searchstring",4,__LINE__);
				getRatings(2,$single_directory);
			}
		}

		# Find most popular
		if ($::popular_flag)
		{
			getRatings(4,$single_directory);
			getPopularViews($single_directory);
		}
	}

	foreach $single_directory (@all_dirs)
	{
		$::full_directory="$::album_dir/";
		if ($already_scanned)
		{
			debug("Concatenating \$already_scanned ($already_scanned) to \$::full_directory ($::full_directory) because \$already_scanned has a value.",2,__LINE__);
			$::full_directory.="$already_scanned/";
		}
		$::full_directory.=$single_directory;
		debug("\$::full_directory=$::full_directory",2,__LINE__);
		if (-d "$::full_directory")
		{
			# Increment "scan depth" counter
			$::scan_depth++;

			debug("$single_directory is a directory.",2,__LINE__);
			$directory_only=$single_directory;

			$::static_albums_done++;

			if ($already_scanned)
			{
				debug("Prepending $already_scanned to $single_directory because \$already_scanned has a value.",2,__LINE__);
				$single_directory="$already_scanned/$single_directory";
			}

			# Do any per directory processing here

			# Search
			if ($::searchstring)
			{
				# Filename (directory) search
				if ($::searchfilenames)
				{
					debug("Searchimg $directory_only for $::searchstring",4,__LINE__);
					if ($directory_only=~/$::searchstring/i)
					{
						debug("Found a MATCH (directory): $directory_only - storing $single_directory",4,__LINE__);
						push @::searchresults,"$single_directory";
					}
				}

				# Description/owner search
				if ($::searchdescriptions || $::searchowners)
				{
					debug("Searching descriptions/owners in $single_directory for $::searchstring",4,__LINE__);
					openDescfile("$::album_dir/$single_directory/");

					# Pass in object of parent dir as parameter
					getDescription("$single_directory/",1);
				}

				# Ratings serch
				if ($::searchcomments)
				{
					debug("Searching ratings in $single_directory for $::searchstring",4,__LINE__);
					getRatings(2,$single_directory);
				}
			}

			# Find most popular
			if ($::popular_flag)
			{
				getRatings(4,$single_directory);
				getPopularViews($single_directory);
			}

			# We're building the list of directories to display for the upload form here...
			if ($::doing_upload==1)
			{
				debug("Building upload category list [$single_directory] - size: $::temp_quota_total...",3,__LINE__);

				# Get description
				openDescfile("$::album_dir/$already_scanned/");
				getDescription($directory_only);
				close(DESC);

				debug("Checking for existance of $::album_dir/$single_directory/no_upload.txt",4,__LINE__);

				# If no_upload.txt file is present in this dir, don't show it on the upload menu
				if (!-e "$::album_dir/$single_directory/no_upload.txt" || isAdmin())
				{
					$::object.="<option value=\"$single_directory\"";

					# Code to set default upload dir to current album provided by Systematic
					if ($query->param('album') eq $single_directory)
					{
						$::object.=" selected"
					}
					$::object.=">";

					# Indent sub albums
					$::temp=$::scan_depth;
					while ($::temp)
					{
						$::object.=$::S{272};
						$::temp--;
					}
	#				if ($already_scanned)
	#				{
						$::object.=$::S{273};
	#				}

					if ($::shortdesc)
					{
						$::object.="$::shortdesc";
					}
					else
					{
						$::object.="$single_directory";
					}
					$::object.="</option>\n";
				}
				else
				{
					debug("Skipping $::album_dir/$already_scanned/$single_directory because no_upload.txt was found.",3,__LINE__);
				}
			}
			elsif (!$::doing_upload)
			{
				print "$::full_directory...";
				if ($::create_html_flag le 1)
				{
					print "<br><ul>";
				}
				print "\n\n";

				# Generate static HTML for $::full_directory
				debug("Calling photoAlbum($::full_directory)",4,__LINE__);
				photoAlbum($::full_directory);
				debug("Back from photoAlbum($::full_directory) call.",4,__LINE__);
			}

			$::debug_num_recurses++;

# Un comment to stop recursing (added when testing started to run away)
#if ($::debug_num_recurses lt 3)
#{
			debug("Calling recursiveScan($::full_directory,$single_directory)",4,__LINE__);
			recursiveScan($::full_directory,$single_directory);
			debug("Back from recursiveScan($::full_directory,$single_directory) call.",4,__LINE__);
			debug("Recursion $::debug_num_recurses...",2,__LINE__);
#}
#else
#{
	debug("Recursion Stopped.",2,__LINE__);
#}

			# Pop back up a level
			$::scan_depth--;
		}

		# Generate HTML for pictures too
		elsif (!$::doing_upload && (-s "$::full_directory") && (isAPhoto($::full_directory)) || $::searchstring)
		{
			$photo_filename=$::full_directory;
			# strip off all but the filename
			$photo_filename=~s/.*\/(.*)/$1/;
			$filename_only=$photo_filename;

			$::photo_and_path=$::full_directory;
			# strip off the album_dir
			$::photo_and_path=~s/$::album_dir\/(.*)/$1/;

			if ($already_scanned)
			{
				# This used to be a typo so $photo_filename wasn't being set, and everything seemed to work. If something is broken, take this out. (I haven't tested it)
#				$photo_filename="Picture: $already_scanned/$photo_filename";
				# Maybe this is what I meant:
				$photo_filename="$already_scanned/$photo_filename";
			}

			# Do any per file processing here

			# Search (filename)
			if ($::searchstring)
			{
				if ($::searchfilenames)
				{
					debug("Searchimg $filename_only for $::searchstring",4,__LINE__);
					if ($filename_only=~/$::searchstring/i)
					{
						debug("Found a MATCH (file): $filename_only - Storing $photo_filename",4,__LINE__);
						push @::searchresults,"$photo_filename";
					}
				}
			}
			else
			{
				debug("Generating photo HTML for $photo_filename",2,__LINE__);
				if ($::create_html_flag le 1)
				{
					print "<li>";
				}
				print "$photo_filename\n";
				if ($::create_html_flag le 1)
				{
					print "<br>";
				}
				$::static_photos_done++;
				debug("Calling photoAlbum($::photo_and_path)",4,__LINE__);
				photoAlbum("$::photo_and_path");
				debug("Back from photoAlbum($::photo_and_path) call.",4,__LINE__);
			}
		}
	}
	debug("Done with $scan_directory...",2,__LINE__);
	if (!$::doing_upload)
	{
		if ($::create_html_flag le 1)
		{
			print "</ul>";
		}
		print "\n";
	}

	debug("Leaving subroutine: recursiveScan($scan_directory,$already_scanned)",4,__LINE__);
}


##########################################################################

=head3 isAPhoto()

 isAPhoto($photo_name);

 $photo_name - name of picture file

Returns 1 if the filename passed in is that of a valid "photo", 0 otherwise.

=cut

sub isAPhoto
{
my $flag=0;
my $photo_name=shift;
my $imgext;

	debug("Checking to see if $photo_name is a photo...",4,__LINE__);

	# *** I may want to add a test to see if $photo_name is a readable file as well, but that might cause problems for relative paths, if they're used

	if ($photo_name=~/^$::thumbprefix/i)
	{
		$flag=0;
	}
	else
	{
		foreach $imgext (@::imgexts)
		{
			if ($photo_name=~/.*\.$imgext$/i)
			{
				$flag=1;
				debug("Yep, it's a photo.",4,__LINE__);
			}
		}
	}
	return($flag);
}


##########################################################################

=head3 isAMovie()

 isAMovie($movie_name);

 $movie_name - name of movie file

Returns 1 if the filename passed in is that of a valid "movie", 0 otherwise.

=cut

sub isAMovie
{
my $flag=0;
my $movie_name=shift;
my $movieext;

	debug("Checking to see if $movie_name is a movie...",4,__LINE__);

	# *** I may want to add a test to see if $movie_name is a readable file as well, but that might cause problems for relative paths, if they're used

	if ($movie_name=~/^$::thumbprefix/i)
	{
		$flag=0;
	}
	else
	{
		foreach $movieext (@::movieexts)
		{
			if ($movie_name=~/.*\.$movieext$/i)
			{
				$flag=1;
				debug("Yep, it's a movie.",4,__LINE__);
			}
		}
	}
	return($flag);
}


##########################################################################

=head3 Authenticate()

 $authenticated=Authenticate($mode);

 $authenticated - Returns 1 if the user was successfully authenticated, otherwise zero.
 $mode - Alternate authentication mode. For UBB, this means Junior Members are not permitted, and will always return zero. (Used to prohibit junior members from uploading).

Authenticates the global variables $::username and $::password, using the specified method. Returns 1 for a successful authentication, otherwise 0.

=cut

sub Authenticate
{
my $data="";
my $auth=0;
my $storedpass="";
my $pwseed;
my $member_status;
my $dbi_fail;
my $mode=shift;
my $memberslist;

# Hard coded value for a UBB Junior Member
my $junior="Junior Member";

	debug("Entering subroutine: Authenticate",4,__LINE__);

	$::usernumber="";

	# Load cookie login information, if present
	$::cookielogin=cookieLogin();

	# UBB authentication
	if ($::authentication_type eq 2)
	{
		debug("Using UBB Authentication (type $::authentication_type)",2,__LINE__);

		$memberslist="$::membersdir/memberslist.cgi";

		open (FILE,"$memberslist") || error(__LINE__,"not_readable","$memberslist: $!");
		while ($data=<FILE>)
		{
			if ($data=~/^$::username\|/i)
			{
				$::usernumber=$data;
				chomp($::usernumber);
				$::usernumber=~s/.*\|(.*)/$1/;
			}
		}
		close(FILE);

		# Only process if a user was found
		if ($::usernumber)
		{
			# Set "logged in" user
			$::loggedin=$::usernumber;

			# Return 0 if not found, to stop username guesses
			open (FILE,"$::membersdir/$::usernumber.cgi") || return(0);
			$storedpass=<FILE>;
			$storedpass=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$member_status=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			$::displayname=<FILE>;
			chomp($storedpass);
			chomp($member_status);
			close(FILE);

			if (!$::displayname)
			{
				$::displayname=$::username;
			}

			# If using alternate authentication, and the member is a junior member, stop now
			if (($member_status eq $junior) && $mode)
			{
				debug("Authentication set to fail: User was a $member_status",3,__LINE__);
				print javaAlert("$::S{42} $::displayname $::S{278} $member_status $::S{279}");
				exit(1);

			}
		}
	}

	# Load YaBB username/password
	if ($::authentication_type eq 3)
	{
		debug("Using YaBB Authentication (type $::authentication_type)",2,__LINE__);

		$memberslist="$::membersdir/$::username.dat";

		# Set "logged in" user
		$::loggedin=$::username;

		# Return 0 if not found, to stop username guesses
		open(FILE,"$memberslist") || return(0);
		$storedpass=<FILE>;
		$::displayname=<FILE>;
		close(FILE);

		chomp($storedpass);
	}

	# Check for DBI package, include if present
	my $pkg="DBI";
	my $method="connect";
	eval("use ".$pkg.";\n".$pkg."::".$method."()");

	if ($@=~/^Can't locate/)
	{
		$dbi_fail=1;
	}

	# Load database username/password
	if ($::authentication_type eq 4 && !$dbi_fail)
	{
	my $user_sql;
	my $dbh;
	my $sth;
	my $rv;
	my @row;

		debug("Using database Authentication (type $::authentication_type)",2,__LINE__);

		if ($::username)
		{
			# Set "logged in" user
			$::loggedin=$::username;

			# Connect to database
			$dbh=DBI->connect("DBI:$::db_driver:$::db_name:$::db_hostname:$::db_port",$::db_user,$::db_password) || die $DBI::errstr;

			# Build SQL command
			$user_sql="SELECT $::db_passwdfield FROM $::db_membertable WHERE $::db_username = '$::username'";

			debug("SQL query: $user_sql",2,__LINE__);

			if ($dbh)
			{
				# Check SQL command
				$sth=$dbh->prepare($user_sql);

				# Check for errors
				if (!$sth)
				{
					$::warning.="$::S{293}$::S{221} ";
					$::warning.=$sth->errstr."<br>";
				}

				# Run SQL command
				$rv=$sth->execute;
				debug("Query returned $rv rows.",2,__LINE__);

				# Check for errors
				if (!$rv)
				{
					$::warning.="$::S{293}$::S{221} ";
					$::warning.=$sth->errstr."<br>";
				}

				# Fetch Rows
				while(@row=$sth->fetchrow_array)
				{
					$storedpass=$row[0];
					debug("\$row[0]=$storedpass",2,__LINE__);
				}

				# Disconnect from database
				$dbh->disconnect;
			}
			else
			{
				$::warning.="$::S{293}$::S{226}<br>";
			}

			debug("Warning is currently: $::warning",2,__LINE__);
			debug("Stored password is: $storedpass",2,__LINE__);
		}
		else
		{
			debug("No user logged in - DB check skipped.",2,__LINE__);
		}
	}

	# Flatfile authentication
	if ($::authentication_type eq 1)
	{
		debug("Using Flatfile Authentication (type $::authentication_type)",2,__LINE__);

		# Open the text database
		open(AUTH_DB,$::auth_db) || error(__LINE__,"open_db","$::auth_db");

		# First check if user exists
		while (<AUTH_DB>)
		{
			chomp;
			($data,$storedpass)=split('\|',$_);
			if ($::username eq $data)
			{
				last;
			}
		}
		close(AUTH_DB);
		$::displayname=$::username;

		# Set "logged in" user
		$::loggedin=$::username;
	}

	# Check for encrypted passwords stored in cookies
	$storedpass=checkPassword($::password,$storedpass);

	# Check for encrypted passwords stored on server
	$::password=checkPassword($storedpass,$::password);

	# If display name is not already set, then just use the username
	if (!$::displayname)
	{
		$::displayname=$::username;
	}

	chomp($::displayname);
	chomp($storedpass);

	# Anonymous, and no other controls are set
	if (!$::authentication_type && !$::protect_album && !$::album_password)
	{
		debug("Using Anonymous Authentication (type $::authentication_type)",2,__LINE__);

		$storedpass=$::password;
		$::displayname=$::username;
		$auth=1;
	}

	# Check the password
	if ($::password eq $storedpass && $::password && $::username eq $albumuser[3])
	{
		$auth=1;
	}
	else
	{
		# If not authenticated, blow away the username. Not doing this opens up a huge hole - users can get into the admin menu knowing only the username of the admins!
		$::loggedin="";
	}

	debug("Username: $::username",3,__LINE__);
	debug("Entered Password: $::password",3,__LINE__);
	debug("Stored Password: $storedpass",3,__LINE__);
	if ($::authentication_type eq 2)
	{
		debug("Member #: $::usernumber",3,__LINE__);
	}
	debug("Authenticated: $auth",3,__LINE__);

	# Reset cookie login to show if login was successful or not
	if ($::cookielogin)
	{
		$::cookielogin=$auth;
	}

	# Set album cookie
	if (($::username && $::password) && !$::cookielogin && $auth && !$::header_printed)
	{
		use CGI qw(:standard);
		use CGI::Cookie;

		debug("\$auth=$auth",3,__LINE__);
		debug("\$::cookielogin=$::cookielogin",3,__LINE__);
		debug("Setting cookie ($::username/$::password)",3,__LINE__);

		# Set cookies with a 5 year expiry
		my $cookie1 = new CGI::Cookie(-name=>$::albumcookieusername,-value=>$::username,-expires=>'+24h');
		my $cookie2 = new CGI::Cookie(-name=>$::albumcookiepassword,-value=>$::password,-expires=>'+24h');

		print header(-cookie=>[$cookie1,$cookie2]);

		# Now we have logged in via a cookie
		$::cookielogin=1;

		# Don't print the HTML header - we just did that
		$::header_printed=1;
	}

	debug("Did authentication come from a cookie? (\$::cookielogin): $::cookielogin",3,__LINE__);

	debug("Leaving subroutine: Authenticate",4,__LINE__);

	return($auth);
}


##########################################################################

=head3 checkPassword()

 $goodpass=checkPassword($mypassword,$storedpass);

 $goodpass - The password that matched, if found. (Otherwise, the stored password ($storedpass) is returned).
 $mypassword - The password that the user has entered.
 $storedpass - The password on file for that user.

Checks $mypassword against $storedpass using all known encryption methods, and returns a copy of the "good" (clear) password, if found

=cut
sub checkPassword
{
my $mypassword=shift;
my $storedpass=shift;
my $passcheck;
my $pwseed;
my $md5_fail=0;

	debug("Entering subroutine: checkPassword($mypassword,$storedpass);",4,__LINE__);

	# Check to ensure we have stuff to check
	if (!$mypassword || !$storedpass)
	{
		return($storedpass);
	}

	# Check plaintext
	if ($mypassword eq $storedpass)
	{
		return($mypassword);
	}

	# YaBB Security Mod
	# Code added from clubSTi.com (Gerlando)
	$pwseed ||= 'ya';
	$passcheck=crypt($mypassword,$pwseed);
	debug("Trying YaBB Security Mod encryption: $passcheck",3,__LINE__);
	if ($passcheck eq $storedpass)
	{
		debug("--> It's a match!",3,__LINE__);
		return($passcheck);
	}
	else
	{
		debug("--> Does not match.",3,__LINE__);
	}

	# Crypt
	$pwseed=$mypassword;
	#$pwseed=~s/(..).*/$1/;
	$pwseed = substr($pwseed, 0, 2);
	$passcheck=crypt($storedpass,$pwseed);
	debug("Trying crypt() encrypted password: $passcheck",3,__LINE__);
	if ($passcheck eq $mypassword)
	{
		debug("--> It's a match!",3,__LINE__);
		return($passcheck);
	}
	else
	{
		debug("--> Does not match.",3,__LINE__);
	}

	debug("Leaving subroutine: checkPassword($mypassword,$storedpass);",4,__LINE__);

	return($storedpass);
}


##########################################################################

=head3 loginStatus()

 $login_html=loginStatus();

 $login_html = The user's login status, as HTML.

Returns the user's login status as either a URL to the login page (if the user is not logged in) or as as "Welcome [username]" message (if the user is logged in).

=cut
sub loginStatus
{
my @chips;
my $singlechip;
my $data;
my $lastchip;

	if ($::authentication_type)
	{
		if ($::authenticated)
		{
			if ($::displayname)
			{
				$data="<span class=meniphoto>$::S{178} $::displayname";
			}
			else
			{
				$data="<span class=meniphoto>$::S{178} $::username";
			}
		}
		else
		{
			$data="<a href=\"$::albumprog?function=$::login_code\">";
			if ($::textmenu)
			{
				$data.=$::S{237};
			}
			else
			{
#				$data.="<img class=\"button\" src=\"$::login_button\" alt=\"\">";
				$data.="<font class=\"meniphoto\">Prijava korisnika<\/font>";
			}
			$data.="</a>";
		}
	}
	else
	{
		$data="<span class=meniphoto>$::S{178}$::S{295}</span>";
	}

	return($data);
}


##########################################################################

=head3 cookieLogin()

 $status=cookieLogin();

 $status - 1 if login info was found, otherwise 0

Retrieves login information from the cookie (if found) and passes it back as $::username, $::password, $::usernumber (UBB) and $::displayname.

=cut
sub cookieLogin
{
my $chip;
my @chips;
my $singlechip;
my $chipcount;
my $lastchip;
my $mypassword;
my $myusername;
my $retcode=0;

# Change these if you've customized your YaBB cookie names...
my $YaBBusername="YaBBusername";
my $YaBBpassword="YaBBpassword";

	debug("Entering subroutine: cookieLogin",4,__LINE__);

	# Check to see if the user has a cookie, and log them in with that.
	foreach $chip (%::cookie)
	{
		# Check YaBBN logins (username)
#		if ($lastchip=~/^$YaBBusername.*/ && $::authentication_type eq 3)
		if ($lastchip=~/^$YaBBusername.*/ && !$myusername)
		{
			debug("Found YaBB username info: $lastchip",3,__LINE__);
			$myusername=$chip;
			debug("\$myusername set to $myusername",3,__LINE__);
		}

		# Check YaBBN logins (password)
#		if ($lastchip=~/^$YaBBpassword.*/ && $::authentication_type eq 3)
		if ($lastchip=~/^$YaBBpassword.*/ && !$mypassword)
		{
			debug("Found YaBB password info: $lastchip",3,__LINE__);
			$mypassword=$chip;
			debug("\$mypassword set to $mypassword",3,__LINE__);
		}

		# Handle arrays
		if ($chip=~/&/)
		{
			@chips=splitCookie($chip);
			$chipcount=0;
			foreach $singlechip (@chips)
			{
				debug("Processing \$singlechip [$singlechip], part of [$lastchip]",4,__LINE__);
				$chipcount++;

				# Check UBB logins
#				if ($lastchip=~/^ubb.*/ && $::authentication_type eq 2)
				if ($lastchip=~/^ubb.*/)
				{
					debug("Found UBB login info: $lastchip",3,__LINE__);

					# Username first
					if ($chipcount eq 1 && !$myusername)
					{
						$myusername=$singlechip;
						debug("\$myusername set to $myusername",3,__LINE__);
					}

					# Password second
					if ($chipcount eq 2 && !$mypassword)
					{
						$mypassword=$singlechip;
						debug("\$mypassword set to $mypassword",3,__LINE__);
					}

					# display name third
					if ($chipcount eq 3)
					{
						$::displayname=$singlechip;
						debug("\$::displayname set to $::displayname",3,__LINE__);
					}

					# Member number fourth
					if ($chipcount eq 5)
					{
						$::usernumber=$singlechip;
						debug("\$::usernumber set to $::usernumber",3,__LINE__);
					}
				}
			}
		}

		# Native album.pl cookie login info :D
		if ($lastchip=~/^$::albumcookieusername.*/)
		{
			debug("Found Native album.pl username info: $lastchip",3,__LINE__);
			$myusername=$chip;
			debug("\$myusername set to $myusername",3,__LINE__);
		}

		# Native album.pl cookie login info :D
		if ($lastchip=~/^$::albumcookiepassword.*/)
		{
			debug("Found Native album.pl password info: $lastchip",3,__LINE__);
			$mypassword=$chip;
			debug("\$mypassword set to $mypassword",3,__LINE__);
		}

		if ($::cookie{$chip})
		{
			debug("[$chip] = [$::cookie{$chip}]",3,__LINE__);
		}
		$lastchip=$chip;
	}

	# Return status flag (was login info found...)
	if  ($myusername && $mypassword)
	{
		$::username=$myusername;
		$::password=$mypassword;
		debug("Found username: $::username and password: $::password in cookie. (Maybe #:$::usernumber and name: $::displayname too...)",2,__LINE__);
		$retcode=1;
	}
	else
	{
		debug("No login information found in cookies.",2,__LINE__);
		$retcode=0;
	}

	debug("Leaving subroutine: cookieLogin --> return code is $retcode",4,__LINE__);
	return($retcode);
}


##########################################################################

=head3 showLogin()

 showLogin();

Returns the login form as HTML, to be inserted into a template.

=cut
sub showLogin
{
my $data;
my $loginAlbum;

	debug("Entering subroutine: showLogin",4,__LINE__);
	$data="<form method=\"post\" action=\"$::albumprog\">\n";

	# If we were logging in to an album, keep that album name. (From J.P. Stewart [j.p.stewart@mindspring.com])
	$loginAlbum=$form->param('album');
	if ($loginAlbum)
	{
		$data.="<input type=hidden name=album value=\"$loginAlbum\">\n";
	}
#	$data.="<td valign=\"top\" align=center>\n";

	# Failed to log in, show failure message
	if ($::password && !$::authenticated)
	{
		$data.="$::S{181}\n";
		# Make it a popup too
		$data.=javaAlert($::S{181});
	}
	else
	{
		# Or show "please log in" message
		# $data.="$::S{182}\n";
	}
	$data.="<table width=299 height=98 border=0 cellpadding=1 cellspacing=1 bgcolor=#868686><tr><td bgcolor=#F3F3F3><table width=297 height=96 border=0 cellpadding=0 cellspacing=0 class=meniphoto><tr><td height=19 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=128 height=17><div align=right>$::S{55}&nbsp;</div></td><td height=17>";

	if (!$::album_password)
	{
		$data.="<input type=\"text\" name=\"username\" value=\"$::username\" class=logintextbox>\n";
	}
	$data.="</td></tr><tr><td height=22 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr><tr><td height=17><div align=right>$::S{57}&nbsp;</div></td><td height=17>";
	$data.="<input type=\"password\" name=\"password\" value=\"$::password\" class=logintextbox>\n";
	$data.="</tr><tr><td height=21 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr></table></td></tr></table><table width=301 border=0 cellspacing=0 cellpadding=0><tr><td>&nbsp;</td><td><div align=right><input name=imageField type=image src=images/button_prijava.gif width=111 height=25 border=0></div></td></tr></table>\n";
	# $data.="<input type=\"submit\" value=\" PRIJAVA \" class=\"button\"><br>\n";

#	$data.="</td>\n";
	$data.=passVars(1);

	$data.="</form>\n";

	debug("Leaving subroutine: showLogin",4,__LINE__);

	return($data);
}


##########################################################################

=head3 showAdminMenu()

 $admin_menu=showAdminMenu($style);

 $style - 0 = Long menu (titles, all options - used at the top of photo/album pages); 1 = Short menu (no title, some options - used under thumbnails)

 $admin_menu - Variable to return completed Administration menu into.

Returns the Administration menu, so it can be substituted into the template.

=cut
sub showAdminMenu
{
my $admin_menu;
my $isadmin;
my $stuff="";
my $style=shift;

	debug("Entering subroutine: showAdminMenu($style)",4,__LINE__);

	$admin_menu="";

	debug("\$::owner = $::owner",2,__LINE__);
	debug("\$::loggedin = $::loggedin",2,__LINE__);
	debug("\$::default_admins = $::default_admins",2,__LINE__);

	$isadmin=isAdmin();

	$stuff=$::relpath;

	# This shouldn't be required. passVars should load an album tag in, but it doesn't...
	$stuff.=$::webdelim;

	if (isAPhoto($::relpath) || isAMovie($::relpath))
	{
		$stuff.="photo";
	}
	else
	{
		$stuff.="album";
	}
	$stuff.="=$::relpath";
	$stuff.=passVars(0);
	$stuff.="\" class=\"adminlink\">";

	# Only proceed if allowed... That means: If we're printing an "abridged" menu, and the guy logged in owns the current object, or is a default admin and is logged in, or the admin function is being used.
	if ($isadmin && $::function ne "upute")
	{
		debug("We're authorized to display the admin menu...",2,__LINE__);

		# Print the short menu. The one that goes under the thumbnails.
		if ($style)
		{
			$admin_menu.="<td valign=top><table width=55 border=0 cellspacing=0 cellpadding=0><tr><td height=7><img src=images/spacer.gif width=1 height=1></td></tr><tr><td>";

			# Edit
			if ($::allow_edit || $isadmin)
			{
				$admin_menu.="<a href=\"$::albumprog?";
				if ($::slide_timer)
				{
					$admin_menu.="slideshow=-1&";
				}
				$admin_menu.="editobject=";
				$admin_menu.="$stuff";
				if ($::textmenu)
				{
					$admin_menu.=$::S{43};
				}
				else
				{
					$admin_menu.="<img border=0 src=\"$::edit_button\" alt=\"\">";
				}
				$admin_menu.="</a>";
			}

			if ($::textmenu && ($isadmin || $::allow_delete && $::allow_edit))
			{
				# $admin_menu.=" $::S{98} ";
			}

			$admin_menu.="</td></tr><tr><td height=7><img src=images/spacer.gif width=1 height=1></td></tr><tr><td>";
			
			# Delete
			if ($::allow_delete || $isadmin)
			{
				$admin_menu.="<a href=\"$::albumprog?deleteobject=";
				$admin_menu.="$stuff";
				if ($::textmenu)
				{
					$admin_menu.=$::S{44};
				}
				else
				{
					$admin_menu.="<img border=0 src=\"$::delete_button\" alt=\"\">";
				}
				$admin_menu.="</a>";
			}

			if ($::textmenu && $isadmin)
			{
				$admin_menu.=" $::S{98} ";
			}

			$admin_menu.="</td></tr><tr><td height=7><img src=images/spacer.gif width=1 height=1></td></tr><tr><td>";

			# Move, reserved for actual admins
			if ($isadmin eq 1)
			{
				$admin_menu.="<a href=\"$::albumprog?moveobject=";
				$admin_menu.="$stuff";
				if ($::textmenu)
				{
					$admin_menu.=$::S{45};
				}
				else
				{
					$admin_menu.="<img border=0 src=\"$::move_button\" alt=\"\">";
				}
				$admin_menu.="</a>";
			}

			$admin_menu.="</td></tr></table></td>";
		}
		else
		# Print the extended menu. The one that goes at the top of a page.
		{

			if ($::photo)
			{
				$admin_menu.="<table width=186 border=0 cellspacing=0 cellpadding=0><tr><td width=49><img src=images/admin_photo1.gif width=49 height=125></td><td width=128 valign=top>";

			}
			if ($::album)
			{
				$admin_menu.="<table width=186 border=0 cellspacing=0 cellpadding=0><tr><td width=49 height=100% valign=top background=images/admin_album1.gif><table width=49 height=100% border=0 cellpadding=0 cellspacing=0><tr><td height=35 valign=middle>&nbsp;</td><td>&nbsp;</td></tr><tr><td width=23 valign=middle><div align=center><img src=images/admin_title.gif width=8 height=76></div></td><td width=26>&nbsp;</td></tr><tr><td height=4 colspan=2><img src=images/admin_album3.gif width=49 height=4></td></tr></table></td><td width=128 valign=top>";
			}

			# Album Admin Menu
			if ($::album)
			{
				# Create album
				$admin_menu.="<table width=128 border=0 cellspacing=0 cellpadding=0><tr><td height=15 background=images/admin_photo_bg.gif><img src=images/spacer.gif width=1 height=1></td></tr><tr><td height=19 background=images/admin_photo_bg3.gif>";
				$admin_menu.="<a href=\"$::albumprog?admincreate=1".$::webdelim."album=$::shortalbum";
				$admin_menu.=passVars(0);
				$admin_menu.="\" class=\"adminlink\">";
				if ($::textmenu)
				{
					$admin_menu.=$::S{246};
				}
				else
				{
					$admin_menu.="Novi album";
				}
				$admin_menu.="</a>";
				$admin_menu.="</td></tr><tr><td height=18 background=images/admin_photo_bg1.gif><img src=images/spacer.gif width=1 height=1></td></tr><tr><td height=19 background=images/admin_photo_bg3.gif>";

				# For regular admins only
				if ($isadmin eq 1)
				{
					if ($::textmenu)
					{
						$admin_menu.=" $::S{98} ";
					}

					# Update titles and descriptions
					$admin_menu.="<a href=\"$::albumprog?album=";
					if ($::goback)
					{
						$admin_menu.="$::goback/";
					}
					if ($::shortalbum ne $::rootalbumname)
					{
						$admin_menu.="$::shortalbum";
					}
					$admin_menu.=$::webdelim."function=$::enter_desc";
					$admin_menu.=passVars(0);
					$admin_menu.="\" class=\"adminlink\">";
					if ($::textmenu)
					{
						$admin_menu.=$::S{247};
					}
					else
					{
						$admin_menu.="Izmjena opisa";
					}
					$admin_menu.="</a>";
					$admin_menu.="</td></tr><tr><td height=18 background=images/admin_photo_bg1.gif>&nbsp;</td></tr><tr><td height=19 background=images/admin_photo_bg3.gif>";
				}

				if ($::textmenu)
				{
					$admin_menu.=" $::S{98} ";
				}

				# Upload
				if ($::allow_uploads)
				{
					$admin_menu.=" <a href=\"$::albumprog?function=$::upload";
					$admin_menu.=passVars(0);
					$admin_menu.="\" class=\"adminlink\">";
					if ($::textmenu)
					{
						$admin_menu.=$::S{248};
					}
					else
					{
						$admin_menu.="Upload";
					}
					$admin_menu.="</a>";
					$admin_menu.="</td></tr>";
				}

				# For regular admins only
				if ($isadmin eq 1)
				{
					if ($::textmenu)
					{
						$admin_menu.=" $::S{98} ";
					}

					# Configuration management
#					$admin_menu.=" <a href=\"$::albumprog?function=$::config";
#					$admin_menu.=passVars(0);
#					$admin_menu.="\" class=\"adminlink\">";
#					if ($::textmenu)
#					{
#						$admin_menu.=$::S{249};
#					}
#					else
#					{
#						$admin_menu.="<img class=\"button\" src=\"$::config_button\" alt=\"\">";
#					}
#					$admin_menu.="</a>";

					if ($::textmenu)
					{
						$admin_menu.=" $::S{98} ";
					}

					# Check for updates
#					$admin_menu.=" <a href=\"$::albumprog?function=$::checkupdate";
#					$admin_menu.=passVars(0);
#					$admin_menu.="\" class=\"adminlink\">";
#					if ($::textmenu)
#					{
#						$admin_menu.=$::S{250};
#					}
#					else
#					{
#						$admin_menu.="<img class=\"button\" src=\"$::updates_button\" alt=\"\">";
#					}
#					$admin_menu.="</a>";
				}

				# Set Album Thumbnail
				if ($::album ne $::album_dir)
				{
					
					$admin_menu.="<tr><td height=18 background=images/admin_photo_bg1.gif>&nbsp;</td></tr><tr><td height=19 background=images/admin_photo_bg3.gif>";
					if ($::textmenu)
					{
						$admin_menu.=" $::S{98} ";
					}

					$admin_menu.="<a href=\"$::albumprog?album=";
					if ($::goback)
					{
						$admin_menu.="$::goback/";
					}
					if ($::shortalbum ne $::rootalbumname)
					{
						$admin_menu.="$::shortalbum";
					}
					$admin_menu.=passVars(0);
					if ($::page)
					{
						$admin_menu.=$::webdelim."page=$::page";
					}
					$admin_menu.=$::webdelim."pickthumb=1\" class=\"adminlink\">";
					if ($::textmenu)
					{
						$admin_menu.=$::S{251};
					}
					else
					{
						$admin_menu.="Izmijeni ikonu";
					}
					$admin_menu.="</a>";
					$admin_menu.="</td></tr>";
				}
				$admin_menu.="<tr><td height=17 background=images/admin_photo_bg2.gif><img src=images/spacer.gif width=1 height=1></td></tr></table></td><td width=9 valign=bottom background=images/admin_album2.gif><img src=images/admin_album4.gif width=9 height=6></td></tr></table>";
			}

			# Photo Admin Menu
			if ($::photo)
			{
				# Edit
				$admin_menu.="<table width=128 border=0 cellspacing=0 cellpadding=0><tr><td height=15 background=images/admin_photo_bg.gif><img src=images/spacer.gif width=1 height=1></td></tr><tr><td height=19 background=images/admin_photo_bg3.gif>";
				$admin_menu.="<a href=\"$::albumprog?";
				if ($::slide_timer)
				{
					$admin_menu.="slideshow=-1".$::webdelim;
				}
				$admin_menu.="editobject=$::photo".$::webdelim."photo=$::photo";
				$admin_menu.=passVars(0);
				$admin_menu.="\" class=\"adminlink\">";
				if ($::textmenu)
				{
					$admin_menu.=$::S{43};
				}
				else
				{
					$admin_menu.="Izmijeni";
				}
				$admin_menu.="</a>";

				if ($::textmenu)
				{
					$admin_menu.=" $::S{98} ";
				}

				# Delete
				$admin_menu.="</td></tr><tr><td height=18 background=images/admin_photo_bg1.gif><img src=images/spacer.gif width=1 height=1></td></tr><tr><td height=19 background=images/admin_photo_bg3.gif>";
				$admin_menu.=" <a href=\"$::albumprog?deleteobject=$::photo".$::webdelim."album=$::goback";
				$admin_menu.=passVars(0);
				$admin_menu.="\" class=\"adminlink\">";
				if ($::textmenu)
				{
					$admin_menu.=$::S{44};
				}
				else
				{
					$admin_menu.="Izbri&#353;i";
				}
				$admin_menu.="</a>";

				if ($::textmenu)
				{
					$admin_menu.=" $::S{98} ";
				}

				# For regular admins only
				if ($isadmin eq 1)
				{
					# Move
					$admin_menu.="</td></tr><tr><td height=18 background=images/admin_photo_bg1.gif>&nbsp;</td></tr><tr><td height=19 background=images/admin_photo_bg3.gif>";
					$admin_menu.=" <a href=\"$::albumprog?moveobject=$::photo".$::webdelim."album=$::goback";
					$admin_menu.=passVars(0);
					$admin_menu.="\" class=\"adminlink\">";
					if ($::textmenu)
					{
						$admin_menu.=$::S{45};
					}
					else
					{
						$admin_menu.="Pomakni";
					}
					$admin_menu.="</a>";
					$admin_menu.="</td></tr><tr><td height=17 background=images/admin_photo_bg2.gif><img src=images/spacer.gif width=1 height=1></td></tr></table>";
					$admin_menu.="</td><td width=9><img src=images/admin_photo2.gif width=9 height=125></td></tr></table>";
				}
			}
		}
	}
	else
	{
		debug("NOT authorized to display admin menu.",2,__LINE__);
	}


	debug("Leaving subroutine: showAdminMenu($style)",4,__LINE__);

	return($admin_menu);
}


##########################################################################

=head3 openDescfile()

 openDescfile($descfilename);

 $descfilename - The full, filesystem path to the album you want to read descriptions from.

Opens up $descfilename so that photo/album titles/descriptions can be loaded.

=cut

sub openDescfile
{
my $descfilename=shift;

	# Close any open filehandles here
	close(DESC);

	$descfilename.=$::descname;
	debug("Looking for DescFile: [$descfilename]<p>",3,__LINE__);
	if (-r $descfilename)
	{
		$::usedesc=1;
		open(DESC,"$descfilename");
		debug("Using DescFile: [$descfilename]<p>",3,__LINE__);
	}
}


##########################################################################

=head3 getDescription()

 getDescription($desctoget,$mode);

 $desctoget - Photo or album to get description of
 $mode - 0 = Normal; 1 = Searching

Retrieves the title, description and owner of the provided object. Puts the title in $::shortdesc, the description in $::longdesc (if present) and the owner in $::owner (if present).

=cut

sub getDescription
{
my $desctoget=shift;
my $mode=shift;
my $descline;
my $prevline;
my $filename;
my $tempowner;
my $desctosearch;

	debug("Entering subroutine: getDescription($desctoget,$mode)",4,__LINE__);

	debug("Getting Description for [$desctoget] ==> \$::usedesc=[$::usedesc]",3,__LINE__);

	# Clear variables, in case they're being re-used
	$::shortdesc=$::longdesc=$::owner="";

	# Haven't found a description yet.
	$::founddesc=0;

	# See if description exists
	if ($::usedesc && $desctoget)
	{

		# Clear $desctoget if it was just set as a placeholder
		if ($desctoget eq "./")
		{
			$desctoget="";
		}

		$desctosearch=quotemeta($desctoget);

		# Rewind description file
#		seek(DESC,SEEK_SET,0); # Original (pre strict)
		seek(DESC,0,0);

		# Reset for search
		$prevline=$::desc_delim;

		while ($descline=<DESC>)
		{
			chomp($descline);

			# Doing search
			if ($mode && ($::searchdescriptions || $::searchowners))
			{
				if ($::searchdescriptions)
				{
					if ($descline=~/$::searchstring/i && $prevline ne $::desc_delim)
					{
						debug("Found a MATCH (description) of $::searchstring in $descline for object $desctoget$filename",4,__LINE__);
						push @::searchresults,"$desctoget$filename";
					}
				}

				# Store off filenames and check owners
				if ($prevline eq $::desc_delim)
				{
					($filename,$tempowner)=split(":",$descline);
					if ($tempowner=~/$::searchstring/ && $::searchowners)
					{
						debug("Found a MATCH (owner) of $::searchstring in $descline for object $desctoget$filename",4,__LINE__);
						push @::searchresults,"$desctoget$filename";
					}
				}

				$prevline=$descline;
			}

			# Found the description we're looking for (not via the search screen)
			if ($descline=~/^$desctosearch$/i || $descline=~/^$desctosearch:.*$/i)
			{
				$::owner=$descline;
				$::owner=~s/.*:(.*)/$1/;
				debug("$descline:$::owner",2,__LINE__);
				if ($::owner eq $descline)
				{
					$::owner="";
				}
				$descline=~s/(.*):.*/$1/;

				debug("$::owner owns $descline",2,__LINE__);
				$::shortdesc=<DESC>;
				chomp($::shortdesc);
				$::longdesc="";
				my $longdescline="";
				while (($::longdescline=<DESC>) && ($::longdescline!~/^$::desc_delim$/))
				{
					$::longdesc.=$::longdescline."<br>";
				}
				$::founddesc=1;
			}
		}
		if (!$::founddesc)
		{
			$::shortdesc=$::longdesc="";
			debug("No description found.",3,__LINE__);
		}
		debug("ShortDesc: [$::shortdesc]",3,__LINE__);
		debug("LongDesc: [$::longdesc]",3,__LINE__);
	}

	debug("Leaving subroutine: getDescription($desctoget,$mode)",4,__LINE__);

}


##########################################################################

=head3 buildDescFooter()

 $add_desc_footer=buildDescFooter($status);

 $add_desc_footer - The HTML code for adding a description, which is returned.
 $status - 0 if building the whole form, 1 if building it as part of another form (like the create album form, for example).

Creates $directory in $basedir, and updates the description with $::shortdesc and $::longdesc.

=cut
sub buildDescFooter
{
my $add_desc_footer;
my $status=shift;

		# Form for entering a new description

	if (!$status)
	{
		$add_desc_footer=<<HTML;
<form name="descriptionform" method=\"post\" action=\"$::albumprog\">
HTML
		$add_desc_footer.="<table width=382 border=0 cellpadding=0 cellspacing=1 bgcolor=#868686 align=center><tr><td bgcolor=#F3F3F3><table width=380 border=0 cellpadding=0 cellspacing=0 class=meniphoto><tr><td height=9 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=176 height=18><div align=right>";
	}
	
	#$add_desc_footer.="<table width=382 border=0 cellpadding=0 cellspacing=1 bgcolor=#868686><tr><td bgcolor=#F3F3F3><table width=380 border=0 cellpadding=0 cellspacing=0 class=meniphoto><tr><td height=9 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=176 height=18><div align=right>";

	$add_desc_footer.="$::S{190}&nbsp;\n";

	if (!$status)
	{
		# Where do we go when we click submit?
		$add_desc_footer.="<input type=\"hidden\" name=\"";
#		if ($::album || isAMovie($::next_obj))

		debug("Checking to see what type of object this is: $::album_dir -- $::realgoback -- $::next_obj",2,__LINE__);

		if (($::next_obj && -d "$::album_dir/$::realgoback/$::next_obj") || isAMovie($::next_obj) || (!$::next_obj && $::album))
		{
			$add_desc_footer.="album";
		}
#		elsif ($::photo || isAPhoto($::next_obj))
		elsif (isAPhoto($::next_obj) || (!$::next_obj && $::photo))
		{
			$add_desc_footer.="photo";
		}
		$add_desc_footer.="\" value=\"";

		# If the next object is a photo, go to it.
		if (isAPhoto($::next_obj))
		{
			$add_desc_footer.="$::realgoback/$::next_obj";
		}
		elsif (isAMovie($::next_obj))
		{
			$add_desc_footer.="$::realgoback";
		}
		else
		{
			$add_desc_footer.="$::middle";
		}
		$add_desc_footer.="\">\n";

		# Where do we go when we click submit?
		if (isAPhoto($::next_obj))
		{
			$add_desc_footer.="<input type=\"hidden\" name=\"photo2\" value=\"";
			if ($::photo)
			{
				$add_desc_footer.="$::photo";
			}
			if ($::album)
			{
				$add_desc_footer.="$::album";
			}
			$add_desc_footer.="\">\n";
		}

		$add_desc_footer.="<input type=\"hidden\" name=\"desc_file_loc\" value=\"$::desc_to_update\">\n";
		$add_desc_footer.="<input type=\"hidden\" name=\"object\" value=\"$::shortobject\">\n";
	}

	if (!$status)
	{
		# Set the correct function
		$::function=$::update_desc;
		$add_desc_footer.=passVars(1);

		# Now set it back
		$::function=$::enter_desc;
	}
	
	$add_desc_footer.="</div></td><td width=204 height=18>";


	$add_desc_footer.="<input type=\"text\" name=\"title\" size=\"30\" value=\"$::existing_shortdesc\" class=titletextbox>\n";

	# Add userlist
#	$add_desc_footer.=$::S{299}." ";
#	$add_desc_footer.=getUserList()."<br>\n";

	$add_desc_footer.="</tr><tr><td height=10 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=176 valign=top><div align=right><table width=100% border=0 cellpadding=0 cellspacing=0 class=meniphoto><tr><td height=18><div align=right>";

	$add_desc_footer.="$::S{191}\n";

	$add_desc_footer.="&nbsp;</div></td></tr></table></div></td><td height=90>";

	$add_desc_footer.="<textarea rows=\"$::enterdesc_rows\" name=\"description\" cols=\"$::enterdesc_cols\" class=desctextbox>$::textlongdesc</textarea>\n";
	
	$add_desc_footer.="</td></tr>";
	if (!$status)
	{

		if (!$form->param('editobject'))
		{
			$add_desc_footer.="<tr><td height=10 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr>";
			$add_desc_footer.="<tr><td height=13 colspan=2><div align=right><table width=380 border=0 cellpadding=0 cellspacing=0 class=meniphoto>";
			$add_desc_footer.="<tr><td width=352><div align=right>$::S{192}&nbsp;</div></td>";
			$add_desc_footer.="<td width=28><input type=checkbox \" name=\"stop_add_desc\" value=\"stop\" class=\"checkbox\"/></td></tr></table></div></td></tr>";
		}
		else
		{
			$add_desc_footer.="<tr><td colspan=2 height=0><input type=hidden \" name=\"stop_add_desc\" value=\"stop\" class=\"checkbox\"/></td></tr>";
		}
		
		$add_desc_footer.="<tr><td height=9 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr></table></td></tr></table>";
		# $add_desc_footer.="<input type=\"";

		# Just enter this one

		#if ($form->param('editobject'))
		#{
		#	$add_desc_footer.="hidden";
		#}
		#else
		#{
		#	$add_desc_footer.="checkbox";
		#}

		#$add_desc_footer.="\" name=\"stop_add_desc\" value=\"stop\" class=\"checkbox\"/>";

		#$add_desc_footer.="<input type=\"submit\" value=\"$::S{193}\" class=\"button\">";
		$add_desc_footer.="<table width=382 border=0 cellspacing=0 cellpadding=0 align=center><tr>";

		# If the next object is a photo, display the option to go to it.
		if (isAPhoto($::next_obj))
		{
			$add_desc_footer.="<td background=images/photo_izmjena_bg.gif align=center><input type=\"image\" src=images/button_izmijeni_idalje.gif width=239 height=9 name=\"advance\"></td>\n";
			$add_desc_footer.="<td width=87><div align=right><input name=imageField type=image src=images/button_izmijeni_idalje2.gif width=87 height=25 border=0></div></td></tr></table></form>\n";
		}
		else
		{
			$add_desc_footer.="<td><div align=right><input name=imageField type=image src=images/button_izmjeni.gif width=111 height=25 border=0></div></td></tr></table></form>\n";
		}
		$add_desc_footer.=<<HTML;
<SCRIPT LANGUAGE="javascript">
<!--
document.descriptionform.title.focus();
//-->
</SCRIPT>
HTML
	}

	return($add_desc_footer);
}


##########################################################################

=head3 updateDesc()

 updateDesc($myobject,$desc_file_loc,$title,$description,$myowner);

 $myobject - The object whose description is being updated
 $desc_file_loc - The location of the descfile to update
 $title - The new title to apply to the object
 $description - The new long description to apply to the object
 $myowner - The new owner of the object

Updates the $::descfile located in $desc_file_loc for the item $myobject, with the information passed in through the web form.

=cut
sub updateDesc
{
my $added_desc;
my $data;
my $skip;
my $oldowner;
my $olddata;
my $virtualfile;
my $myobject=shift;
my $desc_file_loc=shift;
my $title=shift;
my $description=shift;
my $myowner=shift;

	debug("Entering subroutine: updateDesc($myobject,$desc_file_loc,$title,$description,$myowner)",4,__LINE__);

	# Yep, so update the description file, and then display everything normally
	debug("Updating description for $myobject in $desc_file_loc. Title is [$title], description is [$description].",2,__LINE__);

	if (!$myobject || !$desc_file_loc)
	{
		error(__LINE__,"sanity","Not enough info to update description.");
	}

	# Open the description file specified
	openDescfile($desc_file_loc);

	# have not added desc
	$added_desc=0;

	# am not skipping
	$skip=0;

	# Clear "virtual file"
	$virtualfile="";

	while ($data=<DESC>)
	{
		chomp($data);
		debug("Data: [$data]; \$skip=$skip",4,__LINE__);

		$olddata=$data;

		# Pull out owner
		($data,$oldowner)=split(":",$data);

		debug("$oldowner owns $data",2,__LINE__);

		# Check to see if this is the one we want
		if ($data eq $myobject && !$skip)
		{
			debug("Found match: $data",3,__LINE__);

			# Make sure we can do this...
			if ($::function eq $::update_desc || $::function eq $::admin || (($myowner eq $::loggedin || $::default_admins=~/(.*,)*$::loggedin(,.*)*/) && $::loggedin) && $::username eq $albumuser[3])
			{

				debug("Updating Description...",3,__LINE__);

				# If nobody is taking control of this, and someone already owned it, then don't clear the owner
				if (!$myowner && $oldowner)
				{
					$myowner=$oldowner;
				}

				$virtualfile.=$myobject;
				if ($myowner)
				{
					debug("Writing Owner: $myowner",3,__LINE__);
					$virtualfile.=":$myowner";
				}
				else
				{
					debug("No owner provided",3,__LINE__);
				}
				$virtualfile.="\n";
				$virtualfile.=$title;
				$virtualfile.="\n";
				if ($description)
				{
					$virtualfile.=$description;
					$virtualfile.="\n";
				}

				# skip reading until the next $::desc_delim
				$skip=1;
			}

			# don't re-add the desc at the end
			$added_desc=1;
		}

		# we found the next entry, stop skipping
		if ($skip && ($data eq $::desc_delim))
		{
			debug("Stopped skipping.",4,__LINE__);
			$skip=0;
		}

		# Only write if we're not skipping
		if (!$skip)
		{
			debug("Wrote: $olddata",4,__LINE__);
			$virtualfile.="$olddata\n";
		}
	}

	# If the description wasn't added, do it now.
	if (!$added_desc)
	{
		debug("No description found, adding one.",4,__LINE__);
		$virtualfile.="$::desc_delim\n";
		$virtualfile.=$myobject;
		if ($myowner)
		{
			debug("Writing Owner: $myowner",3,__LINE__);
			$virtualfile.=":$myowner";
		}
		else
		{
			debug("No owner provided",3,__LINE__);
		}
		$virtualfile.="\n";
		$virtualfile.=$title;
		$virtualfile.="\n";
		if ($description)
		{
			$virtualfile.=$description;
			$virtualfile.="\n";
		}
	}

	close(DESC);

	# Re-open descfile and write out new contents
	open(DESC,">$desc_file_loc/$::descname") || error(__LINE__,"not_writable","$desc_file_loc/$::descname");
	print DESC $virtualfile;
	close(DESC);

	# Keep on updating
	$::function=$::enter_desc;

	debug("Leaving subroutine: updateDesc($myobject,$desc_file_loc,$title,$description,$myowner)",4,__LINE__);
}


##########################################################################

=head3 deleteDesc()

 deleteDesc($myobject,$desc_file_loc);

 $myobject - The object whose description is being deleted
 $desc_file_loc - The location of the descfile to modify

Deletes the entry for $myobject from the $::descfile located in $desc_file_loc.

=cut
sub deleteDesc
{
my $data;
my $skip;
my $oldowner;
my $olddata;
my $virtualfile="";
my $myobject=shift;
my $desc_file_loc=shift;

	# Yep, so update the description file, and then display everything normally
	debug("Deleting description for $myobject in $desc_file_loc.",2,__LINE__);

	if (!$myobject || !$desc_file_loc)
	{
		error(__LINE__,"sanity","Not enough info to delete description.");
	}

	# Open the description file specified
	openDescfile($desc_file_loc);

	# am not skipping
	$skip=0;

	while ($data=<DESC>)
	{
		chomp($data);
		debug("Data: [$data]; \$skip=$skip",4,__LINE__);

		$olddata=$data;

		# Pull out owner
		($data,$oldowner)=split(":",$data);

		debug("$oldowner owns $data",2,__LINE__);

		# Check to see if this is the one we want
		if ($data eq $myobject && !$skip)
		{
			debug("Found match: $data",3,__LINE__);

			# Make sure we can do this...
			if ($::function eq $::update_desc || $::function eq $::admin || (($::owner eq $::loggedin || $::default_admins=~/(.*,)*$::loggedin(,.*)*/) && $::loggedin) && $::username eq $albumuser[3])
			{

				debug("Deleting Description...",3,__LINE__);

				# skip reading until the next $::desc_delim
				$skip=1;
			}
		}

		# Only write if we're not skipping
		if (!$skip)
		{
			debug("Wrote: $olddata",4,__LINE__);
			$virtualfile.="$olddata\n";
		}

		# we found the next entry, stop skipping
		if ($skip && ($data eq $::desc_delim))
		{
			debug("Stopped skipping.",4,__LINE__);
			$skip=0;
		}
	}

	close(DESC);

	# Re-open descfile and write out new contents
	open(DESC,">$desc_file_loc/$::descname") || error(__LINE__,"not_writable","$desc_file_loc/$::descname");
	print DESC $virtualfile;
	close(DESC);

}


##########################################################################

=head3 uploadPhoto()

 uploadPhoto();

Called when a user wants to upload a photo. Shows the form and handles the file transfer.

=cut

sub uploadPhoto
{
my $myobject;
my $temp;

	debug("Entering subroutine: uploadPhoto()",4,__LINE__);

	openDescfile("$::album_dir/");
	getDescription($::rootalbumname);
	close(DESC);

	if (!$::shortdesc)
	{
		$::shortdesc=$::S{36};
	}

	if (!$::allow_uploads)
	{
		# print the HTML HEADER
		print <<HTML;
<head>
HTML

		if ($::style_sheet)
		{
			print <<HTML;
<link rel="stylesheet" type="text/css" href="$::style_sheet">
HTML
		}
		print <<HTML;
<h1>$::S{37}</h1>
<p>
$::S{38} <a href="$::albumprog">$::shortdesc</a>.
HTML
		exit(0);
	}

	# same as debug=3
	if ($::debug gt 2)
	{
		print "Displaying all form values:<p>";
		my @all=$query->param;
		my $name;
		foreach $name (@all)
		{
			print "<pre>Form Data: $name ->", $query->param($name),"</pre><br>\n";
		}
	}

	# Log the user in
	if ($query->param('userid'))
	{
		$::username=$query->param('userid');
	}
	if ($query->param('upload_password'))
	{
		$::password=$query->param('upload_password');
	}

	$myobject=buildTemplate();

	if ($query->param('upload_file1'))
	{

		debug("A photo is being uploaded.",2,__LINE__);

		my $em='';

		# import the paramets into a series of variables in 'q' namespace
		$query->import_names('q');
		#  check if the necessary fields are empty or not
		$em .= "<br>$::S{39}<br>" if !$q::userid;
		if (!$q::upload_password && $::authentication_type)
		{
			$em .= "$::S{40}<br>"
		}
		$em .= "$::S{41}<br>" if !$q::upload_file1;

		print $myobject;

		if ($em)
		{
			error(__LINE__,"upload_error",$em);
		}

		if (!Authenticate($::block_ubb_junior_members_from_uploading))
		{
			error(__LINE__,"upload_error","$::S{42} $q::userid");
		}

		# Check to see if the user is a guest
		if (isGuest())
		{
			error(__LINE__,"upload_error","$::S{298}");
		}

		# now upload files
		for($temp=1;$temp<=$::concurrent_uploads;$temp++)
		{
			if ($query->param("upload_file$temp"))
			{
				fileUpload($temp);
			}
		}
	}
	else
	{
		debug("No photo is being uploaded.",2,__LINE__);

		print $myobject;
	}

	debug("Leaving subroutine: uploadPhoto()",4,__LINE__);

}


##########################################################################

=head3 showUploadForm()

 $upload_form=showUploadForm();

 $upload_form - Variable to return completed upload form into.

Returns the upload form, so it can be substituted into the template.

=cut

sub showUploadForm()
{
my $upload_form;
my $temp;
my $spacer;

	debug("Entering subroutine: showUploadForm()",4,__LINE__);

	$upload_form="<form method=\"post\" action=\"$::albumprog\" enctype=\"multipart/form-data\">\n";

	$upload_form.="<table width=493 border=0 align=center cellpadding=0 cellspacing=1 bgcolor=#868686>\n";

	# userid field
	$upload_form.="<tr><td height=44 bgcolor=F3F3F3><table width=491 border=0 cellpadding=0 cellspacing=0 class=sivitext><tr><td width=110><strong>&nbsp;&nbsp;&nbsp;&nbsp;\n";

	# Display name/userid depending on if we're using anonymous uploads or not
	if ($::authentication_type)
	{
		$upload_form.="$::S{55}\n";
	}
	else
	{
		$upload_form.="$::S{56}\n";
	}
	$upload_form.="</strong></td><td width=166>\n";

	# Get cookie info, if present
#	$::username=$::password="";

	debug("Username/Pass before cookieLogin: $::username/$::password",4,__LINE__);

	cookieLogin();

	debug("Username/Pass after cookieLogin: $::username/$::password",4,__LINE__);

	$upload_form.="<input type=\"text\" name=\"userid\" value=\"$::username\" class=logintextbox>\n";
	$upload_form.="<input type=\"hidden\" name=\"username\" value=\"$::username\">\n";
	$upload_form.=passVars(1);
	$upload_form.="</td><td width=68><div align=right><strong>\n";

	# Don't display password field if we're using anonymous uploads
	if ($::authentication_type)
	{
		# password field
		$upload_form.="$::S{57}\n";
		$upload_form.="&nbsp;&nbsp;</strong></div>\n";
	}
	$upload_form.="</td><td width=152>\n";

	if ($::authentication_type)
	{
		$upload_form.="<input type=\"password\" name=\"upload_password\" value=\"$::password\" class=logintextbox>\n";
		$upload_form.="<input type=\"hidden\" name=\"password\" value=\"$::password\" size=\"20\">\n";
	}
		$upload_form.="</td></tr></table></td></tr>\n";

	# Set indent spacer
	if ($::concurrent_uploads gt 1)
	{
		$spacer="&nbsp;&nbsp;&nbsp;";
	}

	# Get Category List, by recursively searching all dirs (stored in $::object)
	if (!$::per_member_upload || isAdmin())
	{
		debug("About to call the recuriveScan($::album_dir)",2,__LINE__);

		$::doing_upload=1;
		recursiveScan($::album_dir);
		$::doing_upload=0;
	}

	debug("Returned from the recuriveScan($::album_dir)",2,__LINE__);

	for($temp=1;$temp<=$::concurrent_uploads;$temp++)
	{
		debug("Iterating in upload file loop #$temp.",3,__LINE__);

		# file field
		$upload_form.="<tr><td bgcolor=F3F3F3><table width=491 border=0 cellpadding=0 cellspacing=0 class=sivitext><tr><td height=19 colspan=4 bgcolor=#D3D3D3><strong>&nbsp;&nbsp;&nbsp;&nbsp;\n";
		$upload_form.="$::S{58}$temp$::S{221}\n";
		$upload_form.="</strong></td></tr><tr><td height=12 colspan=4><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=11><img src=images/spacer.gif width=1 height=1></td><td width=208 valign=top><table width=208 height=107 border=0 cellpadding=0 cellspacing=0 class=sivitext><tr><td height=18 colspan=2>\n";
		$upload_form.="<input type=\"file\" name=\"upload_file$temp\" class=browsebox>";

		$upload_form.="</td></tr><tr><td colspan=2>&nbsp;</td></tr><tr><td width=73 height=18><strong>$::S{59}</strong></td><td width=135 height=18>\n";

		# Use "per member" upload directories
#		if ($::per_member_upload && ($::authentication_type eq 2))
		if (!$::per_member_upload || isAdmin())
		{
			$upload_form.=<<HTML;
<select name="category$temp" class="uploadkatbox">
HTML

			$upload_form.=<<HTML;
$::object
</select>
HTML
		}
		else
		{
			$upload_form.="<input type=\"hidden\" name=\"category$temp\" value=\"per_member_upload\">"
		}

		$upload_form.="</td></tr><tr><td colspan=2>&nbsp;</td></tr><tr><td height=18 colspan=2><table width=208 border=0 cellpadding=0 cellspacing=0 class=sivitext><tr><td width=53><strong>$::S{60}</strong></td><td width=155>";

		$upload_form.=<<HTML;
<input type="text" name="title$temp" class="logintextbox">
</td>
</tr>
</table></td>
</tr>
</table></td>
<td width=37 valign=top><strong>$::S{61}</strong></td>
<td width=235>
<textarea name="description$temp" class="descuploadbox">
</textarea>

</td>
        </tr>
        <tr> 
          <td height=14 colspan=4><img src=images/spacer.gif width=1 height=1></td>
        </tr>
      </table></td>
  </tr>
HTML
	}
$upload_form.="</table>\n";
	
	#$upload_form.="<tr>\n";
	#$upload_form.="<td colspan=\"2\" align=\"center\">\n";
	$upload_form.="<table width=493 border=0 align=center cellpadding=0 cellspacing=0><tr><td><div align=right>";
	$upload_form.="<input name=.submit type=image src=images/button_nastavak.gif width=111 height=25 border=0></div></td></tr></table>";
	#$upload_form.="<input type=\"submit\" name=\".submit\" value=\"$::S{62}\" class=\"button\">";
	#$upload_form.="</td>\n";
	#$upload_form.="</tr>\n";
	$upload_form.=<<HTML;
<input type="hidden" name="function" value="$::upload">
HTML
	if ($::debug)
	{
		$upload_form.=<<HTML;
<input type="hidden" name="$::debug_code" value="$::debug">
HTML
}

	#$upload_form.="</table>\n";
$upload_form.="</form>\n";
	
	debug("Leaving subroutine: showUploadForm()",4,__LINE__);

	return($upload_form);
}


##########################################################################

=head3 fileUpload()

 fileUpload($count);

 $count - The file number to process (must be between 1 and $::concurrent_uploads).

Handles the nitty gritty file upload stuff. Called once for each file to upload.

=cut

sub fileUpload
{
my $count=shift;
my $bytes_read=0;
my $size='';
my $buff='';
my $start_time;
my $time_taken;
my $filename='';
my $write_file='';
my $user_quota;
my $system_call;
my $height;
my $width;
my $height2;
my $width2;
my $filepath;
my $photo_title;
my $photo_desc;
my $category;
my $temp;
my $logname;
my $output;
my $dirtomk;

$temp=$query->param("upload_file$count");
eval("\$filepath=\$temp");
$temp=$query->param("title$count");
eval("\$photo_title=\$temp");
$temp=$query->param("description$count");
eval("\$photo_desc=\$temp");
$temp=$query->param("category$count");
eval("\$category=\$temp");
my $errflag=0;

	debug("Entering subroutine: fileUpload($count);",4,__LINE__);

	debug("\$filepath: $filepath",3,__LINE__);
	debug("\$category: $category",3,__LINE__);
	debug("\$photo_title: $photo_title",3,__LINE__);
	debug("\$photo_desc: $photo_desc",3,__LINE__);


	if ($filepath =~ /([^\/\\]+)$/)
	{
		$filename="$1";
	}
	else
	{
		$filename="$filepath";
	}
	# Convert spaces to _'s and strip out any prohibited charactes in the filename
	$filename=~s/\s+/_/g;
	$filename=~tr/a-zA-Z0-9_./ /c;
	$filename=~s/\s+//g;

	# Is $::per_member_upload on? If so, change the category, and create the directory if it's not already there.
	if ($category eq "per_member_upload")
	{
		# UBB categories are user numbers, all others are user names
		if ($::authentication_type eq 2)
		{
			$category=$::usernumber;
		}
		else
		{
			$category=$::username;
		}

		chomp($category);

		# Fix provided by PattayaPete (junk@freelancerbar.com)
		$category=~s/^\s*(\S+)\s*$/$1/g;

		my $tempdir=$::album_dir;

		if ($::member_subdir)
		{
			$tempdir="$::album_dir/$::member_subdir";
			chomp($tempdir);
			debug("Using \$::member_subdir, so target directory is now $tempdir",2,__LINE__);
		}

		$dirtomk="$tempdir/$category";
		chomp($dirtomk);

		# Create directory for user, if not already present
		if (!(-d $dirtomk))
		{
			if (createAlbum($::member_subdir,$category,$::displayname,"$::S{201} $::displayname$::S{226}",$::loggedin,1))
			{
				print javaAlert("$::S{28} $dirtomk");
				return;
			}
		}
		else
		{
			# Get quota by doing a scan
			recursiveScan($dirtomk);
		}

		# Fix up the category now so things work correctly from here on in...
		$category=$::member_subdir."/".$category;

	}

	# Check for any fooling around
	if (!(-d "$::album_dir/$category"))
	{
		error(__LINE__,"sanity","$::S{63} ($::album_dir/$category)");
	}

	$write_file="$::album_dir/$category"."/"."$filename";

	debug("Filename=$filename",2,__LINE__);
	debug("Writefile=$write_file [$::member_subdir]",2,__LINE__);

	debug("Checking to see if $write_file is a photo.",2,__LINE__);

	$::object=0;

	# Check file type
	if (!(isAPhoto($write_file) || (isAMovie($write_file) && $::movie_upload)))
	{
		print javaAlert("$::S{25} $::S{64} $filename $::S{65}");
		$errflag=1;
		return;
	}

	# Don't overwrite, if not allowed
	if (!$::upload_overwrite)
	{
		if (-e $write_file)
		{
			print javaAlert("$::S{25} $::S{46} $filename $::S{66}");
			$errflag=1;
			return;
		}
	}

	# Open file for writing
	if (!open(WFD,">$write_file"))
	{
		print javaAlert("$::S{25} $::S{67} $write_file $::S{68}");
		return;
	}

	$start_time=time();
	debug("Starting upload of [$filepath] into [$write_file] at time $start_time...",2,__LINE__);
	while ($bytes_read=read($filepath,$buff,2096))
	{
		$size+=$bytes_read;
		debug("Uploading $size bytes so far...",3,__LINE__);
		debug("Buffer contains [$buff]",4,__LINE__);
		binmode WFD;
		print WFD $buff;
	}

	debug("size=$size",2,__LINE__);

	close(WFD);

	# Check to see if file exceeds set limit
	if ($size>($::upload_size_limit*1024))
	{
		unlink($write_file);
		print javaAlert("$::S{25} $::S{69} $::upload_size_limit $::S{70}.");
		$errflag=1;
		return;
	}

	# Check to see if the user has exceeded their quota
	$user_quota=$::temp_quota_total+$size;
	debug("User's current used quota is $user_quota. They are allowed $::quota Kb.",2,__LINE__);

	if ($::per_member_upload && $::quota && ($user_quota > ($::quota*1024)))
	{
		unlink($write_file);
		print javaAlert("$::S{71} $::quota $::S{70} $::S{72}");
		$errflag=1;
		return;
	}

	$time_taken=(stat $write_file)[7];

	# Check to see if file is greater than size zero
	if ($time_taken <= 0)
	{
		unlink($write_file);
		print javaAlert("$::S{73} $filename $::S{75}$::S{74} $time_taken$::S{76}");
		$errflag=1;
		return;
	}
	else
	{
		print javaAlert("$::S{46} $filename $::S{77} $size $::S{78}");

		$time_taken=time()-$start_time;

		chomp($::displayname);

		# Update the description for this new photo
		updateDesc($filename,"$::album_dir/$category/",$photo_title,"$photo_desc<p><small><small>$::S{79} $::displayname$::S{226}</small></small>",$::loggedin);

		debug("updateDesc($filename,\"$::album_dir/$category/\",$photo_title,\"$photo_desc<p><small><small>$::S{79} $::displayname$::S{226}</small></small>\",$::loggedin);",3,__LINE__);

		$time_taken=0;

		# Set full filename
		$filepath="$::album_dir/$category/$filename";

		# If desired, resize the photo
		if ($::pic_resize)
		{
			# Only resize "large" pics
			if (!$::always_pic_resize)
			{
				# Check the size of the pic
				$system_call="\"$::imagemagick/identify\" -verbose \"$filepath\"";
				debug("IMAGEMAGICK: $system_call",2,__LINE__);

				open(IMAGEMAGICK,"$system_call|") || error(__LINE__,"cant_fork","$system_call: $!");
				$time_taken=1;
				while (($buff=<IMAGEMAGICK>) && $time_taken)
				{
					debug("$filename: $buff",4,__LINE__);
					if ($buff=~/\s*Geometry:\s+(.*)/)
					{
						$time_taken=0;
						$height=$width=$1;
						$width=~s/([^x]+)x([^x]+)/$1/;
						$height=~s/([^x]+)x([^x]+)/$2/;
					}
				}
				close(IMAGEMAGICK);

				# Pick out pic_resize height/width
				$height2=$width2=$::pic_resize;
				$width2=~s/([^x]*)x([^x]*)/$1/;
				$height2=~s/([^x]*)x([^x]*)/$2/;
				debug("Preferred image size is as follows: $width2 wide by $height2 high.",2,__LINE__);
				debug("$filename size is as follows: $width wide by $height high.",2,__LINE__);

				$time_taken=0;

				# Compare size to requested size
				if ((($height > $height2) && $height2) || (($width > $width2) && $width2))
				{
					# The uploaded pic is bigger on at least one dimension, so resize is required
					$time_taken=1;
					debug("Picture is big, and needs to be scaled down.",2,__LINE__);
				}
			}
			else
			{
				$time_taken=1;
			}

			# Pic is being resized
			if ($time_taken)
			{
				$::thumb_quality="";
				$::thumb_width="";
				$start_time=genThumb($filepath,$filepath,1);
			}
		}

		# Some extra processing, if the file was uploaded properly
		if (!$errflag)
		{
		my $sysdate;

			# Log upload
			if ($::upload_logfile)
			{
				if ($::displayname)
				{
					$logname=$::displayname;
				}
				else
				{
					$logname=$::username;
				}

				$sysdate=setDate(time,1);

				open(UPLOADLOG,">>$::upload_logfile") || error(__LINE__,"cant_append","$::upload_logfile: $!");
				print UPLOADLOG "$sysdate	$ENV{'REMOTE_ADDR'}	$logname	$category/$filename\n";
				close(UPLOADLOG);
			}

			# If there's an extra upload command, run it now
			if ($::postupload)
			{
			my $tempobject="";
			my $tempcommand=$::postupload;

				# Convert ####OBJECT#### into the photo's full path
				$tempcommand=~s/####OBJECT####/"$filepath"/g;

				$tempobject="$filepath.$$";

				if (!-e $tempobject)
				{
					$tempcommand.=" \"$tempobject\"";
				}

				debug("Running postupload task: $tempcommand",2,__LINE__);

				$output=`$tempcommand 2>&1`;
				debug("POSTUPLOAD RETURNED: $output",2,__LINE__);

				if ($output)
				{
					print "$::S{18} $output<p>";
				}

				# If an object was created, replace the original with the new
				if (-e $tempobject)
				{
					unlink($filepath);

					if (!rename($tempobject,$filepath))
					{
						print "$::S{150} $tempobject $::S{219}";
					}
				}
			}
		}
	}
	debug("Leaving subroutine: fileUpload($count);",4,__LINE__);
}


##########################################################################

=head3 showFooter()

 $footer=showFooter($show);

 $show - If set to 0, the footer simply returned, if set to 1, it is displayed and returned.

Rerturns or displays the HTML footer for all pages.

=cut

sub showFooter
{
my @allinfo;
my $revdate;
my $show=shift;

if ($::create_html_flag)
{
	$revdate=setDate();
	$revdate="$::S{80} $revdate";
}
else
{
	@allinfo=stat($0);
	$revdate=localtime($allinfo[9]);
}

my $footer="<p>\n<small><small><a title=\"album.pl\n$::release Release\nWritten by Mike Bobbitt\n$revdate\" href=\"";

if ($::create_html_flag)
{
	$footer.="http://perl.Bobbitt.ca/album";
}
else
{
	$footer.="$::albumprog?function=about";
}

	$footer.=<<HTML;
">$::S{95} V$::ver</a></small></small>
</p>
HTML

	# Check to see if the version is correct
	if (($::cfgver ne $::ver) && (($form->param('function') ne "$::config") && ($form->param('function') ne "$::updateconfig")))
	{
		$::warning.="$::S{81} $::cfgver $::S{82} $::ver $::S{83}<br>";
	}

	if ($::warning)
	{
		$footer.="<div class=\"warning\">$::warning</div>";
	}

	if ($show)
	{
		display($footer);
	}
	return($footer);
}


##########################################################################

=head3 buildTemplate()

 $template=buildTemplate();

 $template = variable to pass the template back into

Builds the object template, and returns it.

=cut
sub buildTemplate
{
my $template;
my $shortdesctitle;
my $template_loaded;

	$template_loaded=0;

	# Photo template
	if ($::photo)
	{
		open(TEMPLATE,"$::photo_template") || error(__LINE__,"not_readable","$::photo_template: $!");
		debug("Using Template File: [$::photo_template]",2,__LINE__);
		$template_loaded=1;
	}

	# Upload Template
	if ($::function eq $::upload)
	{
		open(TEMPLATE,"$::upload_template") || error(__LINE__,"not_readable","$::upload_template: $!");
		debug("Using Template File: [$::upload_template]",2,__LINE__);
		$template_loaded=1;
	}
	if ($::function eq "upute")
	{
		open(TEMPLATE,"$::upute_template") || error(__LINE__,"not_readable","$::upute_template: $!");
		debug("Using Template File: [$::upute_template]",2,__LINE__);
		$template_loaded=1;
	}

	# Login Template
	if (($::function eq $::login_code) && !$::authenticated)
	{
		open(TEMPLATE,"$::login_template") || error(__LINE__,"not_readable","$::login_template: $!");
		debug("Using Template File: [$::login_template]",2,__LINE__);
		$template_loaded=1;
	}

	# Album template
	if (!$template_loaded)
	{
		open(TEMPLATE,"$::album_template") || error(__LINE__,"not_readable","$::album_template: $!");
		debug("Using Template File: [$::album_template]",2,__LINE__);
	}

	$template=join("",<TEMPLATE>);
	close(TEMPLATE);

	debug("Loaded object_template: [$template]",4,__LINE__);

	# Cut out HTML for title
	$shortdesctitle=$::shortdesc;
	$shortdesctitle=~s/<([^>]|\n)*>//g;
	if (!$shortdesctitle)
	{
		$shortdesctitle="$::S{87}";
	}

	# Handle SSI pages by ripping out file includes. It's rough, but it works.
	if ($::ssi)
	{
		$template=~s/####FILE=[^#]*####//g;

		# Also rip out long desciption tags
		$template=~s/####DESCRIPTION####//g;

		# ...and if we're doing a slideshow, we have to re-insert that stuff...
		if ($::slide_timer)
		{
			$template="####SLIDESHOW####$template";
		}

		# Re-add stylesheet tag
		$template="####STYLESHEET####$template";
	}

	# Substitute tags for actual data
	$template=substituteData($template);

	# Adjust style sheet link for static HTML (best when not burning to CD)
	if ($::create_html_flag)
	{
		#$template=~s/$::style_sheet/$::album_dir$::style_sheet/g;
	}

	return($template);
}


##########################################################################

=head3 buildNavFooter()

 $nav_footer=buildNavFooter();

Builds the navigaction footer, and returns it. (The navigation footer is the buttons/links that allow you to visit the next/previous photo or album.)

=cut
sub buildNavFooter
{
my $nav_footer;
my $temp;
my $static_photos_thumb_temp;
my $albumtemp;
my $isalbumtemp;
my $dotdot;

# Max length of button descriptions
my $desclen=25;

	debug("Entering subroutine: buildNavFooter()",4,__LINE__);

	debug("\$::page = [$::page]",2,__LINE__);
	debug("\$::numfiles = [$::numfiles]",2,__LINE__);
	debug("\$::photos_per_page = [$::photos_per_page] [$::rows]x[$::columns]",2,__LINE__);
	debug("\$::filenum = [$::filenum]",2,__LINE__);
	debug("\$::photo = [$::photo]",2,__LINE__);

	# Crappy modulo code that I wrote on the bus
	if ($::photo && $::photos_per_page)
	{
		debug("In the loop",2,__LINE__);
		$::page=1;
		while ($::filenum > $::photos_per_page)
		{
			$::page++;
			$::filenum-=$::photos_per_page;
			debug("Incrementing page to $::page [$::filenum]",2,__LINE__);
		}
	}
	debug("\$::page = [$::page]",2,__LINE__);

	$nav_footer="<div class=\"navwidth\">\n";

	debug("\$::prev_obj = [$::prev_obj]",2,__LINE__);

	# Display the "previous photo" link/button
	if ($::prev_obj)
	{
		# Text link and prev photo thumbnail
		if (!$::usebuttons || $::nextprevthumb)
		{
			$nav_footer.="<a href=\"";
			if (!$::create_html_flag)
			{
				$temp="";
				if ($::realgoback)
				{
					$temp="$::realgoback/";
				}
				$temp.=$::prev_obj;
				$temp=webifyLinks($temp);
				$nav_footer.="$::albumprog?";
				if (isAPhoto($::prev_obj) || isAMovie($::prev_obj))
				{
					$nav_footer.="photo";
				}
				else
				{
					$nav_footer.="album";
				}
				$nav_footer.="=$temp";
				$nav_footer.=passVars(0);
			}
			else
			{
				# Check to see if it's a photo or an album
				if (isAPhoto($::prev_obj) || isAMovie($::prev_obj))
				{
					$nav_footer.="$::prev_obj.html";
				}
				else
				{
					$nav_footer.="../$::prev_obj/$::static_html_filename";
				}
			}
			$nav_footer.="\" class=\"navlink\">\n";

			$static_photos_thumb_temp=$::static_photos_thumb;

			# Show previous object thumbnail
			if ($::nextprevthumb)
			{
				$albumtemp=$::album;
				if ($::album)
				{
					$::album=~s/(.*)\/.*/$1/;
				}
				$isalbumtemp=$::isalbum;
				$::isalbum=1;
				$temp=showThumb("$::realgoback/$::prev_obj");

				$nav_footer.=$temp;
				$::isalbum=$isalbumtemp;
				$::album=$albumtemp;

				# Align description
				if ($::descloc eq 1)
				{
					$nav_footer.="<br>\n";
				}
			}

			$::static_photos_thumb=$static_photos_thumb_temp;

			if (!$::usebuttons)
			{
				if ($::prev_obj_desc)
				{
					$nav_footer.="$::prev_obj_desc";
				}
				else
				{
					$nav_footer.="$::S{88}";
				}
			}
			$nav_footer.="</a>\n";
		}

		if ($::usebuttons)
		{
			$nav_footer.="<form method=\"post\" action=\"$::albumprog\">\n";
			$nav_footer.="<input type=\"submit\"";
			$nav_footer.=" value=\"$::S{89} ";
			if ($::prev_obj_desc)
			{
				# Strip out quotes
				$temp=$::prev_obj_desc;
				$temp=~s/"//g;
				debug("Length of $temp is ".length($temp)." and has a max of $desclen.",2,__LINE__);
				if (length($temp) > $desclen)
				{
					$temp=substr($temp,0,$desclen-3);
					$temp.=$::S{233};
				}

				$nav_footer.=$temp;
			}
			else
			{
				$nav_footer.="$::S{88}";
			}
			$nav_footer.="\" class=\"button\">\n<input type=\"hidden\" name=\"";
			if (isAPhoto($::prev_obj) || isAMovie($::prev_obj))
			{
				$nav_footer.="photo";
			}
			else
			{
				$nav_footer.="album";
			}
			$nav_footer.="\" value=\"";
			if ($::realgoback)
			{
				$nav_footer.="$::realgoback/";
			}
			$nav_footer.="$::prev_obj\">\n";
		}
		$nav_footer.=passVars(1);

		if ($::usebuttons)
		{
			$nav_footer.="</form>";
		}
	}

	$nav_footer.="</div>\n";
	$nav_footer.="<div class=\"navwidth\">\n";

	debug("\$::middle = [$::middle]",2,__LINE__);

	# Display the "back to album" link/button
	if ($::middle)
	{
		$static_photos_thumb_temp=$::static_photos_thumb;

		# Text link and prev photo thumbnail
		if (!$::usebuttons || $::nextprevthumb)
		{
			$nav_footer.="<a href=\"";
			$temp="";
			if ($::realgoback)
			{
				$temp="$::realgoback/";
			}
#			$temp.=$tempobject; # Taken out from strict - there was no $tempobject defined!!

			if (!$::create_html_flag)
			{
				$temp=webifyLinks($temp);
				$nav_footer.="$::albumprog?";
				$nav_footer.="album";
				$nav_footer.="=$::goback";

				# If we're looking at a photo, find out what page it's on, and go back "up" to that page.
				if ($::photo && $::photos_per_page)
				{
					$nav_footer.=$::webdelim."page=$::page";
				}
				$nav_footer.=passVars(0);
			}
			else
			{
				if ($albumtemp)
				{
					$nav_footer.="../$::static_html_filename";
				}
				else
				{
					$nav_footer.="$::static_html_filename";
				}
			}
			$nav_footer.="\" class=\"navlink\">\n";

			# Show parent object thumbnail
			if ($::nextprevthumb)
			{
				$temp=$::middle;

				# Adjust for photos
				if ($::photo)
				{
					$temp=~s/(.*)\/.*/$1/;
				}

				$temp=showThumb("$temp",1);

				# Back up one!
				if ($::goback)
				{
					$temp=~s/$::thumbprefix$::goback/$dotdot..\/$::thumbprefix$::goback/;
				}

				$nav_footer.=$temp;

				# Align description
				if ($::descloc eq 1)
				{
					$nav_footer.="<br>\n";
				}
			}

			$nav_footer.="</a>\n";
		}

		$::static_photos_thumb=$static_photos_thumb_temp;

		if ($::usebuttons)
		{
			$nav_footer.="<form method=\"post\" action=\"$::albumprog\">\n";
			$nav_footer.="<input type=\"submit\"";
		}
		else
		{
			$nav_footer.="<a href=\"";
		}
		if ($::create_html_flag)
		{
			if ($::album)
			{
				$nav_footer.="../$::static_html_filename";
			}
			if ($::photo)
			{
				$nav_footer.="./$::static_html_filename";
			}
		}
		if ($::usebuttons)
		{
			$nav_footer.=" class=\"button\" value=\"";
			if ($::back_desc)
			{
				# Strip out quotes
				$temp=$::back_desc;
				$temp=~s/"//g;

				if (length($temp) > $desclen)
				{
					$temp=substr($temp,0,$desclen-3);
					$temp.=$::S{233};
				}

				$nav_footer.=$temp;
			}
			else
			{
				$nav_footer.="$::S{90}";
			}
			$nav_footer.="\">\n<input type=\"hidden\" name=\"album\" value=\"";
			$nav_footer.="$::goback";
			$nav_footer.="\">\n";
			$nav_footer.="<input type=\"hidden\" name=\"page\" value=\"$::page\">";
		}
		if (!$::create_html_flag && !$::usebuttons)
		{
			$nav_footer.="$::albumprog?album=$::goback";
		}
		$nav_footer.=passVars(1);

		if ($::usebuttons)
		{
			$nav_footer.="</form>";
		}
		else
		{
			$nav_footer.="\" class=\"navlink\">\n";
			if ($::back_desc)
			{
#				if ($::create_html_flag)
#				{
#					$nav_footer.="Back To Album";
					#### TODO This doesn't work for static, for some reason...
#				}
#				else
#				{
					$nav_footer.="$::back_desc";
#				}
			}
			else
			{
				$nav_footer.="$::S{90}";
			}
			$nav_footer.="</a>\n";
		}
	}

	$nav_footer.="</div>\n";
	$nav_footer.="<div class=\"navwidth\">\n";

	debug("\$::next_obj = [$::next_obj]",2,__LINE__);

	# Display the "next photo" link/button
	if ($::next_obj)
	{

		# Text link and next photo thumbnail
		if (!$::usebuttons || $::nextprevthumb)
		{
			$nav_footer.="<a href=\"";
			if (!$::create_html_flag)
			{
				$temp="";
				if ($::realgoback)
				{
					$temp="$::realgoback/";
				}
				$temp.=$::next_obj;
				$temp=webifyLinks($temp);

				$nav_footer.="$::albumprog?";
				if (isAPhoto($::next_obj) || isAMovie($::next_obj))
				{
					$nav_footer.="photo";
				}
				else
				{
					$nav_footer.="album";
				}
				$nav_footer.="=$temp";
				$nav_footer.=passVars(0);
			}
			else
			{
				if (isAPhoto($::next_obj) || isAMovie($::next_obj))
				{
					$nav_footer.="$::next_obj.html";
				}
				else
				{
					$nav_footer.="../$::next_obj/$::static_html_filename";
				}
			}
			$nav_footer.="\" class=\"navlink\">\n";

			$static_photos_thumb_temp=$::static_photos_thumb;

			# Show next object thumbnail
			if ($::nextprevthumb)
			{
				$albumtemp=$::album;
				if ($::album)
				{
					$::album=~s/(.*)\/.*/$1/;
				}
				$isalbumtemp=$::isalbum;
				$::isalbum=1;
				$temp=showThumb("$::realgoback/$::next_obj");

				$nav_footer.=$temp;
				$::isalbum=$isalbumtemp;
				$::album=$albumtemp;

				# Align description
				if ($::descloc eq 1)
				{
					$nav_footer.="<br>\n";
				}
			}

			$::static_photos_thumb=$static_photos_thumb_temp;

			if (!$::usebuttons)
			{
				if ($::next_obj_desc)
				{
					$nav_footer.="$::next_obj_desc";
				}
				else
				{
					$nav_footer.="$::S{91}";
				}
			}
			$nav_footer.="</a>\n";
		}

		if ($::usebuttons)
		{
			$nav_footer.="<form method=\"post\" action=\"$::albumprog\">\n";
			$nav_footer.="<input type=\"submit\"";
		}
		if ($::usebuttons)
		{
			$nav_footer.="  class=\"button\" value=\"";
			if ($::next_obj_desc)
			{
				# Strip out quotes
				$temp=$::next_obj_desc;
				$temp=~s/"//g;

				if (length($temp) > $desclen)
				{
					$temp=substr($temp,0,$desclen-3);
					$temp.=$::S{233};
				}

				$nav_footer.=$temp;
			}
			else
			{
				$nav_footer.="$::S{91}";
			}
			$nav_footer.=" $::S{92}\">\n<input type=\"hidden\" name=\"";
			if (isAPhoto($::next_obj) || isAMovie($::next_obj))
			{
				$nav_footer.="photo";
			}
			else
			{
				$nav_footer.="album";
			}
			$nav_footer.="\" value=\"";
			if ($::realgoback)
			{
				$nav_footer.="$::realgoback/";
			}
			$nav_footer.="$::next_obj\">\n";
		}
		$nav_footer.=passVars(1);

		if ($::usebuttons)
		{
			$nav_footer.="</form>";
		}
	}

	$nav_footer.="</div>";

	# New line
	$nav_footer.="<br clear=\"all\">";

	# Display jump station
	if ($::jump_to)
	{
		$nav_footer.=$::jump_station;
	}

	debug("Leaving subroutine: buildNavFooter()",4,__LINE__);

	return($nav_footer);
}



##########################################################################

=head3 passVars()

 $vars=passVars($format);

 $vars = variable to pass the formed variables back into
 $format = 0: pass in web URL format (&debug=1&configfile=file, etc); 1: pass in button format (<input type="hidden"...); 2: same as zero, but no function code

Sees which variables must be passed (configfile, debug, static, etc), builds the string containing the data, and passes the value back.

=cut
sub passVars
{
my $vars;
my $tempfunc;
my $format=shift;
my $mypass=$::password;
my $myuser=$::username;

	# If function=login or checkupdate, then clear it
	if ($::function eq $::login_code || $::function eq $::checkupdate)
	{
		$tempfunc=$::function;
		$::function="";
	}

	# Strip quotes out of username/password
	$myuser=~s/"//g;
	$mypass=~s/"//g;

#	if (!$::usebuttons)
#	{
#		$format=0;
#	}

	if (!$format || $format eq 2)
	{
		# Exclude function code, when called with $format=2
		if (!$format)
		{
			if ($::function)
			{
				$vars.=$::webdelim."function=$::function";
			}
		}
		if ($::slide_timer)
		{
			$vars.=$::webdelim."slideshow=$::slide_timer";
		}

		if ($::configfilepassed)
		{
			$vars.=$::webdelim."configfile=$::configfile";
		}
		if ($::debug)
		{
			$vars.=$::webdelim."$::debug_code=$::debug";
		}

		if ($::photo_width)
		{
			$vars.=$::webdelim."photo_width=$::photo_width";
		}
		if ($::photo_height)
		{
			$vars.=$::webdelim."photo_height=$::photo_height";
		}
		if ($::fullscreen)
		{
			$vars.=$::webdelim."fullscreen=1";
		}
		if ($::ssi)
		{
			$vars.=$::webdelim."ssi=$::ssi";
		}
		# Only pass username/password if we're not using flatfile authentication
#		if ($::authentication_type lt 2 || !$::cookielogin)
		if (!$::cookielogin)
		{
			if ($mypass)
			{
				$vars.=$::webdelim."password=$mypass";
			}
			if ($myuser)
			{
				$vars.=$::webdelim."username=$myuser";
			}
		}
	}
	else
	{
		if ($::function)
		{
			$vars.="<input type=\"hidden\" name=\"function\" value=\"$::function\">\n";
		}
		if ($::slide_timer_passed)
		{
			$vars.="<input type=\"hidden\" name=\"slideshow\" value=\"$::slide_timer\">\n";
		}
		if ($::configfilepassed)
		{
			$vars.="<input type=\"hidden\" name=\"configfile\" value=\"$::configfile\">\n";
		}
		if ($::debug)
		{
			$vars.="<input type=\"hidden\" name=\"$::debug_code\" value=\"$::debug\">\n";
		}
		if ($mypass)
		{
			$vars.="<input type=\"hidden\" name=\"password\" value=\"$mypass\">\n";
		}
		if ($myuser)
		{
			$vars.="<input type=\"hidden\" name=\"username\" value=\"$myuser\">\n";
		}
		if ($::photo_width)
		{
			$vars.="<input type=\"hidden\" name=\"photo_width\" value=\"$::photo_width\">\n";
		}
		if ($::photo_height)
		{
			$vars.="<input type=\"hidden\" name=\"photo_height\" value=\"$::photo_height\">\n";
		}
		if ($::fullscreen)
		{
			$vars.="<input type=\"hidden\" name=\"fullscreen\" value=\"1\">\n";
		}
		if ($::ssi)
		{
			$vars.="<input type=\"hidden\" name=\"ssi\" value=\"$::ssi\">\n";
		}	}

	# Restore function, if required
	if (!$::function)
	{
		$::function=$tempfunc;
	}

	return($vars);
}


##########################################################################

=head3 printHeader()

 $header=printHeader($mode);

 $header - The formed header, with style sheet or body colour tags, is returned.
 $mode - 0 = Return all header HTML; 1 = Return just style sheet tag

Prints out either the style sheet or a generic body tag.

=cut
sub printHeader
{
my $mode=shift;
my $html;
my $width;
my $padding;
my $float;

	if ($::style_sheet)
	{
		$html="<link rel=\"stylesheet\" type=\"text/css\" href=\"$::style_sheet\">\n";
	}
	$html.="<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-2\">";

	# If columns is not set yet, then give it a value, so we can show things properly
	if (!$::columns)
	{
		$::columns=5;
	}

	# Set the "float" properly, per browser
	if (detectBrowser())
	{
		# Mozilla
		$float="left";
	}
	else
	{
		# IE
		$float="none";
	}

	# Add style info for objects in an album, because width is dynamic
	$width=int(100/$::columns)-int($::column_spacing/3);
	$padding=$::column_spacing."px";

	$html.=<<HTML;
\n<style type="text/css">
.dynwidth	{ width: $width%; display: inline; padding: $padding; float: $float; }
</style>
HTML

	if (!$mode)
	{
		$html.="</head>\n<body bgcolor=\"#000000\" text=\"#FFFFFF\"";
		if (!$::style_sheet)
		{
			$html.=" link=\"#008000\" vlink=\"#800000\" alink=\"#0000FF\"";
		}
		$html.=">\n";
	}


	return($html);
}


##########################################################################

=head3 trackView()

 $current_views=trackView($currentphoto);

 $current_views - Returns a string containing the number of views and the last viewed date.
 $currentphoto - Photo to update views for.
 $mode - 0 = Update views; 1 = Don't update views

Updates the number of views and the last viewed date for the current photo in $::viewfile.

=cut
sub trackView
{
my $currentphoto=shift;
my $mode=shift;
my $updated_views;
my $data;
my $current_count;
my $this_count;
my $last_viewed_date;
my $read_date;
my $virtualfile="";
my $current_viewfile="$::album_dir/";
my $current_view_date=setDate();

	if ($::goback)
	{
		$current_viewfile.="$::goback/";
	}
	$current_viewfile.="$::viewfile";

	if (!$currentphoto)
	{
		debug("No photo selected, not updating views.",2,__LINE__);
		return();
	}

	debug("Entering subroutine: trackView($currentphoto,$mode);",4,__LINE__);

	debug("Updating views for $currentphoto in $current_viewfile",2,__LINE__);

	# Does it already exist?
	if (-e $current_viewfile)
	{
		# Open $::viewfile for reading
		if (!open(VIEWS,"$current_viewfile"))
		{
			$::warning.="$::S{20} <b>$current_viewfile</b><br>";
		}

		if (!-W "$current_viewfile")
		{
			$::warning.="$::S{23} <b>$current_viewfile</b><br>";
		}

		# have not updated views
		$updated_views=0;

		if ($::warning)
		{
			return;
		}

		while ($data=<VIEWS>)
		{
			# Check to see if this is the one we want
			if ($data=~/^$currentphoto\t.*/)
			{
				chomp($data);
				debug("Found match: $data",3,__LINE__);
				close(RATINGS);
				($current_count,$current_count,$read_date)=split("\t",$data);

				if ($read_date eq $data || !$read_date)
				{
					$read_date="$::S{93}";
				}
				debug("Data: [$data] --> Count:[$current_count] Date:[$read_date]",4,__LINE__);

				$this_count=$current_count;
				$this_count++;
				$last_viewed_date=$read_date;
				$virtualfile.="$currentphoto\t$this_count\t$current_view_date\n";

				# don't re-add the desc at the end
				$updated_views=1;
			}
			else
			{
				debug("Wrote: $data",4,__LINE__);
				$virtualfile.="$data";
			}
		}

		# If the photo didn't already hav an entry, add it now.
		if (!$updated_views)
		{
			debug("No entry found, adding one.",2,__LINE__);
			$virtualfile.="$currentphoto\t1\t$current_view_date\n";
		}

		close(VIEWS);

		# Update views if that's what we're doing
		if (!$mode)
		{
			# Re-open views file and write out new contents
			if (!open(VIEWS,">$current_viewfile"))
			{
				$::warning.="$::S{23} <b>$current_viewfile</b><br>";
				return();
			}
			print VIEWS $virtualfile;
			close(VIEWS);
		}
	}
	elsif (!$mode)
	{
		$last_viewed_date="";
		debug("$current_viewfile does not exist, creating...",2,__LINE__);
		if (!open(VIEWS,">$current_viewfile"))
		{
			$::warning.="$::S{23} <b>$current_viewfile</b><br>";
			return();
		}
		print VIEWS "$currentphoto\t1\t$current_view_date\n";
		close(VIEWS);
	}

	if (!$this_count)
	{
		$this_count=1;
	}

	$data="$::S{94} $this_count ";
	if ($this_count gt 1)
	{
		$data.="$::S{202}";
	}
	else
	{
		$data.="$::S{200}";
	}

	if (!$last_viewed_date)
	{
		$data.=" $::S{96}";
	}
	else
	{
		$data.=". $::S{97} $last_viewed_date.";
	}

	debug("Data is: $data",4,__LINE__);

	debug("Leaving subroutine: trackView($currentphoto,$mode);",4,__LINE__);

	return($data);
}


##########################################################################

=head3 substituteData()

 $output_data=substituteData($input_data);

 $input_data - Data that is passed in. Each of the "####TAGS####" tags are replaced with actual data. See the file format section of this document for details on the tags.
 $output_data - After substitutions, the data that is returned.

Replaces all the tags in the data passed in, and returns the updated string.

=cut
sub substituteData
{
my $html_data=shift;
my $footer;
my $legend_html;
my $notify_html;
my $add_desc_footer;
my $slideshow_html;
my $views;
my $ratings;
my $format_html;
my $upload_form;
my $date;
my $fullscreen_html;
my $insert_file;
my $temp;
my $temp2;
my $thisphoto;
my $thisalbum;
my $debug_html;
my $insert_filename;
my $login_html;
my $login_form;
my $jhead_data;
my $vars;
my $recent_uploads_html;
my $purl;
my $purl2;
my $create_html;
my $delete_html;
my $move_html;
my $bread_html;
my $sizes_html;
my $style_html;
my $search_html;
my $config_html;
my $random_html;
my $tempalbum;
my $popular_html;
my $admin_menu;

	debug("Data before substitution: [$html_data]",4,__LINE__);

	# Add create album form - Note that this only replaces the OBJECT tag if we're on admincreate.
	if ($form->param('admincreate') && !$form->param('albumname'))
	{
		$create_html=createAlbumForm($form->param('album'));
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$create_html\n<!-- OBJECT tag end -->\n/g;
	}

	# Add delete form - Note that this only replaces the OBJECT tag if we're on deleteobject.
	if ($form->param('deleteobject'))
	{
		$delete_html=deleteObject($form->param('deleteobject'),1);
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$delete_html\n<!-- OBJECT tag end -->\n/g;
	}

	# Add move form - Note that this only replaces the OBJECT tag if we're on moveobject.
	if ($form->param('moveobject'))
	{
		$move_html=moveObject($form->param('moveobject'),1);
		$::shortdesc=$::S{217};
		$::longdesc="";
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$move_html\n<!-- OBJECT tag end -->\n/g;
	}

	# Add search form - Note that this only replaces the OBJECT tag if we're on search.
	if ($form->param('searchstart'))
	{
		$search_html=searchForm();
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$search_html\n<!-- OBJECT tag end -->\n/g;
	}

	# Add search results - Note that this only replaces the OBJECT tag if we're processing a search.
	if ($::searchstring)
	{
		debug("Calling search($::searchstring)",3,__LINE__);
		$search_html=search($::searchstring);
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$search_html\n<!-- OBJECT tag end -->\n/g;
	}

	# Recent Uploads Page
	if ($::recent_uploads && ($form->param('album') eq $::recent_upload_album))
	{
		$recent_uploads_html=recentUploads();
		$::shortdesc="$::recent_uploads $::S{195}";
		$::longdesc="";
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$recent_uploads_html\n<!-- OBJECT tag end -->\n/g;
	}

	# Add Most Popular results - Note that this only replaces the OBJECT tag if we're processing a search.
	if ($::popular_flag)
	{
		debug("Calling popular()",3,__LINE__);
		$popular_html=popular();
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$popular_html\n<!-- OBJECT tag end -->\n/g;
	}
	# Add rating form - Note that this only replaces the OBJECT tag if we're entering a rating.
	if ($::function eq $::rating_form)
	{
		$ratings=<<HTML;
<p>
HTML
		$::shortphoto=$::object;
		$thisalbum=$form->param('rating_file_loc');
		$thisphoto=$form->param('object');

		if ($::ratingfile)
		{
#			$ratings.=getRatings(1,$rating_file_loc); # strict: $rating_file_loc is undefined!
			$ratings.=getRatings(1,$thisalbum);
		}

		$ratings.=<<HTML;
<form method="post" action="$::albumprog">
<p>
$::S{197} <SELECT name=rating>
<option value="5">$::S{109}</option>
<option value="4">$::S{110}</option>
<option  value="3" selected>$::S{111}</option>
<option value="2">$::S{112}</option>
<option value="1">$::S{113}</option>
</select>
<p>
$::S{114}
HTML

		$ratings.="<input type=\"text\" name=\"name\" ";
		if ($::authenticated)
		{
			$ratings.=" value=\"$::displayname\"";
		}
		$ratings.="/>";
		$ratings.=<<HTML;
<p>
$::S{115}
<br>
<textarea rows="$::enterdesc_rows" name="comments" cols="$::enterdesc_cols">
</textarea>
<p>
HTML
		$::function=$::update_rating;
		$ratings.=passVars(1);

		$ratings.=<<HTML;
<input type="hidden" name="rating_file_loc" value="$thisalbum">
<input type="hidden" name="object" value="$thisphoto">
<input type="submit" value=" $::S{116} " class="button">
</form>
<br><img src="$::album_web/$thisalbum/$thisphoto" border="0" alt=""><br>
HTML
		$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$ratings\n<!-- OBJECT tag end -->\n/g;
	}

	# Replace object tag if we're just doing regular stuff
	$html_data=~s/####OBJECT####/\n<!-- OBJECT tag start -->\n$::actual_object\n<!-- OBJECT tag end -->\n/g;

	# Insert files (this is done first so that all inserted tags are also replaced
	while ($html_data=~/####FILE=([^#]*)####/)
	{
		$insert_filename=$1;

		# Give full path to template
		$insert_filename="$::template_dir/$insert_filename";

		debug("Inserting file: [$insert_filename]",2,__LINE__);
		if (-r $insert_filename)
		{
			open(FILE,$insert_filename);
			$insert_file=join("",<FILE>);
			close(FILE)
		}
		else
		{
			$insert_file="<!-- File ($insert_filename) not found or not readable! -->\n";
			debug("Not inserted! (Not readable)",2,__LINE__);
		}
		$html_data=~s/####FILE=([^#]*)####/\n<!-- FILE ($insert_filename) tag start -->\n$insert_file\n<!-- FILE ($insert_filename) tag end -->\n/;
	}

	# Substitute Strings from album_strings.txt
	$html_data=~s/####STRING=(\d*)####/$::S{$1}/g;

	# Substitute internal variables
	while ($html_data=~/####CONFIG=([^#]*)####/)
	{
		$html_data=~/####CONFIG=([^#]*)####/;
		$config_html=eval("\$$1");
		$html_data=~s/####CONFIG=$1####/$config_html/g;
	}

	# Replace object title tag with object title
	$html_data=~s/####TITLE####/\n<!-- TITLE tag start -->\n$::shortdesc\n<!-- TITLE tag end -->\n/g;

	# Strip out HTML tags from the object title if it's used as the page title.
	$temp=$::shortdesc;
	$temp=~s/<([^>]|\n)*>//g;
	$html_data=~s/<title>.*<\/title>/<title>$temp<\/title>/isg;

	# Perform substitutions of tags for actual data
	if($::longdesc)
	{
		$html_data=~s/####DESCRIPTION####/\n<!-- DESCRIPTION tag start -->\n$::longdesc\n<!-- DESCRIPTION tag end -->\n/g;
	}
	else
	{
		$html_data=~s/####DESCRIPTION####/\n<!-- DESCRIPTION tag start -->\n\n<!-- DESCRIPTION tag end -->\n/g;
	}
	$style_html=printHeader(1);
	$html_data=~s/####STYLESHEET####/\n<!-- STYLESHEET tag start -->\n$style_html\n<!-- STYLESHEET tag end -->\n/g;
	$html_data=~s/####SIZE####/\n<!-- SIZE tag start -->\n$::upload_size_limit\n<!-- SIZE tag end -->\n/g;
	$html_data=~s/####PAGES####/\n<!-- PAGES tag start -->\n$::pages_html\n<!-- PAGES tag end -->\n/g;
	$html_data=~s/####NAV####/\n<!-- NAV tag start -->\n$::nav_footer\n<!-- NAV tag end -->\n/g;

	# Date
	$date=setDate("",1);
	$html_data=~s/####DATE####/\n<!-- DATE tag start -->\n$date\n<!-- DATE tag end -->\n/g;

	# Direct URL to photo (not through album.pl), plain
	if ($::photo)
	{
		$purl="$::album_web/$::photo";
		$purl=~s/ /%20/g;
	}
	$html_data=~s/####OBJECTURL####/$purl/g; # Don't put tags around OBJECTURL, as it screws up the HTML if it's used in a link

	# Direct URL to photo (not through album.pl), HTMLized
	if ($::photo)
	{
		$purl="$::S{210} <a target=\"_blank\" href=\"$purl\">$purl</a> $::S{211}";
	}
	$html_data=~s/####URL####/\n<!-- URL tag start -->\n$purl\n<!-- URL tag end -->\n/g;

	# URL to photo through album.pl, not HTMLized
	if ($::photo)
	{
		$purl2="$::albumprog?photo=$::photo";
	}
	else
	{
		$purl2="$::albumprog";
		if ($::shortalbum ne $::rootalbumname)
		{
			$purl2.="?album=";
			if ($::goback)
			{
				$purl2.="$::goback/";
			}
			$purl2.="$::shortalbum";
		}
	}
	$html_data=~s/####URLONLY####/$purl2/g; # Don't put tags around URLONLY, as it screws up the HTML if it's used in a link

	# Direct call to album.pl root album (with vars), not the curent object.
	$vars=passVars(2);
	$html_data=~s/####ALBUMPROG####/$::albumprog?full=1$vars/g; # Don't put tags around albumprog, as it screws up the HTML if it's used in a link


	# zallo was here
	$menifunczallo=$form->param('function');
	
	if($form->param('part')==1)
	{
		$html_data=~s/####UPUTEBODY####/$::S{301}/g;
		$html_data=~s/####MENI1CLASS####/meniphoto/g;
		$html_data=~s/####MENI2CLASS####/uputelink/g;
		$html_data=~s/####MENI3CLASS####/uputelink/g;
	}
	if($form->param('part')==2)
	{
		$html_data=~s/####UPUTEBODY####/$::S{302}/g;
		$html_data=~s/####MENI1CLASS####/uputelink/g;
		$html_data=~s/####MENI2CLASS####/meniphoto/g;
		$html_data=~s/####MENI3CLASS####/uputelink/g;
	}
	if($form->param('part')==3)
	{
		$html_data=~s/####UPUTEBODY####/$::S{303}/g;
		$html_data=~s/####MENI1CLASS####/uputelink/g;
		$html_data=~s/####MENI2CLASS####/uputelink/g;
		$html_data=~s/####MENI3CLASS####/meniphoto/g;
	}

	if($form->param('function') eq "upload")
	{
		$html_data=~s/####CLASSUPLOAD####/linkorange/g;
	}
	else
	{
		$html_data=~s/####CLASSUPLOAD####/naslovibijelo/g;
	}

	if($form->param('popular'))
	{
		$html_data=~s/####CLASSPOPULAR####/linkorange/g;
	}
	else
	{
		$html_data=~s/####CLASSPOPULAR####/naslovibijelo/g;
	}

	if(!$form->param('function') && !$form->param('album') && !$form->param('popular') && !$form->param('random') && !$form->param('searchstart') && !$::searchstring)
	{
		$html_data=~s/####CLASSHOME####/linkorange/g;
	}
	else
	{
		$html_data=~s/####CLASSHOME####/naslovibijelo/g;
	}

	if($form->param('random'))
	{
		$html_data=~s/####CLASSRANDOM####/linkorange/g;
	}
	else
	{
		$html_data=~s/####CLASSRANDOM####/naslovibijelo/g;
	}

	if($form->param('searchstart') || $::searchstring)
	{
		$html_data=~s/####CLASSSEARCH####/linkorange/g;
	}
	else
	{
		$html_data=~s/####CLASSSEARCH####/naslovibijelo/g;
	}
	




	# Code to set default upload dir to current album provided by Systematic
	if (($::shortalbum ne $::rootalbumname) && $::shortalbum)
	{
		my $temptemp="function=$::upload".$::webdelim."album=$::shortalbum\"";
		$html_data=~s/function=$::upload"/$temptemp/g;
	}

	# Fullscreen slide show
	if ($::photo)
	{
		$fullscreen_html="<a href=\"$::albumprog?slideshow=5".$::webdelim."oldslideshow=";
		if ($::slide_timer)
		{
			$fullscreen_html.=$::slide_timer;
		}
		else
		{
			$fullscreen_html.="5";
		}
		$fullscreen_html.=$::webdelim."fullscreen=1".$::webdelim."photo=$::photo";
		$fullscreen_html.=passVars(0);
		$fullscreen_html.="\" class=\"meniphoto\">";
		if ($::textmenu)
		{
			$fullscreen_html.=$::S{51};
		}
		else
		{
			$fullscreen_html.="fullscreen";
		}
		$fullscreen_html.="</a>";
	}
	$html_data=~s/####FULLSCREEN####/\n<!-- FULLSCREEN tag start -->\n$fullscreen_html\n<!-- FULLSCREEN tag end -->\n/g;

	# Insert "sizes" text for photos
	if ($::photo && !$::create_html_flag)
	{
		$temp=$::photo_width;
		$temp2=$::photo_height;
		$::photo_width=0;
		$::photo_height=0;

		# Display [ Small ] resize link
		if ($::small_width || $::small_height)
		{
			$sizes_html.="<a href=\"$::albumprog?photo=$::photo";
			$sizes_html.=passVars(0);
			if ($::small_width)
			{
				$sizes_html.=$::webdelim."photo_width=$::small_width";
			}
			if ($::small_height)
			{
				$sizes_html.=$::webdelim."photo_height=$::small_height";
			}
			$sizes_html.="\" class=\"meniphoto\">";
			if ($::textmenu)
			{
				$sizes_html.=$::S{54};
			}
			else
			{
				$sizes_html.="small";
			}
			$sizes_html.="</a><img src=images/spacer.gif width=23 height=1>";
		}

		# Display [ Medium ] resize link
		if ($::medium_width || $::medium_height)
		{
			# Insert divider for text menus
			if ($::textmenu && ($::small_width || $::small_height))
			{
				$sizes_html.=" $::S{98} ";
			}

			$sizes_html.="<a href=\"$::albumprog?photo=$::photo";
			$sizes_html.=passVars(0);
			if ($::small_width)
			{
				$sizes_html.=$::webdelim."photo_width=$::medium_width";
			}
			if ($::small_height)
			{
				$sizes_html.=$::webdelim."photo_height=$::medium_height";
			}
			$sizes_html.="\" class=\"meniphoto\">";
			if ($::textmenu)
			{
				$sizes_html.=$::S{139};
			}
			else
			{
				$sizes_html.="medium";
			}
			$sizes_html.="</a><img src=images/spacer.gif width=23 height=1>";
		}

		# Display [ Large ] resize link
		if ($::large_width || $::large_height)
		{
			# Insert divider for text menus
			if ($::textmenu && ($::medium_width || $::medium_height))
			{
				$sizes_html.=" $::S{98} ";
			}

			$sizes_html.="<a href=\"$::albumprog?photo=$::photo";
			$sizes_html.=passVars(0);
			if ($::small_width)
			{
				$sizes_html.=$::webdelim."photo_width=$::large_width";
			}
			if ($::small_height)
			{
				$sizes_html.=$::webdelim."photo_height=$::large_height";
			}
			$sizes_html.="\" class=\"meniphoto\">";
			if ($::textmenu)
			{
				$sizes_html.=$::S{177};
			}
			else
			{
				$sizes_html.="large";
			}
			$sizes_html.="</a><img src=images/spacer.gif width=23 height=1>";
		}

		# If we've displayed any of these, display the [ Full Size ] link.
		if ($::small_width || $::small_height || $::medium_width || $::medium_height || $::large_width || $::large_height)
		{
			# Insert divider for text menus
			if ($::textmenu)
			{
				$sizes_html.=" $::S{98} ";
			}

			$sizes_html.="<a href=\"#\" onClick=\"javascript:window.open('../album/$::photo','','width=640, height=480, resizable=yes')";

			# Add manual resize codes for "full size"
			#$sizes_html.=$::webdelim."photo_height=-1";
			#$sizes_html.=$::webdelim."photo_width=-1";

			#$sizes_html.=passVars(0);
			$sizes_html.="\" class=\"meniphoto\">";
			if ($::textmenu)
			{
				$sizes_html.=$::S{179};
			}
			else
			{
				$sizes_html.="fullsize";
			}
			$sizes_html.="</a><img src=images/spacer.gif width=23 height=1>";
		}

		$::photo_width=$temp;
		$::photo_height=$temp2;
	}
	$html_data=~s/####SIZES####/\n<!-- SIZES tag start -->\n$sizes_html\n<!-- SIZES tag end -->\n/g;

	# Recent Uploads Link
	if ($::recent_uploads && !$::create_html_flag)
	{
		$recent_uploads_html="<td width=\"114\" align=\"center\"><a href=\"$::albumprog?album=$::recent_upload_album$vars\">";
		if ($::textmenu)
		{
			$recent_uploads_html.=$::S{234};
		}
		else
		{
			$recent_uploads_html.="<font class=\"naslovibijelo\">recent uploads<\/font>";
		}
		$recent_uploads_html.="<\/a><\/td>";
	}
	$html_data=~s/####RECENTUPLOADS####/\n<!-- RECENTUPLOADS tag start -->\n$recent_uploads_html\n<!-- RECENTUPLOADS tag end -->\n/g;

	# Are we tracking the number of photo views?
	if ($::viewfile && !$::create_html_flag && !$::album)
	{
		$views=trackView($::shortphoto);
	}
	$html_data=~s/####VIEWS####/\n<!-- VIEWS tag start -->\n$views\n<!-- VIEWS tag end -->\n/g;

	# Insert "breadcrumbs"
	$bread_html=showBreadCrumbs();
	$html_data=~s/####BREAD####/\n<!-- BREAD tag start -->\n$bread_html\n<!-- BREAD tag end -->\n/g;

	# Substitute upload formats
	$format_html=join(", ",@::imgexts);
	if ($::movie_upload)
	{
		if ($::imgexts[0])
		{
			$format_html.=", "
		}
		$format_html.=join(", ",@::movieexts);
	}
	$format_html=~s/(.*), /$1 $::S{245} /;

	$html_data=~s/####FORMAT####/\n<!-- FORMAT tag start -->\n$format_html\n<!-- FORMAT tag end -->\n/g;

	# Random Thumbnail
	if ($html_data=~/####RANDTHUMB####/)
	{
		# Save off album
		$tempalbum=$::album;

		# Get random image
		$random_html=randomizer();

		# Fix album var for this operation
		$::album=$::manual_override;
		$::album=~s/(.*)\/.*/$1/;

		# Generate random HTML
		$random_html=showObject($random_html);
		$html_data=~s/####RANDTHUMB####/\n<!-- RANDTHUMB tag start -->\n$random_html\n<!-- RANDTHUMB tag end -->\n/g;

		# Reset album to normal value
		$::album=$tempalbum;
	}

	# Login status
	$login_html=loginStatus();
	$html_data=~s/####LOGIN####/\n<!-- LOGIN tag start -->\n$login_html\n<!-- LOGIN tag end -->\n/g;

	# jhead information
	if ($::jhead && $::photo)
	{
		$jhead_data=$::jhead_html;
	}
	$html_data=~s/####JHEAD####/\n<!-- JHEAD tag start -->\n$jhead_data\n<!-- JHEAD tag end -->\n/g;

	# Put slide show directive in (must appear in <head> section)
	if ($::slide_timer && $::photo)
	{
	my $next_web_link=$::next_photo_link;

		# If there's a next photo, refresh to it
		if ($::next_obj)
		{
			$next_web_link=~s/;/&/g;
			$slideshow_html="<meta http-equiv=\"Refresh\" content=\"$::slide_timer; url=$next_web_link\">";
		}

		# Full screen mode!
		if ($::fullscreen && $::photo)
		{
			$html_data="<head>$slideshow_html</head>\n<html>\n$::actual_objecta\n<p>\n&nbsp;&nbsp;\n####STOPSLIDESHOW####\n<form><input class=\"button\" type=\"button\" value=\"$::S{277}\" onClick=\"javascript:window.close();\"></form>\n</html>";
		}
	}
	$html_data=~s/####SLIDESHOW####/\n<!-- SLIDESHOW tag start -->\n$slideshow_html\n<!-- SLIDESHOW tag end -->\n/g;

	# Slideshow Controls
	if ($::slide_timer && $::next_obj && $::photo)
	{
		$slideshow_html="<form method=\"post\" action=\"$::albumprog\">\n";
		# Save off slideshow timer
		$temp=$::slide_timer;
		$::slide_timer=-1;
		$slideshow_html.=passVars(1);
		$::slide_timer=$temp;
		$slideshow_html.="<input type=\"hidden\" name=\"photo\" value=\"$::photo\">\n";
		# $slideshow_html.="<input type=\"submit\" value=\"Pause Slideshow\" class=\"button\">\n";

		# Show fullscreen button
		if (!$::fullscreen)
		{
			$slideshow_html.="<input type=\"submit\" value=\"$::S{99}\" class=\"button\">\n";
			$slideshow_html.="<input type=\"hidden\" value=\"$::slide_timer\" name=\"oldslideshow\">\n";
			$slideshow_html.="<input type=\"submit\" value=\"$::S{263}\" name=\"fullscreen\" class=\"button\">\n";
		}
		$slideshow_html.="</form>\n";
	}

	$html_data=~s/####STOPSLIDESHOW####/\n<!-- STOPSLIDESHOW tag start -->\n$slideshow_html\n<!-- STOPSLIDESHOW tag end -->\n/g;

	if ($::debug)
	{
		$debug_html="<form method=\"post\" action=\"$::albumprog\">\n";
		# Save off slideshow timer
		$temp=$::debug;
		$::debug=0;
		$debug_html.=passVars(1);
		$::debug=$temp;
		if ($::photo)
		{
			$debug_html.="<input type=\"hidden\" name=\"photo\" value=\"$::photo\">\n";
		}
		if ($::album && $::shortalbum ne $::rootalbumname)
		{
			$debug_html.="<input type=\"hidden\" name=\"album\" value=\"$::middle\">\n";
		}
		$debug_html.="<input type=\"submit\" value=\"$::S{100}\" class=\"button\">\n";
		$debug_html.="</form>\n";
	}

	$html_data=~s/####STOPDEBUG####/\n<!-- STOPDEBUG tag start -->\n$debug_html\n<!-- STOPDEBUG tag end -->\n/g;

	# Show upload form
	if ($::function eq $::upload)
	{
		$authenticated = Authenticate();

		if ($authenticated == 1) {
			$upload_form=showUploadForm();
		}
	}
	$html_data=~s/####UPLOAD####/\n<!-- UPLOAD tag start -->\n$upload_form\n<!-- UPLOAD tag end -->\n/g;

	# Show Administration menu
	if (isAdmin())
	{
		$admin_menu=showAdminMenu(0);
	}
	$html_data=~s/####ADMIN####/\n<!-- ADMIN tag start -->\n$admin_menu\n<!-- ADMIN tag end -->\n/g;

	# Show Login Form
	if ($::function eq $::login_code)
	{
		$login_form=showLogin();
	}
	$html_data=~s/####LOGINFORM####/\n<!-- LOGINFORM tag start -->\n$login_form\n<!-- LOGINFORM tag end -->\n/g;

	# Is this the root album? If so, build legend and notify chunks.
	if (!$::middle)
	{
		if ($::legend)
		{
			$legend_html.=<<LEGENDARA
            <table width="194" height="125" border="0" cellpadding="0" cellspacing="0">
              <tr> 
                <td width="7" height="20">&nbsp;</td>

                <td width="187" valign="top" background="img/tablica2.gif"><table width="50" height="8" border="0" cellpadding="0" cellspacing="0">
                    <tr> 
                      <td><img src="img/1t.gif" width="1" height="1"></td>
                    </tr>
                  </table>
                  <table width="180" height="32" border="0" cellpadding="0" cellspacing="0">
                    <tr>
                      <td width="48">&nbsp;</td>
                      <td width="80"><img src="img/album_slika2.gif" width="35" height="8"></td>

                      <td width="52"><img src="img/album_slika1.jpg" width="31" height="33"></td>
                    </tr>
                  </table>
                  <table width="50" height="7" border="0" cellpadding="0" cellspacing="0">
                    <tr> 
                      <td><img src="img/1t.gif" width="1" height="1"></td>
                    </tr>
                  </table>
                  <table width="180" height="28" border="0" cellpadding="0" cellspacing="0">

                    <tr> 
                      <td width="48">&nbsp;</td>
                      <td width="82"><img src="img/photo_slika2.gif" width="33" height="10"></td>
                      <td width="50"><img src="img/photo_slika1.jpg" width="27" height="28"></td>
                    </tr>
                  </table>
                  <table width="50" height="6" border="0" cellpadding="0" cellspacing="0">
                    <tr> 
                      <td><img src="img/1t.gif" width="1" height="1"></td>
                    </tr>

                  </table>
                  <table width="180" height="31" border="0" cellpadding="0" cellspacing="0">
                    <tr> 
                      <td width="48">&nbsp;</td>
                      <td width="80"><img src="img/movie_image2.gif" width="34" height="9"></td>
                      <td width="52"><img src="img/movie_image1.jpg"
width="33" height="31"></td>
                    </tr>
                  </table></td>
              </tr>

            </table>
LEGENDARA
		}
		if ($::notify)
		{
			$notify_html="$::S{103} $::shortdesc$::S{105}<br>\n";
			$notify_html.="<form method=\"post\" action=\"$::albumprog\">";
			$notify_html.="<input type=\"text\" name=\"email_notify\">";
			$notify_html.=" <input type=\"submit\" value=\"$::S{106}\" class=\"button\">";
			$notify_html.="</form>\n";
		}
	}
	if ($form->param('email_notify') && $::notify)
	{
		open(NOTIFY,">>$::notify_file") || error(__LINE__,"not_writable","$::notify_file");
		print NOTIFY $form->param('email_notify');
		print NOTIFY "\n";
		close(NOTIFY);
		$notify_html.="<center>$::S{107} (".$form->param('email_notify').") $::S{108}<br>\n";
		$notify_html.="</center><hr>\n";
	}

	$html_data=~s/####LEGEND####/\n<!-- LEGEND tag start -->\n$legend_html\n<!-- LEGEND tag end -->\n/g;
	$html_data=~s/####NOTIFY####/\n<!-- NOTIFY tag start -->\n$notify_html\n<!-- NOTIFY tag end -->\n/g;

	# Check to see if we are adding a description
	if ($::function eq $::enter_desc || $form->param('editobject'))
	{
		$authenticated = Authenticate();

		if ($authenticated == 1) {
			$add_desc_footer=buildDescFooter(0);
		} else {
#			print "<script language=\"Javascript\">alert(\"Not authorized or wrong password!!! Please click login button at the main menu.\")</script>";
			print "<script language=\"Javascript\">var answer = confirm(\"Za unos opis morate se prijaviti koristeæi korisnièko ime i lozinku!!! Kliknite OK za prijavu!\"); if (answer) window.location=\"$::albumprog?function=$::login_code\"</script>";
		}
	}
	$html_data=~s/####ENTERDESC####/\n<!-- ENTERDESC tag start -->\n$add_desc_footer\n<!-- ENTERDESC tag end -->\n/g;

	# Are we rating photos?
	if ($::ratingfile && !$::create_html_flag && !$::album)
	{
		$ratings=getRatings();
	}
	$html_data=~s/####RATINGS####/\n<!-- RATINGS tag start -->\n$ratings\n<!-- RATINGS tag end -->\n/g;

	# Add footer last, in case there are any warnings
	$footer=showFooter(0);
	$html_data=~s/####FOOTER####/\n<!-- FOOTER tag start -->\n$footer\n<!-- FOOTER tag end -->\n/g;

	debug("Data after substitution: [$html_data]",4,__LINE__);

	# Return data
	return($html_data);
}


##########################################################################

=head3 buildObject()

 $output_data=buildObject($vrsta);

 $output_data - The HTML for displaying the object is build and returned.
 $vrsta - 1 =  fullsreen; 0 = Display usual (photos and movies)

Builds the "object" to be displayed. For a photo, it builds the HTML to display the photo, and for an album, it builts the list of objects in that album (photos and sub-albums).

=cut
sub buildObject
{
my $vrsta=shift;
my $actual_object;
my $relpath;
my $temppage;
my $temppage2;
my $pages_html2;
my $jhead_txt;
my @sorted;
my $movietemp;
my @temp_file_list;
my $item;
my $first;

	debug("Entering subroutine: buildObject();",4,__LINE__);

	if ($::function eq "about")
	{
		$actual_object=<<HTML;
</center>
<br>
Version $::ver ($::release Release) written by <a href="mailto:Mike\@Bobbitt.ca">Mike Bobbitt</a>.
<br>&nbsp;<br>
See <a href="http://perl.Bobbitt.ca/album" target="_blank">http://perl.Bobbitt.ca/album</a> for updates and information.
<br>&nbsp;<br>
Please post any problems or questions about this program in the <a href="http://perl.Bobbitt.ca/yabbse" target="_blank">the album.pl support forums</a>.
<br>&nbsp;<br>
<center><a href="http://perl.Bobbitt.ca/album" target="_blank"><img border="0" src="http://perl.Bobbitt.ca/img/album_logo.jpg" alt=""></a></center>
© 1999-2003 Cipher Logic Canada Inc. All Rights Reserved.
<br>&nbsp;<br>
HTML
		return($actual_object);
	}

	if ($::photo)
	{
		# If the next file is also a photo, make a link to it
		if (isAPhoto($::next_obj))
		{
			$relpath=$::next_obj;

			$actual_object.="<a href=\"";
			if ($::create_html_flag)
			{
				# Check to see if it's a photo or an album
				if (isAPhoto($::next_obj))
				{
					$actual_object.=webifyLinks($relpath).".html";
				}
				else
				{
					$actual_object.=webifyLinks($relpath)."$relpath";
				}
			}
			else
			{
				$relpath="$::realgoback/$relpath";

				$actual_object.="$::albumprog?photo=".webifyLinks($relpath);
			}

			$actual_object.=passVars(0);

			$actual_object.="\" class=\"photolink\">";
		}

		if (!isAMovie($::photo))
		{
			# Update jpeg comments (disabled)
			if (0 && ($::shortdesc || $::longdesc))
			{
			my $comment=$::shortdesc;

				if ($::longdesc)
				{
					$comment.="\n$::longdesc";
				}
				updateComment($::photo,$comment);
			}

			$actual_object.="<img src=\"";
			if ($::create_html_flag)
			{
				$actual_object.="$::shortphoto";
			}
			else
			{
				$actual_object.="$::album_web/$::photo";
			}
			$actual_object.="\" border=\"0\" alt=\"";

			# Get jhead data, if jhead is being used
			if ($::jhead && -x $::jhead)
			{
			my $jhead_text;

				$::jhead_html="\"$::jhead\"";
				if ($::jhead_details)
				{
					$::jhead_html.=" -v";
				}
				$::jhead_html.=" \"$::album_dir/$::photo\"";

				open(JHEAD,"$::jhead_html|") or error(__LINE__,"cant_fork","$!");

				debug("Calling jhead: [$::jhead_html]",2,__LINE__);

				$::jhead_html=$jhead_text="";

				while (<JHEAD>)
				{
					$::jhead_html.="$_<br>\n";
					$jhead_text.=$_;
					debug("jhead output: $_",2,__LINE__);
				}
				close(JHEAD);

				debug("jhead text: $jhead_text [$::jhead_html]",2,__LINE__);

				# Turn " into ' so it can be in an alt="" tag
				$jhead_text=~s/"/'/g;
				$actual_object.="$jhead_text";
			}
			else
			{
				$actual_object.="$::S{117} $::photo";
			}

			$actual_object.="\n";
			if ($::next_obj)
			{
				$actual_object.="$::S{118} $::next_obj";
			}
			else
			{
				$actual_object.="$::S{119}";
			}

			$actual_object.="\"";
			$actual_object1=$actual_object;
			if ($::photo_width && $::photo_width ne -1)
			{
				$actual_object.=" width=\"$::photo_width\"";
			}

			if ($::photo_height && $::photo_height ne -1)
			{
				$actual_object.=" height=\"$::photo_height\"";
			}

			$actual_object.=">\n";
			$actual_object1.=">\n";
		}
		else
		{
			$actual_object.=showThumb($::photo);
		}

		# Close off link for next pic
		if (isAPhoto($::next_obj))
		{
			$actual_object.="</a>";
			$actual_object1.="</a>";
		}
	}

	if ($::album)
	{
		$actual_object="";
		if ($form->param('pickthumb'))
		{
			$actual_object.="<img src=images/spacer.gif width=10 height=10><span class=sivitext>".$::S{275}."</span><br><br>";
		}

		# Open object template
		open(TEMPLATE,"$::object_template") || error(__LINE__,"not_readable","$::object_template: $!");
		debug("Using Template File: [$::object_template]",2,__LINE__);

		$::subtemplate=join("",<TEMPLATE>);
		close(TEMPLATE);

		# Reset the number of pictures in the current row and on the current page
		$::num_page_pics=$::multi_page=$::total_objects=0;

		$::starting_number=$::photos_per_page*$::page-$::photos_per_page;
		$::ending_number=$::photos_per_page*$::page+1;
		debug("Displaying pictures in range: $::starting_number to $::ending_number",2,__LINE__);

		@temp_file_list=@::file_list;

		if (@::album_list)
		{
			@::file_list=@::album_list;
			@sorted=sortObjects();

			if (@::photo_list || @::movie_list)
			{
				$actual_object.="<table width=504><tr><td height=20 class=meniphoto bgcolor=#E5E5E5>&nbsp;$::S{259}</td></tr><tr><td height=5></td></tr></table>\n";
			}

			# Open table
			$actual_object.="<table align=\"center\" cellspacing=\"$::column_spacing\"><tr>\n";

			foreach $::shortfile (@sorted)
			{
				$actual_object.=buildAlbum(1);
			}

			# Close table
			$actual_object.="<td></td></tr></table>\n";

			# Close off line
			$actual_object.="<br clear=\"all\">\n";

		}

		# Reset object count
		$::total_objects=0;

		if (@::photo_list || @::movie_list)
		{

			@::file_list=@::photo_list;
			push @::file_list,@::movie_list;

			@sorted=sortObjects();

			if (@::album_list)
			{
				# $actual_object.="<div class=\"group\">";
				if (@::photo_list)
				{
					$actual_object.="<table width=504><tr><td height=20 class=meniphoto bgcolor=#E5E5E5>&nbsp;$::S{260}</td></tr><tr><td height=5></td></tr></table>\n";
				}
				if (@::movie_list && @::photo_list)
				{
					$actual_object.=" $::S{8} ";
				}
				if (@::movie_list)
				{
					$actual_object.="$::S{261}";
				}
				# $actual_object.="$::S{286}</div>\n";
			}

			# Open table
			$actual_object.="<table align=\"center\" cellspacing=\"$::column_spacing\"><tr>\n";

#$actual_object.=<<JAVASCRIPT;
#		<SCRIPT LANGUAGE="JavaScript">
#//arrays of file extensions
#JAVASCRIPT
#
#			$actual_object.="var imgexts=new Array(";
#			$first=1;
#			foreach $item (@::imgexts)
#			{
#				if (!$first)
#				{
#					$actual_object.=",";
#				}
#				else
#				{
#					$first=0;
#				}
#				$actual_object.="\"$item\"";
#			}
#			$actual_object.=");\n";
#
#			$actual_object.="var movieexts=new Array(";
#			$first=1;
#			foreach $item (@::movieexts)
#			{
#				if (!$first)
#				{
#					$actual_object.=",";
#				}
#				else
#				{
#					$first=0;
#				}
#				$actual_object.="\"$item\"";
#			}
#			$actual_object.=");\n";
#
#			$actual_object.=<<JAVASCRIPT;
#var thmb_width=50;
#//current folder name
#folder='$::shortalbum';
#//table dimensions
#nocolumns=3;
#norows=5;
#//JS funstion to get screen width
#sw=screen.width;
#//td = width of table cell:0.6 is a 'fiddle factor'. I think the other tables drawn with <DIV>s eat into the whole width
#tdwidth=parseInt(0.6*(sw/nocolumns));
#//path variables
#var cgi_web='$::cgi_web';
#var album_web='$::album_web';
#var icons_web='$::album_web/$::img_dir';
#//javascript variables (too make it easier!)
#var cl_o=' class= "objects"';
#var cl_at=' class= "albumstitle"';
#var cl_it=' class="imagethumb"';
#//array of files in a directory.links dont woek yet because i added a folder to get the script to work.
#JAVASCRIPT
#
#			$actual_object.="var p=new Array(";
#			$first=1;
#			foreach $item (@::file_list)
#			{
#				if (!$first)
#				{
#					$actual_object.=",";
#				}
#				else
#				{
#					$first=0;
#				}
#				$actual_object.="\"$item\"";
#			}
#			$actual_object.=");\n";
#
#			$actual_object.=<<JAVASCRIPT;
#var picwidth = new Array();
#var pix =new Array();
#if (document.images)
#{
#//loop through array of p
#for (i=0;i<p.length;i++)
#{
#pix[i]= new Image();
#//get p
#pix[i].src= album_web+folder+p[i];
#//wpix is width:hpix is height
#wpix=pix[i].width;
#hpix=pix[i].height;
#if (hpix<wpix)
#//set picture width: if portrait then width=100px if landscape then 90* of <td>.In this arrangement then cell height is unconstrained.We could put a similar calculation and constrain height. The TD definition would then include  <height=
#{picwidth[i]=0.9*tdwidth}
#else
#{picwidth[i]=100}
#}
#}
#//--></SCRIPT>
#<!-- OBJECT tag start -->
#<script language="JavaScript" type="text/javascript">
#document.write('<table align="center" cellspacing="0" border=1 name="photodisplay">');
#pn=0;
#c=1	;
#document.write('<tr>');
#while
#//loop through p array
#(pn<p.length)
#
#{
#//if picture name p[i] contains .imgext then isphoto=true
#var isphoto=-1;
#for (j=0;j<imgexts.length;j++)
#{
#//check if extension is in imgexts array
#if (isphoto == -1)
#{isphoto=p[pn].indexOf("."+imgexts[j]);}
#}
#
#//write the stuff if isphoto is false
#if (isphoto == -1)
#{
#document.write('<td width='+tdwidth+cl_o+'><div' +cl_at+'><a href="$::albumprog?album='+p[pn]+' class="albumthumb">');
#document.write('<img src="'+icons_web+'/$::album_icon" align="middle" class="" border="0" alt="'+p[pn]+'"></a><br><a href="$::albumprog?album='+p[pn]+'" class="albumthumb">$::shortdesc</a></div>');
#document.write('</td>');
#}
#else if (p[pn].substring(0,5)== "$::thumbprefix")
#{
#//if its a thummnail image:does it start with thmb_
#//take off everything after the "_" as the photoname
#ps=p[pn].split("_");
#
#var photoname=ps[1];
#document.write('<td width='+tdwidth+cl_o+' nowrap><div class="photosubtitle"><a href="$::albumprog?photo='+folder+photoname+ cl_it+'>');
#document.write('<img src='+pix[pn].src+ ' width='+thmb_width+' align="middle" class="photo" alt='+photoname+ '/></a></div>');
#document.write('<div'+cl_at+'><a href="$::albumprog?photo='+folder+p[pn]+ cl_it+'>'+photoname+'</a></div>');
#document.write('</td>');
#}
#else
#//assume its a photo & write the stuff if its a photo
#{
#document.write('<td width='+tdwidth+ cl_o+'  nowrap><div class="photosubtitle"><a href="$::albumprog?photo='+folder+p[pn]+ cl_it+'>');
#document.write('<img src='+pix[pn].src+ ' width='+picwidth[pn]+' align="middle" class="photo" alt='+p[pn]+ '/></a></div>');
#document.write('<div '+cl_at+'><a href="$::albumprog?photo='+folder+p[pn]+ cl_it+'>'+p[pn]+'</a></div>');
#document.write('</td>');
#}
#//next pic
#pn++;
#//next column
#c++;
#//ic columns too many start again
#if (c>nocolumns)
#{c=1;
#//if starting again draw a new row
#document.write('</tr>');
#document.write('<tr>');
#}
#}
#</script>
#JAVASCRIPT

			foreach $::shortfile (@sorted)
			{
				$actual_object.=buildAlbum();
			}

			# Close table
			$actual_object.="<td></td></tr></table>\n";

			# Close off line
			$actual_object.="<br clear=\"all\">\n";
		}

		@::file_list=@temp_file_list;

		# Display total number of pages...
		if ($::multi_page)
		{
			$::pages_html="";
			$::num_page_pics=$::total_objects;
			$temppage=1;
			while ($::num_page_pics > 0)
			{
				$::num_page_pics-=$::photos_per_page;
				$::pages_html.=" ";
				if ($::page ne $temppage)
				{
					$::pages_html.="<a href=\"$::albumprog?";
					if ($::shortalbum ne $::rootalbumname)
					{
						$::pages_html.="album=".webifyLinks($::middle).$::webdelim;
					}
					$::pages_html.="page=$temppage";
					$::pages_html.=passVars(0);
					$::pages_html.="\" class=\"adminlink\">";
				}
				else
				{
					$::pages_html.="<span class=menialbum>";
				}
				$::pages_html.="$temppage";
				if ($::page ne $temppage)
				{
					$::pages_html.="</a>";
				}
				else
				{
					$::pages_html.="</span>";
				}
				$temppage++;
			}
			$temppage--;

			debug("Total pages: $temppage",2,__LINE__);
			debug("Current page: $::page",2,__LINE__);

			# Print "Previous" page link
			if (($temppage > 1) && ($::page > 1))
			{
				$pages_html2.=" $::S{89} <a href=\"$::albumprog?";
				if ($::middle)
				{
					$pages_html2.="album=".webifyLinks($::middle).$::webdelim;
				}
				$temppage2=$::page-1;
				$pages_html2.="page=$temppage2";
				$pages_html2.=passVars(0);
				$pages_html2.="\" class=\"adminlink\">";
				$pages_html2.="$::S{209}</a>";
				$::pages_html="$pages_html2 $::pages_html";
			}

			# Print "Next" page link
			if (($temppage > 1) && ($::page < $temppage))
			{
				$::pages_html.=" <a href=\"$::albumprog?";
				if ($::middle)
				{
					$::pages_html.="album=".webifyLinks($::middle).$::webdelim;
				}
				$temppage2=$::page+1;
				$::pages_html.="page=$temppage2";
				$::pages_html.=passVars(0);
				$::pages_html.="\" class=\"adminlink\">";
				$::pages_html.="$::S{208}</a> $::S{92} ";
			}
			$::pages_html="<span class=sivitext>$::S{207} $::pages_html</span>";
		}
	}

	debug("Leaving subroutine: buildObject();",4,__LINE__);

	if ($vrsta==0)
	{
		return($actual_object);
	}
	else
	{
		return($actual_object1);
	}
}


##########################################################################

=head3 sortObjects()

 @sorted=sortObjects($mode);

 @sorted - The @::file_list, sorted according to the configuration
 $mode - 0 = Sorting for album view; 1 = Sorting for navigation bar (cuts off photo filename)

Sorts @::file_list, according to configuration settings, and returns the sorted array.

=cut
sub sortObjects
{
my @tempsort;
my @sorted;
my $count;
my $length;
my $newmiddle=$::middle;
my $mode=shift;
my %m;

# $sortby =
# 0 = Sort by filename (ascending)
# 1 = Sort by filename (descending)
# 2 = Sort by modified date (newest first)
# 3 = Sort by modified date (oldest first)
# 4 = Sort by creation date (newest first)
# 5 = Sort by creation date (oldest first)

	debug("Entering subroutine: sortObject()",4,__LINE__);

	debug("\$::sortby = $::sortby",2,__LINE__);

	# Cheap way to do debug("XX",2,__LINE__);
	if ($::debug gt 2)
	{
	my $temp;

		display("<pre>".__LINE__.": Unsorted...<br>");

		foreach $temp (@::file_list)
		{
			display("--> $temp<br>");
		}
		display("</pre>");
	}

	@::file_list=sort {uc($a) cmp uc($b)} @::file_list;

	# Sort by file date
	if ($::sortby eq 2 || $::sortby eq 3 || $::sortby eq 4 || $::sortby eq 5)
	{
		debug("Sorted by modified date, newest first...",3,__LINE__);
		# Sorting Code by Sukeband (sukeband@vzavenue.net)
		@tempsort=@::file_list;

		# Change all \'s to /'s
		$newmiddle=~s/\\/\//g;
		if ($mode)
		{
			$newmiddle=~s/(.*)\/.*/$1/;
		}
		$newmiddle=$::album_dir."/".$newmiddle."/";

		# Cycle through all elements of @tempsort, adding full path
		for($count=1;$count<=@tempsort;$count++)
		{
			$tempsort[$count-1]="$newmiddle$tempsort[$count-1]";
		}
		$length=1;

		if ($::sortby eq 2 || $::sortby eq 3)
		{
			# Get the modified date of each file
			@sorted=sort{ ($m{$a} ||= -M $a) <=> ($m{$b} ||= -M $b) } @tempsort;
		}
		elsif ($::sortby eq 4 || $::sortby eq 5)
		{
			# Get the creation date of each file
			@sorted=sort{ ($m{$a} ||= -C $a) <=> ($m{$b} ||= -C $b) } @tempsort;
		}

	}
	else
	# Sort by filename, ascending
	{
		debug("Sorted by filename, ascending...",3,__LINE__);
		@sorted=@::file_list;
	}

	# Reverse
	if ($::sortby eq 1 || $::sortby eq 3 || $::sortby eq 5)
	{
		debug("Reversing Sort...",3,__LINE__);
		@sorted=reverse @sorted;
	}


	# Strip out added path, if required
	if ($length)
	{
		# How long is the path we added?
		$length=length("$newmiddle");

		# Chop the added path off again!
		for($count=1;$count<=@sorted;$count++)
		{
			substr($sorted[$count-1],0,$length)="";
		}
	}

	# Cheap way to do debug("XX",2,__LINE__);
	if ($::debug gt 2)
	{
	my $temp;

		display("<pre>".__LINE__.": Sorted...<br>");

		foreach $temp (@sorted)
		{
			display("--> $temp<br>");
		}
		display("</pre>");
	}

	debug("Leaving subroutine: sortObject()",4,__LINE__);

	return(@sorted);
}


##########################################################################

=head3 buildAlbum()

 $return_html=buildAlbum($mode);

 $return_html - The built HTML for the current object
 $mode - 1 = Display this group on every page (albums); 0 = Display as per usual (photos and movies)

Builds the HTML for a photo, album or movie, as it appears in it's album (called when building an album page, for each "thimbnail" object on that page).

=cut
sub buildAlbum
{
# Pull down clean copy of template to use
my $actual_object=$::subtemplate;
my $mode=shift;
my $imagelink="";
my $admin_html="";
my $rating_html="";
my $objthumb="";
my $count_html="";
my $marker_html="";
my $setthumbflag=0;
my $webfile;
my $itsamovie;
my $photocount;
my $moviecount;
my $subalbumcount;
my $eachfile;

	# Keep count of total objects
	if ($::shortfile)
	{
		$::total_objects++;
	}

	# Reverse count for albums
#	if ($mode)
#	{
#		$::total_objects--;
#	}

	debug("\$::num_page_pics: $::num_page_pics",3,__LINE__);
	debug("\$::total_objects: $::total_objects (out of $::photos_per_page, exclusive range $::starting_number to $::ending_number)",3,__LINE__);

	# Is this page full?
	if ($::shortfile && (!$::photos_per_page || (($::starting_number < $::total_objects) && ($::ending_number > $::total_objects))) || $mode)
	{

		debug("\Going to display $::shortfile",3,__LINE__);

		getDescription($::shortfile);

		$::isimage=0;
		$::isalbum=0;
		$::file="$::album_dir";
		if ($::middle)
		{
			$::file.="/$::middle";
		}
		$::file.="/$::shortfile";

		$webfile="$::album_web";
		if ($::middle)
		{
			$webfile.="/$::middle";
		}
		$webfile.="/$::shortfile";

		debug("\$::file: $::file",3,__LINE__);
		debug("\$WebFile: $webfile",3,__LINE__);

		# Find relative path
		$::relpath=$::file;
		$::relpath=~s/$::album_dir\/(.*)/$1/;

		debug("Relpath: $::relpath",3,__LINE__);

		# Check to see if file has photo extension
		$::isimage=isAPhoto($::file);
		$itsamovie=0;

		# If it's not a photo, check to see if it's a movie
		if (!$::isimage)
		{
			$::isimage=$itsamovie=isAMovie($::file);
		}

		debug("Checking to see if $::file is a directory",4,__LINE__);
		if (-d $::file)
		{
			debug("$::file is a directory",4,__LINE__);
			$::isimage=0;
			$::isalbum=1;
		}

		# Cheap way to do debug("XX",2,__LINE__);
		if ($::debug gt 2)
		{
			display("<pre>".__LINE__.": $::file");
			if ($::isimage)
			{
				display(" is a photo (so says \$::isimage)");
			}
			if ($::isalbum)
			{
				display(" is an album (so says \$::isalbum)");
			}
			display("</pre>");
		}

		# Use filename if no desc found
		if (!$::founddesc)
		{
			$::shortdesc=$::shortfile;
		}

		# New object
#		$actual_object.="<div class=\"dynwidth\" align=\"$::object_alignment\">";

		if ($::isimage)
		{
			# $objthumb.="<div class=\"photosubtitle\">";
			$objthumb.="<a href=\"";

			$imagelink="";

			# Keep track of # of pics on this page
			$::num_page_pics++;

			# if it's a movie...
			if (isAMovie($::file))
			{
				$::static_movies_done++;
				if ($::create_html_flag)
				{
					$imagelink="$::shortfile";
				}
				else
				{
					$imagelink="$::album_web/".webifyLinks($::relpath);
				}
			}
			elsif ($::create_html_flag)
			{
				$imagelink="$::shortfile.html";
			}
			else
			{
				$imagelink="$::albumprog?";

				# We're picking thumbnails
				if ($form->param('pickthumb'))
				{
				my $relalbum="";
				my $thumbpick;

					if ($::goback)
					{
						$relalbum="$::goback/";
					}
					if ($::shortalbum ne $::rootalbumname)
					{
						$relalbum.="$::shortalbum";
					}

					# Get thumbnail HTML for this image
					$thumbpick=showThumb("$relalbum/$::shortfile");

					# Kill off HTML, and just leave relative path
					$thumbpick=~s/^<img src="$::album_web\/.*\/(.*)" align=".*/$1/;

					# A thumbnail is there, so let's do this thing...
					if ($thumbpick=~/$::thumbprefix/)
					{
						$imagelink.="album=$relalbum";
						$imagelink.=$::webdelim."setthumb=$thumbpick";
						$setthumbflag=1;
					}
					else
					{
						$imagelink.="photo=$relalbum/$::shortfile";
					}
				}
				else
				{
					$imagelink.="photo=".webifyLinks($::relpath);
				}
			}

			# If you're entering descriptions, keep going. (Unless this object is a movie...)
			if (!$itsamovie)
			{
				$imagelink.=passVars(0);
			}

			# Open movies in a new window
			if (isAMovie($::file))
			{
				$imagelink.="\" target=\"_blank\" class=\"moviethumb";
			}
			else
			{
				$imagelink.="\" class=\"imagethumb";
			}

			$objthumb.=$imagelink;
			$objthumb.="\">\n";

			$objthumb.=showThumb($::relpath);
		}

		# The current object is a sub-album
		if ($::isalbum)
		{
			# $objthumb.="<div class=\"albumsubtitle\">";

			$objthumb.="<a href=\"";

			$imagelink="";

			# Keep track of # of pics on this page
			$::num_page_pics++;

			if ($::create_html_flag)
			{
				$imagelink="$::shortfile/$::static_html_filename";
			}
			else
			{
				$imagelink="$::albumprog?album=".webifyLinks($::relpath);
			}

			# Insert vars
			$imagelink.=passVars(0);

			$objthumb.=$imagelink;
			$objthumb.="\" class=\"albumthumb\">\n";

			$objthumb.=showThumb($::relpath);
		}

		$objthumb.="</a>";

		# Close the div tag
		# $objthumb.="</div>\n";

		# Check to see if we're at the end of a row
		if (!($::total_objects % $::columns))
		{
			$actual_object.="</tr><tr>\n";
#			$actual_object.="<br clear=\"all\">\n";
		}

		# Substitute with actual object
		$actual_object=~s/####OBJECTTHUMB####/\n<!-- OBJECTTHUMB tag start -->\n$objthumb\n<!-- OBJECTTHUMB tag end -->\n/g;
		# dodatak kod prikaza objekata
		if(!isAdmin())
		{
			$zallo_start="<table width=130><tr><td>";
			$zallo_end="</td></tr></table>";
			$actual_object=~s/####OBJECTSPACERS####/\n<!-- OBJECTSPACERS tag start -->\n$zallo_start\n<!-- OBJECTSPACERS tag end -->\n/g;
			$actual_object=~s/####OBJECTSPACERE####/\n<!-- OBJECTSPACERE tag start -->\n$zallo_end\n<!-- OBJECTSPACERE tag end -->\n/g;
		}
		else
		{
			$actual_object=~s/####OBJECTSPACERS####/\n<!-- OBJECTSPACERS tag start -->\n\n<!-- OBJECTSPACERS tag end -->\n/g;
			$actual_object=~s/####OBJECTSPACERE####/\n<!-- OBJECTSPACERE tag start -->\n\n<!-- OBJECTSPACERE tag end -->\n/g;
		}

		# Album admin menu
		$admin_html=showAdminMenu(1);
		$actual_object=~s/####OBJADMIN####/\n<!-- OBJADMIN tag start -->\n$admin_html\n<!-- OBJADMIN tag end -->\n/g;

		# Short Description (Title)
		$actual_object=~s/####OBJTITLE####/\n<!-- OBJTITLE tag start -->\n<a href=\"$imagelink\"><span class=meniphoto>$::shortdesc<\/span><\/a>\n<!-- OBJTITLE tag end -->\n/g;

		# Long Description (no comment tags, so it can be commented out)
		$actual_object=~s/####OBJLONGDESC####/$::longdesc\n/g;

		# Show ratings and long descriptions for movies, or just ratings if rating_location is set.
		if ((isAMovie($::file) || ($::rating_location && $::ratingfile)) && !$::album)
		{
			$rating_html.="<br>\n";
			if (isAMovie($::file))
			{
				if ($::longdesc)
				{
					$rating_html.="$::longdesc<br>\n";
				}
			}
			if ($rating_html)
			{
				$rating_html.=getRatings(3);
			}
		}

		# Ratings Link
		$actual_object=~s/####OBJRATING####/\n<!-- OBJRATING tag start -->\n$rating_html\n<!-- OBJRATING tag end -->\n/g;

		# Show count of album contents
		if ($::isalbum && ($::showcount || $::showmoviecount || $::showsubalbumcount))
		{
			opendir(ENTRIES,"$::file") or error(__LINE__,"not_readable","$::file");

			# Change Grep
			@::file_list=grep !/^\.\.?$/,readdir ENTRIES;
			close(ENTRIES);

			$photocount=0;
			$moviecount=0;
			$subalbumcount=0;

			foreach $eachfile (@::file_list)
			{
				if (isAPhoto($eachfile))
				{
					$photocount++;
				}
				if (isAMovie($eachfile))
				{
					$moviecount++;
				}
				if (-d "$::file/$eachfile")
				{
					$subalbumcount++;
				}
			}

			$count_html.="$::S{75}";
			if ($::showcount)
			{
				$count_html.="$photocount";
			}
			if ($::showcount && $::showmoviecount)
			{
				$count_html.=", ";
			}
			if ($::showmoviecount)
			{
				$count_html.="$moviecount";
			}
			if ($::showmoviecount && $::showsubalbumcount || $::showsubalbumcount && $::showcount)
			{
				$count_html.=", ";
			}
			if ($::showsubalbumcount)
			{
				$count_html.="$subalbumcount";
			}
			$count_html.="$::S{76}";
		}

		# Object count (no comment tags, so it can be commented out)
		$actual_object=~s/####SHOWCOUNT####/$count_html\n/g;

		# Is there a long description too?
		if ($::founddesc && $::longdesc)
		{
			$marker_html="$::S{120}";
		}

		# Object count (no comment tags, so it can be commented out)
		$actual_object=~s/####OBJDESCMARKER####/$marker_html\n/g;
	}

	# Are we looking at multiple pages?
	elsif (($::photos_per_page && $::photos_per_page le $::num_page_pics) || ($::page > 1))
	{
		$actual_object="";
		$::multi_page=1;
	}
	else
	{
		$actual_object="";
	}

	if ($form->param('pickthumb') && !$setthumbflag)
	{
		$actual_object="";
	}

	return($actual_object);
}


##########################################################################

=head3 parseLinks()

 $template=parseLinks($template);

 $template - Data is passed in, made web safe, and passed out.

Checks the data passed and converts special characters within any links into web safe characters.

=cut
sub parseLinks
{
my $template=shift;

	# Replace any spaces in the links to %20. Yeah, that's a cool regex, I know. :)
	while ($template=~s/ (src|href)="([^"]*?) ([^"]*)"/ $1="$2%20$3"/g)
	{
	}

	return($template);
}


##########################################################################

=head3 showThumb()

 $thumbnail_html=showThumb($myobject,$mode);

 $myobject - Path/filename to object to search for thumbnail of, relative to album_dir.
 $thumbnail_html - HTML for the thumbnail.
 $mode - 1 = special case for album thumbnails (built during nav_footer)

Returns the proper HTML for the thumbnail of the passed object, honouring all configfile settings. If configured to do so, will also call genThumb for photos that do not already have a thumbnail.

=cut
sub showThumb
{
my $myobject=shift;
my $thumbnail_html;
my $object_no_ext;
my $imgext;
my $thumb_album;
my $middlebit;
my $origisalbum=$::isalbum;
my $objecttype="";
my $newthumbborder=0;
my $alb_thumb_ext;
my $image_thumb;
my $static_album_last;

	debug("Entering subroutine: showThumb($myobject)",4,__LINE__);

	# Set vars
	$middlebit=$myobject;
	$middlebit=~s/(.*)\/(.*)/$1/;
	$object_no_ext=$2;
	if ($middlebit eq $myobject)
	{
		$middlebit="";
	}

	# Set up album thumbnails
	if (-d "$::album_dir/$myobject")
	{
		$objecttype="album";
	}
	# Set up photo/movie thumbnails
	else
	{
		$objecttype="photo";
	}

	if ($object_no_ext)
	{
		$myobject=$object_no_ext;
	}
	$thumb_album="$::album_dir/$middlebit";

	if ($::photo)
	{
		$::isimage=1;
	}

	debug("\$myobject = $myobject",3,__LINE__);
	debug("\$thumb_album = $thumb_album",3,__LINE__);
	debug("\$middlebit = $middlebit",3,__LINE__);
	debug("\$objecttype = $objecttype",3,__LINE__);

	# Set object with no extention var
	if ($objecttype eq "photo")
	{
		# Set photo thumbnail to search for.
		$object_no_ext=$myobject;
		$object_no_ext=~s/(.+)\..+/$1/;
		debug("Stripping extension off photo...",3,__LINE__);
	}
	elsif ($objecttype eq "album")
	{
		$object_no_ext=$myobject;
	}

	debug("\$object_no_ext = $object_no_ext",3,__LINE__);

	debug("Looking for a thumbnail in $thumb_album/$::thumbprefix$object_no_ext.*",3,__LINE__);

	foreach $imgext (@::imgexts)
	{
		# Check lower case extensions
		$imgext="\L$imgext";
		if (-e "$thumb_album/$::thumbprefix$object_no_ext.$imgext")
		{
			$alb_thumb_ext=$imgext;
			debug("Found: $alb_thumb_ext",3,__LINE__);
		}

		# Check upper case extensions
		$imgext="\U$imgext";
		if (-e "$thumb_album/$::thumbprefix$object_no_ext.$imgext")
		{
			$alb_thumb_ext=$imgext;
			debug("Found: $alb_thumb_ext",3,__LINE__);
		}
	}

	if ($alb_thumb_ext)
	{
		$image_thumb="$thumb_album/$::thumbprefix$object_no_ext.$alb_thumb_ext";
		debug("Found thumbnail at: ($image_thumb) ([$thumb_album][/][$::thumbprefix][$object_no_ext][.][$alb_thumb_ext])",3,__LINE__);
	}
	else
	{
		$image_thumb="$thumb_album/$::thumbprefix$myobject";
		debug("No file thumbnail found.",2,__LINE__);
	}

	# Use *something* as a thumbnail!
	if (($::icons && ((-e $::file_photo_icon && $::photo) || (-e $::file_album_icon && $thumb_album))) || (-e "$image_thumb") || $::constrain_thumbs || $::imagemagick)
	{
		debug("I've been told to use something as a thumbnail.",2,__LINE__);

		$thumbnail_html.="<img src=\"";

		# Found a thumbnail for this specific image
		if (-e "$image_thumb")
		{
			debug("$image_thumb exists!",4,__LINE__);
			if ($::create_html_flag)
			{
				$thumbnail_html.="$::thumbprefix$object_no_ext.$alb_thumb_ext";

				# Keep count of album thumbnails
				if (-d "$thumb_album/$myobject" && $static_album_last ne $myobject)
				{
					$::static_albums_thumb++;
#print "\nALBTHUMB: #$::static_albums_thumb [$myobject] [$static_album_last]\n";
					$static_album_last=$myobject;
				}
			}
			else
			{
				$thumbnail_html.="$::album_web/$middlebit/$::thumbprefix$object_no_ext.$alb_thumb_ext";
				debug("URL to thumbnail: $::album_web/$middlebit/$::thumbprefix$object_no_ext.$alb_thumb_ext",4,__LINE__);
			}
			if ($objecttype eq "photo")
			{
				if (isAMovie($myobject))
				{
					$::static_movies_thumb++;
				}
				else
				{
					$::static_photos_thumb++;
				}
			}
		}
		else
		# No specific thumbnail found, just use the generic one
		{
			debug("$image_thumb does not exist.",4,__LINE__);
			if (isAMovie($myobject))
			{
				debug("$myobject is a movie.",2,__LINE__);
				if ($::create_html_flag)
				{
					$thumbnail_html.="$::file_movie_icon";
				}
				else
				{
					$thumbnail_html.="$::movie_icon";
				}
			}
			else
			{
				debug("$myobject is not a movie.",2,__LINE__);
				if ($::constrain_thumbs && $objecttype eq "photo")
				{
					debug("It's an image, use a constrained thumbnail.",3,__LINE__);
					if ($::create_html_flag)
					{
						$thumbnail_html.="$myobject";
					}
					else
					{
						$thumbnail_html.="$::album_web/$middlebit/$myobject";
					}
					if ($::thumb_height)
					{
						$thumbnail_html.="\" height=\"$::thumb_height";
					}
					if ($::thumb_width)
					{
						$thumbnail_html.="\" width=\"$::thumb_width";
					}
				}
				else
				{
					if ($::create_html_flag)
					{
						if ($objecttype eq "photo")
						{
							$thumbnail_html.="$::file_photo_icon";
						}
						else
						{
							$thumbnail_html.="$::file_album_icon";
						}
					}
					else
					{
						debug("Defaulting to the generic icon for a thumbnail...",3,__LINE__);
						if ($objecttype eq "photo")
						{
							# Try to generate a thumbnail
							if ($::imagemagick)
							{
								$newthumbborder=0;
								if (!$::file)
								{
									$::file="$thumb_album/$myobject";
								}
								debug("\$::file=$::file, \$myobject=$myobject",2,__LINE__);
								$newthumbborder=genThumb($::file,$image_thumb,0);
							}

							# Add thumbnail HTML if it was generated properly
							if ($newthumbborder)
							{
								$thumbnail_html.="$::album_web/$middlebit/$::thumbprefix$myobject";
								$newthumbborder=1;
							}
							else
							{
								$thumbnail_html.="$::photo_icon";
								$newthumbborder=0;
							}
						}
						else
						{
							$thumbnail_html.="$::album_icon";

							# Set this so we don't put borders around the icons (that just looks bad)
							$::isalbum=0;
						}
					}
				}
			}
		}
		$thumbnail_html.="\" align=\"middle\" class=\"";
		if ($newthumbborder)
		{
			# $thumbnail_html.="thumb";
		}
		elsif (isAPhoto($myobject))
		{
			#$thumbnail_html.="photo";
		}
		elsif (isAMovie($myobject))
		{
			#$thumbnail_html.="movie";
		}
		elsif ($::isalbum)
		{
			#$thumbnail_html.="album";
		}
		else
		{
			#$thumbnail_html.="\" border=\"0";
		}
		$thumbnail_html.="\" border=\"0";
		$thumbnail_html.="\" alt=\"$myobject\">";
	}

	# Kill double /'s
	#$thumbnail_html=~s/([^:])\/\//$1\//g;

	# Restore $::isalbum
	$::isalbum=$origisalbum;

	debug("Leaving subroutine: showThumb($myobject)",4,__LINE__);

	return($thumbnail_html);
}


##########################################################################

=head3 readConfig()

 readConfig($confile,$mode);

 $confile - path and filename of the config file
 $mode - 0 = Reading primary config; 1 = Reading local config (per album config)

Reads configuration information from the specified config file.

=cut

sub readConfig
{
my $confile=shift;
my $mode=shift;
my $data;
my $var;
my $value;
my $localfunc;
my $line=0;
my $confopen=0;
my $couldbe=$0;
my @array_values;

	debug("Entering subroutine: readConfig($confile,$mode)",4,__LINE__);

	if (!$mode)
	{
		# Set all config vars to null, just so they exist. (Was causing some setup issues)
		# ALL VARIABLES SHOULD EXIST HERE
		# String variables
		$::cgi_dir=$::cgi_web=$::album_web=$::album_dir=$::notify_file=$::photo_icon=$::movie_icon=$::album_icon=$::style_sheet=$::descname=$::upload_logfile=$::membersdir=$::auth_db=$::static_html_filename=$::thumbprefix=$::album_password=$::enter_desc=$::update_desc=$::viewfile=$::album_template=$::photo_template=$::updateconfig=$::config=$::update_rating=$::ratingfile=$::upload_template=$::debug_code=$::object_alignment=$::jhead=$::template_dir=$::newconfig=$::protect_album=$::default_admins=$::stringtable=$::imagemagick=$::pic_resize=$::album_folder_icon=$::member_subdir=$::img_dir=$::login_button=$::home_button=$::search_button=$::random_button=$::upload_button=$::recent_button=$::rate_button=$::email_button=$::small_button=$::medium_button=$::large_button=$::fullsize_button=$::fullscreen_button=$::edit_button=$::delete_button=$::move_button=$::config_button=$::create_button=$::titles_button=$::updates_button=$::adminupload_button=$::thumb_button=$::db_name=$::db_hostname=$::db_user=$::db_password=$::db_membertable=$::db_username=$::db_driver=$::object_template=$::postupload=$::popular_button=$::default_guests=$::login_template=$::db_passwdfield="";

		# Numeric variables
		$::cfgver=$::columns=$::column_spacing=$::descloc=$::showcount=$::showmoviecount=$::icons=$::legend=$::notify=$::allow_uploads=$::upload_overwrite=$::upload_size_limit=$::authentication_type=$::per_member_upload=$::create_html_flag=$::slide_timer=$::nextprevthumb=$::constrain_thumbs=$::showsubalbumcount=$::quota=$::jhead_details=$::allow_edit=$::allow_delete=$::recent_uploads=$::rating_location=$::thumb_quality=$::always_pic_resize=$::concurrent_uploads=$::block_ubb_junior_members_from_uploading=$::rows=$::default_size=$::db_port=$::textmenu=$::most_popular=$::movie_upload=$::thumb_width=$::thumb_height=$::sortby=$::bread_style=0;

		# Array variables
		@::imgexts=("");
		@::movieexts=("");
	}

	debug("Reading configuration information from $confile...",2,__LINE__);

	# Trying to open the provided config file
	if (open(CONFIG,"$confile"))
	{
		debug("Opened config file at $confile",2,__LINE__);
		$confopen=1;
	}
	else
	{
		$confopen=0;
	}

	# Nope. Try just album.cfg
	if (!$confopen && !$mode)
	{
		debug("Trying to read configuration information from album.cfg...",2,__LINE__);
		if (open(CONFIG,"album.cfg"))
		{
			debug("Opened config file at album.cfg",2,__LINE__);
			$confopen=1;
			$::configfile="album.cfg";
		}
		else
		{
			$confopen=0;
		}
	}

	# Nope. Try the same directory as album.pl explicitly
	if (!$confopen && !$mode)
	{
		# Change all \'s to /'s
		$couldbe=~s/\\/\//g;

		# Drop the filename
		$couldbe=~s/(.*\/).*/$1/;

		$couldbe.="album.cfg";
		debug("Trying to read configuration information from $couldbe...",2,__LINE__);
		if (open(CONFIG,"$couldbe"))
		{
			debug("Opened config file at $couldbe",2,__LINE__);
			$confopen=1;
			$::configfile=$couldbe;
		}
		else
		{
			$confopen=0;
		}
	}

	# Nope. Try the same directory as album.pl explicitly, but use $confile as the name, just in case the user has changed it to something like install.cfg
	if (!$confopen && !$mode)
	{
		# Change all \'s to /'s
		$couldbe=~s/\\/\//g;

		# Drop the filename
		$couldbe=~s/(.*\/).*/$1/;

		$couldbe.=$confile;
		debug("Trying to read configuration information from $couldbe...",2,__LINE__);
		if (open(CONFIG,"$couldbe"))
		{
			debug("Opened config file at $couldbe",2,__LINE__);
			$confopen=1;
			$::configfile=$couldbe;
		}
		else
		{
			$confopen=0;
		}
	}

	# Just couldn't find the bloody thing!
	if (!$confopen && !$mode)
	{
		error(__LINE__,"no_config","$confile");
	}

	# No local config, just return
	if (!$confopen)
	{
		debug("No local config file found, returning...",2,__LINE__);
		debug("Leaving subroutine: readConfig($confile,$mode)",4,__LINE__);
		return;
	}

	while ($data=<CONFIG>)
	{
		$line++;
		chomp($data);

		# Stript out trailing and leading whitespace
		$data=~s/^\s*(\S*)\s*$/$1/;

		# skip comments and blank lines
		if (!(($data eq "") || ($data=~/^#.*/)))
		{
			if ($data!~/.+=.*/)
			{
				if (!$::S{29})
				{
					$::S{29}="Error in configuration file, line:";
				}
				$::warning.="$::S{29} $line";
			}
			$data=~/(@*\w+)=(.*)/;
			$var=$1;
			$value=$2;

			# Change all \'s to /'s
			$value=~s/\\/\//g;

			debug("Var [$var] = [$value]",3,__LINE__);

			# set variables
			# is it an array?
			if ($var=~/^\@/)
			{
				@array_values=split(",",$value);
				eval("$var=\@array_values");
				debug("Setting loaded: [$var=@array_values]",3,__LINE__);
			}
			else
			{
				if ($value || $mode)
				{
					eval("\$$var=\"\$value\"");
				}
			}
		}
	}
	close(CONFIG);

	# Check to see if any data was loaded at all
	if (!$::cgi_dir)
	{
		$::warning.="$::S{29} $::S{121}";
	}

	# Full path to album.pl - don't change this
	$::albumprog=$0;

	debug("\$0: $0<p>",2,__LINE__);

	# Change all \'s to /'s
	$::albumprog=~s/\\/\//g;

	# Drop the preceeding path
	$::albumprog=~s/.*\/(.*)/$1/;

	$::albumprog=$::cgi_web."/".$::albumprog;

	debug("Web Path to Album (albumprog): $::albumprog",2,__LINE__);

	# Set default rows, if none are defined
	if (!$::rows)
	{
		$::rows=10;
	}

	# If cols=0, then give it a value, so we can show things properly
	if (!$::columns)
	{
		$::columns=5;
	}

	# Set $::photos_per_page according to rows x cols
	$::photos_per_page=$::rows*$::columns;
	debug("\$::photos_per_page = [$::photos_per_page] [$::rows]x[$::columns]",2,__LINE__);

	$localfunc=$form->param('function');

	debug("Function is: $localfunc [$::function]",2,__LINE__);

	# Is this the very first time the config has been loaded?
	if ($::newconfig eq "true" && ($localfunc ne $::updateconfig))
	{
		# Set stringtable correctly
		$::stringtable="$::cgi_dir/$::stringtable";
		debug("\$::stringtable is now $::stringtable",3,__LINE__);

		# Check some basic stuff to make sure the environment is safe
		sanityTest();
		showConfig();
	}

	debug("Leaving subroutine: readConfig($confile,$mode)",4,__LINE__);
}


##########################################################################

=head3 showConfig()

 showConfig();

Displays the configuration items from $::configfile in a web submittable form.

=cut
sub showConfig
{
my $data;
my $section;
my $first_section;
my $paramsize;
my $prevline;
my $var;
my $value;
my $line;
my $help;
my $sect_header;
my $guessed;
my $notes;
my $configwarning;
my $readonly;
my $stopcol=$::S{122};
my $warncol=$::S{123};

	printHTMLHeader();

	print "<head><title>album.pl - $::S{52}";

	# If configfile is not writable, then warn user
	if (!-w $::configfile)
	{
		$readonly=1;
		print " - $::S{124}";
	}

	print "</title>\n";

	$data=printHeader();

	print <<HTML;
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" Content="Thu, 01 Jan 1970 00:00:01 GMT">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
$data
<h1>Configuration Management
HTML
	if ($readonly)
	{
		print " - $::S{124}";
	}

	print <<HTML;
</h1>
<form method="post">
HTML

	if ($readonly)
	{
		print "<p><font color=\"$stopcol\">$::S{125} $::S{126}$::configfile$::S{127}</font><p>";
	}

	print "&#187; <a href=\"http://perl.Bobbitt.ca/yabbse\">album.pl $::S{230}</a><br>\n";

	# Show link to !readme.html if present
	if (-r "album_test.pl")
	{
		print "&#187; <a href=\"album_test.pl\">$::S{95} $::S{252}</a><br>\n";
	}

	# Show link to !readme.html if present
	if (-e "!readme.html")
	{
		print "&#187; <a href=\"!readme.html\">$::S{95} $::S{128}</a><p>\n";
	}

	# This is the first time the album has been used - initial config
	if ($::newconfig eq "true")
	{
		print "<p>$::S{129} $0 $::S{130}<p>";
		debug("Configuring album for the first time.",2,__LINE__);
	}

	# Open the config file
	open(CONFIG,"$::configfile") || error(__LINE__,"no_config","$::configfile: $!");

	$first_section=1;
	while ($data=<CONFIG>)
	{
		$line++;
		chomp($data);

		# Stript out trailing and leading whitespace
		$data=~s/^\s*(\S*)\s*$/$1/;

		# Read section blocks
		if ($prevline=~/^##+$/)
		{
			$section=$data;
			$section=~s/^# (.*) #$/$1/;

			if ($first_section)
			{
				$first_section=0;
			}
			elsif ($section)
			{
				print "</table>";
			}

			if (!$section)
			{
				print <<HTML;
<p>
<table border=1 cellpadding="5" cellspacing="0" bordercolor="#111111">
HTML
			}
			else
			{
				print <<HTML;
<p>
<h2>$section</h2>
HTML
			}
			$sect_header=1;
		}

		# Display comments as help
		if (($data!~/.*#$/) && ($data=~/^# (.*)/))
		{
			if ($help)
			{
				$help.="<br>";
			}
			$help.="$1";
		}

		# Print section header help, if any
		if ($sect_header && (!$data) && $help)
		{
			print <<HTML;
$help
<p>
HTML
			$sect_header=0;
			$help="";
		}

		# skip comments and blank lines
		if (!(($data eq "") || ($data=~/^#.*/)))
		{

			$sect_header=0;

			if ($data!~/.+=.*/)
			{
				$::warning.="$::S{29} $line";
			}
			$data=~/(@*\w+)=(.*)/;
			$var=$1;
			$value=$2;
			debug("Var [$var] = [$value]",3,__LINE__);

			# Skip special "newconfig" item
			if ($var ne "newconfig")
			{

				print <<HTML;
<tr><td>
<h3>$var</h3>
HTML
				if ($help)
				{
					print <<HTML;
$help
HTML
				}

				$guessed=0;

				# For new configs, take "best guesses" at what some values should be
				if ($::newconfig eq "true")
				{
					if ($var eq "cgi_dir")
					{
						$value=cwd;
						$value=~s/\\/\//g;
						$guessed=1;
						$::cgi_dir=$value;
						debug("\$::cgi_dir is now [$value]",3,__LINE__);
					}
					if ($var eq "album_dir")
					{
						$value=cwd;
						$value=~s/\\/\//g;
						$value=~s/(.*)\/.*/$1\/album/;
						$guessed=1;
						$::album_dir=$value;
						debug("\$::album_dir is now [$value]",3,__LINE__);
					}
					if ($var eq "cgi_web")
					{
						$value="http://$ENV{HTTP_HOST}$ENV{SCRIPT_NAME}";
						$value=~s/(.*)\/.*/$1/;
						$guessed=1;
						$::cgi_web=$value;
						debug("\$::cgi_web is now [$value]",3,__LINE__);
					}
					if ($var eq "album_web")
					{
						$value="http://$ENV{HTTP_HOST}/album";
						$guessed=1;
						$::album_web=$value;
						debug("\$::album_web is now [$value]",3,__LINE__);
					}
					if ($var eq "template_dir")
					{
						$value=cwd;
						$value=~s/\\/\//g;
						$guessed=1;
						$::template_dir=$value;
						debug("\$::template_dir is now [$value]",3,__LINE__);
					}
					if ($var eq "jhead")
					{
						$value=`which jhead 2>&1`;
						if ($value!~/^\//)
						{
							$value="";
						}
						else
						{
							$guessed=1;
							$::jhead=$value;
							debug("\$::jhead is now [$value]",3,__LINE__);
						}
					}
				}

				# Display some status notes on certain config items

				# Check to see that directories exist
				if (($var eq "cgi_dir") && !(-d $value))
				{
					$notes=$::S{131};
				}

				if (($var eq "album_dir") && !(-d $value))
				{
					$notes=$::S{131};
				}

				if (($var eq "template_dir") && !(-d $value))
				{
					$notes=$::S{131};
				}

				if (($var eq "membersdir") && !(-d $value))
				{
					$notes=$::S{137};
				}

				if (($var eq "img_dir") && !(-d $value))
				{
					$notes=$::S{131};
				}

				if (($var eq "imagemagick") && !(-d $value))
				{
					$configwarning=$::S{198};
				}

				# Check to see that files are readable
				if (($var eq "album_template") && !(-r "$::template_dir/$value"))
				{
					$notes=$::S{133};
				}

				if (($var eq "photo_template") && !(-r "$::template_dir/$value"))
				{
					$notes=$::S{133};
				}

				if (($var eq "object_template") && !(-r "$::template_dir/$value"))
				{
					$notes=$::S{133};
				}

				if (($var eq "upload_template") && !(-r "$::template_dir/$value"))
				{
					$notes=$::S{133};
				}

				if (($var eq "login_template") && !(-r "$::template_dir/$value"))
				{
					$notes=$::S{133};
				}

				if (($var eq "auth_db") && !(-r $value))
				{
					$configwarning=$::S{140};
				}

				if (($var eq "photo_icon") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{147};
				}

				if (($var eq "movie_icon") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{148};
				}

				if (($var eq "album_icon") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "album_folder_icon") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "login_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "home_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "search_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "random_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "upload_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "recent_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "rate_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "email_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "small_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "medium_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "large_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "fullsize_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "fullscreen_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "edit_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "delete_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "move_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "config_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "create_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "titles_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "updates_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "adminupload_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "thumb_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				if (($var eq "popular_button") && !(-r "$::img_dir/$value"))
				{
					$configwarning=$::S{149};
				}

				# Check to see that files are writable
				if (($var eq "notify_file") && !(-w $value))
				{
					$configwarning=$::S{134};
				}

				if (($var eq "album_dir") && !(-w $value))
				{
					$configwarning=$::S{132};
				}

				if (($var eq "upload_logfile") && !(-w $value))
				{
					$notes=$::S{135};
				}

				# Check to see that "required" vars have a value
				if (($var eq "upload_logfile") && !$value)
				{
					$configwarning=$::S{136};
				}

				if (($var eq "\@::imgexts") && !$value)
				{
					$configwarning=$::S{141};
				}

				if (($var eq "\@::movieexts") && !$value)
				{
					$configwarning=$::S{142};
				}

				if (($var eq "\thumbprefix") && !$value)
				{
					$notes=$::S{290};
				}

				# Check to see that programs are executable
				if (($var eq "jhead") && !(-x $value))
				{
					$configwarning=$::S{138};
				}

				# Ensure that function codes are not set to the default
				if (($var eq "admin") && ($value eq "admin"))
				{
					$notes=$::S{143};
				}

				if (($var eq "config") && ($value eq "config"))
				{
					$notes=$::S{143};
				}

				if (($var eq "updateconfig") && ($value eq "updateconfig"))
				{
					$configwarning=$::S{143};
				}

				if (($var eq "update_desc") && ($value eq "update_desc"))
				{
					$configwarning=$::S{144};
				}

				if (($var eq "update_rating") && ($value eq "update_rating"))
				{
					$configwarning=$::S{145};
				}

				if (($var eq "enter_desc") && ($value eq "enter_desc"))
				{
					$notes=$::S{146};
				}

				if (($var eq "debug_code") && ($value eq "debug"))
				{
					$notes=$::S{143};
				}

				# Make sure none of the function codes are null
				if (($var eq "admin" || $var eq "config" || $var eq "updateconfig" || $var eq "enter_desc" || $var eq "update_desc" || $var eq "upload" || $var eq "update_rating" || $var eq "rating_form" || $var eq "debug_code" || $var eq "login_code") && !$value)
				{
					$notes=$::S{227};
				}

				# Set field size
				$paramsize=length($value)+5;

				print <<HTML;
</td><td>
HTML
				if ($guessed)
				{
					print "* ";
				}
				if ($readonly)
				{
					print "$value";
				}
				else
				{
					print <<HTML;
<input type="text" name="$var" size="$paramsize" value="$value">
HTML
				}

				if ($notes)
				{
					print "<br><font color=\"$stopcol\">$::S{125} $notes</font>";
					$notes="";
				}
				if ($configwarning)
				{
					print "<br><font color=\"$warncol\">$::S{150} $configwarning</font>";
					$configwarning="";
				}
				print <<HTML;
</td>
</tr><p>
HTML
			}
			$help="";
		}

		$prevline=$data;
	}

	close(CONFIG);

	$::function=$::updateconfig;
	$data=passVars(1);
	print <<HTML;
</table>
$data
<p>
HTML

	# If configfile is not writable, then warn user
	if ($readonly)
	{
		print "$::S{125} $::configfile $::S{151}";
	}
	else
	{
		print <<HTML;
<h2>$::S{152}</h2>
$::S{153}
<table border=1 cellpadding="5" cellspacing="0" bordercolor="#111111">
<br>
<tr><td>$::S{154}</td><td>$::S{155}</td><td>$::S{156}</td><td>$::S{157}<br>
</td>
</tr>
<tr><td>
$::S{158}</td><td>$::S{159}</td><td>$::S{160}</td><td>$::S{161}
<br>
</td>
</tr>
<tr><td>
$::S{162}</td><td>
<input type="text" name="newconfigcomments" size=75>
</td><td>
<input type="text" name="newconfigitem">
</td><td>
<input type="text" name="newconfigvalue">
</td></table>
HTML

		# Show registration form
		if ($::newconfig eq "true")
		{
			print <<HTML;
<h2>$::S{163}</h2>
<p>
$::S{164}
<p>
$::S{165}
<p>
<table border=1 cellpadding="5" cellspacing="0" bordercolor="#111111">
<br>
<tr><td>$::S{166}</td><td><input type="text" name="regemail"></td>
</tr>
</table>
HTML
		}
	print <<HTML;
<p><center>
<input type="submit" value="$::S{167}" name="Apply" class="button">
<input type="submit" value="$::S{168}" name="ReloadRequested" class="button">
</center>
HTML
	}
	showFooter(1);
	exit(0);
}


##########################################################################

=head3 updateConfig()

 updateConfig();

Updates the settings in $configfile, when the form displayed in showConfig is submitted.

=cut
sub updateConfig
{
my $data;
my $var;
my $value;
my $response;
my $temp;
my $virtualfile="";

	if ($form->param('ReloadRequested'))
	{
		# Refresh config
		showConfig();
		exit(0);
	}

	# Register
	if ($::newconfig eq "true")
	{
		$temp=$0;

		# Change all \'s to /'s
		$temp=~s/\\/\//g;

		# Drop the preceeding path
		$temp=~s/.*\/(.*)/$1/;

		$response=$form->param('cgi_web');

		$temp="$response/$temp";

		$response=regConnect($form->param('regemail'),$temp);
	}

	# Open the configfile
	open(CONFIG,"$::configfile") || error(__LINE__,"no_config","$::configfile: $!");

	while ($data=<CONFIG>)
	{
		chomp($data);
		if ($data=~/(@*\w+)=(.*)/ && $data!~/^#/)
		{
			$var=$1;
			$value=$form->param($var);
			$virtualfile.="$var=$value\n";
			debug("Writing updated line: [$var=$value]",3,__LINE__);
		}
		else
		{
			$virtualfile.="$data\n";
			debug("Writing line: [$data]",4,__LINE__);
		}
	}

	# Add new config item, if there is one...
	if ($form->param('newconfigitem'))
	{
		$::comments=$form->param('newconfigcomments');
		$var=$form->param('newconfigitem');
		$value=$form->param('newconfigvalue');
		$virtualfile.="\n# $::comments\n$var=$value\n";
	}

	close(CONFIG);

	# Re-open config file and write out new contents
	open(CONFIG,">$::configfile") || error(__LINE__,"not_writable","$::configfile");
	print CONFIG $virtualfile;
	close(CONFIG);

	# Re-read config to get newly written values...
	readConfig($::configfile);

	# Display menu after config is updated
	print "<head><title>album.pl - $::S{52}</title>";

	$data=printHeader();

	print <<HTML;
$data
<h1>$::S{52}</h1>
<p>
$::S{169}
<ul>
<li><a href=\"$::albumprog\">$::S{170}</a>
<li><a href=\"$::albumprog?function=$::enter_desc\">$::S{50}</a>
<li><a href=\"$::albumprog?function=$::admin\">$::S{171}</a>
<li><a href=\"$::albumprog?function=$::upload\">$::S{172}</a>
<li><a href=\"$::albumprog?function=$::config\">$::S{173}</a>
</ul>
HTML

	showFooter(1);

	# Now exit
	exit(0);
}


##########################################################################

=head3 updateRating()

 updateRating($myobject,$rating_file_loc,$rating,$comments);

 $myobject - Object to add a rating to
 $rating_file_loc - Location of the ratings file
 $rating - The numerical rating
 $comments - Comments (optional)

Updates the ratings for the object supplied, using the rating and comments supplied.

=cut
sub updateRating
{
my $myobject=shift;
my $rating_file_loc=shift;
my $rating=shift;
my $new_comments=shift;
my $updated_ratings;
my $data;
my $current_rating;
my $current_photo;
my $tempfilename;
my $comments;
my $virtualfile="";
my $filename="";
my $current_ratingfile="$::album_dir/$rating_file_loc/$::ratingfile";

	if ($rating_file_loc eq $::rootalbumname)
	{
		$current_ratingfile="$::album_dir/$::ratingfile";
	}

	debug("Updating ratings for $myobject in $current_ratingfile",2,__LINE__);

	# Strip out HTML from comments
	$new_comments=~s/<([^>]|\n)*>//g;

	# Stip line breaks out of comments.
	$new_comments=~s/[\n\r]/<br \/>/g;

	# Does it already exist?
	if (-e $current_ratingfile)
	{
		# Open $::viewfile for reading
		open(RATINGS,"$current_ratingfile") || error(__LINE__,"not_readable","$current_ratingfile");

		# have not updated views
		$updated_ratings=0;

		while ($data=<RATINGS>)
		{
			# Check to see if this is the one we want
			if ($data=~/^$myobject\t.*/)
			{
				chomp($data);
				debug("Found match: $data",3,__LINE__);
				($filename,$::num_ratings,$current_rating,$comments)=split("\t",$data);
				debug("Data: [$data] --> Ratings:[$::num_ratings] Rating:[$current_rating] Comments:[$comments]",4,__LINE__);
				$comments="$comments<br>$new_comments";

				# Calculate new average rating
				$current_rating=floor((($current_rating*$::num_ratings+$rating)/($::num_ratings+1))*100)/100;
				$::num_ratings++;
				$virtualfile.="$myobject\t$::num_ratings\t$current_rating\t$comments\n";
				$updated_ratings=1;
			}
			else
			{
				debug("Wrote: $data",4,__LINE__);
				$virtualfile.=$data;
			}
		}

		# If the photo didn't already hav an entry, add it now.
		if (!$updated_ratings)
		{
			debug("No entry found, adding one.",2,__LINE__);
			$virtualfile.="$myobject\t1\t$rating\t$new_comments\n";
		}

		close(RATINGS);

		# Re-open ratings file and write out new contents
		open(RATINGS,">$current_ratingfile") || error(__LINE__,"not_writable","$current_ratingfile");
		print RATINGS $virtualfile;
		close(RATINGS);

	}
	else
	{
		debug("$current_ratingfile does not exist, creating...",2,__LINE__);
		open(RATINGS,">$current_ratingfile") || error(__LINE__,"not_writable","$current_ratingfile");
		print RATINGS "$myobject\t1\t$rating\t$new_comments\n";
		close(RATINGS);
	}

	# Return to photo/album
	if (isAPhoto($myobject))
	{
		$::album="";
		$::photo="$rating_file_loc/$myobject";
	}
	else
	{
		$::album="$::album_dir/$rating_file_loc";
		if ($rating_file_loc eq $::rootalbumname)
		{
			$::album=$::album_dir;
		}
	}
	$::function="";
}


##########################################################################

=head3 getRatings()

 $ratings=getRatings($mode,$rating_file_loc);

 $ratings - The string of rating information to insert into the template.
 $mode - 0 = Add a link to submit a rating to the returned data; 1 = Do not return the link to add a rating; 2 = Perform search; 3 = Show rating only, not comments; 4 = It's a popularity contest! Populate @poplist with info on photo ratings.
 $rating_file_loc - Location of ratings file (optional, only used if mode=1).

Returns the ratings information for the current photo/movie.

=cut
sub getRatings
{
my $current_ratingfile="$::album_dir/";
my $mode=shift;
my $rating_file_loc=shift;
my $data="";
my $filename;
my $showcomment;
my $poplistkey;
my $temp1;
my $temp2;

	debug("Entering subroutine: getRatings($mode,$rating_file_loc);",4,__LINE__);

	# Clean out old values
	$::num_ratings=$::current_rating=$::comments="";

	# Reset vars
	$temp1=$temp2=0;

	if ($mode eq 3)
	{
		$showcomment=0;
		$mode=0;
	}
	else
	{
		$showcomment=1;
	}

	if (!$::shortphoto && !$::album)
	{
		debug("No photo selected, not getting ratings.",2,__LINE__);
		return();
	}

	if (!$::ratingfile)
	{
		debug("Ratings are not enabled.",2,__LINE__);
		return();
	}

	# Show rating info for the thumbnail we're looking at, not the current object, if it's a movie or that's how we want it displayed
	if (isAMovie($::file) || $::album && $::rating_location)
	{
		$::shortphoto=$::shortfile;
		$current_ratingfile.="$::middle/";
	}
	elsif ($::goback)
	{
		$current_ratingfile.="$::goback/";
	}
	elsif ($mode)
	{
		$current_ratingfile.="$rating_file_loc/";
	}
	$current_ratingfile.="$::ratingfile";

	if ($rating_file_loc eq $::rootalbumname || $::shortalbum eq $::rootalbumname)
	{
		$current_ratingfile="$::album_dir/$::ratingfile";
	}

	# Reset crap when searching
	if ($mode>1)
	{
		$current_ratingfile="$::album_dir/$rating_file_loc/$::ratingfile";
	}
	debug("\$mode=$mode",3,__LINE__);
	debug("\$::ratingfile=$::ratingfile",3,__LINE__);

	debug("Getting ratings for $::shortphoto in $current_ratingfile",2,__LINE__);

	# Does it already exist?
	if (-e $current_ratingfile)
	{
		# Open $ratings for reading
		open(RATINGS,"$current_ratingfile") || error(__LINE__,"not_readable","$current_ratingfile");

		while ($data=<RATINGS>)
		{
			# Doing search
			if ($mode>1 && $::searchcomments)
			{
				if ($data=~/$::searchstring/i)
				{
					($filename,,,)=split("\t",$data);
					debug("Found a MATCH (description) of $::searchstring in $data for object $rating_file_loc/$filename",4,__LINE__);
					push @::searchresults,"$rating_file_loc/$filename";
				}
			}

			# Check for most popular
			if ($mode eq 4)
			{
				($filename,$::num_ratings,$::current_rating,$::comments)=split("\t",$data);

				# Check to see that it still exists before adding it to the list
				if (-e "$::album_dir/$rating_file_loc/$filename")
				{

					# Are we using galleries or photos?
					if ($::popular_flag eq 2)
					{
						$poplistkey="$rating_file_loc";

						# Add existing values to get a total for the gallery
						if ($::poplist{"$poplistkey"})
						{
							($temp1,$temp2)=split("\t",$::poplist{"$poplistkey"});
							$::num_ratings+=$temp1;
							$::current_rating+=$temp2;
						}
					}
					else
					{
						$poplistkey="$rating_file_loc/$filename";
					}

					$::poplist{"$poplistkey"}="$::num_ratings\t$::current_rating";
				}
			}

			# Check to see if this is the one we want
			elsif ($data=~/^$::shortphoto\t.*/)
			{
				chomp($data);
				debug("Found match: $data",3,__LINE__);
				close(RATINGS);
				($filename,$::num_ratings,$::current_rating,$::comments)=split("\t",$data);
				debug("Data: [$data] --> Ratings:[$::num_ratings] Rating:[$::current_rating] Comments:[$::comments]",4,__LINE__);
			}
		}

		close(RATINGS);
	}
	else
	{
		debug("$::current_ratingfile not found.",2,__LINE__);
	}

	if (!$::num_ratings)
	{
		$data="$::S{174}";
	}
	else
	{
		$data="$::S{175} $::num_ratings ";

		# Singular or plural?
		if ($::num_ratings gt 1)
		{
			$data.="$::S{202}";
		}
		else
		{
			$data.="$::S{200}";
		}
		$data.="$::S{176} $::current_rating.";
		if ($showcomment)
		{
			$data.="<br>$::comments";
		}
	}

	# Add "Rate It" link
	if (!$mode)
	{
		$data.="<br><a href=\"$::albumprog?function=$::rating_form".$::webdelim."rating_file_loc=";

		# Show rating info for the thumbnail we're looking at, not the current object
		if (isAMovie($::file) || $::album && $::rating_location)
		{
			$data.="$::middle";
		}
		else
		{
			$data.="$::goback";
		}
		$data.=$::webdelim."object=";

		# For movies, the object is not the current object, but the object being added to the album. Whew! Also true when rating_location=1...
		if (isAMovie($::file) || $::album && $::rating_location)
		{
			$data.="$::shortfile";
		}
		else
		{
			$data.="$::shortobject";
		}
		$data.=passVars(0);

		# Turn HTML breaks into line breaks when inserting comments as alt text
		$::comments=~s/<br \/>/\n/g;
		$::comments=~s/<br>/\n/g;
		# Kill quotes
		$::comments=~s/"//g;
		$data.="\">";
		if ($::textmenu)
		{
			$data.=$::S{213};
		}
		else
		{
			$data.="<img class=\"button\" src=\"$::rate_button\" alt=\"$::comments\">";
		}
		$data.="</a>";
	}

	$data="<small><small>$data</small></small>";

	debug("Returning rating of [$data]",4,__LINE__);

	debug("Leaving subroutine: getRatings($mode,$rating_file_loc);",4,__LINE__);

	return($data);
}


##########################################################################

=head3 webifyLinks()

 $output=webifyLinks($input);

 $input - The string to webify (make web safe).
 $output - Web safe version returned.

Returns the "websafe" version of the passed filename/path.

=cut
sub webifyLinks
{
my $input=shift;

	# Replace any & chars with %26
	$input=~s/&/\%26/g;

	return($input);
}


##########################################################################

=head3 regConnect()

 $response=regConnect($email,$url);

 $response - The response from the registration server
 $email - E-mail to register (product update notices ONLY will be sent to this address - and maybe not even those!)
 $url - URL of the album itself

Connects to registration server.

=cut
sub regConnect
{
use IO::Socket;

my $email=shift;
my $url=shift;
my $Sock;
my $buf;
my $query;
my $reghost="perl.Bobbitt.ca";

	$Sock=IO::Socket::INET->new(PeerAddr=>$reghost,PeerPort=>80,Proto=>'tcp') || return("Couldn't connect.");

	$query="GET /cgi-bin/album_register.pl?email=$email&url=$url HTTP/1.0";

	debug("Registration query: $query",3,__LINE__);

	print $Sock "$query\n";

	print $Sock "Accept-Language: en-us\n";
	print $Sock "Content-Length: 0\n";
	print $Sock "Accept: */*\n";
	print $Sock "User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)\n";
	print $Sock "Host: $reghost\n";
	print $Sock "Connection: Keep-Alive\n";
	print $Sock "\n";

	sleep(2);
	recv($Sock, $buf, 50000, 0);
	$buf=~s/\r//g;

	my @recs=split(/\n/, $buf);
	my $content=0;
	my $response;
	foreach (@recs)
	{
		if ($_ eq "")
		{
			$content=1;
			next;
		}
		$response=$_;
	}

	debug("Registration response: $response",3,__LINE__);

	return($response);
}


##########################################################################

=head3 deleteObject()

 $delete_form=deleteObject($some_object,$mode);

 $delete_form - The HTML of the confirmation form, returned if $mode=1.
 $some_object - Relative name (from album_dir on) of object to delete.
 $mode - 0 = do it; 1 = show confirmation

Deletes the selected object.

=cut
sub deleteObject
{
my $some_object=shift;
my $mode=shift;
my $some_thumb=$some_object;
my $fullpath;
my $temp;
my $imgext;
my $alb_thumb_ext;
my $movieext;
my @myfile_list;
my $newfile;
my $tempshortdesc;
my $templongdesc;
my $tempowner;
my $tempfunction;
my $delete_form;

	debug("Entering subroutine: deleteObject($some_object,$mode)",4,__LINE__);

	# Get thumbnail name...

	# Change all \'s to /'s
	$some_thumb=~s/\\/\//g;

	# Drop the preceeding path
	$some_thumb=~s/(.*\/)(.*)/$2/;

	$fullpath=$1;

	$some_thumb=~s/(.*)\..*/$1/;
	$some_thumb="$fullpath$::thumbprefix$some_thumb";

	# Check for photo extensions
	foreach $imgext (@::imgexts)
	{
		# Check lower case extensions
		$imgext="\L$imgext";
		if (-e "$::album_dir/$some_thumb.$imgext")
		{
			$alb_thumb_ext=$imgext;
		}

		# Check upper case extensions
		$imgext="\U$imgext";
		if (-e "$::album_dir/$some_thumb.$imgext")
		{
			$alb_thumb_ext=$imgext;
		}
	}

	# Check for movie extensions
	foreach $movieext (@::movieexts)
	{
		# Check lower case extensions
		$movieext="\L$movieext";
		if (-e "$::album_dir/$some_thumb.$movieext")
		{
			$alb_thumb_ext=$movieext;
		}

		# Check upper case extensions
		$movieext="\U$movieext";
		if (-e "$::album_dir/$some_thumb.$movieext")
		{
			$alb_thumb_ext=$movieext;
		}
	}

	# If there wasn't an extension found, then wildcard it for deletion
	if (!$alb_thumb_ext)
	{
		$alb_thumb_ext="*";
	}

	# Add extension
	$some_thumb.=".$alb_thumb_ext";

	if ($mode)
	{
		# Print confirmation form

		# Set temp=1 if it's a photo
		$temp=isAPhoto($some_object);

		# Set temp=2 if it's a movie
		if (!$temp)
		{
			$temp=isAMovie($some_object);
			if ($temp)
			{
				$temp++;
			}
		}

		$delete_form.="<form method=\"post\" action=\"$::albumprog\">\n";
		$delete_form.="<table width=350 border=0 align=center cellpadding=0 cellspacing=1 bgcolor=#868686><tr><td bgcolor=F3F3F3 class=sivitext><img src=images/spacer.gif height=10 width=100 border=0><br><img src=images/spacer.gif height=1 width=10 border=0><b>$::S{184} $some_object?</b><br>\n";
		if ($temp)
		{
			$delete_form.="<img src=images/spacer.gif height=1 width=10 border=0>$some_thumb $::S{199}\n";
		}
		else
		{
			opendir(ENTRIES,"$::album_dir/$some_object") or error(__LINE__,"not_readable","$::album_dir/$some_object");

			# Skip . and ..
			@myfile_list=grep !/^\.\.?$/,readdir ENTRIES;
			close(ENTRIES);

			$newfile=scalar(@myfile_list);
			debug("There are $newfile files in this directory.",2,__LINE__);

			# Display list of files to be deleted, if there are any
			if ($newfile)
			{
				$delete_form.="<br><img src=images/spacer.gif height=1 width=10 border=0>$::S{212}<br>\n";

				foreach $newfile (@myfile_list)
				{
					$delete_form.="<img src=images/spacer.gif height=1 width=10 border=0>$newfile<br>\n";
				}
			}
		}
		

		$delete_form.="<input type=\"hidden\" name=\"confirmdeleteobject\" value=\"$some_object\">\n";

		$delete_form.="<input type=\"hidden\" name=\"";
		$delete_form.="album\" value=\"$::goback\">\n";

		$fullpath=passVars(1);
		$delete_form.=$fullpath;
		$delete_form.="<br><img src=images/spacer.gif height=10 width=10 border=0><br><div align=center><input type=\"submit\" value=\"$::S{224}\" name=\"yes\" class=\"confirmbutton\"> \n";
		$delete_form.="<input type=\"submit\" value=\"$::S{225}\" name=\"no\" class=\"confirmbutton\">\n";
		$delete_form.="</div><img src=images/spacer.gif height=10 width=10 border=0></td></tr></table></form>";

		# If it's a photo, show it.
		if ($temp eq 1)
		{
			$delete_form.="<div align=center><img src=\"$::album_web/$some_object\" alt=\"\" width=$::photo_width></div>\n";
		}

		return($delete_form);
	}
	else
	{
		$some_object="$::album_dir/$some_object";
		$some_thumb="$::album_dir/$some_thumb";

		# Pull out just the object
		$newfile=$some_object;
		$newfile=~s/(.*\/)(.*)/$2/;

		# No change? Then this must be a Win32 machine...
		if ($newfile eq $some_object)
		{
			$newfile=~s/(.*\\)(.*)/$2/;
		}

		# Pull off the path to the object
		$temp=$some_object;
		$temp=~s/(.*\/)(.*)/$1/;

		# No change? Then this must be a Win32 machine...
		if ($temp eq $some_object)
		{
			$temp=~s/(.*\\)(.*)/$1/;
		}

		# Get owner
		openDescfile($temp);

		# Save off old descriptions info
		$tempshortdesc=$::shortdesc;
		$templongdesc=$::longdesc;
		$tempowner=$::owner;
		$tempfunction=$::function;
		getDescription($newfile);

		debug("Deleting [$some_object] and it's thumbnail [$some_thumb]<p>",2,__LINE__);

		debug("Currently logged in user is $::loggedin",2,__LINE__);
		debug("User who owns the object is $::owner",2,__LINE__);
		debug("List of default admins: $::default_admins",2,__LINE__);

		# Only do this if you're in admin mode, or if you're the owner of the thing, or if you're a default admin...
		if ($::function eq $::admin || (($::owner eq $::loggedin || $::default_admins=~/.*,$::loggedin,.*/) && $::loggedin) && $::username eq $albumuser[3])
		{
			debug("Ok, we're going to delete this: $some_object",2,__LINE__);

			if (-d $some_object)
			{
				opendir(ENTRIES,"$some_object") or error(__LINE__,"not_readable","$some_object");

				# Skip . and ..
				@myfile_list=grep !/^\.\.?$/,readdir ENTRIES;
				close(ENTRIES);

				debug("$some_object is a directory.",2,__LINE__);

				foreach $newfile (@myfile_list)
				{
					$newfile="$some_object/$newfile";
					debug("Deleting $newfile",2,__LINE__);
					if (!unlink("$newfile"))
					{
						print "$::S{150} $newfile $::S{185} -- $!<br>";
					}
				}

				if (!rmdir($some_object))
				{
					print "$::S{150} $some_object $::S{185} -- $!<br>";
				}
			}
			else
			{
				debug("$some_object is a file.",2,__LINE__);
				if (!unlink($some_object))
				{
					print "$::S{150} $some_object $::S{185}";
				}
			}

			# Delete Description
			debug("Deleting object $newfile in location $temp.",2,__LINE__);
			deleteDesc($newfile,$temp);

			# Delete thumbnail
			if (!unlink($some_thumb))
			{
				# We found a specific thumbnail, but it wasn't deleted.
				if ($alb_thumb_ext ne "*")
				{
					print "$::S{150} $some_thumb $::S{185}";
				}
			}

			# Kill the static HTML, if it's there
			unlink("$some_object.html");
			unlink("$some_object/$::static_html_filename");
		}
		else
		{
			print "$::S{150} $some_object $::S{186}";
		}

		# Restore descriptions info
		$::shortdesc=$tempshortdesc;
		$::longdesc=$templongdesc;
		$::owner=$tempowner;
		$::function=$tempfunction;
	}

	debug("Leaving subroutine: deleteObject($some_object,$mode)",4,__LINE__);

}


##########################################################################

=head3 moveObject()

 $move_form=moveObject($some_object,$mode,$moveto);

 $move_form - The HTML of the confirmation form, returned if $mode=1.
 $some_object - Relative name (from album_dir on) of object to move.
 $mode - 0 = do it; 1 = show confirmation
 $moveto - The location to move the object to.

Moves the selected object.

=cut
sub moveObject
{
my $some_object=shift;
my $mode=shift;
my $moveto=shift;
my $some_thumb=$some_object;
my $fullpath;
my $temp;
my $imgext;
my $alb_thumb_ext;
my $movieext;
my $newfile;
my $thumb_moveto;
my $short_thumb;
my $short_object;
my $movedir;
my $fromdir;
my $tempshortdesc;
my $templongdesc;
my $tempowner;
my $tempfunction;
my $move_form;

	debug("Entering subroutine: moveObject($some_object,$mode,$moveto)",4,__LINE__);

	# Turn $moveto into a full path
	$moveto="$::album_dir/$moveto";

	# Get thumbnail name...

	# Change all \'s to /'s
	$some_thumb=~s/\\/\//g;

	# Drop the preceeding path
	$some_thumb=~s/(.*\/)(.*)/$2/;

	$fullpath=$1;

	$some_thumb=~s/(.*)\..*/$1/;
	$some_thumb="$fullpath$::thumbprefix$some_thumb";

	# Check for photo extensions
	foreach $imgext (@::imgexts)
	{
		# Check lower case extensions
		$imgext="\L$imgext";
		if (-e "$::album_dir/$some_thumb.$imgext")
		{
			$alb_thumb_ext=$imgext;
		}

		# Check upper case extensions
		$imgext="\U$imgext";
		if (-e "$::album_dir/$some_thumb.$imgext")
		{
			$alb_thumb_ext=$imgext;
		}
	}

	# Check for movie extensions
	foreach $movieext (@::movieexts)
	{
		# Check lower case extensions
		$movieext="\L$movieext";
		if (-e "$::album_dir/$some_thumb.$movieext")
		{
			$alb_thumb_ext=$movieext;
		}

		# Check upper case extensions
		$movieext="\U$movieext";
		if (-e "$::album_dir/$some_thumb.$movieext")
		{
			$alb_thumb_ext=$movieext;
		}
	}

	# If there wasn't an extension found, then wildcard it for moving
	if (!$alb_thumb_ext)
	{
		$alb_thumb_ext="*";
	}

	# Add extension
	$some_thumb.=".$alb_thumb_ext";

	# Print confirmation form
	if ($mode)
	{
		# Set temp=1 if it's a photo
		$temp=isAPhoto($some_object);

		# Set temp=2 if it's a movie
		if (!$temp)
		{
			$temp=isAMovie($some_object);
			if ($temp)
			{
				$temp++;
			}
		}
		
		$move_form.="<form method=\"post\" action=\"$::albumprog\">\n";



		$move_form.="<table width=350 border=0 align=center cellpadding=0 cellspacing=1 bgcolor=#868686><tr><td bgcolor=F3F3F3 class=sivitext>";
		$move_form.="<img src=images/spacer.gif width=10 height=10><br><img src=images/spacer.gif width=10 height=10><b>$::S{218} $some_object?</b>\n";
		if ($temp)
		{
			$move_form.="<br><img src=images/spacer.gif width=10 height=10>$some_thumb $::S{222}\n";
		}
		
		$move_form.="<br><img src=images/spacer.gif width=10 height=10><br><img src=images/spacer.gif width=10 height=10>$::S{223}&nbsp;&nbsp;<select name=\"category\" class=uploadkatbox>\n";

		$::doing_upload=1;
		recursiveScan($::album_dir);
		$::doing_upload=0;
		$move_form.="$::object</select><br><img src=images/spacer.gif width=10 height=10><br>\n";
		$move_form.="<input type=\"hidden\" name=\"confirmmoveobject\" value=\"$some_object\">\n";

		$move_form.="<input type=\"hidden\" name=\"";
		$move_form.="album\" value=\"$::goback\">\n";

		$fullpath=passVars(1);
		$move_form.=$fullpath;
		$move_form.="<div align=center><input type=\"submit\" value=\"$::S{215}\" name=\"yes\" class=\"confirmbutton\"> \n";
		$move_form.="<input type=\"submit\" value=\"$::S{228}\" name=\"no\" class=\"confirmbutton\"></div>\n";
		$move_form.="<img src=images/spacer.gif width=10 height=10></td></tr></table>";
		$move_form.="</form>\n";

		# If it's a photo, show it.
		if ($temp eq 1)
		{
			$move_form.="<div align=center><img src=\"$::album_web/$some_object\" alt=\"\"></div>\n";
		}

		return($move_form);
	}
	else
	# Actually move the object
	{
		$movedir="$moveto";

		$short_thumb=$some_thumb;

		# Change all \'s to /'s
		$some_thumb=~s/\\/\//g;

		# Drop the proceeding path
		$short_thumb=~s/(.*\/)(.*)/$2/;

		$thumb_moveto="$moveto/$short_thumb";

		$short_object=$some_object;

		# Change all \'s to /'s
		$short_object=~s/\\/\//g;

		# Drop the proceeding path
		$short_object=~s/(.*\/)(.*)/$2/;
		$fromdir=$1;

		# Still no change? Then there was no path at all...
		if ($short_object eq $some_object)
		{
			$fromdir="";
		}

		$moveto.="/$short_object";

		# Read the description for the file about to be moved
		openDescfile("$::album_dir/$fromdir");

		# Save off old descriptions info
		$tempshortdesc=$::shortdesc;
		$templongdesc=$::longdesc;
		$tempowner=$::owner;
		$tempfunction=$::function;
		getDescription($short_object);

		$some_object="$::album_dir/$some_object";

		$some_thumb="$::album_dir/$some_thumb";

		debug("Moving [$some_object] and it's thumbnail [$some_thumb] to [$moveto]<p>",2,__LINE__);

		debug("Currently logged in user is $::loggedin",2,__LINE__);
		debug("User who owns the object is $::owner",2,__LINE__);
		debug("List of default admins: $::default_admins",2,__LINE__);

		# Only do this if you're in admin mode, or if you're the owner of the thing, or if you're a default admin...
		if ($::function eq $::admin || (($::owner eq $::loggedin || $::default_admins=~/.*,$::loggedin,.*/) && $::loggedin) && $::username eq $albumuser[3])
		{
			debug("Ok, we're going to move this: $some_object here: $moveto",2,__LINE__);

			if (!rename($some_object,$moveto))
			{
				print "$::S{150} $some_object $::S{219}";
			}

			# Delete description
			# Pull out just the object
			$newfile=$some_object;
			$newfile=~s/(.*\/)(.*)/$2/;

			# No change? Then this must be a Win32 machine...
			if ($newfile eq $some_object)
			{
				$newfile=~s/(.*\\)(.*)/$2/;
			}

			# Pull off the path to the object
			$temp=$some_object;
			$temp=~s/(.*\/)(.*)/$1/;

			# No change? Then this must be a Win32 machine...
			if ($temp eq $some_object)
			{
				$temp=~s/(.*\\)(.*)/$1/;
			}

			# Update description in new location
			updateDesc($short_object,"$movedir/",$::shortdesc,$::longdesc,$::owner);

			# Delete Description
			debug("Deleting object $newfile in location $temp.",2,__LINE__);
			deleteDesc($newfile,$temp);

			# Move thumbnail
			if (!rename($some_thumb,$thumb_moveto))
			{
				# We found a specific thumbnail, but it wasn't moved.
				if ($alb_thumb_ext ne "*")
				{
					print "$::S{150} $some_thumb $::S{219}";
				}
			}

			# Kill the static HTML, if it's there
			unlink("$some_object.html");
			unlink("$some_object/$::static_html_filename");

			# *** Move the image views too!
		}
		else
		{
			print "$::S{150} $some_object $::S{220}";
		}

		# Restore descriptions info
		$::shortdesc=$tempshortdesc;
		$::longdesc=$templongdesc;
		$::owner=$tempowner;
		$::function=$tempfunction;
	}

	debug("Leaving subroutine: moveObject($some_object,$mode,$moveto)",4,__LINE__);

}


##########################################################################

=head3 createAlbumForm()

 $create_form=createAlbumForm($createalbum);

 $create_form - The HTML for the Create Album form.
 $createalbum - The filesystem directory to create the album in.

Displays the "create album" form.

=cut
sub createAlbumForm
{
my $data;
my $create_form;
my $createalbum=shift;

	if ($createalbum eq $::rootalbumname)
	{
		$createalbum="/";
	}

	$data=passVars(1);
	$create_form.="<table width=504 align=center><tr><td height=20 class=meniphoto>&nbsp;$::S{187} $createalbum</td></tr><tr><td height=5></td></tr></table>";
	$create_form.=<<HTML;
<form method="post" action="$::albumprog">
$data
HTML
	$create_form.="<table width=382 border=0 cellpadding=0 cellspacing=1 bgcolor=#868686 align=center><tr><td bgcolor=#F3F3F3><table width=380 border=0 cellpadding=0 cellspacing=0 class=meniphoto><tr><td height=9 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=176 height=18><div align=right>";
	$create_form.="Naziv direktorija&nbsp;";
	$create_form.="</div></td><td width=204 height=18>";
	$create_form.="<input type=\"text\" name=\"albumname\" size=\"30\" class=titletextbox>\n";
	$create_form.=<<HTML;
<input type="hidden" name="admincreate" value="1">
<input type="hidden" name="album" value="$createalbum">
HTML
	$create_form.="</td></tr><tr><td colspan=2 height=8></td></tr><tr><td width=176 height=18><div align=right>";
	$create_form.=buildDescFooter(1);
	$create_form.="<tr><td height=9 colspan=2><img src=images/spacer.gif width=1 height=1></td></tr></table></td></tr></table><table width=382 border=0 cellspacing=0 cellpadding=0 align=center><tr><td><div align=right><input name=imageField type=image src=images/button_izmjeni.gif width=111 height=25 border=0></div></td></tr></table>";
	$create_form.="</form>";
	return($create_form);
}


##########################################################################

=head3 createAlbum()

 $return_code=createAlbum($basedir,$directory,$newshortdesc,$newlongdesc,$newowner,$mode);

 $return_code - Non-zero only if directory could not be created.
 $basedir - The location to create the new album, as an absolute filesystem path.
 $directory - The actual directory name for the album.
 $newshortdesc - Short description for new album.
 $newlongdesc - Long description for new album.
 $newowner - The owner of the album.
 $mode - 0 = No change; 1 = Force album creation, even if not an admin (for uploads)

Creates $directory in $basedir, and updates the description with $newshortdesc and $newlongdesc.

=cut
sub createAlbum
{
my $basedir=shift;
my $directory=shift;
my $newshortdesc=shift;
my $newlongdesc=shift;
my $newowner=shift;
my $mode=shift;
my $dirtomk;
my $status;
	if(!$newshortdesc)
	{
		$newshortdesc=$directory;
	}

	debug("Entering subroutine: createAlbum($basedir,$directory,$newshortdesc,$newlongdesc,$newowner)",4,__LINE__);

	# Check for tampering
	if ($basedir=~/^\\*\./ || $basedir=~/^\/*\./ || $directory=~/^\\*\./ || $directory=~/^\/*\./)
	{
		error(__LINE__,"sanity","$::S{84} $::S{14}.");
	}

	# Prepend $::album_dir to $basedir for security reasons
	$basedir="$::album_dir/$basedir";

	# Strip things down
	$dirtomk=$basedir;
	# Drop the preceeding path
	$dirtomk=~s/(.*\/)(.*)/$2/;

	# Get owner info
	openDescfile("$1/");
	getDescription($2);

	# Force an authentication
	Authenticate();

	if (!isAdmin() && !$mode)
	{
		debug("Not authorized!",4,__LINE__);
		display(javaAlert($::S{296}));
		return(1);
	}

	# Set owner if not already set
	if (!$newowner)
	{
		$newowner=$::loggedin;
	}

	chomp($directory);
	$dirtomk="$basedir/$directory";

	# If dir doesn't already exist, create it.
	if (!(-d $dirtomk))
	{
		if (!mkdir($dirtomk,777))
		{
			$status=1;
		}
		if (!chmod(0777,$dirtomk))
		{
			$status=2;
		}

		# Update the description for this new album
		if ($newshortdesc)
		{
			updateDesc($directory,"$basedir/",$newshortdesc,$newlongdesc,$newowner);
		}
	}
	else
	{
		print "$::S{150} $dirtomk $::S{189}";
	}

	debug("Leaving subroutine: createAlbum($basedir,$directory,$newshortdesc,$newlongdesc,$newowner)",4,__LINE__);

	return($status);
}


##########################################################################

=head3 getCookie()

 getCookie();

Gets cookie from browser, and puts it into %cookie hash.

=cut
sub getCookie
{
my $chip;
my $val;

	# split cookie at each ; (cookie format is name=value; name=value; etc...)
	# Convert plus to space (in case of encoding (not necessary, but recommended)
	foreach (split(/; /, $ENV{'HTTP_COOKIE'}))
	{
		s/\+/ /g;

		# Split into key and value.
		# splits on the first =.
		($chip, $val) = split(/=/,$_,2);

		# Convert %XX from hex numbers to alphanumeric
		$chip =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge;
		$val =~ s/%([A-Fa-f0-9]{2})/pack("c",hex($1))/ge;

		# Associate key and value
		$::cookie{$chip} .= "\1" if (defined($::cookie{$chip})); # \1 is the multiple separator
		$::cookie{$chip} .= $val;
	}
}


##########################################################################

=head3 delCookie()

 delCookie("name1","name2",...);

Deletes cookies of provided names. If more than one name is provided, multiple cookies are deleted. Deletion is handled by expiring the cookie immediately. Must be done before the content type header is sent to the browser.

=cut
sub delCookie
{
my @to_delete=@_;
my $name;

	foreach $name (@to_delete)
	{
		#undefines cookie
		undef $::cookie{$name};
		print "Set-Cookie: $name=deleted; expires=Thu, 01-Jan-1970 00:00:00 GMT;\n";
	}
}


##########################################################################

=head3 splitCookie()

 splitCookie($param);

 $param = parameter to split

Splits a multi-valued chip into a list of parameters.

=cut
sub splitCookie
{
my $param=shift;
my @params=split("&",$param);
	return (wantarray ? @params : $params[0]);
}


##########################################################################

=head3 showCookie()

 showCookie();

Displays the contents of a cookie in debug level 2.

=cut
sub showCookie
{
my $chip;
my @chips;
my $singlechip;

	debug("Cookie Contents Follow: ",2,__LINE__);
	foreach $chip (%::cookie)
	{
		# Handle arrays
		if ($chip=~/&/)
		{
			@chips=splitCookie($chip);
			foreach $singlechip (@chips)
			{
				debug(" --> [$singlechip]",2,__LINE__);
			}
		}
		if ($::cookie{$chip})
		{
			debug("[$chip] = [$::cookie{$chip}]",2,__LINE__);
		}
	}
	debug("END OF COOKIE",2,__LINE__);
}


##########################################################################

=head3 recentUploads()

 $recent_html=recentUploads();

 $recent_html - Contains the HTML for the recent uploads table.

Returns HTML for the last $::recent_uploads number of uploads, as read from $::upload_logfile.

=cut
sub recentUploads
{
my $count=$::recent_uploads;
my $data;
my $filetemp;
my $photoinf;
my $temp;
my $allphotos;
my @photoarray;
my @timearray;
my @userarray;
my $recent_html;
my $allusers;
my $alltimes;
my $tempalbum;
my $tempmiddle;
my $tempgoback;
my $realcount;
my $showall=$form->param('showall');

	# Do a sanity check first...
	if (!$::upload_logfile || !$::recent_uploads || !-r $::upload_logfile)
	{
		return($::S{194});
	}

	$tempalbum=$::album;
	$tempmiddle=$::middle;
	$tempgoback=$::goback;
	$::album=$::middle=$::goback="";
	$::isimage=1;

	if ($::ssi)
	{
		$count=$::ssi;
	}

	open(UPLOADLOG,"$::upload_logfile") || error(__LINE__,"not_readable","$::upload_logfile: $!");
	while ($data=<UPLOADLOG>)
	{
		$realcount++;
		chomp($data);
		debug("\$data=$data",3,__LINE__);

		# Get Photo Info
		$photoinf=$data;
		$photoinf=~s/.+\t[^\t]+\t[^\t]+\t([^\t]+)/$1/;
		debug("\$photoinf(photo)=$photoinf",3,__LINE__);

		if ($allphotos)
		{
			$allphotos="$photoinf\t$allphotos";
		}
		else
		{
			$allphotos=$photoinf;
		}

		# Get User Info
		$photoinf=$data;
		$photoinf=~s/.+\t[^\t]+\t([^\t]+)\t[^\t]+/$1/;
		debug("\$photoinf(user)=$photoinf",3,__LINE__);

		if ($allusers)
		{
			$allusers="$photoinf\t$allusers";
		}
		else
		{
			$allusers=$photoinf;
		}

		# Get Time Info
		$photoinf=$data;
		$photoinf=~s/(.+)\t[^\t]+\t[^\t]+\t[^\t]+/$1/;
		debug("\$photoinf(times)=$photoinf",3,__LINE__);

		if ($alltimes)
		{
			$alltimes="$photoinf\t$alltimes";
		}
		else
		{
			$alltimes=$photoinf;
		}
	}
	close(UPLOADLOG);

	debug("Loaded the upload log file entries.",2,__LINE__);
	debug("\$allphotos=$allphotos",4,__LINE__);

	@photoarray=split("\t",$allphotos);
	@photoarray=reverse @photoarray;
	@timearray=split("\t",$alltimes);
	@timearray=reverse @timearray;
	@userarray=split("\t",$allusers);
	@userarray=reverse @userarray;

	while ($realcount gt 0)
	{
		$photoinf=pop @photoarray;
		$alltimes=pop @timearray;
		$allusers=pop @userarray;

		debug("\$photoinf=$photoinf ($::thumbprefix)",3,__LINE__);

		$temp=showObject($photoinf,1,$allusers,$alltimes);

		# Decrement counter if something was returned
		if ($temp)
		{
			$count--;
			$recent_html.=$temp;
		}

		# If we've displayed all the "most recent" uploads, stop reading from the log
		if (!$count)
		{
			$realcount=0;
		}

		# Increment counter back up if we're showing all recent uploads
		if ($showall)
		{
			$count++;
		}

		$realcount--;

		debug("\$count=$count",3,__LINE__);
		debug("\$photoinf=$photoinf",3,__LINE__);
	}

	if (!$showall && !$::ssi)
	{
		# Show More link
		$recent_html.="<br><br>\n<a href=\"$::albumprog?album=$::recent_upload_album";
		$recent_html.=passVars(0);
		$recent_html.=$::webdelim."showall=1\" class=\"optionslink\">$::S{291}</a>";
	}

	$::album=$tempalbum;
	$::middle=$tempmiddle;
	$::goback=$tempgoback;

	return($recent_html);
}


##########################################################################

=head3 javaAlert()

 $javastuff=javaAlert($message);

 $message - Message to display
 $javastuff - HTML/JavaScript code to display a popup.

Returns HTML/JavaScript code to display $message as a javascript "alert" popup.

=cut
sub javaAlert
{
my $message=shift;
my $javastuff;

	$javastuff="<script language=\"JavaScript\">\n";
	$javastuff.="<!--\n";
	$message=~s/\n//g;
	$message=~s/\r//g;
	$javastuff.="alert('$message');\n";
	$javastuff.="//-->\n";
	$javastuff.="</script>\n";
	return($javastuff);
}


##########################################################################

=head3 genThumb()

 $status=genThumb($myobject,$image_thumb,$mode);

 $status - 0 = Success, 1 = Failure
 $myobject - The full file system path to the object to generate a thumbnail for
 $image_thumb - The full file system path to the thumbnail to create for this image
 $mode - 0 = Generate thumbnails for pictures; 1 = Resize pictures on upload

Generates a thumbnail for $object, according to the current rules for thumbnails. This subroutine requires ImageMagick to be installed in order to work.

=cut
sub genThumb
{
my $myobject=shift;
my $image_thumb=shift;
my $mode=shift;
my $system_call;
my $output;
my $retcode;
my $count;

	debug("Entering subroutine: genThumb($myobject,$image_thumb,$mode)",4,__LINE__);

	$system_call="\"$::imagemagick/convert\" ";
	if ($::thumb_quality)
	{
		$system_call.="-quality $::thumb_quality ";
	}

	# Some older ImageMagick installs don't know "resize" so use "scale" instead
#	$system_call.="-scale ";
#	$system_call.="-resize ";
	$system_call.="-geometry ";

	if ($mode)
	{
		$system_call.="$::pic_resize";
	}
	else
	{
		if ($::thumb_width)
		{
			$system_call.=$::thumb_width;
		}
		if ($::thumb_width || $::thumb_height)
		{
			$system_call.="x";
		}
		if ($::thumb_height)
		{
			$system_call.=$::thumb_height;
		}
	}
	$system_call.=" \"$myobject\" \"$image_thumb\"";

	# Resize into desired quality and dimensions
	debug("IMAGEMAGICK: $system_call",2,__LINE__);
#	system("$system_call");
	$output=`$system_call 2>&1`;
	debug("IMAGEMAGICK RETURNED: $output",2,__LINE__);

	if ($output)
	{
		print "$::S{214} $output<p>";
	}

	$retcode=1;

	# Keep checking for thumbnail, for 2 seconds
	for($count=0;$count ge 20;$count++)
	{
		if (!$retcode)
		{
			next;
		}
		sleep(.1);
		if (-r $image_thumb)
		{
			$retcode=0;
		}
	}

	debug("Leaving subroutine: genThumb($myobject,$image_thumb,$mode)",4,__LINE__);

	return($retcode);

}


##########################################################################

=head3 isAdmin()

 $status=isAdmin();

 $status - 0 = Not an admin; 1 = Yep, they're an admin!; 2 = They're a user, but they own this album.

Checks to see if the current user is an authenticated admin.

=cut
sub isAdmin
{
my $status=0;

	# Check to see if the user owns this album
	if ($::loggedin eq $::owner && $::loggedin)
	{
		$status=1;
	}

	# If the current user is a default admin and is logged in, or the admin function is being used.
	if (($::default_admins=~/.*,$::loggedin,.*/ && $::loggedin) || $::function eq $::admin && $::username eq $albumuser[3])
	{
		$status=1;
	}

	debug("isAdmin: \$::function=$::function; \$::loggedin=$::loggedin; \$::owner=$::owner; \$::default_admins=$::default_admins... Is admin: $status",2,__LINE__);

	return($status);
}


##########################################################################

=head3 isGuest()

 $status=isGuest();

 $status - 0 = Not a guest, 1 = Yep, they're a guest!

Checks to see if the current user is an authenticated guest.

=cut
sub isGuest
{
my $status=0;

	# If the current user is a default admin and is logged in, or the admin function is being used.
	if ($::default_guests=~/.*,$::loggedin,.*/ && $::loggedin)
	{
		$status=1;
	}

	debug("isGuest: \$::loggedin=$::loggedin; \$::default_guests=$::default_guests... Is guest: $status",2,__LINE__);

	return($status);
}


##########################################################################

=head3 showBreadCrumbs()

 $breadcrumbs=showBreadCrumbs();

 $breadcrumbs - The HTML for the breadcrumb trail.

Builds an HTML "breadcrumb" trail so the user can navigate upwards in their album.
$::bread_style defines the format to be used:

 0 = Use folder heirarchy
 1 = use » single » line » breadcrumbs

=cut
sub showBreadCrumbs
{
my @slices;
my $temp;
my $lastslice;
my $count;
my $tempfunction=$::function;
my $indent=0;
my $slice;
my $fullslice;
my $first=1;
my $breadcrumbs;

	debug("Entering subroutine: showBreadCrumbs()",4,__LINE__);

	# Clear function
	$::function="";

	if ($::album)
	{
		$slice=$::album;
	}
	if ($::photo)
	{
		$slice=$::photo;
	}
	$slice=~s/^$::album_dir(.*)/$1/;

	@slices=split("/",$slice);
	$count=scalar(@slices);
	$count--;
	debug("There are $count levels in this breadcrumb path.",2,__LINE__);

	if (($breadcrumbs || $::album eq $::album_dir) && !$::create_html_flag)
	{
		$::function=$tempfunction;
		return($breadcrumbs);
	}

	$breadcrumbs="<a href=\"";
	if ($::create_html_flag)
	{
		$temp=$count;
		while ($temp gt 0)
		{
			$breadcrumbs.="../";
			$temp--;
		}
		$breadcrumbs.="$::static_hml_filename";
	}
	else
	{
		$breadcrumbs.="$::albumprog?full=1";
		$breadcrumbs.=passVars(0);
	}
	$breadcrumbs.="\" class=\"menialbum\">";
	openDescfile("$::album_dir/");
	getDescription($::rootalbumname);

	if (!$::bread_style)
	{
		# $breadcrumbs.="<img border=\"0\" src=\"";
		if ($::create_html_flag)
		{
			# Hard coded. I know, I know...
			# $breadcrumbs.="/folder_mali.gif";
		}
		else
		{
			# $breadcrumbs.="$::album_folder_icon";
		}
		# $breadcrumbs.="\" alt=\"\"> ";
	}

	if (!$::shortdesc)
	{
		$::shortdesc="$::S{87}";
	}
	$breadcrumbs.="$::shortdesc";
	$breadcrumbs.="</a>";







	$breadcrumbs="<table width=178 border=0 cellspacing=0 cellpadding=0><tr><td width=24 valign=top><img src=images/foto_icon3.gif width=24 height=24></td><td width=154><table width=154 border=0 cellspacing=0 cellpadding=0><tr><td height=1><img src=images/foto_icon2.gif width=154 height=5></td></tr><tr><td width=154 background=images/pozadina_meni.jpg><table width=154 border=0 cellspacing=0 cellpadding=0><tr><td width=25 valign=top><img src=images/foto_icon1.gif width=25 height=19></td><td width=129>".$breadcrumbs."</td></tr></table></td></tr><tr><td height=1 bgcolor=#AEB8B9><img src=images/spacer.gif width=1 height=1></td></tr></table></td></tr></table>";
	$breadcrumbs.="<table width=178 height=5 border=0 cellpadding=0 cellspacing=0><tr><td><img src=img/1t.gif width=1 height=1></td></tr></table>";







	foreach $slice (@slices)
	{
	# Are we on the last "slice" and is it a photo?
	my $lastphoto=($::photo && isAPhoto($slice));

		if (!$slice)
		{
			next;
		}

		$indent++;

		if ($lastphoto)
		{
			openDescfile("$::album_dir/$lastslice/");
		}
		else
		{
			openDescfile("$::album_dir/$fullslice/");
		}
		$::shortdesc="";
		getDescription($slice);

		if (!$::bread_style)
		{
			$breadcrumbs.="<table width=178 height=2 border=0 cellpadding=0 cellspacing=0><tr><td><img src=img/1t.gif width=1 height=1></td></tr></table>";

			# Indent sub albums
			#$temp=$indent;
			#while ($temp)
			#{
			# $breadcrumbs.=$::S{232};
			# $temp--;
			#}
		}
		else
		{
			$breadcrumbs.="$::S{276} ";
		}

		if ($first)
		{
			$first=0;
		}
		else
		{
			$fullslice.="/";
		}
		$fullslice.=$slice;
		debug("\$slice=$slice",4,__LINE__);
		debug("\$fullslice=$fullslice",4,__LINE__);

		if ($lastphoto)
		{
			$breadcrumbs.="<table width=178 border=0 cellspacing=0 cellpadding=0><tr><td width=24>&nbsp;</td><td width=154><table width=154 border=0 cellspacing=0 cellpadding=0><tr><td height=1 bgcolor=#AEB8B9><img src=images/spacer.gif width=1 height=1></td></tr><tr><td background=images/background_photo.gif><table width=154 border=0 cellspacing=0 cellpadding=0><tr><td width=18><img src=images/photo_icon.gif width=18 height=18></td><td width=136 class=meniphoto>";
		}
		else
		{
			$breadcrumbs.="<table width=178 border=0 cellspacing=0 cellpadding=0><tr><td width=24>&nbsp;</td><td width=154><table width=154 border=0 cellspacing=0 cellpadding=0><tr><td height=1 bgcolor=#9C9C9C><img src=images/spacer.gif width=1 height=1></td></tr><tr><td background=images/pozadina_meni.jpg><table width=154 border=0 cellspacing=0 cellpadding=0><tr><td width=34><img src=images/album_mali.jpg width=34 height=19></td><td width=120><a href=\"";
		}


		if ($::create_html_flag)
		{
			if ($lastphoto)
			{
				# $breadcrumbs.="$::shortphoto.html";
			}
			else
			{
				$temp=$count-1;
				while ($temp gt 0)
				{
					$breadcrumbs.="../";
					$temp--;
				}
				$breadcrumbs.="$::static_html_filename";
			}
		}
		else
		{

		if (!$lastphoto)
		{
			$breadcrumbs.="$::albumprog?";
		}
			

			if ($lastphoto)
			{
				# $breadcrumbs.="photo";
			}
			else
			{
				$breadcrumbs.="album";
			}

		if (!$lastphoto)
		{
			$breadcrumbs.="=$fullslice";
			$breadcrumbs.=passVars(0);
		}


		}
		if (!$lastphoto)
		{
			$breadcrumbs.="\" class=\"menialbum\">";
		}

		if (!$::shortdesc)
		{
			$::shortdesc=$slice;
		}
		if ($slice eq $::recent_upload_album)
		{
			$::shortdesc="$::recent_uploads $::S{195}";
		}

		if (!$::bread_style)
		{
			# $breadcrumbs.="<img border=\"0\" src=\"";
			if ($::create_html_flag)
			{
				# Hard coded. I know, I know...
				# $breadcrumbs.="/thmb_album.gif";
			}
			else
			{
				# $breadcrumbs.="<table width=178 height=21 border=0 cellpadding=0 cellspacing=0><tr><td><img src=img/1t.gif width=1 height=1><img src=images/album_icon.gif width=48 height=25></td><td width=143 class=naslovisivo><table width=129 height=21 border=0 cellpadding=0 cellspacing=0 background=images/cell_tablice_lijevo.gif><tr><td width=129 class=naslovgore>"$::album_folder_icon</td></tr></table></td></tr></table>";
			}
			# $breadcrumbs.="\" alt=\"\"> ";
		}

		$breadcrumbs.="$::shortdesc";
		if (!$lastphoto)
		{
			$breadcrumbs.="</a>";
		}
		$breadcrumbs.="</tr></table></td></tr><tr><td height=1 bgcolor=#9C9C9C><img src=images/spacer.gif width=1 height=1></td></tr></table></td></tr></table>\n";
		$lastslice=$fullslice;
		$count--;
	}
	# $breadcrumbs.="<table width=178 height=10><tr><td height=10></td></tr></table>";
	# Reset function
	$::function=$tempfunction;

	debug("Leaving subroutine: showBreadCrumbs()",4,__LINE__);
	return($breadcrumbs);
}


##########################################################################

=head3 checkUpdate()

 checkUpdate();

Checks to see if there is a newer version of album.pl available.

=cut
sub checkUpdate
{
use IO::Socket;

my $Sock;
my $buf;
my $query;
my $remotever;
my $remotedate;
my $stripver;
my @allinfo;
my $revdate;
my $quit;
my $reghost="perl.Bobbitt.ca";

	debug("Entering subroutine: checkUpdate()",4,__LINE__);

	$Sock=IO::Socket::INET->new(PeerAddr=>$reghost,PeerPort=>80,Proto=>'tcp');
	if (!$Sock)
	{
		display(javaAlert($::S{264}));
		return();
	}

	$query="GET /cgi-bin/album_update.pl HTTP/1.0";

	debug("Registration query: $query",3,__LINE__);

	print $Sock "$query\n";

	print $Sock "Accept-Language: en-us\n";
	print $Sock "Content-Length: 0\n";
	print $Sock "Accept: */*\n";
	print $Sock "User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)\n";
	print $Sock "Host: $reghost\n";
	print $Sock "Connection: Keep-Alive\n";
	print $Sock "\n";

	sleep(2);
	recv($Sock, $buf, 50000, 0);
	$buf=~s/\r//g;

	my @recs=split(/\n/, $buf);
	my $content=0;
	my $response;
	foreach (@recs)
	{
		if ($_ eq "")
		{
			$content=1;
			next;
		}
		$response=$_;
	}

	($remotever,$remotedate)=split("\t",$response);
	debug("Update response: $response [$remotever][$remotedate] {@recs}",3,__LINE__);

	$stripver=$::ver;
	$stripver=~s/\D//g;

	@allinfo=stat($0);
	$revdate=$allinfo[9];

	debug("Album Version: [$stripver] Available: [$remotever]",3,__LINE__);
	debug("Album Date: [$revdate] Available: [$remotedate]",3,__LINE__);

	$response="";

	# Version check
	if ($remotever <= $stripver)
	{
		debug("Version is up to date.",3,__LINE__);
		$response="$::S{253}";
	}
	else
	{
		debug("Version is out of date.",3,__LINE__);
	}

	# Date check
	if ($remotedate <= $revdate)
	{
		debug("Date is up to date.",3,__LINE__);
		$response="$::S{253}";
	}
	else
	{
		debug("Date is out of date.",3,__LINE__);
		$response="";
	}

	if (!$response)
	{
		$remotever=substr($remotever,0,1).".".substr($remotever,1,10);
		$stripver=substr($stripver,0,1).".".substr($stripver,1,10);
		$response="$::S{254}\\n\\n$::S{255} $stripver, $::S{256} ".localtime($revdate).".\\n$::S{257} $remotever, $::S{256} ".localtime($remotedate)."\\n\\n$::S{258} http://perl.Bobbitt.ca/album";
	}
	debug("To display: $response",3,__LINE__);

	display(javaAlert($response));

	debug("Leaving subroutine: checkUpdate()",4,__LINE__);
}


##########################################################################

=head3 randomizer()

 $photo=randomizer();

 $photo - Returned path (from album root) to a random photo.

Returns the path to a random image in the album.

=cut
sub randomizer
{
my $randpic;
my $rnd;
my $doing_upload_temp;

	debug("Entering subroutine: randomizer()",4,__LINE__);

	$doing_upload_temp=$::doing_upload;
	$::doing_upload=2;
	recursiveScan($::album_dir);

	# Count total number of dirs
	$rnd=($#::total_photo_list)+1;

	debug("Dirs ($rnd total): [@::total_photo_list]",2,__LINE__);

	$rnd=int rand($rnd);

	$randpic=@::total_photo_list[$rnd];

	debug("Picked dir #$rnd [$randpic]",2,__LINE__);

	$::doing_upload=$doing_upload_temp;

	debug("Leaving subroutine: randomizer()",4,__LINE__);

	return($randpic);
}


##########################################################################

=head3 shroudPic()

 $imgcode=shroudPic($image);

 $imgcode - The actual content of the image, to display
 $image - The full file path to the image to display back

Displays the image pointed to by $image, even if it is not under the web root.

=cut
sub shroudPic
{
my $image=shift;
my $imgcode="";
my $ext=$image;
my $buf;
my $err=0;
my $referer=$::album_web;

	debug("Entering subroutine: shroudPic($image)",4,__LINE__);

	$referer=~s/:\/\/([^\/]*).*/$1/;
	debug("Referer is: $referer",2,__LINE__);

	# Check for valid referer
	if ($ENV{'HTTP_REFERER'}!~m|https?://([^/]*)$referer|i)
	{
		debug("Bad Referer: $ENV{'HTTP_REFERER'}",2,__LINE__);
		print "Content-Type: text/html\n\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html>";
		print "You are not permitted to view this image. Please use the following URL: ";
		print "<a href=\"$::albumprog\">$::albumprog</a></html>";
		exit(1);
	}

	# Get extension
	$ext=~s/.*\.(.*)/$1/;
	$ext="\L$ext";

	if ($ext eq "jpg")
	{
		$ext="jpeg";
	}

	# Special hack for /stuff/image.gif/../morestuff --> /morestuff
	if ($image=~/$ext.*$ext/)
	{
		$image=~s/(.*)\/.*$ext\/\.\.(\/.*$ext)/$1$2/;
	}

	# Strip funny stuff off image link
	#$image=~s/[^a-z0-9\.\_\-\\\/:] ,//gi;

	# Check for relative paths
	if ($image=~/^\\*\./)
	{
		$err=1;
	}
	if ($image=~/^\/*\./)
	{
		$err=1;
	}

	# Remove special chars
	$image=~s/[|><]//g;

	if ($err)
	{
		exit(1);
	}

	$image="$::album_dir/$image";
	debug("Displaying shrouded image: $image",2,__LINE__);

	# Only show the image if it exists
#	if (-e $image && isAPhoto($image))
	if (-e $image)
	{
		$imgcode="Content-Type: image/$ext\n\n";
		open(IMG,"< $image");
		binmode(IMG);
		binmode(STDOUT);

		#Read next 1024 bytes
		while(sysread(IMG, $buf, 1024))
		{
			$imgcode.=$buf;
		}

		close(IMG);
	}
	else
	{
		debug("PROBLEM! Could not open $image",4,__LINE__);
	}
	debug("\$imgcode=[$imgcode]",4,__LINE__);

	debug("Leaving subroutine: shroudPic($image)",4,__LINE__);

	return($imgcode);
}


##########################################################################

=head3 searchForm()

 $html=searchForm();

 $html - The search results, formatted in HTML.

Returns the search web form.

=cut
sub searchForm
{
my $html;

	$html=<<HTML;
<form method="POST" action="$::albumprog">
HTML
$html.="<br><br><table width=382 border=0 cellpadding=0 cellspacing=1 bgcolor=#868686 align=center><tr><td bgcolor=#F3F3F3><table width=380 border=0 cellpadding=0 cellspacing=0 class=sivitext><tr><td height=10 colspan=5><img src=images/spacer.gif width=1 height=1></td></tr><tr><td colspan=3><div align=right>$::S{281}&nbsp;</div></td><td colspan=2>";


$html.="<input type=text name=searchstring size=20 class=logintextbox></td></tr><tr><td height=16 colspan=5>&nbsp;</td></tr><tr><td width=73><div align=center>$::S{282}";


$html.="</div></td><td width=24>";
$html.="<input type=checkbox name=searchfilenames value=searchfilenames checked>";
$html.="</td><td width=122>$::S{283}</td><td width=24>";
$html.="<input type=checkbox name=searchcomments value=searchcomments checked></td>";
$html.="<td width=137>$::S{285}</td></tr><tr><td height=13 colspan=5><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=73>&nbsp;</td><td width=24>";
$html.="<input type=checkbox name=searchdescriptions value=searchdescriptions checked></td>";
$html.="<td width=122>$::S{284}</td><td width=24>";
$html.="<input type=checkbox name=searchowners value=searchowners checked></td>";
$html.="<td>$::S{289}</td></tr><tr><td height=14 colspan=5><img src=images/spacer.gif width=1 height=1></td></tr></table></td></tr></table>";
$html.="<table width=382 border=0 cellspacing=0 cellpadding=0 align=center><tr> <td><div align=right>";
$html.="<input name=imageField type=image src=images/button_pretraga.gif width=112 height=25 border=0>";
$html.="</div></td></tr></table>";


	$html.=passVars(1);

	$html.=<<HTML;
</form>
HTML

	return ($html);
}


##########################################################################

=head3 search()

 $html=search();

 $html - The search results, formatted in HTML.
 $searchstring - The search string to look for.
 $searchfilenames - Search photo filenames for a match, if non-zero.
 $searchdescriptions - Search descriptions.txt for a match, if non-zero.
 $searchcomments - Search ratings.txt (user comments for a match, if non-zero.
 $searchowners -Search descriptions.txt for matching users, if non-zero.

Searches for $newsearchstring in the locations defined by the combination of $searchxxx arguments, and returns all matching photos as formatted $html.

=cut
sub search
{
my $html;
my $result;
my $last_item;

	debug("Entering subroutine: search($::searchstring,$::searchfilenames,$::searchdescriptions,$::searchcomments,$::searchowners)",4,__LINE__);

	debug("searchstring: $::searchstring",2,__LINE__);
	debug("searchfilenames: $::searchfilenames",2,__LINE__);
	debug("searchdescriptions: $::searchdescriptions",2,__LINE__);
	debug("searchcomments: $::searchcomments",2,__LINE__);
	debug("searchowners: $::searchowners",2,__LINE__);

	$::doing_upload=1;
	recursiveScan($::album_dir);
	#doing_upload=0;

	# Sort search results
	sort(@::searchresults);

	# Show each item
	$prikazano=0;
	$html="<table align=center>";

	foreach $result (@::searchresults)
	{
		if ($result ne $last_item)
		{
			$prikazano_row=int($prikazano/3);
			if($prikazano_row*3==$prikazano)
			{
				$html.="<tr>";
			}
			$prikazano++;
			$html.="<td width=140>";
			debug("Displaying search result: $result",2,__LINE__);
			$html.="<table width=106 border=0 cellpadding=1 cellspacing=1 bgcolor=A2A2A2 height=100%><tr><td bgcolor=F7F7F7 width=106 height=100% align=center valign=top>".showObject($result)."</td></tr></table>";
			$html.="</td>";
			$prikazano_row=int($prikazano/3);
			if($prikazano_row*3==$prikazano)
			{
				$html.="</tr>";
			}
		}
		$last_item=$result;
	}
	$html.="</table>";

	if (!$::searchresults)
	{
		$::searchresults=0;
	}
	$html.="<span class=meniphoto><br>$::searchresults $::S{288}</span>";

	$::shortdesc=$::S{280};
	$::photo=$::album=$::longdesc="";

	debug("Leaving subroutine: search($::searchstring,$::searchfilenames,$::searchdescriptions,$::searchcomments,$::searchowners)",4,__LINE__);

	return($html);
}


##########################################################################

=head3 popular()

 $html=popular();

 $html - The "Most Popular" results, formatted in HTML.

Searches for the $::most_popular number of Most popular photos, and returns the HTML for them.

=cut
sub popular
{
my $html;
my $temphtml;
my $key;
my $current_count;
my $num_ratings;
my $current_rating;
my $filename;
my @keys;
my @popsortlist;
my $score;
my $overall_popularity;

	debug("Entering subroutine: popular()",4,__LINE__);

	$html="";

	$::doing_upload=1;
	recursiveScan($::album_dir);
	#doing_upload=0;

	@keys=keys %::poplist;
	debug("*** Start PopList Contents",3,__LINE__);
	foreach $key (@keys)
	{
		# Clear re-used vars
		$score=$num_ratings=$current_rating=$current_count=0;

		($num_ratings,$current_rating,$current_count)=split("\t",$::poplist{$key});

		# Adjust for albums
		if ($::popular_flag eq 2)
		{
		my $total;
			$total=$::popcount{$key};
			$num_ratings=int($num_ratings/$total);
			$current_rating=int($current_rating/$total*100)/100;
			$current_count=int($current_count/$total);
		}

		$score=popularityContest($num_ratings,$current_rating,$current_count);

		# Put it into the popular array
		push @popsortlist,"$score\t$key\t$num_ratings\t$current_rating\t$current_count";

		debug("$key: [$num_ratings,$current_rating,$current_count]: $score",3,__LINE__);
	}
	debug("*** End PopList Contents",3,__LINE__);

	# Sort
	@keys=sort(@popsortlist);

	for($key=0;$key <= $::most_popular;$key++)
	{
		if ($key)
		{
			# Clear re-used vars
			$score=$num_ratings=$current_rating=$current_count=0;

			($score,$filename,$num_ratings,$current_rating,$current_count)=split("\t",pop(@keys));
			debug("Pulling out of 'Most Popular List': $score,$filename,$num_ratings,$current_rating,$current_count",3,__LINE__);
			debug("$key/$::most_popular",3,__LINE__);

			if ($filename)
			{

				# Get object HTML
				$html.="<table width=478 border=0 cellspacing=0 cellpadding=0 align=center><tr><td width=100 rowspan=3>".showObject($filename,2)."</td></tr><tr><td height=1 colspan=3><img src=images/spacer.gif width=1 height=1></td></tr><tr><td width=177 bgcolor=#E5E5E5>";

				# Add rating/views info
				$temphtml="";

				# Add popularity
				$overall_popularity++;
				$temphtml.="<img src=images/spacer.gif width=10><span class=sivitext>$::S{274}$::S{221} </span><span class=meniphoto>$overall_popularity</span></td><td width=1><img src=images/spacer.gif width=1 height=1></td><td width=177 bgcolor=#E5E5E5 height=24><span class=sivitext><img src=images/spacer.gif width=10>";

				if ($current_rating || $num_ratings)
				{
					$temphtml.="$::S{175} ";
				}
				if ($current_rating)
				{
					$temphtml.="$current_rating";
				}
				if ($current_rating && $num_ratings)
				{
					$temphtml.=" (";
				}
				if ($num_ratings)
				{
					$temphtml.="$num_ratings";
				}
				if ($current_rating || $num_ratings)
				{
					$temphtml.=" $::S{202}";
				}
				if ($current_rating && $num_ratings)
				{
					$temphtml.=")";
				}
				if ($current_count && ($current_rating || $num_ratings))
				{
					$temphtml.=" - ";
				}
				if ($current_count)
				{
					$temphtml.="$::S{94} <b>$current_count $::S{202}</b>";
				}
				if ($current_count || $current_rating || $num_ratings)
				{
					$temphtml.=".";
				}
				$temphtml.="</span></td></tr></table>";

				if (!$::ssi && $html)
				{
					$html.=$temphtml."<p>\n";
				}
			}
		}
	}

	$::shortdesc="$::most_popular $::S{271}";
	$::photo=$::album=$::longdesc="";

	debug("Leaving subroutine: popular()",4,__LINE__);

	return($html);
}


##########################################################################

=head3 getPopularViews()

 getPopularViews($directory);

 $directory - Directory to check views information for.

Reads all views information from $directory, and populats @poplist (the list of popular files).

=cut
sub getPopularViews
{
my $directory=shift;
my $data;
my $current_count;
my $filename;
my $read_date;
my $fulldirectory;
my $poppic;
my $poplistkey;
my $temp1;
my $temp2;
my $temp3;
my @poppics;

	debug("Entering subroutine: getViews($directory);",4,__LINE__);

	# Add full path
	$fulldirectory="$::album_dir/$directory";

	# Reset vars
	$temp1=$temp2=$temp3=0;

	open(VIEWS,"$fulldirectory/$::viewfile") || return();

	while ($data=<VIEWS>)
	{
		($filename,$current_count,$read_date)=split("\t",$data);

		# Are we using galleries or photos?
		if ($::popular_flag eq 2)
		{
			$poplistkey="$directory";
		}
		else
		{
			$poplistkey="$directory/$filename";
		}

		# Check to see that it still exists before adding it to the list
		if (-e "$::album_dir/$directory/$filename")
		{

			# Clear existing vars
			$temp1=$temp2=$temp3=0;

			# Add existing values to get a total for the gallery
			if ($::poplist{"$poplistkey"})
			{
				($temp1,$temp2,$temp3)=split("\t",$::poplist{"$poplistkey"});
				$current_count+=$temp3;
			}

			$::popcount{"$poplistkey"}++;

			$::poplist{"$poplistkey"}="$temp1\t$temp2\t$current_count";
		}
		debug("TrackDebug: $filename,$current_count,$read_date",3,__LINE__);

	}

	close(VIEWS);

	debug("Leaving subroutine: getViews($directory);",4,__LINE__);
}


##########################################################################

=head3 popularityContest()

 $score=popularityContest($num_ratings,$current_rating,$current_count);

 $html - The "Most Popular" results, formatted in HTML.
 $num_ratings - Number of ratings for this object.
 $current_rating - Object's current ratings.
 $current_count - Number of times this object has been viewed.

Takes as input the ratings and views info, and makes a popularity score out of it. The current formula is:

	(($current_rating-2.5) * $num_ratings) + ($current_count / 20)

If you don't like that formula, modify it here.

=cut
sub popularityContest
{
my $num_ratings=shift;
my $current_rating=shift;
my $current_count=shift;
my $padlimit=6;
my $score;

	$score=(($current_rating-2.5)*$num_ratings)*20+$current_count;

	# Pad scores so they sort properly
	while (length($score) lt $padlimit)
	{
		$score="0".$score;
	}

	debug("Popularity Score is: <b>$score</b>",4,__LINE__);
	return($score);
}

##########################################################################

=head3 showObject()

 $html=showObject($myobject,$mode,$uploaduser,$uploadtime);

 $html - The object, as seen in "album view," including thumbnail, ratings, etc. Formatted in HTML.
 $myobject - The path to the object (relative to $::album_dir) to display.
 $mode - 0 = Display object normally; 1 = Display object for Recent Uploads; 2 = Display for Popular List
 $uploaduser - Username that uploaded this file (recent uploads only)
 $uploadtime - Time/date that the file was uploaded (recent uploads only)

Displays $object using the current settings of the album

=cut
sub showObject
{
my $myobject=shift;
my $mode=shift;
my $uploaduser=shift;
my $uploadtime=shift;
my $object_html="";
my $temp;
my $path;
my $albumtemp;
my $middletemp;
my $filetemp;
my $ssitemp;
my $objecttype;
my $classtype;

	debug("Entering subroutine: showObject($myobject,$mode);",4,__LINE__);

	# Save off vars
	$albumtemp=$::album;
	$middletemp=$::middle;

	# Change all \'s to /'s
	$myobject=~s/\\/\//g;

	# If we were passed an object, and if it still points to a file which isn't a thumbnail, display it
	if ($myobject && -r "$::album_dir/$myobject" && $myobject!~/$::thumbprefix/i)
	{
		debug("Displaying object: $myobject",3,__LINE__);

		# For "regular" photos, view in $::columns colums
#		if (!$mode)
#		{
#			$object_html.="<div class=\"dynwidth\">\n";
#		}
#		else
#		{
			if ($::ssi)
			{
				# Add randomizer
				if ($::randompic && $::slide_timer)
				{
					$object_html="<html><head>\n";
					$object_html.="<meta http-equiv=\"Refresh\" content=\"$::slide_timer; url=$::albumprog?random=1&ssi=$::ssi&slideshow=$::slide_timer\">\n";
					$object_html.="</head><body>\n";
				}
				$object_html.="<div class=\"ssirecentuploads\">\n";
			}
			elsif ($mode eq 1)
			{
				$object_html.="<div class=\"recentuploads\">\n";
			}
			elsif ($mode eq 2)
			{
				$object_html.="<div class=\"popular\">\n";
			}
#		}

		# Is it a photo, movie or an album?
		if (-d "$::album_dir/$myobject")
		{
			$objecttype="album";
		}
		elsif (isAMovie($myobject))
		{
			$objecttype="movie";
		}
		else
		{
			$objecttype="photo";
		}

		# Open link
		$object_html.="<img src=images/spacer.gif height=3 width=106 border=0><a href=\"";

		if ($objecttype eq "movie")
		{
			$object_html.="$::album_web/$myobject";
		}
		else
		{
			$object_html.="$::albumprog?$objecttype=$myobject";
		}
		$ssitemp=$::ssi;
		$::ssi=0;
		if ($objecttype ne "movie")
		{
			$temp=passVars(0);
		}
		$::ssi=$ssitemp;
		$object_html.=$temp;

		# Set link class by object type
		if ($objecttype eq "movie")
		{
			$classtype="moviethumb";
		}
		elsif ($objecttype eq "photo")
		{
			$classtype="imagethumb";
		}
		else
		{
			$classtype="albumthumb";
		}

		$object_html.="\" class=\"$classtype\">";
		$::album=$myobject;
		$::album=~s/(.*)\/(.*)/$1/;
		$path=$2;

		# Clear middle (album) if it's bogus
		if ($::album eq $myobject)
		{
			$::album="";
		}
		$::middle=$::album;

		# Set path if it's empty
		if (!$path)
		{
			$path=$myobject;
		}

		if ($objecttype eq "album")
		{
			$::album="$::album_dir/$myobject";
			$::album=~s/(.*)\/.*/$1/;

			$path=$::middle;
			$::middle=~s/(.*)\/.*/$1/;
			if ($path eq $::middle)
			{
				$::middle="";
			}

			$path=$myobject;
			$path=~s/.*\/(.*)/$1/;

			$::isalbum=1;
		}
		else
		{
			$::album="$::album_dir/$::album";
		}

		debug("\$myobject = $myobject",3,__LINE__);
		debug("\$::album = $::album",3,__LINE__);
		debug("\$path = $path",3,__LINE__);
		debug("\$::middle = $::middle",3,__LINE__);

		# Save off some vars
		$filetemp=$::file;
		$::file="";

		# Insert thumbnail HTML
		$object_html.=showThumb($myobject);

		# Restore vars
		$::file=$filetemp;

		# For SSI, don't display all the "fluff"
		if (!$::ssi)
		{
			# Get description for this photo
			openDescfile("$::album/");
			getDescription($path);
			close(DESC);

			# Set title to filename, if no title was found
			if (!$::shortdesc)
			{
				$::shortdesc=$path;
			}

			# Recent Uploads
			if ($mode)
			{
			my $photodesc=$::shortdesc;
			my $albumdir="$::album_dir/$::middle";

				# Get album description
				$albumdir=~s/(.*)\/(.*)/$1/;
				openDescfile("$albumdir/");
				getDescription("$2");
				close(DESC);

				# Set to album (directory) name if no description
				if (!$::shortdesc)
				{
					$::shortdesc=$::middle;
				}

				$object_html.="</a>";
				$object_html.="</div>";

				if ($mode eq 1)
				{
					$object_html.="<div class=\"recentuploads\">\n";
				}
				elsif ($mode eq 2)
				{
					#$object_html.="<div class=\"popular\">\n";
				}

				$object_html.="</td><td width=22 rowspan=3>&nbsp;</td><td colspan=3 bgcolor=#E5E5E5 valign=top><table width=100% border=0 cellspacing=0 cellpadding=0><tr><td height=20 valign=bottom><span class=meniphoto><img src=images/spacer.gif width=10>$photodesc</span></td></tr><tr><td><img src=images/spacer.gif height=10></td></tr>\n";
				if ($mode eq 1)
				{
					$object_html.="$::S{79} $uploaduser$::S{226}<br>\n";
				}
				if (!(($::popular_flag eq 2) && ($mode eq 2)))
				{
					$object_html.="<tr><td height=20><img src=images/spacer.gif width=10><span class=sivitext>$::S{196} </span><a href=\"$::albumprog?album=$::middle$temp\" class=meniphoto>$::shortdesc</a></td></tr></table>\n";
				}
				$object_html.="$uploadtime\n";
			}
			else
			# Display object info for "normal" viewing
			{

				# Display description
				if ($::descloc!=2)
				{
					if ($::descloc eq 1)
					{
						$object_html.="<br>";
					}
					else
					{
						$object_html.=" ";
					}
					$object_html.="<table width=100 border=0 cellpadding=1 cellspacing=1 align=center><tr><td><span class=meniphoto>$::shortdesc<\/span></td></tr></table>";

					# Is there a long description too?
					if ($::founddesc && $::longdesc)
					{
						# $object_html.=" <sup>$::S{120}</sup>";
					}
				}
				$object_html.="</a>";

				# Increment counter
				$::searchresults++;
			}
		}
		#$object_html.="</div>\n";
	}
	elsif (!-r "$::album_dir/$myobject")
	{
		debug("Warning: $::album_dir/$myobject is not readable",4,__LINE__);
	}


	# Restore vars
	$::album=$albumtemp;
	$::middle=$middletemp;

	debug("Leaving subroutine: showObject($myobject,$mode);",4,__LINE__);

	return ($object_html);
}


##########################################################################

=head3 updateComment()

 $retcode=updateComment($myobject,$comment);

 $retcode - Return value: 0 = Success; 1 = Failure.
 $myobject - The path to the photo, relative to album_dir.
 $comment - The comment to add to the photo.

Adds/Updates the comment in $myobject to be $comment. Uses ImageMagick's mogrify command to actually insert the comments into the photo. Not currently used, because it just keeps adding to the comment, and re-procsses the image. :(

=cut
sub updateComment
{
my $retcode;
my $output;
my $system_call;
my $myobject=shift;
my $comment=shift;

	debug("Entering subroutine: updateComment($myobject,$comment);",4,__LINE__);

	$myobject="$::album_dir/$myobject";

	if (!$::imagemagick || !$comment || !-e $myobject)
	{
		return(1);
	}

	$system_call="\"$::imagemagick/mogrify\" -quality 100 -comment \"$comment\" \"$myobject\"";

	# Resize into desired quality and dimensions
	debug("IMAGEMAGICK: $system_call",2,__LINE__);
	$output=`$system_call 2>&1`;
	debug("IMAGEMAGICK RETURNED: $output",2,__LINE__);

	if ($output)
	{
		print "$::S{214} $output<p>";
		$retcode=1;
	}

	debug("Leaving subroutine: updateComment($myobject,$comment);",4,__LINE__);

	return($retcode);
}


##########################################################################

=head3 detectBrowser()

 $type=detectBrowser();

 $type - The browser type: 0 = IE variant; 1 = Mozilla (Opera, Netscape, Phoenix, etc) variant

Detects the browser type, and returns the appropriate value

=cut
sub detectBrowser
{
my $type=$ENV{HTTP_USER_AGENT};

	debug("Entering subroutine: detectBrowser();",4,__LINE__);

	debug("Browser is: $type",2,__LINE__);

	if ($type=~/MSIE/)
	{
		$type=0;
	}
	else
	{
		$type=1;
	}

	debug("Returning: $type",2,__LINE__);

	debug("Leaving subroutine: detectBrowser();",4,__LINE__);

	return ($type);
}


##########################################################################

=head3 printHTMLeader()

 printHTMLeader();

Prints the HTML header if it hasn't already been printed.

=cut
sub printHTMLHeader
{
	if (!$::header_printed)
	{
		display($::html_header);
		$::header_printed=1;
	}
}


##########################################################################

=head3 getUserList()

 getUserList();

Reads the entire userlist as defined in the config, and returns it in an "HTML drop list" format

=cut
sub getUserList
{
use strict;
my $html;
my $myusername;
my $mydisplayname;
my $data;
my $storedpass;
my $dbi_fail;
my $memberslist;
my @userlist;

	$html=<<HTML;
<SELECT name="owner">
HTML

	# Flatfile authentication
	if ($::authentication_type eq 1)
	{

		# Open the text database
		open(AUTH_DB,$::auth_db) || error(__LINE__,"open_db","$::auth_db");

		# First check if user exists
		while (<AUTH_DB>)
		{
			chomp;
			($mydisplayname,$storedpass)=split('\|',$_);
			if ($mydisplayname)
			{
				$html.="<OPTION value=\"$mydisplayname\"";
				if ($mydisplayname eq $::owner)
				{
					$html.=" SELECTED";
				}
				$html.=">$mydisplayname</OPTION>\n";
			}
		}
		close(AUTH_DB);
		$mydisplayname=$myusername;
	}

	# UBB authentication
	if ($::authentication_type eq 2)
	{
		$memberslist="$::membersdir/memberslist.cgi";

		open (ENTRIES,"$memberslist") || error(__LINE__,"not_readable","$memberslist: $!");
		while ($data=<ENTRIES>)
		{
			$myusername=$data;
			chomp($myusername);
			$myusername=~s/.*\|(.*)/$1/;

			# Only process if a user was found
			if ($myusername)
			{
				open (FILE,"$::membersdir/$myusername.cgi");
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				$mydisplayname=<FILE>;
				close(FILE);

				chomp($mydisplayname);

				if (!$mydisplayname)
				{
					$mydisplayname=$myusername;
				}

				$html.="<OPTION value=\"$myusername\"";
				if ($myusername eq $::owner)
				{
					$html.=" SELECTED";
				}
				$html.=">$mydisplayname</OPTION>\n";
			}
		}
		close(ENTRIES);
	}

	# Load YaBB username/password
	if ($::authentication_type eq 3)
	{
		opendir(ENTRIES,"$::membersdir") or error(__LINE__,"not_readable","$::membersdir");

		# Change Grep
		@userlist=grep /.*\.dat$/,readdir ENTRIES;
		close(ENTRIES);

		foreach $memberslist (@userlist)
		{
			open(FILE,"$memberslist");
			$mydisplayname=<FILE>;
			$mydisplayname=<FILE>;
			close(FILE);
			$myusername=$memberslist;
			$myusername=~s/(.*)\.dat$/$1/;

			if ($mydisplayname)
			{
				$html.="<OPTION value=\"$myusername\"";
				if ($myusername eq $::owner)
				{
					$html.=" SELECTED";
				}
				$html.=">$mydisplayname</OPTION>\n";
			}
		}
	}

	# Check for DBI package, include if present
	my $pkg="DBI";
	my $method="connect";
	eval("use ".$pkg.";\n".$pkg."::".$method."()");

	if ($@=~/^Can't locate/)
	{
		$dbi_fail=1;
	}

	# Load database username/password
	if ($::authentication_type eq 4 && !$dbi_fail)
	{
	my $user_sql;
	my $dbh;
	my $sth;
	my $rv;
	my @row;

		# Connect to database
		$dbh=DBI->connect("DBI:$::db_driver:$::db_name:$::db_hostname:$::db_port",$::db_user,$::db_password) || die $DBI::errstr;

		# Build SQL command
		$user_sql="SELECT $::db_username FROM $::db_membertable";

		debug("SQL query: $user_sql",2,__LINE__);

		if ($dbh)
		{
			# Check SQL command
			$sth=$dbh->prepare($user_sql);

			# Check for errors
			if (!$sth)
			{
				$::warning.="$::S{293}$::S{221} ";
				$::warning.=$sth->errstr."<br>";
			}

			# Run SQL command
			$rv=$sth->execute;
			debug("Query returned $rv rows.",2,__LINE__);

			# Check for errors
			if (!$rv)
			{
				$::warning.="$::S{293}$::S{221} ";
				$::warning.=$sth->errstr."<br>";
			}

			# Fetch Rows
			while(@row=$sth->fetchrow_array)
			{
				$mydisplayname=$row[0];
				debug("\$row[0]=$mydisplayname",2,__LINE__);

				if ($mydisplayname)
				{
					$html.="<OPTION value=\"$mydisplayname\"";
					if ($mydisplayname eq $::owner)
					{
						$html.=" SELECTED";
					}
					$html.=">$mydisplayname</OPTION>\n";
				}
			}

			# Disconnect from database
			$dbh->disconnect;
		}
		else
		{
			$::warning.="$::S{293}$::S{226}<br>";
		}

		debug("Warning is currently: $::warning",2,__LINE__);
	}

	$html.="</SELECT>";

	return($html);
}

######################## END OF SUBROUTINES ########################

######################## END OF FILE ########################

